commit 2b8200409c90ffd169db19aa13c53dc95062ed3f Author: aymeric Date: Thu Sep 4 15:47:34 2008 +0000 Initial import git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@1 3f6dc0c8-ddfe-455d-9043-3cd528dc4637 diff --git a/linphone/.cvsignore b/linphone/.cvsignore new file mode 100644 index 000000000..90955bc8d --- /dev/null +++ b/linphone/.cvsignore @@ -0,0 +1,24 @@ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +intltool-extract +intltool-merge +intltool-update +libtool +ltmain.sh +missing +mkinstalldirs +speex +stamp-h1 +linphone.spec diff --git a/linphone/ABOUT-NLS b/linphone/ABOUT-NLS new file mode 100644 index 000000000..ec20977e0 --- /dev/null +++ b/linphone/ABOUT-NLS @@ -0,0 +1,1101 @@ +1 Notes on the Free Translation Project +*************************************** + +Free software is going international! The Free Translation Project is +a way to get maintainers of free software, translators, and users all +together, so that free software will gradually become able to speak many +languages. A few packages already provide translations for their +messages. + + If you found this `ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU `gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU `gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work on translations can contact the appropriate team. + + When reporting bugs in the `intl/' directory or bugs which may be +related to internationalization, you should tell about the version of +`gettext' which is used. The information can be found in the +`intl/VERSION' file, in internationalized packages. + +1.1 Quick configuration advice +============================== + +If you want to exploit the full power of internationalization, you +should configure it using + + ./configure --with-included-gettext + +to force usage of internationalizing routines provided within this +package, despite the existence of internationalizing capabilities in the +operating system where this package is being installed. So far, only +the `gettext' implementation in the GNU C library version 2 provides as +many features (such as locale alias, message inheritance, automatic +charset conversion or plural form handling) as the implementation here. +It is also not possible to offer this additional functionality on top +of a `catgets' implementation. Future versions of GNU `gettext' will +very likely convey even more functionality. So it might be a good idea +to change to GNU `gettext' as soon as possible. + + So you need _not_ provide this option if you are using GNU libc 2 or +you have installed a recent copy of the GNU gettext package with the +included `libintl'. + +1.2 INSTALL Matters +=================== + +Some packages are "localizable" when properly installed; the programs +they contain can be made to speak your own native language. Most such +packages use GNU `gettext'. Other packages have their own ways to +internationalization, predating GNU `gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU `gettext' functions. If not, the included GNU +`gettext' library will be used. This library is wholly contained +within this package, usually in the `intl/' subdirectory, so prior +installation of the GNU `gettext' package is _not_ required. +Installers may use special options at configuration time for changing +the default behaviour. The commands: + + ./configure --with-included-gettext + ./configure --disable-nls + +will, respectively, bypass any pre-existing `gettext' to use the +internationalizing routines provided within this package, or else, +_totally_ disable translation of messages. + + When you already have GNU `gettext' installed on your system and run +configure without an option for your new package, `configure' will +probably detect the previously built and installed `libintl.a' file and +will decide to use this. This might not be desirable. You should use +the more recent version of the GNU `gettext' library. I.e. if the file +`intl/VERSION' shows that the library which comes with this package is +more recent, you should use + + ./configure --with-included-gettext + +to prevent auto-detection. + + The configuration process will not test for the `catgets' function +and therefore it will not be used. The reason is that even an +emulation of `gettext' on top of `catgets' could not provide all the +extensions of the GNU `gettext' library. + + Internationalized packages usually have many `po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at `configure' time by using the +`--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable `LINGUAS' +may be set, prior to configuration, to limit the installed set. +`LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +1.3 Using This Package +====================== + +As a user, if your language has been installed for this package, you +only have to set the `LANG' environment variable to the appropriate +`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, +and `CC' is an ISO 3166 two-letter country code. For example, let's +suppose that you speak German and live in Germany. At the shell +prompt, merely execute `setenv LANG de_DE' (in `csh'), +`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). +This can be done from your `.login' or `.profile' file, once and for +all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of `LL_CC', with `LL' denoting the +language and `CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are +used, such as `LL' or `LL_CC.ENCODING'. You can get the list of +locales supported by your system for your language by running the +command `locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' +for the purpose of message handling, but you still need to have `LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather +read translations in German than English for when Swedish is not +available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. + + Special advice for Norwegian users: The language code for Norwegian +bokma*l changed from `no' to `nb' recently (in 2003). During the +transition period, while some message catalogs for this language are +installed under `nb' and some older ones under `no', it's recommended +for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and +older translations are used. + + In the `LANGUAGE' environment variable, but not in the `LANG' +environment variable, `LL_CC' combinations can be abbreviated as `LL' +to denote the language's main dialect. For example, `de' is equivalent +to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' +(Portuguese as spoken in Portugal) in this context. + +1.4 Translating Teams +===================== + +For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" +area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +`-request' appended. For example, speakers of Swedish can send a +message to `sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate +_actively_ in translations, or at solving translational difficulties, +rather than merely lurking around. If your team does not exist yet and +you want to start one, or if you are unsure about what to do or how to +get started, please write to `translation@iro.umontreal.ca' to reach the +coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skills are praised more than +programming skills, here. + +1.5 Available Packages +====================== + +Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of October +2006. The matrix shows, in regard of each package, for which languages +PO files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo + +----------------------------------------------------+ + GNUnet | [] | + a2ps | [] [] [] [] [] | + aegis | () | + ant-phone | () | + anubis | [] | + ap-utils | | + aspell | [] [] [] [] [] | + bash | [] [] [] | + batchelor | [] | + bfd | | + bibshelf | [] | + binutils | [] | + bison | [] [] | + bison-runtime | | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | [] [] | + coreutils | [] [] [] | + cpio | | + cpplib | [] [] [] | + cryptonit | [] | + darkstat | [] () [] | + dialog | [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] | + doodle | [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] | + error | [] [] [] [] | + fetchmail | [] [] () [] | + fileutils | [] [] | + findutils | [] [] [] | + flex | [] [] [] | + fslint | [] | + gas | | + gawk | [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] [] [] | + gip | [] | + gliv | [] | + glunarclock | [] | + gmult | [] [] | + gnubiff | () | + gnucash | () () [] | + gnucash-glossary | [] () | + gnuedu | | + gnulib | [] [] [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] | + gpe-conf | [] [] | + gpe-contacts | | + gpe-edit | [] | + gpe-filemanager | | + gpe-go | [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] | + gpe-package | | + gpe-sketchbook | [] [] | + gpe-su | [] [] | + gpe-taskmanager | [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | | + gphoto2 | [] [] [] [] | + gprof | [] [] | + gpsdrive | () () | + gramadoir | [] [] | + grep | [] [] [] [] [] [] | + gretl | | + gsasl | | + gss | | + gst-plugins | [] [] [] [] | + gst-plugins-base | [] [] [] | + gst-plugins-good | [] [] [] [] [] [] [] | + gstreamer | [] [] [] [] [] [] [] | + gtick | () | + gtkam | [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] | + id-utils | [] [] | + impost | | + indent | [] [] [] | + iso_3166 | [] [] | + iso_3166_2 | | + iso_4217 | [] | + iso_639 | [] [] | + jpilot | [] | + jtag | | + jwhois | | + kbd | [] [] [] [] | + keytouch | | + keytouch-editor | | + keytouch-keyboa... | | + latrine | () | + ld | [] | + leafpad | [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] | + libgpg-error | [] | + libgphoto2 | [] [] | + libgphoto2_port | [] [] | + libgsasl | | + libiconv | [] [] | + libidn | [] [] | + lifelines | [] () | + lilypond | [] | + lingoteach | | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | [] | + make | [] [] | + man-db | [] () [] [] | + minicom | [] [] [] | + mysecretdiary | [] [] | + nano | [] [] [] | + nano_1_0 | [] () [] [] | + opcodes | [] | + parted | | + pilot-qof | [] | + psmisc | [] | + pwdutils | | + python | | + qof | | + radius | [] | + recode | [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] [] | + sed | [] [] [] | + sh-utils | [] [] | + shared-mime-info | [] [] [] [] | + sharutils | [] [] [] [] [] [] | + shishi | | + silky | | + skencil | [] () | + sketch | [] () | + solfege | | + soundtracker | [] [] | + sp | [] | + stardict | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] | + texinfo | [] [] [] | + textutils | [] [] [] | + tin | () () | + tp-robot | [] | + tuxpaint | [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + vorbis-tools | [] [] [] [] | + wastesedge | () | + wdiff | [] [] [] [] | + wget | [] [] | + xchat | [] [] [] [] [] [] | + xkeyboard-config | | + xpad | [] [] | + +----------------------------------------------------+ + af am ar az be bg bs ca cs cy da de el en en_GB eo + 10 0 1 2 9 22 1 42 41 2 60 95 16 1 17 16 + + es et eu fa fi fr ga gl gu he hi hr hu id is it + +--------------------------------------------------+ + GNUnet | | + a2ps | [] [] [] () | + aegis | | + ant-phone | [] | + anubis | [] | + ap-utils | [] [] | + aspell | [] [] [] | + bash | [] [] [] | + batchelor | [] [] | + bfd | [] | + bibshelf | [] [] [] | + binutils | [] [] [] | + bison | [] [] [] [] [] [] | + bison-runtime | [] [] [] [] [] | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | | + coreutils | [] [] [] [] [] [] | + cpio | [] [] [] | + cpplib | [] [] | + cryptonit | [] | + darkstat | [] () [] [] [] | + dialog | [] [] [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] [] | + enscript | [] [] [] | + error | [] [] [] [] [] | + fetchmail | [] | + fileutils | [] [] [] [] [] [] | + findutils | [] [] [] [] | + flex | [] [] [] | + fslint | [] | + gas | [] [] | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] | + gettext-tools | [] [] [] | + gimp-print | [] [] | + gip | [] [] [] | + gliv | () | + glunarclock | [] [] [] | + gmult | [] [] [] | + gnubiff | () () | + gnucash | () () () | + gnucash-glossary | [] [] | + gnuedu | [] | + gnulib | [] [] [] [] [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] [] [] | + gpe-conf | [] | + gpe-contacts | [] [] | + gpe-edit | [] [] [] [] | + gpe-filemanager | [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] [] [] [] | + gpe-package | [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] [] | + gpe-taskmanager | [] [] [] | + gpe-timesheet | [] [] [] [] | + gpe-today | [] [] [] [] | + gpe-todo | [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] [] | + gpsdrive | () () [] () | + gramadoir | [] [] | + grep | [] [] [] [] [] [] [] [] [] [] [] [] | + gretl | [] [] [] | + gsasl | [] [] | + gss | [] | + gst-plugins | [] [] [] | + gst-plugins-base | [] [] | + gst-plugins-good | [] [] [] | + gstreamer | [] [] [] | + gtick | [] | + gtkam | [] [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] [] | + impost | [] [] | + indent | [] [] [] [] [] [] [] [] [] [] | + iso_3166 | [] [] [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] [] | + iso_639 | [] [] [] [] [] | + jpilot | [] [] | + jtag | [] | + jwhois | [] [] [] [] [] | + kbd | [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | [] [] [] | + ld | [] [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] [] [] | + libgpg-error | | + libgphoto2 | [] [] [] | + libgphoto2_port | [] [] | + libgsasl | [] [] | + libiconv | [] [] | + libidn | [] [] | + lifelines | () | + lilypond | [] | + lingoteach | [] [] [] | + lynx | [] [] [] | + m4 | [] [] [] [] | + mailutils | [] [] | + make | [] [] [] [] [] [] [] [] | + man-db | () | + minicom | [] [] [] [] | + mysecretdiary | [] [] [] | + nano | [] [] [] [] [] [] | + nano_1_0 | [] [] [] [] [] | + opcodes | [] [] [] [] | + parted | [] [] [] [] | + pilot-qof | | + psmisc | [] [] [] | + pwdutils | | + python | | + qof | [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] | + sed | [] [] [] [] [] | + sh-utils | [] [] [] [] [] [] [] | + shared-mime-info | [] [] [] [] [] [] | + sharutils | [] [] [] [] [] [] [] [] | + shishi | | + silky | [] | + skencil | [] [] | + sketch | [] [] | + solfege | [] | + soundtracker | [] [] [] | + sp | [] | + stardict | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] [] [] | + texinfo | [] [] | + textutils | [] [] [] [] [] | + tin | [] () | + tp-robot | [] [] [] [] | + tuxpaint | [] [] | + unicode-han-tra... | | + unicode-transla... | [] [] | + util-linux | [] [] [] [] [] [] [] | + vorbis-tools | [] [] | + wastesedge | () | + wdiff | [] [] [] [] [] [] [] [] | + wget | [] [] [] [] [] [] [] [] | + xchat | [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] | + xpad | [] [] [] | + +--------------------------------------------------+ + es et eu fa fi fr ga gl gu he hi hr hu id is it + 88 22 14 2 40 115 61 14 1 8 1 6 59 31 0 52 + + ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no + +-------------------------------------------------+ + GNUnet | | + a2ps | () [] [] () | + aegis | () | + ant-phone | [] | + anubis | [] [] [] | + ap-utils | [] | + aspell | [] [] | + bash | [] | + batchelor | [] [] | + bfd | | + bibshelf | [] | + binutils | | + bison | [] [] [] | + bison-runtime | [] [] [] | + bluez-pin | [] [] [] | + cflow | | + clisp | [] | + console-tools | | + coreutils | [] | + cpio | | + cpplib | [] | + cryptonit | [] | + darkstat | [] [] | + dialog | [] [] | + diffutils | [] [] [] | + doodle | | + e2fsprogs | [] | + enscript | [] | + error | [] | + fetchmail | [] [] | + fileutils | [] [] | + findutils | [] | + flex | [] [] | + fslint | [] [] | + gas | | + gawk | [] [] | + gbiff | [] | + gcal | | + gcc | | + gettext-examples | [] [] | + gettext-runtime | [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] | + gip | [] [] | + gliv | [] | + glunarclock | [] [] | + gmult | [] [] | + gnubiff | | + gnucash | () () | + gnucash-glossary | [] | + gnuedu | | + gnulib | [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] | + gpe-beam | [] | + gpe-calendar | [] | + gpe-clock | [] [] [] | + gpe-conf | [] [] | + gpe-contacts | [] | + gpe-edit | [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] | + gpe-taskmanager | [] [] [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | [] | + gphoto2 | [] [] | + gprof | | + gpsdrive | () () () | + gramadoir | () | + grep | [] [] [] [] | + gretl | | + gsasl | [] | + gss | | + gst-plugins | [] | + gst-plugins-base | | + gst-plugins-good | [] | + gstreamer | [] | + gtick | | + gtkam | [] | + gtkorphan | [] | + gtkspell | [] [] | + gutenprint | | + hello | [] [] [] [] [] [] | + id-utils | [] | + impost | | + indent | [] [] | + iso_3166 | [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] | + iso_639 | [] [] | + jpilot | () () () | + jtag | | + jwhois | [] | + kbd | [] | + keytouch | [] | + keytouch-editor | | + keytouch-keyboa... | | + latrine | [] | + ld | | + leafpad | [] [] | + libc | [] [] [] [] [] | + libexif | | + libextractor | | + libgpewidget | [] | + libgpg-error | | + libgphoto2 | [] | + libgphoto2_port | [] | + libgsasl | [] | + libiconv | | + libidn | [] [] | + lifelines | [] | + lilypond | | + lingoteach | [] | + lynx | [] [] | + m4 | [] [] | + mailutils | | + make | [] [] [] | + man-db | () | + minicom | [] | + mysecretdiary | [] | + nano | [] [] [] | + nano_1_0 | [] [] [] | + opcodes | [] | + parted | [] [] | + pilot-qof | | + psmisc | [] [] [] | + pwdutils | | + python | | + qof | | + radius | | + recode | [] | + rpm | [] [] | + screem | [] | + scrollkeeper | [] [] [] [] | + sed | [] [] | + sh-utils | [] [] | + shared-mime-info | [] [] [] [] [] | + sharutils | [] [] | + shishi | | + silky | [] | + skencil | | + sketch | | + solfege | | + soundtracker | | + sp | () | + stardict | [] [] | + system-tools-ba... | [] [] [] [] | + tar | [] [] [] | + texinfo | [] [] [] | + textutils | [] [] [] | + tin | | + tp-robot | [] | + tuxpaint | [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] | + vorbis-tools | [] | + wastesedge | [] | + wdiff | [] [] | + wget | [] [] | + xchat | [] [] [] [] | + xkeyboard-config | [] | + xpad | [] [] [] | + +-------------------------------------------------+ + ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no + 52 24 2 2 1 3 0 2 3 21 0 15 1 97 5 1 + + nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + +------------------------------------------------------+ + GNUnet | | + a2ps | () [] [] [] [] [] [] | + aegis | () () | + ant-phone | [] [] | + anubis | [] [] [] | + ap-utils | () | + aspell | [] [] | + bash | [] [] [] | + batchelor | [] [] | + bfd | | + bibshelf | [] | + binutils | [] [] | + bison | [] [] [] [] [] | + bison-runtime | [] [] [] [] | + bluez-pin | [] [] [] [] [] [] [] [] [] | + cflow | [] | + clisp | [] | + console-tools | [] | + coreutils | [] [] [] [] | + cpio | [] [] [] | + cpplib | [] | + cryptonit | [] [] | + darkstat | [] [] [] [] [] [] | + dialog | [] [] [] [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] [] | + error | [] [] [] [] | + fetchmail | [] [] [] | + fileutils | [] [] [] [] [] | + findutils | [] [] [] [] [] [] | + flex | [] [] [] [] [] | + fslint | [] [] [] [] | + gas | | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] [] [] | + gimp-print | [] [] | + gip | [] [] [] [] | + gliv | [] [] [] [] | + glunarclock | [] [] [] [] [] [] | + gmult | [] [] [] [] | + gnubiff | () | + gnucash | () [] | + gnucash-glossary | [] [] [] | + gnuedu | | + gnulib | [] [] [] [] [] | + gnunet-gtk | [] | + gnutls | [] [] | + gpe-aerial | [] [] [] [] [] [] [] | + gpe-beam | [] [] [] [] [] [] [] | + gpe-calendar | [] | + gpe-clock | [] [] [] [] [] [] [] [] | + gpe-conf | [] [] [] [] [] [] [] | + gpe-contacts | [] [] [] [] [] | + gpe-edit | [] [] [] [] [] [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] [] [] [] | + gpe-login | [] [] [] [] [] [] [] [] | + gpe-ownerinfo | [] [] [] [] [] [] [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] [] [] [] [] [] [] | + gpe-su | [] [] [] [] [] [] [] [] | + gpe-taskmanager | [] [] [] [] [] [] [] [] | + gpe-timesheet | [] [] [] [] [] [] [] [] | + gpe-today | [] [] [] [] [] [] [] [] | + gpe-todo | [] [] [] [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] | + gpsdrive | [] [] [] | + gramadoir | [] [] | + grep | [] [] [] [] [] [] [] [] | + gretl | [] | + gsasl | [] [] [] | + gss | [] [] [] | + gst-plugins | [] [] [] [] | + gst-plugins-base | [] | + gst-plugins-good | [] [] [] [] | + gstreamer | [] [] [] | + gtick | [] | + gtkam | [] [] [] [] | + gtkorphan | [] | + gtkspell | [] [] [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] | + impost | [] | + indent | [] [] [] [] [] [] | + iso_3166 | [] [] [] [] [] [] | + iso_3166_2 | | + iso_4217 | [] [] [] [] | + iso_639 | [] [] [] [] | + jpilot | | + jtag | [] | + jwhois | [] [] [] [] | + kbd | [] [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | [] [] | + ld | [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] [] | + libgpewidget | [] [] [] [] [] [] [] | + libgpg-error | [] [] | + libgphoto2 | [] | + libgphoto2_port | [] [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] | + libidn | [] [] () | + lifelines | [] [] | + lilypond | | + lingoteach | [] | + lynx | [] [] [] | + m4 | [] [] [] [] [] | + mailutils | [] [] [] [] | + make | [] [] [] [] | + man-db | [] [] | + minicom | [] [] [] [] [] | + mysecretdiary | [] [] [] [] | + nano | [] [] [] | + nano_1_0 | [] [] [] [] | + opcodes | [] [] | + parted | [] | + pilot-qof | [] | + psmisc | [] [] | + pwdutils | [] [] | + python | | + qof | [] [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] | + rpm | [] [] [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] | + sed | [] [] [] [] [] [] [] [] [] | + sh-utils | [] [] [] | + shared-mime-info | [] [] [] [] [] | + sharutils | [] [] [] [] | + shishi | [] | + silky | [] | + skencil | [] [] [] | + sketch | [] [] [] | + solfege | [] | + soundtracker | [] [] | + sp | | + stardict | [] [] [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] | + texinfo | [] [] [] [] | + textutils | [] [] [] | + tin | () | + tp-robot | [] | + tuxpaint | [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + vorbis-tools | [] [] | + wastesedge | | + wdiff | [] [] [] [] [] [] | + wget | [] [] [] [] | + xchat | [] [] [] [] [] [] [] | + xkeyboard-config | [] [] | + xpad | [] [] [] | + +------------------------------------------------------+ + nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + 0 2 3 58 30 54 5 73 72 4 40 46 11 50 128 2 + + tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + +---------------------------------------------------+ + GNUnet | [] | 2 + a2ps | [] [] [] | 19 + aegis | | 0 + ant-phone | [] [] | 6 + anubis | [] [] [] | 11 + ap-utils | () [] | 4 + aspell | [] [] [] | 15 + bash | [] | 11 + batchelor | [] [] | 9 + bfd | | 1 + bibshelf | [] | 7 + binutils | [] [] [] | 9 + bison | [] [] [] | 19 + bison-runtime | [] [] [] | 15 + bluez-pin | [] [] [] [] [] [] | 28 + cflow | [] [] | 5 + clisp | | 6 + console-tools | [] [] | 5 + coreutils | [] [] | 16 + cpio | [] [] [] | 9 + cpplib | [] [] [] [] | 11 + cryptonit | | 5 + darkstat | [] () () | 15 + dialog | [] [] [] [] [] | 30 + diffutils | [] [] [] [] | 28 + doodle | [] | 6 + e2fsprogs | [] [] | 10 + enscript | [] [] [] | 16 + error | [] [] [] [] | 18 + fetchmail | [] [] | 12 + fileutils | [] [] [] | 18 + findutils | [] [] [] | 17 + flex | [] [] | 15 + fslint | [] | 9 + gas | [] | 3 + gawk | [] [] | 15 + gbiff | [] | 5 + gcal | [] | 5 + gcc | [] [] [] | 6 + gettext-examples | [] [] [] [] [] [] | 27 + gettext-runtime | [] [] [] [] [] [] | 28 + gettext-tools | [] [] [] [] [] | 19 + gimp-print | [] [] | 12 + gip | [] [] | 12 + gliv | [] [] | 8 + glunarclock | [] [] [] | 15 + gmult | [] [] [] [] | 15 + gnubiff | [] | 1 + gnucash | () | 2 + gnucash-glossary | [] [] | 9 + gnuedu | [] | 2 + gnulib | [] [] [] [] [] | 28 + gnunet-gtk | | 1 + gnutls | | 2 + gpe-aerial | [] [] | 14 + gpe-beam | [] [] | 14 + gpe-calendar | [] | 3 + gpe-clock | [] [] [] [] | 21 + gpe-conf | [] [] | 14 + gpe-contacts | [] [] | 10 + gpe-edit | [] [] [] [] | 20 + gpe-filemanager | [] | 6 + gpe-go | [] [] | 15 + gpe-login | [] [] [] [] [] | 21 + gpe-ownerinfo | [] [] [] [] | 21 + gpe-package | [] | 6 + gpe-sketchbook | [] [] | 16 + gpe-su | [] [] [] | 20 + gpe-taskmanager | [] [] [] | 20 + gpe-timesheet | [] [] [] [] | 18 + gpe-today | [] [] [] [] [] | 21 + gpe-todo | [] | 7 + gphoto2 | [] [] [] [] | 20 + gprof | [] [] | 11 + gpsdrive | | 4 + gramadoir | [] | 7 + grep | [] [] [] [] | 34 + gretl | | 4 + gsasl | [] [] | 8 + gss | [] | 5 + gst-plugins | [] [] [] | 15 + gst-plugins-base | [] [] [] | 9 + gst-plugins-good | [] [] [] [] [] | 20 + gstreamer | [] [] [] | 17 + gtick | [] | 3 + gtkam | [] | 13 + gtkorphan | [] | 7 + gtkspell | [] [] [] [] [] [] | 26 + gutenprint | | 3 + hello | [] [] [] [] [] | 37 + id-utils | [] [] | 14 + impost | [] | 4 + indent | [] [] [] [] | 25 + iso_3166 | [] [] [] [] | 16 + iso_3166_2 | | 2 + iso_4217 | [] [] | 14 + iso_639 | [] | 14 + jpilot | [] [] [] [] | 7 + jtag | [] | 3 + jwhois | [] [] [] | 13 + kbd | [] [] | 12 + keytouch | [] | 4 + keytouch-editor | | 2 + keytouch-keyboa... | [] | 3 + latrine | [] [] | 8 + ld | [] [] [] [] | 8 + leafpad | [] [] [] [] | 23 + libc | [] [] [] | 23 + libexif | [] | 4 + libextractor | [] | 5 + libgpewidget | [] [] [] | 19 + libgpg-error | [] | 4 + libgphoto2 | [] | 8 + libgphoto2_port | [] [] [] | 11 + libgsasl | [] | 8 + libiconv | [] | 7 + libidn | [] [] | 10 + lifelines | | 4 + lilypond | | 2 + lingoteach | [] | 6 + lynx | [] [] [] | 15 + m4 | [] [] [] | 18 + mailutils | [] | 8 + make | [] [] [] | 20 + man-db | [] | 6 + minicom | [] | 14 + mysecretdiary | [] [] | 12 + nano | [] [] | 17 + nano_1_0 | [] [] [] | 18 + opcodes | [] [] | 10 + parted | [] [] [] | 10 + pilot-qof | [] | 3 + psmisc | [] | 10 + pwdutils | [] | 3 + python | | 0 + qof | [] | 4 + radius | [] | 6 + recode | [] [] [] | 25 + rpm | [] [] [] [] | 14 + screem | [] | 2 + scrollkeeper | [] [] [] [] | 26 + sed | [] [] [] | 22 + sh-utils | [] | 15 + shared-mime-info | [] [] [] [] | 24 + sharutils | [] [] [] | 23 + shishi | | 1 + silky | [] | 4 + skencil | [] | 7 + sketch | | 6 + solfege | | 2 + soundtracker | [] [] | 9 + sp | [] | 3 + stardict | [] [] [] [] | 11 + system-tools-ba... | [] [] [] [] [] [] [] | 37 + tar | [] [] [] [] | 20 + texinfo | [] [] [] | 15 + textutils | [] [] [] | 17 + tin | | 1 + tp-robot | [] [] [] | 10 + tuxpaint | [] [] [] | 16 + unicode-han-tra... | | 0 + unicode-transla... | | 2 + util-linux | [] [] [] | 20 + vorbis-tools | [] [] | 11 + wastesedge | | 1 + wdiff | [] [] | 22 + wget | [] [] [] | 19 + xchat | [] [] [] [] | 29 + xkeyboard-config | [] [] [] [] | 11 + xpad | [] [] [] | 14 + +---------------------------------------------------+ + 77 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + 170 domains 0 1 1 77 39 0 136 10 1 48 5 54 0 2028 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and +distributed as such by its maintainer. There might be an observable +lag between the mere existence a PO file and its wide availability in a +distribution. + + If October 2006 seems to be old, you may fetch a more recent copy of +this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date +matrix with full percentage details can be found at +`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. + +1.6 Using `gettext' in new packages +=================================== + +If you are writing a freely available program and want to +internationalize it you are welcome to use GNU `gettext' in your +package. Of course you have to respect the GNU Library General Public +License which covers the use of the GNU `gettext' library. This means +in particular that even non-free programs can use `libintl' as a shared +library, whereas only free software can use `libintl' as a static +library or use modified versions of `libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of `gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +`translation@iro.umontreal.ca' to make the `.pot' files available to +the translation teams. + diff --git a/linphone/AUTHORS b/linphone/AUTHORS new file mode 100644 index 000000000..386427a4f --- /dev/null +++ b/linphone/AUTHORS @@ -0,0 +1,57 @@ +Simon MORLAT (simon dot morlat at linphone dot org) wrotes: + - main graphical program (gnome) + - RTP library (oRTP) + - SIP user-agent library (osipua) + - audio library (mediastreamer), for codec and i/o handling. + - sipomatic, the automatic sip replier, which is often used for testing. + +Florian Wintertein < f-win at gmx dot net > wrotes the console version of linphone (linphonec) +in console/ directory. + +Aymeric Moizard (jack at atosc dot org) wrotes: + - the oSIP SIP transactionnal stack (not part of linphone) + - some piece of code of the osip distribution have been reused in osipua + - presence information support in osipua + - and contributes to some parts of osipua (digest authentification) +For more information about oSIP, see http://osip.atosc.org + +Sharath Udupa is developing the media_api, a usefull library to manage audio and video streams +for basic calls as well as conference. + +Sandro Santilli < strk at keybit dot net > wrote enhancements in the +console interface (readline, new commands) and some bug fixes for +the core api. + +Bryan Ogawa ( bko at cisco dot com ) sent a patch that made the linphone-0.7.1 release. +This patch fixed several issues in the SIP part while working with proxies. + +Koichi KUNITAKE < kunitake at linux-ipv6 dot org > has contributed a patch bringing +full IPv6 support. + +The Speex codec is a project from Jean Marc Valin. See http://speex.sourceforge.net for more +information. + +The GSM library was written by : + Jutta Degener and Carsten Bormann,Technische Universitaet Berlin. + +The LPC10-1.5 library was written by: + Andy Fingerhut + Applied Research Laboratory <-- this line is optional if + Washington University, Campus Box 1045/Bryan 509 you have limited space + One Brookings Drive + Saint Louis, MO 63130-4899 + jaf@arl.wustl.edu + http://www.arl.wustl.edu/~jaf/ + + See text files in gsmlib and lpc10-1.5 directories for further information. + +G711 library has some code from the alsa-lib on http://www.alsa-project.org + +Icons by Pablo Marcelo Moia. + +Translations: +fr: Simon Morlat +en: Simon Morlat and Delphine Perreau +it: Alberto Zanoni +de: Jean-Jacques Sarton +es: Jesús Benítez diff --git a/linphone/BUGS b/linphone/BUGS new file mode 100644 index 000000000..1c45089e5 --- /dev/null +++ b/linphone/BUGS @@ -0,0 +1,9 @@ +linphone-1.0.0: + It seems ipv6 support is "broken". Some help is welcome. + +linphone-0.12.0 + When compiling with gcc-2.95.4 on debian, an assert fails and cause abort() + in libasound (alsa-lib). When compiling with gcc-3.2, it does not happen. + It seems that asoundlib and linphone must be compiled with the same compiler. + +Simon MORLAT diff --git a/linphone/COPYING b/linphone/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/linphone/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/linphone/ChangeLog b/linphone/ChangeLog new file mode 100644 index 000000000..140cdaea0 --- /dev/null +++ b/linphone/ChangeLog @@ -0,0 +1,513 @@ +2008-09-02 Francois-Xavier Kowalski + + * gtk/Makefile.am (INCLUDES): 1.6 + Deprecated automake directive INCLUDES does not work within a + conditionnal. + +2008-08-22 Francois-Xavier Kowalski + + * mediastreamer2/src/Makefile.am (libmediastreamer_la_SOURCES+): 1.27 + Deliver swscale.h in case ffmpeg does not come with libswscale + (in which case the swscale feature is included into + libavcodec). Also deliver ffmpeg-priv.h wrapper. + + * mediastreamer2/src/videoout.c: 1.39 + * mediastreamer2/src/videodec.c: 1.24 + * mediastreamer2/src/sizeconv.c: 1.14 + * mediastreamer2/src/pixconv.c: 1.13 + * mediastreamer2/src/nowebcam.c: 1.15 + Use ffmpeg-priv,h + + * mediastreamer2/mediastreamer-config.h.in: 1.13 + Remove from CVSm as it is generated by autoheader + + * mediastreamer2/configure.ac: 1.47 + Use pkg-config to check for arts + + * mediastreamer2/acinclude.m4: 1.12 + Remove -I/usr/include and -L/usr/lib(64) from CFLAGS and LIBS. + Check for ffmpeg swscale feature into libavcodec or into + libswscale + +2007-09-26 Francois-Xavier Kowalski + + * m4/exosip.m4: 1.3 + make Linphone buildable with the eXosip/osip version that ships + with Fedora. + + * oRTP/include/ortp/stun_udp.h: 1.9 + * mediastreamer2/include/mediastreamer2/msvideo.h: 1.7 + * mediastreamer2/include/mediastreamer2/msticker.h: 1.6 + * mediastreamer2/include/mediastreamer2/msqueue.h: 1.3 + Clean ANSI/C vs. ANSI/C++ differences + +2007-08-01 Sandro Santilli + + * console/commands.c: Clean up commands 'nat', 'stun' + and 'firewall' to be more intuitive. + +2007-02-03 Francois-Xavier Kowalski + + * m4/osip.m4 (OSIP_CFLAGS): 1.2 + * gnome/Makefile.am (linphone_applet_LDADD): 1.33 + * coreapi/Makefile.am (liblinphone_la_CFLAGS): 1.38 + * console/Makefile.am (sipomatic_LDADD): 1.45 + Cope with osip2-2.2.2 delivered as legacy on FC6. New option + "--with-osip-version" + +2007-01-18 Francois-Xavier Kowalski + + * oRTP/Makefile.am: 1.24 + * mediastreamer2/Makefile.am: 1.30 + * Makefile.am: 1.45 + Fix RPM package generattion to cope with + + +2007-01-17 gettextize + + * m4/gettext.m4: Upgrade to gettext-0.16.1. + * m4/lib-link.m4: Upgrade to gettext-0.16.1. + * m4/lib-prefix.m4: Upgrade to gettext-0.16.1. + * m4/nls.m4: Upgrade to gettext-0.16.1. + * m4/po.m4: Upgrade to gettext-0.16.1. + * m4/codeset.m4: Upgrade to gettext-0.16.1. + * m4/intl.m4: New file, from gettext-0.16.1. + * m4/intldir.m4: New file, from gettext-0.16.1. + * m4/intmax.m4: Upgrade to gettext-0.16.1. + * m4/inttypes_h.m4: Upgrade to gettext-0.16.1. + * m4/inttypes-pri.m4: Upgrade to gettext-0.16.1. + * m4/lock.m4: New file, from gettext-0.16.1. + * m4/longdouble.m4: Upgrade to gettext-0.16.1. + * m4/longlong.m4: Upgrade to gettext-0.16.1. + * m4/size_max.m4: Upgrade to gettext-0.16.1. + * m4/stdint_h.m4: Upgrade to gettext-0.16.1. + * m4/ulonglong.m4: Upgrade to gettext-0.16.1. + * m4/visibility.m4: New file, from gettext-0.16.1. + * m4/Makefile.am (EXTRA_DIST): Add the new files. + +2006-10-18 Sandro Santilli + + * console/Makefile.am: set osip includes last in the + search path. + +2006-09-19 Francois-Xavier Kowalski + + * linphone.spec.in (BuildRequires): 1.8 + Add RPM build-time dependency on gettext-devel to define + AM_GNU_GETTEXT. + +2006-07-26 Sandro Santilli + + * .cvsignore, developer-docs/mediastreamer/.cvsignore, + ipkg/.cvsignore, mediastreamer2/.cvsignore, + mediastreamer2/build/.cvsignore, + mediastreamer2/build/win32native/.cvsignore, + mediastreamer2/include/.cvsignore, + mediastreamer2/include/mediastreamer2/.cvsignore, + mediastreamer2/plugins/.cvsignore, + mediastreamer2/src/.cvsignore, + mediastreamer2/tests/.cvsignore, + oRTP/build/win32/.cvsignore, + oRTP/build/win32native/.cvsignore, + oRTP/src/tests/win_receiver/.cvsignore, + oRTP/src/tests/win_sender/.cvsignore, + po/.cvsignore, share/cs/.cvsignore: + Added-fixed .cvsignore files + +2006-07-20 gettextize + + * m4/codeset.m4: New file, from gettext-0.14.6. + * m4/gettext.m4: New file, from gettext-0.14.6. + * m4/glibc2.m4: New file, from gettext-0.14.6. + * m4/glibc21.m4: New file, from gettext-0.14.6. + * m4/iconv.m4: New file, from gettext-0.14.6. + * m4/intdiv0.m4: New file, from gettext-0.14.6. + * m4/intmax.m4: New file, from gettext-0.14.6. + * m4/inttypes.m4: New file, from gettext-0.14.6. + * m4/inttypes_h.m4: New file, from gettext-0.14.6. + * m4/inttypes-pri.m4: New file, from gettext-0.14.6. + * m4/isc-posix.m4: New file, from gettext-0.14.6. + * m4/lcmessage.m4: New file, from gettext-0.14.6. + * m4/lib-ld.m4: New file, from gettext-0.14.6. + * m4/lib-link.m4: New file, from gettext-0.14.6. + * m4/lib-prefix.m4: New file, from gettext-0.14.6. + * m4/longdouble.m4: New file, from gettext-0.14.6. + * m4/longlong.m4: New file, from gettext-0.14.6. + * m4/nls.m4: New file, from gettext-0.14.6. + * m4/po.m4: New file, from gettext-0.14.6. + * m4/printf-posix.m4: New file, from gettext-0.14.6. + * m4/progtest.m4: New file, from gettext-0.14.6. + * m4/signed.m4: New file, from gettext-0.14.6. + * m4/size_max.m4: New file, from gettext-0.14.6. + * m4/stdint_h.m4: New file, from gettext-0.14.6. + * m4/uintmax_t.m4: New file, from gettext-0.14.6. + * m4/ulonglong.m4: New file, from gettext-0.14.6. + * m4/wchar_t.m4: New file, from gettext-0.14.6. + * m4/wint_t.m4: New file, from gettext-0.14.6. + * m4/xsize.m4: New file, from gettext-0.14.6. + * m4/Makefile.am (EXTRA_DIST): Add the new files. + * Makefile.am (EXTRA_DIST): Add config.rpath. + +2006-07-07 Francois-Xavier Kowalski + + * linphone.spec.in (Version): 1.7 + Force build of gtk-doc, as the default choice that comes with + GTK_DOC_CHECK m4 macro is "no". + +2006-05-17 Francois-Xavier Kowalski + + * configure.in: 1.179 + * configure.in: 1.178 + Allow rpm users to use oRTP packages built from Linphone root. + +May 8 2006 : Sandro Santilli + + * configure.in: lowered libspeex requirement to 1.1.6 + +undefined yet: linphone-1.4.0 + - new audio/video streaming engine (mediastreamer2) that let the following improvements: + + split video frame to get them smaller than MTU + + less video latency + + video supported at CIF and QCIF resolution with variable framerate. + + arts sound input/output + + improved sound latency with alsa + + alsa support works with dmix/dsnoop + + old oss drivers that don't like select and non blocking mode should finally work + - lpc10-15 support removed (speex does better at 8kbit/s) + - jack support unported to mediastreamer2, sorry : volunteer needed + - video resolution and framerate set according to bandwidth constraints. + - linphonec new "soundcard" command to list and choose sound devices. + - new download and upload bandwidth parameters. + +March 31 2006: linphone-1.3.4 + - fix linphonec bug in auto-answer mode: was terminating call after a few seconds. + +March 28 2006: linphone-1.3.3 + - various FedoraCore 4 compile problem solved + - fix video bug ('could not mmap': happening on kernel>=2.6.15 with pwc driver) + - SIP register were not using route field (submitted patch) + +March 17 2006: linphone-1.3.2 + - fix early media call problem: ack for 200ok was never sent. + +March 10 2006: linphone-1.3.1 + - fix compile errors with gcc-2.95 (thanks Wolfram Gloger) + +March 8 2006 : linphone-1.3.0 (SUMMARY) + - a lots of improvements in linphonec (see strk 's Changelogs below) + - telephone event problem with sipomatic. + - updated cz translation. + - fix bugs around addressbook. + - video support with H263-1998/RFC2429 nearly clean. + - added timeout for incoming calls + +February 20 2006 : Sandro Santilli + + * console/commands.c: added filter support for + command 'friend list'. + +February 13 2006 : Sandro Santilli + + * console/linphonec.c: fixed unused variable warning. + +February 02 2006 : Sandro Santilli + Console: + - Padded vtable with missing callbacks + (fixing a segfault on friends subscription) + - Handled friends notify (bare version) + - Handled text messages receive (bare version) + - Printed message on subscription request (bare version) + - Added 'friend list' and 'friend call' commands + - Allowed for multiple DTMF send in a single line + - Added status-specific callback (bare version) + + +January 26 2006 : Sandro Santilli + - Core: fixed bug in linphone_core_set_nat_address refusing + to set address if use flag was off, added support + for NULL addr parameter to only change use flag. + - Support: added missing GFileTest enum values + - Console: 'nat' commands, cleanups + +January 25 2006 : Sandro Santilli + - Core: added request uri in proxy registration failure message + - Console: removed the -t switch + (terminate on close is default behaviour) + +January 20 2006 : Sandro Santilli + - Console: + linphonec_init() and linphonec_finish() functions. Handled + SIGINT and SIGTERM to invoke linphonec_finish(). Handling of + auto-termination (-t) moved to linphonec_finish(). Reworked main + (input read) loop to not rely on 'terminate' and 'run' variable + (dropped). configfile_name allocated on stack using PATH_MAX + limit. Changed print_usage signature to allow for an exit_status + specification. + +January 18 2006 : Sandro Santilli + - Console: + Command completion inhibited + in proxy addition and auth request prompts. Avoided use of + readline's internal filename completion. + +January 14 2006 : Sandro Santilli + - Console: + Reworked commands interface to use a table structure, used by + command line parser and help function. Implemented first + level of completion (commands). Added notification of + invalid "answer" and "terminate" commands (no incoming call, + no active call). Forbidden "call" intialization when a call is + already active. Cleaned up all commands, adding more feedback + and error checks. + +January 13 2006 : Sandro Santilli + - Console: + Added linphonec.h. Code layout change (added comments, forward + decl, globals on top, copyright notices and Logs). Handled + out-of-memory condition on history management. Removed + assumption on sizeof(char). Fixed bug in authentication + prompt (introduced by readline). Added support for multiple + authentication requests (up to MAX_PENDING_AUTH). + +January 12 2006 : Sandro Santilli + - Console: + Changed default configuration file to ~/.linphonerc, + automatically handling migration from old layout if not present + (use ~/.linphonec or ~/.gnome2/linphone). Added compile-time + define to show identity in prompt. Used EXIT_SUCCESS and + EXIT_FAILURE macros. + Made readline use ~/.linphonec_history file for + reading/writing. Fixed auto-call handling code. Fixed + OOB write of sscanf() in linphonec_parse_command_line(). + Simplified control flow in linphonec_main_loop(). + Put linphonec_{initialize,finish}_readline() calls out of + main_loop(). Removed redundant exit(0) at end of main(). + Fixed small leaks. + +December 14 2005 : linphone-1.2.0 + - various ipv6 bugfixes (again) + - fix po.pl file (was utf-8 but declared as iso8902) + - enum/automatic proxy conflict solved. use "sip:7887488478" for enums, just "382884824" to go through the default proxy. + - experimental video support progresses, compliance improved. + - remove ilbc from source tree: it is now available as a separete plugin. + - updated to work with lastest ffmpeg cvs + - fix bug when answering 'busy here'; active call was closed ! + - fix Ctrl+H bug in linphonec + - added bresilian translation + - added swedish translation + - uri bar improvements + - fix a DoS attack by setting a payload type number > 127 + +August 24 2005 : linphone-1.1.0 + - peer to peer text chat + - automatic sip url completion when using a default proxy: + when user types 'mymother' in the url bar, linphone calls sip:mymother@[default-proxy] + - ilbc 20 and 30 miliseconds frames support + - support for setting a soundcard for playback and another for record + - ipv6 bugfixes: works with ipv6 local loopback with sipomatic at least ! Needs to be tested in a real network. + - gtk interface bugfixes + - increase max supported sound devices (was 5). + - automatic incoming redirections + - experimental video support (needs special compilation procedure, see mailing lists) + + +March 27 2005 : linphone-1.0.1 + - patch for NAT traversal (SDP connection address in SDP answer) + - patch for writing correct port information when NAT is enabled + - patch for always using "rport" extension to traverse NAT with + signalling. + - patch for saving/restoring correct configuration of proxy: + "reg_register" -> "reg_sendregister" and fix for saving "expires" + +March 21 2005 : linphone-1.0.0 + - switch from osipua to eXosip/osip2 for improved sip functionnalities and compliance. + - support for presence (busy, online...) for everyone in the address book (uses SUBSCRIBE/NOTIFY) + - support for PUBLISH (presence information through sip servers) + - support for configuring multiple proxies. + - RTP adaptive jitter buffer ( provides lower latency ) + - RTCP coumpound messages sent periodically. + - on demand digest authentication for INVITE and REGISTER + - support for 183 with sdp answers. + - add support for jackd (contributed) + - call logging + - arm build improved + - cz and nl translations contributed. + + +January 2004 : linphone-0.12.2 + - add enum support (see RFC3241 and RFC3026) + Thanks to Rene Bartsch < ml at bartschnet dot de > for its usefull + and precious help. + - interactive presence box (no more need to click OK to confirm) + - update spanish translation + - alsa interface: the user can choose precisely the pcm device to be used + by setting the sound/alsadev parameter of the config file. + - use 1 RTP socket instead of 2: this makes linphone NAT-friendly. + +Thursday October 2 2003 : linphone-0.12.1 + - add support for personalizing rings. + - make glib dependency optionnal (but recommended). + - add polish translation. + - use of libartsc to suspend arts instead of killing him. + +Tuesday August 19 2003 : linphone-0.12.0 + - add support for speex/16000 + - re-enable alsa support (0.9.x) + - few improvements on gui. + - added spanish translation by Jesús Benítez + +Monday April 05 2003: linphone-0.11.0 + - merge ipv6 support patch, contributed by Koichi KUNITAKE + < kunitake at linux-ipv6 dot org > (thanks !) + - some improvements on graphical interface. + +Friday Feb 28 2003 : linphone-0.10.1 + - add firewall friendly capability + - compiles all well on arm-linux + - bugfixes. + +Friday Jan 24 2003 : linphone-0.10.0 + - Gnome interface ported to gnome-2 + - Unified core engine for both graphical and console interface. + - Many bug fix and improvements in the SIP stack. + - Japoneese translations and manual added, by Yamaguchi Yoshiya. + - updated for speex-1.0rc1 + - ported to FreeBSD thanks to Georg Shwarz + +Monday Oct 21 2002 : linphone-0.9.1 + - AMD: add support for the "received" and "rport" parameter in osipua. + +Monday Oct 21 2002 : linphone-0.9.1 + - integration of the patch of Lenaic Huard that adds the ability for linphone to send + dtmf tones through rtp (only reported to console interface). + - following this patch, a nice keypad has been added to the graphical interface to bring + the fonctionnality of the patch gui's users. + - integration of the patch of Aymeric Moizard, concerning compliance with RFC3261 (new + sip's RFC) using the new dialog_t api of libosip. + - updated for use of speex-beta1 (speex codec) + - osipua fix by jack@atosc.org + 1: reject calls with 603 + 2: establishement of 1 early dialog for incoming calls. + 3: update to libosip CVS and its new OSIP_TRACE MACROs. + 4: fix presence handling. + 5: fix expires header in REGISTER. + + +Monday Aug 26 2002: linphone-0.9.0 + - the sdp rtpmap string for alaw and mulaw codec was incorrect. + +Sunday Aug 4 2002: linphone-0.9.0pre3 + Non visible changes: + - Linphone's internal audio architecture is ported to the new mediastreamer architecture. + The mediastreamer library is already present in linphone since October 29 2001 but + was never used at this time by the core program. Now lots of work has be done inside the + mediastreamer so that it is ready to be used by the core program. As a consequence, the + old architecture defined by the audio/ directory and the codec.c io.c files is dropped. + The mediastreamer architecture provides a modular framework for audio and video + processing. It includes various audio and video codecs (or wrappers to third party + audio and video codecs). + Visible changes: + - The Speex codec (http://speex.sourceforge.net) is now availlable to linphone, since it has + its mediastreamer wrapper. This patent-free codec provides two bitrates, the lowest + being able to work with 56k dialup connections. This is a very important step, because + from now only the low quality LPC10 codec was availlable for such connections. + - Thanks to Florian Winsterstein (f-win at gmx.de), a console version of linphone called + "linphonec" is availlable. Linphonec can be compiled without gnome. + +Wednesday May 8 2002: linphone-0.8.0 + Visible changes: + - Updated to libosip-0.8.5, that reflects the lastest sip draft. + - Uses the SDP parser the libosip, and uses also a modified version of its SDP negociator. + The MediaDesc object is removed, now osipua users have to deal with BodyHandler's, as the + SdpHandler that deals with sdp message generation and negociation. + The SDP parser and negociator can use the a=rtpmap fields, so that compliance is improved. + - LPC10-1.5 codec has been assigned payload type 115 instead of 4 previously. This breaks + compatibility with older versions of linphone. + - oRTP (the new RTP library) is used in place of the old lprtplib. + - fix endianess problems in the audio part. + Non visible changes (changes on libraries not currently used by linphone but used later): + - mediastreamer has new working objects: webcam image capture, mpeg encoding and decoding + thanks to the libavcodec (ffmpeg) library, rtp wrapper thanks to oRTP. + +Tuesday April 15 2002: linphone-0.7.2 + - A crash in property box "apply" fixed. + - bugfix in osipua. + +Tuesday March 12 2002: linphone-0.7.1 + - Some bug fixes by Bryan Ogawa in osipua: route, record-route, tags. + +Friday March 1 2002: linphone-0.7.0 + - Digest authentification support added by Aymeric. + - Improvements in property box. + - Translations in German and Italian by J.J. Sarton and A. Zanoni + - Bugfix and improvements in the osipua stack. + - Better handling of the registration parameters (the user can set its own address of record). + + +Thu December 6 2001 + -osipua.c: Memory allocations. + fi call of from_tag_add(...,sgetcopy(ua->fromtag)); + -utils.c: Memory allocations. + -CallLegs are removed automatically by the osipua layer (eg: when a transaction timed out). + +Tue November 27 2001 + -Bugfix in osipua for proxy support: record-route and route header support, request-uri bug fixed. + -New choice "outbound proxy" in the property box. + -Fix compilation issues. + + +Mon October 29 2001 + -New unithreaded design of the osipua library, based on libosip-0.7.x series. + -Asynchronous name resolution in osipua. + -To and From tag support added. + -Proxy support added. The user can choose between registering for a redirect server, or + registering for a proxy server. When he choose proxy, then all requests are sent to the proxy. + -New good looking graphical interface. + -Mediastreamer is included, but still unused. It has a begin of gtkdoc dcocumentation. + +Wed September 26 2001 + -Add registration and redirection ability in gui and osipua. + -Critical bugs in osipua/osip fixed. + -Display all sip error strings in appbar. + -Documentation translated in French. + +Tue August 21 2001 + - Add address book functionnality + - Add ringback + - Minor bugfixes in configure.in, src/callbacks.c + - Work with libosip-0.6.1 + +Wed August 1 2001: + - Integration with osip sip stack. lpsiplib is no more used and abandonned. osipua provides the session level + on top of osip. + - added G711 codecs. + - configuration structures and api re-written for more clarity. + - new codec selection box + - new sytem for codec registration + - automatic selection of codecs regarding to network connection type. + - add resizing ability for icon applet. + + +June 2001: linphone-0.3.0 + -Nearly all code in linphone is object oriented. + -linphone can be run as a gnome applet, or as a silent dameon, or as a normal application. + -bugfixes in sip/sdp messages. + -addition of a test program called sipomatic that can automatically answers to call. (for test) + -add io_disk implementation of the audio lib. this can be used to replace the sond card by io on file system. + + + +Tue May 15 2001: linphone-0.2.1 + -Fix a stupid bug in the audio library. + +Fri May 11 2001: linphone-0.2.0 + -add many missing features of version 0.1.0 (for the property box) + -audio levels on the main window. + -Sip library modified: now it uses one thread, and should be able to handle several calls in the future. + -audio library is more performant. It is able to find itself the best blocksize (latency) by testing the driver. + -interactive help on the property box and user manual. + -add an icon. + +linphone-0.1.0 : + Released on april,19 2001 + Initial version. diff --git a/linphone/INSTALL b/linphone/INSTALL new file mode 100644 index 000000000..23e5f25d0 --- /dev/null +++ b/linphone/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/linphone/Makefile.am b/linphone/Makefile.am new file mode 100644 index 000000000..7a3c39db4 --- /dev/null +++ b/linphone/Makefile.am @@ -0,0 +1,42 @@ +## Process this file with automake to produce Makefile.in + +# let make re-run automake upon need +ACLOCAL_AMFLAGS = -I m4 + +if EXTERNAL_ORTP +ORTP_DIR = +else +ORTP_DIR = oRTP +endif + +SUBDIRS = m4 pixmaps po ipkg $(ORTP_DIR) mediastreamer2\ + media_api coreapi console gtk gtk-glade share + + +EXTRA_DIST = config.rpath linphone2.glade BUGS linphone.kdevprj \ + intltool-extract.in \ + intltool-merge.in \ + intltool-update.in \ + README.arm \ + autogen.sh \ + linphone.spec.in linphone.spec +ACLOCAL_FLAGS=-I$(top_srcdir)/m4 + +DISTCLEANFILES= intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache + +# `make rpm' + +all-local: linphone.spec +linphone.spec: linphone.spec.in + +.phony: rpm +rpm: + $(MAKE) dist +# Create "Specfile" at the same level as the tarball content + -rm -f $(PACKAGE)-$(VERSION).tar + gunzip $(PACKAGE)-$(VERSION).tar.gz + cp $(PACKAGE).spec Specfile + tar --append --file=$(PACKAGE)-$(VERSION).tar Specfile + gzip $(PACKAGE)-$(VERSION).tar +# + TAR_OPTIONS=--wildcards rpmbuild -ta --clean --rmsource --rmspec $(PACKAGE)-$(VERSION).tar.gz diff --git a/linphone/NEWS b/linphone/NEWS new file mode 100644 index 000000000..ea93cc1c8 --- /dev/null +++ b/linphone/NEWS @@ -0,0 +1,75 @@ +linphone-2.1.1 -- February 13, 2008 + * fix interroperability bug with Asterisk about a BYE not sent by linphone. + * fix alsa support weakness (capture underruns not recovered) + +linphone-2.1.0 -- January 25, 2008 + * 4CIF support + * enable resizing of video output + * hu translation added + +linphone-2.0.1 -- November 30, 2007 + * fix interop issue with asterisk + * answer OPTIONS and other SIP messages + * allow usage of ALSA user pcm devices with the sound->alsadev config item. + +linphone-2.0.0 -- November 15, 2007 + * port to libeXosip2-3.0.x with libosip2-3.0.x + * implements early media + * implements incoming re-INVITE + * presence support improvements + * ipv6 working on windows + * implements SDP over 200ok/ACK + * add experimental snow codec support + * answers to VFU request in SIP-INFO by sending an I-frame. + * ffmpeg rate control enabled, improved mpeg4 quality for low bandwidths + * separate video grabbing and display in linphonec + +linphone-1.7.1 -- April 16, 2007 + * cz translation + * compilation bugfixes (when video support is disabled) + * fix IM icons path bug + +linphone-1.7.0 -- April 11, 2007 + * new splash screen when no webcam is detected + * new friend commands for linphonec + * gnome interface becomes gtk-only + * fix issue with codec bitrate settings when no bandwidth limits are given + * open rtp sockets before sending SDP offer or answer (so that we don't miss the + first I-frame) + +linphone-1.6.0 -- January 23, 2007 + * Video4Linux V2 support with mjpeg cameras + * use MPEG4 config string provided in the SDP (if any) + * fix bug when choosing an invalid ring sound file + * fix bug when using quickcam driver with CIF size + * reduce audio bandwidth usage for <128kbit/s connections with video + +linphone-1.5.1 -- November 14, 2006 + * fix translations + +linphone-1.5.0 -- October 11, 2006 + * compliant theora support (using Luca Barbato's draft) + * mpeg4 support (compliant with RFC3016) + * controls to display and modify video codec list (gnome interface) + * banwidth usage improvements + * splash screen when no webcam is detected + +linphone-1.4.1 -- September 18, 2006 + * fixes crash when attempting to make two simultaneous calls + * fixes crash when having no soundcard + * require theora>=1.0.0-alpha7 + * do not allow resizing of the gnome interface + * do not change mixer settings at startup + +linphone-1.4.0 -- September 11, 2006 + * no more glib dependency at all + * new mediastreamer2 framework for audio/video streaming + * stable video support with H.263-1998 + * echo cancelation + * experimental theora support + * jack support unported to mediastreamer2, sorry : volunteer needed + * video resolution and framerate set according to bandwidth constraints. + * linphonec new "soundcard" command to list and choose sound devices. + * new download and upload bandwidth parameters used to find suitable video/audio codec choice and parameters. + * new 'play' and 'record' functions to linphonec to play and record wav files + * arts sound backend diff --git a/linphone/README b/linphone/README new file mode 100644 index 000000000..27aafdbcd --- /dev/null +++ b/linphone/README @@ -0,0 +1,53 @@ +******************Building linphone *********************************** +- you need at least: + - libosip2>=3.0.3 + - libeXosip2>=3.0.3 + - speex>=1.1.6 + - libreadline + + gsm codec (gsm source package or libgsm-dev or gsm-devel) (optional) + + if you want to gtk interface: + - gtk>=2.4.0 + + if you want video support: + - SDL>=1.2.10 + - libavcodec (ffmpeg) from a year 2007 or later cvs + +with their corresponding -dev or -devel package if you don't use source packages. + + + +************************************** user documentation ********************* +go to linphone's web site: http://www.linphone.org + + +******************************** DEVELOPER documentation ******************** + +Here is a short description of the content of the source tree. + +- oRTP/ is a poweful implementation of the RTP protocol. See the oRTP/README for more details. + It is used by the mediastreamer to send and receive streams to the network. + +- mediastreamer2/ is one of the important part of linphone. It is a framework library for audio + and video processing. It contains several objects for grabing audio and video and outputing + it (through rtp, to file). + It contains also codec objects to compress audio and video streams. + The mediastream.h files contain routines to easyly setup audio streams. + +- mediastreamer/ is deprecated. + +- media_api/ is going to be an easy to use library to handle audio and video session. It uses + the mediastreamer at the backend to do the processing. It is going to be the only interface + between the core application and the mediastreamer. At the moment this library is still in + early stages of development and is unused by the core application. + +- coreapi/ is the central point of linphone, which handles relationship between sip signalisation and media + streaming. It contains an easy to use api to create a sip phone. + +- gtk/ is the directory that contains the gui frontend of linphone. It uses all libraries descibed above. + +- console/ + * linphonec.c is the main file for the console version of linphone. + * sipomatic.c / sipomatic.h contains the code for sipomatic, the test program that auto-answer to linphone calls. If you want to understand + how linphone runs, this is a good start example. + +- share/ contains translation, documentation, rings and hello sound files. + diff --git a/linphone/README.CVS b/linphone/README.CVS new file mode 100644 index 000000000..53b782def --- /dev/null +++ b/linphone/README.CVS @@ -0,0 +1,12 @@ +In order to compile from CVS, you have to first install: +- pkg-config +- intltool (intltool-devel if rpm) +- install the mandatory and optional dependencies described in README file. + +Then: + ./autogen.sh #to generate the configure script + ./configure # with desired options + make + + +Simon MORLAT < simon dot morlat at linphone dot org > diff --git a/linphone/README.M68k.txt b/linphone/README.M68k.txt new file mode 100644 index 000000000..a3659f8ad --- /dev/null +++ b/linphone/README.M68k.txt @@ -0,0 +1,93 @@ + LINPHONE ON M68k-LINUX (by GIAN) + ******************************** + +The console version of linphone works on arm-linux, but also on m68k-linux? I’m trying to provide this: + +* I used the same toolchain specified in the LTIB menu configuration, that is, on my system: +/opt/mtwk/usr/local/m68k-linux/gcc-3.4.0-glibc-2.3.2-v4e + +* I have created within my home directory a ColdFire-install-environment/ directory, copied into it the fresh tarballs of libogg-1.1.3, libosip2-2.2.2, speex-1.1.12, linphone-1.4.0 readline-5.1 and ncurses-5.5 (readline needs ncurses) Uncompressed all these +tarballs. + +Very important things common to all packages being cross compiled: +****************************************************************** +* Copy the ipaq-config.site in the ipkg/ directory of linphone into some safe place, for example: +cp /home/gianluca/ColdFire-install-environment/linphone-1.4.0-install/linphone-1.4.0/ipkg/ipag-config.site /home/gianluca/ColdFire-install-environment/linphone-1.4.0-install/ +Edit the ipaq-config.site file and replace all the arm-linux strings with m68k-linux one. Add also the –mcfv4e flag to the CFLAGS, CXXFLAGS, and CPPFLAGS labels. +* You need a directory that we call M68K_INSTALL_TREE that will own files in the same way they will be installed on the target computer. + +mkdir /ColdFire-linphonec-1.4.0-mcfv4e +export M68K_INSTALL_TREE=/ColdFire-linphonec-1.4.0-mcfv4e +export CONFIG_SITE=/home/gianluca/ColdFire-install-environment/linphone-1.4.0-install/ipaq-config.site +export PATH=$PATH:/opt/mtwk/usr/local/m68k-linux/gcc-3.4.0-glibc-2.3.2-v4e/bin + + +Cross compiling ncurses for M68k: +******************************** +./configure --prefix=/usr --host=m68k-linux --with-gnu-ld --with-shared +make +make install DESTDIR=$M68K_INSTALL_TREE + + +Cross compiling readline for M68k: +********************************* +./configure --prefix=/usr --host=m68k-linux --with-gnu-ld --disable-static +make +make install DESTDIR=$M68K_INSTALL_TREE + + + +Cross compiling libosip for M68k: +******************************** +./configure --prefix=/usr --host=m68k-linux --with-gnu-ld --disable-static +make +make install DESTDIR=$M68K_INSTALL_TREE + + +Cross compiling libogg for M68k: +******************************** +./configure --prefix=/usr --host=m68k-linux --with-gnu-ld --disable-static –enable-fixed-point +make +make install DESTDIR=$M68K_INSTALL_TREE + + +Cross compiling speex for M68k: +******************************** +./configure --prefix=/usr --host=m68k-linux --with-gnu-ld --disable-static --enable-fixed-point --enable-m68k-asm --with-ogg=/ColdFire-linphonec-1.4.0-mcfv4e/usr --with-ogg-includes=/ColdFire-linphonec-1.4.0-mcfv4e/usr/include –with-ogg-libraries=/ColdFire-linphonec-1.4.0-mcfv4e/usr/lib --disable-oggtest +make +make install DESTDIR=$M68K_INSTALL_TREE + + +cp /home/gianluca/ColdFire-iinstall-environment/linphone-1.4.0-install/linphone-1.4.0/mediastreamer2/src/.libs/libquickstream.so.0.0.0 /opt/mtwk/usr/local/m68k-linux/gcc-3.4.0-glibc-2.3.2-v4e/m68k-linux/lib +cd /opt/mtwk/usr/local/m68k-linux/gcc-3.4.0-glibc-2.3.2-v4e/m68k-linux/lib +ln -s libquickstream.so.0.0.0 libquickstream.so.0 +ln -s libquickstream.so.0.0.0 libquickstream.so + +cp /home/gianluca/ColdFire-install-environment/linphone-1.4.0-install/linphone-1.4.0/mediastreamer2/src/.libs/libmediastreamer.so.0.0.0 /opt/mtwk/usr/local/m68k-linux/gcc-3.4.0-glibc-2.3.2-v4e/m68k-linux/lib +cd /opt/mtwk/usr/local/m68k-linux/gcc-3.4.0-glibc-2.3.2-v4e/m68k-linux/lib +ln -s libmediastreamer.so.0.0.0 libmediastreamer.so.0 +ln -s libmediastreamer.so.0.0.0 libmediastreamer.so + + +Cross compiling linphone for M68k: +******************************** +First you need to remove all .la files from the M68K_INSTALL_TREE because it confuses libtool and makes +the linker use your build machine binaries instead of the m68k-crosscompiled ones. +rm -f $M68K_INSTALL_TREE/usr/lib/*.la +#for some reason pkg-config doesn't like cross-compiling... +export PKG_CONFIG=/usr/bin/pkg-config +./configure --prefix=/usr --host=m68k-linux --with-gnu-ld --disable-static --disable-strict --enable-gnome_ui=no --enable-alsa --disable-glib --disable-video --with-osip=$ARM_INSTALL_TREE/usr --with-osipparser=$ARM_INSTALL_TREE/usr --with-readline=$ARM_INSTALL_TREE/usr SPEEX_CFLAGS="-I$ARM_INSTALL_TREE/usr/include" SPEEX_LIBS="-L$ARM_INSTALL_TREE/usr/lib -lspeex" +make +make install DESTDIR=$M68K_INSTALL_TREE + + +Binaries can also be stripped with m68k-linux-strip to save more space. + + +Running linphone under the ColdFire board +******************************************** + +You just have to start linphone from a terminal by typing 'linphonec'. + +Gianluca Salvador + diff --git a/linphone/README.arm b/linphone/README.arm new file mode 100644 index 000000000..5020729f3 --- /dev/null +++ b/linphone/README.arm @@ -0,0 +1,106 @@ + LINPHONE ON ARM-LINUX (HANDHELD COMPUTERS) + ****************************************** + +The console version of linphone works on arm-linux and has been tested on ipaqs +under the familiar linux distribution (http://www.handhelds.org). +You can find .ipk binary packages on the linphone's download page. +If you want to build your own arm-linux packages, here are some instructions to +cross compile linphone and its dependencies: readline, speex and libosip. +This is my own experience on cross compiling software. As there is no precise +step by step documentation (as far as I know) on how to cross-compile on arm, +there is no guaranty that the following instructions are the best way to do it. +First, be aware that only the console version of linphone can compile on ARM. + + +* You need the lastest arm toolchain from http://www.handhelds.org. Uncompress it in / . + It contains all the cross-compilation tools. Be sure that the arm-linux-gcc binaries + are in your PATH (export PATH=$PATH:/usr/local/arm/3.4.1/bin/ , for example) +* create within your home directory a arm/ directory, copy into it the fresh + tarballs of libosip2>=2.2.x, speex>=1.1.6, linphone>=1.2.1 readline>=5.1 and ncurses>=5.5 (readline needs ncurses) + Uncompress all these + tarballs. + + +Very important things common to all packages being cross compiled: +****************************************************************** +* copy the ipaq-config.site in the ipkg/ directory of linphone into some safe place, +for example: ~/ipaq-config.site . +* You need a directory that we call ARM_INSTALL_TREE that will own files in the same way they will be installed on the target computer. +It is also used to build linphone over the arm binaries of its dependencies (speex,osip,ncurses,readline). + +For example: + +export CONFIG_SITE=~/ipaq-config.site +export ARM_INSTALL_TREE=/armbuild + + +Cross compiling ncurses for ARM: +******************************** +./configure --prefix=/usr --host=arm-linux --with-gnu-ld --with-shared +make +make install DESTDIR=$ARM_INSTALL_TREE +make install DESTDIR=`pwd`/armbuild + + +Cross compiling readline for ARM: +********************************* +./configure --prefix=/usr --host=arm-linux --with-gnu-ld --disable-static +make +make install DESTDIR=$ARM_INSTALL_TREE +make install DESTDIR=`pwd`/armbuild + + + +Cross compiling libosip for ARM: +******************************** +./configure --prefix=/usr --host=arm-linux --with-gnu-ld --disable-static +make +make install DESTDIR=$ARM_INSTALL_TREE +make install DESTDIR=`pwd`/armbuild + +Cross compiling speex for ARM: +******************************** +First you need to remove ogg headers from your build system to avoid a dirty conflict between +your build machine binaries and the arm binaries. They are usually in a libogg-dev package (rpm or deb). +Then: +./configure --prefix=/usr --host=arm-linux --with-gnu-ld --disable-static --enable-fixed-point --enable-arm-asm +make +make install DESTDIR=$ARM_INSTALL_TREE +make install DESTDIR='pwd'/armbuild + + +Cross compiling linphone for ARM +******************************** +First you need to remove all .la files from the ARM_INSTALL_TREE because it confuses libtool and makes +the linker use your build machine binaries instead of the arm-crosscompiled ones. +rm -f $ARM_INSTALL_TREE/usr/lib/*.la +#for some reason pkg-config doesn't like cross-compiling... +export PKG_CONFIG=/usr/bin/pkg-config +./configure --prefix=/usr --host=arm-linux --with-gnu-ld --disable-static \ + --disable-glib --with-osip=$ARM_INSTALL_TREE/usr \ + --with-readline=$ARM_INSTALL_TREE/usr \ + SPEEX_CFLAGS="-I$ARM_INSTALL_TREE/usr/include" \ + SPEEX_LIBS="-L$ARM_INSTALL_TREE/usr/lib -lspeex " +make +make install DESTDIR='pwd'/armbuild + +You can use the install trees libosip2-x.x.x/armbuild speex-x.x.x/armbuild and +linphone-0.x.x/armbuild/ to make binary packages of +each software, as ipkgs for the familiar distribution (http://www.familiar.org). +In the ipkg/ directory of linphone you can find .control files for ipkg-build. +In order to make the osip ipkg, you have to do the following: +- create a directory named CONTROL inside libosip2-2.2.x/armbuild +- copy the libosip.control file into CONTROL/ and rename it into "control". +- edit the "control" file to adjust version number accordingly. +- remove the non essential parts of libosip inside libosip2-2.x.x/armbuild/usr/ : just + leave the lib/ directory. This saves space on the destination computer. +- then inside libosip2-2.x.x, run ipkg-build -o root -g root armbuild +The same procedure applies to make linphone's ipkg. +Binaries can also be stripped with arm-linux-strip to save more space. + +Running linphone under the handheld computer +******************************************** + +You just have to start linphone from a terminal by typing 'linphonec'. + +Simon diff --git a/linphone/TODO b/linphone/TODO new file mode 100644 index 000000000..3a0199c38 --- /dev/null +++ b/linphone/TODO @@ -0,0 +1,22 @@ +hot stuff: +--------- + +* ice support +* run a user given command upon incoming calls +* linphonec on win32 +* RTP inactivity timeout to close lost calls. + + +low priority: +------------- + +* random RTP ports (to enable direct mapping NAT) +* zeroconf support for advertising services (cool stuff!) +* have the possibility to define several profiles (config files) and switch between them +* display call duration +* help tips for the registration box +* The length (or duration) of the call could be displayed (see icons2.png) +* 2. There could be a sound effect for "busy" - a short "beep-beep-beep" would be sufficient (try http://www.google.com/search?q=busy.wav) +* The call history could be a bit more clear (see history.png). And it + should be saved somewhere, so you can track your calls if you need to... +* move resampling stuff to use speex instead of libresample. \ No newline at end of file diff --git a/linphone/autogen.sh b/linphone/autogen.sh new file mode 100755 index 000000000..b8bd738db --- /dev/null +++ b/linphone/autogen.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +AM_VERSION="1.9" +if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then + # automake-1.9 (recommended) is not available on Fedora 8 + AUTOMAKE=automake + ACLOCAL=aclocal +else + ACLOCAL=aclocal-${AM_VERSION} + AUTOMAKE=automake-${AM_VERSION} +fi + +echo "Generating build scripts in linphone..." +set -x +libtoolize --copy --force +autoheader +$ACLOCAL -I m4 +$AUTOMAKE --force-missing --add-missing --copy +autoconf +rm -rf config.cache + +echo "Generating build scripts in oRTP..." +cd oRTP && ./autogen.sh && cd - + +echo "Generating build scripts in mediastreamer2..." +cd mediastreamer2 && ./autogen.sh && cd - diff --git a/linphone/build.mk b/linphone/build.mk new file mode 100755 index 000000000..be5fe460d --- /dev/null +++ b/linphone/build.mk @@ -0,0 +1,140 @@ +#!/usr/bin/make -f +# This script "automatically" builds some binary distribution of linphone : +# debian packages (sid) and familiar (arm-linux/ipaq) packages. +# generation of rpms can be added in the future. +# it can be invoked in the following way: +# ./build.mk debs LINPHONE= +# ./build.mk all LINPHONE= GLIB=2.2's tar.gz> +# LIBOSIP= +# + + +ARMROOT=/armbuild +ARMTOOLCHAIN=/usr/local/arm/3.2.3/bin + +all: check debs ipks + + +clean: + rm -f *.stamp + rm -rf build-debs + rm -rf build-ipks + +check: + @if test -n "${LD_PRELOAD}" ; then echo "ERROR: LD_PRELOAD is set !!"; exit 1;fi + +ipks: ipkg-tools.stamp libosip.ipk linphone.ipk clean + +ipkg-tools.stamp: + if which ipkg-build ; then echo "Found ipkg-build." ;\ + else echo "** ERROR ** Cannot find ipkg-build"; exit 1; fi + if test -e $(ARMTOOLCHAIN)/arm-linux-gcc ; then \ + echo "arm toolchain seems ok.";\ + else echo "** ERROR ** Cannot find arm toolchain."; exit 1; fi + touch ipkg-tools.stamp + +glib.ipk : glib.stamp linphone-sources-ipk.stamp + rm -rf build-ipks/glib* + cp $(GLIB) build-ipks/. + export CONFIG_SITE=`pwd`/build-ipks/ipaq-config.site && \ + cd build-ipks && tar -xvzf glib*.tar.gz && rm -f glib*.tar.gz && cd glib* && \ + ./configure --prefix=$(ARMROOT)/usr --host=arm-linux --with-gnu-ld --disable-static \ + && make AM_CFLAGS=-DSSIZE_MAX=0xffffffff && make install && \ + make install prefix=`pwd`$(ARMROOT)/usr + echo "Building .ipk file..." + cd build-ipks/glib*$(ARMROOT) && mkdir CONTROL && cd CONTROL && \ + cp ../../../linphone*/ipkg/glib.control control && \ + cd ../.. && rm -rf armbuild/usr/include + cd build-ipks/glib* && ipkg-build -o root -g root armbuild/ + cp build-ipks/glib*/*.ipk . + +libosip.ipk : libosip.stamp linphone-sources-ipk.stamp + rm -rf build-ipks/libosip* + cp $(LIBOSIP) build-ipks/ + export CONFIG_SITE=`pwd`/build-ipks/ipaq-config.site && \ + cd build-ipks && tar -xvzf libosip*.tar.gz && rm -f libosip*.tar.gz && cd libosip* && \ + ./configure --prefix=$(ARMROOT)/usr --host=arm-linux --with-gnu-ld --disable-static \ + && make && make install && make install prefix=`pwd`$(ARMROOT)/usr + echo "Building .ipk file..." + cd build-ipks/libosip*$(ARMROOT) && mkdir CONTROL && cd CONTROL && \ + cp ../../../linphone*/ipkg/libosip.control control &&\ + cd ../.. && rm -rf armbuild/usr/include + cd build-ipks/libosip* && ipkg-build -o root -g root armbuild/ + cp build-ipks/libosip*/*.ipk . + + +linphone.ipk : linphone.stamp linphone-sources-ipk.stamp + export CONFIG_SITE=`pwd`/build-ipks/ipaq-config.site && \ + cd build-ipks/linphone* && export PKG_CONFIG_PATH=$(ARMROOT)/usr/lib/pkgconfig &&\ + ./configure --prefix=$(ARMROOT)/usr --with-realprefix=/usr --host=arm-linux \ + --with-gnu-ld --disable-static --disable-gnome_ui --disable-glib --with-osip=$(ARMROOT)/usr \ + --disable-ogg --disable-rtcp && make && make install prefix=`pwd`$(ARMROOT)/usr + echo "Building .ipk file..." + cd build-ipks/linphone*$(ARMROOT) && mkdir -p CONTROL && cd CONTROL && \ + cp -f ../../ipkg/linphone.control control &&\ + cd ../.. && rm -rf armbuild/usr/include armbuild/usr/share/gtk-doc \ + && cd armbuild/usr/share/sounds/linphone/rings && \ + rm -f rock.wav sweet.wav bigben.wav toy.wav tapping.wav synth.wav && cd - \ + cd build-ipks/linphone* && ipkg-build -o root -g root armbuild/ + cp -f build-ipks/linphone*/*.ipk . + +build-ipks.stamp: + -@touch $(ARMROOT)/dummy + @if test -e $(ARMROOT)/dummy ; \ + then echo "armroot is fine: $(ARMROOT)"; \ + else \ + echo "** ERROR: you need to create a $(ARMROOT) directory readable and writeable by the user running this build script.";\ + exit 1;\ + fi + rm -f $(ARMROOT)/dummy + touch build-ipks.stamp + mkdir build-ipks + + +linphone-sources-ipk.stamp: linphone.stamp build-ipks.stamp + cp $(LINPHONE) build-ipks/. + cd build-ipks && tar -xvzf linphone*.tar.gz && cp linphone*/ipkg/ipaq-config.site . \ + && rm -f linphone*.tar.gz + touch linphone-sources-ipk.stamp + +debs: linphone.stamp clean + rm -f linphone.stamp + rm -rf build-debs + mkdir build-debs + cp $(LINPHONE) build-debs/. + cd build-debs && tar -xvzf *.tar.gz && cd linphone* && dpkg-buildpackage -rfakeroot + cp build-debs/*.deb . + +linphone.stamp: + @if test -n "$(LINPHONE)" ; \ + then echo "linphone source is $(LINPHONE)" ; \ + touch linphone.stamp; \ + else \ + echo "No linphone source found." ; \ + exit 1; \ + fi + +libosip.stamp: + @if test -n "$(LIBOSIP)" ; \ + then echo "libosip source is $(LIBOSIP)" ; \ + touch libosip.stamp; \ + else \ + echo "No libosip source found." ; \ + exit 1; \ + fi + +glib.stamp: + @if test -n "$(GLIB)" ; \ + then echo "glib source is $(GLIB)" ; \ + else \ + echo "No glib source found." ; \ + exit -1; \ + fi + @if which glib-genmarshal ; \ + then \ + echo "native glib-2.2 found on build host." ; \ + touch glib.stamp ;\ + else \ + echo "** ERROR ** You need a working glib>2.2 on the build machine to be able to crosscompile it for arm." ;\ + echo "** ERROR ** Please install a glib on this machine."; exit 1; \ + fi diff --git a/linphone/config.rpath b/linphone/config.rpath new file mode 100755 index 000000000..c492a93b6 --- /dev/null +++ b/linphone/config.rpath @@ -0,0 +1,614 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2006 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | pw32* | os2*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux*) + case $cc_basename in + icc* | ecc*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + sco3.2v5*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix3*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. +libname_spec='lib$name' +case "$host_os" in + aix3*) + ;; + aix4* | aix5*) + ;; + amigaos*) + ;; + beos*) + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + shrext=.dll + ;; + darwin* | rhapsody*) + shrext=.dylib + ;; + dgux*) + ;; + freebsd1*) + ;; + kfreebsd*-gnu) + ;; + freebsd* | dragonfly*) + ;; + gnu*) + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + ;; + interix3*) + ;; + irix5* | irix6* | nonstopux*) + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux*) + ;; + knetbsd*-gnu) + ;; + netbsd*) + ;; + newsos6) + ;; + nto-qnx*) + ;; + openbsd*) + ;; + os2*) + libname_spec='$name' + shrext=.dll + ;; + osf3* | osf4* | osf5*) + ;; + solaris*) + ;; + sunos4*) + ;; + sysv4 | sysv4.3*) + ;; + sysv4*MP*) + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + ;; + uts4*) + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <= 2.4.0 gthread-2.0, ,gtk_ui=false) + AC_SUBST(LIBGTK_CFLAGS) + AC_SUBST(LIBGTK_LIBS) + + if test "$gtk_ui" = "true" ; then + AC_DEFINE(HAVE_GTK,1,[Defined if we can use the gtk api]) + else + missing_gtk_libs=true + fi +else + echo "GTK interface compilation is disabled." +fi + + +if test "$gtk_ui" = "true" ; then + PKG_CHECK_MODULES(GNOME_APPLETS, libpanelapplet-2.0 >= 2.0.0 , + build_gnome_applet=true,build_gnome_applet=false) + AC_SUBST(GNOME_APPLETS_CFLAGS) + AC_SUBST(GNOME_APPLETS_LIBS) + PKG_CHECK_MODULES(LIBGLADE, libglade-2.0 >= 2.4.0 , glade_ui=true, glade_ui=false) + AC_SUBST(LIBGLADE_CFLAGS) + AC_SUBST(LIBGLADE_LIBS) +else + build_gnome_applet=false +fi + + +dnl os-specific problems not handled by existing macros. +case "$host_os" in + *freebsd*) + LDFLAGS="$LDFLAGS -pthread" + ;; +esac + +case "$host_cpu" in + *arm*) + AC_DEFINE(__ARM__,1,[Defined if we are compiling for arm processor]) + use_arm_toolchain=yes + ;; +esac + +AC_ARG_WITH( realprefix, + [ --with-realprefix Set the real installation prefix. This option has to be used for cross-compilation only. (ex:/usr or /usr/local)[default=none] ], + [ realprefix=${withval}],[ realprefix="none" ]) + + + +AC_ARG_ENABLE(manual, + [ --disable-manual Do not attempt to build html linphone's user documentation], + [case "${enableval}" in + yes) build_manual=yes ;; + no) build_manual=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-manual) ;; + esac],[build_manual=yes]) + + +dnl enable ipv6 support +AC_ARG_ENABLE(ipv6, + [ --enable-ipv6 Turn on ipv6 support], + [case "${enableval}" in + yes) ipv6=true;; + no) ipv6=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ipv6) ;; + esac],[ipv6=true]) +IPV6_CFLAGS= +if test x$ipv6 = xtrue ; then + IPV6_CFLAGS=-DINET6 +fi +AC_SUBST(IPV6_CFLAGS) + +dnl enable truespeech codec support +AC_ARG_ENABLE(truespeech, + [ --enable-truespeech Turn on TrueSpeech support (x86 only)], + [case "${enableval}" in + yes) truespeech=true;; + no) truespeech=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-truespeech) ;; + esac],[truespeech=false]) +TRUESPEECH_CFLAGS= +if test x$truespeech = xtrue ; then + TRUESPEECH_CFLAGS=-DTRUESPEECH +fi +AC_SUBST(TRUESPEECH_CFLAGS) +AM_CONDITIONAL([BUILD_TRUESPEECH], [test x$truespeech = xtrue]) + + + + +dnl support for RSVP (by Vincent Maury) +AC_ARG_ENABLE(rsvp, +[ --enable-rsvp enable support for QoS reservations.], +AC_DEFINE(VINCENT_MAURY_RSVP,1,[Tell whether RSVP support +should be compiled.]) ) + +if test "x${prefix}" = "xNONE"; then + prefix=${ac_default_prefix} +fi + +dnl Set PACKAGE_LOCALE_DIR in config.h. +DATADIRNAME=share +AC_DEFINE_UNQUOTED(PACKAGE_LOCALE_DIR, "${prefix}/${DATADIRNAME}/locale",[Defines the place where locales can be found]) + +AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${prefix}/${DATADIRNAME}",[Defines the place where data are found]) + +dnl Set PACKAGE_SOUND_DIR in config.h. +AC_DEFINE_UNQUOTED(PACKAGE_SOUND_DIR, "${prefix}/${DATADIRNAME}/sounds/linphone",[Defines the place where linphone sounds are found]) + + +dnl check if we have the getifaddrs() sytem call +AC_CHECK_FUNCS(getifaddrs) + +dnl check for osip2 +LP_CHECK_OSIP2 + +dnl setup flags for exosip library +LP_SETUP_EXOSIP + +if test "$console_ui" = "true" ; then +dnl check gnu readline +LP_CHECK_READLINE +else +echo "Console interface compilation is disabled." +fi + +AC_WORDS_BIGENDIAN + +dnl normaly this should only by done by mediastreamer2/configure.ac +dnl but to workaround bugs when cross-compiling for arm-linux, +dnl we need to have SPEEX_LIBS defined +dnl Furthermore it is good to repeat here all mediastreamer2 toggles +dnl since top-level configure --help will not print them. + +PKG_CHECK_MODULES(SPEEX, speex >= 1.1.6, build_speex=yes) +AC_SUBST(SPEEX_LIBS) + +dnl conditionnal build of video support +AC_ARG_ENABLE(video, + [ --enable-video Turn on video support compiling], + [case "${enableval}" in + yes) video=true ;; + no) video=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;; + esac],[video=true]) + +AC_ARG_WITH( ffmpeg, + [ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ], + [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) + +AC_ARG_WITH( sdl, + [ --with-sdl Sets the installation prefix of libSDL, needed for video support. [default=/usr] ], + [ libsdldir=${withval}],[ libsdldir=/usr ]) + +if test "$video" = "true"; then + AC_DEFINE(VIDEO_ENABLED,1,[defined if video support is available]) +fi + +AC_ARG_ENABLE(alsa, + [ --enable-alsa Turn on alsa native support compiling], + [case "${enableval}" in + yes) alsa=true ;; + no) alsa=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsa) ;; + esac],[alsa=true]) + +AC_ARG_ENABLE(artsc, + [ --enable-artsc Turn on artsc (kde) sound input/output (auto) ], + [case "${enableval}" in + yes) artsc=true ;; + no) artsc=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-artsc) ;; + esac],[artsc=false]) + +AC_ARG_ENABLE(portaudio, + [ --enable-portaudio Turn on portaudio native support compiling], + [case "${enableval}" in + yes) portaudio=true ;; + no) portaudio=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;; + esac],[portaudio=false]) + +dnl same thing for media_api +AM_CONDITIONAL(BUILD_MEDIA_API, test x$media_api = xtrue) + + +dnl build console if required +AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue) +dnl build gtk if required +AM_CONDITIONAL(BUILD_GTK, test x$old_gtk_ui = xtrue) +dnl build gnome applet if possible +AM_CONDITIONAL(BUILD_GNOME_APPLET, test x$build_gnome_applet = xtrue) +dnl special things for arm-linux cross compilation toolchain +AM_CONDITIONAL(ARMBUILD, test x$use_arm_toolchain = xyes) +dnl compilation of gtk-glade user interface +AM_CONDITIONAL(BUILD_GLADE_UI, [test x$glade_ui = xtrue ] ) + +################################################## +# Stricter build options (after external packages) +################################################## + + +AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [Build with stricter options (gcc only) @<:@yes@:>@]),[ + strictness="${enableval}"],[strictness=yes] +) + +if test "$GCC$strictness" = "yesyes" ; then + STRICT_OPTIONS="-Wall -Wp,-D_FORTIFY_SOURCE=2" + STRICT_OPTIONS="$STRICT_OPTIONS -Werror" + CFLAGS="$CFLAGS -fno-strict-aliasing" +fi + +AC_SUBST(STRICT_OPTIONS) + +AC_CONFIG_SUBDIRS( mediastreamer2 ) + +dnl check for db2html (docbook) to generate html user manual +AC_CHECK_PROG(have_sgmltools,sgmltools, yes, no) +AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes ) + +dnl for external use of linphone libs +LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone -I${includedir}/ortp " +LINPHONE_LIBS="-L${libdir} -llinphone" +AC_SUBST(LINPHONE_CFLAGS) +AC_SUBST(LINPHONE_LIBS) + + +AC_DEFINE_UNQUOTED(LINPHONE_VERSION,"$PACKAGE_VERSION",[Linphone's version number]) + + +AC_ARG_ENABLE(external-ortp, + [ --enable-external-ortp Use external oRTP library], + [case "${enableval}" in + yes) external_ortp=true ;; + no) external_ortp=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;; + esac],[external_ortp=false]) + +if test "$external_ortp" = 'true'; then + LP_CHECK_ORTP +else + AC_CONFIG_SUBDIRS( oRTP ) + ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include" + ORTP_LIBS="\$(top_builddir)/oRTP/src/libortp.la" + if test x$ac_cv_c_bigendian = xyes ; then + ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN" + fi +fi +AC_SUBST(ORTP_CFLAGS) +AC_SUBST(ORTP_LIBS) + +AM_CONDITIONAL(EXTERNAL_ORTP, [test "$external_ortp" = 'true']) + +dnl Packaging: Pick oRTP version from ${top_srcdir}/oRTP/configure.ac +dnl Feel free to propose an alternative & cleaner version... +top_srcdir=`dirname $0` +changequote(, )dnl +ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` +MS2_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/mediastreamer2/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` +changequote([, ])dnl +AC_SUBST([ORTP_VERSION]) +AC_SUBST([MS2_VERSION]) + +AC_OUTPUT([ +Makefile +m4/Makefile +po/Makefile.in +pixmaps/Makefile +ipkg/Makefile +ipkg/linphone.control +media_api/Makefile +coreapi/Makefile +gtk/Makefile +gtk-glade/Makefile +console/Makefile +share/Makefile +share/C/Makefile +share/fr/Makefile +share/it/Makefile +share/ja/Makefile +share/cs/Makefile +share/linphone.pc +linphone.spec +]) + +echo "Linphone build configuration ended." + +if test x$gtk_ui = xtrue ; then +echo "* GTK interface will be compiled." +fi +if test x$gtk_ui = xtrue ; then +echo "* Console interface will be compiled." +fi +if test x$glade_ui = xtrue ; then + echo "* Gtk-glade still in early development interface will be compiled" +fi +if test "$have_db2html" = "no" ; then + echo "* db2html not found; user documentation will not be generated." +fi + +echo "Now type 'make' to compile, and then 'make install' as root to install it." diff --git a/linphone/console/.cvsignore b/linphone/console/.cvsignore new file mode 100644 index 000000000..bbea6ace1 --- /dev/null +++ b/linphone/console/.cvsignore @@ -0,0 +1,7 @@ +.deps +.libs +Makefile +Makefile.in +linphonec +sipomatic +wav2raw diff --git a/linphone/console/Makefile.am b/linphone/console/Makefile.am new file mode 100644 index 000000000..d4a481f9e --- /dev/null +++ b/linphone/console/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +if BUILD_CONSOLE + +INCLUDES = \ + -I$(top_srcdir)\ + -I$(top_srcdir)/coreapi\ + $(ORTP_CFLAGS) \ + -I$(top_srcdir)/exosip \ + -I$(top_srcdir)/mediastreamer2/include + + + +bin_PROGRAMS = linphonec sipomatic + +linphonec_SOURCES = linphonec.c linphonec.h commands.c + +linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) $(OSIP_LIBS) + +sipomatic_SOURCES=\ + sipomatic.c sipomatic.h + +sipomatic_LDADD= $(INTLLIBS) \ + $(top_builddir)/coreapi/liblinphone.la \ + $(OSIP_LIBS) + +endif + +AM_CFLAGS=$(STRICT_OPTIONS) -DENABLE_TRACE -D_ORTP_SOURCE $(VIDEO_CFLAGS) $(READLINE_CFLAGS) $(OSIP_CFLAGS) + + + +AM_LDFLAGS= $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ + $(ORTP_LIBS) \ + $(SPEEX_LIBS) \ + $(OSIP_LIBS) + diff --git a/linphone/console/TODO b/linphone/console/TODO new file mode 100644 index 000000000..420d55abe --- /dev/null +++ b/linphone/console/TODO @@ -0,0 +1,20 @@ + +In pseudo-order of priority: +--------------------------- + +- Exctract presence info in friends list + +- Allow friend call arg to be a pattern + +- hide input during password insertions + [ could use ncurses noecho() ] + +- Allow for single-shot mode (call somebody and quit after the fact) + maybe "linphonec [OPTS] " would do.. + Unfortunately the -s switch would confuse people, I'd rather + change its semantic to "source file" where file wold contain + a list of commands, so ./linephone -s myfriend.sip would call + yourfriend... + +- implement "smart" command completion + diff --git a/linphone/console/commands.c b/linphone/console/commands.c new file mode 100644 index 000000000..8ae3a56e3 --- /dev/null +++ b/linphone/console/commands.c @@ -0,0 +1,1236 @@ +/**************************************************************************** + * + * $Id: commands.c,v 1.39 2008/07/03 15:08:34 smorlat Exp $ + * + * Copyright (C) 2006 Sandro Santilli + * Copyright (C) 2004 Simon MORLAT + * + **************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "linphonec.h" + +/*************************************************************************** + * + * Forward declarations + * + ***************************************************************************/ + +extern char *lpc_strip_blanks(char *input); + +/* Command handlers */ +static int lpc_cmd_help(LinphoneCore *, char *); +static int lpc_cmd_proxy(LinphoneCore *, char *); +static int lpc_cmd_call(LinphoneCore *, char *); +static int lpc_cmd_answer(LinphoneCore *, char *); +static int lpc_cmd_terminate(LinphoneCore *, char *); +static int lpc_cmd_call_logs(LinphoneCore *, char *); +static int lpc_cmd_ipv6(LinphoneCore *, char *); +static int lpc_cmd_refer(LinphoneCore *, char *); +static int lpc_cmd_quit(LinphoneCore *, char *); +static int lpc_cmd_nat(LinphoneCore *, char *); +static int lpc_cmd_stun(LinphoneCore *, char *); +static int lpc_cmd_firewall(LinphoneCore *, char *); +static int lpc_cmd_friend(LinphoneCore *, char*); +static int lpc_cmd_soundcard(LinphoneCore *, char *); +static int lpc_cmd_play(LinphoneCore *, char *); +static int lpc_cmd_record(LinphoneCore *, char *); +/* Command handler helpers */ +static void linphonec_proxy_add(LinphoneCore *lc); +static void linphonec_proxy_display(LinphoneProxyConfig *lc); +static void linphonec_proxy_list(LinphoneCore *lc); +static void linphonec_proxy_remove(LinphoneCore *lc, int index); +static int linphonec_proxy_use(LinphoneCore *lc, int index); +static void linphonec_friend_display(LinphoneFriend *fr); +static int linphonec_friend_list(LinphoneCore *lc, char *arg); +static void linphonec_display_command_help(LPC_COMMAND *cmd); +static int linphonec_friend_call(LinphoneCore *lc, unsigned int num); +static int linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr); +static int linphonec_friend_delete(LinphoneCore *lc, int num); + +/* Command table management */ +static LPC_COMMAND *lpc_find_command(const char *name); + +/*************************************************************************** + * + * Global variables + * + ***************************************************************************/ + +/* + * Commands table. + */ +LPC_COMMAND commands[] = { + { "help", lpc_cmd_help, "Print commands help", NULL }, + { "call", lpc_cmd_call, "Call a SIP uri", + "'call ' or 'c ' " + ": initiate a call to the specified destination." + }, + { "terminate", lpc_cmd_terminate, "Terminate the current call", + NULL }, + { "answer", lpc_cmd_answer, "Answer a call", + "Accept an incoming call." + }, + { "proxy", lpc_cmd_proxy, "Manage proxies", + "'proxy list' : list all proxy setups.\n" + "'proxy add' : add a new proxy setup.\n" + "'proxy remove ' : remove proxy setup with number index.\n" + "'proxy use ' : use proxy with number index as default proxy.\n" + "'proxy unuse' : don't use a default proxy." + }, + { "soundcard", lpc_cmd_soundcard, "Manage soundcards", + "'soundcard list' : list all sound devices.\n" + "'soundcard use ' : select a sound device.\n" + "'soundcard use files' : use .wav files instead of soundcard\n" + }, + { "ipv6", lpc_cmd_ipv6, "Use IPV6", + "'ipv6 status' : show ipv6 usage status.\n" + "'ipv6 enable' : enable the use of the ipv6 network.\n" + "'ipv6 disable' : do not use ipv6 network." + }, + { "refer", lpc_cmd_refer, + "Refer the current call to the specified destination.", + "'refer ' or 'r ' " + ": refer the current call to the specified destination." + }, + { "nat", lpc_cmd_nat, "Set nat address", + "'nat' : show nat settings.\n" + "'nat ' : set nat address.\n" + }, + { "stun", lpc_cmd_stun, "Set stun server address", + "'stun' : show stun settings.\n" + "'stun ' : set stun address.\n" + }, + { "firewall", lpc_cmd_firewall, "Set ", + "'firewall' : show current firewall policy.\n" + "'firewall none' : use direct connection.\n" + "'firewall nat' : use nat address given with the 'nat' command.\n" + "'firewall stun' : use stun server given with the 'server' command.\n" + }, + { "call-logs", lpc_cmd_call_logs, "Calls history", + NULL }, + { "friend", lpc_cmd_friend, "Manage friends", + "'friend list []' : list friends.\n" + "'friend call ' : call a friend.\n" + "'friend add ' : add friend, must be quoted to include\n" + " spaces, has \"sip:\" added if it isn't\n" + " there. Don't use '<' '>' around .\n" + "'friend delete ' : remove friend, 'all' removes all\n" + }, + { "play", lpc_cmd_play, "play from a wav file", + "This feature is available only in file mode (see 'help soundcard')\n" + "'play ' : play a wav file." + }, + { "record", lpc_cmd_record, "record to a wav file", + "This feature is available only in file mode (see 'help soundcard')\n" + "'record ' : record into wav file." + }, + { "quit", lpc_cmd_quit, "Exit linphonec", NULL }, + { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL } +}; + +/*************************************************************************** + * + * Public interface + * + ***************************************************************************/ + +/* + * Main command dispatcher. + * WARNING: modifies second argument! + * + * Always return 1 currently. + */ +int +linphonec_parse_command_line(LinphoneCore *lc, char *cl) +{ + char *ptr=cl; + char *args=NULL; + LPC_COMMAND *cmd; + + /* Isolate first word and args */ + while(*ptr && !isspace(*ptr)) ++ptr; + if (*ptr) + { + *ptr='\0'; + /* set args to first nonblank */ + args=ptr+1; + while(*args && isspace(*args)) ++args; + } + + /* Handle DTMF */ + if ( isdigit(*cl) || *cl == '#' || *cl == '*' ) + { + while ( isdigit(*cl) || *cl == '#' || *cl == '*' ) + { + linphone_core_send_dtmf(lc, *cl); + sleep(1); // be nice + ++cl; + } + + // discard spurious trailing chars + return 1; + } + + /* Handle other kind of commands */ + cmd=lpc_find_command(cl); + if ( !cmd ) + { + printf("'%s': Cannot understand this.\n", cl); + return 1; + } + + if ( ! cmd->func(lc, args) ) + { + printf("Syntax error.\n"); + linphonec_display_command_help(cmd); + } + + return 1; +} + +/* + * Generator function for command completion. + * STATE let us know whether to start from scratch; + * without any state (STATE==0), then we start at the + * top of the list. + */ +char * +linphonec_command_generator(const char *text, int state) +{ + static int index, len; + char *name; + + if ( ! state ) + { + index=0; + len=strlen(text); + } + + /* + * Return the next name which partially matches + * from the commands list + */ + while ((name=commands[index].name)) + { + ++index; /* so next call get next command */ + + if (strncmp(name, text, len) == 0) + { + return strdup(name); + } + } + + return NULL; +} + + +/*************************************************************************** + * + * Command handlers + * + ***************************************************************************/ + +static int +lpc_cmd_help(LinphoneCore *lc, char *arg) +{ + int i=0; + LPC_COMMAND *cmd; + + if (!arg || !*arg) + { + printf("Commands are:\n"); + printf("---------------------------\n"); + + while (commands[i].help) + { + printf("%10.10s\t%s\n", commands[i].name, + commands[i].help); + i++; + } + + printf("---------------------------\n"); + printf("Type 'help ' for more details.\n"); + + return 1; + } + + cmd=lpc_find_command(arg); + if ( !cmd ) + { + printf("No such command.\n"); + return 1; + } + + linphonec_display_command_help(cmd); + return 1; + +} + +static int +lpc_cmd_call(LinphoneCore *lc, char *args) +{ + if ( ! args || ! *args ) + { + return 0; + } + + if ( lc->call != NULL ) + { + printf("Terminate current call first.\n"); + } + else + { + if ( -1 == linphone_core_invite(lc, args) ) + { + printf("Error from linphone_core_invite.\n"); + } + else + { + /* current_call=args; */ + } + } + return 1; +} + +static int +lpc_cmd_refer(LinphoneCore *lc, char *args) +{ + if (args) + linphone_core_refer(lc, args); + else{ + printf("refer needs an argument\n"); + } + return 1; +} + +static int +lpc_cmd_terminate(LinphoneCore *lc, char *args) +{ + if ( -1 == linphone_core_terminate_call(lc, NULL) ) + { + printf("No active call.\n"); + } + return 1; +} + +static int +lpc_cmd_answer(LinphoneCore *lc, char *args) +{ + if ( -1 == linphone_core_accept_call(lc, NULL) ) + { + printf("No incoming call.\n"); + } + return 1; +} + +static int +lpc_cmd_quit(LinphoneCore *lc, char *args) +{ + linphonec_finish(EXIT_SUCCESS); + return 1; +} + +static int +lpc_cmd_nat(LinphoneCore *lc, char *args) +{ + bool_t use; + const char *nat; + + if ( args ) args=lpc_strip_blanks(args); + + if ( args && *args ) + { + linphone_core_set_nat_address(lc, args); + /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS); */ + } + + nat = linphone_core_get_nat_address(lc); + use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS; + printf("Nat address: %s%s\n", nat ? nat : "unspecified" , use ? "" : " (disabled - use 'firewall nat' to enable)"); + + return 1; +} + +static int +lpc_cmd_stun(LinphoneCore *lc, char *args) +{ + bool_t use; + const char *stun; + + if ( args ) args=lpc_strip_blanks(args); + + if ( args && *args ) + { + linphone_core_set_stun_server(lc, args); + /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN); */ + } + + stun = linphone_core_get_stun_server(lc); + use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN; + printf("Stun server: %s%s\n", stun ? stun : "unspecified" , use? "" : " (disabled - use 'firewall stun' to enable)"); + + return 1; +} + +static int +lpc_cmd_firewall(LinphoneCore *lc, char *args) +{ + const char* setting=NULL; + + if ( args ) args=lpc_strip_blanks(args); + + if ( args && *args ) + { + if (strcmp(args,"none")==0) + { + linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); + } + else if (strcmp(args,"stun")==0) + { + setting = linphone_core_get_stun_server(lc); + if ( ! setting ) + { + printf("No stun server address is defined, use 'stun
' first"); + return 1; + } + linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN); + } + else if (strcmp(args,"nat")==0) + { + setting = linphone_core_get_nat_address(lc); + if ( ! setting ) + { + printf("No nat address is defined, use 'nat
' first"); + return 1; + } + linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS); + } + } + + switch(linphone_core_get_firewall_policy(lc)) + { + case LINPHONE_POLICY_NO_FIREWALL: + printf("No firewall\n"); + break; + case LINPHONE_POLICY_USE_STUN: + printf("Using stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc)); + break; + case LINPHONE_POLICY_USE_NAT_ADDRESS: + printf("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc)); + break; + } + return 1; +} + +/* Helper function for processing freind names */ +static int +lpc_friend_name(char **args, char **name) +{ + /* Use space as a terminator unless quoted */ + if (('"' == **args) || ('\'' == **args)){ + char *end; + char delim = **args; + (*args)++; + end = (*args); + while ((delim != *end) && ('\0' != *end)) end++; + if ('\0' == *end) { + fprintf(stderr, "Mismatched quotes\n"); + return 0; + } + *name = *args; + *end = '\0'; + *args = ++end; + } else { + *name = strsep(args, " "); + + if (NULL == *args) { /* Means there was no separator */ + fprintf(stderr, "Either name or address is missing\n"); + return 0; + } + if (NULL == *name) return 0; + } + return 1; +} + +static int +lpc_cmd_friend(LinphoneCore *lc, char *args) +{ + int friend_num; + + if ( args ) args=lpc_strip_blanks(args); + + if ( ! args || ! *args ) return 0; + + if ( !strncmp(args, "list", 4) ) + { + return linphonec_friend_list(lc, args+4); + return 1; + } + else if ( !strncmp(args, "call", 4) ) + { + args+=4; + if ( ! *args ) return 0; + friend_num = strtol(args, NULL, 10); + if ( errno == ERANGE ) { + printf("Invalid friend number\n"); + return 0; + } + linphonec_friend_call(lc, friend_num); + return 1; + } + else if ( !strncmp(args, "delete", 6) ) + { + args+=6; + if ( ! *args ) return 0; + while (*args == ' ') args++; + if ( ! *args ) return 0; + if (!strncmp(args, "all", 3)) + { + friend_num = -1; + } + else + { + friend_num = strtol(args, NULL, 10); + if ( errno == ERANGE ) { + printf("Invalid friend number\n"); + return 0; + } + } + linphonec_friend_delete(lc, friend_num); + return 1; + } + else if ( !strncmp(args, "add", 3) ) + { + char *name; + char addr[80]; + char *addr_p = addr; + char *addr_orig; + + args+=3; + if ( ! *args ) return 0; + while (*args == ' ') args++; + if ( ! *args ) return 0; + if (!lpc_friend_name(&args, &name)) return 0; + + while (*args == ' ') args++; + if ( ! *args ) return 0; + if (isdigit(*args)) { + strcpy (addr, "sip:"); + addr_p = addr + strlen("sip:"); + } + addr_orig = strsep(&args, " "); + if (1 >= strlen(addr_orig)) { + fprintf(stderr, "A single-digit address is not valid\n"); + return 0; + } + strcpy(addr_p, addr_orig); + linphonec_friend_add(lc, name, addr); + return 1; + } + return 0; +} + +static int lpc_cmd_play(LinphoneCore *lc, char *args){ + if ( args ) args=lpc_strip_blanks(args); + if ( ! args || ! *args ) return 0; + linphone_core_set_play_file(lc,args); + return 1; +} + +static int lpc_cmd_record(LinphoneCore *lc, char *args){ + if ( args ) args=lpc_strip_blanks(args); + if ( ! args || ! *args ) return 0; + linphone_core_set_record_file(lc,args); + return 1; +} + +/* + * Modified input + */ +static int +lpc_cmd_proxy(LinphoneCore *lc, char *args) +{ + char *arg1 = args; + char *arg2 = NULL; + char *ptr = args; + int proxynum; + + if ( ! arg1 ) return 0; + + /* Isolate first and second arg */ + while(*ptr && !isspace(*ptr)) ++ptr; + if ( *ptr ) + { + *ptr='\0'; + arg2=ptr+1; + while(*arg2 && isspace(*arg2)) ++arg2; + } + + if (strcmp(arg1,"add")==0) + { + rl_inhibit_completion=1; + linphonec_proxy_add(lc); + rl_inhibit_completion=0; + } + else if (strcmp(arg1,"list")==0) + { + linphonec_proxy_list(lc); + } + else if (strcmp(arg1,"remove")==0) + { + linphonec_proxy_remove(lc,atoi(arg2)); + } + else if (strcmp(arg1,"use")==0) + { + if ( arg2 && *arg2 ) + { + proxynum=atoi(arg2); + if ( linphonec_proxy_use(lc, proxynum) ) + printf("Default proxy set to %d.\n", proxynum); + } + else + { + proxynum=linphone_core_get_default_proxy(lc, NULL); + if ( proxynum == -1 ) printf("No default proxy.\n"); + else printf("Current default proxy is %d.\n", proxynum); + } + } + else if (strcmp(arg1, "unuse")==0) + { + linphone_core_set_default_proxy(lc, NULL); + printf("Use no proxy.\n"); + } + else + { + printf("Syntax error - see 'help proxy'\n"); + } + + return 1; +} + +static int +lpc_cmd_call_logs(LinphoneCore *lc, char *args) +{ + MSList *elem=linphone_core_get_call_logs(lc); + for (;elem!=NULL;elem=ms_list_next(elem)) + { + LinphoneCallLog *cl=(LinphoneCallLog*)elem->data; + char *str=linphone_call_log_to_str(cl); + printf("%s\n",str); + ms_free(str); + } + return 1; +} + +static int +lpc_cmd_ipv6(LinphoneCore *lc, char *arg1) +{ + if ( ! arg1 ) + { + printf("Syntax error - see 'help ipv6'\n"); + return 1; + } + + if (strcmp(arg1,"status")==0) + { + printf("ipv6 use enabled: %s\n",linphone_core_ipv6_enabled(lc) ? "true":"false"); + } + else if (strcmp(arg1,"enable")==0) + { + linphone_core_enable_ipv6(lc,TRUE); + printf("ipv6 use enabled.\n"); + } + else if (strcmp(arg1,"disable")==0) + { + linphone_core_enable_ipv6(lc,FALSE); + printf("ipv6 use disabled.\n"); + } + else + { + printf("Syntax error - see 'help ipv6'\n"); + } + return 1; +} + +static int lpc_cmd_soundcard(LinphoneCore *lc, char *cmd){ + int i; + if (cmd==NULL){ + printf("Syntax error - see 'help soundcard'\n"); + return 1; + } + if (strcmp(cmd,"list")==0){ + const char **dev=linphone_core_get_sound_devices(lc); + for(i=0;dev[i]!=NULL;i++){ + printf("%i: %s\n",i,dev[i]); + } + return 1; + }else{ + char *tmp=alloca(strlen(cmd)+1); + char *card=alloca(strlen(cmd)+1); + int index; + int n=sscanf(cmd,"%s %s",tmp,card); + if (n==2 && strcmp(tmp,"use")==0){ + if (strcmp(card,"files")==0) { + printf("Using wav files instead of soundcard.\n"); + linphone_core_use_files(lc,TRUE); + return 1; + }else{ + const char **dev=linphone_core_get_sound_devices(lc); + index=atoi(card); + for(i=0;dev[i]!=NULL;i++){ + if (i==index){ + linphone_core_set_ringer_device(lc,dev[i]); + linphone_core_set_playback_device(lc,dev[i]); + linphone_core_set_capture_device(lc,dev[i]); + printf("Using sound device %s\n",dev[i]); + return 1; + } + } + printf("no such sound device\n"); + return 1; + } + } + printf("Syntax error - see 'help soundcard'\n"); + } + return 1; +} + +/*************************************************************************** + * + * Commands helper functions + * + ***************************************************************************/ + + +static void +linphonec_proxy_add(LinphoneCore *lc) +{ + bool_t enable_register=FALSE; + LinphoneProxyConfig *cfg; + + printf("Adding new proxy setup. Hit ^D to abort.\n"); + + /* + * SIP Proxy address + */ + while (1) + { + char *input=readline("Enter proxy sip address: "); + char *clean; + + if ( ! input ) { + printf("Aborted.\n"); + return; + } + + /* Strip blanks */ + clean=lpc_strip_blanks(input); + if ( ! *clean ) { + free(input); + continue; + } + + cfg=linphone_proxy_config_new(); + if (linphone_proxy_config_set_server_addr(cfg,clean)<0) + { + printf("Invalid sip address (sip:sip.domain.tld).\n"); + free(input); + linphone_proxy_config_destroy(cfg); + continue; + } + free(input); + break; + } + + /* + * SIP Proxy identity + */ + while (1) + { + char *input=readline("Your identity for this proxy: "); + char *clean; + + if ( ! input ) { + printf("Aborted.\n"); + linphone_proxy_config_destroy(cfg); + return; + } + + /* Strip blanks */ + clean=lpc_strip_blanks(input); + if ( ! *clean ) { + free(input); + continue; + } + + linphone_proxy_config_set_identity(cfg, clean); + if ( ! cfg->reg_identity ) + { + printf("Invalid identity (sip:name@sip.domain.tld).\n"); + free(input); + continue; + } + free(input); + break; + } + + /* + * SIP Proxy enable register + */ + while (1) + { + char *input=readline("Do you want to register on this proxy (yes/no): "); + char *clean; + + if ( ! input ) { + printf("Aborted.\n"); + linphone_proxy_config_destroy(cfg); + return; + } + + /* Strip blanks */ + clean=lpc_strip_blanks(input); + if ( ! *clean ) { + free(input); + continue; + } + + if ( ! strcmp(clean, "yes") ) enable_register=TRUE; + else if ( ! strcmp(clean, "no") ) enable_register=FALSE; + else { + printf("Please answer with 'yes' or 'no'\n"); + free(input); + continue; + } + linphone_proxy_config_enableregister(cfg, enable_register); + free(input); + break; + } + + /* + * SIP Proxy registration expiration + */ + if ( enable_register==TRUE ) + { + long int expires=0; + while (1) + { + char *input=readline("Specify register expiration time" + " in seconds (default is 600): "); + + if ( ! input ) { + printf("Aborted.\n"); + linphone_proxy_config_destroy(cfg); + return; + } + + expires=strtol(input, (char **)NULL, 10); + if ( expires == LONG_MIN || expires == LONG_MAX ) + { + printf("Invalid value: %s\n", strerror(errno)); + free(input); + continue; + } + + linphone_proxy_config_expires(cfg, expires); + printf("Expiration: %d seconds\n", cfg->expires); + + free(input); + break; + } + } + + /* + * SIP proxy route + */ + while (1) + { + char *input=readline("Specify route if needed: "); + char *clean; + + if ( ! input ) { + printf("Aborted.\n"); + linphone_proxy_config_destroy(cfg); + return; + } + + /* Strip blanks */ + clean=lpc_strip_blanks(input); + if ( ! *clean ) { + free(input); + printf("No route specified.\n"); + break; + } + + linphone_proxy_config_set_route(cfg, clean); + if ( ! cfg->reg_route ) + { + printf("Invalid route.\n"); + free(input); + continue; + } + + free(input); + break; + } + + /* + * Final confirmation + */ + while (1) + { + char *input; + char *clean; + + printf("--------------------------------------------\n"); + linphonec_proxy_display(cfg); + printf("--------------------------------------------\n"); + input=readline("Accept the above proxy configuration (yes/no) ?: "); + + + if ( ! input ) { + printf("Aborted.\n"); + linphone_proxy_config_destroy(cfg); + return; + } + + /* Strip blanks */ + clean=lpc_strip_blanks(input); + if ( ! *clean ) { + free(input); + continue; + } + + if ( ! strcmp(clean, "yes") ) break; + else if ( ! strcmp(clean, "no") ) + { + printf("Declined.\n"); + linphone_proxy_config_destroy(cfg); + free(input); + return; + } + + printf("Please answer with 'yes' or 'no'\n"); + free(input); + continue; + } + + + linphone_core_add_proxy_config(lc,cfg); + + /* automatically set the last entered proxy as the default one */ + linphone_core_set_default_proxy(lc,cfg); + + printf("Proxy added.\n"); +} + +static void +linphonec_proxy_display(LinphoneProxyConfig *cfg) +{ + printf("sip address: %s\nroute: %s\nidentity: %s\nregister: %s\nexpires: %i\n", + cfg->reg_proxy, + (cfg->reg_route!=NULL)?cfg->reg_route:"", + (cfg->reg_identity!=NULL)?cfg->reg_identity:"", + (cfg->reg_sendregister)?"yes":"no", + cfg->expires); +} + +static void +linphonec_proxy_list(LinphoneCore *lc) +{ + const MSList *proxies; + int n; + int def=linphone_core_get_default_proxy(lc,NULL); + + proxies=linphone_core_get_proxy_config_list(lc); + for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){ + if (n==def) + printf("****** Proxy %i - this is the default one - *******\n",n); + else + printf("****** Proxy %i *******\n",n); + linphonec_proxy_display((LinphoneProxyConfig*)proxies->data); + } +} + +static void +linphonec_proxy_remove(LinphoneCore *lc, int index) +{ + const MSList *proxies; + LinphoneProxyConfig *cfg; + proxies=linphone_core_get_proxy_config_list(lc); + cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index); + if (cfg==NULL){ + printf("No such proxy.\n"); + return; + } + linphone_core_remove_proxy_config(lc,cfg); + printf("Proxy %s removed.\n", cfg->reg_proxy); + linphone_proxy_config_destroy(cfg); +} + +static int +linphonec_proxy_use(LinphoneCore *lc, int index) +{ + const MSList *proxies; + LinphoneProxyConfig *cfg; + proxies=linphone_core_get_proxy_config_list(lc); + cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index); + if (cfg==NULL){ + printf("No such proxy (try 'proxy list')."); + return 0; + } + linphone_core_set_default_proxy(lc,cfg); + return 1; +} + +static void +linphonec_friend_display(LinphoneFriend *fr) +{ + char *name = linphone_friend_get_name(fr); + char *addr = linphone_friend_get_addr(fr); + //char *url = linphone_friend_get_url(fr); + + printf("name: %s\n", name); + printf("address: %s\n", addr); +} + +static int +linphonec_friend_list(LinphoneCore *lc, char *pat) +{ + const MSList *friend; + int n; + + if (pat) { + pat=lpc_strip_blanks(pat); + if (!*pat) pat = NULL; + } + + friend = linphone_core_get_friend_list(lc); + for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n ) + { + if ( pat ) { + char *name = linphone_friend_get_name(friend->data); + if ( ! strstr(name, pat) ) continue; + } + printf("****** Friend %i *******\n",n); + linphonec_friend_display((LinphoneFriend*)friend->data); + } + + return 1; +} + +static int +linphonec_friend_call(LinphoneCore *lc, unsigned int num) +{ + const MSList *friend = linphone_core_get_friend_list(lc); + unsigned int n; + char *addr; + + for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n ) + { + if ( n == num ) + { + addr = linphone_friend_get_addr(friend->data); + return lpc_cmd_call(lc, addr); + } + } + printf("No such friend %u\n", num); + return 1; +} + +static int +linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr) +{ + LinphoneFriend *newFriend; + + char url[PATH_MAX]; + + snprintf(url, PATH_MAX, "%s <%s>", name, addr); + newFriend = linphone_friend_new_with_addr(url); + linphone_core_add_friend(lc, newFriend); + return 0; +} + +static int +linphonec_friend_delete(LinphoneCore *lc, int num) +{ + const MSList *friend = linphone_core_get_friend_list(lc); + unsigned int n; + + for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n ) + { + if ( n == num ) + { + linphone_core_remove_friend(lc, friend->data); + return 0; + } + } + + if (-1 == num) + { + unsigned int i; + for (i = 0 ; i < n ; i++) + linphonec_friend_delete(lc, 0); + return 0; + } + + printf("No such friend %u\n", num); + return 1; +} + +static void +linphonec_display_command_help(LPC_COMMAND *cmd) +{ + if ( cmd->doc ) printf ("%s\n", cmd->doc); + else printf("%s\n", cmd->help); +} + +/*************************************************************************** + * + * Command table management funx + * + ***************************************************************************/ + +/* + * Find a command given its name + */ +static LPC_COMMAND * +lpc_find_command(const char *name) +{ + int i; + + for (i=0; commands[i].name; ++i) + { + if (strcmp(name, commands[i].name) == 0) + return &commands[i]; + } + + return (LPC_COMMAND *)NULL; +} + + +/**************************************************************************** + * + * $Log: commands.c,v $ + * Revision 1.39 2008/07/03 15:08:34 smorlat + * api cleanups, interface in progress. + * + * Revision 1.38 2008/06/17 20:38:59 smorlat + * added missing file. + * + * Revision 1.37 2008/04/09 09:26:00 smorlat + * merge various patches + * H264 support. + * + * Revision 1.36 2007/08/01 14:47:53 strk + * * console/commands.c: Clean up commands 'nat', 'stun' + * and 'firewall' to be more intuitive. + * + * Revision 1.35 2007/06/27 09:01:25 smorlat + * logging improvements. + * + * Revision 1.34 2007/02/20 10:17:13 smorlat + * linphonec friends patch2 + * + * Revision 1.31 2006/09/22 07:22:47 smorlat + * linphonecore api changes. + * + * Revision 1.30 2006/09/08 15:32:57 smorlat + * support for using files instead of soundcard (used by linphonec only) + * + * Revision 1.29 2006/08/28 14:29:07 smorlat + * fix bug. + * + * Revision 1.28 2006/08/21 12:49:59 smorlat + * merged several little patches. + * + * Revision 1.27 2006/07/17 18:45:00 smorlat + * support for several event queues in ortp. + * glib dependency removed from coreapi/ and console/ + * + * Revision 1.26 2006/04/14 15:16:36 smorlat + * soundcard use did nothing ! + * + * Revision 1.25 2006/04/06 20:09:33 smorlat + * add linphonec command to see and select sound devices. + * + * Revision 1.24 2006/03/04 11:17:10 smorlat + * mediastreamer2 in progress. + * + * Revision 1.23 2006/02/20 21:14:01 strk + * Handled syntax errors with 'friend' command + * + * Revision 1.22 2006/02/20 10:20:29 strk + * Added substring-based filter support for command 'friend list' + * + * Revision 1.21 2006/02/02 15:39:18 strk + * - Added 'friend list' and 'friend call' commands + * - Allowed for multiple DTFM send in a single line + * - Added status-specific callback (bare version) + * + * Revision 1.20 2006/01/26 11:54:34 strk + * More robust 'nat' command handler (strip blanks in args) + * + * Revision 1.19 2006/01/26 09:48:05 strk + * Added limits.h include + * + * Revision 1.18 2006/01/26 02:18:05 strk + * Added new commands 'nat use' and 'nat unuse'. + * These will required a pending patch to linphonecore.c + * in order to work. + * + * Revision 1.17 2006/01/20 14:12:33 strk + * Added linphonec_init() and linphonec_finish() functions. + * Handled SIGINT and SIGTERM to invoke linphonec_finish(). + * Handling of auto-termination (-t) moved to linphonec_finish(). + * Reworked main (input read) loop to not rely on 'terminate' + * and 'run' variable (dropped). configfile_name allocated on stack + * using PATH_MAX limit. Changed print_usage signature to allow + * for an exit_status specification. + * + * Revision 1.16 2006/01/18 09:25:32 strk + * Command completion inhibited in proxy addition and auth request prompts. + * Avoided use of readline's internal filename completion. + * + * Revision 1.15 2006/01/14 13:29:32 strk + * Reworked commands interface to use a table structure, + * used by command line parser and help function. + * Implemented first level of completion (commands). + * Added notification of invalid "answer" and "terminate" + * commands (no incoming call, no active call). + * Forbidden "call" intialization when a call is already active. + * Cleaned up all commands, adding more feedback and error checks. + * + * Revision 1.14 2006/01/13 13:00:29 strk + * Added linphonec.h. Code layout change (added comments, forward decl, + * globals on top, copyright notices and Logs). Handled out-of-memory + * condition on history management. Removed assumption on sizeof(char). + * Fixed bug in authentication prompt (introduced by readline). + * Added support for multiple authentication requests (up to MAX_PENDING_AUTH). + * + * + ****************************************************************************/ diff --git a/linphone/console/example/linphonec b/linphone/console/example/linphonec new file mode 100644 index 000000000..a832f8546 --- /dev/null +++ b/linphone/console/example/linphonec @@ -0,0 +1,51 @@ +# this file is used to store user config values for linphonec +# please modify and copy it to ~/.linphonec +# +# + +logfile=~/linphonec.log +debuglevel=0 + +local_addr=192.168.1.10 +if_name=eth0 +# type of network connection 4 = ethernet +con_type=4 + + +# rtp +audio_rtp_port=7078 +jitt_comp=150 + + +# audio +driver_mode=0 +rec_lev=100 +play_lev=100 +source=109 +autokill=0 + + +# sip +sip_port=5060 +use_registrar=0 +username=1006 +hostname=192.168.1.1 +registrar=sip:192.168.1.1:5060 +reg_passwd= +addr_of_rec=sip:1006@192.168.1.1 +reg_expires=900 +as_proxy=1 +as_redirect=0 +as_outbound=1 + + +# codecs +audio_codecs=259 371 264 256 + + +# short dial +s0=sip:1002@130.83.176.121 +s1=sip:1001@192.168.1.1 +s2=sip:1002@192.168.1.1 +s3=sip:1003@192.168.1.1 +s4=sip:1004@192.168.1.1 diff --git a/linphone/console/linphonec.c b/linphone/console/linphonec.c new file mode 100644 index 000000000..bfe770437 --- /dev/null +++ b/linphone/console/linphonec.c @@ -0,0 +1,1114 @@ +/**************************************************************************** + * + * $Id: linphonec.c,v 1.57 2007/11/14 13:40:27 smorlat Exp $ + * + * Copyright (C) 2006 Sandro Santilli + * Copyright (C) 2002 Florian Winterstein + * Copyright (C) 2000 Simon MORLAT + * + **************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "linphonec.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_GETTEXT +#include +#ifndef _ +#define _(String) gettext(String) +#endif +#else +#define _(something) (something) +#endif + +/*************************************************************************** + * + * Types + * + ***************************************************************************/ + +typedef struct { + LinphoneAuthInfo *elem[MAX_PENDING_AUTH]; + int nitems; +} LPC_AUTH_STACK; + +/*************************************************************************** + * + * Forward declarations + * + ***************************************************************************/ + +char *lpc_strip_blanks(char *input); + +static int handle_configfile_migration(void); +static int copy_file(const char *from, const char *to); +static int linphonec_parse_cmdline(int argc, char **argv); +static int linphonec_initialize_readline(void); +static int linphonec_finish_readline(); +static int linphonec_init(int argc, char **argv); +static int linphonec_main_loop (LinphoneCore * opm, char * sipAddr); +static int linphonec_idle_call (void); +static char **linephonec_readline_completion(const char *text, + int start, int end); + +/* These are callback for linphone core */ +static void linphonec_call_received(LinphoneCore *lc, const char *from); +static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, + const char *username); +static void linphonec_display_something (LinphoneCore * lc, const char *something); +static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); +static void linphonec_display_warning (LinphoneCore * lc, const char *something); +static void stub () {} +static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid, + const char *from, const char *status, const char *img); +static void linphonec_new_unknown_subscriber(LinphoneCore *lc, + LinphoneFriend *lf, const char *url); +static void linphonec_bye_received(LinphoneCore *lc, const char *from); +static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, + const char *from, const char *msg); +static void linphonec_display_status (LinphoneCore * lc, const char *something); +static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate); +static void print_prompt(LinphoneCore *opm); + +/*************************************************************************** + * + * Global variables + * + ***************************************************************************/ + +LinphoneCore linphonec; +FILE *mylogfile; +static char *histfile_name=NULL; +static char last_in_history[256]; +//auto answer (-a) option +static bool_t auto_answer=FALSE; +static bool_t answer_call=FALSE; +static bool_t vcap_enabled=FALSE; +static bool_t display_enabled=FALSE; +static bool_t show_general_state=FALSE; +LPC_AUTH_STACK auth_stack; +static int trace_level = 0; +static char *logfile_name = NULL; +static char configfile_name[PATH_MAX]; +static char *sipAddr = NULL; /* for autocall */ +char prompt[PROMPT_MAX_LEN]; + +LinphoneCoreVTable linphonec_vtable = { + show:(ShowInterfaceCb) stub, + inv_recv: linphonec_call_received, + bye_recv: linphonec_bye_received, + notify_recv: linphonec_notify_received, + new_unknown_subscriber: linphonec_new_unknown_subscriber, + auth_info_requested: linphonec_prompt_for_auth, + display_status:linphonec_display_status, + display_message:linphonec_display_something, +#ifdef VINCENT_MAURY_RSVP + /* the yes/no dialog box */ + display_yes_no: (DisplayMessageCb) stub, +#endif + display_warning:linphonec_display_warning, + display_url:linphonec_display_url, + display_question:(DisplayQuestionCb)stub, + text_received:linphonec_text_received, + general_state:linphonec_general_state +}; + +/*************************************************************************** + * + * Linphone core callbacks + * + ***************************************************************************/ + +/* + * Linphone core callback + */ +static void +linphonec_display_something (LinphoneCore * lc, const char *something) +{ + fprintf (stdout, "%s\n%s", something,prompt); + fflush(stdout); +} + +/* + * Linphone core callback + */ +static void +linphonec_display_status (LinphoneCore * lc, const char *something) +{ + fprintf (stdout, "%s\n%s", something,prompt); + fflush(stdout); +} + +/* + * Linphone core callback + */ +static void +linphonec_display_warning (LinphoneCore * lc, const char *something) +{ + fprintf (stdout, "Warning: %s\n%s", something,prompt); + fflush(stdout); +} + +/* + * Linphone core callback + */ +static void +linphonec_display_url (LinphoneCore * lc, const char *something, const char *url) +{ + fprintf (stdout, "%s : %s\n", something, url); +} + + +/* + * Linphone core callback + */ +static void +linphonec_call_received(LinphoneCore *lc, const char *from) +{ + if ( auto_answer) { + answer_call=TRUE; + } +} + +/* + * Linphone core callback + */ +static void +linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username) +{ + LinphoneAuthInfo *pending_auth; + + if ( auth_stack.nitems+1 > MAX_PENDING_AUTH ) + { + fprintf(stderr, + "Can't accept another authentication request.\n" + "Consider incrementing MAX_PENDING_AUTH macro.\n"); + return; + } + + pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm); + auth_stack.elem[auth_stack.nitems++]=pending_auth; + +} + +/* + * Linphone core callback + */ +static void +linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid, + const char *from, const char *status, const char *img) +{ + printf("Friend %s is %s\n", from, status); + // todo: update Friend list state (unimplemented) +} + +/* + * Linphone core callback + */ +static void +linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, + const char *url) +{ + printf("Friend %s requested subscription " + "(accept/deny is not implemented yet)\n", url); + // This means that this person wishes to be notified + // of your presence information (online, busy, away...). + +} + +/* + * Linphone core callback + */ +static void +linphonec_bye_received(LinphoneCore *lc, const char *from) +{ + // Should change prompt back to original maybe + + // printing this is unneeded as we'd get a "Communication ended" + // message trough display_status callback anyway + //printf("Bye received from %s\n", from); +} + +/* + * Linphone core callback + */ +static void +linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, + const char *from, const char *msg) +{ + printf("%s: %s\n", from, msg); + // TODO: provide mechanism for answering.. ('say' command?) +} + + +static void +linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate) +{ + if (show_general_state) { + switch(gstate->new_state) { + case GSTATE_POWER_OFF: + printf("GSTATE_POWER_OFF"); + break; + case GSTATE_POWER_STARTUP: + printf("GSTATE_POWER_STARTUP"); + break; + case GSTATE_POWER_ON: + printf("GSTATE_POWER_ON"); + break; + case GSTATE_POWER_SHUTDOWN: + printf("GSTATE_POWER_SHUTDOWN"); + break; + case GSTATE_REG_NONE: + printf("GSTATE_REG_NONE"); + break; + case GSTATE_REG_OK: + printf("GSTATE_REG_OK"); + break; + case GSTATE_REG_FAILED: + printf("GSTATE_REG_FAILED"); + break; + case GSTATE_CALL_IDLE: + printf("GSTATE_CALL_IDLE"); + break; + case GSTATE_CALL_OUT_INVITE: + printf("GSTATE_CALL_OUT_INVITE"); + break; + case GSTATE_CALL_OUT_CONNECTED: + printf("GSTATE_CALL_OUT_CONNECTED"); + break; + case GSTATE_CALL_IN_INVITE: + printf("GSTATE_CALL_IN_INVITE"); + break; + case GSTATE_CALL_IN_CONNECTED: + printf("GSTATE_CALL_IN_CONNECTED"); + break; + case GSTATE_CALL_END: + printf("GSTATE_CALL_END"); + break; + case GSTATE_CALL_ERROR: + printf("GSTATE_CALL_ERROR"); + break; + default: + printf("GSTATE_UNKNOWN_%d",gstate->new_state); + } + if (gstate->message) printf(" %s", gstate->message); + printf("\n"); + } +} + + +/***************************************************************************/ +/* + * Main + * + * Use globals: + * + * - char *histfile_name + * - FILE *mylogfile + */ +int +main (int argc, char *argv[]) +{ + + if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE); + + linphonec_main_loop (&linphonec, sipAddr); + + linphonec_finish(EXIT_SUCCESS); + + exit(EXIT_SUCCESS); /* should never reach here */ +} + +/* + * Initialize linphonec + */ +static int +linphonec_init(int argc, char **argv) +{ + + //g_mem_set_vtable(&dbgtable); + + /* + * Set initial values for global variables + */ + mylogfile = NULL; + snprintf(configfile_name, PATH_MAX, "%s/.linphonerc", + getenv("HOME")); + + + /* Handle configuration filename changes */ + switch (handle_configfile_migration()) + { + case -1: /* error during file copies */ + fprintf(stderr, + "Error in configuration file migration\n"); + break; + + case 0: /* nothing done */ + case 1: /* migrated */ + default: + break; + } + +#ifdef ENABLE_NLS + if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR)) + perror ("bindtextdomain failed"); +#ifndef __ARM__ + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +#endif + textdomain (GETTEXT_PACKAGE); +#else + printf ("NLS disabled.\n"); +#endif + + linphonec_parse_cmdline(argc, argv); + + if (trace_level > 0) + { + if (logfile_name != NULL) + mylogfile = fopen (logfile_name, "w+"); + + if (mylogfile == NULL) + { + mylogfile = stdout; + fprintf (stderr, + "INFO: no logfile, logging to stdout\n"); + } + linphone_core_enable_logs(mylogfile); + } + else + { + linphone_core_disable_logs(); + } + /* + * Initialize auth stack + */ + auth_stack.nitems=0; + + /* + * Initialize linphone core + */ + linphone_core_init (&linphonec, &linphonec_vtable, configfile_name, + NULL); + linphone_core_enable_video(&linphonec,vcap_enabled,display_enabled); + if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec.\n"); + /* + * Initialize readline + */ + linphonec_initialize_readline(); + + /* + * Initialize signal handlers + */ + signal(SIGTERM, linphonec_finish); + signal(SIGINT, linphonec_finish); + + return 1; +} + + +/* + * Close linphonec, cleanly terminating + * any pending call + */ +void +linphonec_finish(int exit_status) +{ + printf("Terminating...\n"); + + /* Terminate any pending call */ + linphonec_parse_command_line(&linphonec, "terminate"); + + linphonec_finish_readline(); + + linphone_core_uninit (&linphonec); + + if (mylogfile != NULL && mylogfile != stdout) + { + fclose (mylogfile); + } + + exit(exit_status); + +} + +/* + * This is called from idle_call() whenever + * pending_auth != NULL. + * + * It prompts user for a password. + * Hitting ^D (EOF) would make this function + * return 0 (Cancel). + * Any other input would try to set linphone core + * auth_password for the pending_auth, add the auth_info + * and return 1. + */ +int +linphonec_prompt_for_auth_final(LinphoneCore *lc) +{ + char *input, *iptr; + char auth_prompt[256]; + rl_hook_func_t *old_event_hook; + + LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1]; + + snprintf(auth_prompt, 256, "Password for %s on %s: ", + pending_auth->username, pending_auth->realm); + + printf("\n"); + + /* + * Disable event hook to avoid entering an + * infinite loop. This would prevent idle_call + * from being called during authentication reads. + * Note that it might be undesiderable... + */ + old_event_hook=rl_event_hook; + rl_event_hook=NULL; + + while (1) + { + input=readline(auth_prompt); + + /* + * If EOF (^D) is sent you probably don't want + * to provide an auth password... should give up + * the operation, but there's no mechanism to + * send this info back to caller currently... + */ + if ( ! input ) + { + printf("Cancel requested, but not implemented.\n"); + continue; + } + + /* Strip blanks */ + iptr=lpc_strip_blanks(input); + + /* + * Only blanks, continue asking + */ + if ( ! *iptr ) + { + free(input); + continue; + } + + /* Something typed, let's try */ + break; + } + + /* + * No check is done here to ensure password is correct. + * I guess password will be asked again later. + */ + linphone_auth_info_set_passwd(pending_auth, input); + linphone_core_add_auth_info(lc, pending_auth); + --(auth_stack.nitems); + + /* + * Reset line_buffer, to avoid the password + * to be used again from outer readline + */ + rl_line_buffer[0]='\0'; + + rl_event_hook=old_event_hook; + + return 1; +} + +void +print_usage (int exit_status) +{ + fprintf (stdout, "\n\ +usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\ + linphonec -v\n\ +\n\ + -c file specify path of configuration file.\n\ + -d level be verbose. 0 is no output. 6 is all output\n\ + -l logfile specify the log file for your SIP phone\n\ + -s sipaddress specify the sip call to do at startup\n\ + -a enable auto answering for incoming calls\n\ + -V enable video features globally (disabled by default)\n\ + -C enable video capture only (disabled by default)\n\ + -D enable video display only (disabled by default)\n\ + -S show general state messages (disabled by default)\n\ + -v or --version display version and exits.\n"); + + exit(exit_status); +} + + +/* + * + * Called every second from main read loop. + * + * Will use the following globals: + * + * - LinphoneCore linphonec + * - LPC_AUTH_STACK auth_stack; + * + */ +static int +linphonec_idle_call () +{ + LinphoneCore *opm=&linphonec; + + /* Uncomment the following to verify being called */ + /* printf(".\n"); */ + + linphone_core_iterate(opm); + if (answer_call){ + fprintf (stdout, "-------auto answering to call-------\n" ); + linphone_core_accept_call(opm,NULL); + answer_call=FALSE; + } + +#if 0 /* Automatic exit should be requested with a command line switch */ + /* Quit if autocall mode was on and no call is in progress */ + if ( sipAddr != NULL && opm->call == NULL ) + { + linphonec_parse_command_line(&linphonec, "quit"); + } +#endif + + if ( auth_stack.nitems ) + { + /* + * Inhibit command completion + * during password prompts + */ + rl_inhibit_completion=1; + linphonec_prompt_for_auth_final(opm); + rl_inhibit_completion=0; + } + + return 0; +} + +/* + * Use globals: + * + * - char *histfile_name (also sets this) + * - char *last_in_history (allocates it) + */ +static int +linphonec_initialize_readline() +{ + /*rl_bind_key('\t', rl_insert);*/ + + /* Allow conditional parsing of ~/.inputrc */ + rl_readline_name = "linphonec"; + + /* Call idle_call() every second */ + rl_set_keyboard_input_timeout(LPC_READLINE_TIMEOUT); + rl_event_hook=linphonec_idle_call; + + /* Set history file and read it */ + histfile_name = ms_strdup_printf ("%s/.linphonec_history", + getenv("HOME")); + read_history(histfile_name); + + /* Initialized last_in_history cache*/ + last_in_history[0] = '\0'; + + /* Register a completion function */ + rl_attempted_completion_function = linephonec_readline_completion; + + /* printf("Readline initialized.\n"); */ + setlinebuf(stdout); + return 0; +} + +/* + * Uses globals: + * + * - char *histfile_name (writes history to file and frees it) + * - char *last_in_history (frees it) + * + */ +static int +linphonec_finish_readline() +{ + + stifle_history(HISTSIZE); + write_history(histfile_name); + free(histfile_name); + histfile_name=NULL; + return 0; +} + +static void print_prompt(LinphoneCore *opm){ +#ifdef IDENTITY_AS_PROMPT + snprintf(prompt, PROMPT_MAX_LEN, "%s> ", + linphone_core_get_primary_contact(opm)); +#else + snprintf(prompt, PROMPT_MAX_LEN, "linphonec> "); +#endif +} + +static int +linphonec_main_loop (LinphoneCore * opm, char * sipAddr) +{ + char buf[LINE_MAX_LEN]; /* auto call handling */ + bool_t run=TRUE; + char *input; + + print_prompt(opm); + + + /* auto call handling */ + if (sipAddr != NULL ) + { + snprintf (buf, sizeof(buf),"call %s", sipAddr); + run=linphonec_parse_command_line(&linphonec, buf); + } + + while ((input=readline(prompt))) + { + char *iptr; /* input and input pointer */ + size_t input_len; + + /* Strip blanks */ + iptr=lpc_strip_blanks(input); + + input_len = strlen(iptr); + + /* + * Do nothing but release memory + * if only blanks are read + */ + if ( ! input_len ) + { + free(input); + continue; + } + + + /* + * Only add to history if not already + * last item in it + */ + if ( strcmp(last_in_history, iptr) ) + { + strncpy(last_in_history,iptr,sizeof(last_in_history)); + last_in_history[sizeof(last_in_history)-1]='\0'; + add_history(iptr); + } + + linphonec_parse_command_line(&linphonec, iptr); + free(input); + } + + return 0; +} + +/* + * Parse command line switches + * + * Use globals: + * + * - int trace_level + * - char *logfile_name + * - char *configfile_name + * - char *sipAddr + */ +static int +linphonec_parse_cmdline(int argc, char **argv) +{ + int arg_num=1; + + while (arg_num < argc) + { + int old_arg_num = arg_num; + if (strncmp ("-d", argv[arg_num], 2) == 0) + { + arg_num++; + if (arg_num < argc) + trace_level = atoi (argv[arg_num]); + else + trace_level = 1; + } + else if (strncmp ("-l", argv[arg_num], 2) == 0) + { + arg_num++; + if (arg_num < argc) + logfile_name = argv[arg_num]; + } + else if (strncmp ("-c", argv[arg_num], 2) == 0) + { + if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE); + + if (access(argv[arg_num],F_OK)!=0 ) + { + fprintf (stderr, + "Cannot open config file %s.\n", + argv[arg_num]); + exit(EXIT_FAILURE); + } + snprintf(configfile_name, PATH_MAX, argv[arg_num]); + } + else if (strncmp ("-s", argv[arg_num], 2) == 0) + { + arg_num++; + if (arg_num < argc) + sipAddr = argv[arg_num]; + } + else if (strncmp ("-a", argv[arg_num], 2) == 0) + { + auto_answer = TRUE; + } + else if (strncmp ("-C", argv[arg_num], 2) == 0) + { + vcap_enabled = TRUE; + } + else if (strncmp ("-D", argv[arg_num], 2) == 0) + { + display_enabled = TRUE; + } + else if (strncmp ("-V", argv[arg_num], 2) == 0) + { + display_enabled = TRUE; + vcap_enabled = TRUE; + } + else if ((strncmp ("-v", argv[arg_num], 2) == 0) + || + (strncmp + ("--version", argv[arg_num], + strlen ("--version")) == 0)) + { + printf ("version: " LINPHONE_VERSION "\n"); + exit (EXIT_SUCCESS); + } + else if (strncmp ("-S", argv[arg_num], 2) == 0) + { + show_general_state = TRUE; + } + else if (old_arg_num == arg_num) + { + fprintf (stderr, "ERROR: bad arguments\n"); + print_usage (EXIT_FAILURE); + } + arg_num++; + } + + return 1; +} + +/* + * Up to version 1.2.1 linphone used ~/.linphonec for + * CLI and ~/.gnome2/linphone for GUI as configuration file. + * In newer version both interfaces will use ~/.linphonerc. + * + * This function helps transparently migrating from one + * to the other layout using the following heuristic: + * + * IF new_config EXISTS => do nothing + * ELSE IF old_cli_config EXISTS => copy to new_config + * ELSE IF old_gui_config EXISTS => copy to new_config + * + * Returns: + * 0 if it did nothing + * 1 if it migrated successfully + * -1 on error + */ +static int +handle_configfile_migration() +{ + char *old_cfg_gui; + char *old_cfg_cli; + char *new_cfg; + const char *home = getenv("HOME"); + + new_cfg = ms_strdup_printf("%s/.linphonerc", home); + + /* + * If the *NEW* configuration already exists + * do nothing. + */ + if (access(new_cfg,F_OK)==0) + { + free(new_cfg); + return 0; + } + + old_cfg_cli = ms_strdup_printf("%s/.linphonec", home); + + /* + * If the *OLD* CLI configurations exist copy it to + * the new file and make it a symlink. + */ + if (access(old_cfg_cli, F_OK)==0) + { + if ( ! copy_file(old_cfg_cli, new_cfg) ) + { + free(old_cfg_cli); + free(new_cfg); + return -1; + } + printf("%s copied to %s\n", old_cfg_cli, new_cfg); + free(old_cfg_cli); + free(new_cfg); + return 1; + } + + free(old_cfg_cli); + old_cfg_gui = ms_strdup_printf("%s/.gnome2/linphone", home); + + /* + * If the *OLD* GUI configurations exist copy it to + * the new file and make it a symlink. + */ + if (access(old_cfg_gui, F_OK)==0) + { + if ( ! copy_file(old_cfg_gui, new_cfg) ) + { + exit(EXIT_FAILURE); + free(old_cfg_gui); + free(new_cfg); + return -1; + } + printf("%s copied to %s\n", old_cfg_gui, new_cfg); + free(old_cfg_gui); + free(new_cfg); + return 1; + } + + free(old_cfg_gui); + free(new_cfg); + return 0; +} + +/* + * Copy file "from" to file "to". + * Destination file is truncated if existing. + * Return 1 on success, 0 on error (printing an error). + */ +static int +copy_file(const char *from, const char *to) +{ + char message[256]; + FILE *in, *out; + char buf[256]; + size_t n; + + /* Open "from" file for reading */ + in=fopen(from, "r"); + if ( in == NULL ) + { + snprintf(message, 255, "Can't open %s for reading: %s\n", + from, strerror(errno)); + fprintf(stderr, message); + return 0; + } + + /* Open "to" file for writing (will truncate existing files) */ + out=fopen(to, "w"); + if ( out == NULL ) + { + snprintf(message, 255, "Can't open %s for writing: %s\n", + to, strerror(errno)); + fprintf(stderr, message); + return 0; + } + + /* Copy data from "in" to "out" */ + while ( (n=fread(buf, 1, sizeof buf, in)) > 0 ) + { + if ( ! fwrite(buf, 1, n, out) ) + { + return 0; + } + } + + fclose(in); + fclose(out); + + return 1; +} + +static char ** +linephonec_readline_completion(const char *text, int start, int end) +{ + char **matches = NULL; + + /* + * Prevent readline from falling + * back to filename-completion + */ + rl_attempted_completion_over=1; + + /* + * If this is the start of line we complete with commands + */ + if ( ! start ) + { + return rl_completion_matches(text, linphonec_command_generator); + } + + /* + * Otherwise, we should peek at command name + * or context to implement a smart completion. + * For example: "call .." could return + * friends' sip-uri as matches + */ + + return matches; +} + +/* + * Strip blanks from a string. + * Return a pointer into the provided string. + * Modifies input adding a NULL at first + * of trailing blanks. + */ +char * +lpc_strip_blanks(char *input) +{ + char *iptr; + + /* Find first non-blank */ + while(*input && isspace(*input)) ++input; + + /* Find last non-blank */ + iptr=input+strlen(input); + if (iptr > input) { + while(isspace(*--iptr)); + *(iptr+1)='\0'; + } + + return input; +} + +/**************************************************************************** + * + * $Log: linphonec.c,v $ + * Revision 1.57 2007/11/14 13:40:27 smorlat + * fix --disable-video build. + * + * Revision 1.56 2007/09/26 14:07:27 fixkowalski + * - ANSI/C++ compilation issues with non-GCC compilers + * - Faster epm-based packaging + * - Ability to build & run on FC6's eXosip/osip + * + * Revision 1.55 2007/09/24 16:01:58 smorlat + * fix bugs. + * + * Revision 1.54 2007/08/22 14:06:11 smorlat + * authentication bugs fixed. + * + * Revision 1.53 2007/02/13 21:31:01 smorlat + * added patch for general state. + * new doxygen for oRTP + * gtk-doc removed. + * + * Revision 1.52 2007/01/10 14:11:24 smorlat + * add --video to linphonec. + * + * Revision 1.51 2006/08/21 12:49:59 smorlat + * merged several little patches. + * + * Revision 1.50 2006/07/26 08:17:28 smorlat + * fix bugs. + * + * Revision 1.49 2006/07/17 18:45:00 smorlat + * support for several event queues in ortp. + * glib dependency removed from coreapi/ and console/ + * + * Revision 1.48 2006/04/09 12:45:32 smorlat + * linphonec improvements. + * + * Revision 1.47 2006/04/04 08:04:34 smorlat + * switched to mediastreamer2, most bugs fixed. + * + * Revision 1.46 2006/03/16 17:17:40 smorlat + * fix various bugs. + * + * Revision 1.45 2006/03/12 21:48:31 smorlat + * gcc-2.95 compile error fixed. + * mediastreamer2 in progress + * + * Revision 1.44 2006/03/04 11:17:10 smorlat + * mediastreamer2 in progress. + * + * Revision 1.43 2006/02/13 09:50:50 strk + * fixed unused variable warning. + * + * Revision 1.42 2006/02/02 15:39:18 strk + * - Added 'friend list' and 'friend call' commands + * - Allowed for multiple DTFM send in a single line + * - Added status-specific callback (bare version) + * + * Revision 1.41 2006/02/02 13:30:05 strk + * - Padded vtable with missing callbacks + * (fixing a segfault on friends subscription) + * - Handled friends notify (bare version) + * - Handled text messages receive (bare version) + * - Printed message on subscription request (bare version) + * + * Revision 1.40 2006/01/26 09:48:05 strk + * Added limits.h include + * + * Revision 1.39 2006/01/26 02:11:01 strk + * Removed unused variables, fixed copyright date + * + * Revision 1.38 2006/01/25 18:33:02 strk + * Removed the -t swich, terminate_on_close made the default behaviour + * + * Revision 1.37 2006/01/20 14:12:34 strk + * Added linphonec_init() and linphonec_finish() functions. + * Handled SIGINT and SIGTERM to invoke linphonec_finish(). + * Handling of auto-termination (-t) moved to linphonec_finish(). + * Reworked main (input read) loop to not rely on 'terminate' + * and 'run' variable (dropped). configfile_name allocated on stack + * using PATH_MAX limit. Changed print_usage signature to allow + * for an exit_status specification. + * + * Revision 1.36 2006/01/18 09:25:32 strk + * Command completion inhibited in proxy addition and auth request prompts. + * Avoided use of readline's internal filename completion. + * + * Revision 1.35 2006/01/14 13:29:32 strk + * Reworked commands interface to use a table structure, + * used by command line parser and help function. + * Implemented first level of completion (commands). + * Added notification of invalid "answer" and "terminate" + * commands (no incoming call, no active call). + * Forbidden "call" intialization when a call is already active. + * Cleaned up all commands, adding more feedback and error checks. + * + * Revision 1.34 2006/01/13 13:00:29 strk + * Added linphonec.h. Code layout change (added comments, forward decl, + * globals on top, copyright notices and Logs). Handled out-of-memory + * condition on history management. Removed assumption on sizeof(char). + * Fixed bug in authentication prompt (introduced by readline). + * Added support for multiple authentication requests (up to MAX_PENDING_AUTH). + * + * + ****************************************************************************/ diff --git a/linphone/console/linphonec.h b/linphone/console/linphonec.h new file mode 100644 index 000000000..368d63e0f --- /dev/null +++ b/linphone/console/linphonec.h @@ -0,0 +1,134 @@ +/**************************************************************************** + * + * $Id: linphonec.h,v 1.3 2006/01/20 14:12:34 strk Exp $ + * + * Copyright (C) 2005 Sandro Santilli + * + **************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ****************************************************************************/ + +#ifndef LINPHONEC_H +#define LINPHONEC_H 1 + +#ifdef HAVE_READLINE_H +#include +#else +#ifdef HAVE_READLINE_READLINE_H +#include +#endif +#endif +#ifdef HAVE_HISTORY_H +#include +#else +#ifdef HAVE_READLINE_HISTORY_H +#include +#endif +#endif + +/************************************************************************** + * + * Compile-time defines + * + **************************************************************************/ + +#define HISTSIZE 500 /* how many lines of input history */ +#define PROMPT_MAX_LEN 256 /* max len of prompt string */ +#define LINE_MAX_LEN 256 /* really needed ? */ + +/* + * Define this to have your primary contact + * as the prompt string + */ +/* #define IDENTITY_AS_PROMPT 1 */ + +/* + * Time between calls to linphonec_idle_call during main + * input read loop in microseconds. + */ +#define LPC_READLINE_TIMEOUT 1000000 + +/* + * Filename of linphonec history + */ +#define LPC_HIST_FILE "~/.linphonec_history" + +/* + * Maximum number of pending authentications + */ +#define MAX_PENDING_AUTH 8 + +/************************************************************************** + * + * Types + * + **************************************************************************/ + +/* + * A structure which contains information on the commands this program + * can understand. + */ +typedef int (*lpc_cmd_handler)(LinphoneCore *, char *); +typedef struct { + char *name; /* User printable name of the function. */ + lpc_cmd_handler func; /* Function to call to do the job. */ + char *help; /* Short help for this function. */ + char *doc; /* Long description. */ +} LPC_COMMAND; + +/*************************************************************************** + * + * Forward declarations + * + ***************************************************************************/ + +extern int linphonec_parse_command_line(LinphoneCore *lc, char *cl); +extern char *linphonec_command_generator(const char *text, int state); +extern void linphonec_finish(int exit_status); + +#endif /* def LINPHONEC_H */ + +/**************************************************************************** + * + * $Log: linphonec.h,v $ + * Revision 1.3 2006/01/20 14:12:34 strk + * Added linphonec_init() and linphonec_finish() functions. + * Handled SIGINT and SIGTERM to invoke linphonec_finish(). + * Handling of auto-termination (-t) moved to linphonec_finish(). + * Reworked main (input read) loop to not rely on 'terminate' + * and 'run' variable (dropped). configfile_name allocated on stack + * using PATH_MAX limit. Changed print_usage signature to allow + * for an exit_status specification. + * + * Revision 1.2 2006/01/14 13:29:32 strk + * Reworked commands interface to use a table structure, + * used by command line parser and help function. + * Implemented first level of completion (commands). + * Added notification of invalid "answer" and "terminate" + * commands (no incoming call, no active call). + * Forbidden "call" intialization when a call is already active. + * Cleaned up all commands, adding more feedback and error checks. + * + * Revision 1.1 2006/01/13 13:00:29 strk + * Added linphonec.h. Code layout change (added comments, forward decl, + * globals on top, copyright notices and Logs). Handled out-of-memory + * condition on history management. Removed assumption on sizeof(char). + * Fixed bug in authentication prompt (introduced by readline). + * Added support for multiple authentication requests (up to MAX_PENDING_AUTH). + * + * + ****************************************************************************/ diff --git a/linphone/console/sipomatic.c b/linphone/console/sipomatic.c new file mode 100644 index 000000000..08b167b1c --- /dev/null +++ b/linphone/console/sipomatic.c @@ -0,0 +1,467 @@ +/*************************************************************************** + linphone - sipomatic.c +This is a test program for linphone. It acts as a sip server and answers to linphone's +call. + ------------------- + begin : ven mar 30 + copyright : (C) 2001 by Simon MORLAT + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include "sipomatic.h" +#include + + +int run_cond=1; + +Sipomatic sipomatic; + +int sipomatic_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload); +int sipomatic_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload); + + +sdp_handler_t sipomatic_sdp_handler={ + sipomatic_accept_audio_offer, /*from remote sdp */ + sipomatic_accept_video_offer, + NULL, + NULL, + NULL, + NULL, +}; + +void stop_handler(int signum) +{ + run_cond=0; +} + +void sipomatic_process_event(Sipomatic *obj,eXosip_event_t *ev) +{ + Call *call; + switch(ev->type){ + case EXOSIP_CALL_INVITE: + call_new(obj,ev); + break; + case EXOSIP_CALL_CLOSED: + case EXOSIP_CALL_CANCELLED: + call=sipomatic_find_call(obj,ev->did); + if (call==NULL){ + ms_warning("Could not find call with did %i !",ev->did); + } + call_release(call); + call_destroy(call); + break; + default: + break; + } + eXosip_event_free(ev); +} + + +void endoffile_cb(void *ud, unsigned int ev,void * arg){ + Call*call=(Call*)ud; + call->eof=1; +} + +void call_accept(Call *call) +{ + sdp_context_t *ctx; + PayloadType *payload; + char *hellofile; + static int call_count=0; + char record_file[250]; + osip_message_t *msg=NULL; + sprintf(record_file,"/tmp/sipomatic%i.wav",call_count); + + ctx=call->sdpc; + payload=rtp_profile_get_payload(call->profile,call->audio.pt); + if (strcmp(payload->mime_type,"telephone-event")==0){ + /* telephone-event is not enough to accept a call */ + ms_message("Cannot accept call with only telephone-event.\n"); + eXosip_call_send_answer(call->did,415,NULL); + call->state=CALL_STATE_FINISHED; + return; + } + if (payload->clock_rate==16000){ + hellofile=call->root->file_path16000hz; + }else hellofile=call->root->file_path8000hz; + eXosip_call_build_answer(call->tid,200,&msg); + osip_message_set_content_type(msg,"application/sdp"); + osip_message_set_body(msg,call->sdpc->answerstr,strlen(call->sdpc->answerstr)); + eXosip_call_send_answer(call->tid,200,msg); + call->audio_stream=audio_stream_new(call->audio.localport,call->root->ipv6); + audio_stream_start_with_files(call->audio_stream, call->profile, + call->audio.remaddr,call->audio.remoteport,call->audio.remoteport+1, + call->audio.pt,20,hellofile,record_file); + call_count++; +#ifdef VIDEO_ENABLED + if (call->video.remoteport!=0){ + video_stream_send_only_start(call->video_stream,call->profile, + call->video.remaddr,call->video.remoteport,call->video.remoteport+1,call->video.pt, 60, + ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get())); + } +#endif + call->time=time(NULL); + call->state=CALL_STATE_RUNNING; + ms_filter_set_notify_callback(call->audio_stream->soundread,endoffile_cb,(void*)call); +} + + +PayloadType * sipomatic_payload_is_supported(sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile) +{ + int localpt; + if (payload->a_rtpmap!=NULL){ + localpt=rtp_profile_get_payload_number_from_rtpmap(local_profile,payload->a_rtpmap); + }else{ + localpt=payload->pt; + ms_warning("payload has no rtpmap."); + } + + if (localpt>=0){ + /* this payload is supported in our local rtp profile, so add it to the dialog rtp + profile */ + PayloadType *rtppayload; + rtppayload=rtp_profile_get_payload(local_profile,localpt); + if (rtppayload==NULL) return NULL; + /*check if we have the appropriate coder/decoder for this payload */ + if (strcmp(rtppayload->mime_type,"telephone-event")!=0) { + if (!ms_filter_codec_supported(rtppayload->mime_type)) { + ms_message("Codec %s is not supported.", rtppayload->mime_type); + return NULL; + } + } + rtppayload=payload_type_clone(rtppayload); + rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload); + /* add to the rtp payload type some other parameters (bandwidth) */ + if (payload->b_as_bandwidth!=0) rtppayload->normal_bitrate=payload->b_as_bandwidth*1000; + if (payload->a_fmtp!=NULL) + payload_type_set_send_fmtp(rtppayload,payload->a_fmtp); + if (strcasecmp(rtppayload->mime_type,"iLBC")==0){ + /*default to 30 ms mode */ + payload->a_fmtp="ptime=30"; + payload_type_set_recv_fmtp(rtppayload,payload->a_fmtp); + } + return rtppayload; + } + return NULL; +} + +int sipomatic_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload) +{ + static int audioport=8000; + Call *call=(Call*)sdp_context_get_user_pointer(ctx); + PayloadType *supported; + struct stream_params *params=&call->audio; + + /* see if this codec is supported in our local rtp profile*/ + supported=sipomatic_payload_is_supported(payload,&av_profile,call->profile); + if (supported==NULL) { + ms_message("Refusing codec %i (%s)",payload->pt,payload->a_rtpmap); + return -1; + } + if (strcmp(supported->mime_type,"telephone-event")==0) return 0; + if (params->ncodecs==0 ){ + /* this is the first codec we may accept*/ + params->localport=payload->localport=audioport; + params->remoteport=payload->remoteport; + params->line=payload->line; + params->pt=payload->pt; /* remember the first payload accepted */ + params->remaddr=payload->c_addr; + params->ncodecs++; + audioport+=4; + }else{ + /* refuse all other audio lines*/ + if(params->line!=payload->line) return -1; + } + return 0; +} + +int sipomatic_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload) +{ +#ifdef VIDEO_ENABLED + static int videoport=80000; + Call *call=(Call*)sdp_context_get_user_pointer(ctx); + PayloadType *supported; + struct stream_params *params=&call->video; + + /* see if this codec is supported in our local rtp profile*/ + supported=sipomatic_payload_is_supported(payload,&av_profile,call->profile); + if (supported==NULL) { + ms_message("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap); + return -1; + } + if (params->ncodecs==0 ){ + /* this is the first codec we may accept*/ + params->localport=payload->localport=videoport; + params->remoteport=payload->remoteport; + params->line=payload->line; + params->pt=payload->pt; /* remember the first payload accepted */ + params->remaddr=payload->c_addr; + params->ncodecs++; + videoport+=4; + }else{ + /* refuse all other video lines*/ + if(params->line!=payload->line) return -1; + } + return 0; +#else + return -1; +#endif +} + +void sipomatic_init(Sipomatic *obj, char *url, bool_t ipv6) +{ + osip_uri_t *uri=NULL; + int port=5064; + + obj->ipv6=ipv6; + + if (url==NULL){ + url=getenv("SIPOMATIC_URL"); + if (url==NULL){ + if (ipv6) url="sip:robot@[::1]:5064"; + else url="sip:robot@127.0.0.1:5064"; + } + } + if (url!=NULL) { + osip_uri_init(&uri); + if (osip_uri_parse(uri,url)==0){ + if (uri->port!=NULL) port=atoi(uri->port); + }else{ + ms_warning("Invalid identity uri:%s",url); + } + } + ms_message("Starting using url %s",url); + ms_mutex_init(&obj->lock,NULL); + obj->calls=NULL; + obj->acceptance_time=5; + obj->max_call_time=300; + obj->file_path8000hz=ms_strdup_printf("%s/%s",PACKAGE_SOUND_DIR,ANNOUCE_FILE8000HZ); + obj->file_path16000hz=ms_strdup_printf("%s/%s",PACKAGE_SOUND_DIR,ANNOUCE_FILE16000HZ); + osip_trace_initialize(OSIP_INFO1,stdout); + osip_trace_initialize(OSIP_INFO2,stdout); + osip_trace_initialize(OSIP_WARNING,stdout); + osip_trace_initialize(OSIP_ERROR,stdout); + osip_trace_initialize(OSIP_BUG,stdout); + osip_trace_initialize(OSIP_FATAL,stdout); + osip_trace_enable_level(OSIP_INFO1); + osip_trace_enable_level(OSIP_INFO2); + osip_trace_enable_level(OSIP_WARNING); + osip_trace_enable_level(OSIP_ERROR); + osip_trace_enable_level(OSIP_BUG); + osip_trace_enable_level(OSIP_FATAL); + eXosip_init(); + eXosip_set_user_agent("sipomatic-" LINPHONE_VERSION "/eXosip"); + eXosip_listen_addr(IPPROTO_UDP,NULL,port,ipv6 ? AF_INET6 : AF_INET,0); +} + +void sipomatic_uninit(Sipomatic *obj) +{ + ms_mutex_destroy(&obj->lock); + eXosip_quit(); +} + +void sipomatic_iterate(Sipomatic *obj) +{ + MSList *elem; + MSList *to_be_destroyed=NULL; + Call *call; + double elapsed; + eXosip_event_t *ev; + + while((ev=eXosip_event_wait(0,0))!=NULL){ + sipomatic_process_event(obj,ev); + } + elem=obj->calls; + while(elem!=NULL){ + call=(Call*)elem->data; + elapsed=time(NULL)-call->time; + switch(call->state){ + case CALL_STATE_INIT: + if (elapsed>obj->acceptance_time){ + call_accept(call); + } + break; + case CALL_STATE_RUNNING: + if (elapsed>obj->max_call_time || call->eof){ + call_release(call); + to_be_destroyed=ms_list_append(to_be_destroyed,call); + } + break; + } + elem=ms_list_next(elem); + } + for(;to_be_destroyed!=NULL; to_be_destroyed=ms_list_next(to_be_destroyed)){ + call_destroy((Call*)to_be_destroyed->data); + } +} + + +Call* sipomatic_find_call(Sipomatic *obj,int did) +{ + MSList *it; + Call *call=NULL; + for (it=obj->calls;it!=NULL;it=ms_list_next(it)){ + call=(Call*)it->data; + if ( call->did==did) return call; + } + return call; +} + + +Call * call_new(Sipomatic *root, eXosip_event_t *ev) +{ + Call *obj; + char *sdpans; + int status; + sdp_message_t *sdp; + sdp_context_t *sdpc; + + sdp=eXosip_get_sdp_info(ev->request); + sdpc=sdp_handler_create_context(&sipomatic_sdp_handler,NULL,"sipomatic",NULL); + obj=ms_new0(Call,1); + obj->profile=rtp_profile_new("remote"); + eXosip_call_send_answer(ev->tid,100,NULL); + sdp_context_set_user_pointer(sdpc,obj); + sdpans=sdp_context_get_answer(sdpc,sdp); + if (sdpans!=NULL){ + eXosip_call_send_answer(ev->tid,180,NULL); + + }else{ + status=sdp_context_get_status(sdpc); + eXosip_call_send_answer(ev->tid,status,NULL); + sdp_context_free(sdpc); + rtp_profile_destroy(obj->profile); + ms_free(obj); + return NULL; + } + obj->sdpc=sdpc; + obj->did=ev->did; + obj->tid=ev->tid; + obj->time=time(NULL); + obj->audio_stream=NULL; + obj->state=CALL_STATE_INIT; + obj->eof=0; + obj->root=root; + root->calls=ms_list_append(root->calls,obj); + return obj; +} + +void call_release(Call *call) +{ + eXosip_call_terminate(0,call->did); + if (call->audio_stream!=NULL) audio_stream_stop(call->audio_stream); +#ifdef VIDEO_ENABLED + if (call->video_stream!=NULL) video_stream_send_only_stop(call->video_stream); +#endif + call->state=CALL_STATE_FINISHED; +} + +void call_destroy(Call *obj) +{ + obj->root->calls=ms_list_remove(obj->root->calls,obj); + rtp_profile_destroy(obj->profile); + sdp_context_free(obj->sdpc); + ms_free(obj); +} + +void sipomatic_set_annouce_file(Sipomatic *obj, char *file) +{ + if (obj->file_path8000hz!=NULL){ + ms_free(obj->file_path8000hz); + } + obj->file_path8000hz=ms_strdup(file); +} + + +void display_help() +{ + printf("sipomatic [-u sip-url] [-f annouce-file ] [-s port]\n" + "sipomatic -h or --help: display this help.\n" + "sipomatic -v or --version: display version information.\n" + " -u sip-url : specify the sip url sipomatic listens and answers.\n" + " -f annouce-file : set the annouce file (16 bit raw format,8000Hz)\n" + " -6 enable ipv6 network usage\n"); + exit(0); +} + +char *getarg(int argc, char*argv[], int i) +{ + if (i +#undef PACKAGE +#undef VERSION +#include "mediastreamer2/mediastream.h" + +#include +#include + + +#define ANNOUCE_FILE8000HZ "hello8000.wav" +#define ANNOUCE_FILE16000HZ "hello16000.wav" + +struct _Sipomatic +{ + ms_mutex_t lock; + MSList *calls; + double acceptance_time; + double max_call_time; + char *file_path8000hz; + char *file_path16000hz; + bool_t ipv6; +}; + +typedef struct _Sipomatic Sipomatic; + +void sipomatic_init(Sipomatic *obj, char *url, bool_t ipv6); +void sipomatic_uninit(Sipomatic *obj); +void sipomatic_iterate(Sipomatic *obj); +#define sipomatic_lock(obj) ms_mutex_lock(&(obj)->lock); +#define sipomatic_unlock(obj) ms_mutex_unlock(&(obj)->lock); + +void sipomatic_set_annouce_file(Sipomatic *obj, char *file); + +struct stream_params{ + int ncodecs; + int line; + int localport; + int remoteport; + int pt; + char *remaddr; +}; + +struct _Call +{ + Sipomatic *root; + sdp_context_t *sdpc; + int time; + int did; + int tid; + AudioStream *audio_stream; +#ifdef VIDEO_ENABLED + VideoStream *video_stream; +#endif + int state; + struct _CallParams *params; + int eof; + RtpProfile *profile; + struct stream_params audio; + struct stream_params video; +}; + +#define CALL_STATE_INIT 0 +#define CALL_STATE_RUNNING 1 +#define CALL_STATE_FINISHED 2 + +typedef struct _Call Call; + + +Call * call_new(Sipomatic *obj, eXosip_event_t *ev); +void call_accept(Call *call); +void call_release(Call *call); +void call_destroy(Call *call); + +Call* sipomatic_find_call(Sipomatic *obj,int cid); diff --git a/linphone/console/wav2raw.c b/linphone/console/wav2raw.c new file mode 100644 index 000000000..1dc218374 --- /dev/null +++ b/linphone/console/wav2raw.c @@ -0,0 +1,67 @@ + + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int ifd,ofd; + char *name,*p; + char buf[200]; + int len; + + if (argc<2) return -1; + name=malloc(strlen(argv[1])+10); + sprintf(name,"%s",argv[1]); + p=strstr(name,".raw"); + if (p!=NULL){ + sprintf(p,"%s",".wav\0"); + }else{ + sprintf(name,"%s%s",argv[1],".raw"); + } + + ifd=open(name,O_RDONLY); + if (ifd<0) { + perror("Could not open input file"); + return -1; + } + ofd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP); + if (ofd<0) { + perror("Could not open output file"); + return -1; + } + len=read(ifd,buf,20); + printf("len=%i\n",len); + /* erase the wav header */ + if (len>0){ + memset(buf,0,20); + write(ofd,buf,20); + }else{ + printf("Error while processing %s: %s\n",argv[1],strerror(errno)); + return -1; + }; + + while ( (len=read(ifd,buf,200))>0){ + #ifdef WORDS_BIGENDIAN + for (i=0;i +#include +#include "lpconfig.h" + +extern LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid); +extern void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm); +extern void linphone_core_retry_proxy_register(LinphoneCore *lc, const char *realm); + +LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, + const char *passwd, const char *ha1,const char *realm) +{ + LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1); + if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username); + if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid); + if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd); + if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); + if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); + obj->works=FALSE; + obj->first_time=TRUE; + return obj; +} + +void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd){ + if (info->passwd!=NULL) { + ms_free(info->passwd); + info->passwd=NULL; + } + if (passwd!=NULL && (strlen(passwd)>0)) info->passwd=ms_strdup(passwd); +} + +void linphone_auth_info_destroy(LinphoneAuthInfo *obj){ + if (obj->username!=NULL) ms_free(obj->username); + if (obj->userid!=NULL) ms_free(obj->userid); + if (obj->passwd!=NULL) ms_free(obj->passwd); + if (obj->ha1!=NULL) ms_free(obj->ha1); + if (obj->realm!=NULL) ms_free(obj->realm); + ms_free(obj); +} + +void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, int pos) +{ + char key[50]; + sprintf(key,"auth_info_%i",pos); + lp_config_clean_section(config,key); + + if (obj==NULL){ + return; + } + if (obj->username!=NULL){ + lp_config_set_string(config,key,"username",obj->username); + } + if (obj->userid!=NULL){ + lp_config_set_string(config,key,"userid",obj->userid); + } + if (obj->passwd!=NULL){ + lp_config_set_string(config,key,"passwd",obj->passwd); + } + if (obj->ha1!=NULL){ + lp_config_set_string(config,key,"ha1",obj->ha1); + } + if (obj->realm!=NULL){ + lp_config_set_string(config,key,"realm",obj->realm); + } + lp_config_sync(config); +} + +LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos) +{ + char key[50]; + const char *username,*userid,*passwd,*ha1,*realm; + + sprintf(key,"auth_info_%i",pos); + if (!lp_config_has_section(config,key)){ + return NULL; + } + + username=lp_config_get_string(config,key,"username",NULL); + userid=lp_config_get_string(config,key,"userid",NULL); + passwd=lp_config_get_string(config,key,"passwd",NULL); + ha1=lp_config_get_string(config,key,"ha1",NULL); + realm=lp_config_get_string(config,key,"realm",NULL); + return linphone_auth_info_new(username,userid,passwd,ha1,realm); +} + +static bool_t key_match(const char *tmp1, const char *tmp2){ + if (tmp1==NULL && tmp2==NULL) return TRUE; + if (tmp1!=NULL && tmp2!=NULL && strcmp(tmp1,tmp2)==0) return TRUE; + return FALSE; + +} + +static int auth_info_compare(const void *pinfo,const void *pref){ + LinphoneAuthInfo *info=(LinphoneAuthInfo*)pinfo; + LinphoneAuthInfo *ref=(LinphoneAuthInfo*)pref; + if (key_match(info->realm,ref->realm) && key_match(info->username,ref->username)) return 0; + return -1; +} + +LinphoneAuthInfo *linphone_core_auth_info_find(LinphoneCore *lc, const char *realm, const char *username) +{ + LinphoneAuthInfo ref; + MSList *elem; + ref.realm=(char*)realm; + ref.username=(char*)username; + elem=ms_list_find_custom(lc->auth_info,auth_info_compare,(void*)&ref); + if (elem==NULL) return NULL; + return (LinphoneAuthInfo*)elem->data; +} + +void linphone_core_add_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info) +{ + int n; + MSList *elem; + char *userid; + if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; + else userid=info->userid; + eXosip_lock(); + eXosip_add_authentication_info(info->username,userid, + info->passwd,info->ha1,info->realm); + eXosip_unlock(); + /* if the user was prompted, re-allow automatic_action */ + if (lc->automatic_action>0) lc->automatic_action--; + /* find if we are attempting to modify an existing auth info */ + elem=ms_list_find_custom(lc->auth_info,auth_info_compare,info); + if (elem!=NULL){ + linphone_auth_info_destroy((LinphoneAuthInfo*)elem->data); + elem->data=(void *)info; + n=ms_list_position(lc->auth_info,elem); + }else { + lc->auth_info=ms_list_append(lc->auth_info,(void *)info); + n=ms_list_size(lc->auth_info)-1; + } +} + +void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info){ + if (lc->automatic_action>0) lc->automatic_action--; +} + +void linphone_core_remove_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info){ + int len=ms_list_size(lc->auth_info); + int newlen; + int i; + MSList *elem; + lc->auth_info=ms_list_remove(lc->auth_info,info); + newlen=ms_list_size(lc->auth_info); + /*printf("len=%i newlen=%i\n",len,newlen);*/ + linphone_auth_info_destroy(info); + for (i=0;iconfig,NULL,i); + } + for (elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ + linphone_auth_info_write_config(lc->config,(LinphoneAuthInfo*)elem->data,i); + } + +} + +void linphone_core_clear_all_auth_info(LinphoneCore *lc){ + MSList *elem; + int i; + eXosip_lock(); + eXosip_clear_authentication_info(); + eXosip_unlock(); + for(i=0,elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem),i++){ + LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data; + linphone_auth_info_destroy(info); + linphone_auth_info_write_config(lc->config,NULL,i); + } + ms_list_free(lc->auth_info); + lc->auth_info=NULL; +} + +void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev){ + char *prx_realm=NULL,*www_realm=NULL; + osip_proxy_authorization_t *prx_auth; + osip_authorization_t *www_auth; + osip_message_t *msg=ev->request; + char *username; + LinphoneAuthInfo *as=NULL; + + username=osip_uri_get_username(msg->from->url); + osip_message_get_proxy_authorization(msg,0,&prx_auth); + osip_message_get_authorization(msg,0,&www_auth); + if (prx_auth!=NULL) + prx_realm=osip_proxy_authorization_get_realm(prx_auth); + if (www_auth!=NULL) + www_realm=osip_authorization_get_realm(www_auth); + + if (prx_realm==NULL && www_realm==NULL){ + ms_message("No authentication info in the request, ignoring"); + return; + } + /* see if we already have this auth information , not to ask it everytime to the user */ + if (prx_realm!=NULL) + as=linphone_core_auth_info_find(lc,prx_realm,username); + if (www_realm!=NULL) + as=linphone_core_auth_info_find(lc,www_realm,username); + if (as){ + ms_message("Authentication for user=%s realm=%s is working.",username,prx_realm ? prx_realm : www_realm); + as->works=TRUE; + } +} + + +void linphone_core_find_or_ask_for_auth_info(LinphoneCore *lc,const char *username,const char* realm, int tid) +{ + LinphoneAuthInfo *as; + if ((as=linphone_core_auth_info_find(lc,realm,username))==NULL || + (as->works==FALSE && as->first_time==FALSE) ) { + if (lc->vtable.auth_info_requested!=NULL) { + lc->vtable.auth_info_requested(lc,realm,username); + lc->automatic_action++;/*suspends eXosip_automatic_action until the user supplies a password */ + } + if (as) as->first_time=FALSE; + } +} + +void linphone_process_authentication(LinphoneCore *lc, eXosip_event_t *ev) +{ + char *prx_realm=NULL,*www_realm=NULL; + osip_proxy_authenticate_t *prx_auth; + osip_www_authenticate_t *www_auth; + osip_message_t *resp=ev->response; + char *username; + + if (strcmp(ev->request->sip_method,"REGISTER")==0) { + gstate_new_state(lc, GSTATE_REG_FAILED, "Authentication required"); + } + + username=osip_uri_get_username(resp->from->url); + prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); + www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0); + if (prx_auth!=NULL) + prx_realm=osip_proxy_authenticate_get_realm(prx_auth); + if (www_auth!=NULL) + www_realm=osip_www_authenticate_get_realm(www_auth); + + if (prx_realm==NULL && www_realm==NULL){ + ms_warning("No realm in the server response."); + return; + } + /* see if we already have this auth information , not to ask it everytime to the user */ + if (prx_realm!=NULL) + linphone_core_find_or_ask_for_auth_info(lc,username,prx_realm,ev->tid); + if (www_realm!=NULL) + linphone_core_find_or_ask_for_auth_info(lc,username,www_realm,ev->tid); +} + diff --git a/linphone/coreapi/chat.c b/linphone/coreapi/chat.c new file mode 100644 index 000000000..500c957d9 --- /dev/null +++ b/linphone/coreapi/chat.c @@ -0,0 +1,109 @@ +/*************************************************************************** + * chat.c + * + * Sun Jun 5 19:34:18 2005 + * Copyright 2005 Simon Morlat + * Email simon dot morlat at linphone dot org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + #include "linphonecore.h" + #include "private.h" + #include + + LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){ + char *real_url=NULL; + osip_from_t *parsed_url=NULL; + char *route; + if (linphone_core_interpret_url(lc,to,&real_url,&parsed_url,&route)){ + LinphoneChatRoom *cr=ms_new0(LinphoneChatRoom,1); + cr->lc=lc; + cr->peer=real_url; + cr->peer_url=parsed_url; + cr->route=route; + lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr); + return cr; + } + return NULL; + } + + + void linphone_chat_room_destroy(LinphoneChatRoom *cr){ + LinphoneCore *lc=cr->lc; + lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); + osip_from_free(cr->peer_url); + ms_free(cr->peer); + ms_free(cr->route); + } + +void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){ + const char *identity=linphone_core_get_identity(cr->lc); + osip_message_t *sip=NULL; + eXosip_message_build_request(&sip,"MESSAGE",cr->peer,identity,cr->route); + osip_message_set_content_type(sip,"text/plain"); + osip_message_set_body(sip,msg,strlen(msg)); + eXosip_message_send_request(sip); +} + +bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, osip_from_t *from){ + if (cr->peer_url->url->username && from->url->username && + strcmp(cr->peer_url->url->username,from->url->username)==0) return TRUE; + return FALSE; +} + +void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, const char *from, const char *msg){ + if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, from, msg); +} + +void linphone_core_text_received(LinphoneCore *lc, eXosip_event_t *ev){ + MSList *elem; + const char *msg; + LinphoneChatRoom *cr=NULL; + char *cleanfrom; + osip_from_t *from_url=ev->request->from; + osip_body_t *body=NULL; + + osip_message_get_body(ev->request,0,&body); + if (body==NULL){ + ms_error("Could not get text message from SIP body"); + return; + } + msg=body->body; + from_2char_without_params(from_url,&cleanfrom); + for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ + cr=(LinphoneChatRoom*)elem->data; + if (linphone_chat_room_matches(cr,from_url)){ + break; + } + cr=NULL; + } + if (cr==NULL){ + /* create a new chat room */ + cr=linphone_core_create_chat_room(lc,cleanfrom); + } + linphone_chat_room_text_received(cr,lc,cleanfrom,msg); + osip_free(cleanfrom); +} + + +void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){ + cr->user_data=ud; +} +void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){ + return cr->user_data; +} diff --git a/linphone/coreapi/enum.c b/linphone/coreapi/enum.c new file mode 100644 index 000000000..7bded2299 --- /dev/null +++ b/linphone/coreapi/enum.c @@ -0,0 +1,172 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* enum lookup code */ + +#include +#include + +#include "enum.h" + +#define DNS_ANSWER_MAX_SIZE 2048 + + +char *create_enum_domain(const char *number){ + int len=strlen(number); + char *domain=ms_malloc((len*2)+10); + int i,j; + + for (i=0,j=len-1;j>=0;j--){ + domain[i]=number[j]; + i++; + domain[i]='.'; + i++; + } + strcpy(&domain[i],"e164.arpa"); + ms_message("enum domain for %s is %s",number,domain); + return domain; +} + + +bool_t is_a_number(const char *str){ + char *p=(char *)str; + bool_t res=FALSE; + bool_t space_found=FALSE; + for(;;p++){ + switch(p[0]){ + case '9': + case '8': + case '7': + case '6': + case '5': + case '4': + case '3': + case '2': + case '1': + case '0': + res=TRUE; + if (space_found) return FALSE; /* avoid splited numbers */ + break; + case '\0': + return res; + break; + case ' ': + space_found=TRUE; + break; + default: + return FALSE; + } + } + return FALSE; +} +//4970072278724 +bool_t is_enum(const char *sipaddress, char **enum_domain){ + char *p; + p=strstr(sipaddress,"sip:"); + if (p==NULL) return FALSE; /* enum should look like sip:4369959250*/ + else p+=4; + if (is_a_number(p)){ + if (enum_domain!=NULL){ + *enum_domain=create_enum_domain(p); + } + return TRUE; + } + return FALSE; +} + + + +int enum_lookup(const char *enum_domain, enum_lookup_res_t **res){ + int err; + //char dns_answer[DNS_ANSWER_MAX_SIZE]; + char *begin,*end; + char *host_result, *command; + int i; + bool_t forkok; + /* + ns_msg handle; + int count; + + memset(&handle,0,sizeof(handle)); + *res=NULL; + ms_message("Resolving %s...",enum_domain); + + err=res_search(enum_domain,ns_c_in,ns_t_naptr,dns_answer,DNS_ANSWER_MAX_SIZE); + if (err<0){ + ms_warning("Error resolving enum:",herror(h_errno)); + return -1; + } + ns_initparse(dns_answer,DNS_ANSWER_MAX_SIZE,&handle); + count=ns_msg_count(handle,ns_s_an); + + for(i=0;isip_address[i]=ms_strdup(begin); + err++; + begin=strstr(end+1,"sip:"); + if (begin==NULL) break; + } + ms_free(host_result); + return err; + + parse_error: + ms_free(*res); + ms_free(host_result); + *res=NULL; + ms_warning("Parse error in enum_lookup()."); + return -1; +} + +void enum_lookup_res_free(enum_lookup_res_t *res){ + int i; + for (i=0;isip_address[i]!=NULL) ms_free(res->sip_address[i]); + } + ms_free(res); +} diff --git a/linphone/coreapi/enum.h b/linphone/coreapi/enum.h new file mode 100644 index 000000000..05b285fb7 --- /dev/null +++ b/linphone/coreapi/enum.h @@ -0,0 +1,35 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef ENUM_LOOKUP_H +#define ENUM_LOOKUP_H + +#include "private.h" + +#define MAX_ENUM_LOOKUP_RESULTS 10 + +typedef struct enum_lookup_res{ + char *sip_address[MAX_ENUM_LOOKUP_RESULTS]; +}enum_lookup_res_t; + +bool_t is_enum(const char *sipaddress, char **enum_domain); +int enum_lookup(const char *enum_domain, enum_lookup_res_t **res); +void enum_lookup_res_free(enum_lookup_res_t *res); + +#endif diff --git a/linphone/coreapi/exevents.c b/linphone/coreapi/exevents.c new file mode 100644 index 000000000..693d1367d --- /dev/null +++ b/linphone/coreapi/exevents.c @@ -0,0 +1,1012 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "exevents.h" +#include "linphonecore.h" +#include "private.h" +#include "mediastreamer2/mediastream.h" +#include +#include + +static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp); + +static void linphone_call_proceeding(LinphoneCore *lc, eXosip_event_t *ev){ + if (lc->call==NULL){ + ms_warning("Bug in call_proceeding()"); + return; + } + lc->call->cid=ev->cid; + lc->call->did=ev->did; + lc->call->tid=ev->tid; +} + +static void linphone_connect_incoming(LinphoneCore *lc){ + lc->vtable.show(lc); + lc->vtable.display_status(lc,_("Connected.")); + lc->call->state=LCStateAVRunning; + if (lc->ringstream!=NULL){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + if (lc->audiostream->ticker!=NULL){ + /*case where we accepted early media */ + linphone_core_stop_media_streams(lc); + linphone_core_init_media_streams(lc); + } + linphone_core_start_media_streams(lc,lc->call); +} + +int linphone_call_accepted(LinphoneCore *lc, eXosip_event_t *ev) +{ + LinphoneCall *call=lc->call; + sdp_message_t *sdp=eXosip_get_sdp_info(ev->response); + const char *sdpanswer=NULL; + osip_message_t *msg=NULL; + int err; + if (call==NULL){ + ms_warning("No call to accept."); + return 0; + } + linphone_call_proceeding(lc,ev); + call->auth_pending=FALSE; + if (call->state==LCStateAVRunning){ + return 0; /*already accepted*/ + } + linphone_call_init_media_params(call); + if (!lc->sip_conf.sdp_200_ack){ + err=0; + sdp_context_read_answer(call->sdpctx,sdp); + }else{ + /*we receive a 200OK with an sdp offer*/ + err=linphone_answer_sdp(lc,ev,sdp); + if (err==0) sdpanswer=call->sdpctx->answerstr; + } + if (err==0){ + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + linphone_connect_incoming(lc); + } + /*send the ack once streams are started*/ + eXosip_call_build_ack(ev->did,&msg); + if (sdpanswer!=NULL) linphone_set_sdp(msg,sdpanswer); + eXosip_call_send_ack(ev->did,msg); + if (err!=0){ + /*send a bye*/ + ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); + linphone_core_terminate_call(lc,NULL); + } + return 0; +} + + +int linphone_call_terminated(LinphoneCore *lc, eXosip_event_t *ev) +{ + /*stop ringing if necessary*/ + if (lc->call!=NULL){ + if (lc->call->cid!=ev->cid){ + /* this is not current call */ + ms_message("call %i terminated, this was not current call.",ev->cid); + return 0; + } + } + + ms_message("Current call terminated..."); + if (lc->ringstream!=NULL) { + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_core_stop_media_streams(lc); + lc->vtable.show(lc); + lc->vtable.display_status(lc,_("Call terminated.")); + gstate_new_state(lc, GSTATE_CALL_END, NULL); + if (lc->vtable.bye_recv!=NULL){ + char *from; + osip_from_to_str(ev->request->from,&from); + lc->vtable.bye_recv(lc,from); + osip_free(from); + } + if (lc->call!=NULL){ + linphone_call_destroy(lc->call); + lc->call=NULL; + } + return 0; +} + + +int linphone_call_released(LinphoneCore *lc, int cid){ + LinphoneCall *call=lc->call; + if (call!=NULL && call->cid==cid){ + + linphone_call_destroy(lc->call); + lc->call=NULL; + lc->vtable.display_status(lc,_("Could not reach destination.")); + gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); + } + return 0; +} + +int linphone_call_failure(LinphoneCore *lc, eXosip_event_t *ev) +{ + const char *reason=""; + char *msg486=_("User is busy."); + char *msg480=_("User is temporarily unavailable."); + char *msg487=_("Request Cancelled."); + /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ + char *msg600=_("User does not want to be disturbed."); + char *msg603=_("Call declined."); + char* tmpmsg=msg486; + int code; + + if (ev->response){ + code=osip_message_get_status_code(ev->response); + reason=osip_message_get_reason_phrase(ev->response); + }else code=-110; + lc->vtable.show(lc); + + switch(code) + { + case 401: + case 407: + if (lc->call!=NULL) + linphone_process_authentication(lc,ev); + return 0; + break; + case 400: + lc->vtable.display_status(lc,_("Bad request")); + break; + case 404: + lc->vtable.display_status(lc,_("User cannot be found at given address.")); + break; + case 415: + lc->vtable.display_status(lc,_("Remote user cannot support any of proposed codecs.")); + break; + case 480: + tmpmsg=msg480; + case 486: + /* + msg_header_getbyname(msg,"retry-after",0,&retry); + if (retry!=NULL) + { + umsg=g_malloc(strlen(tmpmsg)+strlen(retrymsg)+13); + sprintf(umsg,retrymsg,tmpmsg,atoi(retry->hvalue)/60); + lc->vtable.display_message(lc,umsg); + ms_free(umsg); + }*/ + lc->vtable.display_message(lc,tmpmsg); + break; + case 487: + lc->vtable.display_status(lc,msg487); + break; + case 600: + lc->vtable.display_message(lc,msg600); + break; + case 603: + lc->vtable.display_status(lc,msg603); + break; + case -110: /* time out, call leg is lost */ + lc->vtable.display_status(lc,_("Timeout.")); + break; + case -111: + lc->vtable.display_status(lc,_("Remote host was found but refused connection.")); + break; + + default: + if (code>0) + { + lc->vtable.display_status(lc,reason); + } + else ms_warning("failure_cb unknown code=%i\n",code); + } + if (lc->ringstream!=NULL) { + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_core_stop_media_streams(lc); + if (lc->call!=NULL) { + linphone_call_destroy(lc->call); + gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); + lc->call=NULL; + } + return 0; +} + +extern sdp_handler_t linphone_sdphandler; + +static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp){ + int status=200; + sdp_context_t *ctx=NULL; + + ctx=lc->call->sdpctx; + /* get the result of the negociation */ + sdp_context_get_answer(ctx,sdp); + status=sdp_context_get_status(ctx); + + if (status==200){ + linphone_core_init_media_streams(lc); + return 0; + }else{ + if (status==-1) status=415; + } + return -1; +} + +int linphone_inc_new_call(LinphoneCore *lc, eXosip_event_t *ev) +{ + sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + osip_from_t *from_url=ev->request->from; + char *barmesg; + char *from; + char *to; + int err; + + osip_from_to_str(ev->request->from,&from); + osip_to_to_str(ev->request->to,&to); + + /* first check if we can answer successfully to this invite */ + if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){ + ms_message("Not present !! presence mode : %d\n",lc->presence_mode); + eXosip_lock(); + if (lc->presence_mode==LINPHONE_STATUS_BUSY) + eXosip_call_send_answer(ev->tid,486,NULL); + else if (lc->presence_mode==LINPHONE_STATUS_AWAY + ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK + ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE + ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH + ||lc->presence_mode==LINPHONE_STATUS_OFFLINE) + eXosip_call_send_answer(ev->tid,480,NULL); + else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB) + eXosip_call_send_answer(ev->tid,480,NULL); + else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED) + { + osip_message_t *msg; + eXosip_call_build_answer(ev->tid,302,&msg); + osip_message_set_contact(msg,lc->alt_contact); + eXosip_call_send_answer(ev->tid,302,msg); + } + else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_ALT_SERVICE) + { + osip_message_t *msg; + eXosip_call_build_answer(ev->tid,380,&msg); + osip_message_set_contact(msg,lc->alt_contact); + eXosip_call_send_answer(ev->tid,380,msg); + } + else + eXosip_call_send_answer(ev->tid,486,NULL); + eXosip_unlock(); + goto end; + } + if (lc->call!=NULL){/*busy*/ + eXosip_lock(); + eXosip_call_send_answer(ev->tid,486,NULL); + eXosip_unlock(); + goto end; + } + lc->call=linphone_call_new_incoming(lc,from,to,ev->cid,ev->did,ev->tid); + if (sdp==NULL){ + ms_message("No sdp body in invite, 200-ack scheme"); + err=0; + }else{ + err=linphone_answer_sdp(lc,ev,sdp); + } + if (!err){ + char *tmp; + if (from_2char_without_params(from_url,&tmp)!=0){ + tmp=ms_strdup("Unknown user"); + } + gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); + barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); + lc->vtable.show(lc); + lc->vtable.display_status(lc,barmesg); + lc->vtable.inv_recv(lc,tmp); + ms_free(barmesg); + osip_free(tmp); + + linphone_call_set_state(lc->call,LCStateRinging); + eXosip_lock(); + eXosip_call_send_answer(ev->tid,180,NULL); + eXosip_unlock(); + /* play the ring */ + if (lc->sound_conf.ring_sndcard!=NULL){ + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + } + }else{ + ms_error("Error during sdp negociation. "); + eXosip_lock(); + eXosip_call_send_answer(ev->tid,415,NULL); + eXosip_unlock(); + linphone_call_destroy(lc->call); + lc->call=NULL; + } + end: + osip_free(from); + osip_free(to); + return 0; +} + +void linphone_handle_ack(LinphoneCore *lc, eXosip_event_t *ev){ + sdp_message_t *sdp=eXosip_get_sdp_info(ev->ack); + if (sdp){ + sdp_context_read_answer(lc->call->sdpctx,sdp); + linphone_connect_incoming(lc); + } +} + +void linphone_handle_reinvite(LinphoneCore *lc, eXosip_event_t *ev){ + sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + sdp_context_t *ctx; + LinphoneCall *call=lc->call; + char *answer; + int status; + if (sdp==NULL){ + ms_warning("No sdp in reinvite !"); + eXosip_lock(); + eXosip_call_send_answer(ev->tid,603,NULL); + eXosip_unlock(); + return; + } + ctx=call->sdpctx; + /* get the result of the negociation */ + linphone_call_init_media_params(call); + answer=sdp_context_get_answer(ctx,sdp); + status=sdp_context_get_status(ctx); + if (status==200){ + osip_message_t *msg=NULL; + linphone_core_stop_media_streams(lc); + linphone_core_init_media_streams(lc); + eXosip_lock(); + if (eXosip_call_build_answer(ev->tid,200,&msg)<0){ + ms_warning("Reinvite for closed call ?"); + eXosip_unlock(); + linphone_core_stop_media_streams(lc); + return ; + } + answer=call->sdpctx->answerstr; /* takes the sdp already computed*/ + linphone_set_sdp(msg,answer); + eXosip_call_send_answer(ev->tid,200,msg); + eXosip_unlock(); + linphone_core_start_media_streams(lc,call); + }else{ + eXosip_lock(); + eXosip_call_send_answer(ev->tid,status,NULL); + eXosip_unlock(); + } +} + +void linphone_do_automatic_redirect(LinphoneCore *lc, const char *contact){ + char *msg=ortp_strdup_printf(_("Redirected to %s..."),contact); + lc->vtable.display_status(lc,msg); + ms_free(msg); + if (lc->call!=NULL) linphone_call_destroy(lc->call); + lc->call=NULL; + linphone_core_invite(lc,contact); +} + +void linphone_call_redirected(LinphoneCore *lc, eXosip_event_t *ev){ + int code=osip_message_get_status_code(ev->response); + char *contact=NULL; + osip_contact_t *ct; + osip_message_get_contact(ev->response,0,&ct); + if (ct) osip_contact_to_str(ct,&contact); + switch(code){ + case 380: + lc->vtable.display_url(lc,_("User is not reachable at the moment but he invites you\nto contact him using the following alternate resource:"),contact); + if (lc->call!=NULL) linphone_call_destroy(lc->call); + lc->call=NULL; + break; + case 302: + linphone_do_automatic_redirect(lc,contact); + break; + } + if (contact) osip_free(contact); +} + + +/* these are the SdpHandler callbacks: we are called in to be aware of the content +of the SDP messages exchanged */ + +int linphone_set_audio_offer(sdp_context_t *ctx) +{ + LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); + LinphoneCore *lc=call->core; + PayloadType *codec; + MSList *elem; + sdp_payload_t payload; + + + elem=lc->codecs_conf.audio_codecs; + while(elem!=NULL){ + codec=(PayloadType*) elem->data; + if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){ + sdp_payload_init(&payload); + payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate); + payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap); + payload.localport=lc->rtp_conf.audio_rtp_port; + if (strcasecmp(codec->mime_type,"iLBC")==0){ + /* prefer the 30 ms mode */ + payload.a_fmtp="ptime=30"; + } + sdp_context_add_audio_payload(ctx,&payload); + ms_free(payload.a_rtpmap); + } + elem=ms_list_next(elem); + } + /* add telephone-event payload*/ + sdp_payload_init(&payload); + payload.pt=rtp_profile_get_payload_number_from_mime(lc->local_profile,"telephone-event"); + payload.a_rtpmap="telephone-event/8000"; + payload.a_fmtp="0-11"; + if (lc->dw_audio_bw>0) payload.b_as_bandwidth=lc->dw_audio_bw; + sdp_context_add_audio_payload(ctx,&payload); + return 0; +} + +static int find_payload_type_number(RtpProfile *prof, PayloadType *pt){ + int candidate=-1,i; + PayloadType *it; + for(i=0;i<127;++i){ + it=rtp_profile_get_payload(prof,i); + if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0 + && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0) ){ + if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) || + (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){ + /*exact match*/ + return i; + }else candidate=i; + } + } + if (candidate==-1) ms_fatal("Should not happen."); + return candidate; +} + +static int find_payload_type_number_best_match(RtpProfile *prof, const char *rtpmap, const char *fmtp){ + int localpt=rtp_profile_get_payload_number_from_rtpmap(prof,rtpmap); + PayloadType *pt; + char value[10]; + if (localpt<0) return -1; + pt=rtp_profile_get_payload(prof,localpt); + if (strcasecmp(pt->mime_type,"H264")==0){ + /*hack for H264: need to answer with same packetization-mode*/ + if (fmtp && fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){ + PayloadType tmp; + memset(&tmp,0,sizeof(tmp)); + tmp.mime_type="H264"; + tmp.clock_rate=pt->clock_rate; + tmp.recv_fmtp=(atoi(value)==1) ? "packetization-mode=1" : NULL; + localpt=find_payload_type_number(prof,&tmp); + } + } + return localpt; +} + +int linphone_set_video_offer(sdp_context_t *ctx) +{ + LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); + LinphoneCore *lc=call->core; + PayloadType *codec; + MSList *elem; + bool_t firsttime=TRUE; + + if (!linphone_core_video_enabled(lc)) return -1; + + for(elem=lc->codecs_conf.video_codecs;elem!=NULL;elem=ms_list_next(elem)){ + codec=(PayloadType*) elem->data; + if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){ + sdp_payload_t payload; + sdp_payload_init(&payload); + payload.line=1; + payload.a_rtpmap=ortp_strdup_printf("%s/%i",codec->mime_type,codec->clock_rate); + payload.localport=lc->rtp_conf.video_rtp_port; + payload.pt=find_payload_type_number(lc->local_profile,codec); + payload.a_fmtp=codec->recv_fmtp; + if(firsttime){ + firsttime=FALSE; + if (lc->dw_video_bw>0) + payload.b_as_bandwidth=lc->dw_video_bw; + } + sdp_context_add_video_payload(ctx,&payload); + ms_free(payload.a_rtpmap); + } + } + return 0; +} + +typedef enum { + Unsupported, + Supported, + SupportedAndValid /* valid= the presence of this codec is enough to make a call */ +}SupportLevel; + +SupportLevel linphone_payload_is_supported(LinphoneCore *lc, sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile, bool_t answering, PayloadType **local_payload_type) +{ + int localpt; + SupportLevel ret; + if (payload->a_rtpmap!=NULL){ + localpt=find_payload_type_number_best_match(local_profile,payload->a_rtpmap,payload->a_fmtp); + }else{ + localpt=payload->pt; + ms_warning("payload has no rtpmap."); + } + + if (localpt>=0 && localpt <128 ){ + /* this payload is understood, but does the user want to use it ?? */ + PayloadType *rtppayload; + rtppayload=rtp_profile_get_payload(local_profile,localpt); + if (rtppayload==NULL) { + ms_warning("strange error !!"); + return Unsupported; + } + *local_payload_type=rtppayload; + if (strcmp(rtppayload->mime_type,"telephone-event")!=0){ + if (answering && !linphone_core_check_payload_type_usability(lc,rtppayload) ){ + ms_warning("payload %s is not usable",rtppayload->mime_type); + return Unsupported; + } + if ( !payload_type_enabled(rtppayload)) { + ms_warning("payload %s is not enabled.",rtppayload->mime_type); + return Unsupported; + } + ret=SupportedAndValid; + }else ret=Supported; + if (dialog_profile!=NULL){ + int dbw,ubw; + /* this payload is supported in our local rtp profile, so add it to the dialog rtp + profile */ + rtppayload=payload_type_clone(rtppayload); + rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload); + /* add to the rtp payload type some other parameters (bandwidth) */ + if (rtppayload->type==PAYLOAD_VIDEO){ + dbw=lc->dw_video_bw; + ubw=lc->up_video_bw; + }else{ + dbw=lc->dw_audio_bw; + ubw=lc->up_audio_bw; + } + if (payload->b_as_bandwidth!=0){ + ms_message("Remote bandwidth constraint: %i",payload->b_as_bandwidth); + /*obey to remote bandwidth constraint AND our own upbandwidth constraint*/ + rtppayload->normal_bitrate=1000*get_min_bandwidth( + payload->b_as_bandwidth, ubw); + }else{ + /*limit to upload bandwidth if exist, else no limit*/ + rtppayload->normal_bitrate=(ubw>0)? 1000*ubw : -1; + } + /* but anyway give our download bandwidth constraint*/ + payload->b_as_bandwidth=(dbw>0) ? dbw : 0; + if (payload->a_fmtp!=NULL){ + payload_type_set_send_fmtp(rtppayload,payload->a_fmtp); + } + payload->a_fmtp=rtppayload->recv_fmtp; + if (payload->a_ptime>0){ + char tmp[30]; + snprintf(tmp,sizeof(tmp),"ptime=%i",payload->a_ptime); + payload_type_append_send_fmtp(rtppayload,tmp); + ms_message("%s attribute added to fmtp",tmp); + } + } + return ret; + } + return Unsupported; +} + +int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload) +{ + RtpProfile *remote_profile; + StreamParams *params; + SupportLevel supported; + LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); + LinphoneCore *lc=call->core; + PayloadType *lpt=NULL; + + if (call->profile==NULL){ + /* create a remote user agent profile */ + call->profile=remote_profile=rtp_profile_new("remote"); + } + remote_profile=call->profile; + /* see if this codec is supported in our local rtp profile*/ + supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); + if (supported==Unsupported) { + ms_message("Refusing audio codec %i (%s)",payload->pt,payload->a_rtpmap); + return -1; + } + if (supported==SupportedAndValid) { + params=&call->audio_params; + if (params->initialized==0){ + /* this is the first codec we accept, it is going to be used*/ + params->localport=payload->localport=lc->rtp_conf.audio_rtp_port; + params->line=payload->line; + params->pt=payload->pt; /* remember the first payload accepted */ + if (payload->relay_host!=NULL){ + params->remoteaddr=payload->relay_host; + params->remoteport=payload->relay_port; + params->remotertcpport=payload->relay_port; + params->relay_session_id=payload->relay_session_id; + }else{ + params->remoteaddr=payload->c_addr; + params->remoteport=payload->remoteport; + params->remotertcpport=payload->remoteport+1; + } + params->initialized=1; + /* we can now update the allocated bandwidth for audio, and then video*/ + linphone_core_update_allocated_audio_bandwidth(lc,lpt); + }else{ + /* refuse all other audio lines*/ + if(params->line!=payload->line) return -1; + } + } + return 0; +} + +int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload) +{ + LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); + LinphoneCore *lc=call->core; + RtpProfile *remote_profile; + StreamParams *params; + SupportLevel supported; + PayloadType *lpt=NULL; + + if (!linphone_core_video_enabled(lc)) return -1; + + if (call->profile==NULL){ + /* create a remote user agent profile */ + call->profile=rtp_profile_new("remote"); + } + remote_profile=call->profile; + /* see if this codec is supported in our local rtp profile*/ + supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); + if (supported==Unsupported) { + ms_message("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap); + return -1; + } + if (supported==SupportedAndValid){ + params=&call->video_params; + if (params->initialized==0){ + /* this is the first codec we may accept*/ + params->localport=payload->localport=lc->rtp_conf.video_rtp_port; + params->line=payload->line; + params->pt=payload->pt; /* remember the first payload accepted */ + if (payload->relay_host!=NULL){ + params->remoteaddr=payload->relay_host; + params->remoteport=payload->relay_port; + params->remotertcpport=payload->relay_port; + params->relay_session_id=payload->relay_session_id; + }else{ + params->remoteaddr=payload->c_addr; + params->remoteport=payload->remoteport; + params->remotertcpport=params->remoteport+1; + } + params->initialized=1; + }else{ + /* refuse all other video lines*/ + if(params->line!=payload->line) return -1; + } + } + return 0; +} + +int linphone_read_audio_answer(sdp_context_t *ctx,sdp_payload_t *payload) +{ + LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); + LinphoneCore *lc=call->core; + StreamParams *params; + SupportLevel supported; + PayloadType *lpt=NULL; + + /* paranoid check: see if this codec is supported in our local rtp profile*/ + supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); + if (supported==Unsupported) { + ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); + return 0; + } + if (supported==SupportedAndValid){ + params=&call->audio_params; + if (params->initialized==0){ + /* this is the first codec we accept, this is the one that is going to be used (at least for sending + data.*/ + params->localport=lc->rtp_conf.audio_rtp_port; + params->line=payload->line; + params->pt=payload->pt; /* remember the first payload accepted */ + if (payload->relay_host!=NULL){ + params->remoteaddr=payload->relay_host; + params->remoteport=payload->relay_port; + params->remotertcpport=payload->relay_port; + params->relay_session_id=payload->relay_session_id; + }else{ + params->remoteaddr=payload->c_addr; + params->remoteport=payload->remoteport; + params->remotertcpport=payload->remoteport+1; + } + params->initialized=1; + /* we can now update the allocated bandwidth for audio, and then video*/ + linphone_core_update_allocated_audio_bandwidth(lc,lpt); + } + } + return 0; +} + +int linphone_read_video_answer(sdp_context_t *ctx,sdp_payload_t *payload) +{ + LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); + LinphoneCore *lc=call->core; + StreamParams *params; + SupportLevel supported; + PayloadType *lpt=NULL; + + /* paranoid check: see if this codec is supported in our local rtp profile*/ + supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); + if (supported==Unsupported) { + ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); + return 0; + } + if (supported==SupportedAndValid){ + params=&call->video_params; + if (params->initialized==0){ + /* this is the first codec we may accept*/ + params->localport=lc->rtp_conf.video_rtp_port; + params->line=payload->line; + params->pt=payload->pt; /* remember the first payload accepted */ + if (payload->relay_host!=NULL){ + params->remoteaddr=payload->relay_host; + params->remoteport=payload->relay_port; + params->remotertcpport=payload->relay_port; + params->relay_session_id=payload->relay_session_id; + }else{ + params->remoteaddr=payload->c_addr; + params->remoteport=payload->remoteport; + params->remotertcpport=payload->remoteport+1; + } + params->initialized=1; + } + } + return 0; +} + +void linphone_call_ringing(LinphoneCore *lc, eXosip_event_t *ev){ + sdp_message_t *sdp=eXosip_get_sdp_info(ev->response); + LinphoneCall *call=lc->call; + + linphone_call_proceeding(lc,ev); + + if (sdp==NULL){ + if (lc->ringstream!=NULL) return; /*already ringing !*/ + if (lc->sound_conf.play_sndcard!=NULL){ + ms_message("Remote ringing..."); + lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard); + } + }else{ + /*accept early media */ + StreamParams *audio_params; + if (call==NULL){ + ms_error("No call ?"); + goto end; + } + if (lc->audiostream->ticker!=NULL){ + /*streams already started */ + ms_message("Early media already started."); + goto end; + } + audio_params=&call->audio_params; + sdp_context_read_answer(lc->call->sdpctx,sdp); + lc->vtable.show(lc); + lc->vtable.display_status(lc,_("Early media.")); + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + if (lc->ringstream!=NULL){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + ms_message("Doing early media..."); + linphone_core_start_media_streams(lc,call); + } + call->state=LCStateRinging; + goto end; + end: + sdp_message_free(sdp); + +} + +void linphone_call_message_new(LinphoneCore *lc, eXosip_event_t *ev){ +#ifdef VIDEO_ENABLED + if (ev->request){ + if (MSG_IS_INFO(ev->request)){ + osip_content_type_t *ct; + ct=osip_message_get_content_type(ev->request); + if (ct && ct->subtype && + strcmp(ct->subtype,"media_control+xml")==0){ + osip_body_t *body=NULL; + osip_message_get_body(ev->request,0,&body); + if (body && body->body!=NULL && + strstr(body->body,"picture_fast_update")){ + osip_message_t *ans=NULL; + ms_message("Receiving VFU request !"); + if (lc->videostream) + video_stream_send_vfu(lc->videostream); + eXosip_call_build_answer(ev->tid,200,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,200,ans); + } + } + } + }else ms_warning("linphone_call_message_new: No request ?"); +#endif +} + + +void linphone_registration_faillure(LinphoneCore *lc, eXosip_event_t *ev){ + int status_code=0; + char *msg; + const char *reason=NULL; + osip_uri_t *requri=osip_message_get_uri(ev->request); + char *ru; + + osip_uri_to_str(requri,&ru); + + if (ev->response){ + status_code=osip_message_get_status_code(ev->response); + reason=osip_message_get_reason_phrase(ev->response); + } + switch(status_code){ + case 401: + case 407: + linphone_process_authentication(lc,ev); + break; + default: + msg=ortp_strdup_printf(_("Registration on %s failed: %s"),ru,(reason!=NULL) ? reason : _("no response timeout")); + lc->vtable.display_status(lc,msg); + gstate_new_state(lc, GSTATE_REG_FAILED, msg); + ms_free(msg); + } + osip_free(ru); +} + +void linphone_registration_success(LinphoneCore *lc,eXosip_event_t *ev){ + LinphoneProxyConfig *cfg; + osip_uri_t *requri=osip_message_get_uri(ev->request); + char *msg; + char *ru; + osip_uri_to_str(requri,&ru); + msg=ms_strdup_printf(_("Registration on %s successful."),ru); + lc->vtable.display_status(lc,msg); + ms_free(msg); + osip_free(ru); + cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); + ms_return_if_fail(cfg!=NULL); + cfg->auth_pending=FALSE; + cfg->registered=TRUE; + gstate_new_state(lc, GSTATE_REG_OK, NULL); +} + +static void linphone_other_request(LinphoneCore *lc, eXosip_event_t *ev){ + if (ev->request==NULL) return; + if (strcmp(ev->request->sip_method,"MESSAGE")==0){ + linphone_core_text_received(lc,ev); + eXosip_message_send_answer(ev->tid,200,NULL); + }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ + eXosip_options_send_answer(ev->tid,200,NULL); + } + else { + ms_message("Unsupported request received."); + /*answer with a 501 Not implemented*/ + eXosip_message_send_answer(ev->tid,501,NULL); + } +} + +void linphone_core_process_event(LinphoneCore *lc,eXosip_event_t *ev) +{ + switch(ev->type){ + case EXOSIP_CALL_ANSWERED: + ms_message("CALL_ANSWERED\n"); + linphone_call_accepted(lc,ev); + linphone_authentication_ok(lc,ev); + break; + case EXOSIP_CALL_CLOSED: + case EXOSIP_CALL_CANCELLED: + ms_message("CALL_CLOSED or CANCELLED\n"); + linphone_call_terminated(lc,ev); + break; + case EXOSIP_CALL_TIMEOUT: + case EXOSIP_CALL_NOANSWER: + ms_message("CALL_TIMEOUT or NOANSWER\n"); + linphone_call_failure(lc,ev); + break; + case EXOSIP_CALL_REQUESTFAILURE: + case EXOSIP_CALL_GLOBALFAILURE: + case EXOSIP_CALL_SERVERFAILURE: + ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); + linphone_call_failure(lc,ev); + break; + case EXOSIP_CALL_INVITE: + ms_message("CALL_NEW\n"); + /* CALL_NEW is used twice in qos mode : + * when you receive invite (textinfo = "With QoS" or "Without QoS") + * and when you receive update (textinfo = "New Call") */ + linphone_inc_new_call(lc,ev); + break; + case EXOSIP_CALL_REINVITE: + linphone_handle_reinvite(lc,ev); + break; + case EXOSIP_CALL_ACK: + ms_message("CALL_ACK"); + linphone_handle_ack(lc,ev); + break; + case EXOSIP_CALL_REDIRECTED: + ms_message("CALL_REDIRECTED"); + linphone_call_redirected(lc,ev); + break; + case EXOSIP_CALL_PROCEEDING: + ms_message("CALL_PROCEEDING"); + linphone_call_proceeding(lc,ev); + break; + case EXOSIP_CALL_RINGING: + ms_message("CALL_RINGING"); + linphone_call_ringing(lc,ev); + break; + case EXOSIP_CALL_MESSAGE_NEW: + ms_message("EXOSIP_CALL_MESSAGE_NEW"); + linphone_call_message_new(lc,ev); + break; + case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: + if (ev->did<0 && ev->response && + (ev->response->status_code==407 || ev->response->status_code==401)){ + eXosip_default_action(ev); + } + break; + case EXOSIP_IN_SUBSCRIPTION_NEW: + ms_message("CALL_SUBSCRIPTION_NEW or UPDATE"); + linphone_subscription_new(lc,ev); + break; + case EXOSIP_SUBSCRIPTION_UPDATE: + break; + case EXOSIP_SUBSCRIPTION_NOTIFY: + ms_message("CALL_SUBSCRIPTION_NOTIFY"); + linphone_notify_recv(lc,ev); + break; + case EXOSIP_SUBSCRIPTION_ANSWERED: + ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); + linphone_subscription_answered(lc,ev); + break; + case EXOSIP_SUBSCRIPTION_CLOSED: + ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); + linphone_subscription_closed(lc,ev); + break; + case EXOSIP_CALL_RELEASED: + ms_message("CALL_RELEASED\n"); + linphone_call_released(lc, ev->cid); + break; + case EXOSIP_REGISTRATION_FAILURE: + ms_message("REGISTRATION_FAILURE\n"); + linphone_registration_faillure(lc,ev); + break; + case EXOSIP_REGISTRATION_SUCCESS: + linphone_registration_success(lc,ev); + linphone_authentication_ok(lc,ev); + break; + case EXOSIP_MESSAGE_NEW: + linphone_other_request(lc,ev); + break; + case EXOSIP_MESSAGE_REQUESTFAILURE: + if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ + /*the user is expected to have registered to the proxy, thus password is known*/ + eXosip_default_action(ev); + } + break; + default: + break; + } + eXosip_event_free(ev); +} diff --git a/linphone/coreapi/exevents.h b/linphone/coreapi/exevents.h new file mode 100644 index 000000000..c7e7baa9b --- /dev/null +++ b/linphone/coreapi/exevents.h @@ -0,0 +1,40 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef EXEVENTS_H +#define EXEVENTS_H +#include +#include "sdphandler.h" + + +void linphone_core_process_event(LinphoneCore *lc, eXosip_event_t *ev); + +/* these are the SdpHandler callbacks: we are called in to be aware of the content +of the SDP messages exchanged */ + +int linphone_set_audio_offer(sdp_context_t *ctx); +int linphone_set_video_offer(sdp_context_t *ctx); +int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload); +int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload); +int linphone_read_audio_answer(sdp_context_t *ctx,sdp_payload_t *payload); +int linphone_read_video_answer(sdp_context_t *ctx,sdp_payload_t *payload); + +void linphone_core_text_received(LinphoneCore *lc, eXosip_event_t *ev); + +#endif diff --git a/linphone/coreapi/friend.c b/linphone/coreapi/friend.c new file mode 100644 index 000000000..50938a61f --- /dev/null +++ b/linphone/coreapi/friend.c @@ -0,0 +1,736 @@ +/*************************************************************************** + * friend.c + * + * Sat May 15 15:25:16 2004 + * Copyright 2004 Simon Morlat + * Email + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "linphonecore.h" +#include "private.h" +#include +#include +#include "lpconfig.h" + +const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ + const char *str=NULL; + switch(ss){ + case LINPHONE_STATUS_UNKNOWN: + str=_("Unknown"); + break; + case LINPHONE_STATUS_ONLINE: + str=_("Online"); + break; + case LINPHONE_STATUS_BUSY: + str=_("Busy"); + break; + case LINPHONE_STATUS_BERIGHTBACK: + str=_("Be right back"); + break; + case LINPHONE_STATUS_AWAY: + str=_("Away"); + break; + case LINPHONE_STATUS_ONTHEPHONE: + str=_("On the phone"); + break; + case LINPHONE_STATUS_OUTTOLUNCH: + str=_("Out to lunch"); + break; + case LINPHONE_STATUS_NOT_DISTURB: + str=_("Do not disturb"); + break; + case LINPHONE_STATUS_MOVED: + str=_("Moved"); + break; + case LINPHONE_STATUS_ALT_SERVICE: + str=_("Using another messaging service"); + break; + case LINPHONE_STATUS_OFFLINE: + str=_("Offline"); + break; + case LINPHONE_STATUS_PENDING: + str=_("Pending"); + break; + case LINPHONE_STATUS_CLOSED: + str=_("Closed"); + break; + default: + str=_("Unknown-bug"); + } + return str; +} + +static int friend_data_compare(const void * a, const void * b, void * data){ + osip_from_t *fa=((LinphoneFriend*)a)->url; + osip_from_t *fb=((LinphoneFriend*)b)->url; + char *ua,*ub; + ua=fa->url->username; + ub=fb->url->username; + if (ua!=NULL && ub!=NULL) { + //printf("Comparing usernames %s,%s\n",ua,ub); + return strcasecmp(ua,ub); + } + else { + /* compare hosts*/ + ua=fa->url->host; + ub=fb->url->host; + if (ua!=NULL && ub!=NULL){ + int ret=strcasecmp(ua,ub); + //printf("Comparing hostnames %s,%s,res=%i\n",ua,ub,ret); + return ret; + } + else return -1; + } +} + +static int friend_compare(const void * a, const void * b){ + return friend_data_compare(a,b,NULL); +} + + +MSList *find_friend(MSList *fl, const osip_from_t *friend, LinphoneFriend **lf){ + MSList *res=NULL; + LinphoneFriend dummy; + if (lf!=NULL) *lf=NULL; + dummy.url=(osip_from_t*)friend; + res=ms_list_find_custom(fl,friend_compare,&dummy); + if (lf!=NULL && res!=NULL) *lf=(LinphoneFriend*)res->data; + return res; +} + +LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid){ + MSList *elem; + for (elem=l;elem!=NULL;elem=elem->next){ + LinphoneFriend *lf=(LinphoneFriend*)elem->data; + if (lf->nid==nid) return lf; + } + return NULL; +} + +LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid){ + MSList *elem; + for (elem=l;elem!=NULL;elem=elem->next){ + LinphoneFriend *lf=(LinphoneFriend*)elem->data; + if (lf->sid==sid) return lf; + } + return NULL; +} + +void __linphone_friend_do_subscribe(LinphoneFriend *fr){ + char *friend=NULL; + const char *route=NULL; + const char *from=NULL; + osip_message_t *msg=NULL; + osip_from_to_str(fr->url,&friend); + if (fr->proxy!=NULL){ + route=fr->proxy->reg_route; + from=fr->proxy->reg_identity; + }else from=linphone_core_get_primary_contact(fr->lc); + if (fr->sid<0){ + /* people for which we don't have yet an answer should appear as offline */ + fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr,friend,_("Gone"),"sip-closed.png"); + } + eXosip_lock(); + eXosip_subscribe_build_initial_request(&msg,friend,from,route,"presence",600); + eXosip_subscribe_send_initial_request(msg); + eXosip_unlock(); + osip_free(friend); +} + + +LinphoneFriend * linphone_friend_new(){ + LinphoneFriend *obj=ms_new0(LinphoneFriend,1); + obj->out_did=-1; + obj->in_did=-1; + obj->nid=-1; + obj->sid=-1; + obj->pol=LinphoneSPAccept; + obj->status=LINPHONE_STATUS_OFFLINE; + obj->subscribe=TRUE; + return obj; +} + +LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ + LinphoneFriend *fr=linphone_friend_new(); + if (linphone_friend_set_sip_addr(fr,addr)<0){ + linphone_friend_destroy(fr); + return NULL; + } + return fr; +} + + +int linphone_friend_set_sip_addr(LinphoneFriend *lf, const char *addr){ + int err; + osip_from_t *fr=NULL; + osip_from_init(&fr); + err=osip_from_parse(fr,addr); + if (err<0) { + ms_warning("Invalid friend sip uri: %s",addr); + osip_from_free(fr); + return -1; + } + if (lf->url!=NULL) osip_from_free(lf->url); + lf->url=fr; + return 0; +} + +int linphone_friend_set_name(LinphoneFriend *lf, const char *name){ + osip_from_t *fr=lf->url; + if (fr==NULL){ + ms_error("linphone_friend_set_sip_addr() must be called before linphone_friend_set_name()."); + return -1; + } + if (fr->displayname!=NULL){ + osip_free(fr->displayname); + fr->displayname=NULL; + } + if (name && name[0]!='\0'){ + fr->displayname=osip_strdup(name); + } + return 0; +} + +int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val){ + fr->subscribe=val; + return 0; +} + +int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol) +{ + fr->pol=pol; + return 0; +} + +int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg){ + fr->proxy=cfg; + return 0; +} + +void linphone_friend_set_sid(LinphoneFriend *lf, int sid){ + lf->sid=sid; +} +void linphone_friend_set_nid(LinphoneFriend *lf, int nid){ + lf->nid=nid; + lf->inc_subscribe_pending=TRUE; +} + +void add_presence_body(osip_message_t *notify, LinphoneOnlineStatus online_status) +{ + char buf[1000]; +#ifdef SUPPORT_MSN + int atom_id = 1000; +#endif + char *contact_info; + + osip_contact_t *ct=NULL; + osip_message_get_contact(notify,0,&ct); + osip_contact_to_str(ct,&contact_info); + +#ifdef SUPPORT_MSN + + if (online_status==LINPHONE_STATUS_ONLINE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==LINPHONE_STATUS_BUSY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==LINPHONE_STATUS_BERIGHTBACK) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==LINPHONE_STATUS_AWAY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==LINPHONE_STATUS_ONTHEPHONE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==LINPHONE_STATUS_OUTTOLUNCH) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + } + + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, "application/xpidf+xml"); +#else + + if (online_status==LINPHONE_STATUS_ONLINE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ +%s\n\ +online\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==LINPHONE_STATUS_BUSY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + busy\n\ +\n\ +\n\ +%s\n\ +busy\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==LINPHONE_STATUS_BERIGHTBACK) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + in-transit\n\ +\n\ +\n\ +%s\n\ +be right back\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==LINPHONE_STATUS_AWAY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + away\n\ +\n\ +\n\ +%s\n\ +away\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==LINPHONE_STATUS_ONTHEPHONE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + on-the-phone\n\ +\n\ +\n\ +%s\n\ +on the phone\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==LINPHONE_STATUS_OUTTOLUNCH) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + meal\n\ +\n\ +\n\ +%s\n\ +out to lunch\n\ +\n\ +", + contact_info, contact_info); + } + else + { + /* */ + sprintf(buf, "\n\ +\n%s", + contact_info, +"\n\ +\n\ +closed\n\ +\n\ + permanent-absence\n\ +\n\ +\n\ +\n\ +\n\n"); + } + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, "application/pidf+xml"); + +#endif + osip_free(contact_info); +} + + +void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os){ + //printf("Wish to notify %p, lf->nid=%i\n",lf,lf->nid); + if (lf->in_did!=-1){ + osip_message_t *msg=NULL; + const char *identity; + if (lf->proxy!=NULL) identity=lf->proxy->reg_identity; + else identity=linphone_core_get_primary_contact(lf->lc); + eXosip_lock(); + eXosip_insubscription_build_notify(lf->in_did,ss,0,&msg); + if (msg!=NULL){ + osip_message_set_contact(msg,identity); + add_presence_body(msg,os); + eXosip_insubscription_send_request(lf->in_did,msg); + }else ms_error("could not create notify for incoming subscription."); + eXosip_unlock(); + } +} + +static void linphone_friend_unsubscribe(LinphoneFriend *lf){ + if (lf->out_did!=-1) { + osip_message_t *msg=NULL; + eXosip_lock(); + eXosip_subscribe_build_refresh_request(lf->out_did,&msg); + if (msg){ + osip_message_set_expires(msg,"0"); + eXosip_subscribe_send_refresh_request(lf->out_did,msg); + }else ms_error("Could not build subscribe refresh request !"); + eXosip_unlock(); + } +} + +void linphone_friend_destroy(LinphoneFriend *lf){ + linphone_friend_notify(lf,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED); + linphone_friend_unsubscribe(lf); + if (lf->url!=NULL) osip_from_free(lf->url); + ms_free(lf); +} + +void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg){ + if (lf->proxy==cfg){ + lf->proxy=NULL; + } +} + +char *linphone_friend_get_addr(LinphoneFriend *lf){ + char *ret,*tmp; + if (lf->url==NULL) return NULL; + osip_uri_to_str(lf->url->url,&tmp); + ret=ms_strdup(tmp); + osip_free(tmp); + return ret; +} + +char *linphone_friend_get_name(LinphoneFriend *lf){ + if (lf->url==NULL) return NULL; + if (lf->url->displayname==NULL) return NULL; + return ms_strdup(lf->url->displayname); +} + +char * linphone_friend_get_url(LinphoneFriend *lf){ + char *tmp,*ret; + if (lf->url==NULL) return NULL; + osip_from_to_str(lf->url,&tmp); + ret=ms_strdup(tmp); + ms_free(tmp); + return ret; +} + +bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){ + return lf->subscribe; +} + +LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf){ + return lf->pol; +} + +LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ + return lf->status; +} + + +void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ + if (fr->url==NULL) { + ms_warning("No sip url defined."); + return; + } + fr->lc=lc; + + if (fr->inc_subscribe_pending){ + switch(fr->pol){ + case LinphoneSPWait: + linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_PENDING,LINPHONE_STATUS_PENDING); + break; + case LinphoneSPAccept: + if (fr->lc!=NULL) + { + linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_ACTIVE,fr->lc->presence_mode); + } + break; + case LinphoneSPDeny: + linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED); + break; + } + fr->inc_subscribe_pending=FALSE; + } + if (fr->subscribe && fr->out_did==-1){ + + __linphone_friend_do_subscribe(fr); + } + ms_message("linphone_friend_apply() done."); +} + +void linphone_friend_edit(LinphoneFriend *fr){ +} + +void linphone_friend_done(LinphoneFriend *fr){ + ms_return_if_fail(fr!=NULL); + if (fr->lc==NULL) return; + linphone_friend_apply(fr,fr->lc); +} + +void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) +{ + ms_return_if_fail(lf->lc==NULL); + ms_return_if_fail(lf->url!=NULL); + linphone_friend_apply(lf,lc); + lc->friends=ms_list_append(lc->friends,lf); + return ; +} + +void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){ + MSList *el=ms_list_find(lc->friends,(void *)fl); + if (el!=NULL){ + lc->friends=ms_list_remove_link(lc->friends,el); + linphone_friend_destroy((LinphoneFriend*)el->data); + } +} + +#define key_compare(key, word) strncasecmp((key),(word),strlen(key)) + +LinphoneSubscribePolicy __policy_str_to_enum(const char* pol){ + if (key_compare("accept",pol)==0){ + return LinphoneSPAccept; + } + if (key_compare("deny",pol)==0){ + return LinphoneSPDeny; + } + if (key_compare("wait",pol)==0){ + return LinphoneSPWait; + } + ms_warning("Unrecognized subscribe policy: %s",pol); + return LinphoneSPWait; +} + +LinphoneProxyConfig *__index_to_proxy(LinphoneCore *lc, int index){ + if (index>=0) return (LinphoneProxyConfig*)ms_list_nth_data(lc->sip_conf.proxies,index); + else return NULL; +} + +LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int index){ + const char *tmp; + char item[50]; + int a; + LinphoneFriend *lf; + LpConfig *config=lc->config; + + sprintf(item,"friend_%i",index); + + if (!lp_config_has_section(config,item)){ + return NULL; + } + + tmp=lp_config_get_string(config,item,"url",NULL); + if (tmp==NULL) { + return NULL; + } + lf=linphone_friend_new_with_addr(tmp); + if (lf==NULL) { + return NULL; + } + tmp=lp_config_get_string(config,item,"pol",NULL); + if (tmp==NULL) linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPWait); + else{ + linphone_friend_set_inc_subscribe_policy(lf,__policy_str_to_enum(tmp)); + } + a=lp_config_get_int(config,item,"subscribe",0); + linphone_friend_send_subscribe(lf,a); + + a=lp_config_get_int(config,item,"proxy",-1); + if (a!=-1) { + linphone_friend_set_proxy(lf,__index_to_proxy(lc,a)); + } + return lf; +} + +const char *__policy_enum_to_str(LinphoneSubscribePolicy pol){ + switch(pol){ + case LinphoneSPAccept: + return "accept"; + break; + case LinphoneSPDeny: + return "deny"; + break; + case LinphoneSPWait: + return "wait"; + break; + } + ms_warning("Invalid policy enum value."); + return "wait"; +} + +void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, int index){ + char key[50]; + char *tmp; + int a; + + sprintf(key,"friend_%i",index); + + if (lf==NULL){ + lp_config_clean_section(config,key); + return; + } + if (lf->url!=NULL){ + osip_from_to_str(lf->url,&tmp); + if (tmp==NULL) { + return; + } + lp_config_set_string(config,key,"url",tmp); + osip_free(tmp); + } + lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol)); + lp_config_set_int(config,key,"subscribe",lf->subscribe); + if (lf->proxy!=NULL){ + a=ms_list_index(lf->lc->sip_conf.proxies,lf->proxy); + lp_config_set_int(config,key,"proxy",a); + }else lp_config_set_int(config,key,"proxy",-1); +} diff --git a/linphone/coreapi/general_state.c b/linphone/coreapi/general_state.c new file mode 100644 index 000000000..b92a0fd75 --- /dev/null +++ b/linphone/coreapi/general_state.c @@ -0,0 +1,101 @@ +/**************************************************************************** + * + * File: general_state.c + * + * Copyright (C) 2006, 2007 Thomas Reitmayr + * + **************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ****************************************************************************/ + + +#include "linphonecore.h" + + +static gstate_t _gstates[GSTATE_GROUP_CALL+1]; + +#if 0 +static const char *_gstates_text[] = { + "GSTATE_POWER_OFF", /* 0 */ + "GSTATE_POWER_STARTUP", /* 1 */ + "GSTATE_POWER_ON", /* 2 */ + "GSTATE_POWER_SHUTDOWN", /* 3 */ + NULL, NULL, NULL, NULL, NULL, NULL, + + "GSTATE_REG_NONE", /* 10 */ + "GSTATE_REG_OK", /* 11 */ + "GSTATE_REG_FAILED", /* 12 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + "GSTATE_CALL_IDLE", /* 20 */ + "GSTATE_CALL_OUT_INVITE", /* 21 */ + "GSTATE_CALL_OUT_CONNECTED", /* 22 */ + "GSTATE_CALL_IN_INVITE", /* 23 */ + "GSTATE_CALL_IN_CONNECTED", /* 24 */ + "GSTATE_CALL_END", /* 25 */ + "GSTATE_CALL_ERROR" /* 26 */ +}; +#endif + +/* set the initial states */ +void gstate_initialize(void) { + _gstates[GSTATE_GROUP_POWER] = GSTATE_POWER_OFF; + _gstates[GSTATE_GROUP_REG] = GSTATE_REG_NONE; + _gstates[GSTATE_GROUP_CALL] = GSTATE_CALL_IDLE; +} + + +/* retrieve the current state of the specified state group */ +gstate_t gstate_get_state(gstate_group_t group) { + return _gstates[group]; +} + + +void gstate_new_state(struct _LinphoneCore *lc, + gstate_t new_state, + const char *message) { + LinphoneGeneralState states_arg; + + /* determine the affected group */ + if (new_state < GSTATE_REG_NONE) + states_arg.group = GSTATE_GROUP_POWER; + else if (new_state < GSTATE_CALL_IDLE) + states_arg.group = GSTATE_GROUP_REG; + else + states_arg.group = GSTATE_GROUP_CALL; + + /* store the new state while remembering the old one */ + states_arg.new_state = new_state; + states_arg.old_state = _gstates[states_arg.group]; + _gstates[states_arg.group] = new_state; + states_arg.message = message; + + /*printf("gstate_new_state: %s\t-> %s\t(%s)\n", + _gstates_text[states_arg.old_state], + _gstates_text[states_arg.new_state], + message);*/ + + /* call the virtual method */ + if (lc->vtable.general_state) + lc->vtable.general_state(lc, &states_arg); + + /* immediately proceed to idle state */ + if (new_state == GSTATE_CALL_END || + new_state == GSTATE_CALL_ERROR) + gstate_new_state(lc, GSTATE_CALL_IDLE, NULL); +} + diff --git a/linphone/coreapi/linphonecore.c b/linphone/coreapi/linphonecore.c new file mode 100644 index 000000000..947dc535c --- /dev/null +++ b/linphone/coreapi/linphonecore.c @@ -0,0 +1,2261 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "mediastreamer2/mediastream.h" +#include +#include "sdphandler.h" + +#include +#include +#include "exevents.h" + + +#ifdef INET6 +#ifndef WIN32 +#include +#endif +#endif + +#ifdef WIN32 +#define HAVE_EXOSIP_GET_VERSION 1 +#endif + + +static const char *liblinphone_version=LIBLINPHONE_VERSION; + +#include "enum.h" + +void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result); +static void apply_nat_settings(LinphoneCore *lc); +static void toggle_video_preview(LinphoneCore *lc, bool_t val); + +/* relative path where is stored local ring*/ +#define LOCAL_RING "rings/oldphone.wav" +/* same for remote ring (ringback)*/ +#define REMOTE_RING_FR "ringback.wav" +#define REMOTE_RING_US "ringback.wav" + + +sdp_handler_t linphone_sdphandler={ + linphone_accept_audio_offer, /*from remote sdp */ + linphone_accept_video_offer, /*from remote sdp */ + linphone_set_audio_offer, /*to local sdp */ + linphone_set_video_offer, /*to local sdp */ + linphone_read_audio_answer, /*from incoming answer */ + linphone_read_video_answer /*from incoming answer */ +}; + +void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) +{ + obj->_func=func; + obj->_user_data=ud; +} + +int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ + if (obj->_func!=NULL) obj->_func(lc,obj->_user_data); + return 0; +} + +static void linphone_call_init_common(LinphoneCall *call, char *from, char *to){ + sdp_context_set_user_pointer(call->sdpctx,(void*)call); + call->state=LCStateInit; + call->start_time=time(NULL); + call->log=linphone_call_log_new(call, from, to); + linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE); +} + +void linphone_call_init_media_params(LinphoneCall *call){ + memset(&call->audio_params,0,sizeof(call->audio_params)); + memset(&call->video_params,0,sizeof(call->video_params)); +} + +static void discover_mtu(LinphoneCore *lc, const char *remote){ + int mtu; + if (lc->net_conf.mtu==0 ){ + /*attempt to discover mtu*/ + mtu=ms_discover_mtu(remote); + if (mtu>0){ + ms_set_mtu(mtu); + ms_message("Discovered mtu is %i, RTP payload max size is %i", + mtu, ms_get_payload_max_size()); + } + } +} + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const osip_from_t *from, const osip_to_t *to) +{ + LinphoneCall *call=ms_new0(LinphoneCall,1); + char localip[LINPHONE_IPADDR_SIZE]; + char *fromstr=NULL,*tostr=NULL; + call->dir=LinphoneCallOutgoing; + call->cid=-1; + call->did=-1; + call->tid=-1; + call->core=lc; + linphone_core_get_local_ip(lc,to->url->host,localip); + call->sdpctx=sdp_handler_create_context(&linphone_sdphandler,localip,from->url->username,NULL); + osip_from_to_str(from,&fromstr); + osip_to_to_str(to,&tostr); + linphone_call_init_common(call,fromstr,tostr); + discover_mtu(lc,to->url->host); + return call; +} + + +LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const char *from, const char *to, int cid, int did, int tid) +{ + char localip[LINPHONE_IPADDR_SIZE]; + LinphoneCall *call=ms_new0(LinphoneCall,1); + osip_from_t *me= linphone_core_get_primary_contact_parsed(lc); + osip_from_t *from_url=NULL; + call->dir=LinphoneCallIncoming; + call->cid=cid; + call->did=did; + call->tid=tid; + call->core=lc; + osip_from_init(&from_url); + osip_from_parse(from_url, from); + linphone_core_get_local_ip(lc,from_url->url->host,localip); + call->sdpctx=sdp_handler_create_context(&linphone_sdphandler,localip,me->url->username,NULL); + linphone_call_init_common(call, osip_strdup(from), osip_strdup(to)); + discover_mtu(lc,from_url->url->host); + osip_from_free(me); + osip_from_free(from_url); + return call; +} + +void linphone_call_destroy(LinphoneCall *obj) +{ + linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); + linphone_call_log_completed(obj->log,obj); + if (obj->profile!=NULL && obj->profile!=obj->core->local_profile) rtp_profile_destroy(obj->profile); + if (obj->sdpctx!=NULL) sdp_context_free(obj->sdpctx); + ms_free(obj); +} + +/*prevent a gcc bug with %c*/ +static size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm){ + return strftime(s, max, fmt, tm); +} + +LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, char *from, char *to){ + LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1); + struct tm loctime; + cl->dir=call->dir; +#ifdef WIN32 + loctime=*localtime(&call->start_time); +#else + localtime_r(&call->start_time,&loctime); +#endif + my_strftime(cl->start_date,sizeof(cl->start_date),"%c",&loctime); + cl->from=from; + cl->to=to; + return cl; +} +void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){ + LinphoneCore *lc=call->core; + calllog->duration=time(NULL)-call->start_time; + switch(call->state){ + case LCStateInit: + calllog->status=LinphoneCallAborted; + break; + case LCStateRinging: + if (calllog->dir==LinphoneCallIncoming){ + char *info; + calllog->status=LinphoneCallMissed; + lc->missed_calls++; + info=ortp_strdup_printf(_("You have missed %i call(s)."),lc->missed_calls); + lc->vtable.display_status(lc,info); + ms_free(info); + } + else calllog->status=LinphoneCallAborted; + break; + case LCStateAVRunning: + calllog->status=LinphoneCallSuccess; + break; + } + lc->call_logs=ms_list_append(lc->call_logs,(void *)calllog); + if (ms_list_size(lc->call_logs)>lc->max_call_logs){ + MSList *elem; + elem=lc->call_logs; + linphone_call_log_destroy((LinphoneCallLog*)elem->data); + lc->call_logs=ms_list_remove_link(lc->call_logs,elem); + } + if (lc->vtable.call_log_updated!=NULL){ + lc->vtable.call_log_updated(lc,calllog); + } +} + +char * linphone_call_log_to_str(LinphoneCallLog *cl){ + char *status; + switch(cl->status){ + case LinphoneCallAborted: + status=_("aborted"); + break; + case LinphoneCallSuccess: + status=_("completed"); + break; + case LinphoneCallMissed: + status=_("missed"); + break; + default: + status="unknown"; + } + return ortp_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"), + (cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"), + cl->start_date, + cl->from, + cl->to, + status, + cl->duration/60, + cl->duration%60); +} + +void linphone_call_log_destroy(LinphoneCallLog *cl){ + if (cl->from!=NULL) osip_free(cl->from); + if (cl->to!=NULL) osip_free(cl->to); + ms_free(cl); +} + +void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){ + int ortp_level=ORTP_DEBUG; + switch(level){ + case OSIP_INFO1: + case OSIP_INFO2: + case OSIP_INFO3: + case OSIP_INFO4: + ortp_level=ORTP_MESSAGE; + break; + case OSIP_WARNING: + ortp_level=ORTP_WARNING; + break; + case OSIP_ERROR: + case OSIP_BUG: + ortp_level=ORTP_ERROR; + break; + case OSIP_FATAL: + ortp_level=ORTP_FATAL; + break; + case END_TRACE_LEVEL: + break; + } + if (ortp_log_level_enabled(level)){ + int len=strlen(chfr); + char *chfrdup=ortp_strdup(chfr); + /*need to remove endline*/ + if (len>1){ + if (chfrdup[len-1]=='\n') + chfrdup[len-1]='\0'; + if (chfrdup[len-2]=='\r') + chfrdup[len-2]='\0'; + } + ortp_logv(ortp_level,chfrdup,ap); + ortp_free(chfrdup); + } +} + + +void linphone_core_enable_logs(FILE *file){ + if (file==NULL) file=stdout; + ortp_set_log_file(file); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); +} + +void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); + ortp_set_log_handler(logfunc); +} + +void linphone_core_disable_logs(){ + int tl; + for (tl=0;tl<=OSIP_INFO4;tl++) osip_trace_disable_level(tl); + ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); +} + + +void +net_config_read (LinphoneCore *lc) +{ + int tmp; + const char *tmpstr; + LpConfig *config=lc->config; + + tmp=lp_config_get_int(config,"net","download_bw",0); + linphone_core_set_download_bandwidth(lc,tmp); + tmp=lp_config_get_int(config,"net","upload_bw",0); + linphone_core_set_upload_bandwidth(lc,tmp); + linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL)); + tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL); + if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL; + linphone_core_set_nat_address(lc,tmpstr); + tmp=lp_config_get_int(lc->config,"net","firewall_policy",0); + linphone_core_set_firewall_policy(lc,tmp); + tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0); + lc->net_conf.nat_sdp_only=tmp; + tmp=lp_config_get_int(lc->config,"net","mtu",0); + linphone_core_set_mtu(lc,tmp); +} + + +void sound_config_read(LinphoneCore *lc) +{ + /*int tmp;*/ + const char *tmpbuf; + const char *devid; + const MSList *elem; + const char **devices; + int ndev; + int i; +#ifndef WIN32 + /*alsadev let the user use custom alsa device within linphone*/ + devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); + if (devid){ + MSSndCard *card=ms_alsa_card_new_custom(devid,devid); + ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + } +#endif + /* retrieve all sound devices */ + elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get()); + ndev=ms_list_size(elem); + devices=ms_malloc((ndev+1)*sizeof(const char *)); + for (i=0;elem!=NULL;elem=elem->next,i++){ + devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data); + } + devices[ndev]=NULL; + lc->sound_conf.cards=devices; + devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL); + linphone_core_set_playback_device(lc,devid); + + devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL); + linphone_core_set_ringer_device(lc,devid); + + devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL); + linphone_core_set_capture_device(lc,devid); + +/* + tmp=lp_config_get_int(lc->config,"sound","play_lev",80); + linphone_core_set_play_level(lc,tmp); + tmp=lp_config_get_int(lc->config,"sound","ring_lev",80); + linphone_core_set_ring_level(lc,tmp); + tmp=lp_config_get_int(lc->config,"sound","rec_lev",80); + linphone_core_set_rec_level(lc,tmp); + tmpbuf=lp_config_get_string(lc->config,"sound","source","m"); + linphone_core_set_sound_source(lc,tmpbuf[0]); +*/ + + tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING; + tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf); + if (access(tmpbuf,F_OK)==-1) { + tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING; + } + if (strstr(tmpbuf,".wav")==NULL){ + /* it currently uses old sound files, so replace them */ + tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING; + } + + linphone_core_set_ring(lc,tmpbuf); + + tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING_FR; + tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf); + if (access(tmpbuf,F_OK)==-1){ + tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING_FR; + } + if (strstr(tmpbuf,".wav")==NULL){ + /* it currently uses old sound files, so replace them */ + tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING_FR; + } + linphone_core_set_ringback(lc,0); + check_sound_device(lc); + lc->sound_conf.latency=0; + + linphone_core_enable_echo_cancelation(lc, + lp_config_get_int(lc->config,"sound","echocancelation",0)); +} + +void sip_config_read(LinphoneCore *lc) +{ + char *contact; + const char *tmpstr; + int port; + int i,tmp; + int ipv6; + port=lp_config_get_int(lc->config,"sip","use_info",0); + linphone_core_set_use_info_for_dtmf(lc,port); + + ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1); + if (ipv6==-1){ + ipv6=0; + if (host_has_ipv6_network()){ + lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6")); + } + } + linphone_core_enable_ipv6(lc,ipv6); + port=lp_config_get_int(lc->config,"sip","sip_port",5060); + linphone_core_set_sip_port(lc,port); + + tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL); + if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) { + char *hostname=getenv("HOST"); + char *username=getenv("USER"); + if (hostname==NULL) hostname=getenv("HOSTNAME"); + if (hostname==NULL) + hostname="unknown-host"; + if (username==NULL){ + username="toto"; + } + contact=ortp_strdup_printf("sip:%s@%s",username,hostname); + linphone_core_set_primary_contact(lc,contact); + ms_free(contact); + } + + tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); + linphone_core_set_guess_hostname(lc,tmp); + + + tmp=lp_config_get_int(lc->config,"sip","inc_timeout",15); + linphone_core_set_inc_timeout(lc,tmp); + + /* get proxies config */ + for(i=0;; i++){ + LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i); + if (cfg!=NULL){ + linphone_core_add_proxy_config(lc,cfg); + }else{ + break; + } + } + /* get the default proxy */ + tmp=lp_config_get_int(lc->config,"sip","default_proxy",-1); + linphone_core_set_default_proxy_index(lc,tmp); + + /* read authentication information */ + for(i=0;; i++){ + LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i); + if (ai!=NULL){ + linphone_core_add_auth_info(lc,ai); + }else{ + break; + } + } + /*for test*/ + lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0); + +} + +void rtp_config_read(LinphoneCore *lc) +{ + int port; + int jitt_comp; + int nortp_timeout; + port=lp_config_get_int(lc->config,"rtp","audio_rtp_port",7078); + linphone_core_set_audio_port(lc,port); + + port=lp_config_get_int(lc->config,"rtp","video_rtp_port",9078); + if (port==0) port=9078; + linphone_core_set_video_port(lc,port); + + jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60); + linphone_core_set_audio_jittcomp(lc,jitt_comp); + jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60); + nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30); + linphone_core_set_nortp_timeout(lc,nortp_timeout); +} + + +PayloadType * get_codec(LpConfig *config, char* type,int index){ + char codeckey[50]; + const char *mime,*fmtp; + int rate,enabled; + PayloadType *pt; + + snprintf(codeckey,50,"%s_%i",type,index); + mime=lp_config_get_string(config,codeckey,"mime",NULL); + if (mime==NULL || strlen(mime)==0 ) return NULL; + + pt=payload_type_new(); + pt->mime_type=ms_strdup(mime); + + rate=lp_config_get_int(config,codeckey,"rate",8000); + pt->clock_rate=rate; + fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL); + if (fmtp) pt->recv_fmtp=ms_strdup(fmtp); + enabled=lp_config_get_int(config,codeckey,"enabled",1); + if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; + //ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate); + return pt; +} + +void codecs_config_read(LinphoneCore *lc) +{ + int i; + PayloadType *pt; + MSList *audio_codecs=NULL; + MSList *video_codecs=NULL; + for (i=0;;i++){ + pt=get_codec(lc->config,"audio_codec",i); + if (pt==NULL) break; + audio_codecs=ms_list_append(audio_codecs,(void *)pt); + } + for (i=0;;i++){ + pt=get_codec(lc->config,"video_codec",i); + if (pt==NULL) break; + video_codecs=ms_list_append(video_codecs,(void *)pt); + } + linphone_core_set_audio_codecs(lc,audio_codecs); + linphone_core_set_video_codecs(lc,video_codecs); + linphone_core_setup_local_rtp_profile(lc); +} + +void video_config_read(LinphoneCore *lc) +{ + int capture, display; + int enabled; + const char *str; + int ndev; + const char **devices; + const MSList *elem; + int i; + + /* retrieve all video devices */ + elem=ms_web_cam_manager_get_list(ms_web_cam_manager_get()); + ndev=ms_list_size(elem); + devices=ms_malloc((ndev+1)*sizeof(const char *)); + for (i=0;elem!=NULL;elem=elem->next,i++){ + devices[i]=ms_web_cam_get_string_id((MSWebCam *)elem->data); + } + devices[ndev]=NULL; + lc->video_conf.cams=devices; + + str=lp_config_get_string(lc->config,"video","device",NULL); + if (str && str[0]==0) str=NULL; + linphone_core_set_video_device(lc,str); + + enabled=lp_config_get_int(lc->config,"video","enabled",1); + capture=lp_config_get_int(lc->config,"video","capture",enabled); + display=lp_config_get_int(lc->config,"video","display",enabled); +#ifdef VIDEO_ENABLED + linphone_core_enable_video(lc,capture,display); +#endif +} + +void ui_config_read(LinphoneCore *lc) +{ + LinphoneFriend *lf; + int i; + for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){ + linphone_core_add_friend(lc,lf); + } + +} + +void autoreplier_config_init(LinphoneCore *lc) +{ + autoreplier_config_t *config=&lc->autoreplier_conf; + config->enabled=lp_config_get_int(lc->config,"autoreplier","enabled",0); + config->after_seconds=lp_config_get_int(lc->config,"autoreplier","after_seconds",6); + config->max_users=lp_config_get_int(lc->config,"autoreplier","max_users",1); + config->max_rec_time=lp_config_get_int(lc->config,"autoreplier","max_rec_time",60); + config->max_rec_msg=lp_config_get_int(lc->config,"autoreplier","max_rec_msg",10); + config->message=lp_config_get_string(lc->config,"autoreplier","message",NULL); +} + +void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ + lc->net_conf.download_bw=bw; + if (bw==0){ /*infinite*/ + lc->dw_audio_bw=-1; + lc->dw_video_bw=-1; + }else { + if (bw>=256){ + lc->dw_audio_bw=80; + }else if (bw>=128){ + if (linphone_core_video_enabled(lc)) + lc->dw_audio_bw=30; + else + lc->dw_audio_bw=bw; + }else{ + lc->dw_audio_bw=bw; + } + lc->dw_video_bw=bw-lc->dw_audio_bw; + } +} + +void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){ + lc->net_conf.upload_bw=bw; + if (bw==0){ /*infinite*/ + lc->up_audio_bw=-1; + lc->up_video_bw=-1; + return; + }else if (bw>=128){ + if (linphone_core_video_enabled(lc)) + lc->up_audio_bw=lc->audio_bw; + else + lc->up_audio_bw=bw; + }else{ + lc->up_audio_bw=bw; + } + lc->up_video_bw=bw-lc->up_audio_bw-10;/*-10: security margin*/ +} + +int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ + return lc->net_conf.download_bw; +} + +int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ + return lc->net_conf.upload_bw; +} + +const char * linphone_core_get_version(void){ + return liblinphone_version; +} + +#ifdef VIDEO_ENABLED + +static PayloadType * payload_type_h264_packetization_mode_1=NULL; +static PayloadType * linphone_h263_1998=NULL; +static PayloadType * linphone_mp4v_es=NULL; +#endif + +void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, void * userdata) +{ + memset (lc, 0, sizeof (LinphoneCore)); + lc->data=userdata; + + memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable)); + + gstate_initialize(); + gstate_new_state(lc, GSTATE_POWER_STARTUP, NULL); + + ortp_init(); + rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015); + rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb); + rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb); + rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc); + rtp_profile_set_payload(&av_profile,116,&payload_type_truespeech); + rtp_profile_set_payload(&av_profile,101,&payload_type_telephone_event); + +#ifdef VIDEO_ENABLED + rtp_profile_set_payload(&av_profile,97,&payload_type_theora); + + linphone_h263_1998=payload_type_clone(&payload_type_h263_1998); + payload_type_set_recv_fmtp(linphone_h263_1998,"CIF=1;QCIF=1"); + rtp_profile_set_payload(&av_profile,98,linphone_h263_1998); + + linphone_mp4v_es=payload_type_clone(&payload_type_mp4v); + payload_type_set_recv_fmtp(linphone_mp4v_es,"profile-level-id=3"); + rtp_profile_set_payload(&av_profile,99,linphone_mp4v_es); + rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow); + payload_type_h264_packetization_mode_1=payload_type_clone(&payload_type_h264); + payload_type_set_recv_fmtp(payload_type_h264_packetization_mode_1,"packetization-mode=1"); + rtp_profile_set_payload(&av_profile,103,payload_type_h264_packetization_mode_1); + rtp_profile_set_payload(&av_profile,102,&payload_type_h264); +#endif + + ms_init(); + + lc->config=lp_config_new(config_path); + +#ifdef VINCENT_MAURY_RSVP + /* default qos parameters : rsvp on, rpc off */ + lc->rsvp_enable = 1; + lc->rpc_enable = 0; +#endif + sound_config_read(lc); + net_config_read(lc); + rtp_config_read(lc); + codecs_config_read(lc); + sip_config_read(lc); /* this will start eXosip*/ + video_config_read(lc); + //autoreplier_config_init(&lc->autoreplier_conf); + lc->prev_mode=LINPHONE_STATUS_ONLINE; + lc->presence_mode=LINPHONE_STATUS_ONLINE; + lc->max_call_logs=15; + ui_config_read(lc); + ms_mutex_init(&lc->lock,NULL); + lc->vtable.display_status(lc,_("Ready")); + gstate_new_state(lc, GSTATE_POWER_ON, NULL); +} + +LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, + const char *config_path, void * userdata) +{ + LinphoneCore *core=ms_new(LinphoneCore,1); + linphone_core_init(core,vtable,config_path,userdata); + return core; +} + +const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc) +{ + return lc->codecs_conf.audio_codecs; +} + +const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc) +{ + return lc->codecs_conf.video_codecs; +} + +int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) +{ + osip_from_t *ctt=NULL; + osip_from_init(&ctt); + if (osip_from_parse(ctt,contact)!=0){ + ms_error("Bad contact url: %s",contact); + osip_from_free(ctt); + return -1; + } + if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact); + lc->sip_conf.contact=ms_strdup(contact); + if (lc->sip_conf.guessed_contact!=NULL){ + ms_free(lc->sip_conf.guessed_contact); + lc->sip_conf.guessed_contact=NULL; + } + osip_from_free(ctt); + return 0; +} + +static bool_t stun_get_localip(LinphoneCore *lc, char *result, int *port){ + const char *server=linphone_core_get_stun_server(lc); + StunAddress4 addr; + StunAddress4 mapped; + StunAddress4 changed; + if (server!=NULL){ + if (stunParseServerName((char*)server,&addr)){ + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Stun lookup in progress...")); + if (stunTest(&addr,1,TRUE,NULL,&mapped,&changed)==0){ + struct in_addr inaddr; + char *tmp; + inaddr.s_addr=ntohl(mapped.addr); + tmp=inet_ntoa(inaddr); + *port=ntohs(mapped.port); + strncpy(result,tmp,LINPHONE_IPADDR_SIZE); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Stun lookup done...")); + ms_message("Stun server says we have address %s:i",result,*port); + return TRUE; + }else{ + ms_warning("stun lookup failed."); + } + }else{ + ms_warning("Fail to resolv or parse %s",server); + } + } + return FALSE; +} + +/*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ +void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ + if (lc->apply_nat_settings){ + apply_nat_settings(lc); + lc->apply_nat_settings=FALSE; + } + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){ + strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE); + return; + } + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN) { + if (lc->sip_conf.ipv6_enabled){ + ms_warning("stun support is not implemented for ipv6"); + }else{ + int mport=0; + ms_message("doing stun lookup for local address..."); + if (stun_get_localip(lc,result,&mport)){ + if (!lc->net_conf.nat_sdp_only) + eXosip_masquerade_contact(result,mport); + return; + } + ms_warning("stun lookup failed, falling back to a local interface..."); + } + + } + if (eXosip_guess_localip(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE)<0){ + /*default to something */ + strncpy(result,lc->sip_conf.ipv6_enabled ? "::1" : "127.0.0.1",LINPHONE_IPADDR_SIZE); + ms_error("Could not find default routable ip address !"); + } + eXosip_masquerade_contact("",0); +} + +const char *linphone_core_get_primary_contact(LinphoneCore *lc) +{ + char *identity; + char tmp[LINPHONE_IPADDR_SIZE]; + if (lc->sip_conf.guess_hostname){ + if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){ + char *guessed=NULL; + osip_from_t *url; + if (lc->sip_conf.guessed_contact!=NULL){ + ms_free(lc->sip_conf.guessed_contact); + lc->sip_conf.guessed_contact=NULL; + } + + osip_from_init(&url); + if (osip_from_parse(url,lc->sip_conf.contact)==0){ + + }else ms_error("Could not parse identity contact !"); + linphone_core_get_local_ip(lc, NULL, tmp); + if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ + ms_warning("Local loopback network only !"); + lc->sip_conf.loopback_only=TRUE; + }else lc->sip_conf.loopback_only=FALSE; + osip_free(url->url->host); + url->url->host=osip_strdup(tmp); + if (url->url->port!=NULL){ + osip_free(url->url->port); + url->url->port=NULL; + } + if (lc->sip_conf.sip_port!=5060){ + url->url->port=ortp_strdup_printf("%i",lc->sip_conf.sip_port); + } + osip_from_to_str(url,&guessed); + lc->sip_conf.guessed_contact=guessed; + + osip_from_free(url); + + } + identity=lc->sip_conf.guessed_contact; + }else{ + identity=lc->sip_conf.contact; + } + return identity; +} + +void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){ + lc->sip_conf.guess_hostname=val; +} + +bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){ + return lc->sip_conf.guess_hostname; +} + +osip_from_t *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){ + int err; + osip_from_t *contact; + osip_from_init(&contact); + err=osip_from_parse(contact,linphone_core_get_primary_contact(lc)); + if (err<0) { + osip_from_free(contact); + return NULL; + } + return contact; +} + +int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs) +{ + if (lc->codecs_conf.audio_codecs!=NULL) ms_list_free(lc->codecs_conf.audio_codecs); + lc->codecs_conf.audio_codecs=codecs; + return 0; +} + +int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs) +{ + if (lc->codecs_conf.video_codecs!=NULL) ms_list_free(lc->codecs_conf.video_codecs); + lc->codecs_conf.video_codecs=codecs; + return 0; +} + +const MSList * linphone_core_get_friend_list(LinphoneCore *lc) +{ + return lc->friends; +} + +int linphone_core_get_audio_jittcomp(LinphoneCore *lc) +{ + return lc->rtp_conf.audio_jitt_comp; +} + +int linphone_core_get_audio_port(const LinphoneCore *lc) +{ + return lc->rtp_conf.audio_rtp_port; +} + +int linphone_core_get_video_port(const LinphoneCore *lc){ + return lc->rtp_conf.video_rtp_port; +} + +int linphone_core_get_nortp_timeout(const LinphoneCore *lc){ + return lc->rtp_conf.nortp_timeout; +} + +void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value) +{ + lc->rtp_conf.audio_jitt_comp=value; +} + +void linphone_core_set_audio_port(LinphoneCore *lc, int port) +{ + lc->rtp_conf.audio_rtp_port=port; +} + +void linphone_core_set_video_port(LinphoneCore *lc, int port){ + lc->rtp_conf.video_rtp_port=port; +} + +void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){ + lc->rtp_conf.nortp_timeout=nortp_timeout; +} + +bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) +{ + return lc->sip_conf.use_info; +} + +void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) +{ + lc->sip_conf.use_info=use_info; +} + +int linphone_core_get_sip_port(LinphoneCore *lc) +{ + return lc->sip_conf.sip_port; +} + +static bool_t exosip_running=FALSE; + +void linphone_core_set_sip_port(LinphoneCore *lc,int port) +{ + const char *anyaddr; + char ua_string[256]; + int err=0; + if (port==lc->sip_conf.sip_port) return; + lc->sip_conf.sip_port=port; + if (exosip_running) eXosip_quit(); + eXosip_init(); + eXosip_enable_ipv6(lc->sip_conf.ipv6_enabled); + if (lc->sip_conf.ipv6_enabled) + anyaddr="::0"; + else + anyaddr="0.0.0.0"; + err=eXosip_listen_addr (IPPROTO_UDP, anyaddr, port, + lc->sip_conf.ipv6_enabled ? PF_INET6 : PF_INET, 0); + if (err<0){ + char *msg=ortp_strdup_printf("UDP port %i seems already in use ! Cannot initialize.",port); + ms_warning(msg); + lc->vtable.display_warning(lc,msg); + ms_free(msg); + return; + } +#ifdef VINCENT_MAURY_RSVP + /* tell exosip the qos settings according to default linphone parameters */ + eXosip_set_rsvp_mode (lc->rsvp_enable); + eXosip_set_rpc_mode (lc->rpc_enable); +#endif + snprintf(ua_string,sizeof(ua_string),"Linphone/%s (eXosip2/%s)",LINPHONE_VERSION, +#ifdef HAVE_EXOSIP_GET_VERSION + eXosip_get_version() +#else + "unknown" +#endif +); + eXosip_set_user_agent(ua_string); + exosip_running=TRUE; +} + +bool_t linphone_core_ipv6_enabled(LinphoneCore *lc){ + return lc->sip_conf.ipv6_enabled; +} +void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ + if (lc->sip_conf.ipv6_enabled!=val){ + lc->sip_conf.ipv6_enabled=val; + if (exosip_running){ + /* we need to restart eXosip */ + linphone_core_set_sip_port(lc, lc->sip_conf.sip_port); + } + } +} + +static void display_bandwidth(RtpSession *as, RtpSession *vs){ + ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec", + (as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0, + (as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0, + (vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0, + (vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0); +} + +static void linphone_core_disconnected(LinphoneCore *lc){ + lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); + linphone_core_terminate_call(lc,NULL); +} + +void linphone_core_iterate(LinphoneCore *lc) +{ + eXosip_event_t *ev; + bool_t disconnected=FALSE; + int disconnect_timeout = linphone_core_get_nortp_timeout(lc); + if (lc->preview_finished){ + lc->preview_finished=0; + ring_stop(lc->ringstream); + lc->ringstream=NULL; + lc_callback_obj_invoke(&lc->preview_finished_cb,lc); + } + + if (exosip_running){ + while((ev=eXosip_event_wait(0,0))!=NULL){ + linphone_core_process_event(lc,ev); + } + if (lc->automatic_action==0) eXosip_automatic_action(); + } + if (lc->call!=NULL){ + LinphoneCall *call=lc->call; + int elapsed; + time_t curtime=time(NULL); + if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){ + elapsed=curtime-call->start_time; + ms_message("incoming call ringing for %i seconds",elapsed); + if (elapsed>lc->sip_conf.inc_timeout){ + linphone_core_terminate_call(lc,NULL); + } + }else if (call->state==LCStateAVRunning){ + elapsed=curtime-lc->prevtime; + if (elapsed>=1){ + RtpSession *as=NULL,*vs=NULL; + lc->prevtime=curtime; + if (lc->audiostream!=NULL) + as=lc->audiostream->session; + if (lc->videostream!=NULL) + vs=lc->videostream->session; + display_bandwidth(as,vs); + } +#ifdef VIDEO_ENABLED + if (lc->videostream!=NULL) + video_stream_iterate(lc->videostream); +#endif + if (lc->audiostream!=NULL && disconnect_timeout>0) + disconnected=!audio_stream_alive(lc->audiostream,disconnect_timeout); + } + } + if (linphone_core_video_preview_enabled(lc)){ + if (lc->previewstream==NULL) + toggle_video_preview(lc,TRUE); +#ifdef VIDEO_ENABLED + else video_stream_iterate(lc->previewstream); +#endif + }else{ + if (lc->previewstream!=NULL) + toggle_video_preview(lc,FALSE); + } + if (disconnected) + linphone_core_disconnected(lc); +} + + +bool_t linphone_core_is_in_main_thread(LinphoneCore *lc){ + return TRUE; +} + +static osip_to_t *osip_to_create(const char *to){ + osip_to_t *ret; + osip_to_init(&ret); + if (osip_to_parse(ret,to)<0){ + osip_to_free(ret); + return NULL; + } + return ret; +} + +bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, char **real_url, osip_to_t **real_parsed_url, char **route){ + enum_lookup_res_t *enumres=NULL; + osip_to_t *parsed_url=NULL; + char *enum_domain=NULL; + LinphoneProxyConfig *proxy; + char *tmpurl; + const char *tmproute; + if (real_url!=NULL) *real_url=NULL; + if (real_parsed_url!=NULL) *real_parsed_url=NULL; + *route=NULL; + tmproute=linphone_core_get_route(lc); + + if (is_enum(url,&enum_domain)){ + lc->vtable.display_status(lc,_("Looking for telephone number destination...")); + if (enum_lookup(enum_domain,&enumres)<0){ + lc->vtable.display_status(lc,_("Could not resolve this number.")); + ms_free(enum_domain); + return FALSE; + } + ms_free(enum_domain); + tmpurl=enumres->sip_address[0]; + if (real_url!=NULL) *real_url=ms_strdup(tmpurl); + if (real_parsed_url!=NULL) *real_parsed_url=osip_to_create(tmpurl); + enum_lookup_res_free(enumres); + if (tmproute) *route=ms_strdup(tmproute); + return TRUE; + } + /* check if we have a "sip:" */ + if (strstr(url,"sip:")==NULL){ + /* this doesn't look like a true sip uri */ + proxy=lc->default_proxy; + if (proxy!=NULL){ + /* append the proxy domain suffix */ + osip_from_t *uri; + char *sipaddr; + const char *identity=linphone_proxy_config_get_identity(proxy); + osip_from_init(&uri); + if (osip_from_parse(uri,identity)<0){ + osip_from_free(uri); + return FALSE; + } + sipaddr=ortp_strdup_printf("sip:%s@%s",url,uri->url->host); + if (real_parsed_url!=NULL) *real_parsed_url=osip_to_create(sipaddr); + if (real_url!=NULL) *real_url=sipaddr; + else ms_free(sipaddr); + /*if the prompted uri was auto-suffixed with proxy domain, + then automatically set a route so that the request goes + through the proxy*/ + if (tmproute==NULL){ + osip_route_t *rt=NULL; + char *rtstr=NULL; + osip_route_init(&rt); + if (osip_route_parse(rt,linphone_proxy_config_get_addr(proxy))==0){ + osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); + osip_route_to_str(rt,&rtstr); + *route=ms_strdup(rtstr); + osip_free(rtstr); + } + ms_message("setting automatically a route to %s",*route); + } + else *route=ms_strdup(tmproute); + return TRUE; + } + } + parsed_url=osip_to_create(url); + if (parsed_url!=NULL){ + if (real_url!=NULL) *real_url=ms_strdup(url); + if (real_parsed_url!=NULL) *real_parsed_url=parsed_url; + else osip_to_free(parsed_url); + if (tmproute) *route=ms_strdup(tmproute); + return TRUE; + } + /* else we could not do anything with url given by user, so display an error */ + if (lc->vtable.display_warning!=NULL){ + lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain")); + } + return FALSE; +} + +const char * linphone_core_get_identity(LinphoneCore *lc){ + LinphoneProxyConfig *proxy=NULL; + const char *from; + linphone_core_get_default_proxy(lc,&proxy); + if (proxy!=NULL) { + from=linphone_proxy_config_get_identity(proxy); + }else from=linphone_core_get_primary_contact(lc); + return from; +} + +const char * linphone_core_get_route(LinphoneCore *lc){ + LinphoneProxyConfig *proxy=NULL; + const char *route=NULL; + linphone_core_get_default_proxy(lc,&proxy); + if (proxy!=NULL) { + route=linphone_proxy_config_get_route(proxy); + } + return route; +} + +void linphone_set_sdp(osip_message_t *sip, const char *sdpmesg){ + int sdplen=strlen(sdpmesg); + char clen[10]; + snprintf(clen,sizeof(clen),"%i",sdplen); + osip_message_set_body(sip,sdpmesg,sdplen); + osip_message_set_content_type(sip,"application/sdp"); + osip_message_set_content_length(sip,clen); +} + +int linphone_core_invite(LinphoneCore *lc, const char *url) +{ + char *barmsg; + int err=0; + char *sdpmesg=NULL; + char *route=NULL; + const char *from=NULL; + osip_message_t *invite=NULL; + sdp_context_t *ctx=NULL; + LinphoneProxyConfig *proxy=NULL; + osip_from_t *parsed_url2=NULL; + osip_to_t *real_parsed_url=NULL; + char *real_url=NULL; + + if (lc->call!=NULL){ + lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !")); + return -1; + } + + gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url); + linphone_core_get_default_proxy(lc,&proxy); + if (!linphone_core_interpret_url(lc,url,&real_url,&real_parsed_url,&route)){ + /* bad url */ + gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); + return -1; + } + barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); + lc->vtable.display_status(lc,barmsg); + ms_free(barmsg); + if (proxy!=NULL) { + from=linphone_proxy_config_get_identity(proxy); + + } + /* if no proxy or no identity defined for this proxy, default to primary contact*/ + if (from==NULL) from=linphone_core_get_primary_contact(lc); + + err=eXosip_call_build_initial_invite(&invite,real_url,from, + route,"Phone call"); + + if (err<0){ + ms_warning("Could not build initial invite"); + goto end; + } + + /* make sdp message */ + + osip_from_init(&parsed_url2); + osip_from_parse(parsed_url2,from); + + lc->call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); + if (!lc->sip_conf.sdp_200_ack){ + ctx=lc->call->sdpctx; + lc->call->profile=lc->local_profile; + sdpmesg=sdp_context_get_offer(ctx); + linphone_set_sdp(invite,sdpmesg); + linphone_core_init_media_streams(lc); + } + eXosip_lock(); + err=eXosip_call_send_initial_invite(invite); + lc->call->cid=err; + eXosip_unlock(); + if (err<0){ + ms_warning("Could not initiate call."); + lc->vtable.display_status(lc,_("could not call")); + linphone_call_destroy(lc->call); + lc->call=NULL; + linphone_core_stop_media_streams(lc); + } + + goto end; + end: + if (real_url!=NULL) ms_free(real_url); + if (real_parsed_url!=NULL) osip_to_free(real_parsed_url); + if (parsed_url2!=NULL) osip_from_free(parsed_url2); + if (err<0) + gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); + if (route!=NULL) ms_free(route); + return (err<0) ? -1 : 0; +} + +int linphone_core_refer(LinphoneCore *lc, const char *url) +{ + char *real_url=NULL; + osip_to_t *real_parsed_url=NULL; + LinphoneCall *call; + osip_message_t *msg=NULL; + char *route; + if (!linphone_core_interpret_url(lc,url,&real_url,&real_parsed_url, &route)){ + /* bad url */ + return -1; + } + if (route!=NULL) ms_free(route); + call=lc->call; + if (call==NULL){ + ms_warning("No established call to refer."); + return -1; + } + lc->call=NULL; + eXosip_call_build_refer(call->did, real_url, &msg); + eXosip_lock(); + eXosip_call_send_request(call->did, msg); + eXosip_unlock(); + return 0; +} + +bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ + if (lc->call!=NULL && lc->call->dir==LinphoneCallIncoming){ + return TRUE; + } + return FALSE; +} + +#ifdef VINCENT_MAURY_RSVP +/* on=1 for RPC_ENABLE=1...*/ +int linphone_core_set_rpc_mode(LinphoneCore *lc, int on) +{ + if (on==1) + printf("RPC_ENABLE set on\n"); + else + printf("RPC_ENABLE set off\n"); + lc->rpc_enable = (on==1); + /* need to tell eXosip the new setting */ + if (eXosip_set_rpc_mode (lc->rpc_enable)!=0) + return -1; + return 0; +} + +/* on=1 for RSVP_ENABLE=1...*/ +int linphone_core_set_rsvp_mode(LinphoneCore *lc, int on) +{ + if (on==1) + printf("RSVP_ENABLE set on\n"); + else + printf("RSVP_ENABLE set off\n"); + lc->rsvp_enable = (on==1); + /* need to tell eXosip the new setting */ + if (eXosip_set_rsvp_mode (lc->rsvp_enable)!=0) + return -1; + return 0; +} + +/* answer : 1 for yes, 0 for no */ +int linphone_core_change_qos(LinphoneCore *lc, int answer) +{ + char *sdpmesg; + if (lc->call==NULL){ + return -1; + } + + if (lc->rsvp_enable && answer==1) + { + /* answer is yes, local setting is with qos, so + * the user chose to continue with no qos ! */ + /* so switch in normal mode : ring and 180 */ + lc->rsvp_enable = 0; /* no more rsvp */ + eXosip_set_rsvp_mode (lc->rsvp_enable); + /* send 180 */ + eXosip_lock(); + eXosip_answer_call(lc->call->did,180,NULL); + eXosip_unlock(); + /* play the ring */ + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring, + 2000,ms_snd_card_manager_get_card(ms_snd_card_manager_get(),lc->sound_conf.ring_sndcard)); + } + else if (!lc->rsvp_enable && answer==1) + { + /* switch to QoS mode on : answer 183 session progress */ + lc->rsvp_enable = 1; + eXosip_set_rsvp_mode (lc->rsvp_enable); + /* take the sdp already computed, see osipuacb.c */ + sdpmesg=lc->call->sdpctx->answerstr; + eXosip_lock(); + eXosip_answer_call_with_body(lc->call->did,183,"application/sdp",sdpmesg); + eXosip_unlock(); + } + else + { + /* decline offer (603) */ + linphone_core_terminate_call(lc, NULL); + } + return 0; +} +#endif + +void linphone_core_init_media_streams(LinphoneCore *lc){ + lc->audiostream=audio_stream_new(linphone_core_get_audio_port(lc),linphone_core_ipv6_enabled(lc)); +#ifdef VIDEO_ENABLED + lc->videostream=video_stream_new(linphone_core_get_video_port(lc),linphone_core_ipv6_enabled(lc)); +#else + lc->videostream=NULL; +#endif +} + +void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ + osip_from_t *me=linphone_core_get_primary_contact_parsed(lc); + const char *tool="linphone-" LINPHONE_VERSION; + /* adjust rtp jitter compensation. It must be at least the latency of the sound card */ + int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp); + char *cname=ortp_strdup_printf("%s@%s",me->url->username,me->url->host); + { + StreamParams *audio_params=&call->audio_params; + if (!lc->use_files){ + MSSndCard *playcard=lc->sound_conf.play_sndcard; + MSSndCard *captcard=lc->sound_conf.capt_sndcard; + if (playcard==NULL) { + ms_warning("No card defined for playback !"); + goto end; + } + if (captcard==NULL) { + ms_warning("No card defined for capture !"); + goto end; + } + if (audio_params->relay_session_id!=NULL) + audio_stream_set_relay_session_id(lc->audiostream,audio_params->relay_session_id); + audio_stream_start_now( + lc->audiostream, + call->profile, + audio_params->remoteaddr, + audio_params->remoteport, + audio_params->remotertcpport, + audio_params->pt, + jitt_comp, + playcard, + captcard, + linphone_core_echo_cancelation_enabled(lc)); + }else{ + audio_stream_start_with_files( + lc->audiostream, + call->profile, + audio_params->remoteaddr, + audio_params->remoteport, + audio_params->remotertcpport, + audio_params->pt, + 100, + lc->play_file, + lc->rec_file); + } + audio_stream_set_rtcp_information(lc->audiostream, cname, tool); + } +#ifdef VIDEO_ENABLED + { + /* shutdown preview */ + if (lc->previewstream!=NULL) { + video_preview_stop(lc->previewstream); + lc->previewstream=NULL; + } + if (lc->video_conf.display || lc->video_conf.capture) { + StreamParams *video_params=&call->video_params; + + if (video_params->remoteport>0){ + if (video_params->relay_session_id!=NULL) + video_stream_set_relay_session_id(lc->videostream,video_params->relay_session_id); + if (lc->video_conf.display && lc->video_conf.capture) + video_stream_start(lc->videostream, + call->profile, video_params->remoteaddr, video_params->remoteport, + video_params->remotertcpport, + video_params->pt, jitt_comp, lc->video_conf.device); + else if (lc->video_conf.display) + video_stream_recv_only_start(lc->videostream, + call->profile, video_params->remoteaddr, video_params->remoteport, + video_params->pt, jitt_comp); + else if (lc->video_conf.capture) + video_stream_send_only_start(lc->videostream, + call->profile, video_params->remoteaddr, video_params->remoteport, + video_params->remotertcpport, + video_params->pt, jitt_comp, lc->video_conf.device); + video_stream_set_rtcp_information(lc->videostream, cname,tool); + } + } + } +#endif + goto end; + end: + ms_free(cname); + osip_from_free(me); + lc->call->state=LCStateAVRunning; +} + +void linphone_core_stop_media_streams(LinphoneCore *lc){ + if (lc->audiostream!=NULL) { + audio_stream_stop(lc->audiostream); + lc->audiostream=NULL; + } +#ifdef VIDEO_ENABLED + if (lc->videostream!=NULL){ + if (lc->video_conf.display && lc->video_conf.capture) + video_stream_stop(lc->videostream); + else if (lc->video_conf.display) + video_stream_recv_only_stop(lc->videostream); + else if (lc->video_conf.capture) + video_stream_send_only_stop(lc->videostream); + lc->videostream=NULL; + } + if (linphone_core_video_preview_enabled(lc)){ + if (lc->previewstream==NULL){ + lc->previewstream=video_preview_start(lc->video_conf.device); + } + } +#endif +} + +int linphone_core_accept_call(LinphoneCore *lc, const char *url) +{ + char *sdpmesg; + osip_message_t *msg=NULL; + LinphoneCall *call=lc->call; + int err; + bool_t offering=FALSE; + + if (call==NULL){ + return -1; + } + + if (lc->call->state==LCStateAVRunning){ + /*call already accepted*/ + return -1; + } + + /*stop ringing */ + if (lc->ringstream!=NULL) { + ms_message("stop ringing"); + ring_stop(lc->ringstream); + ms_message("ring stopped"); + lc->ringstream=NULL; + } + /* sends a 200 OK */ + err=eXosip_call_build_answer(call->tid,200,&msg); + if (err<0 || msg==NULL){ + ms_error("Fail to build answer for call: err=%i",err); + return -1; + } + ms_message("eXosip_call_build_answer done"); + /*if a sdp answer is computed, send it, else send an offer */ + sdpmesg=call->sdpctx->answerstr; + if (sdpmesg==NULL){ + offering=TRUE; + call->profile=lc->local_profile; + ms_message("generating sdp offer"); + sdpmesg=sdp_context_get_offer(call->sdpctx); + + if (sdpmesg==NULL){ + ms_error("fail to generate sdp offer !"); + return -1; + } + ms_message("sdp message generated (sdpmesg=%p):\n%s",sdpmesg,sdpmesg); + linphone_set_sdp(msg,sdpmesg); + ms_message("sdp message attached to SIP answer"); + linphone_core_init_media_streams(lc); + ms_message("init_media_streams done"); + }else{ + linphone_set_sdp(msg,sdpmesg); + } + eXosip_lock(); + ms_message("eXosip_lock() done"); + eXosip_call_send_answer(call->tid,200,msg); + ms_message("SIP answer sent."); + eXosip_unlock(); + lc->vtable.display_status(lc,_("Connected.")); + gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); + + if (!offering) linphone_core_start_media_streams(lc, lc->call); + ms_message("call answered."); + return 0; +} + +int linphone_core_terminate_call(LinphoneCore *lc, const char *url) +{ + LinphoneCall *call=lc->call; + if (call==NULL){ + return -1; + } + lc->call=NULL; + + eXosip_lock(); + eXosip_call_terminate(call->cid,call->did); + eXosip_unlock(); + + /*stop ringing*/ + if (lc->ringstream!=NULL) { + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_core_stop_media_streams(lc); + lc->vtable.display_status(lc,_("Call ended") ); + gstate_new_state(lc, GSTATE_CALL_END, NULL); + linphone_call_destroy(call); + return 0; +} + +bool_t linphone_core_in_call(const LinphoneCore *lc){ + return lc->call!=NULL; +} + +int linphone_core_send_publish(LinphoneCore *lc, + LinphoneOnlineStatus presence_mode) +{ + const MSList *elem; + for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence_mode); + } + return 0; +} + +void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds){ + lc->sip_conf.inc_timeout=seconds; +} + +int linphone_core_get_inc_timeout(LinphoneCore *lc){ + return lc->sip_conf.inc_timeout; +} + +void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, + const char *contact, + LinphoneOnlineStatus presence_mode) +{ + int contactok=-1; + if (minutes_away>0) lc->minutes_away=minutes_away; + if (contact!=NULL) { + osip_from_t *url; + osip_from_init(&url); + contactok=osip_from_parse(url,contact); + if (contactok>=0) { + ms_message("contact url is correct."); + } + osip_from_free(url); + + } + if (contactok>=0){ + if (lc->alt_contact!=NULL) ms_free(lc->alt_contact); + lc->alt_contact=ms_strdup(contact); + } + if (lc->presence_mode!=presence_mode){ + linphone_core_notify_all_friends(lc,presence_mode); + /* + Improve the use of all LINPHONE_STATUS available. + !TODO Do not mix "presence status" with "answer status code".. + Use correct parameter to follow sip_if_match/sip_etag. + */ + linphone_core_send_publish(lc,presence_mode); + } + lc->prev_mode=lc->presence_mode; + lc->presence_mode=presence_mode; + +} + +LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){ + return lc->presence_mode; +} + +/* sound functions */ +int linphone_core_get_play_level(LinphoneCore *lc) +{ + return lc->sound_conf.play_lev; +} +int linphone_core_get_ring_level(LinphoneCore *lc) +{ + return lc->sound_conf.ring_lev; +} +int linphone_core_get_rec_level(LinphoneCore *lc){ + return lc->sound_conf.rec_lev; +} +void linphone_core_set_ring_level(LinphoneCore *lc, int level){ + MSSndCard *sndcard; + lc->sound_conf.ring_lev=level; + sndcard=lc->sound_conf.ring_sndcard; + if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); +} + +void linphone_core_set_play_level(LinphoneCore *lc, int level){ + MSSndCard *sndcard; + lc->sound_conf.play_lev=level; + sndcard=lc->sound_conf.play_sndcard; + if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); +} + +void linphone_core_set_rec_level(LinphoneCore *lc, int level) +{ + MSSndCard *sndcard; + lc->sound_conf.rec_lev=level; + sndcard=lc->sound_conf.capt_sndcard; + if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_CAPTURE,level); +} + +static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap){ + MSSndCard *sndcard=NULL; + if (devid!=NULL){ + sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid); + if (sndcard!=NULL && + (ms_snd_card_get_capabilities(sndcard) & cap)==0 ){ + ms_warning("%s card does not have the %s capability, ignoring.", + devid, + cap==MS_SND_CARD_CAP_CAPTURE ? "capture" : "playback"); + sndcard=NULL; + } + } + if (sndcard==NULL) { + /* get a card that has read+write capabilities */ + sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); + /* otherwise refine to the first card having the right capability*/ + if (sndcard==NULL){ + const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get()); + for(;elem!=NULL;elem=elem->next){ + sndcard=(MSSndCard*)elem->data; + if (ms_snd_card_get_capabilities(sndcard) & cap) break; + } + } + if (sndcard==NULL){/*looks like a bug! take the first one !*/ + const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get()); + sndcard=(MSSndCard*)elem->data; + } + } + if (sndcard==NULL) ms_error("Could not find a suitable soundcard !"); + return sndcard; +} + +int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){ + lc->sound_conf.ring_sndcard=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK); + return 0; +} + +int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){ + lc->sound_conf.play_sndcard=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK); + return 0; +} + +int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){ + lc->sound_conf.capt_sndcard=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE); + return 0; +} + +const char * linphone_core_get_ringer_device(LinphoneCore *lc) +{ + return ms_snd_card_get_string_id(lc->sound_conf.ring_sndcard); +} + +const char * linphone_core_get_playback_device(LinphoneCore *lc) +{ + return ms_snd_card_get_string_id(lc->sound_conf.play_sndcard); +} + +const char * linphone_core_get_capture_device(LinphoneCore *lc) +{ + return ms_snd_card_get_string_id(lc->sound_conf.capt_sndcard); +} + +/* returns a static array of string describing the sound devices */ +const char** linphone_core_get_sound_devices(LinphoneCore *lc){ + return lc->sound_conf.cards; +} + +const char** linphone_core_get_video_devices(const LinphoneCore *lc){ + return lc->video_conf.cams; +} + +char linphone_core_get_sound_source(LinphoneCore *lc) +{ + return lc->sound_conf.source; +} + +void linphone_core_set_sound_source(LinphoneCore *lc, char source) +{ + MSSndCard *sndcard=lc->sound_conf.capt_sndcard; + lc->sound_conf.source=source; + if (!sndcard) return; + switch(source){ + case 'm': + ms_snd_card_set_capture(sndcard,MS_SND_CARD_MIC); + break; + case 'l': + ms_snd_card_set_capture(sndcard,MS_SND_CARD_LINE); + break; + } + +} + +void linphone_core_set_ring(LinphoneCore *lc,const char *path){ + if (lc->sound_conf.local_ring!=0){ + ms_free(lc->sound_conf.local_ring); + } + lc->sound_conf.local_ring=ms_strdup(path); +} + +const char *linphone_core_get_ring(LinphoneCore *lc){ + return lc->sound_conf.local_ring; +} + +static void notify_end_of_ring(void *ud ,unsigned int event, void * arg){ + LinphoneCore *lc=(LinphoneCore*)ud; + lc->preview_finished=1; +} + +int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata) +{ + if (lc->ringstream!=0){ + ms_warning("Cannot start ring now,there's already a ring being played"); + return -1; + } + lc_callback_obj_init(&lc->preview_finished_cb,func,userdata); + lc->preview_finished=0; + if (lc->sound_conf.ring_sndcard!=NULL){ + lc->ringstream=ring_start_with_cb(ring,2000,lc->sound_conf.ring_sndcard,notify_end_of_ring,(void *)lc); + } + return 0; +} + + +void linphone_core_set_ringback(LinphoneCore *lc,RingBackType type){ + switch(type){ + case RINGBACK_TYPE_FR: + lc->sound_conf.remote_ring=PACKAGE_SOUND_DIR "/" REMOTE_RING_FR; + break; + case RINGBACK_TYPE_US: + lc->sound_conf.remote_ring=PACKAGE_SOUND_DIR "/" REMOTE_RING_US; + break; + } +} +RingBackType linphone_core_get_ringback(LinphoneCore *lc); + +void linphone_core_enable_echo_cancelation(LinphoneCore *lc, bool_t val){ + lc->sound_conf.ec=val; +} + +bool_t linphone_core_echo_cancelation_enabled(LinphoneCore *lc){ + return lc->sound_conf.ec; +} + + +void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf) +{ + if (linphone_core_get_use_info_for_dtmf(lc)==0){ + /* In Band DTMF */ + if (lc->audiostream!=NULL){ + audio_stream_send_dtmf(lc->audiostream,dtmf); + } + }else{ + char dtmf_body[1000]; + char clen[10]; + osip_message_t *msg=NULL; + /* Out of Band DTMF (use INFO method) */ + LinphoneCall *call=lc->call; + if (call==NULL){ + return; + } + eXosip_call_build_info(call->did,&msg); + snprintf(dtmf_body, 999, "Signal=%c\r\nDuration=250\r\n", dtmf); + osip_message_set_body(msg,dtmf_body,strlen(dtmf_body)); + osip_message_set_content_type(msg,"application/dtmf-relay"); + snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body)); + osip_message_set_content_length(msg,clen); + + eXosip_lock(); + eXosip_call_send_request(call->did,msg); + eXosip_unlock(); + } +} + +void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ + if (lc->net_conf.stun_server!=NULL) + ms_free(lc->net_conf.stun_server); + if (server) + lc->net_conf.stun_server=ms_strdup(server); + else lc->net_conf.stun_server=NULL; + lc->apply_nat_settings=TRUE; +} + +const char * linphone_core_get_stun_server(const LinphoneCore *lc){ + return lc->net_conf.stun_server; +} + +const char * linphone_core_get_relay_addr(const LinphoneCore *lc){ + return lc->net_conf.relay; +} + +int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr){ + if (lc->net_conf.relay!=NULL){ + ms_free(lc->net_conf.relay); + lc->net_conf.relay=NULL; + } + if (addr){ + lc->net_conf.relay=ms_strdup(addr); + } + return 0; +} + +static void apply_nat_settings(LinphoneCore *lc){ + char *wmsg; + char *tmp=NULL; + int err; + struct addrinfo hints,*res; + const char *addr=lc->net_conf.nat_address; + + if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){ + if (addr==NULL || strlen(addr)==0){ + lc->vtable.display_warning(lc,_("No nat/firewall address supplied !")); + linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); + } + /*check the ip address given */ + memset(&hints,0,sizeof(struct addrinfo)); + if (lc->sip_conf.ipv6_enabled) + hints.ai_family=AF_INET6; + else + hints.ai_family=AF_INET; + hints.ai_socktype = SOCK_DGRAM; + err=getaddrinfo(addr,NULL,&hints,&res); + if (err!=0){ + wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"), + addr, gai_strerror(err)); + ms_warning(wmsg); // what is this for ? + lc->vtable.display_warning(lc, wmsg); + ms_free(wmsg); + linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); + return; + } + /*now get it as an numeric ip address */ + tmp=ms_malloc0(50); + err=getnameinfo(res->ai_addr,res->ai_addrlen,tmp,50,NULL,0,NI_NUMERICHOST); + if (err!=0){ + wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"), + addr, gai_strerror(err)); + ms_warning(wmsg); // what is this for ? + lc->vtable.display_warning(lc, wmsg); + ms_free(wmsg); + ms_free(tmp); + freeaddrinfo(res); + linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); + return; + } + freeaddrinfo(res); + } + + if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){ + if (tmp!=NULL){ + if (!lc->net_conf.nat_sdp_only) + eXosip_masquerade_contact(tmp,lc->sip_conf.sip_port); + ms_free(tmp); + } + else + eXosip_masquerade_contact("",0); + } + else { + eXosip_masquerade_contact("",0); + } +} + + +void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) +{ + if (lc->net_conf.nat_address!=NULL){ + ms_free(lc->net_conf.nat_address); + } + if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr); + else lc->net_conf.nat_address=NULL; + lc->apply_nat_settings=TRUE; +} + +const char *linphone_core_get_nat_address(const LinphoneCore *lc) +{ + return lc->net_conf.nat_address; +} + +void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){ + lc->net_conf.firewall_policy=pol; + lc->apply_nat_settings=TRUE; +} + +LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){ + return lc->net_conf.firewall_policy; +} + +MSList * linphone_core_get_call_logs(LinphoneCore *lc){ + lc->missed_calls=0; + return lc->call_logs; +} + +static void toggle_video_preview(LinphoneCore *lc, bool_t val){ +#ifdef VIDEO_ENABLED + if (lc->videostream==NULL){ + if (val){ + if (lc->previewstream==NULL){ + lc->previewstream=video_preview_start(lc->video_conf.device); + } + }else{ + if (lc->previewstream!=NULL){ + video_preview_stop(lc->previewstream); + lc->previewstream=NULL; + } + } + } +#endif +} + +void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled){ +#ifndef VIDEO_ENABLED + if (vcap_enabled || display_enabled) + ms_warning("This version of linphone was built without video support."); +#endif + lc->video_conf.capture=vcap_enabled; + lc->video_conf.display=display_enabled; + if (vcap_enabled && display_enabled) + lc->video_conf.show_local=1; + else + lc->video_conf.show_local=0; + + /* need to re-apply network bandwidth settings*/ + linphone_core_set_download_bandwidth(lc, + linphone_core_get_download_bandwidth(lc)); + linphone_core_set_upload_bandwidth(lc, + linphone_core_get_upload_bandwidth(lc)); +} + +bool_t linphone_core_video_enabled(LinphoneCore *lc){ + return (lc->video_conf.display || lc->video_conf.capture); +} + +void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){ + lc->video_conf.show_local=val; +} + +bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){ + return lc->video_conf.show_local; +} + +int linphone_core_set_video_device(LinphoneCore *lc, const char *id){ + MSWebCam *olddev=lc->video_conf.device; + if (id!=NULL){ + lc->video_conf.device=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),id); + if (lc->video_conf.device==NULL){ + ms_warning("Could not found video device %s",id); + } + } + if (lc->video_conf.device==NULL) + lc->video_conf.device=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get()); + if (olddev!=NULL && olddev!=lc->video_conf.device){ + toggle_video_preview(lc,FALSE);/*restart the video local preview*/ + } + return 0; +} + +const char *linphone_core_get_video_device(const LinphoneCore *lc){ + if (lc->video_conf.device) return ms_web_cam_get_string_id(lc->video_conf.device); + return NULL; +} + +void linphone_core_use_files(LinphoneCore *lc, bool_t yesno){ + lc->use_files=yesno; +} + +void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ + if (lc->play_file!=NULL){ + ms_free(lc->play_file); + lc->play_file=NULL; + } + if (file!=NULL) { + lc->play_file=ms_strdup(file); + if (lc->audiostream) + audio_stream_play(lc->audiostream,file); + } +} + +void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ + if (lc->rec_file!=NULL){ + ms_free(lc->rec_file); + lc->rec_file=NULL; + } + if (file!=NULL) { + lc->rec_file=ms_strdup(file); + if (lc->audiostream) + audio_stream_record(lc->audiostream,file); + } +} + + +void *linphone_core_get_user_data(LinphoneCore *lc){ + return lc->data; +} + +int linphone_core_get_mtu(const LinphoneCore *lc){ + return lc->net_conf.mtu; +} + +void linphone_core_set_mtu(LinphoneCore *lc, int mtu){ + lc->net_conf.mtu=mtu; + if (mtu>0){ + if (mtu<500){ + ms_error("MTU too small !"); + mtu=500; + } + ms_set_mtu(mtu); + ms_message("MTU is supposed to be %i, rtp payload max size will be %i",mtu, ms_get_payload_max_size()); + }else ms_set_mtu(0);//use mediastreamer2 default value +} + +void net_config_uninit(LinphoneCore *lc) +{ + net_config_t *config=&lc->net_conf; + lp_config_set_int(lc->config,"net","download_bw",config->download_bw); + lp_config_set_int(lc->config,"net","upload_bw",config->upload_bw); + + if (config->stun_server!=NULL) + lp_config_set_string(lc->config,"net","stun_server",config->stun_server); + if (config->nat_address!=NULL) + lp_config_set_string(lc->config,"net","nat_address",config->nat_address); + lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy); + lp_config_set_int(lc->config,"net","mtu",config->mtu); +} + + +void sip_config_uninit(LinphoneCore *lc) +{ + MSList *elem; + int i; + sip_config_t *config=&lc->sip_conf; + lp_config_set_int(lc->config,"sip","sip_port",config->sip_port); + lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); + lp_config_set_string(lc->config,"sip","contact",config->contact); + lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout); + lp_config_set_int(lc->config,"sip","use_info",config->use_info); + lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled); + for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); + linphone_proxy_config_write_to_config_file(lc->config,cfg,i); + linphone_proxy_config_edit(cfg); /* to unregister */ + } + + if (exosip_running) + { + int i; + for (i=0;i<20;i++) + { + eXosip_event_t *ev; + while((ev=eXosip_event_wait(0,0))!=NULL){ + linphone_core_process_event(lc,ev); + } + eXosip_automatic_action(); +#ifndef WIN32 + usleep(100000); +#else + Sleep(100); +#endif + } + } + + linphone_proxy_config_write_to_config_file(lc->config,NULL,i); /*mark the end */ + + for(elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ + LinphoneAuthInfo *ai=(LinphoneAuthInfo*)(elem->data); + linphone_auth_info_write_config(lc->config,ai,i); + } + linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */ +} + +void rtp_config_uninit(LinphoneCore *lc) +{ + rtp_config_t *config=&lc->rtp_conf; + lp_config_set_int(lc->config,"rtp","audio_rtp_port",config->audio_rtp_port); + lp_config_set_int(lc->config,"rtp","video_rtp_port",config->video_rtp_port); + lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp); + lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->audio_jitt_comp); + lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); +} + +void sound_config_uninit(LinphoneCore *lc) +{ + /*char tmpbuf[2];*/ + sound_config_t *config=&lc->sound_conf; + lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(config->play_sndcard)); + lp_config_set_string(lc->config,"sound","ringer_dev_id",ms_snd_card_get_string_id(config->ring_sndcard)); + lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(config->capt_sndcard)); + ms_free(config->cards); + /* + lp_config_set_int(lc->config,"sound","rec_lev",config->rec_lev); + lp_config_set_int(lc->config,"sound","play_lev",config->play_lev); + lp_config_set_int(lc->config,"sound","ring_lev",config->ring_lev); + tmpbuf[0]=config->source; + tmpbuf[1]='\0'; + lp_config_set_string(lc->config,"sound","source",tmpbuf); + */ + lp_config_set_string(lc->config,"sound","local_ring",config->local_ring); + lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring); + lp_config_set_int(lc->config,"sound","echocancelation",config->ec); +} + +void video_config_uninit(LinphoneCore *lc) +{ + video_config_t *config=&lc->video_conf; + const char *vd=linphone_core_get_video_device(lc); + if (vd && strstr(vd,"Static picture")!=NULL){ + vd=NULL; + } + lp_config_set_string(lc->config,"video","device",vd); + lp_config_set_int(lc->config,"video","display",config->display); + lp_config_set_int(lc->config,"video","capture",config->capture); + lp_config_set_int(lc->config,"video","show_local",config->show_local); +} + +void codecs_config_uninit(LinphoneCore *lc) +{ + PayloadType *pt; + codecs_config_t *config=&lc->codecs_conf; + MSList *node; + char key[50]; + int index; + index=0; + for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){ + pt=(PayloadType*)(node->data); + sprintf(key,"audio_codec_%i",index); + lp_config_set_string(lc->config,key,"mime",pt->mime_type); + lp_config_set_int(lc->config,key,"rate",pt->clock_rate); + lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt)); + index++; + } + index=0; + for(node=config->video_codecs;node!=NULL;node=ms_list_next(node)){ + pt=(PayloadType*)(node->data); + sprintf(key,"video_codec_%i",index); + lp_config_set_string(lc->config,key,"mime",pt->mime_type); + lp_config_set_int(lc->config,key,"rate",pt->clock_rate); + lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt)); + lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp); + index++; + } +} + +void ui_config_uninit(LinphoneCore* lc) +{ + MSList *elem; + int i; + for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){ + linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i); + linphone_friend_destroy(elem->data); + } + linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */ + ms_list_free(lc->friends); + lc->friends=NULL; +} + +LpConfig *linphone_core_get_config(LinphoneCore *lc){ + return lc->config; +} + +void linphone_core_uninit(LinphoneCore *lc) +{ + gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL); +#ifdef VIDEO_ENABLED + if (lc->previewstream!=NULL){ + video_preview_stop(lc->previewstream); + lc->previewstream=NULL; + } +#endif + /* save all config */ + net_config_uninit(lc); + sip_config_uninit(lc); + lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL)); + rtp_config_uninit(lc); + sound_config_uninit(lc); + video_config_uninit(lc); + codecs_config_uninit(lc); + ui_config_uninit(lc); + lp_config_sync(lc->config); + lp_config_destroy(lc->config); + +#ifdef VIDEO_ENABLED + if (payload_type_h264_packetization_mode_1!=NULL) + payload_type_destroy(payload_type_h264_packetization_mode_1); +#endif + + ortp_exit(); + eXosip_quit(); + exosip_running=FALSE; + gstate_new_state(lc, GSTATE_POWER_OFF, NULL); +} + +void linphone_core_destroy(LinphoneCore *lc){ + linphone_core_uninit(lc); + ms_free(lc); +} diff --git a/linphone/coreapi/linphonecore.h b/linphone/coreapi/linphonecore.h new file mode 100644 index 000000000..aa0216a43 --- /dev/null +++ b/linphone/coreapi/linphonecore.h @@ -0,0 +1,715 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef LINPHONECORE_H +#define LINPHONECORE_H + + +#include +#include "ortp/ortp.h" +#include "ortp/payloadtype.h" +#include "mediastreamer2/mscommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _MSSndCard; +struct _LinphoneCore; + +bool_t payload_type_enabled(struct _PayloadType *pt); +void payload_type_set_enable(struct _PayloadType *pt,int value); +const char *payload_type_get_description(struct _PayloadType *pt); +int payload_type_get_bitrate(PayloadType *pt); +const char *payload_type_get_mime(PayloadType *pt); +int payload_type_get_rate(PayloadType *pt); + + +struct _LpConfig; + +typedef struct sip_config +{ + char *contact; + char *guessed_contact; + int sip_port; + MSList *proxies; + MSList *deleted_proxies; + int inc_timeout; /*timeout after an un-answered incoming call is rejected*/ + bool_t use_info; + bool_t guess_hostname; + bool_t loopback_only; + bool_t ipv6_enabled; + bool_t sdp_200_ack; +} sip_config_t; + +typedef struct rtp_config +{ + int audio_rtp_port; + int video_rtp_port; + int audio_jitt_comp; /*jitter compensation*/ + int video_jitt_comp; /*jitter compensation*/ + int nortp_timeout; +}rtp_config_t; + + + +typedef struct net_config +{ + char *nat_address; + char *stun_server; + char *relay; + int download_bw; + int upload_bw; + int firewall_policy; + int mtu; + bool_t nat_sdp_only; +}net_config_t; + + +typedef struct sound_config +{ + struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */ + struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */ + struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */ + const char **cards; + int latency; /* latency in samples of the current used sound device */ + char rec_lev; + char play_lev; + char ring_lev; + char source; + char pad; + char *local_ring; + char *remote_ring; + bool_t ec; +} sound_config_t; + +typedef struct codecs_config +{ + MSList *audio_codecs; /* list of audio codecs in order of preference*/ + MSList *video_codecs; /* for later use*/ +}codecs_config_t; + +typedef struct video_config{ + struct _MSWebCam *device; + const char **cams; + bool_t capture; + bool_t show_local; + bool_t display; +}video_config_t; + +typedef struct ui_config +{ + int is_daemon; + int is_applet; + unsigned int timer_id; /* the timer id for registration */ +}ui_config_t; + + + +typedef struct autoreplier_config +{ + int enabled; + int after_seconds; /* accept the call after x seconds*/ + int max_users; /* maximum number of user that can call simultaneously */ + int max_rec_time; /* the max time of incoming voice recorded */ + int max_rec_msg; /* maximum number of recorded messages */ + const char *message; /* the path of the file to be played */ +}autoreplier_config_t; + + +struct _LinphoneCore; +struct _sdp_context; + +typedef struct _StreamParams +{ + int initialized; + int line; + int localport; + int remoteport; + int remotertcpport; + char *remoteaddr; + int pt; + char *relay_session_id; +} StreamParams; + +typedef enum _LCState{ + LCStateInit, + LCStateRinging, + LCStateAVRunning +}LCState; + +typedef enum _LinphoneCallDir {LinphoneCallOutgoing, LinphoneCallIncoming} LinphoneCallDir; + + +typedef struct _LinphoneCall +{ + struct _LinphoneCore *core; + StreamParams audio_params; + StreamParams video_params; + LinphoneCallDir dir; + struct _RtpProfile *profile; /*points to the local_profile or to the remote "guessed" profile*/ + struct _LinphoneCallLog *log; + int cid; /*call id */ + int did; /*dialog id */ + int tid; /*last transaction id*/ + struct _sdp_context *sdpctx; + time_t start_time; + LCState state; + bool_t auth_pending; +} LinphoneCall; + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const osip_from_t *from, const osip_to_t *to); +LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const char *from, const char *to, int cid, int did , int tid); +#define linphone_call_set_state(lcall,st) (lcall)->state=(st) +void linphone_call_destroy(struct _LinphoneCall *obj); + + +typedef enum _LinphoneCallStatus { + LinphoneCallSuccess, + LinphoneCallAborted, + LinphoneCallMissed +} LinphoneCallStatus; + +typedef struct _LinphoneCallLog{ + LinphoneCallDir dir; + LinphoneCallStatus status; + char *from; + char *to; + char start_date[128]; + int duration; + +} LinphoneCallLog; + +/* private: */ +LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, char *local, char * remote); +void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call); +void linphone_call_log_destroy(LinphoneCallLog *cl); + +/*public: */ +char * linphone_call_log_to_str(LinphoneCallLog *cl); + +typedef enum{ + LinphoneSPWait, + LinphoneSPDeny, + LinphoneSPAccept +}LinphoneSubscribePolicy; + +typedef enum _LinphoneOnlineStatus{ + LINPHONE_STATUS_UNKNOWN, + LINPHONE_STATUS_ONLINE, + LINPHONE_STATUS_BUSY, + LINPHONE_STATUS_BERIGHTBACK, + LINPHONE_STATUS_AWAY, + LINPHONE_STATUS_ONTHEPHONE, + LINPHONE_STATUS_OUTTOLUNCH, + LINPHONE_STATUS_NOT_DISTURB, + LINPHONE_STATUS_MOVED, + LINPHONE_STATUS_ALT_SERVICE, + LINPHONE_STATUS_OFFLINE, + LINPHONE_STATUS_PENDING, + LINPHONE_STATUS_CLOSED, + LINPHONE_STATUS_END +}LinphoneOnlineStatus; + +const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); + +typedef struct _LinphoneFriend{ + osip_from_t *url; + int in_did; + int out_did; + int sid; + int nid; + LinphoneSubscribePolicy pol; + LinphoneOnlineStatus status; + struct _LinphoneProxyConfig *proxy; + struct _LinphoneCore *lc; + bool_t subscribe; + bool_t inc_subscribe_pending; +}LinphoneFriend; + +LinphoneFriend * linphone_friend_new(); +LinphoneFriend *linphone_friend_new_with_addr(const char *addr); +int linphone_friend_set_sip_addr(LinphoneFriend *fr, const char *uri); +int linphone_friend_set_name(LinphoneFriend *fr, const char *name); +int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val); +int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol); +int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg); +void linphone_friend_edit(LinphoneFriend *fr); +void linphone_friend_done(LinphoneFriend *fr); +void linphone_friend_destroy(LinphoneFriend *lf); +/* memory returned by those 3 functions must be freed */ +char *linphone_friend_get_name(LinphoneFriend *lf); +char *linphone_friend_get_addr(LinphoneFriend *lf); +char *linphone_friend_get_url(LinphoneFriend *lf); /* name */ +bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf); +LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf); +LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); + +#define linphone_friend_url(lf) ((lf)->url) + +void linphone_friend_write_to_config_file(struct _LpConfig *config, LinphoneFriend *lf, int index); +LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, int index); + +typedef struct _LinphoneProxyConfig +{ + struct _LinphoneCore *lc; + char *reg_proxy; + char *reg_identity; + char *reg_route; + char *realm; + int expires; + int reg_time; + int rid; + bool_t frozen; + bool_t reg_sendregister; + bool_t auth_pending; + bool_t registered; + bool_t publish; +} LinphoneProxyConfig; + +LinphoneProxyConfig *linphone_proxy_config_new(void); +int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); +void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); +void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); +void linphone_proxy_config_expires(LinphoneProxyConfig *obj, const int expires); +void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); +#define linphone_proxy_config_enableregister linphone_proxy_config_enable_register +void linphone_proxy_config_edit(LinphoneProxyConfig *obj); +int linphone_proxy_config_done(LinphoneProxyConfig *obj); +void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val); +#define linphone_proxy_config_get_route(obj) ((obj)->reg_route) +#define linphone_proxy_config_get_identity(obj) ((obj)->reg_identity) +#define linphone_proxy_config_publish_enabled(obj) ((obj)->publish) +#define linphone_proxy_config_get_addr(obj) ((obj)->reg_proxy) +#define linphone_proxy_config_get_expires(obj) ((obj)->expires) +#define linphone_proxy_config_register_enabled(obj) ((obj)->reg_sendregister) + +/* destruction is called automatically when removing the proxy config */ +void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg); +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index); +void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index); + +typedef struct _LinphoneAuthInfo +{ + char *username; + char *realm; + char *userid; + char *passwd; + char *ha1; + bool_t works; + bool_t first_time; +}LinphoneAuthInfo; + +LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, + const char *passwd, const char *ha1,const char *realm); +void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); +/* you don't need those function*/ +void linphone_auth_info_destroy(LinphoneAuthInfo *info); +LinphoneAuthInfo * linphone_auth_info_new_from_config_file(struct _LpConfig *config, int pos); + +struct _LinphoneChatRoom{ + struct _LinphoneCore *lc; + char *peer; + char *route; + osip_from_t *peer_url; + void * user_data; +}; +typedef struct _LinphoneChatRoom LinphoneChatRoom; + +LinphoneChatRoom * linphone_core_create_chat_room(struct _LinphoneCore *lc, const char *to); +void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); +void linphone_chat_room_destroy(LinphoneChatRoom *cr); +void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); +void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); + +/* describes the different groups of states */ +typedef enum _gstate_group { + GSTATE_GROUP_POWER, + GSTATE_GROUP_REG, + GSTATE_GROUP_CALL +} gstate_group_t; + +typedef enum _gstate { + /* states for GSTATE_GROUP_POWER */ + GSTATE_POWER_OFF = 0, /* initial state */ + GSTATE_POWER_STARTUP, + GSTATE_POWER_ON, + GSTATE_POWER_SHUTDOWN, + /* states for GSTATE_GROUP_REG */ + GSTATE_REG_NONE = 10, /* initial state */ + GSTATE_REG_OK, + GSTATE_REG_FAILED, + /* states for GSTATE_GROUP_CALL */ + GSTATE_CALL_IDLE = 20, /* initial state */ + GSTATE_CALL_OUT_INVITE, + GSTATE_CALL_OUT_CONNECTED, + GSTATE_CALL_IN_INVITE, + GSTATE_CALL_IN_CONNECTED, + GSTATE_CALL_END, + GSTATE_CALL_ERROR +} gstate_t; + +struct _LinphoneGeneralState { + gstate_t old_state; + gstate_t new_state; + gstate_group_t group; + const char *message; +}; +typedef struct _LinphoneGeneralState LinphoneGeneralState; + +/* retrieve the current state of the specified state group */ +gstate_t gstate_get_state(gstate_group_t group); + +/* private: set the initial states */ +void gstate_initialize(void); + +/* private: set a new state */ +void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, const char *message); + +typedef void (*ShowInterfaceCb)(struct _LinphoneCore *lc); +typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, const char *from); +typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, const char *from); +typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); +typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message); +typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, const char *url); +typedef void (*DisplayQuestionCb)(struct _LinphoneCore *lc, const char *message); +typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data); +typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img); +typedef void (*NewUnknownSubscriberCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url); +typedef void (*AuthInfoRequested)(struct _LinphoneCore *lc, const char *realm, const char *username); +typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl); +typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message); +typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate); + +typedef struct _LinphoneVTable +{ + ShowInterfaceCb show; + InviteReceivedCb inv_recv; + ByeReceivedCb bye_recv; + NotifyReceivedCb notify_recv; + NewUnknownSubscriberCb new_unknown_subscriber; + AuthInfoRequested auth_info_requested; + DisplayStatusCb display_status; + DisplayMessageCb display_message; +#ifdef VINCENT_MAURY_RSVP + /* the yes/no dialog box */ + DisplayMessageCb display_yes_no; +#endif + DisplayMessageCb display_warning; + DisplayUrlCb display_url; + DisplayQuestionCb display_question; + CallLogUpdated call_log_updated; + TextMessageReceived text_received; + GeneralStateChange general_state; +} LinphoneCoreVTable; + +typedef struct _LCCallbackObj +{ + LinphoneCoreCbFunc _func; + void * _user_data; +}LCCallbackObj; + + + +typedef enum _LinphoneFirewallPolicy{ + LINPHONE_POLICY_NO_FIREWALL, + LINPHONE_POLICY_USE_NAT_ADDRESS, + LINPHONE_POLICY_USE_STUN +} LinphoneFirewallPolicy; + +typedef struct _LinphoneCore +{ + LinphoneCoreVTable vtable; + struct _LpConfig *config; + net_config_t net_conf; + sip_config_t sip_conf; + rtp_config_t rtp_conf; + sound_config_t sound_conf; + video_config_t video_conf; + codecs_config_t codecs_conf; + ui_config_t ui_conf; + autoreplier_config_t autoreplier_conf; + LinphoneProxyConfig *default_proxy; + MSList *friends; + MSList *auth_info; + struct _RingStream *ringstream; + LCCallbackObj preview_finished_cb; + bool_t preview_finished; + LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/ + int rid; /*registration id*/ + MSList *queued_calls; /* used by the autoreplier */ + MSList *call_logs; + MSList *chatrooms; + int max_call_logs; + int missed_calls; + struct _AudioStream *audiostream; /**/ + struct _VideoStream *videostream; + struct _VideoStream *previewstream; + struct _RtpProfile *local_profile; + MSList *subscribers; /* unknown subscribers */ + int minutes_away; + LinphoneOnlineStatus presence_mode; + LinphoneOnlineStatus prev_mode; + char *alt_contact; + void *data; + ms_mutex_t lock; + char *play_file; + char *rec_file; + time_t prevtime; + int dw_audio_bw; + int up_audio_bw; + int dw_video_bw; + int up_video_bw; + int audio_bw; + int automatic_action; + bool_t use_files; + bool_t apply_nat_settings; +#ifdef VINCENT_MAURY_RSVP + /* QoS parameters*/ + int rsvp_enable; + int rpc_enable; +#endif +} LinphoneCore; + +#define LINPHONE_IPADDR_SIZE 64 + +/* THE main API */ + +void linphone_core_enable_logs(FILE *file); +void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); +void linphone_core_disable_logs(void); + +const char *linphone_core_get_version(void); + +LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, + const char *config_path, void* userdata); + +void linphone_core_init(LinphoneCore *lc, const LinphoneCoreVTable *vtable, + const char *config_path, void * userdata); + +/* function to be periodically called in a main loop */ +void linphone_core_iterate(LinphoneCore *lc); + +int linphone_core_invite(LinphoneCore *lc, const char *url); + +int linphone_core_refer(LinphoneCore *lc, const char *url); + +bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); + +bool_t linphone_core_in_call(const LinphoneCore *lc); + +int linphone_core_accept_call(LinphoneCore *lc, const char *url); + +int linphone_core_terminate_call(LinphoneCore *lc, const char *url); + +void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); + +int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact); + +const char *linphone_core_get_primary_contact(LinphoneCore *lc); + +void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val); +bool_t linphone_core_get_guess_hostname(LinphoneCore *lc); + +bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); +void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); + +osip_from_t *linphone_core_get_primary_contact_parsed(LinphoneCore *lc); + +/*0= no bandwidth limit*/ +void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw); +void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw); + +int linphone_core_get_download_bandwidth(const LinphoneCore *lc); +int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); + + +#ifdef VINCENT_MAURY_RSVP +/* QoS functions */ +int linphone_core_set_rpc_mode(LinphoneCore *lc, int on); /* on = 1 (RPC_ENABLE = 1) */ +int linphone_core_set_rsvp_mode(LinphoneCore *lc, int on); /* on = 1 (RSVP_ENABLE = 1) */ +int linphone_core_change_qos(LinphoneCore *lc, int answer); /* answer = 1 for yes, 0 for no */ +#endif + +/* returns a MSList of PayloadType */ +const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); + +int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); +/* returns a MSList of PayloadType */ +const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); + +int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); + +bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); + +int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); + +void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); + +const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); + +void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config); + +void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index); + +int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); + +void linphone_core_add_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info); + +void linphone_core_remove_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info); + +void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info); + +void linphone_core_clear_all_auth_info(LinphoneCore *lc); + +int linphone_core_get_audio_jittcomp(LinphoneCore *lc); + +void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); + +int linphone_core_get_audio_port(const LinphoneCore *lc); + +int linphone_core_get_video_port(const LinphoneCore *lc); + +int linphone_core_get_nortp_timeout(const LinphoneCore *lc); + +void linphone_core_set_audio_port(LinphoneCore *lc, int port); + +void linphone_core_set_video_port(LinphoneCore *lc, int port); + +void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port); + +void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info); + +bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc); + +int linphone_core_get_sip_port(LinphoneCore *lc); + +void linphone_core_set_sip_port(LinphoneCore *lc,int port); + +void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds); + +int linphone_core_get_inc_timeout(LinphoneCore *lc); + +void linphone_core_set_stun_server(LinphoneCore *lc, const char *server); + +const char * linphone_core_get_stun_server(const LinphoneCore *lc); + +void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); + +const char *linphone_core_get_nat_address(const LinphoneCore *lc); + +void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol); + +LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc); + +const char * linphone_core_get_relay_addr(const LinphoneCore *lc); + +int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr); + +/* sound functions */ +/* returns a null terminated static array of string describing the sound devices */ +const char** linphone_core_get_sound_devices(LinphoneCore *lc); +int linphone_core_get_ring_level(LinphoneCore *lc); +int linphone_core_get_play_level(LinphoneCore *lc); +int linphone_core_get_rec_level(LinphoneCore *lc); +void linphone_core_set_ring_level(LinphoneCore *lc, int level); +void linphone_core_set_play_level(LinphoneCore *lc, int level); +void linphone_core_set_rec_level(LinphoneCore *lc, int level); +const char * linphone_core_get_ringer_device(LinphoneCore *lc); +const char * linphone_core_get_playback_device(LinphoneCore *lc); +const char * linphone_core_get_capture_device(LinphoneCore *lc); +int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid); +int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); +int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); +char linphone_core_get_sound_source(LinphoneCore *lc); +void linphone_core_set_sound_source(LinphoneCore *lc, char source); +void linphone_core_set_ring(LinphoneCore *lc, const char *path); +const char *linphone_core_get_ring(LinphoneCore *lc); +int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); +typedef enum {RINGBACK_TYPE_FR,RINGBACK_TYPE_US} RingBackType; +void linphone_core_set_ringback(LinphoneCore *lc,RingBackType type); +RingBackType linphone_core_get_ringback(LinphoneCore *lc); +void linphone_core_enable_echo_cancelation(LinphoneCore *lc, bool_t val); +bool_t linphone_core_echo_cancelation_enabled(LinphoneCore *lc); + +void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *contact,LinphoneOnlineStatus os); + +LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); + +void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr); +void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr); +void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); +/* a list of LinphoneFriend */ +const MSList * linphone_core_get_friend_list(LinphoneCore *lc); +/* notify all friends that have subscribed */ +void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os); + +/* returns a list of LinphoneCallLog */ +MSList * linphone_core_get_call_logs(LinphoneCore *lc); + +/* video support */ +void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled); +bool_t linphone_core_video_enabled(LinphoneCore *lc); + +/*play/record support: use files instead of soundcard*/ +void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); +void linphone_core_set_play_file(LinphoneCore *lc, const char *file); +void linphone_core_set_record_file(LinphoneCore *lc, const char *file); + + + +void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); +bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); + + + +/* returns a null terminated static array of string describing the webcams */ +const char** linphone_core_get_video_devices(const LinphoneCore *lc); +int linphone_core_set_video_device(LinphoneCore *lc, const char *id); +const char *linphone_core_get_video_device(const LinphoneCore *lc); + +int linphone_core_get_mtu(const LinphoneCore *lc); +void linphone_core_set_mtu(LinphoneCore *lc, int mtu); + +bool_t linphone_core_is_in_main_thread(LinphoneCore *lc); + +void *linphone_core_get_user_data(LinphoneCore *lc); + +/* returns LpConfig object to read/write to the config file: usefull if you wish to extend +the config file with your own sections */ +struct _LpConfig *linphone_core_get_config(LinphoneCore *lc); + +void linphone_core_uninit(LinphoneCore *lc); +void linphone_core_destroy(LinphoneCore *lc); + +/* end of lecacy api */ + +/*internal use only */ +#define linphone_core_lock(lc) ms_mutex_lock(&(lc)->lock) +#define linphone_core_unlock(lc) ms_mutex_unlock((&lc)->lock) +void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_stop_media_streams(LinphoneCore *lc); +const char * linphone_core_get_identity(LinphoneCore *lc); +const char * linphone_core_get_route(LinphoneCore *lc); +bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, char **real_url, osip_to_t **real_parsed_url, char **route); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/coreapi/lpconfig.c b/linphone/coreapi/lpconfig.c new file mode 100644 index 000000000..c7d1a6049 --- /dev/null +++ b/linphone/coreapi/lpconfig.c @@ -0,0 +1,354 @@ +/*************************************************************************** + * lpconfig.c + * + * Thu Mar 10 11:13:44 2005 + * Copyright 2005 Simon Morlat + * Email simon.morlat@linphone.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define MAX_LEN 1024 + +#include "linphonecore.h" + +#include +#include +#include +#include +#include +#include +#include + +#define lp_new0(type,n) (type*)calloc(sizeof(type),n) + +#include "lpconfig.h" + +#define LISTNODE(_struct_) \ + struct _struct_ *_prev;\ + struct _struct_ *_next; + +typedef struct _ListNode{ + LISTNODE(_ListNode) +} ListNode; + +typedef void (*ListNodeForEachFunc)(ListNode *); + +ListNode * list_node_append(ListNode *head,ListNode *elem){ + ListNode *e=head; + while(e->_next!=NULL) e=e->_next; + e->_next=elem; + elem->_prev=e; + return head; +} + +ListNode * list_node_remove(ListNode *head, ListNode *elem){ + ListNode *before,*after; + before=elem->_prev; + after=elem->_next; + if (before!=NULL) before->_next=after; + if (after!=NULL) after->_prev=before; + elem->_prev=NULL; + elem->_next=NULL; + if (head==elem) return after; + return head; +} + +void list_node_foreach(ListNode *head, ListNodeForEachFunc func){ + for (;head!=NULL;head=head->_next){ + func(head); + } +} + + +#define LIST_PREPEND(e1,e2) ( (e2)->_prev=NULL,(e2)->_next=(e1),(e1)->_prev=(e2),(e2) ) +#define LIST_APPEND(head,elem) ((head)==0 ? (elem) : (list_node_append((ListNode*)(head),(ListNode*)(elem)), (head)) ) +#define LIST_REMOVE(head,elem) + +/* returns void */ +#define LIST_FOREACH(head) list_node_foreach((ListNode*)head) + +typedef struct _LpItem{ + char *key; + char *value; +} LpItem; + +typedef struct _LpSection{ + char *name; + MSList *items; +} LpSection; + +struct _LpConfig{ + FILE *file; + char *filename; + MSList *sections; +}; + +LpItem * lp_item_new(const char *key, const char *value){ + LpItem *item=lp_new0(LpItem,1); + item->key=strdup(key); + item->value=strdup(value); + return item; +} + +LpSection *lp_section_new(const char *name){ + LpSection *sec=lp_new0(LpSection,1); + sec->name=strdup(name); + return sec; +} + +void lp_item_destroy(void *pitem){ + LpItem *item=(LpItem*)pitem; + free(item->key); + free(item->value); + free(item); +} + +void lp_section_destroy(LpSection *sec){ + free(sec->name); + ms_list_for_each(sec->items,lp_item_destroy); + ms_list_free(sec->items); + free(sec); +} + +void lp_section_add_item(LpSection *sec,LpItem *item){ + sec->items=ms_list_append(sec->items,(void *)item); +} + +void lp_config_add_section(LpConfig *lpconfig, LpSection *section){ + lpconfig->sections=ms_list_append(lpconfig->sections,(void *)section); +} + +void lp_config_remove_section(LpConfig *lpconfig, LpSection *section){ + lpconfig->sections=ms_list_remove(lpconfig->sections,(void *)section); + lp_section_destroy(section); +} + +static bool_t is_first_char(const char *start, const char *pos){ + const char *p; + for(p=start;pfile==NULL) return; + + while(fgets(tmp,MAX_LEN,lpconfig->file)!=NULL){ + char *pos1,*pos2; + pos1=strchr(tmp,'['); + if (pos1!=NULL && is_first_char(tmp,pos1) ){ + pos2=strchr(pos1,']'); + if (pos2!=NULL){ + int nbs; + char secname[MAX_LEN]; + secname[0]='\0'; + /* found section */ + *pos2='\0'; + nbs = sscanf(pos1+1,"%s",secname); + if (nbs == 1 ){ + if (strlen(secname)>0){ + cur=lp_section_new(secname); + lp_config_add_section(lpconfig,cur); + } + }else{ + ms_warning("parse error!"); + } + } + }else { + pos1=strchr(tmp,'='); + if (pos1!=NULL){ + char key[MAX_LEN]; + key[0]='\0'; + + *pos1='\0'; + if (sscanf(tmp,"%s",key)>0){ + + pos1++; + pos2=strchr(pos1,'\n'); + if (pos2==NULL) pos2=pos1+strlen(pos2); + else { + *pos2='\0'; /*replace the '\n' */ + pos2--; + } + /* remove ending white spaces */ + for (; pos2>pos1 && *pos2==' ';pos2--) *pos2='\0'; + if (pos2-pos1>=0){ + /* found a pair key,value */ + if (cur!=NULL){ + lp_section_add_item(cur,lp_item_new(key,pos1)); + /*printf("Found %s %s=%s\n",cur->name,key,pos1);*/ + }else{ + ms_warning("found key,item but no sections"); + } + } + } + } + } + } +} + +LpConfig * lp_config_new(const char *filename){ + LpConfig *lpconfig=lp_new0(LpConfig,1); + if (filename!=NULL){ + lpconfig->filename=strdup(filename); + lpconfig->file=fopen(filename,"rw"); + if (lpconfig->file!=NULL){ + lp_config_parse(lpconfig); + fclose(lpconfig->file); + /* make existing configuration files non-group/world-accessible */ + if (chmod(filename, S_IRUSR | S_IWUSR) == -1) + ms_warning("unable to correct permissions on " + "configuration file: %s", + strerror(errno)); + lpconfig->file=NULL; + } + } + return lpconfig; +} + +void lp_item_set_value(LpItem *item, const char *value){ + free(item->value); + item->value=strdup(value); +} + + +void lp_config_destroy(LpConfig *lpconfig){ + if (lpconfig->filename!=NULL) free(lpconfig->filename); + ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy); + ms_list_free(lpconfig->sections); + free(lpconfig); +} + +LpSection *lp_config_find_section(LpConfig *lpconfig, const char *name){ + LpSection *sec; + MSList *elem; + /*printf("Looking for section %s\n",name);*/ + for (elem=lpconfig->sections;elem!=NULL;elem=ms_list_next(elem)){ + sec=(LpSection*)elem->data; + if (strcmp(sec->name,name)==0){ + /*printf("Section %s found\n",name);*/ + return sec; + } + } + return NULL; +} + +LpItem *lp_section_find_item(LpSection *sec, const char *name){ + MSList *elem; + LpItem *item; + /*printf("Looking for item %s\n",name);*/ + for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){ + item=(LpItem*)elem->data; + if (strcmp(item->key,name)==0) { + /*printf("Item %s found\n",name);*/ + return item; + } + } + return NULL; +} + +void lp_section_remove_item(LpSection *sec, LpItem *item){ + sec->items=ms_list_remove(sec->items,(void *)item); + lp_item_destroy(item); +} + +const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const char *key, const char *default_string){ + LpSection *sec; + LpItem *item; + sec=lp_config_find_section(lpconfig,section); + if (sec!=NULL){ + item=lp_section_find_item(sec,key); + if (item!=NULL) return item->value; + } + return default_string; +} + +int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value){ + const char *str=lp_config_get_string(lpconfig,section,key,NULL); + if (str!=NULL) return atoi(str); + else return default_value; +} + +void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value){ + LpItem *item; + LpSection *sec=lp_config_find_section(lpconfig,section); + if (sec!=NULL){ + item=lp_section_find_item(sec,key); + if (item!=NULL){ + if (value!=NULL) + lp_item_set_value(item,value); + else lp_section_remove_item(sec,item); + }else{ + if (value!=NULL) + lp_section_add_item(sec,lp_item_new(key,value)); + } + }else if (value!=NULL){ + sec=lp_section_new(section); + lp_config_add_section(lpconfig,sec); + lp_section_add_item(sec,lp_item_new(key,value)); + } +} + +void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){ + char tmp[30]; + snprintf(tmp,30,"%i",value); + lp_config_set_string(lpconfig,section,key,tmp); +} + +void lp_item_write(LpItem *item, FILE *file){ + fprintf(file,"%s=%s\n",item->key,item->value); +} + +void lp_section_write(LpSection *sec, FILE *file){ + fprintf(file,"[%s]\n",sec->name); + ms_list_for_each2(sec->items,(void (*)(void*, void*))lp_item_write,(void *)file); + fprintf(file,"\n"); +} + +int lp_config_sync(LpConfig *lpconfig){ + FILE *file; + if (lpconfig->filename==NULL) return -1; +#ifndef WIN32 + /* don't create group/world-accessible files */ + (void) umask(S_IRWXG | S_IRWXO); +#endif + file=fopen(lpconfig->filename,"w"); + if (file==NULL){ + ms_warning("Could not write %s !",lpconfig->filename); + return -1; + } + ms_list_for_each2(lpconfig->sections,(void (*)(void *,void*))lp_section_write,(void *)file); + fclose(file); + return 0; +} + +int lp_config_has_section(LpConfig *lpconfig, const char *section){ + if (lp_config_find_section(lpconfig,section)!=NULL) return 1; + return 0; +} + +void lp_config_clean_section(LpConfig *lpconfig, const char *section){ + LpSection *sec=lp_config_find_section(lpconfig,section); + if (sec!=NULL){ + lp_config_remove_section(lpconfig,sec); + } +} diff --git a/linphone/coreapi/lpconfig.h b/linphone/coreapi/lpconfig.h new file mode 100644 index 000000000..2bf18b95e --- /dev/null +++ b/linphone/coreapi/lpconfig.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * lpconfig.h + * + * Thu Mar 10 15:02:49 2005 + * Copyright 2005 Simon Morlat + * Email simon.morlat@linphone.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef LPCONFIG_H +#define LPCONFIG_H + +typedef struct _LpConfig LpConfig; + +#ifdef __cplusplus +extern "C" { +#endif + +LpConfig * lp_config_new(const char *filename); +const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const char *key, const char *default_string); +int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value); +void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); +void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); +int lp_config_sync(LpConfig *lpconfig); +int lp_config_has_section(LpConfig *lpconfig, const char *section); +void lp_config_clean_section(LpConfig *lpconfig, const char *section); +void lp_config_destroy(LpConfig *cfg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/coreapi/misc.c b/linphone/coreapi/misc.c new file mode 100644 index 000000000..418e01c99 --- /dev/null +++ b/linphone/coreapi/misc.c @@ -0,0 +1,450 @@ + +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "private.h" +#include "mediastreamer2/mediastream.h" +#include +#include +#include +#include +#include +#include +#include + + +#ifndef WIN32 + +static char lock_name[80]; +static char lock_set=0; +/* put a lock file in /tmp. this is called when linphone runs as a daemon*/ +int set_lock_file() +{ + FILE *lockfile; + + snprintf(lock_name,80,"/tmp/linphone.%i",getuid()); + lockfile=fopen(lock_name,"w"); + if (lockfile==NULL) + { + printf("Failed to create lock file.\n"); + return(-1); + } + fprintf(lockfile,"%i",getpid()); + fclose(lockfile); + lock_set=1; + return(0); +} + +/* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/ +int get_lock_file() +{ + int pid; + FILE *lockfile; + + snprintf(lock_name,80,"/tmp/linphone.%i",getuid()); + lockfile=fopen(lock_name,"r"); + if (lockfile==NULL) + return(-1); + if (fscanf(lockfile,"%i",&pid)!=1){ + ms_warning("Could not read pid in lock file."); + fclose(lockfile); + return -1; + } + fclose(lockfile); + return pid; +} + +/* remove the lock file if it was set*/ +int remove_lock_file() +{ + int err=0; + if (lock_set) + { + err=unlink(lock_name); + lock_set=0; + } + return(err); +} + +#endif + +char *int2str(int number) +{ + char *numstr=ms_malloc(10); + snprintf(numstr,10,"%i",number); + return numstr; +} + +void check_sound_device(LinphoneCore *lc) +{ + int fd,len; + int a; + char *file=NULL; + char *i810_audio=NULL; + char *snd_pcm_oss=NULL; + char *snd_mixer_oss=NULL; + char *snd_pcm=NULL; + + fd=open("/proc/modules",O_RDONLY); + if (fd>0){ + /* read the entire /proc/modules file and check if sound conf seems correct */ + /*a=fstat(fd,&statbuf); + if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno)); + len=statbuf.st_size; + if (len==0) ms_warning("/proc/modules has zero size!"); + */ + /***** fstat does not work on /proc/modules for unknown reason *****/ + len=6000; + file=ms_malloc(len+1); + a=read(fd,file,len); + if (avtable.display_warning(lc,_("You are currently using the i810_audio driver.\nThis driver is buggy and so does not work with Linphone.\nWe suggest that you replace it by its equivalent ALSA driver,\neither with packages from your distribution, or by downloading\nALSA drivers at http://www.alsa-project.org."));*/ + goto end; + } + snd_pcm=strstr(file,"snd-pcm"); + if (snd_pcm!=NULL){ + snd_pcm_oss=strstr(file,"snd-pcm-oss"); + snd_mixer_oss=strstr(file,"snd-mixer-oss"); + if (snd_pcm_oss==NULL){ + lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the pcm oss emulation module\nis missing and linphone needs it. Please execute\n'modprobe snd-pcm-oss' as root to load it.")); + } + if (snd_mixer_oss==NULL){ + lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the mixer oss emulation module\nis missing and linphone needs it. Please execute\n 'modprobe snd-mixer-oss' as root to load it.")); + } + } + }else { +#ifdef __linux + ms_warning("Could not open /proc/modules."); +#endif + } + /* now check general volume. Some user forget to rise it and then complain that linphone is + not working */ + /* but some other users complain that linphone should not change levels... + if (lc->sound_conf.sndcard!=NULL){ + a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL); + if (a<50){ + ms_warning("General level is quite low (%i). Linphone rises it up for you.",a); + snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80); + } + } + */ + end: + if (file!=NULL) ms_free(file); + if (fd>0) close(fd); +} + +#define UDP_HDR_SZ 8 +#define RTP_HDR_SZ 12 +#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ + +const char *payload_type_get_description(PayloadType *pt){ + return (const char *)pt->user_data; +} + +void payload_type_set_enable(PayloadType *pt,int value) +{ + if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ + else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); +} + + +bool_t payload_type_enabled(PayloadType *pt) { + return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); +} + +int payload_type_get_bitrate(PayloadType *pt) +{ + return pt->normal_bitrate; +} +const char *payload_type_get_mime(PayloadType *pt){ + return pt->mime_type; +} + +int payload_type_get_rate(PayloadType *pt){ + return pt->clock_rate; +} + +static double get_audio_payload_bandwidth(const PayloadType *pt){ + double npacket=50; + double packet_size; + int bitrate; + bitrate=pt->normal_bitrate; + packet_size=(double)(bitrate/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; + return packet_size*8.0*npacket; +} + +void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc, const PayloadType *pt){ + lc->audio_bw=(int)(get_audio_payload_bandwidth(pt)/1000.0); + /*update*/ + linphone_core_set_upload_bandwidth(lc,lc->net_conf.upload_bw); +} + +static void update_allocated_audio_bandwidth(LinphoneCore *lc){ + const MSList *elem; + PayloadType *max=NULL; + for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + if (payload_type_enabled(pt)){ + if (max==NULL) max=pt; + else if (max->normal_bitratenormal_bitrate){ + max=pt; + } + } + } + if (max) { + linphone_core_update_allocated_audio_bandwidth(lc,max); + } +} + +/* return TRUE if codec can be used with bandwidth, FALSE else*/ +bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt) +{ + double codec_band; + int min_audio_bw; + int min_video_bw; + bool_t ret=FALSE; + /* + update allocated audio bandwidth to allocate the remaining to video. + This must be done outside calls, because after sdp negociation + the audio bandwidth is refined to the selected codec + */ + if (!linphone_core_in_call(lc)) update_allocated_audio_bandwidth(lc); + min_audio_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + linphone_core_get_upload_bandwidth(lc)); + if (min_audio_bw==0) min_audio_bw=-1; + min_video_bw=get_min_bandwidth(lc->dw_video_bw,lc->up_video_bw); + + switch (pt->type){ + case PAYLOAD_AUDIO_CONTINUOUS: + case PAYLOAD_AUDIO_PACKETIZED: + codec_band=get_audio_payload_bandwidth(pt); + ret=bandwidth_is_greater(min_audio_bw*1000,codec_band); + //ms_message("Payload %s: %g",pt->mime_type,codec_band); + break; + case PAYLOAD_VIDEO: + if (min_video_bw!=0) {/* infinite (-1) or strictly positive*/ + /*let the video use all the bandwidth minus the maximum bandwidth used by audio */ + if (min_video_bw>0) + pt->normal_bitrate=min_video_bw*1000; + else + pt->normal_bitrate=512000; + ret=TRUE; + } + else ret=FALSE; + break; + } + /*if (!ret) ms_warning("Payload %s is not usable with your internet connection.",pt->mime_type);*/ + + return ret; +} + +static PayloadType * find_payload(RtpProfile *prof, PayloadType *pt /*from config*/){ + PayloadType *candidate=NULL; + int i; + PayloadType *it; + for(i=0;i<127;++i){ + it=rtp_profile_get_payload(prof,i); + if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0 + && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0) + && payload_type_get_user_data(it)==NULL ){ + if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) || + (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){ + /*exact match*/ + return it; + }else candidate=it; + } + } + return candidate; +} + +static MSList *fix_codec_list(RtpProfile *prof, MSList *conflist) +{ + MSList *elem; + MSList *newlist=NULL; + PayloadType *payload,*confpayload; + + for (elem=conflist;elem!=NULL;elem=ms_list_next(elem)) + { + confpayload=(PayloadType*)elem->data; + payload=find_payload(prof,confpayload); + if (payload!=NULL){ + if (ms_filter_codec_supported(confpayload->mime_type)){ + MSFilterDesc *desc=ms_filter_get_encoder(confpayload->mime_type); + payload_type_set_user_data(payload,(void*)desc->text); + payload_type_set_enable(payload,payload_type_enabled(confpayload)); + newlist=ms_list_append(newlist,payload); + } + } + else{ + ms_warning("Cannot support %s/%i: does not exist.",confpayload->mime_type, + confpayload->clock_rate); + } + } + return newlist; +} + + +void linphone_core_setup_local_rtp_profile(LinphoneCore *lc) +{ + int i; + MSList *audiopt,*videopt; + PayloadType *payload; + bool_t prepend; + lc->local_profile=rtp_profile_clone_full(&av_profile); + + /* first look at the list given by configuration file to see if + it is correct */ + audiopt=fix_codec_list(lc->local_profile,lc->codecs_conf.audio_codecs); + videopt=fix_codec_list(lc->local_profile,lc->codecs_conf.video_codecs); + + /* now find and add payloads that are not listed in the configuration + codec list */ + for (i=0;i<127;i++) + { + payload=rtp_profile_get_payload(lc->local_profile,i); + if (payload!=NULL){ + if (payload_type_get_user_data(payload)!=NULL) continue; + /* find a mediastreamer codec for this payload type */ + if (ms_filter_codec_supported(payload->mime_type)){ + MSFilterDesc *desc=ms_filter_get_encoder(payload->mime_type); + ms_message("Adding new codec %s/%i",payload->mime_type,payload->clock_rate); + payload_type_set_enable(payload,1); + payload_type_set_user_data(payload,(void *)desc->text); + prepend=FALSE; + /* by default, put speex, mpeg4, or h264 on top of list*/ + if (strcmp(payload->mime_type,"speex")==0) + prepend=TRUE; + if (strcmp(payload->mime_type,"MP4V-ES")==0) + prepend=TRUE; + if (strcmp(payload->mime_type,"H264")==0) + prepend=TRUE; + switch (payload->type){ + case PAYLOAD_AUDIO_CONTINUOUS: + case PAYLOAD_AUDIO_PACKETIZED: + if (prepend) + audiopt=ms_list_prepend(audiopt,(void *)payload); + else + audiopt=ms_list_append(audiopt,(void *)payload); + break; + case PAYLOAD_VIDEO: + if (prepend) + videopt=ms_list_prepend(videopt,(void *)payload); + else + videopt=ms_list_append(videopt,(void *)payload); + break; + default: + ms_error("Unsupported rtp media type."); + } + } + } + } + ms_list_for_each(lc->codecs_conf.audio_codecs,(void (*)(void*))payload_type_destroy); + ms_list_for_each(lc->codecs_conf.video_codecs,(void (*)(void *))payload_type_destroy); + ms_list_free(lc->codecs_conf.audio_codecs); + ms_list_free(lc->codecs_conf.video_codecs); + /* set the fixed lists instead:*/ + lc->codecs_conf.audio_codecs=audiopt; + lc->codecs_conf.video_codecs=videopt; +} + +int from_2char_without_params(osip_from_t *from,char **str) +{ + osip_from_t *tmpfrom=NULL; + osip_from_clone(from,&tmpfrom); + if (tmpfrom!=NULL){ + while(!osip_list_eol(&tmpfrom->gen_params,0)){ + osip_generic_param_t *param=(osip_generic_param_t*)osip_list_get(&tmpfrom->gen_params,0); + osip_generic_param_free(param); + osip_list_remove(&tmpfrom->gen_params,0); + } + }else return -1; + osip_from_to_str(tmpfrom,str); + osip_from_free(tmpfrom); + return 0; +} + +bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){ + FILE *f=popen(command,"r"); + if (f!=NULL){ + int err; + *result=ms_malloc(4096); + err=fread(*result,1,4096-1,f); + if (err<0){ + ms_warning("Error reading command output:%s",strerror(errno)); + ms_free(result); + return FALSE; + } + (*result)[err]=0; + err=pclose(f); + if (command_ret!=NULL) *command_ret=err; + return TRUE; + } + return FALSE; +} + +#if defined(HAVE_GETIFADDRS) && defined(INET6) +#include +#include +#include +bool_t host_has_ipv6_network() +{ + struct ifaddrs *ifp; + struct ifaddrs *ifpstart; + bool_t ipv6_present=FALSE; + + if (getifaddrs (&ifpstart) < 0) + { + return FALSE; + } + + for (ifp=ifpstart; ifp != NULL; ifp = ifp->ifa_next) + { + if (!ifp->ifa_addr) + continue; + + switch (ifp->ifa_addr->sa_family) { + case AF_INET: + + break; + case AF_INET6: + ipv6_present=TRUE; + break; + default: + continue; + } + } + + freeifaddrs (ifpstart); + + return ipv6_present; +} +#else + +bool_t host_has_ipv6_network() +{ + return FALSE; +} + + +#endif diff --git a/linphone/coreapi/presence.c b/linphone/coreapi/presence.c new file mode 100644 index 000000000..0664fbee7 --- /dev/null +++ b/linphone/coreapi/presence.c @@ -0,0 +1,208 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include +#include +#include "private.h" + + +extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); + + +void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, int did, int nid){ + LinphoneFriend *fl=linphone_friend_new_with_addr(subscriber); + if (fl==NULL) return ; + fl->in_did=did; + linphone_friend_set_nid(fl,nid); + linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept); + fl->inc_subscribe_pending=TRUE; + lc->subscribers=ms_list_append(lc->subscribers,(void *)fl); + if (lc->vtable.new_unknown_subscriber!=NULL) { + char *clean_subscriber; /* we need to remove tags...*/ + from_2char_without_params(fl->url,&clean_subscriber); + lc->vtable.new_unknown_subscriber(lc,fl,clean_subscriber); + ms_free(clean_subscriber); + } +} + +void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){ + linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny); +} + +static void __do_notify(void * data, void * user_data){ + int *tab=(int*)user_data; + LinphoneFriend *lf=(LinphoneFriend*)data; + linphone_friend_notify(lf,tab[0],tab[1]); +} + +void __linphone_core_notify_all_friends(LinphoneCore *lc, int ss, int os){ + int tab[2]; + tab[0]=ss; + tab[1]=os; + ms_list_for_each2(lc->friends,__do_notify,(void *)tab); +} + +void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os){ + ms_message("Notifying all friends that we are in status %i",os); + __linphone_core_notify_all_friends(lc,EXOSIP_SUBCRSTATE_ACTIVE,os); +} + +/* check presence state before answering to call; returns TRUE if we can proceed, else answer the appropriate answer +to close the dialog*/ +bool_t linphone_core_check_presence(LinphoneCore *lc){ + return TRUE; +} + +void linphone_subscription_new(LinphoneCore *lc, eXosip_event_t *ev){ + LinphoneFriend *lf=NULL; + osip_from_t *from=ev->request->from; + char *tmp; + osip_message_t *msg=NULL; + + osip_from_to_str(ev->request->from,&tmp); + + ms_message("Receiving new subscription from %s.",tmp); + /* check if we answer to this subscription */ + if (find_friend(lc->friends,from,&lf)!=NULL){ + lf->in_did=ev->did; + linphone_friend_set_nid(lf,ev->nid); + eXosip_insubscription_build_answer(ev->tid,202,&msg); + eXosip_insubscription_send_answer(ev->tid,202,msg); + __eXosip_wakeup_event(); + linphone_friend_done(lf); /*this will do all necessary actions */ + }else{ + /* check if this subscriber is in our black list */ + if (find_friend(lc->subscribers,from,&lf)){ + if (lf->pol==LinphoneSPDeny){ + ms_message("Rejecting %s because we already rejected it once.",from); + eXosip_insubscription_send_answer(ev->tid,401,NULL); + } + else { + /* else it is in wait for approval state, because otherwise it is in the friend list.*/ + ms_message("New subscriber found in friend list, in %s state.",__policy_enum_to_str(lf->pol)); + } + }else { + eXosip_insubscription_build_answer(ev->tid,202,&msg); + eXosip_insubscription_send_answer(ev->tid,202,msg); + linphone_core_add_subscriber(lc,tmp,ev->did,ev->nid); + } + } + osip_free(tmp); +} + +void linphone_notify_recv(LinphoneCore *lc, eXosip_event_t *ev) +{ + const char *status=_("Gone"); + const char *img="sip-closed.png"; + char *tmp; + LinphoneFriend *lf; + osip_from_t *friend=NULL; + osip_from_t *from=NULL; + osip_body_t *body=NULL; + LinphoneOnlineStatus estatus=LINPHONE_STATUS_UNKNOWN; + ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid); + if (ev->request!=NULL){ + from=ev->request->from; + osip_message_get_body(ev->request,0,&body); + if (body==NULL){ + ms_error("No body in NOTIFY"); + return; + } + if (strstr(body->body,"pending")!=NULL){ + status=_("Waiting for Approval"); + img="sip-wfa.png"; + estatus=LINPHONE_STATUS_PENDING; + }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { + status=_("Online"); + img="sip-online.png"; + estatus=LINPHONE_STATUS_ONLINE; + }else if (strstr(body->body,"busy")!=NULL){ + status=_("Busy"); + img="sip-busy.png"; + estatus=LINPHONE_STATUS_BUSY; + }else if (strstr(body->body,"berightback")!=NULL + || strstr(body->body,"in-transit")!=NULL ){ + status=_("Be Right Back"); + img="sip-bifm.png"; + estatus=LINPHONE_STATUS_BERIGHTBACK; + }else if (strstr(body->body,"away")!=NULL){ + status=_("Away"); + img="sip-away.png"; + estatus=LINPHONE_STATUS_AWAY; + }else if (strstr(body->body,"onthephone")!=NULL + || strstr(body->body,"on-the-phone")!=NULL){ + status=_("On The Phone"); + img="sip-otp.png"; + estatus=LINPHONE_STATUS_ONTHEPHONE; + }else if (strstr(body->body,"outtolunch")!=NULL + || strstr(body->body,"meal")!=NULL){ + status=_("Out To Lunch"); + img="sip-otl.png"; + estatus=LINPHONE_STATUS_OUTTOLUNCH; + }else if (strstr(body->body,"closed")!=NULL){ + status=_("Closed"); + img="sip-away.png"; + estatus=LINPHONE_STATUS_CLOSED; + }else{ + status=_("Gone"); + img="sip-closed.png"; + estatus=LINPHONE_STATUS_OFFLINE; + } + ms_message("We are notified that sip:%s@%s has online status %s",from->url->username,from->url->host,status); + } + lf=linphone_find_friend_by_sid(lc->friends,ev->sid); + if (lf!=NULL){ + friend=lf->url; + from_2char_without_params(friend,&tmp); + lf->status=estatus; + lc->vtable.notify_recv(lc,(LinphoneFriend*)lf,tmp,status,img); + ms_free(tmp); + if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { + lf->sid=-1; + lf->out_did=-1; + ms_message("Outgoing subscription terminated by remote."); + } + }else{ + ms_message("But this person is not part of our friend list, so we don't care."); + } +} + +void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev){ + LinphoneFriend *lf; + osip_from_t *from=ev->response->to; + find_friend(lc->friends,from,&lf); + if (lf!=NULL){ + lf->out_did=ev->did; + linphone_friend_set_sid(lf,ev->sid); + }else{ + ms_warning("Receiving answer for unknown subscribe sip:%s@%s", from->url->username,from->url->host); + } +} +void linphone_subscription_closed(LinphoneCore *lc,eXosip_event_t *ev){ + LinphoneFriend *lf; + osip_from_t *from=ev->request->from; + lf=linphone_find_friend_by_nid(lc->friends,ev->nid); + if (lf!=NULL){ + lf->in_did=-1; + linphone_friend_set_nid(lf,-1); + }else{ + ms_warning("Receiving unsuscribe for unknown in-subscribtion from sip:%s@%s", from->url->username, from->url->host); + } +} diff --git a/linphone/coreapi/private.h b/linphone/coreapi/private.h new file mode 100644 index 000000000..bbb06a39b --- /dev/null +++ b/linphone/coreapi/private.h @@ -0,0 +1,121 @@ +/*************************************************************************** + * private.h + * + * Mon Jun 13 14:23:23 2005 + * Copyright 2005 Simon Morlat + * Email simon dot morlat at linphone dot org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PRIVATE_H +#define _PRIVATE_H + +#include "linphonecore.h" +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef LINPHONE_VERSION +#define LINPHONE_VERSION "2.99.4" +#endif + +#ifndef LIBLINPHONE_VERSION +#define LIBLINPHONE_VERSION LINPHONE_VERSION +#endif + +#ifndef PACKAGE_SOUND_DIR +#define PACKAGE_SOUND_DIR "." +#endif + +#ifdef WIN32 +#include /* for access() */ +#endif + +#ifdef HAVE_GETTEXT +#include +#ifndef _ +#define _(String) gettext(String) +#endif +#else +#define _(something) (something) +#endif + +void linphone_core_init_media_streams(LinphoneCore *lc); + +void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos); + +void linphone_core_update_proxy_register(LinphoneCore *lc); +void linphone_core_refresh_subscribes(LinphoneCore *lc); + +int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); + +int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); + +void linphone_friend_set_sid(LinphoneFriend *lf, int sid); +void linphone_friend_set_nid(LinphoneFriend *lf, int nid); +void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os); + +int set_lock_file(); +int get_lock_file(); +int remove_lock_file(); +int do_registration(LinphoneCore *lc, bool_t doit); +void check_for_registration(LinphoneCore *lc); +char *int2str(int number); +int from_2char_without_params(osip_from_t *from,char **str); +void check_sound_device(LinphoneCore *lc); +void linphone_core_setup_local_rtp_profile(LinphoneCore *lc); +void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); +bool_t host_has_ipv6_network(); +bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); + +static inline int get_min_bandwidth(int dbw, int ubw){ + if (dbw<0) return ubw; + if (ubw<0) return dbw; + return MIN(dbw,ubw); +} + +static inline bool_t bandwidth_is_greater(int bw1, int bw2){ + if (bw1<0) return TRUE; + else if (bw2<0) return FALSE; + else return bw1>=bw2; +} + +#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 + +void linphone_process_authentication(LinphoneCore* lc, eXosip_event_t *ev); +void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev); +void linphone_subscription_new(LinphoneCore *lc, eXosip_event_t *ev); +void linphone_notify_recv(LinphoneCore *lc,eXosip_event_t *ev); +LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid); + +void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev); +void linphone_subscription_closed(LinphoneCore *lc, eXosip_event_t *ev); + +void linphone_call_init_media_params(LinphoneCall *call); + +void linphone_set_sdp(osip_message_t *sip, const char *sdp); + +MSList *find_friend(MSList *fl, const osip_from_t *friend, LinphoneFriend **lf); +LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid); +LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid); + +void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc, const PayloadType *pt); + +#endif /* _PRIVATE_H */ diff --git a/linphone/coreapi/proxy.c b/linphone/coreapi/proxy.c new file mode 100644 index 000000000..458cbadcf --- /dev/null +++ b/linphone/coreapi/proxy.c @@ -0,0 +1,512 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) +*/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "linphonecore.h" +#include +#include +#include "lpconfig.h" +#include "private.h" + + +void linphone_proxy_config_init(LinphoneProxyConfig *obj){ + memset(obj,0,sizeof(LinphoneProxyConfig)); + obj->rid=-1; + obj->expires=3600; +} + +LinphoneProxyConfig *linphone_proxy_config_new(){ + LinphoneProxyConfig *obj=NULL; + obj=ms_new(LinphoneProxyConfig,1); + linphone_proxy_config_init(obj); + return obj; +} + +void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ + if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); + if (obj->reg_identity!=NULL) ms_free(obj->reg_identity); + if (obj->reg_route!=NULL) ms_free(obj->reg_route); +} + +static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ + osip_message_t *msg; + eXosip_lock(); + eXosip_register_build_register(obj->rid,obj->expires,&msg); + eXosip_register_send_register(obj->rid,msg); + eXosip_unlock(); +} + + +int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){ + int err; + osip_from_t *url; + if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); + obj->reg_proxy=NULL; + if (server_addr!=NULL && strlen(server_addr)>0){ + osip_from_init(&url); + err=osip_from_parse(url,server_addr); + if (err==0 && url->url->host!=NULL){ + obj->reg_proxy=ms_strdup(server_addr); + }else{ + ms_warning("Could not parse %s",server_addr); + } + osip_from_free(url); + } + return 0; +} + +void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){ + int err=0; + osip_from_t *url; + if (identity!=NULL && strlen(identity)>0){ + osip_from_init(&url); + err=osip_from_parse(url,identity); + if (err<0 || url->url->host==NULL || url->url->username==NULL){ + ms_warning("Could not parse %s",identity); + osip_from_free(url); + return; + } + osip_from_free(url); + } else err=-2; + if (obj->reg_identity!=NULL) { + ms_free(obj->reg_identity); + obj->reg_identity=NULL; + } + if (err==-2) obj->reg_identity=NULL; + else obj->reg_identity=ms_strdup(identity); +} + +void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) +{ + int err; + osip_uri_param_t *lr_param=NULL; + osip_route_t *rt=NULL; + char *tmproute=NULL; + if (route!=NULL && strlen(route)>0){ + osip_route_init(&rt); + err=osip_route_parse(rt,route); + if (err<0){ + ms_warning("Could not parse %s",route); + osip_route_free(rt); + return ; + } + if (obj->reg_route!=NULL) { + ms_free(obj->reg_route); + obj->reg_route=NULL; + } + + /* check if the lr parameter is set , if not add it */ + osip_uri_uparam_get_byname(rt->url, "lr", &lr_param); + if (lr_param==NULL){ + osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); + osip_route_to_str(rt,&tmproute); + obj->reg_route=ms_strdup(tmproute); + osip_free(tmproute); + }else obj->reg_route=ms_strdup(route); + }else{ + if (obj->reg_route!=NULL) ms_free(obj->reg_route); + obj->reg_route=NULL; + } +} + +bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *obj){ + if (obj->reg_proxy==NULL){ + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,_("The sip proxy address you entered is invalid, it must start with \"sip:\"" + " followed by a hostname.")); + return FALSE; + } + if (obj->reg_identity==NULL){ + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like " + "sip:username@proxydomain, such as sip:alice@example.net")); + return FALSE; + } + return TRUE; +} + +void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){ + obj->reg_sendregister=val; +} + +void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int val){ + if (val<=0) val=600; + obj->expires=val; +} + +void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ + obj->publish=val; +} + +void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ + obj->frozen=TRUE; + if (obj->reg_sendregister){ + /* unregister */ + if (obj->registered) { + osip_message_t *msg; + eXosip_lock(); + eXosip_register_build_register(obj->rid,0,&msg); + eXosip_register_send_register(obj->rid,msg); + eXosip_unlock(); + obj->registered=FALSE; + } + } +} + +void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) +{ + obj->lc=lc; + linphone_proxy_config_done(obj); +} + +int linphone_proxy_config_done(LinphoneProxyConfig *obj) +{ + const char *id_str; + if (!linphone_proxy_config_check(obj->lc,obj)) return -1; + if (obj->reg_identity!=NULL) id_str=obj->reg_identity; + else id_str=linphone_core_get_primary_contact(obj->lc); + obj->frozen=FALSE; + if (obj->reg_sendregister){ + char *ct=NULL; + osip_message_t *msg=NULL; + obj->rid=eXosip_register_build_initial_register(id_str,obj->reg_proxy,NULL,obj->expires,&msg); + eXosip_register_send_register(obj->rid,msg); + if (ct!=NULL) osip_free(ct); + } + return 0; +} + +void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm) +{ + if (cfg->realm!=NULL) { + ms_free(cfg->realm); + cfg->realm=NULL; + } + if (realm!=NULL) cfg->realm=ms_strdup(realm); +} + +int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, + LinphoneOnlineStatus presence_mode) +{ + osip_message_t *pub; + int i; + const char *from=NULL; + char buf[5000]; + + if (proxy->publish==FALSE) return 0; + + if (proxy!=NULL) { + from=linphone_proxy_config_get_identity(proxy); + } + if (from==NULL) from=linphone_core_get_primary_contact(proxy->lc); + + if (presence_mode==LINPHONE_STATUS_ONLINE) + { + snprintf(buf, 5000, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ +%s\n\ +online\n\ +\n\ +", + from, from); + } + else if (presence_mode==LINPHONE_STATUS_BUSY + ||presence_mode==LINPHONE_STATUS_NOT_DISTURB) + { + snprintf(buf, 5000, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + busy\n\ +\n\ +\n\ +%s\n\ +busy\n\ +\n\ +", + from, from); + } + else if (presence_mode==LINPHONE_STATUS_BERIGHTBACK) + { + snprintf(buf, 5000, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + in-transit\n\ +\n\ +\n\ +%s\n\ +be right back\n\ +\n\ +", + from,from); + } + else if (presence_mode==LINPHONE_STATUS_AWAY + ||presence_mode==LINPHONE_STATUS_MOVED + ||presence_mode==LINPHONE_STATUS_ALT_SERVICE) + { + snprintf(buf, 5000, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + away\n\ +\n\ +\n\ +%s\n\ +away\n\ +\n\ +", + from, from); + } + else if (presence_mode==LINPHONE_STATUS_ONTHEPHONE) + { + snprintf(buf, 5000, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + on-the-phone\n\ +\n\ +\n\ +%s\n\ +on the phone\n\ +\n\ +", + from, from); + } + else if (presence_mode==LINPHONE_STATUS_OUTTOLUNCH) + { + snprintf(buf, 5000, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + meal\n\ +\n\ +\n\ +%s\n\ +out to lunch\n\ +\n\ +", + from, from); + } + else if (presence_mode==LINPHONE_STATUS_OFFLINE) + { + /* */ + snprintf(buf, 5000, "\n\ +\n%s", + from, +"\n\ +\n\ +closed\n\ +\n\ + permanent-absence\n\ +\n\ +\n\ +\n\ +\n\n"); + } + + i = eXosip_build_publish(&pub, (char *)from, (char *)from, NULL, "presence", "1800", "application/pidf+xml", buf); + + if (i<0) + { + ms_message("Failed to build publish request."); + return -1; + } + + eXosip_lock(); + i = eXosip_publish(pub, from); /* should update the sip-if-match parameter + from sip-etag from last 200ok of PUBLISH */ + eXosip_unlock(); + if (i<0) + { + ms_message("Failed to send publish request."); + return -1; + } + return 0; +} + +int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ + if (!linphone_proxy_config_check(lc,cfg)) return -1; + lc->sip_conf.proxies=ms_list_append(lc->sip_conf.proxies,(void *)cfg); + linphone_proxy_config_apply(cfg,lc); + return 0; +} + +extern void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg); + +void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ + MSList *elem; + lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,(void *)cfg); + /* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */ + lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,(void *)cfg); + /* this will unREGISTER */ + linphone_proxy_config_edit(cfg); + if (lc->default_proxy==cfg){ + lc->default_proxy=NULL; + } + /* invalidate all references to this proxy in our friend list */ + for (elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){ + linphone_friend_check_for_removed_proxy((LinphoneFriend*)elem->data,cfg); + } + +} + +void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config){ + /* check if this proxy is in our list */ + if (config!=NULL){ + if (ms_list_find(lc->sip_conf.proxies,config)==NULL){ + ms_warning("Bad proxy address: it is not in the list !"); + lc->default_proxy=NULL; + return ; + } + } + lc->default_proxy=config; + +} + + +void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){ + if (index<0) linphone_core_set_default_proxy(lc,NULL); + else linphone_core_set_default_proxy(lc,ms_list_nth_data(lc->sip_conf.proxies,index)); +} + +int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config){ + int pos=-1; + if (config!=NULL) *config=lc->default_proxy; + if (lc->default_proxy!=NULL){ + pos=ms_list_position(lc->sip_conf.proxies,ms_list_find(lc->sip_conf.proxies,(void *)lc->default_proxy)); + } + return pos; +} + +static int rid_compare(const void *pcfg,const void *prid){ + const LinphoneProxyConfig *cfg=(const LinphoneProxyConfig*)pcfg; + const int *rid=(const int*)prid; + ms_message("cfg= %s, cfg->rid=%i, rid=%i",cfg->reg_proxy, cfg->rid, *rid); + return cfg->rid-(*rid); +} + +LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid){ + MSList *elem=ms_list_find_custom(lc->sip_conf.proxies,rid_compare, &rid); + if (elem==NULL){ + ms_message("linphone_core_get_proxy_config_from_rid: searching in deleted proxies..."); + elem=ms_list_find_custom(lc->sip_conf.deleted_proxies,rid_compare, &rid); + } + if (elem==NULL) return NULL; + else return (LinphoneProxyConfig*)elem->data; +} + +void linphone_core_retry_proxy_register(LinphoneCore *lc, const char *realm) +{ + MSList *elem; + for (elem=lc->sip_conf.proxies;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + /*ms_message("linphone_core_retry_proxy_register: cfg->auth_pending=%i, cfg->realm=%s, realm=%s", + cfg->auth_pending,cfg->realm,realm);*/ + if (cfg->auth_pending && cfg->realm!=NULL && strcmp(cfg->realm,realm)==0){ + ms_message("Restarting REGISTER request for %s.",cfg->reg_proxy); + linphone_proxy_config_register(cfg); + } + } +} + +const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc){ + return lc->sip_conf.proxies; +} + + +void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *obj, int index) +{ + char key[50]; + + sprintf(key,"proxy_%i",index); + lp_config_clean_section(config,key); + if (obj==NULL){ + return; + } + if (obj->reg_proxy!=NULL){ + lp_config_set_string(config,key,"reg_proxy",obj->reg_proxy); + } + if (obj->reg_route!=NULL){ + lp_config_set_string(config,key,"reg_route",obj->reg_route); + } + if (obj->reg_identity!=NULL){ + lp_config_set_string(config,key,"reg_identity",obj->reg_identity); + } + lp_config_set_int(config,key,"reg_expires",obj->expires); + lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); + lp_config_set_int(config,key,"publish",obj->publish); +} + +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config, int index) +{ + const char *tmp; + LinphoneProxyConfig *cfg; + char key[50]; + + sprintf(key,"proxy_%i",index); + + if (!lp_config_has_section(config,key)){ + return NULL; + } + tmp=lp_config_get_string(config,key,"reg_proxy",NULL); + if (tmp==NULL) return NULL; + cfg=linphone_proxy_config_new(); + linphone_proxy_config_set_server_addr(cfg,tmp); + + tmp=lp_config_get_string(config,key,"reg_route",NULL); + if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); + + tmp=lp_config_get_string(config,key,"reg_identity",NULL); + if (tmp!=NULL) linphone_proxy_config_set_identity(cfg,tmp); + + linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",600)); + linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); + + linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); + + return cfg; +} diff --git a/linphone/coreapi/sdphandler.c b/linphone/coreapi/sdphandler.c new file mode 100644 index 000000000..e83af1a17 --- /dev/null +++ b/linphone/coreapi/sdphandler.c @@ -0,0 +1,682 @@ +/* + * Linphone is sip (RFC3261) compatible internet phone. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "sdphandler.h" +#include +#include +#include +#include "linphonecore.h" +#include "ortp/b64.h" + +#define keywordcmp(key,str) strncmp(key,str,strlen(key)) + + +#define sstrdup_sprintf ms_strdup_printf + +#define eXosip_trace(loglevel,args) do \ +{ \ + char *__strmsg; \ + __strmsg=ms_strdup_printf args ; \ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,(loglevel),NULL,"%s\n",__strmsg)); \ + osip_free (__strmsg); \ +}while (0); + + +static char *make_relay_session_id(const char *username, const char *relay){ + /*ideally this should be a hash of the parameters with a random part*/ + char tmp[128]; + int s1=(int)random(); + int s2=(int)random(); + long long int res=((long long int)s1)<<32 | (long long int) s2; + void *src=&res; + b64_encode(src, sizeof(long long int), tmp, sizeof(tmp)); + return osip_strdup(tmp); +} + +char * int_2char(int a){ + char *p=osip_malloc(16); + snprintf(p,16,"%i",a); + return p; +} + +/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/ +char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field) +{ + int i,tmppt=0,scanned=0; + char *tmp; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ + if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ + int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned); + /* the return value may depend on how %n is interpreted by the libc: see manpage*/ + if (nb == 1 || nb==2 ){ + if (pt==tmppt){ + tmp=attr->a_att_value+scanned; + if (strlen(tmp)>0) + return tmp; + } + }else eXosip_trace(OSIP_WARNING,("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb)); + } + } + return NULL; +} + +/* return the value of attr "field" */ +char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field) +{ + int i; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ + if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ + return attr->a_att_value; + } + } + return NULL; +} + +static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ + int i,ret; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ + if (keywordcmp("ptime",attr->a_att_field)==0){ + int nb = sscanf(attr->a_att_value,"%i",&ret); + /* the return value may depend on how %n is interpreted by the libc: see manpage*/ + if (nb == 1){ + return ret; + }else eXosip_trace(OSIP_WARNING,("sdp has a strange a=ptime line (%s) ",attr->a_att_value)); + } + } + return 0; +} + +int +sdp_payload_init (sdp_payload_t * payload) +{ + memset (payload, 0, sizeof (sdp_payload_t)); + return 0; +} + +sdp_context_t *sdp_handler_create_context(sdp_handler_t *handler, const char *localip, const char *username, const char *relay){ + sdp_context_t *ctx=osip_malloc(sizeof(sdp_context_t)); + memset(ctx,0,sizeof(sdp_context_t)); + if (localip!=NULL) ctx->localip=osip_strdup(localip); + ctx->username=osip_strdup(username); + ctx->handler=handler; + if (relay){ + ctx->relay=osip_strdup(relay); + ctx->relay_session_id=make_relay_session_id(username,relay); + } + return ctx; +} + +void sdp_context_set_user_pointer(sdp_context_t * ctx, void* up){ + ctx->reference=up; +} + +void *sdp_context_get_user_pointer(sdp_context_t * ctx){ + return ctx->reference; +} + +int sdp_context_get_status(sdp_context_t* ctx){ + return ctx->negoc_status; +} + +/* generate a template sdp */ +sdp_message_t * +sdp_context_generate_template (sdp_context_t * ctx) +{ + sdp_message_t *local; + int inet6; + + sdp_message_init (&local); + if (strchr(ctx->localip,':')!=NULL){ + inet6=1; + }else inet6=0; + if (!inet6){ + sdp_message_v_version_set (local, osip_strdup ("0")); + sdp_message_o_origin_set (local, osip_strdup (ctx->username), + osip_strdup ("123456"), osip_strdup ("654321"), + osip_strdup ("IN"), osip_strdup ("IP4"), + osip_strdup (ctx->localip)); + sdp_message_s_name_set (local, osip_strdup ("A conversation")); + sdp_message_c_connection_add (local, -1, + osip_strdup ("IN"), osip_strdup ("IP4"), + osip_strdup (ctx->localip), NULL, NULL); + sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); + }else{ + sdp_message_v_version_set (local, osip_strdup ("0")); + sdp_message_o_origin_set (local, osip_strdup (ctx->username), + osip_strdup ("123456"), osip_strdup ("654321"), + osip_strdup ("IN"), osip_strdup ("IP6"), + osip_strdup (ctx->localip)); + sdp_message_s_name_set (local, osip_strdup ("A conversation")); + sdp_message_c_connection_add (local, -1, + osip_strdup ("IN"), osip_strdup ("IP6"), + osip_strdup (ctx->localip), NULL, NULL); + sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); + } + return local; +} + +static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){ + + if (relay) sdp_message_a_attribute_add(sdp, mline, + osip_strdup ("relay-addr"),osip_strdup(relay)); + if (relay_session_id) sdp_message_a_attribute_add(sdp, mline, + osip_strdup ("relay-session-id"), osip_strdup(relay_session_id)); +} + +/* to add payloads to the offer, must be called inside the write_offer callback */ +void +sdp_context_add_payload (sdp_context_t * ctx, sdp_payload_t * payload, char *media) +{ + sdp_message_t *offer = ctx->offer; + char *attr_field; + if (!ctx->incb) + { + eXosip_trace (OSIP_ERROR, + ("You must not call sdp_context_add_*_payload outside the write_offer callback\n")); + abort (); + } + if (payload->proto == NULL) + payload->proto = "RTP/AVP"; + /*printf("payload->line=%i payload->pt=%i\n",payload->line, payload->pt);*/ + if (sdp_message_m_media_get (offer, payload->line) == NULL) + { + /*printf("Adding new mline %s \n",media);*/ + /* need a new line */ + sdp_message_m_media_add (offer, osip_strdup (media), + int_2char (payload->localport), NULL, + osip_strdup (payload->proto)); + if (ctx->relay){ + add_relay_info(offer,payload->line,ctx->relay,ctx->relay_session_id); + } + } + sdp_message_m_payload_add (offer, payload->line, int_2char (payload->pt)); + if (payload->a_rtpmap != NULL) + { + attr_field = + sstrdup_sprintf ("%i %s", payload->pt, + payload->a_rtpmap); + sdp_message_a_attribute_add (offer, payload->line, + osip_strdup ("rtpmap"), attr_field); + } + if (payload->a_fmtp != NULL) + { + attr_field = + sstrdup_sprintf ("%i %s", payload->pt, + payload->a_fmtp); + sdp_message_a_attribute_add (offer, payload->line, osip_strdup ("fmtp"), + attr_field); + } + if (payload->b_as_bandwidth != 0) + { + if (sdp_message_bandwidth_get(offer,payload->line,0)==NULL){ + attr_field = + sstrdup_sprintf ("%i", payload->b_as_bandwidth); + sdp_message_b_bandwidth_add (offer, payload->line, osip_strdup ("AS"), + attr_field); + } + } +} + +void +sdp_context_add_audio_payload (sdp_context_t * ctx, sdp_payload_t * payload) +{ + sdp_context_add_payload (ctx, payload, "audio"); +} + +void +sdp_context_add_video_payload (sdp_context_t * ctx, sdp_payload_t * payload) +{ + sdp_context_add_payload (ctx, payload, "video"); +} + +char * +sdp_context_get_offer ( sdp_context_t * ctx) +{ + sdp_message_t *offer; + sdp_handler_t *sdph=ctx->handler; + char *tmp; + + offer = sdp_context_generate_template (ctx); + /* add audio codecs */ + ctx->offer = offer; + ctx->incb = 1; + if (sdph->set_audio_codecs != NULL) + sdph->set_audio_codecs (ctx); + if (sdph->set_video_codecs != NULL) + sdph->set_video_codecs (ctx); + ctx->incb = 0; + sdp_message_to_str(offer,&tmp); + ctx->offerstr=tmp; + return tmp; +} + + +/* refuse the line */ +static void refuse_mline(sdp_message_t *answer,char *mtype,char *proto, int mline) +{ + sdp_message_m_media_add (answer, + osip_strdup (mtype), + int_2char (0), NULL, + osip_strdup (proto)); + /* add a payload just to comply with sdp RFC.*/ + sdp_message_m_payload_add(answer,mline,int_2char(0)); +} + +static char * parse_relay_addr(char *addr, int *port) +{ + char *semicolon=NULL; + char *p; + + *port=56789; + semicolon=strchr(addr,':'); + for (p=addr+strlen(addr)-1;p>addr;p--){ + if (*p==':') { + semicolon=p; + break; + } + } + if (semicolon){ + *port=atoi(semicolon+1); + *semicolon='\0'; + } + return addr; +} + + +char * +sdp_context_get_answer ( sdp_context_t *ctx,sdp_message_t *remote) +{ + sdp_message_t *answer=NULL; + char *mtype=NULL, *tmp=NULL; + char *proto=NULL, *port=NULL, *pt=NULL; + int i, j, ncodec, m_lines_accepted = 0; + int err; + sdp_payload_t payload; + sdp_handler_t *sdph=ctx->handler; + sdp_bandwidth_t *sbw=NULL; + char *relay; + + tmp = sdp_message_c_addr_get (remote, 0, 0); + if (tmp == NULL) + tmp = sdp_message_c_addr_get (remote, -1, 0); + if (ctx->localip==NULL) { + /* NULL means guess, otherwise we use the address given as localip */ + ctx->localip=osip_malloc(128); + eXosip_guess_localip(strchr(tmp,':') ? AF_INET6 : AF_INET,ctx->localip,128); + } + else eXosip_trace(OSIP_INFO1,("Using firewall address in sdp.")); + + answer = sdp_context_generate_template (ctx); + + /* for each m= line */ + for (i = 0; !sdp_message_endof_media (remote, i); i++) + { + sdp_payload_init(&payload); + mtype = sdp_message_m_media_get (remote, i); + proto = sdp_message_m_proto_get (remote, i); + port = sdp_message_m_port_get (remote, i); + payload.remoteport = osip_atoi (port); + payload.proto = proto; + payload.line = i; + payload.c_addr = sdp_message_c_addr_get (remote, i, 0); + if (payload.c_addr == NULL) + payload.c_addr = sdp_message_c_addr_get (remote, -1, 0); + /*parse relay address if given*/ + relay=sdp_message_a_attr_value_get(remote,i,"relay-addr"); + if (relay){ + payload.relay_host=parse_relay_addr(relay,&payload.relay_port); + } + payload.relay_session_id=sdp_message_a_attr_value_get(remote,i,"relay-session-id"); + /* get application specific bandwidth, if any */ + for(j=0;(sbw=sdp_message_bandwidth_get(remote,i,j))!=NULL;j++){ + if (strcasecmp(sbw->b_bwtype,"AS")==0) payload.b_as_bandwidth=atoi(sbw->b_bandwidth); + } + payload.a_ptime=_sdp_message_get_a_ptime(remote,i); + if (keywordcmp ("audio", mtype) == 0) + { + if (sdph->accept_audio_codecs != NULL) + { + ncodec = 0; + /* for each payload type */ + for (j = 0; + ((pt = + sdp_message_m_payload_get (remote, i, + j)) != NULL); j++) + { + payload.pt = osip_atoi (pt); + /* get the rtpmap associated to this codec, if any */ + payload.a_rtpmap = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "rtpmap"); + /* get the fmtp, if any */ + payload.a_fmtp = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "fmtp"); + + /* ask the application if this codec is supported */ + err = sdph->accept_audio_codecs (ctx, + &payload); + if (err == 0 && payload.localport > 0) + { + ncodec++; + /* codec accepted */ + if (ncodec == 1) + { + /* first codec accepted, setup the line */ + sdp_message_m_media_add + (answer, + osip_strdup + (mtype), + int_2char + (payload. + localport), + NULL, + osip_strdup + (proto)); + /* and accept the remote relay addr if we planned to use our own */ + if (ctx->relay!=NULL && relay){ + add_relay_info(answer,i,relay,payload.relay_session_id); + } + } + /* add the payload, rtpmap, fmtp */ + sdp_message_m_payload_add (answer, i, + int_2char + (payload. + pt)); + if (payload.a_rtpmap != NULL) + { + sdp_message_a_attribute_add + (answer, i, + osip_strdup + ("rtpmap"), + sstrdup_sprintf + ("%i %s", + payload.pt, + payload. + a_rtpmap)); + } + if (payload.a_fmtp != NULL) + { + sdp_message_a_attribute_add + (answer, i, + osip_strdup + ("fmtp"), + sstrdup_sprintf + ("%i %s", + payload.pt, + payload. + a_fmtp)); + } + if (payload.b_as_bandwidth != + 0) + { + if (sdp_message_bandwidth_get(answer,i,0)==NULL) + sdp_message_b_bandwidth_add + (answer, i, + osip_strdup + ("AS"), + sstrdup_sprintf + ("%i", + payload. + b_as_bandwidth)); + } + } + } + if (ncodec == 0) + { + /* refuse the line */ + refuse_mline(answer,mtype,proto,i); + + } + else + m_lines_accepted++; + } + else + { + /* refuse this line (leave port to 0) */ + refuse_mline(answer,mtype,proto,i); + } + + } + else if (keywordcmp ("video", mtype) == 0) + { + if (sdph->accept_video_codecs != NULL) + { + ncodec = 0; + /* for each payload type */ + for (j = 0; + ((pt = + sdp_message_m_payload_get (remote, i, + j)) != NULL); j++) + { + payload.pt = osip_atoi (pt); + /* get the rtpmap associated to this codec, if any */ + payload.a_rtpmap = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "rtpmap"); + /* get the fmtp, if any */ + payload.a_fmtp = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "fmtp"); + /* ask the application if this codec is supported */ + err = sdph->accept_video_codecs (ctx, + &payload); + if (err == 0 && payload.localport > 0) + { + ncodec++; + /* codec accepted */ + if (ncodec == 1) + { + /* first codec accepted, setup the line */ + sdp_message_m_media_add + (answer, + osip_strdup + (mtype), + int_2char + (payload.localport), NULL, + osip_strdup + (proto)); + /* and accept the remote relay addr if we planned to use our own */ + if (ctx->relay!=NULL && relay){ + add_relay_info(answer,i,relay,payload.relay_session_id); + } + } + /* add the payload, rtpmap, fmtp */ + sdp_message_m_payload_add (answer, i, + int_2char + (payload. + pt)); + if (payload.a_rtpmap != NULL) + { + sdp_message_a_attribute_add + (answer, i, + osip_strdup + ("rtpmap"), + sstrdup_sprintf + ("%i %s", + payload.pt, + payload. + a_rtpmap)); + } + if (payload.a_fmtp != NULL) + { + sdp_message_a_attribute_add + (answer, i, + osip_strdup + ("fmtp"), + sstrdup_sprintf + ("%i %s", + payload.pt, + payload. + a_fmtp)); + } + if (payload.b_as_bandwidth !=0) + { + if (sdp_message_bandwidth_get(answer,i,0)==NULL) + sdp_message_b_bandwidth_add + (answer, i, + osip_strdup + ("AS"), + sstrdup_sprintf + ("%i", + payload. + b_as_bandwidth)); + } + } + } + if (ncodec == 0) + { + /* refuse the line */ + refuse_mline(answer,mtype,proto,i); + } + else + m_lines_accepted++; + } + else + { + /* refuse the line */ + refuse_mline(answer,mtype,proto,i); + } + } + } + if (ctx->answer!=NULL) + sdp_message_free(ctx->answer); + ctx->answer = answer; + if (m_lines_accepted > 0){ + ctx->negoc_status = 200; + sdp_message_to_str(answer,&tmp); + if (ctx->answerstr!=NULL) + osip_free(ctx->answerstr); + ctx->answerstr=tmp; + return tmp; + }else{ + ctx->negoc_status = 415; + return NULL; + } +} + +void +sdp_context_read_answer (sdp_context_t *ctx, sdp_message_t *remote) +{ + char *mtype; + char *proto, *port, *pt; + int i, j,err; + char *relay; + sdp_payload_t payload,arg_payload; + sdp_handler_t *sdph=ctx->handler; + sdp_bandwidth_t *sbw=NULL; + /* for each m= line */ + for (i = 0; !sdp_message_endof_media (remote, i); i++) + { + sdp_payload_init(&payload); + mtype = sdp_message_m_media_get (remote, i); + proto = sdp_message_m_proto_get (remote, i); + port = sdp_message_m_port_get (remote, i); + payload.remoteport = osip_atoi (port); + payload.localport = osip_atoi (sdp_message_m_port_get (ctx->offer, i)); + payload.proto = proto; + payload.line = i; + payload.c_addr = sdp_message_c_addr_get (remote, i, 0); + if (payload.c_addr == NULL) + payload.c_addr = sdp_message_c_addr_get (remote, -1, 0); + /*parse relay address if given*/ + relay=sdp_message_a_attr_value_get(remote,i,"relay-addr"); + if (relay){ + payload.relay_host=parse_relay_addr(relay,&payload.relay_port); + } + payload.relay_session_id=sdp_message_a_attr_value_get(remote,i,"relay-session-id"); + for(j=0;(sbw=sdp_message_bandwidth_get(remote,i,j))!=NULL;++j){ + if (strcasecmp(sbw->b_bwtype,"AS")==0) payload.b_as_bandwidth=atoi(sbw->b_bandwidth); + } + payload.a_ptime=_sdp_message_get_a_ptime(remote,i); + if (keywordcmp ("audio", mtype) == 0) + { + if (sdph->get_audio_codecs != NULL) + { + /* for each payload type */ + for (j = 0; + ((pt = + sdp_message_m_payload_get (remote, i, + j)) != NULL); j++) + { + payload.pt = osip_atoi (pt); + /* get the rtpmap associated to this codec, if any */ + payload.a_rtpmap = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "rtpmap"); + /* get the fmtp, if any */ + payload.a_fmtp = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "fmtp"); + /* ask the application if this codec is supported */ + memcpy(&arg_payload,&payload,sizeof(payload)); + err = sdph->get_audio_codecs (ctx, + &arg_payload); + } + } + } + else if (keywordcmp ("video", mtype) == 0) + { + if (sdph->get_video_codecs != NULL) + { + /* for each payload type */ + for (j = 0; + ((pt = + sdp_message_m_payload_get (remote, i, + j)) != NULL); j++) + { + payload.pt = osip_atoi (pt); + /* get the rtpmap associated to this codec, if any */ + payload.a_rtpmap = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "rtpmap"); + /* get the fmtp, if any */ + payload.a_fmtp = + sdp_message_a_attr_value_get_with_pt + (remote, i, payload.pt, + "fmtp"); + /* ask the application if this codec is supported */ + memcpy(&arg_payload,&payload,sizeof(payload)); + err = sdph->get_video_codecs (ctx, + &arg_payload); + } + } + } + } +} +void sdp_context_free(sdp_context_t *ctx){ + osip_free(ctx->localip); + osip_free(ctx->username); + if (ctx->offer!=NULL) sdp_message_free(ctx->offer); + if (ctx->answer!=NULL) sdp_message_free(ctx->answer); + if (ctx->offerstr!=NULL) osip_free(ctx->offerstr); + if (ctx->answerstr!=NULL) osip_free(ctx->answerstr); + if (ctx->relay!=NULL) osip_free(ctx->relay); + if (ctx->relay_session_id!=NULL) osip_free(ctx->relay_session_id); + osip_free(ctx); +} diff --git a/linphone/coreapi/sdphandler.h b/linphone/coreapi/sdphandler.h new file mode 100644 index 000000000..b3e811b70 --- /dev/null +++ b/linphone/coreapi/sdphandler.h @@ -0,0 +1,101 @@ + /* + * Linphone is sip (RFC3261) compatible internet phone. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SDP_HANDLER_H +#define SDP_HANDLER_H + +#include +#include "linphonecore.h" + +typedef struct _sdp_payload +{ + int line; /* the index of the m= line */ + int pt; /*payload type */ + int localport; + int remoteport; + int b_as_bandwidth; /* application specific bandwidth */ + char *proto; + char *c_nettype; + char *c_addrtype; + char *c_addr; + char *c_addr_multicast_ttl; + char *c_addr_multicast_int; + char *a_rtpmap; + char *a_fmtp; + char *relay_host; + int relay_port; + char *relay_session_id; + int a_ptime; +} sdp_payload_t; + +typedef struct _sdp_context sdp_context_t; + +typedef int (*sdp_handler_read_codec_func_t) (struct _sdp_context *, + sdp_payload_t *); +typedef int (*sdp_handler_write_codec_func_t) (struct _sdp_context *); + +typedef struct _sdp_handler +{ + sdp_handler_read_codec_func_t accept_audio_codecs; /*from remote sdp */ + sdp_handler_read_codec_func_t accept_video_codecs; /*from remote sdp */ + sdp_handler_write_codec_func_t set_audio_codecs; /*to local sdp */ + sdp_handler_write_codec_func_t set_video_codecs; /*to local sdp */ + sdp_handler_read_codec_func_t get_audio_codecs; /*from incoming answer */ + sdp_handler_read_codec_func_t get_video_codecs; /*from incoming answer */ +} sdp_handler_t; + + +typedef enum _sdp_context_state +{ + SDP_CONTEXT_STATE_INIT, + SDP_CONTEXT_STATE_NEGOCIATION_OPENED, + SDP_CONTEXT_STATE_NEGOCIATION_CLOSED +} sdp_context_state_t; + +struct _sdp_context +{ + sdp_handler_t *handler; + char *localip; + char *username; + void *reference; + sdp_message_t *offer; /* the local sdp to be used for outgoing request */ + char *offerstr; + sdp_message_t *answer; /* the local sdp generated from an inc request */ + char *answerstr; + char *relay; + char *relay_session_id; + int negoc_status; /* in sip code */ + int incb; + sdp_context_state_t state; +}; + +/* create a context for a sdp negociation: localip is the ip address to be used in the sdp message, can +be a firewall address. +It can be null when negociating for an incoming offer; In that case it will be guessed. */ +sdp_context_t *sdp_handler_create_context(sdp_handler_t *handler, const char *localip, const char *username, const char *relay); +void sdp_context_set_user_pointer(sdp_context_t * ctx, void* up); +void *sdp_context_get_user_pointer(sdp_context_t * ctx); +void sdp_context_add_audio_payload( sdp_context_t * ctx, sdp_payload_t * payload); +void sdp_context_add_video_payload( sdp_context_t * ctx, sdp_payload_t * payload); +char * sdp_context_get_offer(sdp_context_t *ctx); +char * sdp_context_get_answer(sdp_context_t* ctx, sdp_message_t *remote_offer); +int sdp_context_get_status(sdp_context_t* ctx); +void sdp_context_read_answer(sdp_context_t *ctx, sdp_message_t *remote_answer); +void sdp_context_free(sdp_context_t *ctx); + +int sdp_payload_init (sdp_payload_t * payload); +#endif diff --git a/linphone/debian/.cvsignore b/linphone/debian/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/debian/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/debian/Makefile.am b/linphone/debian/Makefile.am new file mode 100644 index 000000000..6c6eb29bc --- /dev/null +++ b/linphone/debian/Makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST= copyright dirs manpage.sgml.ex rules \ + control docs manpage.1.ex menu watch.ex changelog + + +changelog: changelog.stamp + echo -n -e "linphone (">changelog + echo -n -e $(VERSION)>>changelog + echo -n -e "-1) unstable; urgency=low\n\n">>changelog + echo -n -e " * New Release.\n\n">>changelog + echo -n -e " -- Simon Morlat ">>changelog + date -R >>changelog + touch changelog.stamp + +changelog.stamp: + touch changelog.stamp diff --git a/linphone/debian/control b/linphone/debian/control new file mode 100644 index 000000000..fef2eba9d --- /dev/null +++ b/linphone/debian/control @@ -0,0 +1,14 @@ +Source: linphone +Section: sound +Priority: optional +Maintainer: Uwe Steinmann +Build-Depends: debhelper (>> 3.0.0), libosip0-dev (>= 0.9.6), libasound2-dev (>=0.9.4) +Standards-Version: 3.5.2 + +Package: linphone +Architecture: any +Depends: ${shlibs:Depends}, libosip0 (>= 0.9.6), libspeex1, libasound2 (>=0.9.4) +Description: A sip phone + Linphone is a web phone: it let you phone to your friends anywhere in the + whole world, freely, simply by using the internet. It is compatible with the + well known SIP protocol. diff --git a/linphone/debian/copyright b/linphone/debian/copyright new file mode 100644 index 000000000..da0129d9f --- /dev/null +++ b/linphone/debian/copyright @@ -0,0 +1,10 @@ +This package was debianized by Uwe Steinmann on +Thu, 28 Feb 2002 08:29:57 +0100. + +It was downloaded from http://www.linphone.org + +Upstream Author(s): Simon Morlat + +Copyright: + +GPL diff --git a/linphone/debian/dirs b/linphone/debian/dirs new file mode 100644 index 000000000..ca882bbb7 --- /dev/null +++ b/linphone/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/linphone/debian/docs b/linphone/debian/docs new file mode 100644 index 000000000..5203c2307 --- /dev/null +++ b/linphone/debian/docs @@ -0,0 +1,3 @@ +BUGS +NEWS +README diff --git a/linphone/debian/manpage.1.ex b/linphone/debian/manpage.1.ex new file mode 100644 index 000000000..f872c3353 --- /dev/null +++ b/linphone/debian/manpage.1.ex @@ -0,0 +1,60 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH LINPHONE SECTION "February 28, 2002" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +linphone \- program to do something +.SH SYNOPSIS +.B linphone +.RI [ options ] " files" ... +.br +.B bar +.RI [ options ] " files" ... +.SH DESCRIPTION +This manual page documents briefly the +.B linphone +and +.B bar +commands. +This manual page was written for the Debian distribution +because the original program does not have a manual page. +Instead, it has documentation in the GNU Info format; see below. +.PP +.\" TeX users may be more comfortable with the \fB\fP and +.\" \fI\fP escape sequences to invode bold face and italics, +.\" respectively. +\fBlinphone\fP is a program that... +.SH OPTIONS +These programs follow the usual GNU command line syntax, with long +options starting with two dashes (`-'). +A summary of options is included below. +For a complete description, see the Info files. +.TP +.B \-h, \-\-help +Show summary of options. +.TP +.B \-v, \-\-version +Show version of program. +.SH SEE ALSO +.BR bar (1), +.BR baz (1). +.br +The programs are documented fully by +.IR "The Rise and Fall of a Fooish Bar" , +available via the Info system. +.SH AUTHOR +This manual page was written by Uwe Steinmann , +for the Debian GNU/Linux system (but may be used by others). diff --git a/linphone/debian/manpage.sgml.ex b/linphone/debian/manpage.sgml.ex new file mode 100644 index 000000000..0b97c1700 --- /dev/null +++ b/linphone/debian/manpage.sgml.ex @@ -0,0 +1,152 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + + + The docbook-to-man binary is found in the docbook-to-man package. + Please remember that if you create the nroff version in one of the + debian/rules file targets (such as build), you will need to include + docbook-to-man in your Build-Depends control field. + + --> + + + FIRSTNAME"> + SURNAME"> + + February 28, 2002"> + + SECTION"> + uwe@steinmann.cx"> + + LINPHONE"> + + + Debian"> + GNU"> +]> + + + +
+ &dhemail; +
+ + &dhfirstname; + &dhsurname; + + + 2001 + &dhusername; + + &dhdate; +
+ + &dhucpackage; + + &dhsection; + + + &dhpackage; + + program to do something + + + + &dhpackage; + + + + + + + + DESCRIPTION + + This manual page documents briefly the + &dhpackage; and bar + commands. + + This manual page was written for the &debian; distribution + because the original program does not have a manual page. + Instead, it has documentation in the &gnu; + Info format; see below. + + &dhpackage; is a program that... + + + + OPTIONS + + These programs follow the usual GNU command line syntax, + with long options starting with two dashes (`-'). A summary of + options is included below. For a complete description, see the + Info files. + + + + + + + + Show summary of options. + + + + + + + + Show version of program. + + + + + + SEE ALSO + + bar (1), baz (1). + + The programs are documented fully by The Rise and + Fall of a Fooish Bar available via the + Info system. + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the GNU Free Documentation + License, Version 1.1 or any later version published by the Free + Software Foundation; with no Invariant Sections, no Front-Cover + Texts and no Back-Cover Texts. + + +
+ + + + diff --git a/linphone/debian/menu b/linphone/debian/menu new file mode 100644 index 000000000..b21a3934a --- /dev/null +++ b/linphone/debian/menu @@ -0,0 +1,3 @@ +?package(linphone):needs=X11 section=Apps/Net \ + title="Linphone" command="/usr/bin/linphone" hints="Telephony"\ + icon="/usr/share/pixmaps/linphone/linphone2.xpm" diff --git a/linphone/debian/rules b/linphone/debian/rules new file mode 100755 index 000000000..621932a43 --- /dev/null +++ b/linphone/debian/rules @@ -0,0 +1,107 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=3 + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --disable-static --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --sysconfdir=/etc + + touch configure-stamp + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + #/usr/bin/docbook-to-man debian/linphone.sgml > linphone.1 + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -make clean + -make distclean + -test -r /usr/share/misc/config.sub && \ + -cp -f /usr/share/misc/config.sub config.sub + -test -r /usr/share/misc/config.guess && \ + -cp -f /usr/share/misc/config.guess config.guess + + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/linphone. + $(MAKE) install PIXDESTDIR=$(CURDIR)/debian/linphone prefix=$(CURDIR)/debian/linphone/usr sysconfdir=$(CURDIR)/debian/linphone/etc + # remove speex libs, in order to not to conflict with speex debian package. + rm -f $(CURDIR)/debian/linphone/usr/lib/libspeex* \ + $(CURDIR)/debian/linphone/usr/bin/speex* \ + $(CURDIR)/debian/linphone/usr/include/speex* \ + $(CURDIR)/debian/linphone/usr/share/man/man1/speex* + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot +# dh_installdebconf + dh_installdocs + dh_installexamples + dh_installmenu +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit + dh_installcron + dh_installman + dh_installinfo +# dh_undocumented + dh_installchangelogs ChangeLog + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_makeshlibs + dh_installdeb +# dh_perl + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/linphone/debian/watch.ex b/linphone/debian/watch.ex new file mode 100644 index 000000000..2002b0f76 --- /dev/null +++ b/linphone/debian/watch.ex @@ -0,0 +1,5 @@ +# Example watch control file for uscan +# Rename this file to "watch" and then you can run the "uscan" command +# to check for upstream updates and more. +# Site Directory Pattern Version Script +sunsite.unc.edu /pub/Linux/Incoming linphone-(.*)\.tar\.gz debian uupdate diff --git a/linphone/developer-docs/.cvsignore b/linphone/developer-docs/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/developer-docs/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/developer-docs/mediastreamer/.cvsignore b/linphone/developer-docs/mediastreamer/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/developer-docs/mediastreamer/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/exosip/.cvsignore b/linphone/exosip/.cvsignore new file mode 100644 index 000000000..09980ae6b --- /dev/null +++ b/linphone/exosip/.cvsignore @@ -0,0 +1,6 @@ +.deps +.libs +Makefile +Makefile.in +*.lo +*.la diff --git a/linphone/exosip/Makefile.am b/linphone/exosip/Makefile.am new file mode 100644 index 000000000..067b1eebd --- /dev/null +++ b/linphone/exosip/Makefile.am @@ -0,0 +1,16 @@ +noinst_LTLIBRARIES = libeXosip.la + + +AM_CFLAGS = $(EXOSIP_CFLAGS) + +libeXosip_la_SOURCES = eXosip.c \ +jrequest.c jresponse.c jcallback.c jdialog.c udp.c \ +jcall.c jreg.c jfreinds.c jidentity.c eXutils.c \ +jnotify.c jsubscribers.c jsubscribe.c jevents.c \ +sdp_offans.c misc.c eXosip2.h \ +jpipe.c jpipe.h jauth.c jpublish.c \ +eXosip.h eXosip_cfg.h + +libeXosip_la_LIBADD = $(EXOSIP_LIBS) + +INCLUDES = -I$(top_srcdir) diff --git a/linphone/exosip/eXosip.c b/linphone/exosip/eXosip.c new file mode 100644 index 000000000..729927b48 --- /dev/null +++ b/linphone/exosip/eXosip.c @@ -0,0 +1,3192 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include +#include + +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include +#endif + +/* Private functions */ +static int eXosip_create_transaction(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_message_t *request); +static int eXosip_create_cancel_transaction(eXosip_call_t *jc, + eXosip_dialog_t *jd, + osip_message_t *request); +static jauthinfo_t *eXosip_find_authentication_info(const char *username, + const char *realm); +static int eXosip_add_authentication_information(osip_message_t *req, + osip_message_t *last_response); +static void *eXosip_thread(void *arg); +static int eXosip_execute(void); +static osip_message_t *eXosip_prepare_request_for_auth(osip_message_t *msg); + +static int eXosip_update_top_via(osip_message_t *sip); + + +eXosip_t eXosip; + +void eXosip_set_firewallip(const char *firewall_address) +{ + if (firewall_address==NULL) return; + snprintf(eXosip.j_firewall_ip,50, "%s", firewall_address); +} + +void eXosip_set_nattype(const char *nat_type) +{ + osip_strncpy(eXosip.nat_type, (nat_type ? nat_type : ""), sizeof(eXosip.nat_type)-1); +} + +void eXosip_force_proxy(const char *proxyurl) +{ + osip_strncpy(eXosip.forced_proxy, (proxyurl ? proxyurl : ""), sizeof(eXosip.forced_proxy)-1); +} + +int eXosip_guess_localip(int family, char *address, int size) +{ + return eXosip_guess_ip_for_via(family, address, size); +} + +void eXosip_get_localip(char *ip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip_get_localip IS DEPRECATED. Use eXosip_guess_localip!\n")); + eXosip_guess_ip_for_via(AF_INET, ip, 15); +} + +int +eXosip_is_public_address(const char *c_address) +{ + return (0!=strncmp(c_address, "192.168",7) + && 0!=strncmp(c_address, "10.",3) + && 0!=strncmp(c_address, "172.16.",7) + && 0!=strncmp(c_address, "172.17.",7) + && 0!=strncmp(c_address, "172.18.",7) + && 0!=strncmp(c_address, "172.19.",7) + && 0!=strncmp(c_address, "172.20.",7) + && 0!=strncmp(c_address, "172.21.",7) + && 0!=strncmp(c_address, "172.22.",7) + && 0!=strncmp(c_address, "172.23.",7) + && 0!=strncmp(c_address, "172.24.",7) + && 0!=strncmp(c_address, "172.25.",7) + && 0!=strncmp(c_address, "172.26.",7) + && 0!=strncmp(c_address, "172.27.",7) + && 0!=strncmp(c_address, "172.28.",7) + && 0!=strncmp(c_address, "172.29.",7) + && 0!=strncmp(c_address, "172.30.",7) + && 0!=strncmp(c_address, "172.31.",7) + && 0!=strncmp(c_address, "169.254",7)); +} + + +void __eXosip_wakeup(void) +{ + jpipe_write(eXosip.j_socketctl, "w", 1); +} + +void __eXosip_wakeup_event(void) +{ + jpipe_write(eXosip.j_socketctl_event, "w", 1); +} + + +int +eXosip_lock(void) +{ + return osip_mutex_lock((struct osip_mutex*)eXosip.j_mutexlock); +} + +int +eXosip_unlock(void) +{ + return osip_mutex_unlock((struct osip_mutex*)eXosip.j_mutexlock); +} + + +jfriend_t *jfriend_get(void) +{ + return eXosip.j_friends; +} + +void jfriend_remove(jfriend_t *fr) +{ + REMOVE_ELEMENT(eXosip.j_friends, fr); +} + +jsubscriber_t *jsubscriber_get(void) +{ + return eXosip.j_subscribers; +} + +jidentity_t *jidentity_get(void) +{ + return eXosip.j_identitys; +} + +void +eXosip_kill_transaction (osip_list_t * transactions) +{ + osip_transaction_t *transaction; + + if (!osip_list_eol (transactions, 0)) + { + /* some transaction are still used by osip, + transaction should be released by modules! */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "module sfp: _osip_kill_transaction transaction should be released by modules!\n")); + } + + while (!osip_list_eol (transactions, 0)) + { + transaction = osip_list_get (transactions, 0); + + __eXosip_delete_jinfo(transaction); + osip_transaction_free (transaction); + } +} + +void eXosip_quit(void) +{ + jauthinfo_t *jauthinfo; + eXosip_call_t *jc; + eXosip_notify_t *jn; + eXosip_subscribe_t *js; + eXosip_reg_t *jreg; + eXosip_pub_t *jpub; + int i; + + eXosip.j_stop_ua = 1; /* ask to quit the application */ + __eXosip_wakeup(); + __eXosip_wakeup_event(); + + i = osip_thread_join((struct osip_thread*)eXosip.j_thread); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: can't terminate thread!")); + } + osip_free((struct osip_thread*)eXosip.j_thread); + + jpipe_close(eXosip.j_socketctl); + jpipe_close(eXosip.j_socketctl_event); + + osip_free(eXosip.localip); + osip_free(eXosip.localport); + osip_free(eXosip.user_agent); + + eXosip.j_input = 0; + eXosip.j_output = 0; + + for (jc = eXosip.j_calls; jc!=NULL;jc = eXosip.j_calls) + { + REMOVE_ELEMENT(eXosip.j_calls, jc); + eXosip_call_free(jc); + } + + for (js = eXosip.j_subscribes; js!=NULL;js = eXosip.j_subscribes) + { + REMOVE_ELEMENT(eXosip.j_subscribes, js); + eXosip_subscribe_free(js); + } + + for (jn = eXosip.j_notifies; jn!=NULL;jn = eXosip.j_notifies) + { + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + } + + osip_mutex_destroy((struct osip_mutex*)eXosip.j_mutexlock); + osip_cond_destroy((struct osip_cond*)eXosip.j_cond); + + eXosip_sdp_negotiation_free(eXosip.osip_negotiation); + + if (eXosip.j_input) + fclose(eXosip.j_input); + if (eXosip.j_output) + osip_free(eXosip.j_output); + if (eXosip.j_socket) + close(eXosip.j_socket); + + for (jreg = eXosip.j_reg; jreg!=NULL; jreg = eXosip.j_reg) + { + REMOVE_ELEMENT(eXosip.j_reg, jreg); + eXosip_reg_free(jreg); + } + + for (jpub = eXosip.j_pub; jpub!=NULL; jpub = eXosip.j_pub) + { + REMOVE_ELEMENT(eXosip.j_pub, jpub); + _eXosip_pub_free(jpub); + } + + /* should be moved to method with an argument */ + jfriend_unload(); + jidentity_unload(); + jsubscriber_unload(); + + /* + for (jid = eXosip.j_identitys; jid!=NULL; jid = eXosip.j_identitys) + { + REMOVE_ELEMENT(eXosip.j_identitys, jid); + eXosip_friend_free(jid); + } + + for (jfr = eXosip.j_friends; jfr!=NULL; jfr = eXosip.j_friends) + { + REMOVE_ELEMENT(eXosip.j_friends, jfr); + eXosip_reg_free(jfr); + } + */ + + while (!osip_list_eol(eXosip.j_transactions, 0)) + { + osip_transaction_t *tr = (osip_transaction_t*) osip_list_get(eXosip.j_transactions, 0); + if (tr->state==IST_TERMINATED || tr->state==ICT_TERMINATED + || tr->state== NICT_TERMINATED || tr->state==NIST_TERMINATED) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Release a terminated transaction\n")); + osip_list_remove(eXosip.j_transactions, 0); + __eXosip_delete_jinfo(tr); + osip_transaction_free(tr); + } + else + { + osip_list_remove(eXosip.j_transactions, 0); + __eXosip_delete_jinfo(tr); + osip_transaction_free(tr); + } + } + + osip_free(eXosip.j_transactions); + + eXosip_kill_transaction (eXosip.j_osip->osip_ict_transactions); + eXosip_kill_transaction (eXosip.j_osip->osip_nict_transactions); + eXosip_kill_transaction (eXosip.j_osip->osip_ist_transactions); + eXosip_kill_transaction (eXosip.j_osip->osip_nist_transactions); + osip_release (eXosip.j_osip); + + if (eXosip.j_events!=NULL) + { + eXosip_event_t *ev; + for(ev=osip_fifo_tryget(eXosip.j_events);ev!=NULL; + ev=osip_fifo_tryget(eXosip.j_events)) + eXosip_event_free(ev); + } + + osip_fifo_free(eXosip.j_events); + + for (jauthinfo = eXosip.authinfos; jauthinfo!=NULL; + jauthinfo = eXosip.authinfos) + { + REMOVE_ELEMENT(eXosip.authinfos, jauthinfo); + osip_free(jauthinfo); + } + + return ; +} + +static int eXosip_execute ( void ) +{ + struct timeval lower_tv; + int i; + + osip_timers_gettimeout(eXosip.j_osip, &lower_tv); + if (lower_tv.tv_sec>15) + { + lower_tv.tv_sec = 15; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: Reseting timer to 15s before waking up!\n")); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: timer sec:%i usec:%i!\n", + lower_tv.tv_sec, lower_tv.tv_usec)); + } + i = eXosip_read_message(1, lower_tv.tv_sec, lower_tv.tv_usec); + + if (i==-2) + { + return -2; + } + + eXosip_lock(); + osip_timers_ict_execute(eXosip.j_osip); + osip_timers_nict_execute(eXosip.j_osip); + osip_timers_ist_execute(eXosip.j_osip); + osip_timers_nist_execute(eXosip.j_osip); + + osip_ict_execute(eXosip.j_osip); + osip_nict_execute(eXosip.j_osip); + osip_ist_execute(eXosip.j_osip); + osip_nist_execute(eXosip.j_osip); + + /* free all Calls that are in the TERMINATED STATE? */ + eXosip_release_terminated_calls(); + + eXosip_unlock(); + + return 0; +} + +void *eXosip_thread ( void *arg ) +{ + int i; + while (eXosip.j_stop_ua==0) + { + i = eXosip_execute(); + if (i==-2) + osip_thread_exit(); + } + osip_thread_exit(); + return NULL; +} + +static int ipv6_enable = 0; + +void eXosip_enable_ipv6(int _ipv6_enable) +{ + ipv6_enable = _ipv6_enable; +} + +int eXosip_init(FILE *input, FILE *output, int port) +{ + osip_t *osip; + int i; + if (port<=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: port must be higher than 0!\n")); + return -1; + } + memset(&eXosip, 0, sizeof(eXosip)); + eXosip.localip = (char *) osip_malloc(50); + memset(eXosip.localip, '\0', 50); + + if (ipv6_enable == 0) + eXosip.ip_family = AF_INET; + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "IPv6 is enabled. Pls report bugs\n")); + eXosip.ip_family = AF_INET6; + } + + eXosip_guess_localip(eXosip.ip_family, eXosip.localip, 49); + if (eXosip.localip[0]=='\0') + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No ethernet interface found!\n")); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: using 127.0.0.1 (debug mode)!\n")); + strcpy(eXosip.localip, "127.0.0.1"); + /* we should always fallback on something. The linphone user will surely + start linphone BEFORE setting its dial up connection.*/ + } + eXosip.user_agent = osip_strdup("eXosip/" EXOSIP_VERSION); + + eXosip_set_mode(EVENT_MODE); + eXosip.j_input = input; + eXosip.j_output = output; + eXosip.j_calls = NULL; + eXosip.j_stop_ua = 0; + eXosip.j_thread = NULL; + eXosip.j_transactions = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(eXosip.j_transactions); + eXosip.j_reg = NULL; + + eXosip.j_cond = (struct osip_cond*)osip_cond_init(); + + eXosip.j_mutexlock = (struct osip_mutex*)osip_mutex_init(); + + if (-1==osip_init(&osip)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot initialize osip!\n")); + return -1; + } + + eXosip_sdp_negotiation_init(&(eXosip.osip_negotiation)); + + eXosip_sdp_negotiation_add_codec(osip_strdup("0"), + NULL, + osip_strdup("RTP/AVP"), + NULL, NULL, NULL, + NULL,NULL, + osip_strdup("0 PCMU/8000")); + + eXosip_sdp_negotiation_add_codec(osip_strdup("8"), + NULL, + osip_strdup("RTP/AVP"), + NULL, NULL, NULL, + NULL,NULL, + osip_strdup("8 PCMA/8000")); + + osip_set_application_context(osip, &eXosip); + + eXosip_set_callbacks(osip); + + eXosip.j_osip = osip; + +#ifdef WIN32 + /* Initializing windows socket library */ + { + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(1,1); + if(i = WSAStartup(wVersionRequested, &wsaData)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Unable to initialize WINSOCK, reason: %d\n",i)); + /* return -1; It might be already initilized?? */ + } + } +#endif + + /* open a TCP socket to wake up the application when needed. */ + eXosip.j_socketctl = jpipe(); + if (eXosip.j_socketctl==NULL) + return -1; + + eXosip.j_socketctl_event = jpipe(); + if (eXosip.j_socketctl_event==NULL) + return -1; + if (ipv6_enable == 0) + { + eXosip.j_socket = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (eXosip.j_socket==-1) + return -1; + + { + struct sockaddr_in raddr; + raddr.sin_addr.s_addr = htons(INADDR_ANY); + raddr.sin_port = htons((short)port); + raddr.sin_family = AF_INET; + + i = bind(eXosip.j_socket, (struct sockaddr *)&raddr, sizeof(raddr)); + if (i < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot bind on port: %i!\n", i)); + return -1; + } + } + } + else + { + eXosip.j_socket = (int)socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (eXosip.j_socket==-1) + return -1; + + { + struct sockaddr_in6 raddr; + memset(&raddr, 0, sizeof(raddr)); + raddr.sin6_port = htons((short)port); + raddr.sin6_family = AF_INET6; + + i = bind(eXosip.j_socket, (struct sockaddr *)&raddr, sizeof(raddr)); + if (i < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot bind on port: %i!\n", i)); + return -1; + } + } + } + + + eXosip.localport = (char*)osip_malloc(10); + sprintf(eXosip.localport, "%i", port); + + eXosip.j_thread = (void*) osip_thread_create(20000,eXosip_thread, NULL); + if (eXosip.j_thread==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot start thread!\n")); + return -1; + } + + /* To be changed in osip! */ + eXosip.j_events = (osip_fifo_t*) osip_malloc(sizeof(osip_fifo_t)); + osip_fifo_init(eXosip.j_events); + + jfriend_load(); + jidentity_load(); + jsubscriber_load(); + return 0; +} + +int eXosip_force_localip(const char *localip){ + if (localip!=NULL){ + strcpy(eXosip.localip,localip); + eXosip.forced_localip=1; + }else { + eXosip_guess_ip_for_via(eXosip.ip_family, eXosip.localip, 49); + eXosip.forced_localip=0; + } + return 0; +} + +void +eXosip_set_mode(int mode) +{ + eXosip.j_runtime_mode = mode; +} + +void +eXosip_set_user_agent(const char *user_agent) +{ + osip_free(eXosip.user_agent); + eXosip.user_agent = osip_strdup(user_agent); +} + +void +eXosip_automatic_refresh() +{ +#if 0 + eXosip_call_t *jc; + eXosip_notify_t *jn; +#endif + eXosip_subscribe_t *js; + eXosip_dialog_t *jd; + eXosip_reg_t *jr; + int now; + + now = time(NULL); + +#if 0 + for (jc=eXosip.j_calls; jc!=NULL; jc=jc->next) + { + if (jc->c_id<1) + { + } + for (jd=jc->c_dialogs; jd!=NULL; jd=jd->next) + { + if (jd->d_dialog!=NULL) /* finished call */ + { + /* sending update for keep-alive mechanism could be done here! */ + } + } + } +#endif + + for (js=eXosip.j_subscribes; js!=NULL; js=js->next) + { + for (jd=js->s_dialogs; jd!=NULL; jd=jd->next) + { + if (jd->d_dialog!=NULL) /* finished call */ + { + if (jd->d_id>=1) + { + if (eXosip_subscribe_need_refresh(js, now)==0) + { + int i; +#ifdef LOW_EXPIRE + i = eXosip_subscribe_send_subscribe(js, jd, "120"); +#else + i = eXosip_subscribe_send_subscribe(js, jd, "3600"); +#endif + } + } + } + } + } + +#if 0 + for (jn=eXosip.j_notifies; jn!=NULL; jn=jn->next) + { + if (jn->n_id<1) + { + jn->n_id = static_id; + static_id++; + } + for (jd=jn->n_dialogs; jd!=NULL; jd=jd->next) + { + if (jd->d_dialog!=NULL) /* finished call */ + { + if (jd->d_id>=1) + { + /* keep-alive of dialog should be done by subscribe */ + /* may be we can decide to close the subscribption + if it is expired */ + } + } + } + } +#endif + + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (jr->r_id >=1 || jr->r_last_tr!=NULL) + { + if (jr->r_reg_period==0) + { + /* skip refresh! */ + } + else if (now-jr->r_last_tr->birth_time>300) + { + /* automatic refresh */ + eXosip_register(jr->r_id, jr->r_reg_period); + } + else if (now-jr->r_last_tr->birth_time>jr->r_reg_period-60) + { + /* automatic refresh */ + eXosip_register(jr->r_id, jr->r_reg_period); + } + else if (now-jr->r_last_tr->birth_time>120 && + (jr->r_last_tr->last_response==NULL + || (!MSG_IS_STATUS_2XX(jr->r_last_tr->last_response)))) + { + /* automatic refresh */ + eXosip_register(jr->r_id, jr->r_reg_period); + } + } + } +} + +void +eXosip_update() +{ + static int static_id = 1; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + eXosip_dialog_t *jd; + int now; + + if (static_id>100000) + static_id = 1; /* loop */ + + now = time(NULL); + for (jc=eXosip.j_calls; jc!=NULL; jc=jc->next) + { + if (jc->c_id<1) + { + jc->c_id = static_id; + static_id++; + } + for (jd=jc->c_dialogs; jd!=NULL; jd=jd->next) + { + if (jd->d_dialog!=NULL) /* finished call */ + { + if (jd->d_id<1) + { + jd->d_id = static_id; + static_id++; + } + } + else jd->d_id = -1; + } + } + + for (js=eXosip.j_subscribes; js!=NULL; js=js->next) + { + if (js->s_id<1) + { + js->s_id = static_id; + static_id++; + } + for (jd=js->s_dialogs; jd!=NULL; jd=jd->next) + { + if (jd->d_dialog!=NULL) /* finished call */ + { + if (jd->d_id<1) + { + jd->d_id = static_id; + static_id++; + } + } + else + jd->d_id = -1; + } + } + + for (jn=eXosip.j_notifies; jn!=NULL; jn=jn->next) + { + if (jn->n_id<1) + { + jn->n_id = static_id; + static_id++; + } + for (jd=jn->n_dialogs; jd!=NULL; jd=jd->next) + { + if (jd->d_dialog!=NULL) /* finished call */ + { + if (jd->d_id<1) + { + jd->d_id = static_id; + static_id++; + } + } + else jd->d_id = -1; + } + } +} + +int eXosip_message (char *to, char *from, char *route, char *buff) +{ + /* eXosip_call_t *jc; + osip_header_t *subject; */ + osip_message_t *message; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + i = generating_message(&message, to, from, route, buff); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send message (cannot build MESSAGE)! ")); + return -1; + } + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + message); + if (i!=0) + { + /* TODO: release the j_call.. */ + + osip_message_free(message); + return -1; + } + + osip_list_add(eXosip.j_transactions, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(message); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, NULL, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_info_call(int jid, char *content_type, char *body) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + osip_message_t *info; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + int i; + + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (jd==NULL || jd->d_dialog==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No established dialog!")); + return -1; + } + + transaction = eXosip_find_last_options(jc, jd); + if (transaction!=NULL) + { + if (transaction->state!=NICT_TERMINATED && + transaction->state!=NIST_TERMINATED) + return -1; + transaction=NULL; + } + + i = generating_info_within_dialog(&info, jd->d_dialog); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send info message! ")); + return -2; + } + + osip_message_set_content_type(info, content_type); + osip_message_set_body(info, body, strlen(body)); + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + info); + if (i!=0) + { + osip_message_free(info); + return -1; + } + + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(info); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_initiate_call_with_body(osip_message_t *invite,const char *bodytype, const char*body, void *reference){ + eXosip_call_t *jc; + osip_header_t *subject; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + char *size; + + if (body!=NULL){ + size= (char *)osip_malloc(7*sizeof(char)); + sprintf(size,"%i",strlen(body)); + osip_message_set_content_length(invite, size); + osip_free(size); + osip_message_set_body(invite, body, strlen(body)); + osip_message_set_content_type(invite,bodytype); + } + else osip_message_set_content_length(invite, "0"); + + eXosip_call_init(&jc); + i = osip_message_get_subject(invite, 0, &subject); + if (subject!=NULL && subject->hvalue!=NULL && subject->hvalue[0]!='\0') + snprintf(jc->c_subject, 99, "%s", subject->hvalue); + + jc->c_ack_sdp = 0; + + i = osip_transaction_init(&transaction, + ICT, + eXosip.j_osip, + invite); + if (i!=0) + { + eXosip_call_free(jc); + osip_message_free(invite); + return -1; + } + + jc->c_out_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage(invite); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, NULL, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + + jc->external_reference = reference; + ADD_ELEMENT(eXosip.j_calls, jc); + + eXosip_update(); /* fixed? */ + __eXosip_wakeup(); + return jc->c_id; +} + +osip_message_t *eXosip_prepare_request_for_auth(osip_message_t *msg) +{ +#ifdef SM + char *locip; +#else + char locip[50]; +#endif + osip_message_t *newmsg; + int cseq; + char tmp[90]; + osip_via_t *via; + + osip_message_clone(msg,&newmsg); + if (newmsg==NULL){ + eXosip_trace(OSIP_INFO1,("eXosip_prepare_request_for_auth: could not clone msg.")); + return NULL; + } + via = (osip_via_t *) osip_list_get (newmsg->vias, 0); + if (via==NULL || newmsg->cseq==NULL || newmsg->cseq->number==NULL) { + osip_message_free(newmsg); + eXosip_trace(OSIP_INFO1,("eXosip_prepare_request_for_auth: Bad headers in previous request.")); + return NULL; + } + /* increment cseq */ + cseq=atoi(newmsg->cseq->number); + osip_free(newmsg->cseq->number); + newmsg->cseq->number=strdup_printf("%i",cseq+1); + + osip_list_remove(newmsg->vias, 0); + locip=osip_strdup(osip_via_get_host(via)); + osip_via_free(via); +#ifdef SM + +#else + eXosip_guess_ip_for_via(eXosip.ip_family, locip, 49); +#endif + if (eXosip.ip_family==AF_INET6) + sprintf(tmp, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, + eXosip.localport, + via_branch_new_random()); + else + sprintf(tmp, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, + eXosip.localport, + via_branch_new_random()); + +#ifdef SM + osip_free(locip); +#endif + osip_via_init(&via); + osip_via_parse(via, tmp); + osip_list_add(newmsg->vias, via, 0); + + return newmsg; +} + +int eXosip_retry_call(int cid) +{ + eXosip_call_t *jc=NULL; + osip_transaction_t *tr,*newtr=NULL; + osip_message_t *inv=NULL; + int i; + osip_event_t *sipevent; + eXosip_call_find(cid,&jc); + if (jc==NULL) { + eXosip_trace(OSIP_INFO1,("eXosip_retry_last_invite: No such call.")); + return -1; + } + tr=eXosip_find_last_out_invite(jc,NULL); + if (tr==NULL){ + eXosip_trace(OSIP_INFO1,("eXosip_retry_last_invite: No such transaction.")); + return -1; + } + if (tr->last_response==NULL){ + eXosip_trace(OSIP_INFO1,("eXosip_retry_last_invite: transaction has not been answered.")); + return -1; + } + inv=eXosip_prepare_request_for_auth(tr->orig_request); + if (inv==NULL) return -1; + eXosip_add_authentication_information(inv,tr->last_response); + if (-1 == eXosip_update_top_via(inv)) + { + osip_message_free(inv); + return -1; + } + + + i = osip_transaction_init(&newtr, + ICT, + eXosip.j_osip, + inv); + if (i!=0) + { + osip_message_free(inv); + return -1; + } + jc->c_out_tr = newtr; + + sipevent = osip_new_outgoing_sipmessage(inv); + + osip_transaction_set_your_instance(newtr, __eXosip_new_jinfo(jc, NULL, NULL, NULL)); + osip_transaction_add_event(newtr, sipevent); + + eXosip_update(); /* fixed? */ + __eXosip_wakeup(); + return jc->c_id; +} + +extern int cb_udp_snd_message(osip_transaction_t *tr, osip_message_t *sip, + char *host, int port, int out_socket); + +int eXosip_send_ack(int did){ + eXosip_call_t *call; + eXosip_dialog_t *dialog; + eXosip_call_dialog_find(did,&call,&dialog); + if (dialog!=NULL){ + if (dialog->d_ack!=NULL){ + osip_route_t *route; + int port; + char *host; + osip_message_t *ack=dialog->d_ack; + osip_message_get_route(ack, 0, &route); + if (route!=NULL) + { + port = 5060; + if (route->url->port!=NULL) + port = osip_atoi(route->url->port); + host = route->url->host; + } + else + { + port = 5060; + if (ack->req_uri->port!=NULL) + port = osip_atoi(ack->req_uri->port); + host = ack->req_uri->host; + } + + cb_udp_snd_message(NULL, ack, host, port, eXosip.j_socket); + } + } + return 0; +} + +extern osip_list_t *supported_codec; + +int eXosip_initiate_call(osip_message_t *invite, void *reference, + void *sdp_context_reference, + char *local_sdp_port) +{ + eXosip_call_t *jc; + osip_header_t *subject; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + sdp_message_t *sdp; + char *body; + char *size; + + if (invite==NULL || invite->req_uri==NULL || invite->req_uri->host==NULL ) return -1; + + if (local_sdp_port!=NULL) + { + osip_negotiation_sdp_build_offer(eXosip.osip_negotiation, NULL, &sdp, local_sdp_port, NULL); + + /* + if speex codec is supported, add bandwith attribute: + b=AS:110 20 + b=AS:111 20 + */ + if (sdp!=NULL) + { + int pos=0; + while (!sdp_message_endof_media (sdp, pos)) + { + int k = 0; + char *tmp = sdp_message_m_media_get (sdp, pos); + if (0 == osip_strncasecmp (tmp, "audio", 5)) + { + char *payload = NULL; + do { + payload = sdp_message_m_payload_get (sdp, pos, k); + if (payload == NULL) + { + } + else if (0==strcmp("110",payload)) + { + sdp_message_a_attribute_add (sdp, + pos, + osip_strdup ("AS"), + osip_strdup ("110 20")); + } + else if (0==strcmp("111",payload)) + { + sdp_message_a_attribute_add (sdp, + pos, + osip_strdup ("AS"), + osip_strdup ("111 20")); + } + k++; + } while (payload != NULL); + } + pos++; + } + } + + if (eXosip.j_firewall_ip[0]!='\0') + { + char *c_address = invite->req_uri->host; + int pos=0; + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, invite->req_uri->host, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + /* If remote message contains a Public IP, we have to replace the SDP + connection address */ + if (eXosip_is_public_address(c_address)) + { + /* replace the IP with our firewall ip */ + sdp_connection_t *conn = sdp_message_connection_get(sdp, -1, 0); + if (conn!=NULL && conn->c_addr!=NULL ) + { + osip_free(conn->c_addr); + conn->c_addr = osip_strdup(eXosip.j_firewall_ip); + } + pos=0; + conn = sdp_message_connection_get(sdp, pos, 0); + while (conn!=NULL) + { + if (conn!=NULL && conn->c_addr!=NULL ) + { + osip_free(conn->c_addr); + conn->c_addr = osip_strdup(eXosip.j_firewall_ip); + } + pos++; + conn = sdp_message_connection_get(sdp, pos, 0); + } + } + + } + + i = sdp_message_to_str(sdp, &body); + if (body!=NULL) + { + size= (char *)osip_malloc(7*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(body)); +#else + sprintf(size,"%i",strlen(body)); +#endif + osip_message_set_content_length(invite, size); + osip_free(size); + + osip_message_set_body(invite, body, strlen(body)); + osip_free(body); + osip_message_set_content_type(invite, "application/sdp"); + } + else + osip_message_set_content_length(invite, "0"); + } + + eXosip_call_init(&jc); + if (local_sdp_port!=NULL) + snprintf(jc->c_sdp_port,9, "%s", local_sdp_port); + i = osip_message_get_subject(invite, 0, &subject); + if (subject!=NULL && subject->hvalue!=NULL && subject->hvalue[0]!='\0') + snprintf(jc->c_subject, 99, "%s", subject->hvalue); + + if (sdp_context_reference==NULL) + osip_negotiation_ctx_set_mycontext(jc->c_ctx, jc); + else + osip_negotiation_ctx_set_mycontext(jc->c_ctx, sdp_context_reference); + + if (local_sdp_port!=NULL) + { + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, sdp); + jc->c_ack_sdp = 0; + } + else + jc->c_ack_sdp = 1; + + i = osip_transaction_init(&transaction, + ICT, + eXosip.j_osip, + invite); + if (i!=0) + { + eXosip_call_free(jc); + osip_message_free(invite); + return -1; + } + + jc->c_out_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage(invite); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, NULL, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + + jc->external_reference = reference; + ADD_ELEMENT(eXosip.j_calls, jc); + + eXosip_update(); /* fixed? */ + __eXosip_wakeup(); + return jc->c_id; +} + + +int eXosip2_answer(int jid, int status, osip_message_t **answer){ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (status>100 && status<200) + { + i = _eXosip2_answer_invite_1xx(jc, jd, status, answer); + } + else if (status>199 && status<300) + { + i = _eXosip2_answer_invite_2xx(jc, jd, status, answer); + } + else if (status>300 && status<699) + { + i = _eXosip2_answer_invite_3456xx(jc, jd, status, answer); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (1010) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (MSG_IS_STATUS_1XX(answer)) + { + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, answer); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + i = 0; + } + else + { + ADD_ELEMENT(jc->c_dialogs, jd); + } + } + } + else if (MSG_IS_STATUS_2XX(answer)) + { + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, answer); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + return -1; + } + ADD_ELEMENT(jc->c_dialogs, jd); + } + else i = 0; + + eXosip_dialog_set_200ok(jd, answer); + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + } + else if (answer->status_code>=300 && answer->status_code<=699) + { + i = 0; + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (101transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return 0; +} + +int eXosip_answer_call_with_body(int jid, int status, const char *bodytype, const char *body){ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (status>100 && status<200) + { + i = eXosip_answer_invite_1xx(jc, jd, status); + } + else if (status>199 && status<300) + { + i = eXosip_answer_invite_2xx_with_body(jc, jd, status,bodytype,body); + } + else if (status>300 && status<699) + { + i = eXosip_answer_invite_3456xx(jc, jd, status); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (1010) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (contact==NULL) + memset(jc->c_redirection, '\0', 1024); + else + snprintf(jc->c_redirection, 1024, "%s", contact); + return 0; +} + +int eXosip_answer_call (int jid, int status, char *local_sdp_port) +{ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (status>100 && status<200) + { + i = eXosip_answer_invite_1xx(jc, jd, status); + } + else if (status>199 && status<300) + { +#if 0 /* this seems to be useless?? */ + if (jc->c_ctx!=NULL) + osip_negotiation_ctx_set_mycontext(jc->c_ctx, jc); + else + osip_negotiation_ctx_set_mycontext(jc->c_ctx, sdp_context_reference); +#endif + if (local_sdp_port!=NULL) + { + osip_negotiation_ctx_set_mycontext(jc->c_ctx, jc); + snprintf(jc->c_sdp_port,9, "%s", local_sdp_port); + } + + i = eXosip_answer_invite_2xx(jc, jd, status, local_sdp_port); + } + else if (status>300 && status<699) + { + i = eXosip_answer_invite_3456xx(jc, jd, status); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (1010) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + pl = eXosip_retrieve_sdp_negotiation_result(jc->c_ctx, payload_name, pnsize); + + if (pl >= 0) + { + *payload = pl; + return 0; + } + + return -1; +} + +int eXosip_options_call (int jid) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + osip_transaction_t *transaction; + osip_event_t *sipevent; + osip_message_t *options; + int i; + + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + transaction = eXosip_find_last_options(jc, jd); + if (transaction!=NULL) + { + if (transaction->state!=NICT_TERMINATED && + transaction->state!=NIST_TERMINATED) + return -1; + transaction=NULL; + } + + i = _eXosip_build_request_within_dialog(&options, "OPTIONS", jd->d_dialog, "UDP"); + if (i!=0) + return -2; + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + options); + if (i!=0) + { + /* TODO: release the j_call.. */ + osip_message_free(options); + return -2; + } + + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(options); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_answer_options (int cid, int jid, int status) +{ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No dialog here?\n")); + return -1; + } + } + else + { + eXosip_call_find(cid, &jc); + if (jc==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + } + if (status>100 && status<200) + { + i = eXosip_answer_options_1xx(jc, jd, status); + } + else if (status>199 && status<300) + { + i = eXosip_answer_options_2xx(jc, jd, status); + } + else if (status>300 && status<699) + { + i = eXosip_answer_options_3456xx(jc, jd, status); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (1010) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jc==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + jc->external_reference = reference; + return 0; +} + +int eXosip_on_hold_call (int jid) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + osip_transaction_t *transaction; + osip_event_t *sipevent; + osip_message_t *invite; + int i; + sdp_message_t *sdp; + char *body; + char *size; + + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + transaction = eXosip_find_last_invite(jc, jd); + if (transaction==NULL) return -1; + if (transaction->state!=ICT_TERMINATED && + transaction->state!=IST_TERMINATED) + return -1; + + sdp = eXosip_get_local_sdp_info(transaction); + if (sdp==NULL) + return -1; + i = osip_negotiation_sdp_message_put_on_hold(sdp); + if (i!=0) + { + sdp_message_free(sdp); + return -2; + } + + i = _eXosip_build_request_within_dialog(&invite, "INVITE", jd->d_dialog, "UDP"); + if (i!=0) { + sdp_message_free(sdp); + return -2; + } + + i = sdp_message_to_str(sdp, &body); + if (body!=NULL) + { + size= (char *)osip_malloc(7*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(body)); +#else + sprintf(size,"%i",strlen(body)); +#endif + osip_message_set_content_length(invite, size); + osip_free(size); + + osip_message_set_body(invite, body, strlen(body)); + osip_free(body); + osip_message_set_content_type(invite, "application/sdp"); + } + else + osip_message_set_content_length(invite, "0"); + + if (jc->c_subject==NULL || jc->c_subject[0]=='\0') + { +#if 0 + osip_message_set_subject(invite, "New Call"); +#endif + } + else + osip_message_set_subject(invite, jc->c_subject); + + transaction=NULL; + i = osip_transaction_init(&transaction, + ICT, + eXosip.j_osip, + invite); + if (i!=0) + { + /* TODO: release the j_call.. */ + osip_message_free(invite); + return -2; + } + + { + sdp_message_t *old_sdp = osip_negotiation_ctx_get_local_sdp(jc->c_ctx); + sdp_message_free(old_sdp); + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, sdp); + } + + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(invite); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_off_hold_call (int jid, char *rtp_ip, int port) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + osip_transaction_t *transaction; + osip_event_t *sipevent; + osip_message_t *invite; + int i; + sdp_message_t *sdp; + char *body; + char *size; + + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + transaction = eXosip_find_last_invite(jc, jd); + if (transaction==NULL) return -1; + if (transaction->state!=ICT_TERMINATED && + transaction->state!=IST_TERMINATED) + return -1; + + sdp = eXosip_get_local_sdp_info(transaction); + if (sdp==NULL) + return -1; + i = osip_negotiation_sdp_message_put_off_hold(sdp); + if (i!=0) + { + sdp_message_free(sdp); + return -2; + } + + i = _eXosip_build_request_within_dialog(&invite, "INVITE", jd->d_dialog, "UDP"); + if (i!=0) { + sdp_message_free(sdp); + return -2; + } + + if (rtp_ip!=NULL) + { + /* modify the connection address of host */ + sdp_connection_t *conn; + sdp_media_t *med; + int pos_media = 0; + conn = sdp_message_connection_get(sdp, -1, 0); + if (conn!=NULL && conn->c_addr!=NULL) + { + osip_free(conn->c_addr); + conn->c_addr = osip_strdup(rtp_ip); + } + med = (sdp_media_t *) osip_list_get (sdp->m_medias, pos_media); + while (med != NULL) + { + if (med->m_media!=NULL && 0==osip_strcasecmp(med->m_media, "audio")) + { + osip_free(med->m_port); + med->m_port=(char *)osip_malloc(15); + snprintf(med->m_port, 14, "%i", port); + break; + } + pos_media++; + med = (sdp_media_t *) osip_list_get (sdp->m_medias, pos_media); + } + } + + i = sdp_message_to_str(sdp, &body); + if (body!=NULL) + { + size= (char *)osip_malloc(7*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(body)); +#else + sprintf(size,"%i",strlen(body)); +#endif + osip_message_set_content_length(invite, size); + osip_free(size); + + osip_message_set_body(invite, body, strlen(body)); + osip_free(body); + osip_message_set_content_type(invite, "application/sdp"); + } + else + osip_message_set_content_length(invite, "0"); + + if (jc->c_subject==NULL || jc->c_subject[0]=='\0') + { +#if 0 + osip_message_set_subject(invite, "New Call"); +#endif + } + else + osip_message_set_subject(invite, jc->c_subject); + + transaction=NULL; + i = osip_transaction_init(&transaction, + ICT, + eXosip.j_osip, + invite); + if (i!=0) + { + /* TODO: release the j_call.. */ + osip_message_free(invite); + return -2; + } + + { + sdp_message_t *old_sdp = osip_negotiation_ctx_get_local_sdp(jc->c_ctx); + sdp_message_free(old_sdp); + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, sdp); + } + + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(invite); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +static int eXosip_create_transaction(eXosip_call_t *jc, + eXosip_dialog_t *jd, + osip_message_t *request) +{ + osip_event_t *sipevent; + osip_transaction_t *tr; + int i; + i = osip_transaction_init(&tr, + NICT, + eXosip.j_osip, + request); + if (i!=0) + { + /* TODO: release the j_call.. */ + + osip_message_free(request); + return -1; + } + + if (jd!=NULL) + osip_list_add(jd->d_out_trs, tr, 0); + + sipevent = osip_new_outgoing_sipmessage(request); + sipevent->transactionid = tr->transactionid; + + osip_transaction_set_your_instance(tr, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + osip_transaction_add_event(tr, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_transfer_call_out_of_dialog(char *refer_to, char *from, char *to, char *proxy) +{ + osip_message_t *refer; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + i = generating_refer_outside_dialog(&refer, refer_to, from, to, proxy); + if (i!=0) return -1; + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + refer); + if (i!=0) + { + osip_message_free(refer); + return -1; + } + + osip_list_add(eXosip.j_transactions, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(refer); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, NULL, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_transfer_call(int jid, char *refer_to) +{ + int i; + osip_message_t *request; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + if (jid<=0) + return -1; + + eXosip_call_dialog_find(jid, &jc, &jd); + if (jd==NULL || jd->d_dialog==NULL || jd->d_dialog->state==DIALOG_EARLY) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No established call here!")); + return -1; + } + + i = generating_refer(&request, jd->d_dialog, refer_to); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot generate REFER for call!")); + return -2; + } + + i = eXosip_create_transaction(jc, jd, request); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transfer transaction!")); + return i; + } + return 0; +} + +static int eXosip_create_cancel_transaction(eXosip_call_t *jc, + eXosip_dialog_t *jd, + osip_message_t *request) +{ + osip_event_t *sipevent; + osip_transaction_t *tr; + int i; + i = osip_transaction_init(&tr, + NICT, + eXosip.j_osip, + request); + if (i!=0) + { + /* TODO: release the j_call.. */ + + osip_message_free(request); + return -2; + } + + osip_list_add(eXosip.j_transactions, tr, 0); + + sipevent = osip_new_outgoing_sipmessage(request); + sipevent->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_terminate_call(int cid, int jid) +{ + int i; + osip_transaction_t *tr; + osip_message_t *request; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here? ")); + return -1; + } + } + else + { + eXosip_call_find(cid, &jc); + } + + if (jc==NULL) + { + return -1; + } + + tr=eXosip_find_last_out_invite(jc, jd); + if (tr!=NULL && tr->last_response!=NULL && MSG_IS_STATUS_1XX(tr->last_response)) + { + i = generating_cancel(&request, tr->orig_request); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot terminate this call! ")); + return -2; + } + i = eXosip_create_cancel_transaction(jc, jd, request); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transaction! ")); + return i; + } + if (jd!=NULL) + { + osip_dialog_free(jd->d_dialog); + jd->d_dialog = NULL; + } + return 0; + } + + if (jd==NULL || jd->d_dialog==NULL) + { + /* Check if some dialog exists */ + jd = jc->c_dialogs; + if (jd!=NULL && jd->d_dialog!=NULL) + { + i = generating_bye(&request, jd->d_dialog); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot terminate this call! ")); + return -2; + } + + i = eXosip_create_transaction(jc, jd, request); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transaction! ")); + return -2; + } + + osip_dialog_free(jd->d_dialog); + jd->d_dialog = NULL; + return 0; + } + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No established dialog!")); + return -1; + } + + if (tr==NULL) + { + /*this may not be enough if it's a re-INVITE! */ + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr!=NULL && tr->last_response!=NULL && + MSG_IS_STATUS_1XX(tr->last_response)) + { /* answer with 603 */ + i = eXosip_answer_call(jid, 603, 0); + return i; + } + } + + + i = generating_bye(&request, jd->d_dialog); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot terminate this call! ")); + return -2; + } + + i = eXosip_create_transaction(jc, jd, request); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transaction! ")); + return -2; + } + + osip_dialog_free(jd->d_dialog); + jd->d_dialog = NULL; + return 0; +} + +static jauthinfo_t * +eXosip_find_authentication_info(const char *username, const char *realm) +{ + jauthinfo_t *fallback = NULL; + jauthinfo_t *authinfo; + + for (authinfo = eXosip.authinfos; + authinfo!=NULL; + authinfo = authinfo->next) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "INFO: authinfo: %s %s\n", realm, authinfo->realm)); + if (0==strcmp(authinfo->username, username)) + { + if (authinfo->realm == NULL || authinfo->realm[0] == '\0') + { + fallback = authinfo; + } + else if (strcmp(realm,authinfo->realm)==0 || 0==strncmp(realm+1, authinfo->realm, strlen(realm)-2)) + { + return authinfo; + } + } + } + return fallback; +} + + +int eXosip_clear_authentication_info(){ + jauthinfo_t *jauthinfo; + for (jauthinfo = eXosip.authinfos; jauthinfo!=NULL; + jauthinfo = eXosip.authinfos) + { + REMOVE_ELEMENT(eXosip.authinfos, jauthinfo); + osip_free(jauthinfo); + } + return 0; +} + +int +eXosip_add_authentication_info(const char *username, const char *userid, + const char *passwd, const char *ha1, + const char *realm) +{ + jauthinfo_t *authinfos; + + if (username==NULL || username[0]=='\0') return -1; + if (userid==NULL || userid[0]=='\0') return -1; + + if ( passwd!=NULL && passwd[0]!='\0') {} + else if (ha1!=NULL && ha1[0]!='\0') {} + else return -1; + + authinfos = (jauthinfo_t *) osip_malloc(sizeof(jauthinfo_t)); + if (authinfos==NULL) + return -1; + memset(authinfos, 0, sizeof(jauthinfo_t)); + + snprintf(authinfos->username, 50, "%s", username); + snprintf(authinfos->userid, 50, "%s", userid); + if ( passwd!=NULL && passwd[0]!='\0') + snprintf(authinfos->passwd, 50, "%s", passwd); + else if (ha1!=NULL && ha1[0]!='\0') + snprintf(authinfos->ha1, 50, "%s", ha1); + if(realm!=NULL && realm[0]!='\0') + snprintf(authinfos->realm, 50, "%s", realm); + + ADD_ELEMENT(eXosip.authinfos, authinfos); + return 0; +} + +static int +eXosip_add_authentication_information(osip_message_t *req, + osip_message_t *last_response) +{ + osip_authorization_t *aut = NULL; + osip_www_authenticate_t *wwwauth = NULL; + osip_proxy_authorization_t *proxy_aut = NULL; + osip_proxy_authenticate_t *proxyauth = NULL; + jauthinfo_t *authinfo = NULL; + int pos; + int i; + + if (req==NULL + ||req->from==NULL + ||req->from->url==NULL + ||req->from->url->username==NULL) + return -1; + + pos=0; + osip_message_get_www_authenticate(last_response, pos, &wwwauth); + osip_message_get_proxy_authenticate(last_response, pos, &proxyauth); + if (wwwauth==NULL && proxyauth==NULL) return -1; + + while (wwwauth!=NULL) + { + char *uri; + authinfo = eXosip_find_authentication_info(req->from->url->username, + wwwauth->realm); + if (authinfo==NULL) return -1; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "authinfo: %s\n", authinfo->username)); + i = osip_uri_to_str (req->req_uri, &uri); + if (i!=0) return -1; + + i = __eXosip_create_authorization_header(last_response, uri, + authinfo->userid, + authinfo->passwd, + &aut); + osip_free(uri); + if (i!=0) return -1; + + if (aut != NULL) + { + osip_list_add (req->authorizations, aut, -1); + osip_message_force_update(req); + } + + pos++; + osip_message_get_www_authenticate(last_response, pos, &wwwauth); + } + + pos=0; + while (proxyauth!=NULL) + { + char *uri; + authinfo = eXosip_find_authentication_info(req->from->url->username, + proxyauth->realm); + if (authinfo==NULL) return -1; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "authinfo: %s\n", authinfo->username)); + i = osip_uri_to_str (req->req_uri, &uri); + if (i!=0) return -1; + + i = __eXosip_create_proxy_authorization_header(last_response, uri, + authinfo->userid, + authinfo->passwd, + &proxy_aut); + osip_free(uri); + if (i!=0) return -1; + + if (proxy_aut != NULL) + { + osip_list_add (req->proxy_authorizations, proxy_aut, -1); + osip_message_force_update(req); + } + + pos++; + osip_message_get_proxy_authenticate (last_response, pos, &proxyauth); + } + + return 0; +} + + +static int +eXosip_update_top_via(osip_message_t *sip) +{ +#ifdef SM + char *locip; +#else + char locip[50]; +#endif + char *tmp = (char *)osip_malloc(256*sizeof(char)); + osip_via_t *via = (osip_via_t *) osip_list_get (sip->vias, 0); + + + osip_list_remove(sip->vias, 0); + locip=osip_strdup(osip_via_get_host(via)); + osip_via_free(via); +#ifdef SM +#else + eXosip_guess_ip_for_via(eXosip.ip_family, locip, 49); +#endif + if (eXosip.ip_family==AF_INET6) + snprintf(tmp, 256, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, + eXosip.localport, + via_branch_new_random()); + else + snprintf(tmp, 256, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, + eXosip.localport, + via_branch_new_random()); + + if (eXosip.nat_type[0]) + { + strncat(tmp, ";xxx-nat-type=", 256); + strncat(tmp, eXosip.nat_type, 256); + } + + +#ifdef SM + osip_free(locip); +#endif + osip_via_init(&via); + osip_via_parse(via, tmp); + osip_list_add(sip->vias, via, 0); + osip_free(tmp); + + return 0; +} + +static eXosip_reg_t * +eXosip_reg_find(int rid) +{ + eXosip_reg_t *jr; + + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (jr->r_id == rid) + { + return jr; + } + } + return NULL; +} + +int eXosip_register (int rid, int registration_period) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + osip_message_t *reg; + eXosip_reg_t *jr; + int i; + + jr = eXosip_reg_find(rid); + if (jr==NULL) + { + /* fprintf(stderr, "eXosip: no registration info saved!\n"); */ + return -1; + } + if (registration_period>=0) + jr->r_reg_period = registration_period; + if (jr->r_reg_period==0) + {} /* unregistration */ + else if (jr->r_reg_period>3600) + jr->r_reg_period = 3600; + else if (jr->r_reg_period<200) /* too low */ + jr->r_reg_period = 200; + + reg = NULL; + if (jr->r_last_tr!=NULL) + { + if (jr->r_last_tr->state!=NICT_TERMINATED + && jr->r_last_tr->state!=NICT_COMPLETED) + { + /* fprintf(stderr, "eXosip: a registration is already pending!\n"); */ + return -1; + } + else + { + osip_message_t *last_response; + + reg = jr->r_last_tr->orig_request; + last_response = jr->r_last_tr->last_response; + + jr->r_last_tr->orig_request = NULL; + jr->r_last_tr->last_response = NULL; + __eXosip_delete_jinfo(jr->r_last_tr); + osip_transaction_free(jr->r_last_tr); + jr->r_last_tr = NULL; + + /* modify the REGISTER request */ + { + int osip_cseq_num = osip_atoi(reg->cseq->number); + int length = strlen(reg->cseq->number); + + + osip_authorization_t *aut; + osip_proxy_authorization_t *proxy_aut; + + aut = (osip_authorization_t *)osip_list_get(reg->authorizations, 0); + while (aut!=NULL) + { + osip_list_remove(reg->authorizations, 0); + osip_authorization_free(aut); + aut = (osip_authorization_t *)osip_list_get(reg->authorizations, 0); + } + + proxy_aut = (osip_proxy_authorization_t*)osip_list_get(reg->proxy_authorizations, 0); + while (proxy_aut!=NULL) + { + osip_list_remove(reg->proxy_authorizations, 0); + osip_proxy_authorization_free(proxy_aut); + proxy_aut = (osip_proxy_authorization_t*)osip_list_get(reg->proxy_authorizations, 0); + } + + + if (-1 == eXosip_update_top_via(reg)) + { + osip_message_free(reg); + return -1; + } + + osip_cseq_num++; + osip_free(reg->cseq->number); + reg->cseq->number = (char*)osip_malloc(length+2); /* +2 like for 9 to 10 */ + sprintf(reg->cseq->number, "%i", osip_cseq_num); + + { + osip_header_t *exp; + osip_message_header_get_byname(reg, "expires", 0, &exp); + osip_free(exp->hvalue); + exp->hvalue = (char*)osip_malloc(10); + snprintf(exp->hvalue, 9, "%i", jr->r_reg_period); + } + + osip_message_force_update(reg); + } + + if (last_response!=NULL) + { + if (MSG_IS_STATUS_4XX(last_response)) + { + eXosip_add_authentication_information(reg, last_response); + } + osip_message_free(last_response); + } + } + } + if (reg==NULL) + { + i = generating_register(®, jr->r_aor, jr->r_registrar, jr->r_contact, jr->r_reg_period); + if (i!=0) + { + /* fprintf(stderr, "eXosip: cannot register (cannot build REGISTER)! "); */ + return -2; + } + } + //!jinti! if exist outbound proxy setting ,register must use outboundproxy! + if (jr->r_route!=NULL) + { + osip_route_t *r=NULL; + osip_message_get_route(reg,0,&r); + if (r==NULL) + osip_message_set_route(reg, jr->r_route); + } + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + reg); + if (i!=0) + { + /* TODO: release the j_call.. */ + + osip_message_free(reg); + return -2; + } + + jr->r_last_tr = transaction; + + /* send REGISTER */ + sipevent = osip_new_outgoing_sipmessage(reg); + sipevent->transactionid = transaction->transactionid; + osip_message_force_update(reg); + + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int +eXosip_register_init(char *from, char *proxy, char *contact, char *route) +{ + eXosip_reg_t *jr; + int i; + + /* Avoid adding the same registration info twice to prevent mem leaks */ + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (strcmp(jr->r_aor, from) == 0 + && strcmp(jr->r_registrar, proxy) == 0) + { + return jr->r_id; + } + } + + /* Add new registration info */ + i = eXosip_reg_init(&jr, from, proxy, contact, route); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot register! ")); + return i; + } + ADD_ELEMENT(eXosip.j_reg, jr); + return jr->r_id; +} + + +int eXosip_build_publish(osip_message_t **message, + char *to, + char *from, + char *route, + const char *event, + const char *expires, + const char *ctype, + const char *body) +{ + int i; + if (to==NULL || to[0]=='\0') + return -1; + if (from==NULL || from[0]=='\0') + return -1; + if (event==NULL || event[0]=='\0') + return -1; + if (ctype==NULL || ctype[0]=='\0') + { + if (body!=NULL && body[0]!='\0') + return -1; + } + else + { + if (body==NULL || body[0]=='\0') + return -1; + } + + i = generating_publish(message, to, from, route); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send message (cannot build PUBLISH)! ")); + return -1; + } + + if (body!=NULL && body[0]!='\0' && ctype!=NULL && ctype[0]!='\0') + { + osip_message_set_content_type(*message, ctype); + osip_message_set_body(*message, body, strlen(body)); + osip_message_set_header(*message, "Content-Disposition", "render;handling=required"); + } + if (expires!=NULL && expires[0]!='\0') + osip_message_set_expires(*message, expires); + else + osip_message_set_expires(*message, "3600"); + + osip_message_set_header(*message, "Event", event); + return 0; +} + +int eXosip_publish (osip_message_t *message, const char *to) +{ + /* eXosip_call_t *jc; + osip_header_t *subject; */ + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + eXosip_pub_t *pub=NULL; + + if (message==NULL) + return -1; + if (message->cseq==NULL||message->cseq->number==NULL) + return -1; + if (to==NULL) + { + osip_message_free(message); + return -1; + } + + i = _eXosip_pub_find_by_aor(&pub, to); + if (i!=0 || pub==NULL) + { + osip_header_t *expires; + osip_message_get_expires(message, 0, &expires); + if (expires==NULL || expires->hvalue==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: missing expires header in PUBLISH!")); + osip_message_free(message); + return -1; + } + else + { + /* start a new publication context */ + _eXosip_pub_init(&pub, to, expires->hvalue); + if (pub==NULL) return -1; + ADD_ELEMENT(eXosip.j_pub, pub); + } + } + else + { + if (pub->p_sip_etag!=NULL && pub->p_sip_etag[0]!='\0') + { + /* increase cseq */ + osip_message_set_header(message, "SIP-If-Match", pub->p_sip_etag); + } + + if (pub->p_last_tr!=NULL && pub->p_last_tr->cseq!=NULL + &&pub->p_last_tr->cseq->number!=NULL) + { + int osip_cseq_num = osip_atoi(pub->p_last_tr->cseq->number); + int length = strlen(pub->p_last_tr->cseq->number); + + osip_cseq_num++; + osip_free(message->cseq->number); + message->cseq->number = (char*)osip_malloc(length+2); /* +2 like for 9 to 10 */ + sprintf(message->cseq->number, "%i", osip_cseq_num); + } + } + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + message); + if (i!=0) + { + osip_message_free(message); + return -1; + } + + if (pub->p_last_tr!=NULL) + osip_list_add(eXosip.j_transactions, pub->p_last_tr, 0); + pub->p_last_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage(message); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, NULL, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_subscribe (char *to, char *from, char *route) +{ + eXosip_subscribe_t *js; + osip_message_t *subscribe; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + i = generating_initial_subscribe(&subscribe, to, from, route); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot subscribe (cannot build SUBSCRIBE)! ")); + return -1; + } + + i = eXosip_subscribe_init(&js, to); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot subscribe.")); + return -1; + } + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + subscribe); + if (i!=0) + { + osip_message_free(subscribe); + return -1; + } + + _eXosip_subscribe_set_refresh_interval(js, subscribe); + js->s_out_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage(subscribe); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, NULL, js, NULL)); + osip_transaction_add_event(transaction, sipevent); + + ADD_ELEMENT(eXosip.j_subscribes, js); + eXosip_update(); /* fixed? */ + __eXosip_wakeup(); + return 0; +} + + +int eXosip_subscribe_refresh (int sid, char *expires) +{ + int i; + eXosip_dialog_t *jd = NULL; + eXosip_subscribe_t *js = NULL; + + if (sid>0) + { + eXosip_subscribe_dialog_find(sid, &js, &jd); + } + if (js==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No subscribe here?\n")); + return -1; + } + + if (jd==NULL) + { + osip_transaction_t *tr; + osip_transaction_t *newtr; + osip_message_t *sub; + osip_event_t *sipevent; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No subscribe dialog here?\n")); + + tr=eXosip_find_last_out_subscribe(js,NULL); + if (tr==NULL){ + eXosip_trace(OSIP_INFO1,("eXosip_retry_last_sub: No such transaction.")); + return -1; + } + if (tr->last_response==NULL){ + eXosip_trace(OSIP_INFO1,("eXosip_retry_last_sub: transaction has not been answered.")); + return -1; + } + sub=eXosip_prepare_request_for_auth(tr->orig_request); + if (sub==NULL) return -1; + eXosip_add_authentication_information(sub,tr->last_response); + + if (expires==NULL) + osip_message_set_expires(sub, "3600"); + else + osip_message_set_expires(sub, expires); + + osip_message_force_update(sub); + i = osip_transaction_init(&newtr, + NICT, + eXosip.j_osip, + sub); + if (i!=0) + { + osip_message_free(sub); + return -1; + } + + if (jd!=NULL) + osip_list_add(jd->d_out_trs, newtr, 0); + else + { + js->s_out_tr = newtr; + /* remove old transaction */ + osip_list_add(eXosip.j_transactions, tr, 0); + } + + sipevent = osip_new_outgoing_sipmessage(sub); + + osip_transaction_set_your_instance(newtr, tr->your_instance); + osip_transaction_set_your_instance(tr, NULL); + osip_transaction_add_event(newtr, sipevent); + + eXosip_update(); /* fixed? */ + __eXosip_wakeup(); + return -1; + } + +#ifdef LOW_EXPIRE + if (expires==NULL) + i = eXosip_subscribe_send_subscribe(js, jd, "60"); + else + i = eXosip_subscribe_send_subscribe(js, jd, expires); +#else + if (expires==NULL) + i = eXosip_subscribe_send_subscribe(js, jd, "3600"); + else + i = eXosip_subscribe_send_subscribe(js, jd, expires); +#endif + return i; +} + +int eXosip_subscribe_close(int sid) +{ + int i; + eXosip_dialog_t *jd = NULL; + eXosip_subscribe_t *js = NULL; + + if (sid>0) + { + eXosip_subscribe_dialog_find(sid, &js, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No subscribe dialog here?\n")); + return -1; + } + + i = eXosip_subscribe_send_subscribe(js, jd, "0"); + return i; +} + +int eXosip_transfer_send_notify(int jid, int subscription_status, char *body) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + if (jid>0) + { + eXosip_call_dialog_find(jid, &jc, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (jd==NULL || jd->d_dialog==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No established dialog!")); + return -1; + } + + return _eXosip_transfer_send_notify(jc, jd, subscription_status, body); +} + +int _eXosip_transfer_send_notify(eXosip_call_t *jc, + eXosip_dialog_t *jd, + int subscription_status, + char *body) +{ + osip_transaction_t *transaction; + osip_message_t *notify; + osip_event_t *sipevent; + int i; + char subscription_state[50]; + char *tmp; + + transaction = eXosip_find_last_inc_refer(jc, jd); + if (transaction==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No pending transfer!\n")); + return -1; + } + + transaction = eXosip_find_last_out_notify_for_refer(jc, jd); + if (transaction!=NULL) + { + if (transaction->state!=NICT_TERMINATED && + transaction->state!=NIST_TERMINATED) + return -1; + transaction=NULL; + } + + i = _eXosip_build_request_within_dialog(¬ify, "NOTIFY", jd->d_dialog, "UDP"); + if (i!=0) + return -2; + + if (subscription_status==EXOSIP_SUBCRSTATE_PENDING) + osip_strncpy(subscription_state, "pending;expires=", 16); + else if (subscription_status==EXOSIP_SUBCRSTATE_ACTIVE) + osip_strncpy(subscription_state, "active;expires=", 15); + else if (subscription_status==EXOSIP_SUBCRSTATE_TERMINATED) + { + int reason = NORESOURCE; + if (reason==DEACTIVATED) + osip_strncpy(subscription_state, "terminated;reason=deactivated", 29); + else if (reason==PROBATION) + osip_strncpy(subscription_state, "terminated;reason=probation", 27); + else if (reason==REJECTED) + osip_strncpy(subscription_state, "terminated;reason=rejected", 26); + else if (reason==TIMEOUT) + osip_strncpy(subscription_state, "terminated;reason=timeout", 25); + else if (reason==GIVEUP) + osip_strncpy(subscription_state, "terminated;reason=giveup", 24); + else if (reason==NORESOURCE) + osip_strncpy(subscription_state, "terminated;reason=noresource", 29); + } + tmp = subscription_state + strlen(subscription_state); + if (subscription_status!=EXOSIP_SUBCRSTATE_TERMINATED) + sprintf(tmp, "%i", 180); + osip_message_set_header(notify, "Subscription-State", + subscription_state); + + /* add a body */ + if (body!=NULL) + { + osip_message_set_body(notify, body, strlen(body)); + osip_message_set_content_type(notify, "message/sipfrag"); + } + + osip_message_set_header(notify, "Event", "refer"); + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + notify); + if (i!=0) + { + osip_message_free(notify); + return -1; + } + + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(notify); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_notify_send_notify(eXosip_notify_t *jn, + eXosip_dialog_t *jd, + int subscription_status, + int online_status) +{ + osip_transaction_t *transaction; + osip_message_t *notify; + osip_event_t *sipevent; + int i; + char subscription_state[50]; + char *tmp; + int now = time(NULL); + transaction = eXosip_find_last_out_notify(jn, jd); + if (transaction!=NULL) + { + if (transaction->state!=NICT_TERMINATED && + transaction->state!=NIST_TERMINATED) + return -1; + transaction=NULL; + } + +#ifndef SUPPORT_MSN + +#else + + /* DO NOT SEND ANY NOTIFY when the status + is not active (or terminated?) */ + if (subscription_status!=EXOSIP_SUBCRSTATE_ACTIVE + && subscription_status!=EXOSIP_SUBCRSTATE_TERMINATED) + { + /* set the new state anyway! */ + jn->n_online_status = online_status; + jn->n_ss_status = subscription_status; + return -1; + } + +#endif + + i = _eXosip_build_request_within_dialog(¬ify, "NOTIFY", jd->d_dialog, "UDP"); + if (i!=0) + return -2; + + jn->n_online_status = online_status; + jn->n_ss_status = subscription_status; + + /* add the notifications info */ + if (jn->n_ss_status==EXOSIP_SUBCRSTATE_UNKNOWN) + jn->n_online_status=EXOSIP_SUBCRSTATE_PENDING; + +#ifndef SUPPORT_MSN + if (jn->n_ss_status==EXOSIP_SUBCRSTATE_PENDING) + osip_strncpy(subscription_state, "pending;expires=", 16); + else if (jn->n_ss_status==EXOSIP_SUBCRSTATE_ACTIVE) + osip_strncpy(subscription_state, "active;expires=", 15); + else if (jn->n_ss_status==EXOSIP_SUBCRSTATE_TERMINATED) + { + if (jn->n_ss_reason==DEACTIVATED) + osip_strncpy(subscription_state, "terminated;reason=deactivated", 29); + else if (jn->n_ss_reason==PROBATION) + osip_strncpy(subscription_state, "terminated;reason=probation", 27); + else if (jn->n_ss_reason==REJECTED) + osip_strncpy(subscription_state, "terminated;reason=rejected", 26); + else if (jn->n_ss_reason==TIMEOUT) + osip_strncpy(subscription_state, "terminated;reason=timeout", 25); + else if (jn->n_ss_reason==GIVEUP) + osip_strncpy(subscription_state, "terminated;reason=giveup", 24); + else if (jn->n_ss_reason==NORESOURCE) + osip_strncpy(subscription_state, "terminated;reason=noresource", 29); + } + tmp = subscription_state + strlen(subscription_state); + if (jn->n_ss_status!=EXOSIP_SUBCRSTATE_TERMINATED) + sprintf(tmp, "%i", jn->n_ss_expires-now); + osip_message_set_header(notify, "Subscription-State", + subscription_state); +#endif + + /* add a body */ + i = _eXosip_notify_add_body(jn, notify); + if (i!=0) + { + + } + +#ifdef SUPPORT_MSN +#else + osip_message_set_header(notify, "Event", "presence"); +#endif + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + notify); + if (i!=0) + { + /* TODO: release the j_call.. */ + osip_message_free(notify); + return -1; + } + + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(notify); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, jd, NULL, jn)); + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + return 0; +} + +int eXosip_notify (int nid, int subscription_status, int online_status) +{ + int i; + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + + if (nid>0) + { + eXosip_notify_dialog_find(nid, &jn, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No subscribe dialog here?\n")); + return -1; + } + + i = eXosip_notify_send_notify(jn, jd, subscription_status, online_status); + return i; +} + + +int eXosip_notify_accept_subscribe(int nid, int code, + int subscription_status, + int online_status) +{ + int i = 0; + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + if (nid>0) + { + eXosip_notify_dialog_find(nid, &jn, &jd); + } + if (jd==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (code>100 && code<200) + { + eXosip_notify_answer_subscribe_1xx(jn, jd, code); + } + else if (code>199 && code<300) + { + eXosip_notify_answer_subscribe_2xx(jn, jd, code); + i = eXosip_notify(nid, subscription_status, online_status); + } + else if (code>300 && code<699) + { + eXosip_notify_answer_subscribe_3456xx(jn, jd, code); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (101url!=NULL && a_from->url->username!=NULL ) + { + if (eXosip.j_firewall_ip[0]!='\0') + { + if (public_net) + { + if (eXosip.localport==NULL) + snprintf(contact, bufsize, "", a_from->url->username, + eXosip.j_firewall_ip); + else + snprintf(contact, bufsize, "", a_from->url->username, + eXosip.j_firewall_ip, + eXosip.localport); + } + else + { + if (eXosip.localport==NULL) + snprintf(contact, bufsize, "", a_from->url->username, + locip); + else + snprintf(contact, bufsize, "", a_from->url->username, + locip, + eXosip.localport); + } + } + else + { + if (eXosip.localport==NULL) + snprintf(contact, bufsize, "", a_from->url->username, + locip); + else + snprintf(contact, bufsize, "", a_from->url->username, + locip, + eXosip.localport); + } + + osip_from_free(a_from); + } +} + +void eXosip_set_answer_contact(const char *contacturl) +{ + osip_strncpy(eXosip.answer_contact, contacturl ? contacturl : "", sizeof(eXosip.answer_contact)-1); +} diff --git a/linphone/exosip/eXosip.h b/linphone/exosip/eXosip.h new file mode 100644 index 000000000..d6881be5b --- /dev/null +++ b/linphone/exosip/eXosip.h @@ -0,0 +1,752 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#ifndef __EXOSIP_H__ +#define __EXOSIP_H__ + +#include +#include +#include + +/** + * @file eXosip.h + * @brief eXosip API + * + * eXosip is a high layer library for rfc3261: the SIP protocol. + * It has limited API and functionnalities to make it easy to use. + * If you need complexity in your SIP applications, you may prefer + * to use directly osip. + * + * eXosip capabilities: + * REGISTER to handle mobility. + * INVITE/BYE/OPTIONS to start/stop VoIP sessions. + * re-INVITE to modify VoIP sessions (On-hold/Off-hold) + * MESSAGE to send Instant Message. + * SUBSCRIBE/NOTIFY to handle presence capabilities. + * + *

+ */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * @defgroup eXosip eXosip Management + * @ingroup eXosip + * @{ + */ + +/** + * Use IPv6 instead of IPv4. + * + * @param ipv6_enable This paramter should be set to 1 to enable IPv6. + */ +void eXosip_enable_ipv6(int ipv6_enable); + +/** + * Initiate the eXtented oSIP library. + * + * @param input command input (RESERVED FOR FUTUR USE). + * @param output resulting output (RESERVED FOR FUTUR USE). + * @param port The SIP port to use. (5060 is the default) + */ +int eXosip_init(FILE *input, FILE *output, int port); + + +/** + * Force eXosip to use a specific local ip address in all its SIP message. + * + * @param localip the ip address. + * + * If set to NULL, then the local ip address will be guessed + * automatically (returns to default mode). + */ +int eXosip_force_localip(const char *localip); + +/** + * Release ressource used by the eXtented oSIP library. + * + */ +void eXosip_quit(void); + +/** + * Automatic refresh of subscription and register + * send subscribe refresh when subscription is close to expiration. + * send register refresh when registration is close to expiration. + * + */ +void eXosip_automatic_refresh(void); + +/** + * Wake Up the eXosip_event_wait method. + * + */ +void __eXosip_wakeup_event(void); + +/** + * This method is used to modify the sdp connection address + * When you are behind a NAT. (EXPERIMENTAL) + * + */ +void eXosip_set_firewallip(const char *firewall_address); + +/** + * This method is used to modify NAT firewall type + * When you are behind a NAT. (EXPERIMENTAL) + * @param nat type ("", "fcone", "rcone", "prcone", "sym") + */ +void eXosip_set_nattype(const char *nat_type); + +/** + * This method is used to force ALL SIP packets to go through given proxy + * @param proxyurl - when empty disable forced proxy behaviour + */ +void eXosip_force_proxy(const char *proxyurl); + +/** + * This method is used to set contact header on answers which establishes dialogs + * @param contacturl - the url to use for conatct SIP header, + * when empty - the contact header will be generated from 'to' + * header of the incoming request + */ +void eXosip_set_answer_contact(const char *contacturl); + +/** + * This method is used to build a contact header for SIP packets + * @param url url from wich username part will be extracted + * @param strbuf buffer where the result will be stored + * @param bufsize size of the 'strbuf' + * @param public_net when TRUE use firewall ip (if defined) as hostname part + * else use local host ip + * + */ +void eXosip_guess_contact_uri(const char *url, char *strbuf, int bufsize, int public_net); + +/** + * Find the current localip (interface with default route). + * ****DEPRECATED**** Use eXosip_guess_localip + * + * @param ip a string containing the local IP address. + */ +void eXosip_get_localip(char *ip); + +/** + * Find the current localip (interface with default route). + * + * @param family AF_INET or AF_INET6 + * @param address a string containing the local IP address. + * @param size The size of the string + */ +int eXosip_guess_localip(int family, char *address, int size); + +/** + * Find the interface to be used to reach the specified host. + * + * @param ip a string containing the local IP address. + * @param localip the local ip address to be used to reach host. + * + * You usually don't need this function at all. + */ +void eXosip_get_localip_for(char *host, char **localip); + +/** + * Add authentication credentials. These are used when an outgoing + * request comes back with an authorization required response. + * + * @param username username + * @param userid not sure what this is for + * @param passwd password + * @param ha1 currently ignored + * @param realm realm within which credentials apply, or NULL + * to apply credentials to unrecognized realms + */ +int eXosip_add_authentication_info(const char *username, const char *userid, + const char *passwd, const char *ha1, + const char *realm); + +/** + * Clear all authentication credentials stored in eXosip. + * + */ +int eXosip_clear_authentication_info(void); + +/** + * Remove an audio payload. + * + */ +void eXosip_sdp_negotiation_remove_audio_payloads(void); + +/** + * Remove an audio payload. + * + * @param payload The payload + * @param number_of_port The number of port + * @param proto The protocol + * @param c_nettype The connection type of network + * @param c_addrtype The connection type of address + * @param c_addr The connection address + * @param c_addr_multicast_ttl The multicast TTL value + * @param c_addr_multicast_int ? + * @param a_rtpmap The rtpmap of element. + */ +void eXosip_sdp_negotiation_add_codec(char *payload, char *number_of_port, + char *proto, char *c_nettype, + char *c_addrtype, char *c_addr, + char *c_addr_multicast_ttl, + char *c_addr_multicast_int, + char *a_rtpmap); + +/** + * Replace the internal SDP negociator facility. + * + * @param sn The new negociator context + */ +int eXosip_sdp_negotiation_replace(osip_negotiation_t *sn); + +struct eXosip_call_t; + +/** + * Set the reference element to be used in callback for the negociator. + * This must be done only if eXosip_sdp_negotiation_replace has been + * used and must not be done if this method has not been used. + * + * @param jc The related call. + * @param sn The new negociator context. + */ +void eXosip_sdp_negotiation_ctx_set_mycontext(struct eXosip_call_t *jc, void *arg); + +#define DEFAULT_MODE 2 +#define CALLBACK_MODE 1 +#define EVENT_MODE 2 +/** + * Set the functionnal mode of eXosip. + * The default mode is the EVENT_MODE. + * + * @param mode mode to use. + */ +void eXosip_set_mode(int mode); + +/** + * Set the SIP User-Agent: header string. + */ +void eXosip_set_user_agent(const char *user_agent); + +/** + * Lock the eXtented oSIP library. + * + */ +int eXosip_lock(void); + +/** + * UnLock the eXtented oSIP library. + * + */ +int eXosip_unlock(void); + +/** @} */ + +/** + * @defgroup eXosip_call eXosip Call Management + * @ingroup eXosip + * @{ + */ + +/** + * Build a default INVITE message for a new call. + * + * @param invite Pointer for the SIP element to hold. + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route header for INVITE. (optionnal) + * @param subject Subject for the call. + */ +int eXosip_build_initial_invite(osip_message_t **invite, char *to, + char *from, char *route, char *subject); +/** + * Initiate a call. + * + * @param invite SIP INVITE message to send. + * @param reference Application context. (optionnal) + * @param sdp_reference_context Sdp Application context. (optionnal) + * @param local_sdp_port The port to be used for this call. + */ +int eXosip_initiate_call (osip_message_t *invite, void *reference, + void *sdp_context_reference, char *local_sdp_port); + +/** + * Initiate a call with the specified body-type and body + * + * @param invite SIP INVITE message to send. + * @param body_type body type (ex: "application/sdp") + * @param body The body. + */ +int eXosip_initiate_call_with_body (osip_message_t *invite, const char *body_type, const char *body, void *reference); + + +/** + * When a call failed to initiate due to authorization reasons (407), retry the call using the authentication information + * previously stored in eXosip using eXosip_add_authentication_info() + * + * @param cid The eXosip call id as returned by eXosip_initiate_call*() + */ +int eXosip_retry_call (int cid); + +/** + * Initiate a blind transfer outside of a call. + * (probably not supported by many softphone...) + * + * @param refer_to SIP url for transfer. + * @param from SIP url for caller. + * @param to SIP url for callee. + * @param route Route header for REFER. (optionnal) + */ + int eXosip_transfer_call_out_of_dialog(char *refer_to, char *from, char *to, char *route); + +/** + * Set redirection url before a call to eXosip_answer_call. + * + * @param jid dialog id of call. + * @param contact contact address. + */ + int eXosip_set_redirection_address (int jid, char *contact); + +/** + * Answer call. + * + * @param jid dialog id of call. + * @param status Status code to use. + */ +int eXosip_answer_call (int jid, int status, char *local_sdp_port); + +/** + * Answer call. + * + * @param jid dialog id of call. + * @param status Status code to use. + * @param answer The resulting sip answer to send. + */ +int eXosip2_answer (int jid, int status, osip_message_t **answer); + +/** + * Answer call. + * + * @param jid dialog id of call. + * @param answer The sip answer to send. + */ +int eXosip2_answer_send(int jid, osip_message_t *answer); + +/** + * Answer call with the specified body. + * + * @param jid dialog id of call. + * @param status Status code to use. + * @param body_type body type (ex: "application/sdp") + * @param body The body. + */ +int eXosip_answer_call_with_body (int jid, int status,const char *body_type, const char*body); + + +/** + * Retreive payload negotiated for this dialog + * + * @param jid dialog id of call. + * @param payload will hold the negotited payload code + * @param payload_name will hold negotioated payload mime string + * @param pnsize size of the payload_name buffer + */ +int eXosip_retrieve_negotiated_payload(int jid, int *payload, char *payload_name, int pnsize); + +/** + * Set a new application context for an existing call + * + * @param jc Pointer to the call to modify + * @param reference New application context. + */ +int eXosip_set_call_reference(int jid, void *reference); + +/** + * Put a call on hold. + * + * @param jid dialog id of call. + */ +int eXosip_on_hold_call (int jid); +int eXosip_off_hold_call (int jid, char *rtp_ip, int port); + +/** + * Tranfer a call. + * + * @param jid dialog id of call. + * @param refer_to SIP Url for transfer. + */ +int eXosip_transfer_call(int jid, char *refer_to); + +/** + * Tranfer a call. + * + * @param jid dialog id of call. + * @param refer_to SIP Url for transfer. + */ +int eXosip_transfer_send_notify(int jid, int subscription_status, char *body); + +/** + * Terminate a call. + * + * @param cid call id of call. + * @param jid dialog id of call. + */ +int eXosip_terminate_call(int cid, int jid); + +/** + * Send an OPTIONS message within a call. + * + * @param cid call id of call. + * @param jid dialog id of call. + */ +int eXosip_options_call (int jid); + +/** + * Send an INFO message within a call. + * + * @param jid dialog id of call. + * @param content_type content-type of body. + * @param body body to attach. + */ +int eXosip_info_call(int jid, char *content_type, char *body); + +/** + * Answer an OPTIONS message. + * + * @param cid call id of call. + * @param jid dialog id of call. + */ +int eXosip_answer_options(int cid, int jid, int status); + +/** @} */ + +/** + * @defgroup eXosip_registration eXosip Registration Management + * @ingroup eXosip + * @{ + */ + +/** + * Send initial registration to a server. (REGISTER request) + * + * @param from SIP url for caller. + * @param proxy Proxy used for registration. + * @param contact Contact address. (optionnal) + * @param route Outbound proxy address. (optionnal) + */ +int eXosip_register_init (char *from, char *proxy, char *contact, char* route); + +/** + * Update the registration. (REGISTER request) + * + * @param rid . + * @param expires The expires value for registration. + */ +int eXosip_register (int rid, int expires); + +/** @} */ + +/** + * @defgroup eXosip_impp eXosip Instant Messaging and Presence Management + * @ingroup eXosip + * @{ + */ + +/** + * Send an Instant Message (MESSAGE request). + * + * @param rid . + */ +int eXosip_message (char *to, char *from, char *route, char *buff); + +/** + * build publication for a user. (PUBLISH request) + * + * @param message returned published request. + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route used for publication. + * @param event SIP Event header. + * @param expires SIP Expires header. + * @param ctype Content-Type of body. + * @param body body for publication. + */ +int eXosip_build_publish(osip_message_t **message, + char *to, + char *from, + char *route, + const char *event, + const char *expires, + const char *ctype, + const char *body); + +/** + * Send an Publication Message (PUBLISH request). + * + * @param message is a ready to be sent publish message . + * @param sip_if_match is the SIP-If-Match header. (NULL for initial publication) + */ +int eXosip_publish (osip_message_t *message, const char *sip_if_match); + +/** + * Send initial subscription to a user. (SUBSCRIBE request) + * + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route used for registration. + */ +int eXosip_subscribe(char *to, char *from, char *route); + +/** + * Update a subscription (SUBSCRIBE request). + * + * @param sid id of subscription. + * @param expires Time between updates. + */ +int eXosip_subscribe_refresh(int sid, char *expires); + +/** + * Close a subscription (SUBSCRIBE request). + * + * @param sid id of subscription. + */ +int eXosip_subscribe_close(int sid); + +typedef enum eXosip_ss { + EXOSIP_SUBCRSTATE_UNKNOWN, + EXOSIP_SUBCRSTATE_PENDING, + EXOSIP_SUBCRSTATE_ACTIVE, + EXOSIP_SUBCRSTATE_TERMINATED +} eXosip_ss_t; + +typedef enum eXosip_ss_reason { + DEACTIVATED, + PROBATION, + REJECTED, + TIMEOUT, + GIVEUP, + NORESOURCE +} eXosip_ss_reason_t; + + /* typo error */ +#define NORESSOURCE NORESOURCE + +typedef enum eXosip_ss_status { + EXOSIP_NOTIFY_UNKNOWN, + EXOSIP_NOTIFY_PENDING, /* subscription not yet accepted */ + EXOSIP_NOTIFY_ONLINE, + EXOSIP_NOTIFY_BUSY, + EXOSIP_NOTIFY_BERIGHTBACK, + EXOSIP_NOTIFY_AWAY, + EXOSIP_NOTIFY_ONTHEPHONE, + EXOSIP_NOTIFY_OUTTOLUNCH, + EXOSIP_NOTIFY_CLOSED +} eXosip_ss_status_t; + +/** + * Accept a subscription and notify state (NOTIFY request). + * + * @param nid call id of call. + * @param code code for answer to subscribe. + * @param subscription_status subscription status. + * @param online_status online status to send. + */ +int eXosip_notify_accept_subscribe (int nid, int code, int subscription_status, int online_status); + +/** + * Update a subscription and notify state (NOTIFY request). + * + * @param nid call id of call. + * @param subscription_status subscription status. + * @param online_status online status to send. + */ +int eXosip_notify(int nid, int subscription_status, int online_status); + +/** @} */ + + +int eXosip_send_ack(int did); + +/** + * @defgroup eXosip_event eXosip event Management + * @ingroup eXosip + * @{ + */ +typedef enum eXosip_event_type_t { + + /* Registration Info */ + EXOSIP_REGISTRATION_NEW, /* announce new registration. */ + EXOSIP_REGISTRATION_SUCCESS, /* user is successfully registred. */ + EXOSIP_REGISTRATION_FAILURE, /* user is not registred. */ + EXOSIP_REGISTRATION_REFRESHED, /* registration has been refreshed. */ + EXOSIP_REGISTRATION_TERMINATED, /* UA is not registred any more. */ + + /* for UAC events */ + EXOSIP_CALL_NOANSWER, /* announce no answer within the timeout */ + EXOSIP_CALL_PROCEEDING, /* announce processing by a remote app */ + EXOSIP_CALL_RINGING, /* announce ringback */ + EXOSIP_CALL_ANSWERED, /* announce start of call */ + EXOSIP_CALL_REDIRECTED, /* announce a redirection */ + EXOSIP_CALL_REQUESTFAILURE, /* announce a request failure */ + EXOSIP_CALL_SERVERFAILURE, /* announce a server failure */ + EXOSIP_CALL_GLOBALFAILURE, /* announce a global failure */ + + /* for UAS events */ + EXOSIP_CALL_NEW, /* announce a new call */ + EXOSIP_CALL_ACK, /* ACK received for 200ok to INVITE */ + EXOSIP_CALL_CANCELLED, /* announce that call has been cancelled */ + EXOSIP_CALL_TIMEOUT, /* announce that call has failed */ + EXOSIP_CALL_HOLD, /* audio must be stopped */ + EXOSIP_CALL_OFFHOLD, /* audio must be restarted */ + EXOSIP_CALL_CLOSED, /* a BYE was received for this call */ + + /* for both UAS & UAC events */ + EXOSIP_CALL_STARTAUDIO, /* audio must be established */ + EXOSIP_CALL_RELEASED, /* call context is cleared. */ + + /* for UAC events */ + EXOSIP_OPTIONS_NOANSWER, /* announce no answer within the timeout */ + EXOSIP_OPTIONS_PROCEEDING, /* announce processing by a remote app */ + EXOSIP_OPTIONS_ANSWERED, /* announce a 200ok */ + EXOSIP_OPTIONS_REDIRECTED, /* announce a redirection */ + EXOSIP_OPTIONS_REQUESTFAILURE, /* announce a request failure */ + EXOSIP_OPTIONS_SERVERFAILURE, /* announce a server failure */ + EXOSIP_OPTIONS_GLOBALFAILURE, /* announce a global failure */ + + EXOSIP_INFO_NOANSWER, /* announce no answer within the timeout */ + EXOSIP_INFO_PROCEEDING, /* announce processing by a remote app */ + EXOSIP_INFO_ANSWERED, /* announce a 200ok */ + EXOSIP_INFO_REDIRECTED, /* announce a redirection */ + EXOSIP_INFO_REQUESTFAILURE, /* announce a request failure */ + EXOSIP_INFO_SERVERFAILURE, /* announce a server failure */ + EXOSIP_INFO_GLOBALFAILURE, /* announce a global failure */ + + /* for UAS events */ + EXOSIP_OPTIONS_NEW, /* announce a new options method */ + EXOSIP_INFO_NEW, /* new info request received */ + + EXOSIP_MESSAGE_NEW, /* announce new incoming MESSAGE. */ + EXOSIP_MESSAGE_SUCCESS, /* announce a 200ok to a previous sent */ + EXOSIP_MESSAGE_FAILURE, /* announce a failure. */ + + /* Presence and Instant Messaging */ + EXOSIP_SUBSCRIPTION_NEW, /* announce new incoming SUBSCRIBE. */ + EXOSIP_SUBSCRIPTION_UPDATE, /* announce incoming SUBSCRIBE. */ + EXOSIP_SUBSCRIPTION_CLOSED, /* announce end of subscription. */ + + EXOSIP_SUBSCRIPTION_NOANSWER, /* announce no answer */ + EXOSIP_SUBSCRIPTION_PROCEEDING, /* announce a 1xx */ + EXOSIP_SUBSCRIPTION_ANSWERED, /* announce a 200ok */ + EXOSIP_SUBSCRIPTION_REDIRECTED, /* announce a redirection */ + EXOSIP_SUBSCRIPTION_REQUESTFAILURE, /* announce a request failure */ + EXOSIP_SUBSCRIPTION_SERVERFAILURE, /* announce a server failure */ + EXOSIP_SUBSCRIPTION_GLOBALFAILURE, /* announce a global failure */ + EXOSIP_SUBSCRIPTION_NOTIFY, /* announce new NOTIFY request */ + + EXOSIP_SUBSCRIPTION_RELEASED, /* call context is cleared. */ + + EXOSIP_IN_SUBSCRIPTION_NEW, /* announce new incoming SUBSCRIBE.*/ + EXOSIP_IN_SUBSCRIPTION_RELEASED, /* announce end of subscription. */ + + EXOSIP_CALL_REFERED, /* announce incoming REFER */ + EXOSIP_CALL_REFER_STATUS, /* announce incoming NOTIFY */ + + EXOSIP_CALLBACK_COUNT +} eXosip_event_type_t; + +typedef struct eXosip_event { + eXosip_event_type_t type; + void *external_reference; + char reason_phrase[50]; + int status_code; + + char textinfo[256]; + char req_uri[256]; + char local_uri[256]; + char remote_uri[256]; + char remote_contact[256]; + char refer_to[256]; + char subject[256]; + osip_content_type_t *i_ctt; + osip_list_t *i_bodies; + + char remote_sdp_audio_ip[50]; + int remote_sdp_audio_port; + int local_sdp_audio_port; + int payload; + char payload_name[50]; + char sdp_body[1000]; /* The whole SDP body */ + int online_status; + int ss_status; + int ss_reason; + + /* For a high level usage of the eXosip stack? (API is enough?) */ + int did; + int cid; + int rid; + int sid; + int nid; + + /* For a low level usage of the eXosip stack */ + struct eXosip_dialog_t *jd; + struct eXosip_call_t *jc; + struct eXosip_reg_t *jr; + struct eXosip_subscribe_t *js; + struct eXosip_notify_t *jn; + +} eXosip_event_t; + +/** + * Free ressource in an eXosip event. + * + * @param je event to work on. + */ +void eXosip_event_free(eXosip_event_t *je); + +/** + * Wait for an eXosip event. (FUTURE USE) + * + * @param tv_s timeout value (seconds). + * @param tv_ms timeout value (mseconds). + */ +eXosip_event_t *eXosip_event_wait(int tv_s, int tv_ms); + + +/** + * Wait for next eXosip event. + * + */ +eXosip_event_t *eXosip_event_get(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/exosip/eXosip2.h b/linphone/exosip/eXosip2.h new file mode 100644 index 000000000..5f3f32163 --- /dev/null +++ b/linphone/exosip/eXosip2.h @@ -0,0 +1,510 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#ifndef __EXOSIP2_H__ +#define __EXOSIP2_H__ + +#ifdef WIN32 +#include +#include +#include +#include +#define snprintf _snprintf +#define close(s) closesocket(s) +#else +#include +#include +#include +#include +#include +#endif + +#include + +#include +#include +#include + +#include +#include + +#include "jpipe.h" + +#ifndef JD_EMPTY + +#define JD_EMPTY 0 +#define JD_INITIALIZED 1 +#define JD_TRYING 2 +#define JD_QUEUED 3 +#define JD_RINGING 4 +#define JD_ESTABLISHED 5 +#define JD_REDIRECTED 6 +#define JD_AUTH_REQUIRED 7 +#define JD_CLIENTERROR 8 +#define JD_SERVERERROR 9 +#define JD_GLOBALFAILURE 10 +#define JD_TERMINATED 11 + +#define JD_MAX 11 + +#endif + +#define EXOSIP_VERSION "0.1" + +#ifdef __cplusplus +extern "C" +{ +#endif + +void eXosip_update(void); +void __eXosip_wakeup(void); + +typedef struct eXosip_dialog_t eXosip_dialog_t; + +struct eXosip_dialog_t { + + int d_id; + int d_STATE; + osip_dialog_t *d_dialog; /* active dialog */ + + int d_timer; + osip_message_t *d_200Ok; + osip_message_t *d_ack; + osip_list_t *media_lines; + + osip_list_t *d_inc_trs; + osip_list_t *d_out_trs; + + /* struct _BodyHandler *d_bh; */ + + eXosip_dialog_t *next; + eXosip_dialog_t *parent; +}; + +typedef struct eXosip_subscribe_t eXosip_subscribe_t; + +struct eXosip_subscribe_t { + + int s_id; + char s_uri[255]; + int s_online_status; + int s_ss_status; + int s_ss_reason; + int s_ss_expires; + eXosip_dialog_t *s_dialogs; + + osip_transaction_t *s_inc_tr; + osip_transaction_t *s_out_tr; + + eXosip_subscribe_t *next; + eXosip_subscribe_t *parent; +}; + +typedef struct eXosip_notify_t eXosip_notify_t; + +struct eXosip_notify_t { + + int n_id; + char n_uri[255]; + int n_online_status; + char *n_contact_info; + + int n_ss_status; + int n_ss_reason; + int n_ss_expires; + eXosip_dialog_t *n_dialogs; + + osip_transaction_t *n_inc_tr; + osip_transaction_t *n_out_tr; + + eXosip_notify_t *next; + eXosip_notify_t *parent; +}; + +typedef struct eXosip_call_t eXosip_call_t; + +struct eXosip_call_t { + + int c_id; + char c_subject[100]; + int c_ack_sdp; /* flag for alternative SDP offer-response model */ + eXosip_dialog_t *c_dialogs; + osip_transaction_t *c_inc_tr; + osip_transaction_t *c_out_tr; + osip_transaction_t *c_inc_options_tr; + osip_transaction_t *c_out_options_tr; + void *external_reference; + + osip_negotiation_ctx_t *c_ctx; + char c_sdp_port[10]; + + char c_redirection[1024]; /* contact for 3xx answers */ + + eXosip_call_t *next; + eXosip_call_t *parent; +}; + + +#if 0 +typedef struct eXosip_realm_t eXosip_realm_t; + +struct eXosip_realm_t { + + int r_id; + + char *r_realm; + char *r_username; + char *r_passwd; + + eXosip_realm_t *next; + eXosip_realm_t *parent; +}; +#endif + +typedef struct eXosip_reg_t eXosip_reg_t; + +struct eXosip_reg_t { + + int r_id; + + int r_reg_period; /* delay between registration */ + char *r_aor; /* sip identity */ + char *r_registrar; /* registrar */ + char *r_route; /* outbound proxy */ +#if 0 + eXosip_realm_t *r_realms; /* list of realms */ +#endif + char *r_contact; /* list of contacts string */ + + osip_transaction_t *r_last_tr; + eXosip_reg_t *next; + eXosip_reg_t *parent; +}; + + +typedef struct eXosip_pub_t eXosip_pub_t; + +struct eXosip_pub_t { + int p_id; + + time_t p_expires; /* expiration date (started+period) */ + int p_period; /* delay between registration */ + char p_aor[256]; /* sip identity */ + char p_sip_etag[64]; /* sip_etag from 200ok */ + + osip_transaction_t *p_last_tr; + eXosip_pub_t *next; + eXosip_pub_t *parent; +}; + +int _eXosip_pub_update(eXosip_pub_t **pub, osip_transaction_t *tr, osip_message_t *answer); +int _eXosip_pub_find_by_aor(eXosip_pub_t **pub, const char *aor); +int _eXosip_pub_init(eXosip_pub_t **pub, const char *aor, const char *exp); +void _eXosip_pub_free(eXosip_pub_t *pub); + +typedef struct jauthinfo_t jauthinfo_t; + +struct jauthinfo_t { + char username[50]; + char userid[50]; + char passwd[50]; + char ha1[50]; + char realm[50]; + jauthinfo_t *parent; + jauthinfo_t *next; +}; + +int +__eXosip_create_authorization_header(osip_message_t *previous_answer, + const char *rquri, const char *username, + const char *passwd, + osip_authorization_t **auth); +int +__eXosip_create_proxy_authorization_header(osip_message_t *previous_answer, + const char *rquri, + const char *username, + const char *passwd, + osip_proxy_authorization_t **auth); + + +eXosip_event_t *eXosip_event_init_for_call(int type, eXosip_call_t *jc, + eXosip_dialog_t *jd); +int eXosip_event_add_sdp_info(eXosip_event_t *je, osip_message_t *message); + +int eXosip_event_add_status(eXosip_event_t *je, osip_message_t *response); +eXosip_event_t *eXosip_event_init_for_subscribe(int type, + eXosip_subscribe_t *js, + eXosip_dialog_t *jd); +eXosip_event_t *eXosip_event_init_for_notify(int type, eXosip_notify_t *jn, + eXosip_dialog_t *jd); +eXosip_event_t *eXosip_event_init_for_reg(int type, eXosip_reg_t *jr); +eXosip_event_t *eXosip_event_init_for_message(int type, osip_transaction_t + *tr, osip_message_t *sip); +int eXosip_event_init(eXosip_event_t **je, int type); +eXosip_call_t *eXosip_event_get_callinfo(eXosip_event_t *je); +eXosip_dialog_t *eXosip_event_get_dialoginfo(eXosip_event_t *je); +eXosip_reg_t *eXosip_event_get_reginfo(eXosip_event_t *je); +eXosip_notify_t *eXosip_event_get_notifyinfo(eXosip_event_t *je); +eXosip_subscribe_t *eXosip_event_get_subscribeinfo(eXosip_event_t *je); +int eXosip_event_add(eXosip_event_t *je); +eXosip_event_t *eXosip_event_wait(int tv_s, int tv_ms); +eXosip_event_t *eXosip_event_get(void); + +typedef void (* eXosip_callback_t) (int type, eXosip_event_t *); + +char *strdup_printf(const char *fmt, ...); + +jfriend_t *jfriend_get(void); +jsubscriber_t *jsubscriber_get(void); +jidentity_t *jidentity_get(void); +int jfriend_get_and_set_next_token (char **dest, char *buf, + char **next); + +#define eXosip_trace(loglevel,args) do \ +{ \ + char *__strmsg; \ + __strmsg=strdup_printf args ; \ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,(loglevel),NULL,"%s\n",__strmsg)); \ + osip_free (__strmsg); \ +}while (0); + +typedef struct eXosip_t eXosip_t; + +struct eXosip_t { + int forced_localip; /* set to 1 when we must always use the default local ip */ + char *localip; /* default local ip */ + char *localport; + + char *user_agent; + + FILE *j_input; + FILE *j_output; + eXosip_call_t *j_calls; /* my calls */ + eXosip_subscribe_t *j_subscribes; /* my friends */ + eXosip_notify_t *j_notifies; /* my susbscribers */ + osip_list_t *j_transactions; + + eXosip_reg_t *j_reg; /* my registrations */ + eXosip_pub_t *j_pub; /* my publications */ + + void *j_cond; + void *j_mutexlock; + + osip_t *j_osip; + int j_socket; + int j_stop_ua; + void *j_thread; + jpipe_t *j_socketctl; + jpipe_t *j_socketctl_event; + + jsubscriber_t *j_subscribers; + jfriend_t *j_friends; + jidentity_t *j_identitys; + + int j_runtime_mode; + eXosip_callback_t j_call_callbacks[EXOSIP_CALLBACK_COUNT]; + osip_fifo_t *j_events; + + osip_negotiation_t *osip_negotiation; + char j_firewall_ip[50]; + jauthinfo_t *authinfos; + + int ip_family; /* AF_INET6 or AF_INET */ + char nat_type[16]; + char forced_proxy[256]; + char answer_contact[256]; /* conatact header value to use in answers */ +}; + +typedef struct jinfo_t jinfo_t; + +struct jinfo_t { + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; +}; + +int eXosip_guess_ip_for_via (int family, char *address, int size); + +int eXosip_sdp_negotiation_init(osip_negotiation_t **sn); +void eXosip_sdp_negotiation_free(osip_negotiation_t *sn); +int eXosip_retrieve_sdp_negotiation_result(osip_negotiation_ctx_t *ctx, char *payload_name, int pnsize); + + +sdp_message_t *eXosip_get_local_sdp_info(osip_transaction_t *invite_tr); +sdp_message_t *eXosip_get_remote_sdp_info(osip_transaction_t *invite_tr); +sdp_message_t *eXosip_get_local_sdp(osip_transaction_t *transaction); +sdp_message_t *eXosip_get_remote_sdp(osip_transaction_t *transaction); + + + +int eXosip_set_callbacks(osip_t *osip); +char *osip_call_id_new_random(void); +char *osip_to_tag_new_random(void); +char *osip_from_tag_new_random(void); +unsigned int via_branch_new_random(void); +void __eXosip_delete_jinfo(osip_transaction_t *transaction); +jinfo_t *__eXosip_new_jinfo(eXosip_call_t *jc, eXosip_dialog_t *jd, + eXosip_subscribe_t *js, eXosip_notify_t *jn); + +int eXosip_dialog_init_as_uac(eXosip_dialog_t **jd, osip_message_t *_200Ok); +int eXosip_dialog_init_as_uas(eXosip_dialog_t **jd, osip_message_t *_invite, osip_message_t *_200Ok); +void eXosip_dialog_free(eXosip_dialog_t *jd); +void eXosip_dialog_set_state(eXosip_dialog_t *jd, int state); +void eXosip_delete_early_dialog(eXosip_dialog_t *jd); + + +struct __eXosip_sockaddr { + u_char ss_len; + u_char ss_family; + u_char padding[128 - 2]; +}; +int eXosip_get_addrinfo (struct addrinfo **addrinfo, + char *hostname, int service); +int isrfc1918(char *ipaddr); +void eXosip_get_localip_from_via(osip_message_t *,char**localip); +int generating_initial_subscribe(osip_message_t **message, char *to, + char *from, char *route); +int generating_message(osip_message_t **message, char *to, char *from, + char *route, char *buff); +int generating_publish(osip_message_t **message, char *to, char *from, + char *route); +int generating_cancel(osip_message_t **dest, osip_message_t *request_cancelled); +int generating_options_within_dialog(osip_message_t **info, osip_dialog_t *dialog); +int generating_info_within_dialog(osip_message_t **info, osip_dialog_t *dialog); +int generating_bye(osip_message_t **bye, osip_dialog_t *dialog); +int generating_refer(osip_message_t **refer, osip_dialog_t *dialog, char *refer_to); +int generating_refer_outside_dialog(osip_message_t **refer, char *refer_to, char *from, char *to, char *proxy); +int generating_invite_on_hold(osip_message_t **invite, osip_dialog_t *dialog, + char *subject, char *sdp); +int generating_invite_off_hold(osip_message_t **invite, osip_dialog_t *dialog, + char *subject, char *sdp); +int generating_options(osip_message_t **options, char *from, char *to, char *proxy); +int generating_ack_for_2xx(osip_message_t **ack, osip_dialog_t *dialog); +int generating_info(osip_message_t **info, char *from, char *to, char *proxy); + +int _eXosip_reg_find(eXosip_reg_t **reg, osip_transaction_t *tr); +int eXosip_reg_init(eXosip_reg_t **jr, char *from, char *proxy, char *contact, char* route); +void eXosip_reg_free(eXosip_reg_t *jreg); +int generating_register(osip_message_t **reg, char *transport, char *from, char *proxy, int expires); +char *generating_sdp_answer(osip_message_t *request, osip_negotiation_ctx_t *context); + +int eXosip_call_dialog_find(int jid, eXosip_call_t **jc, eXosip_dialog_t **jd); +int eXosip_notify_dialog_find(int nid, eXosip_notify_t **jn, eXosip_dialog_t **jd); +int eXosip_subscribe_dialog_find(int nid, eXosip_subscribe_t **js, eXosip_dialog_t **jd); +int eXosip_call_find(int cid, eXosip_call_t **jc); +int eXosip_dialog_set_200ok(eXosip_dialog_t *_jd, osip_message_t *_200Ok); + +int _eXosip2_answer_invite_3456xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, osip_message_t **answer); +int _eXosip2_answer_invite_2xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, osip_message_t **answer); +int _eXosip2_answer_invite_1xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, osip_message_t **answer); +int eXosip_answer_invite_1xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code); +int eXosip_answer_invite_2xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, char *local_sdp_port); +int eXosip_answer_invite_2xx_with_body(eXosip_call_t *jc, eXosip_dialog_t *jd, int code,const char*, const char*); +int eXosip_answer_invite_3456xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code); +int eXosip_answer_options_1xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code); +int eXosip_answer_options_2xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code); +int eXosip_answer_options_3456xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code); +void eXosip_notify_answer_subscribe_1xx(eXosip_notify_t *jc, + eXosip_dialog_t *jd, int code); +void eXosip_notify_answer_subscribe_2xx(eXosip_notify_t *jn, + eXosip_dialog_t *jd, int code); +void eXosip_notify_answer_subscribe_3456xx(eXosip_notify_t *jn, + eXosip_dialog_t *jd, int code); + +int eXosip_build_response_default(int jid, int status); +int _eXosip_build_response_default(osip_message_t **dest, osip_dialog_t *dialog, + int status, osip_message_t *request); +int complete_answer_that_establish_a_dialog(osip_message_t *response, osip_message_t *request); +int _eXosip_build_request_within_dialog(osip_message_t **dest, char *method_name, + osip_dialog_t *dialog, char *transport); +int eXosip_build_initial_options(osip_message_t **options, char *to, char *from, + char *route); + +void eXosip_kill_transaction(osip_list_t * transactions); +int eXosip_remove_transaction_from_call(osip_transaction_t *tr, eXosip_call_t *jc); +osip_transaction_t *eXosip_find_last_inc_notify(eXosip_subscribe_t *jn, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_out_notify(eXosip_notify_t *jn, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_inc_subscribe(eXosip_notify_t *jn, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_out_subscribe(eXosip_subscribe_t *js, eXosip_dialog_t *jd ); + +osip_transaction_t *eXosip_find_last_out_options(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_inc_options(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_options(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_out_info(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_inc_info(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_info(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_invite(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_inc_invite(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_out_invite(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_refer(eXosip_call_t *jc, eXosip_dialog_t *jd ); +osip_transaction_t *eXosip_find_last_inc_notify_for_refer(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_out_notify_for_refer(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_inc_bye(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_out_bye(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_inc_refer(eXosip_call_t *jc, eXosip_dialog_t *jd); +osip_transaction_t *eXosip_find_last_out_refer(eXosip_call_t *jc, eXosip_dialog_t *jd); + + +int eXosip_call_init(eXosip_call_t **jc); +void eXosip_call_free(eXosip_call_t *jc); +void __eXosip_call_remove_dialog_reference_in_call(eXosip_call_t *jc, eXosip_dialog_t *jd); +void eXosip_call_set_subject(eXosip_call_t *jc, char *subject); +int eXosip_read_message(int max_message_nb, int sec_max, int usec_max); +void eXosip_release_terminated_calls ( void ); + + +int eXosip_subscribe_init(eXosip_subscribe_t **js, char *uri); +void eXosip_subscribe_free(eXosip_subscribe_t *js); +int _eXosip_subscribe_set_refresh_interval(eXosip_subscribe_t *js, osip_message_t *inc_subscribe); +int eXosip_subscribe_need_refresh(eXosip_subscribe_t *js, int now); +int eXosip_subscribe_send_subscribe(eXosip_subscribe_t *js, + eXosip_dialog_t *jd, const char *expires); + +int eXosip_notify_init(eXosip_notify_t **jn, osip_message_t *inc_subscribe); +void eXosip_notify_free(eXosip_notify_t *jn); +int _eXosip_notify_set_contact_info(eXosip_notify_t *jn, char *uri); +int _eXosip_notify_set_refresh_interval(eXosip_notify_t *jn, + osip_message_t *inc_subscribe); +void _eXosip_notify_add_expires_in_2XX_for_subscribe(eXosip_notify_t *jn, + osip_message_t *answer); +int _eXosip_notify_add_body(eXosip_notify_t *jn, osip_message_t *notify); +int eXosip_notify_add_allowed_subscriber(char *sip_url); +int _eXosip_notify_is_a_known_subscriber(osip_message_t *sip); +int eXosip_notify_send_notify(eXosip_notify_t *jn, eXosip_dialog_t *jd, + int subsciption_status, + int online_status); +int _eXosip_transfer_send_notify(eXosip_call_t *jc, + eXosip_dialog_t *jd, + int subscription_status, + char *body); + + +int eXosip_is_public_address(const char *addr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/exosip/eXosip_cfg.h b/linphone/exosip/eXosip_cfg.h new file mode 100644 index 000000000..b6a24f68f --- /dev/null +++ b/linphone/exosip/eXosip_cfg.h @@ -0,0 +1,150 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#ifndef __EXOSIP_CFG_H__ +#define __EXOSIP_CFG_H__ + +/** + * @defgroup eXosip_cfg eXosip Configuration Management + * @ingroup eXosip + * @{ + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct jfriend_t jfriend_t; + +struct jfriend_t { + int f_id; + char *f_nick; + char *f_home; + char *f_work; + char *f_email; + char *f_e164; + + jfriend_t *next; + jfriend_t *parent; +}; + +typedef struct jidentity_t jidentity_t; + +struct jidentity_t { + int i_id; + char *i_identity; + char *i_registrar; + char *i_realm; + char *i_userid; + char *i_pwd; + + jidentity_t *next; + jidentity_t *parent; +}; + +typedef struct jsubscriber_t jsubscriber_t; + +struct jsubscriber_t { + int s_id; + char *s_nick; + char *s_uri; + char *s_allow; + + jsubscriber_t *next; + jsubscriber_t *parent; +}; + +jfriend_t *jfriend_get(void); +void jfriend_remove(jfriend_t *fr); + +jsubscriber_t *jsubscriber_get(void); +jidentity_t *jidentity_get(void); + +int jfriend_load(void); +void jfriend_unload(void); +void jfriend_add(char *nickname, char *home, + char *work, char *email, char *e164); +char *jfriend_get_home(int fid); + +int jsubscriber_load(void); +void jsubscriber_unload(void); +void subscribers_add(char *nickname, char *uri, int black_list); +char *jsubscriber_get_uri(int fid); + +int jidentity_load(void); +void jidentity_unload(void); +void identitys_add(char *identity, char *registrar, char *realm, + char *userid, char *password); +char *jidentity_get_identity(int fid); +char *jidentity_get_registrar(int fid); + +#define REMOVE_ELEMENT(first_element, element) \ + if (element->parent==NULL) \ + { first_element = element->next; \ + if (first_element!=NULL) \ + first_element->parent = NULL; } \ + else \ + { element->parent->next = element->next; \ + if (element->next!=NULL) \ + element->next->parent = element->parent; \ + element->next = NULL; \ + element->parent = NULL; } + +#define ADD_ELEMENT(first_element, element) \ + if (first_element==NULL) \ + { \ + first_element = element; \ + element->next = NULL; \ + element->parent = NULL; \ + } \ + else \ + { \ + element->next = first_element; \ + element->parent = NULL; \ + element->next->parent = element; \ + first_element = element; \ + } + +#define APPEND_ELEMENT(type_of_element_t, first_element, element) \ + if (first_element==NULL) \ + { first_element = element; \ + element->next = NULL; /* useless */ \ + element->parent = NULL; /* useless */ } \ + else \ + { type_of_element_t *f; \ + for (f=first_element; f->next!=NULL; f=f->next) \ + { } \ + f->next = element; \ + element->parent = f; \ + element->next = NULL; \ + } + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/linphone/exosip/eXutils.c b/linphone/exosip/eXutils.c new file mode 100644 index 000000000..9a7a52aab --- /dev/null +++ b/linphone/exosip/eXutils.c @@ -0,0 +1,278 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include +#include "eXosip2.h" + +extern eXosip_t eXosip; + +#ifdef WIN32 +/* You need the Platform SDK to compile this. */ +#include + +#else /* sun, *BSD, linux, and other? */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#endif + +int +eXosip_guess_ip_for_via (int family, char *address, int size){ + char *res=NULL; + if (family==AF_INET6) + eXosip_get_localip_for("2001:638:500:101:2e0:81ff:fe24:37c6",&res); + else + eXosip_get_localip_for("15.128.128.93",&res); + strncpy(address,res,size); + osip_free(res); + return 0; +} + + + +#ifdef SM + +void eXosip_get_localip_from_via(osip_message_t *mesg,char **locip){ + osip_via_t *via=NULL; + char *host; + via=(osip_via_t*)osip_list_get(mesg->vias,0); + if (via==NULL) { + host="15.128.128.93"; + eXosip_trace(OSIP_ERROR,("Could not get via:%s")); + }else host=via->host; + eXosip_get_localip_for(host,locip); + +} +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 1024 +#endif + +void eXosip_get_localip_for(char *address_to_reach,char **loc){ + int err,tmp; + struct addrinfo hints; + struct addrinfo *res=NULL,*res0=NULL; + struct sockaddr_storage addr; + int sock; +#ifdef __APPLE_CC__ + int s; +#else + socklen_t s; +#endif + + if (eXosip.forced_localip){ + *loc=osip_strdup(eXosip.localip); + return; + } + + *loc=osip_malloc(MAXHOSTNAMELEN); + if (eXosip.ip_family==AF_INET) + strcpy(*loc,"127.0.0.1"); /* always fallback to local loopback */ + else strcpy(*loc,"::1"); + + memset(&hints,0,sizeof(hints)); + hints.ai_family=(eXosip.ip_family==AF_INET) ? PF_INET:PF_INET6; + hints.ai_socktype=SOCK_DGRAM; + /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/ + err=getaddrinfo(address_to_reach,"5060",&hints,&res0); + if (err!=0){ + eXosip_trace(OSIP_ERROR,("Error in getaddrinfo for %s: %s\n",address_to_reach,gai_strerror(err))); + return ; + } + if (res0==NULL){ + eXosip_trace(OSIP_ERROR,("getaddrinfo reported nothing !")); + abort(); + return ; + } + for (res=res0;res!=NULL;res=res->ai_next){ + sock=socket(res->ai_family,SOCK_DGRAM,0); + tmp=1; + err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof(int)); + if (err<0){ + eXosip_trace(OSIP_ERROR,("Error in setsockopt: %s\n",strerror(errno))); + abort(); + return ; + } + err=connect(sock,res->ai_addr,res->ai_addrlen); + if (err<0) { + eXosip_trace(OSIP_ERROR,("Error in connect: %s\n",strerror(errno))); + close(sock); + sock=-1; + continue; + }else break; + } + freeaddrinfo(res0); + if (sock==-1){ + eXosip_trace(OSIP_WARNING,("Could not find interface to reach %s\n",address_to_reach)); + return; + } + res0=NULL; + res=NULL; + s=sizeof(addr); + err=getsockname(sock,(struct sockaddr*)&addr,&s); + if (err!=0) { + eXosip_trace(OSIP_ERROR,("Error in getsockname: %s\n",strerror(errno))); + close(sock); + return ; + } + + err=getnameinfo((struct sockaddr *)&addr,s,*loc,MAXHOSTNAMELEN,NULL,0,NI_NUMERICHOST); + if (err!=0){ + eXosip_trace(OSIP_ERROR,("getnameinfo error:%s ; while finding local address for %s",strerror(errno), address_to_reach)); + abort(); + return ; + } + close(sock); + eXosip_trace(OSIP_INFO1,("Outgoing interface to reach %s is %s.\n",address_to_reach,*loc)); + return ; +} + +char *strdup_printf(const char *fmt, ...) +{ + /* Guess we need no more than 100 bytes. */ + int n, size = 100; + char *p; + va_list ap; + if ((p = osip_malloc (size)) == NULL) + return NULL; + while (1) + { + /* Try to print in the allocated space. */ + va_start (ap, fmt); +#ifdef WIN32 + n = _vsnprintf (p, size, fmt, ap); +#else + n = vsnprintf (p, size, fmt, ap); +#endif + va_end (ap); + /* If that worked, return the string. */ + if (n > -1 && n < size) + return p; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + if ((p = realloc (p, size)) == NULL) + return NULL; + } +} + +int +eXosip_get_addrinfo (struct addrinfo **addrinfo, char *hostname, int service) +{ +#ifndef WIN32 + struct in_addr addr; + struct in6_addr addrv6; +#else + unsigned long int one_inet_addr; +#endif + struct addrinfo hints; + int error; + char portbuf[10]; + if (service!=0) + snprintf(portbuf, sizeof(portbuf), "%i", service); + + memset (&hints, 0, sizeof (hints)); +#ifndef WIN32 + if (inet_pton(AF_INET, hostname, &addr)>0) + { + /* ipv4 address detected */ + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = PF_INET; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "IPv4 address detected: %s\n", hostname)); + } + else if (inet_pton(AF_INET6, hostname, &addrv6)>0) + { + /* ipv6 address detected */ + /* Do the resolution anyway */ + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_INET6; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "IPv6 address detected: %s\n", hostname)); + } + else + { + /* hostname must be resolved */ + hints.ai_flags = 0; + hints.ai_family = (eXosip.ip_family==AF_INET) ? PF_INET:PF_INET6; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "Not an IPv4 or IPv6 address: %s\n", hostname)); + } +#else + if ((int)(one_inet_addr = inet_addr(hostname)) == -1) + hints.ai_flags = AI_CANONNAME; + else + hints.ai_flags = AI_NUMERICHOST; + +#ifdef IPV6_SUPPORT + hints.ai_family = PF_UNSPEC; /* ipv6 support */ +#else + hints.ai_family = PF_INET; /* ipv4 only support */ +#endif + +#endif + + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + if (service==0) + { + error = getaddrinfo (hostname, "sip", &hints, addrinfo); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "SRV resolution with udp-sip-%s\n", hostname)); + } + else + { + error = getaddrinfo (hostname, portbuf, &hints, addrinfo); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "DNS resolution with %s:%i\n", hostname, service)); + } + if (error || *addrinfo == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "getaddrinfo failure. %s:%s (%s)\n", hostname, portbuf, gai_strerror(error))); + return -1; + } + + return 0; +} diff --git a/linphone/exosip/exosip.dev b/linphone/exosip/exosip.dev new file mode 100755 index 000000000..c90fb628d --- /dev/null +++ b/linphone/exosip/exosip.dev @@ -0,0 +1,289 @@ +[Project] +FileName=exosip.dev +Name=exosip +UnitCount=24 +Type=2 +Ver=1 +ObjFiles= +Includes=. +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-D_WIN32_WINNT=0x501_@@_-DSM_@@_-g_@@_ +CppCompiler= +Linker= +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=1 +OverrideOutputName=libexosip.a +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=udp.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=eXosip2.h +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=eXosip.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=eXosip.h +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=eXosip_cfg.h +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=eXutils.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=jauth.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=jcall.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=jcallback.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=jdialog.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=jevents.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=jfreinds.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=jidentity.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=jnotify.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=jpipe.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=jpipe.h +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=jpublish.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=jreg.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=jrequest.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=jresponse.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=jsubscribe.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=jsubscribers.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=misc.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=sdp_offans.c +CompileCpp=0 +Folder=exosip +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/linphone/exosip/jauth.c b/linphone/exosip/jauth.c new file mode 100644 index 000000000..6a81d8f4c --- /dev/null +++ b/linphone/exosip/jauth.c @@ -0,0 +1,453 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include +#include + +#include +#include + +/* #include */ +#include + +/* TAKEN from rcf2617.txt */ + +#define HASHLEN 16 +typedef char HASH[HASHLEN]; +#define HASHHEXLEN 32 +typedef char HASHHEX[HASHHEXLEN+1]; +#define IN +#define OUT + +extern eXosip_t eXosip; + +/* Private functions */ +static void CvtHex(IN HASH Bin, OUT HASHHEX Hex); +static void DigestCalcHA1(IN const char * pszAlg, IN const char * pszUserName, + IN const char * pszRealm, IN const char * pszPassword, + IN const char * pszNonce, IN const char * pszCNonce, + OUT HASHHEX SessionKey); +static void DigestCalcResponse(IN HASHHEX HA1, + IN const char * pszNonce, + IN const char * pszNonceCount, + IN const char * pszCNonce, + IN const char * pszQop, + IN const char * pszMethod, + IN const char * pszDigestUri, + IN HASHHEX HEntity, OUT HASHHEX Response); + +static void CvtHex(IN HASH Bin, + OUT HASHHEX Hex) +{ + unsigned short i; + unsigned char j; + + for (i = 0; i < HASHLEN; i++) { + j = (Bin[i] >> 4) & 0xf; + if (j <= 9) + Hex[i*2] = (j + '0'); + else + Hex[i*2] = (j + 'a' - 10); + j = Bin[i] & 0xf; + if (j <= 9) + Hex[i*2+1] = (j + '0'); + else + Hex[i*2+1] = (j + 'a' - 10); + }; + Hex[HASHHEXLEN] = '\0'; +} + +/* calculate H(A1) as per spec */ +static void DigestCalcHA1(IN const char * pszAlg, + IN const char * pszUserName, + IN const char * pszRealm, + IN const char * pszPassword, + IN const char * pszNonce, + IN const char * pszCNonce, + OUT HASHHEX SessionKey) +{ + MD5_CTX Md5Ctx; + HASH HA1; + + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, (unsigned char *)pszUserName, strlen(pszUserName)); + MD5Update(&Md5Ctx, (unsigned char *)":", 1); + MD5Update(&Md5Ctx, (unsigned char *)pszRealm, strlen(pszRealm)); + MD5Update(&Md5Ctx, (unsigned char *)":", 1); + MD5Update(&Md5Ctx, (unsigned char *)pszPassword, strlen(pszPassword)); + MD5Final((unsigned char *)HA1, &Md5Ctx); + if ((pszAlg!=NULL)&&osip_strcasecmp(pszAlg, "md5-sess") == 0) + { + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, (unsigned char *)HA1, HASHLEN); + MD5Update(&Md5Ctx, (unsigned char *)":", 1); + MD5Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce)); + MD5Update(&Md5Ctx, (unsigned char *)":", 1); + MD5Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce)); + MD5Final((unsigned char *)HA1, &Md5Ctx); + } + CvtHex(HA1, SessionKey); +} + +/* calculate request-digest/response-digest as per HTTP Digest spec */ +static void DigestCalcResponse(IN HASHHEX HA1, /* H(A1) */ + IN const char * pszNonce, /* nonce from server */ + IN const char * pszNonceCount,/* 8 hex digits */ + IN const char * pszCNonce, /* client nonce */ + IN const char * pszQop, /* qop-value: "", "auth", "auth-int" */ + IN const char * pszMethod, /* method from the request */ + IN const char * pszDigestUri, /* requested URL */ + IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ + OUT HASHHEX Response /* request-digest or response-digest */) +{ + MD5_CTX Md5Ctx; + HASH HA2; + HASH RespHash; + HASHHEX HA2Hex; + + int auth_int_flag = 0; + + /* calculate H(A2) */ + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, (unsigned char *)pszMethod, strlen(pszMethod)); + MD5Update(&Md5Ctx, (unsigned char *)":", 1); + MD5Update(&Md5Ctx, (unsigned char *)pszDigestUri, strlen(pszDigestUri)); + + if (pszQop!=NULL) + { + char *index = strchr(pszQop,'i'); + while (index!=NULL&&index-pszQop>=5&&strlen(index)>=3) + { + if (osip_strncasecmp(index-5, "auth-int",8) == 0) + { + auth_int_flag = 1; + goto auth_withqop; + } + index = strchr(index+1,'i'); + } + + index = strchr(pszQop,'a'); + while (index!=NULL&&strlen(index)>=4) + { + if (osip_strncasecmp(index, "auth",4) == 0) + { + /* and in the case of a unknown token + like auth1. It is not auth, but this + implementation will think it is!?? + This is may not happen but it's a bug! + */ + goto auth_withqop; + } + index = strchr(index+1,'a'); + } + goto auth_withoutqop; + } + + auth_withoutqop: + MD5Final((unsigned char*)HA2, &Md5Ctx); + CvtHex(HA2, HA2Hex); + + /* calculate response */ + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHHEXLEN); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce)); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + + goto end; + + auth_withqop: + + if (auth_int_flag) + { + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + MD5Update(&Md5Ctx, (unsigned char*)HEntity, HASHHEXLEN); + } + + MD5Final((unsigned char*)HA2, &Md5Ctx); + CvtHex(HA2, HA2Hex); + + /* calculate response */ + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHHEXLEN); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce)); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + MD5Update(&Md5Ctx, (unsigned char*)pszNonceCount, strlen(pszNonceCount)); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce)); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + MD5Update(&Md5Ctx, (unsigned char*)pszQop, strlen(pszQop)); + MD5Update(&Md5Ctx, (unsigned char*)":", 1); + + end: + MD5Update(&Md5Ctx, (unsigned char*)HA2Hex, HASHHEXLEN); + MD5Final((unsigned char*)RespHash, &Md5Ctx); + CvtHex(RespHash, Response); +} + + +int +__eXosip_create_authorization_header(osip_message_t *previous_answer, + const char *rquri, const char *username, + const char *passwd, + osip_authorization_t **auth) +{ + static int nc = 1; + + osip_authorization_t *aut; + osip_www_authenticate_t *wa=NULL; + + osip_message_get_www_authenticate(previous_answer,0,&wa); + + /* make some test */ + if (passwd==NULL) + return -1; + if (wa==NULL||wa->auth_type==NULL + ||(wa->realm==NULL)||(wa->nonce==NULL)) { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "www_authenticate header is not acceptable.\n")); + return -1; + } + if (0!=osip_strcasecmp("Digest",wa->auth_type)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (Digest only).\n")); + return -1; + } + /* "MD5" is invalid, but some servers use it. */ + if (wa->algorithm!=NULL&&0!=osip_strcasecmp("MD5",wa->algorithm)&&0!=osip_strcasecmp("\"MD5\"",wa->algorithm)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (Digest only).\n")); + return -1; + } + if (0!=osip_authorization_init(&aut)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "allocation with authorization_init failed.\n")); + return -1; + } + + /* just copy some feilds from response to new request */ + osip_authorization_set_auth_type(aut,osip_strdup("Digest")); + osip_authorization_set_realm(aut,osip_strdup(osip_www_authenticate_get_realm(wa))); + osip_authorization_set_nonce(aut,osip_strdup(osip_www_authenticate_get_nonce(wa))); + if (osip_www_authenticate_get_opaque(wa)!=NULL) + osip_authorization_set_opaque(aut,osip_strdup(osip_www_authenticate_get_opaque(wa))); + /* copy the username field in new request */ + aut->username = osip_malloc(strlen(username)+3); + sprintf(aut->username,"\"%s\"",username); + + { + char *tmp = osip_malloc(strlen(rquri)+3); + sprintf(tmp,"\"%s\"",rquri); + osip_authorization_set_uri(aut,tmp); + } + + osip_authorization_set_algorithm(aut,osip_strdup("MD5")); + + { + char * pszNonce = osip_strdup_without_quote(osip_www_authenticate_get_nonce(wa)); + char * pszCNonce = osip_strdup_without_quote("abcdefghi"); + char * pszUser = osip_strdup_without_quote(username); + char * pszRealm = osip_strdup_without_quote(osip_authorization_get_realm(aut)); + const char * pszPass=NULL; + char * pszAlg = osip_strdup("MD5"); + char *szNonceCount = NULL; + char * pszMethod = osip_strdup_without_quote(previous_answer->cseq->method); + char * pszQop = NULL; + char * pszURI = osip_strdup_without_quote(rquri); + + szNonceCount = osip_strdup("00000000"); + sprintf(szNonceCount, "%08d", nc++); + + HASHHEX HA1; + HASHHEX HA2 = ""; + HASHHEX Response; + + pszPass=passwd; + + if (osip_www_authenticate_get_qop_options(wa)!=NULL) + { + pszQop = osip_strdup_without_quote(osip_www_authenticate_get_qop_options(wa)); + + osip_authorization_set_message_qop(aut,osip_strdup(pszQop)); + osip_authorization_set_nonce_count(aut,osip_strdup(szNonceCount)); + osip_authorization_set_cnonce(aut,osip_strdup("\"abcdefghi\"")); + osip_authorization_set_algorithm(aut,osip_strdup(pszAlg)); + } + + DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce, + pszCNonce, HA1); + DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop, + pszMethod, pszURI, HA2, Response); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Response in authorization |%s|\n", Response)); + { + char *resp = osip_malloc(35); + sprintf(resp,"\"%s\"",Response); + osip_authorization_set_response(aut,resp); + } + osip_free(pszAlg); /* xkd, 2004-5-13*/ + osip_free(pszNonce); + osip_free(pszCNonce); + osip_free(pszRealm); + osip_free(pszQop); + osip_free(szNonceCount); + osip_free(pszUser); + osip_free(pszMethod); + osip_free(pszURI); + } + + *auth = aut; + return 0; +} + +int +__eXosip_create_proxy_authorization_header(osip_message_t *previous_answer, + const char *rquri, + const char *username, + const char *passwd, + osip_proxy_authorization_t **auth) +{ + osip_proxy_authorization_t *aut; + osip_proxy_authenticate_t *wa; + + osip_message_get_proxy_authenticate(previous_answer,0,&wa); + + /* make some test */ + if (passwd==NULL) + return -1; + if (wa==NULL||wa->auth_type==NULL + ||(wa->realm==NULL)||(wa->nonce==NULL)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "www_authenticate header is not acceptable.\n")); + return -1; + } + if (0!=osip_strcasecmp("Digest",wa->auth_type)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (Digest only).\n")); + return -1; + } + /* "MD5" is invalid, but some servers use it. */ + if (wa->algorithm!=NULL&&0!=osip_strcasecmp("MD5",wa->algorithm)&&0!=osip_strcasecmp("\"MD5\"",wa->algorithm)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (MD5 Digest only).\n")); + return -1; + } + if (0!=osip_proxy_authorization_init(&aut)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "allocation with authorization_init failed.\n")); + return -1; + } + + /* just copy some feilds from response to new request */ + osip_proxy_authorization_set_auth_type(aut,osip_strdup("Digest")); + osip_proxy_authorization_set_realm(aut,osip_strdup(osip_proxy_authenticate_get_realm(wa))); + osip_proxy_authorization_set_nonce(aut,osip_strdup(osip_proxy_authenticate_get_nonce(wa))); + if (osip_proxy_authenticate_get_opaque(wa)!=NULL) + osip_proxy_authorization_set_opaque(aut,osip_strdup(osip_proxy_authenticate_get_opaque(wa))); + /* copy the username field in new request */ + aut->username = osip_malloc(strlen(username)+3); + sprintf(aut->username,"\"%s\"",username); + + { + char *tmp = osip_malloc(strlen(rquri)+3); + sprintf(tmp,"\"%s\"",rquri); + osip_proxy_authorization_set_uri(aut,tmp); + } + osip_proxy_authorization_set_algorithm(aut,osip_strdup("MD5")); + + { + char * pszNonce = NULL; + char * pszCNonce= NULL ; + const char * pszUser = username; + char * pszRealm = osip_strdup_without_quote(osip_proxy_authorization_get_realm(aut)); + const char * pszPass = NULL; + char * pszAlg = osip_strdup("MD5"); + char *szNonceCount = NULL; + char * pszMethod = previous_answer->cseq->method; + char * pszQop = NULL; + const char * pszURI = rquri; + + HASHHEX HA1; + HASHHEX HA2 = ""; + HASHHEX Response; + + pszPass=passwd; + + if (osip_www_authenticate_get_nonce(wa)==NULL) + return -1; + pszNonce = osip_strdup_without_quote(osip_www_authenticate_get_nonce(wa)); + + /* should upgrade szNonceCount */ + /* should add szNonceCount in aut*/ + /* should upgrade pszCNonce */ + /* should add pszCNonce in aut */ + + if (osip_proxy_authenticate_get_qop_options(wa)!=NULL) + { + szNonceCount = osip_strdup("00000001"); + /* MUST be incremented on each */ + pszQop = osip_strdup(osip_proxy_authenticate_get_qop_options(wa)); + pszCNonce = osip_strdup("234abcc436e2667097e7fe6eia53e8dd"); + } + DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce, + pszCNonce, HA1); + DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop, + pszMethod, pszURI, HA2, Response); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Response in proxy_authorization |%s|\n", Response)); + { + char *resp = osip_malloc(35); + sprintf(resp,"\"%s\"",Response); + osip_proxy_authorization_set_response(aut,resp); + } + osip_free(pszAlg); /* xkd, 2004-5-13*/ + osip_free(pszNonce); + osip_free(pszCNonce); + osip_free(pszRealm); + osip_free(pszQop); + osip_free(szNonceCount); + } + + *auth = aut; + return 0; +} diff --git a/linphone/exosip/jcall.c b/linphone/exosip/jcall.c new file mode 100644 index 000000000..65eae08a9 --- /dev/null +++ b/linphone/exosip/jcall.c @@ -0,0 +1,122 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + + +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +int eXosip_call_find(int cid, eXosip_call_t **jc) +{ + for (*jc=eXosip.j_calls; *jc!=NULL; *jc=(*jc)->next) + { + if ((*jc)->c_id==cid) + { + return 0; + } + } + *jc = NULL; + return -1; +} + +int +eXosip_call_init(eXosip_call_t **jc) +{ + *jc = (eXosip_call_t *)osip_malloc(sizeof(eXosip_call_t)); + if (*jc == NULL) return -1; + memset(*jc, 0, sizeof(eXosip_call_t)); + + (*jc)->c_id = -1; /* make sure the eXosip_update will assign a valid id to the call */ + osip_negotiation_ctx_init(&(*jc)->c_ctx); + return 0; +} + +void +__eXosip_call_remove_dialog_reference_in_call(eXosip_call_t *jc, eXosip_dialog_t *jd) +{ + eXosip_dialog_t *_jd; + jinfo_t *ji; + if (jc==NULL) return; + if (jd==NULL) return; + + + for (_jd = jc->c_dialogs; _jd!=NULL; _jd=jc->c_dialogs) + { + if (jd==_jd) + break; + } + if (_jd==NULL) + { + /* dialog not found??? */ + } + + ji = osip_transaction_get_your_instance(jc->c_inc_tr); + if (ji!=NULL && ji->jd==jd) + ji->jd=NULL; + ji = osip_transaction_get_your_instance(jc->c_out_tr); + if (ji!=NULL && ji->jd==jd) + ji->jd=NULL; +} + +void +eXosip_call_free(eXosip_call_t *jc) +{ + /* ... */ + + eXosip_dialog_t *jd; + + for (jd = jc->c_dialogs; jd!=NULL; jd=jc->c_dialogs) + { + REMOVE_ELEMENT(jc->c_dialogs, jd); + eXosip_dialog_free(jd); + } + + __eXosip_delete_jinfo(jc->c_inc_tr); + __eXosip_delete_jinfo(jc->c_out_tr); + if (jc->c_inc_tr!=NULL) + osip_list_add(eXosip.j_transactions, jc->c_inc_tr, 0); + if (jc->c_out_tr!=NULL) + osip_list_add(eXosip.j_transactions, jc->c_out_tr, 0); + + __eXosip_delete_jinfo(jc->c_inc_options_tr); + __eXosip_delete_jinfo(jc->c_out_options_tr); + if (jc->c_inc_options_tr!=NULL) + osip_list_add(eXosip.j_transactions, jc->c_inc_options_tr, 0); + if (jc->c_out_options_tr!=NULL) + osip_list_add(eXosip.j_transactions, jc->c_out_options_tr, 0); + + + osip_negotiation_ctx_free(jc->c_ctx); + osip_free(jc); + +} + +void +eXosip_call_set_subject(eXosip_call_t *jc, char *subject) +{ + if (jc==NULL||subject==NULL||subject[0]=='\0') return; + snprintf(jc->c_subject, 99, "%s", subject); +} + diff --git a/linphone/exosip/jcallback.c b/linphone/exosip/jcallback.c new file mode 100644 index 000000000..b8bb2bc58 --- /dev/null +++ b/linphone/exosip/jcallback.c @@ -0,0 +1,1972 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include + +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#endif + +#include +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +#ifdef TEST_AUDIO +static pid_t pid = 0; +#endif + + +/* Private functions */ +static void rcvregister_failure(int type, osip_transaction_t *tr,osip_message_t *sip); +int cb_udp_snd_message(osip_transaction_t *tr, osip_message_t *sip, + char *host, int port, int out_socket); +static void cb_ict_kill_transaction(int type, osip_transaction_t *tr); +static void cb_ist_kill_transaction(int type, osip_transaction_t *tr); +static void cb_nict_kill_transaction(int type, osip_transaction_t *tr); +static void cb_nist_kill_transaction(int type, osip_transaction_t *tr); +static void cb_rcvinvite (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvack (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvack2 (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvregister(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvbye (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvcancel (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvinfo (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvoptions (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvnotify (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvsubscribe (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvunkrequest(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndinvite (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndack (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndregister(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndbye (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndcancel (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndinfo (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndoptions (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndnotify (int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndsubscribe(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_sndunkrequest(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv1xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv2xx_4invite(osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv2xx_4subscribe(osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv2xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv3xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv4xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv5xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcv6xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_snd1xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_snd2xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_snd3xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_snd4xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_snd5xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_snd6xx(int type, osip_transaction_t *tr,osip_message_t *sip); +static void cb_rcvresp_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip); +static void cb_sndreq_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip); +static void cb_sndresp_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip); +static void cb_rcvreq_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip); +static void cb_transport_error(int type, osip_transaction_t *tr, int error); +static void report_call_event_with_status(int evt, eXosip_call_t *jc, eXosip_dialog_t *jd, osip_message_t *sip); +static void report_event_with_status(eXosip_event_t *je, osip_message_t *sip); + +int cb_udp_snd_message(osip_transaction_t *tr, osip_message_t *sip, char *host, + int port, int out_socket) +{ + int len = 0; + size_t length = 0; + static int num = 0; + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + char *message; + int i; + + if (eXosip.j_socket==0) return -1; + + if (host==NULL) + { + host = sip->req_uri->host; + if (sip->req_uri->port!=NULL) + port = osip_atoi(sip->req_uri->port); + else + port = 5060; + } + + i = eXosip_get_addrinfo(&addrinfo, host, port); + if (i!=0) + { + return -1; + } + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + len = addrinfo->ai_addrlen; + + freeaddrinfo (addrinfo); + + i = osip_message_to_str(sip, &message, &length); + + if (i!=0 || length<=0) { + return -1; + } + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Message sent: \n%s (len=%i sizeof(addr)=%i %i)\n", + message, len, sizeof(addr), sizeof(struct sockaddr_in6))); + if (0 > sendto (eXosip.j_socket, (const void*) message, length, 0, + (struct sockaddr *) &addr, len /* sizeof(addr) */ )) + { +#ifdef WIN32 + if (WSAECONNREFUSED==WSAGetLastError()) +#else + if (ECONNREFUSED==errno) +#endif + { + /* This can be considered as an error, but for the moment, + I prefer that the application continue to try sending + message again and again... so we are not in a error case. + Nevertheless, this error should be announced! + ALSO, UAS may not have any other options than retry always + on the same port. + */ + osip_free(message); + return 1; + } + else + { + /* SIP_NETWORK_ERROR; */ + osip_free(message); + return -1; + } + } + if (strncmp(message, "INVITE", 7)==0) + { + num++; + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO4,NULL,"number of message sent: %i\n", num)); + } + + osip_free(message); + return 0; + +} + +static void cb_ict_kill_transaction(int type, osip_transaction_t *tr) +{ + int i; + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_ict_kill_transaction (id=%i)\r\n", tr->transactionid)); + + i = osip_remove_transaction(eXosip.j_osip, tr); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"cb_ict_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", tr->transactionid)); + } +} + +static void cb_ist_kill_transaction(int type, osip_transaction_t *tr) +{ + int i; + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_ist_kill_transaction (id=%i)\r\n", tr->transactionid)); + i = osip_remove_transaction(eXosip.j_osip, tr); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"cb_ist_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", tr->transactionid)); + } +} + +static void cb_nict_kill_transaction(int type, osip_transaction_t *tr) +{ + int i; + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_nict_kill_transaction (id=%i)\r\n", tr->transactionid)); + i = osip_remove_transaction(eXosip.j_osip, tr); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"cb_nict_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", tr->transactionid)); + } + + if (MSG_IS_REGISTER(tr->orig_request) + && type==OSIP_NICT_KILL_TRANSACTION + && tr->last_response==NULL) + { + eXosip_event_t *je; + eXosip_reg_t *jreg=NULL; + /* find matching j_reg */ + _eXosip_reg_find(&jreg, tr); + if (jreg!=NULL) + { + je = eXosip_event_init_for_reg(EXOSIP_REGISTRATION_FAILURE, jreg); + report_event_with_status(je, NULL); + } + return; + } + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (jn==NULL && js==NULL) + return; + + /* no answer to a NOTIFY request! */ + if (MSG_IS_NOTIFY(tr->orig_request) + && type==OSIP_NICT_KILL_TRANSACTION + && tr->last_response==NULL) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + return; + } + + if (MSG_IS_NOTIFY(tr->orig_request) + && type==OSIP_NICT_KILL_TRANSACTION + && tr->last_response!=NULL + && tr->last_response->status_code > 299) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + return; + } + + if (MSG_IS_NOTIFY(tr->orig_request) + && type==OSIP_NICT_KILL_TRANSACTION + && tr->last_response!=NULL + && tr->last_response->status_code > 199 + && tr->last_response->status_code < 300) + { + if (jn->n_ss_status==EXOSIP_SUBCRSTATE_TERMINATED) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + return; + } + } + + /* no answer to a SUBSCRIBE request! */ + if (MSG_IS_SUBSCRIBE(tr->orig_request) + && type==OSIP_NICT_KILL_TRANSACTION + && tr->last_response==NULL) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_subscribes, js); + eXosip_subscribe_free(js); + return; + } + + /* detect SUBSCRIBE request that close the dialogs! */ + /* expires=0 with MSN */ + if (MSG_IS_SUBSCRIBE(tr->orig_request) + && type==OSIP_NICT_KILL_TRANSACTION) + { + osip_header_t *expires; + osip_message_get_expires(tr->orig_request, 0, &expires); + if (expires==NULL || expires->hvalue==NULL) + { + } + else if (0==strcmp(expires->hvalue, "0")) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_subscribes, js); + eXosip_subscribe_free(js); + return; + } + } +} + +static void cb_nist_kill_transaction(int type, osip_transaction_t *tr) +{ + int i; + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_nist_kill_transaction (id=%i)\r\n", tr->transactionid)); + i = osip_remove_transaction(eXosip.j_osip, tr); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"cb_nist_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", tr->transactionid)); + } + +} + +static void cb_rcvinvite (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvinvite (id=%i)\n", tr->transactionid)); +} + +static void cb_rcvack (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvack (id=%i)\n", tr->transactionid)); +} + +static void cb_rcvack2 (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvack2 (id=%i)\r\n", tr->transactionid)); +} + +static void cb_rcvregister(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvregister (id=%i)\r\n", tr->transactionid)); +} + +static void cb_rcvbye (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvbye (id=%i)\r\n", tr->transactionid)); +#ifdef TEST_AUDIO + if (pid!=0) + { + int i = kill(pid, SIGINT); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"audio command kill return %i %i\n", i, pid)); + pid = 0; + } +#endif +} + +static void cb_rcvcancel (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvcancel (id=%i)\r\n", tr->transactionid)); +} + +static void cb_rcvinfo (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_event_t *je; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvinfo (id=%i)\r\n", tr->transactionid)); + + if (jinfo==NULL) + return; + if (jinfo->jc==NULL) + return; + + je = eXosip_event_init_for_call(EXOSIP_INFO_NEW, jinfo->jc, jinfo->jd); + if (je!=NULL) + { + char *tmp; + osip_uri_to_str(sip->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + + if (sip!=NULL) + { + int pos; + /* get content-type info */ + osip_content_type_clone(osip_message_get_content_type(sip), &(je->i_ctt)); + /* get list of bodies */ + je->i_bodies = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(je->i_bodies); + for (pos=0;!osip_list_eol(sip->bodies, pos);pos++) + { + osip_body_t *body; + osip_body_t *_body; + body = (osip_body_t *)osip_list_get(sip->bodies, pos); + osip_body_clone(body, &_body); + osip_list_add(je->i_bodies, _body, -1); + } + } + } + + report_event_with_status(je, NULL); +} + +static void cb_rcvoptions (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_event_t *je; + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvoptions (id=%i)\r\n", tr->transactionid)); + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + if (jinfo->jc==NULL) + return; + + je = eXosip_event_init_for_call(EXOSIP_OPTIONS_NEW, jc, jd); + if (je!=NULL) + { + char *tmp; + osip_uri_to_str(sip->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + report_event_with_status(je, NULL); + +} + +static void cb_rcvnotify (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvnotify (id=%i)\r\n", tr->transactionid)); +} + +static void cb_rcvsubscribe (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_event_t *je; + eXosip_dialog_t *jd; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvsubscribe (id=%i)\r\n", tr->transactionid)); + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jn = jinfo->jn; + if (jinfo->jn==NULL) + return; + + je = eXosip_event_init_for_notify(EXOSIP_IN_SUBSCRIPTION_NEW, jn, jd); + if (je!=NULL) + { + char *tmp; + osip_uri_to_str(sip->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + report_event_with_status(je, NULL); +} + +static void cb_rcvunkrequest(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvunkrequest (id=%i)\r\n", tr->transactionid)); + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jinfo->jc==NULL) + return; + + + if (MSG_IS_REFER(sip)) + { + eXosip_event_t *je; + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvrefer (id=%i)\r\n", tr->transactionid)); + + je = eXosip_event_init_for_call(EXOSIP_CALL_REFERED, jc, jd); + if (je!=NULL) + { + report_event_with_status(je, NULL); + } + } + +} + +static void cb_sndinvite (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndinvite (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndack (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndack (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndregister(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndregister (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndbye (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndbye (id=%i)\r\n", tr->transactionid)); +#ifdef TEST_AUDIO + if (pid!=0) + { + int i = kill(pid, SIGINT); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"audio command kill return %i %i\n", i, pid)); + pid = 0; + } +#endif + +} + +static void cb_sndcancel (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndcancel (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndinfo (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndinfo (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndoptions (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndoptions (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndnotify (int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndnotify (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndsubscribe(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndsubscibe (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndunkrequest(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndunkrequest (id=%i)\r\n", tr->transactionid)); +} + +void __eXosip_delete_jinfo(osip_transaction_t *transaction) +{ + jinfo_t *ji; + if (transaction==NULL) + return; + ji = osip_transaction_get_your_instance(transaction); + osip_free(ji); + osip_transaction_set_your_instance(transaction, NULL); +} + +jinfo_t *__eXosip_new_jinfo(eXosip_call_t *jc, eXosip_dialog_t *jd, + eXosip_subscribe_t *js, eXosip_notify_t *jn) +{ + jinfo_t *ji = (jinfo_t *) osip_malloc(sizeof(jinfo_t)); + if (ji==NULL) return NULL; + ji->jd = jd; + ji->jc = jc; + ji->js = js; + ji->jn = jn; + return ji; +} + +static void cb_rcv1xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv1xx (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR(sip, "OPTIONS")) + { + if (jc==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv1xx (id=%i) Error: no call or transaction info for OPTIONS transaction\r\n", tr->transactionid)); + return; + } + else if (jc->c_out_options_tr==NULL) + { + /* options is within a call */ + } + report_call_event_with_status(EXOSIP_OPTIONS_PROCEEDING, jc, jd, sip); + return; + } + + if ((MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + && !MSG_TEST_CODE(sip, 100)) + { + int i; + /* for SUBSCRIBE, test if the dialog has been already created + with a previous NOTIFY */ + if (jd==NULL && js!=NULL && js->s_dialogs!=NULL && MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + /* find if existing dialog match the to tag */ + osip_generic_param_t *tag; + int i; + i = osip_to_get_tag (sip->to, &tag); + if (i==0 && tag!=NULL && tag->gvalue!=NULL ) + { + for (jd = js->s_dialogs; jd!= NULL ; jd=jd->next) + { + if (0==strcmp(jd->d_dialog->remote_tag, tag->gvalue)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: found established early dialog for this subscribe\n")); + jinfo->jd = jd; + break; + } + } + } + } + + if (jd == NULL) /* This transaction initiate a dialog in the case of + INVITE (else it would be attached to a "jd" element. */ + { + /* allocate a jd */ + + i = eXosip_dialog_init_as_uac(&jd, sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + if (jc!=NULL) + { + ADD_ELEMENT(jc->c_dialogs, jd); + jinfo->jd = jd; + eXosip_update(); + } + else if (js!=NULL) + { + ADD_ELEMENT(js->s_dialogs, jd); + jinfo->jd = jd; + eXosip_update(); + } + else if (jn!=NULL) + { + ADD_ELEMENT(jn->n_dialogs, jd); + jinfo->jd = jd; + eXosip_update(); + } + else + { +#ifndef WIN32 + assert(0==0); +#else + exit(0); +#endif + } + osip_transaction_set_your_instance(tr, jinfo); + } + else + { + osip_dialog_update_route_set_as_uac(jd->d_dialog, sip); + } + + if ( jd!=NULL) + jd->d_STATE = JD_TRYING; + if ( jd!=NULL && MSG_IS_RESPONSE_FOR(sip, "INVITE") + && sip->status_code < 180) + { + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_PROCEEDING, jc, jd); + if (je!=NULL) + { + if (sip->status_code>100) + eXosip_event_add_sdp_info(je, sip); + report_event_with_status(je, sip); + } + } + else if ( jd!=NULL && MSG_IS_RESPONSE_FOR(sip, "INVITE") + && sip->status_code >= 180) + { + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_RINGING, jc, jd); + if (je!=NULL) + { + eXosip_event_add_sdp_info(je, sip); + report_event_with_status(je, sip); + } + } + else if ( jd!=NULL && MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_PROCEEDING, js, jd); + if (je!=NULL) + report_event_with_status(je, sip); + } + if (MSG_TEST_CODE(sip, 180) && jd!=NULL) + { + jd->d_STATE = JD_RINGING; + } + else if (MSG_TEST_CODE(sip, 183) && jd!=NULL) + { + jd->d_STATE = JD_QUEUED; + } + + } +} + +sdp_message_t *eXosip_get_remote_sdp(osip_transaction_t *transaction) +{ + osip_message_t *message; + osip_body_t *body; + sdp_message_t *sdp; + int pos = 0; + int i; + if (transaction->ist_context!=NULL) + /* remote sdp is in INVITE (or ACK!) */ + message = transaction->orig_request; + else + /* remote sdp is in response */ + message = transaction->last_response; + + if (message==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"No remote sdp body found\r\n")); + return NULL; + } + sdp=NULL; + body = (osip_body_t *)osip_list_get(message->bodies,0); + while (body!=NULL) + { + i = sdp_message_init(&sdp); + if (i!=0) + { sdp = NULL; break; } + i = sdp_message_parse(sdp,body->body); + if (i==0) + return sdp; + sdp_message_free(sdp); + sdp = NULL; + pos++; + body = (osip_body_t *)osip_list_get(message->bodies,pos); + } + return NULL; +} + +sdp_message_t *eXosip_get_local_sdp(osip_transaction_t *transaction) +{ + osip_message_t *message; + osip_body_t *body; + sdp_message_t *sdp; + int i; + int pos = 0; + if (transaction->ict_context!=NULL) + /* local sdp is in INVITE (or ACK!) */ + message = transaction->orig_request; + else + /* local sdp is in response */ + message = transaction->last_response; + + sdp=NULL; + body = (osip_body_t *)osip_list_get(message->bodies,0); + while (body!=NULL) + { + i = sdp_message_init(&sdp); + if (i!=0) + { sdp = NULL; break; } + i = sdp_message_parse(sdp,body->body); + if (i==0) + return sdp; + sdp_message_free(sdp); + sdp = NULL; + pos++; + body = (osip_body_t *)osip_list_get(message->bodies,pos); + } + return NULL; +} + + +static +void report_call_event_with_status(int evt, eXosip_call_t *jc, eXosip_dialog_t *jd, osip_message_t *sip) +{ + eXosip_event_t *je; + je = eXosip_event_init_for_call(evt, jc, jd); + if (je!=NULL) + { + if (sip != NULL) + eXosip_event_add_status(je, sip); + if (eXosip.j_call_callbacks[evt]!=NULL) + eXosip.j_call_callbacks[evt](evt, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); + } + +} + +static +void report_event_with_status(eXosip_event_t *je, osip_message_t *sip) +{ + if (je!=NULL) + { + int evt = je->type; + + if (sip != NULL) + eXosip_event_add_status(je, sip); + if (eXosip.j_call_callbacks[evt]!=NULL) + eXosip.j_call_callbacks[evt](evt, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); + } +} + + +#if 0 +void eXosip_update_audio_session(osip_transaction_t *transaction) +{ + char *remaddr; + sdp_message_t *remote_sdp; + sdp_message_t *local_sdp; + char *remote_port; + char *local_port; + char *payload; + char *media_type; + int pos; + /* look for the SDP informations */ + + remote_sdp = eXosip_get_remote_sdp(transaction); + if (remote_sdp==NULL) + return ; + local_sdp = eXosip_get_local_sdp(transaction); + if (local_sdp==NULL) + { + sdp_message_free(remote_sdp); + return ; + } + remaddr=sdp_message_c_addr_get(remote_sdp,-1,0); + if (remaddr==NULL){ + remaddr=sdp_message_c_addr_get(remote_sdp,0,0); + } + + pos=0; + local_port=sdp_message_m_port_get(local_sdp,pos); + media_type = sdp_message_m_media_get(local_sdp,pos); + while (local_port!=NULL && media_type!=NULL) + { /* If we have refused some media lines, the port is set to 0 */ + if (0!=strncmp(local_port,"0", 1)&&0==osip_strcasecmp(media_type,"audio")) + break; + pos++; + media_type = sdp_message_m_media_get(local_sdp,pos); + local_port=sdp_message_m_port_get(local_sdp,pos); + } + + if (media_type!=NULL && local_port!=NULL) + { + remote_port = sdp_message_m_port_get(remote_sdp,pos); + payload = sdp_message_m_payload_get(local_sdp,pos,0); + } + else + { + remote_port = NULL; + payload = NULL; + } + if (remote_port!=NULL && media_type!=NULL) /* if codec has been found */ + { + char tmp[256]; + sprintf(tmp, "mediastream --local %s --remote %s:%s --payload %s > debug_rtp 2>&1" , local_port, remaddr, remote_port, payload); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"audio command %s\n", tmp)); + +#ifdef TEST_AUDIO + if (pid!=0) + { + int i = kill(pid, SIGINT); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"audio command kill return %i %i\n", i, pid)); + pid = 0; + } + + pid = fork(); + if (pid==0) + { + int ret; +#ifndef USE_EXECL + ret = system(tmp); + if (WIFSIGNALED(ret) && + (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT)) + { + exit(-1); + } + if (ret==0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"Could not start audio\n", tmp)); + } + exit(0); +#else + char _remoteipport[100]; + snprintf(_remoteipport, 100, "%s:%s", remaddr, remote_port); + ret = execl("mediastream","--local", local_port, + "--remote", _remoteipport, "--payload", payload); +#endif + } +#endif + + } + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"Could not create audio session.\r\n")); + } + sdp_message_free(local_sdp); + sdp_message_free(remote_sdp); +} +#endif + +static void cb_rcv2xx_4invite(osip_transaction_t *tr,osip_message_t *sip) +{ + int i; + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) /* This transaction initiate a dialog in the case of + INVITE (else it would be attached to a "jd" element. */ + { + /* allocate a jd */ + i = eXosip_dialog_init_as_uac(&jd, sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + ADD_ELEMENT(jc->c_dialogs, jd); + jinfo->jd = jd; + eXosip_update(); + osip_transaction_set_your_instance(tr, jinfo); + } + else + { + /* Here is a special case: + We have initiated a dialog and we have received informationnal + answers from 2 or more remote SIP UA. Those answer can be + differentiated with the "To" header's tag. + + We have used the first informationnal answer to create a + dialog, but we now want to be sure the 200ok received is + for the dialog this dialog. + + We have to check the To tag and if it does not match, we + just have to modify the existing dialog and replace it. */ + osip_generic_param_t *tag; + int i; + i = osip_to_get_tag (sip->to, &tag); + i=1; /* default is the same dialog */ + + if (jd->d_dialog==NULL || jd->d_dialog->remote_tag==NULL) + { + /* There are real use-case where a BYE is received/processed before + the 200ok of the previous INVITE. In this case, jd->d_dialog is + empty and the transaction should be silently discarded. */ + /* a ACK should still be sent... -but there is no dialog built- */ + return; + } + + if (jd->d_dialog->remote_tag==NULL && tag==NULL) + { } /* non compliant remote UA -> assume it is the same dialog */ + else if (jd->d_dialog->remote_tag!=NULL && tag==NULL) + { i=0; } /* different dialog! */ + else if (jd->d_dialog->remote_tag==NULL && tag!=NULL) + { i=0; } /* different dialog! */ + else if (jd->d_dialog->remote_tag!=NULL && tag!=NULL && tag->gvalue!=NULL + && 0!=strcmp(jd->d_dialog->remote_tag, tag->gvalue)) + { i=0; } /* different dialog! */ + + if (i==1) /* just update the dialog */ + { + osip_dialog_update_route_set_as_uac(jd->d_dialog, sip); + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + } + else + { + /* the best thing is to update the repace the current dialog + information... Much easier than creating a useless dialog! */ + osip_dialog_free(jd->d_dialog); + i = osip_dialog_init_as_uac(&(jd->d_dialog), sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"Cannot replace the dialog.\r\n")); + } + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_WARNING,NULL,"The dialog has been replaced with the new one fro 200ok.\r\n")); + } + } + } + + jd->d_STATE = JD_ESTABLISHED; + + eXosip_dialog_set_200ok(jd, sip); + + { + osip_route_t *route; + char *host; + int port; + osip_message_t *ack; + i = _eXosip_build_request_within_dialog(&ack, "ACK", jd->d_dialog, "UDP"); + if (i!=0) { + jd->d_STATE = JD_ESTABLISHED; + return ; + } + + if(jc->c_ack_sdp) /* need to build sdp answer */ + { + char *body; + char *size; + + body = generating_sdp_answer(tr->last_response, jc->c_ctx); + if (body==NULL) + { + return; + } + + i = osip_message_set_body(ack, body, strlen(body)); + if (i!=0) + { + return; + } + + size = (char *) osip_malloc(6*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(body)); +#else + sprintf(size,"%i",strlen(body)); +#endif + osip_free(body); + i = osip_message_set_content_length(ack, size); + osip_free(size); + if (i!=0) + { + return; + } + i = osip_message_set_content_type(ack, "application/sdp"); + if (i!=0) + { + return; + } + } + + /* SM: do not send the ack now, just prepare it. + The application will send it using eXosip_send_ack(int jid) + */ + /* + osip_message_get_route(ack, 0, &route); + if (route!=NULL) + { + port = 5060; + if (route->url->port!=NULL) + port = osip_atoi(route->url->port); + host = route->url->host; + } + else + { + port = 5060; + if (ack->req_uri->port!=NULL) + port = osip_atoi(ack->req_uri->port); + host = ack->req_uri->host; + } + + cb_udp_snd_message(NULL, ack, host, port, eXosip.j_socket); + */ + + jd->d_ack = ack; + + } + + { + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_ANSWERED, jc, jd); + if (je!=NULL) + { + eXosip_event_add_sdp_info(je, sip); + report_event_with_status(je, sip); + } + + + je = eXosip_event_init_for_call(EXOSIP_CALL_STARTAUDIO, jc, jd); + if (je!=NULL) + { + eXosip_event_add_sdp_info(je, sip); + report_event_with_status(je, sip); + } + + } + + /* look for the SDP information and decide if this answer was for + an initial INVITE, an HoldCall, or a RetreiveCall */ + + /* don't handle hold/unhold by now... */ + /* eXosip_update_audio_session(tr); */ + +} + +static void cb_rcv2xx_4subscribe(osip_transaction_t *tr,osip_message_t *sip) +{ + int i; + eXosip_dialog_t *jd; + eXosip_subscribe_t *js; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + if (jinfo==NULL) + return; + jd = jinfo->jd; + js = jinfo->js; + _eXosip_subscribe_set_refresh_interval(js, sip); + + + /* for SUBSCRIBE, test if the dialog has been already created + with a previous NOTIFY */ + if (jd==NULL && js!=NULL && js->s_dialogs!=NULL && MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + /* find if existing dialog match the to tag */ + osip_generic_param_t *tag; + int i; + i = osip_to_get_tag (sip->to, &tag); + if (i==0 && tag!=NULL && tag->gvalue!=NULL ) + { + for (jd = js->s_dialogs; jd!= NULL ; jd=jd->next) + { + if (0==strcmp(jd->d_dialog->remote_tag, tag->gvalue)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: found established early dialog for this subscribe\n")); + jinfo->jd = jd; + break; + } + } + } + } + + if (jd == NULL) /* This transaction initiate a dialog in the case of + SUBSCRIBE (else it would be attached to a "jd" element. */ + { + /* allocate a jd */ + i = eXosip_dialog_init_as_uac(&jd, sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + ADD_ELEMENT(js->s_dialogs, jd); + jinfo->jd = jd; + eXosip_update(); + osip_transaction_set_your_instance(tr, jinfo); + } + else + { + osip_dialog_update_route_set_as_uac(jd->d_dialog, sip); + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + } + + jd->d_STATE = JD_ESTABLISHED; + /* look for the body information */ + + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_ANSWERED, js, jd); + if (je!=NULL) + { + report_event_with_status(je, sip); + } + } + +} + +static void cb_rcv2xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv2xx (id=%i)\r\n", tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR(sip, "PUBLISH")) + { + eXosip_pub_t *pub; + int i; + i = _eXosip_pub_update(&pub, tr, sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"cb_rcv2xx (id=%i) No publication to update\r\n", tr->transactionid)); + } + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "REGISTER")) + { + eXosip_event_t *je; + eXosip_reg_t *jreg=NULL; + /* find matching j_reg */ + _eXosip_reg_find(&jreg, tr); + if (jreg!=NULL) + { + je = eXosip_event_init_for_reg(EXOSIP_REGISTRATION_SUCCESS, jreg); + if (je!=NULL) + { + report_event_with_status(je, sip); + } + } + return; + } + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR(sip, "OPTIONS")) + { + if (jc==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv2xx (id=%i) Error: no call or transaction info for OPTIONS transaction\r\n", tr->transactionid)); + return; + } + else if (jc->c_out_options_tr==NULL) + { + /* options is within a call */ + } + report_call_event_with_status(EXOSIP_OPTIONS_ANSWERED, jc, jd, sip); + return; + } + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + cb_rcv2xx_4invite(tr, sip); + } + else if (MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + cb_rcv2xx_4subscribe(tr, sip); + } + else if (MSG_IS_RESPONSE_FOR(sip, "BYE")) + { + if (jd!=NULL) + jd->d_STATE = JD_TERMINATED; + } + else if (MSG_IS_RESPONSE_FOR(sip, "MESSAGE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_message(EXOSIP_MESSAGE_SUCCESS, tr, sip); + if (je!=NULL) + report_event_with_status(je, sip); + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "NOTIFY")) + { +#ifdef SUPPORT_MSN + osip_header_t *expires; + osip_message_header_get_byname(tr->orig_request, "expires", + 0, &expires); + if (expires==NULL || expires->hvalue==NULL) + { + /* UNCOMPLIANT UA without a subscription-state header */ + } + else if (0==osip_strcasecmp(expires->hvalue, "0")) + { + /* delete the dialog! */ + if (jn!=NULL) + { + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + } + } +#else + osip_header_t *sub_state; + osip_message_header_get_byname(tr->orig_request, "subscription-state", + 0, &sub_state); + if (sub_state==NULL || sub_state->hvalue==NULL) + { + /* UNCOMPLIANT UA without a subscription-state header */ + } + else if (0==osip_strncasecmp(sub_state->hvalue, "terminated", 10)) + { + /* delete the dialog! */ + if (jn!=NULL) + { + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + } + } +#endif + } +} + +void eXosip_delete_early_dialog(eXosip_dialog_t *jd) +{ + if (jd == NULL) /* bug? */ + return; + + /* an early dialog was created, but the call is not established */ + if (jd->d_dialog!=NULL && jd->d_dialog->state==DIALOG_EARLY) + { + osip_dialog_free(jd->d_dialog); + jd->d_dialog = NULL; + eXosip_dialog_set_state(jd, JD_TERMINATED); + } +} + +static void +rcvregister_failure(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_event_t *je; + eXosip_reg_t *jreg=NULL; + /* find matching j_reg */ + _eXosip_reg_find(&jreg, tr); + if (jreg!=NULL) + { + je = eXosip_event_init_for_reg(EXOSIP_REGISTRATION_FAILURE, jreg); + report_event_with_status(je, sip); + } +} + +static void cb_rcv3xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv3xx (id=%i)\r\n", tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR(sip, "PUBLISH")) + { + eXosip_pub_t *pub; + int i; + i = _eXosip_pub_update(&pub, tr, sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"cb_rcv3xx (id=%i) No publication to update\r\n", tr->transactionid)); + } + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "REGISTER")) + { + rcvregister_failure(type, tr, sip); + return; + } + + if (jinfo==NULL) return; + jd = jinfo->jd; + jc = jinfo->jc; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR(sip, "OPTIONS")) + { + if (jc==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv3xx (id=%i) Error: no call or transaction info for INFO transaction\r\n", tr->transactionid)); + return; + } + else if (jc->c_out_options_tr==NULL) + { + /* options is within a call */ + } + + report_call_event_with_status(EXOSIP_OPTIONS_REDIRECTED, jc, jd, sip); + return; + } + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_REDIRECTED, jc, jd, sip); + } + else if (MSG_IS_RESPONSE_FOR(sip, "MESSAGE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_message(EXOSIP_MESSAGE_FAILURE, tr, sip); + if (je) + report_event_with_status(je, sip); + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_REDIRECTED, js, jd); + if (je) + report_event_with_status(je, sip); + } + + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + if (jd->d_dialog==NULL) + jd->d_STATE = JD_REDIRECTED; + } + +} + +static void cb_rcv4xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv4xx (id=%i)\r\n", tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR(sip, "PUBLISH")) + { + eXosip_pub_t *pub; + int i; + i = _eXosip_pub_update(&pub, tr, sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"cb_rcv4xx (id=%i) No publication to update\r\n", tr->transactionid)); + } + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "REGISTER")) + { + rcvregister_failure(type, tr, sip); + return; + } + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR(sip, "OPTIONS")) + { + if (jc==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv4xx (id=%i) Error: no call or transaction info for INFO transaction\r\n", tr->transactionid)); + return; + } + else if (jc->c_out_options_tr==NULL) + { + /* options is within a call */ + } + + report_call_event_with_status(EXOSIP_OPTIONS_REQUESTFAILURE, jc, jd, sip); + return; + } + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_REQUESTFAILURE, jc, jd, sip); + } + else if (MSG_IS_RESPONSE_FOR(sip, "MESSAGE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_message(EXOSIP_MESSAGE_FAILURE, tr, sip); + if (je!=NULL) + report_event_with_status(je, sip); + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_REQUESTFAILURE, js, jd); + if (je!=NULL) + report_event_with_status(je, sip); + } + + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + if (MSG_TEST_CODE(sip, 401) || MSG_TEST_CODE(sip, 407)) + jd->d_STATE = JD_AUTH_REQUIRED; + else + jd->d_STATE = JD_CLIENTERROR; + } + +} + +static void cb_rcv5xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv5xx (id=%i)\r\n", tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR(sip, "PUBLISH")) + { + eXosip_pub_t *pub; + int i; + i = _eXosip_pub_update(&pub, tr, sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"cb_rcv3xx (id=%i) No publication to update\r\n", tr->transactionid)); + } + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "REGISTER")) + { + rcvregister_failure(type, tr, sip); + return; + } + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR(sip, "OPTIONS")) + { + if (jc==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv5xx (id=%i) Error: no call or transaction info for INFO transaction\r\n", tr->transactionid)); + return; + } + else if (jc->c_out_options_tr==NULL) + { + /* options is within a call */ + } + + report_call_event_with_status(EXOSIP_OPTIONS_SERVERFAILURE, jc, jd, sip); + return; + } + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_SERVERFAILURE, jc, jd, sip); + } + else if (MSG_IS_RESPONSE_FOR(sip, "MESSAGE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_message(EXOSIP_MESSAGE_FAILURE, tr, sip); + if (je!=NULL) + report_event_with_status(je, sip); + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_SERVERFAILURE, js, jd); + if (je!=NULL) + report_event_with_status(je, sip); + } + + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + jd->d_STATE = JD_SERVERERROR; + } + +} + +static void cb_rcv6xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv6xx (id=%i)\r\n", tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR(sip, "PUBLISH")) + { + eXosip_pub_t *pub; + int i; + i = _eXosip_pub_update(&pub, tr, sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"cb_rcv6xx (id=%i) No publication to update\r\n", tr->transactionid)); + } + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "REGISTER")) + { + rcvregister_failure(type, tr, sip); + return; + } + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR(sip, "OPTIONS")) + { + if (jc==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcv6xx (id=%i) Error: no call or transaction info for INFO transaction\r\n", tr->transactionid)); + return; + } + else if (jc->c_out_options_tr==NULL) + { + /* options is within a call */ + } + report_call_event_with_status(EXOSIP_OPTIONS_GLOBALFAILURE, jc, jd, sip); + return; + } + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_GLOBALFAILURE, jc, jd, sip); + } + else if (MSG_IS_RESPONSE_FOR(sip, "MESSAGE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_message(EXOSIP_MESSAGE_FAILURE, tr, sip); + if (je!=NULL) + report_event_with_status(je, sip); + return; + } + else if (MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_GLOBALFAILURE, js, jd); + if (je!=NULL) + report_event_with_status(je, sip); + } + + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + jd->d_STATE = JD_GLOBALFAILURE; + } + +} + +static void cb_snd1xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_snd1xx (id=%i)\r\n", tr->transactionid)); + + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd==NULL) return; + jd->d_STATE = JD_TRYING; +} + +static void cb_snd2xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_snd2xx (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + jd->d_STATE = JD_ESTABLISHED; + return; + } + jd->d_STATE = JD_ESTABLISHED; +} + +static void cb_snd3xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_snd3xx (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + } + jd->d_STATE = JD_REDIRECTED; + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_CLOSED, jc, jd, sip); + } +} + +static void cb_snd4xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_snd4xx (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + } + jd->d_STATE = JD_CLIENTERROR; + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_CLOSED, jc, jd, sip); + } + +} + +static void cb_snd5xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_snd5xx (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + } + jd->d_STATE = JD_SERVERERROR; + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_CLOSED, jc, jd, sip); + } + +} + +static void cb_snd6xx(int type, osip_transaction_t *tr,osip_message_t *sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_snd6xx (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd==NULL) return; + if (MSG_IS_RESPONSE_FOR(sip, "INVITE") + || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog(jd); + } + jd->d_STATE = JD_GLOBALFAILURE; + + if (MSG_IS_RESPONSE_FOR(sip, "INVITE")) + { + report_call_event_with_status(EXOSIP_CALL_CLOSED, jc, jd, sip); + } + +} + +static void cb_rcvresp_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvresp_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndreq_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndreq_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void cb_sndresp_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_sndresp_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void cb_rcvreq_retransmission(int type, osip_transaction_t *tr, osip_message_t *sip) +{ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_rcvreq_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void cb_transport_error(int type, osip_transaction_t *tr, int error) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *)osip_transaction_get_your_instance(tr); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"cb_transport_error (id=%i)\r\n", tr->transactionid)); + if (jinfo==NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (jn==NULL && js==NULL) + return; + + if (MSG_IS_NOTIFY(tr->orig_request) + && type==OSIP_NICT_TRANSPORT_ERROR) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_notifies, jn); + eXosip_notify_free(jn); + } + + if (MSG_IS_SUBSCRIBE(tr->orig_request) + && type==OSIP_NICT_TRANSPORT_ERROR) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_subscribes, js); + eXosip_subscribe_free(js); + } + + if (MSG_IS_OPTIONS(tr->orig_request) && jc->c_dialogs==NULL + && type==OSIP_NICT_TRANSPORT_ERROR) + { + /* delete the dialog! */ + REMOVE_ELEMENT(eXosip.j_calls, jc); + eXosip_call_free(jc); + } +} + + + +int +eXosip_set_callbacks(osip_t *osip) +{ + /* register all callbacks */ + + osip_set_cb_send_message(osip, &cb_udp_snd_message); + + osip_set_kill_transaction_callback(osip ,OSIP_ICT_KILL_TRANSACTION, + &cb_ict_kill_transaction); + osip_set_kill_transaction_callback(osip ,OSIP_IST_KILL_TRANSACTION, + &cb_ist_kill_transaction); + osip_set_kill_transaction_callback(osip ,OSIP_NICT_KILL_TRANSACTION, + &cb_nict_kill_transaction); + osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION, + &cb_nist_kill_transaction); + + osip_set_message_callback(osip ,OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback(osip ,OSIP_ICT_STATUS_3456XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback(osip ,OSIP_ICT_INVITE_SENT_AGAIN, + &cb_sndreq_retransmission); + osip_set_message_callback(osip ,OSIP_IST_STATUS_2XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback(osip ,OSIP_IST_STATUS_3456XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback(osip ,OSIP_IST_INVITE_RECEIVED_AGAIN, + &cb_rcvreq_retransmission); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_3456XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback(osip ,OSIP_NICT_REQUEST_SENT_AGAIN, + &cb_sndreq_retransmission); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_2XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_3456XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback(osip ,OSIP_NIST_REQUEST_RECEIVED_AGAIN, + &cb_rcvreq_retransmission); + + osip_set_transport_error_callback(osip ,OSIP_ICT_TRANSPORT_ERROR, + &cb_transport_error); + osip_set_transport_error_callback(osip ,OSIP_IST_TRANSPORT_ERROR, + &cb_transport_error); + osip_set_transport_error_callback(osip ,OSIP_NICT_TRANSPORT_ERROR, + &cb_transport_error); + osip_set_transport_error_callback(osip ,OSIP_NIST_TRANSPORT_ERROR, + &cb_transport_error); + + osip_set_message_callback(osip ,OSIP_ICT_INVITE_SENT, &cb_sndinvite); + osip_set_message_callback(osip ,OSIP_ICT_ACK_SENT, &cb_sndack); + osip_set_message_callback(osip ,OSIP_NICT_REGISTER_SENT, &cb_sndregister); + osip_set_message_callback(osip ,OSIP_NICT_BYE_SENT, &cb_sndbye); + osip_set_message_callback(osip ,OSIP_NICT_CANCEL_SENT, &cb_sndcancel); + osip_set_message_callback(osip ,OSIP_NICT_INFO_SENT, &cb_sndinfo); + osip_set_message_callback(osip ,OSIP_NICT_OPTIONS_SENT, &cb_sndoptions); + osip_set_message_callback(osip ,OSIP_NICT_SUBSCRIBE_SENT, &cb_sndsubscribe); + osip_set_message_callback(osip ,OSIP_NICT_NOTIFY_SENT, &cb_sndnotify); + /* osip_set_cb_nict_sndprack (osip,&cb_sndprack); */ + osip_set_message_callback(osip ,OSIP_NICT_UNKNOWN_REQUEST_SENT, &cb_sndunkrequest); + + osip_set_message_callback(osip ,OSIP_ICT_STATUS_1XX_RECEIVED, &cb_rcv1xx); + osip_set_message_callback(osip ,OSIP_ICT_STATUS_2XX_RECEIVED, &cb_rcv2xx); + osip_set_message_callback(osip ,OSIP_ICT_STATUS_3XX_RECEIVED, &cb_rcv3xx); + osip_set_message_callback(osip ,OSIP_ICT_STATUS_4XX_RECEIVED, &cb_rcv4xx); + osip_set_message_callback(osip ,OSIP_ICT_STATUS_5XX_RECEIVED, &cb_rcv5xx); + osip_set_message_callback(osip ,OSIP_ICT_STATUS_6XX_RECEIVED, &cb_rcv6xx); + + osip_set_message_callback(osip ,OSIP_IST_STATUS_1XX_SENT, &cb_snd1xx); + osip_set_message_callback(osip ,OSIP_IST_STATUS_2XX_SENT, &cb_snd2xx); + osip_set_message_callback(osip ,OSIP_IST_STATUS_3XX_SENT, &cb_snd3xx); + osip_set_message_callback(osip ,OSIP_IST_STATUS_4XX_SENT, &cb_snd4xx); + osip_set_message_callback(osip ,OSIP_IST_STATUS_5XX_SENT, &cb_snd5xx); + osip_set_message_callback(osip ,OSIP_IST_STATUS_6XX_SENT, &cb_snd6xx); + + osip_set_message_callback(osip ,OSIP_NICT_STATUS_1XX_RECEIVED, &cb_rcv1xx); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_2XX_RECEIVED, &cb_rcv2xx); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_3XX_RECEIVED, &cb_rcv3xx); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_4XX_RECEIVED, &cb_rcv4xx); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_5XX_RECEIVED, &cb_rcv5xx); + osip_set_message_callback(osip ,OSIP_NICT_STATUS_6XX_RECEIVED, &cb_rcv6xx); + + osip_set_message_callback(osip ,OSIP_NIST_STATUS_1XX_SENT, &cb_snd1xx); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_2XX_SENT, &cb_snd2xx); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_3XX_SENT, &cb_snd3xx); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_4XX_SENT, &cb_snd4xx); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_5XX_SENT, &cb_snd5xx); + osip_set_message_callback(osip ,OSIP_NIST_STATUS_6XX_SENT, &cb_snd6xx); + + osip_set_message_callback(osip ,OSIP_IST_INVITE_RECEIVED, &cb_rcvinvite); + osip_set_message_callback(osip ,OSIP_IST_ACK_RECEIVED, &cb_rcvack); + osip_set_message_callback(osip ,OSIP_IST_ACK_RECEIVED_AGAIN, &cb_rcvack2); + osip_set_message_callback(osip ,OSIP_NIST_REGISTER_RECEIVED, &cb_rcvregister); + osip_set_message_callback(osip ,OSIP_NIST_BYE_RECEIVED, &cb_rcvbye); + osip_set_message_callback(osip ,OSIP_NIST_CANCEL_RECEIVED, &cb_rcvcancel); + osip_set_message_callback(osip ,OSIP_NIST_INFO_RECEIVED, &cb_rcvinfo); + osip_set_message_callback(osip ,OSIP_NIST_OPTIONS_RECEIVED, &cb_rcvoptions); + osip_set_message_callback(osip ,OSIP_NIST_SUBSCRIBE_RECEIVED, &cb_rcvsubscribe); + osip_set_message_callback(osip ,OSIP_NIST_NOTIFY_RECEIVED, &cb_rcvnotify); + osip_set_message_callback(osip ,OSIP_NIST_UNKNOWN_REQUEST_RECEIVED, &cb_rcvunkrequest); + + + return 0; +} diff --git a/linphone/exosip/jdialog.c b/linphone/exosip/jdialog.c new file mode 100644 index 000000000..9a8f859b6 --- /dev/null +++ b/linphone/exosip/jdialog.c @@ -0,0 +1,209 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +void eXosip_dialog_set_state(eXosip_dialog_t *jd, int state) +{ + jd->d_STATE = state; +} + +int eXosip_call_dialog_find(int jid, eXosip_call_t **jc, eXosip_dialog_t **jd) +{ + for (*jc=eXosip.j_calls; *jc!=NULL; *jc=(*jc)->next) + { + for (*jd=(*jc)->c_dialogs; *jd!=NULL; *jd=(*jd)->next) + { + if ((*jd)->d_id==jid) + return 0; + } + } + *jd = NULL; + *jc = NULL; + return -1; +} + +int eXosip_notify_dialog_find(int nid, eXosip_notify_t **jn, eXosip_dialog_t **jd) +{ + for (*jn=eXosip.j_notifies; *jn!=NULL; *jn=(*jn)->next) + { + for (*jd=(*jn)->n_dialogs; *jd!=NULL; *jd=(*jd)->next) + { + if ((*jd)->d_id==nid) + return 0; + } + } + *jd = NULL; + *jn = NULL; + return -1; +} + +int eXosip_subscribe_dialog_find(int sid, eXosip_subscribe_t **js, eXosip_dialog_t **jd) +{ + for (*js=eXosip.j_subscribes; *js!=NULL; *js=(*js)->next) + { + *jd=NULL; + if ((*js)->s_id==sid) + return 0; + for (*jd=(*js)->s_dialogs; *jd!=NULL; *jd=(*jd)->next) + { + if ((*jd)->d_id==sid) + return 0; + } + } + *jd = NULL; + *js = NULL; + return -1; +} + +int eXosip_dialog_set_200ok(eXosip_dialog_t *jd, osip_message_t *_200Ok) +{ + int i; + if (jd==NULL) return -1; + i = osip_message_clone(_200Ok, &(jd->d_200Ok)); + if (i!=0) { + return -1; + } + return 0; +} + +int eXosip_dialog_init_as_uac(eXosip_dialog_t **_jd, osip_message_t *_200Ok) +{ + int i; + eXosip_dialog_t *jd; + *_jd = NULL; + jd = (eXosip_dialog_t *) osip_malloc(sizeof(eXosip_dialog_t)); + jd->d_id = -1; /* not yet available to user */ + jd->d_STATE = JD_EMPTY; + + if (MSG_IS_REQUEST(_200Ok)) + { + i = osip_dialog_init_as_uac_with_remote_request(&(jd->d_dialog), _200Ok, -1); + } + else + { /* normal usage with response */ + i = osip_dialog_init_as_uac(&(jd->d_dialog), _200Ok); + } + if (i!=0) + { + osip_free(jd); + return -1; + } + + jd->media_lines = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(jd->media_lines); + + jd->d_timer = time(NULL); + jd->d_200Ok = NULL; + jd->d_ack = NULL; + jd->next = NULL; + jd->parent = NULL; + jd->d_out_trs = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(jd->d_out_trs); + jd->d_inc_trs = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(jd->d_inc_trs); + + /* jd->d_bh = sdp_handler_new(); */ + *_jd = jd; + return 0; +} + +int eXosip_dialog_init_as_uas(eXosip_dialog_t **_jd, osip_message_t *_invite, osip_message_t *_200Ok) +{ + int i; + eXosip_dialog_t *jd; + *_jd = NULL; + jd = (eXosip_dialog_t *) osip_malloc(sizeof(eXosip_dialog_t)); + jd->d_id = -1; /* not yet available to user */ + jd->d_STATE = JD_EMPTY; + i = osip_dialog_init_as_uas(&(jd->d_dialog), _invite, _200Ok); + if (i!=0) + { + osip_free(jd); + return -1; + } + + jd->media_lines = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(jd->media_lines); + + jd->d_timer = time(NULL); + jd->d_200Ok = NULL; + jd->d_ack = NULL; + jd->next = NULL; + jd->parent = NULL; + jd->d_out_trs = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(jd->d_out_trs); + jd->d_inc_trs = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(jd->d_inc_trs); + +#ifdef SUPPORT_MSN + /* bugguy MSN */ + jd->d_dialog->local_cseq = 1; +#endif + + /* jd->d_bh = sdp_handler_new(); */ + *_jd = jd; + return 0; +} + +void eXosip_dialog_free(eXosip_dialog_t *jd) +{ + + while (!osip_list_eol(jd->d_inc_trs, 0)) + { + osip_transaction_t *tr; + tr = (osip_transaction_t*) osip_list_get(jd->d_inc_trs, 0); + osip_list_remove(jd->d_inc_trs, 0); + __eXosip_delete_jinfo(tr); + osip_list_add(eXosip.j_transactions, tr, 0); + } + + while (!osip_list_eol(jd->d_out_trs, 0)) + { + osip_transaction_t *tr; + tr = (osip_transaction_t*) osip_list_get(jd->d_out_trs, 0); + osip_list_remove(jd->d_out_trs, 0); + __eXosip_delete_jinfo(tr); + osip_list_add(eXosip.j_transactions, tr, 0); + } + + osip_message_free(jd->d_200Ok); + osip_message_free(jd->d_ack); + + osip_dialog_free(jd->d_dialog); + + while (!osip_list_eol(jd->media_lines, 0)) + { + char *tmp = osip_list_get(jd->media_lines, 0); + osip_list_remove(jd->media_lines, 0); + osip_free(tmp); + } + + osip_free(jd->media_lines); + osip_free(jd->d_out_trs); + osip_free(jd->d_inc_trs); + osip_free(jd); +} diff --git a/linphone/exosip/jevents.c b/linphone/exosip/jevents.c new file mode 100644 index 000000000..a57efe8be --- /dev/null +++ b/linphone/exosip/jevents.c @@ -0,0 +1,949 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include +#include + +extern eXosip_t eXosip; + + +static void fill_dialog_params(eXosip_event_t *je, osip_dialog_t *dialog) +{ + char *tmp; + if (dialog->remote_uri!=NULL){ + osip_to_to_str(dialog->remote_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->remote_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + if (dialog->local_uri!=NULL) + { + osip_to_to_str(dialog->local_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->local_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + if (dialog->remote_contact_uri!=NULL){ + osip_contact_to_str(dialog->remote_contact_uri,&tmp); + if (tmp!=NULL){ + snprintf(je->remote_contact,255,"%s",tmp); + osip_free(tmp); + } + } +} + +eXosip_event_t * +eXosip_event_init_for_call(int type, + eXosip_call_t *jc, + eXosip_dialog_t *jd) +{ + eXosip_event_t *je; + eXosip_event_init(&je, type); + if (je==NULL) return NULL; + je->jc = jc; + je->jd = jd; + + je->cid = jc->c_id; + if (jd!=NULL) + je->did = jd->d_id; + + je->external_reference = jc->external_reference; + + /* fill in usefull info */ + if (type==EXOSIP_CALL_NEW + || type==EXOSIP_CALL_ACK + || type==EXOSIP_CALL_NOANSWER + || type==EXOSIP_CALL_PROCEEDING + || type==EXOSIP_CALL_RINGING + || type==EXOSIP_CALL_ANSWERED + || type==EXOSIP_CALL_REDIRECTED + || type==EXOSIP_CALL_REQUESTFAILURE + || type==EXOSIP_CALL_SERVERFAILURE + || type==EXOSIP_CALL_GLOBALFAILURE + + || type==EXOSIP_OPTIONS_NOANSWER + || type==EXOSIP_OPTIONS_PROCEEDING + || type==EXOSIP_OPTIONS_ANSWERED + || type==EXOSIP_OPTIONS_REDIRECTED + || type==EXOSIP_OPTIONS_REQUESTFAILURE + || type==EXOSIP_OPTIONS_SERVERFAILURE + || type==EXOSIP_OPTIONS_GLOBALFAILURE + || type==EXOSIP_OPTIONS_NEW + + || type==EXOSIP_INFO_NOANSWER + || type==EXOSIP_INFO_PROCEEDING + || type==EXOSIP_INFO_ANSWERED + || type==EXOSIP_INFO_REDIRECTED + || type==EXOSIP_INFO_REQUESTFAILURE + || type==EXOSIP_INFO_SERVERFAILURE + || type==EXOSIP_INFO_GLOBALFAILURE + || type==EXOSIP_INFO_NEW + + || type==EXOSIP_CALL_CANCELLED + || type==EXOSIP_CALL_TIMEOUT + || type==EXOSIP_CALL_HOLD + || type==EXOSIP_CALL_OFFHOLD + || type==EXOSIP_CALL_CLOSED + || type==EXOSIP_CALL_STARTAUDIO + + || type==EXOSIP_CALL_REFERED + || type==EXOSIP_CALL_REFER_STATUS + + || type==EXOSIP_CALL_RELEASED) + { + if (jc->c_sdp_port[0]!='\0') + je->local_sdp_audio_port = osip_atoi(jc->c_sdp_port); + + if (jd!=NULL&&jd->d_dialog!=NULL) + { + osip_transaction_t *tr; + osip_header_t *subject; + char *tmp; + + fill_dialog_params(je,jd->d_dialog); + + if (type==EXOSIP_OPTIONS_NOANSWER + || type==EXOSIP_OPTIONS_PROCEEDING + || type==EXOSIP_OPTIONS_ANSWERED + || type==EXOSIP_OPTIONS_REDIRECTED + || type==EXOSIP_OPTIONS_REQUESTFAILURE + || type==EXOSIP_OPTIONS_SERVERFAILURE + || type==EXOSIP_OPTIONS_GLOBALFAILURE + || type==EXOSIP_OPTIONS_NEW) + tr = eXosip_find_last_options(jc, jd); + else if (type==EXOSIP_INFO_NOANSWER + || type==EXOSIP_INFO_PROCEEDING + || type==EXOSIP_INFO_ANSWERED + || type==EXOSIP_INFO_REDIRECTED + || type==EXOSIP_INFO_REQUESTFAILURE + || type==EXOSIP_INFO_SERVERFAILURE + || type==EXOSIP_INFO_GLOBALFAILURE + || type==EXOSIP_INFO_NEW) + tr = eXosip_find_last_info(jc, jd); + else if (type==EXOSIP_CALL_REFERED) + tr = eXosip_find_last_refer(jc, jd); + else if (type==EXOSIP_CALL_REFER_STATUS) + tr = eXosip_find_last_inc_notify_for_refer(jc, jd); + else + tr = eXosip_find_last_invite(jc, jd); + if (tr!=NULL && tr->orig_request!=NULL) + { + osip_message_get_subject(tr->orig_request, 0, &subject); + if (subject!=NULL && subject->hvalue!=NULL && subject->hvalue[0]!='\0') + snprintf(je->subject, 255, "%s", subject->hvalue); + osip_message_header_get_byname(tr->orig_request, "refer-to", 0, + &subject); + if (subject!=NULL && subject->hvalue!=NULL && subject->hvalue[0]!='\0') + snprintf(je->refer_to, 255, "%s", subject->hvalue); + + osip_uri_to_str(tr->orig_request->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + + }else{ + osip_transaction_t *tr; + char *tmp; + tr=eXosip_find_last_invite(jc,NULL); + /* no dialog established but we need to fill remote_contact */ + if (tr!=NULL && tr->last_response!=NULL) + { + osip_contact_t *ctt=NULL; + snprintf(je->reason_phrase, 49, "%s", tr->last_response->reason_phrase); + je->status_code = tr->last_response->status_code; + osip_message_get_contact(tr->last_response,0,&ctt); + if (ctt){ + tmp=NULL; + osip_contact_to_str(ctt,&tmp); + if (tmp){ + strncpy(je->remote_contact,tmp,255); + } + } + } + } + } + + return je; +} + +int +eXosip_event_add_status(eXosip_event_t *je, osip_message_t *response) +{ + if (response!=NULL && response->reason_phrase!=NULL) + { + snprintf(je->reason_phrase, 49, "%s", response->reason_phrase); + je->status_code = response->status_code; + } + return 0; +} + +int +eXosip_event_add_sdp_info(eXosip_event_t *je, osip_message_t *message) +{ + osip_content_type_t *ctt; + osip_mime_version_t *mv; + sdp_message_t *sdp; + osip_body_t *oldbody; + int pos; + int gotpayload = 0; + + + + /* + search for remote_sdp_audio_port & remote_sdp_audio_ip + in the last SIP message + extract the payload to be used for connection either from negotioation context + or from the last SIP message + */ + + + + if (message==NULL) return -1; + + /* get content-type info */ + ctt = osip_message_get_content_type(message); + mv = osip_message_get_mime_version(message); + if (mv==NULL && ctt==NULL) + return 0; /* previous message was not correct or empty */ + if (mv!=NULL) + { + /* look for the SDP body */ + /* ... */ + } + else if (ctt!=NULL) + { + if (ctt->type==NULL || ctt->subtype==NULL) + /* it can be application/sdp or mime... */ + return -1; + if (osip_strcasecmp(ctt->type, "application")!=0 || + osip_strcasecmp(ctt->subtype, "sdp")!=0 ) + { return -1; } + } + + + if (je->jc) + { + int pl = eXosip_retrieve_sdp_negotiation_result(je->jc->c_ctx, je->payload_name, sizeof(je->payload_name)); + if (pl >= 0) + { + je->payload = pl; + gotpayload = 1; + } + } + + + sdp = NULL; + pos = 0; + while (!osip_list_eol(message->bodies, pos)) + { + int i; + oldbody = (osip_body_t *)osip_list_get(message->bodies, pos); + pos++; + sdp_message_init(&sdp); + i = sdp_message_parse(sdp,oldbody->body); + if (i==0) + { + int len = strlen(oldbody->body); + if (len<999) + osip_strncpy(je->sdp_body, oldbody->body, len); + else + osip_strncpy(je->sdp_body, oldbody->body, 999); + + break; + } + sdp_message_free(sdp); + sdp = NULL; + } + + + + if (sdp!=NULL) + { + int j=0; + if (sdp->c_connection !=NULL + && sdp->c_connection->c_addr !=NULL ) + { + snprintf(je->remote_sdp_audio_ip, 49, "%s", + sdp->c_connection->c_addr); + } + + + for (j=0; !osip_list_eol(sdp->m_medias, j); j++) + { + sdp_media_t *med = (sdp_media_t*) osip_list_get(sdp->m_medias, j); + if (med==NULL) + { + snprintf(je->remote_sdp_audio_ip, 49, "Y a probleme!"); + } + + if (med->m_media!=NULL && + 0==osip_strcasecmp(med->m_media, "audio")) + { + sdp_connection_t *conn; + int pos_attr; + char *payload = (char *) osip_list_get (med->m_payloads, 0); + + if (!gotpayload) + je->payload = 0; + + if (!gotpayload && payload!=NULL) + { + je->payload = osip_atoi(payload); + /* copy payload name! */ + for (pos_attr=0; + !osip_list_eol(med->a_attributes, pos_attr); + pos_attr++) + { + sdp_attribute_t *attr; + attr = (sdp_attribute_t *)osip_list_get(med->a_attributes, pos_attr); + if (0==osip_strncasecmp(attr->a_att_field, "rtpmap", 6)) + { + if ((je->payload<10 && + 0==osip_strncasecmp(attr->a_att_value, payload, 1)) + ||(je->payload>9 && je->payload<100 && + 0==osip_strncasecmp(attr->a_att_value, payload, 2)) + ||(je->payload>100 && je->payload<128 && + 0==osip_strncasecmp(attr->a_att_value, payload, 3))) + { + snprintf(je->payload_name, 49, "%s", attr->a_att_value); + } + } + } + } + + + je->remote_sdp_audio_port = osip_atoi(med->m_port); + conn = (sdp_connection_t*) osip_list_get(med->c_connections, 0); + if (conn!=NULL && conn->c_addr!=NULL) + { + snprintf(je->remote_sdp_audio_ip, 49, "%s", + conn->c_addr); + } + sdp_message_free(sdp); + return 0; + } + } + sdp_message_free(sdp); + } + return -1; +} + + +eXosip_event_t * +eXosip_event_init_for_subscribe(int type, + eXosip_subscribe_t *js, + eXosip_dialog_t *jd) +{ + char *tmp; + eXosip_event_t *je; + eXosip_event_init(&je, type); + if (je==NULL) return NULL; + je->js = js; + je->jd = jd; + + je->sid = js->s_id; + if (jd!=NULL) + je->did = jd->d_id; + + je->ss_status = js->s_ss_status; + je->online_status = js->s_online_status; + je->ss_reason = js->s_ss_reason; + + /* je->external_reference = js->external_reference; */ + + if (jd!=NULL&&jd->d_dialog!=NULL) + { + fill_dialog_params(je,jd->d_dialog); + } + + /* fill in usefull info */ + if (type==EXOSIP_SUBSCRIPTION_NEW + || type==EXOSIP_SUBSCRIPTION_NOANSWER + || type==EXOSIP_SUBSCRIPTION_PROCEEDING + || type==EXOSIP_SUBSCRIPTION_ANSWERED + || type==EXOSIP_SUBSCRIPTION_REDIRECTED + || type==EXOSIP_SUBSCRIPTION_REQUESTFAILURE + || type==EXOSIP_SUBSCRIPTION_SERVERFAILURE + || type==EXOSIP_SUBSCRIPTION_GLOBALFAILURE + || type==EXOSIP_SUBSCRIPTION_RELEASED) + { + if (jd!=NULL&&jd->d_dialog!=NULL) + { + osip_transaction_t *tr; + tr = eXosip_find_last_out_subscribe(js, jd); + if (tr!=NULL && tr->orig_request!=NULL) + { + osip_uri_to_str(tr->orig_request->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + if (tr!=NULL && tr->last_response!=NULL) + { + snprintf(je->reason_phrase, 49, "%s", tr->last_response->reason_phrase); + je->status_code = tr->last_response->status_code; + } + } + } + else if (type==EXOSIP_SUBSCRIPTION_NOTIFY) + { + if (jd!=NULL&&jd->d_dialog!=NULL) + { + osip_transaction_t *tr; + tr = eXosip_find_last_inc_notify(js, jd); + if (tr!=NULL && tr->orig_request!=NULL) + { + osip_uri_to_str(tr->orig_request->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + if (tr!=NULL && tr->last_response!=NULL) + { + snprintf(je->reason_phrase, 49, "%s", tr->last_response->reason_phrase); + je->status_code = tr->last_response->status_code; + } + } + } + + return je; +} + +eXosip_event_t * +eXosip_event_init_for_notify(int type, + eXosip_notify_t *jn, + eXosip_dialog_t *jd) +{ + eXosip_event_t *je; + eXosip_event_init(&je, type); + if (je==NULL) return NULL; + je->jn = jn; + je->jd = jd; + + je->nid = jn->n_id; + if (jd!=NULL) + je->did = jd->d_id; + + je->ss_status = jn->n_ss_status; + je->online_status = jn->n_online_status; + je->ss_reason = jn->n_ss_reason; + + /*je->external_reference = jc->external_reference; */ + + /* fill in usefull info */ + if (type==EXOSIP_IN_SUBSCRIPTION_NEW + || type==EXOSIP_IN_SUBSCRIPTION_RELEASED) + { + if (jd!=NULL&&jd->d_dialog!=NULL) + { + osip_transaction_t *tr; + char *tmp; + fill_dialog_params(je,jd->d_dialog); + tr = eXosip_find_last_inc_subscribe(jn, jd); + if (tr!=NULL && tr->orig_request!=NULL) + { + osip_uri_to_str(tr->orig_request->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + if (tr!=NULL && tr->last_response!=NULL) + { + snprintf(je->reason_phrase, 49, "%s", tr->last_response->reason_phrase); + je->status_code = tr->last_response->status_code; + } + } + } + + return je; +} + +eXosip_event_t * +eXosip_event_init_for_reg(int type, + eXosip_reg_t *jr) +{ + eXosip_event_t *je; + eXosip_event_init(&je, type); + if (je==NULL) return NULL; + je->jr = jr; + je->rid = jr->r_id; + snprintf(je->remote_uri, 255, "%s", jr->r_aor); + snprintf(je->req_uri, 255, "%s", jr->r_registrar); + return je; +} + +eXosip_event_t * +eXosip_event_init_for_message(int type, osip_transaction_t *tr, + osip_message_t *sip) +{ + eXosip_event_t *je; + eXosip_event_init(&je, type); + if (je==NULL) return NULL; + + /* fill in usefull info */ + { + char *tmp; + + /* Request URI */ + + osip_uri_to_str(sip->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + + /* FROM & TO */ + + + if (sip->from != NULL) + { + osip_from_to_str(sip->from, &tmp); + if (tmp!=NULL) + { + snprintf(je->remote_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + if (sip->to != NULL) + { + osip_to_to_str(sip->to, &tmp); + if (tmp!=NULL) + { + snprintf(je->local_uri, 255, "%s", tmp); + osip_free(tmp); + } + } + } + + return je; +} + +int +eXosip_event_init(eXosip_event_t **je, int type) +{ + *je = (eXosip_event_t *) osip_malloc(sizeof(eXosip_event_t)); + if (*je==NULL) return -1; + + memset(*je, 0, sizeof(eXosip_event_t)); + (*je)->type = type; + + if (type==EXOSIP_CALL_NOANSWER) + { + sprintf((*je)->textinfo, "No answer for this Call!"); + } + else if (type==EXOSIP_CALL_PROCEEDING) + { + sprintf((*je)->textinfo, "Call is being processed!"); + } + else if (type==EXOSIP_CALL_RINGING) + { + sprintf((*je)->textinfo, "Remote phone is ringing!"); + } + else if (type==EXOSIP_CALL_ANSWERED) + { + sprintf((*je)->textinfo, "Remote phone has answered!"); + } + else if (type==EXOSIP_CALL_REDIRECTED) + { + sprintf((*je)->textinfo, "Call is redirected!"); + } + else if (type==EXOSIP_CALL_REQUESTFAILURE) + { + sprintf((*je)->textinfo, "4xx received for Call!"); + } + else if (type==EXOSIP_CALL_SERVERFAILURE) + { + sprintf((*je)->textinfo, "5xx received for Call!"); + } + else if (type==EXOSIP_CALL_GLOBALFAILURE) + { + sprintf((*je)->textinfo, "6xx received for Call!"); + } + else if (type==EXOSIP_CALL_NEW) + { + sprintf((*je)->textinfo, "New call received!"); + } + else if (type==EXOSIP_CALL_ACK) + { + sprintf((*je)->textinfo, "ACK received!"); + } + else if (type==EXOSIP_CALL_CANCELLED) + { + sprintf((*je)->textinfo, "Call has been cancelled!"); + } + else if (type==EXOSIP_CALL_TIMEOUT) + { + sprintf((*je)->textinfo, "Timeout. Gived up!"); + } + else if (type==EXOSIP_CALL_HOLD) + { + sprintf((*je)->textinfo, "Call is on Hold!"); + } + else if (type==EXOSIP_CALL_OFFHOLD) + { + sprintf((*je)->textinfo, "Call is off Hold!"); + } + else if (type==EXOSIP_CALL_CLOSED) + { + sprintf((*je)->textinfo, "Bye Received!"); + } + else if (type==EXOSIP_CALL_RELEASED) + { + sprintf((*je)->textinfo, "Call Context is released!"); + } + else if (type==EXOSIP_REGISTRATION_SUCCESS) + { + sprintf((*je)->textinfo, "User is successfully registred!"); + } + else if (type==EXOSIP_REGISTRATION_FAILURE) + { + sprintf((*je)->textinfo, "Registration failed!"); + } + else if (type==EXOSIP_OPTIONS_NEW) + { + sprintf((*je)->textinfo, "New OPTIONS received!"); + } + else if (type==EXOSIP_OPTIONS_NOANSWER) + { + sprintf((*je)->textinfo, "No answer for this OPTIONS!"); + } + else if (type==EXOSIP_OPTIONS_PROCEEDING) + { + sprintf((*je)->textinfo, "OPTIONS is being processed!"); + } + else if (type==EXOSIP_OPTIONS_ANSWERED) + { + sprintf((*je)->textinfo, "2xx received for OPTIONS!"); + } + else if (type==EXOSIP_OPTIONS_REDIRECTED) + { + sprintf((*je)->textinfo, "3xx received for OPTIONS!"); + } + else if (type==EXOSIP_OPTIONS_REQUESTFAILURE) + { + sprintf((*je)->textinfo, "4xx received for OPTIONS!"); + } + else if (type==EXOSIP_OPTIONS_SERVERFAILURE) + { + sprintf((*je)->textinfo, "5xx received for OPTIONS!"); + } + else if (type==EXOSIP_OPTIONS_GLOBALFAILURE) + { + sprintf((*je)->textinfo, "5xx received for OPTIONS!"); + } + else if (type==EXOSIP_INFO_NEW) + { + sprintf((*je)->textinfo, "New INFO received!"); + } + else if (type==EXOSIP_INFO_NOANSWER) + { + sprintf((*je)->textinfo, "No answer for this INFO!"); + } + else if (type==EXOSIP_INFO_PROCEEDING) + { + sprintf((*je)->textinfo, "INFO is being processed!"); + } + else if (type==EXOSIP_INFO_ANSWERED) + { + sprintf((*je)->textinfo, "2xx received for INFO!"); + } + else if (type==EXOSIP_INFO_REDIRECTED) + { + sprintf((*je)->textinfo, "3xx received for INFO!"); + } + else if (type==EXOSIP_INFO_REQUESTFAILURE) + { + sprintf((*je)->textinfo, "4xx received for INFO!"); + } + else if (type==EXOSIP_INFO_SERVERFAILURE) + { + sprintf((*je)->textinfo, "5xx received for INFO!"); + } + else if (type==EXOSIP_INFO_GLOBALFAILURE) + { + sprintf((*je)->textinfo, "6xx received for INFO!"); + } + else if (type==EXOSIP_MESSAGE_NEW) + { + sprintf((*je)->textinfo, "New MESSAGE received!"); + } + else if (type==EXOSIP_MESSAGE_SUCCESS) + { + sprintf((*je)->textinfo, "User has successfully received our MESSAGE!"); + } + else if (type==EXOSIP_MESSAGE_FAILURE) + { + sprintf((*je)->textinfo, "Error received for our MESSAGE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_NEW) + { + sprintf((*je)->textinfo, "New SUBSCRIBE received!"); + } + else if (type==EXOSIP_SUBSCRIPTION_NOANSWER) + { + sprintf((*je)->textinfo, "No answer for this SUBSCRIBE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_PROCEEDING) + { + sprintf((*je)->textinfo, "SUBSCRIBE is being processed!"); + } + else if (type==EXOSIP_SUBSCRIPTION_ANSWERED) + { + sprintf((*je)->textinfo, "2xx received for SUBSCRIBE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_REDIRECTED) + { + sprintf((*je)->textinfo, "3xx received for SUBSCRIBE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_REQUESTFAILURE) + { + sprintf((*je)->textinfo, "4xx received for SUBSCRIBE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_SERVERFAILURE) + { + sprintf((*je)->textinfo, "5xx received for SUBSCRIBE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_GLOBALFAILURE) + { + sprintf((*je)->textinfo, "5xx received for SUBSCRIBE!"); + } + else if (type==EXOSIP_SUBSCRIPTION_NOTIFY) + { + sprintf((*je)->textinfo, "NOTIFY request for subscription!"); + } + else if (type==EXOSIP_SUBSCRIPTION_RELEASED) + { + sprintf((*je)->textinfo, "Subscription has terminate!"); + } + else if (type==EXOSIP_IN_SUBSCRIPTION_NEW) + { + sprintf((*je)->textinfo, "New incoming SUBSCRIBE!"); + } + else if (type==EXOSIP_IN_SUBSCRIPTION_RELEASED) + { + sprintf((*je)->textinfo, "Incoming Subscription has terminate!"); + } + else + { + (*je)->textinfo[0] = '\0'; + } + return 0; +} + +void +eXosip_event_free(eXosip_event_t *je) +{ + if (je==NULL) return; + if (je->i_ctt!=NULL) + osip_content_type_free(je->i_ctt); + if (je->i_bodies!=NULL) + { + int pos; + for (pos=0;!osip_list_eol(je->i_bodies, pos);) + { + osip_body_t *body; + body = (osip_body_t *)osip_list_get(je->i_bodies, pos); + osip_list_remove(je->i_bodies, pos); + osip_body_free(body); + } + } + osip_free(je); +} + +eXosip_call_t * +eXosip_event_get_callinfo(eXosip_event_t *je) +{ + return je->jc; +} + +eXosip_dialog_t * +eXosip_event_get_dialoginfo(eXosip_event_t *je) +{ + return je->jd; +} + +eXosip_reg_t * +eXosip_event_get_reginfo(eXosip_event_t *je) +{ + return je->jr; +} + +eXosip_notify_t * +eXosip_event_get_notifyinfo(eXosip_event_t *je) +{ + return je->jn; +} + +eXosip_subscribe_t * +eXosip_event_get_subscribeinfo(eXosip_event_t *je) +{ + return je->js; +} + +int +eXosip_event_add(eXosip_event_t *je) +{ + int i = osip_fifo_add(eXosip.j_events, (void *) je); + osip_cond_signal((struct osip_cond *)eXosip.j_cond); + __eXosip_wakeup_event(); + return i; +} + +#if 0 +#ifdef CLOCK_REALTIME +/* if CLOCK_REALTIME exist, then clock_gettime should be defined */ + +#define OSIP_CLOCK_REALTIME CLOCK_REALTIME + +void +__eXosip_clock_gettime(clockid_t cid, struct timespec *time) +{ + clock_gettime(cid, time); +} + +#elif defined (WIN32) || defined (_WIN32_WCE) + +#include +#include + +#define OSIP_CLOCK_REALTIME 4002 + +void +__eXosip_clock_gettime(unsigned int clock_id, struct timespec *time) +{ + struct _timeb time_val; + + if (clock_id != OSIP_CLOCK_REALTIME) + return; + + _ftime (&time_val); + time->tv_sec = time_val.time; + time->tv_nsec = time_val.millitm * 1000000; + return; +} +#endif +#endif + +eXosip_event_t * +eXosip_event_wait(int tv_s, int tv_ms) +{ + eXosip_event_t *je = NULL; + +#if 0 /* this does not seems to work. by now */ +#if defined (CLOCK_REALTIME) || defined (WIN32) || defined (_WIN32_WCE) + int i; + + struct timespec deadline; + struct timespec interval; + long tot_ms = (tv_s*1000) + tv_ms; + + static struct osip_mutex *mlock = NULL; + + if (mlock==NULL) mlock = osip_mutex_init(); + + je = (eXosip_event_t *) osip_fifo_tryget(eXosip.j_events); + if(je) return je; + + interval.tv_sec = tot_ms / 1000; + interval.tv_nsec = (tot_ms % 1000) * 1000000L; + + __eXosip_clock_gettime(OSIP_CLOCK_REALTIME, &deadline); + + if ((deadline.tv_nsec += interval.tv_nsec) >= 1000000000L) + { + deadline.tv_nsec -= 1000000000L; + deadline.tv_sec += 1; + } + else + deadline.tv_nsec += interval.tv_nsec; + + deadline.tv_sec += interval.tv_sec; + + i = osip_cond_timedwait ((struct osip_cond *)eXosip.j_cond, + (struct osip_mutex *)mlock, + &deadline); + +#endif +#else + /* basic replacement */ + { + fd_set fdset; + struct timeval tv; + int max, i; + FD_ZERO(&fdset); +#if defined (WIN32) || defined (_WIN32_WCE) + FD_SET((unsigned int)jpipe_get_read_descr(eXosip.j_socketctl_event), &fdset); +#else + FD_SET(jpipe_get_read_descr(eXosip.j_socketctl_event), &fdset); +#endif + max = jpipe_get_read_descr(eXosip.j_socketctl_event); + tv.tv_sec = tv_s; + tv.tv_usec = tv_ms*1000; + + je = (eXosip_event_t *) osip_fifo_tryget(eXosip.j_events); + if (je!=NULL) return je; + + if (tv_s==0 && tv_ms==0) + return NULL; + + i = select(max+1, &fdset, NULL, NULL, &tv); + if (i <= 0) + return 0; + + if (FD_ISSET (jpipe_get_read_descr(eXosip.j_socketctl_event), &fdset)) + { + char buf[500]; + jpipe_read (eXosip.j_socketctl_event, buf, 499); + } + + je = (eXosip_event_t *) osip_fifo_tryget(eXosip.j_events); + if (je!=NULL) return je; + } +#endif + + return je; +} + +eXosip_event_t * +eXosip_event_get() +{ + eXosip_event_t *je; + je = (eXosip_event_t *) osip_fifo_get(eXosip.j_events); + return je; +} diff --git a/linphone/exosip/jfreinds.c b/linphone/exosip/jfreinds.c new file mode 100644 index 000000000..0f546cef7 --- /dev/null +++ b/linphone/exosip/jfreinds.c @@ -0,0 +1,311 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +#ifndef EXOSIP_ETC_DIR +#define EXOSIP_ETC_DIR ".eXosip" +#endif + +#ifndef EXOSIP_ADDFRIENDS_SH +#define EXOSIP_ADDFRIENDS_SH "eXosip_addfriend.sh" +#endif + + +static int jfriend_init(jfriend_t **fr, char *ch) +{ + char *next; + int i; + + *fr = (jfriend_t *)osip_malloc(sizeof(jfriend_t)); + if (*fr==NULL) return -1; + + i = jfriend_get_and_set_next_token(&((*fr)->f_nick), ch, &next); + if (i != 0) + goto jf_error1; + osip_clrspace ((*fr)->f_nick); + ch = next; + + i = jfriend_get_and_set_next_token(&((*fr)->f_home), next, &next); + if (i != 0) + goto jf_error2; + osip_clrspace ((*fr)->f_home); + ch = next; + + i = jfriend_get_and_set_next_token(&((*fr)->f_work), ch, &next); + if (i != 0) + goto jf_error3; + osip_clrspace ((*fr)->f_work); + ch = next; + + i = jfriend_get_and_set_next_token(&((*fr)->f_email), ch, &next); + if (i != 0) + goto jf_error4; + osip_clrspace ((*fr)->f_email); + + (*fr)->f_e164 = osip_strdup(next); + osip_clrspace ((*fr)->f_e164); + + return 0; + + jf_error4: + osip_free((*fr)->f_work); + jf_error3: + osip_free((*fr)->f_home); + jf_error2: + osip_free((*fr)->f_nick); + jf_error1: + osip_free(*fr); + *fr = NULL; + return -1; +} + +int +jfriend_get_and_set_next_token (char **dest, char *buf, char **next) +{ + char *end; + char *start; + + *next = NULL; + + /* find first non space and tab element */ + start = buf; + while (((*start == ' ') || (*start == '\t')) && (*start != '\0') + && (*start != '\r') && (*start != '\n') ) + start++; + end = start+1; + while ((*end != '\0') && (*end != '\r') && (*end != '\n') + && (*end != '\t') && (*end != '|')) + end++; + + if ((*end == '\r') || (*end == '\n')) + /* we should continue normally only if this is the separator asked! */ + return -1; + if (end == start) + return -1; /* empty value (or several space!) */ + + *dest = osip_malloc (end - (start) + 1); + osip_strncpy (*dest, start, end - start); + + *next = end + 1; /* return the position right after the separator + */ + return 0; +} + +void __jfriend_remove(char *nickname, char *home) +{ + char *Home; + char command[256]; + char *tmp = command; + int length = 0; + if (nickname!=NULL) + length = strlen(nickname); + + Home = getenv("HOME"); + if (Home==NULL) + return; + length = length + strlen(Home); + osip_clrspace(nickname); + osip_clrspace(home); + + if (home!=NULL) + length = length + strlen(home); + else + return; /* MUST be set */ + length = length + strlen(EXOSIP_ETC_DIR); + + length = length + strlen("/jm_contact"); + if (length>235) /* leave some room for SPACEs and \r\n */ + return ; + + sprintf(tmp , "%s %s/%s/jm_contact", EXOSIP_ADDFRIENDS_SH, + Home, EXOSIP_ETC_DIR); + + tmp = tmp + strlen(tmp); + if (nickname!=NULL) + sprintf(tmp , " %s", nickname); + else + sprintf(tmp , " \"\""); + + tmp = tmp + strlen(tmp); + if (home!=NULL) + sprintf(tmp , " %s", home); + else + sprintf(tmp , " \"\""); + + sprintf(tmp , "delete"); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "%s", command)); + system(command); +} + +void jfriend_add(char *nickname, char *home, + char *work, char *email, char *e164) +{ + char *Home; + char command[256]; + char *tmp = command; + int length = 0; + if (nickname!=NULL) + length = strlen(nickname); + + Home = getenv("HOME"); + if (Home==NULL) + return; + length = length + strlen(Home); + + osip_clrspace(nickname); + osip_clrspace(home); + osip_clrspace(work); + osip_clrspace(email); + osip_clrspace(e164); + + if (home!=NULL) + length = length + strlen(home); + else + return; /* MUST be set */ + if (work!=NULL) + length = length + strlen(work); + if (email!=NULL) + length = length + strlen(email); + if (e164!=NULL) + length = length + strlen(e164); + length = length + strlen(EXOSIP_ETC_DIR); + + length = length + strlen("/jm_contact"); + if (length>235) /* leave some room for SPACEs and \r\n */ + return ; + + sprintf(tmp , "%s %s/%s/jm_contact", EXOSIP_ADDFRIENDS_SH, + Home, EXOSIP_ETC_DIR); + + tmp = tmp + strlen(tmp); + if (nickname!=NULL) + sprintf(tmp , " %s", nickname); + else + sprintf(tmp , " \"\""); + + tmp = tmp + strlen(tmp); + if (home!=NULL) + sprintf(tmp , " %s", home); + else + sprintf(tmp , " \"\""); + + tmp = tmp + strlen(tmp); + if (work!=NULL) + sprintf(tmp , " %s", work); + else + sprintf(tmp , " \"\""); + + tmp = tmp + strlen(tmp); + if (email!=NULL) + sprintf(tmp , " %s", email); + else + sprintf(tmp , " \"\""); + + tmp = tmp + strlen(tmp); + if (e164!=NULL) + sprintf(tmp , " %s", e164); + else + sprintf(tmp , " \"\""); + + /* fprintf(stderr, "%s", command); */ + system(command); +} + +void +jfriend_unload() +{ + jfriend_t *fr; + if (eXosip.j_friends==NULL) return; + for (fr=eXosip.j_friends; fr!=NULL; fr=eXosip.j_friends) + { + REMOVE_ELEMENT(eXosip.j_friends,fr); + osip_free(fr->f_nick); + osip_free(fr->f_home); + osip_free(fr->f_work); + osip_free(fr->f_email); + osip_free(fr->f_e164); + osip_free(fr); + } + + osip_free(eXosip.j_friends); + eXosip.j_friends=NULL; + return; +} + +int +jfriend_load() +{ + FILE *file; + char *s; + jfriend_t *fr; + int pos; + char *home; + char filename[255]; + + jfriend_unload(); + home = getenv("HOME"); + sprintf(filename, "%s/%s/%s", home, EXOSIP_ETC_DIR, "jm_contact"); + + file = fopen(filename, "r"); + if (file==NULL) return -1; + s = (char *)osip_malloc(255*sizeof(char)); + pos = 0; + while (NULL!=fgets(s, 254, file)) + { + char *tmp = s; + while (*tmp!='\0' && *tmp!=' ') tmp++; + while (*tmp!='\0' && *tmp==' ') tmp++; + while (*tmp!='\0' && *tmp!=' ') tmp++; + tmp++; /* first usefull characters */ + pos++; + + jfriend_init(&fr, tmp); + if (fr!=NULL) + { ADD_ELEMENT(eXosip.j_friends, fr); } + } + osip_free(s); + fclose(file); + + return 0; /* ok */ +} + +char * +jfriend_get_home(int fid) +{ + jfriend_t *fr; + for (fr = eXosip.j_friends; fr!=NULL ; fr=fr->next) + { + if (fid==0) + return osip_strdup(fr->f_home); + fid--; + } + return NULL; +} diff --git a/linphone/exosip/jidentity.c b/linphone/exosip/jidentity.c new file mode 100644 index 000000000..96191e65e --- /dev/null +++ b/linphone/exosip/jidentity.c @@ -0,0 +1,277 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +#ifndef EXOSIP_ETC_DIR +#define EXOSIP_ETC_DIR ".eXosip" +#endif + + +#ifndef EXOSIP_ADDIDENTITYS_SH +#define EXOSIP_ADDIDENTITYS_SH "eXosip_addidentity.sh" +#endif + +static int +jidentity_get_and_set_next_token (char **dest, char *buf, char **next) +{ + char *end; + char *start; + + *next = NULL; + + /* find first non space and tab element */ + start = buf; + while (((*start == ' ') || (*start == '\t')) && (*start != '\0') + && (*start != '\r') && (*start != '\n') ) + start++; + end = start+1; + while ((*end != '\0') && (*end != '\r') && (*end != '\n') + && (*end != '\t') && (*end != '|')) + end++; + + if ((*end == '\r') || (*end == '\n')) + /* we should continue normally only if this is the separator asked! */ + return -1; + if (end == start) + return -1; /* empty value (or several space!) */ + + *dest = osip_malloc (end - (start) + 1); + osip_strncpy (*dest, start, end - start); + + *next = end + 1; /* return the position right after the separator + */ + return 0; +} + +static int jidentity_init(jidentity_t **fr, char *ch) +{ + char *next; + int i; + + *fr = (jidentity_t *)osip_malloc(sizeof(jidentity_t)); + if (*fr==NULL) return -1; + + i = jidentity_get_and_set_next_token(&((*fr)->i_identity), ch, &next); + if (i != 0) + goto ji_error1; + osip_clrspace ((*fr)->i_identity); + ch = next; + + i = jidentity_get_and_set_next_token(&((*fr)->i_registrar), next, &next); + if (i != 0) + goto ji_error2; + osip_clrspace ((*fr)->i_registrar); + ch = next; + + i = jidentity_get_and_set_next_token(&((*fr)->i_realm), ch, &next); + if (i != 0) + goto ji_error3; + osip_clrspace ((*fr)->i_realm); + ch = next; + + i = jidentity_get_and_set_next_token(&((*fr)->i_userid), ch, &next); + if (i != 0) + goto ji_error4; + osip_clrspace ((*fr)->i_userid); + + (*fr)->i_pwd = osip_strdup(next); + osip_clrspace ((*fr)->i_pwd); + + if ((*fr)->i_pwd!=NULL && (*fr)->i_pwd[0]!='\0') + { + eXosip_add_authentication_info((*fr)->i_userid, (*fr)->i_userid, + (*fr)->i_pwd, NULL, + (*fr)->i_realm); + } + return 0; + + ji_error4: + osip_free((*fr)->i_realm); + ji_error3: + osip_free((*fr)->i_registrar); + ji_error2: + osip_free((*fr)->i_identity); + ji_error1: + osip_free(*fr); + *fr = NULL; + return -1; +} + +void identitys_add(char *identity, char *registrar, + char *realm, char *userid, char *pwd) +{ + char command[256]; + char *tmp = command; + char *home; + + int length = 0; + if (identity==NULL) + return ; + if (registrar==NULL) + return ; + + if (realm!=NULL && *realm=='\0') + realm = NULL; + if (userid!=NULL && *userid=='\0') + userid = NULL; + if (pwd!=NULL && *pwd=='\0') + pwd = NULL; + + length = strlen(identity) +3; + length = length + strlen(registrar) +3; + + if (realm!=NULL && userid!=NULL && pwd!=NULL) + { + length = length + strlen(realm) +3; + length = length + strlen(userid) +3; + length = length + strlen(pwd) +3; + } + else if (realm==NULL && userid==NULL && pwd==NULL) + {} + else + return ; + + home = getenv("HOME"); + length = length + strlen(home); + length = length + strlen(EXOSIP_ETC_DIR) + 3; + length = length + strlen("/jm_identity") + 1; + + if (length>235) /* leave some room for SPACEs and \r\n */ + return ; + + sprintf(tmp , "%s \"%s/%s/jm_identity\"", EXOSIP_ADDIDENTITYS_SH, + home, EXOSIP_ETC_DIR); + tmp = tmp + strlen(tmp); + sprintf(tmp , " \"%s\"", identity); + tmp = tmp + strlen(tmp); + sprintf(tmp , " \"%s\"", registrar); + tmp = tmp + strlen(tmp); + + if (realm!=NULL && userid!=NULL && pwd!=NULL) + { + sprintf(tmp , " \"%s\"", realm); + tmp = tmp + strlen(tmp); + sprintf(tmp , " \"%s\"", userid); + tmp = tmp + strlen(tmp); + sprintf(tmp , " \"%s\"", pwd); + } + else if (realm==NULL && userid==NULL && pwd==NULL) + { + sprintf(tmp , " \"\""); + tmp = tmp + strlen(tmp); + sprintf(tmp , " \"\""); + tmp = tmp + strlen(tmp); + sprintf(tmp , " \"\""); + } + + system(command); +} + +void +jidentity_unload() +{ + jidentity_t *fr; + if (eXosip.j_identitys==NULL) return; + for (fr=eXosip.j_identitys; fr!=NULL; fr=eXosip.j_identitys) + { + REMOVE_ELEMENT(eXosip.j_identitys,fr); + osip_free(fr->i_identity); + osip_free(fr->i_registrar); + osip_free(fr->i_realm); + osip_free(fr->i_userid); + osip_free(fr->i_pwd); + osip_free(fr); + } + + osip_free(eXosip.j_identitys); + eXosip.j_identitys=NULL; + return; +} + +int +jidentity_load() +{ + FILE *file; + char *s; + jidentity_t *fr; + int pos; + char *home; + char filename[255]; + jidentity_unload(); + + home = getenv("HOME"); + sprintf(filename, "%s/%s/%s", home, EXOSIP_ETC_DIR, "jm_identity"); + + file = fopen(filename, "r"); + if (file==NULL) return -1; + s = (char *)osip_malloc(255*sizeof(char)); + pos = 0; + while (NULL!=fgets(s, 254, file)) + { + char *tmp = s; + while (*tmp!='\0' && *tmp!=' ') tmp++; + while (*tmp!='\0' && *tmp==' ') tmp++; + while (*tmp!='\0' && *tmp!=' ') tmp++; + tmp++; /* first usefull characters */ + pos++; + + jidentity_init(&fr, tmp); + if (fr!=NULL) + { ADD_ELEMENT(eXosip.j_identitys, fr); } + } + osip_free(s); + fclose(file); + + return 0; /* ok */ +} + +char * +jidentity_get_registrar(int fid) +{ + jidentity_t *fr; + for (fr = eXosip.j_identitys; fr!=NULL ; fr=fr->next) + { + if (fid==0) + return osip_strdup(fr->i_registrar); + fid--; + } + return NULL; +} + +char * +jidentity_get_identity(int fid) +{ + jidentity_t *fr; + for (fr = eXosip.j_identitys; fr!=NULL ; fr=fr->next) + { + if (fid==0) + return osip_strdup(fr->i_identity); + fid--; + } + return NULL; +} diff --git a/linphone/exosip/jnotify.c b/linphone/exosip/jnotify.c new file mode 100644 index 000000000..f784ed884 --- /dev/null +++ b/linphone/exosip/jnotify.c @@ -0,0 +1,528 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + + +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +#if 0 +int eXosip_notify_find(int sid, eXosip_notify_t **jn) +{ + for (*jn=eXosip.j_notifies; *jn!=NULL; *jn=(*jn)->next) + { + if ((*jn)->n_id==sid) + return 0; + } + *jn = NULL; + return -1; +} +#endif + +osip_transaction_t * +eXosip_find_last_inc_subscribe(eXosip_notify_t *jn, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "SUBSCRIBE")) + break; + else inc_tr = NULL; + pos++; + } + } + else + inc_tr = NULL; + + if (inc_tr==NULL) + return jn->n_inc_tr; /* can be NULL */ + + return inc_tr; +} + + +osip_transaction_t * +eXosip_find_last_out_notify(eXosip_notify_t *jn, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "NOTIFY")) + return out_tr; + pos++; + } + } + + return NULL; +} + +int +eXosip_notify_init(eXosip_notify_t **jn, osip_message_t *inc_subscribe) +{ + osip_contact_t *co; + char *uri; + int i; +#ifdef SM + char *locip; + eXosip_get_localip_from_via(inc_subscribe,&locip); +#else + char locip[50]; + eXosip_guess_ip_for_via(eXosip.ip_family, locip, 49); +#endif + if (inc_subscribe==NULL + ||inc_subscribe->to==NULL + ||inc_subscribe->to->url==NULL) + return -1; + co = (osip_contact_t *) osip_list_get(inc_subscribe->contacts, 0); + if (co==NULL || co->url==NULL) + return -1; + + *jn = (eXosip_notify_t *)osip_malloc(sizeof(eXosip_notify_t)); + if (*jn == NULL) return -1; + memset(*jn, 0, sizeof(eXosip_notify_t)); + + i = osip_uri_to_str(co->url, &uri); + if (i!=0) + { + osip_free(*jn); + *jn=NULL; + return -1; + } + osip_strncpy((*jn)->n_uri, uri, 254); + osip_free(uri); + + if (inc_subscribe->to->url->username!=NULL) + { + /* SM: allocate a string instead of risking a buffer overflow */ + if (eXosip.localport==NULL) + (*jn)->n_contact_info=strdup_printf("sip:%s@%s", + inc_subscribe->to->url->username, + locip); + else + (*jn)->n_contact_info= strdup_printf("sip:%s@%s:%s", + inc_subscribe->to->url->username, + locip, eXosip.localport); + } + else + { + if (eXosip.localport==NULL) + (*jn)->n_contact_info=strdup_printf("sip:%s", locip); + else + (*jn)->n_contact_info=strdup_printf("sip:%s:%s", locip, + eXosip.localport); + } + +#ifdef SM + osip_free(locip); +#endif + return 0; +} + +#if 0 +void +__eXosip_notify_remove_dialog_reference_in_notify(eXosip_notify_t *jn, eXosip_dialog_t *jd) +{ + eXosip_dialog_t *_jd; + jinfo_t *ji; + if (jn==NULL) return; + if (jd==NULL) return; + + for (_jd = jn->n_dialogs; _jd!=NULL; _jd=jn->n_dialogs) + { + if (jd==_jd) + break; + } + if (_jd==NULL) + { + /* dialog not found??? */ + } + + ji = osip_transaction_get_your_instance(jn->n_inc_tr); + if (ji!=NULL && ji->jd==jd) + ji->jd=NULL; + ji = osip_transaction_get_your_instance(jn->n_out_tr); + if (ji!=NULL && ji->jd==jd) + ji->jd=NULL; +} +#endif + +void +eXosip_notify_free(eXosip_notify_t *jn) +{ + /* ... */ + + eXosip_dialog_t *jd; + + for (jd = jn->n_dialogs; jd!=NULL; jd=jn->n_dialogs) + { + REMOVE_ELEMENT(jn->n_dialogs, jd); + eXosip_dialog_free(jd); + } + + __eXosip_delete_jinfo(jn->n_inc_tr); + __eXosip_delete_jinfo(jn->n_out_tr); + if (jn->n_inc_tr!=NULL) + osip_list_add(eXosip.j_transactions, jn->n_inc_tr, 0); + if (jn->n_out_tr!=NULL) + osip_list_add(eXosip.j_transactions, jn->n_out_tr, 0); + if (jn->n_contact_info!=NULL) osip_free(jn->n_contact_info); + osip_free(jn); +} + +int +_eXosip_notify_set_refresh_interval(eXosip_notify_t *jn, + osip_message_t *inc_subscribe) +{ + osip_header_t *exp; + int now; + now = time(NULL); + if (jn==NULL || inc_subscribe==NULL) + return -1; + + osip_message_get_expires(inc_subscribe, 0, &exp); + if (exp==NULL || exp->hvalue==NULL) + jn->n_ss_expires = now + 600; + else + { + jn->n_ss_expires = osip_atoi(exp->hvalue); + if (jn->n_ss_expires!=-1) + jn->n_ss_expires = now + jn->n_ss_expires; + else /* on error, set it to default */ + jn->n_ss_expires = now + 600; + } + + return 0; +} + +int +eXosip_notify_add_allowed_subscriber(char *sip_url) +{ + /* TODO */ + return -1; +} + +int +_eXosip_notify_is_a_known_subscriber(osip_message_t *sip) +{ + /* */ + return -1; +} + + +int +_eXosip_notify_add_body(eXosip_notify_t *jn, osip_message_t *notify) +{ + char buf[1000]; +#ifdef SUPPORT_MSN + int atom_id = 1000; +#endif + if (jn->n_ss_status!=EXOSIP_SUBCRSTATE_ACTIVE + || jn->n_contact_info==NULL || jn->n_contact_info=='\0') /* mandatory! */ + return 0; /* don't need a body? */ + +#ifdef SUPPORT_MSN + + if (jn->n_online_status==EXOSIP_NOTIFY_ONLINE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +

\n\ +\n\ +\n\ +
\n\ +\n\ +", jn->n_contact_info, atom_id, jn->n_contact_info); + + } + else if (jn->n_online_status==EXOSIP_NOTIFY_BUSY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", jn->n_contact_info, atom_id, jn->n_contact_info); + + } + else if (jn->n_online_status==EXOSIP_NOTIFY_BERIGHTBACK) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", jn->n_contact_info, atom_id, jn->n_contact_info); + + } + else if (jn->n_online_status==EXOSIP_NOTIFY_AWAY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", jn->n_contact_info, atom_id, jn->n_contact_info); + + } + else if (jn->n_online_status==EXOSIP_NOTIFY_ONTHEPHONE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", jn->n_contact_info, atom_id, jn->n_contact_info); + + } + else if (jn->n_online_status==EXOSIP_NOTIFY_OUTTOLUNCH) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", jn->n_contact_info, atom_id, jn->n_contact_info); + + } + else + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", jn->n_contact_info, atom_id, jn->n_contact_info); + } + + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, "application/xpidf+xml"); +#else + + if (jn->n_online_status==EXOSIP_NOTIFY_ONLINE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ +%s\n\ +online\n\ +\n\ +", + jn->n_contact_info, jn->n_contact_info); + } + else if (jn->n_online_status==EXOSIP_NOTIFY_BUSY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + busy\n\ +\n\ +\n\ +%s\n\ +busy\n\ +\n\ +", + jn->n_contact_info, jn->n_contact_info); + } + else if (jn->n_online_status==EXOSIP_NOTIFY_BERIGHTBACK) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + in-transit\n\ +\n\ +\n\ +%s\n\ +be right back\n\ +\n\ +", + jn->n_contact_info, jn->n_contact_info); + } + else if (jn->n_online_status==EXOSIP_NOTIFY_AWAY) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + away\n\ +\n\ +\n\ +%s\n\ +away\n\ +\n\ +", + jn->n_contact_info, jn->n_contact_info); + } + else if (jn->n_online_status==EXOSIP_NOTIFY_ONTHEPHONE) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + on-the-phone\n\ +\n\ +\n\ +%s\n\ +on the phone\n\ +\n\ +", + jn->n_contact_info, jn->n_contact_info); + } + else if (jn->n_online_status==EXOSIP_NOTIFY_OUTTOLUNCH) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + meal\n\ +\n\ +\n\ +%s\n\ +out to lunch\n\ +\n\ +", + jn->n_contact_info, jn->n_contact_info); + } + else + { + /* */ + sprintf(buf, "\n\ +\n%s", + jn->n_contact_info, +"\n\ +\n\ +closed\n\ +\n\ + permanent-absence\n\ +\n\ +\n\ +\n\ +\n\n"); + } + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, "application/pidf+xml"); + +#endif + + return 0; +} + +void +_eXosip_notify_add_expires_in_2XX_for_subscribe(eXosip_notify_t *jn, osip_message_t *answer) +{ + char tmp[20]; + int now; + now = time(NULL); + + if (jn->n_ss_expires-now<0) + { + tmp[0] = '0'; + tmp[1] = '\0'; + } + else + { + sprintf(tmp, "%i", jn->n_ss_expires-now); + } + osip_message_set_expires(answer, tmp); +} diff --git a/linphone/exosip/jpipe.c b/linphone/exosip/jpipe.c new file mode 100644 index 000000000..a91987dc6 --- /dev/null +++ b/linphone/exosip/jpipe.c @@ -0,0 +1,221 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "jpipe.h" + +#ifndef WIN32 + +jpipe_t * jpipe () +{ + jpipe_t *my_pipe = (jpipe_t *) osip_malloc (sizeof (jpipe_t)); + if (my_pipe==NULL) return NULL; + + if (0 != pipe (my_pipe->pipes)) + { + osip_free (my_pipe); + return NULL; + } + return my_pipe; +} + +int jpipe_close (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + close (apipe->pipes[0]); + close (apipe->pipes[1]); + osip_free (apipe); + return 0; +} + + +/** + * Write in a pipe. + */ +int +jpipe_write (jpipe_t * apipe, const void *buf, int count) +{ + if (apipe == NULL) + return -1; + return write (apipe->pipes[1], buf, count); +} + +/** + * Read in a pipe. + */ +int jpipe_read (jpipe_t * apipe, void *buf, int count) +{ + if (apipe == NULL) + return -1; + return read (apipe->pipes[0], buf, count); +} + +/** + * Get descriptor of reading pipe. + */ +int jpipe_get_read_descr (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + return apipe->pipes[0]; +} + +#else + +jpipe_t * jpipe () +{ + int s = 0; + int timeout = 0; + static int aport = 10500; + struct sockaddr_in raddr; + int j; + + jpipe_t *my_pipe = (jpipe_t *) osip_malloc (sizeof (jpipe_t)); + if (my_pipe==NULL) + return NULL; + + s = (int) socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (0 > s) + { + osip_free (my_pipe); + return NULL; + } + my_pipe->pipes[1] = (int) socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (0 > my_pipe->pipes[1]) + { + closesocket(s); + osip_free (my_pipe); + return NULL; + } + + raddr.sin_addr.s_addr = inet_addr ("127.0.0.1"); + raddr.sin_family = AF_INET; + + j = 50; + while (aport++ && j-- > 0) + { + raddr.sin_port = htons ((short) aport); + if (bind (s, (struct sockaddr *) &raddr, sizeof (raddr)) < 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, + "Failed to bind one local socket %i!\n", + aport)); + } + else + break; + } + + if (j == 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Failed to bind a local socket, aborting!\n")); + closesocket (s); + closesocket (my_pipe->pipes[1]); + osip_free (my_pipe); + } + + j = listen(s,1); + if (j != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Failed to listen on a local socket, aborting!\n")); + closesocket(s); + closesocket(my_pipe->pipes[1]); + osip_free (my_pipe); + } + + j = setsockopt (my_pipe->pipes[1], + SOL_SOCKET, + SO_RCVTIMEO, (const char*) &timeout, sizeof (timeout)); + if (j != NO_ERROR) + { + /* failed for some reason... */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "udp plugin; cannot set O_NONBLOCK to the file desciptor!\n")); + closesocket(s); + closesocket(my_pipe->pipes[1]); + osip_free (my_pipe); + } + + connect (my_pipe->pipes[1], (struct sockaddr *) &raddr, sizeof (raddr)); + + my_pipe->pipes[0] = accept (s, NULL, NULL); + + if (my_pipe->pipes[0]<=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "udp plugin; Failed to call accept!\n")); + closesocket(s); + closesocket(my_pipe->pipes[1]); + osip_free (my_pipe); + } + + return my_pipe; +} + +int jpipe_close (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + closesocket (apipe->pipes[0]); + closesocket (apipe->pipes[1]); + osip_free (apipe); + return 0; +} + + +/** + * Write in a pipe. + */ +int +jpipe_write (jpipe_t * apipe, const void *buf, int count) +{ + if (apipe == NULL) + return -1; + return send (apipe->pipes[1], buf, count, 0); +} + +/** + * Read in a pipe. + */ +int jpipe_read (jpipe_t * apipe, void *buf, int count) +{ + if (apipe == NULL) + return -1; + return recv (apipe->pipes[0], buf, count, 0 /* MSG_DONTWAIT */ ); /* BUG?? */ +} + +/** + * Get descriptor of reading pipe. + */ +int jpipe_get_read_descr (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + return apipe->pipes[0]; +} + +#endif diff --git a/linphone/exosip/jpipe.h b/linphone/exosip/jpipe.h new file mode 100644 index 000000000..3870cefd8 --- /dev/null +++ b/linphone/exosip/jpipe.h @@ -0,0 +1,111 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef _JPIPE_H_ +#define _JPIPE_H_ + +#include + +#ifndef WIN32 +#ifdef HAVE_UNISTD_H +#include +#endif +#endif + +#ifdef WIN32 +#include +#endif + +/** + * @file jpipe.h + * @brief PPL Pipe Handling Routines + */ + +/** + * @defgroup JPIPE Pipe Handling + * @ingroup PPL + * @{ + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef WIN32 + +/** + * Structure for storing a pipe descriptor + * @defvar jpipe_t + */ + typedef struct jpipe_t jpipe_t; + + struct jpipe_t + { + int pipes[2]; + }; + +#else + +/** + * Structure for storing a pipe descriptor + * @defvar ppl_pipe_t + */ + typedef struct jpipe_t jpipe_t; + + struct jpipe_t + { + int pipes[2]; + }; + +#endif + +/** + * Get New pipe pair. + */ + jpipe_t * jpipe (void); + +/** + * Close pipe + */ + int jpipe_close (jpipe_t * apipe); + +/** + * Write in a pipe. + */ + int jpipe_write (jpipe_t * pipe, const void *buf, + int count); + +/** + * Read in a pipe. + */ + int jpipe_read (jpipe_t * pipe, void *buf, + int count); + +/** + * Get descriptor of reading pipe. + */ + int jpipe_get_read_descr (jpipe_t * pipe); + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif diff --git a/linphone/exosip/jpublish.c b/linphone/exosip/jpublish.c new file mode 100644 index 000000000..a309ace8c --- /dev/null +++ b/linphone/exosip/jpublish.c @@ -0,0 +1,118 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int _eXosip_pub_update(eXosip_pub_t **pub, osip_transaction_t *tr, osip_message_t *answer) +{ + eXosip_pub_t *jpub; + + *pub = NULL; + + for (jpub = eXosip.j_pub; jpub!=NULL; jpub = jpub->next) + { + if (jpub->p_last_tr==NULL) + { /*bug? */ } + else if (tr==jpub->p_last_tr) + { + /* update the sip_etag parameter */ + if (answer==NULL) + { /* bug? */ + } + else if (MSG_IS_STATUS_2XX(answer)) + { + osip_header_t *sip_etag=NULL; + osip_message_header_get_byname(answer, "SIP-ETag", 0, &sip_etag); + if (sip_etag!=NULL && sip_etag->hvalue!=NULL) + snprintf(jpub->p_sip_etag, 64, "%s", sip_etag->hvalue); + } + *pub=jpub; + return 0; + } + } + return -1; +} + +int _eXosip_pub_find_by_aor(eXosip_pub_t **pub, const char *aor) +{ + eXosip_pub_t *jpub; + eXosip_pub_t *ptr; + time_t now; + + *pub = NULL; + + /* delete expired publications */ + now = time(NULL); + ptr = eXosip.j_pub; + for (jpub = ptr; jpub!=NULL; jpub = ptr) + { + ptr = jpub->next; + if (now-jpub->p_expires>60) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_WARNING, NULL, + "eXosip: removing expired publication!")); + REMOVE_ELEMENT(eXosip.j_pub, jpub); + _eXosip_pub_free(jpub); + } + } + + for (jpub = eXosip.j_pub; jpub!=NULL; jpub = jpub->next) + { + if (osip_strcasecmp(aor, jpub->p_aor)==0) + { + *pub=jpub; + return 0; + } + } + return -1; +} + +int _eXosip_pub_init(eXosip_pub_t **pub, const char *aor, const char *exp) +{ + eXosip_pub_t *jpub; + + *pub = NULL; + + jpub = (eXosip_pub_t*) osip_malloc(sizeof(eXosip_pub_t)); + if (jpub==0) + return -1; + memset(jpub, 0, sizeof(eXosip_pub_t)); + snprintf(jpub->p_aor, 256, "%s", aor); + + jpub->p_expires = atoi(exp) + time(NULL); + jpub->p_period = atoi(exp); + + *pub = jpub; + return 0; +} + +void _eXosip_pub_free(eXosip_pub_t *pub) +{ + if (pub->p_last_tr!=NULL) + osip_list_add(eXosip.j_transactions, pub->p_last_tr, 0); + osip_free(pub); +} + diff --git a/linphone/exosip/jreg.c b/linphone/exosip/jreg.c new file mode 100644 index 000000000..fc16c0a1e --- /dev/null +++ b/linphone/exosip/jreg.c @@ -0,0 +1,106 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int eXosip_reg_init(eXosip_reg_t **jr, char *from, char *proxy, char *contact, char* route) +{ + static int r_id; + + *jr = (eXosip_reg_t*) osip_malloc(sizeof(eXosip_reg_t)); + if (*jr==NULL) return -1; + + if (r_id > 1000000) /* keep it non-negative */ + r_id = 0; + + (*jr)->r_id = ++r_id; + (*jr)->r_reg_period = 3600; /* delay between registration */ + (*jr)->r_aor = osip_strdup(from); /* sip identity */ + (*jr)->r_contact = osip_strdup(contact); /* sip identity */ + (*jr)->r_registrar = osip_strdup(proxy); /* registrar */ + (*jr)->r_route = osip_strdup(route); /* outbound proxy */ +#if 0 + (*jr)->r_realms = NULL; /* list of realms */ +#endif + (*jr)->r_last_tr = NULL; + + (*jr)->next = NULL; + (*jr)->parent = NULL; + return 0; +} + +void eXosip_reg_free(eXosip_reg_t *jreg) +{ + + osip_free(jreg->r_aor); + osip_free(jreg->r_contact); + osip_free(jreg->r_registrar); +#if 0 + osip_free(jreg->r_realms); +#endif + + if (jreg->r_last_tr != NULL) + { + if (jreg->r_last_tr->state==IST_TERMINATED || + jreg->r_last_tr->state==ICT_TERMINATED || + jreg->r_last_tr->state== NICT_TERMINATED || + jreg->r_last_tr->state==NIST_TERMINATED) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Release a terminated transaction\n")); + __eXosip_delete_jinfo(jreg->r_last_tr); + if (jreg->r_last_tr!=NULL) + osip_list_add(eXosip.j_transactions, jreg->r_last_tr, 0); + } + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Release a non-terminated transaction\n")); + __eXosip_delete_jinfo(jreg->r_last_tr); + if (jreg->r_last_tr!=NULL) + osip_list_add(eXosip.j_transactions, jreg->r_last_tr, 0); + } + } + + osip_free(jreg); +} + +int _eXosip_reg_find(eXosip_reg_t **reg, osip_transaction_t *tr) +{ + eXosip_reg_t *jreg; + *reg = NULL; + if (tr==NULL) return -1; + + for (jreg = eXosip.j_reg; jreg!=NULL; jreg = jreg->next) + { + if (jreg->r_last_tr==tr) + { + *reg = jreg; + return 0; + } + } + return -1; +} diff --git a/linphone/exosip/jrequest.c b/linphone/exosip/jrequest.c new file mode 100644 index 000000000..854c18782 --- /dev/null +++ b/linphone/exosip/jrequest.c @@ -0,0 +1,1158 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" + +#ifndef WIN32 +#include +#include +#include +#include +#ifdef __APPLE_CC__ +#include +#endif +#else +#include +#include +#endif + +extern eXosip_t eXosip; + +/* Private functions */ +static int generating_request_out_of_dialog(osip_message_t **dest, + char *method_name, char *to, + char *transport, char *from, + char *proxy); +static int dialog_fill_route_set(osip_dialog_t *dialog, + osip_message_t *request); + +/* should use cryptographically random identifier is RECOMMENDED.... */ +/* by now this should lead to identical call-id when application are + started at the same time... */ +char * +osip_call_id_new_random() +{ + char *tmp = (char *)osip_malloc(33); + unsigned int number = osip_build_random_number(); + sprintf(tmp,"%u",number); + return tmp; +} + +char * +osip_from_tag_new_random(void) +{ + return osip_call_id_new_random(); +} + +char * +osip_to_tag_new_random(void) +{ + return osip_call_id_new_random(); +} + +unsigned int +via_branch_new_random(void) +{ + return osip_build_random_number(); +} + +/* prepare a minimal request (outside of a dialog) with required headers */ +/* + method_name is the type of request. ("INVITE", "REGISTER"...) + to is the remote target URI + transport is either "TCP" or "UDP" (by now, only UDP is implemented!) +*/ +static int +generating_request_out_of_dialog(osip_message_t **dest, char *method_name, + char *to, char *transport, char *from, + char *proxy) +{ + /* Section 8.1: + A valid request contains at a minimum "To, From, Call-iD, Cseq, + Max-Forwards and Via + */ + int i; + osip_message_t *request; +#ifdef SM + char *locip=NULL; +#else + char locip[50]; +#endif + int doing_register; + char *register_callid_number = NULL; + + i = osip_message_init(&request); + if (i!=0) return -1; + + /* prepare the request-line */ + osip_message_set_method(request, osip_strdup(method_name)); + osip_message_set_version(request, osip_strdup("SIP/2.0")); + osip_message_set_status_code(request, 0); + osip_message_set_reason_phrase(request, NULL); + + doing_register = 0==strcmp("REGISTER", method_name); + + if (doing_register) + { + osip_uri_init(&(request->req_uri)); + i = osip_uri_parse(request->req_uri, proxy); + if (i!=0) + { + goto brood_error_1; + } + osip_message_set_to(request, from); + } + else + { + /* in any cases except REGISTER: */ + i = osip_message_set_to(request, to); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: callee address does not seems to be a sipurl: %s\n", to)); + goto brood_error_1; + } + if (proxy!=NULL && proxy[0] != 0) + { /* equal to a pre-existing route set */ + /* if the pre-existing route set contains a "lr" (compliance + with bis-08) then the req_uri should contains the remote target + URI */ + osip_uri_param_t *lr_param; + osip_route_t *o_proxy; +#ifndef __VXWORKS_OS__ + osip_route_init(&o_proxy); +#else + osip_route_init2(&o_proxy); +#endif + i = osip_route_parse(o_proxy, proxy); + if (i!=0) { + osip_route_free(o_proxy); + goto brood_error_1; + } + + osip_uri_uparam_get_byname(o_proxy->url, "lr", &lr_param); + if (lr_param!=NULL) /* to is the remote target URI in this case! */ + { + osip_uri_clone(request->to->url, &(request->req_uri)); + /* "[request] MUST includes a Route header field containing + the route set values in order." */ + osip_list_add(request->routes, o_proxy, 0); + } + else + /* if the first URI of route set does not contain "lr", the req_uri + is set to the first uri of route set */ + { + request->req_uri = o_proxy->url; + o_proxy->url = NULL; + osip_route_free(o_proxy); + /* add the route set */ + /* "The UAC MUST add a route header field containing + the remainder of the route set values in order. + The UAC MUST then place the remote target URI into + the route header field as the last value + */ + osip_message_set_route(request, to); + } + } + else /* No route set (outbound proxy) is used */ + { + /* The UAC must put the remote target URI (to field) in the req_uri */ + i = osip_uri_clone(request->to->url, &(request->req_uri)); + if (i!=0) goto brood_error_1; + } + } + /*guess the local ip since req uri is known */ +#ifdef SM + { + eXosip_get_localip_for(request->req_uri->host,&locip); + } +#else + eXosip_guess_ip_for_via(eXosip.ip_family, locip, 49); +#endif + /* set To and From */ + osip_message_set_from(request, from); + /* add a tag */ + osip_from_set_tag(request->from, osip_from_tag_new_random()); + + /* set the cseq and call_id header */ + { + osip_call_id_t *callid; + osip_cseq_t *cseq; + char *num; + char *cidrand; + + /* call-id is always the same for REGISTRATIONS */ + i = osip_call_id_init(&callid); + if (i!=0) goto brood_error_1; + cidrand = osip_call_id_new_random(); + osip_call_id_set_number(callid, cidrand); + if (doing_register) + register_callid_number = cidrand; + + osip_call_id_set_host(callid, osip_strdup(locip)); + request->call_id = callid; + + i = osip_cseq_init(&cseq); + if (i!=0) goto brood_error_1; + num = osip_strdup(doing_register ? "1" : "20" ); + osip_cseq_set_number(cseq, num); + osip_cseq_set_method(cseq, osip_strdup(method_name)); + request->cseq = cseq; + } + + /* always add the Max-Forward header */ + osip_message_set_max_forwards(request, "70"); /* a UA should start a request with 70 */ + +#define MASQUERADE_VIA +#ifdef MASQUERADE_VIA + /* should be useless with compliant UA */ + if (eXosip.j_firewall_ip[0]!='\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, request->req_uri->host, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + if (eXosip_is_public_address(c_address)) + { + char tmp[200]; + snprintf(tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + eXosip.j_firewall_ip, + eXosip.localport, + via_branch_new_random() ); + osip_message_set_via(request, tmp); + } + else + { + char tmp[200]; + if (eXosip.ip_family==AF_INET6) + snprintf(tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + else + snprintf(tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + osip_message_set_via(request, tmp); + } + } + else + { + char tmp[200]; + if (eXosip.ip_family==AF_INET6) + snprintf(tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + else + snprintf(tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + osip_message_set_via(request, tmp); + } + +#else + { + char tmp[200]; + if (eXosip.ip_family==AF_INET6) + spnrintf(tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + else + spnrintf(tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + + osip_message_set_via(request, tmp); + } +#endif + + /* add specific headers for each kind of request... */ + + if (0==strcmp("INVITE", method_name) || 0==strcmp("SUBSCRIBE", method_name)) + { + char *contact; + osip_from_t *a_from; + int i; + i = osip_from_init(&a_from); + if (i==0) + i = osip_from_parse(a_from, from); + + if (i==0 && a_from!=NULL + && a_from->url!=NULL && a_from->url->username!=NULL ) + { + contact = (char *) osip_malloc(50+strlen(a_from->url->username)); + + if (eXosip.j_firewall_ip[0]!='\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, request->req_uri->host, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + if (eXosip_is_public_address(c_address)) + { + if (eXosip.localport==NULL) + sprintf(contact, "", a_from->url->username, + eXosip.j_firewall_ip); + else + sprintf(contact, "", a_from->url->username, + eXosip.j_firewall_ip, + eXosip.localport); + } + else + { + if (eXosip.localport==NULL) + sprintf(contact, "", a_from->url->username, + locip); + else + sprintf(contact, "", a_from->url->username, + locip, + eXosip.localport); + } + } + else + { + if (eXosip.localport==NULL) + sprintf(contact, "", a_from->url->username, + locip); + else + sprintf(contact, "", a_from->url->username, + locip, + eXosip.localport); + } + osip_message_set_contact(request, contact); + osip_free(contact); + } + osip_from_free(a_from); + + /* This is probably useless for other messages */ + osip_message_set_allow(request, "INVITE"); + osip_message_set_allow(request, "ACK"); + osip_message_set_allow(request, "CANCEL"); + osip_message_set_allow(request, "BYE"); + osip_message_set_allow(request, "OPTIONS"); + osip_message_set_allow(request, "REFER"); + osip_message_set_allow(request, "SUBSCRIBE"); + osip_message_set_allow(request, "NOTIFY"); + osip_message_set_allow(request, "MESSAGE"); + } + + if (0==strcmp("SUBSCRIBE", method_name)) + { + osip_message_set_header(request, "Event", "presence"); +#ifdef SUPPORT_MSN + osip_message_set_accept(request, "application/xpidf+xml"); +#else + osip_message_set_accept(request, "application/pidf+xml"); +#endif + } + else if (0==strcmp("REGISTER", method_name)) + { + } + else if (0==strcmp("INFO", method_name)) + { + } + else if (0==strcmp("OPTIONS", method_name)) + { + osip_message_set_accept(request, "application/sdp"); + } + + osip_message_set_user_agent(request, eXosip.user_agent); + /* else if ... */ + *dest = request; +#ifdef SM + osip_free(locip); +#endif + return 0; + + brood_error_1: + osip_message_free(request); + *dest = NULL; +#ifdef SM + if (locip!=NULL) osip_free(locip); +#endif + return -1; +} + +int +generating_register(osip_message_t **reg, char *from, + char *proxy, char *contact, int expires) +{ + osip_from_t *a_from; + osip_via_t *via; + int i; + char * locip; + + i = generating_request_out_of_dialog(reg, "REGISTER", NULL, "UDP", + from, proxy); + if (i!=0) return -1; + + /*get the local ip from the via already established by generating_request_out_of_dialog */ + if (osip_message_get_via((*reg),0,&via)==0){ + locip=via->host; + }else return -1; + + if (contact==NULL) + { + i = osip_from_init(&a_from); + if (i==0) + i = osip_from_parse(a_from, from); + + if (i==0 && a_from!=NULL + && a_from->url!=NULL && a_from->url->username!=NULL ) + { + contact = (char *) osip_malloc(50+strlen(a_from->url->username)); + + if (eXosip.ip_family==AF_INET6) + sprintf(contact, "", a_from->url->username, + locip, + eXosip.localport!=NULL ? eXosip.localport : "5060"); + else + sprintf(contact, "", a_from->url->username, + locip, + eXosip.localport!=NULL ? eXosip.localport : "5060"); + osip_message_set_contact(*reg, contact); + osip_free(contact); + } + osip_from_free(a_from); + } + else + { + osip_message_set_contact(*reg, contact); + } + + { + char exp[10]; /* MUST never be ouside 1 and 3600 */ + snprintf(exp, 9, "%i", expires); + osip_message_set_expires(*reg, exp); + } + + osip_message_set_content_length(*reg, "0"); + + return 0; +} + +/* this method can't be called unless the previous + INVITE transaction is over. */ +int eXosip_build_initial_invite(osip_message_t **invite, char *to, char *from, + char *route, char *subject) +{ + int i; + + if (to!=NULL && *to=='\0') + return -1; + + osip_clrspace(to); + osip_clrspace(subject); + osip_clrspace(from); + osip_clrspace(route); + if (route!=NULL && *route=='\0') + route=NULL; + if (subject!=NULL && *subject=='\0') + subject=NULL; + + i = generating_request_out_of_dialog(invite, "INVITE", to, "UDP", from, + route); + if (i!=0) return -1; + +#if 0 + if (subject==NULL) + osip_message_set_subject(*invite, "New Call"); + else + osip_message_set_subject(*invite, subject); +#else + if (subject!=NULL) + osip_message_set_subject(*invite, subject); +#endif + + /* after this delay, we should send a CANCEL */ + osip_message_set_expires(*invite, "120"); + + /* osip_message_set_organization(*invite, "Jack's Org"); */ + return 0; +} + +/* this method can't be called unless the previous + INVITE transaction is over. */ +int eXosip_build_initial_options(osip_message_t **options, char *to, char *from, + char *route) +{ + int i; + + if (to!=NULL && *to=='\0') + return -1; + + osip_clrspace(to); + osip_clrspace(from); + osip_clrspace(route); + if (route!=NULL && *route=='\0') + route=NULL; + + i = generating_request_out_of_dialog(options, "OPTIONS", to, "UDP", from, + route); + if (i!=0) return -1; + + /* after this delay, we should send a CANCEL */ + osip_message_set_expires(*options, "120"); + + /* osip_message_set_organization(*invite, "Jack's Org"); */ + return 0; +} + +/* this method can't be called unless the previous + INVITE transaction is over. */ +int generating_initial_subscribe(osip_message_t **subscribe, char *to, + char *from, char *route) +{ + int i; + + if (to!=NULL && *to=='\0') + return -1; + + osip_clrspace(to); + osip_clrspace(from); + osip_clrspace(route); + if (route!=NULL && *route=='\0') + route=NULL; + + i = generating_request_out_of_dialog(subscribe, "SUBSCRIBE", to, "UDP", from, + route); + if (i!=0) return -1; + +#ifdef LOW_EXPIRE + osip_message_set_expires(*subscribe, "120"); +#else + osip_message_set_expires(*subscribe, "3600"); +#endif + + /* osip_message_set_organization(*subscribe, "Jack's Org"); */ + return 0; +} + +/* this method can't be called unless the previous + INVITE transaction is over. */ +int generating_message(osip_message_t **message, char *to, char *from, + char *route, char *buff) +{ + int i; + + if (to!=NULL && *to=='\0') + return -1; + + osip_clrspace(to); + /* osip_clrspace(buff); */ + osip_clrspace(from); + osip_clrspace(route); + if (route!=NULL && *route=='\0') + route=NULL; + if (buff!=NULL && *buff=='\0') + return -1; /* at least, the message must be of length >= 1 */ + + i = generating_request_out_of_dialog(message, "MESSAGE", to, "UDP", from, + route); + if (i!=0) return -1; + + osip_message_set_expires(*message, "120"); + osip_message_set_body(*message, buff, strlen(buff)); + osip_message_set_content_type(*message, "text/plain"); + + /* osip_message_set_organization(*message, "Jack's Org"); */ + + + return 0; +} + +/* this method can't be called unless the previous + INVITE transaction is over. */ +int +generating_publish(osip_message_t **message, char *to, char *from, + char *route) +{ + int i; + + if (to!=NULL && *to=='\0') + return -1; + + osip_clrspace(to); + osip_clrspace(from); + osip_clrspace(route); + if (route!=NULL && *route=='\0') + route=NULL; + + i = generating_request_out_of_dialog(message, "PUBLISH", to, "UDP", from, + route); + if (i!=0) return -1; + + /* osip_message_set_organization(*message, "Jack's Org"); */ + + return 0; +} + + +int +generating_options(osip_message_t **options, char *from, char *to, char *proxy) +{ + int i; + i = generating_request_out_of_dialog(options, "OPTIONS", to, "UDP", + from, proxy); + if (i!=0) return -1; + +#if 0 + if (sdp!=NULL) + { + osip_message_set_content_type(*options, "application/sdp"); + osip_message_set_body(*options, sdp); + } +#endif + + return 0; +} + +int +generating_info(osip_message_t **info, char *from, char *to, char *proxy) +{ + int i; + i = generating_request_out_of_dialog(info, "INFO", to, "UDP", + from, proxy); + if (i!=0) return -1; + return 0; +} + + +static int +dialog_fill_route_set(osip_dialog_t *dialog, osip_message_t *request) +{ + /* if the pre-existing route set contains a "lr" (compliance + with bis-08) then the req_uri should contains the remote target + URI */ + int i; + int pos=0; + osip_uri_param_t *lr_param; + osip_route_t *route; + char *last_route; + /* AMD bug: fixed 17/06/2002 */ + + if (dialog->type==CALLER) + { + pos = osip_list_size(dialog->route_set)-1; + route = (osip_route_t*)osip_list_get(dialog->route_set, pos); + } + else + route = (osip_route_t*)osip_list_get(dialog->route_set, 0); + + osip_uri_uparam_get_byname(route->url, "lr", &lr_param); + if (lr_param!=NULL) /* the remote target URI is the req_uri! */ + { + i = osip_uri_clone(dialog->remote_contact_uri->url, + &(request->req_uri)); + if (i!=0) return -1; + /* "[request] MUST includes a Route header field containing + the route set values in order." */ + /* AMD bug: fixed 17/06/2002 */ + pos=0; /* first element is at index 0 */ + while (!osip_list_eol(dialog->route_set, pos)) + { + osip_route_t *route2; + route = osip_list_get(dialog->route_set, pos); + i = osip_route_clone(route, &route2); + if (i!=0) return -1; + if (dialog->type==CALLER) + osip_list_add(request->routes, route2, 0); + else + osip_list_add(request->routes, route2, -1); + pos++; + } + return 0; + } + + /* if the first URI of route set does not contain "lr", the req_uri + is set to the first uri of route set */ + + + i = osip_uri_clone(route->url, &(request->req_uri)); + if (i!=0) return -1; + /* add the route set */ + /* "The UAC MUST add a route header field containing + the remainder of the route set values in order. */ + pos=0; /* yes it is */ + + while (!osip_list_eol(dialog->route_set, pos)) /* not the first one in the list */ + { + osip_route_t *route2; + route = osip_list_get(dialog->route_set, pos); + i = osip_route_clone(route, &route2); + if (i!=0) return -1; + if (dialog->type==CALLER) + { + if (pos!=osip_list_size(dialog->route_set)-1) + osip_list_add(request->routes, route2, 0); + else + osip_route_free(route2); + } + else + { + if (!osip_list_eol(dialog->route_set, pos+1)) + osip_list_add(request->routes, route2, -1); + else + osip_route_free(route2); + } + pos++; + } + + /* The UAC MUST then place the remote target URI into + the route header field as the last value */ + i = osip_uri_to_str(dialog->remote_contact_uri->url, &last_route); + if (i!=0) return -1; + i = osip_message_set_route(request, last_route); + osip_free(last_route); + if (i!=0) { return -1; } + + /* route header and req_uri set */ + return 0; +} + +int +_eXosip_build_request_within_dialog(osip_message_t **dest, char *method_name, + osip_dialog_t *dialog, char *transport) +{ + int i; + osip_message_t *request; +#ifdef SM + char *locip=NULL; +#else + char locip[50]; +#endif + + i = osip_message_init(&request); + if (i!=0) return -1; + + if (dialog->remote_contact_uri==NULL) + { + /* this dialog is probably not established! or the remote UA + is not compliant with the latest RFC + */ + osip_message_free(request); + return -1; + } +#ifdef SM + eXosip_get_localip_for(dialog->remote_contact_uri->url->host,&locip); +#else + eXosip_guess_ip_for_via(eXosip.ip_family, locip, 49); +#endif + /* prepare the request-line */ + request->sip_method = osip_strdup(method_name); + request->sip_version = osip_strdup("SIP/2.0"); + request->status_code = 0; + request->reason_phrase = NULL; + + /* and the request uri???? */ + if (osip_list_eol(dialog->route_set, 0)) + { + /* The UAC must put the remote target URI (to field) in the req_uri */ + i = osip_uri_clone(dialog->remote_contact_uri->url, &(request->req_uri)); + if (i!=0) goto grwd_error_1; + } + else + { + /* fill the request-uri, and the route headers. */ + dialog_fill_route_set(dialog, request); + } + + /* To and From already contains the proper tag! */ + i = osip_to_clone(dialog->remote_uri, &(request->to)); + if (i!=0) goto grwd_error_1; + i = osip_from_clone(dialog->local_uri, &(request->from)); + if (i!=0) goto grwd_error_1; + + /* set the cseq and call_id header */ + osip_message_set_call_id(request, dialog->call_id); + + if (0==strcmp("ACK", method_name)) + { + osip_cseq_t *cseq; + char *tmp; + i = osip_cseq_init(&cseq); + if (i!=0) goto grwd_error_1; + tmp = osip_malloc(20); + sprintf(tmp,"%i", dialog->local_cseq); + osip_cseq_set_number(cseq, tmp); + osip_cseq_set_method(cseq, osip_strdup(method_name)); + request->cseq = cseq; + } + else + { + osip_cseq_t *cseq; + char *tmp; + i = osip_cseq_init(&cseq); + if (i!=0) goto grwd_error_1; + dialog->local_cseq++; /* we should we do that?? */ + tmp = osip_malloc(20); + sprintf(tmp,"%i", dialog->local_cseq); + osip_cseq_set_number(cseq, tmp); + osip_cseq_set_method(cseq, osip_strdup(method_name)); + request->cseq = cseq; + } + + /* always add the Max-Forward header */ + osip_message_set_max_forwards(request, "70"); /* a UA should start a request with 70 */ + + + /* even for ACK for 2xx (ACK within a dialog), the branch ID MUST + be a new ONE! */ +#ifdef MASQUERADE_VIA + /* should be useless with compliant UA */ + if (eXosip.j_firewall_ip[0]!='\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, request->req_uri->host, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + if (eXosip_is_public_address(c_address)) + { + char tmp[200]; + sprintf(tmp, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + eXosip.j_firewall_ip, + eXosip.localport, + via_branch_new_random() ); + osip_message_set_via(request, tmp); + } + else + { + char tmp[200]; + if (eXosip.ip_family==AF_INET6) + snprintf(tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + else + snprintf(tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + + osip_message_set_via(request, tmp); + } + } + else + { + char tmp[200]; + if (eXosip.ip_family==AF_INET6) + snprintf(tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + else + snprintf(tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + locip, + eXosip.localport, + via_branch_new_random() ); + + osip_message_set_via(request, tmp); + } + +#else + { + char tmp[200]; + if (eXosip.ip_family==AF_INET6) + sprintf(tmp, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, eXosip.localport, + via_branch_new_random()); + else + sprintf(tmp, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + locip, eXosip.localport, + via_branch_new_random()); + + osip_message_set_via(request, tmp); + } +#endif + + /* add specific headers for each kind of request... */ + +#if 0 + if (0==strcmp("INVITE", method_name) || 0==strcmp("SUBSCRIBE", method_name)) +#endif + { + char contact[200]; + if (eXosip.j_firewall_ip[0]!='\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, request->req_uri->host, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + if (eXosip_is_public_address(c_address)) + { + sprintf(contact, "", dialog->local_uri->url->username, + eXosip.j_firewall_ip, + eXosip.localport); + } + else + { + sprintf(contact, "", dialog->local_uri->url->username, + locip, + eXosip.localport); + } + } + else + { + sprintf(contact, "", dialog->local_uri->url->username, + locip, + eXosip.localport); + } + osip_message_set_contact(request, contact); + /* Here we'll add the supported header if it's needed! */ + /* the require header must be added by the upper layer if needed */ + } + + if (0==strcmp("SUBSCRIBE", method_name)) + { + osip_message_set_header(request, "Event", "presence"); +#ifdef SUPPORT_MSN + osip_message_set_accept(request, "application/xpidf+xml"); +#else + osip_message_set_accept(request, "application/pidf+xml"); +#endif + } + else if (0==strcmp("NOTIFY", method_name)) + { + } + else if (0==strcmp("INFO", method_name)) + { + + } + else if (0==strcmp("OPTIONS", method_name)) + { + osip_message_set_accept(request, "application/sdp"); + } + else if (0==strcmp("ACK", method_name)) + { + /* The ACK MUST contains the same credential than the INVITE!! */ + /* TODO... */ + } + + osip_message_set_user_agent(request, eXosip.user_agent); + /* else if ... */ + *dest = request; + return 0; + + /* grwd_error_2: */ + dialog->local_cseq--; + grwd_error_1: + osip_message_free(request); + *dest = NULL; + return -1; +} + +/* this request is only build within a dialog!! */ +int +generating_bye(osip_message_t **bye, osip_dialog_t *dialog) +{ + int i; + i = _eXosip_build_request_within_dialog(bye, "BYE", dialog, "UDP"); + if (i!=0) return -1; + + return 0; +} + +/* this request is only build within a dialog! (but should not!) */ +int +generating_refer_outside_dialog(osip_message_t **refer, char *refer_to, char *from, char *to, char *proxy) +{ + int i; + i = generating_request_out_of_dialog(refer, "REFER", to, "UDP", + from, proxy); + if (i!=0) return -1; + + osip_message_set_header(*refer, "Refer-to", refer_to); + return 0; +} + +/* this request is only build within a dialog! (but should not!) */ +int +generating_refer(osip_message_t **refer, osip_dialog_t *dialog, char *refer_to) +{ + int i; + i = _eXosip_build_request_within_dialog(refer, "REFER", dialog, "UDP"); + if (i!=0) return -1; + + osip_message_set_header(*refer, "Refer-to", refer_to); + + return 0; +} + +/* this request can be inside or outside a dialog */ +int +generating_options_within_dialog(osip_message_t **options, osip_dialog_t *dialog) +{ + int i; + i = _eXosip_build_request_within_dialog(options, "OPTIONS", dialog, "UDP"); + if (i!=0) return -1; + +#if 0 + if (sdp!=NULL) + { + osip_message_set_content_type(*options, "application/sdp"); + osip_message_set_body(*options, sdp); + } +#endif + + return 0; +} + +int +generating_info_within_dialog(osip_message_t **info, osip_dialog_t *dialog) +{ + int i; + i = _eXosip_build_request_within_dialog(info, "INFO", dialog, "UDP"); + if (i!=0) return -1; + return 0; +} + +/* It is RECOMMENDED to only cancel INVITE request */ +int +generating_cancel(osip_message_t **dest, osip_message_t *request_cancelled) +{ + int i; + osip_message_t *request; + + i = osip_message_init(&request); + if (i!=0) return -1; + + /* prepare the request-line */ + osip_message_set_method(request, osip_strdup("CANCEL")); + osip_message_set_version(request, osip_strdup("SIP/2.0")); + osip_message_set_status_code(request, 0); + osip_message_set_reason_phrase(request, NULL); + + i = osip_uri_clone(request_cancelled->req_uri, &(request->req_uri)); + if (i!=0) goto gc_error_1; + + i = osip_to_clone(request_cancelled->to, &(request->to)); + if (i!=0) goto gc_error_1; + i = osip_from_clone(request_cancelled->from, &(request->from)); + if (i!=0) goto gc_error_1; + + /* set the cseq and call_id header */ + i = osip_call_id_clone(request_cancelled->call_id, &(request->call_id)); + if (i!=0) goto gc_error_1; + i = osip_cseq_clone(request_cancelled->cseq, &(request->cseq)); + if (i!=0) goto gc_error_1; + osip_free(request->cseq->method); + request->cseq->method = osip_strdup("CANCEL"); + + /* copy ONLY the top most Via Field (this method is also used by proxy) */ + { + osip_via_t *via; + osip_via_t *via2; + i = osip_message_get_via(request_cancelled, 0, &via); + if (i!=0) goto gc_error_1; + i = osip_via_clone(via, &via2); + if (i!=0) goto gc_error_1; + osip_list_add(request->vias, via2, -1); + } + + /* add the same route-set than in the previous request */ + { + int pos=0; + osip_route_t *route; + osip_route_t *route2; + while (!osip_list_eol(request_cancelled->routes, pos)) + { + route = (osip_route_t*) osip_list_get(request_cancelled->routes, pos); + i = osip_route_clone(route, &route2); + if (i!=0) goto gc_error_1; + osip_list_add(request->routes, route2, -1); + pos++; + } + } + + osip_message_set_max_forwards(request, "70"); /* a UA should start a request with 70 */ + osip_message_set_user_agent(request, eXosip.user_agent); + + *dest = request; + return 0; + + gc_error_1: + osip_message_free(request); + *dest = NULL; + return -1; +} + + +int +generating_ack_for_2xx(osip_message_t **ack, osip_dialog_t *dialog) +{ + int i; + i = _eXosip_build_request_within_dialog(ack, "ACK", dialog, "UDP"); + if (i!=0) return -1; + + return 0; +} diff --git a/linphone/exosip/jresponse.c b/linphone/exosip/jresponse.c new file mode 100644 index 000000000..39d83c127 --- /dev/null +++ b/linphone/exosip/jresponse.c @@ -0,0 +1,1264 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +/* Private functions */ +static char *generating_no_sdp_answer(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_message_t *orig_request, char *local_sdp_port); + +int +eXosip_build_response_default(int jid, int status) +{ + return -1; +} + +int +_eXosip_build_response_default(osip_message_t **dest, osip_dialog_t *dialog, + int status, osip_message_t *request) +{ + osip_generic_param_t *tag; + osip_message_t *response; + int pos; + int i; + + if (request==NULL) return -1; + + i = osip_message_init(&response); + if (i!=0) + return -1; + /* initialise osip_message_t structure */ + /* yet done... */ + + response->sip_version = (char *)osip_malloc(8*sizeof(char)); + sprintf(response->sip_version,"SIP/2.0"); + osip_message_set_status_code(response, status); + + /* handle some internal reason definitions. */ + if (MSG_IS_NOTIFY(request) && status==481) + { + response->reason_phrase = osip_strdup("Subcription Does Not Exist"); + } + else if (MSG_IS_SUBSCRIBE(request) && status==202) + { + response->reason_phrase = osip_strdup("Accepted subscription"); + } + else + { + response->reason_phrase = osip_strdup(osip_message_get_reason(status)); + if (response->reason_phrase==NULL) + { + if (response->status_code == 101) + response->reason_phrase = osip_strdup("Dialog Establishement"); + else + response->reason_phrase = osip_strdup("Unknown code"); + } + response->req_uri = NULL; + response->sip_method = NULL; + } + + i = osip_to_clone(request->to, &(response->to)); + if (i!=0) goto grd_error_1; + + i = osip_to_get_tag(response->to,&tag); + if (i!=0) + { /* we only add a tag if it does not already contains one! */ + if ((dialog!=NULL) && (dialog->local_tag!=NULL)) + /* it should contain the local TAG we created */ + { osip_to_set_tag(response->to, osip_strdup(dialog->local_tag)); } + else + { + if (status!=100) + osip_to_set_tag(response->to, osip_to_tag_new_random()); + } + } + + i = osip_from_clone(request->from, &(response->from)); + if (i!=0) goto grd_error_1; + + pos = 0; + while (!osip_list_eol(request->vias,pos)) + { + osip_via_t *via; + osip_via_t *via2; + via = (osip_via_t *)osip_list_get(request->vias,pos); + i = osip_via_clone(via, &via2); + if (i!=-0) goto grd_error_1; + osip_list_add(response->vias, via2, -1); + pos++; + } + + i = osip_call_id_clone(request->call_id, &(response->call_id)); + if (i!=0) goto grd_error_1; + i = osip_cseq_clone(request->cseq, &(response->cseq)); + if (i!=0) goto grd_error_1; + + if (MSG_IS_SUBSCRIBE(request)) + { + osip_header_t *exp; + osip_message_set_header(response, "Event", "presence"); + i = osip_message_get_expires(request, 0, &exp); + if (exp==NULL) + { + osip_header_t *cp; + i = osip_header_clone(exp, &cp); + if (cp!=NULL) + osip_list_add(response->headers, cp, 0); + } + } + + osip_message_set_allow(response, "INVITE"); + osip_message_set_allow(response, "ACK"); + osip_message_set_allow(response, "OPTIONS"); + osip_message_set_allow(response, "CANCEL"); + osip_message_set_allow(response, "BYE"); + osip_message_set_allow(response, "SUBSCRIBE"); + osip_message_set_allow(response, "NOTIFY"); + osip_message_set_allow(response, "MESSAGE"); + osip_message_set_allow(response, "INFO"); + + *dest = response; + return 0; + + grd_error_1: + osip_message_free(response); + return -1; +} + +int +complete_answer_that_establish_a_dialog(osip_message_t *response, osip_message_t *request) +{ + int i; + int pos=0; + char contact[1000]; +#ifdef SM + char *locip=NULL; +#else + char locip[50]; +#endif + /* 12.1.1: + copy all record-route in response + add a contact with global scope + */ + while (!osip_list_eol(request->record_routes, pos)) + { + osip_record_route_t *rr; + osip_record_route_t *rr2; + rr = osip_list_get(request->record_routes, pos); + i = osip_record_route_clone(rr, &rr2); + if (i!=0) return -1; + osip_list_add(response->record_routes, rr2, -1); + pos++; + } + +#ifdef SM + eXosip_get_localip_from_via(response,&locip); +#else + eXosip_guess_ip_for_via(eXosip.ip_family, locip, 49); +#endif + + if (eXosip.answer_contact[0]) + snprintf(contact,1000, "%s", eXosip.answer_contact); + else if (request->to->url->username==NULL) + snprintf(contact,1000, "", locip, eXosip.localport); + else + snprintf(contact,1000, "", request->to->url->username, + locip, eXosip.localport); + + if (eXosip.j_firewall_ip[0]!='\0') + { + osip_contact_t *con = (osip_contact_t *) osip_list_get (request->contacts, 0); + if (con!=NULL && con->url!=NULL && con->url->host!=NULL) + { + char *c_address = con->url->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, con->url->host, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + /* If c_address is a PUBLIC address, the request was + coming from the PUBLIC network. */ + if (eXosip_is_public_address(c_address)) + { + if (request->to->url->username==NULL) + snprintf(contact,1000, "", eXosip.j_firewall_ip, + eXosip.localport); + else + snprintf(contact,1000, "", request->to->url->username, + eXosip.j_firewall_ip, eXosip.localport); + } + } + } + +#ifdef SM + osip_free(locip); +#endif + + osip_message_set_contact(response, contact); + + return 0; +} + +static char * +generating_no_sdp_answer(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_message_t *orig_request, char *local_sdp_port) +{ + sdp_message_t *local_sdp = NULL; + char *local_body = NULL; + char *size; + int i; + + jc->c_ack_sdp = 1; + if(osip_negotiation_sdp_build_offer(eXosip.osip_negotiation, NULL, &local_sdp, local_sdp_port, NULL) != 0) + return NULL; + + if (local_sdp!=NULL) + { + int pos=0; + while (!sdp_message_endof_media (local_sdp, pos)) + { + int k = 0; + char *tmp = sdp_message_m_media_get (local_sdp, pos); + if (0 == strncmp (tmp, "audio", 5)) + { + char *payload = NULL; + do { + payload = sdp_message_m_payload_get (local_sdp, pos, k); + if (payload == NULL) + { + } + else if (0==strcmp("110",payload)) + { + sdp_message_a_attribute_add (local_sdp, + pos, + osip_strdup ("AS"), + osip_strdup ("110 20")); + } + else if (0==strcmp("111",payload)) + { + sdp_message_a_attribute_add (local_sdp, + pos, + osip_strdup ("AS"), + osip_strdup ("111 20")); + } + k++; + } while (payload != NULL); + } + pos++; + } + } + + i = sdp_message_to_str(local_sdp, &local_body); + + if (local_body!=NULL) + { + size= (char *)osip_malloc(7*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(local_body)); +#else + sprintf(size,"%i",strlen(local_body)); +#endif + osip_message_set_content_length(orig_request, size); + osip_free(size); + + osip_message_set_body(orig_request, local_body, strlen(local_body)); + osip_message_set_content_type(orig_request, "application/sdp"); + } + else + osip_message_set_content_length(orig_request, "0"); + + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, local_sdp); + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO3,NULL,"200 OK w/ SDP (RESPONSE TO INVITE w/ NO SDP)=\n%s\n", local_body)); + + return local_body; +} + +char * +generating_sdp_answer(osip_message_t *request, osip_negotiation_ctx_t *context) +{ + sdp_message_t *remote_sdp; + sdp_message_t *local_sdp = NULL; + int i; + char *local_body; + if (context==NULL) + return NULL; + + local_body = NULL; + if (MSG_IS_INVITE(request)||MSG_IS_OPTIONS(request)||MSG_IS_RESPONSE_FOR(request, "INVITE")) + { + osip_body_t *body; + body = (osip_body_t *)osip_list_get(request->bodies,0); + if(body == NULL) + return NULL; + + /* remote_sdp = (sdp_message_t *) osip_malloc(sizeof(sdp_message_t)); */ + i = sdp_message_init(&remote_sdp); + if (i!=0) return NULL; + + /* WE ASSUME IT IS A SDP BODY AND THAT */ + /* IT IS THE ONLY ONE, OF COURSE, THIS IS */ + /* NOT TRUE */ + i = sdp_message_parse(remote_sdp,body->body); + if (i!=0) return NULL; + + i = osip_negotiation_ctx_set_remote_sdp(context, remote_sdp); + + i = osip_negotiation_ctx_execute_negotiation(eXosip.osip_negotiation, context); + if (i==200) + { + local_sdp = osip_negotiation_ctx_get_local_sdp(context); + + if (eXosip.j_firewall_ip[0]!='\0') + { + char *c_address = NULL; + int pos=0; + /* If remote message contains a Public IP, we have to replace the SDP + connection address */ + c_address = sdp_message_c_addr_get(remote_sdp, -1, 0); + while (c_address==NULL) + { + c_address = sdp_message_c_addr_get(remote_sdp, pos, 0); + pos++; + if (pos>10) + break; + } + if (c_address!=NULL) /* found a connection address: check if it is public */ + { + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo(&addrinfo, c_address, 5060); + if (i==0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", c_address)); + } + + if (eXosip_is_public_address(c_address)) + { + /* replace the IP with our firewall ip */ + sdp_connection_t *conn; + pos=-1; + conn = sdp_message_connection_get(local_sdp, pos, 0); + while (conn!=NULL) + { + if (conn->c_addr!=NULL ) + { + osip_free(conn->c_addr); + conn->c_addr = osip_strdup(eXosip.j_firewall_ip); + } + pos++; + conn = sdp_message_connection_get(local_sdp, pos, 0); + } + } + } + } + + i = sdp_message_to_str(local_sdp, &local_body); + + remote_sdp = osip_negotiation_ctx_get_remote_sdp(context); + sdp_message_free(remote_sdp); + osip_negotiation_ctx_set_remote_sdp(context, NULL); + + if (i!=0) { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not parse local SDP answer %i\n",i)); + return NULL; + } + return local_body; + } + else if (i==415) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"WARNING: Unsupported media %i\n",i)); + } + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: while building answer to SDP (%i)\n",i)); + } + remote_sdp = osip_negotiation_ctx_get_remote_sdp(context); + sdp_message_free(remote_sdp); + osip_negotiation_ctx_set_remote_sdp(context, NULL); + } + return NULL; +} + +int +eXosip_answer_options_1xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_transaction_t *tr; + osip_message_t *response; + int i; + + tr = eXosip_find_last_inc_options(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + + if (jd!=NULL) + { + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + } + else + { + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + } + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for OPTIONS\n")); + return -1; + } + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return 0; +} + +int +eXosip_answer_options_2xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_transaction_t *tr; + osip_message_t *response; + sdp_message_t *sdp; + char *body; + char size[10]; + int i; + + tr = eXosip_find_last_inc_options(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + osip_negotiation_sdp_build_offer(eXosip.osip_negotiation, NULL, &sdp, "10400", NULL); + if (sdp==NULL) + { + return -1; + } + if (jd!=NULL) + { + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + } + else + { + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + } + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for options\n")); + sdp_message_free(sdp); /* not used */ + return -1; + } + i = sdp_message_to_str(sdp, &body); + sdp_message_free(sdp); + if (i!=0) { + osip_message_free(response); + return -1; + } + i = osip_message_set_body(response, body, strlen(body)); + if (i!=0) { + osip_message_free(response); + return -1; + } +#ifdef __APPLE_CC__ + snprintf(size, 9,"%li",strlen(body)); +#else + snprintf(size, 9,"%i",strlen(body)); +#endif + i = osip_message_set_content_length(response, size); + if (i!=0) { + osip_free(body); + osip_message_free(response); + return -1; + } + osip_free(body); + i = osip_message_set_content_type(response, "application/sdp"); + if (i!=0) { + osip_message_free(response); + return -1; + } + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return 0; +} + +int +eXosip_answer_options_3456xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_transaction_t *tr; + osip_message_t *response; + int i; + tr = eXosip_find_last_inc_options(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + + if (jd!=NULL) + { + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + } + else + { + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + } + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for options\n")); + return -1; + } + + if (300<=code<=399) + { + /* Should add contact fields */ + /* ... */ + osip_message_set_contact(response, jc->c_redirection); + } + + osip_message_set_content_length(response, "0"); + /* send message to transaction layer */ + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + + return 0; +} + +int +_eXosip2_answer_invite_1xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, osip_message_t **answer) +{ + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd==NULL) + i = _eXosip_build_response_default(answer, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(answer, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for invite\n")); + return -2; + } + + osip_message_set_content_length(*answer, "0"); + /* send message to transaction layer */ + + if (code>100) + { + i = complete_answer_that_establish_a_dialog(*answer, tr->orig_request); + } + + return 0; +} + +int +_eXosip2_answer_invite_2xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, osip_message_t **answer) +{ + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + + if (tr==NULL || tr->orig_request==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer\n")); + return -1; + } + + if (jd!=NULL && jd->d_dialog==NULL) + { /* element previously removed */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot answer this closed transaction\n")); + return -1; + } + + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd==NULL) + i = _eXosip_build_response_default(answer, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(answer, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for invite\n")); + return -1; + } + + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + { + i = complete_answer_that_establish_a_dialog(*answer, tr->orig_request); + if (i!=0) goto g2atii_error_1;; /* ?? */ + } + + return 0; + + g2atii_error_1: + osip_message_free(*answer); + return -1; +} + +int +_eXosip2_answer_invite_3456xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, osip_message_t **answer) +{ + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + i = _eXosip_build_response_default(answer, jd->d_dialog, code, tr->orig_request); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for invite\n")); + return -1; + } + + if (300<=code<=399) + { + /* Should add contact fields */ + /* ... */ + } + + osip_message_set_content_length(*answer, "0"); + /* send message to transaction layer */ + + return 0; +} + +int +eXosip_answer_invite_1xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd==NULL) + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for invite\n")); + return -2; + } + + osip_message_set_content_length(response, "0"); + /* send message to transaction layer */ + + if (code>100) + { + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + i = complete_answer_that_establish_a_dialog(response, tr->orig_request); + + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, response); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + } + ADD_ELEMENT(jc->c_dialogs, jd); + } + } + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + + return 0; +} + +int +eXosip_answer_invite_2xx_with_body(eXosip_call_t *jc, eXosip_dialog_t *jd, int code,const char*bodytype, const char*body) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + char *size; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + + if (tr==NULL || tr->orig_request==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer\n")); + return -1; + } + + if (jd!=NULL && jd->d_dialog==NULL) + { /* element previously removed */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot answer this closed transaction\n")); + return -1; + } + + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd==NULL) + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for invite\n")); + code = 500; /* ? which code to use? */ + return -1; + } + + if (code==488) + { + osip_message_set_content_length(response, "0"); + /* TODO: send message to transaction layer */ + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return 0; + } + + i = osip_message_set_body(response, body, strlen(body)); + if (i!=0) { + goto g2atii_error_1; + } + size = (char *) osip_malloc(6*sizeof(char)); + sprintf(size,"%i",strlen(body)); + i = osip_message_set_content_length(response, size); + osip_free(size); + if (i!=0) goto g2atii_error_1; + i = osip_message_set_content_type(response, bodytype); + if (i!=0) goto g2atii_error_1; + + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + { + i = complete_answer_that_establish_a_dialog(response, tr->orig_request); + if (i!=0) goto g2atii_error_1;; /* ?? */ + } + /* THIS RESPONSE MUST BE SENT RELIABILY until the final ACK is received !! */ + /* this response must be stored at the upper layer!!! (it will be destroyed*/ + /* right after being sent! */ + + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, response); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + return -1; + } + ADD_ELEMENT(jc->c_dialogs, jd); + } + + eXosip_dialog_set_200ok(jd, response); + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + __eXosip_wakeup(); + return 0; + + g2atii_error_1: + osip_message_free(response); + return -1; +} + +int +eXosip_answer_invite_2xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code, char *local_sdp_port) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + char *size; + char *body = NULL; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + + if (tr==NULL || tr->orig_request==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer\n")); + return -1; + } + + if (jd!=NULL && jd->d_dialog==NULL) + { /* element previously removed */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot answer this closed transaction\n")); + return -1; + } + + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + /* WE SHOULD LOOK FOR A SDP PACKET!! */ + if(NULL != osip_list_get(tr->orig_request->bodies,0)) + { + body = generating_sdp_answer(tr->orig_request, jc->c_ctx); + if (body==NULL) + code = 488; /* bad sdp */ + } + else + { + if(local_sdp_port==NULL) + code = 488; /* session description in the request is not acceptable. */ + else + /* body is NULL (contains no SDP), generate a response to INVITE w/ no SDP */ + body = generating_no_sdp_answer(jc, jd, tr->orig_request, local_sdp_port); + } + + if (jd==NULL) + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for invite\n")); + code = 500; /* ? which code to use? */ + osip_free(body); /* not used */ + return -1; + } + + if (code==488) + { + osip_message_set_content_length(response, "0"); + /* TODO: send message to transaction layer */ + osip_free(body); + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return 0; + } + + i = osip_message_set_body(response, body, strlen(body)); + if (i!=0) { + goto g2atii_error_1; + } + size = (char *) osip_malloc(6*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(body)); +#else + sprintf(size,"%i",strlen(body)); +#endif + i = osip_message_set_content_length(response, size); + osip_free(size); + if (i!=0) goto g2atii_error_1; + i = osip_message_set_content_type(response, "application/sdp"); + if (i!=0) goto g2atii_error_1; + + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + { + i = complete_answer_that_establish_a_dialog(response, tr->orig_request); + if (i!=0) goto g2atii_error_1;; /* ?? */ + } + + osip_free(body); + /* THIS RESPONSE MUST BE SENT RELIABILY until the final ACK is received !! */ + /* this response must be stored at the upper layer!!! (it will be destroyed*/ + /* right after being sent! */ + + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, response); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + return -1; + } + ADD_ELEMENT(jc->c_dialogs, jd); + } + + eXosip_dialog_set_200ok(jd, response); + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + __eXosip_wakeup(); + return 0; + + g2atii_error_1: + osip_free(body); + osip_message_free(response); + return -1; +} + +int +eXosip_answer_invite_3456xx(eXosip_call_t *jc, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state==IST_COMPLETED + || tr->state==IST_CONFIRMED + || tr->state==IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for invite\n")); + return -1; + } + + if (300<=code<=399) + { + /* Should add contact fields */ + /* ... */ + osip_message_set_contact(response, jc->c_redirection); + } + + osip_message_set_content_length(response, "0"); + /* send message to transaction layer */ + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return 0; +} + + +void +eXosip_notify_answer_subscribe_1xx(eXosip_notify_t *jn, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_subscribe(jn, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return; + } + + if (jd==NULL) + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for subscribe\n")); + return; + } + + if (code>100) + { + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + i = complete_answer_that_establish_a_dialog(response, tr->orig_request); + + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, response); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + } + ADD_ELEMENT(jn->n_dialogs, jd); + } + } + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return ; +} + +void +eXosip_notify_answer_subscribe_2xx(eXosip_notify_t *jn, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_subscribe(jn, jd); + + if (tr==NULL || tr->orig_request==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer\n")); + return; + } + + if (jd!=NULL && jd->d_dialog==NULL) + { /* element previously removed, this is a no hop! */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot answer this closed transaction\n")); + return ; + } + + if (jd==NULL) + i = _eXosip_build_response_default(&response, NULL, code, tr->orig_request); + else + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for subscribe\n")); + code = 500; /* ? which code to use? */ + return; + } + + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + { + i = complete_answer_that_establish_a_dialog(response, tr->orig_request); + if (i!=0) goto g2atii_error_1;; /* ?? */ + } + + /* THIS RESPONSE MUST BE SENT RELIABILY until the final ACK is received !! */ + /* this response must be stored at the upper layer!!! (it will be destroyed*/ + /* right after being sent! */ + + if (jd==NULL) + { + i = eXosip_dialog_init_as_uas(&jd, tr->orig_request, response); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + return; + } + ADD_ELEMENT(jn->n_dialogs, jd); + } + + eXosip_dialog_set_200ok(jd, response); + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + return ; + + g2atii_error_1: + osip_message_free(response); + return ; +} + +void +eXosip_notify_answer_subscribe_3456xx(eXosip_notify_t *jn, eXosip_dialog_t *jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + tr = eXosip_find_last_inc_subscribe(jn, jd); + if (tr==NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return; + } + i = _eXosip_build_response_default(&response, jd->d_dialog, code, tr->orig_request); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for subscribe\n")); + return; + } + + if (300<=code<=399) + { + /* Should add contact fields */ + /* ... */ + } + + evt_answer = osip_new_outgoing_sipmessage(response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event(tr, evt_answer); + __eXosip_wakeup(); + return ; +} diff --git a/linphone/exosip/jsubscribe.c b/linphone/exosip/jsubscribe.c new file mode 100644 index 000000000..d6b9ad11b --- /dev/null +++ b/linphone/exosip/jsubscribe.c @@ -0,0 +1,231 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + + +#include "eXosip2.h" +#include + +extern eXosip_t eXosip; + +#if 0 +int eXosip_subscribe_find(int sid, eXosip_subscribe_t **js) +{ + for (*js=eXosip.j_subscribes; *js!=NULL; *js=(*js)->next) + { + if ((*js)->s_id==sid) + return 0; + } + *js = NULL; + return -1; +} +#endif + +osip_transaction_t * +eXosip_find_last_out_subscribe(eXosip_subscribe_t *js, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "SUBSCRIBE")) + break; + else out_tr = NULL; + pos++; + } + } + else + out_tr = NULL; + + if (out_tr==NULL) + return js->s_out_tr; /* can be NULL */ + + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_notify(eXosip_subscribe_t *js, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "NOTIFY")) + return out_tr; + pos++; + } + } + + return NULL; +} + + +#if 0 +void +__eXosip_subscribe_remove_dialog_reference_in_subscribe(eXosip_subscribe_t *js, eXosip_dialog_t *jd) +{ + eXosip_dialog_t *_jd; + jinfo_t *ji; + if (js==NULL) return; + if (jd==NULL) return; + + + for (_jd = js->s_dialogs; _jd!=NULL; _jd=js->s_dialogs) + { + if (jd==_jd) + break; + } + if (_jd==NULL) + { + /* dialog not found??? */ + } + + ji = osip_transaction_get_your_instance(js->s_inc_tr); + if (ji!=NULL && ji->jd==jd) + ji->jd=NULL; + ji = osip_transaction_get_your_instance(js->s_out_tr); + if (ji!=NULL && ji->jd==jd) + ji->jd=NULL; +} +#endif + +int +eXosip_subscribe_init(eXosip_subscribe_t **js, char *uri) +{ + if (uri==NULL) return -1; + *js = (eXosip_subscribe_t *)osip_malloc(sizeof(eXosip_subscribe_t)); + if (*js == NULL) return -1; + memset(*js, 0, sizeof(eXosip_subscribe_t)); + osip_strncpy((*js)->s_uri, uri, strlen(uri)); + return 0; +} + +void +eXosip_subscribe_free(eXosip_subscribe_t *js) +{ + /* ... */ + + eXosip_dialog_t *jd; + + for (jd = js->s_dialogs; jd!=NULL; jd=js->s_dialogs) + { + REMOVE_ELEMENT(js->s_dialogs, jd); + eXosip_dialog_free(jd); + } + + __eXosip_delete_jinfo(js->s_inc_tr); + __eXosip_delete_jinfo(js->s_out_tr); + if (js->s_inc_tr!=NULL) + osip_list_add(eXosip.j_transactions, js->s_inc_tr, 0); + if (js->s_out_tr!=NULL) + osip_list_add(eXosip.j_transactions, js->s_out_tr, 0); + + osip_free(js); +} + +int +_eXosip_subscribe_set_refresh_interval(eXosip_subscribe_t *js, + osip_message_t *out_subscribe) +{ + osip_header_t *exp; + int now = time(NULL); + if (js==NULL || out_subscribe==NULL) + return -1; + + osip_message_get_expires(out_subscribe, 0, &exp); + if (exp==NULL || exp->hvalue==NULL) + js->s_ss_expires = now + 600; + else + { + js->s_ss_expires = osip_atoi(exp->hvalue); + if (js->s_ss_expires!=-1) + js->s_ss_expires = now + js->s_ss_expires; + else /* on error, set it to default */ + js->s_ss_expires = now + 600; + } + + return 0; +} + +int eXosip_subscribe_need_refresh(eXosip_subscribe_t *js, int now) +{ + if (now-js->s_ss_expires>-120) + return 0; + return -1; +} + +int eXosip_subscribe_send_subscribe(eXosip_subscribe_t *js, + eXosip_dialog_t *jd, const char *expires) +{ + osip_transaction_t *transaction; + osip_message_t *subscribe; + osip_event_t *sipevent; + int i; + transaction = eXosip_find_last_out_subscribe(js, jd); + if (transaction!=NULL) + { + if (transaction->state!=NICT_TERMINATED && + transaction->state!=NIST_TERMINATED) + return -1; + } + + i = _eXosip_build_request_within_dialog(&subscribe, "SUBSCRIBE", + jd->d_dialog, "UDP"); + if (i!=0) + return -2; + + osip_message_set_expires(subscribe, expires); + + i = osip_transaction_init(&transaction, + NICT, + eXosip.j_osip, + subscribe); + if (i!=0) + { + /* TODO: release the j_call.. */ + osip_message_free(subscribe); + return -1; + } + + _eXosip_subscribe_set_refresh_interval(js, subscribe); + osip_list_add(jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(subscribe); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_add_event(transaction, sipevent); + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, jd, js, NULL)); + __eXosip_wakeup(); + return 0; +} diff --git a/linphone/exosip/jsubscribers.c b/linphone/exosip/jsubscribers.c new file mode 100644 index 000000000..a4242b43b --- /dev/null +++ b/linphone/exosip/jsubscribers.c @@ -0,0 +1,185 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include +#include + +extern eXosip_t eXosip; + +#ifndef EXOSIP_ETC_DIR +#define EXOSIP_ETC_DIR ".eXosip" +#endif + +#ifndef EXOSIP_ADDSUBSCRIBERS_SH +#define EXOSIP_ADDSUBSCRIBERS_SH "eXosip_addsubscriber.sh" +#endif + + +static int jsubscriber_init(jsubscriber_t **js, char *ch) +{ + char *next; + int i; + + *js = (jsubscriber_t *)osip_malloc(sizeof(jsubscriber_t)); + if (*js==NULL) return -1; + + i = jfriend_get_and_set_next_token(&((*js)->s_nick), ch, &next); + if (i != 0) + goto js_error1; + osip_clrspace ((*js)->s_nick); + ch = next; + + i = jfriend_get_and_set_next_token(&((*js)->s_uri), ch, &next); + if (i != 0) + goto js_error2; + osip_clrspace ((*js)->s_uri); + ch = next; + + (*js)->s_allow = osip_strdup(next); + osip_clrspace ((*js)->s_allow); + + return 0; + + js_error2: + osip_free((*js)->s_nick); + js_error1: + osip_free(*js); + *js = NULL; + return -1; +} + +void +jsubscriber_unload() +{ + jsubscriber_t *js; + if (eXosip.j_subscribers==NULL) return; + for (js=eXosip.j_subscribers; js!=NULL; js=eXosip.j_subscribers) + { + REMOVE_ELEMENT(eXosip.j_subscribers,js); + osip_free(js->s_nick); + osip_free(js->s_uri); + osip_free(js->s_allow); + osip_free(js); + } + + osip_free(eXosip.j_subscribers); + eXosip.j_subscribers=NULL; + return; +} + +int +jsubscriber_load() +{ + FILE *file; + char *s; + jsubscriber_t *js; + int pos; + char *home; + char filename[255]; + + jsubscriber_unload(); + home = getenv("HOME"); + sprintf(filename, "%s/%s/%s", home, EXOSIP_ETC_DIR, "jm_subscriber"); + + + file = fopen(filename, "r"); + if (file==NULL) return -1; + s = (char *)osip_malloc(255*sizeof(char)); + pos = 0; + while (NULL!=fgets(s, 254, file)) + { + char *tmp = s; + while (*tmp!='\0' && *tmp!=' ') tmp++; + while (*tmp!='\0' && *tmp==' ') tmp++; + while (*tmp!='\0' && *tmp!=' ') tmp++; + tmp++; /* first usefull characters */ + pos++; + + jsubscriber_init(&js, tmp); + if (js!=NULL) + { ADD_ELEMENT(eXosip.j_subscribers, js); } + } + osip_free(s); + fclose(file); + + return 0; /* ok */ +} + +void subscribers_add(char *nickname, char *uri, int black_list) +{ + char *home; + char command[256]; + char *tmp = command; + int length = 0; + if (nickname!=NULL) + length = strlen(nickname); + + if (uri==NULL) + return ; + home = getenv("HOME"); + length = length + strlen(home); + length = length + strlen(uri); + + length = length + 10; /* for black_list info */ + length = length + strlen(EXOSIP_ETC_DIR); + + length = length + strlen("/jm_subscriber"); + if (length>235) /* leave some room for SPACEs and \r\n */ + return ; + + sprintf(tmp , "%s %s/%s/jm_subscriber", EXOSIP_ADDSUBSCRIBERS_SH, home, EXOSIP_ETC_DIR); + + tmp = tmp + strlen(tmp); + if (nickname!=NULL) + sprintf(tmp , " %s", nickname); + else + sprintf(tmp , " \"\""); + + tmp = tmp + strlen(tmp); + sprintf(tmp , " %s", uri); + + tmp = tmp + strlen(tmp); + if (black_list==0) /* allowed */ + sprintf(tmp , " allow"); + else + sprintf(tmp , " reject"); + + system(command); + + jsubscriber_load(); +} + +char * +jsubscriber_get_uri(int fid) +{ + jsubscriber_t *js; + for (js = eXosip.j_subscribers; js!=NULL ; js=js->next) + { + if (fid==0) + return osip_strdup(js->s_uri); + fid--; + } + return NULL; +} diff --git a/linphone/exosip/misc.c b/linphone/exosip/misc.c new file mode 100644 index 000000000..2be6b1a45 --- /dev/null +++ b/linphone/exosip/misc.c @@ -0,0 +1,436 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + + +/* some methods to extract transaction information from a eXosip_call_t */ + +int +eXosip_remove_transaction_from_call(osip_transaction_t *tr, eXosip_call_t *jc) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + eXosip_dialog_t *jd; + int pos=0; + + if (jc->c_inc_tr==tr) + { + jc->c_inc_tr = NULL; /* can be NULL */ + return 0; + } + + for (jd=jc->c_dialogs;jd!=NULL;jd=jd->next) + { + pos=0; + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (inc_tr==tr) + { + osip_list_remove(jd->d_inc_trs, pos); + return 0; + } + pos++; + } + } + + if (jc->c_out_tr==tr) + { + jc->c_out_tr = NULL; /* can be NULL */ + return 0; + } + + for (jd=jc->c_dialogs;jd!=NULL;jd=jd->next) + { + pos=0; + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (out_tr==tr) + { + osip_list_remove(jd->d_out_trs, pos); + return 0; + } + pos++; + } + } + + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "eXosip: No information.\n")); + return -1; +} + +osip_transaction_t * +eXosip_find_last_options(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + inc_tr = eXosip_find_last_inc_options(jc, jd); + out_tr = eXosip_find_last_out_options(jc, jd); + if (inc_tr==NULL) + return out_tr; + if (out_tr==NULL) + return inc_tr; + + if (inc_tr->birth_time>out_tr->birth_time) + return inc_tr; + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_options(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "OPTIONS")) + break; + else inc_tr = NULL; + pos++; + } + } + else + inc_tr = NULL; + + if (inc_tr==NULL) + return jc->c_inc_options_tr; /* can be NULL */ + + return inc_tr; +} + +osip_transaction_t * +eXosip_find_last_out_options(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd==NULL && jc==NULL) return NULL; + + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "OPTIONS")) + break; + else out_tr = NULL; + pos++; + } + } + + if (out_tr==NULL) + return jc->c_out_options_tr; /* can be NULL */ + + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_info(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + inc_tr = eXosip_find_last_inc_info(jc, jd); + out_tr = eXosip_find_last_out_info(jc, jd); + if (inc_tr==NULL) + return out_tr; + if (out_tr==NULL) + return inc_tr; + + if (inc_tr->birth_time>out_tr->birth_time) + return inc_tr; + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_info(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "INFO")) + break; + else inc_tr = NULL; + pos++; + } + } + else + inc_tr = NULL; + + return inc_tr; +} + +osip_transaction_t * +eXosip_find_last_out_info(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd==NULL && jc==NULL) return NULL; + + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "INFO")) + break; + else out_tr = NULL; + pos++; + } + } + + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_refer(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + inc_tr = eXosip_find_last_inc_refer(jc, jd); + out_tr = eXosip_find_last_out_refer(jc, jd); + if (inc_tr==NULL) + return out_tr; + if (out_tr==NULL) + return inc_tr; + + if (inc_tr->birth_time>out_tr->birth_time) + return inc_tr; + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_invite(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + inc_tr = eXosip_find_last_inc_invite(jc, jd); + out_tr = eXosip_find_last_out_invite(jc, jd); + if (inc_tr==NULL) + return out_tr; + if (out_tr==NULL) + return inc_tr; + + if (inc_tr->birth_time>out_tr->birth_time) + return inc_tr; + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_invite(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "INVITE")) + break; + else inc_tr = NULL; + pos++; + } + } + else + inc_tr = NULL; + + if (inc_tr==NULL) + return jc->c_inc_tr; /* can be NULL */ + + return inc_tr; +} + +osip_transaction_t * +eXosip_find_last_out_invite(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd==NULL && jc==NULL) return NULL; + + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "INVITE")) + break; + else out_tr = NULL; + pos++; + } + } + + if (out_tr==NULL) + return jc->c_out_tr; /* can be NULL */ + + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_bye(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "BYE")) + return inc_tr; + pos++; + } + } + + return NULL; +} + +osip_transaction_t * +eXosip_find_last_out_bye(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "BYE")) + return out_tr; + pos++; + } + } + + return NULL; +} + +osip_transaction_t * +eXosip_find_last_inc_refer(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "REFER")) + return inc_tr; + pos++; + } + } + + return NULL; +} + +osip_transaction_t * +eXosip_find_last_out_refer(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "REFER")) + return out_tr; + pos++; + } + } + + return NULL; +} + +osip_transaction_t * +eXosip_find_last_inc_notify_for_refer(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *inc_tr; + int pos; + inc_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get(jd->d_inc_trs, pos); + if (0==strcmp(inc_tr->cseq->method, "NOTIFY")) + return inc_tr; + pos++; + } + } + + return NULL; +} + +osip_transaction_t * +eXosip_find_last_out_notify_for_refer(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *out_tr; + int pos; + out_tr = NULL; + pos=0; + if (jd!=NULL) + { + while (!osip_list_eol(jd->d_out_trs, pos)) + { + out_tr = osip_list_get(jd->d_out_trs, pos); + if (0==strcmp(out_tr->cseq->method, "NOTIFY")) + return out_tr; + pos++; + } + } + + return NULL; +} diff --git a/linphone/exosip/sdp_offans.c b/linphone/exosip/sdp_offans.c new file mode 100644 index 000000000..0abef586c --- /dev/null +++ b/linphone/exosip/sdp_offans.c @@ -0,0 +1,333 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +osip_list_t *supported_codec = NULL; + +int eXosip_sdp_accept_audio_codec(osip_negotiation_ctx_t *context, + char *port, char *number_of_port, + int audio_qty, char *payload); +int eXosip_sdp_accept_video_codec(osip_negotiation_ctx_t *context, + char *port, char *number_of_port, + int video_qty, char *payload); +int eXosip_sdp_accept_other_codec(osip_negotiation_ctx_t *context, + char *type, char *port, + char *number_of_port, char *payload); + +char *eXosip_sdp_get_audio_port(osip_negotiation_ctx_t *context, int pos_media); + +int eXosip_sdp_accept_audio_codec(osip_negotiation_ctx_t *context, + char *port, char *number_of_port, + int audio_qty, char *payload) +{ + int pos; + for (pos=0;!osip_list_eol(supported_codec, pos);pos++) + { + char *_payload; + _payload = osip_list_get(supported_codec, pos); + if (0==strcmp(payload,_payload)) + { + /* + We have to look at the rtpmap attributes in context->remote + to check if we support this stuff. + */ + + return 0; + } + } + return -1; +} + +int eXosip_sdp_accept_video_codec(osip_negotiation_ctx_t *context, + char *port, char *number_of_port, + int video_qty, char *payload) +{ + return -1; +} + +int eXosip_sdp_accept_other_codec(osip_negotiation_ctx_t *context, + char *type, char *port, + char *number_of_port, char *payload) +{ + /* ... */ + return -1; +} + +char *eXosip_sdp_get_audio_port(osip_negotiation_ctx_t *context, int pos_media) +{ + eXosip_call_t *jc = (eXosip_call_t*)osip_negotiation_ctx_get_mycontext(context); + if (jc==NULL) + return osip_strdup("10500"); + else if (jc->c_sdp_port[0]=='\0') + return osip_strdup("10500"); + else return osip_strdup(jc->c_sdp_port); +} + +int eXosip_sdp_negotiation_replace(osip_negotiation_t *sn) +{ + if (eXosip.osip_negotiation!=NULL) + osip_negotiation_free(eXosip.osip_negotiation); + eXosip.osip_negotiation = sn; + return 0; +} + +void +eXosip_sdp_negotiation_ctx_set_mycontext(struct eXosip_call_t *jc, void *arg) +{ + osip_negotiation_ctx_set_mycontext(jc->c_ctx, arg); +} + +void eXosip_sdp_negotiation_remove_audio_payloads() +{ + if (supported_codec==NULL) + return; + for (;!osip_list_eol(supported_codec, 0);) + { + char *p; + p = (char *) osip_list_get(supported_codec, 0); + osip_free(p); + osip_list_remove(supported_codec, 0); + } + osip_negotiation_remove_audio_payloads(eXosip.osip_negotiation); +} + +void eXosip_sdp_negotiation_add_codec(char *payload, char *number_of_port, + char *proto, char *c_nettype, + char *c_addrtype, char *c_addr, + char *c_addr_multicast_ttl, + char *c_addr_multicast_int, + char *a_rtpmap) +{ + osip_negotiation_add_support_for_audio_codec(eXosip.osip_negotiation, + payload, + number_of_port, + proto, + c_nettype, + c_addrtype, + c_addr, + c_addr_multicast_ttl, + c_addr_multicast_int, + a_rtpmap); + osip_list_add(supported_codec, osip_strdup(payload), -1); +} + +int eXosip_sdp_negotiation_init(osip_negotiation_t **sn) +{ + int i = osip_negotiation_init(sn); + if (i!=0) { + return -1; + } + if (supported_codec==NULL) + { + supported_codec = (osip_list_t*) osip_malloc(sizeof(osip_list_t)); + osip_list_init(supported_codec); + } + osip_negotiation_set_o_username(*sn, osip_strdup("userX")); + osip_negotiation_set_o_session_id(*sn, osip_strdup("20000001")); + osip_negotiation_set_o_session_version(*sn, osip_strdup("20000001")); + osip_negotiation_set_o_nettype(*sn, osip_strdup("IN")); + osip_negotiation_set_o_addrtype(*sn, osip_strdup("IP4")); + osip_negotiation_set_o_addr(*sn, osip_strdup(eXosip.localip)); + + osip_negotiation_set_c_nettype(*sn, osip_strdup("IN")); + osip_negotiation_set_c_addrtype(*sn, osip_strdup("IP4")); + osip_negotiation_set_c_addr(*sn, osip_strdup(eXosip.localip)); + + /* ALL CODEC MUST SHARE THE SAME "C=" line and proto as the media + will appear on the same "m" line... */ + + osip_negotiation_set_fcn_accept_audio_codec(*sn, &eXosip_sdp_accept_audio_codec); + osip_negotiation_set_fcn_accept_video_codec(*sn, &eXosip_sdp_accept_video_codec); + + osip_negotiation_set_fcn_accept_other_codec(*sn, &eXosip_sdp_accept_other_codec); + osip_negotiation_set_fcn_get_audio_port(*sn, &eXosip_sdp_get_audio_port); + + return 0; +} + +void eXosip_sdp_negotiation_free(osip_negotiation_t *sn) +{ + if (sn==NULL) + return; + osip_list_ofchar_free(supported_codec); + supported_codec = NULL; + osip_negotiation_free(sn); +} + +sdp_message_t * +eXosip_get_local_sdp_info(osip_transaction_t *invite_tr) +{ + osip_content_type_t *ctt; + osip_mime_version_t *mv; + osip_message_t *message; + sdp_message_t *sdp; + osip_body_t *oldbody; + int pos; + + if (invite_tr->ctx_type == IST) + message = invite_tr->last_response; + else if (invite_tr->ctx_type == ICT) + message = invite_tr->orig_request; + else return NULL; /* BUG -> NOT AN INVITE TRANSACTION!! */ + + if (message==NULL) return NULL; + + /* get content-type info */ + ctt = osip_message_get_content_type(message); + mv = osip_message_get_mime_version(message); + if (mv==NULL && ctt==NULL) + return NULL; /* previous message was not correct or empty */ + if (mv!=NULL) + { + /* look for the SDP body */ + /* ... */ + } + else if (ctt!=NULL) + { + if (ctt->type==NULL || ctt->subtype==NULL) + /* it can be application/sdp or mime... */ + return NULL; + if (osip_strcasecmp(ctt->type, "application")!=0 || + osip_strcasecmp(ctt->subtype, "sdp")!=0 ) + { return NULL; } + } + + pos=0; + while (!osip_list_eol(message->bodies, pos)) + { + int i; + oldbody = (osip_body_t *) osip_list_get(message->bodies, pos); + pos++; + sdp_message_init(&sdp); + i = sdp_message_parse(sdp,oldbody->body); + if (i==0) return sdp; + sdp_message_free(sdp); + sdp = NULL; + } + return NULL; +} + +sdp_message_t * +eXosip_get_remote_sdp_info(osip_transaction_t *invite_tr) +{ + osip_content_type_t *ctt; + osip_mime_version_t *mv; + osip_message_t *message; + sdp_message_t *sdp; + osip_body_t *oldbody; + int pos; + + if (invite_tr->ctx_type == IST) + message = invite_tr->orig_request; + else if (invite_tr->ctx_type == ICT) + message = invite_tr->last_response; + else return NULL; /* BUG -> NOT AN INVITE TRANSACTION!! */ + + if (message==NULL) return NULL; + + /* get content-type info */ + ctt = osip_message_get_content_type(message); + mv = osip_message_get_mime_version(message); + if (mv==NULL && ctt==NULL) + return NULL; /* previous message was not correct or empty */ + if (mv!=NULL) + { + /* look for the SDP body */ + /* ... */ + } + else if (ctt!=NULL) + { + if (ctt->type==NULL || ctt->subtype==NULL) + /* it can be application/sdp or mime... */ + return NULL; + if (osip_strcasecmp(ctt->type, "application")!=0 || + osip_strcasecmp(ctt->subtype, "sdp")!=0 ) + { return NULL; } + } + + pos=0; + while (!osip_list_eol(message->bodies, pos)) + { + int i; + oldbody = (osip_body_t *) osip_list_get(message->bodies, pos); + pos++; + sdp_message_init(&sdp); + i = sdp_message_parse(sdp,oldbody->body); + if (i==0) return sdp; + sdp_message_free(sdp); + sdp = NULL; + } + return NULL; +} + +int eXosip_retrieve_sdp_negotiation_result(osip_negotiation_ctx_t *ctx, char *payload_name, int pnsize) +{ + sdp_message_t *local_sdp = 0; + int payload_result = -1; + + if (!ctx) + return payload_result; + + local_sdp = osip_negotiation_ctx_get_local_sdp(ctx); + + if (local_sdp != NULL) + { + sdp_media_t *med = (sdp_media_t*) osip_list_get(local_sdp->m_medias, 0); + char *payload = (char *) osip_list_get (med->m_payloads, 0); + int pos_attr; + + if (payload!=NULL) + { + payload_result = osip_atoi(payload); + + /* copy payload name! */ + for (pos_attr=0; + !osip_list_eol(med->a_attributes, pos_attr); + pos_attr++) + { + sdp_attribute_t *attr; + attr = (sdp_attribute_t *)osip_list_get(med->a_attributes, pos_attr); + if (0==osip_strncasecmp(attr->a_att_field, "rtpmap", 6)) + { + if ((payload_result <10 && + 0==osip_strncasecmp(attr->a_att_value, payload, 1)) + ||(payload_result>9 && payload_result<100 && + 0==osip_strncasecmp(attr->a_att_value, payload, 2)) + ||(payload_result >100 && payload_result<128 && + 0==osip_strncasecmp(attr->a_att_value, payload, 3))) + { + snprintf(payload_name, pnsize, "%s", attr->a_att_value); + return payload_result; + } + } + } + } + } + + return payload_result; + +} diff --git a/linphone/exosip/udp.c b/linphone/exosip/udp.c new file mode 100644 index 000000000..e192c2646 --- /dev/null +++ b/linphone/exosip/udp.c @@ -0,0 +1,2635 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include +#endif + +#include "eXosip2.h" +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#ifdef __APPLE_CC__ +#include +#endif +#else +#include +#include +#endif + +extern eXosip_t eXosip; + +/* Private functions */ +static void eXosip_send_default_answer(eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, + int status, + char *reason_phrase, + char *warning, + int line); +static void eXosip_process_info(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt); +static void eXosip_process_options(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt); +static void eXosip_process_bye(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt); +static void eXosip_process_refer(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt); +static void eXosip_process_ack(eXosip_call_t *jc, eXosip_dialog_t *jd, osip_event_t *evt); +static int cancel_match_invite(osip_transaction_t *invite, osip_message_t *cancel); +static void eXosip_process_cancel(osip_transaction_t *transaction, osip_event_t *evt); +static osip_event_t *eXosip_process_reinvite(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, sdp_message_t *remote_sdp); +static void eXosip_process_invite_on_hold(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, sdp_message_t *sdp); +static void eXosip_process_invite_off_hold(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, sdp_message_t *sdp); +static void eXosip_process_new_options(osip_transaction_t *transaction, osip_event_t *evt); +static void eXosip_process_new_invite(osip_transaction_t *transaction, osip_event_t *evt); +static void eXosip_process_invite_within_call(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt); +static int eXosip_event_package_is_supported(osip_transaction_t *transaction, + osip_event_t *evt); +static void eXosip_process_new_subscribe(osip_transaction_t *transaction, + osip_event_t *evt); +static void eXosip_process_subscribe_within_call(eXosip_notify_t *jn, + eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt); +static void eXosip_process_notify_within_dialog(eXosip_subscribe_t *js, + eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt); +static int eXosip_match_notify_for_subscribe(eXosip_subscribe_t *js, osip_message_t *notify); +static void eXosip_process_newrequest(osip_event_t *evt); +static void eXosip_process_response_out_of_transaction(osip_event_t *evt); +static int eXosip_pendingosip_transaction_exist(eXosip_call_t *jc, eXosip_dialog_t *jd); +static int eXosip_release_finished_calls(eXosip_call_t *jc, eXosip_dialog_t *jd); +static int eXosip_release_aborted_calls(eXosip_call_t *jc, eXosip_dialog_t *jd); + + +static void eXosip_send_default_answer(eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, + int status, + char *reason_phrase, + char *warning, + int line) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + /* osip_list_add(eXosip.j_transactions, transaction, 0); */ + osip_transaction_set_your_instance(transaction, NULL); + + /* THIS METHOD DOES NOT ACCEPT STATUS CODE BETWEEN 101 and 299 */ + if (status>100 && status<299 && MSG_IS_INVITE(evt->sip)) + return ; + + if (jd!=NULL) + i = _eXosip_build_response_default(&answer, jd->d_dialog, status, evt->sip); + else + i = _eXosip_build_response_default(&answer, NULL, status, evt->sip); + + if (i!=0 || answer==NULL) + { + return ; + } + + if (reason_phrase!=NULL) + { + char *_reason; + _reason = osip_message_get_reason_phrase(answer); + if (_reason!=NULL) + osip_free(_reason); + _reason = osip_strdup(reason_phrase); + osip_message_set_reason_phrase(answer, _reason); + } + + osip_message_set_content_length(answer, "0"); + + if (status==500) + osip_message_set_retry_after(answer, "10"); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); + +} + +static void +__eXosip_report_event(int evt, eXosip_call_t *jc, eXosip_dialog_t *jd, eXosip_event_t *je ) +{ + if (!je) + je = eXosip_event_init_for_call(evt, jc, jd); + + if (eXosip.j_call_callbacks[evt]!=NULL) + eXosip.j_call_callbacks[evt](evt, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); +} + + +static void eXosip_process_options(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + osip_transaction_set_your_instance(transaction, + __eXosip_new_jinfo(jc, + NULL /*jd */, + NULL, + NULL)); + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + return ; + } + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add(jd->d_inc_trs, transaction , 0); + + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); +} + +static void eXosip_process_info(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + osip_transaction_set_your_instance(transaction, + __eXosip_new_jinfo(jc, + jd, + NULL, + NULL)); + /* for now, send default response of 200ok. eventually, application should + be deciding how to answer INFO messages */ + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + return ; + } + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add(jd->d_inc_trs, transaction , 0); + + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); +} + + +static void eXosip_process_bye(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + osip_transaction_set_your_instance(transaction, + __eXosip_new_jinfo(jc, + NULL /*jd */, + NULL, + NULL)); + + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + return ; + } + osip_message_set_content_length(answer, "0"); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add(jd->d_inc_trs, transaction , 0); + + /* Release the eXosip_dialog */ + osip_dialog_free(jd->d_dialog); + jd->d_dialog = NULL; + __eXosip_report_event(EXOSIP_CALL_CLOSED, jc, jd, NULL); + + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); +} + +static void eXosip_process_refer(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + osip_header_t *referto_head = NULL; + osip_contact_t *referto; + int i; + + /* check if the refer is valid */ + osip_message_header_get_byname(evt->sip, "refer-to", 0, &referto_head); + if (referto_head==NULL || referto_head->hvalue==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, "Missing Refer-To header", "Missing Refer-To header", __LINE__); + return; + } + /* check if refer-to is well-formed */ + osip_contact_init(&referto); + i = osip_contact_parse(referto, referto_head->hvalue); + if (i!=0) + { + osip_contact_free(referto); + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, "Non valid Refer-To header", "Non valid Refer-To header", __LINE__); + return; + } + if (0!=osip_strcasecmp(referto->url->scheme, "sip")) + { + osip_contact_free(referto); + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 501, "Scheme Not Implemented", "Scheme Not Implemented", __LINE__); + return; + } + + osip_contact_free(referto); + + /* check policy so we can decline immediatly the refer */ + + osip_transaction_set_your_instance(transaction, + __eXosip_new_jinfo(jc, + jd, + NULL, + NULL)); + + i = _eXosip_build_response_default(&answer, jd->d_dialog, 202, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + return ; + } + + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add(jd->d_inc_trs, transaction , 0); + + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); + + _eXosip_transfer_send_notify(jc, jd, EXOSIP_SUBCRSTATE_ACTIVE, "SIP/2.0 100 Trying"); +} + +static void eXosip_process_notify_for_refer(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + osip_transaction_t *ref; + osip_header_t *event_hdr; + osip_header_t *sub_state; + osip_content_type_t *ctype; + osip_body_t *body = NULL; + + /* get the event type and return "489 Bad Event". */ + osip_message_header_get_byname(evt->sip, "event", 0, &event_hdr); + if (event_hdr==NULL || event_hdr->hvalue==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 481, "Missing Event header in Notify", "Missing Event header in Notify", __LINE__); + return ; + } + if (0!=osip_strcasecmp(event_hdr->hvalue, "refer")) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 501, "Unsupported Event header", "Unsupported Event header in Notify", __LINE__); + return ; + } + osip_message_header_get_byname(evt->sip, "subscription-state", + 0, + &sub_state); + if (sub_state==NULL||sub_state->hvalue==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, NULL, NULL, __LINE__); + return; + } + + ctype = osip_message_get_content_type(evt->sip); + if (ctype==NULL || ctype->type==NULL || ctype->subtype==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, "Missing Header", "Missing Content-Type Header", __LINE__); + return ; + } + if (0!=osip_strcasecmp(ctype->type, "message") + || 0!=osip_strcasecmp(ctype->subtype, "sipfrag")) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 501, "Unsupported body type", "Unsupported body type", __LINE__); + return ; + } + + osip_message_get_body(evt->sip, 0, &body); + if (body==NULL || body->body==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, "Missing Body", "Missing Body", __LINE__); + return ; + } + + + { + eXosip_event_t *je; + int len; + je = eXosip_event_init_for_call(EXOSIP_CALL_REFER_STATUS, jc, jd); + if (je==NULL) return; + + len = strlen(body->body); + if (len<999) + osip_strncpy(je->sdp_body, body->body, len); + else + osip_strncpy(je->sdp_body, body->body, 999); + + __eXosip_report_event(EXOSIP_CALL_REFER_STATUS, NULL, NULL, je); + } + + /* check if a refer was sent previously! */ + ref = eXosip_find_last_out_refer(jc, jd); + if (ref==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 481, NULL, "Not associated refer", __LINE__); + return ; + } + + osip_transaction_set_your_instance(transaction, + __eXosip_new_jinfo(jc, + jd, + NULL, + NULL)); + /* for now, send default response of 200ok. eventually, application should + be deciding how to answer INFO messages */ + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + return ; + } + + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add(jd->d_inc_trs, transaction , 0); + + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); +} + +static void eXosip_process_ack(eXosip_call_t *jc, eXosip_dialog_t *jd, osip_event_t *evt) +{ + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_ACK, jc, jd); + if (je==NULL) return; + + /* MBW - for SDP in ACK used in alternate SDP offer-response model */ + eXosip_event_add_sdp_info(je, evt->sip); + __eXosip_report_event(EXOSIP_CALL_ACK, NULL, NULL, je); + + osip_event_free(evt); +} + +static int cancel_match_invite(osip_transaction_t *invite, osip_message_t *cancel) +{ + osip_generic_param_t *br; + osip_generic_param_t *br2; + osip_via_t *via; + osip_via_param_get_byname (invite->topvia, "branch", &br); + via = osip_list_get(cancel->vias, 0); + if (via==NULL) return -1; /* request without via??? */ + osip_via_param_get_byname (via, "branch", &br2); + if (br!=NULL && br2==NULL) + return -1; + if (br2!=NULL && br==NULL) + return -1; + if (br2!=NULL && br!=NULL) /* compliant UA :) */ + { + if (br->gvalue!=NULL && br2->gvalue!=NULL && + 0==strcmp(br->gvalue, br2->gvalue)) + return 0; + return -1; + } + /* old backward compatibility mechanism */ + if (0 != osip_call_id_match (invite->callid, cancel->call_id)) + return -1; + if (0 != osip_to_tag_match (invite->to, cancel->to)) + return -1; + if (0 != osip_from_tag_match (invite->from, cancel->from)) + return -1; + if (0 != osip_cseq_match (invite->cseq, cancel->cseq)) + return -1; + if (0 != osip_via_match (invite->topvia, via)) + return -1; + return 0; +} + +static void eXosip_process_cancel(osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_transaction_t *tr; + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + eXosip_call_t *jc; + eXosip_dialog_t *jd; + + tr = NULL; + jd = NULL; + /* first, look for a Dialog in the map of element */ + for (jc = eXosip.j_calls; jc!= NULL ; jc=jc->next) + { + if (jc->c_inc_tr!=NULL) + { + i = cancel_match_invite(jc->c_inc_tr, evt->sip); + if (i==0) { + tr = jc->c_inc_tr; + break; + } + } + tr=NULL; + for (jd = jc->c_dialogs; jd!= NULL ; jd=jd->next) + { + int pos=0; + while (!osip_list_eol(jd->d_inc_trs, pos)) + { + tr = osip_list_get(jd->d_inc_trs, pos); + i = cancel_match_invite(tr, evt->sip); + if (i==0) + break; + tr = NULL; + pos++; + } + } + if (jd!=NULL) break; /* tr has just been found! */ + } + + if (tr==NULL) /* we didn't found the transaction to cancel */ + { + i = _eXosip_build_response_default(&answer, NULL, 481, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add(eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance(tr, NULL); + return ; + } + osip_message_set_content_length(answer, "0"); + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction,evt_answer); + + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + __eXosip_wakeup(); + return; + } + + if (tr->state==IST_TERMINATED || tr->state==IST_CONFIRMED + || tr->state==IST_COMPLETED) + { + /* I can't find the status code in the rfc? + (I read I must answer 200? wich I found strange) + I probably misunderstood it... and prefer to send 481 + as the transaction has been answered. */ + if (jd==NULL) + i = _eXosip_build_response_default(&answer, NULL, 481, evt->sip); + else + i = _eXosip_build_response_default(&answer, jd->d_dialog, 481, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add(eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance(tr, NULL); + return ; + } + osip_message_set_content_length(answer, "0"); + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction,evt_answer); + + if (jd!=NULL) + osip_list_add(jd->d_inc_trs, transaction , 0); + else + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + __eXosip_wakeup(); + + return ; + } + + { + if (jd==NULL) + i = _eXosip_build_response_default(&answer, NULL, 200, evt->sip); + else + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add(eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance(tr, NULL); + return ; + } + osip_message_set_content_length(answer, "0"); + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); + + if (jd!=NULL) + osip_list_add(jd->d_inc_trs, transaction , 0); + else + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + + /* answer transaction to cancel */ + if (jd==NULL) + i = _eXosip_build_response_default(&answer, NULL, 487, + tr->orig_request); + else + i = _eXosip_build_response_default(&answer, jd->d_dialog, 487, + tr->orig_request); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add(eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance(tr, NULL); + return ; + } + osip_message_set_content_length(answer, "0"); + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = tr->transactionid; + osip_transaction_add_event(tr,evt_answer); + __eXosip_wakeup(); + } +} + +static osip_event_t * +eXosip_process_reinvite(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, sdp_message_t *remote_sdp) +{ + sdp_message_t *local_sdp; + osip_message_t *answer; + osip_event_t *sipevent; + int i; + + /* We must negociate... */ + local_sdp = NULL; + if (remote_sdp!=NULL) { + sdp_message_t *old_remote_sdp = osip_negotiation_ctx_get_remote_sdp(jc->c_ctx); + if (old_remote_sdp!=NULL) + { + sdp_message_free(old_remote_sdp); + } + osip_negotiation_ctx_set_remote_sdp(jc->c_ctx, remote_sdp); + local_sdp = osip_negotiation_ctx_get_local_sdp(jc->c_ctx); + if (local_sdp!=NULL) + { + sdp_message_free(local_sdp); + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, NULL); + } + local_sdp = NULL; + i = osip_negotiation_ctx_execute_negotiation(eXosip.osip_negotiation, jc->c_ctx); + + if (i!=200) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, i, NULL, NULL, 0); + return NULL; + } + local_sdp = osip_negotiation_ctx_get_local_sdp(jc->c_ctx); + } + +#if 0 + if (remote_sdp==NULL) + { + sdp_message_t *local_sdp; + osip_negotiation_sdp_build_offer(eXosip.osip_negotiation, NULL, &local_sdp, "25563", NULL); + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, local_sdp); + + if (local_sdp==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, NULL, NULL, __LINE__); + return NULL; + } + } +#endif + + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SIP Error", "Failed to build Answer for INVITE within call", __LINE__); + return NULL; + } + + complete_answer_that_establish_a_dialog(answer, evt->sip); + + if (local_sdp!=NULL) + { + char *local_body; + char *size; + + osip_negotiation_ctx_set_local_sdp(jc->c_ctx, NULL); + i = sdp_message_to_str(local_sdp, &local_body); + sdp_message_free(local_sdp); + if (i!=0) { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SDP Error", "SDP packet is corrupted", __LINE__); + osip_message_free(answer); + return NULL; + } + i = osip_message_set_body(answer, local_body, strlen(local_body)); + if (i!=0) { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SDP Error", "SDP cannot be added in message", __LINE__); + osip_free(local_body); + osip_message_free(answer); + return NULL; + } + size = (char *) osip_malloc(6*sizeof(char)); +#ifdef __APPLE_CC__ + sprintf(size,"%li",strlen(local_body)); +#else + sprintf(size,"%i",strlen(local_body)); +#endif + osip_free(local_body); + osip_message_set_content_length(answer, size); + osip_free(size); + i = osip_message_set_content_type(answer, "application/sdp"); + if (i!=0) { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SIP Error", "Content-Type cannot be added in message", __LINE__); + osip_message_free(answer); + return NULL; + } + + } + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + sipevent = osip_new_outgoing_sipmessage(answer); + sipevent->transactionid = transaction->transactionid; + + osip_list_add(jd->d_inc_trs, transaction, 0); + return sipevent; +} + + +static void eXosip_process_invite_on_hold(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, sdp_message_t *sdp) +{ + osip_event_t *sipevent; + sipevent = eXosip_process_reinvite(jc, jd, transaction, evt, sdp); + if (sipevent==NULL) + return; /* ERROR */ + { + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_HOLD, jc, jd); + eXosip_event_add_status(je, sipevent->sip); + eXosip_event_add_sdp_info(je, evt->sip); + __eXosip_report_event(EXOSIP_CALL_HOLD, NULL, NULL, je); + } + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); +} + +static void eXosip_process_invite_off_hold(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt, sdp_message_t *sdp) +{ + osip_event_t *sipevent; + sipevent = eXosip_process_reinvite(jc, jd, transaction, evt, sdp); + if (sipevent==NULL) + return; /* ERROR */ + { + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_OFFHOLD, jc, jd); + eXosip_event_add_status(je, sipevent->sip); + eXosip_event_add_sdp_info(je, evt->sip); + __eXosip_report_event(EXOSIP_CALL_OFFHOLD, NULL, NULL, je); + } + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); +} + +static void eXosip_process_new_options(osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + i = _eXosip_build_response_default(&answer, NULL, 200, evt->sip); + if (i!=0) + { + return ; + } + + osip_list_add(eXosip.j_transactions, transaction, 0); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_transaction_add_event(transaction,evt_answer); + __eXosip_wakeup(); +} + +static void eXosip_process_new_invite(osip_transaction_t *transaction, osip_event_t *evt) +{ + osip_event_t *evt_answer; + int i; + eXosip_call_t *jc; + eXosip_dialog_t *jd; + osip_message_t *answer; + + eXosip_call_init(&jc); + /* eXosip_call_set_subect... */ + + ADD_ELEMENT(eXosip.j_calls, jc); + + i = _eXosip_build_response_default(&answer, NULL, 101, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog.")); + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for invite\n")); + return; + } + osip_message_set_content_length(answer, "0"); + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot complete answer!\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + osip_message_free(answer); + return ; + } + + i = eXosip_dialog_init_as_uas(&jd, evt->sip, answer); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + osip_message_free(answer); + return ; + } + ADD_ELEMENT(jc->c_dialogs, jd); + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(jc, jd, NULL, NULL)); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; +#ifdef AUTO_RING /* default is now to not send a 180 Ringing */ + osip_transaction_add_event(transaction, evt_answer); + __eXosip_wakeup(); +#endif + +#ifdef AUTO_RING /* default is now to not send a 180 Ringing */ + i = _eXosip_build_response_default(&answer, jd->d_dialog, 180, evt->sip); + + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send ringback.")); + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for invite\n")); + return; + } + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot complete answer!\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance(transaction, NULL); + osip_message_free(answer); + return ; + } + + osip_message_set_content_length(answer, "0"); + /* send message to transaction layer */ + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; +#endif + + eXosip_update(); + jc->c_inc_tr = transaction; + osip_transaction_add_event(transaction, evt_answer); + + /* be sure the invite will be processed + before any API call on this dialog*/ + osip_ist_execute(eXosip.j_osip); + + if (transaction->orig_request!=NULL) + { + eXosip_event_t *je; + je = eXosip_event_init_for_call(EXOSIP_CALL_NEW, jc, jd); + if (je!=NULL) + { + osip_header_t *subject; + char *tmp; + osip_message_get_subject(transaction->orig_request, 0, &subject); + if (subject!=NULL && subject->hvalue!=NULL && subject->hvalue[0]!='\0') + snprintf(je->subject, 255, "%s", subject->hvalue); + osip_uri_to_str(transaction->orig_request->req_uri, &tmp); + if (tmp!=NULL) + { + snprintf(je->req_uri, 255, "%s", tmp); + osip_free(tmp); + } + eXosip_event_add_sdp_info(je, transaction->orig_request); + eXosip_event_add_status(je, answer); + } + __eXosip_report_event(EXOSIP_CALL_NEW, NULL, NULL, je); + } + + __eXosip_wakeup(); + +} + +static void eXosip_process_invite_within_call(eXosip_call_t *jc, eXosip_dialog_t *jd, + osip_transaction_t *transaction, osip_event_t *evt) +{ + sdp_message_t *sdp; + int i; + int pos; + int pos_media; + char *sndrcv; + char *ipaddr; + + /* Is this a "on hold" message? */ + sdp = NULL; + pos = 0; + i = 500; + while (!osip_list_eol(evt->sip->bodies,pos)) + { + osip_body_t *body; + body = (osip_body_t *)osip_list_get(evt->sip->bodies,pos); + pos++; + + i = sdp_message_init(&sdp); + if (i!=0) break; + + /* WE ASSUME IT IS A SDP BODY AND THAT */ + /* IT IS THE ONLY ONE, OF COURSE, THIS IS */ + /* NOT TRUE */ + if (body->body!=NULL) + { + i = sdp_message_parse(sdp,body->body); + if (i==0) { + i = 200; + break; + } + } + sdp_message_free(sdp); + sdp = NULL; + } + + if (pos!=0 && i!=200) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, NULL, NULL, __LINE__); + return; + } + + /* TODO: we should verify the content-type */ + if (pos!=0) + { + pos_media=-1; + pos = 0; + ipaddr = NULL; + while (!sdp_message_endof_media(sdp, pos_media)) + { + ipaddr = sdp_message_c_addr_get(sdp, pos_media, pos); + while (ipaddr!=NULL) /* only one is allowed here? */ + { + if (pos==1 && pos_media==-1) + break; + if (0==osip_strcasecmp("0.0.0.0", ipaddr)) + break; + pos++; + ipaddr = sdp_message_c_addr_get(sdp, pos_media, pos); + } + if (pos==1 && pos_media==-1) + ipaddr=NULL; + if (ipaddr!=NULL) + break; + pos = 0; + pos_media++; + } + + if (ipaddr==NULL) + { + sndrcv = NULL; + pos_media=-1; + pos = 0; + while (!sdp_message_endof_media(sdp, pos_media)) + { + sndrcv = sdp_message_a_att_field_get(sdp, pos_media, pos); + while (sndrcv!=NULL) + { + if (0==osip_strcasecmp("inactive", sndrcv) || 0==osip_strcasecmp("sendonly", sndrcv)) + break; + pos++; + sndrcv = sdp_message_a_att_field_get(sdp, pos_media, pos); + } + if (sndrcv!=NULL) + break; + pos = 0; + pos_media++; + } + } + + if (ipaddr!=NULL || (sndrcv!=NULL && (0==osip_strcasecmp("inactive", sndrcv) + || 0==osip_strcasecmp("sendonly", sndrcv)))) + { + /* We received an INVITE to put on hold the other party. */ + eXosip_process_invite_on_hold(jc, jd, transaction, evt, sdp); + return; + } + else + { + /* This is a call modification, probably for taking it of hold */ + eXosip_process_invite_off_hold(jc, jd, transaction, evt, sdp); + return; + } + } + eXosip_process_invite_off_hold(jc, jd, transaction, evt, NULL); + return; +} + +static int eXosip_event_package_is_supported(osip_transaction_t *transaction, + osip_event_t *evt) +{ + osip_header_t *event_hdr; + int code; + + /* get the event type and return "489 Bad Event". */ + osip_message_header_get_byname(evt->sip, "event", 0, &event_hdr); + if (event_hdr==NULL || event_hdr->hvalue==NULL) + { +#ifdef SUPPORT_MSN + /* msn don't show any event header */ + code = 200; /* Bad Request... anyway... */ +#else + code = 400; /* Bad Request */ +#endif + } + else if (0!=osip_strcasecmp(event_hdr->hvalue, "presence")) + code = 489; + else code = 200; + if (code!=200) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(NULL, transaction, evt, code, NULL, NULL, __LINE__); + return 0; + } + return -1; +} + +static void eXosip_process_new_subscribe(osip_transaction_t *transaction, + osip_event_t *evt) +{ + osip_event_t *evt_answer; + eXosip_notify_t *jn; + eXosip_dialog_t *jd; + osip_message_t *answer; + int code; + int i; + + eXosip_notify_init(&jn, evt->sip); + _eXosip_notify_set_refresh_interval(jn, evt->sip); + + i = _eXosip_build_response_default(&answer, NULL, 101, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog.")); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not create response for invite\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_notify_free(jn); + return; + } + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + if (i!=0) + { + osip_message_free(answer); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot complete answer!\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_notify_free(jn); + return ; + } + + i = eXosip_dialog_init_as_uas(&jd, evt->sip, answer); + if (i!=0) + { + osip_message_free(answer); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_notify_free(jn); + return ; + } + ADD_ELEMENT(jn->n_dialogs, jd); + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, jd, NULL, jn)); + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction, evt_answer); + + ADD_ELEMENT(eXosip.j_notifies, jn); + __eXosip_wakeup(); + + /* There should be a list of already accepted freinds for which we + have already accepted the subscription. */ + if (0==_eXosip_notify_is_a_known_subscriber(evt->sip)) + code = 200; + else + code = 202; + + i = _eXosip_build_response_default(&answer, jd->d_dialog, code, evt->sip); + if (i!=0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"ERROR: Could not create response for subscribe\n")); + osip_list_add(eXosip.j_transactions, transaction, 0); + return; + } + + _eXosip_notify_add_expires_in_2XX_for_subscribe(jn, answer); + + { + + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + osip_message_free(answer); + return; + } + } + + jn->n_inc_tr = transaction; + + /* eXosip_dialog_set_200ok(jd, answer); */ + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_transaction_add_event(transaction, evt_answer); + + osip_dialog_set_state(jd->d_dialog, DIALOG_CONFIRMED); + + eXosip_update(); + __eXosip_wakeup(); +} + +static void eXosip_process_subscribe_within_call(eXosip_notify_t *jn, + eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt) +{ + osip_message_t *answer; + osip_event_t *sipevent; + int i; + + _eXosip_notify_set_refresh_interval(jn, evt->sip); + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SIP Error", "Failed to build Answer for SUBSCRIBE", __LINE__); + return ; + } + + _eXosip_notify_add_expires_in_2XX_for_subscribe(jn, answer); + + { + + i = complete_answer_that_establish_a_dialog(answer, evt->sip); + if (i!=0) + { + /* this info is yet known by the remote UA, + so we don't have to exit here */ + } + } + + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, jd, NULL, jn)); + sipevent = osip_new_outgoing_sipmessage(answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction, sipevent); + __eXosip_wakeup(); + + /* if subscribe request contains expires="0", close the subscription */ + { + int now = time(NULL); + if (jn->n_ss_expires-now<=0) + { + jn->n_ss_status=EXOSIP_SUBCRSTATE_TERMINATED; + jn->n_ss_reason=TIMEOUT; + } + } + + osip_list_add(jd->d_inc_trs, transaction, 0); + + eXosip_notify_send_notify(jn, jd, jn->n_ss_status, + jn->n_online_status); + return; +} + +static void +eXosip_process_notify_within_dialog(eXosip_subscribe_t *js, + eXosip_dialog_t *jd, + osip_transaction_t *transaction, + osip_event_t *evt) +{ + osip_message_t *answer; + osip_event_t *sipevent; + osip_header_t *sub_state; +#ifdef SUPPORT_MSN + osip_header_t *expires; +#endif + int i; + + if (jd==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SIP Error", "No dialog for this NOTIFY", __LINE__); + return ; + } + + /* if subscription-state has a reason state set to terminated, + we close the dialog */ +#ifndef SUPPORT_MSN + osip_message_header_get_byname(evt->sip, "subscription-state", + 0, + &sub_state); + if (sub_state==NULL||sub_state->hvalue==NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 400, NULL, NULL, __LINE__); + return; + } +#endif + + i = _eXosip_build_response_default(&answer, jd->d_dialog, 200, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Internal SIP Error", "Failed to build Answer for NOTIFY", __LINE__); + return ; + } + +#ifdef SUPPORT_MSN + osip_message_header_get_byname(evt->sip, "expires", + 0, + &expires); + if (expires!=NULL&&expires->hvalue!=NULL + && 0==osip_strcasecmp(expires->hvalue, "0")) + { + /* delete the dialog! */ + js->s_ss_status = EXOSIP_SUBCRSTATE_TERMINATED; + js->s_online_status = EXOSIP_NOTIFY_UNKNOWN; + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_NOTIFY, js, jd); + if (je!=NULL) + { + eXosip_event_add_status(je, answer); + } + + if (eXosip.j_call_callbacks[EXOSIP_SUBSCRIPTION_NOTIFY]!=NULL) + eXosip.j_call_callbacks[EXOSIP_SUBSCRIPTION_NOTIFY](EXOSIP_SUBSCRIPTION_NOTIFY, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); + } + + sipevent = osip_new_outgoing_sipmessage(answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction, sipevent); + + osip_list_add(eXosip.j_transactions, transaction, 0); + + REMOVE_ELEMENT(eXosip.j_subscribes, js); + eXosip_subscribe_free(js); + __eXosip_wakeup(); + + return ; + } + else + { + osip_content_type_t *ctype; + osip_body_t *body = NULL; + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, jd, js, NULL)); + js->s_ss_status = EXOSIP_SUBCRSTATE_ACTIVE; + js->s_online_status = EXOSIP_NOTIFY_UNKNOWN; /* default value */ + + ctype = osip_message_get_content_type(evt->sip); + if (ctype!=NULL && ctype->type!=NULL && ctype->subtype!=NULL) + { + if (0==osip_strcasecmp(ctype->type, "application") + && 0==osip_strcasecmp(ctype->subtype, "xpidf+xml")) + osip_message_get_body(evt->sip, 0, &body); + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "Unknown body: %s/%s\n", + ctype->type, ctype->subtype)); + } + } + + if (body!=NULL) + { + /* search for the open string */ + char *tmp = body->body; + while (tmp[0]!='\0') + { + if (tmp[0]=='o' && 0==strncmp(tmp, "online", 6)) + { + js->s_online_status = EXOSIP_NOTIFY_ONLINE; + /* search for the contact entry */ + while (tmp[0]!='\0') + { + if (tmp[0]=='c' && 0==strncmp(tmp, "contact", 7)) + { + /* ... */ + } + tmp++; + } + break; + } + else if (tmp[0]=='b' && 0==strncmp(tmp, "busy", 4)) + { + js->s_online_status = EXOSIP_NOTIFY_BUSY; + break; + } + else if (tmp[0]=='b' && 0==strncmp(tmp, "berightback",11)) + { + js->s_online_status = EXOSIP_NOTIFY_BERIGHTBACK; + break; + } + else if (tmp[0]=='a' && 0==strncmp(tmp, "away", 4)) + { + js->s_online_status = EXOSIP_NOTIFY_AWAY; + break; + } + else if (tmp[0]=='o' && 0==strncmp(tmp, "onthephone", 10)) + { + js->s_online_status = EXOSIP_NOTIFY_ONTHEPHONE; + break; + } + else if (tmp[0]=='o' && 0==strncmp(tmp, "outtolunch", 10)) + { + js->s_online_status = EXOSIP_NOTIFY_OUTTOLUNCH; + break; + } + tmp++; + } + } + } +#else + /* modify the status of user */ + if (0==osip_strncasecmp(sub_state->hvalue, "active", 6)) + { + osip_content_type_t *ctype; + osip_body_t *body = NULL; + js->s_ss_status = EXOSIP_SUBCRSTATE_ACTIVE; + js->s_online_status = EXOSIP_NOTIFY_UNKNOWN; /* default value */ + + /* if there is a body which we understand, analyse it */ + ctype = osip_message_get_content_type(evt->sip); + if (ctype!=NULL && ctype->type!=NULL && ctype->subtype!=NULL) + { + if (0==osip_strcasecmp(ctype->type, "application") + && 0==osip_strcasecmp(ctype->subtype, "pidf+xml")) + osip_message_get_body(evt->sip, 0, &body); + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "Unknown body: %s/%s\n", + ctype->type, ctype->subtype)); + } + } + + if (body!=NULL) + { + /* search for the open string */ + char *tmp = body->body; + while (tmp[0]!='\0') + { + if (tmp[0]=='o' && 0==osip_strncasecmp(tmp, "open", 4)) + { + js->s_online_status = EXOSIP_NOTIFY_ONLINE; + /* search for the contact entry */ + while (tmp[0]!='\0') + { + if (tmp[0]=='a' && 0==osip_strncasecmp(tmp, "away", 4)) + js->s_online_status = EXOSIP_NOTIFY_AWAY; + else if (tmp[0]=='m' && 0==osip_strncasecmp(tmp, "meal", 4)) + js->s_online_status = EXOSIP_NOTIFY_OUTTOLUNCH; + else if (tmp[0]=='i' && 0==osip_strncasecmp(tmp, "in-transit", 10)) + js->s_online_status = EXOSIP_NOTIFY_BERIGHTBACK; + else if (tmp[0]=='b' && 0==osip_strncasecmp(tmp, "busy", 4)) + js->s_online_status = EXOSIP_NOTIFY_BUSY; + else if (tmp[0]=='o' && 0==osip_strncasecmp(tmp, "on-the-phone", 12)) + js->s_online_status = EXOSIP_NOTIFY_ONTHEPHONE; + + if (tmp[0]=='/' && 0==osip_strncasecmp(tmp, "/status", 7)) + break; + if (js->s_online_status!=EXOSIP_NOTIFY_ONLINE) + break; + tmp++; + } + + while (tmp[0]!='\0') + { + if (tmp[0]=='c' && 0==osip_strncasecmp(tmp, "contact", 7)) + { + /* ... */ + } + tmp++; + } + break; + } + else if (tmp[0]=='c' && 0==osip_strncasecmp(tmp, "closed", 6)) + { + js->s_online_status = EXOSIP_NOTIFY_CLOSED; + break; + } + tmp++; + } + } + } + else if (0==osip_strncasecmp(sub_state->hvalue, "pending", 7)) + { + js->s_ss_status = EXOSIP_SUBCRSTATE_PENDING; + js->s_online_status = EXOSIP_NOTIFY_PENDING; + } + + if (0==osip_strncasecmp(sub_state->hvalue, "terminated", 10)) + { + /* delete the dialog! */ + js->s_ss_status = EXOSIP_SUBCRSTATE_TERMINATED; + js->s_online_status = EXOSIP_NOTIFY_UNKNOWN; + + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_NOTIFY, js, jd); + if (je!=NULL) + { + eXosip_event_add_status(je, answer); + } + + if (eXosip.j_call_callbacks[EXOSIP_SUBSCRIPTION_NOTIFY]!=NULL) + eXosip.j_call_callbacks[EXOSIP_SUBSCRIPTION_NOTIFY](EXOSIP_SUBSCRIPTION_NOTIFY, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); + } + + sipevent = osip_new_outgoing_sipmessage(answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction, sipevent); + + osip_list_add(eXosip.j_transactions, transaction, 0); + + REMOVE_ELEMENT(eXosip.j_subscribes, js); + eXosip_subscribe_free(js); + __eXosip_wakeup(); + return; + } + else + { + osip_transaction_set_your_instance(transaction, __eXosip_new_jinfo(NULL, jd, js, NULL)); + } +#endif + + osip_list_add(jd->d_inc_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage(answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event(transaction, sipevent); + + { + eXosip_event_t *je; + je = eXosip_event_init_for_subscribe(EXOSIP_SUBSCRIPTION_NOTIFY, js, jd); + if (je!=NULL) + { + eXosip_event_add_status(je, answer); + } + + if (eXosip.j_call_callbacks[EXOSIP_SUBSCRIPTION_NOTIFY]!=NULL) + eXosip.j_call_callbacks[EXOSIP_SUBSCRIPTION_NOTIFY](EXOSIP_SUBSCRIPTION_NOTIFY, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); + } + + __eXosip_wakeup(); + return; +} + +static int +eXosip_match_notify_for_subscribe(eXosip_subscribe_t *js, osip_message_t *notify) +{ + osip_transaction_t *out_sub; + + if (js==NULL) + return -1; + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Trying to match notify with subscribe\n")); + + out_sub = eXosip_find_last_out_subscribe(js, NULL); + if (out_sub==NULL || out_sub->orig_request==NULL) + return -1; + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "subscribe transaction found\n")); + + /* some checks to avoid crashing on bad requests */ + if (notify == NULL || notify->cseq == NULL + || notify->cseq->method == NULL || notify->to == NULL) + return -1; + + if (0 != osip_call_id_match (out_sub->callid, notify->call_id)) + return -1; + + { + /* The From tag of outgoing request must match + the To tag of incoming notify: + */ + osip_generic_param_t *tag_from; + osip_generic_param_t *tag_to; + + osip_from_param_get_byname (out_sub->from, "tag", &tag_from); + osip_from_param_get_byname (notify->to, "tag", &tag_to); + if (tag_to == NULL || tag_to->gvalue==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "Uncompliant user agent: no tag in from of outgoing request\n")); + return -1; + } + if (tag_from == NULL || tag_to->gvalue==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "Uncompliant user agent: no tag in to of incoming request\n")); + return -1; + } + + if (0 != strcmp (tag_from->gvalue, tag_to->gvalue)) + return -1; + } + + return 0; +} + +static void +eXosip_process_message_outside_of_dialog(osip_transaction_t *transaction, + osip_event_t *evt) +{ + osip_message_t *answer; + osip_event_t *evt_answer; + osip_header_t *expires, *date; + int i; + + /* Check whether the Expire time has been reached */ + + /* the Expires header is present ? */ + if (osip_message_get_expires(evt->sip, 0, &expires) != -1 && expires->hvalue!=NULL) + { + + unsigned long expires_ul; + time_t now_ts, date_ts; + + expires_ul = strtoul(expires->hvalue, (char**)NULL, 10); + now_ts = time(NULL); + + /* + ** A MESSAGE request is said to be expired if its expiration time has + ** passed. The expiration time is determined by examining the Expires + ** header field, if present. MESSAGE requests without an Expires header + ** field do not expire. If the MESSAGE request containing an Expires + ** header field also contains a Date header field, the UAS SHOULD + ** interpret the Expires header field value as delta time from the Date + ** header field value. If the request does not contain a Date header + ** field, the UAS SHOULD interpret the Expires header value as delta + ** time from the time the UAS received the request. + */ + + /* Does the message also contain a Date header ? */ + if (osip_message_get_date(evt->sip, 0, &date) != -1 && date->hvalue != NULL) + { + + /* + 20.17 Date + The Date header field contains the date and time. Unlike HTTP/1.1, + SIP only supports the most recent RFC 1123 [20] format for dates. + As in [H3.3], SIP restricts the time zone in SIP-date to "GMT", while + RFC 1123 allows any time zone. An RFC 1123 date is case-sensitive. + The Date header field reflects the time when the request or + response is first sent. + + The Date header field can be used by simple end systems without a + battery-backed clock to acquire a notion of current time. + However, in its GMT form, it requires clients to know their offset + from GMT. + + Example: + + Date: Sat, 13 Nov 2010 23:29:00 GMT + + 20.19 Expires + + The Expires header field gives the relative time after which the + message (or content) expires. + + The precise meaning of this is method dependent. + + The expiration time in an INVITE does not affect the duration of + the actual session that may result from the invitation. Session + description protocols may offer the ability to express time limits + on the session duration, however. + + The value of this field is an integral number of seconds (in decimal) + between 0 and (2**32)-1, measured from the receipt of the request. + + Example: + + Expires: 5 + + */ + + /* TODO: + date_ts = RECUPERE_TIMESTAMP(date->hvalue); + */ + + date_ts = time(NULL); + + /* Has the message expired ? */ + if (date_ts + expires_ul < now_ts) + { + /* discard old data. */ + return; + } + } + else if (expires_ul != 0) + { + /* No date header, but a not null Expires one: + ** TODO: Compare to the UAS reception time + */ + date_ts = transaction->birth_time; + } + /* The message has not expired */ + } + + /* We must create the event */ + { + eXosip_event_t *je; + je = eXosip_event_init_for_message(EXOSIP_MESSAGE_NEW, transaction, evt->sip); + i = _eXosip_build_response_default(&answer, NULL, SIP_OK, evt->sip); + if (i!=0) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + return ; + } + + if (je!=NULL) + { + int pos = 0; + osip_body_t *oldbody; + + eXosip_event_add_status(je, answer); + + while (!osip_list_eol(evt->sip->bodies, pos)) + { + int len; + oldbody = (osip_body_t *)osip_list_get(evt->sip->bodies, pos); + len = strlen(oldbody->body); + pos++; + + if (len<999) + osip_strncpy(je->sdp_body, oldbody->body, len); + else + osip_strncpy(je->sdp_body, oldbody->body, 999); + } + } + + if (eXosip.j_call_callbacks[EXOSIP_MESSAGE_NEW]!=NULL) + eXosip.j_call_callbacks[EXOSIP_MESSAGE_NEW](EXOSIP_MESSAGE_NEW, je); + else if (eXosip.j_runtime_mode==EVENT_MODE) + eXosip_event_add(je); + } + + /* finally, send the 200 OK response */ + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + osip_transaction_add_event(transaction, evt_answer); + +#ifdef NEW_TIMER + __eXosip_wakeup(); +#endif + return; +} + + +static void eXosip_process_newrequest (osip_event_t *evt) +{ + osip_transaction_t *transaction; + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + int ctx_type; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + eXosip_dialog_t *jd; + + if (MSG_IS_INVITE(evt->sip)) + { + ctx_type = IST; + } + else if (MSG_IS_ACK(evt->sip)) + { /* this should be a ACK for 2xx (but could be a late ACK!) */ + ctx_type = -1; +#if 0 /* ACK must be announced */ + osip_event_free(evt); + return ; +#endif + } + else if (MSG_IS_REQUEST(evt->sip)) + { + ctx_type = NIST; + } + else + { /* We should handle late response and 200 OK before coming here. */ + ctx_type = -1; + osip_event_free(evt); + return ; + } + + transaction=NULL; + if (ctx_type != -1) + { + i = osip_transaction_init(&transaction, + (osip_fsm_type_t)ctx_type, + eXosip.j_osip, + evt->sip); + if (i!=0) + { + osip_event_free(evt); + return ; + } + + evt->transactionid = transaction->transactionid; + osip_transaction_set_your_instance(transaction, NULL); + + i = _eXosip_build_response_default(&answer, NULL, 100, evt->sip); + if (i!=0) + { + __eXosip_delete_jinfo(transaction); + osip_transaction_free(transaction); + osip_event_free(evt); + return ; + } + + osip_message_set_content_length(answer, "0"); + /* send message to transaction layer */ + + evt_answer = osip_new_outgoing_sipmessage(answer); + evt_answer->transactionid = transaction->transactionid; + + /* add the REQUEST & the 100 Trying */ + osip_transaction_add_event(transaction, evt); + osip_transaction_add_event(transaction, evt_answer); + __eXosip_wakeup(); + } + + if (MSG_IS_CANCEL(evt->sip)) + { + /* special handling for CANCEL */ + /* in the new spec, if the CANCEL has a Via branch, then it + is the same as the one in the original INVITE */ + eXosip_process_cancel(transaction, evt); + return ; + } + + jd = NULL; + /* first, look for a Dialog in the map of element */ + for (jc = eXosip.j_calls; jc!= NULL ; jc=jc->next) + { + for (jd = jc->c_dialogs; jd!= NULL ; jd=jd->next) + { + if (jd->d_dialog!=NULL) + { + if (osip_dialog_match_as_uas(jd->d_dialog, evt->sip)==0) + break; + } + } + if (jd!=NULL) break; + } + + + if (jd!=NULL) + { + osip_transaction_t *old_trn; + /* it can be: + 1: a new INVITE offer. + 2: a REFER request from one of the party. + 2: a BYE request from one of the party. + 3: a REQUEST with a wrong CSeq. + 4: a NOT-SUPPORTED method with a wrong CSeq. + */ + + if (!MSG_IS_BYE(evt->sip)) + { + /* reject all requests for a closed dialog */ + old_trn = eXosip_find_last_inc_bye(jc, jd); + if (old_trn == NULL) + old_trn = eXosip_find_last_out_bye(jc, jd); + + if (old_trn!=NULL) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 481, NULL, NULL, __LINE__); + return ; + } + } + + if (MSG_IS_INVITE(evt->sip)) + { + /* the previous transaction MUST be freed */ + old_trn = eXosip_find_last_inc_invite(jc, jd); + + if (old_trn!=NULL && old_trn->state!=IST_TERMINATED) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Retry Later", "An INVITE is not terminated", __LINE__); + return ; + } + + old_trn = eXosip_find_last_out_invite(jc, jd); + if (old_trn!=NULL && old_trn->state!=ICT_TERMINATED) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 491, NULL, NULL, __LINE__); + return ; + } + + osip_dialog_update_osip_cseq_as_uas(jd->d_dialog, evt->sip); + osip_dialog_update_route_set_as_uas(jd->d_dialog, evt->sip); + + eXosip_process_invite_within_call(jc, jd, transaction, evt); + } + else if (MSG_IS_BYE(evt->sip)) + { + old_trn = eXosip_find_last_inc_bye(jc, jd); + + if (old_trn!=NULL) /* && old_trn->state!=NIST_TERMINATED) */ + { /* this situation should NEVER occur?? (we can't receive + two different BYE for one call! */ + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Call Already Terminated", "A pending BYE has already terminate this call", __LINE__); + return; + } + /* osip_transaction_free(old_trn); */ + eXosip_process_bye(jc, jd, transaction, evt); + } + else if (MSG_IS_ACK(evt->sip)) + { + eXosip_process_ack(jc, jd, evt); + } + else if (MSG_IS_REFER(evt->sip)) + { + eXosip_process_refer(jc, jd, transaction, evt); + } + else if (MSG_IS_OPTIONS(evt->sip)) + { + eXosip_process_options(jc, jd, transaction, evt); + } + else if (MSG_IS_INFO(evt->sip)) + { + eXosip_process_info(jc, jd, transaction, evt); + } + else if (MSG_IS_NOTIFY(evt->sip)) + { + eXosip_process_notify_for_refer(jc, jd, transaction, evt); + } + else + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 405, NULL, "Method Not Allowed", __LINE__); + } + return ; + } + + if (MSG_IS_ACK(evt->sip)) + { + /* no transaction has been found for this ACK! */ + osip_event_free(evt); + return; + } + + if (MSG_IS_INFO(evt->sip)) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 481, NULL, NULL, __LINE__); + return; /* fixed */ + } + if (MSG_IS_OPTIONS(evt->sip)) + { + eXosip_process_new_options(transaction, evt); + return; + } + else if (MSG_IS_INVITE(evt->sip)) + { + eXosip_process_new_invite(transaction, evt); + return; + } + else if (MSG_IS_BYE(evt->sip)) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 481, NULL, NULL, __LINE__); + return; + } + + js = NULL; + /* first, look for a Dialog in the map of element */ + for (js = eXosip.j_subscribes; js!= NULL ; js=js->next) + { + for (jd = js->s_dialogs; jd!= NULL ; jd=jd->next) + { + if (jd->d_dialog!=NULL) + { + if (osip_dialog_match_as_uas(jd->d_dialog, evt->sip)==0) + break; + } + } + if (jd!=NULL) break; + } + + if (js!=NULL) + { + /* dialog found */ + osip_transaction_t *old_trn; + /* it can be: + 1: a new INVITE offer. + 2: a REFER request from one of the party. + 2: a BYE request from one of the party. + 3: a REQUEST with a wrong CSeq. + 4: a NOT-SUPPORTED method with a wrong CSeq. + */ + if (MSG_IS_MESSAGE(evt->sip)) + { + /* eXosip_process_imessage_within_subscribe_dialog(transaction, evt); */ + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, SIP_NOT_IMPLEMENTED, + NULL, "MESSAGEs within dialogs are not implemented.", __LINE__); + return; + } + else if (MSG_IS_NOTIFY(evt->sip)) + { + /* the previous transaction MUST be freed */ + old_trn = eXosip_find_last_inc_notify(js, jd); + + /* shouldn't we wait for the COMPLETED state? */ + if (old_trn!=NULL && old_trn->state!=NIST_TERMINATED) + { + /* retry later? */ + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Retry Later", "A pending NOTIFY is not terminated", __LINE__); + return ; + } + + osip_dialog_update_osip_cseq_as_uas(jd->d_dialog, evt->sip); + osip_dialog_update_route_set_as_uas(jd->d_dialog, evt->sip); + + eXosip_process_notify_within_dialog(js, jd, transaction, evt); + } + else + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 501, NULL, "Just Not Implemented", __LINE__); + } + return ; + } + + if (MSG_IS_NOTIFY(evt->sip)) + { + /* I should probably initiate a dialog with info from NOTIFY... + By now, I prefer to discard the message until an answer for + the subscribe is received, then I'll be able to answer + the NOTIFY retransmission. */ + + /* let's try to check if the NOTIFY is related to an existing + subscribe */ + js = NULL; + /* first, look for a Dialog in the map of element */ + for (js = eXosip.j_subscribes; js!= NULL ; js=js->next) + { + if (eXosip_match_notify_for_subscribe(js, evt->sip)==0) + { + i = eXosip_dialog_init_as_uac(&jd, evt->sip); + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + + /* update local cseq from subscribe request */ + if (js->s_out_tr!=NULL && js->s_out_tr->cseq!=NULL + && js->s_out_tr->cseq->number!=NULL) + { + jd->d_dialog->local_cseq = atoi(js->s_out_tr->cseq->number); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: local cseq has been updated\n")); + } + + ADD_ELEMENT(js->s_dialogs, jd); + eXosip_update(); + + eXosip_process_notify_within_dialog(js, jd, transaction, evt); + return; + } + } + + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(NULL, transaction, evt, 481, NULL, NULL, __LINE__); + return; + } + + jn = NULL; + /* first, look for a Dialog in the map of element */ + for (jn = eXosip.j_notifies; jn!= NULL ; jn=jn->next) + { + for (jd = jn->n_dialogs; jd!= NULL ; jd=jd->next) + { + if (jd->d_dialog!=NULL) + { + if (osip_dialog_match_as_uas(jd->d_dialog, evt->sip)==0) + break; + } + } + if (jd!=NULL) break; + } + + if (jn!=NULL) + { + /* dialog found */ + osip_transaction_t *old_trn; + /* it can be: + 1: a new INVITE offer. + 2: a REFER request from one of the party. + 2: a BYE request from one of the party. + 3: a REQUEST with a wrong CSeq. + 4: a NOT-SUPPORTED method with a wrong CSeq. + */ + if (MSG_IS_MESSAGE(evt->sip)) + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, SIP_NOT_IMPLEMENTED, + NULL, "MESSAGEs within dialogs are not implemented.", __LINE__); + return; + } + else if (MSG_IS_SUBSCRIBE(evt->sip)) + { + /* the previous transaction MUST be freed */ + old_trn = eXosip_find_last_inc_subscribe(jn, jd); + + /* shouldn't we wait for the COMPLETED state? */ + if (old_trn!=NULL && old_trn->state!=NIST_TERMINATED + && old_trn->state!=NIST_COMPLETED) + { + /* retry later? */ + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 500, "Retry Later", "A SUBSCRIBE is not terminated", __LINE__); + return ; + } + + osip_dialog_update_osip_cseq_as_uas(jd->d_dialog, evt->sip); + osip_dialog_update_route_set_as_uas(jd->d_dialog, evt->sip); + + eXosip_process_subscribe_within_call(jn, jd, transaction, evt); + } + else + { + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(jd, transaction, evt, 501, NULL, NULL, __LINE__); + } + return ; + } + + if (MSG_IS_MESSAGE(evt->sip)) + { + eXosip_process_message_outside_of_dialog(transaction , evt); + return; + } + + if (MSG_IS_SUBSCRIBE(evt->sip)) + { + + if (0==eXosip_event_package_is_supported(transaction, evt)) + { + return; + } + eXosip_process_new_subscribe(transaction, evt); + return; + } + + /* default answer */ + osip_list_add(eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer(NULL, transaction, evt, 501, NULL, NULL, __LINE__); +} + +static void eXosip_process_response_out_of_transaction (osip_event_t *evt) +{ + osip_event_free(evt); +} + +static void fix_via(osip_message_t *msg, const struct sockaddr * sa, socklen_t sa_len){ + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + int err; + err=getnameinfo(sa, sa_len,host,NI_MAXHOST,serv,NI_MAXSERV, + NI_NUMERICHOST|NI_NUMERICSERV); + if (err!=0){ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "sockaddr_to_char: error in getnameinfo():%s\n",gai_strerror(err) )); + return; + } + osip_message_fix_last_via_header(msg,host,atoi(serv)); +} + +/* if second==-1 && useconds==-1 -> wait for ever + if max_message_nb<=0 -> infinite loop.... */ +int eXosip_read_message ( int max_message_nb, int sec_max, int usec_max ) +{ + fd_set osip_fdset; + struct timeval tv; + char *buf; + + tv.tv_sec = sec_max; + tv.tv_usec = usec_max; + + buf = (char *)osip_malloc(SIP_MESSAGE_MAX_LENGTH*sizeof(char)+1); + while (max_message_nb!=0 && eXosip.j_stop_ua==0) + { + int i; + int max; + int wakeup_socket = jpipe_get_read_descr(eXosip.j_socketctl); + FD_ZERO(&osip_fdset); +#if defined (WIN32) || defined (_WIN32_WCE) + FD_SET((unsigned int)eXosip.j_socket, &osip_fdset); +#else + FD_SET(eXosip.j_socket, &osip_fdset); +#endif + max = eXosip.j_socket; +#if defined (WIN32) || defined (_WIN32_WCE) + FD_SET((unsigned int)wakeup_socket, &osip_fdset); +#else + FD_SET(wakeup_socket, &osip_fdset); +#endif + if (wakeup_socket>eXosip.j_socket) + max = wakeup_socket; + if ((sec_max==-1)||(usec_max==-1)) + i = select(max+1, &osip_fdset, NULL, NULL, NULL); + else + i = select(max+1, &osip_fdset, NULL, NULL, &tv); + + if ((i == -1) && (errno == EINTR || errno == EAGAIN)) + continue; + + if ((i > 0) && FD_ISSET (wakeup_socket, &osip_fdset)) + { + char buf2[500]; + jpipe_read (eXosip.j_socketctl, buf2, 499); + } + + if (0==i || eXosip.j_stop_ua!=0) + { + } + else if (-1==i) + { + osip_free(buf); + return -2; /* error */ + } + else if (FD_ISSET (eXosip.j_socket, &osip_fdset)) + { + struct sockaddr_storage sa; +#ifdef __linux + socklen_t slen; +#else + int slen; +#endif + slen = sizeof(struct sockaddr_storage); + i = recvfrom (eXosip.j_socket, buf, SIP_MESSAGE_MAX_LENGTH, 0, + (struct sockaddr *) &sa, &slen); + if( i > 5 ) /* we expect at least one byte, otherwise there's no doubt that it is not a sip message !*/ + { + /* Message might not end with a "\0" but we know the number of */ + /* char received! */ + osip_transaction_t *transaction = NULL; + osip_event_t *sipevent; + osip_strncpy(buf+i,"\0",1); + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Received message: \n%s\n", buf)); +#ifdef WIN32 + if (strlen(buf)>412) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Message suite: \n%s\n", buf+412)); + } +#endif + + sipevent = osip_parse(buf, i); + transaction = NULL; + if (sipevent!=NULL&&sipevent->sip!=NULL) + { + fix_via(sipevent->sip,(struct sockaddr*)&sa,slen); + i = osip_find_transaction_and_add_event(eXosip.j_osip, sipevent); + if (i!=0) + { + /* this event has no transaction, */ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "This is a request\n", buf)); + eXosip_lock(); + if (MSG_IS_REQUEST(sipevent->sip)) + eXosip_process_newrequest(sipevent); + else if (MSG_IS_RESPONSE(sipevent->sip)) + eXosip_process_response_out_of_transaction(sipevent); + eXosip_unlock(); + } + else + { + /* handled by oSIP !*/ + } + } + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "Could not parse SIP message\n")); + osip_event_free(sipevent); + } + } + else if (i<0) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL, + "Could not read socket\n")); + } + else + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Dummy SIP message received\n")); + } + } + max_message_nb--; + } + osip_free(buf); + return 0; +} + + +static int eXosip_pendingosip_transaction_exist ( eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + osip_transaction_t *tr; + int now = time(NULL); + + tr = eXosip_find_last_inc_bye(jc, jd); + if (tr!=NULL && tr->state!=NIST_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time+180state!=NICT_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time+180state!=IST_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time+180state!=ICT_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time+180state!=IST_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time+180state!=NICT_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time+180state==NIST_TERMINATED || tr->state==NICT_TERMINATED )) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_finished_calls remove a dialog\n")); + /* Remove existing reference to the dialog from transactions! */ + __eXosip_call_remove_dialog_reference_in_call(jc, jd); + REMOVE_ELEMENT(jc->c_dialogs, jd); + eXosip_dialog_free(jd); + return 0; + } + return -1; +} + + + +static void +__eXosip_release_call(eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + REMOVE_ELEMENT(eXosip.j_calls, jc); + __eXosip_report_event(EXOSIP_CALL_RELEASED, jc, jd, NULL); + eXosip_call_free(jc); + __eXosip_wakeup(); +} + + +static int eXosip_release_aborted_calls ( eXosip_call_t *jc, eXosip_dialog_t *jd ) +{ + int now = time(NULL); + osip_transaction_t *tr; + tr = eXosip_find_last_inc_invite(jc, jd); + if (tr==NULL) + tr = eXosip_find_last_out_invite(jc, jd); + + if (tr==NULL) + { + if (jd!=NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls remove an empty dialog\n")); + __eXosip_call_remove_dialog_reference_in_call(jc, jd); + REMOVE_ELEMENT(jc->c_dialogs, jd); + eXosip_dialog_free(jd); + return 0; + } + return -1; + } + + if (tr!=NULL + && tr->state!=IST_TERMINATED + && tr->state!=ICT_TERMINATED + && tr->birth_time+180c_dialogs, jd); + __eXosip_report_event(EXOSIP_CALL_NOANSWER, jc, jd, NULL); + eXosip_dialog_free(jd); + __eXosip_wakeup(); + return 0; + } + } + + if (tr!=NULL + && (tr->state==IST_TERMINATED + || tr->state==ICT_TERMINATED)) + { + if (tr==jc->c_inc_tr) + { + if (jc->c_inc_tr->last_response==NULL) + { + /* OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls transaction with no answer\n")); */ + } + else if (MSG_IS_STATUS_3XX(jc->c_inc_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls answered with a 3xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_4XX(jc->c_inc_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls answered with a 4xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_5XX(jc->c_inc_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls answered with a 5xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_6XX(jc->c_inc_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls answered with a 6xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + } + else if (tr==jc->c_out_tr) + { + if (jc->c_out_tr->last_response==NULL) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls completed with no answer\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_3XX(jc->c_out_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 3xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_4XX(jc->c_out_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 4xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_5XX(jc->c_out_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 5xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + else if (MSG_IS_STATUS_6XX(jc->c_out_tr->last_response)) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 6xx\n")); + __eXosip_release_call(jc, jd); + return 0; + } + } + } + + return -1; +} + + +void eXosip_release_terminated_calls ( void ) +{ + eXosip_dialog_t *jd; + eXosip_dialog_t *jdnext; + eXosip_call_t *jc; + eXosip_call_t *jcnext; + int now = time(NULL); + int pos; + + + for (jc = eXosip.j_calls ; jc != NULL; ) + { + jcnext=jc->next; + /* free call terminated with a BYE */ + for (jd = jc->c_dialogs ; jd != NULL; ) + { + jdnext=jd->next; + if (0==eXosip_pendingosip_transaction_exist(jc, jd)) + { } + else if (0==eXosip_release_finished_calls(jc, jd)) + { jd = jc->c_dialogs; } + else if (0==eXosip_release_aborted_calls(jc, jd)) + { jdnext = NULL; } + else + { } + jd=jdnext; + } + jc=jcnext; + } + + for (jc = eXosip.j_calls ; jc != NULL; ) + { + jcnext=jc->next; + if (jc->c_dialogs==NULL) + { + /* release call for options requests */ + if (jc->c_inc_options_tr!=NULL) + { + if (jc->c_inc_options_tr->state==NIST_TERMINATED) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "eXosip: remove an incoming OPTIONS with no final answer\n")); + __eXosip_release_call(jc, NULL); + } + else if (jc->c_inc_options_tr->state!=NIST_TERMINATED + && jc->c_inc_options_tr->birth_time+180c_out_options_tr!=NULL) + { + if (jc->c_out_options_tr->state==NICT_TERMINATED) + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "eXosip: remove an outgoing OPTIONS with no final answer\n")); + __eXosip_release_call(jc, NULL); + } + else if (jc->c_out_options_tr->state!=NIST_TERMINATED + && jc->c_out_options_tr->birth_time+180c_inc_tr!=NULL && jc->c_inc_tr->state!=IST_TERMINATED + && jc->c_inc_tr->birth_time+180c_out_tr!=NULL && jc->c_out_tr->state!=ICT_TERMINATED + && jc->c_out_tr->birth_time+180c_inc_tr!=NULL && jc->c_inc_tr->state!=IST_TERMINATED) + { } + else if (jc->c_out_tr!=NULL && jc->c_out_tr->state!=ICT_TERMINATED) + { } + else /* no active pending transaction */ + { + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "eXosip: remove a call\n")); + __eXosip_release_call(jc, NULL); + } + } + jc = jcnext; + } + + pos = 0; + while (!osip_list_eol(eXosip.j_transactions, pos)) + { + osip_transaction_t *tr = (osip_transaction_t*) osip_list_get(eXosip.j_transactions, pos); + if (tr->state==IST_TERMINATED || tr->state==ICT_TERMINATED + || tr->state== NICT_TERMINATED || tr->state==NIST_TERMINATED) + + { /* free (transaction is already removed from the oSIP stack) */ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL, + "Release a terminated transaction\n")); + osip_list_remove(eXosip.j_transactions, pos); + __eXosip_delete_jinfo(tr); + osip_transaction_free(tr); + } + else if (tr->birth_time+180 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/gnome/GNOME_LinphoneApplet.xml b/linphone/gnome/GNOME_LinphoneApplet.xml new file mode 100644 index 000000000..9a5350fd2 --- /dev/null +++ b/linphone/gnome/GNOME_LinphoneApplet.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/linphone/gnome/Makefile.am b/linphone/gnome/Makefile.am new file mode 100644 index 000000000..7690425e0 --- /dev/null +++ b/linphone/gnome/Makefile.am @@ -0,0 +1,80 @@ +## Process this file with automake to produce Makefile.in + +linphone_common_sources=\ + linphone.c linphone.h \ + gui_utils.c gui_utils.h \ + support.c support.h \ + interface.c interface.h \ + callbacks.c callbacks.h \ + presence.c presence.h \ + propertybox.c propertybox.h \ + addressbook.c addressbook.h \ + friends.c friends.h + + +if BUILD_GNOME + +INCLUDES = \ + -I$(top_srcdir)\ + -I$(top_srcdir)/intl \ + $(ORTP_CFLAGS) \ + -I$(top_srcdir)/coreapi \ + -I$(top_srcdir)/mediastreamer2/include \ + $(OSIP_CFLAGS) + + + +bin_PROGRAMS = linphone + +linphone_SOURCES = \ + main.c \ + $(linphone_common_sources) + +linphone_LDADD = $(LIBGNOMEUI_LIBS) $(INTLLIBS) \ + $(LIBGNOME_LIBS) \ + $(top_builddir)/coreapi/liblinphone.la \ + $(OSIP_LIBS) + +endif + +AM_CFLAGS=$(STRICT_OPTIONS) $(LIBGNOMEUI_CFLAGS) $(LIBGNOME_CFLAGS) $(GNOME_APPLETS_CFLAGS) $(IPV6_CFLAGS) + +@INTLTOOL_SERVER_RULE@ + +if BUILD_GNOME_APPLET + +gnome_appletdir=$(libexecdir) + +gnome_applet_PROGRAMS = linphone_applet + +linphone_applet_SOURCES = \ + $(linphone_common_sources)\ + applet.c + +linphone_applet_CFLAGS=$(AM_CFLAGS) -DLINPHONE_APPLET + +linphone_applet_LDADD = \ + $(GNOME_APPLETS_LIBS) \ + $(top_builddir)/coreapi/liblinphone.la \ + $(OSIP_LIBS) + + +serverdir = $(libdir)/bonobo/servers +server_in_files = GNOME_LinphoneApplet.server.in +server_DATA = $(server_in_files:.server.in=.server) + +$(server_in_files): $(server_in_files:.server.in=.server.in.in) + sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ + + +uidir = $(datadir)/gnome-2.0/ui +ui_DATA = GNOME_LinphoneApplet.xml + +endif + +EXTRA_DIST = \ + GNOME_LinphoneApplet.server.in.in \ + applet.c \ + $(ui_DATA) + +DISTCLEANFILES=GNOME_LinphoneApplet.server.in GNOME_LinphoneApplet.server diff --git a/linphone/gnome/addressbook.c b/linphone/gnome/addressbook.c new file mode 100644 index 000000000..924bc6509 --- /dev/null +++ b/linphone/gnome/addressbook.c @@ -0,0 +1,306 @@ +/*************************************************************************** + addressbook.c - + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include "linphone.h" + +#define get_address_book() (&uiobj->addressbook) +#define get_main_window() (&uiobj->main_window) +#define get_core() (uiobj->core) +#define get_uiobj() (uiobj) + +void fill_address_book(GtkWidget *address_list); + +void ab_destroyed(){ + get_uiobj()->ab=NULL; +} + +void show_address_book(){ + if (get_uiobj()->ab!=NULL){ + gtk_window_present(GTK_WINDOW(get_uiobj()->ab)); + }else{ + get_uiobj()->ab=create_and_fill_address_book(); + g_signal_connect(G_OBJECT(get_uiobj()->ab),"destroy",G_CALLBACK(ab_destroyed),NULL); + gtk_widget_show(get_uiobj()->ab); + } +} + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +void contact_draw(GtkWidget *w, LinphoneProxyConfig *cfg){ + GtkWidget *table=lookup_widget(w,"table10"); + GtkWidget *combo; + combo=proxy_combo_box_new(cfg); + gtk_widget_show(combo); + gtk_table_attach(GTK_TABLE(table),combo,1,2,2,3, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + GLADE_HOOKUP_OBJECT(w,combo,"proxy"); + combo=gtk_combo_box_new_text(); + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),_("Wait")); + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),_("Deny")); + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),_("Accept")); + gtk_widget_show(combo); + gtk_table_attach(GTK_TABLE(table),combo,1,2,3,4, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + GLADE_HOOKUP_OBJECT(w,combo,"pol"); +} + +GtkWidget * contact_new(LinphoneFriend *lf, GtkWidget *ab){ + GtkWidget *w=create_contact_box(); + contact_draw(w,NULL); + gtk_widget_show(w); + g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); + g_object_set_data(G_OBJECT(w),"address_book",(gpointer)ab); + g_object_set_data(G_OBJECT(w),"add",GINT_TO_POINTER(TRUE)); + gtk_combo_box_set_active(GTK_COMBO_BOX(lookup_widget(w,"pol")),lf->pol); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"send_subscribe")),lf->subscribe); + return w; +} + +GtkWidget * contact_edit(LinphoneFriend *lf, GtkWidget *ab){ + GtkWidget *w=create_contact_box(); + gchar *tmpstr; + contact_draw(w,lf->proxy); + + g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); + linphone_friend_edit(lf); + tmpstr=linphone_friend_get_name(lf); + if (tmpstr!=NULL) { + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"name")),tmpstr); + g_free(tmpstr); + } + tmpstr=linphone_friend_get_addr(lf); + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"sipaddr")),tmpstr); + g_free(tmpstr); + + gtk_combo_box_set_active(GTK_COMBO_BOX(lookup_widget(w,"pol")),lf->pol); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"send_subscribe")),lf->subscribe); + + gtk_widget_show(w); + if (ab!=NULL) g_object_set_data(G_OBJECT(w),"address_book",(gpointer)ab); + return w; +} + +GtkWidget * subscriber_edit(LinphoneFriend *lf){ + GtkWidget *w=contact_edit(lf,NULL); + g_object_set_data(G_OBJECT(w),"add",GINT_TO_POINTER(TRUE)); + return w; +} + +gint contact_ok(GtkWidget *dialog){ + gchar *name,*sipaddr; + gchar *url; + gboolean add=FALSE; + GtkWidget *ab; + LinphoneFriend *lf; + int err; + lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(dialog),"friend_ref"); + add=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog),"add")); + name=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"name")),0,-1); + sipaddr=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"sipaddr")),0,-1); + url=g_strdup_printf("%s <%s>",name,sipaddr); + /* workaround a bug in osip ? */ + /* something doesn't like addresses like "machin <>" */ + if (strchr(sipaddr,'<')==NULL){ + err=linphone_friend_set_sip_addr(lf,url); + }else err=-1; + if (err<0){ + linphone_gnome_ui_display_something(get_uiobj(),GTK_MESSAGE_WARNING,_("Bad sip address: a sip address looks like sip:user@domain")); + linphone_friend_destroy(lf); + g_free(name); + g_free(sipaddr); + g_free(url); + return -1; + } + g_free(name); + g_free(sipaddr); + g_free(url); + linphone_friend_set_proxy(lf,proxy_combo_box_get_selected(lookup_widget(dialog,"proxy"))); + linphone_friend_set_inc_subscribe_policy(lf,gtk_combo_box_get_active(GTK_COMBO_BOX(lookup_widget(dialog,"pol")))); + linphone_friend_send_subscribe(lf,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog,"send_subscribe")))); + if (add){ + linphone_core_add_friend(get_core(),lf); + } + else linphone_friend_done(lf); + /* ask the address book to redraw itself */ + ab=g_object_get_data(G_OBJECT(dialog),"address_book"); + if (ab!=NULL) fill_address_book(lookup_widget(ab,"address_list")); + return 0; +} + +enum{ + SIP_ADDRESS_COLUMN, + FRIEND_REFERENCE, + AB_NCOLUMNS +}; + +void choose_address_and_close(GtkWidget *ab){ + GtkTreeSelection *select; + GtkWidget *addressentry=get_main_window()->addressentry; + GtkTreeIter iter; + GtkTreeModel *model; + gchar *address=NULL; + GtkWidget *address_list=lookup_widget(ab,"address_list"); + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + if (select==NULL) return; + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,SIP_ADDRESS_COLUMN , &address, -1); + } + if (address!=NULL){ + gtk_entry_set_text (GTK_ENTRY(addressentry),address); + g_free(address); + } + gtk_widget_destroy(ab); +} +void +address_book_close (GtkWidget *object, + gpointer user_data) +{ + gtk_widget_destroy(gtk_widget_get_toplevel(object)); +} + +void address_selection_changed_cb(GtkTreeSelection *selection, gpointer data) +{ + +} +gboolean address_button_press(GtkWidget *widget,GdkEventButton *event,gpointer user_data) +{ + GtkWidget *ab=(GtkWidget*)user_data; + if (event->type==GDK_2BUTTON_PRESS){ + choose_address_and_close(ab); + return TRUE; + } + return FALSE; +} + +void fill_address_book(GtkWidget *address_list){ + GtkListStore *store; + GtkTreeIter iter; + GtkTreeModel *model; + MSList *elem; + gchar *tmpstr; + /* fill the store */ + elem=linphone_core_get_friend_list(get_core()); + model=gtk_tree_view_get_model(GTK_TREE_VIEW(address_list)); + store=GTK_LIST_STORE(model); + gtk_list_store_clear(store); + for(;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneFriend *lf=(LinphoneFriend*)elem->data; + tmpstr=linphone_friend_get_url(lf); + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,SIP_ADDRESS_COLUMN,tmpstr,FRIEND_REFERENCE,(gpointer)lf,-1); + ms_free(tmpstr); + } +} + +GtkWidget *create_and_fill_address_book(){ + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + GtkWidget *address_list; + GtkWidget *ret=create_address_book(); + + address_list=lookup_widget(ret,"address_list"); + store = gtk_list_store_new (AB_NCOLUMNS, G_TYPE_STRING,G_TYPE_POINTER); + gtk_tree_view_set_model(GTK_TREE_VIEW(address_list),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Contact list"), + renderer, + "text", SIP_ADDRESS_COLUMN, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (address_list), column); + + /* Setup the selection handler */ + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (address_selection_changed_cb), + NULL); + + /* setup handler for double click */ + g_signal_connect(G_OBJECT(address_list),"button-press-event",G_CALLBACK(address_button_press),(gpointer)ret); + + fill_address_book(address_list); + return ret; +} + +void +on_modify_address_clicked (GtkButton *button, + gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *address_list=lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"address_list"); + + /* change the address in the view */ + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + LinphoneFriend *lf=NULL; + gtk_tree_model_get(model,&iter,FRIEND_REFERENCE,&lf,-1); + contact_edit(lf,gtk_widget_get_toplevel(GTK_WIDGET(button))); + } +} + +void on_add_address_clicked(GtkButton *button,gpointer user_data) +{ + LinphoneFriend *lf=linphone_friend_new(); + contact_new(lf,gtk_widget_get_toplevel(GTK_WIDGET(button))); +} + +void on_remove_address_clicked(GtkButton *button,gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *address_list=lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"address_list"); + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + LinphoneFriend *lf=NULL; + gtk_tree_model_get(model,&iter,FRIEND_REFERENCE,&lf,-1); + linphone_core_remove_friend(get_core(),lf); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + } +} + +void on_select_address_clicked(GtkButton *button,gpointer user_data) +{ + choose_address_and_close(gtk_widget_get_toplevel(GTK_WIDGET(button))); +} + + +void +on_contact_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + switch (response_id){ + case GTK_RESPONSE_OK: + contact_ok(GTK_WIDGET(dialog)); + break; + default: + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); +} diff --git a/linphone/gnome/addressbook.h b/linphone/gnome/addressbook.h new file mode 100644 index 000000000..f5f5431e3 --- /dev/null +++ b/linphone/gnome/addressbook.h @@ -0,0 +1,28 @@ +/*************************************************************************** + addressbook.h - + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef ADDRESSBOOK_H +#define ADDRESSBOOK_H + +GtkWidget *create_and_fill_address_book(); +void show_address_book(); +GtkWidget * contact_new(LinphoneFriend *lf, GtkWidget *ab); +GtkWidget * contact_edit(LinphoneFriend *lf, GtkWidget *ab); +GtkWidget * subscriber_edit(LinphoneFriend *lf); + +#endif diff --git a/linphone/gnome/applet.c b/linphone/gnome/applet.c new file mode 100644 index 000000000..0edb30be0 --- /dev/null +++ b/linphone/gnome/applet.c @@ -0,0 +1,182 @@ +/*************************************************************************** + applet.c - Applet code for linphone's gnome + interface + ------------------- + begin : Sat Dec 14 2002 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include "linphone.h" +#include + +#define get_uiobj() (uiobj) + +LinphoneCore core; +LinphoneGnomeUI ui; +static int show=0; +static gulong signal_ref; +static GtkWidget *applet_button=NULL; +static GdkPixbuf *original_icon=NULL; +static GtkWidget *icon=NULL; + +void draw_icon(GtkWidget *button, int size) +{ + GdkPixbuf *resized; + if (original_icon==NULL){ + original_icon=gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/pixmaps/linphone/linphone2.xpm", + NULL); + g_return_if_fail( original_icon!=NULL); + } + if (icon!=NULL){ + gtk_container_remove(GTK_CONTAINER(button),icon); + gtk_widget_destroy(icon); + } + resized=gdk_pixbuf_scale_simple(original_icon,size,size,GDK_INTERP_BILINEAR); + g_return_if_fail(resized!=NULL); + icon=gtk_image_new_from_pixbuf(resized); + g_return_if_fail(icon!=NULL); + gdk_pixbuf_unref(resized); + gtk_container_add(GTK_CONTAINER(button),icon); + gtk_widget_show(icon); +} + +void linphone_applet_about_cb(gpointer p) +{ + GtkWidget *about2; + about2 = create_about2 (); + gtk_widget_show (about2); +} + + + +static void applet_change_pixel_size(GtkWidget *applet, int size) +{ + g_return_if_fail(applet_button!=NULL); + draw_icon(applet_button,size); +} + +static void applet_destroy_cb(GtkWidget *widget, gpointer data) +{ + if (get_uiobj()->main_window.window!=NULL){ + gtk_widget_destroy(get_uiobj()->main_window.window); + } + linphone_gnome_uninit(get_uiobj()); +} + +static gboolean +gui_destroy_cb (GtkWidget *widget, gpointer data) +{ + linphone_gnome_ui_uninit(get_uiobj()); + show=0; + return FALSE; +} + +static gboolean button_press_cb(GtkWidget *applet, GdkEventButton* event, gpointer data) +{ + if (event->button!=1) return FALSE; + if (show){ + g_signal_handlers_disconnect_by_func(G_OBJECT(get_uiobj()->main_window.window), + G_CALLBACK(gui_destroy_cb),NULL); + linphone_gnome_ui_hide(get_uiobj()); + + show=0; + }else { + linphone_gnome_ui_show(get_uiobj()); + signal_ref=g_signal_connect(G_OBJECT(get_uiobj()->main_window.window), + "destroy", + G_CALLBACK(gui_destroy_cb),NULL); + show=1; + } + return FALSE; +} + +const BonoboUIVerb linphone_applet_menu_verbs [] = { + BONOBO_UI_UNSAFE_VERB ("About", linphone_applet_about_cb), + BONOBO_UI_VERB_END +}; + +static gboolean +linphone_applet_fill (PanelApplet *applet) +{ + gint size=panel_applet_get_size(applet); + + applet_button=gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(applet),applet_button); + gtk_widget_show(applet_button); + + draw_icon(applet_button,size); + + g_signal_connect(G_OBJECT(applet),"button-press-event",G_CALLBACK(button_press_cb),NULL); + + + g_signal_connect(G_OBJECT(applet),"change_size", + G_CALLBACK(applet_change_pixel_size), + NULL); + + + g_signal_connect (G_OBJECT (applet), "destroy", + G_CALLBACK (applet_destroy_cb), NULL); + + //sizehint = panel_applet_get_size (PANEL_APPLET (applet)); + panel_applet_setup_menu_from_file (applet, + NULL, + "GNOME_LinphoneApplet.xml", + NULL, + linphone_applet_menu_verbs, + NULL); + + /* tracing for osip */ + TRACE_INITIALIZE(5,stdout); + + linphone_gnome_init(&ui,&core); + gtk_widget_show_all (GTK_WIDGET (applet)); + + return TRUE; +} + + +static gboolean +linphone_applet_factory (PanelApplet *applet, + const gchar *iid, + gpointer data) +{ + static int instances=0; + GtkWidget *dialog; + if (!strcmp (iid, "OAFIID:GNOME_LinphoneApplet")){ + if (instances>0){ + dialog = gtk_message_dialog_new (GTK_WINDOW(applet), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CLOSE, + (const gchar*) _("Cannot run multiples instances of the linphone applet.")); + /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + gtk_widget_show(GTK_WIDGET(dialog)); + return FALSE; + } + return linphone_applet_fill (applet); + } + return FALSE; +} + +#define GNOMELOCALEDIR PACKAGE_LOCALE_DIR + +PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_LinphoneApplet_Factory", + PANEL_TYPE_APPLET, + "linphone_applet", + "0", + linphone_applet_factory, + NULL) diff --git a/linphone/gnome/callbacks.c b/linphone/gnome/callbacks.c new file mode 100644 index 000000000..16ededc8a --- /dev/null +++ b/linphone/gnome/callbacks.c @@ -0,0 +1,695 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +callbacks.c -- gtk callbacks, and osipua callbacks. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" +#include + +#define get_core() (uiobj->core) +#define get_main_window() (&uiobj->main_window) +#define get_uiobj() (uiobj) + +void +on_about1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *about2; + about2 = create_about2 (); + gtk_widget_show (about2); +} + + +gint +on_prop1_close (GnomeDialog *gnomedialog, + gpointer user_data) +{ + LinphoneMainWindow *obj=get_main_window(); + gnome_appbar_clear_stack( GNOME_APPBAR(obj->status_bar)); + + return(FALSE); +} + +void +on_parametres1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + LinphoneGnomeUI *ui=get_uiobj(); + linphone_property_box_init(&ui->propbox); +} + + + +void +on_user_manual1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + gnome_help_display("index.xml",NULL,NULL); +} + + +gboolean +on_play_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + int vol; + vol=(gtk_range_get_adjustment(GTK_RANGE(widget)))->value; + linphone_core_set_play_level(get_core(),vol); + return FALSE; +} + + +gboolean +on_rec_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + int vol; + vol=(gtk_range_get_adjustment(GTK_RANGE(widget)))->value; + linphone_core_set_rec_level(get_core(),vol); + return FALSE; +} + + +gboolean +on_ring_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + int vol; + vol=(gtk_range_get_adjustment(GTK_RANGE(widget)))->value; + linphone_core_set_ring_level(get_core(),vol); + return FALSE; +} + + +void +on_prop1_help (GnomePropertyBox *gnomepropertybox, + gint arg1, + gpointer user_data) +{ + gnome_help_display("index.html",NULL,NULL); +} + + + + +void +on_fermer1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + linphone_gnome_ui_hide(get_uiobj()); +} + + + +#if 0 +/*this is when the panel size changes*/ +void applet_change_pixel_size(GtkWidget *w, int size, gpointer data) +{ + GtkWidget *pixmap,*button; + + pixmap=gtk_object_get_data(GTK_OBJECT(applet),"applet_pixmap"); + button=(GtkWidget*)gtk_object_get_data(GTK_OBJECT(applet),"applet_button"); + if (button==NULL) + { + printf("Cannot find applet button\n"); + return; + } + if (pixmap!=NULL) gtk_widget_destroy(pixmap); + pixmap = gnome_pixmap_new_from_xpm_d_at_size(linphone2_xpm, + size-4, size-4); + gtk_object_set_data(GTK_OBJECT(applet),"applet_pixmap",pixmap); + gtk_widget_show(pixmap); + gtk_container_add(GTK_CONTAINER(button), pixmap); +} +#endif + +void +on_adresse_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + show_address_book(); +} + +void on_address_book_show(GtkWidget *widget,gpointer user_data) +{ + +} + + + +void +on_showmore_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + gint state; + GtkWidget *optioncontrols=get_main_window()->optioncontrols; + state=gtk_toggle_button_get_active(togglebutton); + if (state) gtk_widget_show(optioncontrols); + else { + gtk_widget_hide(optioncontrols); + } +} + + +void +on_useRPC_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ +#ifdef VINCENT_MAURY_RSVP + LinphoneCore *lc=get_core(); + gboolean state; + state=gtk_toggle_button_get_active(togglebutton); + /* change RPC settings according to state */ + if (state) + { + if (linphone_core_set_rpc_mode(lc,1)!=0) /* set rpc on */ + { + printf("RPC error. unable to set rpc on !\n"); + printf("Check to see if RPC server is running\n"); + gtk_toggle_button_set_active(togglebutton,FALSE); + /*linphone_core_set_rpc_mode(lc,0);*/ + } + } + else + { + if (linphone_core_set_rpc_mode(lc,0)!=0) /* set rpc off */ + printf("RPC error. That's impossible !!\n"); + } +#endif +} + +void +on_useRSVP_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ +#ifdef VINCENT_MAURY_RSVP + LinphoneCore *lc=get_core(); + LinphoneGnomeUI *ui=get_uiobj(); + gboolean state; + state=gtk_toggle_button_get_active(togglebutton); + /* change the QoS settings function of the state */ + if (state) + { + linphone_core_set_rsvp_mode(lc,1); /* set RSVP on */ + gtk_widget_show(lookup_widget(ui->propbox.prop,"useRPC")); /* show RPC checkbox */ + } + else + { + linphone_core_set_rsvp_mode(lc,0); /* set RSVP off */ + /* uncheck RPC if necessary and hide RPC checkbox */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( + lookup_widget(ui->propbox.prop,"useRPC")),FALSE); + gtk_widget_hide(lookup_widget(ui->propbox.prop,"useRPC")); + } +#endif +} + +#ifdef VINCENT_MAURY_RSVP +/* callback called when you click the yes/no dialog box + * send yes or no to the core_change_qos which knows the question + * and will be able to ajust qos */ +void dialog_click (GtkDialog *dialog,gint arg1,gpointer user_data) +{ + LinphoneCore *lc=get_core(); + if (lc->call==NULL) + return; + + if (arg1==GTK_RESPONSE_YES) + { + printf("YES\n"); + linphone_core_change_qos(lc, 1); /* 1 = yes */ + } + else + { + printf("NO\n"); + linphone_core_change_qos(lc, 0); /* 0 = no */ + } + gtk_widget_destroy((GtkWidget*)dialog); +} +#endif + + +void +on_alt_href_clicked (GtkButton *button, + gpointer user_data) +{ + gchar *url; + GtkWidget *label; + osip_from_t * from; + LinphoneGnomeUI *ui=get_uiobj(); + label=GTK_BIN(button)->child; + gtk_label_get(GTK_LABEL(label),&url); + osip_from_init(&from); + if ( osip_from_parse(from,url) <0){ + /* do something here */ + }else + { /* it was a sip url, so display it in the entry*/ + gtk_entry_set_text(GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(ui->main_window.addressentry))),url); + } + osip_from_free(from); +} + +void +on_alt_href_realize (GtkWidget *widget, + gpointer user_data) +{ + GdkCursor *cursor = gdk_cursor_new(GDK_HAND2); + gdk_window_set_cursor(widget->window, cursor); + gdk_cursor_destroy(cursor); +} + + +void +on_dtmf_3_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"3"); +} + + +void +on_dmtf_2_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"2"); +} + + +void +on_dtmf_1_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"1"); +} + + +void +on_dtmf_4_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"4"); +} + + +void +on_dtmf_5_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"5"); +} + + +void +on_dtmf_6_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"6"); +} + + +void +on_dtmf_7_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"7"); +} + + +void +on_dtmf_8_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"8"); + +} + + +void +on_dtmf_9_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"9"); + +} + + +void +on_dtmf_star_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"*"); + +} + + +void +on_dtmf_0_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"0"); + +} + + +void +on_dtmf_pound_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"#"); + +} + + +void +on_dtmf_entry_changed (GtkEditable *editable, + gpointer user_data) +{ + gchar *dtmfs; + gint len; + /* get the last entry in the text box and plays it */ + dtmfs=gtk_editable_get_chars(editable,0,-1); + g_return_if_fail(dtmfs!=NULL); + len=strlen(dtmfs); + if (len>0){ + g_message("Sending dtmf %c",dtmfs[len-1]); + linphone_core_send_dtmf(get_uiobj()->core,dtmfs[len-1]); + } + g_free(dtmfs); +} + + +void +on_exit1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ +#ifdef LINPHONE_APPLET +#else + gtk_widget_destroy(get_uiobj()->main_window.window); +#endif +} + + +void on_app1_destroy(GtkWidget *app1, gpointer user_data) +{ +#ifdef LINPHONE_APPLET +#else + gtk_main_quit(); +#endif +} + +void +on_display_ab_clicked (GtkButton *button, + gpointer user_data) +{ + show_address_book(); +} + + +void +on_inc_subscr_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(dialog),"friend_ref"); + switch(response_id){ + case GTK_RESPONSE_ACCEPT: + subscriber_edit(lf); + break; + case GTK_RESPONSE_REJECT: + linphone_core_reject_subscriber(get_core(),lf); + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +void authentication_dialog_ok(GtkWidget *w) +{ + gchar *realm,*username,*userid,*passwd; + LinphoneAuthInfo *info; + realm=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"realm")),0,-1); + username=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"username")),0,-1); + userid=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"userid")),0,-1); + passwd=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"passwd")),0,-1); + info=linphone_auth_info_new(username,userid,passwd,NULL,realm); + linphone_core_add_auth_info(get_core(),info); + g_free(username); + g_free(userid); + g_free(passwd); + g_free(realm); +} + +void +on_authentication_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + switch(response_id){ + case GTK_RESPONSE_OK: + authentication_dialog_ok(GTK_WIDGET(dialog)); + gtk_widget_destroy(GTK_WIDGET(dialog)); + break; + } +} + +void +on_clear_auth_info_clicked (GtkButton *button, + gpointer user_data) +{ + linphone_core_clear_all_auth_info(get_core()); +} + + +void +on_call_history_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + linphone_gnome_show_call_logs_window(get_uiobj()); +} + + +void +on_call_logs_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + + +void +on_call_logs_destroy (GtkObject *object, + gpointer user_data) +{ + get_uiobj()->logs=NULL; +} + + +static void completion_add_text(GtkEntry *entry, const char *text){ + GtkTreeIter iter; + GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry)); + + if (gtk_tree_model_get_iter_first(model,&iter)){ + do { + gchar *uri=NULL; + gtk_tree_model_get(model,&iter,0,&uri,-1); + if (uri!=NULL){ + if (strcmp(uri,text)==0) { + /*remove text */ + gtk_list_store_remove(GTK_LIST_STORE(model),&iter); + g_free(uri); + break; + } + g_free(uri); + } + }while (gtk_tree_model_iter_next(model,&iter)); + } + /* and prepend it on top of the list */ + gtk_list_store_prepend(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1); +} + + +void +on_callbutton_clicked (GtkButton *button, + gpointer user_data) +{ + LinphoneGnomeUI *ui=get_uiobj(); + LinphoneCore *lc=get_core(); + GtkEntry *entry=GTK_ENTRY(ui->main_window.addressentry); + + if (lc->call==NULL){ + const gchar *sipurl=NULL; + int err; + /* we have no dialog in progress */ + /* get the url to call */ + sipurl=gtk_entry_get_text(entry); + err=linphone_core_invite(lc,sipurl); + if (err==0) completion_add_text(entry,sipurl); + }else { + linphone_core_accept_call(lc,NULL); + } +} + +void +on_hangup_clicked (GtkButton *button, + gpointer user_data) +{ + LinphoneGnomeUI *ui=get_uiobj(); + LinphoneCore *lc=get_core(); + if (lc->call!=NULL){ + /* same trick here as for linphone_core_accept_dialog: defer it to gtk's idle loop */ + gtk_window_set_title(GTK_WINDOW(ui->main_window.window),"linphone"); + linphone_core_terminate_call(lc,NULL); + } +} + +GtkWidget *chatroom_new(const gchar *url, LinphoneChatRoom *cr){ + GtkWidget *gcr=NULL; + if (cr==NULL) + cr=linphone_core_create_chat_room(get_core(),url); + if (cr!=NULL){ + gchar *tmp; + gcr=create_chatroom(); + g_object_set_data(G_OBJECT(gcr),"chatroom",(gpointer)cr); + linphone_chat_room_set_user_data(cr,(gpointer)gcr); + tmp=g_strdup_printf(_("Chat with %s"),url); + gtk_window_set_title(GTK_WINDOW(gcr),tmp); + g_free(tmp); + } + return gcr; +} + +void chatroom_append(GtkWidget *gcr, const gchar *from, const gchar *message){ + GtkTextBuffer *tb; + gchar *str; + GtkTextIter enditer; + GtkTextView *tv=GTK_TEXT_VIEW(lookup_widget(gcr,"chattext")); + tb=gtk_text_view_get_buffer(tv); + g_return_if_fail(tb!=NULL); + gtk_text_buffer_get_end_iter(tb,&enditer); + str=g_strdup_printf("[%s]\t:%s\n",from,message); + gtk_text_buffer_insert(tb,&enditer,str,strlen(str)); + g_free(str); +} + +void chatroom_close(GtkWidget *gcr){ + LinphoneChatRoom *cr; + cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(gcr),"chatroom"); + linphone_chat_room_destroy(cr); +} + + +void +on_chat_clicked (GtkButton *button, + gpointer user_data) +{ + gchar *sipurl; + + sipurl=gtk_editable_get_chars(GTK_EDITABLE(get_main_window()->addressentry),0,-1); + GtkWidget *gcr=chatroom_new(sipurl,NULL); + if (gcr!=NULL) gtk_widget_show(gcr); + g_free(sipurl); +} + + +void +on_chatbox_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_widget_destroy(gtk_widget_get_toplevel(GTK_WIDGET(button))); +} + + + +void +on_chatentry_activate (GtkEntry *entry, + gpointer user_data) +{ + LinphoneChatRoom *cr; + gchar *text; + text=gtk_editable_get_chars(GTK_EDITABLE(entry),0,-1); + if (strlen(text)>0){ + GtkWidget *gcr=gtk_widget_get_toplevel(GTK_WIDGET(entry)); + cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(gcr),"chatroom"); + linphone_chat_room_send_message(cr,text); + chatroom_append(gcr,linphone_core_get_primary_contact(get_core()),text); + gtk_editable_delete_text(GTK_EDITABLE(entry),0,-1); + } +} + +void +on_chatroom_destroy (GtkObject *object, + gpointer user_data) +{ + chatroom_close(GTK_WIDGET(object)); +} + + + +void +on_addressentry_activate (GtkEntry *entry, + gpointer user_data) +{ + on_callbutton_clicked(NULL,NULL); +} + +void +on_addressentry_destroy (GtkObject *object, + gpointer user_data) +{ + linphone_gnome_save_uri_history(get_uiobj()); +} + +void +on_video_enabled_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + linphone_core_enable_video(get_core(),gtk_toggle_button_get_active(togglebutton)); +} + + +void +on_echocancelation_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + linphone_core_enable_echo_cancelation(get_core(), + gtk_toggle_button_get_active(togglebutton)); +} + + + + diff --git a/linphone/gnome/callbacks.h b/linphone/gnome/callbacks.h new file mode 100644 index 000000000..11704a6a9 --- /dev/null +++ b/linphone/gnome/callbacks.h @@ -0,0 +1,540 @@ +#include + + +void +on_app1_destroy (GtkObject *object, + gpointer user_data); + +void +on_adresse_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_parametres1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_fermer1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_exit1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_about1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_user_manual1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_greenbutton_clicked (GtkButton *button, + gpointer user_data); + +void +on_redbutton_clicked (GtkButton *button, + gpointer user_data); + +void +on_showmore_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +gboolean +on_play_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +gboolean +on_rec_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +gboolean +on_ring_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +void +on_reachable (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_busy (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_minutesaway_changed (GtkEditable *editable, + gpointer user_data); + +void +on_away (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_do_not_disturb (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_moved_tmply (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_alt_serv (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_contact_field_changed (GtkEditable *editable, + gpointer user_data); + +void +on_presence_validate_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_entry_changed (GtkEditable *editable, + gpointer user_data); + +void +on_dtmf_3_clicked (GtkButton *button, + gpointer user_data); + +void +on_dmtf_2_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_1_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_4_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_5_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_6_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_7_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_8_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_9_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_star_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_0_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_pound_clicked (GtkButton *button, + gpointer user_data); + +void +on_propertybox1_apply (GnomePropertyBox *propertybox, + gint page_num, + gpointer user_data); + +gboolean +on_prop1_close (GnomeDialog *gnomedialog, + gpointer user_data); + +void +on_prop1_help (GnomePropertyBox *propertybox, + gint page_num, + gpointer user_data); + +gboolean +on_hscale1_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +void +on_audioport_changed (GtkEditable *editable, + gpointer user_data); + +void +on_sipport_changed (GtkEditable *editable, + gpointer user_data); + +void +on_user_name_changed (GtkEditable *editable, + gpointer user_data); + +void +on_domain_name_changed (GtkEditable *editable, + gpointer user_data); + +void +on_registrar_checked_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_rsvp_checked_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + + +void +on_redirect_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_proxy_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_obproxy_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_registrar_addr_changed (GtkEditable *editable, + gpointer user_data); + +void +on_reg_passwd_changed (GtkEditable *editable, + gpointer user_data); + +void +on_address_of_record_changed (GtkEditable *editable, + gpointer user_data); + +void +on_aucodec_up_clicked (GtkButton *button, + gpointer user_data); + +void +on_aucodec_down_clicked (GtkButton *button, + gpointer user_data); + +void +on_aucodec_enable_clicked (GtkButton *button, + gpointer user_data); + +void +on_aucodec_disable_clicked (GtkButton *button, + gpointer user_data); + +void +on_sounddriver_changed (GtkEditable *editable, + gpointer user_data); + +void +on_source_changed (GtkEditable *editable, + gpointer user_data); + +void +on_autokill_button1_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_address_book_show (GtkWidget *widget, + gpointer user_data); + +void +on_add_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_remove_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_select_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_modify_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_alt_href_clicked (GtkButton *button, + gpointer user_data); + +void +on_alt_href_realize (GtkWidget *widget, + gpointer user_data); + + +void +on_exit1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +address_book_close (GtkButton *button, + gpointer user_data); + +void +on_card_changed (GtkEditable *editable, + gpointer user_data); + +void +on_audio_jittcomp_value_changed (GtkRange *range, + gpointer user_data); + +void +on_enable_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_nat_address_changed (GtkEditable *editable, + gpointer user_data); + +void +on_display_ab_clicked (GtkButton *button, + gpointer user_data); + +void +on_ringfileentry_changed (GtkEditable *editable, + gpointer user_data); + +void +on_ringpreview_clicked (GtkButton *button, + gpointer user_data); + +gboolean +on_property_box_closed (GnomeDialog *gnomedialog, + gpointer user_data); + +void +on_address_book_close (GtkObject *object, + gpointer user_data); + +#ifndef VERSION +# define VERSION LINPHONE_VERSION +#endif + +void +on_addfriend_clicked (GtkButton *button, + gpointer user_data); + +void +on_removefriend_clicked (GtkButton *button, + gpointer user_data); + +void +on_add_adbk_clicked (GtkButton *button, + gpointer user_data); + +void +on_addfriend_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_friendlist_row_activated (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data); +void +on_useRSVP_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_useRPC_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +#ifdef VINCENT_MAURY_RSVP +void +dialog_click (GtkDialog *dialog, + gint arg1, + gpointer user_data); +#endif + +void +on_proxy_config_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_removeproxy_button_clicked (GtkButton *button, + gpointer user_data); + +void +on_addproxy_button_clicked (GtkButton *button, + gpointer user_data); + +void +on_editproxy_button_clicked (GtkButton *button, + gpointer user_data); + + +void +on_contact_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_inc_subscr_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_ob_proxy_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_authentication_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_clear_auth_info_clicked (GtkButton *button, + gpointer user_data); + +void +on_use_sipinfo_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_guess_hostname_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_call_history_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_call_logs_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_call_logs_destroy (GtkObject *object, + gpointer user_data); + +void +on_enable_ipv6_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_play_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_capt_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_ring_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_callbutton_clicked (GtkButton *button, + gpointer user_data); + +void +on_chatbox_clicked (GtkButton *button, + gpointer user_data); + +void +on_chatentry_activate (GtkEntry *entry, + gpointer user_data); + +void +on_hangup_clicked (GtkButton *button, + gpointer user_data); + +void +on_chat_clicked (GtkButton *button, + gpointer user_data); + +void +on_chatroom_destroy (GtkObject *object, + gpointer user_data); + +void +on_ring_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_addressentry_editing_done (GtkCellEditable *celleditable, + gpointer user_data); + +void +on_addressentry_destroy (GtkObject *object, + gpointer user_data); + +gboolean +on_addressentry_key_pressed (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); + +void +on_addressentry_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_addressentry_activate (GtkEntry *entry, + gpointer user_data); + +void +on_addressentry_destroy (GtkObject *object, + gpointer user_data); + +void +on_download_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data); + +void +on_download_bw_editing_done (GtkCellEditable *celleditable, + gpointer user_data); + +void +on_download_bw_changed (GtkEditable *editable, + gpointer user_data); + +gboolean +on_upload_bw_output (GtkSpinButton *spinbutton, + gpointer user_data); + +void +on_upload_bw_change_value (GtkSpinButton *spinbutton, + GtkScrollType scroll, + gpointer user_data); + +void +on_upload_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data); + +gboolean +on_upload_bw_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer user_data); + +void +on_video_enabled_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_echocancelation_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_no_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_use_stun_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_static_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_stun_server_changed (GtkEditable *editable, + gpointer user_data); diff --git a/linphone/gnome/friends.c b/linphone/gnome/friends.c new file mode 100644 index 000000000..d4da7828e --- /dev/null +++ b/linphone/gnome/friends.c @@ -0,0 +1,127 @@ +/*************************************************************************** + friends.c - display of friend's list + + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "linphone.h" + + +#define get_friend_list() (&uiobj->main_window.friendlist) +#define get_core() (uiobj->core) +#define get_main_window() (&uiobj->main_window) + +enum{ + FRIEND_PRESENCE_IMG, + FRIEND_SIP_ADDRESS, + FRIEND_PRESENCE_STATUS, + FRIEND_ID, + FRIEND_LIST_NCOL +}; + +void friend_list_set_friend_status(FriendList *fl, LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ + GtkTreeIter iter; + LinphoneFriend *tmp=0; + gboolean found=FALSE; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(fl->friendlist)); + if (gtk_tree_model_get_iter_first(model,&iter)) { + do{ + gtk_tree_model_get(model,&iter,FRIEND_ID,&tmp,-1); + //printf("tmp=%i, fid=%i",tmp,fid); + if (fid==tmp) { + GdkPixbuf *pixbuf; + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_STATUS,status,-1); + pixbuf = create_pixbuf(img); + if (pixbuf) + { + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); + } + found=TRUE; + } + }while(gtk_tree_model_iter_next(model,&iter)); + } + if (found==FALSE){ + //printf("Adding new notifier\n"); + GdkPixbuf *pixbuf; + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_SIP_ADDRESS, url, FRIEND_PRESENCE_STATUS,status,FRIEND_ID,fid,-1); + pixbuf = create_pixbuf(img); + if (pixbuf) gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); + } +} + + +void +on_friendlist_row_activated (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + gchar* friend; + select = gtk_tree_view_get_selection (treeview); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,FRIEND_SIP_ADDRESS , &friend, -1); + gtk_entry_set_text(GTK_ENTRY(get_main_window()->addressentry),friend); + g_free(friend); + } +} + +void friend_list_init(FriendList *fl,LinphoneCore *lc,GtkWidget *mainwidget) +{ + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + + + store = gtk_list_store_new (FRIEND_LIST_NCOL, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); + fl->lc=lc; + fl->friendlist=lookup_widget(mainwidget,"friendlist"); + /* need to add friends to the store here ...*/ + + gtk_tree_view_set_model(GTK_TREE_VIEW(fl->friendlist),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "pixbuf", FRIEND_PRESENCE_IMG, + NULL); + gtk_tree_view_column_set_min_width (column, 29); + gtk_tree_view_append_column (GTK_TREE_VIEW (fl->friendlist), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", FRIEND_SIP_ADDRESS, + NULL); + g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (fl->friendlist), column); + + column = gtk_tree_view_column_new_with_attributes (_("Presence status"), + renderer, + "text", FRIEND_PRESENCE_STATUS, + NULL); + g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (fl->friendlist), column); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (fl->friendlist)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + +} diff --git a/linphone/gnome/friends.h b/linphone/gnome/friends.h new file mode 100644 index 000000000..02bf65cb0 --- /dev/null +++ b/linphone/gnome/friends.h @@ -0,0 +1,29 @@ +/*************************************************************************** + friends.h - display of friend's list + + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include + +struct _FriendList { + LinphoneCore *lc; + GtkWidget *friendlist; +}; + +typedef struct _FriendList FriendList; + +void friend_list_init(FriendList *fl,LinphoneCore *lc,GtkWidget *mainwidget); +void friend_list_set_friend_status(FriendList *fl, LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img); diff --git a/linphone/gnome/gui_utils.c b/linphone/gnome/gui_utils.c new file mode 100644 index 000000000..f58390bc2 --- /dev/null +++ b/linphone/gnome/gui_utils.c @@ -0,0 +1,102 @@ +/* +applet.c - some utils functions that cannot be set in interface.c. + +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "linphone.h" + + +/* creates the applet button* +GtkWidget *create_applet() +{ + GtkWidget *frame; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *applet; + + applet = applet_widget_new("linphone_applet"); + + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_show(frame); + + vbox = gtk_vbox_new(FALSE, FALSE); + gtk_container_add(GTK_CONTAINER(frame), vbox); + gtk_widget_show(vbox); + + button = gtk_button_new(); + gtk_widget_ref(button); + GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_DEFAULT); + GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, TRUE, 0); + + + gtk_widget_show(button); + applet_widget_add (APPLET_WIDGET (applet), frame); + gtk_object_set_data_full(GTK_OBJECT(applet),"applet_button",button,(GtkDestroyNotify)gtk_widget_unref); + gtk_signal_connect(GTK_OBJECT(button), "button_press_event", + GTK_SIGNAL_FUNC(on_applet_clicked), NULL); + gtk_signal_connect(GTK_OBJECT(applet), "change_pixel_size", + GTK_SIGNAL_FUNC(applet_change_pixel_size), NULL); + applet_widget_set_tooltip( APPLET_WIDGET (applet),_("linphone")); + gtk_widget_show(applet); + return(applet); +}; + +*/ +/* this just sets level adjustements for startup*/ +void set_levels(LinphoneGnomeUI *ui,gint reclev, gint playlev, gint ringlev) +{ + GtkWidget *range; + GtkWidget *window=ui->main_window.window; + return; + if (window) + { + range=lookup_widget(window,"rec_vol"); + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(range)),(gfloat)reclev); + range=lookup_widget(window,"play_vol"); + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(range)),(gfloat)playlev); + range=lookup_widget(window,"ring_vol"); + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(range)),(gfloat)ringlev); + } +} + + +void alt_ressource_display(LinphoneGnomeUI *ui,const gchar *url) +{ + GtkWidget *href; + GtkWidget *altdisplay; + GtkLabel *label; + gchar *pattern; + + altdisplay=create_altressource(); + g_object_set_data(G_OBJECT(altdisplay),"ui",(gpointer)ui); + href=lookup_widget(altdisplay,"alt_href"); + label=GTK_LABEL(GTK_BIN(href)->child); + gtk_label_set_text(label,url); + /* pattern used to set underline for string */ + pattern = g_strnfill(strlen(url), '_'); + gtk_label_set_pattern(label,pattern); + g_free(pattern); + gtk_widget_show(altdisplay); +} + + + + diff --git a/linphone/gnome/gui_utils.h b/linphone/gnome/gui_utils.h new file mode 100644 index 000000000..426de9c3d --- /dev/null +++ b/linphone/gnome/gui_utils.h @@ -0,0 +1,33 @@ +/* +applet.h - ome utils functions that cannot be set in interface.c. + +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef GUI_UTILS_H +#define GUI_UTILS_H + +#include "linphone.h" + +/* set audio levels on the main window*/ +void set_levels(LinphoneGnomeUI *ui,gint reclev, gint playlev, gint ringlev); + +/* display an alternate url (used in 380 response) */ +void alt_ressource_display(LinphoneGnomeUI *ui, const gchar *url); + +#endif + diff --git a/linphone/gnome/interface.c b/linphone/gnome/interface.c new file mode 100644 index 000000000..05c3136ae --- /dev/null +++ b/linphone/gnome/interface.c @@ -0,0 +1,2919 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +static GnomeUIInfo connexion1_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("Address book"), + NULL, + (gpointer) on_adresse_activate, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, "gnome-stock-book-open", + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_MENU_PREFERENCES_ITEM (on_parametres1_activate, NULL), + { + GNOME_APP_UI_ITEM, N_("Call history"), + N_("Shows calls"), + (gpointer) on_call_history_activate, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, "gtk-justify-fill", + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_MENU_EXIT_ITEM (on_exit1_activate, NULL), + GNOMEUIINFO_END +}; + +static GnomeUIInfo help1_menu_uiinfo[] = +{ + GNOMEUIINFO_MENU_ABOUT_ITEM (on_about1_activate, NULL), + { + GNOME_APP_UI_ITEM, N_("User manual"), + NULL, + (gpointer) on_user_manual1_activate, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, "gtk-help", + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_END +}; + +static GnomeUIInfo menubar1_uiinfo[] = +{ + { + GNOME_APP_UI_SUBTREE, N_("Go"), + NULL, + connexion1_menu_uiinfo, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_MENU_HELP_TREE (help1_menu_uiinfo), + GNOMEUIINFO_END +}; + +GtkWidget* +create_app1 (void) +{ + GtkWidget *app1; + GdkPixbuf *app1_icon_pixbuf; + GtkWidget *dock1; + GtkWidget *frame6; + GtkWidget *vbox4; + GtkWidget *vbox24; + GtkWidget *hbox15; + GtkWidget *frame7; + GtkWidget *addressentry; + GtkWidget *label1; + GtkWidget *display_ab; + GtkWidget *alignment22; + GtkWidget *hbox36; + GtkWidget *image33; + GtkWidget *label108; + GtkWidget *proxy_hbox; + GtkWidget *proxytouse_label; + GtkWidget *hbox2; + GtkWidget *callbutton; + GtkWidget *button14; + GtkWidget *button18; + GtkWidget *showmore; + GtkWidget *alignment5; + GtkWidget *hbox17; + GtkWidget *image12; + GtkWidget *label60; + GtkWidget *optioncontrols; + GtkWidget *vbox31; + GtkWidget *frame8; + GtkWidget *vbox5; + GtkWidget *label30; + GtkWidget *play_vol; + GtkWidget *label31; + GtkWidget *rec_vol; + GtkWidget *label110; + GtkWidget *ring_vol; + GtkWidget *label113; + GtkWidget *frame27; + GtkWidget *alignment23; + GtkWidget *vbox32; + GtkWidget *video_enabled; + GtkWidget *label114; + GtkWidget *label33; + GtkWidget *vbox6; + GtkWidget *presence_frame; + GtkWidget *presence_vbox; + GtkWidget *presence_reachable; + GSList *presence_reachable_group = NULL; + GtkWidget *hbox4; + GtkWidget *radiobutton2; + GtkWidget *minutesaway; + GtkWidget *label35; + GtkWidget *radiobutton3; + GtkWidget *radiobutton4; + GtkWidget *radiobutton5; + GtkWidget *radiobutton6; + GtkWidget *hbox5; + GtkWidget *label36; + GtkWidget *contact_field; + GtkWidget *label34; + GtkWidget *frame19; + GtkWidget *vbox18; + GtkWidget *dtmf_entry; + GtkWidget *table5; + GtkWidget *dtmf_3; + GtkWidget *dmtf_2; + GtkWidget *dtmf_1; + GtkWidget *dtmf_4; + GtkWidget *dtmf_5; + GtkWidget *dtmf_6; + GtkWidget *dtmf_7; + GtkWidget *dtmf_8; + GtkWidget *dtmf_9; + GtkWidget *dtmf_star; + GtkWidget *dtmf_0; + GtkWidget *dtmf_pound; + GtkWidget *label38; + GtkWidget *vbox22; + GtkWidget *scrolledwindow3; + GtkWidget *friendlist; + GtkWidget *label65; + GtkWidget *appbar1; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + app1 = gnome_app_new ("Linphone", _("linphone")); + gtk_window_set_resizable (GTK_WINDOW (app1), FALSE); + app1_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (app1_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (app1), app1_icon_pixbuf); + gdk_pixbuf_unref (app1_icon_pixbuf); + } + + dock1 = GNOME_APP (app1)->dock; + gtk_widget_show (dock1); + + gnome_app_create_menus (GNOME_APP (app1), menubar1_uiinfo); + + frame6 = gtk_frame_new (NULL); + gtk_widget_show (frame6); + gnome_app_set_contents (GNOME_APP (app1), frame6); + gtk_container_set_border_width (GTK_CONTAINER (frame6), 9); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_container_add (GTK_CONTAINER (frame6), vbox4); + + vbox24 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox24); + gtk_box_pack_start (GTK_BOX (vbox4), vbox24, TRUE, TRUE, 0); + + hbox15 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox15); + gtk_box_pack_start (GTK_BOX (vbox24), hbox15, TRUE, TRUE, 0); + + frame7 = gtk_frame_new (NULL); + gtk_widget_show (frame7); + gtk_box_pack_start (GTK_BOX (hbox15), frame7, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame7), 5); + + addressentry = gtk_entry_new (); + gtk_widget_show (addressentry); + gtk_container_add (GTK_CONTAINER (frame7), addressentry); + gtk_tooltips_set_tip (tooltips, addressentry, _("enter sip uri here"), NULL); + gtk_entry_set_text (GTK_ENTRY (addressentry), _("sip:")); + + label1 = gtk_label_new (_("Sip address:")); + gtk_widget_show (label1); + gtk_frame_set_label_widget (GTK_FRAME (frame7), label1); + + display_ab = gtk_button_new (); + gtk_widget_show (display_ab); + gtk_box_pack_start (GTK_BOX (hbox15), display_ab, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (display_ab), 15); + gtk_tooltips_set_tip (tooltips, display_ab, _("Shows the address book"), NULL); + + alignment22 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment22); + gtk_container_add (GTK_CONTAINER (display_ab), alignment22); + + hbox36 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox36); + gtk_container_add (GTK_CONTAINER (alignment22), hbox36); + + image33 = gtk_image_new_from_stock ("gnome-stock-book-open", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image33); + gtk_box_pack_start (GTK_BOX (hbox36), image33, FALSE, FALSE, 0); + + label108 = gtk_label_new_with_mnemonic (_("...")); + gtk_widget_show (label108); + gtk_box_pack_start (GTK_BOX (hbox36), label108, FALSE, FALSE, 0); + + proxy_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (proxy_hbox); + gtk_box_pack_start (GTK_BOX (vbox24), proxy_hbox, TRUE, TRUE, 0); + + proxytouse_label = gtk_label_new (_("Proxy to use:")); + gtk_widget_show (proxytouse_label); + gtk_box_pack_start (GTK_BOX (proxy_hbox), proxytouse_label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (proxytouse_label), GTK_JUSTIFY_CENTER); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox4), hbox2, TRUE, TRUE, 0); + + callbutton = gtk_button_new_with_mnemonic (_("Call or\nanswer")); + gtk_widget_show (callbutton); + gtk_box_pack_start (GTK_BOX (hbox2), callbutton, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (callbutton), 8); + + button14 = gtk_button_new_with_mnemonic (_("Hangup\nor refuse")); + gtk_widget_show (button14); + gtk_box_pack_start (GTK_BOX (hbox2), button14, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (button14), 8); + + button18 = gtk_button_new_with_mnemonic (_("Or chat !")); + gtk_widget_show (button18); + gtk_box_pack_start (GTK_BOX (vbox4), button18, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (button18), 8); + + showmore = gtk_check_button_new (); + gtk_widget_show (showmore); + gtk_box_pack_start (GTK_BOX (vbox4), showmore, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (showmore), TRUE); + + alignment5 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment5); + gtk_container_add (GTK_CONTAINER (showmore), alignment5); + + hbox17 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox17); + gtk_container_add (GTK_CONTAINER (alignment5), hbox17); + + image12 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image12); + gtk_box_pack_start (GTK_BOX (hbox17), image12, FALSE, FALSE, 0); + + label60 = gtk_label_new_with_mnemonic (_("Show more...")); + gtk_widget_show (label60); + gtk_box_pack_start (GTK_BOX (hbox17), label60, FALSE, FALSE, 0); + + optioncontrols = gtk_notebook_new (); + gtk_widget_show (optioncontrols); + gtk_box_pack_start (GTK_BOX (vbox4), optioncontrols, TRUE, TRUE, 0); + + vbox31 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox31); + gtk_container_add (GTK_CONTAINER (optioncontrols), vbox31); + + frame8 = gtk_frame_new (NULL); + gtk_widget_show (frame8); + gtk_box_pack_start (GTK_BOX (vbox31), frame8, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame8), 11); + + vbox5 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox5); + gtk_container_add (GTK_CONTAINER (frame8), vbox5); + gtk_container_set_border_width (GTK_CONTAINER (vbox5), 2); + + label30 = gtk_label_new (_("Playback level:")); + gtk_widget_show (label30); + gtk_box_pack_start (GTK_BOX (vbox5), label30, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label30), 7.45058e-09, 0.5); + + play_vol = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (75, 0, 100, 0, 0, 0))); + gtk_widget_show (play_vol); + gtk_box_pack_start (GTK_BOX (vbox5), play_vol, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (play_vol), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (play_vol), 0); + + label31 = gtk_label_new (_("Recording level:")); + gtk_widget_show (label31); + gtk_box_pack_start (GTK_BOX (vbox5), label31, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label31), 7.45058e-09, 0.5); + + rec_vol = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (75, 0, 100, 0, 0, 0))); + gtk_widget_show (rec_vol); + gtk_box_pack_start (GTK_BOX (vbox5), rec_vol, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (rec_vol), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (rec_vol), 0); + + label110 = gtk_label_new (_("Ring level:")); + gtk_widget_show (label110); + gtk_box_pack_start (GTK_BOX (vbox5), label110, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label110), 7.45058e-09, 0.5); + + ring_vol = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (75, 0, 100, 0, 0, 0))); + gtk_widget_show (ring_vol); + gtk_box_pack_start (GTK_BOX (vbox5), ring_vol, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (ring_vol), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (ring_vol), 0); + + label113 = gtk_label_new (_("Sound")); + gtk_widget_show (label113); + gtk_frame_set_label_widget (GTK_FRAME (frame8), label113); + + frame27 = gtk_frame_new (NULL); + gtk_widget_show (frame27); + gtk_box_pack_start (GTK_BOX (vbox31), frame27, FALSE, FALSE, 0); + + alignment23 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment23); + gtk_container_add (GTK_CONTAINER (frame27), alignment23); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment23), 0, 0, 12, 0); + + vbox32 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox32); + gtk_container_add (GTK_CONTAINER (alignment23), vbox32); + + video_enabled = gtk_check_button_new_with_mnemonic (_("Enable video")); + gtk_widget_show (video_enabled); + gtk_box_pack_start (GTK_BOX (vbox32), video_enabled, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_enabled), TRUE); + + label114 = gtk_label_new (_("Video")); + gtk_widget_show (label114); + gtk_frame_set_label_widget (GTK_FRAME (frame27), label114); + gtk_label_set_use_markup (GTK_LABEL (label114), TRUE); + + label33 = gtk_label_new (_("Controls")); + gtk_widget_show (label33); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 0), label33); + gtk_label_set_justify (GTK_LABEL (label33), GTK_JUSTIFY_CENTER); + + vbox6 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox6); + gtk_container_add (GTK_CONTAINER (optioncontrols), vbox6); + + presence_frame = gtk_frame_new (NULL); + gtk_widget_show (presence_frame); + gtk_box_pack_start (GTK_BOX (vbox6), presence_frame, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (presence_frame), 11); + + presence_vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (presence_vbox); + gtk_container_add (GTK_CONTAINER (presence_frame), presence_vbox); + + presence_reachable = gtk_radio_button_new_with_mnemonic (NULL, _("Reachable")); + gtk_widget_show (presence_reachable); + gtk_box_pack_start (GTK_BOX (presence_vbox), presence_reachable, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (presence_reachable), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (presence_reachable)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (presence_reachable), TRUE); + + hbox4 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox4); + gtk_box_pack_start (GTK_BOX (presence_vbox), hbox4, FALSE, TRUE, 0); + + radiobutton2 = gtk_radio_button_new_with_mnemonic (NULL, _("Busy, I'll be back in ")); + gtk_widget_show (radiobutton2); + gtk_box_pack_start (GTK_BOX (hbox4), radiobutton2, TRUE, TRUE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton2), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton2)); + + minutesaway = gtk_entry_new (); + gtk_widget_show (minutesaway); + gtk_box_pack_start (GTK_BOX (hbox4), minutesaway, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, minutesaway, _("The other party will be informed that you'll be back in X minutes"), NULL); + gtk_entry_set_text (GTK_ENTRY (minutesaway), _("5")); + + label35 = gtk_label_new (_("mn")); + gtk_widget_show (label35); + gtk_box_pack_start (GTK_BOX (hbox4), label35, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label35), GTK_JUSTIFY_CENTER); + + radiobutton3 = gtk_radio_button_new_with_mnemonic (NULL, _("Away")); + gtk_widget_show (radiobutton3); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton3, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton3), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3)); + + radiobutton4 = gtk_radio_button_new_with_mnemonic (NULL, _("Do not disturb")); + gtk_widget_show (radiobutton4); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton4, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton4), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton4)); + + radiobutton5 = gtk_radio_button_new_with_mnemonic (NULL, _("Moved temporarily")); + gtk_widget_show (radiobutton5); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton5, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton5), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton5)); + + radiobutton6 = gtk_radio_button_new_with_mnemonic (NULL, _("Alternative service")); + gtk_widget_show (radiobutton6); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton6, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton6), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton6)); + + hbox5 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox5); + gtk_box_pack_start (GTK_BOX (presence_vbox), hbox5, FALSE, TRUE, 0); + + label36 = gtk_label_new (_("URL:")); + gtk_widget_show (label36); + gtk_box_pack_start (GTK_BOX (hbox5), label36, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label36), GTK_JUSTIFY_CENTER); + + contact_field = gtk_entry_new (); + gtk_widget_show (contact_field); + gtk_box_pack_start (GTK_BOX (hbox5), contact_field, FALSE, FALSE, 0); + + label34 = gtk_label_new (_("Presence")); + gtk_widget_show (label34); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 1), label34); + gtk_label_set_justify (GTK_LABEL (label34), GTK_JUSTIFY_CENTER); + + frame19 = gtk_frame_new (NULL); + gtk_widget_show (frame19); + gtk_container_add (GTK_CONTAINER (optioncontrols), frame19); + gtk_container_set_border_width (GTK_CONTAINER (frame19), 15); + + vbox18 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox18); + gtk_container_add (GTK_CONTAINER (frame19), vbox18); + + dtmf_entry = gtk_entry_new (); + gtk_widget_show (dtmf_entry); + gtk_box_pack_start (GTK_BOX (vbox18), dtmf_entry, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, dtmf_entry, _("Press digits to send DTMFs."), NULL); + + table5 = gtk_table_new (4, 3, TRUE); + gtk_widget_show (table5); + gtk_box_pack_start (GTK_BOX (vbox18), table5, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (table5), 14); + gtk_table_set_row_spacings (GTK_TABLE (table5), 10); + gtk_table_set_col_spacings (GTK_TABLE (table5), 10); + + dtmf_3 = gtk_button_new_with_mnemonic (_(" 3\ndef")); + gtk_widget_show (dtmf_3); + gtk_table_attach (GTK_TABLE (table5), dtmf_3, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dmtf_2 = gtk_button_new_with_mnemonic (_(" 2\nabc")); + gtk_widget_show (dmtf_2); + gtk_table_attach (GTK_TABLE (table5), dmtf_2, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_1 = gtk_button_new_with_mnemonic (_("1")); + gtk_widget_show (dtmf_1); + gtk_table_attach (GTK_TABLE (table5), dtmf_1, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_4 = gtk_button_new_with_mnemonic (_(" 4\nghi")); + gtk_widget_show (dtmf_4); + gtk_table_attach (GTK_TABLE (table5), dtmf_4, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_5 = gtk_button_new_with_mnemonic (_(" 5\njkl")); + gtk_widget_show (dtmf_5); + gtk_table_attach (GTK_TABLE (table5), dtmf_5, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_6 = gtk_button_new_with_mnemonic (_(" 6\nmno")); + gtk_widget_show (dtmf_6); + gtk_table_attach (GTK_TABLE (table5), dtmf_6, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_7 = gtk_button_new_with_mnemonic (_(" 7\npqrs")); + gtk_widget_show (dtmf_7); + gtk_table_attach (GTK_TABLE (table5), dtmf_7, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_8 = gtk_button_new_with_mnemonic (_(" 8\ntuv")); + gtk_widget_show (dtmf_8); + gtk_table_attach (GTK_TABLE (table5), dtmf_8, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_9 = gtk_button_new_with_mnemonic (_(" 9\nwxyz")); + gtk_widget_show (dtmf_9); + gtk_table_attach (GTK_TABLE (table5), dtmf_9, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_star = gtk_button_new_with_mnemonic (_("*")); + gtk_widget_show (dtmf_star); + gtk_table_attach (GTK_TABLE (table5), dtmf_star, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_0 = gtk_button_new_with_mnemonic (_("0")); + gtk_widget_show (dtmf_0); + gtk_table_attach (GTK_TABLE (table5), dtmf_0, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_pound = gtk_button_new_with_mnemonic (_("#")); + gtk_widget_show (dtmf_pound); + gtk_table_attach (GTK_TABLE (table5), dtmf_pound, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label38 = gtk_label_new (_("DTMF")); + gtk_widget_show (label38); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 2), label38); + gtk_label_set_justify (GTK_LABEL (label38), GTK_JUSTIFY_CENTER); + + vbox22 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox22); + gtk_container_add (GTK_CONTAINER (optioncontrols), vbox22); + + scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow3); + gtk_box_pack_start (GTK_BOX (vbox22), scrolledwindow3, TRUE, TRUE, 0); + + friendlist = gtk_tree_view_new (); + gtk_widget_show (friendlist); + gtk_container_add (GTK_CONTAINER (scrolledwindow3), friendlist); + + label65 = gtk_label_new (_("My online friends")); + gtk_widget_show (label65); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 3), label65); + + appbar1 = gnome_appbar_new (FALSE, TRUE, GNOME_PREFERENCES_NEVER); + gtk_widget_show (appbar1); + gnome_app_set_statusbar (GNOME_APP (app1), appbar1); + + g_signal_connect ((gpointer) app1, "destroy", + G_CALLBACK (on_app1_destroy), + NULL); + gnome_app_install_menu_hints (GNOME_APP (app1), menubar1_uiinfo); + g_signal_connect ((gpointer) addressentry, "activate", + G_CALLBACK (on_addressentry_activate), + NULL); + g_signal_connect ((gpointer) addressentry, "destroy", + G_CALLBACK (on_addressentry_destroy), + NULL); + g_signal_connect ((gpointer) display_ab, "clicked", + G_CALLBACK (on_display_ab_clicked), + NULL); + g_signal_connect ((gpointer) callbutton, "clicked", + G_CALLBACK (on_callbutton_clicked), + NULL); + g_signal_connect ((gpointer) button14, "clicked", + G_CALLBACK (on_hangup_clicked), + NULL); + g_signal_connect ((gpointer) button18, "clicked", + G_CALLBACK (on_chat_clicked), + NULL); + g_signal_connect ((gpointer) showmore, "toggled", + G_CALLBACK (on_showmore_toggled), + NULL); + g_signal_connect ((gpointer) play_vol, "button_release_event", + G_CALLBACK (on_play_vol_button_release_event), + NULL); + g_signal_connect ((gpointer) rec_vol, "button_release_event", + G_CALLBACK (on_rec_vol_button_release_event), + NULL); + g_signal_connect ((gpointer) ring_vol, "button_release_event", + G_CALLBACK (on_rec_vol_button_release_event), + NULL); + g_signal_connect ((gpointer) video_enabled, "toggled", + G_CALLBACK (on_video_enabled_toggled), + NULL); + g_signal_connect ((gpointer) presence_reachable, "toggled", + G_CALLBACK (on_reachable), + NULL); + g_signal_connect ((gpointer) radiobutton2, "toggled", + G_CALLBACK (on_busy), + NULL); + g_signal_connect ((gpointer) minutesaway, "changed", + G_CALLBACK (on_minutesaway_changed), + NULL); + g_signal_connect ((gpointer) radiobutton3, "toggled", + G_CALLBACK (on_away), + NULL); + g_signal_connect ((gpointer) radiobutton4, "toggled", + G_CALLBACK (on_do_not_disturb), + NULL); + g_signal_connect ((gpointer) radiobutton5, "toggled", + G_CALLBACK (on_moved_tmply), + NULL); + g_signal_connect ((gpointer) radiobutton6, "toggled", + G_CALLBACK (on_alt_serv), + NULL); + g_signal_connect ((gpointer) contact_field, "changed", + G_CALLBACK (on_contact_field_changed), + NULL); + g_signal_connect ((gpointer) dtmf_entry, "changed", + G_CALLBACK (on_dtmf_entry_changed), + NULL); + g_signal_connect ((gpointer) dtmf_3, "clicked", + G_CALLBACK (on_dtmf_3_clicked), + NULL); + g_signal_connect ((gpointer) dmtf_2, "clicked", + G_CALLBACK (on_dmtf_2_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_1, "clicked", + G_CALLBACK (on_dtmf_1_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_4, "clicked", + G_CALLBACK (on_dtmf_4_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_5, "clicked", + G_CALLBACK (on_dtmf_5_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_6, "clicked", + G_CALLBACK (on_dtmf_6_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_7, "clicked", + G_CALLBACK (on_dtmf_7_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_8, "clicked", + G_CALLBACK (on_dtmf_8_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_9, "clicked", + G_CALLBACK (on_dtmf_9_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_star, "clicked", + G_CALLBACK (on_dtmf_star_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_0, "clicked", + G_CALLBACK (on_dtmf_0_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_pound, "clicked", + G_CALLBACK (on_dtmf_pound_clicked), + NULL); + g_signal_connect ((gpointer) friendlist, "row_activated", + G_CALLBACK (on_friendlist_row_activated), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (app1, app1, "app1"); + GLADE_HOOKUP_OBJECT (app1, dock1, "dock1"); + GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[0].widget, "connexion1"); + GLADE_HOOKUP_OBJECT (app1, connexion1_menu_uiinfo[0].widget, "addresse1"); + GLADE_HOOKUP_OBJECT (app1, connexion1_menu_uiinfo[1].widget, "parametres1"); + GLADE_HOOKUP_OBJECT (app1, connexion1_menu_uiinfo[2].widget, "call_history"); + GLADE_HOOKUP_OBJECT (app1, connexion1_menu_uiinfo[3].widget, "separator1"); + GLADE_HOOKUP_OBJECT (app1, connexion1_menu_uiinfo[4].widget, "exit1"); + GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[1].widget, "help1"); + GLADE_HOOKUP_OBJECT (app1, help1_menu_uiinfo[0].widget, "about1"); + GLADE_HOOKUP_OBJECT (app1, help1_menu_uiinfo[1].widget, "user_manual1"); + GLADE_HOOKUP_OBJECT (app1, frame6, "frame6"); + GLADE_HOOKUP_OBJECT (app1, vbox4, "vbox4"); + GLADE_HOOKUP_OBJECT (app1, vbox24, "vbox24"); + GLADE_HOOKUP_OBJECT (app1, hbox15, "hbox15"); + GLADE_HOOKUP_OBJECT (app1, frame7, "frame7"); + GLADE_HOOKUP_OBJECT (app1, addressentry, "addressentry"); + GLADE_HOOKUP_OBJECT (app1, label1, "label1"); + GLADE_HOOKUP_OBJECT (app1, display_ab, "display_ab"); + GLADE_HOOKUP_OBJECT (app1, alignment22, "alignment22"); + GLADE_HOOKUP_OBJECT (app1, hbox36, "hbox36"); + GLADE_HOOKUP_OBJECT (app1, image33, "image33"); + GLADE_HOOKUP_OBJECT (app1, label108, "label108"); + GLADE_HOOKUP_OBJECT (app1, proxy_hbox, "proxy_hbox"); + GLADE_HOOKUP_OBJECT (app1, proxytouse_label, "proxytouse_label"); + GLADE_HOOKUP_OBJECT (app1, hbox2, "hbox2"); + GLADE_HOOKUP_OBJECT (app1, callbutton, "callbutton"); + GLADE_HOOKUP_OBJECT (app1, button14, "button14"); + GLADE_HOOKUP_OBJECT (app1, button18, "button18"); + GLADE_HOOKUP_OBJECT (app1, showmore, "showmore"); + GLADE_HOOKUP_OBJECT (app1, alignment5, "alignment5"); + GLADE_HOOKUP_OBJECT (app1, hbox17, "hbox17"); + GLADE_HOOKUP_OBJECT (app1, image12, "image12"); + GLADE_HOOKUP_OBJECT (app1, label60, "label60"); + GLADE_HOOKUP_OBJECT (app1, optioncontrols, "optioncontrols"); + GLADE_HOOKUP_OBJECT (app1, vbox31, "vbox31"); + GLADE_HOOKUP_OBJECT (app1, frame8, "frame8"); + GLADE_HOOKUP_OBJECT (app1, vbox5, "vbox5"); + GLADE_HOOKUP_OBJECT (app1, label30, "label30"); + GLADE_HOOKUP_OBJECT (app1, play_vol, "play_vol"); + GLADE_HOOKUP_OBJECT (app1, label31, "label31"); + GLADE_HOOKUP_OBJECT (app1, rec_vol, "rec_vol"); + GLADE_HOOKUP_OBJECT (app1, label110, "label110"); + GLADE_HOOKUP_OBJECT (app1, ring_vol, "ring_vol"); + GLADE_HOOKUP_OBJECT (app1, label113, "label113"); + GLADE_HOOKUP_OBJECT (app1, frame27, "frame27"); + GLADE_HOOKUP_OBJECT (app1, alignment23, "alignment23"); + GLADE_HOOKUP_OBJECT (app1, vbox32, "vbox32"); + GLADE_HOOKUP_OBJECT (app1, video_enabled, "video_enabled"); + GLADE_HOOKUP_OBJECT (app1, label114, "label114"); + GLADE_HOOKUP_OBJECT (app1, label33, "label33"); + GLADE_HOOKUP_OBJECT (app1, vbox6, "vbox6"); + GLADE_HOOKUP_OBJECT (app1, presence_frame, "presence_frame"); + GLADE_HOOKUP_OBJECT (app1, presence_vbox, "presence_vbox"); + GLADE_HOOKUP_OBJECT (app1, presence_reachable, "presence_reachable"); + GLADE_HOOKUP_OBJECT (app1, hbox4, "hbox4"); + GLADE_HOOKUP_OBJECT (app1, radiobutton2, "radiobutton2"); + GLADE_HOOKUP_OBJECT (app1, minutesaway, "minutesaway"); + GLADE_HOOKUP_OBJECT (app1, label35, "label35"); + GLADE_HOOKUP_OBJECT (app1, radiobutton3, "radiobutton3"); + GLADE_HOOKUP_OBJECT (app1, radiobutton4, "radiobutton4"); + GLADE_HOOKUP_OBJECT (app1, radiobutton5, "radiobutton5"); + GLADE_HOOKUP_OBJECT (app1, radiobutton6, "radiobutton6"); + GLADE_HOOKUP_OBJECT (app1, hbox5, "hbox5"); + GLADE_HOOKUP_OBJECT (app1, label36, "label36"); + GLADE_HOOKUP_OBJECT (app1, contact_field, "contact_field"); + GLADE_HOOKUP_OBJECT (app1, label34, "label34"); + GLADE_HOOKUP_OBJECT (app1, frame19, "frame19"); + GLADE_HOOKUP_OBJECT (app1, vbox18, "vbox18"); + GLADE_HOOKUP_OBJECT (app1, dtmf_entry, "dtmf_entry"); + GLADE_HOOKUP_OBJECT (app1, table5, "table5"); + GLADE_HOOKUP_OBJECT (app1, dtmf_3, "dtmf_3"); + GLADE_HOOKUP_OBJECT (app1, dmtf_2, "dmtf_2"); + GLADE_HOOKUP_OBJECT (app1, dtmf_1, "dtmf_1"); + GLADE_HOOKUP_OBJECT (app1, dtmf_4, "dtmf_4"); + GLADE_HOOKUP_OBJECT (app1, dtmf_5, "dtmf_5"); + GLADE_HOOKUP_OBJECT (app1, dtmf_6, "dtmf_6"); + GLADE_HOOKUP_OBJECT (app1, dtmf_7, "dtmf_7"); + GLADE_HOOKUP_OBJECT (app1, dtmf_8, "dtmf_8"); + GLADE_HOOKUP_OBJECT (app1, dtmf_9, "dtmf_9"); + GLADE_HOOKUP_OBJECT (app1, dtmf_star, "dtmf_star"); + GLADE_HOOKUP_OBJECT (app1, dtmf_0, "dtmf_0"); + GLADE_HOOKUP_OBJECT (app1, dtmf_pound, "dtmf_pound"); + GLADE_HOOKUP_OBJECT (app1, label38, "label38"); + GLADE_HOOKUP_OBJECT (app1, vbox22, "vbox22"); + GLADE_HOOKUP_OBJECT (app1, scrolledwindow3, "scrolledwindow3"); + GLADE_HOOKUP_OBJECT (app1, friendlist, "friendlist"); + GLADE_HOOKUP_OBJECT (app1, label65, "label65"); + GLADE_HOOKUP_OBJECT (app1, appbar1, "appbar1"); + GLADE_HOOKUP_OBJECT_NO_REF (app1, tooltips, "tooltips"); + + gtk_widget_grab_focus (appbar1); + return app1; +} + +GtkWidget* +create_about2 (void) +{ + const gchar *authors[] = { + "Simon MORLAT", + "Aymeric Moizard", + "Sharath K Udupa", + NULL + }; + const gchar *documenters[] = { + "Simon MORLAT", + "Philippe Beau", + NULL + }; + gchar *translators = "it: Alberto Zanoni\nde: Jean Jacques Sarton\nfr: Simon Morlat\nes: Jesus Benitez\nja: Yamaguchi Yoshiya\npl: obert Nasiadek \npt_BR: Rafael Caesar Lenzi \nsv: Daniel Nylander "; + GdkPixbuf *about2_logo_pixbuf; + GtkWidget *about2; + GdkPixbuf *about2_icon_pixbuf; + + about2_logo_pixbuf = create_pixbuf ("linphone/linphone.png"); + about2 = gnome_about_new ("Linphone", VERSION, + _("C: 2001\nMade in Old Europe"), + _("Linphone is a web-phone.\nIt is compatible with SIP and RTP protocols."), + authors, + documenters, + translators, + about2_logo_pixbuf); + gtk_container_set_border_width (GTK_CONTAINER (about2), 5); + gtk_window_set_destroy_with_parent (GTK_WINDOW (about2), TRUE); + about2_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (about2_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (about2), about2_icon_pixbuf); + gdk_pixbuf_unref (about2_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (about2), GDK_WINDOW_TYPE_HINT_DIALOG); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (about2, about2, "about2"); + + return about2; +} + +GtkWidget* +create_prop1 (void) +{ + GtkWidget *prop1; + GdkPixbuf *prop1_icon_pixbuf; + GtkWidget *notebook1; + GtkWidget *vbox9; + GtkWidget *frame26; + GtkWidget *alignment21; + GtkWidget *vbox29; + GtkWidget *enable_ipv6; + GtkWidget *label105; + GtkWidget *frame21; + GtkWidget *vbox21; + GtkWidget *label56; + GtkWidget *table13; + GtkWidget *no_nat; + GSList *no_nat_group = NULL; + GtkWidget *use_stun; + GtkWidget *static_nat; + GtkWidget *nat_address; + GtkWidget *stun_server; + GtkWidget *label55; + GtkWidget *frame20; + GtkWidget *table6; + GtkWidget *audio_jittcomp; + GtkObject *audioport_adj; + GtkWidget *audioport; + GtkWidget *label52; + GtkWidget *label53; + GtkWidget *label54; + GtkWidget *frame25; + GtkWidget *alignment20; + GtkWidget *vbox28; + GtkWidget *use_sipinfo; + GtkWidget *label103; + GtkWidget *network; + GtkWidget *vbox12; + GtkWidget *vbox20; + GtkWidget *frame17; + GtkWidget *vbox16; + GtkWidget *table4; + GtkWidget *label10; + GtkWidget *combo3; + GList *combo3_items = NULL; + GtkWidget *rec_source; + GtkWidget *label106; + GtkWidget *play_card; + GtkWidget *capt_card; + GtkWidget *hbox20; + GtkWidget *ringfileentry; + GtkWidget *combo_entry1; + GtkWidget *ringpreview; + GtkWidget *alignment8; + GtkWidget *hbox21; + GtkWidget *image15; + GtkWidget *label64; + GtkWidget *label11; + GtkWidget *ringsnddev_label; + GtkWidget *label63; + GtkWidget *ring_card; + GtkWidget *echocancelation; + GtkWidget *label115; + GtkWidget *label48; + GtkWidget *sound; + GtkWidget *vbox7; + GtkWidget *frame10; + GtkWidget *hbox6; + GtkWidget *label13; + GtkObject *sip_port_adj; + GtkWidget *sip_port; + GtkWidget *label43; + GtkWidget *frame11; + GtkWidget *vbox27; + GtkWidget *hbox7; + GtkWidget *label26; + GtkWidget *label27; + GtkWidget *user_name; + GtkWidget *label28; + GtkWidget *domain_name; + GtkWidget *guess_hostname; + GtkWidget *label44; + GtkWidget *frame1; + GtkWidget *vbox23; + GtkWidget *scrolledwindow4; + GtkWidget *proxy_list; + GtkWidget *hbuttonbox6; + GtkWidget *addproxy_button; + GtkWidget *alignment12; + GtkWidget *hbox25; + GtkWidget *image19; + GtkWidget *label77; + GtkWidget *editproxy_button; + GtkWidget *alignment13; + GtkWidget *hbox26; + GtkWidget *image20; + GtkWidget *label78; + GtkWidget *removeproxy_button; + GtkWidget *alignment14; + GtkWidget *hbox27; + GtkWidget *image21; + GtkWidget *label79; + GtkWidget *label45; + GtkWidget *frame24; + GtkWidget *alignment18; + GtkWidget *clear_auth_info; + GtkWidget *alignment19; + GtkWidget *hbox34; + GtkWidget *image27; + GtkWidget *label102; + GtkWidget *label101; + GtkWidget *sip_pref; + GtkWidget *vbox13; + GtkWidget *frame16; + GtkWidget *hbox9; + GtkWidget *vbox14; + GtkWidget *label9; + GtkWidget *codec_notebook; + GtkWidget *scrolledwindow2; + GtkWidget *au_codec_list; + GtkWidget *label116; + GtkWidget *scrolledwindow7; + GtkWidget *vid_codec_list; + GtkWidget *label117; + GtkWidget *hbuttonbox4; + GtkWidget *aucodec_up; + GtkWidget *aucodec_down; + GtkWidget *aucodec_enable; + GtkWidget *alignment1; + GtkWidget *hbox11; + GtkWidget *image4; + GtkWidget *label50; + GtkWidget *aucodec_disable; + GtkWidget *alignment2; + GtkWidget *hbox12; + GtkWidget *image5; + GtkWidget *label51; + GtkWidget *table12; + GtkWidget *label112; + GtkWidget *label111; + GtkObject *download_bw_adj; + GtkWidget *download_bw; + GtkObject *upload_bw_adj; + GtkWidget *upload_bw; + GtkWidget *vbox17; + GtkWidget *label22; + GtkWidget *frame18; + GtkWidget *codec_info; + GtkWidget *label47; + GtkWidget *label46; + GtkWidget *codecs_pref; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + prop1 = gnome_property_box_new (); + gtk_window_set_title (GTK_WINDOW (prop1), _("Parameters")); + gtk_window_set_resizable (GTK_WINDOW (prop1), FALSE); + prop1_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (prop1_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (prop1), prop1_icon_pixbuf); + gdk_pixbuf_unref (prop1_icon_pixbuf); + } + + notebook1 = GNOME_PROPERTY_BOX (prop1)->notebook; + gtk_widget_show (notebook1); + + vbox9 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox9); + gtk_container_add (GTK_CONTAINER (notebook1), vbox9); + + frame26 = gtk_frame_new (NULL); + gtk_widget_show (frame26); + gtk_box_pack_start (GTK_BOX (vbox9), frame26, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame26), 6); + + alignment21 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment21); + gtk_container_add (GTK_CONTAINER (frame26), alignment21); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment21), 0, 0, 12, 0); + + vbox29 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox29); + gtk_container_add (GTK_CONTAINER (alignment21), vbox29); + + enable_ipv6 = gtk_check_button_new_with_mnemonic (_("Use IPv6 network (if available)")); + gtk_widget_show (enable_ipv6); + gtk_box_pack_start (GTK_BOX (vbox29), enable_ipv6, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, enable_ipv6, _("Toggle this if you are on an ipv6 network and you wish linphone to use it."), NULL); + + label105 = gtk_label_new (_("Global")); + gtk_widget_show (label105); + gtk_frame_set_label_widget (GTK_FRAME (frame26), label105); + gtk_label_set_use_markup (GTK_LABEL (label105), TRUE); + + frame21 = gtk_frame_new (NULL); + gtk_widget_show (frame21); + gtk_box_pack_start (GTK_BOX (vbox9), frame21, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame21), 5); + + vbox21 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox21); + gtk_container_add (GTK_CONTAINER (frame21), vbox21); + gtk_container_set_border_width (GTK_CONTAINER (vbox21), 6); + + label56 = gtk_label_new (_("These options is only for users in a private network, behind a gateway. If you are not in this situation, then leave this empty.")); + gtk_widget_show (label56); + gtk_box_pack_start (GTK_BOX (vbox21), label56, TRUE, TRUE, 0); + gtk_label_set_line_wrap (GTK_LABEL (label56), TRUE); + gtk_misc_set_padding (GTK_MISC (label56), 0, 12); + + table13 = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table13); + gtk_box_pack_start (GTK_BOX (vbox21), table13, FALSE, FALSE, 0); + + no_nat = gtk_radio_button_new_with_mnemonic (NULL, _("No firewall")); + gtk_widget_show (no_nat); + gtk_table_attach (GTK_TABLE (table13), no_nat, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (no_nat), no_nat_group); + no_nat_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (no_nat)); + + use_stun = gtk_radio_button_new_with_mnemonic (NULL, _("Use this STUN server to guess firewall address :")); + gtk_widget_show (use_stun); + gtk_table_attach (GTK_TABLE (table13), use_stun, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (use_stun), no_nat_group); + no_nat_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (use_stun)); + + static_nat = gtk_radio_button_new_with_mnemonic (NULL, _("Specify firewall address manually:")); + gtk_widget_show (static_nat); + gtk_table_attach (GTK_TABLE (table13), static_nat, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (static_nat), no_nat_group); + no_nat_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (static_nat)); + + nat_address = gtk_entry_new (); + gtk_widget_show (nat_address); + gtk_table_attach (GTK_TABLE (table13), nat_address, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + stun_server = gtk_entry_new (); + gtk_widget_show (stun_server); + gtk_table_attach (GTK_TABLE (table13), stun_server, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label55 = gtk_label_new (_("NAT traversal options (experimental)")); + gtk_widget_show (label55); + gtk_frame_set_label_widget (GTK_FRAME (frame21), label55); + + frame20 = gtk_frame_new (NULL); + gtk_widget_show (frame20); + gtk_box_pack_start (GTK_BOX (vbox9), frame20, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame20), 5); + + table6 = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table6); + gtk_container_add (GTK_CONTAINER (frame20), table6); + + audio_jittcomp = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (150, 60, 512, 10, 0, 0))); + gtk_widget_show (audio_jittcomp); + gtk_table_attach (GTK_TABLE (table6), audio_jittcomp, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND), 20, 0); + gtk_scale_set_value_pos (GTK_SCALE (audio_jittcomp), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (audio_jittcomp), 0); + + audioport_adj = gtk_adjustment_new (7000, 5000, 65535, 1, 10, 10); + audioport = gtk_spin_button_new (GTK_ADJUSTMENT (audioport_adj), 4, 0); + gtk_widget_show (audioport); + gtk_table_attach (GTK_TABLE (table6), audioport, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND), 20, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (audioport), TRUE); + + label52 = gtk_label_new (_("Number of buffered miliseconds (jitter compensation):")); + gtk_widget_show (label52); + gtk_table_attach (GTK_TABLE (table6), label52, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label52), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label52), TRUE); + + label53 = gtk_label_new (_("RTP port used for audio:")); + gtk_widget_show (label53); + gtk_table_attach (GTK_TABLE (table6), label53, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label53), GTK_JUSTIFY_CENTER); + + label54 = gtk_label_new (_("RTP properties")); + gtk_widget_show (label54); + gtk_frame_set_label_widget (GTK_FRAME (frame20), label54); + + frame25 = gtk_frame_new (NULL); + gtk_widget_show (frame25); + gtk_box_pack_start (GTK_BOX (vbox9), frame25, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame25), 5); + + alignment20 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment20); + gtk_container_add (GTK_CONTAINER (frame25), alignment20); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment20), 0, 0, 12, 0); + + vbox28 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox28); + gtk_container_add (GTK_CONTAINER (alignment20), vbox28); + + use_sipinfo = gtk_check_button_new_with_mnemonic (_("Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting")); + gtk_widget_show (use_sipinfo); + gtk_box_pack_start (GTK_BOX (vbox28), use_sipinfo, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, use_sipinfo, _("RTP-RFC2833 is the recommended way."), NULL); + + label103 = gtk_label_new (_("Other")); + gtk_widget_show (label103); + gtk_frame_set_label_widget (GTK_FRAME (frame25), label103); + gtk_label_set_use_markup (GTK_LABEL (label103), TRUE); + + network = gtk_label_new (_("Network")); + gtk_widget_show (network); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), network); + gtk_label_set_justify (GTK_LABEL (network), GTK_JUSTIFY_CENTER); + + vbox12 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox12); + gtk_container_add (GTK_CONTAINER (notebook1), vbox12); + + vbox20 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox20); + gtk_box_pack_start (GTK_BOX (vbox12), vbox20, FALSE, TRUE, 0); + + frame17 = gtk_frame_new (NULL); + gtk_widget_show (frame17); + gtk_box_pack_start (GTK_BOX (vbox20), frame17, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame17), 10); + + vbox16 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox16); + gtk_container_add (GTK_CONTAINER (frame17), vbox16); + + table4 = gtk_table_new (6, 2, FALSE); + gtk_widget_show (table4); + gtk_box_pack_start (GTK_BOX (vbox16), table4, TRUE, TRUE, 0); + + label10 = gtk_label_new (_("Playback sound device:")); + gtk_widget_show (label10); + gtk_table_attach (GTK_TABLE (table4), label10, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_EXPAND), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label10), 0, 0.5); + + combo3 = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (combo3)->popwin), + "GladeParentKey", combo3); + gtk_widget_show (combo3); + gtk_table_attach (GTK_TABLE (table4), combo3, 1, 2, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_combo_set_value_in_list (GTK_COMBO (combo3), TRUE, FALSE); + combo3_items = g_list_append (combo3_items, (gpointer) _("micro")); + combo3_items = g_list_append (combo3_items, (gpointer) _("line")); + combo3_items = g_list_append (combo3_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (combo3), combo3_items); + g_list_free (combo3_items); + + rec_source = GTK_COMBO (combo3)->entry; + gtk_widget_show (rec_source); + gtk_editable_set_editable (GTK_EDITABLE (rec_source), FALSE); + + label106 = gtk_label_new (_("Capture sound device:")); + gtk_widget_show (label106); + gtk_table_attach (GTK_TABLE (table4), label106, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label106), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label106), 0, 0.5); + + play_card = gtk_combo_box_new_text (); + gtk_widget_show (play_card); + gtk_table_attach (GTK_TABLE (table4), play_card, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + capt_card = gtk_combo_box_new_text (); + gtk_widget_show (capt_card); + gtk_table_attach (GTK_TABLE (table4), capt_card, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hbox20 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox20); + gtk_table_attach (GTK_TABLE (table4), hbox20, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + ringfileentry = gnome_file_entry_new (NULL, _("Ring sound selection")); + gtk_widget_show (ringfileentry); + gtk_box_pack_start (GTK_BOX (hbox20), ringfileentry, TRUE, TRUE, 0); + gnome_file_entry_set_modal (GNOME_FILE_ENTRY (ringfileentry), TRUE); + + combo_entry1 = gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (ringfileentry)); + gtk_widget_show (combo_entry1); + + ringpreview = gtk_button_new (); + gtk_widget_show (ringpreview); + gtk_box_pack_start (GTK_BOX (hbox20), ringpreview, FALSE, FALSE, 10); + + alignment8 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment8); + gtk_container_add (GTK_CONTAINER (ringpreview), alignment8); + + hbox21 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox21); + gtk_container_add (GTK_CONTAINER (alignment8), hbox21); + + image15 = gtk_image_new_from_stock ("gnome-stock-volume", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image15); + gtk_box_pack_start (GTK_BOX (hbox21), image15, FALSE, FALSE, 0); + + label64 = gtk_label_new_with_mnemonic (_("Listen")); + gtk_widget_show (label64); + gtk_box_pack_start (GTK_BOX (hbox21), label64, FALSE, FALSE, 0); + + label11 = gtk_label_new (_("Recording source:")); + gtk_widget_show (label11); + gtk_table_attach (GTK_TABLE (table4), label11, 0, 1, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label11), 0, 0.5); + + ringsnddev_label = gtk_label_new (_("Ring sound device")); + gtk_widget_show (ringsnddev_label); + gtk_table_attach (GTK_TABLE (table4), ringsnddev_label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (ringsnddev_label), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (ringsnddev_label), 0, 0.5); + + label63 = gtk_label_new (_("Ring sound:")); + gtk_widget_show (label63); + gtk_table_attach (GTK_TABLE (table4), label63, 0, 1, 4, 5, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label63), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label63), 0, 0.5); + + ring_card = gtk_combo_box_new_text (); + gtk_widget_show (ring_card); + gtk_table_attach (GTK_TABLE (table4), ring_card, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + echocancelation = gtk_check_button_new_with_mnemonic (""); + gtk_widget_show (echocancelation); + gtk_table_attach (GTK_TABLE (table4), echocancelation, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label115 = gtk_label_new (_("Enable echo-canceler (cancels the echo heard by the remote party)")); + gtk_widget_show (label115); + gtk_table_attach (GTK_TABLE (table4), label115, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label115), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label115), 0, 0.5); + + label48 = gtk_label_new (_("Sound properties")); + gtk_widget_show (label48); + gtk_frame_set_label_widget (GTK_FRAME (frame17), label48); + + sound = gtk_label_new (_("Sound device")); + gtk_widget_show (sound); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), sound); + gtk_label_set_justify (GTK_LABEL (sound), GTK_JUSTIFY_CENTER); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (notebook1), vbox7); + + frame10 = gtk_frame_new (NULL); + gtk_widget_show (frame10); + gtk_box_pack_start (GTK_BOX (vbox7), frame10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame10), 10); + + hbox6 = gtk_hbox_new (FALSE, 67); + gtk_widget_show (hbox6); + gtk_container_add (GTK_CONTAINER (frame10), hbox6); + + label13 = gtk_label_new (_("Run sip user agent on port:")); + gtk_widget_show (label13); + gtk_box_pack_start (GTK_BOX (hbox6), label13, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label13), GTK_JUSTIFY_CENTER); + + sip_port_adj = gtk_adjustment_new (5060, 5000, 65535, 1, 10, 10); + sip_port = gtk_spin_button_new (GTK_ADJUSTMENT (sip_port_adj), 4, 0); + gtk_widget_show (sip_port); + gtk_box_pack_start (GTK_BOX (hbox6), sip_port, TRUE, TRUE, 32); + gtk_tooltips_set_tip (tooltips, sip_port, _("It is strongly recommended to use port 5060."), NULL); + + label43 = gtk_label_new (_("SIP port")); + gtk_widget_show (label43); + gtk_frame_set_label_widget (GTK_FRAME (frame10), label43); + + frame11 = gtk_frame_new (NULL); + gtk_widget_show (frame11); + gtk_box_pack_start (GTK_BOX (vbox7), frame11, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame11), 10); + + vbox27 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox27); + gtk_container_add (GTK_CONTAINER (frame11), vbox27); + + hbox7 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox7); + gtk_box_pack_start (GTK_BOX (vbox27), hbox7, TRUE, TRUE, 0); + + label26 = gtk_label_new (_("Your sip address:")); + gtk_widget_show (label26); + gtk_box_pack_start (GTK_BOX (hbox7), label26, TRUE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label26), GTK_JUSTIFY_CENTER); + + label27 = gtk_label_new (_("sip:")); + gtk_widget_show (label27); + gtk_box_pack_start (GTK_BOX (hbox7), label27, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label27), GTK_JUSTIFY_RIGHT); + + user_name = gtk_entry_new (); + gtk_widget_show (user_name); + gtk_box_pack_start (GTK_BOX (hbox7), user_name, FALSE, FALSE, 0); + + label28 = gtk_label_new (_("@")); + gtk_widget_show (label28); + gtk_box_pack_start (GTK_BOX (hbox7), label28, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label28), GTK_JUSTIFY_CENTER); + + domain_name = gtk_entry_new (); + gtk_widget_show (domain_name); + gtk_box_pack_start (GTK_BOX (hbox7), domain_name, FALSE, TRUE, 0); + + guess_hostname = gtk_check_button_new_with_mnemonic (_("Automatically guess a valid hostname")); + gtk_widget_show (guess_hostname); + gtk_box_pack_start (GTK_BOX (vbox27), guess_hostname, TRUE, TRUE, 0); + + label44 = gtk_label_new (_("Identity")); + gtk_widget_show (label44); + gtk_frame_set_label_widget (GTK_FRAME (frame11), label44); + + frame1 = gtk_frame_new (NULL); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox7), frame1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame1), 10); + + vbox23 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox23); + gtk_container_add (GTK_CONTAINER (frame1), vbox23); + + scrolledwindow4 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow4); + gtk_box_pack_start (GTK_BOX (vbox23), scrolledwindow4, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_SHADOW_ETCHED_OUT); + + proxy_list = gtk_tree_view_new (); + gtk_widget_show (proxy_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow4), proxy_list); + gtk_widget_set_size_request (proxy_list, -1, 100); + + hbuttonbox6 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox6); + gtk_box_pack_start (GTK_BOX (vbox23), hbuttonbox6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox6), 5); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox6), GTK_BUTTONBOX_SPREAD); + + addproxy_button = gtk_button_new (); + gtk_widget_show (addproxy_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), addproxy_button); + GTK_WIDGET_SET_FLAGS (addproxy_button, GTK_CAN_DEFAULT); + + alignment12 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment12); + gtk_container_add (GTK_CONTAINER (addproxy_button), alignment12); + + hbox25 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox25); + gtk_container_add (GTK_CONTAINER (alignment12), hbox25); + + image19 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image19); + gtk_box_pack_start (GTK_BOX (hbox25), image19, FALSE, FALSE, 0); + + label77 = gtk_label_new_with_mnemonic (_("Add proxy/registrar")); + gtk_widget_show (label77); + gtk_box_pack_start (GTK_BOX (hbox25), label77, FALSE, FALSE, 0); + + editproxy_button = gtk_button_new (); + gtk_widget_show (editproxy_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), editproxy_button); + GTK_WIDGET_SET_FLAGS (editproxy_button, GTK_CAN_DEFAULT); + + alignment13 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment13); + gtk_container_add (GTK_CONTAINER (editproxy_button), alignment13); + + hbox26 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox26); + gtk_container_add (GTK_CONTAINER (alignment13), hbox26); + + image20 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image20); + gtk_box_pack_start (GTK_BOX (hbox26), image20, FALSE, FALSE, 0); + + label78 = gtk_label_new_with_mnemonic (_("Edit")); + gtk_widget_show (label78); + gtk_box_pack_start (GTK_BOX (hbox26), label78, FALSE, FALSE, 0); + + removeproxy_button = gtk_button_new (); + gtk_widget_show (removeproxy_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), removeproxy_button); + GTK_WIDGET_SET_FLAGS (removeproxy_button, GTK_CAN_DEFAULT); + + alignment14 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment14); + gtk_container_add (GTK_CONTAINER (removeproxy_button), alignment14); + + hbox27 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox27); + gtk_container_add (GTK_CONTAINER (alignment14), hbox27); + + image21 = gtk_image_new_from_stock ("gtk-cancel", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image21); + gtk_box_pack_start (GTK_BOX (hbox27), image21, FALSE, FALSE, 0); + + label79 = gtk_label_new_with_mnemonic (_("Remove")); + gtk_widget_show (label79); + gtk_box_pack_start (GTK_BOX (hbox27), label79, FALSE, FALSE, 0); + + label45 = gtk_label_new (_("Remote services")); + gtk_widget_show (label45); + gtk_frame_set_label_widget (GTK_FRAME (frame1), label45); + + frame24 = gtk_frame_new (NULL); + gtk_widget_show (frame24); + gtk_box_pack_start (GTK_BOX (vbox7), frame24, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame24), 10); + + alignment18 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment18); + gtk_container_add (GTK_CONTAINER (frame24), alignment18); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment18), 0, 0, 12, 0); + + clear_auth_info = gtk_button_new (); + gtk_widget_show (clear_auth_info); + gtk_container_add (GTK_CONTAINER (alignment18), clear_auth_info); + + alignment19 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment19); + gtk_container_add (GTK_CONTAINER (clear_auth_info), alignment19); + + hbox34 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox34); + gtk_container_add (GTK_CONTAINER (alignment19), hbox34); + + image27 = gtk_image_new_from_stock ("gtk-delete", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image27); + gtk_box_pack_start (GTK_BOX (hbox34), image27, FALSE, FALSE, 0); + + label102 = gtk_label_new_with_mnemonic (_("Clear all stored authentication information (username,password...)")); + gtk_widget_show (label102); + gtk_box_pack_start (GTK_BOX (hbox34), label102, FALSE, FALSE, 0); + + label101 = gtk_label_new (_("Authentication information")); + gtk_widget_show (label101); + gtk_frame_set_label_widget (GTK_FRAME (frame24), label101); + + sip_pref = gtk_label_new (_("SIP")); + gtk_widget_show (sip_pref); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 2), sip_pref); + gtk_label_set_justify (GTK_LABEL (sip_pref), GTK_JUSTIFY_CENTER); + + vbox13 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox13); + gtk_container_add (GTK_CONTAINER (notebook1), vbox13); + + frame16 = gtk_frame_new (NULL); + gtk_widget_show (frame16); + gtk_box_pack_start (GTK_BOX (vbox13), frame16, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame16), 10); + + hbox9 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox9); + gtk_container_add (GTK_CONTAINER (frame16), hbox9); + + vbox14 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox14); + gtk_box_pack_start (GTK_BOX (hbox9), vbox14, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox14), 9); + + label9 = gtk_label_new (_("List of audio codecs, in order of preference:")); + gtk_widget_show (label9); + gtk_box_pack_start (GTK_BOX (vbox14), label9, FALSE, FALSE, 4); + gtk_misc_set_alignment (GTK_MISC (label9), 0, 0.5); + + codec_notebook = gtk_notebook_new (); + gtk_widget_show (codec_notebook); + gtk_box_pack_start (GTK_BOX (vbox14), codec_notebook, TRUE, TRUE, 0); + + scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow2); + gtk_container_add (GTK_CONTAINER (codec_notebook), scrolledwindow2); + GTK_WIDGET_UNSET_FLAGS (scrolledwindow2, GTK_CAN_FOCUS); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_SHADOW_ETCHED_IN); + + au_codec_list = gtk_tree_view_new (); + gtk_widget_show (au_codec_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow2), au_codec_list); + gtk_tree_view_set_reorderable (GTK_TREE_VIEW (au_codec_list), TRUE); + + label116 = gtk_label_new (_("Audio codecs")); + gtk_widget_show (label116); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (codec_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (codec_notebook), 0), label116); + + scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow7); + gtk_container_add (GTK_CONTAINER (codec_notebook), scrolledwindow7); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_IN); + + vid_codec_list = gtk_tree_view_new (); + gtk_widget_show (vid_codec_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow7), vid_codec_list); + + label117 = gtk_label_new (_("Video Codecs")); + gtk_widget_show (label117); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (codec_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (codec_notebook), 1), label117); + + hbuttonbox4 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox4); + gtk_box_pack_start (GTK_BOX (vbox14), hbuttonbox4, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox4), 10); + + aucodec_up = gtk_button_new_from_stock ("gtk-go-up"); + gtk_widget_show (aucodec_up); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_up); + GTK_WIDGET_SET_FLAGS (aucodec_up, GTK_CAN_DEFAULT); + + aucodec_down = gtk_button_new_from_stock ("gtk-go-down"); + gtk_widget_show (aucodec_down); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_down); + GTK_WIDGET_SET_FLAGS (aucodec_down, GTK_CAN_DEFAULT); + + aucodec_enable = gtk_button_new (); + gtk_widget_show (aucodec_enable); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_enable); + GTK_WIDGET_SET_FLAGS (aucodec_enable, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (aucodec_enable), alignment1); + + hbox11 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox11); + gtk_container_add (GTK_CONTAINER (alignment1), hbox11); + + image4 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image4); + gtk_box_pack_start (GTK_BOX (hbox11), image4, FALSE, FALSE, 0); + + label50 = gtk_label_new_with_mnemonic (_("Enable")); + gtk_widget_show (label50); + gtk_box_pack_start (GTK_BOX (hbox11), label50, FALSE, FALSE, 0); + + aucodec_disable = gtk_button_new (); + gtk_widget_show (aucodec_disable); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_disable); + GTK_WIDGET_SET_FLAGS (aucodec_disable, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (aucodec_disable), alignment2); + + hbox12 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox12); + gtk_container_add (GTK_CONTAINER (alignment2), hbox12); + + image5 = gtk_image_new_from_stock ("gtk-cancel", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image5); + gtk_box_pack_start (GTK_BOX (hbox12), image5, FALSE, FALSE, 0); + + label51 = gtk_label_new_with_mnemonic (_("Disable")); + gtk_widget_show (label51); + gtk_box_pack_start (GTK_BOX (hbox12), label51, FALSE, FALSE, 0); + + table12 = gtk_table_new (2, 2, TRUE); + gtk_widget_show (table12); + gtk_box_pack_start (GTK_BOX (vbox14), table12, FALSE, TRUE, 0); + + label112 = gtk_label_new (_("Upload bandwidth (kbit/sec):")); + gtk_widget_show (label112); + gtk_table_attach (GTK_TABLE (table12), label112, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label112), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label112), 0, 0.5); + + label111 = gtk_label_new (_("Download bandwidth (kbit/sec):")); + gtk_widget_show (label111); + gtk_table_attach (GTK_TABLE (table12), label111, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label111), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label111), 0, 0.5); + + download_bw_adj = gtk_adjustment_new (0, 0, 100000, 10, 100, 10); + download_bw = gtk_spin_button_new (GTK_ADJUSTMENT (download_bw_adj), 1, 0); + gtk_widget_show (download_bw); + gtk_table_attach (GTK_TABLE (table12), download_bw, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (download_bw), GTK_UPDATE_IF_VALID); + + upload_bw_adj = gtk_adjustment_new (0, 0, 100000, 10, 100, 10); + upload_bw = gtk_spin_button_new (GTK_ADJUSTMENT (upload_bw_adj), 1, 0); + gtk_widget_show (upload_bw); + gtk_table_attach (GTK_TABLE (table12), upload_bw, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox17 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox17); + gtk_box_pack_start (GTK_BOX (hbox9), vbox17, TRUE, FALSE, 0); + + label22 = gtk_label_new (_("Note: Codecs in red are not usable regarding to your connection type to the internet.")); + gtk_widget_show (label22); + gtk_box_pack_start (GTK_BOX (vbox17), label22, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label22), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label22), TRUE); + gtk_misc_set_padding (GTK_MISC (label22), 15, 0); + + frame18 = gtk_frame_new (NULL); + gtk_widget_show (frame18); + gtk_box_pack_start (GTK_BOX (vbox17), frame18, TRUE, TRUE, 5); + gtk_container_set_border_width (GTK_CONTAINER (frame18), 8); + + codec_info = gtk_label_new (_("No information availlable")); + gtk_widget_show (codec_info); + gtk_container_add (GTK_CONTAINER (frame18), codec_info); + gtk_label_set_justify (GTK_LABEL (codec_info), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (codec_info), TRUE); + gtk_misc_set_padding (GTK_MISC (codec_info), 10, 10); + + label47 = gtk_label_new (_("Codec information")); + gtk_widget_show (label47); + gtk_frame_set_label_widget (GTK_FRAME (frame18), label47); + + label46 = gtk_label_new (_("Audio and video codecs")); + gtk_widget_show (label46); + gtk_frame_set_label_widget (GTK_FRAME (frame16), label46); + gtk_misc_set_alignment (GTK_MISC (label46), 0.53, 0.5); + + codecs_pref = gtk_label_new (_("Codecs")); + gtk_widget_show (codecs_pref); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 3), codecs_pref); + gtk_label_set_justify (GTK_LABEL (codecs_pref), GTK_JUSTIFY_CENTER); + + g_signal_connect ((gpointer) prop1, "apply", + G_CALLBACK (on_propertybox1_apply), + NULL); + g_signal_connect ((gpointer) prop1, "close", + G_CALLBACK (on_prop1_close), + NULL); + g_signal_connect ((gpointer) prop1, "help", + G_CALLBACK (on_prop1_help), + NULL); + g_signal_connect ((gpointer) prop1, "close", + G_CALLBACK (on_property_box_closed), + NULL); + g_signal_connect ((gpointer) enable_ipv6, "toggled", + G_CALLBACK (on_enable_ipv6_toggled), + NULL); + g_signal_connect ((gpointer) no_nat, "toggled", + G_CALLBACK (on_no_nat_toggled), + NULL); + g_signal_connect ((gpointer) use_stun, "toggled", + G_CALLBACK (on_use_stun_toggled), + NULL); + g_signal_connect ((gpointer) static_nat, "toggled", + G_CALLBACK (on_static_nat_toggled), + NULL); + g_signal_connect ((gpointer) nat_address, "changed", + G_CALLBACK (on_nat_address_changed), + NULL); + g_signal_connect ((gpointer) stun_server, "changed", + G_CALLBACK (on_stun_server_changed), + NULL); + g_signal_connect ((gpointer) audio_jittcomp, "value_changed", + G_CALLBACK (on_audio_jittcomp_value_changed), + NULL); + g_signal_connect ((gpointer) audioport, "changed", + G_CALLBACK (on_audioport_changed), + NULL); + g_signal_connect ((gpointer) use_sipinfo, "toggled", + G_CALLBACK (on_use_sipinfo_toggled), + NULL); + g_signal_connect ((gpointer) rec_source, "changed", + G_CALLBACK (on_source_changed), + NULL); + g_signal_connect ((gpointer) play_card, "changed", + G_CALLBACK (on_play_card_changed), + NULL); + g_signal_connect ((gpointer) capt_card, "changed", + G_CALLBACK (on_capt_card_changed), + NULL); + g_signal_connect ((gpointer) ringfileentry, "changed", + G_CALLBACK (on_ringfileentry_changed), + NULL); + g_signal_connect ((gpointer) ringpreview, "clicked", + G_CALLBACK (on_ringpreview_clicked), + NULL); + g_signal_connect ((gpointer) ring_card, "changed", + G_CALLBACK (on_ring_card_changed), + NULL); + g_signal_connect ((gpointer) echocancelation, "toggled", + G_CALLBACK (on_echocancelation_toggled), + NULL); + g_signal_connect ((gpointer) sip_port, "changed", + G_CALLBACK (on_sipport_changed), + NULL); + g_signal_connect ((gpointer) user_name, "changed", + G_CALLBACK (on_user_name_changed), + NULL); + g_signal_connect ((gpointer) domain_name, "changed", + G_CALLBACK (on_domain_name_changed), + NULL); + g_signal_connect ((gpointer) guess_hostname, "toggled", + G_CALLBACK (on_guess_hostname_toggled), + NULL); + g_signal_connect ((gpointer) addproxy_button, "clicked", + G_CALLBACK (on_addproxy_button_clicked), + NULL); + g_signal_connect ((gpointer) editproxy_button, "clicked", + G_CALLBACK (on_editproxy_button_clicked), + NULL); + g_signal_connect ((gpointer) removeproxy_button, "clicked", + G_CALLBACK (on_removeproxy_button_clicked), + NULL); + g_signal_connect ((gpointer) clear_auth_info, "clicked", + G_CALLBACK (on_clear_auth_info_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_up, "clicked", + G_CALLBACK (on_aucodec_up_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_down, "clicked", + G_CALLBACK (on_aucodec_down_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_enable, "clicked", + G_CALLBACK (on_aucodec_enable_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_disable, "clicked", + G_CALLBACK (on_aucodec_disable_clicked), + NULL); + g_signal_connect ((gpointer) download_bw, "value_changed", + G_CALLBACK (on_download_bw_value_changed), + NULL); + g_signal_connect ((gpointer) upload_bw, "value_changed", + G_CALLBACK (on_upload_bw_value_changed), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (prop1, prop1, "prop1"); + GLADE_HOOKUP_OBJECT_NO_REF (prop1, notebook1, "notebook1"); + GLADE_HOOKUP_OBJECT (prop1, vbox9, "vbox9"); + GLADE_HOOKUP_OBJECT (prop1, frame26, "frame26"); + GLADE_HOOKUP_OBJECT (prop1, alignment21, "alignment21"); + GLADE_HOOKUP_OBJECT (prop1, vbox29, "vbox29"); + GLADE_HOOKUP_OBJECT (prop1, enable_ipv6, "enable_ipv6"); + GLADE_HOOKUP_OBJECT (prop1, label105, "label105"); + GLADE_HOOKUP_OBJECT (prop1, frame21, "frame21"); + GLADE_HOOKUP_OBJECT (prop1, vbox21, "vbox21"); + GLADE_HOOKUP_OBJECT (prop1, label56, "label56"); + GLADE_HOOKUP_OBJECT (prop1, table13, "table13"); + GLADE_HOOKUP_OBJECT (prop1, no_nat, "no_nat"); + GLADE_HOOKUP_OBJECT (prop1, use_stun, "use_stun"); + GLADE_HOOKUP_OBJECT (prop1, static_nat, "static_nat"); + GLADE_HOOKUP_OBJECT (prop1, nat_address, "nat_address"); + GLADE_HOOKUP_OBJECT (prop1, stun_server, "stun_server"); + GLADE_HOOKUP_OBJECT (prop1, label55, "label55"); + GLADE_HOOKUP_OBJECT (prop1, frame20, "frame20"); + GLADE_HOOKUP_OBJECT (prop1, table6, "table6"); + GLADE_HOOKUP_OBJECT (prop1, audio_jittcomp, "audio_jittcomp"); + GLADE_HOOKUP_OBJECT (prop1, audioport, "audioport"); + GLADE_HOOKUP_OBJECT (prop1, label52, "label52"); + GLADE_HOOKUP_OBJECT (prop1, label53, "label53"); + GLADE_HOOKUP_OBJECT (prop1, label54, "label54"); + GLADE_HOOKUP_OBJECT (prop1, frame25, "frame25"); + GLADE_HOOKUP_OBJECT (prop1, alignment20, "alignment20"); + GLADE_HOOKUP_OBJECT (prop1, vbox28, "vbox28"); + GLADE_HOOKUP_OBJECT (prop1, use_sipinfo, "use_sipinfo"); + GLADE_HOOKUP_OBJECT (prop1, label103, "label103"); + GLADE_HOOKUP_OBJECT (prop1, network, "network"); + GLADE_HOOKUP_OBJECT (prop1, vbox12, "vbox12"); + GLADE_HOOKUP_OBJECT (prop1, vbox20, "vbox20"); + GLADE_HOOKUP_OBJECT (prop1, frame17, "frame17"); + GLADE_HOOKUP_OBJECT (prop1, vbox16, "vbox16"); + GLADE_HOOKUP_OBJECT (prop1, table4, "table4"); + GLADE_HOOKUP_OBJECT (prop1, label10, "label10"); + GLADE_HOOKUP_OBJECT (prop1, combo3, "combo3"); + GLADE_HOOKUP_OBJECT (prop1, rec_source, "rec_source"); + GLADE_HOOKUP_OBJECT (prop1, label106, "label106"); + GLADE_HOOKUP_OBJECT (prop1, play_card, "play_card"); + GLADE_HOOKUP_OBJECT (prop1, capt_card, "capt_card"); + GLADE_HOOKUP_OBJECT (prop1, hbox20, "hbox20"); + GLADE_HOOKUP_OBJECT (prop1, ringfileentry, "ringfileentry"); + GLADE_HOOKUP_OBJECT (prop1, combo_entry1, "combo_entry1"); + GLADE_HOOKUP_OBJECT (prop1, ringpreview, "ringpreview"); + GLADE_HOOKUP_OBJECT (prop1, alignment8, "alignment8"); + GLADE_HOOKUP_OBJECT (prop1, hbox21, "hbox21"); + GLADE_HOOKUP_OBJECT (prop1, image15, "image15"); + GLADE_HOOKUP_OBJECT (prop1, label64, "label64"); + GLADE_HOOKUP_OBJECT (prop1, label11, "label11"); + GLADE_HOOKUP_OBJECT (prop1, ringsnddev_label, "ringsnddev_label"); + GLADE_HOOKUP_OBJECT (prop1, label63, "label63"); + GLADE_HOOKUP_OBJECT (prop1, ring_card, "ring_card"); + GLADE_HOOKUP_OBJECT (prop1, echocancelation, "echocancelation"); + GLADE_HOOKUP_OBJECT (prop1, label115, "label115"); + GLADE_HOOKUP_OBJECT (prop1, label48, "label48"); + GLADE_HOOKUP_OBJECT (prop1, sound, "sound"); + GLADE_HOOKUP_OBJECT (prop1, vbox7, "vbox7"); + GLADE_HOOKUP_OBJECT (prop1, frame10, "frame10"); + GLADE_HOOKUP_OBJECT (prop1, hbox6, "hbox6"); + GLADE_HOOKUP_OBJECT (prop1, label13, "label13"); + GLADE_HOOKUP_OBJECT (prop1, sip_port, "sip_port"); + GLADE_HOOKUP_OBJECT (prop1, label43, "label43"); + GLADE_HOOKUP_OBJECT (prop1, frame11, "frame11"); + GLADE_HOOKUP_OBJECT (prop1, vbox27, "vbox27"); + GLADE_HOOKUP_OBJECT (prop1, hbox7, "hbox7"); + GLADE_HOOKUP_OBJECT (prop1, label26, "label26"); + GLADE_HOOKUP_OBJECT (prop1, label27, "label27"); + GLADE_HOOKUP_OBJECT (prop1, user_name, "user_name"); + GLADE_HOOKUP_OBJECT (prop1, label28, "label28"); + GLADE_HOOKUP_OBJECT (prop1, domain_name, "domain_name"); + GLADE_HOOKUP_OBJECT (prop1, guess_hostname, "guess_hostname"); + GLADE_HOOKUP_OBJECT (prop1, label44, "label44"); + GLADE_HOOKUP_OBJECT (prop1, frame1, "frame1"); + GLADE_HOOKUP_OBJECT (prop1, vbox23, "vbox23"); + GLADE_HOOKUP_OBJECT (prop1, scrolledwindow4, "scrolledwindow4"); + GLADE_HOOKUP_OBJECT (prop1, proxy_list, "proxy_list"); + GLADE_HOOKUP_OBJECT (prop1, hbuttonbox6, "hbuttonbox6"); + GLADE_HOOKUP_OBJECT (prop1, addproxy_button, "addproxy_button"); + GLADE_HOOKUP_OBJECT (prop1, alignment12, "alignment12"); + GLADE_HOOKUP_OBJECT (prop1, hbox25, "hbox25"); + GLADE_HOOKUP_OBJECT (prop1, image19, "image19"); + GLADE_HOOKUP_OBJECT (prop1, label77, "label77"); + GLADE_HOOKUP_OBJECT (prop1, editproxy_button, "editproxy_button"); + GLADE_HOOKUP_OBJECT (prop1, alignment13, "alignment13"); + GLADE_HOOKUP_OBJECT (prop1, hbox26, "hbox26"); + GLADE_HOOKUP_OBJECT (prop1, image20, "image20"); + GLADE_HOOKUP_OBJECT (prop1, label78, "label78"); + GLADE_HOOKUP_OBJECT (prop1, removeproxy_button, "removeproxy_button"); + GLADE_HOOKUP_OBJECT (prop1, alignment14, "alignment14"); + GLADE_HOOKUP_OBJECT (prop1, hbox27, "hbox27"); + GLADE_HOOKUP_OBJECT (prop1, image21, "image21"); + GLADE_HOOKUP_OBJECT (prop1, label79, "label79"); + GLADE_HOOKUP_OBJECT (prop1, label45, "label45"); + GLADE_HOOKUP_OBJECT (prop1, frame24, "frame24"); + GLADE_HOOKUP_OBJECT (prop1, alignment18, "alignment18"); + GLADE_HOOKUP_OBJECT (prop1, clear_auth_info, "clear_auth_info"); + GLADE_HOOKUP_OBJECT (prop1, alignment19, "alignment19"); + GLADE_HOOKUP_OBJECT (prop1, hbox34, "hbox34"); + GLADE_HOOKUP_OBJECT (prop1, image27, "image27"); + GLADE_HOOKUP_OBJECT (prop1, label102, "label102"); + GLADE_HOOKUP_OBJECT (prop1, label101, "label101"); + GLADE_HOOKUP_OBJECT (prop1, sip_pref, "sip_pref"); + GLADE_HOOKUP_OBJECT (prop1, vbox13, "vbox13"); + GLADE_HOOKUP_OBJECT (prop1, frame16, "frame16"); + GLADE_HOOKUP_OBJECT (prop1, hbox9, "hbox9"); + GLADE_HOOKUP_OBJECT (prop1, vbox14, "vbox14"); + GLADE_HOOKUP_OBJECT (prop1, label9, "label9"); + GLADE_HOOKUP_OBJECT (prop1, codec_notebook, "codec_notebook"); + GLADE_HOOKUP_OBJECT (prop1, scrolledwindow2, "scrolledwindow2"); + GLADE_HOOKUP_OBJECT (prop1, au_codec_list, "au_codec_list"); + GLADE_HOOKUP_OBJECT (prop1, label116, "label116"); + GLADE_HOOKUP_OBJECT (prop1, scrolledwindow7, "scrolledwindow7"); + GLADE_HOOKUP_OBJECT (prop1, vid_codec_list, "vid_codec_list"); + GLADE_HOOKUP_OBJECT (prop1, label117, "label117"); + GLADE_HOOKUP_OBJECT (prop1, hbuttonbox4, "hbuttonbox4"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_up, "aucodec_up"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_down, "aucodec_down"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_enable, "aucodec_enable"); + GLADE_HOOKUP_OBJECT (prop1, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (prop1, hbox11, "hbox11"); + GLADE_HOOKUP_OBJECT (prop1, image4, "image4"); + GLADE_HOOKUP_OBJECT (prop1, label50, "label50"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_disable, "aucodec_disable"); + GLADE_HOOKUP_OBJECT (prop1, alignment2, "alignment2"); + GLADE_HOOKUP_OBJECT (prop1, hbox12, "hbox12"); + GLADE_HOOKUP_OBJECT (prop1, image5, "image5"); + GLADE_HOOKUP_OBJECT (prop1, label51, "label51"); + GLADE_HOOKUP_OBJECT (prop1, table12, "table12"); + GLADE_HOOKUP_OBJECT (prop1, label112, "label112"); + GLADE_HOOKUP_OBJECT (prop1, label111, "label111"); + GLADE_HOOKUP_OBJECT (prop1, download_bw, "download_bw"); + GLADE_HOOKUP_OBJECT (prop1, upload_bw, "upload_bw"); + GLADE_HOOKUP_OBJECT (prop1, vbox17, "vbox17"); + GLADE_HOOKUP_OBJECT (prop1, label22, "label22"); + GLADE_HOOKUP_OBJECT (prop1, frame18, "frame18"); + GLADE_HOOKUP_OBJECT (prop1, codec_info, "codec_info"); + GLADE_HOOKUP_OBJECT (prop1, label47, "label47"); + GLADE_HOOKUP_OBJECT (prop1, label46, "label46"); + GLADE_HOOKUP_OBJECT (prop1, codecs_pref, "codecs_pref"); + GLADE_HOOKUP_OBJECT_NO_REF (prop1, tooltips, "tooltips"); + + return prop1; +} + +GtkWidget* +create_address_book (void) +{ + GtkWidget *address_book; + GdkPixbuf *address_book_icon_pixbuf; + GtkWidget *dialog_vbox7; + GtkWidget *vbox1; + GtkWidget *scrolledwindow1; + GtkWidget *viewport1; + GtkWidget *address_list; + GtkWidget *dialog_action_area7; + GtkWidget *hbuttonbox1; + GtkWidget *add_address; + GtkWidget *remove_address; + GtkWidget *modify_address; + GtkWidget *alignment15; + GtkWidget *hbox29; + GtkWidget *image22; + GtkWidget *label93; + GtkWidget *close_addbook; + GtkWidget *select_address; + GtkWidget *alignment7; + GtkWidget *hbox19; + GtkWidget *image14; + GtkWidget *label62; + + address_book = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (address_book), _("Address Book")); + gtk_window_set_default_size (GTK_WINDOW (address_book), -1, 305); + address_book_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (address_book_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (address_book), address_book_icon_pixbuf); + gdk_pixbuf_unref (address_book_icon_pixbuf); + } + + dialog_vbox7 = GTK_DIALOG (address_book)->vbox; + gtk_widget_show (dialog_vbox7); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (dialog_vbox7), vbox1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 12); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_box_pack_start (GTK_BOX (vbox1), scrolledwindow1, TRUE, TRUE, 0); + GTK_WIDGET_UNSET_FLAGS (scrolledwindow1, GTK_CAN_FOCUS); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN); + + viewport1 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); + + address_list = gtk_tree_view_new (); + gtk_widget_show (address_list); + gtk_container_add (GTK_CONTAINER (viewport1), address_list); + + dialog_action_area7 = GTK_DIALOG (address_book)->action_area; + gtk_widget_show (dialog_action_area7); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area7), GTK_BUTTONBOX_SPREAD); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (dialog_action_area7), hbuttonbox1); + gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 11); + + add_address = gtk_button_new_from_stock ("gtk-add"); + gtk_widget_show (add_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), add_address); + GTK_WIDGET_SET_FLAGS (add_address, GTK_CAN_DEFAULT); + gtk_button_set_relief (GTK_BUTTON (add_address), GTK_RELIEF_HALF); + + remove_address = gtk_button_new_from_stock ("gtk-delete"); + gtk_widget_show (remove_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), remove_address); + GTK_WIDGET_SET_FLAGS (remove_address, GTK_CAN_DEFAULT); + gtk_button_set_relief (GTK_BUTTON (remove_address), GTK_RELIEF_HALF); + + modify_address = gtk_button_new (); + gtk_widget_show (modify_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), modify_address); + GTK_WIDGET_SET_FLAGS (modify_address, GTK_CAN_DEFAULT); + + alignment15 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment15); + gtk_container_add (GTK_CONTAINER (modify_address), alignment15); + + hbox29 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox29); + gtk_container_add (GTK_CONTAINER (alignment15), hbox29); + + image22 = gtk_image_new_from_stock ("gtk-justify-center", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image22); + gtk_box_pack_start (GTK_BOX (hbox29), image22, FALSE, FALSE, 0); + + label93 = gtk_label_new_with_mnemonic (_("Edit")); + gtk_widget_show (label93); + gtk_box_pack_start (GTK_BOX (hbox29), label93, FALSE, FALSE, 0); + + close_addbook = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (close_addbook); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), close_addbook); + GTK_WIDGET_SET_FLAGS (close_addbook, GTK_CAN_DEFAULT); + + select_address = gtk_button_new (); + gtk_widget_show (select_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), select_address); + GTK_WIDGET_SET_FLAGS (select_address, GTK_CAN_DEFAULT); + + alignment7 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment7); + gtk_container_add (GTK_CONTAINER (select_address), alignment7); + + hbox19 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox19); + gtk_container_add (GTK_CONTAINER (alignment7), hbox19); + + image14 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image14); + gtk_box_pack_start (GTK_BOX (hbox19), image14, FALSE, FALSE, 0); + + label62 = gtk_label_new_with_mnemonic (_("Select")); + gtk_widget_show (label62); + gtk_box_pack_start (GTK_BOX (hbox19), label62, FALSE, FALSE, 0); + + g_signal_connect ((gpointer) add_address, "clicked", + G_CALLBACK (on_add_address_clicked), + NULL); + g_signal_connect ((gpointer) remove_address, "clicked", + G_CALLBACK (on_remove_address_clicked), + NULL); + g_signal_connect ((gpointer) modify_address, "clicked", + G_CALLBACK (on_modify_address_clicked), + NULL); + g_signal_connect ((gpointer) close_addbook, "clicked", + G_CALLBACK (address_book_close), + NULL); + g_signal_connect ((gpointer) select_address, "clicked", + G_CALLBACK (on_select_address_clicked), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (address_book, address_book, "address_book"); + GLADE_HOOKUP_OBJECT_NO_REF (address_book, dialog_vbox7, "dialog_vbox7"); + GLADE_HOOKUP_OBJECT (address_book, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (address_book, scrolledwindow1, "scrolledwindow1"); + GLADE_HOOKUP_OBJECT (address_book, viewport1, "viewport1"); + GLADE_HOOKUP_OBJECT (address_book, address_list, "address_list"); + GLADE_HOOKUP_OBJECT_NO_REF (address_book, dialog_action_area7, "dialog_action_area7"); + GLADE_HOOKUP_OBJECT (address_book, hbuttonbox1, "hbuttonbox1"); + GLADE_HOOKUP_OBJECT (address_book, add_address, "add_address"); + GLADE_HOOKUP_OBJECT (address_book, remove_address, "remove_address"); + GLADE_HOOKUP_OBJECT (address_book, modify_address, "modify_address"); + GLADE_HOOKUP_OBJECT (address_book, alignment15, "alignment15"); + GLADE_HOOKUP_OBJECT (address_book, hbox29, "hbox29"); + GLADE_HOOKUP_OBJECT (address_book, image22, "image22"); + GLADE_HOOKUP_OBJECT (address_book, label93, "label93"); + GLADE_HOOKUP_OBJECT (address_book, close_addbook, "close_addbook"); + GLADE_HOOKUP_OBJECT (address_book, select_address, "select_address"); + GLADE_HOOKUP_OBJECT (address_book, alignment7, "alignment7"); + GLADE_HOOKUP_OBJECT (address_book, hbox19, "hbox19"); + GLADE_HOOKUP_OBJECT (address_book, image14, "image14"); + GLADE_HOOKUP_OBJECT (address_book, label62, "label62"); + + return address_book; +} + +GtkWidget* +create_altressource (void) +{ + GtkWidget *altressource; + GdkPixbuf *altressource_icon_pixbuf; + GtkWidget *dialog_vbox10; + GtkWidget *vbox19; + GtkWidget *label49; + GtkWidget *alt_href; + GtkWidget *dialog_action_area10; + GtkWidget *closebutton1; + + altressource = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (altressource), _("Information")); + gtk_window_set_resizable (GTK_WINDOW (altressource), FALSE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (altressource), TRUE); + altressource_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (altressource_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (altressource), altressource_icon_pixbuf); + gdk_pixbuf_unref (altressource_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (altressource), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox10 = GTK_DIALOG (altressource)->vbox; + gtk_widget_show (dialog_vbox10); + + vbox19 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox19); + gtk_box_pack_start (GTK_BOX (dialog_vbox10), vbox19, TRUE, TRUE, 0); + + label49 = gtk_label_new (_("User is not reachable at the moment but he invites you to contact him using the following alternate ressource:")); + gtk_widget_show (label49); + gtk_box_pack_start (GTK_BOX (vbox19), label49, TRUE, TRUE, 10); + gtk_label_set_justify (GTK_LABEL (label49), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label49), TRUE); + gtk_misc_set_padding (GTK_MISC (label49), 25, 5); + + alt_href = gtk_button_new_with_mnemonic (_("None.")); + gtk_widget_show (alt_href); + gtk_box_pack_start (GTK_BOX (vbox19), alt_href, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (alt_href), 12); + gtk_button_set_relief (GTK_BUTTON (alt_href), GTK_RELIEF_NONE); + + dialog_action_area10 = GTK_DIALOG (altressource)->action_area; + gtk_widget_show (dialog_action_area10); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area10), GTK_BUTTONBOX_END); + + closebutton1 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (closebutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (altressource), closebutton1, GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (closebutton1, GTK_CAN_DEFAULT); + + g_signal_connect_swapped ((gpointer) alt_href, "clicked", + G_CALLBACK (on_alt_href_clicked), + GTK_OBJECT (altressource)); + g_signal_connect ((gpointer) alt_href, "realize", + G_CALLBACK (on_alt_href_realize), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (altressource, altressource, "altressource"); + GLADE_HOOKUP_OBJECT_NO_REF (altressource, dialog_vbox10, "dialog_vbox10"); + GLADE_HOOKUP_OBJECT (altressource, vbox19, "vbox19"); + GLADE_HOOKUP_OBJECT (altressource, label49, "label49"); + GLADE_HOOKUP_OBJECT (altressource, alt_href, "alt_href"); + GLADE_HOOKUP_OBJECT_NO_REF (altressource, dialog_action_area10, "dialog_action_area10"); + GLADE_HOOKUP_OBJECT (altressource, closebutton1, "closebutton1"); + + return altressource; +} + +GtkWidget* +create_proxy_config_box (void) +{ + GtkWidget *proxy_config_box; + GdkPixbuf *proxy_config_box_icon_pixbuf; + GtkWidget *dialog_vbox12; + GtkWidget *frame22; + GtkWidget *table8; + GtkWidget *reg_sendregister; + GtkWidget *label82; + GtkWidget *reg_route; + GtkWidget *reg_proxy; + GtkWidget *label83; + GtkWidget *label84; + GtkWidget *reg_identity; + GtkWidget *label85; + GtkObject *reg_expires_adj; + GtkWidget *reg_expires; + GtkWidget *label81; + GtkWidget *label104; + GtkWidget *publish; + GtkWidget *label86; + GtkWidget *dialog_action_area12; + GtkWidget *helpbutton1; + GtkWidget *okbutton2; + + proxy_config_box = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (proxy_config_box), _("Proxy/Registrar configuration box")); + gtk_window_set_modal (GTK_WINDOW (proxy_config_box), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (proxy_config_box), TRUE); + proxy_config_box_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (proxy_config_box_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (proxy_config_box), proxy_config_box_icon_pixbuf); + gdk_pixbuf_unref (proxy_config_box_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (proxy_config_box), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox12 = GTK_DIALOG (proxy_config_box)->vbox; + gtk_widget_show (dialog_vbox12); + + frame22 = gtk_frame_new (NULL); + gtk_widget_show (frame22); + gtk_box_pack_start (GTK_BOX (dialog_vbox12), frame22, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame22), 8); + + table8 = gtk_table_new (7, 2, FALSE); + gtk_widget_show (table8); + gtk_container_add (GTK_CONTAINER (frame22), table8); + + reg_sendregister = gtk_check_button_new_with_mnemonic (""); + gtk_widget_show (reg_sendregister); + gtk_table_attach (GTK_TABLE (table8), reg_sendregister, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (reg_sendregister), TRUE); + + label82 = gtk_label_new (_("Route (optional):")); + gtk_widget_show (label82); + gtk_table_attach (GTK_TABLE (table8), label82, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label82), 0, 0.5); + + reg_route = gtk_entry_new (); + gtk_widget_show (reg_route); + gtk_table_attach (GTK_TABLE (table8), reg_route, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_max_length (GTK_ENTRY (reg_route), 256); + + reg_proxy = gtk_entry_new (); + gtk_widget_show (reg_proxy); + gtk_table_attach (GTK_TABLE (table8), reg_proxy, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_max_length (GTK_ENTRY (reg_proxy), 250); + gtk_entry_set_text (GTK_ENTRY (reg_proxy), _("sip:")); + + label83 = gtk_label_new (_("SIP Proxy:")); + gtk_widget_show (label83); + gtk_table_attach (GTK_TABLE (table8), label83, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label83), 0, 0.5); + + label84 = gtk_label_new (_("SIP Identity:")); + gtk_widget_show (label84); + gtk_table_attach (GTK_TABLE (table8), label84, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label84), 0, 0.5); + + reg_identity = gtk_entry_new (); + gtk_widget_show (reg_identity); + gtk_table_attach (GTK_TABLE (table8), reg_identity, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_max_length (GTK_ENTRY (reg_identity), 256); + gtk_entry_set_text (GTK_ENTRY (reg_identity), _("sip:")); + + label85 = gtk_label_new (_("Registration Period:")); + gtk_widget_show (label85); + gtk_table_attach (GTK_TABLE (table8), label85, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label85), 0, 0.5); + + reg_expires_adj = gtk_adjustment_new (900, 120, 72000, 1, 10, 10); + reg_expires = gtk_spin_button_new (GTK_ADJUSTMENT (reg_expires_adj), 1, 0); + gtk_widget_show (reg_expires); + gtk_table_attach (GTK_TABLE (table8), reg_expires, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (reg_expires), TRUE); + + label81 = gtk_label_new (_("Send registration:")); + gtk_widget_show (label81); + gtk_table_attach (GTK_TABLE (table8), label81, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label81), 0, 0.5); + + label104 = gtk_label_new (_("Publish presence information:")); + gtk_widget_show (label104); + gtk_table_attach (GTK_TABLE (table8), label104, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label104), 0, 0.5); + + publish = gtk_check_button_new_with_mnemonic (""); + gtk_widget_show (publish); + gtk_table_attach (GTK_TABLE (table8), publish, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label86 = gtk_label_new (_("Proxy/Registrar configuration box")); + gtk_widget_show (label86); + gtk_frame_set_label_widget (GTK_FRAME (frame22), label86); + + dialog_action_area12 = GTK_DIALOG (proxy_config_box)->action_area; + gtk_widget_show (dialog_action_area12); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area12), GTK_BUTTONBOX_END); + + helpbutton1 = gtk_button_new_from_stock ("gtk-help"); + gtk_widget_show (helpbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (proxy_config_box), helpbutton1, GTK_RESPONSE_HELP); + GTK_WIDGET_SET_FLAGS (helpbutton1, GTK_CAN_DEFAULT); + + okbutton2 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (proxy_config_box), okbutton2, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) proxy_config_box, "response", + G_CALLBACK (on_proxy_config_box_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (proxy_config_box, proxy_config_box, "proxy_config_box"); + GLADE_HOOKUP_OBJECT_NO_REF (proxy_config_box, dialog_vbox12, "dialog_vbox12"); + GLADE_HOOKUP_OBJECT (proxy_config_box, frame22, "frame22"); + GLADE_HOOKUP_OBJECT (proxy_config_box, table8, "table8"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_sendregister, "reg_sendregister"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label82, "label82"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_route, "reg_route"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_proxy, "reg_proxy"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label83, "label83"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label84, "label84"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_identity, "reg_identity"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label85, "label85"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_expires, "reg_expires"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label81, "label81"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label104, "label104"); + GLADE_HOOKUP_OBJECT (proxy_config_box, publish, "publish"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label86, "label86"); + GLADE_HOOKUP_OBJECT_NO_REF (proxy_config_box, dialog_action_area12, "dialog_action_area12"); + GLADE_HOOKUP_OBJECT (proxy_config_box, helpbutton1, "helpbutton1"); + GLADE_HOOKUP_OBJECT (proxy_config_box, okbutton2, "okbutton2"); + + gtk_widget_grab_focus (proxy_config_box); + return proxy_config_box; +} + +GtkWidget* +create_contact_box (void) +{ + GtkWidget *contact_box; + GdkPixbuf *contact_box_icon_pixbuf; + GtkWidget *dialog_vbox13; + GtkWidget *frame23; + GtkWidget *vbox25; + GtkWidget *table10; + GtkWidget *sipaddr; + GtkWidget *name; + GtkWidget *label89; + GtkWidget *label90; + GtkWidget *label91; + GtkWidget *label92; + GtkWidget *send_subscribe; + GtkWidget *label88; + GtkWidget *dialog_action_area13; + GtkWidget *helpbutton2; + GtkWidget *cancelbutton2; + GtkWidget *okbutton3; + + contact_box = gtk_dialog_new (); + GTK_WIDGET_SET_FLAGS (contact_box, GTK_CAN_FOCUS); + gtk_window_set_title (GTK_WINDOW (contact_box), _("Edit contact information")); + gtk_window_set_destroy_with_parent (GTK_WINDOW (contact_box), TRUE); + contact_box_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (contact_box_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (contact_box), contact_box_icon_pixbuf); + gdk_pixbuf_unref (contact_box_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (contact_box), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox13 = GTK_DIALOG (contact_box)->vbox; + gtk_widget_show (dialog_vbox13); + + frame23 = gtk_frame_new (NULL); + gtk_widget_show (frame23); + gtk_box_pack_start (GTK_BOX (dialog_vbox13), frame23, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame23), 6); + + vbox25 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox25); + gtk_container_add (GTK_CONTAINER (frame23), vbox25); + + table10 = gtk_table_new (4, 2, TRUE); + gtk_widget_show (table10); + gtk_box_pack_start (GTK_BOX (vbox25), table10, TRUE, TRUE, 0); + + sipaddr = gtk_entry_new (); + gtk_widget_show (sipaddr); + gtk_table_attach (GTK_TABLE (table10), sipaddr, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_text (GTK_ENTRY (sipaddr), _("sip:")); + + name = gtk_entry_new (); + gtk_widget_show (name); + gtk_table_attach (GTK_TABLE (table10), name, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label89 = gtk_label_new (_("Name:")); + gtk_widget_show (label89); + gtk_table_attach (GTK_TABLE (table10), label89, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label89), 0, 0.5); + + label90 = gtk_label_new (_("Sip address:")); + gtk_widget_show (label90); + gtk_table_attach (GTK_TABLE (table10), label90, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label90), 0, 0.5); + + label91 = gtk_label_new (_("Proxy to use:")); + gtk_widget_show (label91); + gtk_table_attach (GTK_TABLE (table10), label91, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label91), 0, 0.5); + + label92 = gtk_label_new (_("Subscribe policy:")); + gtk_widget_show (label92); + gtk_table_attach (GTK_TABLE (table10), label92, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label92), 0, 0.5); + + send_subscribe = gtk_check_button_new_with_mnemonic (_("Send subscription (see person's online status)")); + gtk_widget_show (send_subscribe); + gtk_box_pack_start (GTK_BOX (vbox25), send_subscribe, TRUE, TRUE, 0); + + label88 = gtk_label_new (_("Contact information")); + gtk_widget_show (label88); + gtk_frame_set_label_widget (GTK_FRAME (frame23), label88); + + dialog_action_area13 = GTK_DIALOG (contact_box)->action_area; + gtk_widget_show (dialog_action_area13); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area13), GTK_BUTTONBOX_END); + + helpbutton2 = gtk_button_new_from_stock ("gtk-help"); + gtk_widget_show (helpbutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (contact_box), helpbutton2, GTK_RESPONSE_HELP); + GTK_WIDGET_SET_FLAGS (helpbutton2, GTK_CAN_DEFAULT); + + cancelbutton2 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (contact_box), cancelbutton2, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton2, GTK_CAN_DEFAULT); + + okbutton3 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton3); + gtk_dialog_add_action_widget (GTK_DIALOG (contact_box), okbutton3, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton3, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) contact_box, "response", + G_CALLBACK (on_contact_box_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (contact_box, contact_box, "contact_box"); + GLADE_HOOKUP_OBJECT_NO_REF (contact_box, dialog_vbox13, "dialog_vbox13"); + GLADE_HOOKUP_OBJECT (contact_box, frame23, "frame23"); + GLADE_HOOKUP_OBJECT (contact_box, vbox25, "vbox25"); + GLADE_HOOKUP_OBJECT (contact_box, table10, "table10"); + GLADE_HOOKUP_OBJECT (contact_box, sipaddr, "sipaddr"); + GLADE_HOOKUP_OBJECT (contact_box, name, "name"); + GLADE_HOOKUP_OBJECT (contact_box, label89, "label89"); + GLADE_HOOKUP_OBJECT (contact_box, label90, "label90"); + GLADE_HOOKUP_OBJECT (contact_box, label91, "label91"); + GLADE_HOOKUP_OBJECT (contact_box, label92, "label92"); + GLADE_HOOKUP_OBJECT (contact_box, send_subscribe, "send_subscribe"); + GLADE_HOOKUP_OBJECT (contact_box, label88, "label88"); + GLADE_HOOKUP_OBJECT_NO_REF (contact_box, dialog_action_area13, "dialog_action_area13"); + GLADE_HOOKUP_OBJECT (contact_box, helpbutton2, "helpbutton2"); + GLADE_HOOKUP_OBJECT (contact_box, cancelbutton2, "cancelbutton2"); + GLADE_HOOKUP_OBJECT (contact_box, okbutton3, "okbutton3"); + + return contact_box; +} + +GtkWidget* +create_inc_subscr_dialog (void) +{ + GtkWidget *inc_subscr_dialog; + GdkPixbuf *inc_subscr_dialog_icon_pixbuf; + GtkWidget *dialog_vbox14; + GtkWidget *hbox32; + GtkWidget *image25; + GtkWidget *subscr_label; + GtkWidget *dialog_action_area14; + GtkWidget *button15; + GtkWidget *alignment17; + GtkWidget *hbox31; + GtkWidget *image24; + GtkWidget *label95; + GtkWidget *button16; + GtkWidget *alignment16; + GtkWidget *hbox30; + GtkWidget *image23; + GtkWidget *label94; + + inc_subscr_dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (inc_subscr_dialog), _("New incoming subscription")); + inc_subscr_dialog_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (inc_subscr_dialog_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (inc_subscr_dialog), inc_subscr_dialog_icon_pixbuf); + gdk_pixbuf_unref (inc_subscr_dialog_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (inc_subscr_dialog), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox14 = GTK_DIALOG (inc_subscr_dialog)->vbox; + gtk_widget_show (dialog_vbox14); + + hbox32 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox32); + gtk_box_pack_start (GTK_BOX (dialog_vbox14), hbox32, TRUE, TRUE, 0); + + image25 = gtk_image_new_from_stock ("gtk-dialog-warning", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image25); + gtk_box_pack_start (GTK_BOX (hbox32), image25, FALSE, TRUE, 0); + + subscr_label = gtk_label_new (_("You have received a new subscription...")); + gtk_widget_show (subscr_label); + gtk_box_pack_start (GTK_BOX (hbox32), subscr_label, TRUE, TRUE, 0); + gtk_label_set_line_wrap (GTK_LABEL (subscr_label), TRUE); + gtk_misc_set_padding (GTK_MISC (subscr_label), 14, 9); + + dialog_action_area14 = GTK_DIALOG (inc_subscr_dialog)->action_area; + gtk_widget_show (dialog_action_area14); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area14), GTK_BUTTONBOX_SPREAD); + + button15 = gtk_button_new (); + gtk_widget_show (button15); + gtk_dialog_add_action_widget (GTK_DIALOG (inc_subscr_dialog), button15, GTK_RESPONSE_REJECT); + GTK_WIDGET_SET_FLAGS (button15, GTK_CAN_DEFAULT); + + alignment17 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment17); + gtk_container_add (GTK_CONTAINER (button15), alignment17); + + hbox31 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox31); + gtk_container_add (GTK_CONTAINER (alignment17), hbox31); + + image24 = gtk_image_new_from_stock ("gtk-stop", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image24); + gtk_box_pack_start (GTK_BOX (hbox31), image24, FALSE, FALSE, 0); + + label95 = gtk_label_new_with_mnemonic (_("Refuse")); + gtk_widget_show (label95); + gtk_box_pack_start (GTK_BOX (hbox31), label95, FALSE, FALSE, 0); + + button16 = gtk_button_new (); + gtk_widget_show (button16); + gtk_dialog_add_action_widget (GTK_DIALOG (inc_subscr_dialog), button16, GTK_RESPONSE_ACCEPT); + GTK_WIDGET_SET_FLAGS (button16, GTK_CAN_DEFAULT); + + alignment16 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment16); + gtk_container_add (GTK_CONTAINER (button16), alignment16); + + hbox30 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox30); + gtk_container_add (GTK_CONTAINER (alignment16), hbox30); + + image23 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image23); + gtk_box_pack_start (GTK_BOX (hbox30), image23, FALSE, FALSE, 0); + + label94 = gtk_label_new_with_mnemonic (_("Accept")); + gtk_widget_show (label94); + gtk_box_pack_start (GTK_BOX (hbox30), label94, FALSE, FALSE, 0); + + g_signal_connect ((gpointer) inc_subscr_dialog, "response", + G_CALLBACK (on_inc_subscr_dialog_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (inc_subscr_dialog, inc_subscr_dialog, "inc_subscr_dialog"); + GLADE_HOOKUP_OBJECT_NO_REF (inc_subscr_dialog, dialog_vbox14, "dialog_vbox14"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, hbox32, "hbox32"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, image25, "image25"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, subscr_label, "subscr_label"); + GLADE_HOOKUP_OBJECT_NO_REF (inc_subscr_dialog, dialog_action_area14, "dialog_action_area14"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, button15, "button15"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, alignment17, "alignment17"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, hbox31, "hbox31"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, image24, "image24"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, label95, "label95"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, button16, "button16"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, alignment16, "alignment16"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, hbox30, "hbox30"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, image23, "image23"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, label94, "label94"); + + return inc_subscr_dialog; +} + +GtkWidget* +create_authentication_dialog (void) +{ + GtkWidget *authentication_dialog; + GdkPixbuf *authentication_dialog_icon_pixbuf; + GtkWidget *dialog_vbox15; + GtkWidget *vbox26; + GtkWidget *hbox33; + GtkWidget *image26; + GtkWidget *question; + GtkWidget *table11; + GtkWidget *realm; + GtkWidget *username; + GtkWidget *passwd; + GtkWidget *userid; + GtkWidget *label100; + GtkWidget *label99; + GtkWidget *label98; + GtkWidget *label97; + GtkWidget *dialog_action_area15; + GtkWidget *cancelbutton3; + GtkWidget *okbutton4; + + authentication_dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (authentication_dialog), _("Authentication requested")); + gtk_window_set_destroy_with_parent (GTK_WINDOW (authentication_dialog), TRUE); + authentication_dialog_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (authentication_dialog_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (authentication_dialog), authentication_dialog_icon_pixbuf); + gdk_pixbuf_unref (authentication_dialog_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (authentication_dialog), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox15 = GTK_DIALOG (authentication_dialog)->vbox; + gtk_widget_show (dialog_vbox15); + + vbox26 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox26); + gtk_box_pack_start (GTK_BOX (dialog_vbox15), vbox26, TRUE, TRUE, 0); + + hbox33 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox33); + gtk_box_pack_start (GTK_BOX (vbox26), hbox33, FALSE, FALSE, 0); + + image26 = gtk_image_new_from_stock ("gtk-dialog-question", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image26); + gtk_box_pack_start (GTK_BOX (hbox33), image26, TRUE, TRUE, 0); + gtk_misc_set_padding (GTK_MISC (image26), 16, 0); + + question = gtk_label_new (_("Authentication required for realm")); + gtk_widget_show (question); + gtk_box_pack_start (GTK_BOX (hbox33), question, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (question), GTK_JUSTIFY_CENTER); + gtk_misc_set_padding (GTK_MISC (question), 29, 14); + + table11 = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table11); + gtk_box_pack_start (GTK_BOX (vbox26), table11, TRUE, TRUE, 0); + + realm = gtk_entry_new (); + gtk_widget_show (realm); + gtk_table_attach (GTK_TABLE (table11), realm, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_editable_set_editable (GTK_EDITABLE (realm), FALSE); + + username = gtk_entry_new (); + gtk_widget_show (username); + gtk_table_attach (GTK_TABLE (table11), username, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + passwd = gtk_entry_new (); + gtk_widget_show (passwd); + gtk_table_attach (GTK_TABLE (table11), passwd, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_visibility (GTK_ENTRY (passwd), FALSE); + + userid = gtk_entry_new (); + gtk_widget_show (userid); + gtk_table_attach (GTK_TABLE (table11), userid, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label100 = gtk_label_new (_("userid:")); + gtk_widget_show (label100); + gtk_table_attach (GTK_TABLE (table11), label100, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label100), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label100), 0, 0.5); + + label99 = gtk_label_new (_("password:")); + gtk_widget_show (label99); + gtk_table_attach (GTK_TABLE (table11), label99, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label99), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label99), 0, 0.5); + + label98 = gtk_label_new (_("username:")); + gtk_widget_show (label98); + gtk_table_attach (GTK_TABLE (table11), label98, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label98), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label98), 0, 0.5); + + label97 = gtk_label_new (_("realm:")); + gtk_widget_show (label97); + gtk_table_attach (GTK_TABLE (table11), label97, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label97), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label97), 0, 0.5); + + dialog_action_area15 = GTK_DIALOG (authentication_dialog)->action_area; + gtk_widget_show (dialog_action_area15); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area15), GTK_BUTTONBOX_END); + + cancelbutton3 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton3); + gtk_dialog_add_action_widget (GTK_DIALOG (authentication_dialog), cancelbutton3, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton3, GTK_CAN_DEFAULT); + + okbutton4 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton4); + gtk_dialog_add_action_widget (GTK_DIALOG (authentication_dialog), okbutton4, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton4, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) authentication_dialog, "response", + G_CALLBACK (on_authentication_dialog_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (authentication_dialog, authentication_dialog, "authentication_dialog"); + GLADE_HOOKUP_OBJECT_NO_REF (authentication_dialog, dialog_vbox15, "dialog_vbox15"); + GLADE_HOOKUP_OBJECT (authentication_dialog, vbox26, "vbox26"); + GLADE_HOOKUP_OBJECT (authentication_dialog, hbox33, "hbox33"); + GLADE_HOOKUP_OBJECT (authentication_dialog, image26, "image26"); + GLADE_HOOKUP_OBJECT (authentication_dialog, question, "question"); + GLADE_HOOKUP_OBJECT (authentication_dialog, table11, "table11"); + GLADE_HOOKUP_OBJECT (authentication_dialog, realm, "realm"); + GLADE_HOOKUP_OBJECT (authentication_dialog, username, "username"); + GLADE_HOOKUP_OBJECT (authentication_dialog, passwd, "passwd"); + GLADE_HOOKUP_OBJECT (authentication_dialog, userid, "userid"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label100, "label100"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label99, "label99"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label98, "label98"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label97, "label97"); + GLADE_HOOKUP_OBJECT_NO_REF (authentication_dialog, dialog_action_area15, "dialog_action_area15"); + GLADE_HOOKUP_OBJECT (authentication_dialog, cancelbutton3, "cancelbutton3"); + GLADE_HOOKUP_OBJECT (authentication_dialog, okbutton4, "okbutton4"); + + return authentication_dialog; +} + +GtkWidget* +create_call_logs (void) +{ + GtkWidget *call_logs; + GdkPixbuf *call_logs_icon_pixbuf; + GtkWidget *dialog_vbox16; + GtkWidget *scrolledwindow5; + GtkWidget *logview; + GtkWidget *dialog_action_area16; + GtkWidget *closebutton2; + + call_logs = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (call_logs), _("Linphone - Call history")); + gtk_window_set_default_size (GTK_WINDOW (call_logs), 240, 240); + gtk_window_set_destroy_with_parent (GTK_WINDOW (call_logs), TRUE); + call_logs_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (call_logs_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (call_logs), call_logs_icon_pixbuf); + gdk_pixbuf_unref (call_logs_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (call_logs), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox16 = GTK_DIALOG (call_logs)->vbox; + gtk_widget_show (dialog_vbox16); + + scrolledwindow5 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow5); + gtk_box_pack_start (GTK_BOX (dialog_vbox16), scrolledwindow5, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_SHADOW_IN); + + logview = gtk_text_view_new (); + gtk_widget_show (logview); + gtk_container_add (GTK_CONTAINER (scrolledwindow5), logview); + gtk_text_view_set_editable (GTK_TEXT_VIEW (logview), FALSE); + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (logview), FALSE); + + dialog_action_area16 = GTK_DIALOG (call_logs)->action_area; + gtk_widget_show (dialog_action_area16); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area16), GTK_BUTTONBOX_END); + + closebutton2 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (closebutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (call_logs), closebutton2, GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (closebutton2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) call_logs, "response", + G_CALLBACK (on_call_logs_response), + NULL); + g_signal_connect ((gpointer) call_logs, "destroy", + G_CALLBACK (on_call_logs_destroy), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (call_logs, call_logs, "call_logs"); + GLADE_HOOKUP_OBJECT_NO_REF (call_logs, dialog_vbox16, "dialog_vbox16"); + GLADE_HOOKUP_OBJECT (call_logs, scrolledwindow5, "scrolledwindow5"); + GLADE_HOOKUP_OBJECT (call_logs, logview, "logview"); + GLADE_HOOKUP_OBJECT_NO_REF (call_logs, dialog_action_area16, "dialog_action_area16"); + GLADE_HOOKUP_OBJECT (call_logs, closebutton2, "closebutton2"); + + return call_logs; +} + +GtkWidget* +create_chatroom (void) +{ + GtkWidget *chatroom; + GdkPixbuf *chatroom_icon_pixbuf; + GtkWidget *vbox30; + GtkWidget *scrolledwindow6; + GtkWidget *chattext; + GtkWidget *hbox35; + GtkWidget *label107; + GtkWidget *chatentry; + GtkWidget *button17; + + chatroom = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (chatroom), _("Chat Room")); + gtk_window_set_default_size (GTK_WINDOW (chatroom), 400, 400); + gtk_window_set_destroy_with_parent (GTK_WINDOW (chatroom), TRUE); + chatroom_icon_pixbuf = create_pixbuf ("linphone/linphone2.xpm"); + if (chatroom_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (chatroom), chatroom_icon_pixbuf); + gdk_pixbuf_unref (chatroom_icon_pixbuf); + } + + vbox30 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox30); + gtk_container_add (GTK_CONTAINER (chatroom), vbox30); + + scrolledwindow6 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow6); + gtk_box_pack_start (GTK_BOX (vbox30), scrolledwindow6, TRUE, TRUE, 0); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_SHADOW_IN); + + chattext = gtk_text_view_new (); + gtk_widget_show (chattext); + gtk_container_add (GTK_CONTAINER (scrolledwindow6), chattext); + gtk_text_view_set_editable (GTK_TEXT_VIEW (chattext), FALSE); + + hbox35 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox35); + gtk_box_pack_start (GTK_BOX (vbox30), hbox35, FALSE, TRUE, 0); + + label107 = gtk_label_new (_("Text:")); + gtk_widget_show (label107); + gtk_box_pack_start (GTK_BOX (hbox35), label107, FALSE, FALSE, 0); + + chatentry = gtk_entry_new (); + gtk_widget_show (chatentry); + gtk_box_pack_start (GTK_BOX (hbox35), chatentry, TRUE, TRUE, 0); + + button17 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (button17); + gtk_box_pack_start (GTK_BOX (vbox30), button17, FALSE, FALSE, 0); + + g_signal_connect ((gpointer) chatroom, "destroy", + G_CALLBACK (on_chatroom_destroy), + NULL); + g_signal_connect ((gpointer) chatentry, "activate", + G_CALLBACK (on_chatentry_activate), + NULL); + g_signal_connect ((gpointer) button17, "clicked", + G_CALLBACK (on_chatbox_clicked), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (chatroom, chatroom, "chatroom"); + GLADE_HOOKUP_OBJECT (chatroom, vbox30, "vbox30"); + GLADE_HOOKUP_OBJECT (chatroom, scrolledwindow6, "scrolledwindow6"); + GLADE_HOOKUP_OBJECT (chatroom, chattext, "chattext"); + GLADE_HOOKUP_OBJECT (chatroom, hbox35, "hbox35"); + GLADE_HOOKUP_OBJECT (chatroom, label107, "label107"); + GLADE_HOOKUP_OBJECT (chatroom, chatentry, "chatentry"); + GLADE_HOOKUP_OBJECT (chatroom, button17, "button17"); + + gtk_widget_grab_focus (chatentry); + return chatroom; +} + diff --git a/linphone/gnome/interface.h b/linphone/gnome/interface.h new file mode 100644 index 000000000..1e94fd3f7 --- /dev/null +++ b/linphone/gnome/interface.h @@ -0,0 +1,15 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_app1 (void); +GtkWidget* create_about2 (void); +GtkWidget* create_prop1 (void); +GtkWidget* create_address_book (void); +GtkWidget* create_altressource (void); +GtkWidget* create_proxy_config_box (void); +GtkWidget* create_contact_box (void); +GtkWidget* create_inc_subscr_dialog (void); +GtkWidget* create_authentication_dialog (void); +GtkWidget* create_call_logs (void); +GtkWidget* create_chatroom (void); diff --git a/linphone/gnome/linphone.c b/linphone/gnome/linphone.c new file mode 100644 index 000000000..535cef11d --- /dev/null +++ b/linphone/gnome/linphone.c @@ -0,0 +1,449 @@ +/*************************************************************************** + linphone.c - Main code for linphone's gnome + interface + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "linphone.h" +#include "support.h" +#include "interface.h" +#include "callbacks.h" +#include "gui_utils.h" +#include "lpconfig.h" + + +LinphoneGnomeUI *uiobj=NULL; +#define get_uiobj() (uiobj) +#define get_core() (uiobj->core) +#define get_friend_list() (&uiobj->main_window.friendlist) + +void linphone_gnome_ui_init(LinphoneGnomeUI *ui,LinphoneCore *core) +{ + gdk_threads_init(); + memset(ui,0,sizeof(LinphoneGnomeUI)); + ui->core=core; + uiobj=ui; + ui->main_window.shown_once=FALSE; +} + +static void restore_uri_history(GtkEntry *uribar, LpConfig *cfg){ + char key[20]; + int i; + GtkEntryCompletion *gep=gtk_entry_completion_new(); + GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING); + for (i=0;;i++){ + const char *uri; + snprintf(key,sizeof(key),"uri%i",i); + uri=lp_config_get_string(cfg,"GtkUi",key,NULL); + if (uri!=NULL) { + GtkTreeIter iter; + gtk_list_store_append(model,&iter); + gtk_list_store_set(model,&iter,0,uri,-1); + if (i==0) gtk_entry_set_text(uribar,uri); + } + else break; + } + gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); + gtk_entry_completion_set_text_column(gep,0); + gtk_entry_set_completion(uribar,gep); +} + +void linphone_gnome_save_uri_history(LinphoneGnomeUI *ui){ + char key[20]; + int i=0; + char *uri=NULL; + GtkTreeIter iter; + GtkEntry *uribar=GTK_ENTRY(ui->main_window.addressentry); + GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar)); + LpConfig *cfg=linphone_core_get_config(ui->core); + if (!gtk_tree_model_get_iter_first(model,&iter)) return; + do { + gtk_tree_model_get(model,&iter,0,&uri,-1); + if (uri) { + snprintf(key,sizeof(key),"uri%i",i); + lp_config_set_string(cfg,"GtkUi",key,uri); + g_free(uri); + }else break; + i++; + if (i>5) break; + }while(gtk_tree_model_iter_next(model,&iter)); +} + +void main_window_create(LinphoneGnomeUI *obj) +{ + GtkWidget *child; + GtkWidget *window; + window=create_app1 (); + gnome_window_icon_set_from_default(GTK_WINDOW(window)); + obj->main_window.status_bar=lookup_widget(window,"appbar1"); + obj->main_window.addressentry=lookup_widget(window,"addressentry"); + obj->main_window.optioncontrols=lookup_widget(window,"optioncontrols"); + obj->main_window.dtmfentry=lookup_widget(window,"dtmf_entry"); + obj->main_window.callbutton=lookup_widget(window,"callbutton"); + child=lookup_widget(window,"showmore"); + /* hide the optionnal controls at startup */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(child),0); +#ifndef VIDEO_ENABLED + gtk_widget_hide(lookup_widget(child,"video_enabled")); +#endif + presence_box_init(&obj->main_window.presencebox,window,obj->core); + friend_list_init(&obj->main_window.friendlist,obj->core,window); + g_object_set_data(G_OBJECT(window),"ui",(gpointer)obj); + obj->main_window.window=window; +} + +void linphone_gnome_ui_show(LinphoneGnomeUI *ui) +{ + if (ui->main_window.window==NULL){ + main_window_create(ui); + } + gtk_widget_show(ui->main_window.window); + gtk_window_present(GTK_WINDOW(ui->main_window.window)); + ui->main_window.shown_once=TRUE; +} + +void linphone_gnome_ui_hide(LinphoneGnomeUI *ui) +{ + if (ui->main_window.window==NULL) return; + gtk_widget_hide(ui->main_window.window); +} + + +void linphone_gnome_ui_uninit(LinphoneGnomeUI *ui) +{ + ui->main_window.window=NULL; +} + +void linphone_gnome_ui_display_something(LinphoneGnomeUI *ui,GtkMessageType type,const gchar *message) +{ + GtkWidget *dialog; + + if (!linphone_core_is_in_main_thread(ui->core)) gdk_threads_enter(); + linphone_gnome_ui_show(ui); + if (type==GTK_MESSAGE_QUESTION) + { +#ifdef VINCENT_MAURY_RSVP + /* draw a question box. link to dialog_click callback */ + dialog = gtk_message_dialog_new ( + GTK_WINDOW(ui->main_window.window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + (const gchar*)message); + /* connect the click event to the callback */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (dialog_click), + G_OBJECT (dialog)); + /* actually show the box */ + gtk_widget_show(dialog); +#endif + } + else + { + dialog = gtk_message_dialog_new (GTK_WINDOW(ui->main_window.window), + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + GTK_BUTTONS_CLOSE, + (const gchar*)message); + /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + gtk_widget_show(dialog); + } + if (!linphone_core_is_in_main_thread(ui->core)) gdk_threads_leave(); +} + +/* these are the LinphoneCore virtual functions */ +void linphone_gnome_display_message(LinphoneCore *lc, const char *message) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_INFO,message); +} + +#ifdef VINCENT_MAURY_RSVP +/* Question box with yes/no answer. */ +void linphone_gnome_display_yes_no(LinphoneCore *lc,const char *message) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + if (strcmp(message,"With QoS")==0) + /* the caller asks for QoS, this function is called because, by default, + * you don't use QoS ! */ + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_QUESTION, + _("The caller asks for resource reservation. Do you agree ?")); + else + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_QUESTION, + _("The caller doesn't use resource reservation. \ + Do you wish to continue anyway ?")); +} +#endif + +void linphone_gnome_display_warning(LinphoneCore *lc, const char *warning) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_WARNING,warning); +} + +void linphone_gnome_display_status(LinphoneCore *lc, const char *status) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + if (ui->main_window.window==NULL) return; + if (!ui->main_window.shown_once) return; /* avoid a gnome bug*/ + gnome_appbar_push(GNOME_APPBAR(ui->main_window.status_bar),status); + +} + +void linphone_gnome_inv_recv(LinphoneCore *lc,const char *from) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + gchar *title; + if (ui->main_window.window==NULL) return; + gtk_entry_set_text(GTK_ENTRY(ui->main_window.addressentry),from); + title=g_strdup_printf(_("linphone - receiving call from %s"),from); + gtk_window_set_title(GTK_WINDOW(ui->main_window.window),title); + g_free(title); +} + +void linphone_gnome_show(LinphoneCore *lc) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + linphone_gnome_ui_show(ui); +} + +void linphone_gnome_display_url(LinphoneCore *lc, const char *message, const char *url) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + alt_ressource_display(ui,url); +} + + + +void linphone_gnome_notify_received(LinphoneCore *lc,LinphoneFriend *fid, const char *from, const char *status, const char *img){ + FriendList *fl=get_friend_list(); + friend_list_set_friend_status(fl,fid,from,status, img); +} + +void linphone_gnome_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + GtkWidget *d=create_inc_subscr_dialog(); + gchar *text=g_strdup_printf(_("You have received a subscription from %s." + "This means that this person wishes to be notified of your presence information (online, busy, away...).\n" + "Do you agree ?"),url); + gtk_label_set_text(GTK_LABEL(lookup_widget(d,"subscr_label")),text); + g_object_set_data(G_OBJECT(d),"friend_ref",(gpointer)lf); + gtk_widget_show(d); +} + +void linphone_gnome_prompt_authentication(LinphoneCore *lc, const gchar *realm, const gchar *username){ + GtkWidget *w=create_authentication_dialog(); + gchar *question=g_strdup_printf(_("Authentication required for realm %s"),realm); + gtk_label_set_text(GTK_LABEL(lookup_widget(w,"question")),question); + g_free(question); + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"realm")),realm); + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"username")),username); + gtk_widget_show(w); +} + +void linphone_gnome_bye_recv(LinphoneCore *lc, const char *from){ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + gtk_window_set_title(GTK_WINDOW(ui->main_window.window),"linphone"); +} + +void stub(){ +} + +void linphone_gnome_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl){ + LinphoneGnomeUI *ui=(LinphoneGnomeUI *)linphone_core_get_user_data(lc); + linphone_gnome_update_call_logs(ui); +} + +void linphone_gnome_text_received(LinphoneCore *lc,LinphoneChatRoom *cr, const char *from, const char *msg){ + GtkWidget *gcr=(GtkWidget*)linphone_chat_room_get_user_data(cr); + if (gcr==NULL){ + gcr=chatroom_new(from,cr); + } + gtk_widget_show(gcr); + chatroom_append(gcr,from,msg); +} + +LinphoneCoreVTable linphone_gnome_vtable= +{ + show: linphone_gnome_show, + inv_recv: linphone_gnome_inv_recv, + bye_recv : linphone_gnome_bye_recv, + notify_recv: linphone_gnome_notify_received, + new_unknown_subscriber: linphone_gnome_new_unknown_subscriber, + auth_info_requested: linphone_gnome_prompt_authentication, + display_status : linphone_gnome_display_status, + display_message : linphone_gnome_display_message, + display_warning : linphone_gnome_display_warning, +#ifdef VINCENT_MAURY_RSVP + display_yes_no : linphone_gnome_display_yes_no, +#endif + display_url : linphone_gnome_display_url, + display_question : stub, + call_log_updated : linphone_gnome_call_log_updated, + text_received: linphone_gnome_text_received +}; + +gboolean linphone_gnome_iterate(LinphoneCore *lc) +{ + linphone_core_iterate(lc); + return TRUE; +} + +void proxy_changed(GtkWidget *combo){ + LinphoneProxyConfig *pcfg=proxy_combo_box_get_selected(combo); + linphone_core_set_default_proxy(get_core(),pcfg); +} + +void linphone_refresh_proxy_combo_box(GtkWidget *window){ + LinphoneCore *lc=get_core(); + GtkWidget *combo; + const MSList *elem=linphone_core_get_proxy_config_list(lc); + LinphoneProxyConfig *cfg=NULL; + GtkWidget *hbox=lookup_widget(window,"proxy_hbox"); + + linphone_core_get_default_proxy(lc,&cfg); + + if (elem==NULL){ + gtk_widget_hide(hbox); + return; + } + combo=(GtkWidget*)g_object_get_data(G_OBJECT(hbox),"proxy"); + if (combo!=NULL){ + gtk_widget_destroy(combo); + } + combo=proxy_combo_box_new(cfg); + g_object_set_data(G_OBJECT(hbox),"proxy",(gpointer)combo); + g_signal_connect(G_OBJECT(combo),"changed",G_CALLBACK(proxy_changed),NULL); + gtk_box_pack_start_defaults(GTK_BOX(hbox),combo); + gtk_widget_show(combo); + gtk_widget_show(hbox); + +} + +void linphone_gnome_init(LinphoneGnomeUI *ui,LinphoneCore *lc) +{ + gchar *configfile_name = + g_strdup_printf ("%s/.gnome2/linphone", getenv ("HOME")); + linphone_gnome_ui_init(ui,lc); + linphone_gnome_ui_show(ui); + linphone_core_init(lc,&linphone_gnome_vtable,configfile_name,(gpointer)ui); + g_free(configfile_name); + set_levels(ui,linphone_core_get_rec_level(lc),linphone_core_get_play_level(lc),linphone_core_get_ring_level(lc)); + /* get history of uri bar */ + restore_uri_history(GTK_ENTRY(ui->main_window.addressentry), linphone_core_get_config(lc)); + linphone_refresh_proxy_combo_box(ui->main_window.window); + ui->timeout_id=gtk_timeout_add(500,(GtkFunction)linphone_gnome_iterate,(gpointer)lc); +} + +void linphone_gnome_uninit(LinphoneGnomeUI *ui) +{ + LinphoneCore *lc=ui->core; + linphone_gnome_ui_uninit(ui); + linphone_core_uninit(lc); + gtk_timeout_remove (ui->timeout_id); +} + +GtkWidget *proxy_combo_box_new(LinphoneProxyConfig *selected){ + GtkWidget *combo; + const MSList *elem; + GtkListStore *store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_POINTER); + GtkTreeIter iter; + GtkTreeIter prxiter; + GtkCellRenderer *renderer; + gboolean proxy_found=FALSE; + /* fill the store */ + elem=linphone_core_get_proxy_config_list(get_core()); + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,_("None"),1,(gpointer)NULL,-1); + for(;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *proxy=(LinphoneProxyConfig*)elem->data; + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,proxy->reg_proxy,1,(gpointer)proxy,-1); + if (selected==proxy) { + prxiter=iter; + proxy_found=TRUE; + } + } + combo=gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, + "text", 0, + NULL); + if (proxy_found){ + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),&prxiter); + }else{ + /*else select "None" */ + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),0); + } + return combo; +} + +LinphoneProxyConfig *proxy_combo_box_get_selected(GtkWidget *combo){ + LinphoneProxyConfig *pcfg=NULL; + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo),&iter)){ + GtkTreeModel *model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)); + gtk_tree_model_get(model,&iter,1,(gpointer)&pcfg,-1); + } + return pcfg; +} + +void linphone_gnome_update_call_logs(LinphoneGnomeUI *ui){ + LinphoneCore *lc=ui->core; + GtkTextView *tv; + GtkTextBuffer *tb; + GtkTextIter begin,end; + GtkTextTag *tag; + MSList *elem; + if (ui->logs==NULL) return; + tv=GTK_TEXT_VIEW(lookup_widget(ui->logs,"logview")); + tb=gtk_text_view_get_buffer(tv); + + gtk_text_buffer_get_bounds(tb,&begin,&end); + gtk_text_buffer_delete(tb,&begin,&end); + gtk_text_buffer_get_end_iter(tb,&end); + for (elem=linphone_core_get_call_logs(lc);elem!=NULL;elem=ms_list_next(elem)){ + LinphoneCallLog *cl=(LinphoneCallLog*)elem->data; + gchar *str=linphone_call_log_to_str(cl); + tag=NULL; + if (cl->status==LinphoneCallMissed){ + tag=gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(tb),"redforeground"); + if (tag==NULL) tag = gtk_text_buffer_create_tag (tb, "redforeground", + "foreground", "red", NULL); + } + gtk_text_buffer_insert_with_tags(tb,&end,str,-1,tag,NULL); + gtk_text_buffer_insert(tb,&end,"\n",-1); + + ms_free(str); + } +} + +void linphone_gnome_show_call_logs_window(LinphoneGnomeUI *ui){ + if (ui->logs==NULL) { + ui->logs=create_call_logs(); + } + linphone_gnome_update_call_logs(ui); + gtk_widget_show(ui->logs); +} diff --git a/linphone/gnome/linphone.h b/linphone/gnome/linphone.h new file mode 100644 index 000000000..fd3fa3872 --- /dev/null +++ b/linphone/gnome/linphone.h @@ -0,0 +1,66 @@ + + +#ifndef LINPHONE_H +#define LINPHONE_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "lpconfig.h" + +#include "support.h" +#include "propertybox.h" +#include "presence.h" +#include "addressbook.h" +#include "friends.h" + +typedef struct _LinphoneMainWindow +{ + GtkWidget *window; + GtkWidget *status_bar; + GtkWidget *addressentry; + GtkWidget *optioncontrols; + GtkWidget *dtmfentry; + GtkWidget *callbutton; + PresenceBox presencebox; + FriendList friendlist; + gboolean shown_once; +}LinphoneMainWindow; + +typedef struct _LinphoneGnomeUI +{ + LinphoneMainWindow main_window; + LinphonePropertyBox propbox; + GtkWidget *ab; /*the address book */ + GtkWidget *logs; /* the call logs window */ + LinphoneCore *core; + guint timeout_id; +}LinphoneGnomeUI; + + +void linphone_gnome_ui_init(LinphoneGnomeUI *ui,LinphoneCore *core); +void linphone_gnome_ui_show(LinphoneGnomeUI *ui); +void linphone_gnome_ui_hide(LinphoneGnomeUI *ui); +void linphone_gnome_ui_uninit(LinphoneGnomeUI *ui); + +void linphone_gnome_init(LinphoneGnomeUI *ui,LinphoneCore *lc); +void linphone_gnome_uninit(LinphoneGnomeUI *ui); + +extern LinphoneGnomeUI *uiobj; + +GtkWidget *proxy_combo_box_new(LinphoneProxyConfig *selected); +void linphone_refresh_proxy_combo_box(GtkWidget *window); +LinphoneProxyConfig *proxy_combo_box_get_selected(GtkWidget *combo); +void linphone_gnome_show_call_logs_window(LinphoneGnomeUI *ui); +void linphone_gnome_update_call_logs(LinphoneGnomeUI *ui); +void linphone_gnome_ui_display_something(LinphoneGnomeUI *ui,GtkMessageType type,const gchar *message); +void linphone_gnome_save_uri_history(LinphoneGnomeUI *ui); + +GtkWidget *chatroom_new(const gchar *url, LinphoneChatRoom *cr); +void chatroom_append(GtkWidget *gcr, const gchar *from, const gchar *message); +void chatroom_close(GtkWidget *gcr); + +#endif diff --git a/linphone/gnome/main.c b/linphone/gnome/main.c new file mode 100644 index 000000000..e62d199f0 --- /dev/null +++ b/linphone/gnome/main.c @@ -0,0 +1,70 @@ +/* + * Initial main.c file generated by Glade. Edit as required. + * Glade will not overwrite this file. + */ + + +#include "linphone.h" + + +/* +#include "../osipua/src/dbgalloc.h" + +GMemVTable dbgtable={ + smalloc, + srealloc, + sfree, + scalloc, + smalloc, + srealloc +}; +*/ +LinphoneCore core; +LinphoneGnomeUI ui; +static int verbose=0; +struct poptOption linphone_options[2]={ + { + longName: "verbose", + shortName: '\0', + argInfo: POPT_ARG_NONE, + arg : (void*)&verbose, + val : 0, + descrip: "log to stdout some debug information while running.", + NULL + }, + POPT_TABLEEND +}; + +int +main (int argc, char *argv[]) +{ + void *p; + + //g_log_set_fatal_mask("GLib",G_LOG_LEVEL_WARNING); + //g_mem_set_vtable(glib_mem_profiler_table); + //g_mem_set_vtable(&dbgtable); +#ifdef ENABLE_NLS + p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); + if (p==NULL) perror("bindtextdomain failed"); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); +#else + printf("NLS disabled.\n"); +#endif + + gnome_program_init ("linphone", LINPHONE_VERSION, LIBGNOMEUI_MODULE, + argc, argv, + GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR, + GNOME_PARAM_POPT_TABLE,&linphone_options,NULL); + + if (verbose) linphone_core_enable_logs(stdout); + else linphone_core_disable_logs(); + linphone_gnome_init(&ui,&core); + linphone_gnome_ui_show(&ui); + gtk_main (); + gdk_threads_leave(); /* it appears that the gdk lock is hold while exiting from gtk_main() */ + linphone_gnome_uninit(&ui); + //g_mem_profile(); + exit(0); + return 0; +} diff --git a/linphone/gnome/presence.c b/linphone/gnome/presence.c new file mode 100644 index 000000000..18042b2c8 --- /dev/null +++ b/linphone/gnome/presence.c @@ -0,0 +1,150 @@ +/*************************************************************************** + presence.c - code for the presence box + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "linphone.h" +#include "callbacks.h" +#include "support.h" + + +void presence_box_init(PresenceBox *p, GtkWidget *main_window,LinphoneCore *lc) +{ + GtkWidget *r; + p->lc=lc; + p->contact_field=lookup_widget(main_window,"contact_field"); + p->minutesaway=lookup_widget(main_window,"minutesaway"); + r=lookup_widget(main_window,"presence_reachable"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(r),TRUE); + r=lookup_widget(main_window,"presence_frame"); +} + +void presence_box_changed(PresenceBox *p) +{ + presence_box_apply(p); +} + +#define get_presence_box() (&(uiobj)->main_window.presencebox) + + +void +on_reachable (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + p->toggled_button=PRESENCE_MODE_REACHABLE; + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + //gtk_widget_set_sensitive(p->contact_field,FALSE); + presence_box_changed(p); +} + + +void +on_busy (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + p->toggled_button=PRESENCE_MODE_BUSY; + //gtk_widget_set_sensitive(p->minutesaway,TRUE); + presence_box_changed(p); +} + + +void +on_minutesaway_changed (GtkEditable *editable,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + presence_box_changed(p); +} + + +void +on_away (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + //gtk_widget_set_sensitive(p->minutesaway,TRUE); + p->toggled_button=PRESENCE_MODE_AWAY; + presence_box_changed(p); +} + + +void +on_do_not_disturb (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + p->toggled_button=PRESENCE_MODE_NOT_DISTURB; + presence_box_changed(p); +} + + +void +on_moved_tmply (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,TRUE); + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + p->toggled_button=PRESENCE_MODE_MOVED; + presence_box_changed(p); +} + + +void +on_alt_serv (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,TRUE); + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + p->toggled_button=PRESENCE_MODE_ALT_SERVICE; + presence_box_changed(p); +} + + +void +on_contact_field_changed (GtkEditable *entry,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + presence_box_changed(p); +} + +void presence_box_apply(PresenceBox *p) +{ + gchar *tmp,*contact=NULL; + int minutes_away=-1; + g_message("presence_box_apply"); + /* retrieve the minutes away */ + tmp = gtk_editable_get_chars (GTK_EDITABLE(p->minutesaway),0,-1); + if (tmp!=NULL && strlen(tmp)>0) + { + minutes_away = atoi(tmp); + g_free(tmp); + } + /* retrieve the alternate contact url */ + tmp = gtk_editable_get_chars (GTK_EDITABLE(p->contact_field),0,-1); + if (tmp!=NULL && strlen(tmp)>0) + { + contact=tmp; + } + /* set presence mode */ + linphone_core_set_presence_info(p->lc,minutes_away,contact,p->toggled_button); + if (tmp!=NULL) g_free(tmp); +} diff --git a/linphone/gnome/presence.h b/linphone/gnome/presence.h new file mode 100644 index 000000000..cbe8701c7 --- /dev/null +++ b/linphone/gnome/presence.h @@ -0,0 +1,43 @@ +/*************************************************************************** + presence.h - code for the presence box + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef PRESENCE_H +#define PRESENCE_H + +enum { PRESENCE_MODE_REACHABLE=LINPHONE_STATUS_ONLINE, + PRESENCE_MODE_BUSY=LINPHONE_STATUS_BUSY, + PRESENCE_MODE_AWAY=LINPHONE_STATUS_AWAY, + PRESENCE_MODE_NOT_DISTURB=LINPHONE_STATUS_NOT_DISTURB, + PRESENCE_MODE_MOVED=LINPHONE_STATUS_MOVED, + PRESENCE_MODE_ALT_SERVICE=LINPHONE_STATUS_ALT_SERVICE + }; + + +typedef struct _PresenceBox +{ + LinphoneCore *lc; + GtkWidget *minutesaway; + GtkWidget *contact_field; + gint toggled_button; /* indicate which button is toggled*/ +} PresenceBox; + + +void presence_box_init(PresenceBox *p, GtkWidget *main_window,LinphoneCore *lc); +void presence_box_changed(PresenceBox *p); +void presence_box_apply(PresenceBox *p); + +#endif diff --git a/linphone/gnome/propertybox.c b/linphone/gnome/propertybox.c new file mode 100644 index 000000000..50f818176 --- /dev/null +++ b/linphone/gnome/propertybox.c @@ -0,0 +1,1065 @@ +/*************************************************************************** + propertybox.c - description + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include "linphone.h" + +enum{ +#ifdef INET6 + IFACE_INDEX, +#endif + IFACE_NAME, + IFACE_ADDR, + IFACE_NCOLUMNS +}; + +enum { + CODEC_NAME, + CODEC_RATE, + CODEC_BITRATE, + CODEC_STATUS, + CODEC_PRIVDATA, + CODEC_COLOR, + CODEC_NCOLUMNS +}; + +#define get_core() (uiobj->core) +#define get_property_box() (&uiobj->propbox) +#define property_box_changed() gnome_property_box_changed(GNOME_PROPERTY_BOX ( (&uiobj->propbox)->prop)) +#define get_main_window() (&uiobj->main_window) + +#if !GTK_CHECK_VERSION(2,6,0) +static gchar * _lp_combo_box_get_active_text (GtkComboBox *combobox) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gchar *text = NULL; + model = gtk_combo_box_get_model (combobox); + if (gtk_combo_box_get_active_iter (combobox, &iter) && model) + gtk_tree_model_get (model, &iter, 0, &text, -1); + return text; +} +#endif /* GTK+ < 2.6.0 */ + +void net_section_init(NetSection *sec, GtkWidget *prop) +{ + sec->au_port=lookup_widget(prop,"audioport"); + sec->audio_jittcomp=lookup_widget(prop,"audio_jittcomp"); +#ifdef LINPHONE_DEPRECATED + sec->interfaces=lookup_widget(prop, "interfaces"); +#endif + sec->nat_address=lookup_widget(prop,"nat_address"); + sec->use_sipinfo=lookup_widget(prop,"use_sipinfo"); + sec->enable_ipv6=lookup_widget(prop,"enable_ipv6"); +} + +void codec_list_update(GtkTreeView *listview); + + +void net_selection_changed_cb(GtkTreeSelection *select, gpointer userdata) +{ + property_box_changed(); +} + +void net_section_fill(NetSection *sec,LinphoneCore *lc) +{ + gfloat value; + const gchar *nat_address,*stun_server; + + value=(gfloat)linphone_core_get_audio_jittcomp(lc); + /* put the current value of jitt_comp*/ + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(sec->audio_jittcomp)),value); + /* display current rtp port */ + gtk_spin_button_set_value(GTK_SPIN_BUTTON(sec->au_port), + (gfloat)linphone_core_get_audio_port(lc)); + + + /* nat setup */ + nat_address=linphone_core_get_nat_address(lc); + + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS) + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(lookup_widget(get_property_box()->prop,"static_nat")) + ,TRUE); + + if (nat_address!=NULL) { + gtk_entry_set_text(GTK_ENTRY(sec->nat_address),nat_address); + } + stun_server=linphone_core_get_stun_server(lc); + if (stun_server!=NULL) + gtk_entry_set_text( + GTK_ENTRY(lookup_widget(get_property_box()->prop,"stun_server")), + stun_server); + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN) + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(lookup_widget(get_property_box()->prop,"use_stun")),TRUE); + + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sec->use_sipinfo), + linphone_core_get_use_info_for_dtmf(lc)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sec->enable_ipv6), + linphone_core_ipv6_enabled(lc)); +} + +void +on_enable_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); + +} + + + +void +on_nat_address_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_enable_ipv6_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + + +void net_section_apply(NetSection *sec,LinphoneCore *lc) +{ + gboolean use_nat,use_stun; + gchar *name; + + use_nat=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + lookup_widget(get_property_box()->prop,"static_nat"))); + name=gtk_editable_get_chars(GTK_EDITABLE(sec->nat_address),0,-1); + linphone_core_set_nat_address(lc,name); + g_free(name); + + use_stun=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + lookup_widget(get_property_box()->prop,"use_stun") )); + name=gtk_editable_get_chars(GTK_EDITABLE( + lookup_widget(get_property_box()->prop,"stun_server") ),0,-1); + linphone_core_set_stun_server(lc,name); + g_free(name); + if (use_stun) linphone_core_set_firewall_policy(lc, + LINPHONE_POLICY_USE_STUN); + else if (use_nat) linphone_core_set_firewall_policy(lc, + LINPHONE_POLICY_USE_NAT_ADDRESS); + else linphone_core_set_firewall_policy(lc, + LINPHONE_POLICY_NO_FIREWALL); + + { + /* get the value of jitt_comp*/ + GtkAdjustment *adj= gtk_range_get_adjustment(GTK_RANGE(sec->audio_jittcomp)); + linphone_core_set_audio_jittcomp(lc,(gint)adj->value); + /* get rtp port */ + adj=gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(sec->au_port)); + linphone_core_set_audio_port(lc,(gint)adj->value); + } + linphone_core_enable_ipv6(lc,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sec->enable_ipv6))); +} + + +enum{ + PROXY_CONFIG_IDENTITY, + PROXY_CONFIG_REF, + PROXY_CONFIG_NCOL +}; + +void sip_section_init(SipSection *sec,GtkWidget *prop) +{ + + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + sec->port=lookup_widget(prop,"sip_port"); + sec->username=lookup_widget(prop, "user_name"); + sec->hostname=lookup_widget(prop,"domain_name"); + sec->proxy_list=lookup_widget(prop,"proxy_list"); + sec->guess_hostname=lookup_widget(prop,"guess_hostname"); + /* create the proxy list */ + store = gtk_list_store_new (PROXY_CONFIG_NCOL, G_TYPE_STRING, G_TYPE_POINTER); + + gtk_tree_view_set_model(GTK_TREE_VIEW(sec->proxy_list),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Account"), + renderer, + "text", PROXY_CONFIG_IDENTITY, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (sec->proxy_list), column); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (sec->proxy_list)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); +} + + +void proxy_list_fill(GtkTreeModel *model, LinphoneCore *lc){ + const MSList *elem; + GtkTreeIter iter; + /* fill the proxy list */ + gtk_list_store_clear(GTK_LIST_STORE(model)); + elem=linphone_core_get_proxy_config_list(lc); + for(;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *pcfg=(LinphoneProxyConfig*)elem->data; + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,PROXY_CONFIG_IDENTITY,pcfg->reg_identity, + PROXY_CONFIG_REF,pcfg,-1); + } +} + +void sip_section_fill(SipSection *sec, LinphoneCore *lc) +{ + osip_from_t *contact; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(sec->proxy_list)); + + /* set sip port */ + gtk_spin_button_set_value(GTK_SPIN_BUTTON(sec->port), + (gfloat)linphone_core_get_sip_port(lc)); + contact=linphone_core_get_primary_contact_parsed(lc); + g_return_if_fail(contact!=NULL); + /* set sip username */ + gtk_entry_set_text(GTK_ENTRY(sec->username),contact->url->username); + /* set domain name */ + gtk_entry_set_text(GTK_ENTRY(sec->hostname),contact->url->host); + osip_from_free(contact); + proxy_list_fill(model,lc); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sec->guess_hostname), + linphone_core_get_guess_hostname(lc)); +} + +void sip_section_apply(SipSection *sec, LinphoneCore *lc) +{ + GtkAdjustment *adj; + gchar *tmp; + gchar *username,*hostname; + /* get sip port*/ + adj=gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(sec->port)); + + username=gtk_editable_get_chars(GTK_EDITABLE(sec->username),0,-1); + if (username!=NULL && strlen(username)!=0) + { + hostname=gtk_editable_get_chars(GTK_EDITABLE(sec->hostname),0,-1); + if (hostname!=NULL && strlen(hostname)!=0) + { + tmp=g_strdup_printf("sip:%s@%s",username,hostname); + linphone_core_set_primary_contact(lc,tmp); + linphone_core_set_sip_port(lc,(int)gtk_adjustment_get_value(adj)); + g_free(hostname); + g_free(tmp); + } + g_free(username); + } +} + + +void +on_addproxy_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *w=create_proxy_config_box(); + gtk_widget_show(w); +} + + +void +on_editproxy_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *w; + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneProxyConfig * cfg; + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (get_property_box()->sip.proxy_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,PROXY_CONFIG_REF , &cfg, -1); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + linphone_proxy_config_edit(cfg); + }else return; + w=create_proxy_config_box(); + gtk_widget_show(w); + if (cfg->reg_proxy!=NULL) gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"reg_proxy")),cfg->reg_proxy); + if (cfg->reg_route!=NULL) gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"reg_route")),cfg->reg_route); + if (cfg->reg_identity!=NULL) gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"reg_identity")),cfg->reg_identity); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"reg_sendregister")),cfg->reg_sendregister); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"publish")),cfg->publish); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(lookup_widget(w,"reg_expires")),cfg->expires); + g_object_set_data(G_OBJECT(w),"edited_config",(gpointer)cfg); +} + + +void +on_removeproxy_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneProxyConfig * cfg; + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (get_property_box()->sip.proxy_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,PROXY_CONFIG_REF , &cfg, -1); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + linphone_core_remove_proxy_config(get_core(),cfg); + linphone_refresh_proxy_combo_box(get_main_window()->window); + } +} + +void get_proxy_config_box_data(GtkWidget *dialog) +{ + gchar *tmp; + gboolean editing=FALSE; + LinphoneProxyConfig *cfg; + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_proxy")),0,-1); + cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(dialog),"edited_config"); + if (cfg==NULL){ + cfg=linphone_proxy_config_new(tmp); + g_free(tmp); + if (cfg==NULL) { + /* set an error message here */ + return; + } + }else{ + linphone_proxy_config_set_server_addr(cfg,tmp); + g_free(tmp); + editing=TRUE; + } + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_route")),0,-1); + linphone_proxy_config_set_route(cfg,tmp); + g_free(tmp); + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_identity")),0,-1); + linphone_proxy_config_set_identity(cfg,tmp); + g_free(tmp); + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_expires")),0,-1); + { + int exp; + if (tmp!=NULL) + { + exp = atoi(tmp); + if (exp<=0) + exp = 200; /* minimum */ + if (exp>7200) + exp = 7200; /* maximum */ + linphone_proxy_config_expires(cfg,exp); + } + } + g_free(tmp); + linphone_proxy_config_enableregister(cfg,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog,"reg_sendregister")))); + linphone_proxy_config_enable_publish(cfg,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog,"publish")))); + if (editing) linphone_proxy_config_done(cfg); + else linphone_core_add_proxy_config(get_core(),cfg); + /* set the last entered/changed proxy as the default one */ + linphone_core_set_default_proxy(get_core(),cfg); + proxy_list_fill(gtk_tree_view_get_model(GTK_TREE_VIEW(get_property_box()->sip.proxy_list)),get_core()); + linphone_refresh_proxy_combo_box(get_main_window()->window); +} + +void +on_proxy_config_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + switch(response_id){ + case GTK_RESPONSE_OK: + get_proxy_config_box_data(GTK_WIDGET(dialog)); + gtk_widget_destroy(GTK_WIDGET(dialog)); + + break; + } +} + + +void codec_section_init(CodecSection *sec, GtkWidget *prop) +{ + sec->au_codec_list=lookup_widget(prop,"au_codec_list"); + sec->vi_codec_list=lookup_widget(prop,"vid_codec_list"); + sec->codec_info=lookup_widget(prop,"codec_info"); +} + +void codec_selection_changed_cb(GtkTreeSelection *selection, gpointer data) +{ + GtkTreeIter iter; + GtkTreeModel *model; + struct _PayloadType *pt=NULL; + LinphonePropertyBox *prop=get_property_box(); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, CODEC_PRIVDATA, &pt, -1); + g_return_if_fail(pt!=NULL); + /* display the codec information */ + gtk_label_set_text(GTK_LABEL(prop->codec.codec_info),payload_type_get_description(pt)); + } +} + +void codec_list_build(GtkTreeView *listview,const MSList *codeclist) +{ + const MSList *elem; + GtkListStore *store = gtk_list_store_new (CODEC_NCOLUMNS, G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_FLOAT, + G_TYPE_STRING, + G_TYPE_POINTER, + G_TYPE_STRING); + GtkTreeIter iter; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select=gtk_tree_view_get_selection (listview); + for(elem=codeclist; elem!=NULL; elem=elem->next){ + gchar *status; + gint rate; + gfloat bitrate; + gchar *color; + struct _PayloadType *pt=(struct _PayloadType *)elem->data; + if (payload_type_enabled(pt)) status=_("Enabled"); + else status=_("Disabled"); + if (linphone_core_check_payload_type_usability(get_core(),pt)) color="blue"; + else color="red"; + /* get an iterator */ + gtk_list_store_append(store,&iter); + bitrate=payload_type_get_bitrate(pt)/1000.0; + rate=payload_type_get_rate(pt); + gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt), + CODEC_RATE,rate, + CODEC_BITRATE,bitrate, + CODEC_STATUS,status, + CODEC_PRIVDATA,(gpointer)pt, + CODEC_COLOR,(gpointer)color, + -1); + } + gtk_tree_view_set_model(listview,GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", CODEC_NAME, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Rate (Hz)"), + renderer, + "text", CODEC_RATE, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Status"), + renderer, + "text", CODEC_STATUS, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Min bitrate (kbit/s)"), + renderer, + "text", CODEC_BITRATE, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + + /* Setup the selection handler */ + select = gtk_tree_view_get_selection (listview); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + //gtk_tree_view_columns_autosize(GTK_TREE_VIEW (sec->interfaces)); + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (codec_selection_changed_cb), + NULL); +} + +void codec_section_fill(CodecSection *sec, LinphoneCore *lc, GtkWidget *propbox) +{ + /* display prefered codecs*/ + int value; + const MSList *audio_codecs=linphone_core_get_audio_codecs(lc); + const MSList *video_codecs=linphone_core_get_video_codecs(lc); + codec_list_build(GTK_TREE_VIEW(sec->au_codec_list),audio_codecs); + codec_list_build(GTK_TREE_VIEW(lookup_widget(propbox,"vid_codec_list")),video_codecs); + value=linphone_core_get_download_bandwidth(lc); + if (value!=0) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(lookup_widget(propbox,"download_bw")),value); + else + gtk_entry_set_text(GTK_ENTRY(lookup_widget(propbox,"download_bw")),_("Unlimited")); + value=linphone_core_get_upload_bandwidth(lc); + if (value!=0) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(lookup_widget(propbox,"upload_bw")),value); + else + gtk_entry_set_text(GTK_ENTRY(lookup_widget(propbox,"upload_bw")),_("Unlimited")); +} + +void codec_section_apply(CodecSection *sec, LinphoneCore *lc) +{ + GtkTreeIter iter; + struct _PayloadType *pt; + MSList *codeclist=NULL; + gchar *status; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(sec->au_codec_list)); + /* retrieve the codec list */ + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + gtk_tree_model_get (model, &iter, CODEC_STATUS,&status,CODEC_PRIVDATA, &pt,-1); + g_return_if_fail(pt!=NULL); + if (strcmp(status,_("Enabled"))==0) payload_type_set_enable(pt,1); + else payload_type_set_enable(pt,0); + codeclist=ms_list_append(codeclist,pt); + }while (gtk_tree_model_iter_next(model,&iter)); + linphone_core_set_audio_codecs(lc,codeclist); + model=gtk_tree_view_get_model(GTK_TREE_VIEW(sec->vi_codec_list)); + /* retrieve the codec list */ + codeclist=NULL; + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + gtk_tree_model_get (model, &iter, CODEC_STATUS,&status,CODEC_PRIVDATA, &pt,-1); + g_return_if_fail(pt!=NULL); + if (strcmp(status,_("Enabled"))==0) payload_type_set_enable(pt,1); + else payload_type_set_enable(pt,0); + codeclist=ms_list_append(codeclist,pt); + }while (gtk_tree_model_iter_next(model,&iter)); + linphone_core_set_video_codecs(lc,codeclist); +} + +void sound_section_init(SoundSection *sec, GtkWidget *prop) +{ + sec->source_entry=lookup_widget(prop,"rec_source"); + sec->ringfileentry=lookup_widget(prop,"ringfileentry"); +} + + +void +on_play_card_changed (GtkComboBox *combobox, + gpointer user_data) +{ +#if GTK_CHECK_VERSION(2,6,0) + char *dev=gtk_combo_box_get_active_text(combobox); +#else /* GTK < 2.6.0 */ + char *dev=_lp_combo_box_get_active_text(combobox); +#endif /* GTK < 2.6.0 */ + linphone_core_set_playback_device(get_core(),dev); + property_box_changed(); + g_free(dev); +} + + +void +on_capt_card_changed (GtkComboBox *combobox, + gpointer user_data) +{ +#if GTK_CHECK_VERSION(2,6,0) + char * dev=gtk_combo_box_get_active_text(combobox); +#else /* GTK < 2.6.0 */ + char * dev=_lp_combo_box_get_active_text(combobox); +#endif /* GTK < 2.6.0 */ + linphone_core_set_capture_device(get_core(),dev); + property_box_changed(); + g_free(dev); +} + +void +on_ring_card_changed (GtkComboBox *combobox, + gpointer user_data) +{ +#if GTK_CHECK_VERSION(2,6,0) + char * dev=gtk_combo_box_get_active_text(combobox); +#else /* GTK < 2.6.0 */ + char * dev=_lp_combo_box_get_active_text(combobox); +#endif /* GTK < 2.6.0 */ + linphone_core_set_ringer_device(get_core(),dev); + property_box_changed(); + g_free(dev); +} + +static int get_dev_index(const char **devnames, const char *dev){ + int i; + for (i=0;devnames[i]!=NULL;i++){ + if (strcmp(devnames[i],dev)==0) + return i; + } + g_warning("could not find %s in device list.",dev); + return 0; +} + +void sound_section_fill(SoundSection *sec, LinphoneCore *lc) +{ + GtkComboBox *play_card=GTK_COMBO_BOX(lookup_widget(get_property_box()->prop,"play_card")); + GtkComboBox *capt_card=GTK_COMBO_BOX(lookup_widget(get_property_box()->prop,"capt_card")); + GtkComboBox *ring_card=GTK_COMBO_BOX(lookup_widget(get_property_box()->prop,"ring_card")); + int i; + const char **devnames=linphone_core_get_sound_devices(lc); + /* select used sound drivers*/ + + for (i=0;devnames[i]!=NULL;i++){ + const char *carddesc=devnames[i]; + gtk_combo_box_append_text(play_card,carddesc); + gtk_combo_box_append_text(capt_card,carddesc); + gtk_combo_box_append_text(ring_card,carddesc); + } + /*select used cards */ + gtk_combo_box_set_active(play_card,get_dev_index(devnames,linphone_core_get_playback_device(lc))); + gtk_combo_box_set_active(capt_card,get_dev_index(devnames,linphone_core_get_capture_device(lc))); + gtk_combo_box_set_active(ring_card,get_dev_index(devnames,linphone_core_get_ringer_device(lc))); + /* select audio source*/ + switch(linphone_core_get_sound_source(lc)) + { + case 'm': + gtk_entry_set_text (GTK_ENTRY (sec->source_entry), _("micro")); + break; + case 'l': + gtk_entry_set_text (GTK_ENTRY (sec->source_entry), _("line")); + break; + default: + g_warning("Invalid source !"); + } + { + gchar *ringfile=linphone_core_get_ring(lc); + gnome_file_entry_set_filename(GNOME_FILE_ENTRY(sec->ringfileentry),ringfile); + + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(get_property_box()->prop,"echocancelation")),linphone_core_echo_cancelation_enabled(lc)); +} + + + + +void sound_section_apply(SoundSection *sec, LinphoneCore *lc) +{ + gchar *tmp; + + /* get audio source*/ + tmp=gtk_editable_get_chars(GTK_EDITABLE(sec->source_entry),0,-1); + if (strcmp(tmp,_("micro"))==0) linphone_core_set_sound_source(lc,'m'); + else if (strcmp(tmp,_("line"))==0) linphone_core_set_sound_source(lc,'l'); + g_free(tmp); + + /* get ring path */ + tmp=gtk_editable_get_chars(GTK_EDITABLE(gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(sec->ringfileentry))),0,-1); + linphone_core_set_ring(lc,tmp); + g_free(tmp); + +} + +void ring_finished(LinphoneCore *lc,gpointer user_data) +{ + GtkWidget *button=(GtkWidget*)user_data; + LinphonePropertyBox *prop=get_property_box(); + if (prop->prop==NULL) return; /* the box has been closed before the end of the preview */ + gtk_widget_set_sensitive(button,1); +} + +void +on_ringpreview_clicked (GtkButton *button, + gpointer user_data) +{ + int err; + gchar *tmp; + LinphonePropertyBox *prop=get_property_box(); + LinphoneCore *lc=get_core(); + /* get ring path */ + tmp=gtk_editable_get_chars(GTK_EDITABLE(gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(prop->sound.ringfileentry))),0,-1); + err=linphone_core_preview_ring(lc,tmp,ring_finished,(gpointer)button); + if (err==0) gtk_widget_set_sensitive(GTK_WIDGET(button),0); + g_free(tmp); +} + + +void linphone_property_box_fill(LinphonePropertyBox * box, LinphoneCore *lp) +{ + net_section_fill(&box->net,lp); + sip_section_fill(&box->sip,lp); + codec_section_fill(&box->codec,lp,box->prop); + sound_section_fill(&box->sound,lp); + /* set uchanged state to the prop1 box, because gtk_entry_set_text() causes signal "changed" + to be sent */ + gnome_property_box_set_state(GNOME_PROPERTY_BOX(box->prop),0); +} + +void linphone_property_box_init(LinphonePropertyBox *box) +{ + if (box->prop==NULL){ + GtkWidget *prop=create_prop1(); + box->prop=prop; + net_section_init(&box->net,prop); + sip_section_init(&box->sip,prop); + codec_section_init(&box->codec,prop); + sound_section_init(&box->sound,prop); + gtk_widget_show(prop); + linphone_property_box_fill(box,get_core()); + }else{ + gtk_widget_show(box->prop); + gtk_window_present(GTK_WINDOW(box->prop)); + } +} + + + + +void on_propertybox1_apply (GtkButton *button, + gint pagenum) +{ + LinphonePropertyBox *prop=get_property_box(); + LinphoneCore *lc=get_core(); + switch(pagenum) + { + case 0: + net_section_apply(&prop->net,lc); + break; + case 1: + sound_section_apply(&prop->sound,lc); + break; + case 2: + sip_section_apply(&prop->sip,lc); + break; + case 3: + codec_section_apply(&prop->codec,lc); + break; + } +} + + +void +on_audioport_changed (GtkEditable *editable, + gpointer user_data) +{ + LinphonePropertyBox *prop=get_property_box(); + gnome_property_box_changed(GNOME_PROPERTY_BOX(prop->prop)); + return; +} + + +void +on_sipport_changed (GtkEditable *editable, + gpointer user_data) +{ + LinphonePropertyBox *prop=get_property_box(); + gnome_property_box_changed(GNOME_PROPERTY_BOX(prop->prop)); + return; +} + + +void +on_source_changed (GtkEditable *editable, + gpointer user_data) +{ + LinphonePropertyBox *prop=get_property_box(); + gnome_property_box_changed(GNOME_PROPERTY_BOX(prop->prop)); +} + +enum { + CODEC_ACTION_UP, + CODEC_ACTION_DOWN +}; + + +void codec_row_move(GtkTreeView *listview, int action) +{ + GtkTreeIter iter; + GtkTreeIter previter,nextiter,newiter; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreePath *treepath; + struct _PayloadType *codec=NULL; + gchar *name=NULL; + gint rate; + gfloat bitrate; + gchar *status=NULL; + gchar *color=NULL; + + selection=gtk_tree_view_get_selection(listview); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, CODEC_NAME,&name, + CODEC_RATE,&rate, + CODEC_BITRATE,&bitrate, + CODEC_STATUS,&status, + CODEC_PRIVDATA, &codec, + CODEC_COLOR,&color, + -1); + g_return_if_fail(codec!=NULL); + switch(action){ + case CODEC_ACTION_UP: + /* get an iterator on the prev codec */ + treepath=gtk_tree_model_get_path(model,&iter); + if (!gtk_tree_path_prev(treepath)){ + /* codec is the first, no match. */ + return; + } + gtk_tree_model_get_iter(model,&previter,treepath); + gtk_list_store_insert_before(GTK_LIST_STORE(model),&newiter,&previter); + break; + case CODEC_ACTION_DOWN: + /* get an iterator on the next codec */ + nextiter=iter; + if (!gtk_tree_model_iter_next(model,&nextiter)){ + /* codec is the last, no match. */ + return; + } + gtk_list_store_insert_after(GTK_LIST_STORE(model),&newiter,&nextiter); + + break; + } + gtk_list_store_set(GTK_LIST_STORE(model),&newiter, + CODEC_NAME,name, + CODEC_RATE,rate, + CODEC_BITRATE,bitrate, + CODEC_STATUS,status, + CODEC_PRIVDATA, codec, + CODEC_COLOR,color, + -1); + /* remove the selected line */ + gtk_list_store_remove(GTK_LIST_STORE(model),&iter); + gtk_tree_selection_select_iter(selection,&newiter); + g_free(name); + g_free(status); + g_free(color); + } +} + +static void codec_move(int action){ + GtkTreeView *listview; + int page=gtk_notebook_get_current_page(GTK_NOTEBOOK( + lookup_widget(get_property_box()->prop,"codec_notebook"))); + if (page==0) + listview=GTK_TREE_VIEW(get_property_box()->codec.au_codec_list); + else + listview=GTK_TREE_VIEW(lookup_widget(get_property_box()->prop,"vid_codec_list")); + codec_row_move(listview,action); + property_box_changed(); +} + +void +on_aucodec_up_clicked (GtkButton *button, + gpointer user_data) +{ + codec_move(CODEC_ACTION_UP); +} + + +void +on_aucodec_down_clicked (GtkButton *button, + gpointer user_data) +{ + codec_move(CODEC_ACTION_DOWN); +} + +void codec_set_status(GtkTreeView *listview,gboolean status) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gchar *statusstring; + selection=gtk_tree_view_get_selection(listview); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + if (status) statusstring=_("Enabled"); + else statusstring=_("Disabled"); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_STATUS,statusstring,-1); + } +} + +void codec_list_update(GtkTreeView *listview) +{ + GtkTreeModel *model; + GtkTreeIter iter; + PayloadType *pt; + gchar *color; + gfloat bitrate; + model=gtk_tree_view_get_model(listview); + + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + gtk_tree_model_get (model, &iter, CODEC_PRIVDATA, &pt,-1); + if (linphone_core_check_payload_type_usability(get_core(),pt)){ + color="blue"; + }else color="red"; + bitrate=payload_type_get_bitrate(pt)/1000.0; + gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR,color,CODEC_BITRATE,bitrate,-1); + }while (gtk_tree_model_iter_next(model,&iter)); +} + +static void codec_enable(gboolean val){ + GtkTreeView *listview; + int page=gtk_notebook_get_current_page(GTK_NOTEBOOK( + lookup_widget(get_property_box()->prop,"codec_notebook"))); + if (page==0) + listview=GTK_TREE_VIEW(get_property_box()->codec.au_codec_list); + else + listview=GTK_TREE_VIEW(lookup_widget(get_property_box()->prop,"vid_codec_list")); + codec_set_status(listview,val); + property_box_changed(); +} + +void +on_aucodec_enable_clicked (GtkButton *button, + gpointer user_data) +{ + codec_enable(TRUE); +} + + +void +on_aucodec_disable_clicked (GtkButton *button, + gpointer user_data) +{ + codec_enable(FALSE); +} + + +void +on_user_name_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_domain_name_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + + +void +on_reg_passwd_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_obproxy_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_address_of_record_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_audio_jittcomp_value_changed (GtkRange *range, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_ringfileentry_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + +void linphone_property_box_uninit(LinphonePropertyBox *box) +{ + memset(box,0, sizeof(LinphonePropertyBox)); +} + + +gboolean +on_property_box_closed (GnomeDialog *gnomedialog, + gpointer user_data) +{ + linphone_property_box_uninit(get_property_box()); + return FALSE; +} + +void +on_use_sipinfo_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + linphone_core_set_use_info_for_dtmf(get_core(),gtk_toggle_button_get_active(togglebutton)); +} + + +void +on_guess_hostname_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + GtkWidget *hostname; + osip_from_t *from; + gboolean val=gtk_toggle_button_get_active(togglebutton); + linphone_core_set_guess_hostname(get_core(),val); + hostname=get_property_box()->sip.hostname; + from=linphone_core_get_primary_contact_parsed(get_core()); + gtk_entry_set_text(GTK_ENTRY(hostname),from->url->host); + gtk_widget_set_sensitive(hostname,!val); + osip_from_free(from); +} + +void +on_download_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data) +{ + gdouble val=gtk_spin_button_get_value(spinbutton); + if (val==0) gtk_entry_set_text(GTK_ENTRY(spinbutton),_("Unlimited")); + linphone_core_set_download_bandwidth(get_core(),(int)val); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"au_codec_list"))); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"vid_codec_list"))); +} + +void +on_upload_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data) +{ + gdouble val=gtk_spin_button_get_value(spinbutton); + if (val==0) gtk_entry_set_text(GTK_ENTRY(spinbutton),_("Unlimited")); + linphone_core_set_upload_bandwidth(get_core(),(int)val); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"au_codec_list"))); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"vid_codec_list"))); +} + +void +on_no_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_use_stun_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_static_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_stun_server_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + diff --git a/linphone/gnome/propertybox.h b/linphone/gnome/propertybox.h new file mode 100644 index 000000000..911c72ef7 --- /dev/null +++ b/linphone/gnome/propertybox.h @@ -0,0 +1,96 @@ +/*************************************************************************** + propertybox.h - description + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "interface.h" +#include + +struct _NetSection +{ + GtkWidget *interfaces; + gint if_sel; + GtkWidget *au_port; + GtkWidget *audio_jittcomp; + GtkWidget *enable_nat; + GtkWidget *nat_label; + GtkWidget *nat_address; + GtkWidget *use_sipinfo; + GtkWidget *enable_ipv6; +}; +typedef struct _NetSection NetSection; + +void net_section_init(NetSection *sec, GtkWidget *prop); +void net_section_apply(NetSection *sec, LinphoneCore *lp); + +struct _SipSection +{ + GtkWidget *port; + GtkWidget *username; + GtkWidget *hostname; + GtkWidget *proxy_list; + GtkWidget *guess_hostname; +}; + +typedef struct _SipSection SipSection; + +void sip_section_enable_registrar(SipSection *sec, LinphoneCore *lp, gboolean state); +void sip_section_fill(SipSection *sec, LinphoneCore *lp); + +void sip_section_init(SipSection *sec, GtkWidget *prop); +void sip_section_apply(SipSection *sec, LinphoneCore *lp); + +struct _CodecSection +{ + GtkWidget *au_codec_list; + GtkWidget *vi_codec_list; + GtkWidget *codec_info; +}; + +typedef struct _CodecSection CodecSection; + +void codec_section_init(CodecSection *sec, GtkWidget *prop); +void codec_section_apply(CodecSection *sec, LinphoneCore *lc); + +struct _SoundSection +{ + GtkWidget *source_entry; + GtkWidget *autokill_button; + GtkWidget *ringfileentry; + GtkWidget *ringpreview; +}; +typedef struct _SoundSection SoundSection; + +void sound_section_init(SoundSection *sec,GtkWidget *prop); +void sound_section_apply(SoundSection *sec, LinphoneCore *lc); + +struct _LinphonePropertyBox +{ + GtkWidget *prop; + NetSection net; + SipSection sip; + CodecSection codec; + SoundSection sound; +}; + +typedef struct _LinphonePropertyBox LinphonePropertyBox; + +void linphone_property_box_init(LinphonePropertyBox *box); +void linphone_property_box_apply(LinphonePropertyBox * box, LinphoneCore *lc, int page); +void linphone_property_box_uninit(LinphonePropertyBox *box); diff --git a/linphone/gnome/support.c b/linphone/gnome/support.c new file mode 100644 index 000000000..06a04b7dd --- /dev/null +++ b/linphone/gnome/support.c @@ -0,0 +1,115 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + GtkWidget *pixmap; + gchar *pathname; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP, + filename, TRUE, NULL); + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP, + filename, TRUE, NULL); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/linphone/gnome/support.h b/linphone/gnome/support.h new file mode 100644 index 000000000..2bec209a5 --- /dev/null +++ b/linphone/gnome/support.h @@ -0,0 +1,49 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#undef Q_ +#ifdef ENABLE_NLS +# define Q_(String) g_strip_context ((String), gettext (String)) +#else +# define Q_(String) g_strip_context ((String), (String)) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/linphone/gsmlib/.cvsignore b/linphone/gsmlib/.cvsignore new file mode 100644 index 000000000..05623353b --- /dev/null +++ b/linphone/gsmlib/.cvsignore @@ -0,0 +1,6 @@ +*.lo +.deps +.libs +Makefile +Makefile.in +libgsm.la diff --git a/linphone/gsmlib/COPYRIGHT b/linphone/gsmlib/COPYRIGHT new file mode 100644 index 000000000..eba0e523b --- /dev/null +++ b/linphone/gsmlib/COPYRIGHT @@ -0,0 +1,16 @@ +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +Any use of this software is permitted provided that this notice is not +removed and that neither the authors nor the Technische Universitaet Berlin +are deemed to have made any representations as to the suitability of this +software for any purpose nor are held responsible for any defects of +this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + +As a matter of courtesy, the authors request to be informed about uses +this software has found, about bugs in this software, and about any +improvements that may be of general interest. + +Berlin, 28.11.1994 +Jutta Degener +Carsten Bormann diff --git a/linphone/gsmlib/ChangeLog b/linphone/gsmlib/ChangeLog new file mode 100644 index 000000000..4cf467d09 --- /dev/null +++ b/linphone/gsmlib/ChangeLog @@ -0,0 +1,80 @@ + +Fri Jul 5 19:26:37 1996 Jutta Degener (jutta@cs.tu-berlin.de) + + * Release 1.0 Patchlevel 10 + src/toast_alaw.c: exchanged A-law tables for something + slightly more A-law. + +Tue Jul 2 12:18:20 1996 Jutta Degener (jutta@cs.tu-berlin.de) + + * Release 1.0 Patchlevel 9 + src/long_term.c: in FLOAT_MUL mode, an array was accessed past its end + src/gsm_option.c: three options related to WAV #49 packing + src/gsm_encode.c: support WAV #49-style encoding. + src/gsm_decode.c: support WAV #49-style decoding. + tls/sour.c: generate the WAV bit shifting code, encode + tls/ginger.c: generate the WAV bit shifting code, decode + The WAV code goes back to an inofficial patch #8 that + Jeff Chilton sent us (hence the jump from 7 to 9). + src/toast.c: add _fsetmode() calls to set stdin/stdout to + binary (from an OS/2 port by Arnd Gronenberg.) + +Tue Mar 7 01:55:10 1995 Jutta Degener (jutta@cs.tu-berlin.de) + + * Release 1.0 Patchlevel 7 + src/long_term.c: Yet another 16-bit overflow + src/toast.c: -C option to toast, cuts LPC time + src/gsm_option.c: corresponding LPC_CUT option to GSM library + +Fri Dec 30 23:33:50 1994 Jutta Degener (jutta@cs.tu-berlin.de) + + * Release 1.0 Patchlevel 6 + src/lpc.c: fixed 16-bit addition overflow in Autocorrelation code + src/add.c: gsm_L_asl should fall back on gsm_L_asr, not gsm_asr + +Mon Nov 28 20:49:57 1994 Jutta Degener (jutta@cs.tu-berlin.de) + + * Release 1.0 Patchlevel 5 + src/toast_audio.c: initialization should return -1 on error + src/gsm_destroy.c: #include configuration header file + src/add.c: gsm_sub should cast its parameters to longword + man/*: bug reports to {jutta,cabo}@cs.tu-berlin.de, not to toast@tub + inc/private.h: longword long by default, not int + inc/toast.h: read/write fopen modes "rb" and "wb", not just "r" + src/toast.c: better (or different, anyway) error handling in process() + +Tue May 10 19:41:34 1994 Jutta Degener (jutta at kugelbus) + + * Release 1.0 Patchlevel 4 + inc/private.h: GSM_ADD should cast to ulongword, not to unsigned. + src/long_term.c: missing cast to longword. + add-test/add_test.c: Test macros too, not only functions, + thanks to Simao Ferraz de Campos Neto, simao@dragon.cpqd.ansp.br + General cleanup: remove unused variables, add function prototypes. + +Tue Jan 25 22:53:40 1994 Jutta Degener (jutta at kugelbus) + + * Release 1.0 Patchlevel 3 + changed rpe.c's STEP macro to work with 16-bit integers, + thanks to Dr Alex Lee (alexlee@solomon.technet.sg); + removed non-fatal bugs from add-test.dta, private.h + and toast_audio.c, thanks to P. Emanuelsson. + +Fri Jan 29 19:02:12 1993 Jutta Degener (jutta at kraftbus) + + * Release 1.0 Patchlevel 2 + fixed L_add(0,-1) in src/add.c and inc/private.h, + thanks to Raphael Trommer at AT&T Bell Laboratories; + various other ANSI C compatibility details + +Fri Oct 30 17:58:54 1992 Jutta Degener (jutta at kraftbus) + + * Release 1.0 Patchlevel 1 + Switched uid/gid in toast's [f]chown calls. + +Wed Oct 28 14:12:35 1992 Carsten Bormann (cabo at kubus) + + * Release 1.0: released + Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + Universitaet Berlin. See the accompanying file "COPYRIGHT" for + details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. diff --git a/linphone/gsmlib/ChangeLog.orig b/linphone/gsmlib/ChangeLog.orig new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/gsmlib/INSTALL b/linphone/gsmlib/INSTALL new file mode 100644 index 000000000..5850304f8 --- /dev/null +++ b/linphone/gsmlib/INSTALL @@ -0,0 +1,99 @@ +How to get started: + + Edit the Makefile. + + You should configure a few machine-dependencies and what + compiler you want to use. + + The code works both with ANSI and K&R-C. Use + -DNeedFunctionPrototypes to compile with, or + -UNeedFunctionPrototypes to compile without, function + prototypes in the header files. + + Make addtst + + The "add" program that will be compiled and run checks whether + the basic math functions of the gsm library work with your + compiler. If it prints anything to stderr, complain (to us). + + Edit inc/config.h. + + Make + + Local versions of the gsm library and the "compress"-like filters + toast, untoast and tcat will be generated. + + If the compilation aborts because of a missing function, + declaration, or header file, see if there's something in + inc/config.h to work around it. If not, complain. + + Try it + + Grab an audio file from somewhere (raw u-law or Sun .au is fine, + linear 16-bit in host byte order will do), copy it, toast it, + untoast it, and listen to the result. + + The GSM-encoded and -decoded audio should have the quality + of a good phone line. If the resulting audio is noisier than + your original, or if you hear compression artifacts, complain; + that's a bug in our software, not a bug in the GSM encoding + standard itself. + +Installation + + You can install the gsm library interface, or the toast binaries, + or both. + + Edit the Makefile + + Fill in the directories where you want to install the + library, header files, manual pages, and binaries. + + Turn off the installation of one half of the distribution + (i.e., gsm library or toast binaries) by not setting the + corresponding directory root Makefile macro. + + make install + + will install the programs "toast" with two links named + "tcat" and "untoast", and the gsm library "libgsm.a" with + a "gsm.h" header file, and their respective manual pages. + + +Optimizing + + This code was developed on a machine without an integer + multiplication instruction, where we obtained the fastest result by + replacing some of the integer multiplications with floating point + multiplications. + + If your machine does multiply integers fast enough, + leave USE_FLOAT_MUL undefined. The results should be the + same in both cases. + + On machines with fast floating point arithmetic, defining + both USE_FLOAT_MUL and FAST makes a run-time library + option available that will (in a few crucial places) use + ``native'' floating point operations rather than the bit-by-bit + defined ones of the GSM standard. If you use this fast + option, the outcome will not be bitwise identical to the + results prescribed by the standard, but it is compatible with + the standard encoding, and a user is unlikely to notice a + difference. + + +Bug Reports + + Please direct bug reports, questions, and comments to + jutta@cs.tu-berlin.de and cabo@informatik.uni-bremen.de. + + +Good luck, + + Jutta Degener, + Carsten Bormann + +-- +Copyright 1992, 1993, 1994, by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin. See the accompanying file "COPYRIGHT" +for details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. diff --git a/linphone/gsmlib/MACHINES b/linphone/gsmlib/MACHINES new file mode 100644 index 000000000..4adafd24f --- /dev/null +++ b/linphone/gsmlib/MACHINES @@ -0,0 +1,11 @@ +The gsm library has been tested successfully on the following platforms: + +- Various Sun4's running SunOS 4.1.2 +- SPARC1 (SunOS 4.1.1) +- Integrated Solutions 68k Optimum running 4.3BSD UNIX with a Green Hills cc +- NeXTstation running NeXT-OS/Mach 3.0 +- No-name AT/386 with Xenix 2.3.2 (using -DSTUPID_COMPILER) +- RS/6000-350 running AIX 3.2.0 +- RS/6000-320 running AIX 3.1.5 +- Alliant FX80 (Concentrix 5.7) +- SGI Indigo XS4000 (IRIX 4.0.5F) diff --git a/linphone/gsmlib/MANIFEST b/linphone/gsmlib/MANIFEST new file mode 100644 index 000000000..6db3b2a3e --- /dev/null +++ b/linphone/gsmlib/MANIFEST @@ -0,0 +1,59 @@ +gsm-1.0/COPYRIGHT +gsm-1.0/ChangeLog +gsm-1.0/INSTALL +gsm-1.0/MACHINES +gsm-1.0/MANIFEST +gsm-1.0/Makefile +gsm-1.0/README +gsm-1.0/add-test/add_test.c +gsm-1.0/add-test/add_test.dta +gsm-1.0/inc/gsm.h +gsm-1.0/inc/proto.h +gsm-1.0/inc/unproto.h +gsm-1.0/inc/config.h +gsm-1.0/inc/private.h +gsm-1.0/inc/toast.h +gsm-1.0/man/bitter.1 +gsm-1.0/man/gsm.3 +gsm-1.0/man/gsm_explode.3 +gsm-1.0/man/gsm_print.3 +gsm-1.0/man/gsm_option.3 +gsm-1.0/man/toast.1 +gsm-1.0/src/add.c +gsm-1.0/src/code.c +gsm-1.0/src/debug.c +gsm-1.0/src/decode.c +gsm-1.0/src/gsm_destroy.c +gsm-1.0/src/gsm_decode.c +gsm-1.0/src/gsm_encode.c +gsm-1.0/src/gsm_explode.c +gsm-1.0/src/gsm_implode.c +gsm-1.0/src/gsm_create.c +gsm-1.0/src/gsm_print.c +gsm-1.0/src/gsm_option.c +gsm-1.0/src/long_term.c +gsm-1.0/src/lpc.c +gsm-1.0/src/preprocess.c +gsm-1.0/src/rpe.c +gsm-1.0/src/short_term.c +gsm-1.0/src/table.c +gsm-1.0/src/toast.c +gsm-1.0/src/toast_alaw.c +gsm-1.0/src/toast_audio.c +gsm-1.0/src/toast_lin.c +gsm-1.0/src/toast_ulaw.c +gsm-1.0/tls/bitter.c +gsm-1.0/tls/bitter.dta +gsm-1.0/tls/taste.c +gsm-1.0/tls/taste.h +gsm-1.0/tls/sweet.c +gsm-1.0/tls/sour.c +gsm-1.0/tls/sour1.dta +gsm-1.0/tls/sour2.dta +gsm-1.0/tls/ginger.c +gsm-1.0/tst/cod2lin.c +gsm-1.0/tst/cod2txt.c +gsm-1.0/tst/gsm2cod.c +gsm-1.0/tst/lin2cod.c +gsm-1.0/tst/lin2txt.c +gsm-1.0/tst/run diff --git a/linphone/gsmlib/Makefile.am b/linphone/gsmlib/Makefile.am new file mode 100644 index 000000000..01b5cfd73 --- /dev/null +++ b/linphone/gsmlib/Makefile.am @@ -0,0 +1,26 @@ + +EXTRA_DIST= ChangeLog INSTALL MACHINES MANIFEST README COPYRIGHT + +noinst_LTLIBRARIES= libgsm.la + +libgsm_la_SOURCES= gsmadd.c proto.h unproto.h config.h private.h gsm.h toast.h \ + code.c proto.h unproto.h config.h private.h gsm.h toast.h \ + debug.c proto.h unproto.h config.h private.h gsm.h toast.h \ + decode.c proto.h unproto.h config.h private.h gsm.h toast.h \ + long_term.c proto.h unproto.h config.h private.h gsm.h toast.h \ + lpc.c proto.h unproto.h config.h private.h gsm.h toast.h \ + preprocess.c proto.h unproto.h config.h private.h gsm.h toast.h \ + rpe.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_destroy.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_decode.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_encode.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_explode.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_implode.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_create.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_print.c proto.h unproto.h config.h private.h gsm.h toast.h \ + gsm_option.c proto.h unproto.h config.h private.h gsm.h toast.h \ + short_term.c proto.h unproto.h config.h private.h gsm.h toast.h \ + table.c proto.h unproto.h config.h private.h gsm.h toast.h + + +AM_CFLAGS=-w diff --git a/linphone/gsmlib/README b/linphone/gsmlib/README new file mode 100644 index 000000000..cb6af85cf --- /dev/null +++ b/linphone/gsmlib/README @@ -0,0 +1,37 @@ + +GSM 06.10 13 kbit/s RPE/LTP speech compression available +-------------------------------------------------------- + +The Communications and Operating Systems Research Group (KBS) at the +Technische Universitaet Berlin is currently working on a set of +UNIX-based tools for computer-mediated telecooperation that will be +made freely available. + +As part of this effort we are publishing an implementation of the +European GSM 06.10 provisional standard for full-rate speech +transcoding, prI-ETS 300 036, which uses RPE/LTP (residual pulse +excitation/long term prediction) coding at 13 kbit/s. + +GSM 06.10 compresses frames of 160 13-bit samples (8 kHz sampling +rate, i.e. a frame rate of 50 Hz) into 260 bits; for compatibility +with typical UNIX applications, our implementation turns frames of 160 +16-bit linear samples into 33-byte frames (1650 Bytes/s). +The quality of the algorithm is good enough for reliable speaker +recognition; even music often survives transcoding in recognizable +form (given the bandwidth limitations of 8 kHz sampling rate). + +The interfaces offered are a front end modelled after compress(1), and +a library API. Compression and decompression run faster than realtime +on most SPARCstations. The implementation has been verified against the +ETSI standard test patterns. + +Jutta Degener (jutta@cs.tu-berlin.de) +Carsten Bormann (cabo@cs.tu-berlin.de) + +Communications and Operating Systems Research Group, TU Berlin +Fax: +49.30.31425156, Phone: +49.30.31424315 + +-- +Copyright 1992 by Jutta Degener and Carsten Bormann, Technische +Universitaet Berlin. See the accompanying file "COPYRIGHT" for +details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. diff --git a/linphone/gsmlib/code.c b/linphone/gsmlib/code.c new file mode 100644 index 000000000..a6003da04 --- /dev/null +++ b/linphone/gsmlib/code.c @@ -0,0 +1,99 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/code.c,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#include "config.h" + + +#ifdef HAS_STDLIB_H +#include +#else +# include "proto.h" + extern char * memcpy P((char *, char *, int)); +#endif + +#include "private.h" +#include "gsm.h" +#include "proto.h" + +/* + * 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER + */ + +void Gsm_Coder P8((S,s,LARc,Nc,bc,Mc,xmaxc,xMc), + + struct gsm_state * S, + + word * s, /* [0..159] samples IN */ + +/* + * The RPE-LTD coder works on a frame by frame basis. The length of + * the frame is equal to 160 samples. Some computations are done + * once per frame to produce at the output of the coder the + * LARc[1..8] parameters which are the coded LAR coefficients and + * also to realize the inverse filtering operation for the entire + * frame (160 samples of signal d[0..159]). These parts produce at + * the output of the coder: + */ + + word * LARc, /* [0..7] LAR coefficients OUT */ + +/* + * Procedure 4.2.11 to 4.2.18 are to be executed four times per + * frame. That means once for each sub-segment RPE-LTP analysis of + * 40 samples. These parts produce at the output of the coder: + */ + + word * Nc, /* [0..3] LTP lag OUT */ + word * bc, /* [0..3] coded LTP gain OUT */ + word * Mc, /* [0..3] RPE grid selection OUT */ + word * xmaxc,/* [0..3] Coded maximum amplitude OUT */ + word * xMc /* [13*4] normalized RPE samples OUT */ +) +{ + int k; + word * dp = S->dp0 + 120; /* [ -120...-1 ] */ + word * dpp = dp; /* [ 0...39 ] */ + + static word e[50]; + + word so[160]; + + Gsm_Preprocess (S, s, so); + Gsm_LPC_Analysis (S, so, LARc); + Gsm_Short_Term_Analysis_Filter (S, LARc, so); + + for (k = 0; k <= 3; k++, xMc += 13) { + + Gsm_Long_Term_Predictor ( S, + so+k*40, /* d [0..39] IN */ + dp, /* dp [-120..-1] IN */ + e + 5, /* e [0..39] OUT */ + dpp, /* dpp [0..39] OUT */ + Nc++, + bc++); + + Gsm_RPE_Encoding ( S, + e + 5, /* e ][0..39][ IN/OUT */ + xmaxc++, Mc++, xMc ); + /* + * Gsm_Update_of_reconstructed_short_time_residual_signal + * ( dpp, e + 5, dp ); + */ + + { register int i; + register longword ltmp; + for (i = 0; i <= 39; i++) + dp[ i ] = GSM_ADD( e[5 + i], dpp[i] ); + } + dp += 40; + dpp += 40; + + } + (void)memcpy( (char *)S->dp0, (char *)(S->dp0 + 160), + 120 * sizeof(*S->dp0) ); +} diff --git a/linphone/gsmlib/config.h b/linphone/gsmlib/config.h new file mode 100644 index 000000000..d5f9a13ac --- /dev/null +++ b/linphone/gsmlib/config.h @@ -0,0 +1,37 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/*$Header: /sources/linphone/linphone/gsmlib/config.h,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $*/ + +#ifndef CONFIG_H +#define CONFIG_H + +/*efine SIGHANDLER_T int /* signal handlers are void */ +/*efine HAS_SYSV_SIGNAL 1 /* sigs not blocked/reset? */ + +#define HAS_STDLIB_H 1 /* /usr/include/stdlib.h */ +/*efine HAS_LIMITS_H 1 /* /usr/include/limits.h */ +#define HAS_FCNTL_H 1 /* /usr/include/fcntl.h */ +/*efine HAS_ERRNO_DECL 1 /* errno.h declares errno */ + +#define HAS_FSTAT 1 /* fstat syscall */ +#define HAS_FCHMOD 1 /* fchmod syscall */ +#define HAS_CHMOD 1 /* chmod syscall */ +#define HAS_FCHOWN 1 /* fchown syscall */ +#define HAS_CHOWN 1 /* chown syscall */ +/*efine HAS__FSETMODE 1 /* _fsetmode -- set file mode */ + +#define HAS_STRING_H 1 /* /usr/include/string.h */ +/*efine HAS_STRINGS_H 1 /* /usr/include/strings.h */ + +#define HAS_UNISTD_H 1 /* /usr/include/unistd.h */ +#define HAS_UTIME 1 /* POSIX utime(path, times) */ +/*efine HAS_UTIMES 1 /* use utimes() syscall instead */ +#define HAS_UTIME_H 1 /* UTIME header file */ +/*efine HAS_UTIMBUF 1 /* struct utimbuf */ +/*efine HAS_UTIMEUSEC 1 /* microseconds in utimbuf? */ + +#endif /* CONFIG_H */ diff --git a/linphone/gsmlib/debug.c b/linphone/gsmlib/debug.c new file mode 100644 index 000000000..d4b820d23 --- /dev/null +++ b/linphone/gsmlib/debug.c @@ -0,0 +1,76 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/debug.c,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#include "private.h" + +#ifndef NDEBUG + +/* If NDEBUG _is_ defined and no debugging should be performed, + * calls to functions in this module are #defined to nothing + * in private.h. + */ + +#include +#include "proto.h" + +void gsm_debug_words P4( (name, from, to, ptr), + char * name, + int from, + int to, + word * ptr) +{ + int nprinted = 0; + + fprintf( stderr, "%s [%d .. %d]: ", name, from, to ); + while (from <= to) { + fprintf(stderr, "%d ", ptr[ from ] ); + from++; + if (nprinted++ >= 7) { + nprinted = 0; + if (from < to) putc('\n', stderr); + } + } + putc('\n', stderr); +} + +void gsm_debug_longwords P4( (name, from, to, ptr), + char * name, + int from, + int to, + longword * ptr) +{ + int nprinted = 0; + + fprintf( stderr, "%s [%d .. %d]: ", name, from, to ); + while (from <= to) { + + fprintf(stderr, "%d ", ptr[ from ] ); + from++; + if (nprinted++ >= 7) { + nprinted = 0; + if (from < to) putc('\n', stderr); + } + } + putc('\n', stderr); +} + +void gsm_debug_longword P2( (name, value), + char * name, + longword value ) +{ + fprintf(stderr, "%s: %d\n", name, (long)value ); +} + +void gsm_debug_word P2( (name, value), + char * name, + word value ) +{ + fprintf(stderr, "%s: %d\n", name, (long)value); +} + +#endif diff --git a/linphone/gsmlib/decode.c b/linphone/gsmlib/decode.c new file mode 100644 index 000000000..fa4a3068f --- /dev/null +++ b/linphone/gsmlib/decode.c @@ -0,0 +1,63 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/decode.c,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#include + +#include "private.h" +#include "gsm.h" +#include "proto.h" + +/* + * 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER + */ + +static void Postprocessing P2((S,s), + struct gsm_state * S, + register word * s) +{ + register int k; + register word msr = S->msr; + register longword ltmp; /* for GSM_ADD */ + register word tmp; + + for (k = 160; k--; s++) { + tmp = GSM_MULT_R( msr, 28180 ); + msr = GSM_ADD(*s, tmp); /* Deemphasis */ + *s = GSM_ADD(msr, msr) & 0xFFF8; /* Truncation & Upscaling */ + } + S->msr = msr; +} + +void Gsm_Decoder P8((S,LARcr, Ncr,bcr,Mcr,xmaxcr,xMcr,s), + struct gsm_state * S, + + word * LARcr, /* [0..7] IN */ + + word * Ncr, /* [0..3] IN */ + word * bcr, /* [0..3] IN */ + word * Mcr, /* [0..3] IN */ + word * xmaxcr, /* [0..3] IN */ + word * xMcr, /* [0..13*4] IN */ + + word * s) /* [0..159] OUT */ +{ + int j, k; + word erp[40], wt[160]; + word * drp = S->dp0 + 120; + + for (j=0; j <= 3; j++, xmaxcr++, bcr++, Ncr++, Mcr++, xMcr += 13) { + + Gsm_RPE_Decoding( S, *xmaxcr, *Mcr, xMcr, erp ); + Gsm_Long_Term_Synthesis_Filtering( S, *Ncr, *bcr, erp, drp ); + + for (k = 0; k <= 39; k++) wt[ j * 40 + k ] = drp[ k ]; + } + + Gsm_Short_Term_Synthesis_Filter( S, LARcr, wt, s ); + Postprocessing(S, s); +} diff --git a/linphone/gsmlib/gsm.h b/linphone/gsmlib/gsm.h new file mode 100644 index 000000000..78e7f82c1 --- /dev/null +++ b/linphone/gsmlib/gsm.h @@ -0,0 +1,96 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/*$Header: /sources/linphone/linphone/gsmlib/gsm.h,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $*/ + +#ifndef GSM_H +#define GSM_H + +#ifdef __cplusplus +# define NeedFunctionPrototypes 1 +#endif + +#if __STDC__ +# define NeedFunctionPrototypes 1 +#endif + +#ifdef _NO_PROTO +# undef NeedFunctionPrototypes +#endif + +#ifdef NeedFunctionPrototypes +# include /* for FILE * */ +#endif + +#undef GSM_P +#if NeedFunctionPrototypes +# define GSM_P( protos ) protos +#else +# define GSM_P( protos ) ( /* protos */ ) +#endif + +/* + * Interface +vocoders.h" */ + + +typedef struct gsm_state * gsm; +typedef short gsm_signal; /* signed 16 bit */ +typedef unsigned char gsm_byte; +typedef gsm_byte gsm_frame[33]; /* 33 * 8 bits */ + +#define GSM_MAGIC 0xD /* 13 kbit/s RPE-LTP */ + +#define GSM_PATCHLEVEL 10 +#define GSM_MINOR 0 +#define GSM_MAJOR 1 + +#define GSM_OPT_VERBOSE 1 +#define GSM_OPT_FAST 2 +#define GSM_OPT_LTP_CUT 3 +#define GSM_OPT_WAV49 4 +#define GSM_OPT_FRAME_INDEX 5 +#define GSM_OPT_FRAME_CHAIN 6 + +#ifndef __cplusplus + +extern gsm gsm_create GSM_P((void)); +extern void gsm_destroy GSM_P((gsm)); + +extern int gsm_print GSM_P((FILE *, gsm, gsm_byte *)); +extern int gsm_option GSM_P((gsm, int, int *)); + +extern void gsm_encode GSM_P((gsm, gsm_signal *, gsm_byte *)); +extern int gsm_decode GSM_P((gsm, gsm_byte *, gsm_signal *)); + +extern int gsm_explode GSM_P((gsm, gsm_byte *, gsm_signal *)); +extern void gsm_implode GSM_P((gsm, gsm_signal *, gsm_byte *)); +#else +extern "C" +{ +gsm gsm_create GSM_P((void)); +void gsm_destroy GSM_P((gsm)); + +int gsm_print GSM_P((FILE *, gsm, gsm_byte *)); +int gsm_option GSM_P((gsm, int, int *)); + +void gsm_encode GSM_P((gsm, gsm_signal *, gsm_byte *)); +int gsm_decode GSM_P((gsm, gsm_byte *, gsm_signal *)); + +int gsm_explode GSM_P((gsm, gsm_byte *, gsm_signal *)); +void gsm_implode GSM_P((gsm, gsm_signal *, gsm_byte *)); +} + + + + +#endif + + + +#undef GSM_P + +#endif /* GSM_H */ diff --git a/linphone/gsmlib/gsm_create.c b/linphone/gsmlib/gsm_create.c new file mode 100644 index 000000000..b3e6bb13e --- /dev/null +++ b/linphone/gsmlib/gsm_create.c @@ -0,0 +1,45 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +static char const ident[] = "$Header: /sources/linphone/linphone/gsmlib/gsm_create.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $"; + +#include "config.h" + +#ifdef HAS_STRING_H +#include +#else +# include "proto.h" + extern char * memset P((char *, int, int)); +#endif + +#ifdef HAS_STDLIB_H +# include +#else +# ifdef HAS_MALLOC_H +# include +# else + extern char * malloc(); +# endif +#endif + +#include + +#include "gsm.h" +#include "private.h" +#include "proto.h" + +gsm gsm_create P0() +{ + gsm r; + + r = (gsm)malloc(sizeof(struct gsm_state)); + if (!r) return r; + + memset((char *)r, 0, sizeof(*r)); + r->nrp = 40; + + return r; +} diff --git a/linphone/gsmlib/gsm_decode.c b/linphone/gsmlib/gsm_decode.c new file mode 100644 index 000000000..928de7d56 --- /dev/null +++ b/linphone/gsmlib/gsm_decode.c @@ -0,0 +1,361 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_decode.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +int gsm_decode P3((s, c, target), gsm s, gsm_byte * c, gsm_signal * target) +{ + word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4]; + +#ifdef WAV49 + if (s->wav_fmt) { + + uword sr = 0; + + s->frame_index = !s->frame_index; + if (s->frame_index) { + + sr = *c++; + LARc[0] = sr & 0x3f; sr >>= 6; + sr |= (uword)*c++ << 2; + LARc[1] = sr & 0x3f; sr >>= 6; + sr |= (uword)*c++ << 4; + LARc[2] = sr & 0x1f; sr >>= 5; + LARc[3] = sr & 0x1f; sr >>= 5; + sr |= (uword)*c++ << 2; + LARc[4] = sr & 0xf; sr >>= 4; + LARc[5] = sr & 0xf; sr >>= 4; + sr |= (uword)*c++ << 2; /* 5 */ + LARc[6] = sr & 0x7; sr >>= 3; + LARc[7] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[0] = sr & 0x7f; sr >>= 7; + bc[0] = sr & 0x3; sr >>= 2; + Mc[0] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[0] = sr & 0x3f; sr >>= 6; + xmc[0] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[1] = sr & 0x7; sr >>= 3; + xmc[2] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[3] = sr & 0x7; sr >>= 3; + xmc[4] = sr & 0x7; sr >>= 3; + xmc[5] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 10 */ + xmc[6] = sr & 0x7; sr >>= 3; + xmc[7] = sr & 0x7; sr >>= 3; + xmc[8] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[9] = sr & 0x7; sr >>= 3; + xmc[10] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[11] = sr & 0x7; sr >>= 3; + xmc[12] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[1] = sr & 0x7f; sr >>= 7; + bc[1] = sr & 0x3; sr >>= 2; + Mc[1] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[1] = sr & 0x3f; sr >>= 6; + xmc[13] = sr & 0x7; sr >>= 3; + sr = *c++; /* 15 */ + xmc[14] = sr & 0x7; sr >>= 3; + xmc[15] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[16] = sr & 0x7; sr >>= 3; + xmc[17] = sr & 0x7; sr >>= 3; + xmc[18] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[19] = sr & 0x7; sr >>= 3; + xmc[20] = sr & 0x7; sr >>= 3; + xmc[21] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[22] = sr & 0x7; sr >>= 3; + xmc[23] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[24] = sr & 0x7; sr >>= 3; + xmc[25] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; /* 20 */ + Nc[2] = sr & 0x7f; sr >>= 7; + bc[2] = sr & 0x3; sr >>= 2; + Mc[2] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[2] = sr & 0x3f; sr >>= 6; + xmc[26] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[27] = sr & 0x7; sr >>= 3; + xmc[28] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[29] = sr & 0x7; sr >>= 3; + xmc[30] = sr & 0x7; sr >>= 3; + xmc[31] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[32] = sr & 0x7; sr >>= 3; + xmc[33] = sr & 0x7; sr >>= 3; + xmc[34] = sr & 0x7; sr >>= 3; + sr = *c++; /* 25 */ + xmc[35] = sr & 0x7; sr >>= 3; + xmc[36] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[37] = sr & 0x7; sr >>= 3; + xmc[38] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[3] = sr & 0x7f; sr >>= 7; + bc[3] = sr & 0x3; sr >>= 2; + Mc[3] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[3] = sr & 0x3f; sr >>= 6; + xmc[39] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[40] = sr & 0x7; sr >>= 3; + xmc[41] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; /* 30 */ + xmc[42] = sr & 0x7; sr >>= 3; + xmc[43] = sr & 0x7; sr >>= 3; + xmc[44] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[45] = sr & 0x7; sr >>= 3; + xmc[46] = sr & 0x7; sr >>= 3; + xmc[47] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[48] = sr & 0x7; sr >>= 3; + xmc[49] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[50] = sr & 0x7; sr >>= 3; + xmc[51] = sr & 0x7; sr >>= 3; + + s->frame_chain = sr & 0xf; + } + else { + sr = s->frame_chain; + sr |= (uword)*c++ << 4; /* 1 */ + LARc[0] = sr & 0x3f; sr >>= 6; + LARc[1] = sr & 0x3f; sr >>= 6; + sr = *c++; + LARc[2] = sr & 0x1f; sr >>= 5; + sr |= (uword)*c++ << 3; + LARc[3] = sr & 0x1f; sr >>= 5; + LARc[4] = sr & 0xf; sr >>= 4; + sr |= (uword)*c++ << 2; + LARc[5] = sr & 0xf; sr >>= 4; + LARc[6] = sr & 0x7; sr >>= 3; + LARc[7] = sr & 0x7; sr >>= 3; + sr = *c++; /* 5 */ + Nc[0] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[0] = sr & 0x3; sr >>= 2; + Mc[0] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[0] = sr & 0x3f; sr >>= 6; + xmc[0] = sr & 0x7; sr >>= 3; + xmc[1] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[2] = sr & 0x7; sr >>= 3; + xmc[3] = sr & 0x7; sr >>= 3; + xmc[4] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[5] = sr & 0x7; sr >>= 3; + xmc[6] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; /* 10 */ + xmc[7] = sr & 0x7; sr >>= 3; + xmc[8] = sr & 0x7; sr >>= 3; + xmc[9] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[10] = sr & 0x7; sr >>= 3; + xmc[11] = sr & 0x7; sr >>= 3; + xmc[12] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[1] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[1] = sr & 0x3; sr >>= 2; + Mc[1] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[1] = sr & 0x3f; sr >>= 6; + xmc[13] = sr & 0x7; sr >>= 3; + xmc[14] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 15 */ + xmc[15] = sr & 0x7; sr >>= 3; + xmc[16] = sr & 0x7; sr >>= 3; + xmc[17] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[18] = sr & 0x7; sr >>= 3; + xmc[19] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[20] = sr & 0x7; sr >>= 3; + xmc[21] = sr & 0x7; sr >>= 3; + xmc[22] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[23] = sr & 0x7; sr >>= 3; + xmc[24] = sr & 0x7; sr >>= 3; + xmc[25] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[2] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; /* 20 */ + bc[2] = sr & 0x3; sr >>= 2; + Mc[2] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[2] = sr & 0x3f; sr >>= 6; + xmc[26] = sr & 0x7; sr >>= 3; + xmc[27] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[28] = sr & 0x7; sr >>= 3; + xmc[29] = sr & 0x7; sr >>= 3; + xmc[30] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[31] = sr & 0x7; sr >>= 3; + xmc[32] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[33] = sr & 0x7; sr >>= 3; + xmc[34] = sr & 0x7; sr >>= 3; + xmc[35] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 25 */ + xmc[36] = sr & 0x7; sr >>= 3; + xmc[37] = sr & 0x7; sr >>= 3; + xmc[38] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[3] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[3] = sr & 0x3; sr >>= 2; + Mc[3] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[3] = sr & 0x3f; sr >>= 6; + xmc[39] = sr & 0x7; sr >>= 3; + xmc[40] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[41] = sr & 0x7; sr >>= 3; + xmc[42] = sr & 0x7; sr >>= 3; + xmc[43] = sr & 0x7; sr >>= 3; + sr = *c++; /* 30 */ + xmc[44] = sr & 0x7; sr >>= 3; + xmc[45] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[46] = sr & 0x7; sr >>= 3; + xmc[47] = sr & 0x7; sr >>= 3; + xmc[48] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[49] = sr & 0x7; sr >>= 3; + xmc[50] = sr & 0x7; sr >>= 3; + xmc[51] = sr & 0x7; sr >>= 3; + } + } + else +#endif + { + /* GSM_MAGIC = (*c >> 4) & 0xF; */ + + if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1; + + LARc[0] = (*c++ & 0xF) << 2; /* 1 */ + LARc[0] |= (*c >> 6) & 0x3; + LARc[1] = *c++ & 0x3F; + LARc[2] = (*c >> 3) & 0x1F; + LARc[3] = (*c++ & 0x7) << 2; + LARc[3] |= (*c >> 6) & 0x3; + LARc[4] = (*c >> 2) & 0xF; + LARc[5] = (*c++ & 0x3) << 2; + LARc[5] |= (*c >> 6) & 0x3; + LARc[6] = (*c >> 3) & 0x7; + LARc[7] = *c++ & 0x7; + Nc[0] = (*c >> 1) & 0x7F; + bc[0] = (*c++ & 0x1) << 1; + bc[0] |= (*c >> 7) & 0x1; + Mc[0] = (*c >> 5) & 0x3; + xmaxc[0] = (*c++ & 0x1F) << 1; + xmaxc[0] |= (*c >> 7) & 0x1; + xmc[0] = (*c >> 4) & 0x7; + xmc[1] = (*c >> 1) & 0x7; + xmc[2] = (*c++ & 0x1) << 2; + xmc[2] |= (*c >> 6) & 0x3; + xmc[3] = (*c >> 3) & 0x7; + xmc[4] = *c++ & 0x7; + xmc[5] = (*c >> 5) & 0x7; + xmc[6] = (*c >> 2) & 0x7; + xmc[7] = (*c++ & 0x3) << 1; /* 10 */ + xmc[7] |= (*c >> 7) & 0x1; + xmc[8] = (*c >> 4) & 0x7; + xmc[9] = (*c >> 1) & 0x7; + xmc[10] = (*c++ & 0x1) << 2; + xmc[10] |= (*c >> 6) & 0x3; + xmc[11] = (*c >> 3) & 0x7; + xmc[12] = *c++ & 0x7; + Nc[1] = (*c >> 1) & 0x7F; + bc[1] = (*c++ & 0x1) << 1; + bc[1] |= (*c >> 7) & 0x1; + Mc[1] = (*c >> 5) & 0x3; + xmaxc[1] = (*c++ & 0x1F) << 1; + xmaxc[1] |= (*c >> 7) & 0x1; + xmc[13] = (*c >> 4) & 0x7; + xmc[14] = (*c >> 1) & 0x7; + xmc[15] = (*c++ & 0x1) << 2; + xmc[15] |= (*c >> 6) & 0x3; + xmc[16] = (*c >> 3) & 0x7; + xmc[17] = *c++ & 0x7; + xmc[18] = (*c >> 5) & 0x7; + xmc[19] = (*c >> 2) & 0x7; + xmc[20] = (*c++ & 0x3) << 1; + xmc[20] |= (*c >> 7) & 0x1; + xmc[21] = (*c >> 4) & 0x7; + xmc[22] = (*c >> 1) & 0x7; + xmc[23] = (*c++ & 0x1) << 2; + xmc[23] |= (*c >> 6) & 0x3; + xmc[24] = (*c >> 3) & 0x7; + xmc[25] = *c++ & 0x7; + Nc[2] = (*c >> 1) & 0x7F; + bc[2] = (*c++ & 0x1) << 1; /* 20 */ + bc[2] |= (*c >> 7) & 0x1; + Mc[2] = (*c >> 5) & 0x3; + xmaxc[2] = (*c++ & 0x1F) << 1; + xmaxc[2] |= (*c >> 7) & 0x1; + xmc[26] = (*c >> 4) & 0x7; + xmc[27] = (*c >> 1) & 0x7; + xmc[28] = (*c++ & 0x1) << 2; + xmc[28] |= (*c >> 6) & 0x3; + xmc[29] = (*c >> 3) & 0x7; + xmc[30] = *c++ & 0x7; + xmc[31] = (*c >> 5) & 0x7; + xmc[32] = (*c >> 2) & 0x7; + xmc[33] = (*c++ & 0x3) << 1; + xmc[33] |= (*c >> 7) & 0x1; + xmc[34] = (*c >> 4) & 0x7; + xmc[35] = (*c >> 1) & 0x7; + xmc[36] = (*c++ & 0x1) << 2; + xmc[36] |= (*c >> 6) & 0x3; + xmc[37] = (*c >> 3) & 0x7; + xmc[38] = *c++ & 0x7; + Nc[3] = (*c >> 1) & 0x7F; + bc[3] = (*c++ & 0x1) << 1; + bc[3] |= (*c >> 7) & 0x1; + Mc[3] = (*c >> 5) & 0x3; + xmaxc[3] = (*c++ & 0x1F) << 1; + xmaxc[3] |= (*c >> 7) & 0x1; + xmc[39] = (*c >> 4) & 0x7; + xmc[40] = (*c >> 1) & 0x7; + xmc[41] = (*c++ & 0x1) << 2; + xmc[41] |= (*c >> 6) & 0x3; + xmc[42] = (*c >> 3) & 0x7; + xmc[43] = *c++ & 0x7; /* 30 */ + xmc[44] = (*c >> 5) & 0x7; + xmc[45] = (*c >> 2) & 0x7; + xmc[46] = (*c++ & 0x3) << 1; + xmc[46] |= (*c >> 7) & 0x1; + xmc[47] = (*c >> 4) & 0x7; + xmc[48] = (*c >> 1) & 0x7; + xmc[49] = (*c++ & 0x1) << 2; + xmc[49] |= (*c >> 6) & 0x3; + xmc[50] = (*c >> 3) & 0x7; + xmc[51] = *c & 0x7; /* 33 */ + } + + Gsm_Decoder(s, LARc, Nc, bc, Mc, xmaxc, xmc, target); + + return 0; +} diff --git a/linphone/gsmlib/gsm_destroy.c b/linphone/gsmlib/gsm_destroy.c new file mode 100644 index 000000000..e8bc33e63 --- /dev/null +++ b/linphone/gsmlib/gsm_destroy.c @@ -0,0 +1,26 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_destroy.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include "gsm.h" +#include "config.h" +#include "proto.h" + +#ifdef HAS_STDLIB_H +# include +#else +# ifdef HAS_MALLOC_H +# include +# else + extern void free(); +# endif +#endif + +void gsm_destroy P1((S), gsm S) +{ + if (S) free((char *)S); +} diff --git a/linphone/gsmlib/gsm_encode.c b/linphone/gsmlib/gsm_encode.c new file mode 100644 index 000000000..0c55ee0aa --- /dev/null +++ b/linphone/gsmlib/gsm_encode.c @@ -0,0 +1,451 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_encode.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include "private.h" +#include "gsm.h" +#include "proto.h" + +void gsm_encode P3((s, source, c), gsm s, gsm_signal * source, gsm_byte * c) +{ + word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4]; + + Gsm_Coder(s, source, LARc, Nc, bc, Mc, xmaxc, xmc); + + + /* variable size + + GSM_MAGIC 4 + + LARc[0] 6 + LARc[1] 6 + LARc[2] 5 + LARc[3] 5 + LARc[4] 4 + LARc[5] 4 + LARc[6] 3 + LARc[7] 3 + + Nc[0] 7 + bc[0] 2 + Mc[0] 2 + xmaxc[0] 6 + xmc[0] 3 + xmc[1] 3 + xmc[2] 3 + xmc[3] 3 + xmc[4] 3 + xmc[5] 3 + xmc[6] 3 + xmc[7] 3 + xmc[8] 3 + xmc[9] 3 + xmc[10] 3 + xmc[11] 3 + xmc[12] 3 + + Nc[1] 7 + bc[1] 2 + Mc[1] 2 + xmaxc[1] 6 + xmc[13] 3 + xmc[14] 3 + xmc[15] 3 + xmc[16] 3 + xmc[17] 3 + xmc[18] 3 + xmc[19] 3 + xmc[20] 3 + xmc[21] 3 + xmc[22] 3 + xmc[23] 3 + xmc[24] 3 + xmc[25] 3 + + Nc[2] 7 + bc[2] 2 + Mc[2] 2 + xmaxc[2] 6 + xmc[26] 3 + xmc[27] 3 + xmc[28] 3 + xmc[29] 3 + xmc[30] 3 + xmc[31] 3 + xmc[32] 3 + xmc[33] 3 + xmc[34] 3 + xmc[35] 3 + xmc[36] 3 + xmc[37] 3 + xmc[38] 3 + + Nc[3] 7 + bc[3] 2 + Mc[3] 2 + xmaxc[3] 6 + xmc[39] 3 + xmc[40] 3 + xmc[41] 3 + xmc[42] 3 + xmc[43] 3 + xmc[44] 3 + xmc[45] 3 + xmc[46] 3 + xmc[47] 3 + xmc[48] 3 + xmc[49] 3 + xmc[50] 3 + xmc[51] 3 + */ + +#ifdef WAV49 + + if (s->wav_fmt) { + s->frame_index = !s->frame_index; + if (s->frame_index) { + + uword sr; + + sr = 0; + sr = sr >> 6 | LARc[0] << 10; + sr = sr >> 6 | LARc[1] << 10; + *c++ = sr >> 4; + sr = sr >> 5 | LARc[2] << 11; + *c++ = sr >> 7; + sr = sr >> 5 | LARc[3] << 11; + sr = sr >> 4 | LARc[4] << 12; + *c++ = sr >> 6; + sr = sr >> 4 | LARc[5] << 12; + sr = sr >> 3 | LARc[6] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | LARc[7] << 13; + sr = sr >> 7 | Nc[0] << 9; + *c++ = sr >> 5; + sr = sr >> 2 | bc[0] << 14; + sr = sr >> 2 | Mc[0] << 14; + sr = sr >> 6 | xmaxc[0] << 10; + *c++ = sr >> 3; + sr = sr >> 3 | xmc[0] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[1] << 13; + sr = sr >> 3 | xmc[2] << 13; + sr = sr >> 3 | xmc[3] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[4] << 13; + sr = sr >> 3 | xmc[5] << 13; + sr = sr >> 3 | xmc[6] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[7] << 13; + sr = sr >> 3 | xmc[8] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[9] << 13; + sr = sr >> 3 | xmc[10] << 13; + sr = sr >> 3 | xmc[11] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[12] << 13; + sr = sr >> 7 | Nc[1] << 9; + *c++ = sr >> 5; + sr = sr >> 2 | bc[1] << 14; + sr = sr >> 2 | Mc[1] << 14; + sr = sr >> 6 | xmaxc[1] << 10; + *c++ = sr >> 3; + sr = sr >> 3 | xmc[13] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[14] << 13; + sr = sr >> 3 | xmc[15] << 13; + sr = sr >> 3 | xmc[16] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[17] << 13; + sr = sr >> 3 | xmc[18] << 13; + sr = sr >> 3 | xmc[19] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[20] << 13; + sr = sr >> 3 | xmc[21] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[22] << 13; + sr = sr >> 3 | xmc[23] << 13; + sr = sr >> 3 | xmc[24] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[25] << 13; + sr = sr >> 7 | Nc[2] << 9; + *c++ = sr >> 5; + sr = sr >> 2 | bc[2] << 14; + sr = sr >> 2 | Mc[2] << 14; + sr = sr >> 6 | xmaxc[2] << 10; + *c++ = sr >> 3; + sr = sr >> 3 | xmc[26] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[27] << 13; + sr = sr >> 3 | xmc[28] << 13; + sr = sr >> 3 | xmc[29] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[30] << 13; + sr = sr >> 3 | xmc[31] << 13; + sr = sr >> 3 | xmc[32] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[33] << 13; + sr = sr >> 3 | xmc[34] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[35] << 13; + sr = sr >> 3 | xmc[36] << 13; + sr = sr >> 3 | xmc[37] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[38] << 13; + sr = sr >> 7 | Nc[3] << 9; + *c++ = sr >> 5; + sr = sr >> 2 | bc[3] << 14; + sr = sr >> 2 | Mc[3] << 14; + sr = sr >> 6 | xmaxc[3] << 10; + *c++ = sr >> 3; + sr = sr >> 3 | xmc[39] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[40] << 13; + sr = sr >> 3 | xmc[41] << 13; + sr = sr >> 3 | xmc[42] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[43] << 13; + sr = sr >> 3 | xmc[44] << 13; + sr = sr >> 3 | xmc[45] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[46] << 13; + sr = sr >> 3 | xmc[47] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[48] << 13; + sr = sr >> 3 | xmc[49] << 13; + sr = sr >> 3 | xmc[50] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[51] << 13; + sr = sr >> 4; + *c = sr >> 8; + s->frame_chain = *c; + } + else { + uword sr; + + sr = 0; + sr = sr >> 4 | s->frame_chain << 12; + sr = sr >> 6 | LARc[0] << 10; + *c++ = sr >> 6; + sr = sr >> 6 | LARc[1] << 10; + *c++ = sr >> 8; + sr = sr >> 5 | LARc[2] << 11; + sr = sr >> 5 | LARc[3] << 11; + *c++ = sr >> 6; + sr = sr >> 4 | LARc[4] << 12; + sr = sr >> 4 | LARc[5] << 12; + *c++ = sr >> 6; + sr = sr >> 3 | LARc[6] << 13; + sr = sr >> 3 | LARc[7] << 13; + *c++ = sr >> 8; + sr = sr >> 7 | Nc[0] << 9; + sr = sr >> 2 | bc[0] << 14; + *c++ = sr >> 7; + sr = sr >> 2 | Mc[0] << 14; + sr = sr >> 6 | xmaxc[0] << 10; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[0] << 13; + sr = sr >> 3 | xmc[1] << 13; + sr = sr >> 3 | xmc[2] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[3] << 13; + sr = sr >> 3 | xmc[4] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[5] << 13; + sr = sr >> 3 | xmc[6] << 13; + sr = sr >> 3 | xmc[7] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[8] << 13; + sr = sr >> 3 | xmc[9] << 13; + sr = sr >> 3 | xmc[10] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[11] << 13; + sr = sr >> 3 | xmc[12] << 13; + *c++ = sr >> 8; + sr = sr >> 7 | Nc[1] << 9; + sr = sr >> 2 | bc[1] << 14; + *c++ = sr >> 7; + sr = sr >> 2 | Mc[1] << 14; + sr = sr >> 6 | xmaxc[1] << 10; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[13] << 13; + sr = sr >> 3 | xmc[14] << 13; + sr = sr >> 3 | xmc[15] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[16] << 13; + sr = sr >> 3 | xmc[17] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[18] << 13; + sr = sr >> 3 | xmc[19] << 13; + sr = sr >> 3 | xmc[20] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[21] << 13; + sr = sr >> 3 | xmc[22] << 13; + sr = sr >> 3 | xmc[23] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[24] << 13; + sr = sr >> 3 | xmc[25] << 13; + *c++ = sr >> 8; + sr = sr >> 7 | Nc[2] << 9; + sr = sr >> 2 | bc[2] << 14; + *c++ = sr >> 7; + sr = sr >> 2 | Mc[2] << 14; + sr = sr >> 6 | xmaxc[2] << 10; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[26] << 13; + sr = sr >> 3 | xmc[27] << 13; + sr = sr >> 3 | xmc[28] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[29] << 13; + sr = sr >> 3 | xmc[30] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[31] << 13; + sr = sr >> 3 | xmc[32] << 13; + sr = sr >> 3 | xmc[33] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[34] << 13; + sr = sr >> 3 | xmc[35] << 13; + sr = sr >> 3 | xmc[36] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[37] << 13; + sr = sr >> 3 | xmc[38] << 13; + *c++ = sr >> 8; + sr = sr >> 7 | Nc[3] << 9; + sr = sr >> 2 | bc[3] << 14; + *c++ = sr >> 7; + sr = sr >> 2 | Mc[3] << 14; + sr = sr >> 6 | xmaxc[3] << 10; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[39] << 13; + sr = sr >> 3 | xmc[40] << 13; + sr = sr >> 3 | xmc[41] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[42] << 13; + sr = sr >> 3 | xmc[43] << 13; + *c++ = sr >> 8; + sr = sr >> 3 | xmc[44] << 13; + sr = sr >> 3 | xmc[45] << 13; + sr = sr >> 3 | xmc[46] << 13; + *c++ = sr >> 7; + sr = sr >> 3 | xmc[47] << 13; + sr = sr >> 3 | xmc[48] << 13; + sr = sr >> 3 | xmc[49] << 13; + *c++ = sr >> 6; + sr = sr >> 3 | xmc[50] << 13; + sr = sr >> 3 | xmc[51] << 13; + *c++ = sr >> 8; + } + } + + else + +#endif /* WAV49 */ + { + + *c++ = ((GSM_MAGIC & 0xF) << 4) /* 1 */ + | ((LARc[0] >> 2) & 0xF); + *c++ = ((LARc[0] & 0x3) << 6) + | (LARc[1] & 0x3F); + *c++ = ((LARc[2] & 0x1F) << 3) + | ((LARc[3] >> 2) & 0x7); + *c++ = ((LARc[3] & 0x3) << 6) + | ((LARc[4] & 0xF) << 2) + | ((LARc[5] >> 2) & 0x3); + *c++ = ((LARc[5] & 0x3) << 6) + | ((LARc[6] & 0x7) << 3) + | (LARc[7] & 0x7); + *c++ = ((Nc[0] & 0x7F) << 1) + | ((bc[0] >> 1) & 0x1); + *c++ = ((bc[0] & 0x1) << 7) + | ((Mc[0] & 0x3) << 5) + | ((xmaxc[0] >> 1) & 0x1F); + *c++ = ((xmaxc[0] & 0x1) << 7) + | ((xmc[0] & 0x7) << 4) + | ((xmc[1] & 0x7) << 1) + | ((xmc[2] >> 2) & 0x1); + *c++ = ((xmc[2] & 0x3) << 6) + | ((xmc[3] & 0x7) << 3) + | (xmc[4] & 0x7); + *c++ = ((xmc[5] & 0x7) << 5) /* 10 */ + | ((xmc[6] & 0x7) << 2) + | ((xmc[7] >> 1) & 0x3); + *c++ = ((xmc[7] & 0x1) << 7) + | ((xmc[8] & 0x7) << 4) + | ((xmc[9] & 0x7) << 1) + | ((xmc[10] >> 2) & 0x1); + *c++ = ((xmc[10] & 0x3) << 6) + | ((xmc[11] & 0x7) << 3) + | (xmc[12] & 0x7); + *c++ = ((Nc[1] & 0x7F) << 1) + | ((bc[1] >> 1) & 0x1); + *c++ = ((bc[1] & 0x1) << 7) + | ((Mc[1] & 0x3) << 5) + | ((xmaxc[1] >> 1) & 0x1F); + *c++ = ((xmaxc[1] & 0x1) << 7) + | ((xmc[13] & 0x7) << 4) + | ((xmc[14] & 0x7) << 1) + | ((xmc[15] >> 2) & 0x1); + *c++ = ((xmc[15] & 0x3) << 6) + | ((xmc[16] & 0x7) << 3) + | (xmc[17] & 0x7); + *c++ = ((xmc[18] & 0x7) << 5) + | ((xmc[19] & 0x7) << 2) + | ((xmc[20] >> 1) & 0x3); + *c++ = ((xmc[20] & 0x1) << 7) + | ((xmc[21] & 0x7) << 4) + | ((xmc[22] & 0x7) << 1) + | ((xmc[23] >> 2) & 0x1); + *c++ = ((xmc[23] & 0x3) << 6) + | ((xmc[24] & 0x7) << 3) + | (xmc[25] & 0x7); + *c++ = ((Nc[2] & 0x7F) << 1) /* 20 */ + | ((bc[2] >> 1) & 0x1); + *c++ = ((bc[2] & 0x1) << 7) + | ((Mc[2] & 0x3) << 5) + | ((xmaxc[2] >> 1) & 0x1F); + *c++ = ((xmaxc[2] & 0x1) << 7) + | ((xmc[26] & 0x7) << 4) + | ((xmc[27] & 0x7) << 1) + | ((xmc[28] >> 2) & 0x1); + *c++ = ((xmc[28] & 0x3) << 6) + | ((xmc[29] & 0x7) << 3) + | (xmc[30] & 0x7); + *c++ = ((xmc[31] & 0x7) << 5) + | ((xmc[32] & 0x7) << 2) + | ((xmc[33] >> 1) & 0x3); + *c++ = ((xmc[33] & 0x1) << 7) + | ((xmc[34] & 0x7) << 4) + | ((xmc[35] & 0x7) << 1) + | ((xmc[36] >> 2) & 0x1); + *c++ = ((xmc[36] & 0x3) << 6) + | ((xmc[37] & 0x7) << 3) + | (xmc[38] & 0x7); + *c++ = ((Nc[3] & 0x7F) << 1) + | ((bc[3] >> 1) & 0x1); + *c++ = ((bc[3] & 0x1) << 7) + | ((Mc[3] & 0x3) << 5) + | ((xmaxc[3] >> 1) & 0x1F); + *c++ = ((xmaxc[3] & 0x1) << 7) + | ((xmc[39] & 0x7) << 4) + | ((xmc[40] & 0x7) << 1) + | ((xmc[41] >> 2) & 0x1); + *c++ = ((xmc[41] & 0x3) << 6) /* 30 */ + | ((xmc[42] & 0x7) << 3) + | (xmc[43] & 0x7); + *c++ = ((xmc[44] & 0x7) << 5) + | ((xmc[45] & 0x7) << 2) + | ((xmc[46] >> 1) & 0x3); + *c++ = ((xmc[46] & 0x1) << 7) + | ((xmc[47] & 0x7) << 4) + | ((xmc[48] & 0x7) << 1) + | ((xmc[49] >> 2) & 0x1); + *c++ = ((xmc[49] & 0x3) << 6) + | ((xmc[50] & 0x7) << 3) + | (xmc[51] & 0x7); + + } +} diff --git a/linphone/gsmlib/gsm_explode.c b/linphone/gsmlib/gsm_explode.c new file mode 100644 index 000000000..b7c98ed5a --- /dev/null +++ b/linphone/gsmlib/gsm_explode.c @@ -0,0 +1,417 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_explode.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include "private.h" +#include "gsm.h" +#include "proto.h" + +int gsm_explode P3((s, c, target), gsm s, gsm_byte * c, gsm_signal * target) +{ +# define LARc target +# define Nc *((gsm_signal (*) [17])(target + 8)) +# define bc *((gsm_signal (*) [17])(target + 9)) +# define Mc *((gsm_signal (*) [17])(target + 10)) +# define xmaxc *((gsm_signal (*) [17])(target + 11)) + + +#ifdef WAV49 + if (s->wav_fmt) { + + uword sr = 0; + + if (s->frame_index == 1) { + + sr = *c++; + LARc[0] = sr & 0x3f; sr >>= 6; + sr |= (uword)*c++ << 2; + LARc[1] = sr & 0x3f; sr >>= 6; + sr |= (uword)*c++ << 4; + LARc[2] = sr & 0x1f; sr >>= 5; + LARc[3] = sr & 0x1f; sr >>= 5; + sr |= (uword)*c++ << 2; + LARc[4] = sr & 0xf; sr >>= 4; + LARc[5] = sr & 0xf; sr >>= 4; + sr |= (uword)*c++ << 2; /* 5 */ + LARc[6] = sr & 0x7; sr >>= 3; + LARc[7] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[0] = sr & 0x7f; sr >>= 7; + bc[0] = sr & 0x3; sr >>= 2; + Mc[0] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[0] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (target + 12) + xmc[0] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[1] = sr & 0x7; sr >>= 3; + xmc[2] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[3] = sr & 0x7; sr >>= 3; + xmc[4] = sr & 0x7; sr >>= 3; + xmc[5] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 10 */ + xmc[6] = sr & 0x7; sr >>= 3; + xmc[7] = sr & 0x7; sr >>= 3; + xmc[8] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[9] = sr & 0x7; sr >>= 3; + xmc[10] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[11] = sr & 0x7; sr >>= 3; + xmc[12] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[1] = sr & 0x7f; sr >>= 7; + bc[1] = sr & 0x3; sr >>= 2; + Mc[1] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[1] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (target + 29 - 13) + + xmc[13] = sr & 0x7; sr >>= 3; + sr = *c++; /* 15 */ + xmc[14] = sr & 0x7; sr >>= 3; + xmc[15] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[16] = sr & 0x7; sr >>= 3; + xmc[17] = sr & 0x7; sr >>= 3; + xmc[18] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[19] = sr & 0x7; sr >>= 3; + xmc[20] = sr & 0x7; sr >>= 3; + xmc[21] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[22] = sr & 0x7; sr >>= 3; + xmc[23] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[24] = sr & 0x7; sr >>= 3; + xmc[25] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; /* 20 */ + Nc[2] = sr & 0x7f; sr >>= 7; + bc[2] = sr & 0x3; sr >>= 2; + Mc[2] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[2] = sr & 0x3f; sr >>= 6; + +#undef xmc +#define xmc (target + 46 - 26) + + xmc[26] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[27] = sr & 0x7; sr >>= 3; + xmc[28] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[29] = sr & 0x7; sr >>= 3; + xmc[30] = sr & 0x7; sr >>= 3; + xmc[31] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[32] = sr & 0x7; sr >>= 3; + xmc[33] = sr & 0x7; sr >>= 3; + xmc[34] = sr & 0x7; sr >>= 3; + sr = *c++; /* 25 */ + xmc[35] = sr & 0x7; sr >>= 3; + xmc[36] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[37] = sr & 0x7; sr >>= 3; + xmc[38] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[3] = sr & 0x7f; sr >>= 7; + bc[3] = sr & 0x3; sr >>= 2; + Mc[3] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[3] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (target + 63 - 39) + + xmc[39] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[40] = sr & 0x7; sr >>= 3; + xmc[41] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; /* 30 */ + xmc[42] = sr & 0x7; sr >>= 3; + xmc[43] = sr & 0x7; sr >>= 3; + xmc[44] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[45] = sr & 0x7; sr >>= 3; + xmc[46] = sr & 0x7; sr >>= 3; + xmc[47] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[48] = sr & 0x7; sr >>= 3; + xmc[49] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[50] = sr & 0x7; sr >>= 3; + xmc[51] = sr & 0x7; sr >>= 3; + + s->frame_chain = sr & 0xf; + } + else { + sr = s->frame_chain; + sr |= (uword)*c++ << 4; /* 1 */ + LARc[0] = sr & 0x3f; sr >>= 6; + LARc[1] = sr & 0x3f; sr >>= 6; + sr = *c++; + LARc[2] = sr & 0x1f; sr >>= 5; + sr |= (uword)*c++ << 3; + LARc[3] = sr & 0x1f; sr >>= 5; + LARc[4] = sr & 0xf; sr >>= 4; + sr |= (uword)*c++ << 2; + LARc[5] = sr & 0xf; sr >>= 4; + LARc[6] = sr & 0x7; sr >>= 3; + LARc[7] = sr & 0x7; sr >>= 3; + sr = *c++; /* 5 */ + Nc[0] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[0] = sr & 0x3; sr >>= 2; + Mc[0] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[0] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (target + 12) + xmc[0] = sr & 0x7; sr >>= 3; + xmc[1] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[2] = sr & 0x7; sr >>= 3; + xmc[3] = sr & 0x7; sr >>= 3; + xmc[4] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[5] = sr & 0x7; sr >>= 3; + xmc[6] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; /* 10 */ + xmc[7] = sr & 0x7; sr >>= 3; + xmc[8] = sr & 0x7; sr >>= 3; + xmc[9] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[10] = sr & 0x7; sr >>= 3; + xmc[11] = sr & 0x7; sr >>= 3; + xmc[12] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[1] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[1] = sr & 0x3; sr >>= 2; + Mc[1] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[1] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (target + 29 - 13) + + xmc[13] = sr & 0x7; sr >>= 3; + xmc[14] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 15 */ + xmc[15] = sr & 0x7; sr >>= 3; + xmc[16] = sr & 0x7; sr >>= 3; + xmc[17] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[18] = sr & 0x7; sr >>= 3; + xmc[19] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[20] = sr & 0x7; sr >>= 3; + xmc[21] = sr & 0x7; sr >>= 3; + xmc[22] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[23] = sr & 0x7; sr >>= 3; + xmc[24] = sr & 0x7; sr >>= 3; + xmc[25] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[2] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; /* 20 */ + bc[2] = sr & 0x3; sr >>= 2; + Mc[2] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[2] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (target + 46 - 26) + xmc[26] = sr & 0x7; sr >>= 3; + xmc[27] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[28] = sr & 0x7; sr >>= 3; + xmc[29] = sr & 0x7; sr >>= 3; + xmc[30] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[31] = sr & 0x7; sr >>= 3; + xmc[32] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[33] = sr & 0x7; sr >>= 3; + xmc[34] = sr & 0x7; sr >>= 3; + xmc[35] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 25 */ + xmc[36] = sr & 0x7; sr >>= 3; + xmc[37] = sr & 0x7; sr >>= 3; + xmc[38] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[3] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[3] = sr & 0x3; sr >>= 2; + Mc[3] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[3] = sr & 0x3f; sr >>= 6; + +#undef xmc +#define xmc (target + 63 - 39) + + xmc[39] = sr & 0x7; sr >>= 3; + xmc[40] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[41] = sr & 0x7; sr >>= 3; + xmc[42] = sr & 0x7; sr >>= 3; + xmc[43] = sr & 0x7; sr >>= 3; + sr = *c++; /* 30 */ + xmc[44] = sr & 0x7; sr >>= 3; + xmc[45] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[46] = sr & 0x7; sr >>= 3; + xmc[47] = sr & 0x7; sr >>= 3; + xmc[48] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[49] = sr & 0x7; sr >>= 3; + xmc[50] = sr & 0x7; sr >>= 3; + xmc[51] = sr & 0x7; sr >>= 3; + } + } + else +#endif + { + /* GSM_MAGIC = (*c >> 4) & 0xF; */ + + if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1; + + LARc[0] = (*c++ & 0xF) << 2; /* 1 */ + LARc[0] |= (*c >> 6) & 0x3; + LARc[1] = *c++ & 0x3F; + LARc[2] = (*c >> 3) & 0x1F; + LARc[3] = (*c++ & 0x7) << 2; + LARc[3] |= (*c >> 6) & 0x3; + LARc[4] = (*c >> 2) & 0xF; + LARc[5] = (*c++ & 0x3) << 2; + LARc[5] |= (*c >> 6) & 0x3; + LARc[6] = (*c >> 3) & 0x7; + LARc[7] = *c++ & 0x7; + + Nc[0] = (*c >> 1) & 0x7F; + + bc[0] = (*c++ & 0x1) << 1; + bc[0] |= (*c >> 7) & 0x1; + + Mc[0] = (*c >> 5) & 0x3; + + xmaxc[0] = (*c++ & 0x1F) << 1; + xmaxc[0] |= (*c >> 7) & 0x1; + +#undef xmc +#define xmc (target + 12) + + xmc[0] = (*c >> 4) & 0x7; + xmc[1] = (*c >> 1) & 0x7; + xmc[2] = (*c++ & 0x1) << 2; + xmc[2] |= (*c >> 6) & 0x3; + xmc[3] = (*c >> 3) & 0x7; + xmc[4] = *c++ & 0x7; + xmc[5] = (*c >> 5) & 0x7; + xmc[6] = (*c >> 2) & 0x7; + xmc[7] = (*c++ & 0x3) << 1; /* 10 */ + xmc[7] |= (*c >> 7) & 0x1; + xmc[8] = (*c >> 4) & 0x7; + xmc[9] = (*c >> 1) & 0x7; + xmc[10] = (*c++ & 0x1) << 2; + xmc[10] |= (*c >> 6) & 0x3; + xmc[11] = (*c >> 3) & 0x7; + xmc[12] = *c++ & 0x7; + + Nc[1] = (*c >> 1) & 0x7F; + + bc[1] = (*c++ & 0x1) << 1; + bc[1] |= (*c >> 7) & 0x1; + + Mc[1] = (*c >> 5) & 0x3; + + xmaxc[1] = (*c++ & 0x1F) << 1; + xmaxc[1] |= (*c >> 7) & 0x1; + +#undef xmc +#define xmc (target + 29 - 13) + + xmc[13] = (*c >> 4) & 0x7; + xmc[14] = (*c >> 1) & 0x7; + xmc[15] = (*c++ & 0x1) << 2; + xmc[15] |= (*c >> 6) & 0x3; + xmc[16] = (*c >> 3) & 0x7; + xmc[17] = *c++ & 0x7; + xmc[18] = (*c >> 5) & 0x7; + xmc[19] = (*c >> 2) & 0x7; + xmc[20] = (*c++ & 0x3) << 1; + xmc[20] |= (*c >> 7) & 0x1; + xmc[21] = (*c >> 4) & 0x7; + xmc[22] = (*c >> 1) & 0x7; + xmc[23] = (*c++ & 0x1) << 2; + xmc[23] |= (*c >> 6) & 0x3; + xmc[24] = (*c >> 3) & 0x7; + xmc[25] = *c++ & 0x7; + + Nc[2] = (*c >> 1) & 0x7F; + + bc[2] = (*c++ & 0x1) << 1; /* 20 */ + bc[2] |= (*c >> 7) & 0x1; + + Mc[2] = (*c >> 5) & 0x3; + + xmaxc[2] = (*c++ & 0x1F) << 1; + xmaxc[2] |= (*c >> 7) & 0x1; + +#undef xmc +#define xmc (target + 46 - 26) + + xmc[26] = (*c >> 4) & 0x7; + xmc[27] = (*c >> 1) & 0x7; + xmc[28] = (*c++ & 0x1) << 2; + xmc[28] |= (*c >> 6) & 0x3; + xmc[29] = (*c >> 3) & 0x7; + xmc[30] = *c++ & 0x7; + xmc[31] = (*c >> 5) & 0x7; + xmc[32] = (*c >> 2) & 0x7; + xmc[33] = (*c++ & 0x3) << 1; + xmc[33] |= (*c >> 7) & 0x1; + xmc[34] = (*c >> 4) & 0x7; + xmc[35] = (*c >> 1) & 0x7; + xmc[36] = (*c++ & 0x1) << 2; + xmc[36] |= (*c >> 6) & 0x3; + xmc[37] = (*c >> 3) & 0x7; + xmc[38] = *c++ & 0x7; + + Nc[3] = (*c >> 1) & 0x7F; + + bc[3] = (*c++ & 0x1) << 1; + bc[3] |= (*c >> 7) & 0x1; + + Mc[3] = (*c >> 5) & 0x3; + + xmaxc[3] = (*c++ & 0x1F) << 1; + xmaxc[3] |= (*c >> 7) & 0x1; + +#undef xmc +#define xmc (target + 63 - 39) + + xmc[39] = (*c >> 4) & 0x7; + xmc[40] = (*c >> 1) & 0x7; + xmc[41] = (*c++ & 0x1) << 2; + xmc[41] |= (*c >> 6) & 0x3; + xmc[42] = (*c >> 3) & 0x7; + xmc[43] = *c++ & 0x7; /* 30 */ + xmc[44] = (*c >> 5) & 0x7; + xmc[45] = (*c >> 2) & 0x7; + xmc[46] = (*c++ & 0x3) << 1; + xmc[46] |= (*c >> 7) & 0x1; + xmc[47] = (*c >> 4) & 0x7; + xmc[48] = (*c >> 1) & 0x7; + xmc[49] = (*c++ & 0x1) << 2; + xmc[49] |= (*c >> 6) & 0x3; + xmc[50] = (*c >> 3) & 0x7; + xmc[51] = *c & 0x7; /* 33 */ + } + + return 0; +} diff --git a/linphone/gsmlib/gsm_implode.c b/linphone/gsmlib/gsm_implode.c new file mode 100644 index 000000000..e2c9d1c72 --- /dev/null +++ b/linphone/gsmlib/gsm_implode.c @@ -0,0 +1,515 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_implode.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +void gsm_implode P3((s, source, c), gsm s, gsm_signal * source, gsm_byte * c) +{ + /* variable size index + + GSM_MAGIC 4 - + + LARc[0] 6 0 + LARc[1] 6 1 + LARc[2] 5 2 + LARc[3] 5 3 + LARc[4] 4 4 + LARc[5] 4 5 + LARc[6] 3 6 + LARc[7] 3 7 + + Nc[0] 7 8 + bc[0] 2 9 + Mc[0] 2 10 + xmaxc[0] 6 11 + xmc[0] 3 12 + xmc[1] 3 13 + xmc[2] 3 14 + xmc[3] 3 15 + xmc[4] 3 16 + xmc[5] 3 17 + xmc[6] 3 18 + xmc[7] 3 19 + xmc[8] 3 20 + xmc[9] 3 21 + xmc[10] 3 22 + xmc[11] 3 23 + xmc[12] 3 24 + + Nc[1] 7 25 + bc[1] 2 26 + Mc[1] 2 27 + xmaxc[1] 6 28 + xmc[13] 3 29 + xmc[14] 3 30 + xmc[15] 3 31 + xmc[16] 3 32 + xmc[17] 3 33 + xmc[18] 3 34 + xmc[19] 3 35 + xmc[20] 3 36 + xmc[21] 3 37 + xmc[22] 3 38 + xmc[23] 3 39 + xmc[24] 3 40 + xmc[25] 3 41 + + Nc[2] 7 42 + bc[2] 2 43 + Mc[2] 2 44 + xmaxc[2] 6 45 + xmc[26] 3 46 + xmc[27] 3 47 + xmc[28] 3 48 + xmc[29] 3 49 + xmc[30] 3 50 + xmc[31] 3 51 + xmc[32] 3 52 + xmc[33] 3 53 + xmc[34] 3 54 + xmc[35] 3 55 + xmc[36] 3 56 + xmc[37] 3 57 + xmc[38] 3 58 + + Nc[3] 7 59 + bc[3] 2 60 + Mc[3] 2 61 + xmaxc[3] 6 62 + xmc[39] 3 63 + xmc[40] 3 64 + xmc[41] 3 65 + xmc[42] 3 66 + xmc[43] 3 67 + xmc[44] 3 68 + xmc[45] 3 69 + xmc[46] 3 70 + xmc[47] 3 71 + xmc[48] 3 72 + xmc[49] 3 73 + xmc[50] 3 74 + xmc[51] 3 75 + */ + + /* There are 76 parameters per frame. The first eight are + * unique. The remaining 68 are four identical subframes of + * 17 parameters each. gsm_implode converts from a representation + * of these parameters as values in one array of signed words + * to the "packed" version of a GSM frame. + */ + +# define LARc source +# define Nc *((gsm_signal (*) [17])(source + 8)) +# define bc *((gsm_signal (*) [17])(source + 9)) +# define Mc *((gsm_signal (*) [17])(source + 10)) +# define xmaxc *((gsm_signal (*) [17])(source + 11)) + +#ifdef WAV49 + if (s->wav_fmt) { + + uword sr = 0; + if (s->frame_index == 0) { + + sr = *c++; + LARc[0] = sr & 0x3f; sr >>= 6; + sr |= (uword)*c++ << 2; + LARc[1] = sr & 0x3f; sr >>= 6; + sr |= (uword)*c++ << 4; + LARc[2] = sr & 0x1f; sr >>= 5; + LARc[3] = sr & 0x1f; sr >>= 5; + sr |= (uword)*c++ << 2; + LARc[4] = sr & 0xf; sr >>= 4; + LARc[5] = sr & 0xf; sr >>= 4; + sr |= (uword)*c++ << 2; /* 5 */ + LARc[6] = sr & 0x7; sr >>= 3; + LARc[7] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[0] = sr & 0x7f; sr >>= 7; + bc[0] = sr & 0x3; sr >>= 2; + Mc[0] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[0] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 12) + xmc[0] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[1] = sr & 0x7; sr >>= 3; + xmc[2] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[3] = sr & 0x7; sr >>= 3; + xmc[4] = sr & 0x7; sr >>= 3; + xmc[5] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 10 */ + xmc[6] = sr & 0x7; sr >>= 3; + xmc[7] = sr & 0x7; sr >>= 3; + xmc[8] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[9] = sr & 0x7; sr >>= 3; + xmc[10] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[11] = sr & 0x7; sr >>= 3; + xmc[12] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[1] = sr & 0x7f; sr >>= 7; + bc[1] = sr & 0x3; sr >>= 2; + Mc[1] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[1] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 29 - 13) + xmc[13] = sr & 0x7; sr >>= 3; + sr = *c++; /* 15 */ + xmc[14] = sr & 0x7; sr >>= 3; + xmc[15] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[16] = sr & 0x7; sr >>= 3; + xmc[17] = sr & 0x7; sr >>= 3; + xmc[18] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[19] = sr & 0x7; sr >>= 3; + xmc[20] = sr & 0x7; sr >>= 3; + xmc[21] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[22] = sr & 0x7; sr >>= 3; + xmc[23] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[24] = sr & 0x7; sr >>= 3; + xmc[25] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; /* 20 */ + Nc[2] = sr & 0x7f; sr >>= 7; + bc[2] = sr & 0x3; sr >>= 2; + Mc[2] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[2] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 46 - 26) + xmc[26] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[27] = sr & 0x7; sr >>= 3; + xmc[28] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[29] = sr & 0x7; sr >>= 3; + xmc[30] = sr & 0x7; sr >>= 3; + xmc[31] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[32] = sr & 0x7; sr >>= 3; + xmc[33] = sr & 0x7; sr >>= 3; + xmc[34] = sr & 0x7; sr >>= 3; + sr = *c++; /* 25 */ + xmc[35] = sr & 0x7; sr >>= 3; + xmc[36] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[37] = sr & 0x7; sr >>= 3; + xmc[38] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 4; + Nc[3] = sr & 0x7f; sr >>= 7; + bc[3] = sr & 0x3; sr >>= 2; + Mc[3] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 1; + xmaxc[3] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 63 - 39) + + xmc[39] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[40] = sr & 0x7; sr >>= 3; + xmc[41] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; /* 30 */ + xmc[42] = sr & 0x7; sr >>= 3; + xmc[43] = sr & 0x7; sr >>= 3; + xmc[44] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[45] = sr & 0x7; sr >>= 3; + xmc[46] = sr & 0x7; sr >>= 3; + xmc[47] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[48] = sr & 0x7; sr >>= 3; + xmc[49] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[50] = sr & 0x7; sr >>= 3; + xmc[51] = sr & 0x7; sr >>= 3; + + s->frame_chain = sr & 0xf; + } + else { + sr = s->frame_chain; + sr |= (uword)*c++ << 4; /* 1 */ + LARc[0] = sr & 0x3f; sr >>= 6; + LARc[1] = sr & 0x3f; sr >>= 6; + sr = *c++; + LARc[2] = sr & 0x1f; sr >>= 5; + sr |= (uword)*c++ << 3; + LARc[3] = sr & 0x1f; sr >>= 5; + LARc[4] = sr & 0xf; sr >>= 4; + sr |= (uword)*c++ << 2; + LARc[5] = sr & 0xf; sr >>= 4; + LARc[6] = sr & 0x7; sr >>= 3; + LARc[7] = sr & 0x7; sr >>= 3; + sr = *c++; /* 5 */ + Nc[0] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[0] = sr & 0x3; sr >>= 2; + Mc[0] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[0] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 12) + xmc[0] = sr & 0x7; sr >>= 3; + xmc[1] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[2] = sr & 0x7; sr >>= 3; + xmc[3] = sr & 0x7; sr >>= 3; + xmc[4] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[5] = sr & 0x7; sr >>= 3; + xmc[6] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; /* 10 */ + xmc[7] = sr & 0x7; sr >>= 3; + xmc[8] = sr & 0x7; sr >>= 3; + xmc[9] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[10] = sr & 0x7; sr >>= 3; + xmc[11] = sr & 0x7; sr >>= 3; + xmc[12] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[1] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[1] = sr & 0x3; sr >>= 2; + Mc[1] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[1] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 29 - 13) + xmc[13] = sr & 0x7; sr >>= 3; + xmc[14] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 15 */ + xmc[15] = sr & 0x7; sr >>= 3; + xmc[16] = sr & 0x7; sr >>= 3; + xmc[17] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[18] = sr & 0x7; sr >>= 3; + xmc[19] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[20] = sr & 0x7; sr >>= 3; + xmc[21] = sr & 0x7; sr >>= 3; + xmc[22] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[23] = sr & 0x7; sr >>= 3; + xmc[24] = sr & 0x7; sr >>= 3; + xmc[25] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[2] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; /* 20 */ + bc[2] = sr & 0x3; sr >>= 2; + Mc[2] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[2] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 46 - 26) + xmc[26] = sr & 0x7; sr >>= 3; + xmc[27] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[28] = sr & 0x7; sr >>= 3; + xmc[29] = sr & 0x7; sr >>= 3; + xmc[30] = sr & 0x7; sr >>= 3; + sr = *c++; + xmc[31] = sr & 0x7; sr >>= 3; + xmc[32] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[33] = sr & 0x7; sr >>= 3; + xmc[34] = sr & 0x7; sr >>= 3; + xmc[35] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; /* 25 */ + xmc[36] = sr & 0x7; sr >>= 3; + xmc[37] = sr & 0x7; sr >>= 3; + xmc[38] = sr & 0x7; sr >>= 3; + sr = *c++; + Nc[3] = sr & 0x7f; sr >>= 7; + sr |= (uword)*c++ << 1; + bc[3] = sr & 0x3; sr >>= 2; + Mc[3] = sr & 0x3; sr >>= 2; + sr |= (uword)*c++ << 5; + xmaxc[3] = sr & 0x3f; sr >>= 6; +#undef xmc +#define xmc (source + 63 - 39) + + xmc[39] = sr & 0x7; sr >>= 3; + xmc[40] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[41] = sr & 0x7; sr >>= 3; + xmc[42] = sr & 0x7; sr >>= 3; + xmc[43] = sr & 0x7; sr >>= 3; + sr = *c++; /* 30 */ + xmc[44] = sr & 0x7; sr >>= 3; + xmc[45] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 2; + xmc[46] = sr & 0x7; sr >>= 3; + xmc[47] = sr & 0x7; sr >>= 3; + xmc[48] = sr & 0x7; sr >>= 3; + sr |= (uword)*c++ << 1; + xmc[49] = sr & 0x7; sr >>= 3; + xmc[50] = sr & 0x7; sr >>= 3; + xmc[51] = sr & 0x7; sr >>= 3; + } + } + else +#endif + { + + *c++ = ((GSM_MAGIC & 0xF) << 4) /* 1 */ + | ((LARc[0] >> 2) & 0xF); + *c++ = ((LARc[0] & 0x3) << 6) + | (LARc[1] & 0x3F); + *c++ = ((LARc[2] & 0x1F) << 3) + | ((LARc[3] >> 2) & 0x7); + *c++ = ((LARc[3] & 0x3) << 6) + | ((LARc[4] & 0xF) << 2) + | ((LARc[5] >> 2) & 0x3); + *c++ = ((LARc[5] & 0x3) << 6) + | ((LARc[6] & 0x7) << 3) + | (LARc[7] & 0x7); + + + *c++ = ((Nc[0] & 0x7F) << 1) + + + | ((bc[0] >> 1) & 0x1); + *c++ = ((bc[0] & 0x1) << 7) + + + | ((Mc[0] & 0x3) << 5) + + | ((xmaxc[0] >> 1) & 0x1F); + *c++ = ((xmaxc[0] & 0x1) << 7) + +#undef xmc +#define xmc (source + 12) + + | ((xmc[0] & 0x7) << 4) + | ((xmc[1] & 0x7) << 1) + | ((xmc[2] >> 2) & 0x1); + *c++ = ((xmc[2] & 0x3) << 6) + | ((xmc[3] & 0x7) << 3) + | (xmc[4] & 0x7); + *c++ = ((xmc[5] & 0x7) << 5) /* 10 */ + | ((xmc[6] & 0x7) << 2) + | ((xmc[7] >> 1) & 0x3); + *c++ = ((xmc[7] & 0x1) << 7) + | ((xmc[8] & 0x7) << 4) + | ((xmc[9] & 0x7) << 1) + | ((xmc[10] >> 2) & 0x1); + *c++ = ((xmc[10] & 0x3) << 6) + | ((xmc[11] & 0x7) << 3) + | (xmc[12] & 0x7); + + + *c++ = ((Nc[1] & 0x7F) << 1) + + + | ((bc[1] >> 1) & 0x1); + *c++ = ((bc[1] & 0x1) << 7) + + + | ((Mc[1] & 0x3) << 5) + + + | ((xmaxc[1] >> 1) & 0x1F); + *c++ = ((xmaxc[1] & 0x1) << 7) + +#undef xmc +#define xmc (source + 29 - 13) + + | ((xmc[13] & 0x7) << 4) + | ((xmc[14] & 0x7) << 1) + | ((xmc[15] >> 2) & 0x1); + *c++ = ((xmc[15] & 0x3) << 6) + | ((xmc[16] & 0x7) << 3) + | (xmc[17] & 0x7); + *c++ = ((xmc[18] & 0x7) << 5) + | ((xmc[19] & 0x7) << 2) + | ((xmc[20] >> 1) & 0x3); + *c++ = ((xmc[20] & 0x1) << 7) + | ((xmc[21] & 0x7) << 4) + | ((xmc[22] & 0x7) << 1) + | ((xmc[23] >> 2) & 0x1); + *c++ = ((xmc[23] & 0x3) << 6) + | ((xmc[24] & 0x7) << 3) + | (xmc[25] & 0x7); + + + *c++ = ((Nc[2] & 0x7F) << 1) /* 20 */ + + + | ((bc[2] >> 1) & 0x1); + *c++ = ((bc[2] & 0x1) << 7) + + + | ((Mc[2] & 0x3) << 5) + + + | ((xmaxc[2] >> 1) & 0x1F); + *c++ = ((xmaxc[2] & 0x1) << 7) + +#undef xmc +#define xmc (source + 46 - 26) + + | ((xmc[26] & 0x7) << 4) + | ((xmc[27] & 0x7) << 1) + | ((xmc[28] >> 2) & 0x1); + *c++ = ((xmc[28] & 0x3) << 6) + | ((xmc[29] & 0x7) << 3) + | (xmc[30] & 0x7); + *c++ = ((xmc[31] & 0x7) << 5) + | ((xmc[32] & 0x7) << 2) + | ((xmc[33] >> 1) & 0x3); + *c++ = ((xmc[33] & 0x1) << 7) + | ((xmc[34] & 0x7) << 4) + | ((xmc[35] & 0x7) << 1) + | ((xmc[36] >> 2) & 0x1); + *c++ = ((xmc[36] & 0x3) << 6) + | ((xmc[37] & 0x7) << 3) + | (xmc[38] & 0x7); + + + *c++ = ((Nc[3] & 0x7F) << 1) + + + | ((bc[3] >> 1) & 0x1); + *c++ = ((bc[3] & 0x1) << 7) + + + | ((Mc[3] & 0x3) << 5) + + + | ((xmaxc[3] >> 1) & 0x1F); + *c++ = ((xmaxc[3] & 0x1) << 7) + +#undef xmc +#define xmc (source + 63 - 39) + + | ((xmc[39] & 0x7) << 4) + | ((xmc[40] & 0x7) << 1) + | ((xmc[41] >> 2) & 0x1); + *c++ = ((xmc[41] & 0x3) << 6) /* 30 */ + | ((xmc[42] & 0x7) << 3) + | (xmc[43] & 0x7); + *c++ = ((xmc[44] & 0x7) << 5) + | ((xmc[45] & 0x7) << 2) + | ((xmc[46] >> 1) & 0x3); + *c++ = ((xmc[46] & 0x1) << 7) + | ((xmc[47] & 0x7) << 4) + | ((xmc[48] & 0x7) << 1) + | ((xmc[49] >> 2) & 0x1); + *c++ = ((xmc[49] & 0x3) << 6) + | ((xmc[50] & 0x7) << 3) + | (xmc[51] & 0x7); + } +} diff --git a/linphone/gsmlib/gsm_option.c b/linphone/gsmlib/gsm_option.c new file mode 100644 index 000000000..17a174a32 --- /dev/null +++ b/linphone/gsmlib/gsm_option.c @@ -0,0 +1,69 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_option.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +int gsm_option P3((r, opt, val), gsm r, int opt, int * val) +{ + int result = -1; + + switch (opt) { + case GSM_OPT_LTP_CUT: +#ifdef LTP_CUT + result = r->ltp_cut; + if (val) r->ltp_cut = *val; +#endif + break; + + case GSM_OPT_VERBOSE: +#ifndef NDEBUG + result = r->verbose; + if (val) r->verbose = *val; +#endif + break; + + case GSM_OPT_FAST: + +#if defined(FAST) && defined(USE_FLOAT_MUL) + result = r->fast; + if (val) r->fast = !!*val; +#endif + break; + + case GSM_OPT_FRAME_CHAIN: + +#ifdef WAV49 + result = r->frame_chain; + if (val) r->frame_chain = *val; +#endif + break; + + case GSM_OPT_FRAME_INDEX: + +#ifdef WAV49 + result = r->frame_index; + if (val) r->frame_index = *val; +#endif + break; + + case GSM_OPT_WAV49: + +#ifdef WAV49 + result = r->wav_fmt; + if (val) r->wav_fmt = !!*val; +#endif + break; + + default: + break; + } + return result; +} diff --git a/linphone/gsmlib/gsm_print.c b/linphone/gsmlib/gsm_print.c new file mode 100644 index 000000000..bdd467911 --- /dev/null +++ b/linphone/gsmlib/gsm_print.c @@ -0,0 +1,167 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsm_print.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +int gsm_print P3((f, s, c), FILE * f, gsm s, gsm_byte * c) +{ + word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4]; + + /* GSM_MAGIC = (*c >> 4) & 0xF; */ + + if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1; + + LARc[0] = (*c++ & 0xF) << 2; /* 1 */ + LARc[0] |= (*c >> 6) & 0x3; + LARc[1] = *c++ & 0x3F; + LARc[2] = (*c >> 3) & 0x1F; + LARc[3] = (*c++ & 0x7) << 2; + LARc[3] |= (*c >> 6) & 0x3; + LARc[4] = (*c >> 2) & 0xF; + LARc[5] = (*c++ & 0x3) << 2; + LARc[5] |= (*c >> 6) & 0x3; + LARc[6] = (*c >> 3) & 0x7; + LARc[7] = *c++ & 0x7; + + + Nc[0] = (*c >> 1) & 0x7F; + bc[0] = (*c++ & 0x1) << 1; + bc[0] |= (*c >> 7) & 0x1; + Mc[0] = (*c >> 5) & 0x3; + xmaxc[0] = (*c++ & 0x1F) << 1; + xmaxc[0] |= (*c >> 7) & 0x1; + xmc[0] = (*c >> 4) & 0x7; + xmc[1] = (*c >> 1) & 0x7; + xmc[2] = (*c++ & 0x1) << 2; + xmc[2] |= (*c >> 6) & 0x3; + xmc[3] = (*c >> 3) & 0x7; + xmc[4] = *c++ & 0x7; + xmc[5] = (*c >> 5) & 0x7; + xmc[6] = (*c >> 2) & 0x7; + xmc[7] = (*c++ & 0x3) << 1; /* 10 */ + xmc[7] |= (*c >> 7) & 0x1; + xmc[8] = (*c >> 4) & 0x7; + xmc[9] = (*c >> 1) & 0x7; + xmc[10] = (*c++ & 0x1) << 2; + xmc[10] |= (*c >> 6) & 0x3; + xmc[11] = (*c >> 3) & 0x7; + xmc[12] = *c++ & 0x7; + + Nc[1] = (*c >> 1) & 0x7F; + bc[1] = (*c++ & 0x1) << 1; + bc[1] |= (*c >> 7) & 0x1; + Mc[1] = (*c >> 5) & 0x3; + xmaxc[1] = (*c++ & 0x1F) << 1; + xmaxc[1] |= (*c >> 7) & 0x1; + xmc[13] = (*c >> 4) & 0x7; + xmc[14] = (*c >> 1) & 0x7; + xmc[15] = (*c++ & 0x1) << 2; + xmc[15] |= (*c >> 6) & 0x3; + xmc[16] = (*c >> 3) & 0x7; + xmc[17] = *c++ & 0x7; + xmc[18] = (*c >> 5) & 0x7; + xmc[19] = (*c >> 2) & 0x7; + xmc[20] = (*c++ & 0x3) << 1; + xmc[20] |= (*c >> 7) & 0x1; + xmc[21] = (*c >> 4) & 0x7; + xmc[22] = (*c >> 1) & 0x7; + xmc[23] = (*c++ & 0x1) << 2; + xmc[23] |= (*c >> 6) & 0x3; + xmc[24] = (*c >> 3) & 0x7; + xmc[25] = *c++ & 0x7; + + + Nc[2] = (*c >> 1) & 0x7F; + bc[2] = (*c++ & 0x1) << 1; /* 20 */ + bc[2] |= (*c >> 7) & 0x1; + Mc[2] = (*c >> 5) & 0x3; + xmaxc[2] = (*c++ & 0x1F) << 1; + xmaxc[2] |= (*c >> 7) & 0x1; + xmc[26] = (*c >> 4) & 0x7; + xmc[27] = (*c >> 1) & 0x7; + xmc[28] = (*c++ & 0x1) << 2; + xmc[28] |= (*c >> 6) & 0x3; + xmc[29] = (*c >> 3) & 0x7; + xmc[30] = *c++ & 0x7; + xmc[31] = (*c >> 5) & 0x7; + xmc[32] = (*c >> 2) & 0x7; + xmc[33] = (*c++ & 0x3) << 1; + xmc[33] |= (*c >> 7) & 0x1; + xmc[34] = (*c >> 4) & 0x7; + xmc[35] = (*c >> 1) & 0x7; + xmc[36] = (*c++ & 0x1) << 2; + xmc[36] |= (*c >> 6) & 0x3; + xmc[37] = (*c >> 3) & 0x7; + xmc[38] = *c++ & 0x7; + + Nc[3] = (*c >> 1) & 0x7F; + bc[3] = (*c++ & 0x1) << 1; + bc[3] |= (*c >> 7) & 0x1; + Mc[3] = (*c >> 5) & 0x3; + xmaxc[3] = (*c++ & 0x1F) << 1; + xmaxc[3] |= (*c >> 7) & 0x1; + + xmc[39] = (*c >> 4) & 0x7; + xmc[40] = (*c >> 1) & 0x7; + xmc[41] = (*c++ & 0x1) << 2; + xmc[41] |= (*c >> 6) & 0x3; + xmc[42] = (*c >> 3) & 0x7; + xmc[43] = *c++ & 0x7; /* 30 */ + xmc[44] = (*c >> 5) & 0x7; + xmc[45] = (*c >> 2) & 0x7; + xmc[46] = (*c++ & 0x3) << 1; + xmc[46] |= (*c >> 7) & 0x1; + xmc[47] = (*c >> 4) & 0x7; + xmc[48] = (*c >> 1) & 0x7; + xmc[49] = (*c++ & 0x1) << 2; + xmc[49] |= (*c >> 6) & 0x3; + xmc[50] = (*c >> 3) & 0x7; + xmc[51] = *c & 0x7; /* 33 */ + + fprintf(f, + "LARc:\t%2.2d %2.2d %2.2d %2.2d %2.2d %2.2d %2.2d %2.2d\n", + LARc[0],LARc[1],LARc[2],LARc[3],LARc[4],LARc[5],LARc[6],LARc[7]); + + fprintf(f, "#1: Nc %4.4d bc %d Mc %d xmaxc %d\n", + Nc[0], bc[0], Mc[0], xmaxc[0]); + fprintf(f, +"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n", + xmc[0],xmc[1],xmc[2],xmc[3],xmc[4],xmc[5],xmc[6], + xmc[7],xmc[8],xmc[9],xmc[10],xmc[11],xmc[12] ); + + fprintf(f, "#2: Nc %4.4d bc %d Mc %d xmaxc %d\n", + Nc[1], bc[1], Mc[1], xmaxc[1]); + fprintf(f, +"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n", + xmc[13+0],xmc[13+1],xmc[13+2],xmc[13+3],xmc[13+4],xmc[13+5], + xmc[13+6], xmc[13+7],xmc[13+8],xmc[13+9],xmc[13+10],xmc[13+11], + xmc[13+12] ); + + fprintf(f, "#3: Nc %4.4d bc %d Mc %d xmaxc %d\n", + Nc[2], bc[2], Mc[2], xmaxc[2]); + fprintf(f, +"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n", + xmc[26+0],xmc[26+1],xmc[26+2],xmc[26+3],xmc[26+4],xmc[26+5], + xmc[26+6], xmc[26+7],xmc[26+8],xmc[26+9],xmc[26+10],xmc[26+11], + xmc[26+12] ); + + fprintf(f, "#4: Nc %4.4d bc %d Mc %d xmaxc %d\n", + Nc[3], bc[3], Mc[3], xmaxc[3]); + fprintf(f, +"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n", + xmc[39+0],xmc[39+1],xmc[39+2],xmc[39+3],xmc[39+4],xmc[39+5], + xmc[39+6], xmc[39+7],xmc[39+8],xmc[39+9],xmc[39+10],xmc[39+11], + xmc[39+12] ); + + return 0; +} diff --git a/linphone/gsmlib/gsm_wrapper.c b/linphone/gsmlib/gsm_wrapper.c new file mode 100644 index 000000000..1179080e3 --- /dev/null +++ b/linphone/gsmlib/gsm_wrapper.c @@ -0,0 +1,67 @@ +#include "gsm_wrapper.h" +#include + +/* the following code has been added by Simon MORLAT to make GSM interface compatible with linphone*/ + +/* the public codec_info structure*/ + +struct codec_info gsm_codec_info= +{ + "GSM", + 160*2, /* size of the uncompressed frame*/ + 33, /* size of compressed frame*/ + 13000, /* bit rate*/ + {{ + 8000 + }}, /* audio sampling freq*/ + GSMcodec_new, /* codec constructor*/ + 3, /* payload type*/ + "gsm/8000/1", + CODEC_AUDIO, /* type*/ + 0, /*usable, set later*/ + 1 /*usable for user, default value*/ +}; + + +Codec *GSMcodec_new() +{ + GSMCodec *obj; + + obj=(GSMCodec*)malloc(sizeof(GSMCodec));/* we should make a few check to see if this codec is a GSM...*/ + + obj->baseclass._getinfo=&wgsm_getinfo; + obj->baseclass._encode=&wgsm_encode; + obj->baseclass._decode=&wgsm_decode; + obj->baseclass._destroy=&wgsm_destroy; + obj->gsm_enc=gsm_create(); + obj->gsm_dec=gsm_create(); + return((Codec*)obj); +} + + +void wgsm_getinfo(Codec *codec,struct codec_info *info) +{ + if (info==NULL) return; + memcpy(info,&gsm_codec_info,sizeof(codec_info_t)); +} + +void wgsm_encode(Codec *codec,char *frame, char *data) +{ + GSMCodec *obj=(GSMCodec*)codec; /* we should make a few check to see if this codec is a GSM...*/ + gsm_encode(obj->gsm_enc,(gsm_signal*)frame,data); +} + +void wgsm_decode(Codec *codec,char *data, char *frame) +{ + GSMCodec *obj=(GSMCodec*)codec; /* we should make a few check to see if this codec is a GSM...*/ + gsm_decode(obj->gsm_dec,data,(gsm_signal*)frame); +} + +void wgsm_destroy(Codec *codec) +{ + GSMCodec *obj=(GSMCodec*)codec; /* we should make a few check to see if this codec is a GSM...*/ + gsm_destroy(obj->gsm_enc); + gsm_destroy(obj->gsm_dec); + free(obj); +} + diff --git a/linphone/gsmlib/gsm_wrapper.h b/linphone/gsmlib/gsm_wrapper.h new file mode 100644 index 000000000..8fc9d4f09 --- /dev/null +++ b/linphone/gsmlib/gsm_wrapper.h @@ -0,0 +1,28 @@ +#ifndef GSM_WRAPPER +#define GSM_WRAPPER + +#include "../console/codec.h" +#include "gsm.h" + +/* the following code has been added by Simon MORLAT to make lpc10 interface compatible with linphone*/ + +/*Class definition*/ +typedef struct _GSMCodec +{ + Codec baseclass; /* Codec must be the first element of the structure in order to have the object mechanism to work*/ + gsm gsm_enc,gsm_dec; +} GSMCodec; + +/* this the constructor for derivate class GSMCodec*/ +Codec * GSMcodec_new(); + +extern struct codec_info gsm_codec_info; + +/* these are the overrides for the base class 's functions*/ +void wgsm_getinfo(Codec *codec, struct codec_info *info); +void wgsm_encode(Codec *codec, char *frame, char *data); +void wgsm_decode(Codec *codec, char *data, char *frame); +void wgsm_destroy(Codec *codec); + + +#endif diff --git a/linphone/gsmlib/gsmadd.c b/linphone/gsmlib/gsmadd.c new file mode 100644 index 000000000..ddf1516f0 --- /dev/null +++ b/linphone/gsmlib/gsmadd.c @@ -0,0 +1,235 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/gsmadd.c,v 1.1 2005/03/09 17:26:29 smorlat Exp $ */ + +/* + * See private.h for the more commonly used macro versions. + */ + +#include +#include + +#include "private.h" +#include "gsm.h" +#include "proto.h" + +#define saturate(x) \ + ((x) < MIN_WORD ? MIN_WORD : (x) > MAX_WORD ? MAX_WORD: (x)) + +word gsm_add P2((a,b), word a, word b) +{ + longword sum = (longword)a + (longword)b; + return saturate(sum); +} + +word gsm_sub P2((a,b), word a, word b) +{ + longword diff = (longword)a - (longword)b; + return saturate(diff); +} + +word gsm_mult P2((a,b), word a, word b) +{ + if (a == MIN_WORD && b == MIN_WORD) return MAX_WORD; + else return SASR( (longword)a * (longword)b, 15 ); +} + +word gsm_mult_r P2((a,b), word a, word b) +{ + if (b == MIN_WORD && a == MIN_WORD) return MAX_WORD; + else { + longword prod = (longword)a * (longword)b + 16384; + prod >>= 15; + return prod & 0xFFFF; + } +} + +word gsm_abs P1((a), word a) +{ + return a < 0 ? (a == MIN_WORD ? MAX_WORD : -a) : a; +} + +longword gsm_L_mult P2((a,b),word a, word b) +{ + assert( a != MIN_WORD || b != MIN_WORD ); + return ((longword)a * (longword)b) << 1; +} + +longword gsm_L_add P2((a,b), longword a, longword b) +{ + if (a < 0) { + if (b >= 0) return a + b; + else { + ulongword A = (ulongword)-(a + 1) + (ulongword)-(b + 1); + return A >= MAX_LONGWORD ? MIN_LONGWORD :-(longword)A-2; + } + } + else if (b <= 0) return a + b; + else { + ulongword A = (ulongword)a + (ulongword)b; + return A > MAX_LONGWORD ? MAX_LONGWORD : A; + } +} + +longword gsm_L_sub P2((a,b), longword a, longword b) +{ + if (a >= 0) { + if (b >= 0) return a - b; + else { + /* a>=0, b<0 */ + + ulongword A = (ulongword)a + -(b + 1); + return A >= MAX_LONGWORD ? MAX_LONGWORD : (A + 1); + } + } + else if (b <= 0) return a - b; + else { + /* a<0, b>0 */ + + ulongword A = (ulongword)-(a + 1) + b; + return A >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)A - 1; + } +} + +static unsigned char const bitoff[ 256 ] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +word gsm_norm P1((a), longword a ) +/* + * the number of left shifts needed to normalize the 32 bit + * variable L_var1 for positive values on the interval + * + * with minimum of + * minimum of 1073741824 (01000000000000000000000000000000) and + * maximum of 2147483647 (01111111111111111111111111111111) + * + * + * and for negative values on the interval with + * minimum of -2147483648 (-10000000000000000000000000000000) and + * maximum of -1073741824 ( -1000000000000000000000000000000). + * + * in order to normalize the result, the following + * operation must be done: L_norm_var1 = L_var1 << norm( L_var1 ); + * + * (That's 'ffs', only from the left, not the right..) + */ +{ + assert(a != 0); + + if (a < 0) { + if (a <= -1073741824) return 0; + a = ~a; + } + + return a & 0xffff0000 + ? ( a & 0xff000000 + ? -1 + bitoff[ 0xFF & (a >> 24) ] + : 7 + bitoff[ 0xFF & (a >> 16) ] ) + : ( a & 0xff00 + ? 15 + bitoff[ 0xFF & (a >> 8) ] + : 23 + bitoff[ 0xFF & a ] ); +} + +longword gsm_L_asl P2((a,n), longword a, int n) +{ + if (n >= 32) return 0; + if (n <= -32) return -(a < 0); + if (n < 0) return gsm_L_asr(a, -n); + return a << n; +} + +word gsm_asl P2((a,n), word a, int n) +{ + if (n >= 16) return 0; + if (n <= -16) return -(a < 0); + if (n < 0) return gsm_asr(a, -n); + return a << n; +} + +longword gsm_L_asr P2((a,n), longword a, int n) +{ + if (n >= 32) return -(a < 0); + if (n <= -32) return 0; + if (n < 0) return a << -n; + +# ifdef SASR + return a >> n; +# else + if (a >= 0) return a >> n; + else return -(longword)( -(ulongword)a >> n ); +# endif +} + +word gsm_asr P2((a,n), word a, int n) +{ + if (n >= 16) return -(a < 0); + if (n <= -16) return 0; + if (n < 0) return a << -n; + +# ifdef SASR + return a >> n; +# else + if (a >= 0) return a >> n; + else return -(word)( -(uword)a >> n ); +# endif +} + +/* + * (From p. 46, end of section 4.2.5) + * + * NOTE: The following lines gives [sic] one correct implementation + * of the div(num, denum) arithmetic operation. Compute div + * which is the integer division of num by denum: with denum + * >= num > 0 + */ + +word gsm_div P2((num,denum), word num, word denum) +{ + longword L_num = num; + longword L_denum = denum; + word div = 0; + int k = 15; + + /* The parameter num sometimes becomes zero. + * Although this is explicitly guarded against in 4.2.5, + * we assume that the result should then be zero as well. + */ + + /* assert(num != 0); */ + + assert(num >= 0 && denum >= num); + if (num == 0) + return 0; + + while (k--) { + div <<= 1; + L_num <<= 1; + + if (L_num >= L_denum) { + L_num -= L_denum; + div++; + } + } + + return div; +} diff --git a/linphone/gsmlib/long_term.c b/linphone/gsmlib/long_term.c new file mode 100644 index 000000000..c5365920c --- /dev/null +++ b/linphone/gsmlib/long_term.c @@ -0,0 +1,949 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/long_term.c,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#include +#include + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +/* + * 4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION + */ + + +/* + * This module computes the LTP gain (bc) and the LTP lag (Nc) + * for the long term analysis filter. This is done by calculating a + * maximum of the cross-correlation function between the current + * sub-segment short term residual signal d[0..39] (output of + * the short term analysis filter; for simplification the index + * of this array begins at 0 and ends at 39 for each sub-segment of the + * RPE-LTP analysis) and the previous reconstructed short term + * residual signal dp[ -120 .. -1 ]. A dynamic scaling must be + * performed to avoid overflow. + */ + + /* The next procedure exists in six versions. First two integer + * version (if USE_FLOAT_MUL is not defined); then four floating + * point versions, twice with proper scaling (USE_FLOAT_MUL defined), + * once without (USE_FLOAT_MUL and FAST defined, and fast run-time + * option used). Every pair has first a Cut version (see the -C + * option to toast or the LTP_CUT option to gsm_option()), then the + * uncut one. (For a detailed explanation of why this is altogether + * a bad idea, see Henry Spencer and Geoff Collyer, ``#ifdef Considered + * Harmful''.) + */ + +#ifndef USE_FLOAT_MUL + +#ifdef LTP_CUT + +static void Cut_Calculation_of_the_LTP_parameters P5((st, d,dp,bc_out,Nc_out), + + struct gsm_state * st, + + register word * d, /* [0..39] IN */ + register word * dp, /* [-120..-1] IN */ + word * bc_out, /* OUT */ + word * Nc_out /* OUT */ +) +{ + register int k, lambda; + word Nc, bc; + word wt[40]; + + longword L_result; + longword L_max, L_power; + word R, S, dmax, scal, best_k; + word ltp_cut; + + register word temp, wt_k; + + /* Search of the optimum scaling of d[0..39]. + */ + dmax = 0; + for (k = 0; k <= 39; k++) { + temp = d[k]; + temp = GSM_ABS( temp ); + if (temp > dmax) { + dmax = temp; + best_k = k; + } + } + temp = 0; + if (dmax == 0) scal = 0; + else { + assert(dmax > 0); + temp = gsm_norm( (longword)dmax << 16 ); + } + if (temp > 6) scal = 0; + else scal = 6 - temp; + assert(scal >= 0); + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + wt_k = SASR(d[best_k], scal); + + for (lambda = 40; lambda <= 120; lambda++) { + L_result = (longword)wt_k * dp[best_k - lambda]; + if (L_result > L_max) { + Nc = lambda; + L_max = L_result; + } + } + *Nc_out = Nc; + L_max <<= 1; + + /* Rescaling of L_max + */ + assert(scal <= 100 && scal >= -100); + L_max = L_max >> (6 - scal); /* sub(6, scal) */ + + assert( Nc <= 120 && Nc >= 40); + + /* Compute the power of the reconstructed short term residual + * signal dp[..] + */ + L_power = 0; + for (k = 0; k <= 39; k++) { + + register longword L_temp; + + L_temp = SASR( dp[k - Nc], 3 ); + L_power += L_temp * L_temp; + } + L_power <<= 1; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) { + *bc_out = 0; + return; + } + if (L_max >= L_power) { + *bc_out = 3; + return; + } + + temp = gsm_norm( L_power ); + + R = SASR( L_max << temp, 16 ); + S = SASR( L_power << temp, 16 ); + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; + *bc_out = bc; +} + +#endif /* LTP_CUT */ + +static void Calculation_of_the_LTP_parameters P4((d,dp,bc_out,Nc_out), + register word * d, /* [0..39] IN */ + register word * dp, /* [-120..-1] IN */ + word * bc_out, /* OUT */ + word * Nc_out /* OUT */ +) +{ + register int k, lambda; + word Nc, bc; + word wt[40]; + + longword L_max, L_power; + word R, S, dmax, scal; + register word temp; + + /* Search of the optimum scaling of d[0..39]. + */ + dmax = 0; + + for (k = 0; k <= 39; k++) { + temp = d[k]; + temp = GSM_ABS( temp ); + if (temp > dmax) dmax = temp; + } + + temp = 0; + if (dmax == 0) scal = 0; + else { + assert(dmax > 0); + temp = gsm_norm( (longword)dmax << 16 ); + } + + if (temp > 6) scal = 0; + else scal = 6 - temp; + + assert(scal >= 0); + + /* Initialization of a working array wt + */ + + for (k = 0; k <= 39; k++) wt[k] = SASR( d[k], scal ); + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda <= 120; lambda++) { + +# undef STEP +# define STEP(k) (longword)wt[k] * dp[k - lambda] + + register longword L_result; + + L_result = STEP(0) ; L_result += STEP(1) ; + L_result += STEP(2) ; L_result += STEP(3) ; + L_result += STEP(4) ; L_result += STEP(5) ; + L_result += STEP(6) ; L_result += STEP(7) ; + L_result += STEP(8) ; L_result += STEP(9) ; + L_result += STEP(10) ; L_result += STEP(11) ; + L_result += STEP(12) ; L_result += STEP(13) ; + L_result += STEP(14) ; L_result += STEP(15) ; + L_result += STEP(16) ; L_result += STEP(17) ; + L_result += STEP(18) ; L_result += STEP(19) ; + L_result += STEP(20) ; L_result += STEP(21) ; + L_result += STEP(22) ; L_result += STEP(23) ; + L_result += STEP(24) ; L_result += STEP(25) ; + L_result += STEP(26) ; L_result += STEP(27) ; + L_result += STEP(28) ; L_result += STEP(29) ; + L_result += STEP(30) ; L_result += STEP(31) ; + L_result += STEP(32) ; L_result += STEP(33) ; + L_result += STEP(34) ; L_result += STEP(35) ; + L_result += STEP(36) ; L_result += STEP(37) ; + L_result += STEP(38) ; L_result += STEP(39) ; + + if (L_result > L_max) { + + Nc = lambda; + L_max = L_result; + } + } + + *Nc_out = Nc; + + L_max <<= 1; + + /* Rescaling of L_max + */ + assert(scal <= 100 && scal >= -100); + L_max = L_max >> (6 - scal); /* sub(6, scal) */ + + assert( Nc <= 120 && Nc >= 40); + + /* Compute the power of the reconstructed short term residual + * signal dp[..] + */ + L_power = 0; + for (k = 0; k <= 39; k++) { + + register longword L_temp; + + L_temp = SASR( dp[k - Nc], 3 ); + L_power += L_temp * L_temp; + } + L_power <<= 1; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) { + *bc_out = 0; + return; + } + if (L_max >= L_power) { + *bc_out = 3; + return; + } + + temp = gsm_norm( L_power ); + + R = SASR( L_max << temp, 16 ); + S = SASR( L_power << temp, 16 ); + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; + *bc_out = bc; +} + +#else /* USE_FLOAT_MUL */ + +#ifdef LTP_CUT + +static void Cut_Calculation_of_the_LTP_parameters P5((st, d,dp,bc_out,Nc_out), + struct gsm_state * st, /* IN */ + register word * d, /* [0..39] IN */ + register word * dp, /* [-120..-1] IN */ + word * bc_out, /* OUT */ + word * Nc_out /* OUT */ +) +{ + register int k, lambda; + word Nc, bc; + word ltp_cut; + + float wt_float[40]; + float dp_float_base[120], * dp_float = dp_float_base + 120; + + longword L_max, L_power; + word R, S, dmax, scal; + register word temp; + + /* Search of the optimum scaling of d[0..39]. + */ + dmax = 0; + + for (k = 0; k <= 39; k++) { + temp = d[k]; + temp = GSM_ABS( temp ); + if (temp > dmax) dmax = temp; + } + + temp = 0; + if (dmax == 0) scal = 0; + else { + assert(dmax > 0); + temp = gsm_norm( (longword)dmax << 16 ); + } + + if (temp > 6) scal = 0; + else scal = 6 - temp; + + assert(scal >= 0); + ltp_cut = (longword)SASR(dmax, scal) * st->ltp_cut / 100; + + + /* Initialization of a working array wt + */ + + for (k = 0; k < 40; k++) { + register word w = SASR( d[k], scal ); + if (w < 0 ? w > -ltp_cut : w < ltp_cut) { + wt_float[k] = 0.0; + } + else { + wt_float[k] = w; + } + } + for (k = -120; k < 0; k++) dp_float[k] = dp[k]; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda <= 120; lambda += 9) { + + /* Calculate L_result for l = lambda .. lambda + 9. + */ + register float *lp = dp_float - lambda; + + register float W; + register float a = lp[-8], b = lp[-7], c = lp[-6], + d = lp[-5], e = lp[-4], f = lp[-3], + g = lp[-2], h = lp[-1]; + register float E; + register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, + S5 = 0, S6 = 0, S7 = 0, S8 = 0; + +# undef STEP +# define STEP(K, a, b, c, d, e, f, g, h) \ + if ((W = wt_float[K]) != 0.0) { \ + E = W * a; S8 += E; \ + E = W * b; S7 += E; \ + E = W * c; S6 += E; \ + E = W * d; S5 += E; \ + E = W * e; S4 += E; \ + E = W * f; S3 += E; \ + E = W * g; S2 += E; \ + E = W * h; S1 += E; \ + a = lp[K]; \ + E = W * a; S0 += E; } else (a = lp[K]) + +# define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h) +# define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a) +# define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b) +# define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c) +# define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d) +# define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e) +# define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f) +# define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g) + + STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3); + STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7); + + STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11); + STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15); + + STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19); + STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23); + + STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27); + STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31); + + STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35); + STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39); + + if (S0 > L_max) { L_max = S0; Nc = lambda; } + if (S1 > L_max) { L_max = S1; Nc = lambda + 1; } + if (S2 > L_max) { L_max = S2; Nc = lambda + 2; } + if (S3 > L_max) { L_max = S3; Nc = lambda + 3; } + if (S4 > L_max) { L_max = S4; Nc = lambda + 4; } + if (S5 > L_max) { L_max = S5; Nc = lambda + 5; } + if (S6 > L_max) { L_max = S6; Nc = lambda + 6; } + if (S7 > L_max) { L_max = S7; Nc = lambda + 7; } + if (S8 > L_max) { L_max = S8; Nc = lambda + 8; } + + } + *Nc_out = Nc; + + L_max <<= 1; + + /* Rescaling of L_max + */ + assert(scal <= 100 && scal >= -100); + L_max = L_max >> (6 - scal); /* sub(6, scal) */ + + assert( Nc <= 120 && Nc >= 40); + + /* Compute the power of the reconstructed short term residual + * signal dp[..] + */ + L_power = 0; + for (k = 0; k <= 39; k++) { + + register longword L_temp; + + L_temp = SASR( dp[k - Nc], 3 ); + L_power += L_temp * L_temp; + } + L_power <<= 1; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) { + *bc_out = 0; + return; + } + if (L_max >= L_power) { + *bc_out = 3; + return; + } + + temp = gsm_norm( L_power ); + + R = SASR( L_max << temp, 16 ); + S = SASR( L_power << temp, 16 ); + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; + *bc_out = bc; +} + +#endif /* LTP_CUT */ + +static void Calculation_of_the_LTP_parameters P4((d,dp,bc_out,Nc_out), + register word * d, /* [0..39] IN */ + register word * dp, /* [-120..-1] IN */ + word * bc_out, /* OUT */ + word * Nc_out /* OUT */ +) +{ + register int k, lambda; + word Nc, bc; + + float wt_float[40]; + float dp_float_base[120], * dp_float = dp_float_base + 120; + + longword L_max, L_power; + word R, S, dmax, scal; + register word temp; + + /* Search of the optimum scaling of d[0..39]. + */ + dmax = 0; + + for (k = 0; k <= 39; k++) { + temp = d[k]; + temp = GSM_ABS( temp ); + if (temp > dmax) dmax = temp; + } + + temp = 0; + if (dmax == 0) scal = 0; + else { + assert(dmax > 0); + temp = gsm_norm( (longword)dmax << 16 ); + } + + if (temp > 6) scal = 0; + else scal = 6 - temp; + + assert(scal >= 0); + + /* Initialization of a working array wt + */ + + for (k = 0; k < 40; k++) wt_float[k] = SASR( d[k], scal ); + for (k = -120; k < 0; k++) dp_float[k] = dp[k]; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda <= 120; lambda += 9) { + + /* Calculate L_result for l = lambda .. lambda + 9. + */ + register float *lp = dp_float - lambda; + + register float W; + register float a = lp[-8], b = lp[-7], c = lp[-6], + d = lp[-5], e = lp[-4], f = lp[-3], + g = lp[-2], h = lp[-1]; + register float E; + register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, + S5 = 0, S6 = 0, S7 = 0, S8 = 0; + +# undef STEP +# define STEP(K, a, b, c, d, e, f, g, h) \ + W = wt_float[K]; \ + E = W * a; S8 += E; \ + E = W * b; S7 += E; \ + E = W * c; S6 += E; \ + E = W * d; S5 += E; \ + E = W * e; S4 += E; \ + E = W * f; S3 += E; \ + E = W * g; S2 += E; \ + E = W * h; S1 += E; \ + a = lp[K]; \ + E = W * a; S0 += E + +# define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h) +# define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a) +# define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b) +# define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c) +# define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d) +# define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e) +# define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f) +# define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g) + + STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3); + STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7); + + STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11); + STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15); + + STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19); + STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23); + + STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27); + STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31); + + STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35); + STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39); + + if (S0 > L_max) { L_max = S0; Nc = lambda; } + if (S1 > L_max) { L_max = S1; Nc = lambda + 1; } + if (S2 > L_max) { L_max = S2; Nc = lambda + 2; } + if (S3 > L_max) { L_max = S3; Nc = lambda + 3; } + if (S4 > L_max) { L_max = S4; Nc = lambda + 4; } + if (S5 > L_max) { L_max = S5; Nc = lambda + 5; } + if (S6 > L_max) { L_max = S6; Nc = lambda + 6; } + if (S7 > L_max) { L_max = S7; Nc = lambda + 7; } + if (S8 > L_max) { L_max = S8; Nc = lambda + 8; } + } + *Nc_out = Nc; + + L_max <<= 1; + + /* Rescaling of L_max + */ + assert(scal <= 100 && scal >= -100); + L_max = L_max >> (6 - scal); /* sub(6, scal) */ + + assert( Nc <= 120 && Nc >= 40); + + /* Compute the power of the reconstructed short term residual + * signal dp[..] + */ + L_power = 0; + for (k = 0; k <= 39; k++) { + + register longword L_temp; + + L_temp = SASR( dp[k - Nc], 3 ); + L_power += L_temp * L_temp; + } + L_power <<= 1; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) { + *bc_out = 0; + return; + } + if (L_max >= L_power) { + *bc_out = 3; + return; + } + + temp = gsm_norm( L_power ); + + R = SASR( L_max << temp, 16 ); + S = SASR( L_power << temp, 16 ); + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; + *bc_out = bc; +} + +#ifdef FAST +#ifdef LTP_CUT + +static void Cut_Fast_Calculation_of_the_LTP_parameters P5((st, + d,dp,bc_out,Nc_out), + struct gsm_state * st, /* IN */ + register word * d, /* [0..39] IN */ + register word * dp, /* [-120..-1] IN */ + word * bc_out, /* OUT */ + word * Nc_out /* OUT */ +) +{ + register int k, lambda; + register float wt_float; + word Nc, bc; + word wt_max, best_k, ltp_cut; + + float dp_float_base[120], * dp_float = dp_float_base + 120; + + register float L_result, L_max, L_power; + + wt_max = 0; + + for (k = 0; k < 40; ++k) { + if ( d[k] > wt_max) wt_max = d[best_k = k]; + else if (-d[k] > wt_max) wt_max = -d[best_k = k]; + } + + assert(wt_max >= 0); + wt_float = (float)wt_max; + + for (k = -120; k < 0; ++k) dp_float[k] = (float)dp[k]; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda <= 120; lambda++) { + L_result = wt_float * dp_float[best_k - lambda]; + if (L_result > L_max) { + Nc = lambda; + L_max = L_result; + } + } + + *Nc_out = Nc; + if (L_max <= 0.) { + *bc_out = 0; + return; + } + + /* Compute the power of the reconstructed short term residual + * signal dp[..] + */ + dp_float -= Nc; + L_power = 0; + for (k = 0; k < 40; ++k) { + register float f = dp_float[k]; + L_power += f * f; + } + + if (L_max >= L_power) { + *bc_out = 3; + return; + } + + /* Coding of the LTP gain + * Table 4.3a must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + lambda = L_max / L_power * 32768.; + for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break; + *bc_out = bc; +} + +#endif /* LTP_CUT */ + +static void Fast_Calculation_of_the_LTP_parameters P4((d,dp,bc_out,Nc_out), + register word * d, /* [0..39] IN */ + register word * dp, /* [-120..-1] IN */ + word * bc_out, /* OUT */ + word * Nc_out /* OUT */ +) +{ + register int k, lambda; + word Nc, bc; + + float wt_float[40]; + float dp_float_base[120], * dp_float = dp_float_base + 120; + + register float L_max, L_power; + + for (k = 0; k < 40; ++k) wt_float[k] = (float)d[k]; + for (k = -120; k < 0; ++k) dp_float[k] = (float)dp[k]; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0; + Nc = 40; /* index for the maximum cross-correlation */ + + for (lambda = 40; lambda <= 120; lambda += 9) { + + /* Calculate L_result for l = lambda .. lambda + 9. + */ + register float *lp = dp_float - lambda; + + register float W; + register float a = lp[-8], b = lp[-7], c = lp[-6], + d = lp[-5], e = lp[-4], f = lp[-3], + g = lp[-2], h = lp[-1]; + register float E; + register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, + S5 = 0, S6 = 0, S7 = 0, S8 = 0; + +# undef STEP +# define STEP(K, a, b, c, d, e, f, g, h) \ + W = wt_float[K]; \ + E = W * a; S8 += E; \ + E = W * b; S7 += E; \ + E = W * c; S6 += E; \ + E = W * d; S5 += E; \ + E = W * e; S4 += E; \ + E = W * f; S3 += E; \ + E = W * g; S2 += E; \ + E = W * h; S1 += E; \ + a = lp[K]; \ + E = W * a; S0 += E + +# define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h) +# define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a) +# define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b) +# define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c) +# define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d) +# define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e) +# define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f) +# define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g) + + STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3); + STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7); + + STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11); + STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15); + + STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19); + STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23); + + STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27); + STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31); + + STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35); + STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39); + + if (S0 > L_max) { L_max = S0; Nc = lambda; } + if (S1 > L_max) { L_max = S1; Nc = lambda + 1; } + if (S2 > L_max) { L_max = S2; Nc = lambda + 2; } + if (S3 > L_max) { L_max = S3; Nc = lambda + 3; } + if (S4 > L_max) { L_max = S4; Nc = lambda + 4; } + if (S5 > L_max) { L_max = S5; Nc = lambda + 5; } + if (S6 > L_max) { L_max = S6; Nc = lambda + 6; } + if (S7 > L_max) { L_max = S7; Nc = lambda + 7; } + if (S8 > L_max) { L_max = S8; Nc = lambda + 8; } + } + *Nc_out = Nc; + + if (L_max <= 0.) { + *bc_out = 0; + return; + } + + /* Compute the power of the reconstructed short term residual + * signal dp[..] + */ + dp_float -= Nc; + L_power = 0; + for (k = 0; k < 40; ++k) { + register float f = dp_float[k]; + L_power += f * f; + } + + if (L_max >= L_power) { + *bc_out = 3; + return; + } + + /* Coding of the LTP gain + * Table 4.3a must be used to obtain the level DLB[i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + lambda = L_max / L_power * 32768.; + for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break; + *bc_out = bc; +} + +#endif /* FAST */ +#endif /* USE_FLOAT_MUL */ + + +/* 4.2.12 */ + +static void Long_term_analysis_filtering P6((bc,Nc,dp,d,dpp,e), + word bc, /* IN */ + word Nc, /* IN */ + register word * dp, /* previous d [-120..-1] IN */ + register word * d, /* d [0..39] IN */ + register word * dpp, /* estimate [0..39] OUT */ + register word * e /* long term res. signal [0..39] OUT */ +) +/* + * In this part, we have to decode the bc parameter to compute + * the samples of the estimate dpp[0..39]. The decoding of bc needs the + * use of table 4.3b. The long term residual signal e[0..39] + * is then calculated to be fed to the RPE encoding section. + */ +{ + register int k; + register longword ltmp; + +# undef STEP +# define STEP(BP) \ + for (k = 0; k <= 39; k++) { \ + dpp[k] = GSM_MULT_R( BP, dp[k - Nc]); \ + e[k] = GSM_SUB( d[k], dpp[k] ); \ + } + + switch (bc) { + case 0: STEP( 3277 ); break; + case 1: STEP( 11469 ); break; + case 2: STEP( 21299 ); break; + case 3: STEP( 32767 ); break; + } +} + +void Gsm_Long_Term_Predictor P7((S,d,dp,e,dpp,Nc,bc), /* 4x for 160 samples */ + + struct gsm_state * S, + + word * d, /* [0..39] residual signal IN */ + word * dp, /* [-120..-1] d' IN */ + + word * e, /* [0..39] OUT */ + word * dpp, /* [0..39] OUT */ + word * Nc, /* correlation lag OUT */ + word * bc /* gain factor OUT */ +) +{ + assert( d ); assert( dp ); assert( e ); + assert( dpp); assert( Nc ); assert( bc ); + +#if defined(FAST) && defined(USE_FLOAT_MUL) + if (S->fast) +#if defined (LTP_CUT) + if (S->ltp_cut) + Cut_Fast_Calculation_of_the_LTP_parameters(S, + d, dp, bc, Nc); + else +#endif /* LTP_CUT */ + Fast_Calculation_of_the_LTP_parameters(d, dp, bc, Nc ); + else +#endif /* FAST & USE_FLOAT_MUL */ +#ifdef LTP_CUT + if (S->ltp_cut) + Cut_Calculation_of_the_LTP_parameters(S, d, dp, bc, Nc); + else +#endif + Calculation_of_the_LTP_parameters(d, dp, bc, Nc); + + Long_term_analysis_filtering( *bc, *Nc, dp, d, dpp, e ); +} + +/* 4.3.2 */ +void Gsm_Long_Term_Synthesis_Filtering P5((S,Ncr,bcr,erp,drp), + struct gsm_state * S, + + word Ncr, + word bcr, + register word * erp, /* [0..39] IN */ + register word * drp /* [-120..-1] IN, [-120..40] OUT */ +) +/* + * This procedure uses the bcr and Ncr parameter to realize the + * long term synthesis filtering. The decoding of bcr needs + * table 4.3b. + */ +{ + register longword ltmp; /* for ADD */ + register int k; + word brp, drpp, Nr; + + /* Check the limits of Nr. + */ + Nr = Ncr < 40 || Ncr > 120 ? S->nrp : Ncr; + S->nrp = Nr; + assert(Nr >= 40 && Nr <= 120); + + /* Decoding of the LTP gain bcr + */ + brp = gsm_QLB[ bcr ]; + + /* Computation of the reconstructed short term residual + * signal drp[0..39] + */ + assert(brp != MIN_WORD); + + for (k = 0; k <= 39; k++) { + drpp = GSM_MULT_R( brp, drp[ k - Nr ] ); + drp[k] = GSM_ADD( erp[k], drpp ); + } + + /* + * Update of the reconstructed short term residual signal + * drp[ -1..-120 ] + */ + + for (k = 0; k <= 119; k++) drp[ -120 + k ] = drp[ -80 + k ]; +} diff --git a/linphone/gsmlib/lpc.c b/linphone/gsmlib/lpc.c new file mode 100644 index 000000000..5fa53ac12 --- /dev/null +++ b/linphone/gsmlib/lpc.c @@ -0,0 +1,341 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/lpc.c,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#include +#include + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +#undef P + +/* + * 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION + */ + +/* 4.2.4 */ + + +static void Autocorrelation P2((s, L_ACF), + word * s, /* [0..159] IN/OUT */ + longword * L_ACF) /* [0..8] OUT */ +/* + * The goal is to compute the array L_ACF[k]. The signal s[i] must + * be scaled in order to avoid an overflow situation. + */ +{ + register int k, i; + + word temp, smax, scalauto; + +#ifdef USE_FLOAT_MUL + float float_s[160]; +#endif + + /* Dynamic scaling of the array s[0..159] + */ + + /* Search for the maximum. + */ + smax = 0; + for (k = 0; k <= 159; k++) { + temp = GSM_ABS( s[k] ); + if (temp > smax) smax = temp; + } + + /* Computation of the scaling factor. + */ + if (smax == 0) scalauto = 0; + else { + assert(smax > 0); + scalauto = 4 - gsm_norm( (longword)smax << 16 );/* sub(4,..) */ + } + + /* Scaling of the array s[0...159] + */ + + if (scalauto > 0) { + +# ifdef USE_FLOAT_MUL +# define SCALE(n) \ + case n: for (k = 0; k <= 159; k++) \ + float_s[k] = (float) \ + (s[k] = GSM_MULT_R(s[k], 16384 >> (n-1)));\ + break; +# else +# define SCALE(n) \ + case n: for (k = 0; k <= 159; k++) \ + s[k] = GSM_MULT_R( s[k], 16384 >> (n-1) );\ + break; +# endif /* USE_FLOAT_MUL */ + + switch (scalauto) { + SCALE(1) + SCALE(2) + SCALE(3) + SCALE(4) + } +# undef SCALE + } +# ifdef USE_FLOAT_MUL + else for (k = 0; k <= 159; k++) float_s[k] = (float) s[k]; +# endif + + /* Compute the L_ACF[..]. + */ + { +# ifdef USE_FLOAT_MUL + register float * sp = float_s; + register float sl = *sp; + +# define STEP(k) L_ACF[k] += (longword)(sl * sp[ -(k) ]); +# else + word * sp = s; + word sl = *sp; + +# define STEP(k) L_ACF[k] += ((longword)sl * sp[ -(k) ]); +# endif + +# define NEXTI sl = *++sp + + + for (k = 9; k--; L_ACF[k] = 0) ; + + STEP (0); + NEXTI; + STEP(0); STEP(1); + NEXTI; + STEP(0); STEP(1); STEP(2); + NEXTI; + STEP(0); STEP(1); STEP(2); STEP(3); + NEXTI; + STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); + NEXTI; + STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); + NEXTI; + STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); + NEXTI; + STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); STEP(7); + + for (i = 8; i <= 159; i++) { + + NEXTI; + + STEP(0); + STEP(1); STEP(2); STEP(3); STEP(4); + STEP(5); STEP(6); STEP(7); STEP(8); + } + + for (k = 9; k--; L_ACF[k] <<= 1) ; + + } + /* Rescaling of the array s[0..159] + */ + if (scalauto > 0) { + assert(scalauto <= 4); + for (k = 160; k--; *s++ <<= scalauto) ; + } +} + +#if defined(USE_FLOAT_MUL) && defined(FAST) + +static void Fast_Autocorrelation P2((s, L_ACF), + word * s, /* [0..159] IN/OUT */ + longword * L_ACF) /* [0..8] OUT */ +{ + register int k, i; + float f_L_ACF[9]; + float scale; + + float s_f[160]; + register float *sf = s_f; + + for (i = 0; i < 160; ++i) sf[i] = s[i]; + for (k = 0; k <= 8; k++) { + register float L_temp2 = 0; + register float *sfl = sf - k; + for (i = k; i < 160; ++i) L_temp2 += sf[i] * sfl[i]; + f_L_ACF[k] = L_temp2; + } + scale = MAX_LONGWORD / f_L_ACF[0]; + + for (k = 0; k <= 8; k++) { + L_ACF[k] = f_L_ACF[k] * scale; + } +} +#endif /* defined (USE_FLOAT_MUL) && defined (FAST) */ + +/* 4.2.5 */ + +static void Reflection_coefficients P2( (L_ACF, r), + longword * L_ACF, /* 0...8 IN */ + register word * r /* 0...7 OUT */ +) +{ + register int i, m, n; + register word temp; + register longword ltmp; + word ACF[9]; /* 0..8 */ + word P[ 9]; /* 0..8 */ + word K[ 9]; /* 2..8 */ + + /* Schur recursion with 16 bits arithmetic. + */ + + if (L_ACF[0] == 0) { + for (i = 8; i--; *r++ = 0) ; + return; + } + + assert( L_ACF[0] != 0 ); + temp = gsm_norm( L_ACF[0] ); + + assert(temp >= 0 && temp < 32); + + /* ? overflow ? */ + for (i = 0; i <= 8; i++) ACF[i] = SASR( L_ACF[i] << temp, 16 ); + + /* Initialize array P[..] and K[..] for the recursion. + */ + + for (i = 1; i <= 7; i++) K[ i ] = ACF[ i ]; + for (i = 0; i <= 8; i++) P[ i ] = ACF[ i ]; + + /* Compute reflection coefficients + */ + for (n = 1; n <= 8; n++, r++) { + + temp = P[1]; + temp = GSM_ABS(temp); + if (P[0] < temp) { + for (i = n; i <= 8; i++) *r++ = 0; + return; + } + + *r = gsm_div( temp, P[0] ); + + assert(*r >= 0); + if (P[1] > 0) *r = -*r; /* r[n] = sub(0, r[n]) */ + assert (*r != MIN_WORD); + if (n == 8) return; + + /* Schur recursion + */ + temp = GSM_MULT_R( P[1], *r ); + P[0] = GSM_ADD( P[0], temp ); + + for (m = 1; m <= 8 - n; m++) { + temp = GSM_MULT_R( K[ m ], *r ); + P[m] = GSM_ADD( P[ m+1 ], temp ); + + temp = GSM_MULT_R( P[ m+1 ], *r ); + K[m] = GSM_ADD( K[ m ], temp ); + } + } +} + +/* 4.2.6 */ + +static void Transformation_to_Log_Area_Ratios P1((r), + register word * r /* 0..7 IN/OUT */ +) +/* + * The following scaling for r[..] and LAR[..] has been used: + * + * r[..] = integer( real_r[..]*32768. ); -1 <= real_r < 1. + * LAR[..] = integer( real_LAR[..] * 16384 ); + * with -1.625 <= real_LAR <= 1.625 + */ +{ + register word temp; + register int i; + + + /* Computation of the LAR[0..7] from the r[0..7] + */ + for (i = 1; i <= 8; i++, r++) { + + temp = *r; + temp = GSM_ABS(temp); + assert(temp >= 0); + + if (temp < 22118) { + temp >>= 1; + } else if (temp < 31130) { + assert( temp >= 11059 ); + temp -= 11059; + } else { + assert( temp >= 26112 ); + temp -= 26112; + temp <<= 2; + } + + *r = *r < 0 ? -temp : temp; + assert( *r != MIN_WORD ); + } +} + +/* 4.2.7 */ + +static void Quantization_and_coding P1((LAR), + register word * LAR /* [0..7] IN/OUT */ +) +{ + register word temp; + longword ltmp; + + + /* This procedure needs four tables; the following equations + * give the optimum scaling for the constants: + * + * A[0..7] = integer( real_A[0..7] * 1024 ) + * B[0..7] = integer( real_B[0..7] * 512 ) + * MAC[0..7] = maximum of the LARc[0..7] + * MIC[0..7] = minimum of the LARc[0..7] + */ + +# undef STEP +# define STEP( A, B, MAC, MIC ) \ + temp = GSM_MULT( A, *LAR ); \ + temp = GSM_ADD( temp, B ); \ + temp = GSM_ADD( temp, 256 ); \ + temp = SASR( temp, 9 ); \ + *LAR = temp>MAC ? MAC - MIC : (tempfast) Fast_Autocorrelation (s, L_ACF ); + else +#endif + Autocorrelation (s, L_ACF ); + Reflection_coefficients (L_ACF, LARc ); + Transformation_to_Log_Area_Ratios (LARc); + Quantization_and_coding (LARc); +} diff --git a/linphone/gsmlib/preprocess.c b/linphone/gsmlib/preprocess.c new file mode 100644 index 000000000..82ee9099e --- /dev/null +++ b/linphone/gsmlib/preprocess.c @@ -0,0 +1,113 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/preprocess.c,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#include +#include + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +/* 4.2.0 .. 4.2.3 PREPROCESSING SECTION + * + * After A-law to linear conversion (or directly from the + * Ato D converter) the following scaling is assumed for + * input to the RPE-LTP algorithm: + * + * in: 0.1.....................12 + * S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.* + * + * Where S is the sign bit, v a valid bit, and * a "don't care" bit. + * The original signal is called sop[..] + * + * out: 0.1................... 12 + * S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0 + */ + + +void Gsm_Preprocess P3((S, s, so), + struct gsm_state * S, + word * s, + word * so ) /* [0..159] IN/OUT */ +{ + + word z1 = S->z1; + longword L_z2 = S->L_z2; + word mp = S->mp; + + word s1; + longword L_s2; + + longword L_temp; + + word msp, lsp; + word SO; + + longword ltmp; /* for ADD */ + ulongword utmp; /* for L_ADD */ + + register int k = 160; + + while (k--) { + + /* 4.2.1 Downscaling of the input signal + */ + SO = SASR( *s, 3 ) << 2; + s++; + + assert (SO >= -0x4000); /* downscaled by */ + assert (SO <= 0x3FFC); /* previous routine. */ + + + /* 4.2.2 Offset compensation + * + * This part implements a high-pass filter and requires extended + * arithmetic precision for the recursive part of this filter. + * The input of this procedure is the array so[0...159] and the + * output the array sof[ 0...159 ]. + */ + /* Compute the non-recursive part + */ + + s1 = SO - z1; /* s1 = gsm_sub( *so, z1 ); */ + z1 = SO; + + assert(s1 != MIN_WORD); + + /* Compute the recursive part + */ + L_s2 = s1; + L_s2 <<= 15; + + /* Execution of a 31 bv 16 bits multiplication + */ + + msp = SASR( L_z2, 15 ); + lsp = L_z2-((longword)msp<<15); /* gsm_L_sub(L_z2,(msp<<15)); */ + + L_s2 += GSM_MULT_R( lsp, 32735 ); + L_temp = (longword)msp * 32735; /* GSM_L_MULT(msp,32735) >> 1;*/ + L_z2 = GSM_L_ADD( L_temp, L_s2 ); + + /* Compute sof[k] with rounding + */ + L_temp = GSM_L_ADD( L_z2, 16384 ); + + /* 4.2.3 Preemphasis + */ + + msp = GSM_MULT_R( mp, -28180 ); + mp = SASR( L_temp, 15 ); + *so++ = GSM_ADD( mp, msp ); + } + + S->z1 = z1; + S->L_z2 = L_z2; + S->mp = mp; +} diff --git a/linphone/gsmlib/private.h b/linphone/gsmlib/private.h new file mode 100644 index 000000000..d78fd6b97 --- /dev/null +++ b/linphone/gsmlib/private.h @@ -0,0 +1,268 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/*$Header: /sources/linphone/linphone/gsmlib/private.h,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $*/ + +#ifndef PRIVATE_H +#define PRIVATE_H + +typedef short word; /* 16 bit signed int */ +typedef long longword; /* 32 bit signed int */ + +typedef unsigned short uword; /* unsigned word */ +typedef unsigned long ulongword; /* unsigned longword */ + +struct gsm_state { + + word dp0[ 280 ]; + + word z1; /* preprocessing.c, Offset_com. */ + longword L_z2; /* Offset_com. */ + int mp; /* Preemphasis */ + + word u[8]; /* short_term_aly_filter.c */ + word LARpp[2][8]; /* */ + word j; /* */ + + word ltp_cut; /* long_term.c, LTP crosscorr. */ + word nrp; /* 40 */ /* long_term.c, synthesis */ + word v[9]; /* short_term.c, synthesis */ + word msr; /* decoder.c, Postprocessing */ + + char verbose; /* only used if !NDEBUG */ + char fast; /* only used if FAST */ + + char wav_fmt; /* only used if WAV49 defined */ + unsigned char frame_index; /* odd/even chaining */ + unsigned char frame_chain; /* half-byte to carry forward */ +}; + + +#define MIN_WORD (-32767 - 1) +#define MAX_WORD 32767 + +#define MIN_LONGWORD (-2147483647 - 1) +#define MAX_LONGWORD 2147483647 + +#ifdef SASR /* flag: >> is a signed arithmetic shift right */ +#undef SASR +#define SASR(x, by) ((x) >> (by)) +#else +#define SASR(x, by) ((x) >= 0 ? (x) >> (by) : (~(-((x) + 1) >> (by)))) +#endif /* SASR */ + +#include "proto.h" + +/* + * Prototypes from add.c + */ +extern word gsm_mult P((word a, word b)); +extern longword gsm_L_mult P((word a, word b)); +extern word gsm_mult_r P((word a, word b)); + +extern word gsm_div P((word num, word denum)); + +extern word gsm_add P(( word a, word b )); +extern longword gsm_L_add P(( longword a, longword b )); + +extern word gsm_sub P((word a, word b)); +extern longword gsm_L_sub P((longword a, longword b)); + +extern word gsm_abs P((word a)); + +extern word gsm_norm P(( longword a )); + +extern longword gsm_L_asl P((longword a, int n)); +extern word gsm_asl P((word a, int n)); + +extern longword gsm_L_asr P((longword a, int n)); +extern word gsm_asr P((word a, int n)); + +/* + * Inlined functions from add.h + */ + +/* + * #define GSM_MULT_R(a, b) (* word a, word b, !(a == b == MIN_WORD) *) \ + * (0x0FFFF & SASR(((longword)(a) * (longword)(b) + 16384), 15)) + */ +#define GSM_MULT_R(a, b) /* word a, word b, !(a == b == MIN_WORD) */ \ + (SASR( ((longword)(a) * (longword)(b) + 16384), 15 )) + +# define GSM_MULT(a,b) /* word a, word b, !(a == b == MIN_WORD) */ \ + (SASR( ((longword)(a) * (longword)(b)), 15 )) + +# define GSM_L_MULT(a, b) /* word a, word b */ \ + (((longword)(a) * (longword)(b)) << 1) + +# define GSM_L_ADD(a, b) \ + ( (a) < 0 ? ( (b) >= 0 ? (a) + (b) \ + : (utmp = (ulongword)-((a) + 1) + (ulongword)-((b) + 1)) \ + >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)utmp-2 ) \ + : ((b) <= 0 ? (a) + (b) \ + : (utmp = (ulongword)(a) + (ulongword)(b)) >= MAX_LONGWORD \ + ? MAX_LONGWORD : utmp)) + +/* + * # define GSM_ADD(a, b) \ + * ((ltmp = (longword)(a) + (longword)(b)) >= MAX_WORD \ + * ? MAX_WORD : ltmp <= MIN_WORD ? MIN_WORD : ltmp) + */ +/* Nonportable, but faster: */ + +#define GSM_ADD(a, b) \ + ((ulongword)((ltmp = (longword)(a) + (longword)(b)) - MIN_WORD) > \ + MAX_WORD - MIN_WORD ? (ltmp > 0 ? MAX_WORD : MIN_WORD) : ltmp) + +# define GSM_SUB(a, b) \ + ((ltmp = (longword)(a) - (longword)(b)) >= MAX_WORD \ + ? MAX_WORD : ltmp <= MIN_WORD ? MIN_WORD : ltmp) + +# define GSM_ABS(a) ((a) < 0 ? ((a) == MIN_WORD ? MAX_WORD : -(a)) : (a)) + +/* Use these if necessary: + +# define GSM_MULT_R(a, b) gsm_mult_r(a, b) +# define GSM_MULT(a, b) gsm_mult(a, b) +# define GSM_L_MULT(a, b) gsm_L_mult(a, b) + +# define GSM_L_ADD(a, b) gsm_L_add(a, b) +# define GSM_ADD(a, b) gsm_add(a, b) +# define GSM_SUB(a, b) gsm_sub(a, b) + +# define GSM_ABS(a) gsm_abs(a) + +*/ + +/* + * More prototypes from implementations.. + */ +extern void Gsm_Coder P(( + struct gsm_state * S, + word * s, /* [0..159] samples IN */ + word * LARc, /* [0..7] LAR coefficients OUT */ + word * Nc, /* [0..3] LTP lag OUT */ + word * bc, /* [0..3] coded LTP gain OUT */ + word * Mc, /* [0..3] RPE grid selection OUT */ + word * xmaxc,/* [0..3] Coded maximum amplitude OUT */ + word * xMc /* [13*4] normalized RPE samples OUT */)); + +extern void Gsm_Long_Term_Predictor P(( /* 4x for 160 samples */ + struct gsm_state * S, + word * d, /* [0..39] residual signal IN */ + word * dp, /* [-120..-1] d' IN */ + word * e, /* [0..40] OUT */ + word * dpp, /* [0..40] OUT */ + word * Nc, /* correlation lag OUT */ + word * bc /* gain factor OUT */)); + +extern void Gsm_LPC_Analysis P(( + struct gsm_state * S, + word * s, /* 0..159 signals IN/OUT */ + word * LARc)); /* 0..7 LARc's OUT */ + +extern void Gsm_Preprocess P(( + struct gsm_state * S, + word * s, word * so)); + +extern void Gsm_Encoding P(( + struct gsm_state * S, + word * e, + word * ep, + word * xmaxc, + word * Mc, + word * xMc)); + +extern void Gsm_Short_Term_Analysis_Filter P(( + struct gsm_state * S, + word * LARc, /* coded log area ratio [0..7] IN */ + word * d /* st res. signal [0..159] IN/OUT */)); + +extern void Gsm_Decoder P(( + struct gsm_state * S, + word * LARcr, /* [0..7] IN */ + word * Ncr, /* [0..3] IN */ + word * bcr, /* [0..3] IN */ + word * Mcr, /* [0..3] IN */ + word * xmaxcr, /* [0..3] IN */ + word * xMcr, /* [0..13*4] IN */ + word * s)); /* [0..159] OUT */ + +extern void Gsm_Decoding P(( + struct gsm_state * S, + word xmaxcr, + word Mcr, + word * xMcr, /* [0..12] IN */ + word * erp)); /* [0..39] OUT */ + +extern void Gsm_Long_Term_Synthesis_Filtering P(( + struct gsm_state* S, + word Ncr, + word bcr, + word * erp, /* [0..39] IN */ + word * drp)); /* [-120..-1] IN, [0..40] OUT */ + +void Gsm_RPE_Decoding P(( + struct gsm_state *S, + word xmaxcr, + word Mcr, + word * xMcr, /* [0..12], 3 bits IN */ + word * erp)); /* [0..39] OUT */ + +void Gsm_RPE_Encoding P(( + struct gsm_state * S, + word * e, /* -5..-1][0..39][40..44 IN/OUT */ + word * xmaxc, /* OUT */ + word * Mc, /* OUT */ + word * xMc)); /* [0..12] OUT */ + +extern void Gsm_Short_Term_Synthesis_Filter P(( + struct gsm_state * S, + word * LARcr, /* log area ratios [0..7] IN */ + word * drp, /* received d [0...39] IN */ + word * s)); /* signal s [0..159] OUT */ + +extern void Gsm_Update_of_reconstructed_short_time_residual_signal P(( + word * dpp, /* [0...39] IN */ + word * ep, /* [0...39] IN */ + word * dp)); /* [-120...-1] IN/OUT */ + +/* + * Tables from table.c + */ +#ifndef GSM_TABLE_C + +extern word gsm_A[8], gsm_B[8], gsm_MIC[8], gsm_MAC[8]; +extern word gsm_INVA[8]; +extern word gsm_DLB[4], gsm_QLB[4]; +extern word gsm_H[11]; +extern word gsm_NRFAC[8]; +extern word gsm_FAC[8]; + +#endif /* GSM_TABLE_C */ + +/* + * Debugging + */ +#ifdef NDEBUG + +# define gsm_debug_words(a, b, c, d) /* nil */ +# define gsm_debug_longwords(a, b, c, d) /* nil */ +# define gsm_debug_word(a, b) /* nil */ +# define gsm_debug_longword(a, b) /* nil */ + +#else /* !NDEBUG => DEBUG */ + + extern void gsm_debug_words P((char * name, int, int, word *)); + extern void gsm_debug_longwords P((char * name, int, int, longword *)); + extern void gsm_debug_longword P((char * name, longword)); + extern void gsm_debug_word P((char * name, word)); + +#endif /* !NDEBUG */ + +#include "unproto.h" + +#endif /* PRIVATE_H */ diff --git a/linphone/gsmlib/proto.h b/linphone/gsmlib/proto.h new file mode 100644 index 000000000..3cedd367e --- /dev/null +++ b/linphone/gsmlib/proto.h @@ -0,0 +1,65 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/*$Header: /sources/linphone/linphone/gsmlib/proto.h,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $*/ + +#ifndef PROTO_H +#define PROTO_H + +#if __cplusplus +# define NeedFunctionPrototypes 1 +#endif + +#if __STDC__ +# define NeedFunctionPrototypes 1 +#endif + +#ifdef _NO_PROTO +# undef NeedFunctionPrototypes +#endif + +#undef P /* gnu stdio.h actually defines this... */ +#undef P0 +#undef P1 +#undef P2 +#undef P3 +#undef P4 +#undef P5 +#undef P6 +#undef P7 +#undef P8 + +#if NeedFunctionPrototypes + +# define P( protos ) protos + +# define P0() (void) +# define P1(x, a) (a) +# define P2(x, a, b) (a, b) +# define P3(x, a, b, c) (a, b, c) +# define P4(x, a, b, c, d) (a, b, c, d) +# define P5(x, a, b, c, d, e) (a, b, c, d, e) +# define P6(x, a, b, c, d, e, f) (a, b, c, d, e, f) +# define P7(x, a, b, c, d, e, f, g) (a, b, c, d, e, f, g) +# define P8(x, a, b, c, d, e, f, g, h) (a, b, c, d, e, f, g, h) + +#else /* !NeedFunctionPrototypes */ + +# define P( protos ) ( /* protos */ ) + +# define P0() () +# define P1(x, a) x a; +# define P2(x, a, b) x a; b; +# define P3(x, a, b, c) x a; b; c; +# define P4(x, a, b, c, d) x a; b; c; d; +# define P5(x, a, b, c, d, e) x a; b; c; d; e; +# define P6(x, a, b, c, d, e, f) x a; b; c; d; e; f; +# define P7(x, a, b, c, d, e, f, g) x a; b; c; d; e; f; g; +# define P8(x, a, b, c, d, e, f, g, h) x a; b; c; d; e; f; g; h; + +#endif /* !NeedFunctionPrototypes */ + +#endif /* PROTO_H */ diff --git a/linphone/gsmlib/rpe.c b/linphone/gsmlib/rpe.c new file mode 100644 index 000000000..15a359c76 --- /dev/null +++ b/linphone/gsmlib/rpe.c @@ -0,0 +1,488 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/rpe.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include +#include + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +/* 4.2.13 .. 4.2.17 RPE ENCODING SECTION + */ + +/* 4.2.13 */ + +static void Weighting_filter P2((e, x), + register word * e, /* signal [-5..0.39.44] IN */ + word * x /* signal [0..39] OUT */ +) +/* + * The coefficients of the weighting filter are stored in a table + * (see table 4.4). The following scaling is used: + * + * H[0..10] = integer( real_H[ 0..10] * 8192 ); + */ +{ + /* word wt[ 50 ]; */ + + register longword L_result; + register int k /* , i */ ; + + /* Initialization of a temporary working array wt[0...49] + */ + + /* for (k = 0; k <= 4; k++) wt[k] = 0; + * for (k = 5; k <= 44; k++) wt[k] = *e++; + * for (k = 45; k <= 49; k++) wt[k] = 0; + * + * (e[-5..-1] and e[40..44] are allocated by the caller, + * are initially zero and are not written anywhere.) + */ + e -= 5; + + /* Compute the signal x[0..39] + */ + for (k = 0; k <= 39; k++) { + + L_result = 8192 >> 1; + + /* for (i = 0; i <= 10; i++) { + * L_temp = GSM_L_MULT( wt[k+i], gsm_H[i] ); + * L_result = GSM_L_ADD( L_result, L_temp ); + * } + */ + +#undef STEP +#define STEP( i, H ) (e[ k + i ] * (longword)H) + + /* Every one of these multiplications is done twice -- + * but I don't see an elegant way to optimize this. + * Do you? + */ + +#ifdef STUPID_COMPILER + L_result += STEP( 0, -134 ) ; + L_result += STEP( 1, -374 ) ; + /* + STEP( 2, 0 ) */ + L_result += STEP( 3, 2054 ) ; + L_result += STEP( 4, 5741 ) ; + L_result += STEP( 5, 8192 ) ; + L_result += STEP( 6, 5741 ) ; + L_result += STEP( 7, 2054 ) ; + /* + STEP( 8, 0 ) */ + L_result += STEP( 9, -374 ) ; + L_result += STEP( 10, -134 ) ; +#else + L_result += + STEP( 0, -134 ) + + STEP( 1, -374 ) + /* + STEP( 2, 0 ) */ + + STEP( 3, 2054 ) + + STEP( 4, 5741 ) + + STEP( 5, 8192 ) + + STEP( 6, 5741 ) + + STEP( 7, 2054 ) + /* + STEP( 8, 0 ) */ + + STEP( 9, -374 ) + + STEP(10, -134 ) + ; +#endif + + /* L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x2) *) + * L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x4) *) + * + * x[k] = SASR( L_result, 16 ); + */ + + /* 2 adds vs. >>16 => 14, minus one shift to compensate for + * those we lost when replacing L_MULT by '*'. + */ + + L_result = SASR( L_result, 13 ); + x[k] = ( L_result < MIN_WORD ? MIN_WORD + : (L_result > MAX_WORD ? MAX_WORD : L_result )); + } +} + +/* 4.2.14 */ + +static void RPE_grid_selection P3((x,xM,Mc_out), + word * x, /* [0..39] IN */ + word * xM, /* [0..12] OUT */ + word * Mc_out /* OUT */ +) +/* + * The signal x[0..39] is used to select the RPE grid which is + * represented by Mc. + */ +{ + /* register word temp1; */ + register int /* m, */ i; + register longword L_result, L_temp; + longword EM; /* xxx should be L_EM? */ + word Mc; + + longword L_common_0_3; + + EM = 0; + Mc = 0; + + /* for (m = 0; m <= 3; m++) { + * L_result = 0; + * + * + * for (i = 0; i <= 12; i++) { + * + * temp1 = SASR( x[m + 3*i], 2 ); + * + * assert(temp1 != MIN_WORD); + * + * L_temp = GSM_L_MULT( temp1, temp1 ); + * L_result = GSM_L_ADD( L_temp, L_result ); + * } + * + * if (L_result > EM) { + * Mc = m; + * EM = L_result; + * } + * } + */ + +#undef STEP +#define STEP( m, i ) L_temp = SASR( x[m + 3 * i], 2 ); \ + L_result += L_temp * L_temp; + + /* common part of 0 and 3 */ + + L_result = 0; + STEP( 0, 1 ); STEP( 0, 2 ); STEP( 0, 3 ); STEP( 0, 4 ); + STEP( 0, 5 ); STEP( 0, 6 ); STEP( 0, 7 ); STEP( 0, 8 ); + STEP( 0, 9 ); STEP( 0, 10); STEP( 0, 11); STEP( 0, 12); + L_common_0_3 = L_result; + + /* i = 0 */ + + STEP( 0, 0 ); + L_result <<= 1; /* implicit in L_MULT */ + EM = L_result; + + /* i = 1 */ + + L_result = 0; + STEP( 1, 0 ); + STEP( 1, 1 ); STEP( 1, 2 ); STEP( 1, 3 ); STEP( 1, 4 ); + STEP( 1, 5 ); STEP( 1, 6 ); STEP( 1, 7 ); STEP( 1, 8 ); + STEP( 1, 9 ); STEP( 1, 10); STEP( 1, 11); STEP( 1, 12); + L_result <<= 1; + if (L_result > EM) { + Mc = 1; + EM = L_result; + } + + /* i = 2 */ + + L_result = 0; + STEP( 2, 0 ); + STEP( 2, 1 ); STEP( 2, 2 ); STEP( 2, 3 ); STEP( 2, 4 ); + STEP( 2, 5 ); STEP( 2, 6 ); STEP( 2, 7 ); STEP( 2, 8 ); + STEP( 2, 9 ); STEP( 2, 10); STEP( 2, 11); STEP( 2, 12); + L_result <<= 1; + if (L_result > EM) { + Mc = 2; + EM = L_result; + } + + /* i = 3 */ + + L_result = L_common_0_3; + STEP( 3, 12 ); + L_result <<= 1; + if (L_result > EM) { + Mc = 3; + EM = L_result; + } + + /**/ + + /* Down-sampling by a factor 3 to get the selected xM[0..12] + * RPE sequence. + */ + for (i = 0; i <= 12; i ++) xM[i] = x[Mc + 3*i]; + *Mc_out = Mc; +} + +/* 4.12.15 */ + +static void APCM_quantization_xmaxc_to_exp_mant P3((xmaxc,exp_out,mant_out), + word xmaxc, /* IN */ + word * exp_out, /* OUT */ + word * mant_out ) /* OUT */ +{ + word exp, mant; + + /* Compute exponent and mantissa of the decoded version of xmaxc + */ + + exp = 0; + if (xmaxc > 15) exp = SASR(xmaxc, 3) - 1; + mant = xmaxc - (exp << 3); + + if (mant == 0) { + exp = -4; + mant = 7; + } + else { + while (mant <= 7) { + mant = mant << 1 | 1; + exp--; + } + mant -= 8; + } + + assert( exp >= -4 && exp <= 6 ); + assert( mant >= 0 && mant <= 7 ); + + *exp_out = exp; + *mant_out = mant; +} + +static void APCM_quantization P5((xM,xMc,mant_out,exp_out,xmaxc_out), + word * xM, /* [0..12] IN */ + + word * xMc, /* [0..12] OUT */ + word * mant_out, /* OUT */ + word * exp_out, /* OUT */ + word * xmaxc_out /* OUT */ +) +{ + int i, itest; + + word xmax, xmaxc, temp, temp1, temp2; + word exp, mant; + + + /* Find the maximum absolute value xmax of xM[0..12]. + */ + + xmax = 0; + for (i = 0; i <= 12; i++) { + temp = xM[i]; + temp = GSM_ABS(temp); + if (temp > xmax) xmax = temp; + } + + /* Qantizing and coding of xmax to get xmaxc. + */ + + exp = 0; + temp = SASR( xmax, 9 ); + itest = 0; + + for (i = 0; i <= 5; i++) { + + itest |= (temp <= 0); + temp = SASR( temp, 1 ); + + assert(exp <= 5); + if (itest == 0) exp++; /* exp = add (exp, 1) */ + } + + assert(exp <= 6 && exp >= 0); + temp = exp + 5; + + assert(temp <= 11 && temp >= 0); + xmaxc = gsm_add( SASR(xmax, temp), exp << 3 ); + + /* Quantizing and coding of the xM[0..12] RPE sequence + * to get the xMc[0..12] + */ + + APCM_quantization_xmaxc_to_exp_mant( xmaxc, &exp, &mant ); + + /* This computation uses the fact that the decoded version of xmaxc + * can be calculated by using the exponent and the mantissa part of + * xmaxc (logarithmic table). + * So, this method avoids any division and uses only a scaling + * of the RPE samples by a function of the exponent. A direct + * multiplication by the inverse of the mantissa (NRFAC[0..7] + * found in table 4.5) gives the 3 bit coded version xMc[0..12] + * of the RPE samples. + */ + + + /* Direct computation of xMc[0..12] using table 4.5 + */ + + assert( exp <= 4096 && exp >= -4096); + assert( mant >= 0 && mant <= 7 ); + + temp1 = 6 - exp; /* normalization by the exponent */ + temp2 = gsm_NRFAC[ mant ]; /* inverse mantissa */ + + for (i = 0; i <= 12; i++) { + + assert(temp1 >= 0 && temp1 < 16); + + temp = xM[i] << temp1; + temp = GSM_MULT( temp, temp2 ); + temp = SASR(temp, 12); + xMc[i] = temp + 4; /* see note below */ + } + + /* NOTE: This equation is used to make all the xMc[i] positive. + */ + + *mant_out = mant; + *exp_out = exp; + *xmaxc_out = xmaxc; +} + +/* 4.2.16 */ + +static void APCM_inverse_quantization P4((xMc,mant,exp,xMp), + register word * xMc, /* [0..12] IN */ + word mant, + word exp, + register word * xMp) /* [0..12] OUT */ +/* + * This part is for decoding the RPE sequence of coded xMc[0..12] + * samples to obtain the xMp[0..12] array. Table 4.6 is used to get + * the mantissa of xmaxc (FAC[0..7]). + */ +{ + int i; + word temp, temp1, temp2, temp3; + longword ltmp; + + assert( mant >= 0 && mant <= 7 ); + + temp1 = gsm_FAC[ mant ]; /* see 4.2-15 for mant */ + temp2 = gsm_sub( 6, exp ); /* see 4.2-15 for exp */ + temp3 = gsm_asl( 1, gsm_sub( temp2, 1 )); + + for (i = 13; i--;) { + + assert( *xMc <= 7 && *xMc >= 0 ); /* 3 bit unsigned */ + + /* temp = gsm_sub( *xMc++ << 1, 7 ); */ + temp = (*xMc++ << 1) - 7; /* restore sign */ + assert( temp <= 7 && temp >= -7 ); /* 4 bit signed */ + + temp <<= 12; /* 16 bit signed */ + temp = GSM_MULT_R( temp1, temp ); + temp = GSM_ADD( temp, temp3 ); + *xMp++ = gsm_asr( temp, temp2 ); + } +} + +/* 4.2.17 */ + +static void RPE_grid_positioning P3((Mc,xMp,ep), + word Mc, /* grid position IN */ + register word * xMp, /* [0..12] IN */ + register word * ep /* [0..39] OUT */ +) +/* + * This procedure computes the reconstructed long term residual signal + * ep[0..39] for the LTP analysis filter. The inputs are the Mc + * which is the grid position selection and the xMp[0..12] decoded + * RPE samples which are upsampled by a factor of 3 by inserting zero + * values. + */ +{ + int i = 13; + + assert(0 <= Mc && Mc <= 3); + + switch (Mc) { + case 3: *ep++ = 0; + case 2: do { + *ep++ = 0; + case 1: *ep++ = 0; + case 0: *ep++ = *xMp++; + } while (--i); + } + while (++Mc < 4) *ep++ = 0; + + /* + + int i, k; + for (k = 0; k <= 39; k++) ep[k] = 0; + for (i = 0; i <= 12; i++) { + ep[ Mc + (3*i) ] = xMp[i]; + } + */ +} + +/* 4.2.18 */ + +/* This procedure adds the reconstructed long term residual signal + * ep[0..39] to the estimated signal dpp[0..39] from the long term + * analysis filter to compute the reconstructed short term residual + * signal dp[-40..-1]; also the reconstructed short term residual + * array dp[-120..-41] is updated. + */ + +#if 0 /* Has been inlined in code.c */ +void Gsm_Update_of_reconstructed_short_time_residual_signal P3((dpp, ep, dp), + word * dpp, /* [0...39] IN */ + word * ep, /* [0...39] IN */ + word * dp) /* [-120...-1] IN/OUT */ +{ + int k; + + for (k = 0; k <= 79; k++) + dp[ -120 + k ] = dp[ -80 + k ]; + + for (k = 0; k <= 39; k++) + dp[ -40 + k ] = gsm_add( ep[k], dpp[k] ); +} +#endif /* Has been inlined in code.c */ + +void Gsm_RPE_Encoding P5((S,e,xmaxc,Mc,xMc), + + struct gsm_state * S, + + word * e, /* -5..-1][0..39][40..44 IN/OUT */ + word * xmaxc, /* OUT */ + word * Mc, /* OUT */ + word * xMc) /* [0..12] OUT */ +{ + word x[40]; + word xM[13], xMp[13]; + word mant, exp; + + Weighting_filter(e, x); + RPE_grid_selection(x, xM, Mc); + + APCM_quantization( xM, xMc, &mant, &exp, xmaxc); + APCM_inverse_quantization( xMc, mant, exp, xMp); + + RPE_grid_positioning( *Mc, xMp, e ); + +} + +void Gsm_RPE_Decoding P5((S, xmaxcr, Mcr, xMcr, erp), + struct gsm_state * S, + + word xmaxcr, + word Mcr, + word * xMcr, /* [0..12], 3 bits IN */ + word * erp /* [0..39] OUT */ +) +{ + word exp, mant; + word xMp[ 13 ]; + + APCM_quantization_xmaxc_to_exp_mant( xmaxcr, &exp, &mant ); + APCM_inverse_quantization( xMcr, mant, exp, xMp ); + RPE_grid_positioning( Mcr, xMp, erp ); + +} diff --git a/linphone/gsmlib/short_term.c b/linphone/gsmlib/short_term.c new file mode 100644 index 000000000..951261edc --- /dev/null +++ b/linphone/gsmlib/short_term.c @@ -0,0 +1,429 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/short_term.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +#include +#include + +#include "private.h" + +#include "gsm.h" +#include "proto.h" + +/* + * SHORT TERM ANALYSIS FILTERING SECTION + */ + +/* 4.2.8 */ + +static void Decoding_of_the_coded_Log_Area_Ratios P2((LARc,LARpp), + word * LARc, /* coded log area ratio [0..7] IN */ + word * LARpp) /* out: decoded .. */ +{ + register word temp1 /* , temp2 */; + register long ltmp; /* for GSM_ADD */ + + /* This procedure requires for efficient implementation + * two tables. + * + * INVA[1..8] = integer( (32768 * 8) / real_A[1..8]) + * MIC[1..8] = minimum value of the LARc[1..8] + */ + + /* Compute the LARpp[1..8] + */ + + /* for (i = 1; i <= 8; i++, B++, MIC++, INVA++, LARc++, LARpp++) { + * + * temp1 = GSM_ADD( *LARc, *MIC ) << 10; + * temp2 = *B << 1; + * temp1 = GSM_SUB( temp1, temp2 ); + * + * assert(*INVA != MIN_WORD); + * + * temp1 = GSM_MULT_R( *INVA, temp1 ); + * *LARpp = GSM_ADD( temp1, temp1 ); + * } + */ + +#undef STEP +#define STEP( B, MIC, INVA ) \ + temp1 = GSM_ADD( *LARc++, MIC ) << 10; \ + temp1 = GSM_SUB( temp1, B << 1 ); \ + temp1 = GSM_MULT_R( INVA, temp1 ); \ + *LARpp++ = GSM_ADD( temp1, temp1 ); + + STEP( 0, -32, 13107 ); + STEP( 0, -32, 13107 ); + STEP( 2048, -16, 13107 ); + STEP( -2560, -16, 13107 ); + + STEP( 94, -8, 19223 ); + STEP( -1792, -8, 17476 ); + STEP( -341, -4, 31454 ); + STEP( -1144, -4, 29708 ); + + /* NOTE: the addition of *MIC is used to restore + * the sign of *LARc. + */ +} + +/* 4.2.9 */ +/* Computation of the quantized reflection coefficients + */ + +/* 4.2.9.1 Interpolation of the LARpp[1..8] to get the LARp[1..8] + */ + +/* + * Within each frame of 160 analyzed speech samples the short term + * analysis and synthesis filters operate with four different sets of + * coefficients, derived from the previous set of decoded LARs(LARpp(j-1)) + * and the actual set of decoded LARs (LARpp(j)) + * + * (Initial value: LARpp(j-1)[1..8] = 0.) + */ + +static void Coefficients_0_12 P3((LARpp_j_1, LARpp_j, LARp), + register word * LARpp_j_1, + register word * LARpp_j, + register word * LARp) +{ + register int i; + register longword ltmp; + + for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++) { + *LARp = GSM_ADD( SASR( *LARpp_j_1, 2 ), SASR( *LARpp_j, 2 )); + *LARp = GSM_ADD( *LARp, SASR( *LARpp_j_1, 1)); + } +} + +static void Coefficients_13_26 P3((LARpp_j_1, LARpp_j, LARp), + register word * LARpp_j_1, + register word * LARpp_j, + register word * LARp) +{ + register int i; + register longword ltmp; + for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) { + *LARp = GSM_ADD( SASR( *LARpp_j_1, 1), SASR( *LARpp_j, 1 )); + } +} + +static void Coefficients_27_39 P3((LARpp_j_1, LARpp_j, LARp), + register word * LARpp_j_1, + register word * LARpp_j, + register word * LARp) +{ + register int i; + register longword ltmp; + + for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) { + *LARp = GSM_ADD( SASR( *LARpp_j_1, 2 ), SASR( *LARpp_j, 2 )); + *LARp = GSM_ADD( *LARp, SASR( *LARpp_j, 1 )); + } +} + + +static void Coefficients_40_159 P2((LARpp_j, LARp), + register word * LARpp_j, + register word * LARp) +{ + register int i; + + for (i = 1; i <= 8; i++, LARp++, LARpp_j++) + *LARp = *LARpp_j; +} + +/* 4.2.9.2 */ + +static void LARp_to_rp P1((LARp), + register word * LARp) /* [0..7] IN/OUT */ +/* + * The input of this procedure is the interpolated LARp[0..7] array. + * The reflection coefficients, rp[i], are used in the analysis + * filter and in the synthesis filter. + */ +{ + register int i; + register word temp; + register longword ltmp; + + for (i = 1; i <= 8; i++, LARp++) { + + /* temp = GSM_ABS( *LARp ); + * + * if (temp < 11059) temp <<= 1; + * else if (temp < 20070) temp += 11059; + * else temp = GSM_ADD( temp >> 2, 26112 ); + * + * *LARp = *LARp < 0 ? -temp : temp; + */ + + if (*LARp < 0) { + temp = *LARp == MIN_WORD ? MAX_WORD : -(*LARp); + *LARp = - ((temp < 11059) ? temp << 1 + : ((temp < 20070) ? temp + 11059 + : GSM_ADD( temp >> 2, 26112 ))); + } else { + temp = *LARp; + *LARp = (temp < 11059) ? temp << 1 + : ((temp < 20070) ? temp + 11059 + : GSM_ADD( temp >> 2, 26112 )); + } + } +} + + +/* 4.2.10 */ +static void Short_term_analysis_filtering P4((S,rp,k_n,s), + struct gsm_state * S, + register word * rp, /* [0..7] IN */ + register int k_n, /* k_end - k_start */ + register word * s /* [0..n-1] IN/OUT */ +) +/* + * This procedure computes the short term residual signal d[..] to be fed + * to the RPE-LTP loop from the s[..] signal and from the local rp[..] + * array (quantized reflection coefficients). As the call of this + * procedure can be done in many ways (see the interpolation of the LAR + * coefficient), it is assumed that the computation begins with index + * k_start (for arrays d[..] and s[..]) and stops with index k_end + * (k_start and k_end are defined in 4.2.9.1). This procedure also + * needs to keep the array u[0..7] in memory for each call. + */ +{ + register word * u = S->u; + register int i; + register word di, zzz, ui, sav, rpi; + register longword ltmp; + + for (; k_n--; s++) { + + di = sav = *s; + + for (i = 0; i < 8; i++) { /* YYY */ + + ui = u[i]; + rpi = rp[i]; + u[i] = sav; + + zzz = GSM_MULT_R(rpi, di); + sav = GSM_ADD( ui, zzz); + + zzz = GSM_MULT_R(rpi, ui); + di = GSM_ADD( di, zzz ); + } + + *s = di; + } +} + +#if defined(USE_FLOAT_MUL) && defined(FAST) + +static void Fast_Short_term_analysis_filtering P4((S,rp,k_n,s), + struct gsm_state * S, + register word * rp, /* [0..7] IN */ + register int k_n, /* k_end - k_start */ + register word * s /* [0..n-1] IN/OUT */ +) +{ + register word * u = S->u; + register int i; + + float uf[8], + rpf[8]; + + register float scalef = 3.0517578125e-5; + register float sav, di, temp; + + for (i = 0; i < 8; ++i) { + uf[i] = u[i]; + rpf[i] = rp[i] * scalef; + } + for (; k_n--; s++) { + sav = di = *s; + for (i = 0; i < 8; ++i) { + register float rpfi = rpf[i]; + register float ufi = uf[i]; + + uf[i] = sav; + temp = rpfi * di + ufi; + di += rpfi * ufi; + sav = temp; + } + *s = di; + } + for (i = 0; i < 8; ++i) u[i] = uf[i]; +} +#endif /* ! (defined (USE_FLOAT_MUL) && defined (FAST)) */ + +static void Short_term_synthesis_filtering P5((S,rrp,k,wt,sr), + struct gsm_state * S, + register word * rrp, /* [0..7] IN */ + register int k, /* k_end - k_start */ + register word * wt, /* [0..k-1] IN */ + register word * sr /* [0..k-1] OUT */ +) +{ + register word * v = S->v; + register int i; + register word sri, tmp1, tmp2; + register longword ltmp; /* for GSM_ADD & GSM_SUB */ + + while (k--) { + sri = *wt++; + for (i = 8; i--;) { + + /* sri = GSM_SUB( sri, gsm_mult_r( rrp[i], v[i] ) ); + */ + tmp1 = rrp[i]; + tmp2 = v[i]; + tmp2 = ( tmp1 == MIN_WORD && tmp2 == MIN_WORD + ? MAX_WORD + : 0x0FFFF & (( (longword)tmp1 * (longword)tmp2 + + 16384) >> 15)) ; + + sri = GSM_SUB( sri, tmp2 ); + + /* v[i+1] = GSM_ADD( v[i], gsm_mult_r( rrp[i], sri ) ); + */ + tmp1 = ( tmp1 == MIN_WORD && sri == MIN_WORD + ? MAX_WORD + : 0x0FFFF & (( (longword)tmp1 * (longword)sri + + 16384) >> 15)) ; + + v[i+1] = GSM_ADD( v[i], tmp1); + } + *sr++ = v[0] = sri; + } +} + + +#if defined(FAST) && defined(USE_FLOAT_MUL) + +static void Fast_Short_term_synthesis_filtering P5((S,rrp,k,wt,sr), + struct gsm_state * S, + register word * rrp, /* [0..7] IN */ + register int k, /* k_end - k_start */ + register word * wt, /* [0..k-1] IN */ + register word * sr /* [0..k-1] OUT */ +) +{ + register word * v = S->v; + register int i; + + float va[9], rrpa[8]; + register float scalef = 3.0517578125e-5, temp; + + for (i = 0; i < 8; ++i) { + va[i] = v[i]; + rrpa[i] = (float)rrp[i] * scalef; + } + while (k--) { + register float sri = *wt++; + for (i = 8; i--;) { + sri -= rrpa[i] * va[i]; + if (sri < -32768.) sri = -32768.; + else if (sri > 32767.) sri = 32767.; + + temp = va[i] + rrpa[i] * sri; + if (temp < -32768.) temp = -32768.; + else if (temp > 32767.) temp = 32767.; + va[i+1] = temp; + } + *sr++ = va[0] = sri; + } + for (i = 0; i < 9; ++i) v[i] = va[i]; +} + +#endif /* defined(FAST) && defined(USE_FLOAT_MUL) */ + +void Gsm_Short_Term_Analysis_Filter P3((S,LARc,s), + + struct gsm_state * S, + + word * LARc, /* coded log area ratio [0..7] IN */ + word * s /* signal [0..159] IN/OUT */ +) +{ + word * LARpp_j = S->LARpp[ S->j ]; + word * LARpp_j_1 = S->LARpp[ S->j ^= 1 ]; + + word LARp[8]; + +#undef FILTER +#if defined(FAST) && defined(USE_FLOAT_MUL) +# define FILTER (* (S->fast \ + ? Fast_Short_term_analysis_filtering \ + : Short_term_analysis_filtering )) + +#else +# define FILTER Short_term_analysis_filtering +#endif + + Decoding_of_the_coded_Log_Area_Ratios( LARc, LARpp_j ); + + Coefficients_0_12( LARpp_j_1, LARpp_j, LARp ); + LARp_to_rp( LARp ); + FILTER( S, LARp, 13, s); + + Coefficients_13_26( LARpp_j_1, LARpp_j, LARp); + LARp_to_rp( LARp ); + FILTER( S, LARp, 14, s + 13); + + Coefficients_27_39( LARpp_j_1, LARpp_j, LARp); + LARp_to_rp( LARp ); + FILTER( S, LARp, 13, s + 27); + + Coefficients_40_159( LARpp_j, LARp); + LARp_to_rp( LARp ); + FILTER( S, LARp, 120, s + 40); +} + +void Gsm_Short_Term_Synthesis_Filter P4((S, LARcr, wt, s), + struct gsm_state * S, + + word * LARcr, /* received log area ratios [0..7] IN */ + word * wt, /* received d [0..159] IN */ + + word * s /* signal s [0..159] OUT */ +) +{ + word * LARpp_j = S->LARpp[ S->j ]; + word * LARpp_j_1 = S->LARpp[ S->j ^=1 ]; + + word LARp[8]; + +#undef FILTER +#if defined(FAST) && defined(USE_FLOAT_MUL) + +# define FILTER (* (S->fast \ + ? Fast_Short_term_synthesis_filtering \ + : Short_term_synthesis_filtering )) +#else +# define FILTER Short_term_synthesis_filtering +#endif + + Decoding_of_the_coded_Log_Area_Ratios( LARcr, LARpp_j ); + + Coefficients_0_12( LARpp_j_1, LARpp_j, LARp ); + LARp_to_rp( LARp ); + FILTER( S, LARp, 13, wt, s ); + + Coefficients_13_26( LARpp_j_1, LARpp_j, LARp); + LARp_to_rp( LARp ); + FILTER( S, LARp, 14, wt + 13, s + 13 ); + + Coefficients_27_39( LARpp_j_1, LARpp_j, LARp); + LARp_to_rp( LARp ); + FILTER( S, LARp, 13, wt + 27, s + 27 ); + + Coefficients_40_159( LARpp_j, LARp ); + LARp_to_rp( LARp ); + FILTER(S, LARp, 120, wt + 40, s + 40); +} diff --git a/linphone/gsmlib/table.c b/linphone/gsmlib/table.c new file mode 100644 index 000000000..46a090978 --- /dev/null +++ b/linphone/gsmlib/table.c @@ -0,0 +1,63 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/table.c,v 1.1.1.1 2001/11/19 19:50:12 smorlat Exp $ */ + +/* Most of these tables are inlined at their point of use. + */ + +/* 4.4 TABLES USED IN THE FIXED POINT IMPLEMENTATION OF THE RPE-LTP + * CODER AND DECODER + * + * (Most of them inlined, so watch out.) + */ + +#define GSM_TABLE_C +#include "private.h" +#include "gsm.h" + +/* Table 4.1 Quantization of the Log.-Area Ratios + */ +/* i 1 2 3 4 5 6 7 8 */ +word gsm_A[8] = {20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036}; +word gsm_B[8] = { 0, 0, 2048, -2560, 94, -1792, -341, -1144}; +word gsm_MIC[8] = { -32, -32, -16, -16, -8, -8, -4, -4 }; +word gsm_MAC[8] = { 31, 31, 15, 15, 7, 7, 3, 3 }; + + +/* Table 4.2 Tabulation of 1/A[1..8] + */ +word gsm_INVA[8]={ 13107, 13107, 13107, 13107, 19223, 17476, 31454, 29708 }; + + +/* Table 4.3a Decision level of the LTP gain quantizer + */ +/* bc 0 1 2 3 */ +word gsm_DLB[4] = { 6554, 16384, 26214, 32767 }; + + +/* Table 4.3b Quantization levels of the LTP gain quantizer + */ +/* bc 0 1 2 3 */ +word gsm_QLB[4] = { 3277, 11469, 21299, 32767 }; + + +/* Table 4.4 Coefficients of the weighting filter + */ +/* i 0 1 2 3 4 5 6 7 8 9 10 */ +word gsm_H[11] = {-134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 }; + + +/* Table 4.5 Normalized inverse mantissa used to compute xM/xmax + */ +/* i 0 1 2 3 4 5 6 7 */ +word gsm_NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 }; + + +/* Table 4.6 Normalized direct mantissa used to compute xM/xmax + */ +/* i 0 1 2 3 4 5 6 7 */ +word gsm_FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 }; diff --git a/linphone/gsmlib/toast.h b/linphone/gsmlib/toast.h new file mode 100644 index 000000000..4c33a35d2 --- /dev/null +++ b/linphone/gsmlib/toast.h @@ -0,0 +1,109 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* $Header: /sources/linphone/linphone/gsmlib/toast.h,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $ */ + +#ifndef TOAST_H +#define TOAST_H /* Guard against multiple includes */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include +#ifndef HAS_ERRNO_DECL + extern int errno; +#endif + +#ifdef HAS_LIMITS_H +#include +#endif + +#ifdef HAS_FCNTL_H +# include +#endif + +#ifdef HAS_UTIME +# ifdef HAS_UTIME_H +# include +# endif +#endif + +#include "gsm.h" + +#ifndef S_ISREG +#define S_ISREG(x) ((x) & S_IFREG) +#endif /* S_ISREG */ + + +# define READ "rb" +# define WRITE "wb" +#ifdef O_BINARY +# define O_WRITE_EXCL O_WRONLY|O_CREAT|O_EXCL|O_BINARY +#else +# define O_WRITE_EXCL O_WRONLY|O_CREAT|O_EXCL +#endif + +#ifndef SIGHANDLER_T +#define SIGHANDLER_T void /* what does a signal handler return? */ +#endif + + +#ifdef HAS_STRING_H +#include +#else +# ifdef HAS_STRINGS_H +# include +# else +# include "proto.h" + + extern int strlen P((char *)); + extern char * strcpy P((char *, char *)); + extern char * strcat P((char *, char *)); + extern char * strrchr P((char *, int)); + +# include "unproto.h" +# endif +#endif + + +#ifdef HAS_STDLIB_H +#include +#else +# include "proto.h" +# ifdef HAS_MALLOC_H +# include +# else + extern char * malloc P((unsigned)); +# endif + extern int exit P((int)); +# include "unproto.h" +#endif + + +#ifdef HAS_UNISTD_H +# include +#endif + +/* + * This suffix is tacked onto/removed from filenames + * similar to the way freeze and compress do it. + */ +#define SUFFIX_TOASTED ".gsm" + +#include "proto.h" + +extern int audio_init_input P((void)), audio_init_output P((void)); +extern int ulaw_input P((gsm_signal*)), ulaw_output P((gsm_signal *)); +extern int alaw_input P((gsm_signal*)), alaw_output P((gsm_signal *)); +extern int linear_input P((gsm_signal*)), linear_output P((gsm_signal *)); + +#endif /* TOAST_H */ diff --git a/linphone/gsmlib/unproto.h b/linphone/gsmlib/unproto.h new file mode 100644 index 000000000..6ef49e36f --- /dev/null +++ b/linphone/gsmlib/unproto.h @@ -0,0 +1,23 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/*$Header: /sources/linphone/linphone/gsmlib/unproto.h,v 1.1.1.1 2001/11/19 19:50:11 smorlat Exp $*/ + +#ifdef PROTO_H /* sic */ +#undef PROTO_H + +#undef P +#undef P0 +#undef P1 +#undef P2 +#undef P3 +#undef P4 +#undef P5 +#undef P6 +#undef P7 +#undef P8 + +#endif /* PROTO_H */ diff --git a/linphone/gtk-glade/Makefile.am b/linphone/gtk-glade/Makefile.am new file mode 100644 index 000000000..8145c5964 --- /dev/null +++ b/linphone/gtk-glade/Makefile.am @@ -0,0 +1,57 @@ +GLADE_FILES= about.glade \ + gtk-linphone.glade \ + main.glade \ + password.glade \ + contact.glade \ + incoming_call.glade \ + parameters.glade \ + sip_account.glade \ + chatroom.glade \ + call_logs.glade \ + log.glade + +PIXMAPS= linphone2.png \ + linphone.png \ + stock_people.png + +EXTRA_DIST= $(PIXMAPS) \ + $(GLADE_FILES) + +if BUILD_GLADE_UI + +bin_PROGRAMS=linphone-3 + +linphone_3_SOURCES= main.c\ + propertybox.c \ + friendlist.c \ + support.c \ + chat.c \ + calllogs.c \ + logging.c \ + linphone.h + +linphone_3_LDADD=$(top_builddir)/oRTP/src/libortp.la \ + $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ + $(top_builddir)/coreapi/liblinphone.la \ + $(LIBGTK_LIBS) $(INTLLIBS) \ + $(LIBGLADE_LIBS) + +linphone_3_LDFLAGS=-export-dynamic + +gladedir=$(datadir)/linphone +glade_DATA=$(GLADE_FILES) $(PIXMAPS) + +#all-local: gtk-linphone.ui + +#gtk-linphone.ui: gtk-linphone.glade +# gtk-builder-convert gtk-linphone.glade $@ + +endif + + +AM_CFLAGS= -I$(top_srcdir)/coreapi/ \ + -I$(top_srcdir)/mediastreamer2/include/ \ + $(LIBGLADE_CFLAGS) $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(IPV6_CFLAGS) \ + $(ORTP_CFLAGS) $(OSIP_CFLAGS) + + diff --git a/linphone/gtk-glade/about.glade b/linphone/gtk-glade/about.glade new file mode 100644 index 000000000..96c6b5f10 --- /dev/null +++ b/linphone/gtk-glade/about.glade @@ -0,0 +1,61 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + About linphone + False + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + Linphone + undef + Created by Simon Morlat + + An internet video phone using the standart SIP (rfc3261) protocol. + http://www.linphone.org + GPL + Simon Morlat + + fr: Simon Morlat +en: Simon Morlat and Delphine Perreau +it: Alberto Zanoni <alberto.zanoni@-NO-SPAM-PLEASE!-tiscalinet.it> +de: Jean-Jacques Sarton <jj.sarton@-NO-SPAM-PLEASE-t-online.de> +sv: Daniel Nylander <po@danielnylander.se> +es: Jesus Benitez <gnelson at inMail dot sk> +ja: YAMAGUCHI YOSHIYA <yushiya@anet.ne.jp> +pt_BR: Rafael Caesar Lenzi <rc_lenzi@yahoo.com.br> +pl: Robert Nasiadek <darkone@darkone.pl> +cs: Petr Pisar <petr.pisar@atlas.cz> +hu: anonymous + + Icons by Pablo Marcello Moia + + linphone.png + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/call_logs.glade b/linphone/gtk-glade/call_logs.glade new file mode 100644 index 000000000..d2ac682d3 --- /dev/null +++ b/linphone/gtk-glade/call_logs.glade @@ -0,0 +1,66 @@ + + + + + + 500 + 370 + 5 + Call history + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + 2 + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + + + True + True + False + GTK_WRAP_WORD + + + + + 1 + + + + + True + GTK_BUTTONBOX_END + + + + + + True + True + True + gtk-close + True + 0 + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/calllogs.c b/linphone/gtk-glade/calllogs.c new file mode 100644 index 000000000..59a8bcbda --- /dev/null +++ b/linphone/gtk-glade/calllogs.c @@ -0,0 +1,68 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" + +void linphone_gtk_call_log_update(GtkWidget *w){ + GtkTextView *v=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"logtextview")); + GtkTextBuffer *b=gtk_text_view_get_buffer(v); + GtkTextIter iter,begin; + int off; + char *logmsg; + MSList *logs; + for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){ + LinphoneCallLog *cl=(LinphoneCallLog*)logs->data; + logmsg=linphone_call_log_to_str(cl); + gtk_text_buffer_get_end_iter(b,&iter); + off=gtk_text_iter_get_offset(&iter); + gtk_text_buffer_insert(b,&iter,logmsg,-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_insert(b,&iter,"\n",-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_get_iter_at_offset(b,&begin,off); + gtk_text_buffer_apply_tag_by_name(b,cl->dir==LinphoneCallOutgoing ? "green" : "blue" ,&begin,&iter); + ms_free(logmsg); + } + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_view_scroll_to_iter(v,&iter,0,FALSE,0,0); +} + +void linphone_gtk_call_log_response(GtkWidget *w){ + GtkWidget *mw=linphone_gtk_get_main_window(); + g_object_set_data(G_OBJECT(mw),"call_logs",NULL); + gtk_widget_destroy(w); +} + +GtkWidget * linphone_gtk_show_call_logs(void){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkTextBuffer *b; + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs"); + if (w==NULL){ + w=linphone_gtk_create_window("call_logs"); + g_object_set_data(G_OBJECT(mw),"call_logs",w); + g_signal_connect(G_OBJECT(w),"response",(GCallback)linphone_gtk_call_log_response,NULL); + gtk_widget_show(w); + b=gtk_text_view_get_buffer(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"logtextview"))); + gtk_text_buffer_create_tag(b,"blue","foreground","blue",NULL); + gtk_text_buffer_create_tag(b,"green","foreground","green",NULL); + linphone_gtk_call_log_update(w); + }else gtk_window_present(GTK_WINDOW(w)); + return w; +} + diff --git a/linphone/gtk-glade/chat.c b/linphone/gtk-glade/chat.c new file mode 100644 index 000000000..bc61850a8 --- /dev/null +++ b/linphone/gtk-glade/chat.c @@ -0,0 +1,108 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" + +GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){ + GtkWidget *w; + GtkTextBuffer *b; + gchar *tmp; + w=linphone_gtk_create_window("chatroom"); + tmp=g_strdup_printf(_("Chat with %s"),with); + gtk_window_set_title(GTK_WINDOW(w),tmp); + g_free(tmp); + g_object_set_data(G_OBJECT(w),"cr",cr); + gtk_widget_show(w); + linphone_chat_room_set_user_data(cr,w); + b=gtk_text_view_get_buffer(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog"))); + gtk_text_buffer_create_tag(b,"blue","foreground","blue",NULL); + gtk_text_buffer_create_tag(b,"green","foreground","green",NULL); + return w; +} + +void linphone_gtk_create_chatroom(const char *with){ + LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),with); + if (!cr) return; + linphone_gtk_init_chatroom(cr,with); +} + +void linphone_gtk_chat_destroyed(GtkWidget *w){ + LinphoneChatRoom *cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(w),"cr"); + linphone_chat_room_destroy(cr); +} + +void linphone_gtk_chat_close(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + gtk_widget_destroy(w); +} + +void linphone_gtk_push_text(GtkTextView *v, const char *from, const char *message, gboolean me){ + GtkTextBuffer *b=gtk_text_view_get_buffer(v); + GtkTextIter iter,begin; + int off; + gtk_text_buffer_get_end_iter(b,&iter); + off=gtk_text_iter_get_offset(&iter); + gtk_text_buffer_insert(b,&iter,from,-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_insert(b,&iter,":\t",-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_get_iter_at_offset(b,&begin,off); + gtk_text_buffer_apply_tag_by_name(b,me ? "green" : "blue" ,&begin,&iter); + gtk_text_buffer_insert(b,&iter,message,-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_insert(b,&iter,"\n",-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_view_scroll_to_iter(v,&iter,0,FALSE,0,0); +} + +const char* linphone_gtk_get_used_identity(){ + LinphoneCore *lc=linphone_gtk_get_core(); + LinphoneProxyConfig *cfg; + linphone_core_get_default_proxy(lc,&cfg); + if (cfg) return linphone_proxy_config_get_identity(cfg); + else return linphone_core_get_primary_contact(lc); +} + +void linphone_gtk_send_text(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry"); + LinphoneChatRoom *cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(w),"cr"); + const gchar *entered; + entered=gtk_entry_get_text(GTK_ENTRY(entry)); + if (strlen(entered)>0) { + linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")), + linphone_gtk_get_used_identity(), + entered,TRUE); + linphone_chat_room_send_message(cr,entered); + gtk_entry_set_text(GTK_ENTRY(entry),""); + } +} + +void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message){ + GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room); + if (w==NULL){ + w=linphone_gtk_init_chatroom(room,from); + } + linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")), + from, + message,FALSE); + gtk_window_present(GTK_WINDOW(w)); + /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ +} + diff --git a/linphone/gtk-glade/chatroom.glade b/linphone/gtk-glade/chatroom.glade new file mode 100644 index 000000000..870ae537e --- /dev/null +++ b/linphone/gtk-glade/chatroom.glade @@ -0,0 +1,100 @@ + + + + + + + + + True + + + 200 + 200 + True + True + False + GTK_WRAP_WORD + + + + + True + + + True + True + True + + + + + + True + True + True + 0 + + + + True + + + True + gtk-ok + + + + + True + Send + + + 7 + 1 + + + + + + + False + False + 1 + + + + + False + False + 1 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-close + True + 0 + + + + GTK_PACK_END + + + + + False + 2 + + + + + + diff --git a/linphone/gtk-glade/contact.glade b/linphone/gtk-glade/contact.glade new file mode 100644 index 000000000..31f806f80 --- /dev/null +++ b/linphone/gtk-glade/contact.glade @@ -0,0 +1,179 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Name + + + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP Address + + + 1 + 2 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Show this contact presence status + 0 + True + True + + + 1 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Allow this contact to see my presence status + 0 + True + True + + + 2 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Contact information + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok + True + 0 + + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/friendlist.c b/linphone/gtk-glade/friendlist.c new file mode 100644 index 000000000..95f1779d0 --- /dev/null +++ b/linphone/gtk-glade/friendlist.c @@ -0,0 +1,454 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include "linphone.h" + +static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list); + +enum{ + FRIEND_PRESENCE_IMG, + FRIEND_NAME, + FRIEND_PRESENCE_STATUS, + FRIEND_ID, + FRIEND_SIP_ADDRESS, + FRIEND_LIST_NCOL +}; + + +typedef struct _status_picture_tab_t{ + LinphoneOnlineStatus status; + const char *img; +} status_picture_tab_t; + +status_picture_tab_t status_picture_tab[]={ + { LINPHONE_STATUS_UNKNOWN, "sip-closed.png" }, + { LINPHONE_STATUS_ONLINE, "sip-online.png" }, + { LINPHONE_STATUS_BUSY, "sip-busy.png" }, + { LINPHONE_STATUS_BERIGHTBACK, "sip-bifm.png" }, + { LINPHONE_STATUS_AWAY, "sip-away.png" }, + { LINPHONE_STATUS_ONTHEPHONE, "sip-otp.png" }, + { LINPHONE_STATUS_OUTTOLUNCH, "sip-otl.png" }, + { LINPHONE_STATUS_NOT_DISTURB, "sip-closed.png" }, + { LINPHONE_STATUS_MOVED, "sip-closed.png" }, + { LINPHONE_STATUS_ALT_SERVICE, "sip-closed.png" }, + { LINPHONE_STATUS_OFFLINE, "sip-away.png" }, + { LINPHONE_STATUS_PENDING, "sip-wfa.png" }, + { LINPHONE_STATUS_CLOSED, "sip-closed.png" }, + { LINPHONE_STATUS_END, NULL }, +}; + +static GdkPixbuf *create_status_picture(LinphoneOnlineStatus ss){ + status_picture_tab_t *t=status_picture_tab; + while(t->img!=NULL){ + if (ss==t->status){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf(t->img); + return pixbuf; + } + ++t; + } + g_error("No pixmap defined for status %i",ss); + return NULL; +} + +void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ + GtkTreeIter iter; + LinphoneFriend *tmp=0; + gboolean found=FALSE; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); + if (gtk_tree_model_get_iter_first(model,&iter)) { + do{ + gtk_tree_model_get(model,&iter,FRIEND_ID,&tmp,-1); + //printf("tmp=%i, fid=%i",tmp,fid); + if (fid==tmp) { + GdkPixbuf *pixbuf; + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_STATUS,status,-1); + pixbuf = create_pixbuf(img); + if (pixbuf) + { + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); + } + found=TRUE; + } + }while(gtk_tree_model_iter_next(model,&iter)); + } + +} + + +static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneFriend *lf=NULL; + gchar* friend; + select = gtk_tree_view_get_selection (treeview); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + friend=linphone_friend_get_url(lf); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),friend); + ms_free(friend); + } +} + +static void linphone_gtk_call_selected(GtkTreeView *treeview){ + linphone_gtk_set_selection_to_uri_bar(treeview); + linphone_gtk_start_call(linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(treeview)), + "start_call")); +} + +void linphone_gtk_contact_activated(GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + linphone_gtk_set_selection_to_uri_bar(treeview); +} + +static GtkWidget * create_presence_menu(){ + GtkWidget *menu=gtk_menu_new(); + GtkWidget *menu_item; + GdkPixbuf *pbuf; + status_picture_tab_t *t; + for(t=status_picture_tab;t->img!=NULL;++t){ + if (t->status==LINPHONE_STATUS_UNKNOWN || + t->status==LINPHONE_STATUS_PENDING){ + continue; + } + menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status)); + pbuf=create_status_picture(t->status); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), + gtk_image_new_from_pixbuf(pbuf)); + g_object_unref(G_OBJECT(pbuf)); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_set_my_presence,GINT_TO_POINTER(t->status)); + } + return menu; +} + +void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss){ + GtkWidget *button=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"presence_button"); + GdkPixbuf *pbuf=create_status_picture(ss); + GtkWidget *image=gtk_image_new_from_pixbuf(pbuf); + GtkWidget *menu; + g_object_unref(G_OBJECT(pbuf)); + gtk_button_set_label(GTK_BUTTON(button),linphone_online_status_to_string(ss)); + gtk_button_set_image(GTK_BUTTON(button),image); + /*prepare menu*/ + menu=(GtkWidget*)g_object_get_data(G_OBJECT(button),"presence_menu"); + if (menu==NULL){ + menu=create_presence_menu(); + /*the menu is destroyed when the button is destroyed*/ + g_object_weak_ref(G_OBJECT(button),(GWeakNotify)gtk_widget_destroy,menu); + g_object_set_data(G_OBJECT(button),"presence_menu",menu); + } + linphone_core_set_presence_info(linphone_gtk_get_core(),0,NULL,ss); +} + +void linphone_gtk_my_presence_clicked(GtkWidget *button){ + GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(button),"presence_menu"); + gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0, + gtk_get_current_event_time()); + gtk_widget_show(menu); +} + + +static void linphone_gtk_friend_list_init(GtkWidget *friendlist) +{ + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + + + store = gtk_list_store_new(FRIEND_LIST_NCOL, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, + G_TYPE_STRING); + /* need to add friends to the store here ...*/ + + gtk_tree_view_set_model(GTK_TREE_VIEW(friendlist),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "pixbuf", FRIEND_PRESENCE_IMG, + NULL); + gtk_tree_view_column_set_min_width (column, 29); + gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", FRIEND_NAME, + NULL); + g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); + + column = gtk_tree_view_column_new_with_attributes (_("Presence status"), + renderer, + "text", FRIEND_PRESENCE_STATUS, + NULL); + g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (friendlist)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + + gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(friendlist),FRIEND_SIP_ADDRESS); + + gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget( + gtk_widget_get_toplevel(friendlist),"show_category")),0); +} + +void linphone_gtk_show_friends(void){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(mw,"contact_list"); + GtkListStore *store=NULL; + GtkTreeIter iter; + const MSList *itf; + GtkWidget *category=linphone_gtk_get_widget(mw,"show_category"); + GtkWidget *filter=linphone_gtk_get_widget(mw,"search_bar"); + LinphoneCore *core=linphone_gtk_get_core(); + const gchar *search=NULL; + gboolean online_only=FALSE,lookup=FALSE; + + if (gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))==NULL){ + linphone_gtk_friend_list_init(friendlist); + } + store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))); + gtk_list_store_clear(store); + + online_only=(gtk_combo_box_get_active(GTK_COMBO_BOX(category))==1); + search=gtk_entry_get_text(GTK_ENTRY(filter)); + if (search==NULL || search[0]=='\0') + lookup=FALSE; + else lookup=TRUE; + + for(itf=linphone_core_get_friend_list(core);itf!=NULL;itf=ms_list_next(itf)){ + LinphoneFriend *lf=(LinphoneFriend*)itf->data; + char *uri=linphone_friend_get_url(lf); + char *name=linphone_friend_get_name(lf); + char *addr=linphone_friend_get_addr(lf); + char *display=name; + char *escaped=NULL; + if (lookup){ + if (strstr(uri,search)==NULL){ + ms_free(uri); + if (name) ms_free(name); + if (addr) ms_free(addr); + continue; + } + } + if (!online_only || (linphone_friend_get_status(lf)!=LINPHONE_STATUS_OFFLINE)){ + if (name==NULL || name[0]=='\0') display=addr; + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,FRIEND_NAME, display, + FRIEND_PRESENCE_STATUS, linphone_online_status_to_string(linphone_friend_get_status(lf)), + FRIEND_ID,lf,-1); + gtk_list_store_set(store,&iter, + FRIEND_PRESENCE_IMG, create_status_picture(linphone_friend_get_status(lf)), + -1); + escaped=g_markup_escape_text(uri,-1); + gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1); + g_free(escaped); + } + ms_free(uri); + if (name) ms_free(name); + if (addr) ms_free(addr); + } +} + +void linphone_gtk_add_contact(void){ + GtkWidget *w=linphone_gtk_create_window("contact"); + gtk_widget_show(w); +} + +void linphone_gtk_remove_contact(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneFriend *lf=NULL; + select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + linphone_core_remove_friend(linphone_gtk_get_core(),lf); + linphone_gtk_show_friends(); + } +} + +void linphone_gtk_show_contact(LinphoneFriend *lf){ + GtkWidget *w=linphone_gtk_create_window("contact"); + char *uri,*name; + uri=linphone_friend_get_addr(lf); + name=linphone_friend_get_name(lf); + if (uri) { + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address")),uri); + ms_free(uri); + } + if (name){ + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name")),name); + ms_free(name); + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")), + linphone_friend_get_send_subscribe(lf)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")), + linphone_friend_get_inc_subscribe_policy(lf)==LinphoneSPAccept); + g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); + gtk_widget_show(w); +} + +void linphone_gtk_edit_contact(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneFriend *lf=NULL; + select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + linphone_gtk_show_contact(lf); + } +} + +void linphone_gtk_chat_selected(GtkWidget *item){ + GtkWidget *w=gtk_widget_get_toplevel(item); + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneFriend *lf=NULL; + select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + char *uri; + gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + uri=linphone_friend_get_url(lf); + linphone_gtk_create_chatroom(uri); + ms_free(uri); + } +} + +void linphone_gtk_contact_cancel(GtkWidget *button){ + gtk_widget_destroy(gtk_widget_get_toplevel(button)); +} + +void linphone_gtk_contact_ok(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(w),"friend_ref"); + gboolean editing=FALSE,show_presence,allow_presence; + const gchar *name,*uri; + if (lf==NULL){ + lf=linphone_friend_new(); + }else{ + editing=TRUE; + } + name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))); + uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address"))); + show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence"))); + allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence"))); + linphone_friend_set_sip_addr(lf,uri); + linphone_friend_set_name(lf,name); + linphone_friend_send_subscribe(lf,show_presence); + linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny); + if (editing){ + linphone_friend_done(lf); + }else{ + linphone_core_add_friend(linphone_gtk_get_core(),lf); + } + linphone_gtk_show_friends(); + gtk_widget_destroy(w); +} + +static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list){ + GtkWidget *menu=gtk_menu_new(); + GtkWidget *menu_item; + gchar *call_label=NULL; + gchar *text_label=NULL; + gchar *name=NULL; + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *image; + g_signal_connect(G_OBJECT(menu), "selection-done", G_CALLBACK (gtk_widget_destroy), NULL); + select = gtk_tree_view_get_selection(GTK_TREE_VIEW(contact_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)){ + gtk_tree_model_get(model, &iter,FRIEND_NAME , &name, -1); + call_label=g_strdup_printf(_("Call %s"),name); + text_label=g_strdup_printf(_("Send text to %s"),name); + g_free(name); + }else g_warning("No selection"); + if (call_label){ + menu_item=gtk_image_menu_item_new_with_label(call_label); + image=gtk_image_new_from_stock(GTK_STOCK_NETWORK,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); + gtk_widget_show(image); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_selected,contact_list); + } + if (text_label){ + menu_item=gtk_image_menu_item_new_with_label(text_label); + image=gtk_image_new_from_stock(GTK_STOCK_NETWORK,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); + gtk_widget_show(image); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_chat_selected,contact_list); + } + menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_EDIT,NULL); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_edit_contact,contact_list); + menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE,NULL); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_remove_contact,contact_list); + menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD,NULL); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_add_contact,contact_list); + gtk_widget_show(menu); + gtk_menu_attach_to_widget (GTK_MENU (menu), contact_list, NULL); + if (call_label) g_free(call_label); + if (text_label) g_free(text_label); + return menu; +} + + +gboolean linphone_gtk_popup_contact_menu(GtkWidget *list, GdkEventButton *event){ + GtkWidget *m=linphone_gtk_create_contact_menu(list); + gtk_menu_popup (GTK_MENU (m), NULL, NULL, NULL, NULL, + event ? event->button : 0, event ? event->time : gtk_get_current_event_time()); + return TRUE; +} + +gboolean linphone_gtk_contact_list_button_pressed(GtkWidget *widget, GdkEventButton *event){ + /* Ignore double-clicks and triple-clicks */ + if (event->button == 3 && event->type == GDK_BUTTON_PRESS) + { + return linphone_gtk_popup_contact_menu(widget, event); + } + return FALSE; +} + diff --git a/linphone/gtk-glade/gtk-linphone.glade b/linphone/gtk-glade/gtk-linphone.glade new file mode 100644 index 000000000..8b2771f6d --- /dev/null +++ b/linphone/gtk-glade/gtk-linphone.glade @@ -0,0 +1,2417 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + linphone2.png + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + É_dition + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + _Properties + True + + + + True + gtk-preferences + + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Modes + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio only + True + True + menuitem3 + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio & Video + True + True + True + menuitem1 + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Aid_e + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Show logs + True + + + + gtk-dialog-info + + + + + + + True + _About + True + + + + True + gtk-about + + + + + + + + + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-close + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Terminate call + + + 1 + + + + + + + False + False + GTK_PACK_END + 2 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-go-forward + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Start call + + + 1 + + + + + + + False + False + GTK_PACK_END + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Current call + True + + + label_item + + + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + GTK_SHADOW_OUT + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + GTK_SHADOW_NONE + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Show All +Show Online + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Search: + + + 8 + 1 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 2 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Display filters + True + + + label_item + + + + + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + GTK_BUTTONBOX_SPREAD + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-add + True + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-edit + True + 0 + + + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-remove + True + 0 + + + 2 + + + + + False + 2 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Contact list</b> + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + GTK_SHADOW_OUT + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Proxy in use + True + + + label_item + + + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + GTK_SHADOW_OUT + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 4 + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + D + 0 + + + 3 + 4 + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + # + 0 + + + 2 + 3 + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + 0 + + + 1 + 2 + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + * + 0 + + + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + C + 0 + + + 3 + 4 + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 9 + 0 + + + 2 + 3 + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 8 + 0 + + + 1 + 2 + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 7 + 0 + + + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + B + 0 + + + 3 + 4 + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 6 + 0 + + + 2 + 3 + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 0 + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 0 + + + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + A + 0 + + + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 0 + + + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 0 + + + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 + 0 + + + + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Digits + True + + + label_item + + + + + False + False + 1 + + + + + 1 + + + + + 1 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + False + 2 + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + linphone2.png + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Use IPv6 instead of IPv4 + 0 + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>IPv6 usage</b> + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 1 65535 1 10 10 + + + 1 + 2 + 2 + 3 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 1 65535 1 10 10 + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 1 65535 1 10 10 + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Video RTP/UDP + + + 2 + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio RTP/UDP + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP (UDP) + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Ports used</b> + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Public IP address + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Stun server + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + + + + + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Firewall settings</b> + True + + + label_item + + + + + 2 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-network + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Network settings + + + 1 + + + + + tab + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-media-play + True + 0 + + + 1 + + + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Ring sound + + + 4 + 5 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + ALSA special device (optional) + + + 3 + 4 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Capture device + + + 2 + 3 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Ring device + + + 1 + 2 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Playback device + + + GTK_FILL + GTK_FILL + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Sound + True + + + label_item + + + + + + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-missing-image + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Multimedia settings + + + 1 + + + + + tab + 1 + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + This section defines your SIP address when not using a SIP account + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your display name (eg: John Doe): + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your username: + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your resulting SIP address: + + + 2 + 3 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + 2 + 3 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Default identity + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-add + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Add + + + 1 + + + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-edit + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Edit + + + 1 + + + + + + + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Remove + + + 1 + + + + + + + 2 + + + + + False + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Proxy accounts + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Erase all passwords + + + 1 + + + + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Privacy + True + + + label_item + + + + + 2 + + + + + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + stock_people.png + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Manage SIP Accounts + + + 1 + + + + + tab + 2 + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Audio codecs +Video codecs + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_OUT + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-go-up + True + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-go-down + True + 0 + + + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-yes + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Enable + + + 1 + + + + + + + 2 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-no + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Disable + + + 1 + + + + + + + 3 + + + + + False + 1 + + + + + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Codecs + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + 0 -1 100000 1 10 10 + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + 0 -1 100000 1 10 10 + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Upload limit in kbits/sec + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Download limit in kbits/sec + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Bandwidth usage + True + + + label_item + + + + + 1 + + + + + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-execute + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Codecs + + + 1 + + + + + tab + 3 + False + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-close + True + 0 + + + + + 1 + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Linphone - Configure a SIP account + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 0 100000 1 10 10 + + + 1 + 2 + 3 + 4 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Registration period (sec): + + + 3 + 4 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 2 + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Route (optional): + + + 2 + 3 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP Proxy address: + + + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your SIP identity: + + + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Publish presence information + 0 + True + + + False + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Configure a SIP account + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok + True + 0 + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + + 1 + + + + + False + GTK_PACK_END + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Linphone - Authentication required + True + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Please enter your password for domain... + True + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok + True + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + 1 + + + + + False + GTK_PACK_END + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP Address + + + 1 + 2 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Name + + + GTK_FILL + + + + + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Show this contact presence status + 0 + True + True + + + 1 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Allow this contact to see my presence status + 0 + True + True + + + 2 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Contact information + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok + True + 0 + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/incoming_call.glade b/linphone/gtk-glade/incoming_call.glade new file mode 100644 index 000000000..303c815f9 --- /dev/null +++ b/linphone/gtk-glade/incoming_call.glade @@ -0,0 +1,140 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + GTK_WINDOW_POPUP + Linphone - Incoming call + True + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_NOTIFICATION + True + False + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Incoming call from + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Incoming call + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_SPREAD + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-yes + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Accept + + + 1 + + + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-no + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Decline + + + 1 + + + + + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/linphone.dev b/linphone/gtk-glade/linphone.dev new file mode 100755 index 000000000..b4a14f0d9 --- /dev/null +++ b/linphone/gtk-glade/linphone.dev @@ -0,0 +1,165 @@ +[Project] +FileName=linphone.dev +Name=linphone +UnitCount=8 +PchHead=-1 +PchSource=-1 +Ver=3 +IsCpp=1 +ProfilesCount=2 +ProfileIndex=0 +Folders= + +[Unit1] +FileName=support.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=calllogs.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=chat.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=friendlist.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=linphone.h +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=logging.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=main.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=propertybox.c +CompileCpp=0 +Folder=linphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription= +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 + +[Profile1] +ProfileName=Mingw 3.4.2 +Type=0 +ObjFiles= +Includes=C:\Dev-Cpp\gtk+2.12\include\gtk-2.0;C:\Dev-Cpp\gtk+2.12\include\libglade-2.0;../coreapi;C:\Dev-Cpp\gtk+2.12\include\cairo;C:\Dev-Cpp\gtk+2.12\include\pango-1.0;C:\Dev-Cpp\gtk+2.12\include\glib-2.0;C:\Dev-Cpp\gtk+2.12\lib\glib-2.0\include;C:\Dev-Cpp\gtk+2.12\lib\gtk-2.0\include;C:\Dev-Cpp\gtk+2.12\include\atk-1.0;../../linphone-deps/include;../oRTP/include;../mediastreamer2/include;C:\Dev-Cpp\gtk+2.12\include +Libs=../win32;C:\Dev-Cpp\gtk+2.12\lib;../mediastreamer2/build/win32native;../oRTP/build/win32native;../../linphone-deps/lib +ResourceIncludes= +MakeIncludes= +Compiler=-ggdb -O2_@@_-DENABLE_NLS_@@__@@_ +CppCompiler= +Linker=-mwindows_@@_-Wl,--export-all-symbols_@@_-Wl,--add-stdcall-alias_@@_-llinphone_@@_-lmediastreamer2_@@_-lortp_@@_-lglade-2.0_@@_-lgtk-win32-2.0_@@_-lglib-2.0_@@_-lintl_@@_-lgdk_pixbuf-2.0_@@_-latk-1.0_@@_-lgobject-2.0_@@_-lgthread-2.0_@@_-lgdk-win32-2.0_@@_-losip2_@@_-losipparser2_@@_-leXosip2_@@_-lws2_32_@@_ +PreprocDefines= +CompilerSettings=0000000000000000000000 +Icon=linphone.ico +ExeOutput= +ObjectOutput=Objects +OverrideOutput=0 +OverrideOutputName=linphone.exe +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + +[Profile2] +ProfileName=MS VC++ 2005 +Type=1 +ObjFiles= +Includes= +Libs= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker= +PreprocDefines= +CompilerSettings=000000000000010000000000000000000000 +Icon= +ExeOutput=Output\MSVC++2005 +ObjectOutput=Objects\MSVC++2005 +OverrideOutput=0 +OverrideOutputName= +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=1 +compilerType=1 + diff --git a/linphone/gtk-glade/linphone.h b/linphone/gtk-glade/linphone.h new file mode 100644 index 000000000..e0ccc8446 --- /dev/null +++ b/linphone/gtk-glade/linphone.h @@ -0,0 +1,53 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define PACKAGE_DATA_DIR "./" +#define LINPHONE_VERSION "2.99.4" +#endif + +#include +#include "linphonecore.h" + +#include +#define _(String) gettext (String) + +GdkPixbuf * create_pixbuf(const gchar *filename); +void add_pixmap_directory(const gchar *directory); +GtkWidget *linphone_gtk_create_window(const char *window_name); +GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name); +LinphoneCore *linphone_gtk_get_core(void); +GtkWidget *linphone_gtk_get_main_window(); +void linphone_gtk_start_call(GtkWidget *button); +void linphone_gtk_show_friends(void); +void linphone_gtk_show_contact(LinphoneFriend *lf); +void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss); +void linphone_gtk_show_parameters(void); +void linphone_gtk_load_identities(void); +void linphone_gtk_create_chatroom(const char *with); +void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message); +void linphone_gtk_call_log_update(GtkWidget *w); +void linphone_gtk_create_log_window(void); +void linphone_gtk_log_show(void); +void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args); +void linphone_gtk_destroy_log_window(void); +gboolean linphone_gtk_check_logs(); + diff --git a/linphone/gtk-glade/linphone.iss b/linphone/gtk-glade/linphone.iss new file mode 100755 index 000000000..c5808db71 --- /dev/null +++ b/linphone/gtk-glade/linphone.iss @@ -0,0 +1,69 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=Linphone +AppVerName=Linphone for windows 2.99.4 (gtk/glade interface based on liblinphone) +AppPublisher=linphone.org +AppPublisherURL=http://www.linphone.org +AppSupportURL=http://www.linphone.org +AppUpdatesURL=http://www.linphone.org +DefaultDirName={pf}\Linphone +DefaultGroupName=Linphone +LicenseFile=C:\Documents and Settings\simorl.EMEA\cvs\linphone\COPYING +InfoBeforeFile=C:\Documents and Settings\simorl.EMEA\cvs\linphone\README +OutputBaseFilename=setup +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\gtk-glade\linphone.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\mediastreamer2\build\win32native\mediastream.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\gtk-glade\*.glade"; DestDir: "{app}/linphone"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\pixmaps\*.png"; DestDir: "{app}/linphone"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\pixmaps\*.png"; DestDir: "{app}/pixmaps"; Flags: ignoreversion +Source: "C:\Dev-Cpp\gtk+2.12\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Dev-Cpp\gtk+2.12\etc\gtk-2.0\*"; DestDir: "{app}\etc\gtk-2.0\"; Flags: ignoreversion +Source: "C:\Dev-Cpp\libxml2-2.6.32+.win32\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Dev-Cpp\iconv-1.9.2.win32\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Dev-Cpp\gtk+2.12\lib\gtk-2.0\2.10.0\engines\*"; DestDir: "{app}\lib\gtk-2.0\2.10.0\engines"; Flags: ignoreversion +Source: "C:\Dev-Cpp\gtk+2.12\lib\gtk-2.0\2.10.0\loaders\*"; DestDir: "{app}\lib\gtk-2.0\2.10.0\loaders"; Flags: ignoreversion +Source: "C:\Dev-Cpp\gtk+2.12\lib\gtk-2.0\2.10.0\immodules\*"; DestDir: "{app}\lib\gtk-2.0\2.10.0\immodules"; Flags: ignoreversion +; all icons: +;Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\win32\linphonec.exe"; DestDir: "{app}"; Flags: ignoreversion +;Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\win32\linphonec-remote.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\mediastreamer2\src\nowebcamCIF.jpg"; DestDir: "{app}\images"; Flags: ignoreversion + +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\COPYING"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\share\ringback.wav"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\share\rings\orig.wav"; DestDir: "{app}\rings"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\share\rings\bigben.wav"; DestDir: "{app}\rings"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\share\rings\toy.wav"; DestDir: "{app}\rings"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\share\rings\tapping.wav"; DestDir: "{app}\rings"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\share\rings\oldphone.wav"; DestDir: "{app}\rings"; Flags: ignoreversion + +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\osipparser2.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\osip2.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\exosip2.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\libogg.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\speex.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\avcodec.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone-deps\bin\avutil.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\mediastreamer2\build\win32native\mediastreamer2.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\oRTP\build\win32native\ortp.dll"; DestDir: "{app}"; Flags: ignoreversion + +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\Linphone"; Filename: "{app}\linphone.exe" ; WorkingDir: "{app}" +Name: "{userdesktop}\Linphone"; Filename: "{app}\linphone.exe"; WorkingDir: "{app}" ; Tasks: desktopicon + +[Run] +Filename: "{app}\linphone.exe"; Description: "{cm:LaunchProgram,Linphone}"; WorkingDir: "{app}" ; Flags: nowait postinstall skipifsilent + diff --git a/linphone/gtk-glade/linphone.png b/linphone/gtk-glade/linphone.png new file mode 100644 index 000000000..06cf18315 Binary files /dev/null and b/linphone/gtk-glade/linphone.png differ diff --git a/linphone/gtk-glade/linphone2.png b/linphone/gtk-glade/linphone2.png new file mode 100644 index 000000000..d1bf1ab63 Binary files /dev/null and b/linphone/gtk-glade/linphone2.png differ diff --git a/linphone/gtk-glade/log.glade b/linphone/gtk-glade/log.glade new file mode 100644 index 000000000..0dfc558de --- /dev/null +++ b/linphone/gtk-glade/log.glade @@ -0,0 +1,71 @@ + + + + + + 540 + 290 + 5 + Linphone debug window + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + False + + + + True + 2 + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_CORNER_BOTTOM_LEFT + True + GTK_SHADOW_IN + + + True + True + False + GTK_WRAP_WORD + + + + + 1 + + + + + True + GTK_BUTTONBOX_END + + + + + + True + True + True + gtk-close + True + 0 + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/logging.c b/linphone/gtk-glade/logging.c new file mode 100644 index 000000000..a8211d1ea --- /dev/null +++ b/linphone/gtk-glade/logging.c @@ -0,0 +1,125 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" + +static GtkWidget *log_window=NULL; +static GStaticMutex log_mutex=G_STATIC_MUTEX_INIT; +static GList *log_queue=NULL; + +typedef struct _LinphoneGtkLog{ + OrtpLogLevel lev; + gchar *msg; +}LinphoneGtkLog; + +void linphone_gtk_create_log_window(void){ + GtkTextBuffer *b; + log_window=linphone_gtk_create_window("log"); + b=gtk_text_view_get_buffer(GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview"))); + gtk_text_buffer_create_tag(b,"red","foreground","red",NULL); + gtk_text_buffer_create_tag(b,"orange","foreground","orange",NULL); +} + +void linphone_gtk_destroy_log_window(void){ + GtkWidget *w=log_window; + g_static_mutex_lock(&log_mutex); + log_window=NULL; + gtk_widget_destroy(w); + g_static_mutex_unlock(&log_mutex); +} + +void linphone_gtk_log_show(void){ + gtk_widget_show(log_window); + gtk_window_present(GTK_WINDOW(log_window)); +} + +static void linphone_gtk_display_log(OrtpLogLevel lev, const char *msg){ + GtkTextIter iter,begin; + int off; + static GtkTextView *v=NULL; + GtkTextBuffer *b; + const char *lname="undef"; + + if (log_window==NULL) { + return; + } + + if (v==NULL) v=GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview")); + b=gtk_text_view_get_buffer(v); + switch(lev){ + case ORTP_DEBUG: + lname="debug"; + break; + case ORTP_MESSAGE: + lname="message"; + break; + case ORTP_WARNING: + lname="warning"; + break; + case ORTP_ERROR: + lname="error"; + break; + case ORTP_FATAL: + lname="fatal"; + break; + default: + g_error("Bad level !"); + } + gtk_text_buffer_get_end_iter(b,&iter); + off=gtk_text_iter_get_offset(&iter); + gtk_text_buffer_insert(b,&iter,lname,-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_insert(b,&iter,": ",-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_insert(b,&iter,msg,-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_insert(b,&iter,"\n",-1); + gtk_text_buffer_get_end_iter(b,&iter); + gtk_text_buffer_get_iter_at_offset(b,&begin,off); + if (lev==ORTP_ERROR || lev==ORTP_FATAL) gtk_text_buffer_apply_tag_by_name(b,"red",&begin,&iter); + else if (lev==ORTP_WARNING) gtk_text_buffer_apply_tag_by_name(b,"orange",&begin,&iter); + gtk_text_buffer_get_end_iter(b,&iter); + //gtk_text_view_scroll_to_iter(v,&iter,0,FALSE,0,0); +} + +gboolean linphone_gtk_check_logs(){ + GList *elem; + g_static_mutex_lock(&log_mutex); + for(elem=log_queue;elem!=NULL;elem=elem->next){ + LinphoneGtkLog *lgl=(LinphoneGtkLog*)elem->data; + linphone_gtk_display_log(lgl->lev,lgl->msg); + g_free(lgl->msg); + g_free(lgl); + } + if (log_queue) g_list_free(log_queue); + log_queue=NULL; + g_static_mutex_unlock(&log_mutex); + return TRUE; +} + +void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args){ + gchar *msg=g_strdup_vprintf(fmt,args); + LinphoneGtkLog *lgl=g_new(LinphoneGtkLog,1); + lgl->lev=lev; + lgl->msg=msg; + g_static_mutex_lock(&log_mutex); + log_queue=g_list_append(log_queue,lgl); + g_static_mutex_unlock(&log_mutex); +} + diff --git a/linphone/gtk-glade/main.c b/linphone/gtk-glade/main.c new file mode 100644 index 000000000..5a59e443a --- /dev/null +++ b/linphone/gtk-glade/main.c @@ -0,0 +1,725 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#define USE_LIBGLADE 1 + +#include "lpconfig.h" + +#include "linphone.h" + +#ifdef USE_LIBGLADE +#include +#endif + +#include +#include +#include + +#ifndef GETTEXT_PACKAGE +#define GETTEXT_PACKAGE "linphone" +#endif + +#ifndef PACKAGE_LOCALE_DIR +#define PACKAGE_LOCALE_DIR "po" +#endif + + +static LinphoneCore *the_core=NULL; +static GtkWidget *the_ui=NULL; + +static void linphone_gtk_show(LinphoneCore *lc); +static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from); +static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from); +static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img); +static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); +static void linphone_gtk_display_status(LinphoneCore *lc, const char *status); +static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg); +static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); +static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url); +static void linphone_gtk_display_question(LinphoneCore *lc, const char *question); +static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); +static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate); + +static LinphoneCoreVTable vtable={ + .show=linphone_gtk_show, + .inv_recv=linphone_gtk_inv_recv, + .bye_recv=linphone_gtk_bye_recv, + .notify_recv=linphone_gtk_notify_recv, + .new_unknown_subscriber=linphone_gtk_new_unknown_subscriber, + .auth_info_requested=linphone_gtk_auth_info_requested, + .display_status=linphone_gtk_display_status, + .display_message=linphone_gtk_display_message, + .display_warning=linphone_gtk_display_warning, + .display_url=linphone_gtk_display_url, + .display_question=linphone_gtk_display_question, + .call_log_updated=linphone_gtk_call_log_updated, + .text_received=linphone_gtk_text_received, + .general_state=linphone_gtk_general_state +}; + +static gboolean verbose=0; +static GOptionEntry linphone_options[2]={ + { + .long_name="verbose", + .short_name= '\0', + .arg=G_OPTION_ARG_NONE, + .arg_data= (gpointer)&verbose, + .description="log to stdout some debug information while running." + } +}; + +#define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone" +#define BUILD_TREE_XML_DIR "gtk-glade" +#define CONFIG_FILE ".linphonerc" + +static void linphone_gtk_init_liblinphone(){ + const char *home; + char file[1024]; + /*try accessing a local file first if exists*/ + if (access(CONFIG_FILE,F_OK)==0){ + snprintf(file,sizeof(file),"%s",CONFIG_FILE); + }else{ +#ifdef WIN32 + const char *appdata=getenv("APPDATA"); + if (appdata){ + snprintf(file,sizeof(file),"%s\\%s",appdata,"Linphone\\"); + CreateDirectory(file,NULL); + snprintf(file,sizeof(file),"%s\\%s",appdata,"Linphone\\linphonerc"); + } +#else + home=getenv("HOME"); + if (home==NULL) home=""; + snprintf(file,sizeof(file),"%s/%s",home,CONFIG_FILE); +#endif + } + the_core=linphone_core_new(&vtable,file,NULL); +} + + + +LinphoneCore *linphone_gtk_get_core(void){ + return the_core; +} + +GtkWidget *linphone_gtk_get_main_window(){ + return the_ui; +} + +#ifdef USE_LIBGLADE + +GtkWidget *linphone_gtk_create_window(const char *window_name){ + GtkWidget *w; + GladeXML *gxml; + char path[2048]; + snprintf(path,sizeof(path),"%s/%s.glade",BUILD_TREE_XML_DIR,window_name); + if (access(path,F_OK)!=0){ + snprintf(path,sizeof(path),"%s/%s.glade",INSTALLED_XML_DIR,window_name); + if (access(path,F_OK)!=0){ + g_error("Could not locate neither %s/%s.glade and %s/%s.glade .",BUILD_TREE_XML_DIR,window_name, + INSTALLED_XML_DIR,window_name); + return NULL; + } + } + gxml=glade_xml_new(path,NULL,NULL); + glade_xml_signal_autoconnect(gxml); + w=glade_xml_get_widget(gxml,window_name); + if (w==NULL) g_error("Could not retrieve '%s' window from xml file",window_name); + return w; +} + +GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ + GtkWidget *w; + GladeXML *gxml=glade_get_widget_tree(window); + if (gxml==NULL) g_error("Could not retrieve XML tree of window %s",name); + w=glade_xml_get_widget(gxml,name); + if (w==NULL) g_error("Could not retrieve widget %s",name); + return GTK_WIDGET(w); +} + +#else + +GtkWidget *linphone_gtk_create_window(const char *window_name){ + +} + +GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ + GObject *w=gtk_builder_get_object(the_ui,name); + if (w==NULL){ + g_error("No widget named %s found in xml interface.",name); + } + return GTK_WIDGET(w); +} + +#endif + +void linphone_gtk_display_something(GtkMessageType type,const gchar *message){ + GtkWidget *dialog; + GtkWidget *main_window=linphone_gtk_get_main_window(); + + gtk_widget_show(main_window); + if (type==GTK_MESSAGE_QUESTION) + { + /* draw a question box. link to dialog_click callback */ + dialog = gtk_message_dialog_new ( + GTK_WINDOW(main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + (const gchar*)message); + /* connect to some callback : REVISIT */ + /* + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (dialog_click), + G_OBJECT (dialog)); + */ + /* actually show the box */ + gtk_widget_show(dialog); + } + else + { + dialog = gtk_message_dialog_new (GTK_WINDOW(main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + GTK_BUTTONS_CLOSE, + (const gchar*)message); + /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + gtk_widget_show(dialog); + } +} + +void linphone_gtk_about_response(GtkDialog *dialog, gint id){ + if (id==GTK_RESPONSE_CANCEL){ + gtk_widget_destroy(GTK_WIDGET(dialog)); + } +} + +void linphone_gtk_show_about(){ + struct stat filestat; + const char *license_file=PACKAGE_DATA_DIR "/doc/COPYING"; + GtkWidget *about; + + about=linphone_gtk_create_window("about"); + memset(&filestat,0,sizeof(filestat)); + if (stat(license_file,&filestat)!=0){ + license_file="COPYING"; + stat(license_file,&filestat); + } + if (filestat.st_size>0){ + char *license=g_malloc(filestat.st_size+1); + FILE *f=fopen(license_file,"r"); + if (f && fread(license,filestat.st_size,1,f)==1){ + license[filestat.st_size]='\0'; + gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license); + } + g_free(license); + } + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION); + + gtk_widget_show(about); +} + +static gboolean linphone_gtk_iterate(LinphoneCore *lc){ + linphone_core_iterate(lc); + return TRUE; +} + +static void load_uri_history(){ + GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); + LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); + char key[20]; + int i; + GtkEntryCompletion *gep=gtk_entry_completion_new(); + GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING); + for (i=0;;i++){ + const char *uri; + snprintf(key,sizeof(key),"uri%i",i); + uri=lp_config_get_string(cfg,"GtkUi",key,NULL); + if (uri!=NULL) { + GtkTreeIter iter; + gtk_list_store_append(model,&iter); + gtk_list_store_set(model,&iter,0,uri,-1); + if (i==0) gtk_entry_set_text(uribar,uri); + } + else break; + } + gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); + gtk_entry_completion_set_text_column(gep,0); + gtk_entry_set_completion(uribar,gep); +} + +static void save_uri_history(){ + LinphoneCore *lc=linphone_gtk_get_core(); + LpConfig *cfg=linphone_core_get_config(lc); + GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); + char key[20]; + int i=0; + char *uri=NULL; + GtkTreeIter iter; + GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar)); + + if (!gtk_tree_model_get_iter_first(model,&iter)) return; + do { + gtk_tree_model_get(model,&iter,0,&uri,-1); + if (uri) { + snprintf(key,sizeof(key),"uri%i",i); + lp_config_set_string(cfg,"GtkUi",key,uri); + g_free(uri); + }else break; + i++; + if (i>5) break; + }while(gtk_tree_model_iter_next(model,&iter)); + lp_config_sync(cfg); +} + +static void completion_add_text(GtkEntry *entry, const char *text){ + GtkTreeIter iter; + GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry)); + + if (gtk_tree_model_get_iter_first(model,&iter)){ + do { + gchar *uri=NULL; + gtk_tree_model_get(model,&iter,0,&uri,-1); + if (uri!=NULL){ + if (strcmp(uri,text)==0) { + /*remove text */ + gtk_list_store_remove(GTK_LIST_STORE(model),&iter); + g_free(uri); + break; + } + g_free(uri); + } + }while (gtk_tree_model_iter_next(model,&iter)); + } + /* and prepend it on top of the list */ + gtk_list_store_prepend(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1); + save_uri_history(); +} + +static void linphone_gtk_call_started(GtkWidget *mw){ + gtk_widget_hide(linphone_gtk_get_widget(mw,"start_call")); + gtk_widget_show(linphone_gtk_get_widget(mw,"terminate_call")); +} + +void linphone_gtk_start_call(GtkWidget *button){ + LinphoneCore *lc=linphone_gtk_get_core(); + if (linphone_core_inc_invite_pending(lc)){ + /*already in call */ + }else{ + GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"uribar"); + const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); + if (linphone_core_invite(lc,entered)==0) { + linphone_gtk_call_started(linphone_gtk_get_main_window()); + completion_add_text(GTK_ENTRY(uri_bar),entered); + } + } +} + +static void linphone_gtk_call_terminated(GtkWidget *mw){ + gtk_widget_hide(linphone_gtk_get_widget(mw,"terminate_call")); + gtk_widget_show(linphone_gtk_get_widget(mw,"start_call")); + g_object_set_data(G_OBJECT(mw),"incoming_call",NULL); +} + +void linphone_gtk_terminate_call(GtkWidget *button){ + linphone_core_terminate_call(linphone_gtk_get_core(),NULL); + linphone_gtk_call_terminated(gtk_widget_get_toplevel(button)); +} + +void linphone_gtk_decline_call(GtkWidget *button){ + linphone_core_terminate_call(linphone_gtk_get_core(),NULL); + linphone_gtk_call_terminated(gtk_widget_get_toplevel(button)); + gtk_widget_destroy(gtk_widget_get_toplevel(button)); +} + +void linphone_gtk_accept_call(GtkWidget *button){ + linphone_core_accept_call(linphone_gtk_get_core(),NULL); + g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",NULL); + gtk_widget_destroy(gtk_widget_get_toplevel(button)); + linphone_gtk_call_started(linphone_gtk_get_main_window()); +} + +void linphone_gtk_set_audio_video(){ + linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE); +} + +void linphone_gtk_set_audio_only(){ + linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE); +} + +void linphone_gtk_used_identity_changed(GtkWidget *w){ + int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w)); + char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + if (sel && strlen(sel)>0) //avoid a dummy "changed" at gui startup + linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1)); +} + +static void linphone_gtk_show_main_window(){ + GtkWidget *w=linphone_gtk_get_main_window(); + LinphoneCore *lc=linphone_gtk_get_core(); + linphone_core_enable_video_preview(lc,linphone_core_video_enabled(lc)); + gtk_widget_show(w); + gtk_window_present(GTK_WINDOW(w)); +} + +static void linphone_gtk_show(LinphoneCore *lc){ + linphone_gtk_show_main_window(); +} + +static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){ + GtkWidget *w=linphone_gtk_create_window("incoming_call"); + GtkWidget *label; + gchar *msg; + gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window())); + gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT); + + label=linphone_gtk_get_widget(w,"message"); + msg=g_strdup_printf(_("Incoming call from %s"),from); + gtk_label_set_text(GTK_LABEL(label),msg); + gtk_window_set_title(GTK_WINDOW(w),msg); + gtk_widget_show(w); + gtk_window_present(GTK_WINDOW(w)); + /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ + g_free(msg); + g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")), + from); +} + +static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){ + GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call")); + if (icw!=NULL){ + gtk_widget_destroy(icw); + } + linphone_gtk_call_terminated(linphone_gtk_get_main_window()); +} + +static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img){ +} + +static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){ + switch(response_id){ + case GTK_RESPONSE_YES: + linphone_gtk_show_contact(lf); + break; + default: + linphone_core_reject_subscriber(linphone_gtk_get_core(),lf); + } + gtk_widget_destroy(dialog); +} + +static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + GtkWidget *dialog; + gchar *message=g_strdup_printf(_("%s would like to add you to his contact list.\nWould you allow him to see your presence status or add him to your contact list ?\nIf you answer no, this person will be temporarily blacklisted."),url); + dialog = gtk_message_dialog_new ( + GTK_WINDOW(linphone_gtk_get_main_window()), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + message); + g_free(message); + g_signal_connect(G_OBJECT (dialog), "response", + G_CALLBACK (linphone_gtk_new_subscriber_response),lf); + /* actually show the box */ + gtk_widget_show(dialog); +} + +typedef struct _AuthTimeout{ + GtkWidget *w; +} AuthTimeout; + + +static void auth_timeout_clean(AuthTimeout *tout){ + tout->w=NULL; +} + +static gboolean auth_timeout_destroy(AuthTimeout *tout){ + if (tout->w) { + g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout); + gtk_widget_destroy(tout->w); + } + g_free(tout); + return FALSE; +} + +static AuthTimeout * auth_timeout_new(GtkWidget *w){ + AuthTimeout *tout=g_new(AuthTimeout,1); + tout->w=w; + /*so that the timeout no more references the widget when it is destroyed:*/ + g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout); + /*so that the widget is automatically destroyed after some time */ + g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout); + return tout; +} + +void linphone_gtk_password_cancel(GtkWidget *w){ + LinphoneAuthInfo *info; + GtkWidget *window=gtk_widget_get_toplevel(w); + info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info"); + linphone_core_abort_authentication(linphone_gtk_get_core(),info); + gtk_widget_destroy(window); +} + +void linphone_gtk_password_ok(GtkWidget *w){ + GtkWidget *entry; + GtkWidget *window=gtk_widget_get_toplevel(w); + LinphoneAuthInfo *info; + info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info"); + g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info); + entry=linphone_gtk_get_widget(window,"password_entry"); + linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry))); + linphone_core_add_auth_info(linphone_gtk_get_core(),info); + gtk_widget_destroy(window); +} + +static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){ + GtkWidget *w=linphone_gtk_create_window("password"); + GtkWidget *label=linphone_gtk_get_widget(w,"message"); + LinphoneAuthInfo *info; + gchar *msg; + msg=g_strdup_printf(_("Please enter your password for domain %s:"),realm); + gtk_label_set_text(GTK_LABEL(label),msg); + g_free(msg); + info=linphone_auth_info_new(username, NULL, NULL, NULL,realm); + g_object_set_data(G_OBJECT(w),"auth_info",info); + g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info); + gtk_widget_show(w); + auth_timeout_new(w); +} + +static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar"); + gtk_statusbar_push(GTK_STATUSBAR(status_bar), + gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""), + status); +} + +static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){ + linphone_gtk_display_something(GTK_MESSAGE_INFO,msg); +} + +static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){ + linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning); +} + +static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){ + char richtext[4096]; + snprintf(richtext,sizeof(richtext),"%s %s",msg,url); + linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext); +} + +static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){ + linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question); +} + +static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){ + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs"); + if (w) linphone_gtk_call_log_update(w); +} + +static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){ +} + + +static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){ + GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu"); + gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time); +} + +static GtkWidget *create_icon_menu(){ + GtkWidget *menu=gtk_menu_new(); + GtkWidget *menu_item; + menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL); + menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL); + gtk_widget_show(menu); + return menu; +} + +static void linphone_gtk_init_status_icon(){ + GtkStatusIcon *icon; + GdkPixbuf *pbuf=create_pixbuf("linphone2.png"); + GtkWidget *menu=create_icon_menu(); + icon=gtk_status_icon_new_from_pixbuf(pbuf); + g_object_unref(G_OBJECT(pbuf)); + g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window()); + g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL); + gtk_status_icon_set_tooltip(icon,_("Linphone - a video internet phone")); + g_object_set_data(G_OBJECT(icon),"menu",menu); + g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu); +} + +void linphone_gtk_load_identities(void){ + const MSList *elem; + GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities")); + char *def_identity; + LinphoneProxyConfig *def=NULL; + int def_index=0,i; + GtkListStore *store; + + store=GTK_LIST_STORE(gtk_combo_box_get_model(box)); + gtk_list_store_clear(store); + + linphone_core_get_default_proxy(linphone_gtk_get_core(),&def); + def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core())); + gtk_combo_box_append_text(box,def_identity); + g_free(def_identity); + for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core()); + elem!=NULL; + elem=ms_list_next(elem),i++){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg)); + if (cfg==def) { + def_index=i; + } + } + gtk_combo_box_set_active(box,def_index); +} + +static void linphone_gtk_dtmf_clicked(GtkButton *button){ + const char *label=gtk_button_get_label(button); + linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]); +} + +static void linphone_gtk_connect_digits(void){ + GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table")); + GList *children=gtk_container_get_children(cont); + GList *elem; + for(elem=children;elem!=NULL;elem=elem->next){ + GtkButton *button=GTK_BUTTON(elem->data); + g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL); + } +} + +static void linphone_gtk_check_menu_items(void){ + bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core()); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget( + linphone_gtk_get_main_window(), + audio_only ? "audio_only_item" : "video_item")), TRUE); +} + +static void linphone_gtk_init_main_window(){ + load_uri_history(); + linphone_gtk_load_identities(); + linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core())); + linphone_gtk_show_friends(); + linphone_gtk_connect_digits(); + linphone_gtk_check_menu_items(); + if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started( + linphone_gtk_get_main_window());/*hide the call button, show terminate button*/ +} + +void linphone_gtk_close(){ + /* couldn't find a way to prevent closing to destroy the main window*/ + linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE); + the_ui=NULL; + the_ui=linphone_gtk_create_window("main"); + linphone_gtk_init_main_window(); +} + +void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ + if (verbose){ + const char *lname="undef"; + char *msg; + #ifdef __linux + va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ + #endif + switch(lev){ + case ORTP_DEBUG: + lname="debug"; + break; + case ORTP_MESSAGE: + lname="message"; + break; + case ORTP_WARNING: + lname="warning"; + break; + case ORTP_ERROR: + lname="error"; + break; + case ORTP_FATAL: + lname="fatal"; + break; + default: + g_error("Bad level !"); + } +#ifdef __linux + va_copy(cap,args); + msg=g_strdup_vprintf(fmt,cap); + va_end(cap); +#else + msg=g_strdup_vprintf(fmt,args); +#endif + fprintf(stdout,"linphone-%s : %s\n",lname,msg); + ortp_free(msg); + } + linphone_gtk_log_push(lev,fmt,args); +} + +int main(int argc, char *argv[]){ + void *p; + g_thread_init(NULL); + gdk_threads_init(); +#ifdef ENABLE_NLS + p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); + if (p==NULL) perror("bindtextdomain failed"); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); +#else + g_message("NLS disabled.\n"); +#endif + gdk_threads_enter(); + if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"), + linphone_options,NULL,NULL)){ + gdk_threads_leave(); + return -1; + } + + add_pixmap_directory("pixmaps"); + add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); + + the_ui=linphone_gtk_create_window("main"); + + linphone_gtk_create_log_window(); + linphone_core_enable_logs_with_cb(linphone_gtk_log_handler); + + linphone_gtk_init_liblinphone(); + gtk_timeout_add(20,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); + gtk_timeout_add(20,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL); + linphone_gtk_init_main_window(); + linphone_gtk_init_status_icon(); + gtk_widget_show(the_ui); + gtk_main(); + gdk_threads_leave(); + linphone_gtk_destroy_log_window(); + linphone_core_destroy(the_core); + return 0; +} + + diff --git a/linphone/gtk-glade/main.glade b/linphone/gtk-glade/main.glade new file mode 100644 index 000000000..d8eb57990 --- /dev/null +++ b/linphone/gtk-glade/main.glade @@ -0,0 +1,804 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + linphone2.png + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + É_dition + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + _Properties + True + + + + True + gtk-preferences + + + + + + + True + Call history + True + + + + True + gtk-info + + + + + + + True + gtk-quit + True + True + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Modes + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio only + True + True + video_item + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio & Video + True + True + True + audio_only_item + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Aid_e + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Show debug window + True + + + + gtk-dialog-info + + + + + + + True + _About + True + + + + True + gtk-about + + + + + + + + + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-close + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Terminate call + + + 1 + + + + + + + False + False + GTK_PACK_END + 2 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-go-forward + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Start call + + + 1 + + + + + + + False + False + GTK_PACK_END + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Current call + True + + + label_item + + + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + GTK_SHADOW_NONE + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Show All +Show Online + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Search: + + + 8 + 1 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + 2 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Display filters + True + + + label_item + + + + + False + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + + + 120 + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + + + + + + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Contact list</b> + True + + + label_item + + + + + 8 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 15 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 4 + True + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + D + 0 + + + 3 + 4 + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + # + 0 + + + 2 + 3 + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + 0 + + + 1 + 2 + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + * + 0 + + + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + C + 0 + + + 3 + 4 + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 9 + 0 + + + 2 + 3 + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 8 + 0 + + + 1 + 2 + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 7 + 0 + + + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + B + 0 + + + 3 + 4 + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 6 + 0 + + + 2 + 3 + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 0 + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 0 + + + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + A + 0 + + + 3 + 4 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 0 + + + 2 + 3 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 0 + + + 1 + 2 + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 + 0 + + + + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Digits + True + + + label_item + + + + + False + False + + + + + 1 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Default + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + My identity : + True + + + label_item + + + + + False + False + 2 + + + + + 1 + + + + + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + + + True + True + True + 0 + + + + + + + False + 1 + + + + + False + 2 + + + + + + diff --git a/linphone/gtk-glade/parameters.glade b/linphone/gtk-glade/parameters.glade new file mode 100644 index 000000000..2061f0b91 --- /dev/null +++ b/linphone/gtk-glade/parameters.glade @@ -0,0 +1,1393 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + linphone2.png + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Use IPv6 instead of IPv4 + 0 + True + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>IPv6 usage</b> + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 1 65535 1 10 10 + + + + 1 + 2 + 2 + 3 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 1 65535 1 10 10 + + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 1 65535 1 10 10 + + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Video RTP/UDP + + + 2 + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio RTP/UDP + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP (UDP) + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Ports used</b> + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Public IP address + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + 1 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Stun server + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + 1 + + + + + 1 + + + + + True + True + I'm not behing a firewall + 0 + True + True + + + + 2 + + + + + True + True + I'm behind a firewall, use supplied public IP address + 0 + True + True + no_nat + + + + 3 + + + + + True + True + Use the supplied stun server above and do as best as possible + 0 + True + True + no_nat + + + + 4 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Firewall settings</b> + True + + + label_item + + + + + 2 + + + + + True + 0 + GTK_SHADOW_NONE + + + True + 12 + + + True + 2 + 2 + + + + + + True + True + 500 500 3001 1 10 10 + + + + 1 + 2 + + + + + True + True + Set Maximum Transmission Unit + 0 + True + + + + + + True + True + Send DTMFs as SIP info + 0 + True + + + + 1 + 2 + + + + + + + + + True + <b>Miscelaneous</b> + True + + + label_item + + + + + 3 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-network + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Network settings + + + 1 + + + + + tab + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 6 + 2 + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-media-play + True + 0 + + + + 1 + + + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Ring sound + + + 4 + 5 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + default soundcard + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + default soundcard + + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + ALSA special device (optional) + + + 3 + 4 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Capture device + + + 2 + 3 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Ring device + + + 1 + 2 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Playback device + + + GTK_FILL + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + a sound card + + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + True + Enable echo cancelation + 0 + True + + + + 1 + 2 + 5 + 6 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Sound</b> + True + + + label_item + + + + + + + True + 0 + + + True + 12 + + + True + 1 + 2 + + + True + Video input device + + + GTK_EXPAND + + + + + True + default camera + + + + 1 + 2 + GTK_EXPAND + + + + + + + + + True + <b>Video</b> + True + + + label_item + + + + + False + 1 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-media-play + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Multimedia settings + + + 1 + + + + + tab + 1 + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + This section defines your SIP address when not using a SIP account + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your display name (eg: John Doe): + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your username: + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your resulting SIP address: + + + 2 + 3 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + 1 + 2 + 2 + 3 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Default identity</b> + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-add + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Add + + + 1 + + + + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-edit + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Edit + + + 1 + + + + + + + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Remove + + + 1 + + + + + + + 2 + + + + + False + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Proxy accounts</b> + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Erase all passwords + + + 1 + + + + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Privacy</b> + True + + + label_item + + + + + 2 + + + + + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + stock_people.png + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Manage SIP Accounts + + + 1 + + + + + tab + 2 + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Audio codecs +Video codecs + + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_OUT + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-go-up + True + 0 + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-go-down + True + 0 + + + + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-yes + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Enable + + + 1 + + + + + + + 2 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-no + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Disable + + + 1 + + + + + + + 3 + + + + + False + 1 + + + + + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Codecs</b> + True + + + label_item + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + 0 -1 100000 1 10 10 + + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + 0 -1 100000 1 10 10 + + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Upload limit in kbits/sec + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Download limit in kbits/sec + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Bandwidth usage</b> + True + + + label_item + + + + + 1 + + + + + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-execute + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Codecs + + + 1 + + + + + tab + 3 + False + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-close + True + 0 + + + + + + 1 + + + + + + diff --git a/linphone/gtk-glade/password.glade b/linphone/gtk-glade/password.glade new file mode 100644 index 000000000..5e391eb35 --- /dev/null +++ b/linphone/gtk-glade/password.glade @@ -0,0 +1,89 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Linphone - Authentication required + True + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Please enter your password for domain... + True + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + + 1 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok + True + 0 + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/propertybox.c b/linphone/gtk-glade/propertybox.c new file mode 100644 index 000000000..da6b5d059 --- /dev/null +++ b/linphone/gtk-glade/propertybox.c @@ -0,0 +1,648 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" + +static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected){ + const char **p=devices; + int i=0,active=0; + /* glade creates a combo box without list model and text renderer, + unless we fill it with a dummy text. + This dummy text needs to be removed first*/ + gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),0); + for(;*p!=NULL;++p,++i){ + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),*p); + if (strcmp(selected,*p)==0) active=i; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); +} + +void linphone_gtk_parameters_closed(GtkWidget *button){ + GtkWidget *pb=gtk_widget_get_toplevel(button); + gtk_widget_destroy(pb); +} + +void linphone_gtk_update_my_contact(GtkWidget *w){ + GtkWidget *pb=gtk_widget_get_toplevel(w); + const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username"))); + const char *displayname=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"displayname"))); + int port=linphone_core_get_sip_port(linphone_gtk_get_core()); + osip_from_t *parsed=linphone_core_get_primary_contact_parsed(linphone_gtk_get_core()); + char *contact; + g_return_if_fail(parsed!=NULL); + if (username[0]=='\0') return; + if (port!=5060) + contact=g_strdup_printf("%s ",displayname,username,parsed->url->host,port); + else + contact=g_strdup_printf("%s ",displayname,username,parsed->url->host); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"sip_address")),contact); + linphone_core_set_primary_contact(linphone_gtk_get_core(),contact); + g_free(contact); + linphone_gtk_load_identities(); +} + +void linphone_gtk_stun_server_changed(GtkWidget *w){ + const gchar *addr=gtk_entry_get_text(GTK_ENTRY(w)); + linphone_core_set_stun_server(linphone_gtk_get_core(),addr); +} + +void linphone_gtk_nat_address_changed(GtkWidget *w){ + const gchar *addr=gtk_entry_get_text(GTK_ENTRY(w)); + linphone_core_set_nat_address(linphone_gtk_get_core(),addr); +} + +void linphone_gtk_ipv6_toggled(GtkWidget *w){ + linphone_core_enable_ipv6(linphone_gtk_get_core(), + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); +} + +void linphone_gtk_sip_port_changed(GtkWidget *w){ + linphone_core_set_sip_port(linphone_gtk_get_core(), + (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); +} + +void linphone_gtk_audio_port_changed(GtkWidget *w){ + linphone_core_set_audio_port(linphone_gtk_get_core(), + (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); +} + +void linphone_gtk_video_port_changed(GtkWidget *w){ + linphone_core_set_video_port(linphone_gtk_get_core(), + (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); +} + +void linphone_gtk_no_firewall_toggled(GtkWidget *w){ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_NO_FIREWALL); +} + +void linphone_gtk_use_nat_address_toggled(GtkWidget *w){ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_NAT_ADDRESS); +} + +void linphone_gtk_use_stun_toggled(GtkWidget *w){ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_STUN); +} + +void linphone_gtk_mtu_changed(GtkWidget *w){ + if (GTK_WIDGET_SENSITIVE(w)) + linphone_core_set_mtu(linphone_gtk_get_core(),gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); +} + +void linphone_gtk_use_sip_info_dtmf_toggled(GtkWidget *w){ + linphone_core_set_use_info_for_dtmf(linphone_gtk_get_core(), + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); +} + +void linphone_gtk_mtu_set(GtkWidget *w){ + GtkWidget *mtu=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"mtu"); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ + gtk_widget_set_sensitive(mtu,TRUE); + linphone_gtk_mtu_changed(mtu); + }else{ + gtk_widget_set_sensitive(mtu,FALSE); + linphone_core_set_mtu(linphone_gtk_get_core(),0); + } +} + +void linphone_gtk_playback_device_changed(GtkWidget *w){ + gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + linphone_core_set_playback_device(linphone_gtk_get_core(),sel); + g_free(sel); +} + +void linphone_gtk_capture_device_changed(GtkWidget *w){ + gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + linphone_core_set_capture_device(linphone_gtk_get_core(),sel); + g_free(sel); +} + +void linphone_gtk_ring_device_changed(GtkWidget *w){ + gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + linphone_core_set_ringer_device(linphone_gtk_get_core(),sel); + g_free(sel); +} + +void linphone_gtk_alsa_special_device_changed(GtkWidget *w){ + /* + const gchar *dev=gtk_entry_get_text(GTK_ENTRY(w)); + ...*/ +} + +void linphone_gtk_cam_changed(GtkWidget *w){ + gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + linphone_core_set_video_device(linphone_gtk_get_core(),sel); + g_free(sel); +} + +void linphone_gtk_ring_file_set(GtkWidget *w){ + gchar *file=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w)); + linphone_core_set_ring(linphone_gtk_get_core(),file); + g_free(file); +} + +static void linphone_gtk_end_of_ring(LinphoneCore *lc, void *user_data){ + gtk_widget_set_sensitive((GtkWidget*)user_data,TRUE); +} + +void linphone_gtk_play_ring_file(GtkWidget *w){ + if (linphone_core_preview_ring(linphone_gtk_get_core(), + linphone_core_get_ring(linphone_gtk_get_core()), + linphone_gtk_end_of_ring, + w)==0){ + gtk_widget_set_sensitive(w,FALSE); + } +} + +void linphone_gtk_echo_cancelation_toggled(GtkWidget *w){ + linphone_core_enable_echo_cancelation(linphone_gtk_get_core(), + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); +} + +enum { + CODEC_NAME, + CODEC_RATE, + CODEC_BITRATE, + CODEC_STATUS, + CODEC_PARAMS, + CODEC_PRIVDATA, + CODEC_COLOR, + CODEC_INFO, + CODEC_NCOLUMNS +}; + +static void linphone_gtk_init_codec_list(GtkTreeView *listview){ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + + GtkListStore *store = gtk_list_store_new (CODEC_NCOLUMNS, G_TYPE_STRING,G_TYPE_INT, + G_TYPE_FLOAT, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_POINTER, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_tree_view_set_model(listview,GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", CODEC_NAME, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Rate (Hz)"), + renderer, + "text", CODEC_RATE, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Status"), + renderer, + "text", CODEC_STATUS, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Min bitrate (kbit/s)"), + renderer, + "text", CODEC_BITRATE, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Parameters"), + renderer, + "text", CODEC_PARAMS, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + /* Setup the selection handler */ + select = gtk_tree_view_get_selection (listview); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); +} + +static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codeclist) +{ + const MSList *elem; + GtkTreeIter iter; + GtkListStore *store=GTK_LIST_STORE(gtk_tree_view_get_model(listview)); + GtkTreeSelection *selection; + + gtk_list_store_clear(store); + + for(elem=codeclist; elem!=NULL; elem=elem->next){ + gchar *status; + gint rate; + gfloat bitrate; + gchar *color; + const char *params=""; + struct _PayloadType *pt=(struct _PayloadType *)elem->data; + if (payload_type_enabled(pt)) status=_("Enabled"); + else status=_("Disabled"); + if (linphone_core_check_payload_type_usability(linphone_gtk_get_core(),pt)) color="blue"; + else color="red"; + /* get an iterator */ + gtk_list_store_append(store,&iter); + bitrate=payload_type_get_bitrate(pt)/1000.0; + rate=payload_type_get_rate(pt); + if (pt->recv_fmtp!=NULL) params=pt->recv_fmtp; + gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt), + CODEC_RATE,rate, + CODEC_BITRATE,bitrate, + CODEC_STATUS,status, + CODEC_PARAMS,params, + CODEC_PRIVDATA,(gpointer)pt, + CODEC_COLOR,(gpointer)color, + CODEC_INFO,(gpointer)payload_type_get_description(pt), + -1); + } + + + + /* Setup the selection handler */ + selection = gtk_tree_view_get_selection (listview); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + //gtk_tree_view_columns_autosize(GTK_TREE_VIEW (sec->interfaces)); + gtk_tree_view_set_tooltip_column(listview,CODEC_INFO); +} + +static void linphone_gtk_check_codec_bandwidth(GtkTreeView *v){ + GtkTreeIter iter; + GtkTreeModel *model; + model=gtk_tree_view_get_model(v); + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + PayloadType *pt=NULL; + const gchar *color; + gfloat bitrate; + gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1); + if (linphone_core_check_payload_type_usability(linphone_gtk_get_core(),pt)) color="blue"; + else color="red"; + bitrate=payload_type_get_bitrate(pt)/1000.0; + gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR, (gpointer)color, + CODEC_BITRATE, bitrate,-1); + }while(gtk_tree_model_iter_next(model,&iter)); +} + +static void linphone_gtk_select_codec(GtkTreeView *v, PayloadType *ref){ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + selection=gtk_tree_view_get_selection(v); + model=gtk_tree_view_get_model(v); + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + PayloadType *pt=NULL; + gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1); + if (pt==ref){ + gtk_tree_selection_select_iter(selection,&iter); + } + + }while(gtk_tree_model_iter_next(model,&iter)); +} + +static void linphone_gtk_draw_codec_list(GtkTreeView *v, int type){ /* 0=audio, 1=video*/ + const MSList *list; + if (type==0) list=linphone_core_get_audio_codecs(linphone_gtk_get_core()); + else list=linphone_core_get_video_codecs(linphone_gtk_get_core()); + linphone_gtk_show_codecs(v,list); +} + +void linphone_gtk_codec_view_changed(GtkWidget *w){ + GtkWidget *listview=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"codec_list"); + int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w)); + linphone_gtk_draw_codec_list(GTK_TREE_VIEW(listview),active); +} + +void linphone_gtk_download_bw_changed(GtkWidget *w){ + GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"codec_list")); + linphone_core_set_download_bandwidth(linphone_gtk_get_core(), + (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); + linphone_gtk_check_codec_bandwidth(v); +} + +void linphone_gtk_upload_bw_changed(GtkWidget *w){ + GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"codec_list")); + linphone_core_set_upload_bandwidth(linphone_gtk_get_core(), + (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); + linphone_gtk_check_codec_bandwidth(v); +} + +static void linphone_gtk_codec_move(GtkWidget *button, int dir){ + GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"codec_list")); + GtkTreeSelection *sel=gtk_tree_view_get_selection(v); + GtkTreeModel *mod; + GtkTreeIter iter; + PayloadType *pt=NULL; + LinphoneCore *lc=linphone_gtk_get_core(); + if (gtk_tree_selection_get_selected(sel,&mod,&iter)){ + MSList *sel_elem,*before; + MSList *codec_list; + gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1); + if (pt->type==PAYLOAD_VIDEO) + codec_list=ms_list_copy(linphone_core_get_video_codecs(lc)); + else codec_list=ms_list_copy(linphone_core_get_audio_codecs(lc)); + sel_elem=ms_list_find(codec_list,pt); + if (dir>0) { + if (sel_elem->prev) before=sel_elem->prev; + else before=sel_elem; + codec_list=ms_list_insert(codec_list,before,pt); + } + else{ + if (sel_elem->next) before=sel_elem->next->next; + else before=sel_elem; + codec_list=ms_list_insert(codec_list,before,pt); + } + codec_list=ms_list_remove_link(codec_list,sel_elem); + if (pt->type==PAYLOAD_VIDEO) + linphone_core_set_video_codecs(lc,codec_list); + else linphone_core_set_audio_codecs(lc,codec_list); + linphone_gtk_show_codecs(v,codec_list); + linphone_gtk_select_codec(v,pt); + } +} + +static void linphone_gtk_codec_set_enable(GtkWidget *button, gboolean enabled){ + GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"codec_list")); + GtkTreeSelection *sel=gtk_tree_view_get_selection(v); + GtkTreeModel *mod; + GtkListStore *store; + GtkTreeIter iter; + PayloadType *pt=NULL; + + if (gtk_tree_selection_get_selected(sel,&mod,&iter)){ + store=GTK_LIST_STORE(mod); + gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1); + payload_type_set_enable(pt,enabled); + gtk_list_store_set(store,&iter,CODEC_STATUS, enabled ? _("Enabled") : _("Disabled"), -1); + } +} + +void linphone_gtk_codec_up(GtkWidget *button){ + linphone_gtk_codec_move(button,+1); +} + +void linphone_gtk_codec_down(GtkWidget *button){ + linphone_gtk_codec_move(button,-1); +} + +void linphone_gtk_codec_enable(GtkWidget *button){ + linphone_gtk_codec_set_enable(button,TRUE); +} + +void linphone_gtk_codec_disable(GtkWidget *button){ + linphone_gtk_codec_set_enable(button,FALSE); +} + +void linphone_gtk_clear_passwords(GtkWidget *button){ + linphone_core_clear_all_auth_info(linphone_gtk_get_core()); +} + +enum{ + PROXY_CONFIG_IDENTITY, + PROXY_CONFIG_REF, + PROXY_CONFIG_NCOL +}; + +void linphone_gtk_show_sip_accounts(GtkWidget *w){ + GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"proxy_list")); + GtkTreeModel *model=gtk_tree_view_get_model(v); + GtkListStore *store; + GtkTreeSelection *select; + const MSList *elem; + if (!model){ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + /* create the proxy list */ + store = gtk_list_store_new (PROXY_CONFIG_NCOL, G_TYPE_STRING, G_TYPE_POINTER); + + gtk_tree_view_set_model(v,GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Account"), + renderer, + "text", PROXY_CONFIG_IDENTITY, + NULL); + gtk_tree_view_append_column (v, column); + + select = gtk_tree_view_get_selection (v); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + model=GTK_TREE_MODEL(store); + }else { + store=GTK_LIST_STORE(model); + } + gtk_list_store_clear(store); + for(elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + GtkTreeIter iter; + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,PROXY_CONFIG_IDENTITY,linphone_proxy_config_get_identity(cfg), + PROXY_CONFIG_REF,cfg,-1); + } +} + +static void linphone_gtk_proxy_closed(GtkWidget *w){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); + if (cfg){ + linphone_proxy_config_done(cfg); + } +} + +void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ + GtkWidget *w=linphone_gtk_create_window("sip_account"); + const char *tmp; + if (cfg){ + linphone_proxy_config_edit(cfg); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")), + linphone_proxy_config_get_identity(cfg)); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")), + linphone_proxy_config_get_addr(cfg)); + tmp=linphone_proxy_config_get_route(cfg); + if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")),tmp); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")), + linphone_proxy_config_get_expires(cfg)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")), + linphone_proxy_config_register_enabled(cfg)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")), + linphone_proxy_config_publish_enabled(cfg)); + } + g_object_set_data(G_OBJECT(w),"config",(gpointer)cfg); + g_object_set_data(G_OBJECT(w),"parameters",(gpointer)pb); + g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_proxy_closed,w); + gtk_widget_show(w); +} + +void linphone_gtk_proxy_cancel(GtkButton *button){ + GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); + gtk_widget_destroy(w); +} + +void linphone_gtk_proxy_ok(GtkButton *button){ + GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); + gboolean was_editing=TRUE; + if (!cfg){ + was_editing=FALSE; + cfg=linphone_proxy_config_new(); + } + linphone_proxy_config_set_identity(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")))); + linphone_proxy_config_set_server_addr(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")))); + linphone_proxy_config_set_route(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")))); + linphone_proxy_config_expires(cfg, + (int)gtk_spin_button_get_value( + GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")))); + linphone_proxy_config_enable_publish(cfg, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")))); + linphone_proxy_config_enable_register(cfg, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); + if (was_editing){ + if (linphone_proxy_config_done(cfg)==-1) + return; + } + else { + if (linphone_core_add_proxy_config(linphone_gtk_get_core(),cfg)==-1) return; + linphone_core_set_default_proxy(linphone_gtk_get_core(),cfg); + } + g_object_set_data(G_OBJECT(w),"config",NULL); + linphone_gtk_show_sip_accounts(GTK_WIDGET(g_object_get_data(G_OBJECT(w),"parameters"))); + gtk_widget_destroy(w); + /* also update the main window's list of identities*/ + linphone_gtk_load_identities(); +} + +static LinphoneProxyConfig *linphone_gtk_get_selected_proxy_config(GtkWidget* pb){ + GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(pb,"proxy_list")); + GtkTreeSelection *selection=gtk_tree_view_get_selection(v); + GtkTreeIter iter; + GtkTreeModel *model; + if (gtk_tree_selection_get_selected(selection,&model,&iter)){ + LinphoneProxyConfig *cfg=NULL; + gtk_tree_model_get(model,&iter,PROXY_CONFIG_REF,&cfg,-1); + return cfg; + } + return NULL; +} + +void linphone_gtk_add_proxy(GtkButton *button){ + linphone_gtk_show_proxy_config(gtk_widget_get_toplevel(GTK_WIDGET(button)),NULL); +} + +void linphone_gtk_remove_proxy(GtkButton *button){ + LinphoneProxyConfig *cfg=linphone_gtk_get_selected_proxy_config( + gtk_widget_get_toplevel(GTK_WIDGET(button))); + if (cfg){ + linphone_core_remove_proxy_config(linphone_gtk_get_core(),cfg); + linphone_gtk_show_sip_accounts(gtk_widget_get_toplevel(GTK_WIDGET(button))); + } +} + +void linphone_gtk_edit_proxy(GtkButton *button){ + GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(button)); + LinphoneProxyConfig *cfg=linphone_gtk_get_selected_proxy_config(pb); + if (cfg) + linphone_gtk_show_proxy_config(pb,cfg); +} + +void linphone_gtk_show_parameters(void){ + GtkWidget *pb=linphone_gtk_create_window("parameters"); + LinphoneCore *lc=linphone_gtk_get_core(); + const char **sound_devices=linphone_core_get_sound_devices(lc); + const char *tmp; + osip_from_t *contact; + LinphoneFirewallPolicy pol; + GtkWidget *codec_list=linphone_gtk_get_widget(pb,"codec_list"); + int mtu; + /* NETWORK CONFIG */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ipv6_enabled")), + linphone_core_ipv6_enabled(lc)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_port")), + linphone_core_get_sip_port(lc)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"audio_rtp_port")), + linphone_core_get_audio_port(lc)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_rtp_port")), + linphone_core_get_video_port(lc)); + tmp=linphone_core_get_nat_address(lc); + if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp); + tmp=linphone_core_get_stun_server(lc); + if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"stun_server")),tmp); + pol=linphone_core_get_firewall_policy(lc); + switch(pol){ + case LINPHONE_POLICY_NO_FIREWALL: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"no_nat")),TRUE); + break; + case LINPHONE_POLICY_USE_NAT_ADDRESS: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_nat_address")),TRUE); + break; + case LINPHONE_POLICY_USE_STUN: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE); + break; + } + mtu=linphone_core_get_mtu(lc); + if (mtu<=0){ + gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"mtu"),FALSE); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"mtu")),1500); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"mtu_set")),FALSE); + }else{ + gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"mtu"),TRUE); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"mtu")),mtu); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"mtu_set")),TRUE); + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"dtmf_sipinfo")), + linphone_core_get_use_info_for_dtmf(lc)); + /* MUTIMEDIA CONFIG */ + linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"playback_device"), sound_devices, + linphone_core_get_playback_device(lc)); + linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"ring_device"), sound_devices, + linphone_core_get_ringer_device(lc)); + linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"capture_device"), sound_devices, + linphone_core_get_capture_device(lc)); + linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"webcams"),linphone_core_get_video_devices(lc), + linphone_core_get_video_device(lc)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"echo_cancelation")), + linphone_core_echo_cancelation_enabled(lc)); + + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(linphone_gtk_get_widget(pb,"ring_chooser")), + linphone_core_get_ring(lc)); + /* SIP CONFIG */ + contact=linphone_core_get_primary_contact_parsed(lc); + if (contact){ + if (contact->displayname) + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"displayname")),contact->displayname); + if (contact->url->username) + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username")),contact->url->username); + } + linphone_gtk_show_sip_accounts(pb); + /* CODECS CONFIG */ + linphone_gtk_init_codec_list(GTK_TREE_VIEW(codec_list)); + gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"codec_view")),0); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"download_bw")), + linphone_core_get_download_bandwidth(lc)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"upload_bw")), + linphone_core_get_upload_bandwidth(lc)); + gtk_widget_show(pb); +} diff --git a/linphone/gtk-glade/sip_account.glade b/linphone/gtk-glade/sip_account.glade new file mode 100644 index 000000000..f578f009e --- /dev/null +++ b/linphone/gtk-glade/sip_account.glade @@ -0,0 +1,220 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Linphone - Configure a SIP account + GTK_WIN_POS_CENTER_ON_PARENT + linphone2.png + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 4 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your SIP identity: + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP Proxy address: + + + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + sip: + + + 1 + 2 + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Route (optional): + + + 2 + 3 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 2 + 3 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Registration period (sec): + + + 3 + 4 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3600 0 100000 1 10 10 + + + 1 + 2 + 3 + 4 + + + + + + + True + True + Register at startup + 0 + True + True + + + 1 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Publish presence information + 0 + True + + + False + 2 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Configure a SIP account + True + + + label_item + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok + True + 0 + + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + + 1 + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/gtk-glade/stock_people.png b/linphone/gtk-glade/stock_people.png new file mode 100644 index 000000000..ed2d33b9f Binary files /dev/null and b/linphone/gtk-glade/stock_people.png differ diff --git a/linphone/gtk-glade/support.c b/linphone/gtk-glade/support.c new file mode 100644 index 000000000..618216c24 --- /dev/null +++ b/linphone/gtk-glade/support.c @@ -0,0 +1,103 @@ +#include "linphone.h" + + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/linphone/gtk/.cvsignore b/linphone/gtk/.cvsignore new file mode 100644 index 000000000..ce7656e3e --- /dev/null +++ b/linphone/gtk/.cvsignore @@ -0,0 +1,5 @@ +.deps +.libs +Makefile +Makefile.in +linphone diff --git a/linphone/gtk/GNOME_LinphoneApplet.server.in.in b/linphone/gtk/GNOME_LinphoneApplet.server.in.in new file mode 100644 index 000000000..79920977f --- /dev/null +++ b/linphone/gtk/GNOME_LinphoneApplet.server.in.in @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/gtk/GNOME_LinphoneApplet.xml b/linphone/gtk/GNOME_LinphoneApplet.xml new file mode 100644 index 000000000..9a5350fd2 --- /dev/null +++ b/linphone/gtk/GNOME_LinphoneApplet.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/linphone/gtk/Makefile.am b/linphone/gtk/Makefile.am new file mode 100644 index 000000000..506bcf4e0 --- /dev/null +++ b/linphone/gtk/Makefile.am @@ -0,0 +1,77 @@ +## Process this file with automake to produce Makefile.in + +linphone_common_sources=\ + linphone.c linphone.h \ + gui_utils.c gui_utils.h \ + support.c support.h \ + interface.c interface.h \ + callbacks.c callbacks.h \ + presence.c presence.h \ + propertybox.c propertybox.h \ + addressbook.c addressbook.h \ + friends.c friends.h + + +INCLUDES = \ + -I$(top_srcdir)\ + -I$(top_srcdir)/intl \ + -I$(top_srcdir)/coreapi \ + -I$(top_srcdir)/mediastreamer2/include + +if BUILD_GTK + +bin_PROGRAMS = linphone + +linphone_SOURCES = \ + main.c \ + $(linphone_common_sources) + +linphone_LDADD = $(LIBGTK_LIBS) $(INTLLIBS) \ + $(ORTP_LIBS) \ + $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ + $(top_builddir)/coreapi/liblinphone.la + +endif + +AM_CFLAGS=$(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(IPV6_CFLAGS) \ + $(ORTP_CFLAGS) $(OSIP_CFLAGS) + +@INTLTOOL_SERVER_RULE@ + +if BUILD_GNOME_APPLET + +gnome_appletdir=$(libexecdir) + +gnome_applet_PROGRAMS = linphone_applet + +linphone_applet_SOURCES = \ + $(linphone_common_sources)\ + applet.c + +linphone_applet_CFLAGS=$(AM_CFLAGS) $(GNOME_APPLETS_CFLAGS) -DLINPHONE_APPLET + +linphone_applet_LDADD = \ + $(GNOME_APPLETS_LIBS) \ + $(top_builddir)/coreapi/liblinphone.la \ + $(OSIP_LIBS) + + +serverdir = $(libdir)/bonobo/servers +server_in_files = GNOME_LinphoneApplet.server.in +server_DATA = $(server_in_files:.server.in=.server) + +$(server_in_files): $(server_in_files:.server.in=.server.in.in) + sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ + + +uidir = $(datadir)/gnome-2.0/ui +ui_DATA = GNOME_LinphoneApplet.xml + +endif + +EXTRA_DIST = \ + GNOME_LinphoneApplet.server.in.in \ + applet.c \ + $(ui_DATA) + +DISTCLEANFILES=GNOME_LinphoneApplet.server.in GNOME_LinphoneApplet.server diff --git a/linphone/gtk/addressbook.c b/linphone/gtk/addressbook.c new file mode 100644 index 000000000..edefde3d0 --- /dev/null +++ b/linphone/gtk/addressbook.c @@ -0,0 +1,306 @@ +/*************************************************************************** + addressbook.c - + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include "linphone.h" + +#define get_address_book() (&uiobj->addressbook) +#define get_main_window() (&uiobj->main_window) +#define get_core() (uiobj->core) +#define get_uiobj() (uiobj) + +void fill_address_book(GtkWidget *address_list); + +void ab_destroyed(){ + get_uiobj()->ab=NULL; +} + +void show_address_book(){ + if (get_uiobj()->ab!=NULL){ + gtk_widget_show(get_uiobj()->ab); + }else{ + get_uiobj()->ab=create_and_fill_address_book(); + g_signal_connect(G_OBJECT(get_uiobj()->ab),"destroy",G_CALLBACK(ab_destroyed),NULL); + gtk_widget_show(get_uiobj()->ab); + } +} + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +void contact_draw(GtkWidget *w, LinphoneProxyConfig *cfg){ + GtkWidget *table=lookup_widget(w,"table10"); + GtkWidget *combo; + combo=proxy_combo_box_new(cfg); + gtk_widget_show(combo); + gtk_table_attach(GTK_TABLE(table),combo,1,2,2,3, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + GLADE_HOOKUP_OBJECT(w,combo,"proxy"); + combo=gtk_combo_box_new_text(); + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),_("Wait")); + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),_("Deny")); + gtk_combo_box_append_text(GTK_COMBO_BOX(combo),_("Accept")); + gtk_widget_show(combo); + gtk_table_attach(GTK_TABLE(table),combo,1,2,3,4, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + GLADE_HOOKUP_OBJECT(w,combo,"pol"); +} + +GtkWidget * contact_new(LinphoneFriend *lf, GtkWidget *ab){ + GtkWidget *w=create_contact_box(); + contact_draw(w,NULL); + gtk_widget_show(w); + g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); + g_object_set_data(G_OBJECT(w),"address_book",(gpointer)ab); + g_object_set_data(G_OBJECT(w),"add",GINT_TO_POINTER(TRUE)); + gtk_combo_box_set_active(GTK_COMBO_BOX(lookup_widget(w,"pol")),lf->pol); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"send_subscribe")),lf->subscribe); + return w; +} + +GtkWidget * contact_edit(LinphoneFriend *lf, GtkWidget *ab){ + GtkWidget *w=create_contact_box(); + gchar *tmpstr; + contact_draw(w,lf->proxy); + + g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); + linphone_friend_edit(lf); + tmpstr=linphone_friend_get_name(lf); + if (tmpstr!=NULL) { + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"name")),tmpstr); + g_free(tmpstr); + } + tmpstr=linphone_friend_get_addr(lf); + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"sipaddr")),tmpstr); + g_free(tmpstr); + + gtk_combo_box_set_active(GTK_COMBO_BOX(lookup_widget(w,"pol")),lf->pol); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"send_subscribe")),lf->subscribe); + + gtk_widget_show(w); + if (ab!=NULL) g_object_set_data(G_OBJECT(w),"address_book",(gpointer)ab); + return w; +} + +GtkWidget * subscriber_edit(LinphoneFriend *lf){ + GtkWidget *w=contact_edit(lf,NULL); + g_object_set_data(G_OBJECT(w),"add",GINT_TO_POINTER(TRUE)); + return w; +} + +gint contact_ok(GtkWidget *dialog){ + gchar *name,*sipaddr; + gchar *url; + gboolean add=FALSE; + GtkWidget *ab; + LinphoneFriend *lf; + int err; + lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(dialog),"friend_ref"); + add=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog),"add")); + name=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"name")),0,-1); + sipaddr=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"sipaddr")),0,-1); + url=g_strdup_printf("%s <%s>",name,sipaddr); + /* workaround a bug in osip ? */ + /* something doesn't like addresses like "machin <>" */ + if (strchr(sipaddr,'<')==NULL){ + err=linphone_friend_set_sip_addr(lf,url); + }else err=-1; + if (err<0){ + linphone_gnome_ui_display_something(get_uiobj(),GTK_MESSAGE_WARNING,_("Bad sip address: a sip address looks like sip:user@domain")); + linphone_friend_destroy(lf); + g_free(name); + g_free(sipaddr); + g_free(url); + return -1; + } + g_free(name); + g_free(sipaddr); + g_free(url); + linphone_friend_set_proxy(lf,proxy_combo_box_get_selected(lookup_widget(dialog,"proxy"))); + linphone_friend_set_inc_subscribe_policy(lf,gtk_combo_box_get_active(GTK_COMBO_BOX(lookup_widget(dialog,"pol")))); + linphone_friend_send_subscribe(lf,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog,"send_subscribe")))); + if (add){ + linphone_core_add_friend(get_core(),lf); + } + else linphone_friend_done(lf); + /* ask the address book to redraw itself */ + ab=g_object_get_data(G_OBJECT(dialog),"address_book"); + if (ab!=NULL) fill_address_book(lookup_widget(ab,"address_list")); + return 0; +} + +enum{ + SIP_ADDRESS_COLUMN, + FRIEND_REFERENCE, + AB_NCOLUMNS +}; + +void choose_address_and_close(GtkWidget *ab){ + GtkTreeSelection *select; + GtkWidget *addressentry=get_main_window()->addressentry; + GtkTreeIter iter; + GtkTreeModel *model; + gchar *address=NULL; + GtkWidget *address_list=lookup_widget(ab,"address_list"); + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + if (select==NULL) return; + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,SIP_ADDRESS_COLUMN , &address, -1); + } + if (address!=NULL){ + gtk_entry_set_text (GTK_ENTRY(addressentry),address); + g_free(address); + } + gtk_widget_destroy(ab); +} +void +address_book_close (GtkWidget *object, + gpointer user_data) +{ + gtk_widget_destroy(gtk_widget_get_toplevel(object)); +} + +void address_selection_changed_cb(GtkTreeSelection *selection, gpointer data) +{ + +} +gboolean address_button_press(GtkWidget *widget,GdkEventButton *event,gpointer user_data) +{ + GtkWidget *ab=(GtkWidget*)user_data; + if (event->type==GDK_2BUTTON_PRESS){ + choose_address_and_close(ab); + return TRUE; + } + return FALSE; +} + +void fill_address_book(GtkWidget *address_list){ + GtkListStore *store; + GtkTreeIter iter; + GtkTreeModel *model; + const MSList *elem; + gchar *tmpstr; + /* fill the store */ + elem=linphone_core_get_friend_list(get_core()); + model=gtk_tree_view_get_model(GTK_TREE_VIEW(address_list)); + store=GTK_LIST_STORE(model); + gtk_list_store_clear(store); + for(;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneFriend *lf=(LinphoneFriend*)elem->data; + tmpstr=linphone_friend_get_url(lf); + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,SIP_ADDRESS_COLUMN,tmpstr,FRIEND_REFERENCE,(gpointer)lf,-1); + ms_free(tmpstr); + } +} + +GtkWidget *create_and_fill_address_book(){ + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + GtkWidget *address_list; + GtkWidget *ret=create_address_book(); + + address_list=lookup_widget(ret,"address_list"); + store = gtk_list_store_new (AB_NCOLUMNS, G_TYPE_STRING,G_TYPE_POINTER); + gtk_tree_view_set_model(GTK_TREE_VIEW(address_list),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Contact list"), + renderer, + "text", SIP_ADDRESS_COLUMN, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (address_list), column); + + /* Setup the selection handler */ + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (address_selection_changed_cb), + NULL); + + /* setup handler for double click */ + g_signal_connect(G_OBJECT(address_list),"button-press-event",G_CALLBACK(address_button_press),(gpointer)ret); + + fill_address_book(address_list); + return ret; +} + +void +on_modify_address_clicked (GtkButton *button, + gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *address_list=lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"address_list"); + + /* change the address in the view */ + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + LinphoneFriend *lf=NULL; + gtk_tree_model_get(model,&iter,FRIEND_REFERENCE,&lf,-1); + contact_edit(lf,gtk_widget_get_toplevel(GTK_WIDGET(button))); + } +} + +void on_add_address_clicked(GtkButton *button,gpointer user_data) +{ + LinphoneFriend *lf=linphone_friend_new(); + contact_new(lf,gtk_widget_get_toplevel(GTK_WIDGET(button))); +} + +void on_remove_address_clicked(GtkButton *button,gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *address_list=lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"address_list"); + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (address_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + LinphoneFriend *lf=NULL; + gtk_tree_model_get(model,&iter,FRIEND_REFERENCE,&lf,-1); + linphone_core_remove_friend(get_core(),lf); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + } +} + +void on_select_address_clicked(GtkButton *button,gpointer user_data) +{ + choose_address_and_close(gtk_widget_get_toplevel(GTK_WIDGET(button))); +} + + +void +on_contact_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + switch (response_id){ + case GTK_RESPONSE_OK: + contact_ok(GTK_WIDGET(dialog)); + break; + default: + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); +} diff --git a/linphone/gtk/addressbook.h b/linphone/gtk/addressbook.h new file mode 100644 index 000000000..f5f5431e3 --- /dev/null +++ b/linphone/gtk/addressbook.h @@ -0,0 +1,28 @@ +/*************************************************************************** + addressbook.h - + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef ADDRESSBOOK_H +#define ADDRESSBOOK_H + +GtkWidget *create_and_fill_address_book(); +void show_address_book(); +GtkWidget * contact_new(LinphoneFriend *lf, GtkWidget *ab); +GtkWidget * contact_edit(LinphoneFriend *lf, GtkWidget *ab); +GtkWidget * subscriber_edit(LinphoneFriend *lf); + +#endif diff --git a/linphone/gtk/applet.c b/linphone/gtk/applet.c new file mode 100644 index 000000000..68149e652 --- /dev/null +++ b/linphone/gtk/applet.c @@ -0,0 +1,185 @@ +/*************************************************************************** + applet.c - Applet code for linphone's gnome + interface + ------------------- + begin : Sat Dec 14 2002 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "linphone.h" + +#define get_uiobj() (uiobj) + +LinphoneCore core; +LinphoneGnomeUI ui; +static int show=0; +static gulong signal_ref; +static GtkWidget *applet_button=NULL; +static GdkPixbuf *original_icon=NULL; +static GtkWidget *icon=NULL; + +void draw_icon(GtkWidget *button, int size) +{ + GdkPixbuf *resized; + if (original_icon==NULL){ + original_icon=gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/pixmaps/linphone/linphone2.xpm", + NULL); + g_return_if_fail( original_icon!=NULL); + } + if (icon!=NULL){ + gtk_container_remove(GTK_CONTAINER(button),icon); + gtk_widget_destroy(icon); + } + resized=gdk_pixbuf_scale_simple(original_icon,size,size,GDK_INTERP_BILINEAR); + g_return_if_fail(resized!=NULL); + icon=gtk_image_new_from_pixbuf(resized); + g_return_if_fail(icon!=NULL); + gdk_pixbuf_unref(resized); + gtk_container_add(GTK_CONTAINER(button),icon); + gtk_widget_show(icon); +} + +void linphone_applet_about_cb(gpointer p) +{ + GtkWidget *about2; + about2 = create_about2 (); + gtk_widget_show (about2); +} + + + +static void applet_change_pixel_size(GtkWidget *applet, int size) +{ + g_return_if_fail(applet_button!=NULL); + draw_icon(applet_button,size); +} + +static void applet_destroy_cb(GtkWidget *widget, gpointer data) +{ + if (get_uiobj()->main_window.window!=NULL){ + gtk_widget_destroy(get_uiobj()->main_window.window); + } + linphone_gnome_uninit(get_uiobj()); +} + +static gboolean +gui_destroy_cb (GtkWidget *widget, gpointer data) +{ + linphone_gnome_ui_uninit(get_uiobj()); + show=0; + return FALSE; +} + +static gboolean button_press_cb(GtkWidget *applet, GdkEventButton* event, gpointer data) +{ + if (event->button!=1) return FALSE; + if (show){ + g_signal_handlers_disconnect_by_func(G_OBJECT(get_uiobj()->main_window.window), + G_CALLBACK(gui_destroy_cb),NULL); + linphone_gnome_ui_hide(get_uiobj()); + + show=0; + }else { + linphone_gnome_ui_show(get_uiobj()); + signal_ref=g_signal_connect(G_OBJECT(get_uiobj()->main_window.window), + "destroy", + G_CALLBACK(gui_destroy_cb),NULL); + show=1; + } + return FALSE; +} + +const BonoboUIVerb linphone_applet_menu_verbs [] = { + BONOBO_UI_UNSAFE_VERB ("About", linphone_applet_about_cb), + BONOBO_UI_VERB_END +}; + +static gboolean +linphone_applet_fill (PanelApplet *applet) +{ + gint size=panel_applet_get_size(applet); + + applet_button=gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(applet),applet_button); + gtk_widget_show(applet_button); + + draw_icon(applet_button,size); + + g_signal_connect(G_OBJECT(applet),"button-press-event",G_CALLBACK(button_press_cb),NULL); + + + g_signal_connect(G_OBJECT(applet),"change_size", + G_CALLBACK(applet_change_pixel_size), + NULL); + + + g_signal_connect (G_OBJECT (applet), "destroy", + G_CALLBACK (applet_destroy_cb), NULL); + + //sizehint = panel_applet_get_size (PANEL_APPLET (applet)); + panel_applet_setup_menu_from_file (applet, + NULL, + "GNOME_LinphoneApplet.xml", + NULL, + linphone_applet_menu_verbs, + NULL); + + /* tracing for osip */ + TRACE_INITIALIZE(5,stdout); + + linphone_gnome_init(&ui,&core); + gtk_widget_show_all (GTK_WIDGET (applet)); + + return TRUE; +} + + +static gboolean +linphone_applet_factory (PanelApplet *applet, + const gchar *iid, + gpointer data) +{ + static int instances=0; + GtkWidget *dialog; + if (!strcmp (iid, "OAFIID:GNOME_LinphoneApplet")){ + if (instances>0){ + dialog = gtk_message_dialog_new (GTK_WINDOW(applet), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CLOSE, + (const gchar*) _("Cannot run multiples instances of the linphone applet.")); + /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + gtk_widget_show(GTK_WIDGET(dialog)); + return FALSE; + } + return linphone_applet_fill (applet); + } + return FALSE; +} + +#define GNOMELOCALEDIR PACKAGE_LOCALE_DIR + +PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_LinphoneApplet_Factory", + PANEL_TYPE_APPLET, + "linphone_applet", + "0", + linphone_applet_factory, + NULL) diff --git a/linphone/gtk/callbacks.c b/linphone/gtk/callbacks.c new file mode 100644 index 000000000..78f293db6 --- /dev/null +++ b/linphone/gtk/callbacks.c @@ -0,0 +1,707 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +callbacks.c -- gtk callbacks, and osipua callbacks. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" +#include + +#define get_core() (uiobj->core) +#define get_main_window() (&uiobj->main_window) +#define get_uiobj() (uiobj) + +void +on_about1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *about2; + about2 = create_about2 (); + gtk_widget_show (about2); +} + + +gint +on_prop1_close (GtkDialog *gnomedialog, + gpointer user_data) +{ +#ifdef NOTYET + LinphoneMainWindow *obj=get_main_window(); + gnome_appbar_clear_stack( GNOME_APPBAR(obj->status_bar)); +#endif + + return(FALSE); +} + +void +on_parametres1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + LinphoneGnomeUI *ui=get_uiobj(); + linphone_property_box_init(&ui->propbox); +} + + + +void +on_user_manual1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ +#ifdef NOTYET + gnome_help_display("index.xml",NULL,NULL); +#endif +} + + +gboolean +on_play_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + int vol; + vol=(gtk_range_get_adjustment(GTK_RANGE(widget)))->value; + linphone_core_set_play_level(get_core(),vol); + return FALSE; +} + + +gboolean +on_rec_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + int vol; + vol=(gtk_range_get_adjustment(GTK_RANGE(widget)))->value; + linphone_core_set_rec_level(get_core(),vol); + return FALSE; +} + + +gboolean +on_ring_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + int vol; + vol=(gtk_range_get_adjustment(GTK_RANGE(widget)))->value; + linphone_core_set_ring_level(get_core(),vol); + return FALSE; +} + + +void +on_prop1_help (GtkDialog *gnomepropertybox, + gint arg1, + gpointer user_data) +{ +#ifdef NOTYET + gnome_help_display("index.html",NULL,NULL); +#endif +} + + + + +void +on_fermer1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + linphone_gnome_ui_hide(get_uiobj()); +} + + + +#if 0 +/*this is when the panel size changes*/ +void applet_change_pixel_size(GtkWidget *w, int size, gpointer data) +{ + GtkWidget *pixmap,*button; + + pixmap=gtk_object_get_data(GTK_OBJECT(applet),"applet_pixmap"); + button=(GtkWidget*)gtk_object_get_data(GTK_OBJECT(applet),"applet_button"); + if (button==NULL) + { + printf("Cannot find applet button\n"); + return; + } + if (pixmap!=NULL) gtk_widget_destroy(pixmap); + pixmap = gnome_pixmap_new_from_xpm_d_at_size(linphone2_xpm, + size-4, size-4); + gtk_object_set_data(GTK_OBJECT(applet),"applet_pixmap",pixmap); + gtk_widget_show(pixmap); + gtk_container_add(GTK_CONTAINER(button), pixmap); +} +#endif + +void +on_adresse_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + show_address_book(); +} + +void on_address_book_show(GtkWidget *widget,gpointer user_data) +{ + +} + + + +void +on_showmore_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + gint state; + GtkWidget *optioncontrols=get_main_window()->optioncontrols; + state=gtk_toggle_button_get_active(togglebutton); + if (state) gtk_widget_show(optioncontrols); + else { + gtk_widget_hide(optioncontrols); + } +} + + +void +on_useRPC_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ +#ifdef VINCENT_MAURY_RSVP + LinphoneCore *lc=get_core(); + gboolean state; + state=gtk_toggle_button_get_active(togglebutton); + /* change RPC settings according to state */ + if (state) + { + if (linphone_core_set_rpc_mode(lc,1)!=0) /* set rpc on */ + { + printf("RPC error. unable to set rpc on !\n"); + printf("Check to see if RPC server is running\n"); + gtk_toggle_button_set_active(togglebutton,FALSE); + /*linphone_core_set_rpc_mode(lc,0);*/ + } + } + else + { + if (linphone_core_set_rpc_mode(lc,0)!=0) /* set rpc off */ + printf("RPC error. That's impossible !!\n"); + } +#endif +} + +void +on_useRSVP_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ +#ifdef VINCENT_MAURY_RSVP + LinphoneCore *lc=get_core(); + LinphoneGnomeUI *ui=get_uiobj(); + gboolean state; + state=gtk_toggle_button_get_active(togglebutton); + /* change the QoS settings function of the state */ + if (state) + { + linphone_core_set_rsvp_mode(lc,1); /* set RSVP on */ + gtk_widget_show(lookup_widget(ui->propbox.prop,"useRPC")); /* show RPC checkbox */ + } + else + { + linphone_core_set_rsvp_mode(lc,0); /* set RSVP off */ + /* uncheck RPC if necessary and hide RPC checkbox */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( + lookup_widget(ui->propbox.prop,"useRPC")),FALSE); + gtk_widget_hide(lookup_widget(ui->propbox.prop,"useRPC")); + } +#endif +} + +#ifdef VINCENT_MAURY_RSVP +/* callback called when you click the yes/no dialog box + * send yes or no to the core_change_qos which knows the question + * and will be able to ajust qos */ +void dialog_click (GtkDialog *dialog,gint arg1,gpointer user_data) +{ + LinphoneCore *lc=get_core(); + if (lc->call==NULL) + return; + + if (arg1==GTK_RESPONSE_YES) + { + printf("YES\n"); + linphone_core_change_qos(lc, 1); /* 1 = yes */ + } + else + { + printf("NO\n"); + linphone_core_change_qos(lc, 0); /* 0 = no */ + } + gtk_widget_destroy((GtkWidget*)dialog); +} +#endif + + +void +on_alt_href_clicked (GtkButton *button, + gpointer user_data) +{ +#ifdef NOTYET + gchar *url; + GtkWidget *label; + osip_from_t * from; + LinphoneGnomeUI *ui=get_uiobj(); + label=GTK_BIN(button)->child; + gtk_label_get(GTK_LABEL(label),&url); + osip_from_init(&from); + if ( osip_from_parse(from,url) <0){ + /* do something here */ + }else + { /* it was a sip url, so display it in the entry*/ + gtk_entry_set_text(GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(ui->main_window.addressentry))),url); + } + osip_from_free(from); +#endif +} + +void +on_alt_href_realize (GtkWidget *widget, + gpointer user_data) +{ + GdkCursor *cursor = gdk_cursor_new(GDK_HAND2); + gdk_window_set_cursor(widget->window, cursor); + gdk_cursor_destroy(cursor); +} + + +void +on_dtmf_3_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"3"); +} + + +void +on_dmtf_2_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"2"); +} + + +void +on_dtmf_1_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"1"); +} + + +void +on_dtmf_4_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"4"); +} + + +void +on_dtmf_5_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"5"); +} + + +void +on_dtmf_6_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"6"); +} + + +void +on_dtmf_7_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"7"); +} + + +void +on_dtmf_8_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"8"); + +} + + +void +on_dtmf_9_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"9"); + +} + + +void +on_dtmf_star_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"*"); + +} + + +void +on_dtmf_0_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"0"); + +} + + +void +on_dtmf_pound_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *dtmf_entry=get_main_window()->dtmfentry; + gtk_entry_append_text(GTK_ENTRY(dtmf_entry),"#"); + +} + + +void +on_dtmf_entry_changed (GtkEditable *editable, + gpointer user_data) +{ + gchar *dtmfs; + gint len; + /* get the last entry in the text box and plays it */ + dtmfs=gtk_editable_get_chars(editable,0,-1); + g_return_if_fail(dtmfs!=NULL); + len=strlen(dtmfs); + if (len>0){ + g_message("Sending dtmf %c",dtmfs[len-1]); + linphone_core_send_dtmf(get_uiobj()->core,dtmfs[len-1]); + } + g_free(dtmfs); +} + + +void +on_exit1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ +#ifdef LINPHONE_APPLET +#else + gtk_widget_destroy(get_uiobj()->main_window.window); +#endif +} + + +void on_app1_destroy(GtkWidget *app1, gpointer user_data) +{ +#ifdef LINPHONE_APPLET +#else + gtk_main_quit(); +#endif +} + +void +on_display_ab_clicked (GtkButton *button, + gpointer user_data) +{ + show_address_book(); +} + + +void +on_inc_subscr_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(dialog),"friend_ref"); + switch(response_id){ + case GTK_RESPONSE_ACCEPT: + subscriber_edit(lf); + break; + case GTK_RESPONSE_REJECT: + linphone_core_reject_subscriber(get_core(),lf); + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +void authentication_dialog_ok(GtkWidget *w) +{ + gchar *realm,*username,*userid,*passwd; + LinphoneAuthInfo *info; + realm=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"realm")),0,-1); + username=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"username")),0,-1); + userid=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"userid")),0,-1); + passwd=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(w,"passwd")),0,-1); + info=linphone_auth_info_new(username,userid,passwd,NULL,realm); + linphone_core_add_auth_info(get_core(),info); + g_free(username); + g_free(userid); + g_free(passwd); + g_free(realm); +} + +void +on_authentication_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + switch(response_id){ + case GTK_RESPONSE_OK: + authentication_dialog_ok(GTK_WIDGET(dialog)); + gtk_widget_destroy(GTK_WIDGET(dialog)); + break; + case GTK_RESPONSE_CANCEL: + gtk_widget_destroy(GTK_WIDGET(dialog)); + } +} + +void +on_clear_auth_info_clicked (GtkButton *button, + gpointer user_data) +{ + linphone_core_clear_all_auth_info(get_core()); +} + + +void +on_call_history_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + linphone_gnome_show_call_logs_window(get_uiobj()); +} + + +void +on_call_logs_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + + +void +on_call_logs_destroy (GtkObject *object, + gpointer user_data) +{ + get_uiobj()->logs=NULL; +} + + +static void completion_add_text(GtkEntry *entry, const char *text){ + GtkTreeIter iter; + GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry)); + + if (gtk_tree_model_get_iter_first(model,&iter)){ + do { + gchar *uri=NULL; + gtk_tree_model_get(model,&iter,0,&uri,-1); + if (uri!=NULL){ + if (strcmp(uri,text)==0) { + /*remove text */ + gtk_list_store_remove(GTK_LIST_STORE(model),&iter); + g_free(uri); + break; + } + g_free(uri); + } + }while (gtk_tree_model_iter_next(model,&iter)); + } + /* and prepend it on top of the list */ + gtk_list_store_prepend(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1); +} + + +void +on_callbutton_clicked (GtkButton *button, + gpointer user_data) +{ + LinphoneGnomeUI *ui=get_uiobj(); + LinphoneCore *lc=get_core(); + GtkEntry *entry=GTK_ENTRY(ui->main_window.addressentry); + + if (lc->call==NULL){ + const gchar *sipurl=NULL; + int err; + /* we have no dialog in progress */ + /* get the url to call */ + sipurl=gtk_entry_get_text(entry); + err=linphone_core_invite(lc,sipurl); + if (err==0) completion_add_text(entry,sipurl); + }else { + linphone_core_accept_call(lc,NULL); + gdk_window_set_keep_above (ui->main_window.window->window, 0); + } +} + +void +on_hangup_clicked (GtkButton *button, + gpointer user_data) +{ + LinphoneGnomeUI *ui=get_uiobj(); + LinphoneCore *lc=get_core(); + gdk_window_set_keep_above (ui->main_window.window->window, 0); + if (lc->call!=NULL){ + gtk_window_set_title(GTK_WINDOW(ui->main_window.window),"linphone"); + linphone_core_terminate_call(lc,NULL); + } +} + +GtkWidget *chatroom_new(const gchar *url, LinphoneChatRoom *cr){ + GtkWidget *gcr=NULL; + if (cr==NULL) + cr=linphone_core_create_chat_room(get_core(),url); + if (cr!=NULL){ + gchar *tmp; + gcr=create_chatroom(); + g_object_set_data(G_OBJECT(gcr),"chatroom",(gpointer)cr); + linphone_chat_room_set_user_data(cr,(gpointer)gcr); + tmp=g_strdup_printf(_("Chat with %s"),url); + gtk_window_set_title(GTK_WINDOW(gcr),tmp); + g_free(tmp); + } + return gcr; +} + +void chatroom_append(GtkWidget *gcr, const gchar *from, const gchar *message){ + GtkTextBuffer *tb; + gchar *str; + GtkTextIter enditer; + GtkTextView *tv=GTK_TEXT_VIEW(lookup_widget(gcr,"chattext")); + tb=gtk_text_view_get_buffer(tv); + g_return_if_fail(tb!=NULL); + gtk_text_buffer_get_end_iter(tb,&enditer); + str=g_strdup_printf("[%s]\t:%s\n",from,message); + gtk_text_buffer_insert(tb,&enditer,str,strlen(str)); + g_free(str); +} + +void chatroom_close(GtkWidget *gcr){ + LinphoneChatRoom *cr; + cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(gcr),"chatroom"); + linphone_chat_room_destroy(cr); +} + + +void +on_chat_clicked (GtkButton *button, + gpointer user_data) +{ + gchar *sipurl; + + sipurl=gtk_editable_get_chars(GTK_EDITABLE(get_main_window()->addressentry),0,-1); + GtkWidget *gcr=chatroom_new(sipurl,NULL); + if (gcr!=NULL) gtk_widget_show(gcr); + g_free(sipurl); +} + + +void +on_chatbox_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_widget_destroy(gtk_widget_get_toplevel(GTK_WIDGET(button))); +} + + + +void +on_chatentry_activate (GtkEntry *entry, + gpointer user_data) +{ + LinphoneChatRoom *cr; + gchar *text; + text=gtk_editable_get_chars(GTK_EDITABLE(entry),0,-1); + if (strlen(text)>0){ + GtkWidget *gcr=gtk_widget_get_toplevel(GTK_WIDGET(entry)); + cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(gcr),"chatroom"); + linphone_chat_room_send_message(cr,text); + chatroom_append(gcr,linphone_core_get_primary_contact(get_core()),text); + gtk_editable_delete_text(GTK_EDITABLE(entry),0,-1); + } +} + +void +on_chatroom_destroy (GtkObject *object, + gpointer user_data) +{ + chatroom_close(GTK_WIDGET(object)); +} + + + +void +on_addressentry_activate (GtkEntry *entry, + gpointer user_data) +{ + on_callbutton_clicked(NULL,NULL); +} + +void +on_addressentry_destroy (GtkObject *object, + gpointer user_data) +{ + linphone_gnome_save_uri_history(get_uiobj()); +} + +void +on_video_enabled_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + bool_t enabled=gtk_toggle_button_get_active(togglebutton); + linphone_core_enable_video(get_core(),enabled,enabled); +} + + +void +on_echocancelation_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + linphone_core_enable_echo_cancelation(get_core(), + gtk_toggle_button_get_active(togglebutton)); +} + + + + diff --git a/linphone/gtk/callbacks.h b/linphone/gtk/callbacks.h new file mode 100644 index 000000000..505539c47 --- /dev/null +++ b/linphone/gtk/callbacks.h @@ -0,0 +1,545 @@ +#include + + +void +on_app1_destroy (GtkObject *object, + gpointer user_data); + +void +on_adresse_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_parametres1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_fermer1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_exit1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_about1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_user_manual1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_greenbutton_clicked (GtkButton *button, + gpointer user_data); + +void +on_redbutton_clicked (GtkButton *button, + gpointer user_data); + +void +on_showmore_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +gboolean +on_play_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +gboolean +on_rec_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +gboolean +on_ring_vol_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +void +on_reachable (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_busy (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_minutesaway_changed (GtkEditable *editable, + gpointer user_data); + +void +on_away (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_do_not_disturb (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_moved_tmply (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_alt_serv (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_contact_field_changed (GtkEditable *editable, + gpointer user_data); + +void +on_presence_validate_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_entry_changed (GtkEditable *editable, + gpointer user_data); + +void +on_dtmf_3_clicked (GtkButton *button, + gpointer user_data); + +void +on_dmtf_2_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_1_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_4_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_5_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_6_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_7_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_8_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_9_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_star_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_0_clicked (GtkButton *button, + gpointer user_data); + +void +on_dtmf_pound_clicked (GtkButton *button, + gpointer user_data); + +void +on_propertybox1_apply (GtkDialog *propertybox, + gint page_num, + gpointer user_data); + +void +on_property_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +gboolean +on_prop1_close (GtkDialog *gnomedialog, + gpointer user_data); + +void +on_prop1_help (GtkDialog *propertybox, + gint page_num, + gpointer user_data); + +gboolean +on_hscale1_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +void +on_audioport_changed (GtkEditable *editable, + gpointer user_data); + +void +on_sipport_changed (GtkEditable *editable, + gpointer user_data); + +void +on_user_name_changed (GtkEditable *editable, + gpointer user_data); + +void +on_domain_name_changed (GtkEditable *editable, + gpointer user_data); + +void +on_registrar_checked_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_rsvp_checked_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + + +void +on_redirect_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_proxy_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_obproxy_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_registrar_addr_changed (GtkEditable *editable, + gpointer user_data); + +void +on_reg_passwd_changed (GtkEditable *editable, + gpointer user_data); + +void +on_address_of_record_changed (GtkEditable *editable, + gpointer user_data); + +void +on_aucodec_up_clicked (GtkButton *button, + gpointer user_data); + +void +on_aucodec_down_clicked (GtkButton *button, + gpointer user_data); + +void +on_aucodec_enable_clicked (GtkButton *button, + gpointer user_data); + +void +on_aucodec_disable_clicked (GtkButton *button, + gpointer user_data); + +void +on_sounddriver_changed (GtkEditable *editable, + gpointer user_data); + +void +on_source_changed (GtkEditable *editable, + gpointer user_data); + +void +on_autokill_button1_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_address_book_show (GtkWidget *widget, + gpointer user_data); + +void +on_add_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_remove_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_select_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_modify_address_clicked (GtkButton *button, + gpointer user_data); + +void +on_alt_href_clicked (GtkButton *button, + gpointer user_data); + +void +on_alt_href_realize (GtkWidget *widget, + gpointer user_data); + + +void +on_exit1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +address_book_close (GtkButton *button, + gpointer user_data); + +void +on_card_changed (GtkEditable *editable, + gpointer user_data); + +void +on_audio_jittcomp_value_changed (GtkRange *range, + gpointer user_data); + +void +on_enable_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_nat_address_changed (GtkEditable *editable, + gpointer user_data); + +void +on_display_ab_clicked (GtkButton *button, + gpointer user_data); + +void +on_ringfileentry_changed (GtkEditable *editable, + gpointer user_data); + +void +on_ringpreview_clicked (GtkButton *button, + gpointer user_data); + +gboolean +on_property_box_closed (GtkDialog *gnomedialog, + gpointer user_data); + +void +on_address_book_close (GtkObject *object, + gpointer user_data); + +#ifndef VERSION +# define VERSION LINPHONE_VERSION +#endif + +void +on_addfriend_clicked (GtkButton *button, + gpointer user_data); + +void +on_removefriend_clicked (GtkButton *button, + gpointer user_data); + +void +on_add_adbk_clicked (GtkButton *button, + gpointer user_data); + +void +on_addfriend_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_friendlist_row_activated (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data); +void +on_useRSVP_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_useRPC_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +#ifdef VINCENT_MAURY_RSVP +void +dialog_click (GtkDialog *dialog, + gint arg1, + gpointer user_data); +#endif + +void +on_proxy_config_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_removeproxy_button_clicked (GtkButton *button, + gpointer user_data); + +void +on_addproxy_button_clicked (GtkButton *button, + gpointer user_data); + +void +on_editproxy_button_clicked (GtkButton *button, + gpointer user_data); + + +void +on_contact_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_inc_subscr_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_ob_proxy_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_authentication_dialog_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_clear_auth_info_clicked (GtkButton *button, + gpointer user_data); + +void +on_use_sipinfo_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_guess_hostname_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_call_history_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_call_logs_response (GtkDialog *dialog, + gint response_id, + gpointer user_data); + +void +on_call_logs_destroy (GtkObject *object, + gpointer user_data); + +void +on_enable_ipv6_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_play_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_capt_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_ring_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_callbutton_clicked (GtkButton *button, + gpointer user_data); + +void +on_chatbox_clicked (GtkButton *button, + gpointer user_data); + +void +on_chatentry_activate (GtkEntry *entry, + gpointer user_data); + +void +on_hangup_clicked (GtkButton *button, + gpointer user_data); + +void +on_chat_clicked (GtkButton *button, + gpointer user_data); + +void +on_chatroom_destroy (GtkObject *object, + gpointer user_data); + +void +on_ring_card_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_addressentry_editing_done (GtkCellEditable *celleditable, + gpointer user_data); + +void +on_addressentry_destroy (GtkObject *object, + gpointer user_data); + +gboolean +on_addressentry_key_pressed (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); + +void +on_addressentry_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_addressentry_activate (GtkEntry *entry, + gpointer user_data); + +void +on_addressentry_destroy (GtkObject *object, + gpointer user_data); + +void +on_download_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data); + +void +on_download_bw_editing_done (GtkCellEditable *celleditable, + gpointer user_data); + +void +on_download_bw_changed (GtkEditable *editable, + gpointer user_data); + +gboolean +on_upload_bw_output (GtkSpinButton *spinbutton, + gpointer user_data); + +void +on_upload_bw_change_value (GtkSpinButton *spinbutton, + GtkScrollType scroll, + gpointer user_data); + +void +on_upload_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data); + +gboolean +on_upload_bw_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer user_data); + +void +on_video_enabled_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_echocancelation_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_no_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_use_stun_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_static_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_stun_server_changed (GtkEditable *editable, + gpointer user_data); diff --git a/linphone/gtk/friends.c b/linphone/gtk/friends.c new file mode 100644 index 000000000..d4da7828e --- /dev/null +++ b/linphone/gtk/friends.c @@ -0,0 +1,127 @@ +/*************************************************************************** + friends.c - display of friend's list + + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "linphone.h" + + +#define get_friend_list() (&uiobj->main_window.friendlist) +#define get_core() (uiobj->core) +#define get_main_window() (&uiobj->main_window) + +enum{ + FRIEND_PRESENCE_IMG, + FRIEND_SIP_ADDRESS, + FRIEND_PRESENCE_STATUS, + FRIEND_ID, + FRIEND_LIST_NCOL +}; + +void friend_list_set_friend_status(FriendList *fl, LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ + GtkTreeIter iter; + LinphoneFriend *tmp=0; + gboolean found=FALSE; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(fl->friendlist)); + if (gtk_tree_model_get_iter_first(model,&iter)) { + do{ + gtk_tree_model_get(model,&iter,FRIEND_ID,&tmp,-1); + //printf("tmp=%i, fid=%i",tmp,fid); + if (fid==tmp) { + GdkPixbuf *pixbuf; + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_STATUS,status,-1); + pixbuf = create_pixbuf(img); + if (pixbuf) + { + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); + } + found=TRUE; + } + }while(gtk_tree_model_iter_next(model,&iter)); + } + if (found==FALSE){ + //printf("Adding new notifier\n"); + GdkPixbuf *pixbuf; + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_SIP_ADDRESS, url, FRIEND_PRESENCE_STATUS,status,FRIEND_ID,fid,-1); + pixbuf = create_pixbuf(img); + if (pixbuf) gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); + } +} + + +void +on_friendlist_row_activated (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + gchar* friend; + select = gtk_tree_view_get_selection (treeview); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,FRIEND_SIP_ADDRESS , &friend, -1); + gtk_entry_set_text(GTK_ENTRY(get_main_window()->addressentry),friend); + g_free(friend); + } +} + +void friend_list_init(FriendList *fl,LinphoneCore *lc,GtkWidget *mainwidget) +{ + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + + + store = gtk_list_store_new (FRIEND_LIST_NCOL, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); + fl->lc=lc; + fl->friendlist=lookup_widget(mainwidget,"friendlist"); + /* need to add friends to the store here ...*/ + + gtk_tree_view_set_model(GTK_TREE_VIEW(fl->friendlist),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "pixbuf", FRIEND_PRESENCE_IMG, + NULL); + gtk_tree_view_column_set_min_width (column, 29); + gtk_tree_view_append_column (GTK_TREE_VIEW (fl->friendlist), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", FRIEND_SIP_ADDRESS, + NULL); + g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (fl->friendlist), column); + + column = gtk_tree_view_column_new_with_attributes (_("Presence status"), + renderer, + "text", FRIEND_PRESENCE_STATUS, + NULL); + g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (fl->friendlist), column); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (fl->friendlist)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + +} diff --git a/linphone/gtk/friends.h b/linphone/gtk/friends.h new file mode 100644 index 000000000..02bf65cb0 --- /dev/null +++ b/linphone/gtk/friends.h @@ -0,0 +1,29 @@ +/*************************************************************************** + friends.h - display of friend's list + + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include + +struct _FriendList { + LinphoneCore *lc; + GtkWidget *friendlist; +}; + +typedef struct _FriendList FriendList; + +void friend_list_init(FriendList *fl,LinphoneCore *lc,GtkWidget *mainwidget); +void friend_list_set_friend_status(FriendList *fl, LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img); diff --git a/linphone/gtk/gui_utils.c b/linphone/gtk/gui_utils.c new file mode 100644 index 000000000..f58390bc2 --- /dev/null +++ b/linphone/gtk/gui_utils.c @@ -0,0 +1,102 @@ +/* +applet.c - some utils functions that cannot be set in interface.c. + +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "linphone.h" + + +/* creates the applet button* +GtkWidget *create_applet() +{ + GtkWidget *frame; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *applet; + + applet = applet_widget_new("linphone_applet"); + + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_show(frame); + + vbox = gtk_vbox_new(FALSE, FALSE); + gtk_container_add(GTK_CONTAINER(frame), vbox); + gtk_widget_show(vbox); + + button = gtk_button_new(); + gtk_widget_ref(button); + GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_DEFAULT); + GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, TRUE, 0); + + + gtk_widget_show(button); + applet_widget_add (APPLET_WIDGET (applet), frame); + gtk_object_set_data_full(GTK_OBJECT(applet),"applet_button",button,(GtkDestroyNotify)gtk_widget_unref); + gtk_signal_connect(GTK_OBJECT(button), "button_press_event", + GTK_SIGNAL_FUNC(on_applet_clicked), NULL); + gtk_signal_connect(GTK_OBJECT(applet), "change_pixel_size", + GTK_SIGNAL_FUNC(applet_change_pixel_size), NULL); + applet_widget_set_tooltip( APPLET_WIDGET (applet),_("linphone")); + gtk_widget_show(applet); + return(applet); +}; + +*/ +/* this just sets level adjustements for startup*/ +void set_levels(LinphoneGnomeUI *ui,gint reclev, gint playlev, gint ringlev) +{ + GtkWidget *range; + GtkWidget *window=ui->main_window.window; + return; + if (window) + { + range=lookup_widget(window,"rec_vol"); + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(range)),(gfloat)reclev); + range=lookup_widget(window,"play_vol"); + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(range)),(gfloat)playlev); + range=lookup_widget(window,"ring_vol"); + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(range)),(gfloat)ringlev); + } +} + + +void alt_ressource_display(LinphoneGnomeUI *ui,const gchar *url) +{ + GtkWidget *href; + GtkWidget *altdisplay; + GtkLabel *label; + gchar *pattern; + + altdisplay=create_altressource(); + g_object_set_data(G_OBJECT(altdisplay),"ui",(gpointer)ui); + href=lookup_widget(altdisplay,"alt_href"); + label=GTK_LABEL(GTK_BIN(href)->child); + gtk_label_set_text(label,url); + /* pattern used to set underline for string */ + pattern = g_strnfill(strlen(url), '_'); + gtk_label_set_pattern(label,pattern); + g_free(pattern); + gtk_widget_show(altdisplay); +} + + + + diff --git a/linphone/gtk/gui_utils.h b/linphone/gtk/gui_utils.h new file mode 100644 index 000000000..426de9c3d --- /dev/null +++ b/linphone/gtk/gui_utils.h @@ -0,0 +1,33 @@ +/* +applet.h - ome utils functions that cannot be set in interface.c. + +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef GUI_UTILS_H +#define GUI_UTILS_H + +#include "linphone.h" + +/* set audio levels on the main window*/ +void set_levels(LinphoneGnomeUI *ui,gint reclev, gint playlev, gint ringlev); + +/* display an alternate url (used in 380 response) */ +void alt_ressource_display(LinphoneGnomeUI *ui, const gchar *url); + +#endif + diff --git a/linphone/gtk/interface.c b/linphone/gtk/interface.c new file mode 100644 index 000000000..ced4cbeb6 --- /dev/null +++ b/linphone/gtk/interface.c @@ -0,0 +1,3045 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_app1 (void) +{ + GtkWidget *app1; + GdkPixbuf *app1_icon_pixbuf; + GtkWidget *dock1; + GtkWidget *menubar1; + GtkWidget *connexion1; + GtkWidget *connexion1_menu; + GtkWidget *addresse1; + GtkWidget *image39; + GtkWidget *parametres1; + GtkWidget *call_history; + GtkWidget *image40; + GtkWidget *separator1; + GtkWidget *exit1; + GtkWidget *image41; + GtkWidget *help1; + GtkWidget *help1_menu; + GtkWidget *about1; + GtkWidget *user_manual1; + GtkWidget *frame6; + GtkWidget *vbox4; + GtkWidget *vbox24; + GtkWidget *hbox15; + GtkWidget *frame7; + GtkWidget *addressentry; + GtkWidget *label1; + GtkWidget *display_ab; + GtkWidget *alignment22; + GtkWidget *hbox36; + GtkWidget *image33; + GtkWidget *label108; + GtkWidget *proxy_hbox; + GtkWidget *proxytouse_label; + GtkWidget *hbox2; + GtkWidget *callbutton; + GtkWidget *button14; + GtkWidget *button18; + GtkWidget *showmore; + GtkWidget *alignment5; + GtkWidget *hbox17; + GtkWidget *image12; + GtkWidget *label60; + GtkWidget *optioncontrols; + GtkWidget *vbox31; + GtkWidget *frame8; + GtkWidget *vbox5; + GtkWidget *label30; + GtkWidget *play_vol; + GtkWidget *label31; + GtkWidget *rec_vol; + GtkWidget *label110; + GtkWidget *ring_vol; + GtkWidget *label113; + GtkWidget *frame27; + GtkWidget *alignment23; + GtkWidget *vbox32; + GtkWidget *video_enabled; + GtkWidget *label114; + GtkWidget *label33; + GtkWidget *vbox6; + GtkWidget *presence_frame; + GtkWidget *presence_vbox; + GtkWidget *presence_reachable; + GSList *presence_reachable_group = NULL; + GtkWidget *hbox4; + GtkWidget *radiobutton2; + GtkWidget *minutesaway; + GtkWidget *label35; + GtkWidget *radiobutton3; + GtkWidget *radiobutton4; + GtkWidget *radiobutton5; + GtkWidget *radiobutton6; + GtkWidget *hbox5; + GtkWidget *label36; + GtkWidget *contact_field; + GtkWidget *label34; + GtkWidget *frame19; + GtkWidget *vbox18; + GtkWidget *dtmf_entry; + GtkWidget *table5; + GtkWidget *dtmf_3; + GtkWidget *dmtf_2; + GtkWidget *dtmf_1; + GtkWidget *dtmf_4; + GtkWidget *dtmf_5; + GtkWidget *dtmf_6; + GtkWidget *dtmf_7; + GtkWidget *dtmf_8; + GtkWidget *dtmf_9; + GtkWidget *dtmf_star; + GtkWidget *dtmf_0; + GtkWidget *dtmf_pound; + GtkWidget *label38; + GtkWidget *vbox22; + GtkWidget *scrolledwindow3; + GtkWidget *friendlist; + GtkWidget *label65; + GtkWidget *appbarframe1; + GtkWidget *appbar1; + GtkAccelGroup *accel_group; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + accel_group = gtk_accel_group_new (); + + app1 = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (app1), _("linphone")); + gtk_window_set_resizable (GTK_WINDOW (app1), FALSE); + app1_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (app1_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (app1), app1_icon_pixbuf); + gdk_pixbuf_unref (app1_icon_pixbuf); + } + + dock1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (dock1); + gtk_container_add (GTK_CONTAINER (app1), dock1); + + menubar1 = gtk_menu_bar_new (); + gtk_widget_show (menubar1); + gtk_box_pack_start (GTK_BOX (dock1), menubar1, TRUE, TRUE, 0); + + connexion1 = gtk_menu_item_new_with_mnemonic (_("Go")); + gtk_widget_show (connexion1); + gtk_container_add (GTK_CONTAINER (menubar1), connexion1); + + connexion1_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (connexion1), connexion1_menu); + + addresse1 = gtk_image_menu_item_new_with_mnemonic (_("Address book")); + gtk_widget_show (addresse1); + gtk_container_add (GTK_CONTAINER (connexion1_menu), addresse1); + + image39 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU); + gtk_widget_show (image39); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (addresse1), image39); + + parametres1 = gtk_image_menu_item_new_from_stock ("gtk-preferences", accel_group); + gtk_widget_show (parametres1); + gtk_container_add (GTK_CONTAINER (connexion1_menu), parametres1); + + call_history = gtk_image_menu_item_new_with_mnemonic (_("Call history")); + gtk_widget_show (call_history); + gtk_container_add (GTK_CONTAINER (connexion1_menu), call_history); + gtk_tooltips_set_tip (tooltips, call_history, _("Shows calls"), NULL); + + image40 = gtk_image_new_from_stock ("gtk-justify-fill", GTK_ICON_SIZE_MENU); + gtk_widget_show (image40); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (call_history), image40); + + separator1 = gtk_separator_menu_item_new (); + gtk_widget_show (separator1); + gtk_container_add (GTK_CONTAINER (connexion1_menu), separator1); + gtk_widget_set_sensitive (separator1, FALSE); + + exit1 = gtk_image_menu_item_new_with_mnemonic (_("Exit")); + gtk_widget_show (exit1); + gtk_container_add (GTK_CONTAINER (connexion1_menu), exit1); + + image41 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU); + gtk_widget_show (image41); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (exit1), image41); + + help1 = gtk_menu_item_new_with_mnemonic (_("Help")); + gtk_widget_show (help1); + gtk_container_add (GTK_CONTAINER (menubar1), help1); + + help1_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (help1), help1_menu); + + about1 = gtk_image_menu_item_new_from_stock ("gtk-about", accel_group); + gtk_widget_show (about1); + gtk_container_add (GTK_CONTAINER (help1_menu), about1); + + user_manual1 = gtk_image_menu_item_new_from_stock ("gtk-help", accel_group); + gtk_widget_show (user_manual1); + gtk_container_add (GTK_CONTAINER (help1_menu), user_manual1); + + frame6 = gtk_frame_new (NULL); + gtk_widget_show (frame6); + gtk_box_pack_start (GTK_BOX (dock1), frame6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame6), 9); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_container_add (GTK_CONTAINER (frame6), vbox4); + + vbox24 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox24); + gtk_box_pack_start (GTK_BOX (vbox4), vbox24, TRUE, TRUE, 0); + + hbox15 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox15); + gtk_box_pack_start (GTK_BOX (vbox24), hbox15, TRUE, TRUE, 0); + + frame7 = gtk_frame_new (NULL); + gtk_widget_show (frame7); + gtk_box_pack_start (GTK_BOX (hbox15), frame7, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame7), 5); + + addressentry = gtk_entry_new (); + gtk_widget_show (addressentry); + gtk_container_add (GTK_CONTAINER (frame7), addressentry); + gtk_tooltips_set_tip (tooltips, addressentry, _("Enter sip address or phone number here"), NULL); + gtk_entry_set_text (GTK_ENTRY (addressentry), _("sip:")); + + label1 = gtk_label_new (_("Sip address:")); + gtk_widget_show (label1); + gtk_frame_set_label_widget (GTK_FRAME (frame7), label1); + + display_ab = gtk_button_new (); + gtk_widget_show (display_ab); + gtk_box_pack_start (GTK_BOX (hbox15), display_ab, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (display_ab), 15); + gtk_tooltips_set_tip (tooltips, display_ab, _("Shows the address book"), NULL); + + alignment22 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment22); + gtk_container_add (GTK_CONTAINER (display_ab), alignment22); + + hbox36 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox36); + gtk_container_add (GTK_CONTAINER (alignment22), hbox36); + + image33 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image33); + gtk_box_pack_start (GTK_BOX (hbox36), image33, FALSE, FALSE, 0); + + label108 = gtk_label_new_with_mnemonic (_("...")); + gtk_widget_show (label108); + gtk_box_pack_start (GTK_BOX (hbox36), label108, FALSE, FALSE, 0); + + proxy_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (proxy_hbox); + gtk_box_pack_start (GTK_BOX (vbox24), proxy_hbox, TRUE, TRUE, 0); + + proxytouse_label = gtk_label_new (_("Proxy to use:")); + gtk_widget_show (proxytouse_label); + gtk_box_pack_start (GTK_BOX (proxy_hbox), proxytouse_label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (proxytouse_label), GTK_JUSTIFY_CENTER); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox4), hbox2, TRUE, TRUE, 0); + + callbutton = gtk_button_new_with_mnemonic (_("Call or\nanswer")); + gtk_widget_show (callbutton); + gtk_box_pack_start (GTK_BOX (hbox2), callbutton, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (callbutton), 8); + + button14 = gtk_button_new_with_mnemonic (_("Hangup\nor refuse")); + gtk_widget_show (button14); + gtk_box_pack_start (GTK_BOX (hbox2), button14, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (button14), 8); + + button18 = gtk_button_new_with_mnemonic (_("Or chat !")); + gtk_widget_show (button18); + gtk_box_pack_start (GTK_BOX (vbox4), button18, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (button18), 8); + + showmore = gtk_check_button_new (); + gtk_widget_show (showmore); + gtk_box_pack_start (GTK_BOX (vbox4), showmore, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (showmore), TRUE); + + alignment5 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment5); + gtk_container_add (GTK_CONTAINER (showmore), alignment5); + + hbox17 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox17); + gtk_container_add (GTK_CONTAINER (alignment5), hbox17); + + image12 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image12); + gtk_box_pack_start (GTK_BOX (hbox17), image12, FALSE, FALSE, 0); + + label60 = gtk_label_new_with_mnemonic (_("Show more...")); + gtk_widget_show (label60); + gtk_box_pack_start (GTK_BOX (hbox17), label60, FALSE, FALSE, 0); + + optioncontrols = gtk_notebook_new (); + gtk_widget_show (optioncontrols); + gtk_box_pack_start (GTK_BOX (vbox4), optioncontrols, TRUE, TRUE, 0); + + vbox31 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox31); + gtk_container_add (GTK_CONTAINER (optioncontrols), vbox31); + + frame8 = gtk_frame_new (NULL); + gtk_widget_show (frame8); + gtk_box_pack_start (GTK_BOX (vbox31), frame8, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame8), 11); + + vbox5 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox5); + gtk_container_add (GTK_CONTAINER (frame8), vbox5); + gtk_container_set_border_width (GTK_CONTAINER (vbox5), 2); + + label30 = gtk_label_new (_("Playback level:")); + gtk_widget_show (label30); + gtk_box_pack_start (GTK_BOX (vbox5), label30, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label30), 7.45058e-09, 0.5); + + play_vol = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (75, 0, 100, 0, 0, 0))); + gtk_widget_show (play_vol); + gtk_box_pack_start (GTK_BOX (vbox5), play_vol, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (play_vol), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (play_vol), 0); + + label31 = gtk_label_new (_("Recording level:")); + gtk_widget_show (label31); + gtk_box_pack_start (GTK_BOX (vbox5), label31, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label31), 7.45058e-09, 0.5); + + rec_vol = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (75, 0, 100, 0, 0, 0))); + gtk_widget_show (rec_vol); + gtk_box_pack_start (GTK_BOX (vbox5), rec_vol, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (rec_vol), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (rec_vol), 0); + + label110 = gtk_label_new (_("Ring level:")); + gtk_widget_show (label110); + gtk_box_pack_start (GTK_BOX (vbox5), label110, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label110), 7.45058e-09, 0.5); + + ring_vol = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (75, 0, 100, 0, 0, 0))); + gtk_widget_show (ring_vol); + gtk_box_pack_start (GTK_BOX (vbox5), ring_vol, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (ring_vol), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (ring_vol), 0); + + label113 = gtk_label_new (_("Sound")); + gtk_widget_show (label113); + gtk_frame_set_label_widget (GTK_FRAME (frame8), label113); + + frame27 = gtk_frame_new (NULL); + gtk_widget_show (frame27); + gtk_box_pack_start (GTK_BOX (vbox31), frame27, FALSE, FALSE, 0); + + alignment23 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment23); + gtk_container_add (GTK_CONTAINER (frame27), alignment23); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment23), 0, 0, 12, 0); + + vbox32 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox32); + gtk_container_add (GTK_CONTAINER (alignment23), vbox32); + + video_enabled = gtk_check_button_new_with_mnemonic (_("Enable video")); + gtk_widget_show (video_enabled); + gtk_box_pack_start (GTK_BOX (vbox32), video_enabled, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_enabled), TRUE); + + label114 = gtk_label_new (_("Video")); + gtk_widget_show (label114); + gtk_frame_set_label_widget (GTK_FRAME (frame27), label114); + gtk_label_set_use_markup (GTK_LABEL (label114), TRUE); + + label33 = gtk_label_new (_("Controls")); + gtk_widget_show (label33); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 0), label33); + gtk_label_set_justify (GTK_LABEL (label33), GTK_JUSTIFY_CENTER); + + vbox6 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox6); + gtk_container_add (GTK_CONTAINER (optioncontrols), vbox6); + + presence_frame = gtk_frame_new (NULL); + gtk_widget_show (presence_frame); + gtk_box_pack_start (GTK_BOX (vbox6), presence_frame, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (presence_frame), 11); + + presence_vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (presence_vbox); + gtk_container_add (GTK_CONTAINER (presence_frame), presence_vbox); + + presence_reachable = gtk_radio_button_new_with_mnemonic (NULL, _("Reachable")); + gtk_widget_show (presence_reachable); + gtk_box_pack_start (GTK_BOX (presence_vbox), presence_reachable, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (presence_reachable), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (presence_reachable)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (presence_reachable), TRUE); + + hbox4 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox4); + gtk_box_pack_start (GTK_BOX (presence_vbox), hbox4, FALSE, TRUE, 0); + + radiobutton2 = gtk_radio_button_new_with_mnemonic (NULL, _("Busy, I'll be back in ")); + gtk_widget_show (radiobutton2); + gtk_box_pack_start (GTK_BOX (hbox4), radiobutton2, TRUE, TRUE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton2), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton2)); + + minutesaway = gtk_entry_new (); + gtk_widget_show (minutesaway); + gtk_box_pack_start (GTK_BOX (hbox4), minutesaway, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, minutesaway, _("The other party will be informed that you'll be back in X minutes"), NULL); + gtk_entry_set_text (GTK_ENTRY (minutesaway), _("5")); + + label35 = gtk_label_new (_("mn")); + gtk_widget_show (label35); + gtk_box_pack_start (GTK_BOX (hbox4), label35, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label35), GTK_JUSTIFY_CENTER); + + radiobutton3 = gtk_radio_button_new_with_mnemonic (NULL, _("Away")); + gtk_widget_show (radiobutton3); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton3, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton3), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3)); + + radiobutton4 = gtk_radio_button_new_with_mnemonic (NULL, _("Do not disturb")); + gtk_widget_show (radiobutton4); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton4, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton4), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton4)); + + radiobutton5 = gtk_radio_button_new_with_mnemonic (NULL, _("Moved temporarily")); + gtk_widget_show (radiobutton5); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton5, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton5), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton5)); + + radiobutton6 = gtk_radio_button_new_with_mnemonic (NULL, _("Alternative service")); + gtk_widget_show (radiobutton6); + gtk_box_pack_start (GTK_BOX (presence_vbox), radiobutton6, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton6), presence_reachable_group); + presence_reachable_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton6)); + + hbox5 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox5); + gtk_box_pack_start (GTK_BOX (presence_vbox), hbox5, FALSE, TRUE, 0); + + label36 = gtk_label_new (_("URL:")); + gtk_widget_show (label36); + gtk_box_pack_start (GTK_BOX (hbox5), label36, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label36), GTK_JUSTIFY_CENTER); + + contact_field = gtk_entry_new (); + gtk_widget_show (contact_field); + gtk_box_pack_start (GTK_BOX (hbox5), contact_field, FALSE, FALSE, 0); + + label34 = gtk_label_new (_("Presence")); + gtk_widget_show (label34); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 1), label34); + gtk_label_set_justify (GTK_LABEL (label34), GTK_JUSTIFY_CENTER); + + frame19 = gtk_frame_new (NULL); + gtk_widget_show (frame19); + gtk_container_add (GTK_CONTAINER (optioncontrols), frame19); + gtk_container_set_border_width (GTK_CONTAINER (frame19), 15); + + vbox18 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox18); + gtk_container_add (GTK_CONTAINER (frame19), vbox18); + + dtmf_entry = gtk_entry_new (); + gtk_widget_show (dtmf_entry); + gtk_box_pack_start (GTK_BOX (vbox18), dtmf_entry, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, dtmf_entry, _("Press digits to send DTMFs."), NULL); + + table5 = gtk_table_new (4, 3, TRUE); + gtk_widget_show (table5); + gtk_box_pack_start (GTK_BOX (vbox18), table5, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (table5), 14); + gtk_table_set_row_spacings (GTK_TABLE (table5), 10); + gtk_table_set_col_spacings (GTK_TABLE (table5), 10); + + dtmf_3 = gtk_button_new_with_mnemonic (_(" 3\ndef")); + gtk_widget_show (dtmf_3); + gtk_table_attach (GTK_TABLE (table5), dtmf_3, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dmtf_2 = gtk_button_new_with_mnemonic (_(" 2\nabc")); + gtk_widget_show (dmtf_2); + gtk_table_attach (GTK_TABLE (table5), dmtf_2, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_1 = gtk_button_new_with_mnemonic (_("1")); + gtk_widget_show (dtmf_1); + gtk_table_attach (GTK_TABLE (table5), dtmf_1, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_4 = gtk_button_new_with_mnemonic (_(" 4\nghi")); + gtk_widget_show (dtmf_4); + gtk_table_attach (GTK_TABLE (table5), dtmf_4, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_5 = gtk_button_new_with_mnemonic (_(" 5\njkl")); + gtk_widget_show (dtmf_5); + gtk_table_attach (GTK_TABLE (table5), dtmf_5, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_6 = gtk_button_new_with_mnemonic (_(" 6\nmno")); + gtk_widget_show (dtmf_6); + gtk_table_attach (GTK_TABLE (table5), dtmf_6, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_7 = gtk_button_new_with_mnemonic (_(" 7\npqrs")); + gtk_widget_show (dtmf_7); + gtk_table_attach (GTK_TABLE (table5), dtmf_7, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_8 = gtk_button_new_with_mnemonic (_(" 8\ntuv")); + gtk_widget_show (dtmf_8); + gtk_table_attach (GTK_TABLE (table5), dtmf_8, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_9 = gtk_button_new_with_mnemonic (_(" 9\nwxyz")); + gtk_widget_show (dtmf_9); + gtk_table_attach (GTK_TABLE (table5), dtmf_9, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_star = gtk_button_new_with_mnemonic (_("*")); + gtk_widget_show (dtmf_star); + gtk_table_attach (GTK_TABLE (table5), dtmf_star, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_0 = gtk_button_new_with_mnemonic (_("0")); + gtk_widget_show (dtmf_0); + gtk_table_attach (GTK_TABLE (table5), dtmf_0, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + dtmf_pound = gtk_button_new_with_mnemonic (_("#")); + gtk_widget_show (dtmf_pound); + gtk_table_attach (GTK_TABLE (table5), dtmf_pound, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label38 = gtk_label_new (_("DTMF")); + gtk_widget_show (label38); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 2), label38); + gtk_label_set_justify (GTK_LABEL (label38), GTK_JUSTIFY_CENTER); + + vbox22 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox22); + gtk_container_add (GTK_CONTAINER (optioncontrols), vbox22); + + scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow3); + gtk_box_pack_start (GTK_BOX (vbox22), scrolledwindow3, TRUE, TRUE, 0); + + friendlist = gtk_tree_view_new (); + gtk_widget_show (friendlist); + gtk_container_add (GTK_CONTAINER (scrolledwindow3), friendlist); + + label65 = gtk_label_new (_("My online friends")); + gtk_widget_show (label65); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (optioncontrols), gtk_notebook_get_nth_page (GTK_NOTEBOOK (optioncontrols), 3), label65); + + appbarframe1 = gtk_frame_new (NULL); + gtk_widget_show (appbarframe1); + gtk_box_pack_start (GTK_BOX (dock1), appbarframe1, TRUE, TRUE, 0); + + appbar1 = gtk_statusbar_new (); + gtk_widget_show (appbar1); + gtk_container_add (GTK_CONTAINER (appbarframe1), appbar1); + + g_signal_connect ((gpointer) app1, "destroy", + G_CALLBACK (on_app1_destroy), + NULL); + g_signal_connect ((gpointer) addresse1, "activate", + G_CALLBACK (on_adresse_activate), + NULL); + g_signal_connect ((gpointer) parametres1, "activate", + G_CALLBACK (on_parametres1_activate), + NULL); + g_signal_connect ((gpointer) call_history, "activate", + G_CALLBACK (on_call_history_activate), + NULL); + g_signal_connect ((gpointer) exit1, "activate", + G_CALLBACK (on_exit1_activate), + NULL); + g_signal_connect ((gpointer) about1, "activate", + G_CALLBACK (on_about1_activate), + NULL); + g_signal_connect ((gpointer) user_manual1, "activate", + G_CALLBACK (on_user_manual1_activate), + NULL); + g_signal_connect ((gpointer) addressentry, "activate", + G_CALLBACK (on_addressentry_activate), + NULL); + g_signal_connect ((gpointer) addressentry, "destroy", + G_CALLBACK (on_addressentry_destroy), + NULL); + g_signal_connect ((gpointer) display_ab, "clicked", + G_CALLBACK (on_display_ab_clicked), + NULL); + g_signal_connect ((gpointer) callbutton, "clicked", + G_CALLBACK (on_callbutton_clicked), + NULL); + g_signal_connect ((gpointer) button14, "clicked", + G_CALLBACK (on_hangup_clicked), + NULL); + g_signal_connect ((gpointer) button18, "clicked", + G_CALLBACK (on_chat_clicked), + NULL); + g_signal_connect ((gpointer) showmore, "toggled", + G_CALLBACK (on_showmore_toggled), + NULL); + g_signal_connect ((gpointer) play_vol, "button_release_event", + G_CALLBACK (on_play_vol_button_release_event), + NULL); + g_signal_connect ((gpointer) rec_vol, "button_release_event", + G_CALLBACK (on_rec_vol_button_release_event), + NULL); + g_signal_connect ((gpointer) ring_vol, "button_release_event", + G_CALLBACK (on_rec_vol_button_release_event), + NULL); + g_signal_connect ((gpointer) video_enabled, "toggled", + G_CALLBACK (on_video_enabled_toggled), + NULL); + g_signal_connect ((gpointer) presence_reachable, "toggled", + G_CALLBACK (on_reachable), + NULL); + g_signal_connect ((gpointer) radiobutton2, "toggled", + G_CALLBACK (on_busy), + NULL); + g_signal_connect ((gpointer) minutesaway, "changed", + G_CALLBACK (on_minutesaway_changed), + NULL); + g_signal_connect ((gpointer) radiobutton3, "toggled", + G_CALLBACK (on_away), + NULL); + g_signal_connect ((gpointer) radiobutton4, "toggled", + G_CALLBACK (on_do_not_disturb), + NULL); + g_signal_connect ((gpointer) radiobutton5, "toggled", + G_CALLBACK (on_moved_tmply), + NULL); + g_signal_connect ((gpointer) radiobutton6, "toggled", + G_CALLBACK (on_alt_serv), + NULL); + g_signal_connect ((gpointer) contact_field, "changed", + G_CALLBACK (on_contact_field_changed), + NULL); + g_signal_connect ((gpointer) dtmf_entry, "changed", + G_CALLBACK (on_dtmf_entry_changed), + NULL); + g_signal_connect ((gpointer) dtmf_3, "clicked", + G_CALLBACK (on_dtmf_3_clicked), + NULL); + g_signal_connect ((gpointer) dmtf_2, "clicked", + G_CALLBACK (on_dmtf_2_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_1, "clicked", + G_CALLBACK (on_dtmf_1_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_4, "clicked", + G_CALLBACK (on_dtmf_4_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_5, "clicked", + G_CALLBACK (on_dtmf_5_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_6, "clicked", + G_CALLBACK (on_dtmf_6_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_7, "clicked", + G_CALLBACK (on_dtmf_7_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_8, "clicked", + G_CALLBACK (on_dtmf_8_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_9, "clicked", + G_CALLBACK (on_dtmf_9_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_star, "clicked", + G_CALLBACK (on_dtmf_star_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_0, "clicked", + G_CALLBACK (on_dtmf_0_clicked), + NULL); + g_signal_connect ((gpointer) dtmf_pound, "clicked", + G_CALLBACK (on_dtmf_pound_clicked), + NULL); + g_signal_connect ((gpointer) friendlist, "row_activated", + G_CALLBACK (on_friendlist_row_activated), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (app1, app1, "app1"); + GLADE_HOOKUP_OBJECT (app1, dock1, "dock1"); + GLADE_HOOKUP_OBJECT (app1, menubar1, "menubar1"); + GLADE_HOOKUP_OBJECT (app1, connexion1, "connexion1"); + GLADE_HOOKUP_OBJECT (app1, connexion1_menu, "connexion1_menu"); + GLADE_HOOKUP_OBJECT (app1, addresse1, "addresse1"); + GLADE_HOOKUP_OBJECT (app1, image39, "image39"); + GLADE_HOOKUP_OBJECT (app1, parametres1, "parametres1"); + GLADE_HOOKUP_OBJECT (app1, call_history, "call_history"); + GLADE_HOOKUP_OBJECT (app1, image40, "image40"); + GLADE_HOOKUP_OBJECT (app1, separator1, "separator1"); + GLADE_HOOKUP_OBJECT (app1, exit1, "exit1"); + GLADE_HOOKUP_OBJECT (app1, image41, "image41"); + GLADE_HOOKUP_OBJECT (app1, help1, "help1"); + GLADE_HOOKUP_OBJECT (app1, help1_menu, "help1_menu"); + GLADE_HOOKUP_OBJECT (app1, about1, "about1"); + GLADE_HOOKUP_OBJECT (app1, user_manual1, "user_manual1"); + GLADE_HOOKUP_OBJECT (app1, frame6, "frame6"); + GLADE_HOOKUP_OBJECT (app1, vbox4, "vbox4"); + GLADE_HOOKUP_OBJECT (app1, vbox24, "vbox24"); + GLADE_HOOKUP_OBJECT (app1, hbox15, "hbox15"); + GLADE_HOOKUP_OBJECT (app1, frame7, "frame7"); + GLADE_HOOKUP_OBJECT (app1, addressentry, "addressentry"); + GLADE_HOOKUP_OBJECT (app1, label1, "label1"); + GLADE_HOOKUP_OBJECT (app1, display_ab, "display_ab"); + GLADE_HOOKUP_OBJECT (app1, alignment22, "alignment22"); + GLADE_HOOKUP_OBJECT (app1, hbox36, "hbox36"); + GLADE_HOOKUP_OBJECT (app1, image33, "image33"); + GLADE_HOOKUP_OBJECT (app1, label108, "label108"); + GLADE_HOOKUP_OBJECT (app1, proxy_hbox, "proxy_hbox"); + GLADE_HOOKUP_OBJECT (app1, proxytouse_label, "proxytouse_label"); + GLADE_HOOKUP_OBJECT (app1, hbox2, "hbox2"); + GLADE_HOOKUP_OBJECT (app1, callbutton, "callbutton"); + GLADE_HOOKUP_OBJECT (app1, button14, "button14"); + GLADE_HOOKUP_OBJECT (app1, button18, "button18"); + GLADE_HOOKUP_OBJECT (app1, showmore, "showmore"); + GLADE_HOOKUP_OBJECT (app1, alignment5, "alignment5"); + GLADE_HOOKUP_OBJECT (app1, hbox17, "hbox17"); + GLADE_HOOKUP_OBJECT (app1, image12, "image12"); + GLADE_HOOKUP_OBJECT (app1, label60, "label60"); + GLADE_HOOKUP_OBJECT (app1, optioncontrols, "optioncontrols"); + GLADE_HOOKUP_OBJECT (app1, vbox31, "vbox31"); + GLADE_HOOKUP_OBJECT (app1, frame8, "frame8"); + GLADE_HOOKUP_OBJECT (app1, vbox5, "vbox5"); + GLADE_HOOKUP_OBJECT (app1, label30, "label30"); + GLADE_HOOKUP_OBJECT (app1, play_vol, "play_vol"); + GLADE_HOOKUP_OBJECT (app1, label31, "label31"); + GLADE_HOOKUP_OBJECT (app1, rec_vol, "rec_vol"); + GLADE_HOOKUP_OBJECT (app1, label110, "label110"); + GLADE_HOOKUP_OBJECT (app1, ring_vol, "ring_vol"); + GLADE_HOOKUP_OBJECT (app1, label113, "label113"); + GLADE_HOOKUP_OBJECT (app1, frame27, "frame27"); + GLADE_HOOKUP_OBJECT (app1, alignment23, "alignment23"); + GLADE_HOOKUP_OBJECT (app1, vbox32, "vbox32"); + GLADE_HOOKUP_OBJECT (app1, video_enabled, "video_enabled"); + GLADE_HOOKUP_OBJECT (app1, label114, "label114"); + GLADE_HOOKUP_OBJECT (app1, label33, "label33"); + GLADE_HOOKUP_OBJECT (app1, vbox6, "vbox6"); + GLADE_HOOKUP_OBJECT (app1, presence_frame, "presence_frame"); + GLADE_HOOKUP_OBJECT (app1, presence_vbox, "presence_vbox"); + GLADE_HOOKUP_OBJECT (app1, presence_reachable, "presence_reachable"); + GLADE_HOOKUP_OBJECT (app1, hbox4, "hbox4"); + GLADE_HOOKUP_OBJECT (app1, radiobutton2, "radiobutton2"); + GLADE_HOOKUP_OBJECT (app1, minutesaway, "minutesaway"); + GLADE_HOOKUP_OBJECT (app1, label35, "label35"); + GLADE_HOOKUP_OBJECT (app1, radiobutton3, "radiobutton3"); + GLADE_HOOKUP_OBJECT (app1, radiobutton4, "radiobutton4"); + GLADE_HOOKUP_OBJECT (app1, radiobutton5, "radiobutton5"); + GLADE_HOOKUP_OBJECT (app1, radiobutton6, "radiobutton6"); + GLADE_HOOKUP_OBJECT (app1, hbox5, "hbox5"); + GLADE_HOOKUP_OBJECT (app1, label36, "label36"); + GLADE_HOOKUP_OBJECT (app1, contact_field, "contact_field"); + GLADE_HOOKUP_OBJECT (app1, label34, "label34"); + GLADE_HOOKUP_OBJECT (app1, frame19, "frame19"); + GLADE_HOOKUP_OBJECT (app1, vbox18, "vbox18"); + GLADE_HOOKUP_OBJECT (app1, dtmf_entry, "dtmf_entry"); + GLADE_HOOKUP_OBJECT (app1, table5, "table5"); + GLADE_HOOKUP_OBJECT (app1, dtmf_3, "dtmf_3"); + GLADE_HOOKUP_OBJECT (app1, dmtf_2, "dmtf_2"); + GLADE_HOOKUP_OBJECT (app1, dtmf_1, "dtmf_1"); + GLADE_HOOKUP_OBJECT (app1, dtmf_4, "dtmf_4"); + GLADE_HOOKUP_OBJECT (app1, dtmf_5, "dtmf_5"); + GLADE_HOOKUP_OBJECT (app1, dtmf_6, "dtmf_6"); + GLADE_HOOKUP_OBJECT (app1, dtmf_7, "dtmf_7"); + GLADE_HOOKUP_OBJECT (app1, dtmf_8, "dtmf_8"); + GLADE_HOOKUP_OBJECT (app1, dtmf_9, "dtmf_9"); + GLADE_HOOKUP_OBJECT (app1, dtmf_star, "dtmf_star"); + GLADE_HOOKUP_OBJECT (app1, dtmf_0, "dtmf_0"); + GLADE_HOOKUP_OBJECT (app1, dtmf_pound, "dtmf_pound"); + GLADE_HOOKUP_OBJECT (app1, label38, "label38"); + GLADE_HOOKUP_OBJECT (app1, vbox22, "vbox22"); + GLADE_HOOKUP_OBJECT (app1, scrolledwindow3, "scrolledwindow3"); + GLADE_HOOKUP_OBJECT (app1, friendlist, "friendlist"); + GLADE_HOOKUP_OBJECT (app1, label65, "label65"); + GLADE_HOOKUP_OBJECT (app1, appbarframe1, "appbarframe1"); + GLADE_HOOKUP_OBJECT (app1, appbar1, "appbar1"); + GLADE_HOOKUP_OBJECT_NO_REF (app1, tooltips, "tooltips"); + + gtk_window_add_accel_group (GTK_WINDOW (app1), accel_group); + + return app1; +} + +GtkWidget* +create_about2 (void) +{ + GtkWidget *about2; + const gchar *authors[] = { + "Simon MORLAT", + "Aymeric Moizard", + "Sharath K Udupa", + NULL + }; + const gchar *documenters[] = { + "Simon MORLAT", + "Philippe Beau", + NULL + }; + gchar *translators = "it: Alberto Zanoni\nde: Jean Jacques Sarton\nfr: Simon Morlat\nde: Jean-Jacques Sarton, Ursula Herles-Hartz\nes: Jesus Benitez, Nelson Benitez\nja: Yamaguchi Yoshiya\nnl: Hendrik-Jan Heins\npl: Robert Nasiadek <darkone@darkone.pl>\npt_BR: Rafael Caesar Lenzi \nsv: Daniel Nylander "; + GdkPixbuf *about2_logo_pixbuf; + + about2 = gtk_about_dialog_new (); + gtk_container_set_border_width (GTK_CONTAINER (about2), 5); + gtk_window_set_destroy_with_parent (GTK_WINDOW (about2), TRUE); + gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (about2), VERSION); + gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (about2), _("Linphone")); + gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (about2), _("C: 2001\nMade in Old Europe")); + gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (about2), _("Linphone is a web-phone.\nIt is compatible with SIP and RTP protocols.")); + gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (about2), " This program is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; either version 2 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"); + gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (about2), "http://www.linphone.org"); + gtk_about_dialog_set_website_label (GTK_ABOUT_DIALOG (about2), _("http://www.linphone.org")); + gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (about2), authors); + gtk_about_dialog_set_documenters (GTK_ABOUT_DIALOG (about2), documenters); + gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (about2), translators); + about2_logo_pixbuf = create_pixbuf ("linphone.png"); + gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (about2), about2_logo_pixbuf); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (about2, about2, "about2"); + + return about2; +} + +GtkWidget* +create_prop1 (void) +{ + GtkWidget *prop1; + GdkPixbuf *prop1_icon_pixbuf; + GtkWidget *prop1box; + GtkWidget *prop1notebook; + GtkWidget *vbox9; + GtkWidget *frame26; + GtkWidget *alignment21; + GtkWidget *vbox29; + GtkWidget *enable_ipv6; + GtkWidget *label105; + GtkWidget *frame21; + GtkWidget *vbox21; + GtkWidget *label56; + GtkWidget *table13; + GtkWidget *no_nat; + GSList *no_nat_group = NULL; + GtkWidget *use_stun; + GtkWidget *static_nat; + GtkWidget *nat_address; + GtkWidget *stun_server; + GtkWidget *label55; + GtkWidget *frame20; + GtkWidget *table6; + GtkWidget *audio_jittcomp; + GtkObject *audioport_adj; + GtkWidget *audioport; + GtkWidget *label52; + GtkWidget *label53; + GtkWidget *label54; + GtkWidget *frame25; + GtkWidget *alignment20; + GtkWidget *vbox28; + GtkWidget *use_sipinfo; + GtkWidget *label103; + GtkWidget *network; + GtkWidget *vbox12; + GtkWidget *vbox20; + GtkWidget *frame17; + GtkWidget *vbox16; + GtkWidget *table4; + GtkWidget *label10; + GtkWidget *combo3; + GList *combo3_items = NULL; + GtkWidget *rec_source; + GtkWidget *label106; + GtkWidget *play_card; + GtkWidget *capt_card; + GtkWidget *label11; + GtkWidget *ringsnddev_label; + GtkWidget *label63; + GtkWidget *ring_card; + GtkWidget *echocancelation; + GtkWidget *label115; + GtkWidget *hbox20; + GtkWidget *ringfileentry; + GtkWidget *ringpreview; + GtkWidget *alignment24; + GtkWidget *hbox37; + GtkWidget *image42; + GtkWidget *label118; + GtkWidget *label48; + GtkWidget *sound; + GtkWidget *vbox7; + GtkWidget *frame10; + GtkWidget *hbox6; + GtkWidget *label13; + GtkObject *sip_port_adj; + GtkWidget *sip_port; + GtkWidget *label43; + GtkWidget *frame11; + GtkWidget *vbox27; + GtkWidget *hbox7; + GtkWidget *label26; + GtkWidget *label27; + GtkWidget *user_name; + GtkWidget *label28; + GtkWidget *domain_name; + GtkWidget *guess_hostname; + GtkWidget *label44; + GtkWidget *frame1; + GtkWidget *vbox23; + GtkWidget *scrolledwindow4; + GtkWidget *proxy_list; + GtkWidget *hbuttonbox6; + GtkWidget *addproxy_button; + GtkWidget *alignment12; + GtkWidget *hbox25; + GtkWidget *image19; + GtkWidget *label77; + GtkWidget *editproxy_button; + GtkWidget *alignment13; + GtkWidget *hbox26; + GtkWidget *image20; + GtkWidget *label78; + GtkWidget *removeproxy_button; + GtkWidget *alignment14; + GtkWidget *hbox27; + GtkWidget *image21; + GtkWidget *label79; + GtkWidget *label45; + GtkWidget *frame24; + GtkWidget *alignment18; + GtkWidget *clear_auth_info; + GtkWidget *alignment19; + GtkWidget *hbox34; + GtkWidget *image27; + GtkWidget *label102; + GtkWidget *label101; + GtkWidget *sip_pref; + GtkWidget *vbox13; + GtkWidget *frame16; + GtkWidget *hbox9; + GtkWidget *vbox14; + GtkWidget *label9; + GtkWidget *codec_notebook; + GtkWidget *scrolledwindow2; + GtkWidget *au_codec_list; + GtkWidget *label116; + GtkWidget *scrolledwindow7; + GtkWidget *vid_codec_list; + GtkWidget *label117; + GtkWidget *hbuttonbox4; + GtkWidget *aucodec_up; + GtkWidget *aucodec_down; + GtkWidget *aucodec_enable; + GtkWidget *alignment1; + GtkWidget *hbox11; + GtkWidget *image4; + GtkWidget *label50; + GtkWidget *aucodec_disable; + GtkWidget *alignment2; + GtkWidget *hbox12; + GtkWidget *image5; + GtkWidget *label51; + GtkWidget *table12; + GtkWidget *label112; + GtkWidget *label111; + GtkObject *download_bw_adj; + GtkWidget *download_bw; + GtkObject *upload_bw_adj; + GtkWidget *upload_bw; + GtkWidget *vbox17; + GtkWidget *label22; + GtkWidget *frame18; + GtkWidget *codec_info; + GtkWidget *label47; + GtkWidget *label46; + GtkWidget *codecs_pref; + GtkWidget *hbuttonbox7; + GtkWidget *prop_help_button; + GtkWidget *prop_apply_button; + GtkWidget *prop_close_button; + GtkWidget *prop_ok_button; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + prop1 = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (prop1), _("Parameters")); + gtk_window_set_resizable (GTK_WINDOW (prop1), FALSE); + prop1_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (prop1_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (prop1), prop1_icon_pixbuf); + gdk_pixbuf_unref (prop1_icon_pixbuf); + } + + prop1box = GTK_DIALOG (prop1)->vbox; + + prop1notebook = gtk_notebook_new (); + gtk_widget_show (prop1notebook); + gtk_box_pack_start (GTK_BOX (prop1box), prop1notebook, TRUE, TRUE, 0); + + vbox9 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox9); + gtk_container_add (GTK_CONTAINER (prop1notebook), vbox9); + + frame26 = gtk_frame_new (NULL); + gtk_widget_show (frame26); + gtk_box_pack_start (GTK_BOX (vbox9), frame26, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame26), 6); + + alignment21 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment21); + gtk_container_add (GTK_CONTAINER (frame26), alignment21); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment21), 0, 0, 12, 0); + + vbox29 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox29); + gtk_container_add (GTK_CONTAINER (alignment21), vbox29); + + enable_ipv6 = gtk_check_button_new_with_mnemonic (_("Use IPv6 network (if available)")); + gtk_widget_show (enable_ipv6); + gtk_box_pack_start (GTK_BOX (vbox29), enable_ipv6, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, enable_ipv6, _("Toggle this if you are on an ipv6 network and you wish linphone to use it."), NULL); + + label105 = gtk_label_new (_("Global")); + gtk_widget_show (label105); + gtk_frame_set_label_widget (GTK_FRAME (frame26), label105); + gtk_label_set_use_markup (GTK_LABEL (label105), TRUE); + + frame21 = gtk_frame_new (NULL); + gtk_widget_show (frame21); + gtk_box_pack_start (GTK_BOX (vbox9), frame21, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame21), 5); + + vbox21 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox21); + gtk_container_add (GTK_CONTAINER (frame21), vbox21); + gtk_container_set_border_width (GTK_CONTAINER (vbox21), 6); + + label56 = gtk_label_new (_("These options is only for users in a private network, behind a gateway. If you are not in this situation, then leave this empty.")); + gtk_widget_show (label56); + gtk_box_pack_start (GTK_BOX (vbox21), label56, TRUE, TRUE, 0); + gtk_label_set_line_wrap (GTK_LABEL (label56), TRUE); + gtk_misc_set_padding (GTK_MISC (label56), 0, 12); + + table13 = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table13); + gtk_box_pack_start (GTK_BOX (vbox21), table13, FALSE, FALSE, 0); + + no_nat = gtk_radio_button_new_with_mnemonic (NULL, _("No firewall")); + gtk_widget_show (no_nat); + gtk_table_attach (GTK_TABLE (table13), no_nat, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (no_nat), no_nat_group); + no_nat_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (no_nat)); + + use_stun = gtk_radio_button_new_with_mnemonic (NULL, _("Use this STUN server to guess firewall address :")); + gtk_widget_show (use_stun); + gtk_table_attach (GTK_TABLE (table13), use_stun, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (use_stun), no_nat_group); + no_nat_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (use_stun)); + + static_nat = gtk_radio_button_new_with_mnemonic (NULL, _("Specify firewall address manually:")); + gtk_widget_show (static_nat); + gtk_table_attach (GTK_TABLE (table13), static_nat, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (static_nat), no_nat_group); + no_nat_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (static_nat)); + + nat_address = gtk_entry_new (); + gtk_widget_show (nat_address); + gtk_table_attach (GTK_TABLE (table13), nat_address, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + stun_server = gtk_entry_new (); + gtk_widget_show (stun_server); + gtk_table_attach (GTK_TABLE (table13), stun_server, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label55 = gtk_label_new (_("NAT traversal options (experimental)")); + gtk_widget_show (label55); + gtk_frame_set_label_widget (GTK_FRAME (frame21), label55); + + frame20 = gtk_frame_new (NULL); + gtk_widget_show (frame20); + gtk_box_pack_start (GTK_BOX (vbox9), frame20, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame20), 5); + + table6 = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table6); + gtk_container_add (GTK_CONTAINER (frame20), table6); + + audio_jittcomp = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (150, 60, 512, 10, 0, 0))); + gtk_widget_show (audio_jittcomp); + gtk_table_attach (GTK_TABLE (table6), audio_jittcomp, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND), 20, 0); + gtk_scale_set_value_pos (GTK_SCALE (audio_jittcomp), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (audio_jittcomp), 0); + + audioport_adj = gtk_adjustment_new (7000, 5000, 65535, 1, 10, 10); + audioport = gtk_spin_button_new (GTK_ADJUSTMENT (audioport_adj), 4, 0); + gtk_widget_show (audioport); + gtk_table_attach (GTK_TABLE (table6), audioport, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND), 20, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (audioport), TRUE); + + label52 = gtk_label_new (_("Number of buffered miliseconds (jitter compensation):")); + gtk_widget_show (label52); + gtk_table_attach (GTK_TABLE (table6), label52, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label52), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label52), TRUE); + + label53 = gtk_label_new (_("RTP port used for audio:")); + gtk_widget_show (label53); + gtk_table_attach (GTK_TABLE (table6), label53, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label53), GTK_JUSTIFY_CENTER); + + label54 = gtk_label_new (_("RTP properties")); + gtk_widget_show (label54); + gtk_frame_set_label_widget (GTK_FRAME (frame20), label54); + + frame25 = gtk_frame_new (NULL); + gtk_widget_show (frame25); + gtk_box_pack_start (GTK_BOX (vbox9), frame25, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame25), 5); + + alignment20 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment20); + gtk_container_add (GTK_CONTAINER (frame25), alignment20); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment20), 0, 0, 12, 0); + + vbox28 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox28); + gtk_container_add (GTK_CONTAINER (alignment20), vbox28); + + use_sipinfo = gtk_check_button_new_with_mnemonic (_("Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting")); + gtk_widget_show (use_sipinfo); + gtk_box_pack_start (GTK_BOX (vbox28), use_sipinfo, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, use_sipinfo, _("RTP-RFC2833 is the recommended way."), NULL); + + label103 = gtk_label_new (_("Other")); + gtk_widget_show (label103); + gtk_frame_set_label_widget (GTK_FRAME (frame25), label103); + gtk_label_set_use_markup (GTK_LABEL (label103), TRUE); + + network = gtk_label_new (_("Network")); + gtk_widget_show (network); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (prop1notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (prop1notebook), 0), network); + gtk_label_set_justify (GTK_LABEL (network), GTK_JUSTIFY_CENTER); + + vbox12 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox12); + gtk_container_add (GTK_CONTAINER (prop1notebook), vbox12); + + vbox20 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox20); + gtk_box_pack_start (GTK_BOX (vbox12), vbox20, FALSE, TRUE, 0); + + frame17 = gtk_frame_new (NULL); + gtk_widget_show (frame17); + gtk_box_pack_start (GTK_BOX (vbox20), frame17, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame17), 10); + + vbox16 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox16); + gtk_container_add (GTK_CONTAINER (frame17), vbox16); + + table4 = gtk_table_new (6, 2, FALSE); + gtk_widget_show (table4); + gtk_box_pack_start (GTK_BOX (vbox16), table4, TRUE, TRUE, 0); + + label10 = gtk_label_new (_("Playback sound device:")); + gtk_widget_show (label10); + gtk_table_attach (GTK_TABLE (table4), label10, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_EXPAND), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label10), 0, 0.5); + + combo3 = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (combo3)->popwin), + "GladeParentKey", combo3); + gtk_widget_show (combo3); + gtk_table_attach (GTK_TABLE (table4), combo3, 1, 2, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_combo_set_value_in_list (GTK_COMBO (combo3), TRUE, FALSE); + combo3_items = g_list_append (combo3_items, (gpointer) _("micro")); + combo3_items = g_list_append (combo3_items, (gpointer) _("line")); + combo3_items = g_list_append (combo3_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (combo3), combo3_items); + g_list_free (combo3_items); + + rec_source = GTK_COMBO (combo3)->entry; + gtk_widget_show (rec_source); + gtk_editable_set_editable (GTK_EDITABLE (rec_source), FALSE); + + label106 = gtk_label_new (_("Capture sound device:")); + gtk_widget_show (label106); + gtk_table_attach (GTK_TABLE (table4), label106, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label106), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label106), 0, 0.5); + + play_card = gtk_combo_box_new_text (); + gtk_widget_show (play_card); + gtk_table_attach (GTK_TABLE (table4), play_card, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + capt_card = gtk_combo_box_new_text (); + gtk_widget_show (capt_card); + gtk_table_attach (GTK_TABLE (table4), capt_card, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label11 = gtk_label_new (_("Recording source:")); + gtk_widget_show (label11); + gtk_table_attach (GTK_TABLE (table4), label11, 0, 1, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label11), 0, 0.5); + + ringsnddev_label = gtk_label_new (_("Ring sound device")); + gtk_widget_show (ringsnddev_label); + gtk_table_attach (GTK_TABLE (table4), ringsnddev_label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (ringsnddev_label), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (ringsnddev_label), 0, 0.5); + + label63 = gtk_label_new (_("Ring sound:")); + gtk_widget_show (label63); + gtk_table_attach (GTK_TABLE (table4), label63, 0, 1, 4, 5, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label63), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label63), 0, 0.5); + + ring_card = gtk_combo_box_new_text (); + gtk_widget_show (ring_card); + gtk_table_attach (GTK_TABLE (table4), ring_card, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + echocancelation = gtk_check_button_new_with_mnemonic (""); + gtk_widget_show (echocancelation); + gtk_table_attach (GTK_TABLE (table4), echocancelation, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label115 = gtk_label_new (_("Enable echo-canceler (cancels the echo heard by the remote party)")); + gtk_widget_show (label115); + gtk_table_attach (GTK_TABLE (table4), label115, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label115), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label115), 0, 0.5); + + hbox20 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox20); + gtk_table_attach (GTK_TABLE (table4), hbox20, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + ringfileentry = gtk_file_chooser_button_new (_("Choose file"), GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_widget_show (ringfileentry); + gtk_box_pack_start (GTK_BOX (hbox20), ringfileentry, TRUE, TRUE, 0); + + ringpreview = gtk_button_new (); + gtk_widget_show (ringpreview); + gtk_box_pack_start (GTK_BOX (hbox20), ringpreview, FALSE, FALSE, 10); + + alignment24 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment24); + gtk_container_add (GTK_CONTAINER (ringpreview), alignment24); + + hbox37 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox37); + gtk_container_add (GTK_CONTAINER (alignment24), hbox37); + + image42 = gtk_image_new_from_stock ("gtk-dialog-info", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image42); + gtk_box_pack_start (GTK_BOX (hbox37), image42, FALSE, FALSE, 0); + + label118 = gtk_label_new_with_mnemonic (_("Listen")); + gtk_widget_show (label118); + gtk_box_pack_start (GTK_BOX (hbox37), label118, FALSE, FALSE, 0); + + label48 = gtk_label_new (_("Sound properties")); + gtk_widget_show (label48); + gtk_frame_set_label_widget (GTK_FRAME (frame17), label48); + + sound = gtk_label_new (_("Sound device")); + gtk_widget_show (sound); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (prop1notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (prop1notebook), 1), sound); + gtk_label_set_justify (GTK_LABEL (sound), GTK_JUSTIFY_CENTER); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (prop1notebook), vbox7); + + frame10 = gtk_frame_new (NULL); + gtk_widget_show (frame10); + gtk_box_pack_start (GTK_BOX (vbox7), frame10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame10), 10); + + hbox6 = gtk_hbox_new (FALSE, 67); + gtk_widget_show (hbox6); + gtk_container_add (GTK_CONTAINER (frame10), hbox6); + + label13 = gtk_label_new (_("Run sip user agent on port:")); + gtk_widget_show (label13); + gtk_box_pack_start (GTK_BOX (hbox6), label13, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label13), GTK_JUSTIFY_CENTER); + + sip_port_adj = gtk_adjustment_new (5060, 5000, 65535, 1, 10, 10); + sip_port = gtk_spin_button_new (GTK_ADJUSTMENT (sip_port_adj), 4, 0); + gtk_widget_show (sip_port); + gtk_box_pack_start (GTK_BOX (hbox6), sip_port, TRUE, TRUE, 32); + gtk_tooltips_set_tip (tooltips, sip_port, _("It is strongly recommended to use port 5060."), NULL); + + label43 = gtk_label_new (_("SIP port")); + gtk_widget_show (label43); + gtk_frame_set_label_widget (GTK_FRAME (frame10), label43); + + frame11 = gtk_frame_new (NULL); + gtk_widget_show (frame11); + gtk_box_pack_start (GTK_BOX (vbox7), frame11, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame11), 10); + + vbox27 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox27); + gtk_container_add (GTK_CONTAINER (frame11), vbox27); + + hbox7 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox7); + gtk_box_pack_start (GTK_BOX (vbox27), hbox7, TRUE, TRUE, 0); + + label26 = gtk_label_new (_("Your sip address:")); + gtk_widget_show (label26); + gtk_box_pack_start (GTK_BOX (hbox7), label26, TRUE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label26), GTK_JUSTIFY_CENTER); + + label27 = gtk_label_new (_("sip:")); + gtk_widget_show (label27); + gtk_box_pack_start (GTK_BOX (hbox7), label27, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label27), GTK_JUSTIFY_RIGHT); + + user_name = gtk_entry_new (); + gtk_widget_show (user_name); + gtk_box_pack_start (GTK_BOX (hbox7), user_name, FALSE, FALSE, 0); + + label28 = gtk_label_new (_("@")); + gtk_widget_show (label28); + gtk_box_pack_start (GTK_BOX (hbox7), label28, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label28), GTK_JUSTIFY_CENTER); + + domain_name = gtk_entry_new (); + gtk_widget_show (domain_name); + gtk_box_pack_start (GTK_BOX (hbox7), domain_name, FALSE, TRUE, 0); + + guess_hostname = gtk_check_button_new_with_mnemonic (_("Automatically guess a valid hostname")); + gtk_widget_show (guess_hostname); + gtk_box_pack_start (GTK_BOX (vbox27), guess_hostname, TRUE, TRUE, 0); + + label44 = gtk_label_new (_("Identity")); + gtk_widget_show (label44); + gtk_frame_set_label_widget (GTK_FRAME (frame11), label44); + + frame1 = gtk_frame_new (NULL); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox7), frame1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame1), 10); + + vbox23 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox23); + gtk_container_add (GTK_CONTAINER (frame1), vbox23); + + scrolledwindow4 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow4); + gtk_box_pack_start (GTK_BOX (vbox23), scrolledwindow4, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_SHADOW_ETCHED_OUT); + + proxy_list = gtk_tree_view_new (); + gtk_widget_show (proxy_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow4), proxy_list); + gtk_widget_set_size_request (proxy_list, -1, 100); + + hbuttonbox6 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox6); + gtk_box_pack_start (GTK_BOX (vbox23), hbuttonbox6, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox6), 5); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox6), GTK_BUTTONBOX_SPREAD); + + addproxy_button = gtk_button_new (); + gtk_widget_show (addproxy_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), addproxy_button); + GTK_WIDGET_SET_FLAGS (addproxy_button, GTK_CAN_DEFAULT); + + alignment12 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment12); + gtk_container_add (GTK_CONTAINER (addproxy_button), alignment12); + + hbox25 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox25); + gtk_container_add (GTK_CONTAINER (alignment12), hbox25); + + image19 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image19); + gtk_box_pack_start (GTK_BOX (hbox25), image19, FALSE, FALSE, 0); + + label77 = gtk_label_new_with_mnemonic (_("Add proxy/registrar")); + gtk_widget_show (label77); + gtk_box_pack_start (GTK_BOX (hbox25), label77, FALSE, FALSE, 0); + + editproxy_button = gtk_button_new (); + gtk_widget_show (editproxy_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), editproxy_button); + GTK_WIDGET_SET_FLAGS (editproxy_button, GTK_CAN_DEFAULT); + + alignment13 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment13); + gtk_container_add (GTK_CONTAINER (editproxy_button), alignment13); + + hbox26 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox26); + gtk_container_add (GTK_CONTAINER (alignment13), hbox26); + + image20 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image20); + gtk_box_pack_start (GTK_BOX (hbox26), image20, FALSE, FALSE, 0); + + label78 = gtk_label_new_with_mnemonic (_("Edit")); + gtk_widget_show (label78); + gtk_box_pack_start (GTK_BOX (hbox26), label78, FALSE, FALSE, 0); + + removeproxy_button = gtk_button_new (); + gtk_widget_show (removeproxy_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox6), removeproxy_button); + GTK_WIDGET_SET_FLAGS (removeproxy_button, GTK_CAN_DEFAULT); + + alignment14 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment14); + gtk_container_add (GTK_CONTAINER (removeproxy_button), alignment14); + + hbox27 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox27); + gtk_container_add (GTK_CONTAINER (alignment14), hbox27); + + image21 = gtk_image_new_from_stock ("gtk-cancel", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image21); + gtk_box_pack_start (GTK_BOX (hbox27), image21, FALSE, FALSE, 0); + + label79 = gtk_label_new_with_mnemonic (_("Remove")); + gtk_widget_show (label79); + gtk_box_pack_start (GTK_BOX (hbox27), label79, FALSE, FALSE, 0); + + label45 = gtk_label_new (_("Remote services")); + gtk_widget_show (label45); + gtk_frame_set_label_widget (GTK_FRAME (frame1), label45); + + frame24 = gtk_frame_new (NULL); + gtk_widget_show (frame24); + gtk_box_pack_start (GTK_BOX (vbox7), frame24, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame24), 10); + + alignment18 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment18); + gtk_container_add (GTK_CONTAINER (frame24), alignment18); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment18), 0, 0, 12, 0); + + clear_auth_info = gtk_button_new (); + gtk_widget_show (clear_auth_info); + gtk_container_add (GTK_CONTAINER (alignment18), clear_auth_info); + + alignment19 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment19); + gtk_container_add (GTK_CONTAINER (clear_auth_info), alignment19); + + hbox34 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox34); + gtk_container_add (GTK_CONTAINER (alignment19), hbox34); + + image27 = gtk_image_new_from_stock ("gtk-delete", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image27); + gtk_box_pack_start (GTK_BOX (hbox34), image27, FALSE, FALSE, 0); + + label102 = gtk_label_new_with_mnemonic (_("Clear all stored authentication information (username,password...)")); + gtk_widget_show (label102); + gtk_box_pack_start (GTK_BOX (hbox34), label102, FALSE, FALSE, 0); + + label101 = gtk_label_new (_("Authentication information")); + gtk_widget_show (label101); + gtk_frame_set_label_widget (GTK_FRAME (frame24), label101); + + sip_pref = gtk_label_new (_("SIP")); + gtk_widget_show (sip_pref); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (prop1notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (prop1notebook), 2), sip_pref); + gtk_label_set_justify (GTK_LABEL (sip_pref), GTK_JUSTIFY_CENTER); + + vbox13 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox13); + gtk_container_add (GTK_CONTAINER (prop1notebook), vbox13); + + frame16 = gtk_frame_new (NULL); + gtk_widget_show (frame16); + gtk_box_pack_start (GTK_BOX (vbox13), frame16, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame16), 10); + + hbox9 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox9); + gtk_container_add (GTK_CONTAINER (frame16), hbox9); + + vbox14 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox14); + gtk_box_pack_start (GTK_BOX (hbox9), vbox14, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox14), 9); + + label9 = gtk_label_new (_("List of audio codecs, in order of preference:")); + gtk_widget_show (label9); + gtk_box_pack_start (GTK_BOX (vbox14), label9, FALSE, FALSE, 4); + gtk_misc_set_alignment (GTK_MISC (label9), 0, 0.5); + + codec_notebook = gtk_notebook_new (); + gtk_widget_show (codec_notebook); + gtk_box_pack_start (GTK_BOX (vbox14), codec_notebook, TRUE, TRUE, 0); + + scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow2); + gtk_container_add (GTK_CONTAINER (codec_notebook), scrolledwindow2); + GTK_WIDGET_UNSET_FLAGS (scrolledwindow2, GTK_CAN_FOCUS); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_SHADOW_ETCHED_IN); + + au_codec_list = gtk_tree_view_new (); + gtk_widget_show (au_codec_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow2), au_codec_list); + gtk_tree_view_set_reorderable (GTK_TREE_VIEW (au_codec_list), TRUE); + + label116 = gtk_label_new (_("Audio codecs")); + gtk_widget_show (label116); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (codec_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (codec_notebook), 0), label116); + + scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow7); + gtk_container_add (GTK_CONTAINER (codec_notebook), scrolledwindow7); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_IN); + + vid_codec_list = gtk_tree_view_new (); + gtk_widget_show (vid_codec_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow7), vid_codec_list); + + label117 = gtk_label_new (_("Video Codecs")); + gtk_widget_show (label117); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (codec_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (codec_notebook), 1), label117); + + hbuttonbox4 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox4); + gtk_box_pack_start (GTK_BOX (vbox14), hbuttonbox4, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox4), 10); + + aucodec_up = gtk_button_new_from_stock ("gtk-go-up"); + gtk_widget_show (aucodec_up); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_up); + GTK_WIDGET_SET_FLAGS (aucodec_up, GTK_CAN_DEFAULT); + + aucodec_down = gtk_button_new_from_stock ("gtk-go-down"); + gtk_widget_show (aucodec_down); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_down); + GTK_WIDGET_SET_FLAGS (aucodec_down, GTK_CAN_DEFAULT); + + aucodec_enable = gtk_button_new (); + gtk_widget_show (aucodec_enable); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_enable); + GTK_WIDGET_SET_FLAGS (aucodec_enable, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (aucodec_enable), alignment1); + + hbox11 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox11); + gtk_container_add (GTK_CONTAINER (alignment1), hbox11); + + image4 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image4); + gtk_box_pack_start (GTK_BOX (hbox11), image4, FALSE, FALSE, 0); + + label50 = gtk_label_new_with_mnemonic (_("Enable")); + gtk_widget_show (label50); + gtk_box_pack_start (GTK_BOX (hbox11), label50, FALSE, FALSE, 0); + + aucodec_disable = gtk_button_new (); + gtk_widget_show (aucodec_disable); + gtk_container_add (GTK_CONTAINER (hbuttonbox4), aucodec_disable); + GTK_WIDGET_SET_FLAGS (aucodec_disable, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (aucodec_disable), alignment2); + + hbox12 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox12); + gtk_container_add (GTK_CONTAINER (alignment2), hbox12); + + image5 = gtk_image_new_from_stock ("gtk-cancel", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image5); + gtk_box_pack_start (GTK_BOX (hbox12), image5, FALSE, FALSE, 0); + + label51 = gtk_label_new_with_mnemonic (_("Disable")); + gtk_widget_show (label51); + gtk_box_pack_start (GTK_BOX (hbox12), label51, FALSE, FALSE, 0); + + table12 = gtk_table_new (2, 2, TRUE); + gtk_widget_show (table12); + gtk_box_pack_start (GTK_BOX (vbox14), table12, FALSE, TRUE, 0); + + label112 = gtk_label_new (_("Upload bandwidth (kbit/sec):")); + gtk_widget_show (label112); + gtk_table_attach (GTK_TABLE (table12), label112, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label112), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label112), 0, 0.5); + + label111 = gtk_label_new (_("Download bandwidth (kbit/sec):")); + gtk_widget_show (label111); + gtk_table_attach (GTK_TABLE (table12), label111, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label111), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label111), 0, 0.5); + + download_bw_adj = gtk_adjustment_new (0, 0, 100000, 10, 100, 10); + download_bw = gtk_spin_button_new (GTK_ADJUSTMENT (download_bw_adj), 1, 0); + gtk_widget_show (download_bw); + gtk_table_attach (GTK_TABLE (table12), download_bw, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (download_bw), GTK_UPDATE_IF_VALID); + + upload_bw_adj = gtk_adjustment_new (0, 0, 100000, 10, 100, 10); + upload_bw = gtk_spin_button_new (GTK_ADJUSTMENT (upload_bw_adj), 1, 0); + gtk_widget_show (upload_bw); + gtk_table_attach (GTK_TABLE (table12), upload_bw, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox17 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox17); + gtk_box_pack_start (GTK_BOX (hbox9), vbox17, TRUE, FALSE, 0); + + label22 = gtk_label_new (_("Note: Codecs in red are not usable regarding to your connection type to the internet.")); + gtk_widget_show (label22); + gtk_box_pack_start (GTK_BOX (vbox17), label22, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label22), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label22), TRUE); + gtk_misc_set_padding (GTK_MISC (label22), 15, 0); + + frame18 = gtk_frame_new (NULL); + gtk_widget_show (frame18); + gtk_box_pack_start (GTK_BOX (vbox17), frame18, TRUE, TRUE, 5); + gtk_container_set_border_width (GTK_CONTAINER (frame18), 8); + + codec_info = gtk_label_new (_("No information availlable")); + gtk_widget_show (codec_info); + gtk_container_add (GTK_CONTAINER (frame18), codec_info); + gtk_label_set_justify (GTK_LABEL (codec_info), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (codec_info), TRUE); + gtk_misc_set_padding (GTK_MISC (codec_info), 10, 10); + + label47 = gtk_label_new (_("Codec information")); + gtk_widget_show (label47); + gtk_frame_set_label_widget (GTK_FRAME (frame18), label47); + + label46 = gtk_label_new (_("Audio and video codecs")); + gtk_widget_show (label46); + gtk_frame_set_label_widget (GTK_FRAME (frame16), label46); + gtk_misc_set_alignment (GTK_MISC (label46), 0.53, 0.5); + + codecs_pref = gtk_label_new (_("Codecs")); + gtk_widget_show (codecs_pref); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (prop1notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (prop1notebook), 3), codecs_pref); + gtk_label_set_justify (GTK_LABEL (codecs_pref), GTK_JUSTIFY_CENTER); + + hbuttonbox7 = GTK_DIALOG (prop1)->action_area; + gtk_widget_show (hbuttonbox7); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox7), GTK_BUTTONBOX_END); + + prop_help_button = gtk_button_new_from_stock ("gtk-help"); + gtk_widget_show (prop_help_button); + gtk_dialog_add_action_widget (GTK_DIALOG (prop1), prop_help_button, GTK_RESPONSE_HELP); + GTK_WIDGET_SET_FLAGS (prop_help_button, GTK_CAN_DEFAULT); + + prop_apply_button = gtk_button_new_from_stock ("gtk-apply"); + gtk_widget_show (prop_apply_button); + gtk_dialog_add_action_widget (GTK_DIALOG (prop1), prop_apply_button, GTK_RESPONSE_APPLY); + GTK_WIDGET_SET_FLAGS (prop_apply_button, GTK_CAN_DEFAULT); + + prop_close_button = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (prop_close_button); + gtk_dialog_add_action_widget (GTK_DIALOG (prop1), prop_close_button, GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (prop_close_button, GTK_CAN_DEFAULT); + + prop_ok_button = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (prop_ok_button); + gtk_dialog_add_action_widget (GTK_DIALOG (prop1), prop_ok_button, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (prop_ok_button, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) prop1, "close", + G_CALLBACK (on_prop1_close), + NULL); + g_signal_connect ((gpointer) prop1, "close", + G_CALLBACK (on_property_box_closed), + NULL); + g_signal_connect ((gpointer) prop1, "response", + G_CALLBACK (on_property_box_response), + NULL); + g_signal_connect ((gpointer) enable_ipv6, "toggled", + G_CALLBACK (on_enable_ipv6_toggled), + NULL); + g_signal_connect ((gpointer) no_nat, "toggled", + G_CALLBACK (on_no_nat_toggled), + NULL); + g_signal_connect ((gpointer) use_stun, "toggled", + G_CALLBACK (on_use_stun_toggled), + NULL); + g_signal_connect ((gpointer) static_nat, "toggled", + G_CALLBACK (on_static_nat_toggled), + NULL); + g_signal_connect ((gpointer) nat_address, "changed", + G_CALLBACK (on_nat_address_changed), + NULL); + g_signal_connect ((gpointer) stun_server, "changed", + G_CALLBACK (on_stun_server_changed), + NULL); + g_signal_connect ((gpointer) audio_jittcomp, "value_changed", + G_CALLBACK (on_audio_jittcomp_value_changed), + NULL); + g_signal_connect ((gpointer) audioport, "changed", + G_CALLBACK (on_audioport_changed), + NULL); + g_signal_connect ((gpointer) use_sipinfo, "toggled", + G_CALLBACK (on_use_sipinfo_toggled), + NULL); + g_signal_connect ((gpointer) rec_source, "changed", + G_CALLBACK (on_source_changed), + NULL); + g_signal_connect ((gpointer) play_card, "changed", + G_CALLBACK (on_play_card_changed), + NULL); + g_signal_connect ((gpointer) capt_card, "changed", + G_CALLBACK (on_capt_card_changed), + NULL); + g_signal_connect ((gpointer) ring_card, "changed", + G_CALLBACK (on_ring_card_changed), + NULL); + g_signal_connect ((gpointer) echocancelation, "toggled", + G_CALLBACK (on_echocancelation_toggled), + NULL); + g_signal_connect ((gpointer) ringpreview, "clicked", + G_CALLBACK (on_ringpreview_clicked), + NULL); + g_signal_connect ((gpointer) sip_port, "changed", + G_CALLBACK (on_sipport_changed), + NULL); + g_signal_connect ((gpointer) user_name, "changed", + G_CALLBACK (on_user_name_changed), + NULL); + g_signal_connect ((gpointer) domain_name, "changed", + G_CALLBACK (on_domain_name_changed), + NULL); + g_signal_connect ((gpointer) guess_hostname, "toggled", + G_CALLBACK (on_guess_hostname_toggled), + NULL); + g_signal_connect ((gpointer) addproxy_button, "clicked", + G_CALLBACK (on_addproxy_button_clicked), + NULL); + g_signal_connect ((gpointer) editproxy_button, "clicked", + G_CALLBACK (on_editproxy_button_clicked), + NULL); + g_signal_connect ((gpointer) removeproxy_button, "clicked", + G_CALLBACK (on_removeproxy_button_clicked), + NULL); + g_signal_connect ((gpointer) clear_auth_info, "clicked", + G_CALLBACK (on_clear_auth_info_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_up, "clicked", + G_CALLBACK (on_aucodec_up_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_down, "clicked", + G_CALLBACK (on_aucodec_down_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_enable, "clicked", + G_CALLBACK (on_aucodec_enable_clicked), + NULL); + g_signal_connect ((gpointer) aucodec_disable, "clicked", + G_CALLBACK (on_aucodec_disable_clicked), + NULL); + g_signal_connect ((gpointer) download_bw, "value_changed", + G_CALLBACK (on_download_bw_value_changed), + NULL); + g_signal_connect ((gpointer) upload_bw, "value_changed", + G_CALLBACK (on_upload_bw_value_changed), + NULL); + g_signal_connect ((gpointer) prop_help_button, "clicked", + G_CALLBACK (on_prop1_help), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (prop1, prop1, "prop1"); + GLADE_HOOKUP_OBJECT_NO_REF (prop1, prop1box, "prop1box"); + GLADE_HOOKUP_OBJECT (prop1, prop1notebook, "prop1notebook"); + GLADE_HOOKUP_OBJECT (prop1, vbox9, "vbox9"); + GLADE_HOOKUP_OBJECT (prop1, frame26, "frame26"); + GLADE_HOOKUP_OBJECT (prop1, alignment21, "alignment21"); + GLADE_HOOKUP_OBJECT (prop1, vbox29, "vbox29"); + GLADE_HOOKUP_OBJECT (prop1, enable_ipv6, "enable_ipv6"); + GLADE_HOOKUP_OBJECT (prop1, label105, "label105"); + GLADE_HOOKUP_OBJECT (prop1, frame21, "frame21"); + GLADE_HOOKUP_OBJECT (prop1, vbox21, "vbox21"); + GLADE_HOOKUP_OBJECT (prop1, label56, "label56"); + GLADE_HOOKUP_OBJECT (prop1, table13, "table13"); + GLADE_HOOKUP_OBJECT (prop1, no_nat, "no_nat"); + GLADE_HOOKUP_OBJECT (prop1, use_stun, "use_stun"); + GLADE_HOOKUP_OBJECT (prop1, static_nat, "static_nat"); + GLADE_HOOKUP_OBJECT (prop1, nat_address, "nat_address"); + GLADE_HOOKUP_OBJECT (prop1, stun_server, "stun_server"); + GLADE_HOOKUP_OBJECT (prop1, label55, "label55"); + GLADE_HOOKUP_OBJECT (prop1, frame20, "frame20"); + GLADE_HOOKUP_OBJECT (prop1, table6, "table6"); + GLADE_HOOKUP_OBJECT (prop1, audio_jittcomp, "audio_jittcomp"); + GLADE_HOOKUP_OBJECT (prop1, audioport, "audioport"); + GLADE_HOOKUP_OBJECT (prop1, label52, "label52"); + GLADE_HOOKUP_OBJECT (prop1, label53, "label53"); + GLADE_HOOKUP_OBJECT (prop1, label54, "label54"); + GLADE_HOOKUP_OBJECT (prop1, frame25, "frame25"); + GLADE_HOOKUP_OBJECT (prop1, alignment20, "alignment20"); + GLADE_HOOKUP_OBJECT (prop1, vbox28, "vbox28"); + GLADE_HOOKUP_OBJECT (prop1, use_sipinfo, "use_sipinfo"); + GLADE_HOOKUP_OBJECT (prop1, label103, "label103"); + GLADE_HOOKUP_OBJECT (prop1, network, "network"); + GLADE_HOOKUP_OBJECT (prop1, vbox12, "vbox12"); + GLADE_HOOKUP_OBJECT (prop1, vbox20, "vbox20"); + GLADE_HOOKUP_OBJECT (prop1, frame17, "frame17"); + GLADE_HOOKUP_OBJECT (prop1, vbox16, "vbox16"); + GLADE_HOOKUP_OBJECT (prop1, table4, "table4"); + GLADE_HOOKUP_OBJECT (prop1, label10, "label10"); + GLADE_HOOKUP_OBJECT (prop1, combo3, "combo3"); + GLADE_HOOKUP_OBJECT (prop1, rec_source, "rec_source"); + GLADE_HOOKUP_OBJECT (prop1, label106, "label106"); + GLADE_HOOKUP_OBJECT (prop1, play_card, "play_card"); + GLADE_HOOKUP_OBJECT (prop1, capt_card, "capt_card"); + GLADE_HOOKUP_OBJECT (prop1, label11, "label11"); + GLADE_HOOKUP_OBJECT (prop1, ringsnddev_label, "ringsnddev_label"); + GLADE_HOOKUP_OBJECT (prop1, label63, "label63"); + GLADE_HOOKUP_OBJECT (prop1, ring_card, "ring_card"); + GLADE_HOOKUP_OBJECT (prop1, echocancelation, "echocancelation"); + GLADE_HOOKUP_OBJECT (prop1, label115, "label115"); + GLADE_HOOKUP_OBJECT (prop1, hbox20, "hbox20"); + GLADE_HOOKUP_OBJECT (prop1, ringfileentry, "ringfileentry"); + GLADE_HOOKUP_OBJECT (prop1, ringpreview, "ringpreview"); + GLADE_HOOKUP_OBJECT (prop1, alignment24, "alignment24"); + GLADE_HOOKUP_OBJECT (prop1, hbox37, "hbox37"); + GLADE_HOOKUP_OBJECT (prop1, image42, "image42"); + GLADE_HOOKUP_OBJECT (prop1, label118, "label118"); + GLADE_HOOKUP_OBJECT (prop1, label48, "label48"); + GLADE_HOOKUP_OBJECT (prop1, sound, "sound"); + GLADE_HOOKUP_OBJECT (prop1, vbox7, "vbox7"); + GLADE_HOOKUP_OBJECT (prop1, frame10, "frame10"); + GLADE_HOOKUP_OBJECT (prop1, hbox6, "hbox6"); + GLADE_HOOKUP_OBJECT (prop1, label13, "label13"); + GLADE_HOOKUP_OBJECT (prop1, sip_port, "sip_port"); + GLADE_HOOKUP_OBJECT (prop1, label43, "label43"); + GLADE_HOOKUP_OBJECT (prop1, frame11, "frame11"); + GLADE_HOOKUP_OBJECT (prop1, vbox27, "vbox27"); + GLADE_HOOKUP_OBJECT (prop1, hbox7, "hbox7"); + GLADE_HOOKUP_OBJECT (prop1, label26, "label26"); + GLADE_HOOKUP_OBJECT (prop1, label27, "label27"); + GLADE_HOOKUP_OBJECT (prop1, user_name, "user_name"); + GLADE_HOOKUP_OBJECT (prop1, label28, "label28"); + GLADE_HOOKUP_OBJECT (prop1, domain_name, "domain_name"); + GLADE_HOOKUP_OBJECT (prop1, guess_hostname, "guess_hostname"); + GLADE_HOOKUP_OBJECT (prop1, label44, "label44"); + GLADE_HOOKUP_OBJECT (prop1, frame1, "frame1"); + GLADE_HOOKUP_OBJECT (prop1, vbox23, "vbox23"); + GLADE_HOOKUP_OBJECT (prop1, scrolledwindow4, "scrolledwindow4"); + GLADE_HOOKUP_OBJECT (prop1, proxy_list, "proxy_list"); + GLADE_HOOKUP_OBJECT (prop1, hbuttonbox6, "hbuttonbox6"); + GLADE_HOOKUP_OBJECT (prop1, addproxy_button, "addproxy_button"); + GLADE_HOOKUP_OBJECT (prop1, alignment12, "alignment12"); + GLADE_HOOKUP_OBJECT (prop1, hbox25, "hbox25"); + GLADE_HOOKUP_OBJECT (prop1, image19, "image19"); + GLADE_HOOKUP_OBJECT (prop1, label77, "label77"); + GLADE_HOOKUP_OBJECT (prop1, editproxy_button, "editproxy_button"); + GLADE_HOOKUP_OBJECT (prop1, alignment13, "alignment13"); + GLADE_HOOKUP_OBJECT (prop1, hbox26, "hbox26"); + GLADE_HOOKUP_OBJECT (prop1, image20, "image20"); + GLADE_HOOKUP_OBJECT (prop1, label78, "label78"); + GLADE_HOOKUP_OBJECT (prop1, removeproxy_button, "removeproxy_button"); + GLADE_HOOKUP_OBJECT (prop1, alignment14, "alignment14"); + GLADE_HOOKUP_OBJECT (prop1, hbox27, "hbox27"); + GLADE_HOOKUP_OBJECT (prop1, image21, "image21"); + GLADE_HOOKUP_OBJECT (prop1, label79, "label79"); + GLADE_HOOKUP_OBJECT (prop1, label45, "label45"); + GLADE_HOOKUP_OBJECT (prop1, frame24, "frame24"); + GLADE_HOOKUP_OBJECT (prop1, alignment18, "alignment18"); + GLADE_HOOKUP_OBJECT (prop1, clear_auth_info, "clear_auth_info"); + GLADE_HOOKUP_OBJECT (prop1, alignment19, "alignment19"); + GLADE_HOOKUP_OBJECT (prop1, hbox34, "hbox34"); + GLADE_HOOKUP_OBJECT (prop1, image27, "image27"); + GLADE_HOOKUP_OBJECT (prop1, label102, "label102"); + GLADE_HOOKUP_OBJECT (prop1, label101, "label101"); + GLADE_HOOKUP_OBJECT (prop1, sip_pref, "sip_pref"); + GLADE_HOOKUP_OBJECT (prop1, vbox13, "vbox13"); + GLADE_HOOKUP_OBJECT (prop1, frame16, "frame16"); + GLADE_HOOKUP_OBJECT (prop1, hbox9, "hbox9"); + GLADE_HOOKUP_OBJECT (prop1, vbox14, "vbox14"); + GLADE_HOOKUP_OBJECT (prop1, label9, "label9"); + GLADE_HOOKUP_OBJECT (prop1, codec_notebook, "codec_notebook"); + GLADE_HOOKUP_OBJECT (prop1, scrolledwindow2, "scrolledwindow2"); + GLADE_HOOKUP_OBJECT (prop1, au_codec_list, "au_codec_list"); + GLADE_HOOKUP_OBJECT (prop1, label116, "label116"); + GLADE_HOOKUP_OBJECT (prop1, scrolledwindow7, "scrolledwindow7"); + GLADE_HOOKUP_OBJECT (prop1, vid_codec_list, "vid_codec_list"); + GLADE_HOOKUP_OBJECT (prop1, label117, "label117"); + GLADE_HOOKUP_OBJECT (prop1, hbuttonbox4, "hbuttonbox4"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_up, "aucodec_up"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_down, "aucodec_down"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_enable, "aucodec_enable"); + GLADE_HOOKUP_OBJECT (prop1, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (prop1, hbox11, "hbox11"); + GLADE_HOOKUP_OBJECT (prop1, image4, "image4"); + GLADE_HOOKUP_OBJECT (prop1, label50, "label50"); + GLADE_HOOKUP_OBJECT (prop1, aucodec_disable, "aucodec_disable"); + GLADE_HOOKUP_OBJECT (prop1, alignment2, "alignment2"); + GLADE_HOOKUP_OBJECT (prop1, hbox12, "hbox12"); + GLADE_HOOKUP_OBJECT (prop1, image5, "image5"); + GLADE_HOOKUP_OBJECT (prop1, label51, "label51"); + GLADE_HOOKUP_OBJECT (prop1, table12, "table12"); + GLADE_HOOKUP_OBJECT (prop1, label112, "label112"); + GLADE_HOOKUP_OBJECT (prop1, label111, "label111"); + GLADE_HOOKUP_OBJECT (prop1, download_bw, "download_bw"); + GLADE_HOOKUP_OBJECT (prop1, upload_bw, "upload_bw"); + GLADE_HOOKUP_OBJECT (prop1, vbox17, "vbox17"); + GLADE_HOOKUP_OBJECT (prop1, label22, "label22"); + GLADE_HOOKUP_OBJECT (prop1, frame18, "frame18"); + GLADE_HOOKUP_OBJECT (prop1, codec_info, "codec_info"); + GLADE_HOOKUP_OBJECT (prop1, label47, "label47"); + GLADE_HOOKUP_OBJECT (prop1, label46, "label46"); + GLADE_HOOKUP_OBJECT (prop1, codecs_pref, "codecs_pref"); + GLADE_HOOKUP_OBJECT_NO_REF (prop1, hbuttonbox7, "hbuttonbox7"); + GLADE_HOOKUP_OBJECT (prop1, prop_help_button, "prop_help_button"); + GLADE_HOOKUP_OBJECT (prop1, prop_apply_button, "prop_apply_button"); + GLADE_HOOKUP_OBJECT (prop1, prop_close_button, "prop_close_button"); + GLADE_HOOKUP_OBJECT (prop1, prop_ok_button, "prop_ok_button"); + GLADE_HOOKUP_OBJECT_NO_REF (prop1, tooltips, "tooltips"); + + return prop1; +} + +GtkWidget* +create_address_book (void) +{ + GtkWidget *address_book; + GdkPixbuf *address_book_icon_pixbuf; + GtkWidget *dialog_vbox7; + GtkWidget *vbox1; + GtkWidget *scrolledwindow1; + GtkWidget *viewport1; + GtkWidget *address_list; + GtkWidget *dialog_action_area7; + GtkWidget *hbuttonbox1; + GtkWidget *add_address; + GtkWidget *remove_address; + GtkWidget *modify_address; + GtkWidget *alignment15; + GtkWidget *hbox29; + GtkWidget *image22; + GtkWidget *label93; + GtkWidget *close_addbook; + GtkWidget *select_address; + GtkWidget *alignment7; + GtkWidget *hbox19; + GtkWidget *image14; + GtkWidget *label62; + + address_book = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (address_book), _("Address Book")); + gtk_window_set_default_size (GTK_WINDOW (address_book), -1, 305); + address_book_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (address_book_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (address_book), address_book_icon_pixbuf); + gdk_pixbuf_unref (address_book_icon_pixbuf); + } + + dialog_vbox7 = GTK_DIALOG (address_book)->vbox; + gtk_widget_show (dialog_vbox7); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (dialog_vbox7), vbox1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 12); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_box_pack_start (GTK_BOX (vbox1), scrolledwindow1, TRUE, TRUE, 0); + GTK_WIDGET_UNSET_FLAGS (scrolledwindow1, GTK_CAN_FOCUS); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN); + + viewport1 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); + + address_list = gtk_tree_view_new (); + gtk_widget_show (address_list); + gtk_container_add (GTK_CONTAINER (viewport1), address_list); + + dialog_action_area7 = GTK_DIALOG (address_book)->action_area; + gtk_widget_show (dialog_action_area7); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area7), GTK_BUTTONBOX_SPREAD); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (dialog_action_area7), hbuttonbox1); + gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 11); + + add_address = gtk_button_new_from_stock ("gtk-add"); + gtk_widget_show (add_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), add_address); + GTK_WIDGET_SET_FLAGS (add_address, GTK_CAN_DEFAULT); + gtk_button_set_relief (GTK_BUTTON (add_address), GTK_RELIEF_HALF); + + remove_address = gtk_button_new_from_stock ("gtk-delete"); + gtk_widget_show (remove_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), remove_address); + GTK_WIDGET_SET_FLAGS (remove_address, GTK_CAN_DEFAULT); + gtk_button_set_relief (GTK_BUTTON (remove_address), GTK_RELIEF_HALF); + + modify_address = gtk_button_new (); + gtk_widget_show (modify_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), modify_address); + GTK_WIDGET_SET_FLAGS (modify_address, GTK_CAN_DEFAULT); + + alignment15 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment15); + gtk_container_add (GTK_CONTAINER (modify_address), alignment15); + + hbox29 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox29); + gtk_container_add (GTK_CONTAINER (alignment15), hbox29); + + image22 = gtk_image_new_from_stock ("gtk-justify-center", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image22); + gtk_box_pack_start (GTK_BOX (hbox29), image22, FALSE, FALSE, 0); + + label93 = gtk_label_new_with_mnemonic (_("Edit")); + gtk_widget_show (label93); + gtk_box_pack_start (GTK_BOX (hbox29), label93, FALSE, FALSE, 0); + + close_addbook = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (close_addbook); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), close_addbook); + GTK_WIDGET_SET_FLAGS (close_addbook, GTK_CAN_DEFAULT); + + select_address = gtk_button_new (); + gtk_widget_show (select_address); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), select_address); + GTK_WIDGET_SET_FLAGS (select_address, GTK_CAN_DEFAULT); + + alignment7 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment7); + gtk_container_add (GTK_CONTAINER (select_address), alignment7); + + hbox19 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox19); + gtk_container_add (GTK_CONTAINER (alignment7), hbox19); + + image14 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image14); + gtk_box_pack_start (GTK_BOX (hbox19), image14, FALSE, FALSE, 0); + + label62 = gtk_label_new_with_mnemonic (_("Select")); + gtk_widget_show (label62); + gtk_box_pack_start (GTK_BOX (hbox19), label62, FALSE, FALSE, 0); + + g_signal_connect ((gpointer) add_address, "clicked", + G_CALLBACK (on_add_address_clicked), + NULL); + g_signal_connect ((gpointer) remove_address, "clicked", + G_CALLBACK (on_remove_address_clicked), + NULL); + g_signal_connect ((gpointer) modify_address, "clicked", + G_CALLBACK (on_modify_address_clicked), + NULL); + g_signal_connect ((gpointer) close_addbook, "clicked", + G_CALLBACK (address_book_close), + NULL); + g_signal_connect ((gpointer) select_address, "clicked", + G_CALLBACK (on_select_address_clicked), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (address_book, address_book, "address_book"); + GLADE_HOOKUP_OBJECT_NO_REF (address_book, dialog_vbox7, "dialog_vbox7"); + GLADE_HOOKUP_OBJECT (address_book, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (address_book, scrolledwindow1, "scrolledwindow1"); + GLADE_HOOKUP_OBJECT (address_book, viewport1, "viewport1"); + GLADE_HOOKUP_OBJECT (address_book, address_list, "address_list"); + GLADE_HOOKUP_OBJECT_NO_REF (address_book, dialog_action_area7, "dialog_action_area7"); + GLADE_HOOKUP_OBJECT (address_book, hbuttonbox1, "hbuttonbox1"); + GLADE_HOOKUP_OBJECT (address_book, add_address, "add_address"); + GLADE_HOOKUP_OBJECT (address_book, remove_address, "remove_address"); + GLADE_HOOKUP_OBJECT (address_book, modify_address, "modify_address"); + GLADE_HOOKUP_OBJECT (address_book, alignment15, "alignment15"); + GLADE_HOOKUP_OBJECT (address_book, hbox29, "hbox29"); + GLADE_HOOKUP_OBJECT (address_book, image22, "image22"); + GLADE_HOOKUP_OBJECT (address_book, label93, "label93"); + GLADE_HOOKUP_OBJECT (address_book, close_addbook, "close_addbook"); + GLADE_HOOKUP_OBJECT (address_book, select_address, "select_address"); + GLADE_HOOKUP_OBJECT (address_book, alignment7, "alignment7"); + GLADE_HOOKUP_OBJECT (address_book, hbox19, "hbox19"); + GLADE_HOOKUP_OBJECT (address_book, image14, "image14"); + GLADE_HOOKUP_OBJECT (address_book, label62, "label62"); + + return address_book; +} + +GtkWidget* +create_altressource (void) +{ + GtkWidget *altressource; + GdkPixbuf *altressource_icon_pixbuf; + GtkWidget *dialog_vbox10; + GtkWidget *vbox19; + GtkWidget *label49; + GtkWidget *alt_href; + GtkWidget *dialog_action_area10; + GtkWidget *closebutton1; + + altressource = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (altressource), _("Information")); + gtk_window_set_resizable (GTK_WINDOW (altressource), FALSE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (altressource), TRUE); + altressource_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (altressource_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (altressource), altressource_icon_pixbuf); + gdk_pixbuf_unref (altressource_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (altressource), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox10 = GTK_DIALOG (altressource)->vbox; + gtk_widget_show (dialog_vbox10); + + vbox19 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox19); + gtk_box_pack_start (GTK_BOX (dialog_vbox10), vbox19, TRUE, TRUE, 0); + + label49 = gtk_label_new (_("User is not reachable at the moment but he invites you to contact him using the following alternate ressource:")); + gtk_widget_show (label49); + gtk_box_pack_start (GTK_BOX (vbox19), label49, TRUE, TRUE, 10); + gtk_label_set_justify (GTK_LABEL (label49), GTK_JUSTIFY_CENTER); + gtk_label_set_line_wrap (GTK_LABEL (label49), TRUE); + gtk_misc_set_padding (GTK_MISC (label49), 25, 5); + + alt_href = gtk_button_new_with_mnemonic (_("None.")); + gtk_widget_show (alt_href); + gtk_box_pack_start (GTK_BOX (vbox19), alt_href, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (alt_href), 12); + gtk_button_set_relief (GTK_BUTTON (alt_href), GTK_RELIEF_NONE); + + dialog_action_area10 = GTK_DIALOG (altressource)->action_area; + gtk_widget_show (dialog_action_area10); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area10), GTK_BUTTONBOX_END); + + closebutton1 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (closebutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (altressource), closebutton1, GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (closebutton1, GTK_CAN_DEFAULT); + + g_signal_connect_swapped ((gpointer) alt_href, "clicked", + G_CALLBACK (on_alt_href_clicked), + GTK_OBJECT (altressource)); + g_signal_connect ((gpointer) alt_href, "realize", + G_CALLBACK (on_alt_href_realize), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (altressource, altressource, "altressource"); + GLADE_HOOKUP_OBJECT_NO_REF (altressource, dialog_vbox10, "dialog_vbox10"); + GLADE_HOOKUP_OBJECT (altressource, vbox19, "vbox19"); + GLADE_HOOKUP_OBJECT (altressource, label49, "label49"); + GLADE_HOOKUP_OBJECT (altressource, alt_href, "alt_href"); + GLADE_HOOKUP_OBJECT_NO_REF (altressource, dialog_action_area10, "dialog_action_area10"); + GLADE_HOOKUP_OBJECT (altressource, closebutton1, "closebutton1"); + + return altressource; +} + +GtkWidget* +create_proxy_config_box (void) +{ + GtkWidget *proxy_config_box; + GdkPixbuf *proxy_config_box_icon_pixbuf; + GtkWidget *dialog_vbox12; + GtkWidget *frame22; + GtkWidget *table8; + GtkWidget *reg_sendregister; + GtkWidget *label82; + GtkWidget *reg_route; + GtkWidget *reg_proxy; + GtkWidget *label83; + GtkWidget *label84; + GtkWidget *reg_identity; + GtkWidget *label85; + GtkObject *reg_expires_adj; + GtkWidget *reg_expires; + GtkWidget *label81; + GtkWidget *label104; + GtkWidget *publish; + GtkWidget *label86; + GtkWidget *dialog_action_area12; + GtkWidget *helpbutton1; + GtkWidget *okbutton2; + + proxy_config_box = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (proxy_config_box), _("Proxy/Registrar configuration box")); + gtk_window_set_modal (GTK_WINDOW (proxy_config_box), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (proxy_config_box), TRUE); + proxy_config_box_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (proxy_config_box_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (proxy_config_box), proxy_config_box_icon_pixbuf); + gdk_pixbuf_unref (proxy_config_box_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (proxy_config_box), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox12 = GTK_DIALOG (proxy_config_box)->vbox; + gtk_widget_show (dialog_vbox12); + + frame22 = gtk_frame_new (NULL); + gtk_widget_show (frame22); + gtk_box_pack_start (GTK_BOX (dialog_vbox12), frame22, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame22), 8); + + table8 = gtk_table_new (7, 2, FALSE); + gtk_widget_show (table8); + gtk_container_add (GTK_CONTAINER (frame22), table8); + + reg_sendregister = gtk_check_button_new_with_mnemonic (""); + gtk_widget_show (reg_sendregister); + gtk_table_attach (GTK_TABLE (table8), reg_sendregister, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (reg_sendregister), TRUE); + + label82 = gtk_label_new (_("Route (optional):")); + gtk_widget_show (label82); + gtk_table_attach (GTK_TABLE (table8), label82, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label82), 0, 0.5); + + reg_route = gtk_entry_new (); + gtk_widget_show (reg_route); + gtk_table_attach (GTK_TABLE (table8), reg_route, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_max_length (GTK_ENTRY (reg_route), 256); + + reg_proxy = gtk_entry_new (); + gtk_widget_show (reg_proxy); + gtk_table_attach (GTK_TABLE (table8), reg_proxy, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_max_length (GTK_ENTRY (reg_proxy), 250); + gtk_entry_set_text (GTK_ENTRY (reg_proxy), _("sip:")); + + label83 = gtk_label_new (_("SIP Proxy:")); + gtk_widget_show (label83); + gtk_table_attach (GTK_TABLE (table8), label83, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label83), 0, 0.5); + + label84 = gtk_label_new (_("SIP Identity:")); + gtk_widget_show (label84); + gtk_table_attach (GTK_TABLE (table8), label84, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label84), 0, 0.5); + + reg_identity = gtk_entry_new (); + gtk_widget_show (reg_identity); + gtk_table_attach (GTK_TABLE (table8), reg_identity, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_max_length (GTK_ENTRY (reg_identity), 256); + gtk_entry_set_text (GTK_ENTRY (reg_identity), _("sip:")); + + label85 = gtk_label_new (_("Registration Period:")); + gtk_widget_show (label85); + gtk_table_attach (GTK_TABLE (table8), label85, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label85), 0, 0.5); + + reg_expires_adj = gtk_adjustment_new (900, 120, 72000, 1, 10, 10); + reg_expires = gtk_spin_button_new (GTK_ADJUSTMENT (reg_expires_adj), 1, 0); + gtk_widget_show (reg_expires); + gtk_table_attach (GTK_TABLE (table8), reg_expires, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (reg_expires), TRUE); + + label81 = gtk_label_new (_("Send registration:")); + gtk_widget_show (label81); + gtk_table_attach (GTK_TABLE (table8), label81, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label81), 0, 0.5); + + label104 = gtk_label_new (_("Publish presence information:")); + gtk_widget_show (label104); + gtk_table_attach (GTK_TABLE (table8), label104, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label104), 0, 0.5); + + publish = gtk_check_button_new_with_mnemonic (""); + gtk_widget_show (publish); + gtk_table_attach (GTK_TABLE (table8), publish, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label86 = gtk_label_new (_("Proxy/Registrar configuration box")); + gtk_widget_show (label86); + gtk_frame_set_label_widget (GTK_FRAME (frame22), label86); + + dialog_action_area12 = GTK_DIALOG (proxy_config_box)->action_area; + gtk_widget_show (dialog_action_area12); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area12), GTK_BUTTONBOX_END); + + helpbutton1 = gtk_button_new_from_stock ("gtk-help"); + gtk_widget_show (helpbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (proxy_config_box), helpbutton1, GTK_RESPONSE_HELP); + GTK_WIDGET_SET_FLAGS (helpbutton1, GTK_CAN_DEFAULT); + + okbutton2 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (proxy_config_box), okbutton2, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) proxy_config_box, "response", + G_CALLBACK (on_proxy_config_box_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (proxy_config_box, proxy_config_box, "proxy_config_box"); + GLADE_HOOKUP_OBJECT_NO_REF (proxy_config_box, dialog_vbox12, "dialog_vbox12"); + GLADE_HOOKUP_OBJECT (proxy_config_box, frame22, "frame22"); + GLADE_HOOKUP_OBJECT (proxy_config_box, table8, "table8"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_sendregister, "reg_sendregister"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label82, "label82"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_route, "reg_route"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_proxy, "reg_proxy"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label83, "label83"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label84, "label84"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_identity, "reg_identity"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label85, "label85"); + GLADE_HOOKUP_OBJECT (proxy_config_box, reg_expires, "reg_expires"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label81, "label81"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label104, "label104"); + GLADE_HOOKUP_OBJECT (proxy_config_box, publish, "publish"); + GLADE_HOOKUP_OBJECT (proxy_config_box, label86, "label86"); + GLADE_HOOKUP_OBJECT_NO_REF (proxy_config_box, dialog_action_area12, "dialog_action_area12"); + GLADE_HOOKUP_OBJECT (proxy_config_box, helpbutton1, "helpbutton1"); + GLADE_HOOKUP_OBJECT (proxy_config_box, okbutton2, "okbutton2"); + + gtk_widget_grab_focus (proxy_config_box); + return proxy_config_box; +} + +GtkWidget* +create_contact_box (void) +{ + GtkWidget *contact_box; + GdkPixbuf *contact_box_icon_pixbuf; + GtkWidget *dialog_vbox13; + GtkWidget *frame23; + GtkWidget *vbox25; + GtkWidget *table10; + GtkWidget *sipaddr; + GtkWidget *name; + GtkWidget *label89; + GtkWidget *label90; + GtkWidget *label91; + GtkWidget *label92; + GtkWidget *send_subscribe; + GtkWidget *label88; + GtkWidget *dialog_action_area13; + GtkWidget *helpbutton2; + GtkWidget *cancelbutton2; + GtkWidget *okbutton3; + + contact_box = gtk_dialog_new (); + GTK_WIDGET_SET_FLAGS (contact_box, GTK_CAN_FOCUS); + gtk_window_set_title (GTK_WINDOW (contact_box), _("Edit contact information")); + gtk_window_set_destroy_with_parent (GTK_WINDOW (contact_box), TRUE); + contact_box_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (contact_box_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (contact_box), contact_box_icon_pixbuf); + gdk_pixbuf_unref (contact_box_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (contact_box), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox13 = GTK_DIALOG (contact_box)->vbox; + gtk_widget_show (dialog_vbox13); + + frame23 = gtk_frame_new (NULL); + gtk_widget_show (frame23); + gtk_box_pack_start (GTK_BOX (dialog_vbox13), frame23, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (frame23), 6); + + vbox25 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox25); + gtk_container_add (GTK_CONTAINER (frame23), vbox25); + + table10 = gtk_table_new (4, 2, TRUE); + gtk_widget_show (table10); + gtk_box_pack_start (GTK_BOX (vbox25), table10, TRUE, TRUE, 0); + + sipaddr = gtk_entry_new (); + gtk_widget_show (sipaddr); + gtk_table_attach (GTK_TABLE (table10), sipaddr, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_text (GTK_ENTRY (sipaddr), _("sip:")); + + name = gtk_entry_new (); + gtk_widget_show (name); + gtk_table_attach (GTK_TABLE (table10), name, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label89 = gtk_label_new (_("Name:")); + gtk_widget_show (label89); + gtk_table_attach (GTK_TABLE (table10), label89, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label89), 0, 0.5); + + label90 = gtk_label_new (_("Sip address:")); + gtk_widget_show (label90); + gtk_table_attach (GTK_TABLE (table10), label90, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label90), 0, 0.5); + + label91 = gtk_label_new (_("Proxy to use:")); + gtk_widget_show (label91); + gtk_table_attach (GTK_TABLE (table10), label91, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label91), 0, 0.5); + + label92 = gtk_label_new (_("Subscribe policy:")); + gtk_widget_show (label92); + gtk_table_attach (GTK_TABLE (table10), label92, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label92), 0, 0.5); + + send_subscribe = gtk_check_button_new_with_mnemonic (_("Send subscription (see person's online status)")); + gtk_widget_show (send_subscribe); + gtk_box_pack_start (GTK_BOX (vbox25), send_subscribe, TRUE, TRUE, 0); + + label88 = gtk_label_new (_("Contact information")); + gtk_widget_show (label88); + gtk_frame_set_label_widget (GTK_FRAME (frame23), label88); + + dialog_action_area13 = GTK_DIALOG (contact_box)->action_area; + gtk_widget_show (dialog_action_area13); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area13), GTK_BUTTONBOX_END); + + helpbutton2 = gtk_button_new_from_stock ("gtk-help"); + gtk_widget_show (helpbutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (contact_box), helpbutton2, GTK_RESPONSE_HELP); + GTK_WIDGET_SET_FLAGS (helpbutton2, GTK_CAN_DEFAULT); + + cancelbutton2 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (contact_box), cancelbutton2, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton2, GTK_CAN_DEFAULT); + + okbutton3 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton3); + gtk_dialog_add_action_widget (GTK_DIALOG (contact_box), okbutton3, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton3, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) contact_box, "response", + G_CALLBACK (on_contact_box_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (contact_box, contact_box, "contact_box"); + GLADE_HOOKUP_OBJECT_NO_REF (contact_box, dialog_vbox13, "dialog_vbox13"); + GLADE_HOOKUP_OBJECT (contact_box, frame23, "frame23"); + GLADE_HOOKUP_OBJECT (contact_box, vbox25, "vbox25"); + GLADE_HOOKUP_OBJECT (contact_box, table10, "table10"); + GLADE_HOOKUP_OBJECT (contact_box, sipaddr, "sipaddr"); + GLADE_HOOKUP_OBJECT (contact_box, name, "name"); + GLADE_HOOKUP_OBJECT (contact_box, label89, "label89"); + GLADE_HOOKUP_OBJECT (contact_box, label90, "label90"); + GLADE_HOOKUP_OBJECT (contact_box, label91, "label91"); + GLADE_HOOKUP_OBJECT (contact_box, label92, "label92"); + GLADE_HOOKUP_OBJECT (contact_box, send_subscribe, "send_subscribe"); + GLADE_HOOKUP_OBJECT (contact_box, label88, "label88"); + GLADE_HOOKUP_OBJECT_NO_REF (contact_box, dialog_action_area13, "dialog_action_area13"); + GLADE_HOOKUP_OBJECT (contact_box, helpbutton2, "helpbutton2"); + GLADE_HOOKUP_OBJECT (contact_box, cancelbutton2, "cancelbutton2"); + GLADE_HOOKUP_OBJECT (contact_box, okbutton3, "okbutton3"); + + return contact_box; +} + +GtkWidget* +create_inc_subscr_dialog (void) +{ + GtkWidget *inc_subscr_dialog; + GdkPixbuf *inc_subscr_dialog_icon_pixbuf; + GtkWidget *dialog_vbox14; + GtkWidget *hbox32; + GtkWidget *image25; + GtkWidget *subscr_label; + GtkWidget *dialog_action_area14; + GtkWidget *button15; + GtkWidget *alignment17; + GtkWidget *hbox31; + GtkWidget *image24; + GtkWidget *label95; + GtkWidget *button16; + GtkWidget *alignment16; + GtkWidget *hbox30; + GtkWidget *image23; + GtkWidget *label94; + + inc_subscr_dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (inc_subscr_dialog), _("New incoming subscription")); + inc_subscr_dialog_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (inc_subscr_dialog_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (inc_subscr_dialog), inc_subscr_dialog_icon_pixbuf); + gdk_pixbuf_unref (inc_subscr_dialog_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (inc_subscr_dialog), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox14 = GTK_DIALOG (inc_subscr_dialog)->vbox; + gtk_widget_show (dialog_vbox14); + + hbox32 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox32); + gtk_box_pack_start (GTK_BOX (dialog_vbox14), hbox32, TRUE, TRUE, 0); + + image25 = gtk_image_new_from_stock ("gtk-dialog-warning", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image25); + gtk_box_pack_start (GTK_BOX (hbox32), image25, FALSE, TRUE, 0); + + subscr_label = gtk_label_new (_("You have received a new subscription...")); + gtk_widget_show (subscr_label); + gtk_box_pack_start (GTK_BOX (hbox32), subscr_label, TRUE, TRUE, 0); + gtk_label_set_line_wrap (GTK_LABEL (subscr_label), TRUE); + gtk_misc_set_padding (GTK_MISC (subscr_label), 14, 9); + + dialog_action_area14 = GTK_DIALOG (inc_subscr_dialog)->action_area; + gtk_widget_show (dialog_action_area14); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area14), GTK_BUTTONBOX_SPREAD); + + button15 = gtk_button_new (); + gtk_widget_show (button15); + gtk_dialog_add_action_widget (GTK_DIALOG (inc_subscr_dialog), button15, GTK_RESPONSE_REJECT); + GTK_WIDGET_SET_FLAGS (button15, GTK_CAN_DEFAULT); + + alignment17 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment17); + gtk_container_add (GTK_CONTAINER (button15), alignment17); + + hbox31 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox31); + gtk_container_add (GTK_CONTAINER (alignment17), hbox31); + + image24 = gtk_image_new_from_stock ("gtk-stop", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image24); + gtk_box_pack_start (GTK_BOX (hbox31), image24, FALSE, FALSE, 0); + + label95 = gtk_label_new_with_mnemonic (_("Refuse")); + gtk_widget_show (label95); + gtk_box_pack_start (GTK_BOX (hbox31), label95, FALSE, FALSE, 0); + + button16 = gtk_button_new (); + gtk_widget_show (button16); + gtk_dialog_add_action_widget (GTK_DIALOG (inc_subscr_dialog), button16, GTK_RESPONSE_ACCEPT); + GTK_WIDGET_SET_FLAGS (button16, GTK_CAN_DEFAULT); + + alignment16 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment16); + gtk_container_add (GTK_CONTAINER (button16), alignment16); + + hbox30 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox30); + gtk_container_add (GTK_CONTAINER (alignment16), hbox30); + + image23 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image23); + gtk_box_pack_start (GTK_BOX (hbox30), image23, FALSE, FALSE, 0); + + label94 = gtk_label_new_with_mnemonic (_("Accept")); + gtk_widget_show (label94); + gtk_box_pack_start (GTK_BOX (hbox30), label94, FALSE, FALSE, 0); + + g_signal_connect ((gpointer) inc_subscr_dialog, "response", + G_CALLBACK (on_inc_subscr_dialog_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (inc_subscr_dialog, inc_subscr_dialog, "inc_subscr_dialog"); + GLADE_HOOKUP_OBJECT_NO_REF (inc_subscr_dialog, dialog_vbox14, "dialog_vbox14"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, hbox32, "hbox32"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, image25, "image25"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, subscr_label, "subscr_label"); + GLADE_HOOKUP_OBJECT_NO_REF (inc_subscr_dialog, dialog_action_area14, "dialog_action_area14"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, button15, "button15"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, alignment17, "alignment17"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, hbox31, "hbox31"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, image24, "image24"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, label95, "label95"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, button16, "button16"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, alignment16, "alignment16"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, hbox30, "hbox30"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, image23, "image23"); + GLADE_HOOKUP_OBJECT (inc_subscr_dialog, label94, "label94"); + + return inc_subscr_dialog; +} + +GtkWidget* +create_authentication_dialog (void) +{ + GtkWidget *authentication_dialog; + GdkPixbuf *authentication_dialog_icon_pixbuf; + GtkWidget *dialog_vbox15; + GtkWidget *vbox26; + GtkWidget *hbox33; + GtkWidget *image26; + GtkWidget *question; + GtkWidget *table11; + GtkWidget *realm; + GtkWidget *username; + GtkWidget *passwd; + GtkWidget *userid; + GtkWidget *label100; + GtkWidget *label99; + GtkWidget *label98; + GtkWidget *label97; + GtkWidget *dialog_action_area15; + GtkWidget *cancelbutton3; + GtkWidget *okbutton4; + + authentication_dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (authentication_dialog), _("Authentication requested")); + gtk_window_set_destroy_with_parent (GTK_WINDOW (authentication_dialog), TRUE); + authentication_dialog_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (authentication_dialog_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (authentication_dialog), authentication_dialog_icon_pixbuf); + gdk_pixbuf_unref (authentication_dialog_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (authentication_dialog), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox15 = GTK_DIALOG (authentication_dialog)->vbox; + gtk_widget_show (dialog_vbox15); + + vbox26 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox26); + gtk_box_pack_start (GTK_BOX (dialog_vbox15), vbox26, TRUE, TRUE, 0); + + hbox33 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox33); + gtk_box_pack_start (GTK_BOX (vbox26), hbox33, FALSE, FALSE, 0); + + image26 = gtk_image_new_from_stock ("gtk-dialog-question", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image26); + gtk_box_pack_start (GTK_BOX (hbox33), image26, TRUE, TRUE, 0); + gtk_misc_set_padding (GTK_MISC (image26), 16, 0); + + question = gtk_label_new (_("Authentication required for realm")); + gtk_widget_show (question); + gtk_box_pack_start (GTK_BOX (hbox33), question, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (question), GTK_JUSTIFY_CENTER); + gtk_misc_set_padding (GTK_MISC (question), 29, 14); + + table11 = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table11); + gtk_box_pack_start (GTK_BOX (vbox26), table11, TRUE, TRUE, 0); + + realm = gtk_entry_new (); + gtk_widget_show (realm); + gtk_table_attach (GTK_TABLE (table11), realm, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_editable_set_editable (GTK_EDITABLE (realm), FALSE); + + username = gtk_entry_new (); + gtk_widget_show (username); + gtk_table_attach (GTK_TABLE (table11), username, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + passwd = gtk_entry_new (); + gtk_widget_show (passwd); + gtk_table_attach (GTK_TABLE (table11), passwd, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_visibility (GTK_ENTRY (passwd), FALSE); + + userid = gtk_entry_new (); + gtk_widget_show (userid); + gtk_table_attach (GTK_TABLE (table11), userid, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label100 = gtk_label_new (_("userid:")); + gtk_widget_show (label100); + gtk_table_attach (GTK_TABLE (table11), label100, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label100), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label100), 0, 0.5); + + label99 = gtk_label_new (_("password:")); + gtk_widget_show (label99); + gtk_table_attach (GTK_TABLE (table11), label99, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label99), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label99), 0, 0.5); + + label98 = gtk_label_new (_("username:")); + gtk_widget_show (label98); + gtk_table_attach (GTK_TABLE (table11), label98, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label98), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label98), 0, 0.5); + + label97 = gtk_label_new (_("realm:")); + gtk_widget_show (label97); + gtk_table_attach (GTK_TABLE (table11), label97, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label97), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment (GTK_MISC (label97), 0, 0.5); + + dialog_action_area15 = GTK_DIALOG (authentication_dialog)->action_area; + gtk_widget_show (dialog_action_area15); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area15), GTK_BUTTONBOX_END); + + cancelbutton3 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton3); + gtk_dialog_add_action_widget (GTK_DIALOG (authentication_dialog), cancelbutton3, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton3, GTK_CAN_DEFAULT); + + okbutton4 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton4); + gtk_dialog_add_action_widget (GTK_DIALOG (authentication_dialog), okbutton4, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton4, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) authentication_dialog, "response", + G_CALLBACK (on_authentication_dialog_response), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (authentication_dialog, authentication_dialog, "authentication_dialog"); + GLADE_HOOKUP_OBJECT_NO_REF (authentication_dialog, dialog_vbox15, "dialog_vbox15"); + GLADE_HOOKUP_OBJECT (authentication_dialog, vbox26, "vbox26"); + GLADE_HOOKUP_OBJECT (authentication_dialog, hbox33, "hbox33"); + GLADE_HOOKUP_OBJECT (authentication_dialog, image26, "image26"); + GLADE_HOOKUP_OBJECT (authentication_dialog, question, "question"); + GLADE_HOOKUP_OBJECT (authentication_dialog, table11, "table11"); + GLADE_HOOKUP_OBJECT (authentication_dialog, realm, "realm"); + GLADE_HOOKUP_OBJECT (authentication_dialog, username, "username"); + GLADE_HOOKUP_OBJECT (authentication_dialog, passwd, "passwd"); + GLADE_HOOKUP_OBJECT (authentication_dialog, userid, "userid"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label100, "label100"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label99, "label99"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label98, "label98"); + GLADE_HOOKUP_OBJECT (authentication_dialog, label97, "label97"); + GLADE_HOOKUP_OBJECT_NO_REF (authentication_dialog, dialog_action_area15, "dialog_action_area15"); + GLADE_HOOKUP_OBJECT (authentication_dialog, cancelbutton3, "cancelbutton3"); + GLADE_HOOKUP_OBJECT (authentication_dialog, okbutton4, "okbutton4"); + + return authentication_dialog; +} + +GtkWidget* +create_call_logs (void) +{ + GtkWidget *call_logs; + GdkPixbuf *call_logs_icon_pixbuf; + GtkWidget *dialog_vbox16; + GtkWidget *scrolledwindow5; + GtkWidget *logview; + GtkWidget *dialog_action_area16; + GtkWidget *closebutton2; + + call_logs = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (call_logs), _("Linphone - Call history")); + gtk_window_set_default_size (GTK_WINDOW (call_logs), 240, 240); + gtk_window_set_destroy_with_parent (GTK_WINDOW (call_logs), TRUE); + call_logs_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (call_logs_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (call_logs), call_logs_icon_pixbuf); + gdk_pixbuf_unref (call_logs_icon_pixbuf); + } + gtk_window_set_type_hint (GTK_WINDOW (call_logs), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox16 = GTK_DIALOG (call_logs)->vbox; + gtk_widget_show (dialog_vbox16); + + scrolledwindow5 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow5); + gtk_box_pack_start (GTK_BOX (dialog_vbox16), scrolledwindow5, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_SHADOW_IN); + + logview = gtk_text_view_new (); + gtk_widget_show (logview); + gtk_container_add (GTK_CONTAINER (scrolledwindow5), logview); + gtk_text_view_set_editable (GTK_TEXT_VIEW (logview), FALSE); + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (logview), FALSE); + + dialog_action_area16 = GTK_DIALOG (call_logs)->action_area; + gtk_widget_show (dialog_action_area16); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area16), GTK_BUTTONBOX_END); + + closebutton2 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (closebutton2); + gtk_dialog_add_action_widget (GTK_DIALOG (call_logs), closebutton2, GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (closebutton2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) call_logs, "response", + G_CALLBACK (on_call_logs_response), + NULL); + g_signal_connect ((gpointer) call_logs, "destroy", + G_CALLBACK (on_call_logs_destroy), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (call_logs, call_logs, "call_logs"); + GLADE_HOOKUP_OBJECT_NO_REF (call_logs, dialog_vbox16, "dialog_vbox16"); + GLADE_HOOKUP_OBJECT (call_logs, scrolledwindow5, "scrolledwindow5"); + GLADE_HOOKUP_OBJECT (call_logs, logview, "logview"); + GLADE_HOOKUP_OBJECT_NO_REF (call_logs, dialog_action_area16, "dialog_action_area16"); + GLADE_HOOKUP_OBJECT (call_logs, closebutton2, "closebutton2"); + + return call_logs; +} + +GtkWidget* +create_chatroom (void) +{ + GtkWidget *chatroom; + GdkPixbuf *chatroom_icon_pixbuf; + GtkWidget *vbox30; + GtkWidget *scrolledwindow6; + GtkWidget *chattext; + GtkWidget *hbox35; + GtkWidget *label107; + GtkWidget *chatentry; + GtkWidget *button17; + + chatroom = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (chatroom), _("Chat Room")); + gtk_window_set_default_size (GTK_WINDOW (chatroom), 400, 400); + gtk_window_set_destroy_with_parent (GTK_WINDOW (chatroom), TRUE); + chatroom_icon_pixbuf = create_pixbuf ("linphone2.xpm"); + if (chatroom_icon_pixbuf) + { + gtk_window_set_icon (GTK_WINDOW (chatroom), chatroom_icon_pixbuf); + gdk_pixbuf_unref (chatroom_icon_pixbuf); + } + + vbox30 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox30); + gtk_container_add (GTK_CONTAINER (chatroom), vbox30); + + scrolledwindow6 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow6); + gtk_box_pack_start (GTK_BOX (vbox30), scrolledwindow6, TRUE, TRUE, 0); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_SHADOW_IN); + + chattext = gtk_text_view_new (); + gtk_widget_show (chattext); + gtk_container_add (GTK_CONTAINER (scrolledwindow6), chattext); + gtk_text_view_set_editable (GTK_TEXT_VIEW (chattext), FALSE); + + hbox35 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox35); + gtk_box_pack_start (GTK_BOX (vbox30), hbox35, FALSE, TRUE, 0); + + label107 = gtk_label_new (_("Text:")); + gtk_widget_show (label107); + gtk_box_pack_start (GTK_BOX (hbox35), label107, FALSE, FALSE, 0); + + chatentry = gtk_entry_new (); + gtk_widget_show (chatentry); + gtk_box_pack_start (GTK_BOX (hbox35), chatentry, TRUE, TRUE, 0); + + button17 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (button17); + gtk_box_pack_start (GTK_BOX (vbox30), button17, FALSE, FALSE, 0); + + g_signal_connect ((gpointer) chatroom, "destroy", + G_CALLBACK (on_chatroom_destroy), + NULL); + g_signal_connect ((gpointer) chatentry, "activate", + G_CALLBACK (on_chatentry_activate), + NULL); + g_signal_connect ((gpointer) button17, "clicked", + G_CALLBACK (on_chatbox_clicked), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (chatroom, chatroom, "chatroom"); + GLADE_HOOKUP_OBJECT (chatroom, vbox30, "vbox30"); + GLADE_HOOKUP_OBJECT (chatroom, scrolledwindow6, "scrolledwindow6"); + GLADE_HOOKUP_OBJECT (chatroom, chattext, "chattext"); + GLADE_HOOKUP_OBJECT (chatroom, hbox35, "hbox35"); + GLADE_HOOKUP_OBJECT (chatroom, label107, "label107"); + GLADE_HOOKUP_OBJECT (chatroom, chatentry, "chatentry"); + GLADE_HOOKUP_OBJECT (chatroom, button17, "button17"); + + gtk_widget_grab_focus (chatentry); + return chatroom; +} + +GtkWidget* +create_aboutdialog1 (void) +{ + GtkWidget *aboutdialog1; + const gchar *authors[] = { + "Simon MORLAT", + "Aymeric Moizard", + "Sharath K Udupa", + NULL + }; + const gchar *documenters[] = { + "Simon MORLAT", + "Philippe Beau", + NULL + }; + gchar *translators = "it: Alberto Zanoni\nde: Jean Jacques Sarton\nfr: Simon Morlat\nes: Jesus Benitez\nja: Yamaguchi Yoshiya\npl: obert Nasiadek \npt_BR: Rafael Caesar Lenzi \nsv: Daniel Nylander "; + GdkPixbuf *aboutdialog1_logo_pixbuf; + + aboutdialog1 = gtk_about_dialog_new (); + gtk_container_set_border_width (GTK_CONTAINER (aboutdialog1), 5); + gtk_window_set_destroy_with_parent (GTK_WINDOW (aboutdialog1), TRUE); + gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog1), VERSION); + gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog1), _("Linphone")); + gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (aboutdialog1), _("C: 2001\nMade in Old Europe")); + gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog1), _("Linphone is a web-phone.\nIt is compatible with SIP and RTP protocols.")); + gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (aboutdialog1), " This program is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; either version 2 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"); + gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (aboutdialog1), "http://www.linphone.org"); + gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (aboutdialog1), authors); + gtk_about_dialog_set_documenters (GTK_ABOUT_DIALOG (aboutdialog1), documenters); + gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (aboutdialog1), translators); + aboutdialog1_logo_pixbuf = create_pixbuf ("linphone.png"); + gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (aboutdialog1), aboutdialog1_logo_pixbuf); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (aboutdialog1, aboutdialog1, "aboutdialog1"); + + return aboutdialog1; +} + diff --git a/linphone/gtk/interface.h b/linphone/gtk/interface.h new file mode 100644 index 000000000..4556c2706 --- /dev/null +++ b/linphone/gtk/interface.h @@ -0,0 +1,16 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_app1 (void); +GtkWidget* create_about2 (void); +GtkWidget* create_prop1 (void); +GtkWidget* create_address_book (void); +GtkWidget* create_altressource (void); +GtkWidget* create_proxy_config_box (void); +GtkWidget* create_contact_box (void); +GtkWidget* create_inc_subscr_dialog (void); +GtkWidget* create_authentication_dialog (void); +GtkWidget* create_call_logs (void); +GtkWidget* create_chatroom (void); +GtkWidget* create_aboutdialog1 (void); diff --git a/linphone/gtk/linphone.c b/linphone/gtk/linphone.c new file mode 100644 index 000000000..29c212526 --- /dev/null +++ b/linphone/gtk/linphone.c @@ -0,0 +1,482 @@ +/*************************************************************************** + linphone.c - Main code for linphone's gnome + interface + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "linphone.h" +#include "support.h" +#include "interface.h" +#include "callbacks.h" +#include "gui_utils.h" +#include "lpconfig.h" + +#include + + +LinphoneGnomeUI *uiobj=NULL; +#define get_uiobj() (uiobj) +#define get_core() (uiobj->core) +#define get_friend_list() (&uiobj->main_window.friendlist) + +void linphone_gnome_ui_init(LinphoneGnomeUI *ui,LinphoneCore *core) +{ + memset(ui,0,sizeof(LinphoneGnomeUI)); + ui->core=core; + uiobj=ui; + ui->main_window.shown_once=FALSE; +} + +static void restore_uri_history(GtkEntry *uribar, LpConfig *cfg){ + char key[20]; + int i; + GtkEntryCompletion *gep=gtk_entry_completion_new(); + GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING); + for (i=0;;i++){ + const char *uri; + snprintf(key,sizeof(key),"uri%i",i); + uri=lp_config_get_string(cfg,"GtkUi",key,NULL); + if (uri!=NULL) { + GtkTreeIter iter; + gtk_list_store_append(model,&iter); + gtk_list_store_set(model,&iter,0,uri,-1); + if (i==0) gtk_entry_set_text(uribar,uri); + } + else break; + } + gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); + gtk_entry_completion_set_text_column(gep,0); + gtk_entry_set_completion(uribar,gep); +} + +void linphone_gnome_save_uri_history(LinphoneGnomeUI *ui){ + char key[20]; + int i=0; + char *uri=NULL; + GtkTreeIter iter; + GtkEntry *uribar=GTK_ENTRY(ui->main_window.addressentry); + GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar)); + LpConfig *cfg=linphone_core_get_config(ui->core); + if (!gtk_tree_model_get_iter_first(model,&iter)) return; + do { + gtk_tree_model_get(model,&iter,0,&uri,-1); + if (uri) { + snprintf(key,sizeof(key),"uri%i",i); + lp_config_set_string(cfg,"GtkUi",key,uri); + g_free(uri); + }else break; + i++; + if (i>5) break; + }while(gtk_tree_model_iter_next(model,&iter)); +} + +void main_window_create(LinphoneGnomeUI *obj) +{ + GtkWidget *child; + GtkWidget *window; + window=create_app1 (); +#ifdef NOTYET + gnome_window_icon_set_from_default(GTK_WINDOW(window)); +#endif + obj->main_window.status_bar=lookup_widget(window,"appbar1"); + obj->main_window.addressentry=lookup_widget(window,"addressentry"); + obj->main_window.optioncontrols=lookup_widget(window,"optioncontrols"); + obj->main_window.dtmfentry=lookup_widget(window,"dtmf_entry"); + obj->main_window.callbutton=lookup_widget(window,"callbutton"); + child=lookup_widget(window,"showmore"); + /* hide the optionnal controls at startup */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(child),0); +#ifndef VIDEO_ENABLED + gtk_widget_hide(lookup_widget(child,"video_enabled")); +#else + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(lookup_widget(child,"video_enabled")), + linphone_core_video_enabled(obj->core)); +#endif + presence_box_init(&obj->main_window.presencebox,window,obj->core); + friend_list_init(&obj->main_window.friendlist,obj->core,window); + g_object_set_data(G_OBJECT(window),"ui",(gpointer)obj); + obj->main_window.window=window; +} + +void linphone_gnome_ui_show(LinphoneGnomeUI *ui) +{ + if (ui->main_window.window==NULL){ + main_window_create(ui); + + } + gtk_widget_show(ui->main_window.window); + ui->main_window.shown_once=TRUE; +} + +void linphone_gnome_ui_hide(LinphoneGnomeUI *ui) +{ + if (ui->main_window.window==NULL) return; + gtk_widget_hide(ui->main_window.window); +} + + +void linphone_gnome_ui_uninit(LinphoneGnomeUI *ui) +{ + ui->main_window.window=NULL; +} + +void linphone_gnome_ui_display_something(LinphoneGnomeUI *ui,GtkMessageType type,const gchar *message) +{ + GtkWidget *dialog; + + linphone_gnome_ui_show(ui); + if (type==GTK_MESSAGE_QUESTION) + { +#ifdef VINCENT_MAURY_RSVP + /* draw a question box. link to dialog_click callback */ + dialog = gtk_message_dialog_new ( + GTK_WINDOW(ui->main_window.window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + (const gchar*)message); + /* connect the click event to the callback */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (dialog_click), + G_OBJECT (dialog)); + /* actually show the box */ + gtk_widget_show(dialog); +#endif + } + else + { + dialog = gtk_message_dialog_new (GTK_WINDOW(ui->main_window.window), + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + GTK_BUTTONS_CLOSE, + (const gchar*)message); + /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + gtk_widget_show(dialog); + } +} + +/* these are the LinphoneCore virtual functions */ +void linphone_gnome_display_message(LinphoneCore *lc, const char *message) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_INFO,message); +} + +#ifdef VINCENT_MAURY_RSVP +/* Question box with yes/no answer. */ +void linphone_gnome_display_yes_no(LinphoneCore *lc,const char *message) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + if (strcmp(message,"With QoS")==0) + /* the caller asks for QoS, this function is called because, by default, + * you don't use QoS ! */ + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_QUESTION, + _("The caller asks for resource reservation. Do you agree ?")); + else + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_QUESTION, + _("The caller doesn't use resource reservation. \ + Do you wish to continue anyway ?")); +} +#endif + +void linphone_gnome_display_warning(LinphoneCore *lc, const char *warning) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + linphone_gnome_ui_display_something(ui,GTK_MESSAGE_WARNING,warning); +} + +void linphone_gnome_display_status(LinphoneCore *lc, const char *status) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + if (ui->main_window.window==NULL) return; + if (!ui->main_window.shown_once) return; /* avoid a gnome bug*/ + gtk_statusbar_push(GTK_STATUSBAR(ui->main_window.status_bar), + gtk_statusbar_get_context_id(GTK_STATUSBAR(ui->main_window.status_bar),"") + ,status); +} + +void linphone_gnome_inv_recv(LinphoneCore *lc,const char *from) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + gchar *title; + if (ui->main_window.window==NULL) return; + gtk_entry_set_text(GTK_ENTRY(ui->main_window.addressentry),from); + title=g_strdup_printf(_("linphone - receiving call from %s"),from); + gtk_window_set_title(GTK_WINDOW(ui->main_window.window),title); + gdk_window_set_keep_above (ui->main_window.window->window, 1); + g_free(title); +} + +void linphone_gnome_show(LinphoneCore *lc) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + linphone_gnome_ui_show(ui); +} + +void linphone_gnome_display_url(LinphoneCore *lc, const char *message, const char *url) +{ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + alt_ressource_display(ui,url); +} + + + +void linphone_gnome_notify_received(LinphoneCore *lc,LinphoneFriend *fid, const char *from, const char *status, const char *img){ + FriendList *fl=get_friend_list(); + friend_list_set_friend_status(fl,fid,from,status, img); +} + +void linphone_gnome_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + GtkWidget *d=create_inc_subscr_dialog(); + gchar *text=g_strdup_printf(_("You have received a subscription from %s." + "This means that this person wishes to be notified of your presence information (online, busy, away...).\n" + "Do you agree ?"),url); + gtk_label_set_text(GTK_LABEL(lookup_widget(d,"subscr_label")),text); + g_object_set_data(G_OBJECT(d),"friend_ref",(gpointer)lf); + gtk_widget_show(d); +} + +static gboolean destroy_auth(GtkWidget *w){ + gtk_widget_destroy(w); + return FALSE; +} + +void linphone_gnome_prompt_authentication(LinphoneCore *lc, const gchar *realm, const gchar *username){ + GtkWidget *w=create_authentication_dialog(); + gchar *question=g_strdup_printf(_("Authentication required for realm %s"),realm); + gtk_label_set_text(GTK_LABEL(lookup_widget(w,"question")),question); + g_free(question); + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"realm")),realm); + gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"username")),username); + gtk_widget_show(w); + //automatically destroys the window after 30 seconds to avoid multiple windows to be popped up after some hours. + g_timeout_add(30000,(GtkFunction)destroy_auth,w); +} + +void linphone_gnome_bye_recv(LinphoneCore *lc, const char *from){ + LinphoneGnomeUI *ui=(LinphoneGnomeUI*)lc->data; + gtk_window_set_title(GTK_WINDOW(ui->main_window.window),"linphone"); +} + +void stub(){ +} + +void linphone_gnome_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl){ + LinphoneGnomeUI *ui=(LinphoneGnomeUI *)linphone_core_get_user_data(lc); + linphone_gnome_update_call_logs(ui); +} + +void linphone_gnome_text_received(LinphoneCore *lc,LinphoneChatRoom *cr, const char *from, const char *msg){ + GtkWidget *gcr=(GtkWidget*)linphone_chat_room_get_user_data(cr); + if (gcr==NULL){ + gcr=chatroom_new(from,cr); + } + gtk_widget_show(gcr); + chatroom_append(gcr,from,msg); +} + +LinphoneCoreVTable linphone_gnome_vtable= +{ + show: linphone_gnome_show, + inv_recv: linphone_gnome_inv_recv, + bye_recv : linphone_gnome_bye_recv, + notify_recv: linphone_gnome_notify_received, + new_unknown_subscriber: linphone_gnome_new_unknown_subscriber, + auth_info_requested: linphone_gnome_prompt_authentication, + display_status : linphone_gnome_display_status, + display_message : linphone_gnome_display_message, + display_warning : linphone_gnome_display_warning, +#ifdef VINCENT_MAURY_RSVP + display_yes_no : linphone_gnome_display_yes_no, +#endif + display_url : linphone_gnome_display_url, + display_question : stub, + call_log_updated : linphone_gnome_call_log_updated, + text_received: linphone_gnome_text_received +}; + +gboolean linphone_gnome_iterate(LinphoneCore *lc) +{ + linphone_core_iterate(lc); + return TRUE; +} + +void proxy_changed(GtkWidget *combo){ + LinphoneProxyConfig *pcfg=proxy_combo_box_get_selected(combo); + linphone_core_set_default_proxy(get_core(),pcfg); +} + +void linphone_refresh_proxy_combo_box(GtkWidget *window){ + LinphoneCore *lc=get_core(); + GtkWidget *combo; + const MSList *elem=linphone_core_get_proxy_config_list(lc); + LinphoneProxyConfig *cfg=NULL; + GtkWidget *hbox=lookup_widget(window,"proxy_hbox"); + + linphone_core_get_default_proxy(lc,&cfg); + + if (elem==NULL){ + gtk_widget_hide(hbox); + return; + } + combo=(GtkWidget*)g_object_get_data(G_OBJECT(hbox),"proxy"); + if (combo!=NULL){ + gtk_widget_destroy(combo); + } + combo=proxy_combo_box_new(cfg); + g_object_set_data(G_OBJECT(hbox),"proxy",(gpointer)combo); + g_signal_connect(G_OBJECT(combo),"changed",G_CALLBACK(proxy_changed),NULL); + gtk_box_pack_start_defaults(GTK_BOX(hbox),combo); + gtk_widget_show(combo); + gtk_widget_show(hbox); + +} + +void linphone_gnome_init(LinphoneGnomeUI *ui,LinphoneCore *lc) +{ + gchar *configfile_name = + g_strdup_printf ("%s/.gnome2/linphone", getenv ("HOME")); + linphone_gnome_ui_init(ui,lc); + linphone_gnome_ui_show(ui); + linphone_core_init(lc,&linphone_gnome_vtable,configfile_name,(gpointer)ui); + g_free(configfile_name); + set_levels(ui,linphone_core_get_rec_level(lc),linphone_core_get_play_level(lc),linphone_core_get_ring_level(lc)); + /* get history of uri bar */ + restore_uri_history(GTK_ENTRY(ui->main_window.addressentry), linphone_core_get_config(lc)); + linphone_refresh_proxy_combo_box(ui->main_window.window); + ui->timeout_id=gtk_timeout_add(20,(GtkFunction)linphone_gnome_iterate,(gpointer)lc); +} + +void linphone_gnome_uninit(LinphoneGnomeUI *ui) +{ + LinphoneCore *lc=ui->core; + linphone_gnome_ui_uninit(ui); + linphone_core_uninit(lc); + gtk_timeout_remove (ui->timeout_id); +} + +GtkWidget *proxy_combo_box_new(LinphoneProxyConfig *selected){ + GtkWidget *combo; + const MSList *elem; + GtkListStore *store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_POINTER); + GtkTreeIter iter; + GtkTreeIter prxiter; + GtkCellRenderer *renderer; + gboolean proxy_found=FALSE; + /* fill the store */ + elem=linphone_core_get_proxy_config_list(get_core()); + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,_("None"),1,(gpointer)NULL,-1); + for(;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *proxy=(LinphoneProxyConfig*)elem->data; + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,proxy->reg_proxy,1,(gpointer)proxy,-1); + if (selected==proxy) { + prxiter=iter; + proxy_found=TRUE; + } + } + combo=gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, + "text", 0, + NULL); + if (proxy_found){ + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),&prxiter); + }else{ + /*else select "None" */ + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),0); + } + return combo; +} + +LinphoneProxyConfig *proxy_combo_box_get_selected(GtkWidget *combo){ + LinphoneProxyConfig *pcfg=NULL; + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo),&iter)){ + GtkTreeModel *model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)); + gtk_tree_model_get(model,&iter,1,(gpointer)&pcfg,-1); + } + return pcfg; +} + +void linphone_gnome_update_call_logs(LinphoneGnomeUI *ui){ + LinphoneCore *lc=ui->core; + GtkTextView *tv; + GtkTextBuffer *tb; + GtkTextIter begin,end; + GtkTextTag *tag; + MSList *elem; + if (ui->logs==NULL) return; + tv=GTK_TEXT_VIEW(lookup_widget(ui->logs,"logview")); + tb=gtk_text_view_get_buffer(tv); + + gtk_text_buffer_get_bounds(tb,&begin,&end); + gtk_text_buffer_delete(tb,&begin,&end); + gtk_text_buffer_get_end_iter(tb,&end); + for (elem=linphone_core_get_call_logs(lc);elem!=NULL;elem=ms_list_next(elem)){ + LinphoneCallLog *cl=(LinphoneCallLog*)elem->data; + gchar *str=linphone_call_log_to_str(cl); + tag=NULL; + if (cl->status==LinphoneCallMissed){ + tag=gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(tb),"redforeground"); + if (tag==NULL) tag = gtk_text_buffer_create_tag (tb, "redforeground", + "foreground", "red", NULL); + } + gtk_text_buffer_insert_with_tags(tb,&end,str,-1,tag,NULL); + gtk_text_buffer_insert(tb,&end,"\n",-1); + + ms_free(str); + } +} + +void linphone_gnome_show_call_logs_window(LinphoneGnomeUI *ui){ + if (ui->logs==NULL) { + ui->logs=create_call_logs(); + } + linphone_gnome_update_call_logs(ui); + gtk_widget_show(ui->logs); +} diff --git a/linphone/gtk/linphone.h b/linphone/gtk/linphone.h new file mode 100644 index 000000000..983815529 --- /dev/null +++ b/linphone/gtk/linphone.h @@ -0,0 +1,68 @@ + + +#ifndef LINPHONE_H +#define LINPHONE_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#define _(String) gettext (String) + +#include +#include "lpconfig.h" + +#include "support.h" +#include "propertybox.h" +#include "presence.h" +#include "addressbook.h" +#include "friends.h" + +typedef struct _LinphoneMainWindow +{ + GtkWidget *window; + GtkWidget *status_bar; + GtkWidget *addressentry; + GtkWidget *optioncontrols; + GtkWidget *dtmfentry; + GtkWidget *callbutton; + PresenceBox presencebox; + FriendList friendlist; + gboolean shown_once; +}LinphoneMainWindow; + +typedef struct _LinphoneGnomeUI +{ + LinphoneMainWindow main_window; + LinphonePropertyBox propbox; + GtkWidget *ab; /*the address book */ + GtkWidget *logs; /* the call logs window */ + LinphoneCore *core; + guint timeout_id; +}LinphoneGnomeUI; + + +void linphone_gnome_ui_init(LinphoneGnomeUI *ui,LinphoneCore *core); +void linphone_gnome_ui_show(LinphoneGnomeUI *ui); +void linphone_gnome_ui_hide(LinphoneGnomeUI *ui); +void linphone_gnome_ui_uninit(LinphoneGnomeUI *ui); + +void linphone_gnome_init(LinphoneGnomeUI *ui,LinphoneCore *lc); +void linphone_gnome_uninit(LinphoneGnomeUI *ui); + +extern LinphoneGnomeUI *uiobj; + +GtkWidget *proxy_combo_box_new(LinphoneProxyConfig *selected); +void linphone_refresh_proxy_combo_box(GtkWidget *window); +LinphoneProxyConfig *proxy_combo_box_get_selected(GtkWidget *combo); +void linphone_gnome_show_call_logs_window(LinphoneGnomeUI *ui); +void linphone_gnome_update_call_logs(LinphoneGnomeUI *ui); +void linphone_gnome_ui_display_something(LinphoneGnomeUI *ui,GtkMessageType type,const gchar *message); +void linphone_gnome_save_uri_history(LinphoneGnomeUI *ui); + +GtkWidget *chatroom_new(const gchar *url, LinphoneChatRoom *cr); +void chatroom_append(GtkWidget *gcr, const gchar *from, const gchar *message); +void chatroom_close(GtkWidget *gcr); + +#endif diff --git a/linphone/gtk/main.c b/linphone/gtk/main.c new file mode 100644 index 000000000..646d5540f --- /dev/null +++ b/linphone/gtk/main.c @@ -0,0 +1,74 @@ +/* + * Initial main.c file generated by Glade. Edit as required. + * Glade will not overwrite this file. + */ + + +#include "linphone.h" + +/* +#include "../osipua/src/dbgalloc.h" + +GMemVTable dbgtable={ + smalloc, + srealloc, + sfree, + scalloc, + smalloc, + srealloc +}; +*/ +LinphoneCore core; +LinphoneGnomeUI ui; +static gboolean verbose=0; +GOptionEntry linphone_options[2]={ + { + .long_name="verbose", + .short_name= '\0', + .arg=G_OPTION_ARG_NONE, + .arg_data= (gpointer)&verbose, + .description="log to stdout some debug information while running." + } +}; + +int +main (int argc, char *argv[]) +{ + void *p; + + g_thread_init(NULL); + //g_log_set_fatal_mask("GLib",G_LOG_LEVEL_WARNING); + //g_mem_set_vtable(glib_mem_profiler_table); + //g_mem_set_vtable(&dbgtable); +#ifdef ENABLE_NLS + p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); + if (p==NULL) perror("bindtextdomain failed"); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); +#else + printf("NLS disabled.\n"); +#endif + +#ifdef NOWOBSOLETE_NOTYET + gnome_program_init ("linphone", LINPHONE_VERSION, LIBGNOMEUI_MODULE, + argc, argv, + GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR, + GNOME_PARAM_POPT_TABLE,&linphone_options,NULL); +#endif + if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"), + linphone_options,NULL,NULL)) + return -1; + add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); + add_pixmap_directory("pixmaps"); + + if (verbose) linphone_core_enable_logs(stdout); + else linphone_core_disable_logs(); + linphone_gnome_init(&ui,&core); + linphone_gnome_ui_show(&ui); + gtk_main (); + gdk_threads_leave(); /* it appears that the gdk lock is hold while exiting from gtk_main() */ + linphone_gnome_uninit(&ui); + //g_mem_profile(); + exit(0); + return 0; +} diff --git a/linphone/gtk/presence.c b/linphone/gtk/presence.c new file mode 100644 index 000000000..18042b2c8 --- /dev/null +++ b/linphone/gtk/presence.c @@ -0,0 +1,150 @@ +/*************************************************************************** + presence.c - code for the presence box + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "linphone.h" +#include "callbacks.h" +#include "support.h" + + +void presence_box_init(PresenceBox *p, GtkWidget *main_window,LinphoneCore *lc) +{ + GtkWidget *r; + p->lc=lc; + p->contact_field=lookup_widget(main_window,"contact_field"); + p->minutesaway=lookup_widget(main_window,"minutesaway"); + r=lookup_widget(main_window,"presence_reachable"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(r),TRUE); + r=lookup_widget(main_window,"presence_frame"); +} + +void presence_box_changed(PresenceBox *p) +{ + presence_box_apply(p); +} + +#define get_presence_box() (&(uiobj)->main_window.presencebox) + + +void +on_reachable (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + p->toggled_button=PRESENCE_MODE_REACHABLE; + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + //gtk_widget_set_sensitive(p->contact_field,FALSE); + presence_box_changed(p); +} + + +void +on_busy (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + p->toggled_button=PRESENCE_MODE_BUSY; + //gtk_widget_set_sensitive(p->minutesaway,TRUE); + presence_box_changed(p); +} + + +void +on_minutesaway_changed (GtkEditable *editable,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + presence_box_changed(p); +} + + +void +on_away (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + //gtk_widget_set_sensitive(p->minutesaway,TRUE); + p->toggled_button=PRESENCE_MODE_AWAY; + presence_box_changed(p); +} + + +void +on_do_not_disturb (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,FALSE); + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + p->toggled_button=PRESENCE_MODE_NOT_DISTURB; + presence_box_changed(p); +} + + +void +on_moved_tmply (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,TRUE); + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + p->toggled_button=PRESENCE_MODE_MOVED; + presence_box_changed(p); +} + + +void +on_alt_serv (GtkToggleButton *togglebutton,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + if (!gtk_toggle_button_get_active(togglebutton)) return; + //gtk_widget_set_sensitive(p->contact_field,TRUE); + //gtk_widget_set_sensitive(p->minutesaway,FALSE); + p->toggled_button=PRESENCE_MODE_ALT_SERVICE; + presence_box_changed(p); +} + + +void +on_contact_field_changed (GtkEditable *entry,gpointer user_data) +{ + PresenceBox *p=get_presence_box(); + presence_box_changed(p); +} + +void presence_box_apply(PresenceBox *p) +{ + gchar *tmp,*contact=NULL; + int minutes_away=-1; + g_message("presence_box_apply"); + /* retrieve the minutes away */ + tmp = gtk_editable_get_chars (GTK_EDITABLE(p->minutesaway),0,-1); + if (tmp!=NULL && strlen(tmp)>0) + { + minutes_away = atoi(tmp); + g_free(tmp); + } + /* retrieve the alternate contact url */ + tmp = gtk_editable_get_chars (GTK_EDITABLE(p->contact_field),0,-1); + if (tmp!=NULL && strlen(tmp)>0) + { + contact=tmp; + } + /* set presence mode */ + linphone_core_set_presence_info(p->lc,minutes_away,contact,p->toggled_button); + if (tmp!=NULL) g_free(tmp); +} diff --git a/linphone/gtk/presence.h b/linphone/gtk/presence.h new file mode 100644 index 000000000..cbe8701c7 --- /dev/null +++ b/linphone/gtk/presence.h @@ -0,0 +1,43 @@ +/*************************************************************************** + presence.h - code for the presence box + ------------------- + begin : Mon Dec 17 2001 + copyright : (C) 2001 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef PRESENCE_H +#define PRESENCE_H + +enum { PRESENCE_MODE_REACHABLE=LINPHONE_STATUS_ONLINE, + PRESENCE_MODE_BUSY=LINPHONE_STATUS_BUSY, + PRESENCE_MODE_AWAY=LINPHONE_STATUS_AWAY, + PRESENCE_MODE_NOT_DISTURB=LINPHONE_STATUS_NOT_DISTURB, + PRESENCE_MODE_MOVED=LINPHONE_STATUS_MOVED, + PRESENCE_MODE_ALT_SERVICE=LINPHONE_STATUS_ALT_SERVICE + }; + + +typedef struct _PresenceBox +{ + LinphoneCore *lc; + GtkWidget *minutesaway; + GtkWidget *contact_field; + gint toggled_button; /* indicate which button is toggled*/ +} PresenceBox; + + +void presence_box_init(PresenceBox *p, GtkWidget *main_window,LinphoneCore *lc); +void presence_box_changed(PresenceBox *p); +void presence_box_apply(PresenceBox *p); + +#endif diff --git a/linphone/gtk/propertybox.c b/linphone/gtk/propertybox.c new file mode 100644 index 000000000..3a4b472ed --- /dev/null +++ b/linphone/gtk/propertybox.c @@ -0,0 +1,1107 @@ +/*************************************************************************** + propertybox.c - description + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include "linphone.h" + +enum{ +#ifdef INET6 + IFACE_INDEX, +#endif + IFACE_NAME, + IFACE_ADDR, + IFACE_NCOLUMNS +}; + +enum { + CODEC_NAME, + CODEC_RATE, + CODEC_BITRATE, + CODEC_STATUS, + CODEC_PRIVDATA, + CODEC_COLOR, + CODEC_NCOLUMNS +}; + +#define get_core() (uiobj->core) +#define get_property_box() (&uiobj->propbox) +#ifdef NOTYET +#define property_box_changed() gnome_property_box_changed(GNOME_PROPERTY_BOX ( (&uiobj->propbox)->prop)) +#else +#define property_box_changed() +#endif +#define get_main_window() (&uiobj->main_window) + +#if !GTK_CHECK_VERSION(2,6,0) +static gchar * _lp_combo_box_get_active_text (GtkComboBox *combobox) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gchar *text = NULL; + model = gtk_combo_box_get_model (combobox); + if (gtk_combo_box_get_active_iter (combobox, &iter) && model) + gtk_tree_model_get (model, &iter, 0, &text, -1); + return text; +} +#endif /* GTK+ < 2.6.0 */ + +void net_section_init(NetSection *sec, GtkWidget *prop) +{ + sec->au_port=lookup_widget(prop,"audioport"); + sec->audio_jittcomp=lookup_widget(prop,"audio_jittcomp"); +#ifdef LINPHONE_DEPRECATED + sec->interfaces=lookup_widget(prop, "interfaces"); +#endif + sec->nat_address=lookup_widget(prop,"nat_address"); + sec->use_sipinfo=lookup_widget(prop,"use_sipinfo"); + sec->enable_ipv6=lookup_widget(prop,"enable_ipv6"); +} + +void codec_list_update(GtkTreeView *listview); + + +void net_selection_changed_cb(GtkTreeSelection *select, gpointer userdata) +{ + property_box_changed(); +} + +void net_section_fill(NetSection *sec,LinphoneCore *lc) +{ + gfloat value; + const gchar *nat_address,*stun_server; + + value=(gfloat)linphone_core_get_audio_jittcomp(lc); + /* put the current value of jitt_comp*/ + gtk_adjustment_set_value (gtk_range_get_adjustment(GTK_RANGE(sec->audio_jittcomp)),value); + /* display current rtp port */ + gtk_spin_button_set_value(GTK_SPIN_BUTTON(sec->au_port), + (gfloat)linphone_core_get_audio_port(lc)); + + + /* nat setup */ + nat_address=linphone_core_get_nat_address(lc); + + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS) + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(lookup_widget(get_property_box()->prop,"static_nat")) + ,TRUE); + + if (nat_address!=NULL) { + gtk_entry_set_text(GTK_ENTRY(sec->nat_address),nat_address); + } + stun_server=linphone_core_get_stun_server(lc); + if (stun_server!=NULL) + gtk_entry_set_text( + GTK_ENTRY(lookup_widget(get_property_box()->prop,"stun_server")), + stun_server); + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN) + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(lookup_widget(get_property_box()->prop,"use_stun")),TRUE); + + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sec->use_sipinfo), + linphone_core_get_use_info_for_dtmf(lc)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sec->enable_ipv6), + linphone_core_ipv6_enabled(lc)); +} + +void +on_enable_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); + +} + + + +void +on_nat_address_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_enable_ipv6_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + + +void net_section_apply(NetSection *sec,LinphoneCore *lc) +{ + gboolean use_nat,use_stun; + gchar *name; + + use_nat=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + lookup_widget(get_property_box()->prop,"static_nat"))); + name=gtk_editable_get_chars(GTK_EDITABLE(sec->nat_address),0,-1); + linphone_core_set_nat_address(lc,name); + g_free(name); + + use_stun=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + lookup_widget(get_property_box()->prop,"use_stun") )); + name=gtk_editable_get_chars(GTK_EDITABLE( + lookup_widget(get_property_box()->prop,"stun_server") ),0,-1); + linphone_core_set_stun_server(lc,name); + g_free(name); + if (use_stun) linphone_core_set_firewall_policy(lc, + LINPHONE_POLICY_USE_STUN); + else if (use_nat) linphone_core_set_firewall_policy(lc, + LINPHONE_POLICY_USE_NAT_ADDRESS); + else linphone_core_set_firewall_policy(lc, + LINPHONE_POLICY_NO_FIREWALL); + + { + /* get the value of jitt_comp*/ + GtkAdjustment *adj= gtk_range_get_adjustment(GTK_RANGE(sec->audio_jittcomp)); + linphone_core_set_audio_jittcomp(lc,(gint)adj->value); + /* get rtp port */ + adj=gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(sec->au_port)); + linphone_core_set_audio_port(lc,(gint)adj->value); + } + linphone_core_enable_ipv6(lc,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sec->enable_ipv6))); +} + + +enum{ + PROXY_CONFIG_IDENTITY, + PROXY_CONFIG_REF, + PROXY_CONFIG_NCOL +}; + +void sip_section_init(SipSection *sec,GtkWidget *prop) +{ + + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select; + sec->port=lookup_widget(prop,"sip_port"); + sec->username=lookup_widget(prop, "user_name"); + sec->hostname=lookup_widget(prop,"domain_name"); + sec->proxy_list=lookup_widget(prop,"proxy_list"); + sec->guess_hostname=lookup_widget(prop,"guess_hostname"); + /* create the proxy list */ + store = gtk_list_store_new (PROXY_CONFIG_NCOL, G_TYPE_STRING, G_TYPE_POINTER); + + gtk_tree_view_set_model(GTK_TREE_VIEW(sec->proxy_list),GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Account"), + renderer, + "text", PROXY_CONFIG_IDENTITY, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (sec->proxy_list), column); + + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (sec->proxy_list)); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); +} + + +void proxy_list_fill(GtkTreeModel *model, LinphoneCore *lc){ + const MSList *elem; + GtkTreeIter iter; + /* fill the proxy list */ + gtk_list_store_clear(GTK_LIST_STORE(model)); + elem=linphone_core_get_proxy_config_list(lc); + for(;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *pcfg=(LinphoneProxyConfig*)elem->data; + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,PROXY_CONFIG_IDENTITY,pcfg->reg_identity, + PROXY_CONFIG_REF,pcfg,-1); + } +} + +void sip_section_fill(SipSection *sec, LinphoneCore *lc) +{ + osip_from_t *contact; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(sec->proxy_list)); + + /* set sip port */ + gtk_spin_button_set_value(GTK_SPIN_BUTTON(sec->port), + (gfloat)linphone_core_get_sip_port(lc)); + contact=linphone_core_get_primary_contact_parsed(lc); + g_return_if_fail(contact!=NULL); + /* set sip username */ + gtk_entry_set_text(GTK_ENTRY(sec->username),contact->url->username); + /* set domain name */ + gtk_entry_set_text(GTK_ENTRY(sec->hostname),contact->url->host); + osip_from_free(contact); + proxy_list_fill(model,lc); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sec->guess_hostname), + linphone_core_get_guess_hostname(lc)); +} + +void sip_section_apply(SipSection *sec, LinphoneCore *lc) +{ + GtkAdjustment *adj; + gchar *tmp; + gchar *username,*hostname; + /* get sip port*/ + adj=gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(sec->port)); + + username=gtk_editable_get_chars(GTK_EDITABLE(sec->username),0,-1); + if (username!=NULL && strlen(username)!=0) + { + hostname=gtk_editable_get_chars(GTK_EDITABLE(sec->hostname),0,-1); + if (hostname!=NULL && strlen(hostname)!=0) + { + tmp=g_strdup_printf("sip:%s@%s",username,hostname); + linphone_core_set_primary_contact(lc,tmp); + linphone_core_set_sip_port(lc,(int)gtk_adjustment_get_value(adj)); + g_free(hostname); + g_free(tmp); + } + g_free(username); + } +} + + +void +on_addproxy_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *w=create_proxy_config_box(); + gtk_widget_show(w); +} + + +void +on_editproxy_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *w; + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneProxyConfig * cfg; + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (get_property_box()->sip.proxy_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,PROXY_CONFIG_REF , &cfg, -1); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + linphone_proxy_config_edit(cfg); + }else return; + w=create_proxy_config_box(); + gtk_widget_show(w); + if (cfg->reg_proxy!=NULL) gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"reg_proxy")),cfg->reg_proxy); + if (cfg->reg_route!=NULL) gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"reg_route")),cfg->reg_route); + if (cfg->reg_identity!=NULL) gtk_entry_set_text(GTK_ENTRY(lookup_widget(w,"reg_identity")),cfg->reg_identity); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"reg_sendregister")),cfg->reg_sendregister); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(w,"publish")),cfg->publish); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(lookup_widget(w,"reg_expires")),cfg->expires); + g_object_set_data(G_OBJECT(w),"edited_config",(gpointer)cfg); +} + + +void +on_removeproxy_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneProxyConfig * cfg; + select = gtk_tree_view_get_selection (GTK_TREE_VIEW (get_property_box()->sip.proxy_list)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + gtk_tree_model_get (model, &iter,PROXY_CONFIG_REF , &cfg, -1); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + linphone_core_remove_proxy_config(get_core(),cfg); + linphone_refresh_proxy_combo_box(get_main_window()->window); + } +} + +void get_proxy_config_box_data(GtkWidget *dialog) +{ + gchar *tmp; + gboolean editing=FALSE; + LinphoneProxyConfig *cfg; + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_proxy")),0,-1); + cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(dialog),"edited_config"); + if (cfg==NULL){ + cfg=linphone_proxy_config_new(); + linphone_proxy_config_set_server_addr(cfg,tmp); + g_free(tmp); + if (cfg==NULL) { + /* set an error message here */ + return; + } + }else{ + linphone_proxy_config_set_server_addr(cfg,tmp); + g_free(tmp); + editing=TRUE; + } + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_route")),0,-1); + linphone_proxy_config_set_route(cfg,tmp); + g_free(tmp); + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_identity")),0,-1); + linphone_proxy_config_set_identity(cfg,tmp); + g_free(tmp); + tmp=gtk_editable_get_chars(GTK_EDITABLE(lookup_widget(dialog,"reg_expires")),0,-1); + { + int exp; + if (tmp!=NULL) + { + exp = atoi(tmp); + if (exp<=0) + exp = 200; /* minimum */ + if (exp>7200) + exp = 7200; /* maximum */ + linphone_proxy_config_expires(cfg,exp); + } + } + g_free(tmp); + linphone_proxy_config_enableregister(cfg,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog,"reg_sendregister")))); + linphone_proxy_config_enable_publish(cfg,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog,"publish")))); + if (editing) linphone_proxy_config_done(cfg); + else linphone_core_add_proxy_config(get_core(),cfg); + /* set the last entered/changed proxy as the default one */ + linphone_core_set_default_proxy(get_core(),cfg); + proxy_list_fill(gtk_tree_view_get_model(GTK_TREE_VIEW(get_property_box()->sip.proxy_list)),get_core()); + linphone_refresh_proxy_combo_box(get_main_window()->window); +} + +void +on_proxy_config_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + switch(response_id){ + case GTK_RESPONSE_OK: + get_proxy_config_box_data(GTK_WIDGET(dialog)); + gtk_widget_destroy(GTK_WIDGET(dialog)); + + break; + } +} + + +void codec_section_init(CodecSection *sec, GtkWidget *prop) +{ + sec->au_codec_list=lookup_widget(prop,"au_codec_list"); + sec->vi_codec_list=lookup_widget(prop,"vid_codec_list"); + sec->codec_info=lookup_widget(prop,"codec_info"); +} + +void codec_selection_changed_cb(GtkTreeSelection *selection, gpointer data) +{ + GtkTreeIter iter; + GtkTreeModel *model; + struct _PayloadType *pt=NULL; + LinphonePropertyBox *prop=get_property_box(); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, CODEC_PRIVDATA, &pt, -1); + g_return_if_fail(pt!=NULL); + /* display the codec information */ + gtk_label_set_text(GTK_LABEL(prop->codec.codec_info),payload_type_get_description(pt)); + } +} + +void codec_list_build(GtkTreeView *listview,const MSList *codeclist) +{ + const MSList *elem; + GtkListStore *store = gtk_list_store_new (CODEC_NCOLUMNS, G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_FLOAT, + G_TYPE_STRING, + G_TYPE_POINTER, + G_TYPE_STRING); + GtkTreeIter iter; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *select=gtk_tree_view_get_selection (listview); + for(elem=codeclist; elem!=NULL; elem=elem->next){ + gchar *status; + gint rate; + gfloat bitrate; + gchar *color; + struct _PayloadType *pt=(struct _PayloadType *)elem->data; + if (payload_type_enabled(pt)) status=_("Enabled"); + else status=_("Disabled"); + if (linphone_core_check_payload_type_usability(get_core(),pt)) color="blue"; + else color="red"; + /* get an iterator */ + gtk_list_store_append(store,&iter); + bitrate=payload_type_get_bitrate(pt)/1000.0; + rate=payload_type_get_rate(pt); + gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt), + CODEC_RATE,rate, + CODEC_BITRATE,bitrate, + CODEC_STATUS,status, + CODEC_PRIVDATA,(gpointer)pt, + CODEC_COLOR,(gpointer)color, + -1); + } + gtk_tree_view_set_model(listview,GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", CODEC_NAME, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Rate (Hz)"), + renderer, + "text", CODEC_RATE, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Status"), + renderer, + "text", CODEC_STATUS, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + column = gtk_tree_view_column_new_with_attributes (_("Min bitrate (kbit/s)"), + renderer, + "text", CODEC_BITRATE, + "foreground",CODEC_COLOR, + NULL); + gtk_tree_view_append_column (listview, column); + + /* Setup the selection handler */ + select = gtk_tree_view_get_selection (listview); + gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + //gtk_tree_view_columns_autosize(GTK_TREE_VIEW (sec->interfaces)); + g_signal_connect (G_OBJECT (select), "changed", + G_CALLBACK (codec_selection_changed_cb), + NULL); +} + +void codec_section_fill(CodecSection *sec, LinphoneCore *lc, GtkWidget *propbox) +{ + /* display prefered codecs*/ + int value; + const MSList *audio_codecs=linphone_core_get_audio_codecs(lc); + const MSList *video_codecs=linphone_core_get_video_codecs(lc); + codec_list_build(GTK_TREE_VIEW(sec->au_codec_list),audio_codecs); + codec_list_build(GTK_TREE_VIEW(lookup_widget(propbox,"vid_codec_list")),video_codecs); + value=linphone_core_get_download_bandwidth(lc); + if (value!=0) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(lookup_widget(propbox,"download_bw")),value); + else + gtk_entry_set_text(GTK_ENTRY(lookup_widget(propbox,"download_bw")),_("Unlimited")); + value=linphone_core_get_upload_bandwidth(lc); + if (value!=0) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(lookup_widget(propbox,"upload_bw")),value); + else + gtk_entry_set_text(GTK_ENTRY(lookup_widget(propbox,"upload_bw")),_("Unlimited")); +} + +void codec_section_apply(CodecSection *sec, LinphoneCore *lc) +{ + GtkTreeIter iter; + struct _PayloadType *pt; + MSList *codeclist=NULL; + gchar *status; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(sec->au_codec_list)); + /* retrieve the codec list */ + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + gtk_tree_model_get (model, &iter, CODEC_STATUS,&status,CODEC_PRIVDATA, &pt,-1); + g_return_if_fail(pt!=NULL); + if (strcmp(status,_("Enabled"))==0) payload_type_set_enable(pt,1); + else payload_type_set_enable(pt,0); + codeclist=ms_list_append(codeclist,pt); + }while (gtk_tree_model_iter_next(model,&iter)); + linphone_core_set_audio_codecs(lc,codeclist); + model=gtk_tree_view_get_model(GTK_TREE_VIEW(sec->vi_codec_list)); + /* retrieve the codec list */ + codeclist=NULL; + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + gtk_tree_model_get (model, &iter, CODEC_STATUS,&status,CODEC_PRIVDATA, &pt,-1); + g_return_if_fail(pt!=NULL); + if (strcmp(status,_("Enabled"))==0) payload_type_set_enable(pt,1); + else payload_type_set_enable(pt,0); + codeclist=ms_list_append(codeclist,pt); + }while (gtk_tree_model_iter_next(model,&iter)); + linphone_core_set_video_codecs(lc,codeclist); +} + +void sound_section_init(SoundSection *sec, GtkWidget *prop) +{ + sec->source_entry=lookup_widget(prop,"rec_source"); + sec->ringfileentry=lookup_widget(prop,"ringfileentry"); +} + + +void +on_play_card_changed (GtkComboBox *combobox, + gpointer user_data) +{ +#if GTK_CHECK_VERSION(2,6,0) + char *dev=gtk_combo_box_get_active_text(combobox); +#else /* GTK < 2.6.0 */ + char *dev=_lp_combo_box_get_active_text(combobox); +#endif /* GTK < 2.6.0 */ + linphone_core_set_playback_device(get_core(),dev); + property_box_changed(); + g_free(dev); +} + + +void +on_capt_card_changed (GtkComboBox *combobox, + gpointer user_data) +{ +#if GTK_CHECK_VERSION(2,6,0) + char * dev=gtk_combo_box_get_active_text(combobox); +#else /* GTK < 2.6.0 */ + char * dev=_lp_combo_box_get_active_text(combobox); +#endif /* GTK < 2.6.0 */ + linphone_core_set_capture_device(get_core(),dev); + property_box_changed(); + g_free(dev); +} + +void +on_ring_card_changed (GtkComboBox *combobox, + gpointer user_data) +{ +#if GTK_CHECK_VERSION(2,6,0) + char * dev=gtk_combo_box_get_active_text(combobox); +#else /* GTK < 2.6.0 */ + char * dev=_lp_combo_box_get_active_text(combobox); +#endif /* GTK < 2.6.0 */ + if(dev != NULL) + { + linphone_core_set_ringer_device(get_core(),dev); + property_box_changed(); + g_free(dev); + } +} + +static int get_dev_index(const char **devnames, const char *dev){ + int i; + for (i=0;devnames[i]!=NULL;i++){ + if (strcmp(devnames[i],dev)==0) + return i; + } + g_warning("could not find %s in device list.",dev); + return 0; +} + +void sound_section_fill(SoundSection *sec, LinphoneCore *lc) +{ + GtkComboBox *play_card=GTK_COMBO_BOX(lookup_widget(get_property_box()->prop,"play_card")); + GtkComboBox *capt_card=GTK_COMBO_BOX(lookup_widget(get_property_box()->prop,"capt_card")); + GtkComboBox *ring_card=GTK_COMBO_BOX(lookup_widget(get_property_box()->prop,"ring_card")); + int i; + const char **devnames=linphone_core_get_sound_devices(lc); + /* select used sound drivers*/ + + for (i=0;devnames[i]!=NULL;i++){ + const char *carddesc=devnames[i]; + gtk_combo_box_append_text(play_card,carddesc); + gtk_combo_box_append_text(capt_card,carddesc); + gtk_combo_box_append_text(ring_card,carddesc); + } + /*select used cards */ + gtk_combo_box_set_active(play_card,get_dev_index(devnames,linphone_core_get_playback_device(lc))); + gtk_combo_box_set_active(capt_card,get_dev_index(devnames,linphone_core_get_capture_device(lc))); + gtk_combo_box_set_active(ring_card,get_dev_index(devnames,linphone_core_get_ringer_device(lc))); + /* select audio source*/ + switch(linphone_core_get_sound_source(lc)) + { + case 'm': + gtk_entry_set_text (GTK_ENTRY (sec->source_entry), _("micro")); + break; + case 'l': + gtk_entry_set_text (GTK_ENTRY (sec->source_entry), _("line")); + break; + default: + g_warning("Invalid source !"); + } + { + const gchar *ringfile=linphone_core_get_ring(lc); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(sec->ringfileentry),ringfile); + + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(get_property_box()->prop,"echocancelation")),linphone_core_echo_cancelation_enabled(lc)); +} + + + + +void sound_section_apply(SoundSection *sec, LinphoneCore *lc) +{ + gchar *tmp; + + /* get audio source*/ + tmp=gtk_editable_get_chars(GTK_EDITABLE(sec->source_entry),0,-1); + if (strcmp(tmp,_("micro"))==0) linphone_core_set_sound_source(lc,'m'); + else if (strcmp(tmp,_("line"))==0) linphone_core_set_sound_source(lc,'l'); + g_free(tmp); + + /* get ring path */ + tmp=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(sec->ringfileentry)); + if(tmp != NULL) + { + linphone_core_set_ring(lc,tmp); + g_free(tmp); + } +} + +void ring_finished(LinphoneCore *lc,gpointer user_data) +{ + GtkWidget *button=(GtkWidget*)user_data; + LinphonePropertyBox *prop=get_property_box(); + if (prop->prop==NULL) return; /* the box has been closed before the end of the preview */ + gtk_widget_set_sensitive(button,1); +} + +void +on_ringpreview_clicked (GtkButton *button, + gpointer user_data) +{ + int err; + gchar *tmp; + LinphonePropertyBox *prop=get_property_box(); + LinphoneCore *lc=get_core(); + /* get ring path */ + tmp=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(prop->sound.ringfileentry)); + err=linphone_core_preview_ring(lc,tmp,ring_finished,(gpointer)button); + if (err==0) gtk_widget_set_sensitive(GTK_WIDGET(button),0); + g_free(tmp); +} + + +void linphone_property_box_fill(LinphonePropertyBox * box, LinphoneCore *lp) +{ + net_section_fill(&box->net,lp); + sip_section_fill(&box->sip,lp); + codec_section_fill(&box->codec,lp,box->prop); + sound_section_fill(&box->sound,lp); + /* set uchanged state to the prop1 box, because gtk_entry_set_text() causes signal "changed" + to be sent */ +#ifdef NOTYET + gnome_property_box_set_state(GNOME_PROPERTY_BOX(box->prop),0); +#else + fprintf(stderr, "not yet implemented\n"); +#endif +} + +void linphone_property_box_init(LinphonePropertyBox *box) +{ + GtkWidget *prop=create_prop1(); + box->prop=prop; + net_section_init(&box->net,prop); + sip_section_init(&box->sip,prop); + codec_section_init(&box->codec,prop); + sound_section_init(&box->sound,prop); + gtk_widget_show(prop); + linphone_property_box_fill(box,get_core()); +} + + + + +void linphone_property_box_apply (gint pagenum) +{ + LinphonePropertyBox *prop=get_property_box(); + LinphoneCore *lc=get_core(); + switch(pagenum) + { + case 0: + net_section_apply(&prop->net,lc); + break; + case 1: + sound_section_apply(&prop->sound,lc); + break; + case 2: + sip_section_apply(&prop->sip,lc); + break; + case 3: + codec_section_apply(&prop->codec,lc); + break; + } +} + + +void +on_audioport_changed (GtkEditable *editable, + gpointer user_data) +{ +#ifdef NOTYET + LinphonePropertyBox *prop=get_property_box(); + gnome_property_box_changed(GNOME_PROPERTY_BOX(prop->prop)); + return; +#endif +} + + +void +on_sipport_changed (GtkEditable *editable, + gpointer user_data) +{ +#ifdef NOTYET + LinphonePropertyBox *prop=get_property_box(); + gnome_property_box_changed(GNOME_PROPERTY_BOX(prop->prop)); + return; +#endif +} + + +void +on_source_changed (GtkEditable *editable, + gpointer user_data) +{ +#ifdef NOTYET + LinphonePropertyBox *prop=get_property_box(); + gnome_property_box_changed(GNOME_PROPERTY_BOX(prop->prop)); +#endif +} + +enum { + CODEC_ACTION_UP, + CODEC_ACTION_DOWN +}; + + +void codec_row_move(GtkTreeView *listview, int action) +{ + GtkTreeIter iter; + GtkTreeIter previter,nextiter,newiter; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreePath *treepath; + struct _PayloadType *codec=NULL; + gchar *name=NULL; + gint rate; + gfloat bitrate; + gchar *status=NULL; + gchar *color=NULL; + + selection=gtk_tree_view_get_selection(listview); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, CODEC_NAME,&name, + CODEC_RATE,&rate, + CODEC_BITRATE,&bitrate, + CODEC_STATUS,&status, + CODEC_PRIVDATA, &codec, + CODEC_COLOR,&color, + -1); + g_return_if_fail(codec!=NULL); + switch(action){ + case CODEC_ACTION_UP: + /* get an iterator on the prev codec */ + treepath=gtk_tree_model_get_path(model,&iter); + if (!gtk_tree_path_prev(treepath)){ + /* codec is the first, no match. */ + return; + } + gtk_tree_model_get_iter(model,&previter,treepath); + gtk_list_store_insert_before(GTK_LIST_STORE(model),&newiter,&previter); + break; + case CODEC_ACTION_DOWN: + /* get an iterator on the next codec */ + nextiter=iter; + if (!gtk_tree_model_iter_next(model,&nextiter)){ + /* codec is the last, no match. */ + return; + } + gtk_list_store_insert_after(GTK_LIST_STORE(model),&newiter,&nextiter); + + break; + } + gtk_list_store_set(GTK_LIST_STORE(model),&newiter, + CODEC_NAME,name, + CODEC_RATE,rate, + CODEC_BITRATE,bitrate, + CODEC_STATUS,status, + CODEC_PRIVDATA, codec, + CODEC_COLOR,color, + -1); + /* remove the selected line */ + gtk_list_store_remove(GTK_LIST_STORE(model),&iter); + gtk_tree_selection_select_iter(selection,&newiter); + g_free(name); + g_free(status); + g_free(color); + } +} + +static void codec_move(int action){ + GtkTreeView *listview; + int page=gtk_notebook_get_current_page(GTK_NOTEBOOK( + lookup_widget(get_property_box()->prop,"codec_notebook"))); + if (page==0) + listview=GTK_TREE_VIEW(get_property_box()->codec.au_codec_list); + else + listview=GTK_TREE_VIEW(lookup_widget(get_property_box()->prop,"vid_codec_list")); + codec_row_move(listview,action); + property_box_changed(); +} + +void +on_aucodec_up_clicked (GtkButton *button, + gpointer user_data) +{ + codec_move(CODEC_ACTION_UP); +} + + +void +on_aucodec_down_clicked (GtkButton *button, + gpointer user_data) +{ + codec_move(CODEC_ACTION_DOWN); +} + +void codec_set_status(GtkTreeView *listview,gboolean status) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gchar *statusstring; + selection=gtk_tree_view_get_selection(listview); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + if (status) statusstring=_("Enabled"); + else statusstring=_("Disabled"); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_STATUS,statusstring,-1); + } +} + +void codec_list_update(GtkTreeView *listview) +{ + GtkTreeModel *model; + GtkTreeIter iter; + PayloadType *pt; + gchar *color; + gfloat bitrate; + model=gtk_tree_view_get_model(listview); + + g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); + do{ + gtk_tree_model_get (model, &iter, CODEC_PRIVDATA, &pt,-1); + if (linphone_core_check_payload_type_usability(get_core(),pt)){ + color="blue"; + }else color="red"; + bitrate=payload_type_get_bitrate(pt)/1000.0; + gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR,color,CODEC_BITRATE,bitrate,-1); + }while (gtk_tree_model_iter_next(model,&iter)); +} + +static void codec_enable(gboolean val){ + GtkTreeView *listview; + int page=gtk_notebook_get_current_page(GTK_NOTEBOOK( + lookup_widget(get_property_box()->prop,"codec_notebook"))); + if (page==0) + listview=GTK_TREE_VIEW(get_property_box()->codec.au_codec_list); + else + listview=GTK_TREE_VIEW(lookup_widget(get_property_box()->prop,"vid_codec_list")); + codec_set_status(listview,val); + property_box_changed(); +} + +void +on_aucodec_enable_clicked (GtkButton *button, + gpointer user_data) +{ + codec_enable(TRUE); +} + + +void +on_aucodec_disable_clicked (GtkButton *button, + gpointer user_data) +{ + codec_enable(FALSE); +} + + +void +on_user_name_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_domain_name_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + + +void +on_reg_passwd_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_obproxy_button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_address_of_record_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_audio_jittcomp_value_changed (GtkRange *range, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_ringfileentry_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + +void linphone_property_box_uninit(LinphonePropertyBox *box) +{ + memset(box,0, sizeof(LinphonePropertyBox)); +} + +void +on_property_box_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + int i; + switch(response_id) + { + case GTK_RESPONSE_OK: + for(i = 0; i < 4; i++) + { + linphone_property_box_apply(i); + } + gtk_widget_destroy(GTK_WIDGET(dialog)); + break; + case GTK_RESPONSE_APPLY: + { + GtkNotebook *notebook = GTK_NOTEBOOK(lookup_widget(get_property_box()->prop,"prop1notebook")); + i = gtk_notebook_get_current_page(notebook); + linphone_property_box_apply(i); + } + break; + case GTK_RESPONSE_CLOSE: + case GTK_RESPONSE_CANCEL: + gtk_widget_destroy(GTK_WIDGET(dialog)); + break; + } +} + +gboolean +on_property_box_closed (GtkDialog *gnomedialog, + gpointer user_data) +{ + linphone_property_box_uninit(get_property_box()); + return FALSE; +} + +void +on_use_sipinfo_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + linphone_core_set_use_info_for_dtmf(get_core(),gtk_toggle_button_get_active(togglebutton)); +} + + +void +on_guess_hostname_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + GtkWidget *hostname; + osip_from_t *from; + gboolean val=gtk_toggle_button_get_active(togglebutton); + linphone_core_set_guess_hostname(get_core(),val); + hostname=get_property_box()->sip.hostname; + from=linphone_core_get_primary_contact_parsed(get_core()); + gtk_entry_set_text(GTK_ENTRY(hostname),from->url->host); + gtk_widget_set_sensitive(hostname,!val); + osip_from_free(from); +} + +void +on_download_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data) +{ + gdouble val=gtk_spin_button_get_value(spinbutton); + if (val==0) gtk_entry_set_text(GTK_ENTRY(spinbutton),_("Unlimited")); + linphone_core_set_download_bandwidth(get_core(),(int)val); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"au_codec_list"))); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"vid_codec_list"))); +} + +void +on_upload_bw_value_changed (GtkSpinButton *spinbutton, + gpointer user_data) +{ + gdouble val=gtk_spin_button_get_value(spinbutton); + if (val==0) gtk_entry_set_text(GTK_ENTRY(spinbutton),_("Unlimited")); + linphone_core_set_upload_bandwidth(get_core(),(int)val); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"au_codec_list"))); + codec_list_update(GTK_TREE_VIEW(lookup_widget(gtk_widget_get_toplevel(GTK_WIDGET(spinbutton)),"vid_codec_list"))); +} + +void +on_no_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_use_stun_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + + +void +on_static_nat_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + property_box_changed(); +} + +void +on_stun_server_changed (GtkEditable *editable, + gpointer user_data) +{ + property_box_changed(); +} + diff --git a/linphone/gtk/propertybox.h b/linphone/gtk/propertybox.h new file mode 100644 index 000000000..5126a7d2d --- /dev/null +++ b/linphone/gtk/propertybox.h @@ -0,0 +1,96 @@ +/*************************************************************************** + propertybox.h - description + ------------------- + begin : Wed Jan 30 2002 + copyright : (C) 2002 by Simon Morlat + email : simon.morlat@linphone.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "interface.h" + +struct _NetSection +{ + GtkWidget *interfaces; + gint if_sel; + GtkWidget *au_port; + GtkWidget *audio_jittcomp; + GtkWidget *enable_nat; + GtkWidget *nat_label; + GtkWidget *nat_address; + GtkWidget *use_sipinfo; + GtkWidget *enable_ipv6; +}; +typedef struct _NetSection NetSection; + +void net_section_init(NetSection *sec, GtkWidget *prop); +void net_section_apply(NetSection *sec, LinphoneCore *lp); + +struct _SipSection +{ + GtkWidget *port; + GtkWidget *username; + GtkWidget *hostname; + GtkWidget *proxy_list; + GtkWidget *guess_hostname; +}; + +typedef struct _SipSection SipSection; + +void sip_section_enable_registrar(SipSection *sec, LinphoneCore *lp, gboolean state); +void sip_section_fill(SipSection *sec, LinphoneCore *lp); + +void sip_section_init(SipSection *sec, GtkWidget *prop); +void sip_section_apply(SipSection *sec, LinphoneCore *lp); + +struct _CodecSection +{ + GtkWidget *au_codec_list; + GtkWidget *vi_codec_list; + GtkWidget *codec_info; +}; + +typedef struct _CodecSection CodecSection; + +void codec_section_init(CodecSection *sec, GtkWidget *prop); +void codec_section_apply(CodecSection *sec, LinphoneCore *lc); + +struct _SoundSection +{ + GtkWidget *source_entry; + GtkWidget *autokill_button; + GtkWidget *ringfileentry; + GtkWidget *ringpreview; +}; +typedef struct _SoundSection SoundSection; + +void sound_section_init(SoundSection *sec,GtkWidget *prop); +void sound_section_apply(SoundSection *sec, LinphoneCore *lc); + +struct _LinphonePropertyBox +{ + GtkWidget *prop; + NetSection net; + SipSection sip; + CodecSection codec; + SoundSection sound; +}; + +typedef struct _LinphonePropertyBox LinphonePropertyBox; + +void linphone_property_box_init(LinphonePropertyBox *box); +//void linphone_property_box_apply(LinphonePropertyBox * box, LinphoneCore *lc, int page); +void linphone_property_box_apply(int page); +void linphone_property_box_uninit(LinphonePropertyBox *box); diff --git a/linphone/gtk/support.c b/linphone/gtk/support.c new file mode 100644 index 000000000..00aff2982 --- /dev/null +++ b/linphone/gtk/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/linphone/gtk/support.h b/linphone/gtk/support.h new file mode 100644 index 000000000..a32649e53 --- /dev/null +++ b/linphone/gtk/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/linphone/intl/ChangeLog b/linphone/intl/ChangeLog new file mode 100644 index 000000000..65ec50f78 --- /dev/null +++ b/linphone/intl/ChangeLog @@ -0,0 +1,4 @@ +2002-08-06 GNU + + * Version 0.11.5 released. + diff --git a/linphone/intl/Makefile.in b/linphone/intl/Makefile.in new file mode 100644 index 000000000..0486dc93a --- /dev/null +++ b/linphone/intl/Makefile.in @@ -0,0 +1,337 @@ +# Makefile for directory with message catalog handling in GNU NLS Utilities. +# Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU Library General Public License as published +# by the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +transform = @program_transform_name@ +libdir = @libdir@ +includedir = @includedir@ +datadir = @datadir@ +localedir = $(datadir)/locale +gettextsrcdir = $(datadir)/gettext/intl +aliaspath = $(localedir) +subdir = intl + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +mkinstalldirs = $(SHELL) `case "$(MKINSTALLDIRS)" in /*) echo "$(MKINSTALLDIRS)" ;; *) echo "$(top_builddir)/$(MKINSTALLDIRS)" ;; esac` + +l = @INTL_LIBTOOL_SUFFIX_PREFIX@ + +AR = ar +CC = @CC@ +LIBTOOL = @LIBTOOL@ +RANLIB = @RANLIB@ +YACC = @INTLBISON@ -y -d +YFLAGS = --name-prefix=__gettext + +DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \ +-DLIBDIR=\"$(libdir)\" -DIN_LIBINTL @DEFS@ +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) + +HEADERS = $(COMHDRS) libgnuintl.h loadinfo.h +COMHDRS = gmo.h gettextP.h hash-string.h plural-exp.h eval-plural.h os2compat.h +SOURCES = $(COMSRCS) intl-compat.c +COMSRCS = bindtextdom.c dcgettext.c dgettext.c gettext.c \ +finddomain.c loadmsgcat.c localealias.c textdomain.c l10nflist.c \ +explodename.c dcigettext.c dcngettext.c dngettext.c ngettext.c plural.y \ +plural-exp.c localcharset.c localename.c osdep.c os2compat.c +OBJECTS = @INTLOBJS@ bindtextdom.$lo dcgettext.$lo dgettext.$lo gettext.$lo \ +finddomain.$lo loadmsgcat.$lo localealias.$lo textdomain.$lo l10nflist.$lo \ +explodename.$lo dcigettext.$lo dcngettext.$lo dngettext.$lo ngettext.$lo \ +plural.$lo plural-exp.$lo localcharset.$lo localename.$lo osdep.$lo +GETTOBJS = intl-compat.$lo +DISTFILES.common = Makefile.in \ +config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) +DISTFILES.generated = plural.c +DISTFILES.normal = VERSION +DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc +DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \ +COPYING.LIB-2 gettext.h libgettext.h plural-eval.c + +# Libtool's library version information for libintl. +# Before making a gettext release, the gettext maintainer must change this +# according to the libtool documentation, section "Library interface versions". +# Maintainers of other packages that include the intl directory must *not* +# change these values. +LTV_CURRENT=4 +LTV_REVISION=0 +LTV_AGE=2 + +.SUFFIXES: +.SUFFIXES: .c .y .o .lo .sin .sed +.c.o: + $(COMPILE) $< +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) $< + +.y.c: + $(YACC) $(YFLAGS) --output $@ $< + rm -f $*.h + +.sin.sed: + sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $< > t-$@ + mv t-$@ $@ + +INCLUDES = -I.. -I. -I$(top_srcdir)/intl + +all: all-@USE_INCLUDED_LIBINTL@ +all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed +all-no: all-no-@BUILD_INCLUDED_LIBINTL@ +all-no-yes: libgnuintl.$la +all-no-no: + +libintl.a libgnuintl.a: $(OBJECTS) + rm -f $@ + $(AR) cru $@ $(OBJECTS) + $(RANLIB) $@ + +libintl.la libgnuintl.la: $(OBJECTS) + $(LIBTOOL) --mode=link \ + $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \ + $(OBJECTS) @LTLIBICONV@ -lc \ + -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \ + -rpath $(libdir) \ + -no-undefined + +libintl.h: libgnuintl.h + cp $(srcdir)/libgnuintl.h libintl.h + +charset.alias: config.charset + $(SHELL) $(srcdir)/config.charset '@host@' > t-$@ + mv t-$@ $@ + +check: all + +# This installation goal is only used in GNU gettext. Packages which +# only use the library should use install instead. + +# We must not install the libintl.h/libintl.a files if we are on a +# system which has the GNU gettext() function in its C library or in a +# separate library. +# If you want to use the one which comes with this version of the +# package, you have to use `configure --with-included-gettext'. +install: install-exec install-data +install-exec: all + if test "$(PACKAGE)" = "gettext" \ + && test '@INTLOBJS@' = '$(GETTOBJS)'; then \ + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ + $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \ + $(LIBTOOL) --mode=install \ + $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \ + else \ + : ; \ + fi + if test '@USE_INCLUDED_LIBINTL@' = yes; then \ + test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ + temp=$(DESTDIR)$(libdir)/t-charset.alias; \ + dest=$(DESTDIR)$(libdir)/charset.alias; \ + if test -f $(DESTDIR)$(libdir)/charset.alias; then \ + orig=$(DESTDIR)$(libdir)/charset.alias; \ + sed -f ref-add.sed $$orig > $$temp; \ + $(INSTALL_DATA) $$temp $$dest; \ + rm -f $$temp; \ + else \ + if test @GLIBC21@ = no; then \ + orig=charset.alias; \ + sed -f ref-add.sed $$orig > $$temp; \ + $(INSTALL_DATA) $$temp $$dest; \ + rm -f $$temp; \ + fi; \ + fi; \ + $(mkinstalldirs) $(DESTDIR)$(localedir); \ + test -f $(DESTDIR)$(localedir)/locale.alias \ + && orig=$(DESTDIR)$(localedir)/locale.alias \ + || orig=$(srcdir)/locale.alias; \ + temp=$(DESTDIR)$(localedir)/t-locale.alias; \ + dest=$(DESTDIR)$(localedir)/locale.alias; \ + sed -f ref-add.sed $$orig > $$temp; \ + $(INSTALL_DATA) $$temp $$dest; \ + rm -f $$temp; \ + else \ + : ; \ + fi +install-data: all + if test "$(PACKAGE)" = "gettext"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \ + $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \ + dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \ + for file in $$dists; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \ + dists="$(DISTFILES.generated)"; \ + for file in $$dists; do \ + if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ + $(INSTALL_DATA) $$dir/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + dists="$(DISTFILES.obsolete)"; \ + for file in $$dists; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi + +install-strip: install + +installdirs: + if test "$(PACKAGE)" = "gettext" \ + && test '@INTLOBJS@' = '$(GETTOBJS)'; then \ + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ + else \ + : ; \ + fi + if test '@USE_INCLUDED_LIBINTL@' = yes; then \ + test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ + $(mkinstalldirs) $(DESTDIR)$(localedir); \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext"; then \ + $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: + if test "$(PACKAGE)" = "gettext" \ + && test '@INTLOBJS@' = '$(GETTOBJS)'; then \ + rm -f $(DESTDIR)$(includedir)/libintl.h; \ + $(LIBTOOL) --mode=uninstall \ + rm -f $(DESTDIR)$(libdir)/libintl.$la; \ + else \ + : ; \ + fi + if test '@USE_INCLUDED_LIBINTL@' = yes; then \ + if test -f $(DESTDIR)$(libdir)/charset.alias; then \ + temp=$(DESTDIR)$(libdir)/t-charset.alias; \ + dest=$(DESTDIR)$(libdir)/charset.alias; \ + sed -f ref-del.sed $$dest > $$temp; \ + if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ + rm -f $$dest; \ + else \ + $(INSTALL_DATA) $$temp $$dest; \ + fi; \ + rm -f $$temp; \ + fi; \ + if test -f $(DESTDIR)$(localedir)/locale.alias; then \ + temp=$(DESTDIR)$(localedir)/t-locale.alias; \ + dest=$(DESTDIR)$(localedir)/locale.alias; \ + sed -f ref-del.sed $$dest > $$temp; \ + if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ + rm -f $$dest; \ + else \ + $(INSTALL_DATA) $$temp $$dest; \ + fi; \ + rm -f $$temp; \ + fi; \ + else \ + : ; \ + fi + if test "$(PACKAGE)" = "gettext"; then \ + for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi + +info dvi: + +$(OBJECTS): ../config.h libgnuintl.h +bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: gettextP.h gmo.h loadinfo.h +dcigettext.$lo: hash-string.h +explodename.$lo l10nflist.$lo: loadinfo.h +dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: plural-exp.h +dcigettext.$lo: eval-plural.h + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) + here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES) + +id: ID + +ID: $(HEADERS) $(SOURCES) + here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES) + + +mostlyclean: + rm -f *.a *.la *.o *.lo core core.* + rm -f libintl.h charset.alias ref-add.sed ref-del.sed + rm -f -r .libs _libs + +clean: mostlyclean + +distclean: clean + rm -f Makefile ID TAGS + if test "$(PACKAGE)" = gettext; then \ + rm -f ChangeLog.inst $(DISTFILES.normal); \ + else \ + : ; \ + fi + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + + +# GNU gettext needs not contain the file `VERSION' but contains some +# other files which should not be distributed in other packages. +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: Makefile + if test "$(PACKAGE)" = gettext; then \ + additional="$(DISTFILES.gettext)"; \ + else \ + additional="$(DISTFILES.normal)"; \ + fi; \ + $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \ + for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \ + if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ + cp -p $$dir/$$file $(distdir); \ + done + +Makefile: Makefile.in ../config.status + cd .. \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/linphone/intl/VERSION b/linphone/intl/VERSION new file mode 100644 index 000000000..acc8052f3 --- /dev/null +++ b/linphone/intl/VERSION @@ -0,0 +1 @@ +GNU gettext library from gettext-0.11.5 diff --git a/linphone/intl/bindtextdom.c b/linphone/intl/bindtextdom.c new file mode 100644 index 000000000..d582ce11d --- /dev/null +++ b/linphone/intl/bindtextdom.c @@ -0,0 +1,369 @@ +/* Implementation of the bindtextdomain(3) function + Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#ifdef _LIBC +# include +#else +# include "libgnuintl.h" +#endif +#include "gettextP.h" + +#ifdef _LIBC +/* We have to handle multi-threaded applications. */ +# include +#else +/* Provide dummy implementation if this is outside glibc. */ +# define __libc_rwlock_define(CLASS, NAME) +# define __libc_rwlock_wrlock(NAME) +# define __libc_rwlock_unlock(NAME) +#endif + +/* The internal variables in the standalone libintl.a must have different + names than the internal variables in GNU libc, otherwise programs + using libintl.a cannot be linked statically. */ +#if !defined _LIBC +# define _nl_default_dirname libintl_nl_default_dirname +# define _nl_domain_bindings libintl_nl_domain_bindings +#endif + +/* Some compilers, like SunOS4 cc, don't have offsetof in . */ +#ifndef offsetof +# define offsetof(type,ident) ((size_t)&(((type*)0)->ident)) +#endif + +/* @@ end of prolog @@ */ + +/* Contains the default location of the message catalogs. */ +extern const char _nl_default_dirname[]; + +/* List with bindings of specific domains. */ +extern struct binding *_nl_domain_bindings; + +/* Lock variable to protect the global data in the gettext implementation. */ +__libc_rwlock_define (extern, _nl_state_lock attribute_hidden) + + +/* Names for the libintl functions are a problem. They must not clash + with existing names and they should follow ANSI C. But this source + code is also used in GNU C Library where the names have a __ + prefix. So we have to make a difference here. */ +#ifdef _LIBC +# define BINDTEXTDOMAIN __bindtextdomain +# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset +# ifndef strdup +# define strdup(str) __strdup (str) +# endif +#else +# define BINDTEXTDOMAIN libintl_bindtextdomain +# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset +#endif + +/* Prototypes for local functions. */ +static void set_binding_values PARAMS ((const char *domainname, + const char **dirnamep, + const char **codesetp)); + +/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP + to be used for the DOMAINNAME message catalog. + If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not + modified, only the current value is returned. + If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither + modified nor returned. */ +static void +set_binding_values (domainname, dirnamep, codesetp) + const char *domainname; + const char **dirnamep; + const char **codesetp; +{ + struct binding *binding; + int modified; + + /* Some sanity checks. */ + if (domainname == NULL || domainname[0] == '\0') + { + if (dirnamep) + *dirnamep = NULL; + if (codesetp) + *codesetp = NULL; + return; + } + + __libc_rwlock_wrlock (_nl_state_lock); + + modified = 0; + + for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next) + { + int compare = strcmp (domainname, binding->domainname); + if (compare == 0) + /* We found it! */ + break; + if (compare < 0) + { + /* It is not in the list. */ + binding = NULL; + break; + } + } + + if (binding != NULL) + { + if (dirnamep) + { + const char *dirname = *dirnamep; + + if (dirname == NULL) + /* The current binding has be to returned. */ + *dirnamep = binding->dirname; + else + { + /* The domain is already bound. If the new value and the old + one are equal we simply do nothing. Otherwise replace the + old binding. */ + char *result = binding->dirname; + if (strcmp (dirname, result) != 0) + { + if (strcmp (dirname, _nl_default_dirname) == 0) + result = (char *) _nl_default_dirname; + else + { +#if defined _LIBC || defined HAVE_STRDUP + result = strdup (dirname); +#else + size_t len = strlen (dirname) + 1; + result = (char *) malloc (len); + if (__builtin_expect (result != NULL, 1)) + memcpy (result, dirname, len); +#endif + } + + if (__builtin_expect (result != NULL, 1)) + { + if (binding->dirname != _nl_default_dirname) + free (binding->dirname); + + binding->dirname = result; + modified = 1; + } + } + *dirnamep = result; + } + } + + if (codesetp) + { + const char *codeset = *codesetp; + + if (codeset == NULL) + /* The current binding has be to returned. */ + *codesetp = binding->codeset; + else + { + /* The domain is already bound. If the new value and the old + one are equal we simply do nothing. Otherwise replace the + old binding. */ + char *result = binding->codeset; + if (result == NULL || strcmp (codeset, result) != 0) + { +#if defined _LIBC || defined HAVE_STRDUP + result = strdup (codeset); +#else + size_t len = strlen (codeset) + 1; + result = (char *) malloc (len); + if (__builtin_expect (result != NULL, 1)) + memcpy (result, codeset, len); +#endif + + if (__builtin_expect (result != NULL, 1)) + { + if (binding->codeset != NULL) + free (binding->codeset); + + binding->codeset = result; + binding->codeset_cntr++; + modified = 1; + } + } + *codesetp = result; + } + } + } + else if ((dirnamep == NULL || *dirnamep == NULL) + && (codesetp == NULL || *codesetp == NULL)) + { + /* Simply return the default values. */ + if (dirnamep) + *dirnamep = _nl_default_dirname; + if (codesetp) + *codesetp = NULL; + } + else + { + /* We have to create a new binding. */ + size_t len = strlen (domainname) + 1; + struct binding *new_binding = + (struct binding *) malloc (offsetof (struct binding, domainname) + len); + + if (__builtin_expect (new_binding == NULL, 0)) + goto failed; + + memcpy (new_binding->domainname, domainname, len); + + if (dirnamep) + { + const char *dirname = *dirnamep; + + if (dirname == NULL) + /* The default value. */ + dirname = _nl_default_dirname; + else + { + if (strcmp (dirname, _nl_default_dirname) == 0) + dirname = _nl_default_dirname; + else + { + char *result; +#if defined _LIBC || defined HAVE_STRDUP + result = strdup (dirname); + if (__builtin_expect (result == NULL, 0)) + goto failed_dirname; +#else + size_t len = strlen (dirname) + 1; + result = (char *) malloc (len); + if (__builtin_expect (result == NULL, 0)) + goto failed_dirname; + memcpy (result, dirname, len); +#endif + dirname = result; + } + } + *dirnamep = dirname; + new_binding->dirname = (char *) dirname; + } + else + /* The default value. */ + new_binding->dirname = (char *) _nl_default_dirname; + + new_binding->codeset_cntr = 0; + + if (codesetp) + { + const char *codeset = *codesetp; + + if (codeset != NULL) + { + char *result; + +#if defined _LIBC || defined HAVE_STRDUP + result = strdup (codeset); + if (__builtin_expect (result == NULL, 0)) + goto failed_codeset; +#else + size_t len = strlen (codeset) + 1; + result = (char *) malloc (len); + if (__builtin_expect (result == NULL, 0)) + goto failed_codeset; + memcpy (result, codeset, len); +#endif + codeset = result; + new_binding->codeset_cntr++; + } + *codesetp = codeset; + new_binding->codeset = (char *) codeset; + } + else + new_binding->codeset = NULL; + + /* Now enqueue it. */ + if (_nl_domain_bindings == NULL + || strcmp (domainname, _nl_domain_bindings->domainname) < 0) + { + new_binding->next = _nl_domain_bindings; + _nl_domain_bindings = new_binding; + } + else + { + binding = _nl_domain_bindings; + while (binding->next != NULL + && strcmp (domainname, binding->next->domainname) > 0) + binding = binding->next; + + new_binding->next = binding->next; + binding->next = new_binding; + } + + modified = 1; + + /* Here we deal with memory allocation failures. */ + if (0) + { + failed_codeset: + if (new_binding->dirname != _nl_default_dirname) + free (new_binding->dirname); + failed_dirname: + free (new_binding); + failed: + if (dirnamep) + *dirnamep = NULL; + if (codesetp) + *codesetp = NULL; + } + } + + /* If we modified any binding, we flush the caches. */ + if (modified) + ++_nl_msg_cat_cntr; + + __libc_rwlock_unlock (_nl_state_lock); +} + +/* Specify that the DOMAINNAME message catalog will be found + in DIRNAME rather than in the system locale data base. */ +char * +BINDTEXTDOMAIN (domainname, dirname) + const char *domainname; + const char *dirname; +{ + set_binding_values (domainname, &dirname, NULL); + return (char *) dirname; +} + +/* Specify the character encoding in which the messages from the + DOMAINNAME message catalog will be returned. */ +char * +BIND_TEXTDOMAIN_CODESET (domainname, codeset) + const char *domainname; + const char *codeset; +{ + set_binding_values (domainname, NULL, &codeset); + return (char *) codeset; +} + +#ifdef _LIBC +/* Aliases for function names in GNU C Library. */ +weak_alias (__bindtextdomain, bindtextdomain); +weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset); +#endif diff --git a/linphone/intl/cat-compat.c b/linphone/intl/cat-compat.c new file mode 100644 index 000000000..867d901b8 --- /dev/null +++ b/linphone/intl/cat-compat.c @@ -0,0 +1,262 @@ +/* Compatibility code for gettext-using-catgets interface. + Copyright (C) 1995, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef STDC_HEADERS +# include +# include +#else +char *getenv (); +# ifdef HAVE_MALLOC_H +# include +# endif +#endif + +#ifdef HAVE_NL_TYPES_H +# include +#endif + +#include "libgettext.h" + +/* @@ end of prolog @@ */ + +/* XPG3 defines the result of `setlocale (category, NULL)' as: + ``Directs `setlocale()' to query `category' and return the current + setting of `local'.'' + However it does not specify the exact format. And even worse: POSIX + defines this not at all. So we can use this feature only on selected + system (e.g. those using GNU C Library). */ +#ifdef _LIBC +# define HAVE_LOCALE_NULL +#endif + +/* The catalog descriptor. */ +static nl_catd catalog = (nl_catd) -1; + +/* Name of the default catalog. */ +static const char default_catalog_name[] = "messages"; + +/* Name of currently used catalog. */ +static const char *catalog_name = default_catalog_name; + +/* Get ID for given string. If not found return -1. */ +static int msg_to_cat_id PARAMS ((const char *msg)); + +/* Substitution for systems lacking this function in their C library. */ +#if !_LIBC && !HAVE_STPCPY +static char *stpcpy PARAMS ((char *dest, const char *src)); +#endif + + +/* Set currently used domain/catalog. */ +char * +textdomain (domainname) + const char *domainname; +{ + nl_catd new_catalog; + char *new_name; + size_t new_name_len; + char *lang; + +#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES \ + && defined HAVE_LOCALE_NULL + lang = setlocale (LC_MESSAGES, NULL); +#else + lang = getenv ("LC_ALL"); + if (lang == NULL || lang[0] == '\0') + { + lang = getenv ("LC_MESSAGES"); + if (lang == NULL || lang[0] == '\0') + lang = getenv ("LANG"); + } +#endif + if (lang == NULL || lang[0] == '\0') + lang = "C"; + + /* See whether name of currently used domain is asked. */ + if (domainname == NULL) + return (char *) catalog_name; + + if (domainname[0] == '\0') + domainname = default_catalog_name; + + /* Compute length of added path element. */ + new_name_len = sizeof (LOCALEDIR) - 1 + 1 + strlen (lang) + + sizeof ("/LC_MESSAGES/") - 1 + sizeof (PACKAGE) - 1 + + sizeof (".cat"); + + new_name = (char *) malloc (new_name_len); + if (new_name == NULL) + return NULL; + + strcpy (new_name, PACKAGE); + new_catalog = catopen (new_name, 0); + + if (new_catalog == (nl_catd) -1) + { + /* NLSPATH search didn't work, try absolute path */ + sprintf (new_name, "%s/%s/LC_MESSAGES/%s.cat", LOCALEDIR, lang, + PACKAGE); + new_catalog = catopen (new_name, 0); + + if (new_catalog == (nl_catd) -1) + { + free (new_name); + return (char *) catalog_name; + } + } + + /* Close old catalog. */ + if (catalog != (nl_catd) -1) + catclose (catalog); + if (catalog_name != default_catalog_name) + free ((char *) catalog_name); + + catalog = new_catalog; + catalog_name = new_name; + + return (char *) catalog_name; +} + +char * +bindtextdomain (domainname, dirname) + const char *domainname; + const char *dirname; +{ +#if HAVE_SETENV || HAVE_PUTENV + char *old_val, *new_val, *cp; + size_t new_val_len; + + /* This does not make much sense here but to be compatible do it. */ + if (domainname == NULL) + return NULL; + + /* Compute length of added path element. If we use setenv we don't need + the first byts for NLSPATH=, but why complicate the code for this + peanuts. */ + new_val_len = sizeof ("NLSPATH=") - 1 + strlen (dirname) + + sizeof ("/%L/LC_MESSAGES/%N.cat"); + + old_val = getenv ("NLSPATH"); + if (old_val == NULL || old_val[0] == '\0') + { + old_val = NULL; + new_val_len += 1 + sizeof (LOCALEDIR) - 1 + + sizeof ("/%L/LC_MESSAGES/%N.cat"); + } + else + new_val_len += strlen (old_val); + + new_val = (char *) malloc (new_val_len); + if (new_val == NULL) + return NULL; + +# if HAVE_SETENV + cp = new_val; +# else + cp = stpcpy (new_val, "NLSPATH="); +# endif + + cp = stpcpy (cp, dirname); + cp = stpcpy (cp, "/%L/LC_MESSAGES/%N.cat:"); + + if (old_val == NULL) + { +# if __STDC__ + stpcpy (cp, LOCALEDIR "/%L/LC_MESSAGES/%N.cat"); +# else + + cp = stpcpy (cp, LOCALEDIR); + stpcpy (cp, "/%L/LC_MESSAGES/%N.cat"); +# endif + } + else + stpcpy (cp, old_val); + +# if HAVE_SETENV + setenv ("NLSPATH", new_val, 1); + free (new_val); +# else + putenv (new_val); + /* Do *not* free the environment entry we just entered. It is used + from now on. */ +# endif + +#endif + + return (char *) domainname; +} + +#undef gettext +char * +gettext (msg) + const char *msg; +{ + int msgid; + + if (msg == NULL || catalog == (nl_catd) -1) + return (char *) msg; + + /* Get the message from the catalog. We always use set number 1. + The message ID is computed by the function `msg_to_cat_id' + which works on the table generated by `po-to-tbl'. */ + msgid = msg_to_cat_id (msg); + if (msgid == -1) + return (char *) msg; + + return catgets (catalog, 1, msgid, (char *) msg); +} + +/* Look through the table `_msg_tbl' which has `_msg_tbl_length' entries + for the one equal to msg. If it is found return the ID. In case when + the string is not found return -1. */ +static int +msg_to_cat_id (msg) + const char *msg; +{ + int cnt; + + for (cnt = 0; cnt < _msg_tbl_length; ++cnt) + if (strcmp (msg, _msg_tbl[cnt]._msg) == 0) + return _msg_tbl[cnt]._msg_number; + + return -1; +} + + +/* @@ begin of epilog @@ */ + +/* We don't want libintl.a to depend on any other library. So we + avoid the non-standard function stpcpy. In GNU C Library this + function is available, though. Also allow the symbol HAVE_STPCPY + to be defined. */ +#if !_LIBC && !HAVE_STPCPY +static char * +stpcpy (dest, src) + char *dest; + const char *src; +{ + while ((*dest++ = *src++) != '\0') + /* Do nothing. */ ; + return dest - 1; +} +#endif diff --git a/linphone/intl/dcgettext.c b/linphone/intl/dcgettext.c new file mode 100644 index 000000000..ca6a1c82d --- /dev/null +++ b/linphone/intl/dcgettext.c @@ -0,0 +1,59 @@ +/* Implementation of the dcgettext(3) function. + Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "gettextP.h" +#ifdef _LIBC +# include +#else +# include "libgnuintl.h" +#endif + +/* @@ end of prolog @@ */ + +/* Names for the libintl functions are a problem. They must not clash + with existing names and they should follow ANSI C. But this source + code is also used in GNU C Library where the names have a __ + prefix. So we have to make a difference here. */ +#ifdef _LIBC +# define DCGETTEXT __dcgettext +# define DCIGETTEXT __dcigettext +#else +# define DCGETTEXT libintl_dcgettext +# define DCIGETTEXT libintl_dcigettext +#endif + +/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY + locale. */ +char * +DCGETTEXT (domainname, msgid, category) + const char *domainname; + const char *msgid; + int category; +{ + return DCIGETTEXT (domainname, msgid, NULL, 0, 0, category); +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +INTDEF(__dcgettext) +weak_alias (__dcgettext, dcgettext); +#endif diff --git a/linphone/intl/dgettext.c b/linphone/intl/dgettext.c new file mode 100644 index 000000000..cf5b4037f --- /dev/null +++ b/linphone/intl/dgettext.c @@ -0,0 +1,59 @@ +/* Implementation of the dgettext(3) function. + Copyright (C) 1995-1997, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "gettextP.h" +#ifdef _LIBC +# include +#else +# include "libgnuintl.h" +#endif + +/* @@ end of prolog @@ */ + +/* Names for the libintl functions are a problem. They must not clash + with existing names and they should follow ANSI C. But this source + code is also used in GNU C Library where the names have a __ + prefix. So we have to make a difference here. */ +#ifdef _LIBC +# define DGETTEXT __dgettext +# define DCGETTEXT INTUSE(__dcgettext) +#else +# define DGETTEXT libintl_dgettext +# define DCGETTEXT libintl_dcgettext +#endif + +/* Look up MSGID in the DOMAINNAME message catalog of the current + LC_MESSAGES locale. */ +char * +DGETTEXT (domainname, msgid) + const char *domainname; + const char *msgid; +{ + return DCGETTEXT (domainname, msgid, LC_MESSAGES); +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +weak_alias (__dgettext, dgettext); +#endif diff --git a/linphone/intl/explodename.c b/linphone/intl/explodename.c new file mode 100644 index 000000000..2985064c9 --- /dev/null +++ b/linphone/intl/explodename.c @@ -0,0 +1,192 @@ +/* Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 1995. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "loadinfo.h" + +/* On some strange systems still no definition of NULL is found. Sigh! */ +#ifndef NULL +# if defined __STDC__ && __STDC__ +# define NULL ((void *) 0) +# else +# define NULL 0 +# endif +#endif + +/* @@ end of prolog @@ */ + +char * +_nl_find_language (name) + const char *name; +{ + while (name[0] != '\0' && name[0] != '_' && name[0] != '@' + && name[0] != '+' && name[0] != ',') + ++name; + + return (char *) name; +} + + +int +_nl_explode_name (name, language, modifier, territory, codeset, + normalized_codeset, special, sponsor, revision) + char *name; + const char **language; + const char **modifier; + const char **territory; + const char **codeset; + const char **normalized_codeset; + const char **special; + const char **sponsor; + const char **revision; +{ + enum { undecided, xpg, cen } syntax; + char *cp; + int mask; + + *modifier = NULL; + *territory = NULL; + *codeset = NULL; + *normalized_codeset = NULL; + *special = NULL; + *sponsor = NULL; + *revision = NULL; + + /* Now we determine the single parts of the locale name. First + look for the language. Termination symbols are `_' and `@' if + we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ + mask = 0; + syntax = undecided; + *language = cp = name; + cp = _nl_find_language (*language); + + if (*language == cp) + /* This does not make sense: language has to be specified. Use + this entry as it is without exploding. Perhaps it is an alias. */ + cp = strchr (*language, '\0'); + else if (cp[0] == '_') + { + /* Next is the territory. */ + cp[0] = '\0'; + *territory = ++cp; + + while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@' + && cp[0] != '+' && cp[0] != ',' && cp[0] != '_') + ++cp; + + mask |= TERRITORY; + + if (cp[0] == '.') + { + /* Next is the codeset. */ + syntax = xpg; + cp[0] = '\0'; + *codeset = ++cp; + + while (cp[0] != '\0' && cp[0] != '@') + ++cp; + + mask |= XPG_CODESET; + + if (*codeset != cp && (*codeset)[0] != '\0') + { + *normalized_codeset = _nl_normalize_codeset (*codeset, + cp - *codeset); + if (strcmp (*codeset, *normalized_codeset) == 0) + free ((char *) *normalized_codeset); + else + mask |= XPG_NORM_CODESET; + } + } + } + + if (cp[0] == '@' || (syntax != xpg && cp[0] == '+')) + { + /* Next is the modifier. */ + syntax = cp[0] == '@' ? xpg : cen; + cp[0] = '\0'; + *modifier = ++cp; + + while (syntax == cen && cp[0] != '\0' && cp[0] != '+' + && cp[0] != ',' && cp[0] != '_') + ++cp; + + mask |= XPG_MODIFIER | CEN_AUDIENCE; + } + + if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_')) + { + syntax = cen; + + if (cp[0] == '+') + { + /* Next is special application (CEN syntax). */ + cp[0] = '\0'; + *special = ++cp; + + while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_') + ++cp; + + mask |= CEN_SPECIAL; + } + + if (cp[0] == ',') + { + /* Next is sponsor (CEN syntax). */ + cp[0] = '\0'; + *sponsor = ++cp; + + while (cp[0] != '\0' && cp[0] != '_') + ++cp; + + mask |= CEN_SPONSOR; + } + + if (cp[0] == '_') + { + /* Next is revision (CEN syntax). */ + cp[0] = '\0'; + *revision = ++cp; + + mask |= CEN_REVISION; + } + } + + /* For CEN syntax values it might be important to have the + separator character in the file name, not for XPG syntax. */ + if (syntax == xpg) + { + if (*territory != NULL && (*territory)[0] == '\0') + mask &= ~TERRITORY; + + if (*codeset != NULL && (*codeset)[0] == '\0') + mask &= ~XPG_CODESET; + + if (*modifier != NULL && (*modifier)[0] == '\0') + mask &= ~XPG_MODIFIER; + } + + return mask; +} diff --git a/linphone/intl/finddomain.c b/linphone/intl/finddomain.c new file mode 100644 index 000000000..2f103d556 --- /dev/null +++ b/linphone/intl/finddomain.c @@ -0,0 +1,198 @@ +/* Handle list of needed message catalogs + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + Written by Ulrich Drepper , 1995. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#if defined HAVE_UNISTD_H || defined _LIBC +# include +#endif + +#include "gettextP.h" +#ifdef _LIBC +# include +#else +# include "libgnuintl.h" +#endif + +/* @@ end of prolog @@ */ +/* List of already loaded domains. */ +static struct loaded_l10nfile *_nl_loaded_domains; + + +/* Return a data structure describing the message catalog described by + the DOMAINNAME and CATEGORY parameters with respect to the currently + established bindings. */ +struct loaded_l10nfile * +internal_function +_nl_find_domain (dirname, locale, domainname, domainbinding) + const char *dirname; + char *locale; + const char *domainname; + struct binding *domainbinding; +{ + struct loaded_l10nfile *retval; + const char *language; + const char *modifier; + const char *territory; + const char *codeset; + const char *normalized_codeset; + const char *special; + const char *sponsor; + const char *revision; + const char *alias_value; + int mask; + + /* LOCALE can consist of up to four recognized parts for the XPG syntax: + + language[_territory[.codeset]][@modifier] + + and six parts for the CEN syntax: + + language[_territory][+audience][+special][,[sponsor][_revision]] + + Beside the first part all of them are allowed to be missing. If + the full specified locale is not found, the less specific one are + looked for. The various parts will be stripped off according to + the following order: + (1) revision + (2) sponsor + (3) special + (4) codeset + (5) normalized codeset + (6) territory + (7) audience/modifier + */ + + /* If we have already tested for this locale entry there has to + be one data set in the list of loaded domains. */ + retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, + strlen (dirname) + 1, 0, locale, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, domainname, 0); + if (retval != NULL) + { + /* We know something about this locale. */ + int cnt; + + if (retval->decided == 0) + _nl_load_domain (retval, domainbinding); + + if (retval->data != NULL) + return retval; + + for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) + { + if (retval->successor[cnt]->decided == 0) + _nl_load_domain (retval->successor[cnt], domainbinding); + + if (retval->successor[cnt]->data != NULL) + break; + } + return cnt >= 0 ? retval : NULL; + /* NOTREACHED */ + } + + /* See whether the locale value is an alias. If yes its value + *overwrites* the alias name. No test for the original value is + done. */ + alias_value = _nl_expand_alias (locale); + if (alias_value != NULL) + { +#if defined _LIBC || defined HAVE_STRDUP + locale = strdup (alias_value); + if (locale == NULL) + return NULL; +#else + size_t len = strlen (alias_value) + 1; + locale = (char *) malloc (len); + if (locale == NULL) + return NULL; + + memcpy (locale, alias_value, len); +#endif + } + + /* Now we determine the single parts of the locale name. First + look for the language. Termination symbols are `_' and `@' if + we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ + mask = _nl_explode_name (locale, &language, &modifier, &territory, + &codeset, &normalized_codeset, &special, + &sponsor, &revision); + + /* Create all possible locale entries which might be interested in + generalization. */ + retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, + strlen (dirname) + 1, mask, language, territory, + codeset, normalized_codeset, modifier, special, + sponsor, revision, domainname, 1); + if (retval == NULL) + /* This means we are out of core. */ + return NULL; + + if (retval->decided == 0) + _nl_load_domain (retval, domainbinding); + if (retval->data == NULL) + { + int cnt; + for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) + { + if (retval->successor[cnt]->decided == 0) + _nl_load_domain (retval->successor[cnt], domainbinding); + if (retval->successor[cnt]->data != NULL) + break; + } + } + + /* The room for an alias was dynamically allocated. Free it now. */ + if (alias_value != NULL) + free (locale); + + /* The space for normalized_codeset is dynamically allocated. Free it. */ + if (mask & XPG_NORM_CODESET) + free ((void *) normalized_codeset); + + return retval; +} + + +#ifdef _LIBC +static void __attribute__ ((unused)) +free_mem (void) +{ + struct loaded_l10nfile *runp = _nl_loaded_domains; + + while (runp != NULL) + { + struct loaded_l10nfile *here = runp; + if (runp->data != NULL) + _nl_unload_domain ((struct loaded_domain *) runp->data); + runp = runp->next; + free ((char *) here->filename); + free (here); + } +} + +text_set_element (__libc_subfreeres, free_mem); +#endif diff --git a/linphone/intl/gettext.c b/linphone/intl/gettext.c new file mode 100644 index 000000000..43d689f55 --- /dev/null +++ b/linphone/intl/gettext.c @@ -0,0 +1,64 @@ +/* Implementation of gettext(3) function. + Copyright (C) 1995, 1997, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _LIBC +# define __need_NULL +# include +#else +# include /* Just for NULL. */ +#endif + +#include "gettextP.h" +#ifdef _LIBC +# include +#else +# include "libgnuintl.h" +#endif + +/* @@ end of prolog @@ */ + +/* Names for the libintl functions are a problem. They must not clash + with existing names and they should follow ANSI C. But this source + code is also used in GNU C Library where the names have a __ + prefix. So we have to make a difference here. */ +#ifdef _LIBC +# define GETTEXT __gettext +# define DCGETTEXT INTUSE(__dcgettext) +#else +# define GETTEXT libintl_gettext +# define DCGETTEXT libintl_dcgettext +#endif + +/* Look up MSGID in the current default message catalog for the current + LC_MESSAGES locale. If not found, returns MSGID itself (the default + text). */ +char * +GETTEXT (msgid) + const char *msgid; +{ + return DCGETTEXT (NULL, msgid, LC_MESSAGES); +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +weak_alias (__gettext, gettext); +#endif diff --git a/linphone/intl/gettext.h b/linphone/intl/gettext.h new file mode 100644 index 000000000..6f5d76055 --- /dev/null +++ b/linphone/intl/gettext.h @@ -0,0 +1,102 @@ +/* Description of GNU message catalog format: general file layout. + Copyright (C) 1995, 1997, 2000, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETTEXT_H +#define _GETTEXT_H 1 + +#if HAVE_LIMITS_H || _LIBC +# include +#endif + +/* @@ end of prolog @@ */ + +/* The magic number of the GNU message catalog format. */ +#define _MAGIC 0x950412de +#define _MAGIC_SWAPPED 0xde120495 + +/* Revision number of the currently used .mo (binary) file format. */ +#define MO_REVISION_NUMBER 0 + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + as of version autoconf-2.13, the AC_CHECK_SIZEOF macro doesn't work + when cross-compiling. */ + +#if __STDC__ +# define UINT_MAX_32_BITS 4294967295U +#else +# define UINT_MAX_32_BITS 0xFFFFFFFF +#endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +#ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +#endif + +#if UINT_MAX == UINT_MAX_32_BITS +typedef unsigned nls_uint32; +#else +# if USHRT_MAX == UINT_MAX_32_BITS +typedef unsigned short nls_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS +typedef unsigned long nls_uint32; +# else + /* The following line is intended to throw an error. Using #error is + not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +#endif + + +/* Header for binary .mo file format. */ +struct mo_file_header +{ + /* The magic number. */ + nls_uint32 magic; + /* The revision number of the file format. */ + nls_uint32 revision; + /* The number of strings pairs. */ + nls_uint32 nstrings; + /* Offset of table with start offsets of original strings. */ + nls_uint32 orig_tab_offset; + /* Offset of table with start offsets of translation strings. */ + nls_uint32 trans_tab_offset; + /* Size of hashing table. */ + nls_uint32 hash_tab_size; + /* Offset of first hashing entry. */ + nls_uint32 hash_tab_offset; +}; + +struct string_desc +{ + /* Length of addressed string. */ + nls_uint32 length; + /* Offset of string in file. */ + nls_uint32 offset; +}; + +/* @@ begin of epilog @@ */ + +#endif /* gettext.h */ diff --git a/linphone/intl/gettextP.h b/linphone/intl/gettextP.h new file mode 100644 index 000000000..f085c59bb --- /dev/null +++ b/linphone/intl/gettextP.h @@ -0,0 +1,242 @@ +/* Header describing internals of libintl library. + Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc. + Written by Ulrich Drepper , 1995. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETTEXTP_H +#define _GETTEXTP_H + +#include /* Get size_t. */ + +#ifdef _LIBC +# include "../iconv/gconv_int.h" +#else +# if HAVE_ICONV +# include +# endif +#endif + +#include "loadinfo.h" + +#include "gmo.h" /* Get nls_uint32. */ + +/* @@ end of prolog @@ */ + +#ifndef PARAMS +# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif +#endif + +#ifndef internal_function +# define internal_function +#endif + +#ifndef attribute_hidden +# define attribute_hidden +#endif + +/* Tell the compiler when a conditional or integer expression is + almost always true or almost always false. */ +#ifndef HAVE_BUILTIN_EXPECT +# define __builtin_expect(expr, val) (expr) +#endif + +#ifndef W +# define W(flag, data) ((flag) ? SWAP (data) : (data)) +#endif + + +#ifdef _LIBC +# include +# define SWAP(i) bswap_32 (i) +#else +static inline nls_uint32 +SWAP (i) + nls_uint32 i; +{ + return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); +} +#endif + + +/* In-memory representation of system dependent string. */ +struct sysdep_string_desc +{ + /* Length of addressed string, including the trailing NUL. */ + size_t length; + /* Pointer to addressed string. */ + const char *pointer; +}; + +/* The representation of an opened message catalog. */ +struct loaded_domain +{ + /* Pointer to memory containing the .mo file. */ + const char *data; + /* 1 if the memory is mmap()ed, 0 if the memory is malloc()ed. */ + int use_mmap; + /* Size of mmap()ed memory. */ + size_t mmap_size; + /* 1 if the .mo file uses a different endianness than this machine. */ + int must_swap; + /* Pointer to additional malloc()ed memory. */ + void *malloced; + + /* Number of static strings pairs. */ + nls_uint32 nstrings; + /* Pointer to descriptors of original strings in the file. */ + const struct string_desc *orig_tab; + /* Pointer to descriptors of translated strings in the file. */ + const struct string_desc *trans_tab; + + /* Number of system dependent strings pairs. */ + nls_uint32 n_sysdep_strings; + /* Pointer to descriptors of original sysdep strings. */ + const struct sysdep_string_desc *orig_sysdep_tab; + /* Pointer to descriptors of translated sysdep strings. */ + const struct sysdep_string_desc *trans_sysdep_tab; + + /* Size of hash table. */ + nls_uint32 hash_size; + /* Pointer to hash table. */ + const nls_uint32 *hash_tab; + /* 1 if the hash table uses a different endianness than this machine. */ + int must_swap_hash_tab; + + int codeset_cntr; +#ifdef _LIBC + __gconv_t conv; +#else +# if HAVE_ICONV + iconv_t conv; +# endif +#endif + char **conv_tab; + + struct expression *plural; + unsigned long int nplurals; +}; + +/* We want to allocate a string at the end of the struct. But ISO C + doesn't allow zero sized arrays. */ +#ifdef __GNUC__ +# define ZERO 0 +#else +# define ZERO 1 +#endif + +/* A set of settings bound to a message domain. Used to store settings + from bindtextdomain() and bind_textdomain_codeset(). */ +struct binding +{ + struct binding *next; + char *dirname; + int codeset_cntr; /* Incremented each time codeset changes. */ + char *codeset; + char domainname[ZERO]; +}; + +/* A counter which is incremented each time some previous translations + become invalid. + This variable is part of the external ABI of the GNU libintl. */ +extern int _nl_msg_cat_cntr; + +#ifndef _LIBC +const char *_nl_locale_name PARAMS ((int category, const char *categoryname)); +#endif + +struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname, + char *__locale, + const char *__domainname, + struct binding *__domainbinding)) + internal_function; +void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain, + struct binding *__domainbinding)) + internal_function; +void _nl_unload_domain PARAMS ((struct loaded_domain *__domain)) + internal_function; +const char *_nl_init_domain_conv PARAMS ((struct loaded_l10nfile *__domain_file, + struct loaded_domain *__domain, + struct binding *__domainbinding)) + internal_function; +void _nl_free_domain_conv PARAMS ((struct loaded_domain *__domain)) + internal_function; + +char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file, + struct binding *domainbinding, + const char *msgid, size_t *lengthp)) + internal_function; + +#ifdef _LIBC +extern char *__gettext PARAMS ((const char *__msgid)); +extern char *__dgettext PARAMS ((const char *__domainname, + const char *__msgid)); +extern char *__dcgettext PARAMS ((const char *__domainname, + const char *__msgid, int __category)); +extern char *__ngettext PARAMS ((const char *__msgid1, const char *__msgid2, + unsigned long int __n)); +extern char *__dngettext PARAMS ((const char *__domainname, + const char *__msgid1, const char *__msgid2, + unsigned long int n)); +extern char *__dcngettext PARAMS ((const char *__domainname, + const char *__msgid1, const char *__msgid2, + unsigned long int __n, int __category)); +extern char *__dcigettext PARAMS ((const char *__domainname, + const char *__msgid1, const char *__msgid2, + int __plural, unsigned long int __n, + int __category)); +extern char *__textdomain PARAMS ((const char *__domainname)); +extern char *__bindtextdomain PARAMS ((const char *__domainname, + const char *__dirname)); +extern char *__bind_textdomain_codeset PARAMS ((const char *__domainname, + const char *__codeset)); +#else +extern char *libintl_gettext PARAMS ((const char *__msgid)); +extern char *libintl_dgettext PARAMS ((const char *__domainname, + const char *__msgid)); +extern char *libintl_dcgettext PARAMS ((const char *__domainname, + const char *__msgid, int __category)); +extern char *libintl_ngettext PARAMS ((const char *__msgid1, + const char *__msgid2, + unsigned long int __n)); +extern char *libintl_dngettext PARAMS ((const char *__domainname, + const char *__msgid1, + const char *__msgid2, + unsigned long int __n)); +extern char *libintl_dcngettext PARAMS ((const char *__domainname, + const char *__msgid1, + const char *__msgid2, + unsigned long int __n, + int __category)); +extern char *libintl_dcigettext PARAMS ((const char *__domainname, + const char *__msgid1, + const char *__msgid2, + int __plural, unsigned long int __n, + int __category)); +extern char *libintl_textdomain PARAMS ((const char *__domainname)); +extern char *libintl_bindtextdomain PARAMS ((const char *__domainname, + const char *__dirname)); +extern char *libintl_bind_textdomain_codeset PARAMS ((const char *__domainname, + const char *__codeset)); +#endif + +/* @@ begin of epilog @@ */ + +#endif /* gettextP.h */ diff --git a/linphone/intl/hash-string.h b/linphone/intl/hash-string.h new file mode 100644 index 000000000..b267a8778 --- /dev/null +++ b/linphone/intl/hash-string.h @@ -0,0 +1,59 @@ +/* Description of GNU message catalog format: string hashing function. + Copyright (C) 1995, 1997, 1998, 2000, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* @@ end of prolog @@ */ + +#ifndef PARAMS +# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +#endif + +/* We assume to have `unsigned long int' value with at least 32 bits. */ +#define HASHWORDBITS 32 + + +/* Defines the so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +static unsigned long int hash_string PARAMS ((const char *__str_param)); + +static inline unsigned long int +hash_string (str_param) + const char *str_param; +{ + unsigned long int hval, g; + const char *str = str_param; + + /* Compute the hash value for the given string. */ + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned long int) *str++; + g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} diff --git a/linphone/intl/intl-compat.c b/linphone/intl/intl-compat.c new file mode 100644 index 000000000..da890159f --- /dev/null +++ b/linphone/intl/intl-compat.c @@ -0,0 +1,131 @@ +/* intl-compat.c - Stub functions to call gettext functions from GNU gettext + Library. + Copyright (C) 1995, 2000-2002 Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define _INTL_REDIRECT_MACROS +#include "libgnuintl.h" +#include "gettextP.h" + +/* @@ end of prolog @@ */ + +/* This file redirects the gettext functions (without prefix) to those + defined in the included GNU libintl library (with "libintl_" prefix). + It is compiled into libintl in order to make the AM_GNU_GETTEXT test + of gettext <= 0.11.2 work with the libintl library >= 0.11.3 which + has the redirections primarily in the include file. */ + + +#undef gettext +#undef dgettext +#undef dcgettext +#undef ngettext +#undef dngettext +#undef dcngettext +#undef textdomain +#undef bindtextdomain +#undef bind_textdomain_codeset + + +char * +gettext (msgid) + const char *msgid; +{ + return libintl_gettext (msgid); +} + + +char * +dgettext (domainname, msgid) + const char *domainname; + const char *msgid; +{ + return libintl_dgettext (domainname, msgid); +} + + +char * +dcgettext (domainname, msgid, category) + const char *domainname; + const char *msgid; + int category; +{ + return libintl_dcgettext (domainname, msgid, category); +} + + +char * +ngettext (msgid1, msgid2, n) + const char *msgid1; + const char *msgid2; + unsigned long int n; +{ + return libintl_ngettext (msgid1, msgid2, n); +} + + +char * +dngettext (domainname, msgid1, msgid2, n) + const char *domainname; + const char *msgid1; + const char *msgid2; + unsigned long int n; +{ + return libintl_dngettext (domainname, msgid1, msgid2, n); +} + + +char * +dcngettext (domainname, msgid1, msgid2, n, category) + const char *domainname; + const char *msgid1; + const char *msgid2; + unsigned long int n; + int category; +{ + return libintl_dcngettext (domainname, msgid1, msgid2, n, category); +} + + +char * +textdomain (domainname) + const char *domainname; +{ + return libintl_textdomain (domainname); +} + + +char * +bindtextdomain (domainname, dirname) + const char *domainname; + const char *dirname; +{ + return libintl_bindtextdomain (domainname, dirname); +} + + +char * +bind_textdomain_codeset (domainname, codeset) + const char *domainname; + const char *codeset; +{ + return libintl_bind_textdomain_codeset (domainname, codeset); +} diff --git a/linphone/intl/l10nflist.c b/linphone/intl/l10nflist.c new file mode 100644 index 000000000..ec8713f8e --- /dev/null +++ b/linphone/intl/l10nflist.c @@ -0,0 +1,453 @@ +/* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 1995. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Tell glibc's to provide a prototype for stpcpy(). + This must come before because may include + , and once has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if defined _LIBC || defined HAVE_ARGZ_H +# include +#endif +#include +#include +#include + +#include "loadinfo.h" + +/* On some strange systems still no definition of NULL is found. Sigh! */ +#ifndef NULL +# if defined __STDC__ && __STDC__ +# define NULL ((void *) 0) +# else +# define NULL 0 +# endif +#endif + +/* @@ end of prolog @@ */ + +#ifdef _LIBC +/* Rename the non ANSI C functions. This is required by the standard + because some ANSI C functions will require linking with this object + file and the name space must not be polluted. */ +# ifndef stpcpy +# define stpcpy(dest, src) __stpcpy(dest, src) +# endif +#else +# ifndef HAVE_STPCPY +static char *stpcpy PARAMS ((char *dest, const char *src)); +# endif +#endif + +/* Pathname support. + ISSLASH(C) tests whether C is a directory separator character. + IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, + it may be concatenated to a directory pathname. + */ +#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ + /* Win32, OS/2, DOS */ +# define ISSLASH(C) ((C) == '/' || (C) == '\\') +# define HAS_DEVICE(P) \ + ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ + && (P)[1] == ':') +# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) +#else + /* Unix */ +# define ISSLASH(C) ((C) == '/') +# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) +#endif + +/* Define function which are usually not available. */ + +#if !defined _LIBC && !defined HAVE___ARGZ_COUNT +/* Returns the number of strings in ARGZ. */ +static size_t argz_count__ PARAMS ((const char *argz, size_t len)); + +static size_t +argz_count__ (argz, len) + const char *argz; + size_t len; +{ + size_t count = 0; + while (len > 0) + { + size_t part_len = strlen (argz); + argz += part_len + 1; + len -= part_len + 1; + count++; + } + return count; +} +# undef __argz_count +# define __argz_count(argz, len) argz_count__ (argz, len) +#else +# ifdef _LIBC +# define __argz_count(argz, len) INTUSE(__argz_count) (argz, len) +# endif +#endif /* !_LIBC && !HAVE___ARGZ_COUNT */ + +#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY +/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's + except the last into the character SEP. */ +static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep)); + +static void +argz_stringify__ (argz, len, sep) + char *argz; + size_t len; + int sep; +{ + while (len > 0) + { + size_t part_len = strlen (argz); + argz += part_len; + len -= part_len + 1; + if (len > 0) + *argz++ = sep; + } +} +# undef __argz_stringify +# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep) +#else +# ifdef _LIBC +# define __argz_stringify(argz, len, sep) \ + INTUSE(__argz_stringify) (argz, len, sep) +# endif +#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */ + +#if !defined _LIBC && !defined HAVE___ARGZ_NEXT +static char *argz_next__ PARAMS ((char *argz, size_t argz_len, + const char *entry)); + +static char * +argz_next__ (argz, argz_len, entry) + char *argz; + size_t argz_len; + const char *entry; +{ + if (entry) + { + if (entry < argz + argz_len) + entry = strchr (entry, '\0') + 1; + + return entry >= argz + argz_len ? NULL : (char *) entry; + } + else + if (argz_len > 0) + return argz; + else + return 0; +} +# undef __argz_next +# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry) +#endif /* !_LIBC && !HAVE___ARGZ_NEXT */ + + +/* Return number of bits set in X. */ +static int pop PARAMS ((int x)); + +static inline int +pop (x) + int x; +{ + /* We assume that no more than 16 bits are used. */ + x = ((x & ~0x5555) >> 1) + (x & 0x5555); + x = ((x & ~0x3333) >> 2) + (x & 0x3333); + x = ((x >> 4) + x) & 0x0f0f; + x = ((x >> 8) + x) & 0xff; + + return x; +} + + +struct loaded_l10nfile * +_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, + territory, codeset, normalized_codeset, modifier, special, + sponsor, revision, filename, do_allocate) + struct loaded_l10nfile **l10nfile_list; + const char *dirlist; + size_t dirlist_len; + int mask; + const char *language; + const char *territory; + const char *codeset; + const char *normalized_codeset; + const char *modifier; + const char *special; + const char *sponsor; + const char *revision; + const char *filename; + int do_allocate; +{ + char *abs_filename; + struct loaded_l10nfile **lastp; + struct loaded_l10nfile *retval; + char *cp; + size_t dirlist_count; + size_t entries; + int cnt; + + /* If LANGUAGE contains an absolute directory specification, we ignore + DIRLIST. */ + if (IS_ABSOLUTE_PATH (language)) + dirlist_len = 0; + + /* Allocate room for the full file name. */ + abs_filename = (char *) malloc (dirlist_len + + strlen (language) + + ((mask & TERRITORY) != 0 + ? strlen (territory) + 1 : 0) + + ((mask & XPG_CODESET) != 0 + ? strlen (codeset) + 1 : 0) + + ((mask & XPG_NORM_CODESET) != 0 + ? strlen (normalized_codeset) + 1 : 0) + + (((mask & XPG_MODIFIER) != 0 + || (mask & CEN_AUDIENCE) != 0) + ? strlen (modifier) + 1 : 0) + + ((mask & CEN_SPECIAL) != 0 + ? strlen (special) + 1 : 0) + + (((mask & CEN_SPONSOR) != 0 + || (mask & CEN_REVISION) != 0) + ? (1 + ((mask & CEN_SPONSOR) != 0 + ? strlen (sponsor) : 0) + + ((mask & CEN_REVISION) != 0 + ? strlen (revision) + 1 : 0)) : 0) + + 1 + strlen (filename) + 1); + + if (abs_filename == NULL) + return NULL; + + /* Construct file name. */ + cp = abs_filename; + if (dirlist_len > 0) + { + memcpy (cp, dirlist, dirlist_len); + __argz_stringify (cp, dirlist_len, PATH_SEPARATOR); + cp += dirlist_len; + cp[-1] = '/'; + } + + cp = stpcpy (cp, language); + + if ((mask & TERRITORY) != 0) + { + *cp++ = '_'; + cp = stpcpy (cp, territory); + } + if ((mask & XPG_CODESET) != 0) + { + *cp++ = '.'; + cp = stpcpy (cp, codeset); + } + if ((mask & XPG_NORM_CODESET) != 0) + { + *cp++ = '.'; + cp = stpcpy (cp, normalized_codeset); + } + if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0) + { + /* This component can be part of both syntaces but has different + leading characters. For CEN we use `+', else `@'. */ + *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@'; + cp = stpcpy (cp, modifier); + } + if ((mask & CEN_SPECIAL) != 0) + { + *cp++ = '+'; + cp = stpcpy (cp, special); + } + if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0) + { + *cp++ = ','; + if ((mask & CEN_SPONSOR) != 0) + cp = stpcpy (cp, sponsor); + if ((mask & CEN_REVISION) != 0) + { + *cp++ = '_'; + cp = stpcpy (cp, revision); + } + } + + *cp++ = '/'; + stpcpy (cp, filename); + + /* Look in list of already loaded domains whether it is already + available. */ + lastp = l10nfile_list; + for (retval = *l10nfile_list; retval != NULL; retval = retval->next) + if (retval->filename != NULL) + { + int compare = strcmp (retval->filename, abs_filename); + if (compare == 0) + /* We found it! */ + break; + if (compare < 0) + { + /* It's not in the list. */ + retval = NULL; + break; + } + + lastp = &retval->next; + } + + if (retval != NULL || do_allocate == 0) + { + free (abs_filename); + return retval; + } + + dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1); + + /* Allocate a new loaded_l10nfile. */ + retval = + (struct loaded_l10nfile *) + malloc (sizeof (*retval) + + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0)) + * sizeof (struct loaded_l10nfile *))); + if (retval == NULL) + return NULL; + + retval->filename = abs_filename; + + /* We set retval->data to NULL here; it is filled in later. + Setting retval->decided to 1 here means that retval does not + correspond to a real file (dirlist_count > 1) or is not worth + looking up (if an unnormalized codeset was specified). */ + retval->decided = (dirlist_count > 1 + || ((mask & XPG_CODESET) != 0 + && (mask & XPG_NORM_CODESET) != 0)); + retval->data = NULL; + + retval->next = *lastp; + *lastp = retval; + + entries = 0; + /* Recurse to fill the inheritance list of RETVAL. + If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL + entry does not correspond to a real file; retval->filename contains + colons. In this case we loop across all elements of DIRLIST and + across all bit patterns dominated by MASK. + If the DIRLIST is a single directory or entirely redundant (i.e. + DIRLIST_COUNT == 1), we loop across all bit patterns dominated by + MASK, excluding MASK itself. + In either case, we loop down from MASK to 0. This has the effect + that the extra bits in the locale name are dropped in this order: + first the modifier, then the territory, then the codeset, then the + normalized_codeset. */ + for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt) + if ((cnt & ~mask) == 0 + && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) + && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) + { + if (dirlist_count > 1) + { + /* Iterate over all elements of the DIRLIST. */ + char *dir = NULL; + + while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) + != NULL) + retval->successor[entries++] + = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, + cnt, language, territory, codeset, + normalized_codeset, modifier, special, + sponsor, revision, filename, 1); + } + else + retval->successor[entries++] + = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, + cnt, language, territory, codeset, + normalized_codeset, modifier, special, + sponsor, revision, filename, 1); + } + retval->successor[entries] = NULL; + + return retval; +} + +/* Normalize codeset name. There is no standard for the codeset + names. Normalization allows the user to use any of the common + names. The return value is dynamically allocated and has to be + freed by the caller. */ +const char * +_nl_normalize_codeset (codeset, name_len) + const char *codeset; + size_t name_len; +{ + int len = 0; + int only_digit = 1; + char *retval; + char *wp; + size_t cnt; + + for (cnt = 0; cnt < name_len; ++cnt) + if (isalnum ((unsigned char) codeset[cnt])) + { + ++len; + + if (isalpha ((unsigned char) codeset[cnt])) + only_digit = 0; + } + + retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); + + if (retval != NULL) + { + if (only_digit) + wp = stpcpy (retval, "iso"); + else + wp = retval; + + for (cnt = 0; cnt < name_len; ++cnt) + if (isalpha ((unsigned char) codeset[cnt])) + *wp++ = tolower ((unsigned char) codeset[cnt]); + else if (isdigit ((unsigned char) codeset[cnt])) + *wp++ = codeset[cnt]; + + *wp = '\0'; + } + + return (const char *) retval; +} + + +/* @@ begin of epilog @@ */ + +/* We don't want libintl.a to depend on any other library. So we + avoid the non-standard function stpcpy. In GNU C Library this + function is available, though. Also allow the symbol HAVE_STPCPY + to be defined. */ +#if !_LIBC && !HAVE_STPCPY +static char * +stpcpy (dest, src) + char *dest; + const char *src; +{ + while ((*dest++ = *src++) != '\0') + /* Do nothing. */ ; + return dest - 1; +} +#endif diff --git a/linphone/intl/libgettext.h b/linphone/intl/libgettext.h new file mode 100644 index 000000000..c5be54a80 --- /dev/null +++ b/linphone/intl/libgettext.h @@ -0,0 +1,49 @@ +/* Convenience header for conditional use of GNU . + Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include + +#else + +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (char *) (Msgid1) : (char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (char *) (Msgid1) : (char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (char *) (Msgid1) : (char *) (Msgid2)) +# define textdomain(Domainname) ((char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((char *) (Codeset)) + +#endif + +/* For automatical extraction of messages sometimes no real + translation is needed. Instead the string itself is the result. */ +#define gettext_noop(Str) (Str) + +#endif /* _LIBGETTEXT_H */ diff --git a/linphone/intl/linux-msg.sed b/linphone/intl/linux-msg.sed new file mode 100644 index 000000000..5918e720a --- /dev/null +++ b/linphone/intl/linux-msg.sed @@ -0,0 +1,100 @@ +# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file +# Copyright (C) 1995 Free Software Foundation, Inc. +# Ulrich Drepper , 1995. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# +# The first directive in the .msg should be the definition of the +# message set number. We use always set number 1. +# +1 { + i\ +$set 1 # Automatically created by po2msg.sed + h + s/.*/0/ + x +} +# +# Mitch's old catalog format does not allow comments. +# +# We copy the original message as a comment into the .msg file. +# +/^msgid/ { + s/msgid[ ]*"// +# +# This does not work now with the new format. +# /"$/! { +# s/\\$// +# s/$/ ... (more lines following)"/ +# } + x +# The following nice solution is by +# Bruno + td +# Increment a decimal number in pattern space. +# First hide trailing `9' digits. + :d + s/9\(_*\)$/_\1/ + td +# Assure at least one digit is available. + s/^\(_*\)$/0\1/ +# Increment the last digit. + s/8\(_*\)$/9\1/ + s/7\(_*\)$/8\1/ + s/6\(_*\)$/7\1/ + s/5\(_*\)$/6\1/ + s/4\(_*\)$/5\1/ + s/3\(_*\)$/4\1/ + s/2\(_*\)$/3\1/ + s/1\(_*\)$/2\1/ + s/0\(_*\)$/1\1/ +# Convert the hidden `9' digits to `0's. + s/_/0/g + x + G + s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p +} +# +# The .msg file contains, other then the .po file, only the translations +# but each given a unique ID. Starting from 1 and incrementing by 1 for +# each message we assign them to the messages. +# It is important that the .po file used to generate the cat-id-tbl.c file +# (with po-to-tbl) is the same as the one used here. (At least the order +# of declarations must not be changed.) +# +/^msgstr/ { + s/msgstr[ ]*"\(.*\)"/# \1/ +# Clear substitution flag. + tb +# Append the next line. + :b + N +# Look whether second part is continuation line. + s/\(.*\n\)"\(.*\)"/\1\2/ +# Yes, then branch. + ta + P + D +# Note that D includes a jump to the start!! +# We found a continuation line. But before printing insert '\'. + :a + s/\(.*\)\(\n.*\)/\1\\\2/ + P +# We cannot use D here. + s/.*\n\(.*\)/\1/ + tb +} +d diff --git a/linphone/intl/loadinfo.h b/linphone/intl/loadinfo.h new file mode 100644 index 000000000..1d3ba6162 --- /dev/null +++ b/linphone/intl/loadinfo.h @@ -0,0 +1,156 @@ +/* Copyright (C) 1996-1999, 2000-2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LOADINFO_H +#define _LOADINFO_H 1 + +/* Declarations of locale dependent catalog lookup functions. + Implemented in + + localealias.c Possibly replace a locale name by another. + explodename.c Split a locale name into its various fields. + l10nflist.c Generate a list of filenames of possible message catalogs. + finddomain.c Find and open the relevant message catalogs. + + The main function _nl_find_domain() in finddomain.c is declared + in gettextP.h. + */ + +#ifndef PARAMS +# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif +#endif + +#ifndef internal_function +# define internal_function +#endif + +/* Tell the compiler when a conditional or integer expression is + almost always true or almost always false. */ +#ifndef HAVE_BUILTIN_EXPECT +# define __builtin_expect(expr, val) (expr) +#endif + +/* Separator in PATH like lists of pathnames. */ +#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ + /* Win32, OS/2, DOS */ +# define PATH_SEPARATOR ';' +#else + /* Unix */ +# define PATH_SEPARATOR ':' +#endif + +/* Encoding of locale name parts. */ +#define CEN_REVISION 1 +#define CEN_SPONSOR 2 +#define CEN_SPECIAL 4 +#define XPG_NORM_CODESET 8 +#define XPG_CODESET 16 +#define TERRITORY 32 +#define CEN_AUDIENCE 64 +#define XPG_MODIFIER 128 + +#define CEN_SPECIFIC (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE) +#define XPG_SPECIFIC (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER) + + +struct loaded_l10nfile +{ + const char *filename; + int decided; + + const void *data; + + struct loaded_l10nfile *next; + struct loaded_l10nfile *successor[1]; +}; + + +/* Normalize codeset name. There is no standard for the codeset + names. Normalization allows the user to use any of the common + names. The return value is dynamically allocated and has to be + freed by the caller. */ +extern const char *_nl_normalize_codeset PARAMS ((const char *codeset, + size_t name_len)); + +/* Lookup a locale dependent file. + *L10NFILE_LIST denotes a pool of lookup results of locale dependent + files of the same kind, sorted in decreasing order of ->filename. + DIRLIST and DIRLIST_LEN are an argz list of directories in which to + look, containing at least one directory (i.e. DIRLIST_LEN > 0). + MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER, + SPECIAL, SPONSOR, REVISION are the pieces of the locale name, as + produced by _nl_explode_name(). FILENAME is the filename suffix. + The return value is the lookup result, either found in *L10NFILE_LIST, + or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL. + If the return value is non-NULL, it is added to *L10NFILE_LIST, and + its ->next field denotes the chaining inside *L10NFILE_LIST, and + furthermore its ->successor[] field contains a list of other lookup + results from which this lookup result inherits. */ +extern struct loaded_l10nfile * +_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list, + const char *dirlist, size_t dirlist_len, int mask, + const char *language, const char *territory, + const char *codeset, + const char *normalized_codeset, + const char *modifier, const char *special, + const char *sponsor, const char *revision, + const char *filename, int do_allocate)); + +/* Lookup the real locale name for a locale alias NAME, or NULL if + NAME is not a locale alias (but possibly a real locale name). + The return value is statically allocated and must not be freed. */ +extern const char *_nl_expand_alias PARAMS ((const char *name)); + +/* Split a locale name NAME into its pieces: language, modifier, + territory, codeset, special, sponsor, revision. + NAME gets destructively modified: NUL bytes are inserted here and + there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY, + *CODESET, *SPECIAL, *SPONSOR, *REVISION gets assigned either a + pointer into the old NAME string, or NULL. *NORMALIZED_CODESET + gets assigned the expanded *CODESET, if it is different from *CODESET; + this one is dynamically allocated and has to be freed by the caller. + The return value is a bitmask, where each bit corresponds to one + filled-in value: + XPG_MODIFIER, CEN_AUDIENCE for *MODIFIER, + TERRITORY for *TERRITORY, + XPG_CODESET for *CODESET, + XPG_NORM_CODESET for *NORMALIZED_CODESET, + CEN_SPECIAL for *SPECIAL, + CEN_SPONSOR for *SPONSOR, + CEN_REVISION for *REVISION. + */ +extern int _nl_explode_name PARAMS ((char *name, const char **language, + const char **modifier, + const char **territory, + const char **codeset, + const char **normalized_codeset, + const char **special, + const char **sponsor, + const char **revision)); + +/* Split a locale name NAME into a leading language part and all the + rest. Return a pointer to the first character after the language, + i.e. to the first byte of the rest. */ +extern char *_nl_find_language PARAMS ((const char *name)); + +#endif /* loadinfo.h */ diff --git a/linphone/intl/loadmsgcat.c b/linphone/intl/loadmsgcat.c new file mode 100644 index 000000000..516f5211b --- /dev/null +++ b/linphone/intl/loadmsgcat.c @@ -0,0 +1,1316 @@ +/* Load needed message catalogs. + Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Tell glibc's to provide a prototype for mempcpy(). + This must come before because may include + , and once has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +# define alloca __builtin_alloca +# define HAVE_ALLOCA 1 +#else +# if defined HAVE_ALLOCA_H || defined _LIBC +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca +char *alloca (); +# endif +# endif +# endif +#endif + +#include +#include + +#if defined HAVE_UNISTD_H || defined _LIBC +# include +#endif + +#ifdef _LIBC +# include +# include +#endif + +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ + || (defined _LIBC && defined _POSIX_MAPPED_FILES) +# include +# undef HAVE_MMAP +# define HAVE_MMAP 1 +#else +# undef HAVE_MMAP +#endif + +#if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC +# include +#endif +#if defined HAVE_INTTYPES_H || defined _LIBC +# include +#endif + +#include "gmo.h" +#include "gettextP.h" +#include "hash-string.h" +#include "plural-exp.h" + +#ifdef _LIBC +# include "../locale/localeinfo.h" +#endif + +/* Provide fallback values for macros that ought to be defined in . + Note that our fallback values need not be literal strings, because we don't + use them with preprocessor string concatenation. */ +#if !defined PRId8 || PRI_MACROS_BROKEN +# undef PRId8 +# define PRId8 "d" +#endif +#if !defined PRIi8 || PRI_MACROS_BROKEN +# undef PRIi8 +# define PRIi8 "i" +#endif +#if !defined PRIo8 || PRI_MACROS_BROKEN +# undef PRIo8 +# define PRIo8 "o" +#endif +#if !defined PRIu8 || PRI_MACROS_BROKEN +# undef PRIu8 +# define PRIu8 "u" +#endif +#if !defined PRIx8 || PRI_MACROS_BROKEN +# undef PRIx8 +# define PRIx8 "x" +#endif +#if !defined PRIX8 || PRI_MACROS_BROKEN +# undef PRIX8 +# define PRIX8 "X" +#endif +#if !defined PRId16 || PRI_MACROS_BROKEN +# undef PRId16 +# define PRId16 "d" +#endif +#if !defined PRIi16 || PRI_MACROS_BROKEN +# undef PRIi16 +# define PRIi16 "i" +#endif +#if !defined PRIo16 || PRI_MACROS_BROKEN +# undef PRIo16 +# define PRIo16 "o" +#endif +#if !defined PRIu16 || PRI_MACROS_BROKEN +# undef PRIu16 +# define PRIu16 "u" +#endif +#if !defined PRIx16 || PRI_MACROS_BROKEN +# undef PRIx16 +# define PRIx16 "x" +#endif +#if !defined PRIX16 || PRI_MACROS_BROKEN +# undef PRIX16 +# define PRIX16 "X" +#endif +#if !defined PRId32 || PRI_MACROS_BROKEN +# undef PRId32 +# define PRId32 "d" +#endif +#if !defined PRIi32 || PRI_MACROS_BROKEN +# undef PRIi32 +# define PRIi32 "i" +#endif +#if !defined PRIo32 || PRI_MACROS_BROKEN +# undef PRIo32 +# define PRIo32 "o" +#endif +#if !defined PRIu32 || PRI_MACROS_BROKEN +# undef PRIu32 +# define PRIu32 "u" +#endif +#if !defined PRIx32 || PRI_MACROS_BROKEN +# undef PRIx32 +# define PRIx32 "x" +#endif +#if !defined PRIX32 || PRI_MACROS_BROKEN +# undef PRIX32 +# define PRIX32 "X" +#endif +#if !defined PRId64 || PRI_MACROS_BROKEN +# undef PRId64 +# define PRId64 (sizeof (long) == 8 ? "ld" : "lld") +#endif +#if !defined PRIi64 || PRI_MACROS_BROKEN +# undef PRIi64 +# define PRIi64 (sizeof (long) == 8 ? "li" : "lli") +#endif +#if !defined PRIo64 || PRI_MACROS_BROKEN +# undef PRIo64 +# define PRIo64 (sizeof (long) == 8 ? "lo" : "llo") +#endif +#if !defined PRIu64 || PRI_MACROS_BROKEN +# undef PRIu64 +# define PRIu64 (sizeof (long) == 8 ? "lu" : "llu") +#endif +#if !defined PRIx64 || PRI_MACROS_BROKEN +# undef PRIx64 +# define PRIx64 (sizeof (long) == 8 ? "lx" : "llx") +#endif +#if !defined PRIX64 || PRI_MACROS_BROKEN +# undef PRIX64 +# define PRIX64 (sizeof (long) == 8 ? "lX" : "llX") +#endif +#if !defined PRIdLEAST8 || PRI_MACROS_BROKEN +# undef PRIdLEAST8 +# define PRIdLEAST8 "d" +#endif +#if !defined PRIiLEAST8 || PRI_MACROS_BROKEN +# undef PRIiLEAST8 +# define PRIiLEAST8 "i" +#endif +#if !defined PRIoLEAST8 || PRI_MACROS_BROKEN +# undef PRIoLEAST8 +# define PRIoLEAST8 "o" +#endif +#if !defined PRIuLEAST8 || PRI_MACROS_BROKEN +# undef PRIuLEAST8 +# define PRIuLEAST8 "u" +#endif +#if !defined PRIxLEAST8 || PRI_MACROS_BROKEN +# undef PRIxLEAST8 +# define PRIxLEAST8 "x" +#endif +#if !defined PRIXLEAST8 || PRI_MACROS_BROKEN +# undef PRIXLEAST8 +# define PRIXLEAST8 "X" +#endif +#if !defined PRIdLEAST16 || PRI_MACROS_BROKEN +# undef PRIdLEAST16 +# define PRIdLEAST16 "d" +#endif +#if !defined PRIiLEAST16 || PRI_MACROS_BROKEN +# undef PRIiLEAST16 +# define PRIiLEAST16 "i" +#endif +#if !defined PRIoLEAST16 || PRI_MACROS_BROKEN +# undef PRIoLEAST16 +# define PRIoLEAST16 "o" +#endif +#if !defined PRIuLEAST16 || PRI_MACROS_BROKEN +# undef PRIuLEAST16 +# define PRIuLEAST16 "u" +#endif +#if !defined PRIxLEAST16 || PRI_MACROS_BROKEN +# undef PRIxLEAST16 +# define PRIxLEAST16 "x" +#endif +#if !defined PRIXLEAST16 || PRI_MACROS_BROKEN +# undef PRIXLEAST16 +# define PRIXLEAST16 "X" +#endif +#if !defined PRIdLEAST32 || PRI_MACROS_BROKEN +# undef PRIdLEAST32 +# define PRIdLEAST32 "d" +#endif +#if !defined PRIiLEAST32 || PRI_MACROS_BROKEN +# undef PRIiLEAST32 +# define PRIiLEAST32 "i" +#endif +#if !defined PRIoLEAST32 || PRI_MACROS_BROKEN +# undef PRIoLEAST32 +# define PRIoLEAST32 "o" +#endif +#if !defined PRIuLEAST32 || PRI_MACROS_BROKEN +# undef PRIuLEAST32 +# define PRIuLEAST32 "u" +#endif +#if !defined PRIxLEAST32 || PRI_MACROS_BROKEN +# undef PRIxLEAST32 +# define PRIxLEAST32 "x" +#endif +#if !defined PRIXLEAST32 || PRI_MACROS_BROKEN +# undef PRIXLEAST32 +# define PRIXLEAST32 "X" +#endif +#if !defined PRIdLEAST64 || PRI_MACROS_BROKEN +# undef PRIdLEAST64 +# define PRIdLEAST64 PRId64 +#endif +#if !defined PRIiLEAST64 || PRI_MACROS_BROKEN +# undef PRIiLEAST64 +# define PRIiLEAST64 PRIi64 +#endif +#if !defined PRIoLEAST64 || PRI_MACROS_BROKEN +# undef PRIoLEAST64 +# define PRIoLEAST64 PRIo64 +#endif +#if !defined PRIuLEAST64 || PRI_MACROS_BROKEN +# undef PRIuLEAST64 +# define PRIuLEAST64 PRIu64 +#endif +#if !defined PRIxLEAST64 || PRI_MACROS_BROKEN +# undef PRIxLEAST64 +# define PRIxLEAST64 PRIx64 +#endif +#if !defined PRIXLEAST64 || PRI_MACROS_BROKEN +# undef PRIXLEAST64 +# define PRIXLEAST64 PRIX64 +#endif +#if !defined PRIdFAST8 || PRI_MACROS_BROKEN +# undef PRIdFAST8 +# define PRIdFAST8 "d" +#endif +#if !defined PRIiFAST8 || PRI_MACROS_BROKEN +# undef PRIiFAST8 +# define PRIiFAST8 "i" +#endif +#if !defined PRIoFAST8 || PRI_MACROS_BROKEN +# undef PRIoFAST8 +# define PRIoFAST8 "o" +#endif +#if !defined PRIuFAST8 || PRI_MACROS_BROKEN +# undef PRIuFAST8 +# define PRIuFAST8 "u" +#endif +#if !defined PRIxFAST8 || PRI_MACROS_BROKEN +# undef PRIxFAST8 +# define PRIxFAST8 "x" +#endif +#if !defined PRIXFAST8 || PRI_MACROS_BROKEN +# undef PRIXFAST8 +# define PRIXFAST8 "X" +#endif +#if !defined PRIdFAST16 || PRI_MACROS_BROKEN +# undef PRIdFAST16 +# define PRIdFAST16 "d" +#endif +#if !defined PRIiFAST16 || PRI_MACROS_BROKEN +# undef PRIiFAST16 +# define PRIiFAST16 "i" +#endif +#if !defined PRIoFAST16 || PRI_MACROS_BROKEN +# undef PRIoFAST16 +# define PRIoFAST16 "o" +#endif +#if !defined PRIuFAST16 || PRI_MACROS_BROKEN +# undef PRIuFAST16 +# define PRIuFAST16 "u" +#endif +#if !defined PRIxFAST16 || PRI_MACROS_BROKEN +# undef PRIxFAST16 +# define PRIxFAST16 "x" +#endif +#if !defined PRIXFAST16 || PRI_MACROS_BROKEN +# undef PRIXFAST16 +# define PRIXFAST16 "X" +#endif +#if !defined PRIdFAST32 || PRI_MACROS_BROKEN +# undef PRIdFAST32 +# define PRIdFAST32 "d" +#endif +#if !defined PRIiFAST32 || PRI_MACROS_BROKEN +# undef PRIiFAST32 +# define PRIiFAST32 "i" +#endif +#if !defined PRIoFAST32 || PRI_MACROS_BROKEN +# undef PRIoFAST32 +# define PRIoFAST32 "o" +#endif +#if !defined PRIuFAST32 || PRI_MACROS_BROKEN +# undef PRIuFAST32 +# define PRIuFAST32 "u" +#endif +#if !defined PRIxFAST32 || PRI_MACROS_BROKEN +# undef PRIxFAST32 +# define PRIxFAST32 "x" +#endif +#if !defined PRIXFAST32 || PRI_MACROS_BROKEN +# undef PRIXFAST32 +# define PRIXFAST32 "X" +#endif +#if !defined PRIdFAST64 || PRI_MACROS_BROKEN +# undef PRIdFAST64 +# define PRIdFAST64 PRId64 +#endif +#if !defined PRIiFAST64 || PRI_MACROS_BROKEN +# undef PRIiFAST64 +# define PRIiFAST64 PRIi64 +#endif +#if !defined PRIoFAST64 || PRI_MACROS_BROKEN +# undef PRIoFAST64 +# define PRIoFAST64 PRIo64 +#endif +#if !defined PRIuFAST64 || PRI_MACROS_BROKEN +# undef PRIuFAST64 +# define PRIuFAST64 PRIu64 +#endif +#if !defined PRIxFAST64 || PRI_MACROS_BROKEN +# undef PRIxFAST64 +# define PRIxFAST64 PRIx64 +#endif +#if !defined PRIXFAST64 || PRI_MACROS_BROKEN +# undef PRIXFAST64 +# define PRIXFAST64 PRIX64 +#endif +#if !defined PRIdMAX || PRI_MACROS_BROKEN +# undef PRIdMAX +# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld") +#endif +#if !defined PRIiMAX || PRI_MACROS_BROKEN +# undef PRIiMAX +# define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli") +#endif +#if !defined PRIoMAX || PRI_MACROS_BROKEN +# undef PRIoMAX +# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo") +#endif +#if !defined PRIuMAX || PRI_MACROS_BROKEN +# undef PRIuMAX +# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu") +#endif +#if !defined PRIxMAX || PRI_MACROS_BROKEN +# undef PRIxMAX +# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx") +#endif +#if !defined PRIXMAX || PRI_MACROS_BROKEN +# undef PRIXMAX +# define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX") +#endif +#if !defined PRIdPTR || PRI_MACROS_BROKEN +# undef PRIdPTR +# define PRIdPTR \ + (sizeof (void *) == sizeof (long) ? "ld" : \ + sizeof (void *) == sizeof (int) ? "d" : \ + "lld") +#endif +#if !defined PRIiPTR || PRI_MACROS_BROKEN +# undef PRIiPTR +# define PRIiPTR \ + (sizeof (void *) == sizeof (long) ? "li" : \ + sizeof (void *) == sizeof (int) ? "i" : \ + "lli") +#endif +#if !defined PRIoPTR || PRI_MACROS_BROKEN +# undef PRIoPTR +# define PRIoPTR \ + (sizeof (void *) == sizeof (long) ? "lo" : \ + sizeof (void *) == sizeof (int) ? "o" : \ + "llo") +#endif +#if !defined PRIuPTR || PRI_MACROS_BROKEN +# undef PRIuPTR +# define PRIuPTR \ + (sizeof (void *) == sizeof (long) ? "lu" : \ + sizeof (void *) == sizeof (int) ? "u" : \ + "llu") +#endif +#if !defined PRIxPTR || PRI_MACROS_BROKEN +# undef PRIxPTR +# define PRIxPTR \ + (sizeof (void *) == sizeof (long) ? "lx" : \ + sizeof (void *) == sizeof (int) ? "x" : \ + "llx") +#endif +#if !defined PRIXPTR || PRI_MACROS_BROKEN +# undef PRIXPTR +# define PRIXPTR \ + (sizeof (void *) == sizeof (long) ? "lX" : \ + sizeof (void *) == sizeof (int) ? "X" : \ + "llX") +#endif + +/* @@ end of prolog @@ */ + +#ifdef _LIBC +/* Rename the non ISO C functions. This is required by the standard + because some ISO C functions will require linking with this object + file and the name space must not be polluted. */ +# define open __open +# define close __close +# define read __read +# define mmap __mmap +# define munmap __munmap +#endif + +/* For those losing systems which don't have `alloca' we have to add + some additional code emulating it. */ +#ifdef HAVE_ALLOCA +# define freea(p) /* nothing */ +#else +# define alloca(n) malloc (n) +# define freea(p) free (p) +#endif + +/* For systems that distinguish between text and binary I/O. + O_BINARY is usually declared in . */ +#if !defined O_BINARY && defined _O_BINARY + /* For MSC-compatible compilers. */ +# define O_BINARY _O_BINARY +# define O_TEXT _O_TEXT +#endif +#ifdef __BEOS__ + /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */ +# undef O_BINARY +# undef O_TEXT +#endif +/* On reasonable systems, binary I/O is the default. */ +#ifndef O_BINARY +# define O_BINARY 0 +#endif + + +/* Prototypes for local functions. Needed to ensure compiler checking of + function argument counts despite of K&R C function definition syntax. */ +static const char *get_sysdep_segment_value PARAMS ((const char *name)); + + +/* We need a sign, whether a new catalog was loaded, which can be associated + with all translations. This is important if the translations are + cached by one of GCC's features. */ +int _nl_msg_cat_cntr; + + +/* Expand a system dependent string segment. Return NULL if unsupported. */ +static const char * +get_sysdep_segment_value (name) + const char *name; +{ + /* Test for an ISO C 99 section 7.8.1 format string directive. + Syntax: + P R I { d | i | o | u | x | X } + { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR } */ + /* We don't use a table of 14 times 6 'const char *' strings here, because + data relocations cost startup time. */ + if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I') + { + if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u' + || name[3] == 'x' || name[3] == 'X') + { + if (name[4] == '8' && name[5] == '\0') + { + if (name[3] == 'd') + return PRId8; + if (name[3] == 'i') + return PRIi8; + if (name[3] == 'o') + return PRIo8; + if (name[3] == 'u') + return PRIu8; + if (name[3] == 'x') + return PRIx8; + if (name[3] == 'X') + return PRIX8; + abort (); + } + if (name[4] == '1' && name[5] == '6' && name[6] == '\0') + { + if (name[3] == 'd') + return PRId16; + if (name[3] == 'i') + return PRIi16; + if (name[3] == 'o') + return PRIo16; + if (name[3] == 'u') + return PRIu16; + if (name[3] == 'x') + return PRIx16; + if (name[3] == 'X') + return PRIX16; + abort (); + } + if (name[4] == '3' && name[5] == '2' && name[6] == '\0') + { + if (name[3] == 'd') + return PRId32; + if (name[3] == 'i') + return PRIi32; + if (name[3] == 'o') + return PRIo32; + if (name[3] == 'u') + return PRIu32; + if (name[3] == 'x') + return PRIx32; + if (name[3] == 'X') + return PRIX32; + abort (); + } + if (name[4] == '6' && name[5] == '4' && name[6] == '\0') + { + if (name[3] == 'd') + return PRId64; + if (name[3] == 'i') + return PRIi64; + if (name[3] == 'o') + return PRIo64; + if (name[3] == 'u') + return PRIu64; + if (name[3] == 'x') + return PRIx64; + if (name[3] == 'X') + return PRIX64; + abort (); + } + if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A' + && name[7] == 'S' && name[8] == 'T') + { + if (name[9] == '8' && name[10] == '\0') + { + if (name[3] == 'd') + return PRIdLEAST8; + if (name[3] == 'i') + return PRIiLEAST8; + if (name[3] == 'o') + return PRIoLEAST8; + if (name[3] == 'u') + return PRIuLEAST8; + if (name[3] == 'x') + return PRIxLEAST8; + if (name[3] == 'X') + return PRIXLEAST8; + abort (); + } + if (name[9] == '1' && name[10] == '6' && name[11] == '\0') + { + if (name[3] == 'd') + return PRIdLEAST16; + if (name[3] == 'i') + return PRIiLEAST16; + if (name[3] == 'o') + return PRIoLEAST16; + if (name[3] == 'u') + return PRIuLEAST16; + if (name[3] == 'x') + return PRIxLEAST16; + if (name[3] == 'X') + return PRIXLEAST16; + abort (); + } + if (name[9] == '3' && name[10] == '2' && name[11] == '\0') + { + if (name[3] == 'd') + return PRIdLEAST32; + if (name[3] == 'i') + return PRIiLEAST32; + if (name[3] == 'o') + return PRIoLEAST32; + if (name[3] == 'u') + return PRIuLEAST32; + if (name[3] == 'x') + return PRIxLEAST32; + if (name[3] == 'X') + return PRIXLEAST32; + abort (); + } + if (name[9] == '6' && name[10] == '4' && name[11] == '\0') + { + if (name[3] == 'd') + return PRIdLEAST64; + if (name[3] == 'i') + return PRIiLEAST64; + if (name[3] == 'o') + return PRIoLEAST64; + if (name[3] == 'u') + return PRIuLEAST64; + if (name[3] == 'x') + return PRIxLEAST64; + if (name[3] == 'X') + return PRIXLEAST64; + abort (); + } + } + if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S' + && name[7] == 'T') + { + if (name[8] == '8' && name[9] == '\0') + { + if (name[3] == 'd') + return PRIdFAST8; + if (name[3] == 'i') + return PRIiFAST8; + if (name[3] == 'o') + return PRIoFAST8; + if (name[3] == 'u') + return PRIuFAST8; + if (name[3] == 'x') + return PRIxFAST8; + if (name[3] == 'X') + return PRIXFAST8; + abort (); + } + if (name[8] == '1' && name[9] == '6' && name[10] == '\0') + { + if (name[3] == 'd') + return PRIdFAST16; + if (name[3] == 'i') + return PRIiFAST16; + if (name[3] == 'o') + return PRIoFAST16; + if (name[3] == 'u') + return PRIuFAST16; + if (name[3] == 'x') + return PRIxFAST16; + if (name[3] == 'X') + return PRIXFAST16; + abort (); + } + if (name[8] == '3' && name[9] == '2' && name[10] == '\0') + { + if (name[3] == 'd') + return PRIdFAST32; + if (name[3] == 'i') + return PRIiFAST32; + if (name[3] == 'o') + return PRIoFAST32; + if (name[3] == 'u') + return PRIuFAST32; + if (name[3] == 'x') + return PRIxFAST32; + if (name[3] == 'X') + return PRIXFAST32; + abort (); + } + if (name[8] == '6' && name[9] == '4' && name[10] == '\0') + { + if (name[3] == 'd') + return PRIdFAST64; + if (name[3] == 'i') + return PRIiFAST64; + if (name[3] == 'o') + return PRIoFAST64; + if (name[3] == 'u') + return PRIuFAST64; + if (name[3] == 'x') + return PRIxFAST64; + if (name[3] == 'X') + return PRIXFAST64; + abort (); + } + } + if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X' + && name[7] == '\0') + { + if (name[3] == 'd') + return PRIdMAX; + if (name[3] == 'i') + return PRIiMAX; + if (name[3] == 'o') + return PRIoMAX; + if (name[3] == 'u') + return PRIuMAX; + if (name[3] == 'x') + return PRIxMAX; + if (name[3] == 'X') + return PRIXMAX; + abort (); + } + if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R' + && name[7] == '\0') + { + if (name[3] == 'd') + return PRIdPTR; + if (name[3] == 'i') + return PRIiPTR; + if (name[3] == 'o') + return PRIoPTR; + if (name[3] == 'u') + return PRIuPTR; + if (name[3] == 'x') + return PRIxPTR; + if (name[3] == 'X') + return PRIXPTR; + abort (); + } + } + } + /* Other system dependent strings are not valid. */ + return NULL; +} + +/* Initialize the codeset dependent parts of an opened message catalog. + Return the header entry. */ +const char * +internal_function +_nl_init_domain_conv (domain_file, domain, domainbinding) + struct loaded_l10nfile *domain_file; + struct loaded_domain *domain; + struct binding *domainbinding; +{ + /* Find out about the character set the file is encoded with. + This can be found (in textual form) in the entry "". If this + entry does not exist or if this does not contain the `charset=' + information, we will assume the charset matches the one the + current locale and we don't have to perform any conversion. */ + char *nullentry; + size_t nullentrylen; + + /* Preinitialize fields, to avoid recursion during _nl_find_msg. */ + domain->codeset_cntr = + (domainbinding != NULL ? domainbinding->codeset_cntr : 0); +#ifdef _LIBC + domain->conv = (__gconv_t) -1; +#else +# if HAVE_ICONV + domain->conv = (iconv_t) -1; +# endif +#endif + domain->conv_tab = NULL; + + /* Get the header entry. */ + nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen); + + if (nullentry != NULL) + { +#if defined _LIBC || HAVE_ICONV + const char *charsetstr; + + charsetstr = strstr (nullentry, "charset="); + if (charsetstr != NULL) + { + size_t len; + char *charset; + const char *outcharset; + + charsetstr += strlen ("charset="); + len = strcspn (charsetstr, " \t\n"); + + charset = (char *) alloca (len + 1); +# if defined _LIBC || HAVE_MEMPCPY + *((char *) mempcpy (charset, charsetstr, len)) = '\0'; +# else + memcpy (charset, charsetstr, len); + charset[len] = '\0'; +# endif + + /* The output charset should normally be determined by the + locale. But sometimes the locale is not used or not correctly + set up, so we provide a possibility for the user to override + this. Moreover, the value specified through + bind_textdomain_codeset overrides both. */ + if (domainbinding != NULL && domainbinding->codeset != NULL) + outcharset = domainbinding->codeset; + else + { + outcharset = getenv ("OUTPUT_CHARSET"); + if (outcharset == NULL || outcharset[0] == '\0') + { +# ifdef _LIBC + outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string; +# else +# if HAVE_ICONV + extern const char *locale_charset PARAMS ((void)); + outcharset = locale_charset (); +# endif +# endif + } + } + +# ifdef _LIBC + /* We always want to use transliteration. */ + outcharset = norm_add_slashes (outcharset, "TRANSLIT"); + charset = norm_add_slashes (charset, NULL); + if (__gconv_open (outcharset, charset, &domain->conv, + GCONV_AVOID_NOCONV) + != __GCONV_OK) + domain->conv = (__gconv_t) -1; +# else +# if HAVE_ICONV + /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, + we want to use transliteration. */ +# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \ + || _LIBICONV_VERSION >= 0x0105 + if (strchr (outcharset, '/') == NULL) + { + char *tmp; + + len = strlen (outcharset); + tmp = (char *) alloca (len + 10 + 1); + memcpy (tmp, outcharset, len); + memcpy (tmp + len, "//TRANSLIT", 10 + 1); + outcharset = tmp; + + domain->conv = iconv_open (outcharset, charset); + + freea (outcharset); + } + else +# endif + domain->conv = iconv_open (outcharset, charset); +# endif +# endif + + freea (charset); + } +#endif /* _LIBC || HAVE_ICONV */ + } + + return nullentry; +} + +/* Frees the codeset dependent parts of an opened message catalog. */ +void +internal_function +_nl_free_domain_conv (domain) + struct loaded_domain *domain; +{ + if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1) + free (domain->conv_tab); + +#ifdef _LIBC + if (domain->conv != (__gconv_t) -1) + __gconv_close (domain->conv); +#else +# if HAVE_ICONV + if (domain->conv != (iconv_t) -1) + iconv_close (domain->conv); +# endif +#endif +} + +/* Load the message catalogs specified by FILENAME. If it is no valid + message catalog do nothing. */ +void +internal_function +_nl_load_domain (domain_file, domainbinding) + struct loaded_l10nfile *domain_file; + struct binding *domainbinding; +{ + int fd; + size_t size; +#ifdef _LIBC + struct stat64 st; +#else + struct stat st; +#endif + struct mo_file_header *data = (struct mo_file_header *) -1; + int use_mmap = 0; + struct loaded_domain *domain; + int revision; + const char *nullentry; + + domain_file->decided = 1; + domain_file->data = NULL; + + /* Note that it would be useless to store domainbinding in domain_file + because domainbinding might be == NULL now but != NULL later (after + a call to bind_textdomain_codeset). */ + + /* If the record does not represent a valid locale the FILENAME + might be NULL. This can happen when according to the given + specification the locale file name is different for XPG and CEN + syntax. */ + if (domain_file->filename == NULL) + return; + + /* Try to open the addressed file. */ + fd = open (domain_file->filename, O_RDONLY | O_BINARY); + if (fd == -1) + return; + + /* We must know about the size of the file. */ + if ( +#ifdef _LIBC + __builtin_expect (fstat64 (fd, &st) != 0, 0) +#else + __builtin_expect (fstat (fd, &st) != 0, 0) +#endif + || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0) + || __builtin_expect (size < sizeof (struct mo_file_header), 0)) + { + /* Something went wrong. */ + close (fd); + return; + } + +#ifdef HAVE_MMAP + /* Now we are ready to load the file. If mmap() is available we try + this first. If not available or it failed we try to load it. */ + data = (struct mo_file_header *) mmap (NULL, size, PROT_READ, + MAP_PRIVATE, fd, 0); + + if (__builtin_expect (data != (struct mo_file_header *) -1, 1)) + { + /* mmap() call was successful. */ + close (fd); + use_mmap = 1; + } +#endif + + /* If the data is not yet available (i.e. mmap'ed) we try to load + it manually. */ + if (data == (struct mo_file_header *) -1) + { + size_t to_read; + char *read_ptr; + + data = (struct mo_file_header *) malloc (size); + if (data == NULL) + return; + + to_read = size; + read_ptr = (char *) data; + do + { + long int nb = (long int) read (fd, read_ptr, to_read); + if (nb <= 0) + { +#ifdef EINTR + if (nb == -1 && errno == EINTR) + continue; +#endif + close (fd); + return; + } + read_ptr += nb; + to_read -= nb; + } + while (to_read > 0); + + close (fd); + } + + /* Using the magic number we can test whether it really is a message + catalog file. */ + if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED, + 0)) + { + /* The magic number is wrong: not a message catalog file. */ +#ifdef HAVE_MMAP + if (use_mmap) + munmap ((caddr_t) data, size); + else +#endif + free (data); + return; + } + + domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); + if (domain == NULL) + return; + domain_file->data = domain; + + domain->data = (char *) data; + domain->use_mmap = use_mmap; + domain->mmap_size = size; + domain->must_swap = data->magic != _MAGIC; + domain->malloced = NULL; + + /* Fill in the information about the available tables. */ + revision = W (domain->must_swap, data->revision); + /* We support only the major revision 0. */ + switch (revision >> 16) + { + case 0: + domain->nstrings = W (domain->must_swap, data->nstrings); + domain->orig_tab = (const struct string_desc *) + ((char *) data + W (domain->must_swap, data->orig_tab_offset)); + domain->trans_tab = (const struct string_desc *) + ((char *) data + W (domain->must_swap, data->trans_tab_offset)); + domain->hash_size = W (domain->must_swap, data->hash_tab_size); + domain->hash_tab = + (domain->hash_size > 2 + ? (const nls_uint32 *) + ((char *) data + W (domain->must_swap, data->hash_tab_offset)) + : NULL); + domain->must_swap_hash_tab = domain->must_swap; + + /* Now dispatch on the minor revision. */ + switch (revision & 0xffff) + { + case 0: + domain->n_sysdep_strings = 0; + domain->orig_sysdep_tab = NULL; + domain->trans_sysdep_tab = NULL; + break; + case 1: + default: + { + nls_uint32 n_sysdep_strings; + + if (domain->hash_tab == NULL) + /* This is invalid. These minor revisions need a hash table. */ + goto invalid; + + n_sysdep_strings = + W (domain->must_swap, data->n_sysdep_strings); + if (n_sysdep_strings > 0) + { + nls_uint32 n_sysdep_segments; + const struct sysdep_segment *sysdep_segments; + const char **sysdep_segment_values; + const nls_uint32 *orig_sysdep_tab; + const nls_uint32 *trans_sysdep_tab; + size_t memneed; + char *mem; + struct sysdep_string_desc *inmem_orig_sysdep_tab; + struct sysdep_string_desc *inmem_trans_sysdep_tab; + nls_uint32 *inmem_hash_tab; + unsigned int i; + + /* Get the values of the system dependent segments. */ + n_sysdep_segments = + W (domain->must_swap, data->n_sysdep_segments); + sysdep_segments = (const struct sysdep_segment *) + ((char *) data + + W (domain->must_swap, data->sysdep_segments_offset)); + sysdep_segment_values = + alloca (n_sysdep_segments * sizeof (const char *)); + for (i = 0; i < n_sysdep_segments; i++) + { + const char *name = + (char *) data + + W (domain->must_swap, sysdep_segments[i].offset); + nls_uint32 namelen = + W (domain->must_swap, sysdep_segments[i].length); + + if (!(namelen > 0 && name[namelen - 1] == '\0')) + { + freea (sysdep_segment_values); + goto invalid; + } + + sysdep_segment_values[i] = get_sysdep_segment_value (name); + } + + orig_sysdep_tab = (const nls_uint32 *) + ((char *) data + + W (domain->must_swap, data->orig_sysdep_tab_offset)); + trans_sysdep_tab = (const nls_uint32 *) + ((char *) data + + W (domain->must_swap, data->trans_sysdep_tab_offset)); + + /* Compute the amount of additional memory needed for the + system dependent strings and the augmented hash table. */ + memneed = 2 * n_sysdep_strings + * sizeof (struct sysdep_string_desc) + + domain->hash_size * sizeof (nls_uint32); + for (i = 0; i < 2 * n_sysdep_strings; i++) + { + const struct sysdep_string *sysdep_string = + (const struct sysdep_string *) + ((char *) data + + W (domain->must_swap, + i < n_sysdep_strings + ? orig_sysdep_tab[i] + : trans_sysdep_tab[i - n_sysdep_strings])); + size_t need = 0; + const struct segment_pair *p = sysdep_string->segments; + + if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END) + for (p = sysdep_string->segments;; p++) + { + nls_uint32 sysdepref; + + need += W (domain->must_swap, p->segsize); + + sysdepref = W (domain->must_swap, p->sysdepref); + if (sysdepref == SEGMENTS_END) + break; + + if (sysdepref >= n_sysdep_segments) + { + /* Invalid. */ + freea (sysdep_segment_values); + goto invalid; + } + + need += strlen (sysdep_segment_values[sysdepref]); + } + + memneed += need; + } + + /* Allocate additional memory. */ + mem = (char *) malloc (memneed); + if (mem == NULL) + goto invalid; + + domain->malloced = mem; + inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem; + mem += n_sysdep_strings * sizeof (struct sysdep_string_desc); + inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem; + mem += n_sysdep_strings * sizeof (struct sysdep_string_desc); + inmem_hash_tab = (nls_uint32 *) mem; + mem += domain->hash_size * sizeof (nls_uint32); + + /* Compute the system dependent strings. */ + for (i = 0; i < 2 * n_sysdep_strings; i++) + { + const struct sysdep_string *sysdep_string = + (const struct sysdep_string *) + ((char *) data + + W (domain->must_swap, + i < n_sysdep_strings + ? orig_sysdep_tab[i] + : trans_sysdep_tab[i - n_sysdep_strings])); + const char *static_segments = + (char *) data + + W (domain->must_swap, sysdep_string->offset); + const struct segment_pair *p = sysdep_string->segments; + + /* Concatenate the segments, and fill + inmem_orig_sysdep_tab[i] (for i < n_sysdep_strings) and + inmem_trans_sysdep_tab[i-n_sysdep_strings] (for + i >= n_sysdep_strings). */ + + if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END) + { + /* Only one static segment. */ + inmem_orig_sysdep_tab[i].length = + W (domain->must_swap, p->segsize); + inmem_orig_sysdep_tab[i].pointer = static_segments; + } + else + { + inmem_orig_sysdep_tab[i].pointer = mem; + + for (p = sysdep_string->segments;; p++) + { + nls_uint32 segsize = + W (domain->must_swap, p->segsize); + nls_uint32 sysdepref = + W (domain->must_swap, p->sysdepref); + size_t n; + + if (segsize > 0) + { + memcpy (mem, static_segments, segsize); + mem += segsize; + static_segments += segsize; + } + + if (sysdepref == SEGMENTS_END) + break; + + n = strlen (sysdep_segment_values[sysdepref]); + memcpy (mem, sysdep_segment_values[sysdepref], n); + mem += n; + } + + inmem_orig_sysdep_tab[i].length = + mem - inmem_orig_sysdep_tab[i].pointer; + } + } + + /* Compute the augmented hash table. */ + for (i = 0; i < domain->hash_size; i++) + inmem_hash_tab[i] = + W (domain->must_swap_hash_tab, domain->hash_tab[i]); + for (i = 0; i < n_sysdep_strings; i++) + { + const char *msgid = inmem_orig_sysdep_tab[i].pointer; + nls_uint32 hash_val = hash_string (msgid); + nls_uint32 idx = hash_val % domain->hash_size; + nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); + + for (;;) + { + if (inmem_hash_tab[idx] == 0) + { + /* Hash table entry is empty. Use it. */ + inmem_hash_tab[idx] = 1 + domain->nstrings + i; + break; + } + + if (idx >= domain->hash_size - incr) + idx -= domain->hash_size - incr; + else + idx += incr; + } + } + + freea (sysdep_segment_values); + + domain->n_sysdep_strings = n_sysdep_strings; + domain->orig_sysdep_tab = inmem_orig_sysdep_tab; + domain->trans_sysdep_tab = inmem_trans_sysdep_tab; + + domain->hash_tab = inmem_hash_tab; + domain->must_swap_hash_tab = 0; + } + else + { + domain->n_sysdep_strings = 0; + domain->orig_sysdep_tab = NULL; + domain->trans_sysdep_tab = NULL; + } + } + break; + } + break; + default: + /* This is an invalid revision. */ + invalid: + /* This is an invalid .mo file. */ + if (domain->malloced) + free (domain->malloced); +#ifdef HAVE_MMAP + if (use_mmap) + munmap ((caddr_t) data, size); + else +#endif + free (data); + free (domain); + domain_file->data = NULL; + return; + } + + /* Now initialize the character set converter from the character set + the file is encoded with (found in the header entry) to the domain's + specified character set or the locale's character set. */ + nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding); + + /* Also look for a plural specification. */ + EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals); +} + + +#ifdef _LIBC +void +internal_function +_nl_unload_domain (domain) + struct loaded_domain *domain; +{ + if (domain->plural != &__gettext_germanic_plural) + __gettext_free_exp (domain->plural); + + _nl_free_domain_conv (domain); + + if (domain->malloced) + free (domain->malloced); + +# ifdef _POSIX_MAPPED_FILES + if (domain->use_mmap) + munmap ((caddr_t) domain->data, domain->mmap_size); + else +# endif /* _POSIX_MAPPED_FILES */ + free ((void *) domain->data); + + free (domain); +} +#endif diff --git a/linphone/intl/localealias.c b/linphone/intl/localealias.c new file mode 100644 index 000000000..456e41e37 --- /dev/null +++ b/linphone/intl/localealias.c @@ -0,0 +1,419 @@ +/* Handle aliases for locale names. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Tell glibc's to provide a prototype for mempcpy(). + This must come before because may include + , and once has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#if defined _LIBC || defined HAVE___FSETLOCKING +# include +#endif +#include + +#ifdef __GNUC__ +# define alloca __builtin_alloca +# define HAVE_ALLOCA 1 +#else +# if defined HAVE_ALLOCA_H || defined _LIBC +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca +char *alloca (); +# endif +# endif +# endif +#endif + +#include +#include + +#include "gettextP.h" + +/* @@ end of prolog @@ */ + +#ifdef _LIBC +/* Rename the non ANSI C functions. This is required by the standard + because some ANSI C functions will require linking with this object + file and the name space must not be polluted. */ +# define strcasecmp __strcasecmp + +# ifndef mempcpy +# define mempcpy __mempcpy +# endif +# define HAVE_MEMPCPY 1 +# define HAVE___FSETLOCKING 1 + +/* We need locking here since we can be called from different places. */ +# include + +__libc_lock_define_initialized (static, lock); +#endif + +#ifndef internal_function +# define internal_function +#endif + +/* Some optimizations for glibc. */ +#ifdef _LIBC +# define FEOF(fp) feof_unlocked (fp) +# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp) +#else +# define FEOF(fp) feof (fp) +# define FGETS(buf, n, fp) fgets (buf, n, fp) +#endif + +/* For those losing systems which don't have `alloca' we have to add + some additional code emulating it. */ +#ifdef HAVE_ALLOCA +# define freea(p) /* nothing */ +#else +# define alloca(n) malloc (n) +# define freea(p) free (p) +#endif + +#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED +# undef fgets +# define fgets(buf, len, s) fgets_unlocked (buf, len, s) +#endif +#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED +# undef feof +# define feof(s) feof_unlocked (s) +#endif + + +struct alias_map +{ + const char *alias; + const char *value; +}; + + +static char *string_space; +static size_t string_space_act; +static size_t string_space_max; +static struct alias_map *map; +static size_t nmap; +static size_t maxmap; + + +/* Prototypes for local functions. */ +static size_t read_alias_file PARAMS ((const char *fname, int fname_len)) + internal_function; +static int extend_alias_table PARAMS ((void)); +static int alias_compare PARAMS ((const struct alias_map *map1, + const struct alias_map *map2)); + + +const char * +_nl_expand_alias (name) + const char *name; +{ + static const char *locale_alias_path; + struct alias_map *retval; + const char *result = NULL; + size_t added; + +#ifdef _LIBC + __libc_lock_lock (lock); +#endif + + if (locale_alias_path == NULL) + locale_alias_path = LOCALE_ALIAS_PATH; + + do + { + struct alias_map item; + + item.alias = name; + + if (nmap > 0) + retval = (struct alias_map *) bsearch (&item, map, nmap, + sizeof (struct alias_map), + (int (*) PARAMS ((const void *, + const void *)) + ) alias_compare); + else + retval = NULL; + + /* We really found an alias. Return the value. */ + if (retval != NULL) + { + result = retval->value; + break; + } + + /* Perhaps we can find another alias file. */ + added = 0; + while (added == 0 && locale_alias_path[0] != '\0') + { + const char *start; + + while (locale_alias_path[0] == PATH_SEPARATOR) + ++locale_alias_path; + start = locale_alias_path; + + while (locale_alias_path[0] != '\0' + && locale_alias_path[0] != PATH_SEPARATOR) + ++locale_alias_path; + + if (start < locale_alias_path) + added = read_alias_file (start, locale_alias_path - start); + } + } + while (added != 0); + +#ifdef _LIBC + __libc_lock_unlock (lock); +#endif + + return result; +} + + +static size_t +internal_function +read_alias_file (fname, fname_len) + const char *fname; + int fname_len; +{ + FILE *fp; + char *full_fname; + size_t added; + static const char aliasfile[] = "/locale.alias"; + + full_fname = (char *) alloca (fname_len + sizeof aliasfile); +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (full_fname, fname, fname_len), + aliasfile, sizeof aliasfile); +#else + memcpy (full_fname, fname, fname_len); + memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile); +#endif + + fp = fopen (full_fname, "r"); + freea (full_fname); + if (fp == NULL) + return 0; + +#ifdef HAVE___FSETLOCKING + /* No threads present. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); +#endif + + added = 0; + while (!FEOF (fp)) + { + /* It is a reasonable approach to use a fix buffer here because + a) we are only interested in the first two fields + b) these fields must be usable as file names and so must not + be that long + */ + char buf[BUFSIZ]; + char *alias; + char *value; + char *cp; + + if (FGETS (buf, sizeof buf, fp) == NULL) + /* EOF reached. */ + break; + + /* Possibly not the whole line fits into the buffer. Ignore + the rest of the line. */ + if (strchr (buf, '\n') == NULL) + { + char altbuf[BUFSIZ]; + do + if (FGETS (altbuf, sizeof altbuf, fp) == NULL) + /* Make sure the inner loop will be left. The outer loop + will exit at the `feof' test. */ + break; + while (strchr (altbuf, '\n') == NULL); + } + + cp = buf; + /* Ignore leading white space. */ + while (isspace ((unsigned char) cp[0])) + ++cp; + + /* A leading '#' signals a comment line. */ + if (cp[0] != '\0' && cp[0] != '#') + { + alias = cp++; + while (cp[0] != '\0' && !isspace ((unsigned char) cp[0])) + ++cp; + /* Terminate alias name. */ + if (cp[0] != '\0') + *cp++ = '\0'; + + /* Now look for the beginning of the value. */ + while (isspace ((unsigned char) cp[0])) + ++cp; + + if (cp[0] != '\0') + { + size_t alias_len; + size_t value_len; + + value = cp++; + while (cp[0] != '\0' && !isspace ((unsigned char) cp[0])) + ++cp; + /* Terminate value. */ + if (cp[0] == '\n') + { + /* This has to be done to make the following test + for the end of line possible. We are looking for + the terminating '\n' which do not overwrite here. */ + *cp++ = '\0'; + *cp = '\n'; + } + else if (cp[0] != '\0') + *cp++ = '\0'; + + if (nmap >= maxmap) + if (__builtin_expect (extend_alias_table (), 0)) + return added; + + alias_len = strlen (alias) + 1; + value_len = strlen (value) + 1; + + if (string_space_act + alias_len + value_len > string_space_max) + { + /* Increase size of memory pool. */ + size_t new_size = (string_space_max + + (alias_len + value_len > 1024 + ? alias_len + value_len : 1024)); + char *new_pool = (char *) realloc (string_space, new_size); + if (new_pool == NULL) + return added; + + if (__builtin_expect (string_space != new_pool, 0)) + { + size_t i; + + for (i = 0; i < nmap; i++) + { + map[i].alias += new_pool - string_space; + map[i].value += new_pool - string_space; + } + } + + string_space = new_pool; + string_space_max = new_size; + } + + map[nmap].alias = memcpy (&string_space[string_space_act], + alias, alias_len); + string_space_act += alias_len; + + map[nmap].value = memcpy (&string_space[string_space_act], + value, value_len); + string_space_act += value_len; + + ++nmap; + ++added; + } + } + } + + /* Should we test for ferror()? I think we have to silently ignore + errors. --drepper */ + fclose (fp); + + if (added > 0) + qsort (map, nmap, sizeof (struct alias_map), + (int (*) PARAMS ((const void *, const void *))) alias_compare); + + return added; +} + + +static int +extend_alias_table () +{ + size_t new_size; + struct alias_map *new_map; + + new_size = maxmap == 0 ? 100 : 2 * maxmap; + new_map = (struct alias_map *) realloc (map, (new_size + * sizeof (struct alias_map))); + if (new_map == NULL) + /* Simply don't extend: we don't have any more core. */ + return -1; + + map = new_map; + maxmap = new_size; + return 0; +} + + +#ifdef _LIBC +static void __attribute__ ((unused)) +free_mem (void) +{ + if (string_space != NULL) + free (string_space); + if (map != NULL) + free (map); +} +text_set_element (__libc_subfreeres, free_mem); +#endif + + +static int +alias_compare (map1, map2) + const struct alias_map *map1; + const struct alias_map *map2; +{ +#if defined _LIBC || defined HAVE_STRCASECMP + return strcasecmp (map1->alias, map2->alias); +#else + const unsigned char *p1 = (const unsigned char *) map1->alias; + const unsigned char *p2 = (const unsigned char *) map2->alias; + unsigned char c1, c2; + + if (p1 == p2) + return 0; + + do + { + /* I know this seems to be odd but the tolower() function in + some systems libc cannot handle nonalpha characters. */ + c1 = isupper (*p1) ? tolower (*p1) : *p1; + c2 = isupper (*p2) ? tolower (*p2) : *p2; + if (c1 == '\0') + break; + ++p1; + ++p2; + } + while (c1 == c2); + + return c1 - c2; +#endif +} diff --git a/linphone/intl/po2tbl.sed.in b/linphone/intl/po2tbl.sed.in new file mode 100644 index 000000000..b3bcca4d7 --- /dev/null +++ b/linphone/intl/po2tbl.sed.in @@ -0,0 +1,102 @@ +# po2tbl.sed - Convert Uniforum style .po file to lookup table for catgets +# Copyright (C) 1995 Free Software Foundation, Inc. +# Ulrich Drepper , 1995. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +1 { + i\ +/* Automatically generated by po2tbl.sed from @PACKAGE NAME@.pot. */\ +\ +#if HAVE_CONFIG_H\ +# include \ +#endif\ +\ +#include "libgettext.h"\ +\ +const struct _msg_ent _msg_tbl[] = { + h + s/.*/0/ + x +} +# +# Write msgid entries in C array form. +# +/^msgid/ { + s/msgid[ ]*\(".*"\)/ {\1/ + tb +# Append the next line + :b + N +# Look whether second part is continuation line. + s/\(.*\)"\(\n\)"\(.*"\)/\1\2\3/ +# Yes, then branch. + ta +# Because we assume that the input file correctly formed the line +# just read cannot be again be a msgid line. So it's safe to ignore +# it. + s/\(.*\)\n.*/\1/ + bc +# We found a continuation line. But before printing insert '\'. + :a + s/\(.*\)\(\n.*\)/\1\\\2/ + P +# We cannot use D here. + s/.*\n\(.*\)/\1/ +# Some buggy seds do not clear the `successful substitution since last ``t''' +# flag on `N', so we do a `t' here to clear it. + tb +# Not reached + :c + x +# The following nice solution is by +# Bruno + td +# Increment a decimal number in pattern space. +# First hide trailing `9' digits. + :d + s/9\(_*\)$/_\1/ + td +# Assure at least one digit is available. + s/^\(_*\)$/0\1/ +# Increment the last digit. + s/8\(_*\)$/9\1/ + s/7\(_*\)$/8\1/ + s/6\(_*\)$/7\1/ + s/5\(_*\)$/6\1/ + s/4\(_*\)$/5\1/ + s/3\(_*\)$/4\1/ + s/2\(_*\)$/3\1/ + s/1\(_*\)$/2\1/ + s/0\(_*\)$/1\1/ +# Convert the hidden `9' digits to `0's. + s/_/0/g + x + G + s/\(.*\)\n\([0-9]*\)/\1, \2},/ + s/\(.*\)"$/\1/ + p +} +# +# Last line. +# +$ { + i\ +};\ + + g + s/0*\(.*\)/int _msg_tbl_length = \1;/p +} +d diff --git a/linphone/intl/textdomain.c b/linphone/intl/textdomain.c new file mode 100644 index 000000000..f259c696d --- /dev/null +++ b/linphone/intl/textdomain.c @@ -0,0 +1,142 @@ +/* Implementation of the textdomain(3) function. + Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#ifdef _LIBC +# include +#else +# include "libgnuintl.h" +#endif +#include "gettextP.h" + +#ifdef _LIBC +/* We have to handle multi-threaded applications. */ +# include +#else +/* Provide dummy implementation if this is outside glibc. */ +# define __libc_rwlock_define(CLASS, NAME) +# define __libc_rwlock_wrlock(NAME) +# define __libc_rwlock_unlock(NAME) +#endif + +/* The internal variables in the standalone libintl.a must have different + names than the internal variables in GNU libc, otherwise programs + using libintl.a cannot be linked statically. */ +#if !defined _LIBC +# define _nl_default_default_domain libintl_nl_default_default_domain +# define _nl_current_default_domain libintl_nl_current_default_domain +#endif + +/* @@ end of prolog @@ */ + +/* Name of the default text domain. */ +extern const char _nl_default_default_domain[] attribute_hidden; + +/* Default text domain in which entries for gettext(3) are to be found. */ +extern const char *_nl_current_default_domain attribute_hidden; + + +/* Names for the libintl functions are a problem. They must not clash + with existing names and they should follow ANSI C. But this source + code is also used in GNU C Library where the names have a __ + prefix. So we have to make a difference here. */ +#ifdef _LIBC +# define TEXTDOMAIN __textdomain +# ifndef strdup +# define strdup(str) __strdup (str) +# endif +#else +# define TEXTDOMAIN libintl_textdomain +#endif + +/* Lock variable to protect the global data in the gettext implementation. */ +__libc_rwlock_define (extern, _nl_state_lock attribute_hidden) + +/* Set the current default message catalog to DOMAINNAME. + If DOMAINNAME is null, return the current default. + If DOMAINNAME is "", reset to the default of "messages". */ +char * +TEXTDOMAIN (domainname) + const char *domainname; +{ + char *new_domain; + char *old_domain; + + /* A NULL pointer requests the current setting. */ + if (domainname == NULL) + return (char *) _nl_current_default_domain; + + __libc_rwlock_wrlock (_nl_state_lock); + + old_domain = (char *) _nl_current_default_domain; + + /* If domain name is the null string set to default domain "messages". */ + if (domainname[0] == '\0' + || strcmp (domainname, _nl_default_default_domain) == 0) + { + _nl_current_default_domain = _nl_default_default_domain; + new_domain = (char *) _nl_current_default_domain; + } + else if (strcmp (domainname, old_domain) == 0) + /* This can happen and people will use it to signal that some + environment variable changed. */ + new_domain = old_domain; + else + { + /* If the following malloc fails `_nl_current_default_domain' + will be NULL. This value will be returned and so signals we + are out of core. */ +#if defined _LIBC || defined HAVE_STRDUP + new_domain = strdup (domainname); +#else + size_t len = strlen (domainname) + 1; + new_domain = (char *) malloc (len); + if (new_domain != NULL) + memcpy (new_domain, domainname, len); +#endif + + if (new_domain != NULL) + _nl_current_default_domain = new_domain; + } + + /* We use this possibility to signal a change of the loaded catalogs + since this is most likely the case and there is no other easy we + to do it. Do it only when the call was successful. */ + if (new_domain != NULL) + { + ++_nl_msg_cat_cntr; + + if (old_domain != new_domain && old_domain != _nl_default_default_domain) + free (old_domain); + } + + __libc_rwlock_unlock (_nl_state_lock); + + return new_domain; +} + +#ifdef _LIBC +/* Alias for function name in GNU C Library. */ +weak_alias (__textdomain, textdomain); +#endif diff --git a/linphone/intl/xopen-msg.sed b/linphone/intl/xopen-msg.sed new file mode 100644 index 000000000..b19c0bbd0 --- /dev/null +++ b/linphone/intl/xopen-msg.sed @@ -0,0 +1,104 @@ +# po2msg.sed - Convert Uniforum style .po file to X/Open style .msg file +# Copyright (C) 1995 Free Software Foundation, Inc. +# Ulrich Drepper , 1995. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# +# The first directive in the .msg should be the definition of the +# message set number. We use always set number 1. +# +1 { + i\ +$set 1 # Automatically created by po2msg.sed + h + s/.*/0/ + x +} +# +# We copy all comments into the .msg file. Perhaps they can help. +# +/^#/ s/^#[ ]*/$ /p +# +# We copy the original message as a comment into the .msg file. +# +/^msgid/ { +# Does not work now +# /"$/! { +# s/\\$// +# s/$/ ... (more lines following)"/ +# } + s/^msgid[ ]*"\(.*\)"$/$ Original Message: \1/ + p +} +# +# The .msg file contains, other then the .po file, only the translations +# but each given a unique ID. Starting from 1 and incrementing by 1 for +# each message we assign them to the messages. +# It is important that the .po file used to generate the cat-id-tbl.c file +# (with po-to-tbl) is the same as the one used here. (At least the order +# of declarations must not be changed.) +# +/^msgstr/ { + s/msgstr[ ]*"\(.*\)"/\1/ + x +# The following nice solution is by +# Bruno + td +# Increment a decimal number in pattern space. +# First hide trailing `9' digits. + :d + s/9\(_*\)$/_\1/ + td +# Assure at least one digit is available. + s/^\(_*\)$/0\1/ +# Increment the last digit. + s/8\(_*\)$/9\1/ + s/7\(_*\)$/8\1/ + s/6\(_*\)$/7\1/ + s/5\(_*\)$/6\1/ + s/4\(_*\)$/5\1/ + s/3\(_*\)$/4\1/ + s/2\(_*\)$/3\1/ + s/1\(_*\)$/2\1/ + s/0\(_*\)$/1\1/ +# Convert the hidden `9' digits to `0's. + s/_/0/g + x +# Bring the line in the format ` ' + G + s/^[^\n]*$/& / + s/\(.*\)\n\([0-9]*\)/\2 \1/ +# Clear flag from last substitution. + tb +# Append the next line. + :b + N +# Look whether second part is a continuation line. + s/\(.*\n\)"\(.*\)"/\1\2/ +# Yes, then branch. + ta + P + D +# Note that `D' includes a jump to the start!! +# We found a continuation line. But before printing insert '\'. + :a + s/\(.*\)\(\n.*\)/\1\\\2/ + P +# We cannot use the sed command `D' here + s/.*\n\(.*\)/\1/ + tb +} +d diff --git a/linphone/intltool-extract.in b/linphone/intltool-extract.in new file mode 100644 index 000000000..256a959a1 --- /dev/null +++ b/linphone/intltool-extract.in @@ -0,0 +1,325 @@ +#!@INTLTOOL_PERL@ -w +# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# +# The Intltool Message Extractor +# +# Copyright (C) 2000-2001 Free Software Foundation. +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +# +# Authors: Kenneth Christiansen +# Darin Adler +# + +## Release information +my $PROGRAM = "intltool-extract"; +my $PACKAGE = "intltool"; +my $VERSION = "0.22"; + +## Loaded modules +use strict; +use File::Basename; +use Getopt::Long; + +## Scalars used by the option stuff +my $TYPE_ARG = "0"; +my $LOCAL_ARG = "0"; +my $HELP_ARG = "0"; +my $VERSION_ARG = "0"; +my $UPDATE_ARG = "0"; +my $QUIET_ARG = "0"; + +my $FILE; +my $OUTFILE; + +my $gettext_type = ""; +my $input; +my %messages = (); + +## Use this instead of \w for XML files to handle more possible characters. +my $w = "[-A-Za-z0-9._:]"; + +## Always print first +$| = 1; + +## Handle options +GetOptions ( + "type=s" => \$TYPE_ARG, + "local|l" => \$LOCAL_ARG, + "help|h" => \$HELP_ARG, + "version|v" => \$VERSION_ARG, + "update" => \$UPDATE_ARG, + "quiet|q" => \$QUIET_ARG, + ) or &error; + +&split_on_argument; + + +## Check for options. +## This section will check for the different options. + +sub split_on_argument { + + if ($VERSION_ARG) { + &version; + + } elsif ($HELP_ARG) { + &help; + + } elsif ($LOCAL_ARG) { + &place_local; + &extract; + + } elsif ($UPDATE_ARG) { + &place_normal; + &extract; + + } elsif (@ARGV > 0) { + &place_normal; + &message; + &extract; + + } else { + &help; + + } +} + +sub place_normal { + $FILE = $ARGV[0]; + $OUTFILE = "$FILE.h"; +} + +sub place_local { + $OUTFILE = fileparse($FILE, ()); + if (!-e "tmp/") { + system("mkdir tmp/"); + } + $OUTFILE = "./tmp/$OUTFILE.h" +} + +sub determine_type { + if ($TYPE_ARG =~ /^gettext\/(.*)/) { + $gettext_type=$1 + } +} + +## Sub for printing release information +sub version{ + print "${PROGRAM} (${PACKAGE}) $VERSION\n"; + print "Copyright (C) 2000 Free Software Foundation, Inc.\n"; + print "Written by Kenneth Christiansen, 2000.\n\n"; + print "This is free software; see the source for copying conditions. There is NO\n"; + print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; + exit; +} + +## Sub for printing usage information +sub help{ + print "Usage: ${PROGRAM} [FILENAME] [OPTIONS] ...\n"; + print "Generates a header file from an xml source file.\n\nGrabs all strings "; + print "between <_translatable_node> and it's end tag,\nwhere tag are all allowed "; + print "xml tags. Read the docs for more info.\n\n"; + print " -v, --version shows the version\n"; + print " -h, --help shows this help page\n"; + print " -q, --quiet quiet mode\n"; + print "\nReport bugs to .\n"; + exit; +} + +## Sub for printing error messages +sub error{ + print "Try `${PROGRAM} --help' for more information.\n"; + exit; +} + +sub message { + print "Generating C format header file for translation.\n"; +} + +sub extract { + &determine_type; + + &convert ($FILE); + + open OUT, ">$OUTFILE"; + &msg_write; + close OUT; + + print "Wrote $OUTFILE\n" unless $QUIET_ARG; +} + +sub convert($) { + + ## Reading the file + { + local (*IN); + local $/; #slurp mode + open (IN, "<$FILE") || die "can't open $FILE: $!"; + $input = ; + } + + &type_ini if $gettext_type eq "ini"; + &type_keys if $gettext_type eq "keys"; + &type_xml if $gettext_type eq "xml"; + &type_glade if $gettext_type eq "glade"; + &type_scheme if $gettext_type eq "scheme"; + &type_schemas if $gettext_type eq "schemas"; +} + +sub entity_decode_minimal +{ + local ($_) = @_; + + s/'/'/g; # ' + s/"/"/g; # " + s/&/&/g; + + return $_; +} + +sub entity_decode +{ + local ($_) = @_; + + s/'/'/g; # ' + s/"/"/g; # " + s/&/&/g; + s/<//g; + + return $_; +} + +sub escape_char +{ + return '\"' if $_ eq '"'; + return '\n' if $_ eq "\n"; + return '\\' if $_ eq '\\'; + + return $_; +} + +sub escape +{ + my ($string) = @_; + return join "", map &escape_char, split //, $string; +} + +sub type_ini { + ### For generic translatable desktop files ### + while ($input =~ /^_.*=(.*)$/mg) { + $messages{$1} = []; + } +} + +sub type_keys { + ### For generic translatable mime/keys files ### + while ($input =~ /^\s*_\w+=(.*)$/mg) { + $messages{$1} = []; + } +} + +sub type_xml { + ### For generic translatable XML files ### + + while ($input =~ /\s_$w+=\"([^"]+)\"/sg) { # " + $messages{entity_decode_minimal($1)} = []; + } + + while ($input =~ /<_($w+)>(.+?)<\/_\1>/sg) { + $_ = $2; + s/\s+/ /g; + s/^ //; + s/ $//; + $messages{entity_decode_minimal($_)} = []; + } +} + +sub type_schemas { + ### For schemas XML files ### + + # FIXME: We should handle escaped < (less than) + while ($input =~ /<(short|long)>([^<]+)<\/\1>/sg) { + $_ = $2; + s/\s+/ /g; + s/^ //; + s/ $//; + $messages{entity_decode_minimal($_)} = []; + } +} + +sub type_glade { + ### For translatable Glade XML files ### + + my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; + + while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { + # Glade sometimes uses tags that normally mark translatable things for + # little bits of non-translatable content. We work around this by not + # translating strings that only includes something like label4 or window1. + $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label)[0-9]+$/; + } + + while ($input =~ /(..[^<]*)<\/items>/sg) { + for my $item (split (/\n/, $1)) { + $messages{entity_decode($item)} = []; + } + } + + ## handle new glade files + while ($input =~ /<(property|atkproperty)\s+[^>]*translatable\s*=\s*"yes"[^>]*>([^<]+)<\/\1>/sg) { + $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label)[0-9]+$/; + } + while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { + $messages{entity_decode_minimal($2)} = []; + } +} + +sub type_scheme { + while ($input =~ /_\(?"((?:[^"\\]+|\\.)*)"\)?/sg) { + $messages{$1} = []; + } +} + +sub msg_write { + for my $message (sort keys %messages) { + print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; + + my @lines = split (/\n/, $message); + for (my $n = 0; $n < @lines; $n++) { + if ($n == 0) { + print OUT "char *s = N_(\""; + } else { + print OUT " \""; + } + + print OUT escape($lines[$n]); + + if ($n < @lines - 1) { + print OUT "\\n\"\n"; + } else { + print OUT "\");\n"; + } + } + } +} + diff --git a/linphone/intltool-merge.in b/linphone/intltool-merge.in new file mode 100644 index 000000000..fd35cfdef --- /dev/null +++ b/linphone/intltool-merge.in @@ -0,0 +1,657 @@ +#!@INTLTOOL_PERL@ -w + +# +# The Intltool Message Merger +# +# Copyright (C) 2000, 2002 Free Software Foundation. +# Copyright (C) 2000, 2001 Eazel, Inc +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 published by the Free Software Foundation. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +# +# Authors: Maciej Stachowiak +# Kenneth Christiansen +# Darin Adler +# +# Proper XML UTF-8'ification written by Cyrille Chepelov +# + +## Release information +my $PROGRAM = "intltool-merge"; +my $PACKAGE = "intltool"; +my $VERSION = "0.22"; + +## Loaded modules +use strict; +use Getopt::Long; + +## Scalars used by the option stuff +my $HELP_ARG = 0; +my $VERSION_ARG = 0; +my $BA_STYLE_ARG = 0; +my $XML_STYLE_ARG = 0; +my $KEYS_STYLE_ARG = 0; +my $DESKTOP_STYLE_ARG = 0; +my $SCHEMAS_STYLE_ARG = 0; +my $QUIET_ARG = 0; +my $PASS_THROUGH_ARG = 0; +my $UTF8_ARG = 0; +my $cache_file; + +## Handle options +GetOptions +( + "help" => \$HELP_ARG, + "version" => \$VERSION_ARG, + "quiet|q" => \$QUIET_ARG, + "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility + "ba-style|b" => \$BA_STYLE_ARG, + "xml-style|x" => \$XML_STYLE_ARG, + "keys-style|k" => \$KEYS_STYLE_ARG, + "desktop-style|d" => \$DESKTOP_STYLE_ARG, + "schemas-style|s" => \$SCHEMAS_STYLE_ARG, + "pass-through|p" => \$PASS_THROUGH_ARG, + "utf8|u" => \$UTF8_ARG, + "cache|c=s" => \$cache_file + ) or &error; + +my $PO_DIR; +my $FILE; +my $OUTFILE; + +my %po_files_by_lang = (); +my %translations = (); + +# Use this instead of \w for XML files to handle more possible characters. +my $w = "[-A-Za-z0-9._:]"; + +# XML quoted string contents +my $q = "[^\\\"]*"; + +## Check for options. + +if ($VERSION_ARG) { + &print_version; +} elsif ($HELP_ARG) { + &print_help; +} elsif ($BA_STYLE_ARG && @ARGV > 2) { + &preparation; + &print_message; + &ba_merge_translations; + &finalize; +} elsif ($XML_STYLE_ARG && @ARGV > 2) { + &utf8_sanity_check; + &preparation; + &print_message; + &xml_merge_translations; + &finalize; +} elsif ($KEYS_STYLE_ARG && @ARGV > 2) { + &utf8_sanity_check; + &preparation; + &print_message; + &keys_merge_translations; + &finalize; +} elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) { + &preparation; + &print_message; + &desktop_merge_translations; + &finalize; +} elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) { + &preparation; + &print_message; + &schemas_merge_translations; + &finalize; +} else { + &print_help; +} + +exit; + +## Sub for printing release information +sub print_version +{ + print "${PROGRAM} (${PACKAGE}) ${VERSION}\n"; + print "Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen.\n\n"; + print "Copyright (C) 2000-2002 Free Software Foundation, Inc.\n"; + print "Copyright (C) 2000-2001 Eazel, Inc.\n"; + print "This is free software; see the source for copying conditions. There is NO\n"; + print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; + exit; +} + +## Sub for printing usage information +sub print_help +{ + print "Usage: ${PROGRAM} [OPTIONS] PO_DIRECTORY FILENAME OUTPUT_FILE\n"; + print "Generates an output file that includes translated versions of some attributes,\n"; + print "from an untranslated source and a po directory that includes translations.\n\n"; + print " -b, --ba-style includes translations in the bonobo-activation style\n"; + print " -d, --desktop-style includes translations in the desktop style\n"; + print " -k, --keys-style includes translations in the keys style\n"; + print " -s, --schemas-style includes translations in the schemas style\n"; + print " -x, --xml-style includes translations in the standard xml style\n"; + print " -u, --utf8 convert all strings to UTF-8 before merging\n"; + print " -p, --pass-through use strings as found in .po files, without\n"; + print " conversion (STRONGLY unrecommended with -x)\n"; + print " -q, --quiet suppress most messages\n"; + print " --help display this help and exit\n"; + print " --version output version information and exit\n"; + print "\nReport bugs to bugzilla.gnome.org, module intltool, or contact us through \n"; + print ".\n"; + exit; +} + + +## Sub for printing error messages +sub print_error +{ + print "Try `${PROGRAM} --help' for more information.\n"; + exit; +} + + +sub print_message +{ + print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; +} + + +sub preparation +{ + $PO_DIR = $ARGV[0]; + $FILE = $ARGV[1]; + $OUTFILE = $ARGV[2]; + + &gather_po_files; + &get_translation_database; +} + +# General-purpose code for looking up translations in .po files + +sub po_file2lang +{ + my ($tmp) = @_; + $tmp =~ s/^.*\/(.*)\.po$/$1/; + return $tmp; +} + +sub gather_po_files +{ + for my $po_file (glob "$PO_DIR/*.po") { + $po_files_by_lang{po_file2lang($po_file)} = $po_file; + } +} + +sub get_po_encoding +{ + my ($in_po_file) = @_; + my $encoding = ""; + + open IN_PO_FILE, $in_po_file or die; + while () { + ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" + if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) { + $encoding = $1; + last; + } + } + close IN_PO_FILE; + + if (!$encoding) { + print "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n"; + $encoding = "ISO-8859-1"; + } + return $encoding +} + +sub utf8_sanity_check +{ + if (!$UTF8_ARG) { + if (!$PASS_THROUGH_ARG) { + $PASS_THROUGH_ARG="1"; + } + } +} + +sub get_translation_database +{ + if ($cache_file) { + &get_cached_translation_database; + } else { + &create_translation_database; + } +} + +sub get_newest_po_age +{ + my $newest_age; + + foreach my $file (values %po_files_by_lang) { + my $file_age = -M $file; + $newest_age = $file_age if !$newest_age || $file_age < $newest_age; + } + + return $newest_age; +} + +sub create_cache +{ + print "Generating and caching the translation database\n" unless $QUIET_ARG; + + &create_translation_database; + + open CACHE, ">$cache_file" || die; + print CACHE join "\x01", %translations; + close CACHE; +} + +sub load_cache +{ + print "Found cached translation database\n" unless $QUIET_ARG; + + my $contents; + open CACHE, "<$cache_file" || die; + { + local $/; + $contents = ; + } + close CACHE; + %translations = split "\x01", $contents; +} + +sub get_cached_translation_database +{ + my $cache_file_age = -M $cache_file; + if (defined $cache_file_age) { + if ($cache_file_age <= &get_newest_po_age) { + &load_cache; + return; + } + print "Found too-old cached translation database\n" unless $QUIET_ARG; + } + + &create_cache; +} + +sub create_translation_database +{ + for my $lang (keys %po_files_by_lang) { + my $po_file = $po_files_by_lang{$lang}; + + if ($UTF8_ARG) { + my $encoding = get_po_encoding ($po_file); + if (lc $encoding eq "utf-8") { + open PO_FILE, "<$po_file"; + } else { + my $iconv = $ENV{"INTLTOOL_ICONV"} || "iconv"; + open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|"; + } + } else { + open PO_FILE, "<$po_file"; + } + + my $nextfuzzy = 0; + my $inmsgid = 0; + my $inmsgstr = 0; + my $msgid = ""; + my $msgstr = ""; + while () { + $nextfuzzy = 1 if /^#, fuzzy/; + if (/^msgid "((\\.|[^\\])*)"/ ) { + $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; + $msgid = ""; + $msgstr = ""; + + if ($nextfuzzy) { + $inmsgid = 0; + } else { + $msgid = unescape_po_string($1); + $inmsgid = 1; + } + $inmsgstr = 0; + $nextfuzzy = 0; + } + if (/^msgstr "((\\.|[^\\])*)"/) { + $msgstr = unescape_po_string($1); + $inmsgstr = 1; + $inmsgid = 0; + } + if (/^"((\\.|[^\\])*)"/) { + $msgid .= unescape_po_string($1) if $inmsgid; + $msgstr .= unescape_po_string($1) if $inmsgstr; + } + } + $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; + } +} + +sub finalize +{ +} + +sub unescape_one_sequence +{ + my ($sequence) = @_; + + return "\\" if $sequence eq "\\\\"; + return "\"" if $sequence eq "\\\""; + + # gettext also handles \n, \t, \b, \r, \f, \v, \a, \xxx (octal), + # \xXX (hex) and has a comment saying they want to handle \u and \U. + + return $sequence; +} + +sub unescape_po_string +{ + my ($string) = @_; + + $string =~ s/(\\.)/unescape_one_sequence($1)/eg; + + return $string; +} + +sub entity_decode +{ + local ($_) = @_; + + s/'/'/g; # ' + s/"/"/g; # " + s/&/&/g; + + return $_; +} + +sub entity_encode +{ + my ($pre_encoded) = @_; + + my @list_of_chars = unpack ('C*', $pre_encoded); + + if ($PASS_THROUGH_ARG) { + return join ('', map (&entity_encode_int_even_high_bit, @list_of_chars)); + } else { + return join ('', map (&entity_encode_int_minimalist, @list_of_chars)); + } +} + +sub entity_encode_int_minimalist +{ + return """ if $_ == 34; + return "&" if $_ == 38; + return "'" if $_ == 39; + return chr $_; +} + +sub entity_encode_int_even_high_bit +{ + if ($_ > 127 || $_ == 34 || $_ == 38 || $_ == 39) { + # the ($_ > 127) should probably be removed + return "&#" . $_ . ";"; + } else { + return chr $_; + } +} + +sub entity_encoded_translation +{ + my ($lang, $string) = @_; + + my $translation = $translations{$lang, $string}; + return $string if !$translation; + return entity_encode ($translation); +} + +## XML (bonobo-activation specific) merge code + +sub ba_merge_translations +{ + my $source; + + { + local $/; # slurp mode + open INPUT, "<$FILE" or die "can't open $FILE: $!"; + $source = ; + close INPUT; + } + + open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; + + while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) { + print OUTPUT $1; + + my $node = $2 . "\n"; + + my @strings = (); + $_ = $node; + while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { + push @strings, entity_decode($3); + } + print OUTPUT; + + my %langs; + for my $string (@strings) { + for my $lang (keys %po_files_by_lang) { + $langs{$lang} = 1 if $translations{$lang, $string}; + } + } + + for my $lang (sort keys %langs) { + $_ = $node; + s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; + s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; + print OUTPUT; + } + } + + print OUTPUT $source; + + close OUTPUT; +} + + +## XML (non-bonobo-activation) merge code + +sub xml_merge_translations +{ + my $source; + + { + local $/; # slurp mode + open INPUT, "<$FILE" or die "can't open $FILE: $!"; + $source = ; + close INPUT; + } + + open OUTPUT, ">$OUTFILE" or die; + + # FIXME: support attribute translations + + # Empty nodes never need translation, so unmark all of them. + # For example, <_foo/> is just replaced by . + $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; + + # Support for <_foo>blah style translations. + while ($source =~ s|^(.*?)([ \t]*)<\s*_($w+)\s*>(.*?)<\s*/_\3\s*>([ \t]*\n)?||s) { + print OUTPUT $1; + + my $spaces = $2; + my $tag = $3; + my $string = $4; + + print OUTPUT "$spaces<$tag>$string\n"; + + $string =~ s/\s+/ /g; + $string =~ s/^ //; + $string =~ s/ $//; + $string = entity_decode($string); + + for my $lang (sort keys %po_files_by_lang) { + my $translation = $translations{$lang, $string}; + next if !$translation; + $translation = entity_encode($translation); + print OUTPUT "$spaces<$tag xml:lang=\"$lang\">$translation\n"; + } + } + + print OUTPUT $source; + + close OUTPUT; +} + +sub keys_merge_translations +{ + open INPUT, "<${FILE}" or die; + open OUTPUT, ">${OUTFILE}" or die; + + while () { + if (s/^(\s*)_(\w+=(.*))/$1$2/) { + my $string = $3; + + print OUTPUT; + + my $non_translated_line = $_; + + for my $lang (sort keys %po_files_by_lang) { + my $translation = $translations{$lang, $string}; + next if !$translation; + + $_ = $non_translated_line; + s/(\w+)=.*/[$lang]$1=$translation/; + print OUTPUT; + } + } else { + print OUTPUT; + } + } + + close OUTPUT; + close INPUT; +} + +sub desktop_merge_translations +{ + open INPUT, "<${FILE}" or die; + open OUTPUT, ">${OUTFILE}" or die; + + while () { + if (s/^(\s*)_(\w+=(.*))/$1$2/) { + my $string = $3; + + print OUTPUT; + + my $non_translated_line = $_; + + for my $lang (sort keys %po_files_by_lang) { + my $translation = $translations{$lang, $string}; + next if !$translation; + + $_ = $non_translated_line; + s/(\w+)=.*/${1}[$lang]=$translation/; + print OUTPUT; + } + } else { + print OUTPUT; + } + } + + close OUTPUT; + close INPUT; +} + +sub schemas_merge_translations +{ + my $source; + + { + local $/; # slurp mode + open INPUT, "<$FILE" or die "can't open $FILE: $!"; + $source = ; + close INPUT; + } + + open OUTPUT, ">$OUTFILE" or die; + + # FIXME: support attribute translations + + # Empty nodes never need translation, so unmark all of them. + # For example, <_foo/> is just replaced by . + $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; + + # Support for <_foo>blah style translations. + + my $regex_start = "^(.*?)([ \t]*)"; + my $regex_short = "([ \t\n]*)(.*?)"; + my $regex_long = "([ \t\n]*)(.*?)"; + my $regex_end = "([ \t\n]*)"; + + while ($source =~ s|$regex_start$regex_short$regex_long$regex_end||s) { + print OUTPUT $1; + + my $locale_start_spaces = $2; + my $locale_end_spaces = $7; + my $short_spaces = $3; + my $short_string = $4; + my $long_spaces = $5; + my $long_string = $6; + + # English first + + print OUTPUT "$locale_start_spaces"; + print OUTPUT "$short_spaces$short_string"; + print OUTPUT "$long_spaces$long_string"; + print OUTPUT "$locale_end_spaces"; + + $short_string =~ s/\s+/ /g; + $short_string =~ s/^ //; + $short_string =~ s/ $//; + $short_string = entity_decode($short_string); + + $long_string =~ s/\s+/ /g; + $long_string =~ s/^ //; + $long_string =~ s/ $//; + $long_string = entity_decode($long_string); + + for my $lang (sort keys %po_files_by_lang) { + my $short_translation = $translations{$lang, $short_string}; + my $long_translation = $translations{$lang, $long_string}; + + next if (!$short_translation && !$long_translation); + + print OUTPUT "\n$locale_start_spaces"; + + if ($short_translation) + { + $short_translation = entity_encode($short_translation); + print OUTPUT "$short_spaces$short_translation"; + } + + if ($long_translation) + { + $long_translation = entity_encode($long_translation); + print OUTPUT "$long_spaces$long_translation"; + } + + print OUTPUT "$locale_end_spaces"; + } + } + + print OUTPUT $source; + + close OUTPUT; +} diff --git a/linphone/intltool-update.in b/linphone/intltool-update.in new file mode 100644 index 000000000..cc5fc141d --- /dev/null +++ b/linphone/intltool-update.in @@ -0,0 +1,634 @@ +#!@INTLTOOL_PERL@ -w + +# +# The Intltool Message Updater +# +# Copyright (C) 2000-2002 Free Software Foundation. +# +# Intltool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 published by the Free Software Foundation. +# +# Intltool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +# +# Authors: Kenneth Christiansen +# Maciej Stachowiak +# Darin Adler + +## Release information +my $PROGRAM = "intltool-update"; +my $VERSION = "0.22"; +my $PACKAGE = "intltool"; + +## Loaded modules +use strict; +use Getopt::Long; +use Cwd; +use File::Copy; +use File::Find; + +## Scalars used by the option stuff +my $HELP_ARG = 0; +my $VERSION_ARG = 0; +my $DIST_ARG = 0; +my $POT_ARG = 0; +my $HEADERS_ARG = 0; +my $MAINTAIN_ARG = 0; +my $REPORT_ARG = 0; +my $VERBOSE = 0; +my $GETTEXT_PACKAGE = ""; + +my @languages; +my %po_files_by_lang = (); + +# Regular expressions to categorize file types. +# FIXME: Please check if the following is correct + +my $xml_extension = +"xml(\.in)*|". # .in is not required +"ui|". +"glade2?(\.in)*|". # .in is not required +"scm(\.in)*|". # .in is not required +"oaf(\.in)+|". +"etspec|". +"sheet(\.in)+|". +"schemas(\.in)+|". +"pong(\.in)+"; + +my $ini_extension = +"desktop(\.in)+|". +"caves(\.in)+|". +"directory(\.in)+|". +"soundlist(\.in)+|". +"keys(\.in)+|". +"server(\.in)+"; + +## Always print as the first thing +$| = 1; + +## Handle options +GetOptions +( + "help" => \$HELP_ARG, + "version" => \$VERSION_ARG, + "dist|d" => \$DIST_ARG, + "pot|p" => \$POT_ARG, + "headers|s" => \$HEADERS_ARG, + "maintain|m" => \$MAINTAIN_ARG, + "report|r" => \$REPORT_ARG, + "verbose|x" => \$VERBOSE, + "gettext-package|g=s" => \$GETTEXT_PACKAGE, + ) or &print_error_invalid_option; + +&print_help if $HELP_ARG; +&print_version if $VERSION_ARG; + +my $arg_count = ($DIST_ARG > 0) + + ($POT_ARG > 0) + + ($HEADERS_ARG > 0) + + ($MAINTAIN_ARG > 0) + + ($REPORT_ARG > 0); +&print_help if $arg_count > 1; + +# --version and --help don't require a module name +my $MODULE = $GETTEXT_PACKAGE || &find_package_name; + +if ($DIST_ARG) { + if ($ARGV[0] =~ /^[a-z]/){ + &update_po_file ($ARGV[0]); + &print_status ($ARGV[0]); + } else { + &print_help; + } +} elsif ($POT_ARG) { + &generate_headers; + &generate_po_template; +} elsif ($HEADERS_ARG) { + &generate_headers; +} elsif ($MAINTAIN_ARG) { + &find_leftout_files; +} elsif ($REPORT_ARG) { + &print_report; +} else { + if ($ARGV[0] =~ /^[a-z]/) { + &main ($ARGV[0]); + } else { + &print_help; + } +} + +exit; + +######### + +sub print_version +{ + ## Print version information + print "${PROGRAM} (${PACKAGE}) $VERSION\n"; + print "Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler.\n\n"; + print "Copyright (C) 2000-2002 Free Software Foundation, Inc.\n"; + print "This is free software; see the source for copying conditions. There is NO\n"; + print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; + exit; +} + +sub print_help +{ + ## Print usage information + print "Usage: ${PROGRAM} [OPTIONS] ...LANGCODE\n"; + print "Updates PO template files and merge them with the translations.\n\n"; + print " -p, --pot generate the PO template only\n"; + print " -s, --headers generate the header files in POTFILES.in\n"; + print " -m, --maintain search for left out files from POTFILES.in\n"; + print " -r, --report display a status report for the module.\n"; + print " -x, --verbose display lots of feedback\n"; + print " --help display this help and exit\n"; + print " --version output version information and exit\n"; + print "\nExamples of use:\n"; + print "${PROGRAM} --pot just creates a new PO template from the source\n"; + print "${PROGRAM} da created new PO template and updated the da.po file\n\n"; + print "Report bugs to bugzilla.gnome.org, module 'intltool'.\n"; + exit; +} + +sub main +{ + my ($lang) = @_; + + ## Report error if the language file supplied + ## to the command line is non-existent + &print_error_not_existing("$lang.po") if ! -s "$lang.po"; + + print "Working, please wait..." unless $VERBOSE; + &generate_headers; + &generate_po_template; + &update_po_file ($lang); + &print_status ($lang); +} + +sub determine_type ($) +{ + my $type = $_; + my $gettext_type; + + # FIXME: Use $xml_extentions, and maybe do all this even nicer + my $xml_regex = + "(?:xml(\.in)*|ui|oaf(?:\.in)+|server(?:\.in)+|sheet(?:\.in)+|". + "pong(?:\.in)+|etspec|schemas(?:\.in)+)"; + my $ini_regex = + "(?:desktop(?:\.in)+|caves(?:\.in)+|directory(?:\.in)+|". + "soundlist(?:\.in)+)"; + + if ($type =~ /\[type: gettext\/([^\]].*)]/) { + $gettext_type=$1; + } + elsif ($type =~ /schemas(\.in)+$/) { + $gettext_type="schemas"; + } + elsif ($type =~ /$xml_regex$/) { + $gettext_type="xml"; + } + elsif ($type =~ /glade2?(\.in)*$/) { + $gettext_type="glade"; + } + elsif ($type =~ /$ini_regex$/) { + $gettext_type="ini"; + } + elsif ($type =~ /scm(\.in)*$/) { + $gettext_type="scheme"; + } + elsif ($type =~ /keys(\.in)+$/) { + $gettext_type="keys"; + } + else { $gettext_type=""; } + + return "gettext\/$gettext_type"; +} + +sub find_leftout_files +{ + my (@buf_i18n_plain, + @buf_i18n_xml, + @buf_i18n_xml_unmarked, + @buf_i18n_ini, + @buf_potfiles, + @buf_potfiles_ignore, + @buf_allfiles, + @buf_allfiles_sorted, + @buf_potfiles_sorted + ); + + ## Search and find all translatable files + find sub { + push @buf_i18n_plain, "$File::Find::name" if /\.(c|y|cc|cpp|c\+\+|h|gob)$/ + }, ".."; + find sub { + push @buf_i18n_xml, "$File::Find::name" if /\.($xml_extension)$/ + }, ".."; + find sub { + push @buf_i18n_ini, "$File::Find::name" if /\.($ini_extension)$/ + }, ".."; + find sub { + push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/ + }, ".."; + + + open POTFILES, "POTFILES.in" or die "$PROGRAM: there's no POTFILES.in!\n"; + + @buf_potfiles = grep /^[^#]/, ; + + print "Searching for missing translatable files...\n" if $VERBOSE; + + ## Check if we should ignore some found files, when + ## comparing with POTFILES.in + foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") { + if (-s $ignore) { + open FILE, $ignore; + while () { + if (/^[^#]/){ + push @buf_potfiles_ignore, $_; + } + } + print "Found $ignore: Ignoring files...\n" if $VERBOSE; + @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles); + } + } + + foreach my $file (@buf_i18n_plain) + { + my $in_comment = 0; + my $in_macro = 0; + + open FILE, "<$file"; + while () + { + # Handle continued multi-line comment. + if ($in_comment) + { + next unless s-.*\*/--; + $in_comment = 0; + } + + # Handle continued macro. + if ($in_macro) + { + $in_macro = 0 unless /\\$/; + next; + } + + # Handle start of macro (or any preprocessor directive). + if (/^\s*\#/) + { + $in_macro = 1 if /^([^\\]|\\.)*\\$/; + next; + } + + # Handle comments and quoted text. + while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy + { + my $match = $1; + if ($match eq "/*") + { + if (!s-/\*.*?\*/--) + { + s-/\*.*--; + $in_comment = 1; + } + } + elsif ($match eq "//") + { + s-//.*--; + } + else # ' or " + { + if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-) + { + warn "mismatched quotes at line $. in $file\n"; + s-$match.*--; + } + } + } + + + if (/_\(QUOTEDTEXT/) + { + ## Remove the first 3 chars and add newline + push @buf_allfiles, unpack("x3 A*", $file) . "\n"; + last; + } + } + close FILE; + } + + foreach my $file (@buf_i18n_xml) { + open FILE, "<$file"; + while () { + if (/\s_(.*)=\"/ || /translatable=\"yes\"/){ + push @buf_allfiles, unpack("x3 A*", $file) . "\n"; + last; + } + } + } + + foreach my $file (@buf_i18n_ini){ + open FILE, "<$file"; + while () { + if (/_(.*)=/){ + push @buf_allfiles, unpack("x3 A*", $file) . "\n"; + last; + } + } + } + + foreach my $file (@buf_i18n_xml_unmarked){ + push @buf_allfiles, unpack("x3 A*", $file) . "\n"; + } + + + @buf_allfiles_sorted = sort (@buf_allfiles); + @buf_potfiles_sorted = sort (@buf_potfiles); + + my %in2; + foreach (@buf_potfiles_sorted) { + $in2{$_} = 1; + } + + my @result; + + foreach (@buf_allfiles_sorted){ + if (!exists($in2{$_})){ + push @result, $_ + } + } + + ## Save file with information about the files missing + ## if any, and give information about this procedure. + if (@result) { + print "\n" if $VERBOSE; + open OUT, ">missing"; + print OUT @result; + print "The following files contain translations and are currently not in use. Please\n"; + print "consider adding these to the POTFILES.in file, located in the po/ directory.\n\n"; + print @result, "\n"; + print "If some of these files are left out on purpose then please add them to\n"; + print "POTFILES.skip instead of POTFILES.in. A file 'missing' containing this list\n"; + print "of left out files has been written in the current directory.\n"; + } + + ## If there is nothing to complain about, notify the user + else { + print "\nAll files containing translations are present in POTFILES.in.\n"; + } +} + +sub print_error_invalid_option +{ + ## Handle invalid arguments + print "Try `${PROGRAM} --help' for more information.\n"; + exit 1; +} + +sub generate_headers +{ + my $EXTRACT = `which intltool-extract 2>/dev/null`; + chomp $EXTRACT; + + $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"}; + + ## Generate the .h header files, so we can allow glade and + ## xml translation support + if (! -s $EXTRACT) + { + print "\n *** The intltool-extract script wasn't found!" + ."\n *** Without it, intltool-update can not generate files.\n"; + exit; + } + else + { + open FILE, ") { + chomp; + + ## Find xml files in POTFILES.in and generate the + ## files with help from the extract script + + my $gettext_type= &determine_type ($1); + + if (/\.($xml_extension|$ini_extension)$/ || /^\[/){ + $_ =~ s/^\[[^\[].*]\s*//; + my $filename = "../$_"; + + if ($VERBOSE){ + system($EXTRACT, "--update", "--type=$gettext_type", $filename); + } else { + system($EXTRACT, "--update", "--type=$gettext_type", "--quiet", $filename); + } + } + } + close FILE; + } +} + +sub generate_po_template +{ + ## Generate the potfiles from the POTFILES.in file + + print "Building the $MODULE.pot...\n" if $VERBOSE; + + move ("POTFILES.in", "POTFILES.in.old"); + + open INFILE, "POTFILES.in"; + while () { + s/\.($xml_extension|$ini_extension)$/$&.h/; + s/^\[.*]\s*(.*)/$1.h/; + print OUTFILE $_; + } + close OUTFILE; + close INFILE; + + system ("xgettext", "--default-domain\=$MODULE", + "--directory\=\.\.", + "--add-comments", + "--keyword\=\_", + "--keyword\=N\_", + "--keyword\=U\_", + "--files-from\=\.\/POTFILES\.in"); + + move ("POTFILES.in.old", "POTFILES.in"); + + print "Removing generated header (.h) files..." if $VERBOSE; + + open FILE, ") + { + chomp; + unlink "../$_.h" if /\.($xml_extension|$ini_extension)$/; + } + + close FILE; + print "done\n" if $VERBOSE; + + if (!-e "$MODULE.po") { + print "WARNING: It seems that none of the files in POTFILES.in ". + "contain marked strings\n"; + exit (1); + } + + system ("rm", "-f", "$MODULE.pot"); + move ("$MODULE.po", "$MODULE.pot") or die "$PROGRAM: couldn't move $MODULE.po to $MODULE.pot.\n"; + + print "Wrote $MODULE.pot\n" if $VERBOSE; +} + +sub update_po_file +{ + my ($lang) = @_; + + print "Merging $lang.po with $MODULE.pot..." if $VERBOSE; + + copy ("$lang.po", "$lang.po.old") || die "copy failed: $!"; + + # Perform merge, remove backup file and the "messages" trash file + # generated by gettext + system ("msgmerge", "$lang.po.old", "$MODULE.pot", "-o", "$lang.po"); + unlink "$lang.po.old"; + unlink "messages"; +} + +sub print_error_not_existing +{ + my ($file) = @_; + + ## Report error if supplied language file is non-existing + print "$PROGRAM: $file does not exist!\n"; + print "Try '$PROGRAM --help' for more information.\n"; + exit; +} + +sub gather_po_files +{ + my @po_files = glob ("./*.po"); + + @languages = map (&po_file2lang, @po_files); + + foreach my $lang (@languages) { + $po_files_by_lang{$lang} = shift (@po_files); + } +} + +sub po_file2lang ($) +{ + my $tmp = $_; + $tmp =~ s/^.*\/(.*)\.po$/$1/; + return $tmp; +} + +sub print_status +{ + my ($lang) = @_; + + system ("msgfmt", "--statistics", "$lang.po"); + print "\n"; +} + +sub print_report +{ + &generate_headers; + &generate_po_template; + &gather_po_files; + + foreach my $lang (@languages) { + print "$lang: "; + &update_po_file ($lang); + } + + print "\n\n * Current translation support in $MODULE \n\n"; + + foreach my $lang (@languages){ + print "$lang: "; + system ("msgfmt", "--statistics", "$lang.po"); + } +} + +sub find_package_name +{ + my $base_dirname = getcwd(); + $base_dirname =~ s@.*/@@; + + my ($conf_in, $src_dir); + + if ($base_dirname =~ /^po(-.+)?$/) { + if (-f "../configure.in") { + $conf_in = "../configure.in"; + } elsif (-f "../configure.ac") { + $conf_in = "../configure.ac"; + } else { + my $makefile_source; + local (*IN); + open IN, ") { + if (/^top_srcdir[ \t]*=/) { + $src_dir = $_; + # print "${src_dir}\n"; + + $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; + # print "${src_dir}\n"; + chomp $src_dir; + $conf_in = "$src_dir" . "/configure.in" . "\n"; + last; + } + } + $conf_in || die "Cannot find top_srcdir in Makefile." + } + + my %varhash = (); + my $conf_source; { + local (*IN); + open (IN, "<$conf_in") || die "can't open $conf_in: $!"; + while () { + if (/^(\w+)=(\S+)/) { $varhash{$1} = $2 }; + } + seek (IN, 0, 0); + local $/; # slurp mode + $conf_source = ; + } + + my $name = ""; + $name = $1 if $conf_source =~ /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m; + if ($conf_source =~ /^AC_INIT\([\s\[]*([^,\)\s\]]+)\]?\s*,/m) { + $name = $1; + $varhash{"AC_PACKAGE_NAME"} = $1; + } + $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\s\]]+)/m; + + $name = "\$AC_PACKAGE_NAME" if "$name" eq "AC_PACKAGE_NAME"; + + my $oldname = ""; + while (($name =~ /[\$](\S+)/) && ("$oldname" ne "$name")) { + $oldname = $name; + if (exists $varhash{$1}) { + $name =~ s/[\$](\S+)/$varhash{$1}/; + } + } + return $name if $name; + } + + print "$PROGRAM: Unable to determine package name.\n" . + "Make sure to run this script inside the po directory.\n"; + exit; +} diff --git a/linphone/ipkg/.cvsignore b/linphone/ipkg/.cvsignore new file mode 100644 index 000000000..bf7b0e90e --- /dev/null +++ b/linphone/ipkg/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +linphone.control diff --git a/linphone/ipkg/Makefile.am b/linphone/ipkg/Makefile.am new file mode 100644 index 000000000..b5d762405 --- /dev/null +++ b/linphone/ipkg/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST=ipaq-config.site linphone.control glib.control libosip.control linphone.control.in diff --git a/linphone/ipkg/glib.control b/linphone/ipkg/glib.control new file mode 100644 index 000000000..2af6a91f4 --- /dev/null +++ b/linphone/ipkg/glib.control @@ -0,0 +1,8 @@ +Package: libglib2.2 +Section: libs +Priority: optional +Version: 2.2.2 +Architecture: arm +Maintainer: Simon Morlat +Depends: libc6 +Description: a usefull set of C routines in a portable library. diff --git a/linphone/ipkg/ipaq-config.site b/linphone/ipkg/ipaq-config.site new file mode 100644 index 000000000..8a320dce5 --- /dev/null +++ b/linphone/ipkg/ipaq-config.site @@ -0,0 +1,89 @@ +# config.site for configure +# iPAQ Familiar Linux TARGET + +# this config file is only suitable for the 3.2 release of the arm toolchain. + +# run with +# CONFIG_SITE=/wherever/you/store/it/ipaq-config.site ./configure +# or +# export CONFIG_SITE=/wherever/you/store/it/ipaq-config.site +# if this is going to be a whole compilation orgy + +# Modified from the one provided by Bradley D. LaRonde +# Edited by Andrej Cedilnik +# Used some of solutions by Tilman Vogel +# Ported for iPAQ Familiar by Oliver Kurth + +HOSTCC=gcc + +# Names of the cross-compilers +CC=arm-linux-gcc +CXX=arm-linux-g++ + +# The cross compiler specific options +CFLAGS="-O2 -fno-exceptions" +CXXFLAGS="-O2 -fno-exceptions" +CPPFLAGS="-O2 -fno-exceptions" +LDFLAGS="" + +# Some other programs +AR=arm-linux-ar +RANLIB=arm-linux-ranlib +NM=arm-linux-nm +ac_cv_path_NM=arm-linux-nm +ac_cv_func_setpgrp_void=yes +host=arm-linux +#prefix=/usr/mipsel-linux +x_includes=/skiff/local/arm-linux/include/X11 +x_libraries=/skiff/local/arm-linux/lib/X11 + +# These are for GNU shellutils +jm_cv_have_proc_uptime=yes +jm_cv_func_working_gnu_strftime=yes + +# Some options for ease of compiling python +# (these are left over from the agenda. Not checked for iPAQ) +ac_cv_sizeof_int=4 +ac_cv_sizeof_char=1 +ac_cv_sizeof_short=2 +ac_cv_sizeof_float=4 +ac_cv_sizeof_double=8 +ac_cv_sizeof_pthread_t=4 +ac_cv_sizeof_long=4 +ac_cv_sizeof_void_p=4 +ac_cv_sizeof_long_long=8 +ac_cv_sizeof_off_t=4 +ac_cv_sizeof_fpos_t=4 +ac_cv_sizeof_time_t=4 + +# Some other stuff nobody knows why +#bad_forward=no +#LDSHARED='mipsel-linux-gcc -msoft-float -shared' +#ac_cv_malloc_zero=nonnull + +# squeak wants this +# can't do misaligned access to doubles +ac_cv_double_align=no +# dunno what order doubles are in +ac_cv_double_order=no + +ac_cv_header_wchar_h=no + +# added by oku, for compiling glib: +glib_cv_has__inline=yes +glib_cv_has__inline__=yes +glib_cv_hasinline=yes +glib_cv_sane_realloc=yes +glib_cv_va_copy=no +glib_cv___va_copy=yes +glib_cv_va_val_copy=yes +glib_cv_rtldglobal_broken=no +glib_cv_uscore=yes +ac_cv_func_getpwuid_r=yes +glib_cv_sizeof_gmutex=24 + +#added by Simon Morlat, for compiling glib-2.2.x + +glib_cv_stack_grows=no +ac_cv_func_posix_getpwuid_r=yes +glib_cv_use_pid_surrogate=yes diff --git a/linphone/ipkg/libosip.control b/linphone/ipkg/libosip.control new file mode 100644 index 000000000..2da070de4 --- /dev/null +++ b/linphone/ipkg/libosip.control @@ -0,0 +1,8 @@ +Package: libosip +Section: libs +Priority: optional +Version: 0.9.7-1 +Architecture: arm +Maintainer: Simon Morlat +Depends: libc6 +Description: a SIP (RFC3261) C library. diff --git a/linphone/ipkg/linphone.control.in b/linphone/ipkg/linphone.control.in new file mode 100644 index 000000000..4edc99577 --- /dev/null +++ b/linphone/ipkg/linphone.control.in @@ -0,0 +1,8 @@ +Package: linphone +Section: net +Priority: optional +Version: @VERSION@-1 +Architecture: arm +Maintainer: Simon Morlat +Depends: libc6, libosip +Description: a SIP (RFC3261) internet phone. diff --git a/linphone/linphone.kdevprj b/linphone/linphone.kdevprj new file mode 100644 index 000000000..a8c231dc2 --- /dev/null +++ b/linphone/linphone.kdevprj @@ -0,0 +1,2285 @@ +[./ABOUT-NLS] +dist=true +install=false +install_location= +type=DATA + +[./AUTHORS] +dist=true +install=false +install_location= +type=DATA + +[./BUGS] +dist=true +install=false +install_location= +type=DATA + +[./COPYING] +dist=true +install=false +install_location= +type=DATA + +[./ChangeLog] +dist=true +install=false +install_location= +type=DATA + +[./INSTALL] +dist=true +install=false +install_location= +type=DATA + +[./Makefile.am] +files=./ABOUT-NLS,./AUTHORS,./BUGS,./COPYING,./ChangeLog,./INSTALL,./NEWS,./README,./acconfig.h,./aclocal.m4,./config.guess,./config.h.in,./config.sub,./configure,./configure.in,./install-sh,./linphone.glade,./ltconfig,./ltmain.sh,./missing,./mkinstalldirs,./stamp-h.in,./config.log,./libtool,./linphone.log,./config.h,./config.cache,./stamp-h,./autogen.sh,./linphone.glade.bak,./config.status,./linphone.kdevprj, +sub_dirs=G711,audio,gsmlib,intl,lpc10-1.5,lprtplib,macros,osipua,pixmaps,po,share,src, +type=normal + +[./NEWS] +dist=true +install=false +install_location= +type=DATA + +[./README] +dist=true +install=false +install_location= +type=DATA + +[./acconfig.h] +dist=true +install=false +install_location= +type=HEADER + +[./aclocal.m4] +dist=true +install=false +install_location= +type=DATA + +[./autogen.sh] +dist=true +install=false +install_location= +type=DATA + +[./config.cache] +dist=true +install=false +install_location= +type=DATA + +[./config.guess] +dist=true +install=false +install_location= +type=DATA + +[./config.h] +dist=true +install=false +install_location= +type=HEADER + +[./config.h.in] +dist=true +install=false +install_location= +type=DATA + +[./config.log] +dist=true +install=false +install_location= +type=DATA + +[./config.status] +dist=true +install=false +install_location= +type=DATA + +[./config.sub] +dist=true +install=false +install_location= +type=DATA + +[./configure] +dist=true +install=false +install_location= +type=DATA + +[./configure.in] +dist=true +install=false +install_location= +type=DATA + +[./install-sh] +dist=true +install=false +install_location= +type=DATA + +[./libtool] +dist=true +install=false +install_location= +type=DATA + +[./linphone.glade] +dist=true +install=false +install_location= +type=DATA + +[./linphone.glade.bak] +dist=true +install=false +install_location= +type=DATA + +[./linphone.kdevprj] +dist=true +install=false +install_location= +type=DATA + +[./linphone.log] +dist=true +install=false +install_location= +type=DATA + +[./ltconfig] +dist=true +install=false +install_location= +type=DATA + +[./ltmain.sh] +dist=true +install=false +install_location= +type=DATA + +[./missing] +dist=true +install=false +install_location= +type=DATA + +[./mkinstalldirs] +dist=true +install=false +install_location= +type=DATA + +[./stamp-h] +dist=true +install=false +install_location= +type=DATA + +[./stamp-h.in] +dist=true +install=false +install_location= +type=DATA + +[Config for BinMakefileAm] +addcxxflags= +bin_program=linphone +cxxflags=\s-O1 +ldadd= +ldflags= +libtool_dir= +path_to_bin_program=./src + +[G711/Makefile.am] +files=G711/g711alaw.c,G711/g711alaw.h,G711/g711ulaw.c,G711/g711ulaw.h, +sub_dirs= +type=normal + +[G711/g711alaw.c] +dist=true +install=false +install_location= +type=SOURCE + +[G711/g711alaw.h] +dist=true +install=false +install_location= +type=HEADER + +[G711/g711ulaw.c] +dist=true +install=false +install_location= +type=SOURCE + +[G711/g711ulaw.h] +dist=true +install=false +install_location= +type=HEADER + +[General] +AMChanged=false +author=Simon Morlat +dir_where_make_will_be_called=./ +email=simon.morlat@linphone.org +kdevprj_version=1.3 +lfv_open_groups= +make_options=\s-j1 +makefiles=./Makefile.am,src/Makefile.am,share/Makefile.am,share/fr/Makefile.am,share/C/Makefile.am,po/Makefile.am,pixmaps/Makefile.am,pixmaps/.xvpics/Makefile.am,osipua/Makefile.am,macros/Makefile.am,lprtplib/Makefile.am,lpc10-1.5/Makefile.am,intl/Makefile.am,gsmlib/Makefile.am,audio/Makefile.am,G711/Makefile.am,developer-docs/mediastreamer/Makefile.am,developer-docs/Makefile.am,mediastreamer/Makefile.am,media_api/Makefile.am,oRTP/Makefile.am +modifyMakefiles=false +project_name=linphone +project_type=normal_empty +short_info= +sub_dir= +version= +version_control=CVS +workspace=1 + +[LFV Groups] +Desktop=*.desktop, +GNU=AUTHORS,COPYING,ChangeLog,INSTALL,README,TODO,NEWS, +Headers=*.h,*.hxx,*.hpp,*.H, +Others=*, +Sources=*.cpp,*.c,*.cc,*.C,*.cxx,*.ec,*.ecpp,*.lxx,*.l++,*.ll,*.l, +Translations=*.ts,*.po, +User Interface=*.ui,*.kdevdlg,*.rc, +groups=Headers,Sources,GNU,Translations,User Interface,Desktop,Others + +[Makefile.am] +sub_dirs=osipua,developer-docs,mediastreamer,media_api,oRTP,src,share + +[audio/Makefile.am] +files=audio/alsa.c,audio/alsa.h,audio/audio.c,audio/audio.h,audio/audiotest.c,audio/iodisk.c,audio/iodisk.h,audio/loopback.c,audio/loopback.h,audio/oss.c,audio/oss.h,audio/ring.c,audio/ring.h, +sub_dirs= +type=normal + +[audio/alsa.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/alsa.h] +dist=true +install=false +install_location= +type=HEADER + +[audio/audio.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/audio.h] +dist=true +install=false +install_location= +type=HEADER + +[audio/audiotest.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/iodisk.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/iodisk.h] +dist=true +install=false +install_location= +type=HEADER + +[audio/loopback.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/loopback.h] +dist=true +install=false +install_location= +type=HEADER + +[audio/oss.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/oss.h] +dist=true +install=false +install_location= +type=HEADER + +[audio/ring.c] +dist=true +install=false +install_location= +type=SOURCE + +[audio/ring.h] +dist=true +install=false +install_location= +type=HEADER + +[developer-docs/Makefile.am] +sub_dirs=mediastreamer +type=normal + +[developer-docs/mediastreamer/Makefile.am] +files=developer-docs/mediastreamer/mediastreamer-decl.txt,developer-docs/mediastreamer/mediastreamer-docs.sgml,developer-docs/mediastreamer/mediastreamer-sections.txt,developer-docs/mediastreamer/mediastreamer.types +sub_dirs= +type=normal + +[developer-docs/mediastreamer/mediastreamer-decl.txt] +dist=true +install=false +install_location= +type=DATA + +[developer-docs/mediastreamer/mediastreamer-docs.sgml] +dist=true +install=false +install_location= +type=DATA + +[developer-docs/mediastreamer/mediastreamer-sections.txt] +dist=true +install=false +install_location= +type=DATA + +[developer-docs/mediastreamer/mediastreamer.types] +dist=true +install=false +install_location= +type=SCRIPT + +[gsmlib/COPYRIGHT] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/ChangeLog] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/ChangeLog.orig] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/INSTALL] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/MACHINES] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/MANIFEST] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/Makefile.am] +files=gsmlib/COPYRIGHT,gsmlib/ChangeLog,gsmlib/INSTALL,gsmlib/MACHINES,gsmlib/MANIFEST,gsmlib/README,gsmlib/add.c,gsmlib/code.c,gsmlib/config.h,gsmlib/debug.c,gsmlib/decode.c,gsmlib/gsm.h,gsmlib/gsm_create.c,gsmlib/gsm_decode.c,gsmlib/gsm_destroy.c,gsmlib/gsm_encode.c,gsmlib/gsm_explode.c,gsmlib/gsm_implode.c,gsmlib/gsm_option.c,gsmlib/gsm_print.c,gsmlib/gsm_wrapper.c,gsmlib/gsm_wrapper.h,gsmlib/long_term.c,gsmlib/lpc.c,gsmlib/preprocess.c,gsmlib/private.h,gsmlib/proto.h,gsmlib/rpe.c,gsmlib/short_term.c,gsmlib/table.c,gsmlib/toast.h,gsmlib/unproto.h,gsmlib/ChangeLog.orig, +sub_dirs= +type=normal + +[gsmlib/README] +dist=true +install=false +install_location= +type=DATA + +[gsmlib/add.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/code.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/config.h] +dist=true +install=false +install_location= +type=HEADER + +[gsmlib/debug.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/decode.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm.h] +dist=true +install=false +install_location= +type=HEADER + +[gsmlib/gsm_create.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_decode.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_destroy.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_encode.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_explode.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_implode.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_option.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_print.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_wrapper.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/gsm_wrapper.h] +dist=true +install=false +install_location= +type=HEADER + +[gsmlib/long_term.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/lpc.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/preprocess.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/private.h] +dist=true +install=false +install_location= +type=HEADER + +[gsmlib/proto.h] +dist=true +install=false +install_location= +type=HEADER + +[gsmlib/rpe.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/short_term.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/table.c] +dist=true +install=false +install_location= +type=SOURCE + +[gsmlib/toast.h] +dist=true +install=false +install_location= +type=HEADER + +[gsmlib/unproto.h] +dist=true +install=false +install_location= +type=HEADER + +[intl/ChangeLog] +dist=true +install=false +install_location= +type=DATA + +[intl/Makefile.am] +files=intl/ChangeLog,intl/VERSION,intl/bindtextdom.c,intl/cat-compat.c,intl/dcgettext.c,intl/dgettext.c,intl/explodename.c,intl/finddomain.c,intl/gettext.c,intl/gettext.h,intl/gettextP.h,intl/hash-string.h,intl/intl-compat.c,intl/l10nflist.c,intl/libgettext.h,intl/linux-msg.sed,intl/loadinfo.h,intl/loadmsgcat.c,intl/localealias.c,intl/po2tbl.sed.in,intl/textdomain.c,intl/xopen-msg.sed,intl/po2tbl.sed, +sub_dirs= +type=normal + +[intl/VERSION] +dist=true +install=false +install_location= +type=DATA + +[intl/bindtextdom.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/cat-compat.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/dcgettext.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/dgettext.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/explodename.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/finddomain.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/gettext.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/gettext.h] +dist=true +install=false +install_location= +type=HEADER + +[intl/gettextP.h] +dist=true +install=false +install_location= +type=HEADER + +[intl/hash-string.h] +dist=true +install=false +install_location= +type=HEADER + +[intl/intl-compat.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/l10nflist.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/libgettext.h] +dist=true +install=false +install_location= +type=HEADER + +[intl/linux-msg.sed] +dist=true +install=false +install_location= +type=DATA + +[intl/loadinfo.h] +dist=true +install=false +install_location= +type=HEADER + +[intl/loadmsgcat.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/localealias.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/po2tbl.sed] +dist=true +install=false +install_location= +type=DATA + +[intl/po2tbl.sed.in] +dist=true +install=false +install_location= +type=DATA + +[intl/textdomain.c] +dist=true +install=false +install_location= +type=SOURCE + +[intl/xopen-msg.sed] +dist=true +install=false +install_location= +type=DATA + +[lpc10-1.5/FAQ] +dist=true +install=false +install_location= +type=DATA + +[lpc10-1.5/Makefile.am] +files=lpc10-1.5/FAQ,lpc10-1.5/README,lpc10-1.5/README-1.0,lpc10-1.5/README.new,lpc10-1.5/analys.c,lpc10-1.5/bitio.c,lpc10-1.5/bsynz.c,lpc10-1.5/chanwr.c,lpc10-1.5/dcbias.c,lpc10-1.5/decode.c,lpc10-1.5/deemp.c,lpc10-1.5/difmag.c,lpc10-1.5/dyptrk.c,lpc10-1.5/encode.c,lpc10-1.5/energy.c,lpc10-1.5/f2c.h,lpc10-1.5/f2clib.c,lpc10-1.5/ham84.c,lpc10-1.5/hp100.c,lpc10-1.5/invert.c,lpc10-1.5/irc2pc.c,lpc10-1.5/ivfilt.c,lpc10-1.5/lpc10.h,lpc10-1.5/lpc10_wrapper.c,lpc10-1.5/lpc10_wrapper.h,lpc10-1.5/lpcdec.c,lpc10-1.5/lpcenc.c,lpc10-1.5/lpcini.c,lpc10-1.5/lpfilt.c,lpc10-1.5/median.c,lpc10-1.5/mload.c,lpc10-1.5/onset.c,lpc10-1.5/pitsyn.c,lpc10-1.5/placea.c,lpc10-1.5/placev.c,lpc10-1.5/preemp.c,lpc10-1.5/prepro.c,lpc10-1.5/random.c,lpc10-1.5/rcchk.c,lpc10-1.5/synths.c,lpc10-1.5/tbdm.c,lpc10-1.5/voicin.c,lpc10-1.5/vparms.c, +sub_dirs= +type=normal + +[lpc10-1.5/README] +dist=true +install=false +install_location= +type=DATA + +[lpc10-1.5/README-1.0] +dist=true +install=false +install_location= +type=DATA + +[lpc10-1.5/README.new] +dist=true +install=false +install_location= +type=DATA + +[lpc10-1.5/analys.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/bitio.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/bsynz.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/chanwr.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/dcbias.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/decode.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/deemp.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/difmag.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/dyptrk.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/encode.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/energy.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/f2c.h] +dist=true +install=false +install_location= +type=HEADER + +[lpc10-1.5/f2clib.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/ham84.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/hp100.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/invert.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/irc2pc.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/ivfilt.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/lpc10.h] +dist=true +install=false +install_location= +type=HEADER + +[lpc10-1.5/lpc10_wrapper.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/lpc10_wrapper.h] +dist=true +install=false +install_location= +type=HEADER + +[lpc10-1.5/lpcdec.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/lpcenc.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/lpcini.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/lpfilt.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/median.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/mload.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/onset.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/pitsyn.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/placea.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/placev.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/preemp.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/prepro.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/random.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/rcchk.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/synths.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/tbdm.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/voicin.c] +dist=true +install=false +install_location= +type=SOURCE + +[lpc10-1.5/vparms.c] +dist=true +install=false +install_location= +type=SOURCE + +[lprtplib/Makefile.am] +files=lprtplib/rtp.c,lprtplib/rtp.h,lprtplib/rtp_private.h,lprtplib/rtp_ptypes.h,lprtplib/rtprecept.c,lprtplib/rtprecv.c,lprtplib/rtpsend.c,lprtplib/rtpsender.c,lprtplib/rtputils.c, +sub_dirs= +type=normal + +[lprtplib/rtp.c] +dist=true +install=false +install_location= +type=SOURCE + +[lprtplib/rtp.h] +dist=true +install=false +install_location= +type=HEADER + +[lprtplib/rtp_private.h] +dist=true +install=false +install_location= +type=HEADER + +[lprtplib/rtp_ptypes.h] +dist=true +install=false +install_location= +type=HEADER + +[lprtplib/rtprecept.c] +dist=true +install=false +install_location= +type=SOURCE + +[lprtplib/rtprecv.c] +dist=true +install=false +install_location= +type=SOURCE + +[lprtplib/rtpsend.c] +dist=true +install=false +install_location= +type=SOURCE + +[lprtplib/rtpsender.c] +dist=true +install=false +install_location= +type=SOURCE + +[lprtplib/rtputils.c] +dist=true +install=false +install_location= +type=SOURCE + +[macros/Makefile.am] +files=macros/aclocal-include.m4,macros/autogen.sh,macros/compiler-flags.m4,macros/curses.m4,macros/gnome-bonobo-check.m4,macros/gnome-common.m4,macros/gnome-fileutils.m4,macros/gnome-ghttp-check.m4,macros/gnome-gnorba-check.m4,macros/gnome-guile-checks.m4,macros/gnome-libgtop-check.m4,macros/gnome-objc-checks.m4,macros/gnome-orbit-check.m4,macros/gnome-print-check.m4,macros/gnome-pthread-check.m4,macros/gnome-support.m4,macros/gnome-undelfs.m4,macros/gnome-vfs.m4,macros/gnome-x-checks.m4,macros/gnome-xml-check.m4,macros/gnome.m4,macros/gperf-check.m4,macros/linger.m4,macros/need-declaration.m4, +sub_dirs= +type=normal + +[macros/aclocal-include.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/autogen.sh] +dist=true +install=false +install_location= +type=DATA + +[macros/compiler-flags.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/curses.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-bonobo-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-common.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-fileutils.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-ghttp-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-gnorba-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-guile-checks.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-libgtop-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-objc-checks.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-orbit-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-print-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-pthread-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-support.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-undelfs.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-vfs.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-x-checks.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome-xml-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gnome.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/gperf-check.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/linger.m4] +dist=true +install=false +install_location= +type=DATA + +[macros/need-declaration.m4] +dist=true +install=false +install_location= +type=DATA + +[media_api/DESIGN.txt] +dist=true +install=false +install_location= +type=DATA + +[media_api/Makefile.am] +dist=true +files=media_api/DESIGN.txt,media_api/Makefile.am +install=false +install_location= +sub_dirs= +type=DATA + +[mediastreamer/Makefile.am] +dist=true +files=mediastreamer/Makefile.am,mediastreamer/README,mediastreamer/ms.c,mediastreamer/ms.h,mediastreamer/msbuffer.c,mediastreamer/msbuffer.h,mediastreamer/mscopy.c,mediastreamer/mscopy.h,mediastreamer/msfifo.c,mediastreamer/msfifo.h,mediastreamer/msfilter.c,mediastreamer/msfilter.h,mediastreamer/msnosync.c,mediastreamer/msnosync.h,mediastreamer/msqueue.c,mediastreamer/msqueue.h,mediastreamer/msread.c,mediastreamer/msread.h,mediastreamer/mssync.c,mediastreamer/mssync.h,mediastreamer/mswrite.c,mediastreamer/mswrite.h,mediastreamer/test.c,mediastreamer/msoss.c,mediastreamer/msoss.h,mediastreamer/msosswrite.h,mediastreamer/msosswrite.c,mediastreamer/msringplayer.c,mediastreamer/msringplayer.h,mediastreamer/msossread.c,mediastreamer/msossread.h,mediastreamer/msGSMencoder.c,mediastreamer/msGSMencoder.h,mediastreamer/msrtprecv.c,mediastreamer/msrtprecv.h,mediastreamer/msGSMdecoder.c,mediastreamer/msGSMdecoder.h,mediastreamer/msLPC10encoder.c,mediastreamer/msLPC10encoder.h,mediastreamer/msLPC10decoder.c,mediastreamer/msLPC10decoder.h,mediastreamer/msAlawenc.h,mediastreamer/msAlawenc.c,mediastreamer/g711common.h,mediastreamer/msMUlawenc.c,mediastreamer/msMUlawenc.h,mediastreamer/msAlawdec.c,mediastreamer/msAlawdec.h,mediastreamer/msMUlawdec.c,mediastreamer/msMUlawdec.h,mediastreamer/msutils.h,mediastreamer/msvideosource.c,mediastreamer/msvideosource.h,mediastreamer/msv4l.h,mediastreamer/msv4l.c,mediastreamer/ring_test.c,mediastreamer/test_gsm.c,mediastreamer/test_lpc10.c,mediastreamer/test_alaw.c,mediastreamer/test_mulaw.c,mediastreamer/msavencoder.h,mediastreamer/msavencoder.c,mediastreamer/test_avenc.c,mediastreamer/msavdecoder.h,mediastreamer/msavdecoder.c,mediastreamer/test_avdec.c,mediastreamer/mstimer.h,mediastreamer/mstimer.c +install=false +install_location= +sub_dirs= +type=static_library + +[mediastreamer/README] +dist=true +install=false +install_location= +type=DATA + +[mediastreamer/g711common.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/ms.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/ms.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msAlawdec.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msAlawdec.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msAlawenc.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msAlawenc.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msGSMdecoder.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msGSMdecoder.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msGSMencoder.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msGSMencoder.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msLPC10decoder.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msLPC10decoder.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msLPC10encoder.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msLPC10encoder.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msMUlawdec.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msMUlawdec.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msMUlawenc.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msMUlawenc.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msavdecoder.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msavdecoder.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msavencoder.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msavencoder.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msbuffer.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msbuffer.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/mscopy.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/mscopy.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msfifo.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msfifo.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msfilter.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msfilter.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msnosync.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msnosync.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msoss.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msoss.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msossread.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msossread.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msosswrite.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msosswrite.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msqueue.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msqueue.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msread.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msread.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msringplayer.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msringplayer.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msrtprecv.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msrtprecv.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/mssync.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/mssync.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/mstimer.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/mstimer.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msutils.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msv4l.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msv4l.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/msvideosource.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/msvideosource.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/mswrite.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/mswrite.h] +dist=true +install=false +install_location= +type=HEADER + +[mediastreamer/ring_test.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test_alaw.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test_avdec.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test_avenc.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test_gsm.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test_lpc10.c] +dist=true +install=false +install_location= +type=SOURCE + +[mediastreamer/test_mulaw.c] +dist=true +install=false +install_location= +type=SOURCE + +[oRTP/Makefile.am] +dist=true +files=oRTP/Makefile.am,oRTP/rtp.h,oRTP/rtpsession.c,oRTP/str_utils.c,oRTP/rtpsend.c,oRTP/rtprecv.c,oRTP/str_utils.h,oRTP/rtpsession.h,oRTP/rtpmod.c,oRTP/rtpmod.h +install=false +install_location= +sub_dirs= +type=static_library + +[oRTP/rtp.h] +dist=true +install=false +install_location= +type=HEADER + +[oRTP/rtpmod.c] +dist=true +install=false +install_location= +type=SOURCE + +[oRTP/rtpmod.h] +dist=true +install=false +install_location= +type=HEADER + +[oRTP/rtprecv.c] +dist=true +install=false +install_location= +type=SOURCE + +[oRTP/rtpsend.c] +dist=true +install=false +install_location= +type=SOURCE + +[oRTP/rtpsession.c] +dist=true +install=false +install_location= +type=SOURCE + +[oRTP/rtpsession.h] +dist=true +install=false +install_location= +type=HEADER + +[oRTP/str_utils.c] +dist=true +install=false +install_location= +type=SOURCE + +[oRTP/str_utils.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/Makefile.am] +dist=true +files=osipua/osipua.c,osipua/osipcallleg.c,osipua/osipua.h,osipua/callbacks_uac.c,osipua/callbacks_uas.c,osipua/osipua_tester.c,osipua/osipua_tester.h,osipua/utils.c,osipua/utils.h,osipua/osipcallleg.h,osipua/udp.c,osipua/udp.h,osipua/osipmanager.c,osipua/osipmanager.h,osipua/resolver.c,osipua/resolver.h,osipua/uatransaction.h,osipua/uatransaction.c,osipua/mediadesc.h,osipua/mediadesc.c,osipua/Makefile.am,osipua/regctxt.h,osipua/digcalc.h,osipua/regctxt.c,osipua/bodyhandlerinfo.h,osipua/authentication.c,osipua/bodyhandler.h,osipua/bodyhandlerinfo.c,osipua/bodyhandler.c,osipua/sdphandler.h,osipua/sdphandler.c,osipua/sdphandlerinfo.h,osipua/sdphandlerinfo.c +install=false +install_location= +sub_dirs= +type=static_library + +[osipua/authentication.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/bodyhandler.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/bodyhandler.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/bodyhandlerinfo.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/bodyhandlerinfo.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/callbacks_uac.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/callbacks_uas.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/digcalc.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/mediadesc.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/mediadesc.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/osipcallleg.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/osipcallleg.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/osipmanager.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/osipmanager.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/osipua.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/osipua.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/osipua_tester.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/osipua_tester.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/regctxt.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/regctxt.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/resolver.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/resolver.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/sdphandler.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/sdphandler.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/sdphandlerinfo.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/sdphandlerinfo.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/uatransaction.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/uatransaction.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/udp.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/udp.h] +dist=true +install=false +install_location= +type=HEADER + +[osipua/utils.c] +dist=true +install=false +install_location= +type=SOURCE + +[osipua/utils.h] +dist=true +install=false +install_location= +type=HEADER + +[pixmaps/.xvpics/Makefile.am] +files=pixmaps/.xvpics/linphone.png, +sub_dirs= +type=normal + +[pixmaps/.xvpics/linphone.png] +dist=true +install=false +install_location= +type=DATA + +[pixmaps/Makefile.am] +files=pixmaps/linphone2.png,pixmaps/linphone2.xpm,pixmaps/linphone.png, +sub_dirs= +type=normal + +[pixmaps/linphone.png] +dist=true +install=false +install_location= +type=DATA + +[pixmaps/linphone2.png] +dist=true +install=false +install_location= +type=DATA + +[pixmaps/linphone2.xpm] +dist=true +install=false +install_location= +type=DATA + +[po/ChangeLog] +dist=true +install=false +install_location= +type=DATA + +[po/Makefile.am] +files=po/ChangeLog,po/POTFILES.in,po/cat-id-tbl.c,po/fr.gmo,po/fr.po,po/linphone.pot,po/stamp-cat-id,po/POTFILES,po/fr.po.old,po/fr.po.new~,po/fr.po~, +sub_dirs= +type=po + +[po/POTFILES] +dist=true +install=false +install_location= +type=DATA + +[po/POTFILES.in] +dist=true +install=false +install_location= +type=DATA + +[po/cat-id-tbl.c] +dist=true +install=false +install_location= +type=SOURCE + +[po/fr.gmo] +dist=true +install=false +install_location= +type=DATA + +[po/fr.po] +dist=true +install=false +install_location= +type=DATA + +[po/fr.po.new~] +dist=true +install=false +install_location= +type=DATA + +[po/fr.po.old] +dist=true +install=false +install_location= +type=DATA + +[po/fr.po~] +dist=true +install=false +install_location= +type=DATA + +[po/linphone.pot] +dist=true +install=false +install_location= +type=DATA + +[po/stamp-cat-id] +dist=true +install=false +install_location= +type=DATA + +[share/C/Makefile.am] +files=share/C/manual.html,share/C/parameters-1.html,share/C/parameters-2.html,share/C/parameters-3.html,share/C/parameters-4.html,share/C/parameters-5.html,share/C/manual.sdw,share/C/css.css, +sub_dirs= +type=normal + +[share/C/css.css] +dist=true +install=false +install_location= +type=DATA + +[share/C/manual.html] +dist=true +install=false +install_location= +type=DATA + +[share/C/manual.sdw] +dist=true +install=false +install_location= +type=DATA + +[share/C/parameters-1.html] +dist=true +install=false +install_location= +type=DATA + +[share/C/parameters-2.html] +dist=true +install=false +install_location= +type=DATA + +[share/C/parameters-3.html] +dist=true +install=false +install_location= +type=DATA + +[share/C/parameters-4.html] +dist=true +install=false +install_location= +type=DATA + +[share/C/parameters-5.html] +dist=true +install=false +install_location= +type=DATA + +[share/Makefile.am] +dist=true +files=share/hello.wav,share/linphone.desktop,share/linphone.gnorba,share/linphone_applet.desktop,share/ring.wav,share/ringback.wav,share/Makefile.am +install=false +install_location= +sub_dirs=C,fr, +type=DATA + +[share/fr/Makefile.am] +files=share/fr/manual.html,share/fr/parameters-1.html,share/fr/parameters-2.html,share/fr/parameters-3.html,share/fr/parameters-4.html,share/fr/parameters-5.html,share/fr/css.css, +sub_dirs= +type=normal + +[share/fr/css.css] +dist=true +install=false +install_location= +type=DATA + +[share/fr/manual.html] +dist=true +install=false +install_location= +type=DATA + +[share/fr/parameters-1.html] +dist=true +install=false +install_location= +type=DATA + +[share/fr/parameters-2.html] +dist=true +install=false +install_location= +type=DATA + +[share/fr/parameters-3.html] +dist=true +install=false +install_location= +type=DATA + +[share/fr/parameters-4.html] +dist=true +install=false +install_location= +type=DATA + +[share/fr/parameters-5.html] +dist=true +install=false +install_location= +type=DATA + +[share/hello.wav] +dist=true +install=false +install_location= +type=DATA + +[share/linphone.desktop] +dist=true +install=false +install_location= +type=DATA + +[share/linphone.gnorba] +dist=true +install=false +install_location= +type=DATA + +[share/linphone_applet.desktop] +dist=true +install=false +install_location= +type=DATA + +[share/ring.wav] +dist=true +install=false +install_location= +type=DATA + +[share/ringback.wav] +dist=true +install=false +install_location= +type=DATA + +[src/LinphoneMain.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/LinphoneMain.h] +dist=true +install=false +install_location= +type=HEADER + +[src/Makefile.am] +dist=true +files=src/LinphoneMain.c,src/LinphoneMain.h,src/callbacks.c,src/callbacks.h,src/codec.c,src/codec.h,src/gui_utils.c,src/gui_utils.h,src/interface.h,src/interface.c_ref,src/interface.c,src/io.c,src/io.h,src/main.c,src/sip_handlers.h,src/sipomatic.c,src/sipomatic.h,src/state-machine.h,src/support.c,src/support.h,src/presence.c,src/presence.h,src/Makefile.am,src/propertybox.h,src/propertybox.c +install=false +install_location= +sub_dirs= +type=static_library + +[src/callbacks.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/callbacks.h] +dist=true +install=false +install_location= +type=HEADER + +[src/codec.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/codec.h] +dist=true +install=false +install_location= +type=HEADER + +[src/gui_utils.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/gui_utils.h] +dist=true +install=false +install_location= +type=HEADER + +[src/interface.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/interface.c_ref] +dist=true +install=false +install_location= +type=DATA + +[src/interface.h] +dist=true +install=false +install_location= +type=HEADER + +[src/io.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/io.h] +dist=true +install=false +install_location= +type=HEADER + +[src/main.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/presence.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/presence.h] +dist=true +install=false +install_location= +type=HEADER + +[src/propertybox.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/propertybox.h] +dist=true +install=false +install_location= +type=HEADER + +[src/sip_handlers.h] +dist=true +install=false +install_location= +type=HEADER + +[src/sipomatic.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/sipomatic.h] +dist=true +install=false +install_location= +type=HEADER + +[src/state-machine.h] +dist=true +install=false +install_location= +type=HEADER + +[src/support.c] +dist=true +install=false +install_location= +type=SOURCE + +[src/support.h] +dist=true +install=false +install_location= +type=HEADER diff --git a/linphone/linphone.spec.in b/linphone/linphone.spec.in new file mode 100644 index 000000000..3bdeeea57 --- /dev/null +++ b/linphone/linphone.spec.in @@ -0,0 +1,258 @@ +# -*- rpm-spec -*- + +## rpmbuild options + +# default is to build with video support & without truespeech support +%define video %{?_without_video:0}%{!?_without_video:1} +%define truespeech %{?_with_truespeech:1}%{!?_with_truespeech:0} + +# Linphone requires an old osip version, sometimes (e.g. fc6) +# delivered as "compat-" +%define _without_old_osip 0 + +Name: linphone +Version: @VERSION@ +Release: 1%{?dist} +Summary: Phone anywhere in the whole world by using the Internet + +Group: Applications/Communications +License: GPL +URL: http://www.linphone.org +Source0: http://download.savannah.gnu.org/releases/linphone/stable/source/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +%ifarch %{ix86} +BuildArch: i686 +%endif + +BuildRequires: gnome-panel-devel libgnomeui-devel glib2-devel alsa-lib-devel +BuildRequires: libosip2-devel speex-devel gettext desktop-file-utils +BuildRequires: readline-devel ncurses-devel +BuildRequires: intltool gettext-devel +%if %{video} +BuildRequires: ffmpeg-devel SDL-devel +%endif + +%description +Linphone is mostly sip compliant. It works successfully with these +implementations: + * eStara softphone (commercial software for windows) + * Pingtel phones (with DNS enabled and VLAN QOS support disabled). + * Hotsip, a free of charge phone for Windows. + * Vocal, an open source SIP stack from Vovida that includes a SIP proxy + that works with linphone since version 0.7.1. + * Siproxd is a free sip proxy being developped by Thomas Ries because he + would like to have linphone working behind his firewall. Siproxd is + simple to setup and works perfectly with linphone. + * Partysip aims at being a generic and fully functionnal SIP proxy. Visit + the web page for more details on its functionalities. + +Linphone may work also with other sip phones, but this has not been tested yet. + +%package devel +Summary: Development libraries for linphone +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: ortp-devel = @ORTP_VERSION@ +Requires: glib2-devel + +%description devel +Libraries and headers required to develop software with linphone. + +%package -n ortp +Summary: A C library implementing the RTP protocol (rfc1889) +Group: System Environment/Libraries +Version: @ORTP_VERSION@ + +%description -n ortp +oRTP is a LGPL licensed C library implementing the RTP protocol (rfc1889). It +is available for most *nix clones (primilarly Linux and HP-UX), and Win32. + +%package -n ortp-devel +Summary: Development libraries for ortp +Group: Development/Libraries +Version: @ORTP_VERSION@ +Requires: ortp = @ORTP_VERSION@ + +%description -n ortp-devel +oRTP is a LGPL licensed C library implementing the RTP protocol (rfc1889). It +is available for most *nix clones (primilarly Linux and HP-UX), and Win32. + +This package contains header files and development libraries needed to +develop programs using the oRTP library. + +%package -n mediastreamer2 +Summary: Audio/Video real-time streaming +Group: Development/Libraries +Version: @MS2_VERSION@ + +%description -n mediastreamer2 +Mediastreamer2 is a GPL licensed library to make audio and video +real-time streaming and processing. Written in pure C, it is based +upon the oRTP library. + +%package -n mediastreamer2-devel +Summary: Headers, libraries and docs for the mediastreamer2 library +Group: Development/Libraries +Version: @MS2_VERSION@ +Requires: mediastreamer2 = @MS2_VERSION@ +Requires: ortp-devel = @ORTP_VERSION@ + +%description -n mediastreamer2-devel +Mediastreamer2 is a GPL licensed library to make audio and video +real-time streaming and processing. Written in pure C, it is based +upon the ortp library. + +This package contains header files and development libraries needed to +develop programs using the mediastreamer2 library. + +%prep +%setup -q +#%patch -p 1 -b .pkgconfig +#%patch1 -p 1 -b .Werror +#%patch2 -p 1 -b .old + +%build +%configure \ + --with-osip=/usr \ + --with-speex=/usr \ + --with-readline=/usr \ +%if %{video} + --enable-video \ + --with-ffmpeg=/usr \ + --with-sdl=/usr \ +%endif +%if %{truespeech} + --enable-truespeech \ +%endif +%{?_without_old_osip: --with-osip-version=2.2.2} \ + --enable-ipv6 +%__make %{?_smp_mflags} + + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT +install -p -m 0644 pixmaps/linphone2.png $RPM_BUILD_ROOT%{_datadir}/pixmaps +%find_lang %{name} +rm $RPM_BUILD_ROOT%{_datadir}/gnome/apps/Internet/linphone.desktop +desktop-file-install --vendor=fedora \ + --delete-original \ + --dir $RPM_BUILD_ROOT%{_datadir}/applications \ + --add-category X-Fedora \ + --add-category Telephony \ + --add-category GTK \ + $RPM_BUILD_ROOT%{_datadir}/applications/%{name}.desktop + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%post -n ortp -p /sbin/ldconfig + +%postun -n ortp -p /sbin/ldconfig + +%post -n mediastreamer2 -p /sbin/ldconfig + +%postun -n mediastreamer2 -p /sbin/ldconfig + +%files -f %{name}.lang +%defattr(-,root,root) +%doc AUTHORS ChangeLog COPYING NEWS README TODO +%{_bindir}/* +%{_libdir}/bonobo/servers/*.server +%{_libdir}/liblinphone.so.* +%exclude %{_libdir}/libortp* +%{_libexecdir}/* +%{_mandir}/* +%{_datadir}/applications/*%{name}.desktop +%{_datadir}/gnome/help/linphone +%{_datadir}/gnome-2.0/ui/*.xml +%{_datadir}/pixmaps/linphone +%{_datadir}/pixmaps/linphone2.png +%{_datadir}/sounds/linphone + +%files devel +%defattr(-,root,root) +%{_includedir}/linphone +%{_libdir}/liblinphone.a +%{_libdir}/liblinphone.la +%{_libdir}/liblinphone.so +%{_libdir}/pkgconfig/linphone.pc + +%files -n ortp +%defattr(-,root,root) +%doc oRTP/AUTHORS oRTP/ChangeLog oRTP/COPYING oRTP/NEWS oRTP/README oRTP/TODO +%{_libdir}/libortp.so.* +%exclude %{_libdir}/liblinphone* + +%files -n ortp-devel +%defattr(-,root,root) +%{_includedir}/ortp +%{_libdir}/pkgconfig/ortp.pc +%{_libdir}/libortp.a +%{_libdir}/libortp.la +%{_libdir}/libortp.so +%{_datadir}/gtk-doc/html/ortp + +%files -n mediastreamer2 +%defattr(-,root,root) +%doc mediastreamer2/AUTHORS mediastreamer2/ChangeLog mediastreamer2/COPYING +%doc mediastreamer2/NEWS mediastreamer2/README +%{_libdir}/libmediastreamer.so.* +%{_libdir}/libquickstream.so.* + +%files -n mediastreamer2-devel +%{_includedir}/mediastreamer2 +%{_libdir}/pkgconfig/mediastreamer.pc +%{_libdir}/libmediastreamer.so +%{_libdir}/libmediastreamer.*a +%{_libdir}/libquickstream.so +%{_libdir}/libquickstream.*a + +%changelog +* Wed Sep 28 2005 Francois-Xavier 'FiX' KOWALSKI - 1.2.0pre3 +- Updated to latests Simon's work + +* Fri May 27 2005 Ignacio Vazquez-Abrams 1.0.1-3 +- Fix multiple menu entry and missing icon (#158975) +- Clean up spec file + +* Fri May 6 2005 Ignacio Vazquez-Abrams 1.0.1-2 +- Fix libosip2-devel BR + +* Wed May 4 2005 Ignacio Vazquez-Abrams 1.0.1-1 +- Update to 1.0.1 +- Port patches from devel + +* Wed Mar 23 2005 Ignacio Vazquez-Abrams 0.12.2-7 +- pkgconfig and -devel fixes + +* Wed Mar 23 2005 Ignacio Vazquez-Abrams 0.12.2-6 +- Fix build on x86_64 + +* Sat Mar 19 2005 Ignacio Vazquez-Abrams 0.12.2-5 +- %% + +* Sat Mar 19 2005 Ignacio Vazquez-Abrams 0.12.2-4 +- Used %%find_lang +- Tightened up %%files +- Streamlined spec file + +* Thu Mar 17 2005 Ignacio Vazquez-Abrams 0.12.2-3 +- Broke %%description at 80 columns + +* Wed Mar 16 2005 Ignacio Vazquez-Abrams 0.12.2-2 +- Removed explicit Requires + +* Tue Mar 15 2005 Ignacio Vazquez-Abrams 0.12.2-1 +- Bump release to 1 +- Cleaned up the -docs and -speex patches + +* Fri Jan 21 2005 Ignacio Vazquez-Abrams 0:0.12.2-0.iva.1 +- Fixed a silly spec error + +* Fri Jan 21 2005 Ignacio Vazquez-Abrams 0:0.12.2-0.iva.0 +- Initial RPM release. diff --git a/linphone/linphone2-gtk.glade b/linphone/linphone2-gtk.glade new file mode 100644 index 000000000..58e091051 --- /dev/null +++ b/linphone/linphone2-gtk.glade @@ -0,0 +1,3788 @@ + + + + + + True + linphone + False + linphone2.xpm + + + + True + + + True + + + True + Go + True + + + + + True + Address book + True + + + + True + gtk-open + 1 + + + + + + + True + gtk-preferences + True + True + + + + + + True + Shows calls + Call history + True + + + + True + gtk-justify-fill + 1 + + + + + + + True + + + + + True + Exit + True + + + + True + gtk-quit + 1 + + + + + + + + + + + True + Help + True + + + + + True + gtk-about + True + True + + + + + + True + gtk-help + True + True + + + + + + + + + + + + True + 9 + 0 + + + True + + + True + + + True + + + True + 5 + 0 + + + True + True + Enter sip address or phone number here + * + sip: + + + + + + + True + Sip address: + + + label_item + + + + + + + True + True + Shows the address book + 15 + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-open + + + False + False + + + + + True + ... + True + + + False + False + 1 + + + + + + + + + False + False + 1 + + + + + + + True + + + True + Proxy to use: + GTK_JUSTIFY_CENTER + + + + + + + + 1 + + + + + + + True + + + True + True + 8 + Call or +answer + True + 0 + + + + + + True + True + 8 + Hangup +or refuse + True + 0 + + + + 1 + + + + + 1 + + + + + True + True + 8 + Or chat ! + True + 0 + + + + False + False + 2 + + + + + True + True + 0 + True + True + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-jump-to + + + False + False + + + + + True + Show more... + True + + + False + False + 1 + + + + + + + + + False + False + 3 + + + + + True + True + + + True + + + True + 11 + 0 + + + True + 2 + + + True + 7.4505801528346183e-09 + Playback level: + + + False + False + + + + + True + True + 75 0 100 0 0 0 + 0 + GTK_POS_RIGHT + + + + 1 + + + + + True + 7.4505801528346183e-09 + Recording level: + + + False + False + 2 + + + + + True + True + 75 0 100 0 0 0 + 0 + GTK_POS_RIGHT + + + + 3 + + + + + True + 7.4505801528346183e-09 + Ring level: + + + False + False + 4 + + + + + True + True + 75 0 100 0 0 0 + 0 + GTK_POS_RIGHT + + + + 5 + + + + + + + True + Sound + + + label_item + + + + + False + False + + + + + True + 0 + + + True + 12 + + + True + + + True + True + Enable video + True + 0 + True + True + + + + False + False + + + + + + + + + True + Video + True + + + label_item + + + + + False + False + 1 + + + + + False + + + + + True + Controls + GTK_JUSTIFY_CENTER + + + tab + False + False + + + + + True + + + True + 11 + 0 + + + True + + + True + True + Reachable + True + 0 + True + True + + + + False + False + + + + + True + + + True + True + Busy, I'll be back in + True + 0 + True + presence_reachable + + + + + + True + True + The other party will be informed that you'll be back in X minutes + * + 5 + + + + False + False + 1 + + + + + True + mn + GTK_JUSTIFY_CENTER + + + 2 + + + + + False + 1 + + + + + True + True + Away + True + 0 + True + presence_reachable + + + + False + False + 2 + + + + + True + True + Do not disturb + True + 0 + True + presence_reachable + + + + False + False + 3 + + + + + True + True + Moved temporarily + True + 0 + True + presence_reachable + + + + False + False + 4 + + + + + True + True + Alternative service + True + 0 + True + presence_reachable + + + + False + False + 5 + + + + + True + + + True + URL: + GTK_JUSTIFY_CENTER + + + + + True + True + * + + + + False + False + 1 + + + + + False + 6 + + + + + + + + + 1 + False + + + + + True + Presence + GTK_JUSTIFY_CENTER + + + tab + 1 + False + False + + + + + True + 15 + 0 + + + True + + + True + True + Press digits to send DTMFs. + * + + + + False + False + + + + + True + 14 + 4 + 3 + 10 + 10 + True + + + True + True + # + True + 0 + + + + 2 + 3 + 3 + 4 + + + + + True + True + 0 + True + 0 + + + + 1 + 2 + 3 + 4 + + + + + True + True + * + True + 0 + + + + 3 + 4 + + + + + True + True + 9 +wxyz + True + 0 + + + + 2 + 3 + 2 + 3 + + + + + True + True + 8 +tuv + True + 0 + + + + 1 + 2 + 2 + 3 + + + + + True + True + 7 +pqrs + True + 0 + + + + 2 + 3 + + + + + True + True + 6 +mno + True + 0 + + + + 2 + 3 + 1 + 2 + + + + + True + True + 5 +jkl + True + 0 + + + + 1 + 2 + 1 + 2 + + + + + True + True + 4 +ghi + True + 0 + + + + 1 + 2 + + + + + True + True + 1 + True + 0 + + + + + + True + True + 2 +abc + True + 0 + + + + 1 + 2 + + + + + True + True + 3 +def + True + 0 + + + + 2 + 3 + + + + + 1 + + + + + + + 2 + False + + + + + True + DTMF + GTK_JUSTIFY_CENTER + + + tab + 2 + False + False + + + + + True + + + True + True + + + True + True + + + + + + + + + + + 3 + False + + + + + True + My online friends + + + tab + 3 + False + False + + + + + 4 + + + + + + + 1 + + + + + True + 0 + + + True + + + + + 2 + + + + + + + True + 5 + True + GDK_WINDOW_TYPE_HINT_NORMAL + Linphone + C: 2001 +Made in Old Europe + Linphone is a web-phone. +It is compatible with SIP and RTP protocols. + http://www.linphone.org + http://www.linphone.org + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Simon MORLAT +Aymeric Moizard +Sharath K Udupa + Simon MORLAT +Philippe Beau + it: Alberto Zanoni +de: Jean Jacques Sarton +fr: Simon Morlat +de: Jean-Jacques Sarton, Ursula Herles-Hartz +es: Jesus Benitez, Nelson Benitez +ja: Yamaguchi Yoshiya +nl: Hendrik-Jan Heins +pl: Robert Nasiadek &lt;darkone@darkone.pl&gt; +pt_BR: Rafael Caesar Lenzi <rc_lenzi@yahoo.com.br> +sv: Daniel Nylander <po@danielnylander.se> + linphone.png + + + + + + + + False + GTK_PACK_END + + + + + + + True + Parameters + False + linphone2.xpm + GDK_WINDOW_TYPE_HINT_NORMAL + + + + + + + + True + True + + + True + + + True + 6 + 0 + + + True + 12 + + + True + + + True + True + Toggle this if you are on an ipv6 network and you wish linphone to use it. + Use IPv6 network (if available) + True + 0 + True + + + + False + False + + + + + + + + + True + Global + True + + + label_item + + + + + + + True + 5 + 0 + + + True + 6 + + + True + 12 + These options is only for users in a private network, behind a gateway. If you are not in this situation, then leave this empty. + True + + + + + True + 3 + 2 + + + + + + True + True + * + + + + 1 + 2 + 1 + 2 + + + + + + True + True + * + + + + 1 + 2 + 2 + 3 + + + + + + True + True + Specify firewall address manually: + True + 0 + True + no_nat + + + + 2 + 3 + GTK_FILL + + + + + + True + True + Use this STUN server to guess firewall address : + True + 0 + True + no_nat + + + + 1 + 2 + GTK_FILL + + + + + + True + True + No firewall + True + 0 + True + + + + GTK_FILL + + + + + + False + False + 1 + + + + + + + True + NAT traversal options (experimental) + + + label_item + + + + + 1 + + + + + True + 5 + 0 + + + True + 2 + 2 + + + True + RTP port used for audio: + GTK_JUSTIFY_CENTER + + + GTK_FILL + + + + + True + Number of buffered miliseconds (jitter compensation): + GTK_JUSTIFY_CENTER + True + + + 1 + 2 + + + + + + True + True + 7000 5000 65535 1 10 10 + 4 + True + + + + 1 + 2 + GTK_EXPAND + 20 + + + + + True + True + 150 60 512 10 0 0 + 0 + GTK_POS_RIGHT + + + + 1 + 2 + 1 + 2 + GTK_EXPAND + 20 + + + + + + + True + RTP properties + + + label_item + + + + + 2 + + + + + True + 5 + 0 + + + True + 12 + + + True + + + True + True + RTP-RFC2833 is the recommended way. + Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting + True + 0 + True + + + + False + False + + + + + + + + + True + Other + True + + + label_item + + + + + 3 + + + + + False + + + + + True + Network + GTK_JUSTIFY_CENTER + + + tab + False + False + + + + + True + + + True + + + True + 10 + 0 + + + True + + + True + 6 + 2 + + + True + + + True + Choose file + + + + + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-dialog-info + + + False + False + + + + + True + Listen + True + + + False + False + 1 + + + + + + + + + False + False + 10 + 1 + + + + + 1 + 2 + 4 + 5 + GTK_FILL + GTK_FILL + + + + + True + 0 + Enable echo-canceler (cancels the echo heard by the remote party) + GTK_JUSTIFY_CENTER + + + 5 + 6 + + + + + True + True + True + 0 + True + + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + + True + + + + 1 + 2 + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + 0 + Ring sound: + GTK_JUSTIFY_CENTER + + + 4 + 5 + + + + + + + True + 0 + Ring sound device + GTK_JUSTIFY_CENTER + + + 3 + 4 + GTK_EXPAND + + + + + + True + 0 + Recording source: + + + 2 + 3 + + + + + + + True + + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + 0 + Capture sound device: + GTK_JUSTIFY_CENTER + + + 1 + 2 + + + + + + + True + False + False + True + + + 1 + 2 + 2 + 3 + + + + + + + True + 0 + Playback sound device: + + + GTK_EXPAND + GTK_EXPAND + + + + + + + + + True + Sound properties + + + label_item + + + + + + + False + + + + + 1 + False + + + + + True + Sound device + GTK_JUSTIFY_CENTER + + + tab + 1 + False + False + + + + + True + + + True + 10 + 0 + + + True + 67 + + + True + Run sip user agent on port: + GTK_JUSTIFY_CENTER + + + + + True + True + It is strongly recommended to use port 5060. + 5060 5000 65535 1 10 10 + 4 + + + + 32 + 1 + + + + + + + True + SIP port + + + label_item + + + + + False + + + + + True + 10 + 0 + + + True + + + True + + + True + Your sip address: + GTK_JUSTIFY_CENTER + + + False + + + + + True + sip: + GTK_JUSTIFY_RIGHT + + + False + False + 1 + + + + + True + True + * + + + + False + False + 2 + + + + + True + @ + GTK_JUSTIFY_CENTER + + + False + False + 3 + + + + + True + True + * + + + + False + 4 + + + + + + + True + True + Automatically guess a valid hostname + True + 0 + True + + + + 1 + + + + + + + True + Identity + + + label_item + + + + + False + 1 + + + + + True + 10 + 0 + + + True + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_OUT + + + 100 + True + True + + + + + + + True + 5 + GTK_BUTTONBOX_SPREAD + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-add + + + False + False + + + + + True + Add proxy/registrar + True + + + False + False + 1 + + + + + + + + + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-jump-to + + + False + False + + + + + True + Edit + True + + + False + False + 1 + + + + + + + + + 1 + + + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-cancel + + + False + False + + + + + True + Remove + True + + + False + False + 1 + + + + + + + + + 2 + + + + + 1 + + + + + + + True + Remote services + + + label_item + + + + + 2 + + + + + True + 10 + 0 + + + True + 12 + + + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-delete + + + False + False + + + + + True + Clear all stored authentication information (username,password...) + True + + + False + False + 1 + + + + + + + + + + + + + True + Authentication information + + + label_item + + + + + 3 + + + + + 2 + False + + + + + True + SIP + GTK_JUSTIFY_CENTER + + + tab + 2 + False + False + + + + + True + + + True + 10 + 0 + + + True + + + True + 9 + + + True + 0 + List of audio codecs, in order of preference: + + + False + False + 4 + + + + + True + True + + + True + False + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + True + + + + + False + + + + + True + Audio codecs + + + tab + False + False + + + + + True + True + GTK_SHADOW_IN + + + True + True + + + + + 1 + False + + + + + True + Video Codecs + + + tab + 1 + False + False + + + + + 1 + + + + + True + 10 + + + True + True + True + gtk-go-up + True + 0 + + + + + + True + True + True + gtk-go-down + True + 0 + + + + 1 + + + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-apply + + + False + False + + + + + True + Enable + True + + + False + False + 1 + + + + + + + + + 2 + + + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-cancel + + + False + False + + + + + True + Disable + True + + + False + False + 1 + + + + + + + + + 3 + + + + + False + False + 2 + + + + + True + 2 + 2 + True + + + True + True + 0 0 100000 10 100 10 + 1 + + + + 1 + 2 + 1 + 2 + + + + + + True + True + 0 0 100000 10 100 10 + 1 + GTK_UPDATE_IF_VALID + + + + 1 + 2 + + + + + + True + 0 + Download bandwidth (kbit/sec): + GTK_JUSTIFY_CENTER + + + GTK_FILL + + + + + + True + 0 + Upload bandwidth (kbit/sec): + GTK_JUSTIFY_CENTER + + + 1 + 2 + GTK_FILL + + + + + + False + 3 + + + + + + + True + + + True + 15 + Note: Codecs in red are not usable regarding to your connection type to the internet. + GTK_JUSTIFY_CENTER + True + + + False + False + + + + + True + 8 + 0 + + + True + 10 + 10 + No information availlable + GTK_JUSTIFY_CENTER + True + + + + + True + Codec information + + + label_item + + + + + 5 + 1 + + + + + False + 1 + + + + + + + True + 0.52999997138977051 + Audio and video codecs + + + label_item + + + + + + + 3 + False + + + + + True + Codecs + GTK_JUSTIFY_CENTER + + + tab + 3 + False + False + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-help + True + -11 + + + + + + True + True + True + gtk-apply + True + -10 + + + 1 + + + + + True + True + True + gtk-close + True + -7 + + + 2 + + + + + True + True + True + gtk-ok + True + -5 + + + 3 + + + + + False + GTK_PACK_END + + + + + + + True + Address Book + 305 + linphone2.xpm + GDK_WINDOW_TYPE_HINT_NORMAL + + + True + + + True + 12 + + + True + False + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + + + True + + + True + True + + + + + + + + + 2 + + + + + True + GTK_BUTTONBOX_SPREAD + + + True + 11 + + + True + True + True + gtk-add + GTK_RELIEF_HALF + True + 0 + + + + + + True + True + True + gtk-delete + GTK_RELIEF_HALF + True + 0 + + + + 1 + + + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-justify-center + + + False + False + + + + + True + Edit + True + + + False + False + 1 + + + + + + + + + 2 + + + + + True + True + True + gtk-close + True + 0 + + + + 3 + + + + + True + True + True + 0 + + + + True + 0 + 0 + + + True + 2 + + + True + gtk-quit + + + False + False + + + + + True + Select + True + + + False + False + 1 + + + + + + + + + 4 + + + + + + + False + False + GTK_PACK_END + + + + + + + True + Information + False + True + linphone2.xpm + GDK_WINDOW_TYPE_HINT_DIALOG + + + True + + + True + + + True + 25 + 5 + User is not reachable at the moment but he invites you to contact him using the following alternate ressource: + GTK_JUSTIFY_CENTER + True + + + 10 + + + + + True + True + 12 + None. + GTK_RELIEF_NONE + True + 0 + + + + + False + False + 1 + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-close + True + -7 + + + + + False + GTK_PACK_END + + + + + + + True + True + Proxy/Registrar configuration box + True + True + linphone2.xpm + GDK_WINDOW_TYPE_HINT_DIALOG + + + + True + + + True + 8 + 0 + + + True + 7 + 2 + + + + + + + + + True + True + True + 0 + True + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + + True + 0 + Publish presence information: + + + 6 + 7 + GTK_FILL + + + + + + True + 0 + Send registration: + + + 1 + 2 + GTK_FILL + + + + + + True + True + 900 120 72000 1 10 10 + 1 + True + + + 1 + 2 + 2 + 3 + + + + + + True + 0 + Registration Period: + + + 2 + 3 + GTK_FILL + + + + + + True + True + 256 + * + sip: + + + 1 + 2 + 3 + 4 + + + + + + True + 0 + SIP Identity: + + + 3 + 4 + GTK_FILL + + + + + + True + 0 + SIP Proxy: + + + 4 + 5 + GTK_FILL + + + + + + True + True + 250 + * + sip: + + + 1 + 2 + 4 + 5 + + + + + + True + True + 256 + * + + + 1 + 2 + 5 + 6 + + + + + + True + 0 + Route (optional): + + + 5 + 6 + GTK_FILL + + + + + + True + True + True + 0 + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + + + + True + Proxy/Registrar configuration box + + + label_item + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-help + True + -11 + + + + + True + True + True + gtk-ok + True + -5 + + + 1 + + + + + False + GTK_PACK_END + + + + + + + True + True + Edit contact information + True + linphone2.xpm + GDK_WINDOW_TYPE_HINT_DIALOG + + + + True + + + True + 6 + 0 + + + True + + + True + 4 + 2 + True + + + + + + + + + True + 0 + Subscribe policy: + + + 3 + 4 + GTK_FILL + + + + + + True + 0 + Proxy to use: + + + 2 + 3 + GTK_FILL + + + + + + True + 0 + Sip address: + + + 1 + 2 + + + + + + True + 0 + Name: + + + + + + + + True + True + * + + + 1 + 2 + + + + + + True + True + * + sip: + + + 1 + 2 + 1 + 2 + + + + + + + + True + True + Send subscription (see person's online status) + True + 0 + True + + + 1 + + + + + + + True + Contact information + + + label_item + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-help + True + -11 + + + + + True + True + True + gtk-cancel + True + -6 + + + 1 + + + + + True + True + True + gtk-ok + True + -5 + + + 2 + + + + + False + GTK_PACK_END + + + + + + + True + New incoming subscription + linphone2.xpm + GDK_WINDOW_TYPE_HINT_DIALOG + + + + True + + + True + + + True + gtk-dialog-warning + + + False + + + + + True + 14 + 9 + You have received a new subscription... + True + + + 1 + + + + + 2 + + + + + True + GTK_BUTTONBOX_SPREAD + + + True + True + True + -2 + + + True + 0 + 0 + + + True + 2 + + + True + gtk-stop + + + False + False + + + + + True + Refuse + True + + + False + False + 1 + + + + + + + + + + + True + True + True + -3 + + + True + 0 + 0 + + + True + 2 + + + True + gtk-jump-to + + + False + False + + + + + True + Accept + True + + + False + False + 1 + + + + + + + + + 1 + + + + + False + GTK_PACK_END + + + + + + + True + Authentication requested + True + linphone2.xpm + GDK_WINDOW_TYPE_HINT_DIALOG + + + + True + + + True + + + True + + + True + 16 + gtk-dialog-question + + + + + True + 29 + 14 + Authentication required for realm + GTK_JUSTIFY_CENTER + + + 1 + + + + + False + False + + + + + True + 5 + 2 + + + + + + + + + True + 0 + realm: + GTK_JUSTIFY_CENTER + + + GTK_EXPAND + + + + + + True + 0 + username: + GTK_JUSTIFY_CENTER + + + 1 + 2 + + + + + + + True + 0 + password: + GTK_JUSTIFY_CENTER + + + 2 + 3 + GTK_EXPAND + + + + + + True + 0 + userid: + GTK_JUSTIFY_CENTER + + + 3 + 4 + GTK_EXPAND | GTK_SHRINK + + + + + + True + True + * + + + 1 + 2 + 3 + 4 + + + + + + True + True + False + * + + + 1 + 2 + 2 + 3 + + + + + + True + True + * + + + 1 + 2 + 1 + 2 + + + + + + True + True + False + * + + + 1 + 2 + + + + + + 1 + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-cancel + True + -6 + + + + + True + True + True + gtk-ok + True + -5 + + + 1 + + + + + False + GTK_PACK_END + + + + + + + True + Linphone - Call history + 240 + 240 + True + linphone2.xpm + GDK_WINDOW_TYPE_HINT_DIALOG + + + + + True + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + + + True + True + False + False + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-close + True + -7 + + + + + False + GTK_PACK_END + + + + + + + True + Chat Room + 400 + 400 + True + linphone2.xpm + + + + True + + + True + True + GTK_SHADOW_IN + + + True + True + False + + + + + + + True + + + True + Text: + + + False + False + + + + + True + True + True + * + + + + 1 + + + + + False + 1 + + + + + True + True + gtk-close + True + 0 + + + + False + False + 2 + + + + + + + True + 5 + True + GDK_WINDOW_TYPE_HINT_NORMAL + Linphone + C: 2001 +Made in Old Europe + Linphone is a web-phone. +It is compatible with SIP and RTP protocols. + http://www.linphone.org + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Simon MORLAT +Aymeric Moizard +Sharath K Udupa + Simon MORLAT +Philippe Beau + it: Alberto Zanoni +de: Jean Jacques Sarton +fr: Simon Morlat +es: Jesus Benitez +ja: Yamaguchi Yoshiya +pl: obert Nasiadek <darkone@darkone.pl> +pt_BR: Rafael Caesar Lenzi <rc_lenzi@yahoo.com.br> +sv: Daniel Nylander <po@danielnylander.se> + linphone.png + + + + + + + False + GTK_PACK_END + + + + + + diff --git a/linphone/linphone2.glade b/linphone/linphone2.glade new file mode 100644 index 000000000..5b2464b91 --- /dev/null +++ b/linphone/linphone2.glade @@ -0,0 +1,6127 @@ + + + + + + + + + True + linphone + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + + True + True + + + + 2 + True + GTK_SHADOW_OUT + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + Go + True + + + + + + + True + Address book + True + + + + + True + gnome-stock-book-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + GNOMEUIINFO_MENU_PREFERENCES_ITEM + + + + + + + True + Shows calls + Call history + True + + + + + True + gtk-justify-fill + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + GNOMEUIINFO_MENU_EXIT_ITEM + + + + + + + + + + + True + GNOMEUIINFO_MENU_HELP_TREE + + + + + + + True + GNOMEUIINFO_MENU_ABOUT_ITEM + + + + + + + True + User manual + True + + + + + True + gtk-help + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + + BONOBO_DOCK_TOP + 0 + 0 + 0 + BONOBO_DOCK_ITEM_BEH_EXCLUSIVE|BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL + + + + + + 9 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + False + 0 + + + + True + False + 0 + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + enter sip uri here + True + True + True + 0 + sip: + True + * + False + + + + + + + + True + Sip address: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + 15 + True + Shows the address book + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gnome-stock-book-open + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + ... + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Proxy to use: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + 8 + True + True + Call or +answer + True + GTK_RELIEF_NORMAL + True + + + + 0 + True + True + + + + + + 8 + True + True + Hangup +or refuse + True + GTK_RELIEF_NORMAL + True + + + + 0 + True + True + + + + + 0 + True + True + + + + + + 8 + True + True + Or chat ! + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + True + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-jump-to + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Show more... + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + 0 + False + False + + + + + + True + True + True + True + GTK_POS_TOP + False + False + + + + True + False + 0 + + + + 11 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 2 + True + False + 0 + + + + True + Playback level: + False + False + GTK_JUSTIFY_LEFT + False + False + 7.45058015283e-09 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + GTK_POS_RIGHT + 0 + GTK_UPDATE_CONTINUOUS + False + 75 0 100 0 0 0 + + + + 0 + True + True + + + + + + True + Recording level: + False + False + GTK_JUSTIFY_LEFT + False + False + 7.45058015283e-09 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + GTK_POS_RIGHT + 0 + GTK_UPDATE_CONTINUOUS + False + 75 0 100 0 0 0 + + + + 0 + True + True + + + + + + True + Ring level: + False + False + GTK_JUSTIFY_LEFT + False + False + 7.45058015283e-09 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + GTK_POS_RIGHT + 0 + GTK_UPDATE_CONTINUOUS + False + 75 0 100 0 0 0 + + + + 0 + True + True + + + + + + + + True + Sound + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + True + Enable video + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + 0 + False + False + + + + + + + + + + True + Video + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + False + True + + + + + + True + Controls + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 0 + + + + 11 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + True + Reachable + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + Busy, I'll be back in + True + GTK_RELIEF_NORMAL + True + False + False + True + presence_reachable + + + + 0 + True + True + + + + + + True + The other party will be informed that you'll be back in X minutes + True + True + True + 0 + 5 + True + * + False + + + + 0 + False + False + + + + + + True + mn + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 0 + False + True + + + + + + True + True + Away + True + GTK_RELIEF_NORMAL + True + False + False + True + presence_reachable + + + + 0 + False + False + + + + + + True + True + Do not disturb + True + GTK_RELIEF_NORMAL + True + False + False + True + presence_reachable + + + + 0 + False + False + + + + + + True + True + Moved temporarily + True + GTK_RELIEF_NORMAL + True + False + False + True + presence_reachable + + + + 0 + False + False + + + + + + True + True + Alternative service + True + GTK_RELIEF_NORMAL + True + False + False + True + presence_reachable + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + URL: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + + True + True + True + True + 0 + + True + * + False + + + + 0 + False + False + + + + + 0 + False + True + + + + + + + 0 + True + True + + + + + False + True + + + + + + True + Presence + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 15 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + Press digits to send DTMFs. + True + True + True + 0 + + True + * + False + + + + 0 + False + False + + + + + + 14 + True + 4 + 3 + True + 10 + 10 + + + + True + True + 3 +def + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 0 + 1 + + + + + + True + True + 2 +abc + True + GTK_RELIEF_NORMAL + True + + + + 1 + 2 + 0 + 1 + + + + + + True + True + 1 + True + GTK_RELIEF_NORMAL + True + + + + 0 + 1 + 0 + 1 + + + + + + True + True + 4 +ghi + True + GTK_RELIEF_NORMAL + True + + + + 0 + 1 + 1 + 2 + + + + + + True + True + 5 +jkl + True + GTK_RELIEF_NORMAL + True + + + + 1 + 2 + 1 + 2 + + + + + + True + True + 6 +mno + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 1 + 2 + + + + + + True + True + 7 +pqrs + True + GTK_RELIEF_NORMAL + True + + + + 0 + 1 + 2 + 3 + + + + + + True + True + 8 +tuv + True + GTK_RELIEF_NORMAL + True + + + + 1 + 2 + 2 + 3 + + + + + + True + True + 9 +wxyz + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 2 + 3 + + + + + + True + True + * + True + GTK_RELIEF_NORMAL + True + + + + 0 + 1 + 3 + 4 + + + + + + True + True + 0 + True + GTK_RELIEF_NORMAL + True + + + + 1 + 2 + 3 + 4 + + + + + + True + True + # + True + GTK_RELIEF_NORMAL + True + + + + 2 + 3 + 3 + 4 + + + + + 0 + True + True + + + + + + + False + True + + + + + + True + DTMF + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 0 + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + False + False + False + + + + + + 0 + True + True + + + + + + + + + False + True + + + + + + True + My online friends + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + + + + 0 + True + True + + + + + + True + True + False + True + + + 0 + True + True + + + + + + 5 + True + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + linphone.png + C: 2001 +Made in Old Europe + Linphone is a web-phone. +It is compatible with SIP and RTP protocols. + Simon MORLAT +Aymeric Moizard +Sharath K Udupa + Simon MORLAT +Philippe Beau + cs: Klara Cihlarova, Petr Pisar +de: Jean-Jacques Sarton, Ursula Herles-Hartz +es: Jesus Benitez, Nelson Benitez +fr: Simon Morlat +it: Alberto Zanoni +ja: Yamaguchi Yoshiya +nl: Hendrik-Jan Heins +pl: Robert Nasiadek <darkone@darkone.pl> +pt_BR: Rafael Caesar Lenzi <rc_lenzi@yahoo.com.br> +sv: Daniel Nylander <po@danielnylander.se> + + + + True + Parameters + GTK_WIN_POS_NONE + False + False + False + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + + + + True + True + True + True + GTK_POS_TOP + False + False + + + + True + False + 0 + + + + 6 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + Toggle this if you are on an ipv6 network and you wish linphone to use it. + True + Use IPv6 network (if available) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + False + False + + + + + + + + + + True + Global + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 6 + True + False + 0 + + + + True + These options is only for users in a private network, behind a gateway. If you are not in this situation, then leave this empty. + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 12 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + + True + 3 + 2 + False + 0 + 0 + + + + True + True + No firewall + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + Use this STUN server to guess firewall address : + True + GTK_RELIEF_NORMAL + True + False + False + True + no_nat + + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + Specify firewall address manually: + True + GTK_RELIEF_NORMAL + True + False + False + True + no_nat + + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + + 1 + 2 + 2 + 3 + + + + + + + True + True + True + True + 0 + + True + * + False + + + + 1 + 2 + 1 + 2 + + + + + + 0 + False + False + + + + + + + + True + NAT traversal options (experimental) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 2 + 2 + False + 0 + 0 + + + + True + True + True + GTK_POS_RIGHT + 0 + GTK_UPDATE_CONTINUOUS + False + 150 60 512 10 0 0 + + + + 1 + 2 + 1 + 2 + 20 + expand + + + + + + True + True + 4 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 7000 5000 65535 1 10 10 + + + + 1 + 2 + 0 + 1 + 20 + expand + + + + + + True + Number of buffered miliseconds (jitter compensation): + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + + + + + + + True + RTP port used for audio: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + + True + RTP properties + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + 5 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + RTP-RFC2833 is the recommended way. + True + Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + False + False + + + + + + + + + + True + Other + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + False + True + + + + + + True + Network + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 0 + + + + True + False + 0 + + + + 10 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + 6 + 2 + False + 0 + 0 + + + + True + Playback sound device: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + expand + expand + + + + + + True + True + False + False + True + False + + + + True + True + False + True + 0 + + True + * + False + + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + micro + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + True + + + + True + line + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 1 + 2 + 2 + 3 + + + + + + + + True + Capture sound device: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + + + + + + + + True + False + True + + + + 1 + 2 + 0 + 1 + fill + fill + + + + + + True + False + True + + + + 1 + 2 + 1 + 2 + fill + fill + + + + + + True + False + 0 + + + + True + 10 + Ring sound selection + False + True + False + GTK_FILE_CHOOSER_ACTION_OPEN + + + + + True + True + True + True + 0 + + True + * + False + + + + + 0 + True + True + + + + + + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gnome-stock-volume + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Listen + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + 10 + False + False + + + + + 1 + 2 + 4 + 5 + fill + + + + + + True + Recording source: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + + + + + + + + True + Ring sound device + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + expand + + + + + + + True + Ring sound: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 4 + 5 + + + + + + + + True + False + True + + + + 1 + 2 + 3 + 4 + fill + fill + + + + + + True + True + + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 1 + 2 + 5 + 6 + fill + + + + + + + True + Enable echo-canceler (cancels the echo heard by the remote party) + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 5 + 6 + + + + + 0 + True + True + + + + + + + + True + Sound properties + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + 0 + False + True + + + + + False + True + + + + + + True + Sound device + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 0 + + + + 10 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 67 + + + + True + Run sip user agent on port: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + + True + It is strongly recommended to use port 5060. + True + 4 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 5060 5000 65535 1 10 10 + + + + 32 + True + True + + + + + + + + True + SIP port + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + True + + + + + + 10 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + False + 0 + + + + True + Your sip address: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + False + + + + + + True + sip: + False + False + GTK_JUSTIFY_RIGHT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + + 0 + False + False + + + + + + True + @ + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + + 0 + False + True + + + + + 0 + True + True + + + + + + True + True + Automatically guess a valid hostname + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + True + True + + + + + + + + True + Identity + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + True + + + + + + 10 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_OUT + GTK_CORNER_TOP_LEFT + + + + 100 + True + True + True + False + False + True + False + False + False + + + + + 0 + True + True + + + + + + 5 + True + GTK_BUTTONBOX_SPREAD + 0 + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-add + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Add proxy/registrar + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-jump-to + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Edit + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Remove + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + True + True + + + + + + + + True + Remote services + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + 10 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-delete + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Clear all stored authentication information (username,password...) + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + + + True + Authentication information + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + False + True + + + + + + True + SIP + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 0 + + + + 10 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + 9 + True + False + 0 + + + + True + List of audio codecs, in order of preference: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 4 + False + False + + + + + + True + True + True + True + GTK_POS_TOP + False + False + + + + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + True + True + False + False + False + + + + + False + True + + + + + + True + Audio codecs + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + False + False + False + + + + + False + True + + + + + + True + Video Codecs + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + 10 + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + gtk-go-up + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + gtk-go-down + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-apply + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Enable + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Disable + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + False + + + + + + True + 2 + 2 + True + 0 + 0 + + + + True + Upload bandwidth (kbit/sec): + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Download bandwidth (kbit/sec): + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_IF_VALID + False + False + 0 0 100000 10 100 10 + + + + 1 + 2 + 0 + 1 + + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 0 100000 10 100 10 + + + + 1 + 2 + 1 + 2 + + + + + + 0 + False + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Note: Codecs in red are not usable regarding to your connection type to the internet. + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 15 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 8 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + No information availlable + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 10 + 10 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + True + Codec information + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 5 + True + True + + + + + 0 + True + False + + + + + + + + True + Audio and video codecs + False + False + GTK_JUSTIFY_LEFT + False + False + 0.52999997139 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + False + True + + + + + + True + Codecs + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + True + Address Book + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 305 + True + False + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_SPREAD + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 11 + + + + True + True + True + gtk-add + True + GTK_RELIEF_HALF + True + + + + + + + True + True + True + gtk-delete + True + GTK_RELIEF_HALF + True + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-justify-center + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Edit + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-quit + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Select + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + + 0 + False + False + GTK_PACK_END + + + + + + 12 + True + False + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_IN + + + + True + True + True + False + False + True + False + False + False + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + True + Information + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + User is not reachable at the moment but he invites you to contact him using the following alternate ressource: + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 25 + 5 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 10 + True + True + + + + + + 12 + True + True + None. + True + GTK_RELIEF_NONE + True + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + + + True + True + Proxy/Registrar configuration box + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + True + True + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + True + -11 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 8 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 7 + 2 + False + 0 + 0 + + + + True + True + + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + Route (optional): + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 5 + 6 + fill + + + + + + + True + True + True + True + 256 + + True + * + False + + + 1 + 2 + 5 + 6 + + + + + + + True + True + True + True + 250 + sip: + True + * + False + + + 1 + 2 + 4 + 5 + + + + + + + True + SIP Proxy: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + SIP Identity: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + True + True + True + 256 + sip: + True + * + False + + + 1 + 2 + 3 + 4 + + + + + + + True + Registration Period: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 900 120 72000 1 10 10 + + + 1 + 2 + 2 + 3 + + + + + + + True + Send registration: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Publish presence information: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 6 + 7 + fill + + + + + + + True + True + + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 6 + 7 + fill + + + + + + + + + True + Proxy/Registrar configuration box + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + + + True + True + Edit contact information + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + True + -11 + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + False + 0 + + + + True + 4 + 2 + True + 0 + 0 + + + + True + True + True + True + 0 + sip: + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + Name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + + + + + + + True + Sip address: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + + + + + + + True + Proxy to use: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + Subscribe policy: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + fill + + + + + + 0 + True + True + + + + + + True + True + Send subscription (see person's online status) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + True + True + + + + + + + + True + Contact information + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + + + True + New incoming subscription + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_SPREAD + + + + True + True + True + GTK_RELIEF_NORMAL + True + -2 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-stop + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Refuse + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + -3 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-jump-to + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Accept + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + gtk-dialog-warning + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + True + + + + + + True + You have received a new subscription... + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 14 + 9 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + True + Authentication requested + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + False + 0 + + + + True + gtk-dialog-question + 4 + 0.5 + 0.5 + 16 + 0 + + + 0 + True + True + + + + + + True + Authentication required for realm + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 29 + 14 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + 5 + 2 + False + 0 + 0 + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + False + 0 + + True + * + False + + + 1 + 2 + 2 + 3 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 3 + 4 + + + + + + + True + userid: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + expand|shrink + + + + + + + True + password: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + expand + + + + + + + True + username: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + + + + + + + + True + realm: + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + expand + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + True + Linphone - Call history + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 240 + 240 + True + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_NONE + False + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + + + + + + + + True + Chat Room + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 400 + 400 + True + True + linphone2.xpm + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_NONE + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Text: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + True + 0 + + True + * + False + + + + 0 + True + True + + + + + 0 + False + True + + + + + + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + + diff --git a/linphone/lpc10-1.5/.cvsignore b/linphone/lpc10-1.5/.cvsignore new file mode 100644 index 000000000..fe404a3f7 --- /dev/null +++ b/linphone/lpc10-1.5/.cvsignore @@ -0,0 +1,6 @@ +*.lo +.deps +.libs +Makefile +Makefile.in +liblpc10.la diff --git a/linphone/lpc10-1.5/FAQ b/linphone/lpc10-1.5/FAQ new file mode 100644 index 000000000..559c251b9 --- /dev/null +++ b/linphone/lpc10-1.5/FAQ @@ -0,0 +1,102 @@ + Information on 2400 bps LPC and 4800 bps CELP speech coders + for Frequently Asked Questions lists (audio-formats, comp.compression) + +The U.S. DoD's Federal-Standard-1016 based 4800 bps code excited linear +prediction voice coder version 3.2 (CELP 3.2) Fortran and C simulation +source codes are available for worldwide distribution (on DOS +diskettes, but configured to compile on Sun SPARC stations) from NTIS +and DTIC. Example input and processed speech files are included. A +Technical Information Bulletin (TIB), "Details to Assist in +Implementation of Federal Standard 1016 CELP," and the official +standard, "Federal Standard 1016, Telecommunications: Analog to +Digital Conversion of Radio Voice by 4,800 bit/second Code Excited +Linear Prediction (CELP)," are also available. + +This is available through the National Technical Information Service: + +NTIS +U.S. Department of Commerce +5285 Port Royal Road +Springfield, VA 22161 +USA +(703) 487-4650 + +The "AD" ordering number for the CELP software is AD M000 118 +(US$ 90.00) and for the TIB it's AD A256 629 (US$ 17.50). The LPC-10 +standard, described below, is FIPS Pub 137 (US$ 12.50). There is a +$3.00 shipping charge on all U.S. orders. The telephone number for +their automated system is 703-487-4650, or 703-487-4600 if you'd prefer +to talk with a real person. + +(U.S. DoD personnel and contractors can receive the package from the +Defense Technical Information Center: DTIC, Building 5, Cameron +Station, Alexandria, VA 22304-6145. Their telephone number is +703-274-7633.) + +The following articles describe the Federal-Standard-1016 4.8-kbps CELP +coder (it's unnecessary to read more than one): + +Campbell, Joseph P. Jr., Thomas E. Tremain and Vanoy C. Welch, +"The Federal Standard 1016 4800 bps CELP Voice Coder," Digital Signal +Processing, Academic Press, 1991, Vol. 1, No. 3, p. 145-155. + +Campbell, Joseph P. Jr., Thomas E. Tremain and Vanoy C. Welch, +"The DoD 4.8 kbps Standard (Proposed Federal Standard 1016)," +in Advances in Speech Coding, ed. Atal, Cuperman and Gersho, +Kluwer Academic Publishers, 1991, Chapter 12, p. 121-133. + +Campbell, Joseph P. Jr., Thomas E. Tremain and Vanoy C. Welch, "The +Proposed Federal Standard 1016 4800 bps Voice Coder: CELP," Speech +Technology Magazine, April/May 1990, p. 58-64. + + +The U.S. DoD's Federal-Standard-1015/NATO-STANAG-4198 based 2400 bps +linear prediction coder (LPC-10) was republished as a Federal +Information Processing Standards Publication 137 (FIPS Pub 137). +It is described in: + +Thomas E. Tremain, "The Government Standard Linear Predictive Coding +Algorithm: LPC-10," Speech Technology Magazine, April 1982, p. 40-49. + +There is also a section about FS-1015 in the book: +Panos E. Papamichalis, Practical Approaches to Speech Coding, +Prentice-Hall, 1987. + +The voicing classifier used in the enhanced LPC-10 (LPC-10e) is described in: +Campbell, Joseph P., Jr. and T. E. Tremain, "Voiced/Unvoiced Classification +of Speech with Applications to the U.S. Government LPC-10E Algorithm," +Proceedings of the IEEE International Conference on Acoustics, Speech, and +Signal Processing, 1986, p. 473-6. + +Copies of the official standard +"Federal Standard 1016, Telecommunications: Analog to Digital Conversion +of Radio Voice by 4,800 bit/second Code Excited Linear Prediction (CELP)" +are available for US$ 5.00 each from: + +GSA Federal Supply Service Bureau +Specification Section, Suite 8100 +470 E. L'Enfant Place, S.W. +Washington, DC 20407 +(202)755-0325 + +Realtime DSP code for FS-1015 and FS-1016 is sold by: + +John DellaMorte +DSP Software Engineering +165 Middlesex Tpk, Suite 206 +Bedford, MA 01730 +USA +1-617-275-3733 +1-617-275-4323 (fax) +dspse.bedford@channel1.com + +DSP Software Engineering's FS-1016 code can run on a DSP Research's Tiger 30 +(a PC board with a TMS320C3x and analog interface suited to development work). + +DSP Research +1095 E. Duane Ave. +Sunnyvale, CA 94086 +USA +(408)773-1042 +(408)736-3451 (fax) + diff --git a/linphone/lpc10-1.5/Makefile.am b/linphone/lpc10-1.5/Makefile.am new file mode 100644 index 000000000..289649bab --- /dev/null +++ b/linphone/lpc10-1.5/Makefile.am @@ -0,0 +1,49 @@ +EXTRA_DIST=README README-1.0 FAQ README.new + +noinst_LTLIBRARIES=liblpc10.la + + +liblpc10_la_SOURCES=f2clib.c lpc10.h f2c.h\ + analys.c \ + bsynz.c \ + chanwr.c \ + dcbias.c \ + decode.c \ + deemp.c \ + difmag.c \ + dyptrk.c \ + encode.c \ + energy.c \ + ham84.c \ + hp100.c \ + invert.c \ + irc2pc.c \ + ivfilt.c \ + lpcdec.c \ + lpcenc.c \ + lpcini.c \ + lpfilt.c \ + median.c \ + mload.c \ + onset.c \ + pitsyn.c \ + placea.c \ + placev.c \ + preemp.c \ + prepro.c \ + random.c \ + rcchk.c \ + synths.c \ + tbdm.c \ + voicin.c \ + vparms.c + +liblpc10_la_LIBADD=-lm + +#noinst_PROGRAMS=bitio + +#bitio_SOURCES=bitio.c lpc10_wrapper.h + +#bitio_LDADD=liblpc10.la + +AM_CFLAGS=-w diff --git a/linphone/lpc10-1.5/README b/linphone/lpc10-1.5/README new file mode 100644 index 000000000..b31e79315 --- /dev/null +++ b/linphone/lpc10-1.5/README @@ -0,0 +1,81 @@ + U.S. Department of Defense + LPC-10 2400 bps Voice Coder + Release 1.5 + October 1997 + +(Note that this release 1.5 is not from any "official" source. It is +from Andy Fingerhut. Contact information below.) + +This package is available from: + +http://www.arl.wustl.edu/~jaf/lpc/lpc10-1.5.tar.gz + + +New in release 1.5: + +Just some minor fixes to sample applications "nuke" and "unnuke" that +caused them not to work correctly on compilers with 16 bit int's. +This was only a bug in the sample application code, not in the LPC-10 +library itself. + +NEW IN RELEASE 1.4! + +You can now compress (or decompress) multiple audio streams +"simultaneously", by alternating the compression (or decompression) of +frames for each audio stream. Only the C version supports this +feature, but who really cared whether the Fortran version supported +this or not, eh? + + +Contents: + README - This file + README-1.0 - The original README file from Release 1.0 + FAQ - Frequently Asked Questions items for LPC and CELP + lpc55 - modified Fortran code for LPC-10 Version 55 + README - summary of modifications made + README.f2c - hints on installing f2c on some machines, + and notes on the f2c invocation options used + README.jaf - hints on using the LPC-10 coder from a C application + RCS - Revision Control System directory containing + master files for all sources, showing the steps + of changes that I made to the original 1.0 sources. + lpc55-C - Hand-modified C version of code, most of + which was created by running f2c on the + Fortran code in directory lpc55 above. I'm + fairly certain that the C code from the 1.0 + release was out of date with respect to the + Fortran code, so it was not included in this + distribution. + data - Sample speech files, containing: + dam9.spd - Sample input speech file + dam9-out.spd - Speech processed by modified Fortran code. + This is identical to dam9_lpc55.spd from + release 1.0, except for 180 0 samples at the + beginning, and many samples here and there + that are off by 1, probably due to different + rounding of reals. + abtool_1.2 - Sun GUI tool for playing listening comparisons + between speech files (this is a beta version) + misc + bin - Several useful shell scripts for audio on Sun machines + README - Description of audio file formats + fortran-locals - Some files I made when determining whether local + variables in Fortran subroutines and functions + were like C "static" local variables or not. + gcc-2.6.0-bug - A program that demonstrates a bug in GCC 2.6.0 + on the Solaris 2.4 machine siesta.cs.wustl.edu. + I don't know how widespread this problem is, + but it does have an unpleasant side effect if + GCC 2.6.0 is used to compile f2c. + +See also the file README-1.0 for some other useful details. + + +Andy Fingerhut +Applied Research Laboratory <-- this line is optional if +Washington University, Campus Box 1045/Bryan 509 you have limited space +One Brookings Drive +Saint Louis, MO 63130-4899 + +jaf@arl.wustl.edu +http://www.arl.wustl.edu/~jaf/ diff --git a/linphone/lpc10-1.5/README-1.0 b/linphone/lpc10-1.5/README-1.0 new file mode 100644 index 000000000..7fb7871dc --- /dev/null +++ b/linphone/lpc10-1.5/README-1.0 @@ -0,0 +1,47 @@ + U.S. Department of Defense + LPC-10 2400 bps Voice Coder + Release 1.0 + October 1993 + + +Contents: + README - This file + FAQ - Frequently Asked Questions items for LPC and CELP + lpc55 - Fortran code for LPC-10 Version 55 + lpc55-C - C code for LPC-10 + data - Sample speech files, containing: + dam9.spd - Sample input speech file + dam9_lpc55.spd - Speech processed by LPC-10 + abtool_1.2 - Sun GUI tool for playing listening comparisons + between speech files (this is a beta version) + + The distribution file has been compressed with the GNU compression +program gzip version 1.2.3, available from archives such as ftp.uu.net and +wuarchive.wustl.edu. To unpack it, use the commands: + + gunzip lpc-1.0.tar (uncompress the archive file) + tar xvf lpc-1.0.tar (extract the contents of the archive) + +(For distribution on pcfs floppy disks (IBM PC format), the file names may + not appear exactly as shown above.) + + Documentation on using the above programs is included in README files +in each directory. Documentation describing the internal operation of +LPC-10 is currently available only in hardcopy format. We will include +more extensive documentation with future releases of this package. + + All development of LPC-10 has been done in Fortran, so the Fortran +code has been written for flexible and easy use in a research environment. +The C version was translated from the Fortran to assist in porting LPC +to Digital Signal Processors (DSPs), and does not have the debugging +features or I/O flexiblility of the Fortran version. Both versions +have been tested on a Sun SPARCstation-10 running Solaris 2.2 and +SunOS 4.1.2. + + The speech files are in 16 bit linear format, sampled at 8000 Hz. There +are no headers on these files, so some manipulation may be required to +play them on your system. The following alias will play speech files on +the Sun speakerbox: + + alias play 'audioconvert -i pcm16,mono,raw,r=8k -f sun \!* | audioplay' + play dam9.spd diff --git a/linphone/lpc10-1.5/README.new b/linphone/lpc10-1.5/README.new new file mode 100644 index 000000000..30abe4c97 --- /dev/null +++ b/linphone/lpc10-1.5/README.new @@ -0,0 +1,89 @@ +Tue Aug 20 16:19:51 CDT 1996 +Andy Fingerhut (jaf@arl.wustl.edu) + +In release 1.4, there are quite a few hand modifications to the C code +that was automatically created from the Fortran code with f2c. They +are all summarized in change log comments at the beginning of the +changed files. All of the original files from f2c were checked in to +RCS before modification, so it is possible to see exactly what changes +were made, for the extremely curious. That precaution was also for my +benefit, in case I ever recompile the Fortran sources, and want to +make similar changes to that new C source code. + +Below is the README file for this directory included with the 1.3 +release of the LPC-10 package. A few parts of it are a little out of +date, but it is correct for the most part. + + +Sun Jul 7 15:30:31 CDT 1996 +Andy Fingerhut (jaf@arl.wustl.edu) + +To create the LPC-10 library, copy the appropriate makefile to the +proper name for easy use, e.g., for Unix, copy makefile.unx to the +file "Makefile". The file makefile.dos has been used with some +version of the 'nmake' utility that comes with the Microsoft C +compiler (the same one used for Nautilus v1.5a, which I believe +specifies Microsoft C version 7.0 or later). + +Then edit the file lpc10.h in the directory above. It should already +be set up to work properly on any Unix compiler for which "int" is 32 +bits and "short" is 16 bits, and under the Microsoft C compiler +configured so that "long" is 32 bits and "int" is 16 bits. There must +be a typedef for the two types INT32 and INT16 in that file. You +should choose types that compile to those sizes using your compiler, +because there are places in the LPC-10 code that expect INT16's to +have exactly 16 bits (at least, I *think* they must be no larger), and +INT32's to have exactly 32 bits. + + +A few notes on how these files were created +------------------------------------------- + +(This section is mostly for my benefit, so I can remember what I did. +You don't need to read it if you just want to use this package. It +might be useful to read it if you change the Fortran sources and want +to recreate a usable library of C sources. -- Andy) + +These C sources were created automatically from the Fortran sources +using f2c, for the most part. Listed below are the extra +modifications that were made after this automatic conversion. Many of +them were made so that it was not necessary to install f2c in order to +use this LPC-10 coder. + +1. + +Put all of those files that were necessary for only the coder, rather +than an application that uses the coder, into this subdirectory called +lpc10. + +2. + +Copied f2c.h from the f2c distribution into this subdirectory. Some +modifications were made to the "typedef" statements in this file, to +explicitly indicate the sizes (in bits) that different integer types +should be. The types INT32 and INT16 must be defined in a file called +lpc10.h in the directory above. Created the file f2clib.c, containing +only the functions pow_ii(), r_sign(), and i_nint() from the f2c +library. + +3. + +The f2c output originally had a file called contrl_com.c, that defined +a small structure containing a few variables that were used in many +different functions of the LPC10 code. Every file containing +functions that used it defined it as "extern", while contrl_com.c +actually allocated storage for the structure. Bill Dorsey, one of the +lead developers of Nautilus, said that the Microsoft C compiler had +problems either compiling this file, or linking it with all of the +other compiled files, so he just eliminated that file and removed the +"extern" keyword from the one of the files that declared it that way. +The file chosen (arbitrarily) was analys.c. + +4. + +Copied the makefiles for Unix and Microsoft C from the Nautilus v1.5a +distribution into the lpc10 directory. Modified them to take out +references to Nautilus. These makefiles don't create an executable, +but a library of compiled functions called liblpc10.a (Unix) or +LPC10.LIB (DOS). This library can be used when linking an executable +that calls the functions lpcini_(), lpcenc_(), and lpcdec_(). diff --git a/linphone/lpc10-1.5/analys.c b/linphone/lpc10-1.5/analys.c new file mode 100644 index 000000000..6e8ece4ab --- /dev/null +++ b/linphone/lpc10-1.5/analys.c @@ -0,0 +1,617 @@ +/* + +$Log: analys.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:16:01 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:29:08 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int analys_(real *speech, integer *voice, integer *pitch, real *rms, real *rc, struct lpc10_encoder_state *st); +/* comlen contrl_ 12 */ +/*:ref: preemp_ 14 5 6 6 4 6 6 */ +/*:ref: onset_ 14 7 6 4 4 4 4 4 4 */ +/*:ref: placev_ 14 11 4 4 4 4 4 4 4 4 4 4 4 */ +/*:ref: lpfilt_ 14 4 6 6 4 4 */ +/*:ref: ivfilt_ 14 5 6 6 4 4 6 */ +/*:ref: tbdm_ 14 8 6 4 4 4 6 4 4 4 */ +/*:ref: voicin_ 14 12 4 6 6 4 4 6 6 4 6 4 4 4 */ +/*:ref: dyptrk_ 14 6 6 4 4 4 4 4 */ +/*:ref: placea_ 14 9 4 4 4 4 4 4 4 4 4 */ +/*:ref: dcbias_ 14 3 4 6 6 */ +/*:ref: energy_ 14 3 4 6 6 */ +/*:ref: mload_ 14 6 4 4 4 6 6 6 */ +/*:ref: invert_ 14 4 4 6 6 6 */ +/*:ref: rcchk_ 14 3 4 6 6 */ +/*:ref: initonset_ 14 0 */ +/*:ref: initvoicin_ 14 0 */ +/*:ref: initdyptrk_ 14 0 */ +/* Rerunning f2c -P may change prototypes or declarations. */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* Table of constant values */ + +static integer c__10 = 10; +static integer c__181 = 181; +static integer c__720 = 720; +static integer c__3 = 3; +static integer c__90 = 90; +static integer c__156 = 156; +static integer c__307 = 307; +static integer c__462 = 462; +static integer c__312 = 312; +static integer c__60 = 60; +static integer c__1 = 1; + +/* ****************************************************************** */ + +/* ANALYS Version 55 */ + +/* $Log: analys.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:16:01 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:29:08 jaf + * Initial revision + * */ +/* Revision 1.9 1996/05/23 19:41:07 jaf */ +/* Commented out some unnecessary lines that were reading uninitialized */ +/* values. */ + +/* Revision 1.8 1996/03/27 23:57:55 jaf */ +/* Added some comments about which indices of the local buffers INBUF, */ +/* LPBUF, etc., get read or modified by some of the subroutine calls. I */ +/* just did this while trying to figure out the discrepancy between the */ +/* embedded code compiled with all local variables implicitly saved, and */ +/* without. */ + +/* I added some debugging write statements in hopes of finding a problem. */ +/* None of them ever printed anything while running with the long input */ +/* speech file dam9.spd provided in the distribution. */ + +/* Revision 1.7 1996/03/27 18:06:20 jaf */ +/* Commented out access to MAXOSP, which is just a debugging variable */ +/* that was defined in the COMMON block CONTRL in contrl.fh. */ + +/* Revision 1.6 1996/03/26 19:31:33 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.5 1996/03/21 15:19:35 jaf */ +/* Added comments for ENTRY PITDEC. */ + +/* Revision 1.4 1996/03/19 20:54:27 jaf */ +/* Added a line to INITANALYS. See comments there. */ + +/* Revision 1.3 1996/03/19 20:52:49 jaf */ +/* Rearranged the order of the local variables quite a bit, to separate */ +/* them into groups of "constants", "locals that don't need to be saved */ +/* from one call to the next", and "local that do need to be saved from */ +/* one call to the next". */ + +/* Several locals in the last set should have been given initial values, */ +/* but weren't. I gave them all initial values of 0. */ + +/* Added a separate ENTRY INITANALYS that initializes all local state */ +/* that should be, and also calls the corresponding entries of the */ +/* subroutines called by ANALYS that also have local state. */ + +/* There used to be DATA statements in ANALYS. I got rid of most of */ +/* them, and added a local logical variable FIRST that calls the entry */ +/* INITANALYS on the first call to ANALYS. This is just so that one need */ +/* not remember to call INITANALYS first in order for the state to be */ +/* initialized. */ + +/* Revision 1.2 1996/03/11 23:29:32 jaf */ +/* Added several comments with my own personal questions about the */ +/* Fortran 77 meaning of the parameters passed to the subroutine PREEMP. */ + +/* Revision 1.1 1996/02/07 14:42:29 jaf */ +/* Initial revision */ + + +/* ****************************************************************** */ + +/* SUBROUTINE ANALYS */ + +/* Input: */ +/* SPEECH */ +/* Indices 1 through LFRAME read. */ +/* Output: */ +/* VOICE */ +/* Indices 1 through 2 written. */ +/* PITCH */ +/* Written in subroutine DYPTRK, and then perhaps read and written */ +/* some more. */ +/* RMS */ +/* Written. */ +/* RC */ +/* Indices 1 through ORDER written (ORDER defined in contrl.fh). */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITANALYS. */ + + +/* ENTRY PITDEC */ + +/* Input: */ +/* PITCH - Encoded pitch index */ +/* Output: */ +/* PTAU - Decoded pitch period */ + +/* This entry has no local state. It accesses a "constant" array */ +/* declared in ANALYS. */ + +/* Subroutine */ int analys_(real *speech, integer *voice, integer + *pitch, real *rms, real *rc, struct lpc10_encoder_state *st) +{ + /* Initialized data */ + + static integer tau[60] = { 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34, + 35,36,37,38,39,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72, + 74,76,78,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136, + 140,144,148,152,156 }; + static integer buflim[4] = { 181,720,25,720 }; + static real precoef = .9375f; + + /* System generated locals */ + integer i__1; + + /* Local variables */ + real amdf[60]; + integer half; + real abuf[156]; + real *bias; + extern /* Subroutine */ int tbdm_(real *, integer *, integer *, integer *, + real *, integer *, integer *, integer *); + integer *awin; + integer midx, ewin[6] /* was [2][3] */; + real ivrc[2], temp; + real *zpre; + integer *vwin; + integer i__, j, lanal; + extern /* Subroutine */ int rcchk_(integer *, real *, real *), mload_( + integer *, integer *, integer *, real *, real *, real *); + real *inbuf, *pebuf; + real *lpbuf, *ivbuf; + real *rcbuf; + integer *osbuf; + extern /* Subroutine */ int onset_(real *, integer *, integer *, integer * + , integer *, integer *, integer *, struct lpc10_encoder_state *); + integer *osptr; + extern /* Subroutine */ placea_(integer *, integer * + , integer *, integer *, integer *, integer *, integer *, integer * + , integer *), dcbias_(integer *, real *, real *), placev_(integer + *, integer *, integer *, integer *, integer *, integer *, integer + *, integer *, integer *, integer *, integer *); + integer ipitch; + integer *obound; + extern /* Subroutine */ int preemp_(real *, real *, integer *, real *, + real *), voicin_(integer *, real *, real *, integer *, integer *, + real *, real *, integer *, real *, integer *, integer *, integer *, + struct lpc10_encoder_state *); + integer *voibuf; + integer mintau; + real *rmsbuf; + extern /* Subroutine */ int lpfilt_(real *, real *, integer *, integer *), + ivfilt_(real *, real *, integer *, integer *, real *), energy_( + integer *, real *, real *), invert_(integer *, real *, real *, + real *); + integer minptr, maxptr; + extern /* Subroutine */ int dyptrk_(real *, integer *, integer *, integer + *, integer *, integer *, struct lpc10_encoder_state *); + real phi[100] /* was [10][10] */, psi[10]; + +/* $Log: analys.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:16:01 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:29:08 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Arguments to ANALYS */ +/* $Log: analys.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:16:01 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:29:08 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Arguments to entry PITDEC (below) */ +/* Parameters/constants */ +/* Constants */ +/* NF = Number of frames */ +/* AF = Frame in which analysis is done */ +/* OSLEN = Length of the onset buffer */ +/* LTAU = Number of pitch lags */ +/* SBUFL, SBUFH = Start and end index of speech buffers */ +/* LBUFL, LBUFH = Start and end index of LPF speech buffer */ +/* MINWIN, MAXWIN = Min and Max length of voicing (and analysis) windows +*/ +/* PWLEN, PWINH, PWINL = Length, upper and lower limits of pitch window + */ +/* DVWINL, DVWINH = Default lower and upper limits of voicing window */ +/* The tables TAU and BUFLIM, and the variable PRECOEF, are not */ +/* Fortran PARAMETER's, but they are initialized with DATA */ +/* statements, and never modified. Thus, they need not have SAVE */ +/* statements for them to keep their values from one invocation to +*/ +/* the next. */ +/* Local variables that need not be saved */ +/* Local state */ +/* Data Buffers */ +/* INBUF Raw speech (with DC bias removed each frame) */ +/* PEBUF Preemphasized speech */ +/* LPBUF Low pass speech buffer */ +/* IVBUF Inverse filtered speech */ +/* OSBUF Indexes of onsets in speech buffers */ +/* VWIN Voicing window indices */ +/* AWIN Analysis window indices */ +/* EWIN Energy window indices */ +/* VOIBUF Voicing decisions on windows in VWIN */ +/* RMSBUF RMS energy */ +/* RCBUF Reflection Coefficients */ + +/* Pitch is handled separately from the above parameters. */ +/* The following variables deal with pitch: */ +/* MIDX Encoded initial pitch estimate for analysis frame */ +/* IPITCH Initial pitch computed for frame AF (decoded from MIDX) */ +/* PITCH The encoded pitch value (index into TAU) for the present */ +/* frame (delayed and smoothed by Dyptrack) */ + /* Parameter adjustments */ + if (speech) { + --speech; + } + if (voice) { + --voice; + } + if (rc) { + --rc; + } + + /* Function Body */ + +/* Calculations are done on future frame due to requirements */ +/* of the pitch tracker. Delay RMS and RC's 2 frames to give */ +/* current frame parameters on return. */ +/* Update all buffers */ + + inbuf = &(st->inbuf[0]); + pebuf = &(st->pebuf[0]); + lpbuf = &(st->lpbuf[0]); + ivbuf = &(st->ivbuf[0]); + bias = &(st->bias); + osbuf = &(st->osbuf[0]); + osptr = &(st->osptr); + obound = &(st->obound[0]); + vwin = &(st->vwin[0]); + awin = &(st->awin[0]); + voibuf = &(st->voibuf[0]); + rmsbuf = &(st->rmsbuf[0]); + rcbuf = &(st->rcbuf[0]); + zpre = &(st->zpre); + + i__1 = 720 - contrl_1.lframe; + for (i__ = 181; i__ <= i__1; ++i__) { + inbuf[i__ - 181] = inbuf[contrl_1.lframe + i__ - 181]; + pebuf[i__ - 181] = pebuf[contrl_1.lframe + i__ - 181]; + } + i__1 = 540 - contrl_1.lframe; + for (i__ = 229; i__ <= i__1; ++i__) { + ivbuf[i__ - 229] = ivbuf[contrl_1.lframe + i__ - 229]; + } + i__1 = 720 - contrl_1.lframe; + for (i__ = 25; i__ <= i__1; ++i__) { + lpbuf[i__ - 25] = lpbuf[contrl_1.lframe + i__ - 25]; + } + j = 1; + i__1 = (*osptr) - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (osbuf[i__ - 1] > contrl_1.lframe) { + osbuf[j - 1] = osbuf[i__ - 1] - contrl_1.lframe; + ++j; + } + } + *osptr = j; + voibuf[0] = voibuf[2]; + voibuf[1] = voibuf[3]; + for (i__ = 1; i__ <= 2; ++i__) { + vwin[(i__ << 1) - 2] = vwin[(i__ + 1 << 1) - 2] - contrl_1.lframe; + vwin[(i__ << 1) - 1] = vwin[(i__ + 1 << 1) - 1] - contrl_1.lframe; + awin[(i__ << 1) - 2] = awin[(i__ + 1 << 1) - 2] - contrl_1.lframe; + awin[(i__ << 1) - 1] = awin[(i__ + 1 << 1) - 1] - contrl_1.lframe; +/* EWIN(*,J) is unused for J .NE. AF, so the following shift is +*/ +/* unnecessary. It also causes error messages when the C versio +n */ +/* of the code created from this by f2c is run with Purify. It +*/ +/* correctly complains that uninitialized memory is being read. +*/ +/* EWIN(1,I) = EWIN(1,I+1) - LFRAME */ +/* EWIN(2,I) = EWIN(2,I+1) - LFRAME */ + obound[i__ - 1] = obound[i__]; + voibuf[i__ * 2] = voibuf[(i__ + 1) * 2]; + voibuf[(i__ << 1) + 1] = voibuf[(i__ + 1 << 1) + 1]; + rmsbuf[i__ - 1] = rmsbuf[i__]; + i__1 = contrl_1.order; + for (j = 1; j <= i__1; ++j) { + rcbuf[j + i__ * 10 - 11] = rcbuf[j + (i__ + 1) * 10 - 11]; + } + } +/* Copy input speech, scale to sign+12 bit integers */ +/* Remove long term DC bias. */ +/* If the average value in the frame was over 1/4096 (after current +*/ +/* BIAS correction), then subtract that much more from samples in */ +/* next frame. If the average value in the frame was under */ +/* -1/4096, add 1/4096 more to samples in next frame. In all other +*/ +/* cases, keep BIAS the same. */ + temp = 0.f; + i__1 = contrl_1.lframe; + for (i__ = 1; i__ <= i__1; ++i__) { + inbuf[720 - contrl_1.lframe + i__ - 181] = speech[i__] * 4096.f - + (*bias); + temp += inbuf[720 - contrl_1.lframe + i__ - 181]; + } + if (temp > (real) contrl_1.lframe) { + *bias += 1; + } + if (temp < (real) (-contrl_1.lframe)) { + *bias += -1; + } +/* Place Voicing Window */ + i__ = 721 - contrl_1.lframe; + preemp_(&inbuf[i__ - 181], &pebuf[i__ - 181], &contrl_1.lframe, &precoef, + zpre); + onset_(pebuf, osbuf, osptr, &c__10, &c__181, &c__720, &contrl_1.lframe, st); + +/* MAXOSP is just a debugging variable. */ + +/* MAXOSP = MAX( MAXOSP, OSPTR ) */ + + placev_(osbuf, osptr, &c__10, &obound[2], vwin, &c__3, &contrl_1.lframe, + &c__90, &c__156, &c__307, &c__462); +/* The Pitch Extraction algorithm estimates the pitch for a frame +*/ +/* of speech by locating the minimum of the average magnitude difference + */ +/* function (AMDF). The AMDF operates on low-pass, inverse filtered */ +/* speech. (The low-pass filter is an 800 Hz, 19 tap, equiripple, FIR +*/ +/* filter and the inverse filter is a 2nd-order LPC filter.) The pitch +*/ +/* estimate is later refined by dynamic programming (DYPTRK). However, +*/ +/* since some of DYPTRK's parameters are a function of the voicing */ +/* decisions, a voicing decision must precede the final pitch estimation. +*/ +/* See subroutines LPFILT, IVFILT, and TBDM. */ +/* LPFILT reads indices LBUFH-LFRAME-29 = 511 through LBUFH = 720 */ +/* of INBUF, and writes indices LBUFH+1-LFRAME = 541 through LBUFH +*/ +/* = 720 of LPBUF. */ + lpfilt_(&inbuf[228], &lpbuf[384], &c__312, &contrl_1.lframe); +/* IVFILT reads indices (PWINH-LFRAME-7) = 353 through PWINH = 540 +*/ +/* of LPBUF, and writes indices (PWINH-LFRAME+1) = 361 through */ +/* PWINH = 540 of IVBUF. */ + ivfilt_(&lpbuf[204], ivbuf, &c__312, &contrl_1.lframe, ivrc); +/* TBDM reads indices PWINL = 229 through */ +/* (PWINL-1)+MAXWIN+(TAU(LTAU)-TAU(1))/2 = 452 of IVBUF, and writes +*/ +/* indices 1 through LTAU = 60 of AMDF. */ + tbdm_(ivbuf, &c__156, tau, &c__60, amdf, &minptr, &maxptr, &mintau); +/* Voicing decisions are made for each half frame of input speech. +*/ +/* An initial voicing classification is made for each half of the */ +/* analysis frame, and the voicing decisions for the present frame */ +/* are finalized. See subroutine VOICIN. */ +/* The voicing detector (VOICIN) classifies the input signal as */ +/* unvoiced (including silence) or voiced using the AMDF windowed */ +/* maximum-to-minimum ratio, the zero crossing rate, energy measures, */ +/* reflection coefficients, and prediction gains. */ +/* The pitch and voicing rules apply smoothing and isolated */ +/* corrections to the pitch and voicing estimates and, in the process, +*/ +/* introduce two frames of delay into the corrected pitch estimates and +*/ +/* voicing decisions. */ + for (half = 1; half <= 2; ++half) { + voicin_(&vwin[4], inbuf, lpbuf, buflim, &half, &amdf[minptr - 1], & + amdf[maxptr - 1], &mintau, ivrc, obound, voibuf, &c__3, st); + } +/* Find the minimum cost pitch decision over several frames */ +/* given the current voicing decision and the AMDF array */ + dyptrk_(amdf, &c__60, &minptr, &voibuf[7], pitch, &midx, st); + ipitch = tau[midx - 1]; +/* Place spectrum analysis and energy windows */ + placea_(&ipitch, voibuf, &obound[2], &c__3, vwin, awin, ewin, & + contrl_1.lframe, &c__156); +/* Remove short term DC bias over the analysis window, Put result in ABUF +*/ + lanal = awin[5] + 1 - awin[4]; + dcbias_(&lanal, &pebuf[awin[4] - 181], abuf); +/* ABUF(1:LANAL) is now defined. It is equal to */ +/* PEBUF(AWIN(1,AF):AWIN(2,AF)) corrected for short term DC bias. */ +/* Compute RMS over integer number of pitch periods within the */ +/* analysis window. */ +/* Note that in a hardware implementation this computation may be */ +/* simplified by using diagonal elements of PHI computed by MLOAD. */ + i__1 = ewin[5] - ewin[4] + 1; + energy_(&i__1, &abuf[ewin[4] - awin[4]], &rmsbuf[2]); +/* Matrix load and invert, check RC's for stability */ + mload_(&contrl_1.order, &c__1, &lanal, abuf, phi, psi); + invert_(&contrl_1.order, phi, psi, &rcbuf[20]); + rcchk_(&contrl_1.order, &rcbuf[10], &rcbuf[20]); +/* Set return parameters */ + voice[1] = voibuf[2]; + voice[2] = voibuf[3]; + *rms = rmsbuf[0]; + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + rc[i__] = rcbuf[i__ - 1]; + } + return 0; +} /* analys_ */ diff --git a/linphone/lpc10-1.5/bitio.c b/linphone/lpc10-1.5/bitio.c new file mode 100644 index 000000000..86c38f0c9 --- /dev/null +++ b/linphone/lpc10-1.5/bitio.c @@ -0,0 +1,20 @@ +#include "lpc10_wrapper.c" +#include + + + +int main() +{ + FILE *input; + int i; + unsigned char buffer[10]; + INT32 bits[54]; + + input=fopen("/tmp/dam9.bits","r"); + if (input==NULL) printf("error opening file\n"); + fread(buffer,7,1,input); + read_bits(buffer,bits,54); + for (i=0;i<54;i++) printf("%i ",bits[i]); + fclose(input); + return(0); +} \ No newline at end of file diff --git a/linphone/lpc10-1.5/bsynz.c b/linphone/lpc10-1.5/bsynz.c new file mode 100644 index 000000000..4cec9d14e --- /dev/null +++ b/linphone/lpc10-1.5/bsynz.c @@ -0,0 +1,423 @@ +/* + +$Log: bsynz.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:18:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:58 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int bsynz_(real *coef, integer *ip, integer *iv, real *sout, real *rms, real *ratio, real *g2pass, struct lpc10_decoder_state *st); +/* comlen contrl_ 12 */ +/*:ref: random_ 4 0 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* ***************************************************************** */ + +/* BSYNZ Version 54 */ + +/* $Log: bsynz.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:18:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:58 jaf + * Initial revision + * */ +/* Revision 1.4 1996/03/27 18:11:22 jaf */ +/* Changed the range of NOISE printed out in the debugging statements, */ +/* even though they are commented out. I didn't discover this until I */ +/* tried comparing two different versions of the LPC-10 coder, each with */ +/* full tracing enabled. */ + +/* Revision 1.3 1996/03/26 19:33:23 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.2 1996/03/20 17:12:54 jaf */ +/* Added comments about which indices of array arguments are read or */ +/* written. */ + +/* Rearranged local variable declarations to indicate which need to be */ +/* saved from one invocation to the next. Added entry INITBSYNZ to */ +/* reinitialize the local state variables, if desired. */ + +/* Revision 1.1 1996/02/07 14:43:15 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Synthesize One Pitch Epoch */ + +/* Input: */ +/* COEF - Predictor coefficients */ +/* Indices 1 through ORDER read. */ +/* IP - Pitch period (number of samples to synthesize) */ +/* IV - Voicing for the current epoch */ +/* RMS - Energy for the current epoch */ +/* RATIO - Energy slope for plosives */ +/* G2PASS- Sharpening factor for 2 pass synthesis */ +/* Output: */ +/* SOUT - Synthesized speech */ +/* Indices 1 through IP written. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITBSYNZ. */ + +/* Subroutine */ int bsynz_(real *coef, integer *ip, integer *iv, + real *sout, real *rms, real *ratio, real *g2pass, + struct lpc10_decoder_state *st) +{ + /* Initialized data */ + + integer *ipo; + real *rmso; + static integer kexc[25] = { 8,-16,26,-48,86,-162,294,-502,718,-728,184, + 672,-610,-672,184,728,718,502,294,162,86,48,26,16,8 }; + real *exc; + real *exc2; + real *lpi1; + real *lpi2; + real *lpi3; + real *hpi1; + real *hpi2; + real *hpi3; + + /* System generated locals */ + integer i__1, i__2; + real r__1, r__2; + + /* Builtin functions */ + double sqrt(doublereal); + + /* Local variables */ + real gain, xssq; + integer i__, j, k; + real noise[166], pulse; + integer px; + real sscale; + extern integer random_(struct lpc10_decoder_state *); + real xy, sum, ssq; + real lpi0, hpi0; + +/* $Log: bsynz.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:18:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:58 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Arguments */ +/* $Log: bsynz.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:18:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:58 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Function return value definitions */ +/* Parameters/constants */ +/* KEXC is not a Fortran PARAMETER, but it is an array initialized +*/ +/* with a DATA statement that is never modified. */ +/* Local variables that need not be saved */ +/* NOISE is declared with range (1:MAXPIT+MAXORD), but only indices +*/ +/* ORDER+1 through ORDER+IP are ever used, and I think that IP */ +/* .LE. MAXPIT. Why not declare it to be in the range (1:MAXPIT) */ +/* and use that range? */ +/* Local state */ +/* I believe that only indices 1 through ORDER of EXC need to be */ +/* saved from one invocation to the next, but we may as well save */ +/* the whole array. */ +/* None of these local variables were given initial values in the */ +/* original code. I'm guessing that 0 is a reasonable initial */ +/* value for all of them. */ + /* Parameter adjustments */ + if (coef) { + --coef; + } + if (sout) { + --sout; + } + + /* Function Body */ + ipo = &(st->ipo); + exc = &(st->exc[0]); + exc2 = &(st->exc2[0]); + lpi1 = &(st->lpi1); + lpi2 = &(st->lpi2); + lpi3 = &(st->lpi3); + hpi1 = &(st->hpi1); + hpi2 = &(st->hpi2); + hpi3 = &(st->hpi3); + rmso = &(st->rmso_bsynz); + +/* MAXPIT+MAXORD=166 */ +/* Calculate history scale factor XY and scale filter state */ +/* Computing MIN */ + r__1 = *rmso / (*rms + 1e-6f); + xy = min(r__1,8.f); + *rmso = *rms; + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + exc2[i__ - 1] = exc2[*ipo + i__ - 1] * xy; + } + *ipo = *ip; + if (*iv == 0) { +/* Generate white noise for unvoiced */ + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + exc[contrl_1.order + i__ - 1] = (real) (random_(st) / 64); + } +/* Impulse doublet excitation for plosives */ +/* (RANDOM()+32768) is in the range 0 to 2**16-1. Therefore the + */ +/* following expression should be evaluated using integers with +at */ +/* least 32 bits (16 isn't enough), and PX should be in the rang +e */ +/* ORDER+1+0 through ORDER+1+(IP-2) .EQ. ORDER+IP-1. */ + px = (random_(st) + 32768) * (*ip - 1) / 65536 + contrl_1.order + 1; + r__1 = *ratio / 4 * 1.f; + pulse = r__1 * 342; + if (pulse > 2e3f) { + pulse = 2e3f; + } + exc[px - 1] += pulse; + exc[px] -= pulse; +/* Load voiced excitation */ + } else { + sscale = sqrt((real) (*ip)) / 6.928f; + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + exc[contrl_1.order + i__ - 1] = 0.f; + if (i__ <= 25) { + exc[contrl_1.order + i__ - 1] = sscale * kexc[i__ - 1]; + } + lpi0 = exc[contrl_1.order + i__ - 1]; + r__2 = exc[contrl_1.order + i__ - 1] * .125f + *lpi1 * .75f; + r__1 = r__2 + *lpi2 * .125f; + exc[contrl_1.order + i__ - 1] = r__1 + *lpi3 * 0.f; + *lpi3 = *lpi2; + *lpi2 = *lpi1; + *lpi1 = lpi0; + } + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + noise[contrl_1.order + i__ - 1] = random_(st) * 1.f / 64; + hpi0 = noise[contrl_1.order + i__ - 1]; + r__2 = noise[contrl_1.order + i__ - 1] * -.125f + *hpi1 * .25f; + r__1 = r__2 + *hpi2 * -.125f; + noise[contrl_1.order + i__ - 1] = r__1 + *hpi3 * 0.f; + *hpi3 = *hpi2; + *hpi2 = *hpi1; + *hpi1 = hpi0; + } + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + exc[contrl_1.order + i__ - 1] += noise[contrl_1.order + i__ - 1]; + } + } +/* Synthesis filters: */ +/* Modify the excitation with all-zero filter 1 + G*SUM */ + xssq = 0.f; + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + k = contrl_1.order + i__; + sum = 0.f; + i__2 = contrl_1.order; + for (j = 1; j <= i__2; ++j) { + sum += coef[j] * exc[k - j - 1]; + } + sum *= *g2pass; + exc2[k - 1] = sum + exc[k - 1]; + } +/* Synthesize using the all pole filter 1 / (1 - SUM) */ + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + k = contrl_1.order + i__; + sum = 0.f; + i__2 = contrl_1.order; + for (j = 1; j <= i__2; ++j) { + sum += coef[j] * exc2[k - j - 1]; + } + exc2[k - 1] = sum + exc2[k - 1]; + xssq += exc2[k - 1] * exc2[k - 1]; + } +/* Save filter history for next epoch */ + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + exc[i__ - 1] = exc[*ip + i__ - 1]; + exc2[i__ - 1] = exc2[*ip + i__ - 1]; + } +/* Apply gain to match RMS */ + r__1 = *rms * *rms; + ssq = r__1 * *ip; + gain = sqrt(ssq / xssq); + i__1 = *ip; + for (i__ = 1; i__ <= i__1; ++i__) { + sout[i__] = gain * exc2[contrl_1.order + i__ - 1]; + } + return 0; +} /* bsynz_ */ diff --git a/linphone/lpc10-1.5/chanwr.c b/linphone/lpc10-1.5/chanwr.c new file mode 100644 index 000000000..7a2712ec3 --- /dev/null +++ b/linphone/lpc10-1.5/chanwr.c @@ -0,0 +1,225 @@ +/* + +$Log: chanwr.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:20:24 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Revision 1.1 1996/08/19 22:40:31 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int chanwr_(integer *order, integer *ipitv, integer *irms, integer *irc, integer *ibits, struct lpc10_encoder_state *st); +extern int chanrd_(integer *order, integer *ipitv, integer *irms, integer *irc, integer *ibits); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* *********************************************************************** */ + +/* CHANL Version 49 */ + +/* $Log: chanwr.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:20:24 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Revision 1.1 1996/08/19 22:40:31 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/21 15:14:57 jaf */ +/* Added comments about which indices of argument arrays are read or */ +/* written, and about the one bit of local state in CHANWR. CHANRD */ +/* has no local state. */ + +/* Revision 1.2 1996/03/13 18:55:10 jaf */ +/* Comments added explaining which of the local variables of this */ +/* subroutine need to be saved from one invocation to the next, and which */ +/* do not. */ + +/* Revision 1.1 1996/02/07 14:43:31 jaf */ +/* Initial revision */ + + +/* *********************************************************************** */ + +/* CHANWR: */ +/* Place quantized parameters into bitstream */ + +/* Input: */ +/* ORDER - Number of reflection coefficients (not really variable) */ +/* IPITV - Quantized pitch/voicing parameter */ +/* IRMS - Quantized energy parameter */ +/* IRC - Quantized reflection coefficients */ +/* Indices 1 through ORDER read. */ +/* Output: */ +/* IBITS - Serial bitstream */ +/* Indices 1 through 54 written. */ +/* Bit 54, the SYNC bit, alternates from one call to the next. */ + +/* Subroutine CHANWR maintains one bit of local state from one call to */ +/* the next, in the variable ISYNC. I believe that this one bit is only */ +/* intended to allow a receiver to resynchronize its interpretation of */ +/* the bit stream, by looking for which of the 54 bits alternates every */ +/* frame time. This is just a simple framing mechanism that is not */ +/* useful when other, higher overhead framing mechanisms are used to */ +/* transmit the coded frames. */ + +/* I'm not going to make an entry to reinitialize this bit, since it */ +/* doesn't help a receiver much to know whether the first sync bit is a 0 */ +/* or a 1. It needs to examine several frames in sequence to have */ +/* reasonably good assurance that its framing is correct. */ + + +/* CHANRD: */ +/* Reconstruct parameters from bitstream */ + +/* Input: */ +/* ORDER - Number of reflection coefficients (not really variable) */ +/* IBITS - Serial bitstream */ +/* Indices 1 through 53 read (SYNC bit is ignored). */ +/* Output: */ +/* IPITV - Quantized pitch/voicing parameter */ +/* IRMS - Quantized energy parameter */ +/* IRC - Quantized reflection coefficients */ +/* Indices 1 through ORDER written */ + +/* Entry CHANRD has no local state. */ + + + +/* IBITS is 54 bits of LPC data ordered as follows: */ +/* R1-0, R2-0, R3-0, P-0, A-0, */ +/* R1-1, R2-1, R3-1, P-1, A-1, */ +/* R1-2, R4-0, R3-2, A-2, P-2, R4-1, */ +/* R1-3, R2-2, R3-3, R4-2, A-3, */ +/* R1-4, R2-3, R3-4, R4-3, A-4, */ +/* P-3, R2-4, R7-0, R8-0, P-4, R4-4, */ +/* R5-0, R6-0, R7-1,R10-0, R8-1, */ +/* R5-1, R6-1, R7-2, R9-0, P-5, */ +/* R5-2, R6-2,R10-1, R8-2, P-6, R9-1, */ +/* R5-3, R6-3, R7-3, R9-2, R8-3, SYNC */ +/* Subroutine */ int chanwr_0_(int n__, integer *order, integer *ipitv, + integer *irms, integer *irc, integer *ibits, + struct lpc10_encoder_state *st) +{ + /* Initialized data */ + + integer *isync; + static integer bit[10] = { 2,4,8,8,8,8,16,16,16,16 }; + static integer iblist[53] = { 13,12,11,1,2,13,12,11,1,2,13,10,11,2,1,10, + 13,12,11,10,2,13,12,11,10,2,1,12,7,6,1,10,9,8,7,4,6,9,8,7,5,1,9,8, + 4,6,1,5,9,8,7,5,6 }; + + /* System generated locals */ + integer i__1; + + /* Local variables */ + integer itab[13], i__; + +/* Arguments */ +/* Parameters/constants */ +/* These arrays are not Fortran PARAMETER's, but they are defined */ +/* by DATA statements below, and their contents are never altered. +*/ +/* Local variables that need not be saved */ +/* Local state */ +/* ISYNC is only used by CHANWR, not by ENTRY CHANRD. */ + + /* Parameter adjustments */ + --irc; + --ibits; + + /* Function Body */ + switch(n__) { + case 1: goto L_chanrd; + } + + isync = &(st->isync); + +/* *********************************************************************** + */ +/* Place quantized parameters into bitstream */ +/* *********************************************************************** + */ +/* Place parameters into ITAB */ + itab[0] = *ipitv; + itab[1] = *irms; + itab[2] = 0; + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + itab[i__ + 2] = irc[*order + 1 - i__] & 32767; + } +/* Put 54 bits into IBITS array */ + for (i__ = 1; i__ <= 53; ++i__) { + ibits[i__] = itab[iblist[i__ - 1] - 1] & 1; + itab[iblist[i__ - 1] - 1] /= 2; + } + ibits[54] = *isync & 1; + *isync = 1 - *isync; + return 0; +/* *********************************************************************** + */ +/* Reconstruct parameters from bitstream */ +/* *********************************************************************** + */ + +L_chanrd: +/* Reconstruct ITAB */ + for (i__ = 1; i__ <= 13; ++i__) { + itab[i__ - 1] = 0; + } + for (i__ = 1; i__ <= 53; ++i__) { + itab[iblist[54 - i__ - 1] - 1] = (itab[iblist[54 - i__ - 1] - 1] << 1) + + ibits[54 - i__]; + } +/* Sign extend RC's */ + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((itab[i__ + 2] & bit[i__ - 1]) != 0) { + itab[i__ + 2] -= bit[i__ - 1] << 1; + } + } +/* Restore variables */ + *ipitv = itab[0]; + *irms = itab[1]; + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + irc[i__] = itab[*order + 4 - i__ - 1]; + } + return 0; +} /* chanwr_ */ + +/* Subroutine */ int chanwr_(integer *order, integer *ipitv, integer *irms, + integer *irc, integer *ibits, struct lpc10_encoder_state *st) +{ + return chanwr_0_(0, order, ipitv, irms, irc, ibits, st); + } + +/* Subroutine */ int chanrd_(integer *order, integer *ipitv, integer *irms, + integer *irc, integer *ibits) +{ + return chanwr_0_(1, order, ipitv, irms, irc, ibits, 0); + } diff --git a/linphone/lpc10-1.5/dcbias.c b/linphone/lpc10-1.5/dcbias.c new file mode 100644 index 000000000..60d41e9ae --- /dev/null +++ b/linphone/lpc10-1.5/dcbias.c @@ -0,0 +1,95 @@ +/* + +$Log: dcbias.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:40:23 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int dcbias_(integer *len, real *speech, real *sigout); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************* */ + +/* DCBIAS Version 50 */ + +/* $Log: dcbias.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:40:23 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/18 21:19:22 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 16:44:53 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:44:21 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Calculate and remove DC bias from buffer. */ + +/* Input: */ +/* LEN - Length of speech buffers */ +/* SPEECH - Input speech buffer */ +/* Indices 1 through LEN read. */ +/* Output: */ +/* SIGOUT - Output speech buffer */ +/* Indices 1 through LEN written */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int dcbias_(integer *len, real *speech, real *sigout) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + real bias; + integer i__; + +/* Arguments */ +/* Local variables that need not be saved */ + /* Parameter adjustments */ + --sigout; + --speech; + + /* Function Body */ + bias = 0.f; + i__1 = *len; + for (i__ = 1; i__ <= i__1; ++i__) { + bias += speech[i__]; + } + bias /= *len; + i__1 = *len; + for (i__ = 1; i__ <= i__1; ++i__) { + sigout[i__] = speech[i__] - bias; + } + return 0; +} /* dcbias_ */ + diff --git a/linphone/lpc10-1.5/decode.c b/linphone/lpc10-1.5/decode.c new file mode 100644 index 000000000..8e2abb325 --- /dev/null +++ b/linphone/lpc10-1.5/decode.c @@ -0,0 +1,589 @@ +/* + +$Log: decode.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:22:39 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:38 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int decode_(integer *ipitv, integer *irms, integer *irc, integer *voice, integer *pitch, real *rms, real *rc, struct lpc10_decoder_state *st); +/* comlen contrl_ 12 */ +/*:ref: ham84_ 14 3 4 4 4 */ +/*:ref: median_ 4 3 4 4 4 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* Table of constant values */ + +static integer c__2 = 2; + +/* ***************************************************************** */ + +/* DECODE Version 54 */ + +/* $Log: decode.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:22:39 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:38 jaf + * Initial revision + * */ +/* Revision 1.5 1996/05/23 20:06:03 jaf */ +/* Assigned PITCH a "default" value on the first call, since otherwise it */ +/* would be left uninitialized. */ + +/* Revision 1.4 1996/03/26 19:35:18 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.3 1996/03/21 21:10:50 jaf */ +/* Added entry INITDECODE to reinitialize the local state of subroutine */ +/* DECODE. */ + +/* Revision 1.2 1996/03/21 21:04:50 jaf */ +/* Determined which local variables should be saved from one invocation */ +/* to the next, and guessed initial values for some that should have been */ +/* saved, but weren't given initial values. Many of the arrays are */ +/* "constants", and many local variables are only used if the "global" */ +/* variable CORRP is .TRUE. */ + +/* Added comments explaining which indices of array arguments are read or */ +/* written. */ + +/* Revision 1.1 1996/02/12 03:21:10 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* This subroutine provides error correction and decoding */ +/* for all LPC parameters */ + +/* Input: */ +/* IPITV - Index value of pitch */ +/* IRMS - Coded Energy */ +/* CORRP - Error correction: */ +/* If FALSE, parameters are decoded directly with no delay. If TRUE, */ +/* most important parameter bits are protected by Hamming code and */ +/* median smoothed. This requires an additional frame of delay. */ +/* Input/Output: */ +/* IRC - Coded Reflection Coefficients */ +/* Indices 1 through ORDER always read, then written. */ +/* Output: */ +/* VOICE - Half frame voicing decisions */ +/* Indices 1 through 2 written. */ +/* PITCH - Decoded pitch */ +/* RMS - Energy */ +/* RC - Reflection coefficients */ +/* Indices 1 through ORDER written. */ + +/* NOTE: Zero RC's should be done more directly, but this would affect */ +/* coded parameter printout. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITDECODE. */ + +/* Subroutine */ int decode_(integer *ipitv, integer *irms, + integer *irc, integer *voice, integer *pitch, real *rms, real *rc, + struct lpc10_decoder_state *st) +{ + /* Initialized data */ + + logical *first; + static integer ethrs = 2048; + static integer ethrs1 = 128; + static integer ethrs2 = 1024; + static integer ethrs3 = 2048; + static integer ivtab[32] = { 24960,24960,24960,24960,25480,25480,25483, + 25480,16640,1560,1560,1560,16640,1816,1563,1560,24960,24960,24859, + 24856,26001,25881,25915,25913,1560,1560,7800,3640,1561,1561,3643, + 3641 }; + static real corth[32] /* was [4][8] */ = { 32767.f,10.f,5.f,0.f, + 32767.f,8.f,4.f,0.f,32.f,6.4f,3.2f,0.f,32.f,6.4f,3.2f,0.f,32.f, + 11.2f,6.4f,0.f,32.f,11.2f,6.4f,0.f,16.f,5.6f,3.2f,0.f,16.f,5.6f, + 3.2f,0.f }; + static integer detau[128] = { 0,0,0,3,0,3,3,31,0,3,3,21,3,3,29,30,0,3,3, + 20,3,25,27,26,3,23,58,22,3,24,28,3,0,3,3,3,3,39,33,32,3,37,35,36, + 3,38,34,3,3,42,46,44,50,40,48,3,54,3,56,3,52,3,3,1,0,3,3,108,3,78, + 100,104,3,84,92,88,156,80,96,3,3,74,70,72,66,76,68,3,62,3,60,3,64, + 3,3,1,3,116,132,112,148,152,3,3,140,3,136,3,144,3,3,1,124,120,128, + 3,3,3,3,1,3,3,3,1,3,1,1,1 }; + static integer rmst[64] = { 1024,936,856,784,718,656,600,550,502,460,420, + 384,352,328,294,270,246,226,206,188,172,158,144,132,120,110,102, + 92,84,78,70,64,60,54,50,46,42,38,34,32,30,26,24,22,20,18,17,16,15, + 14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 }; + static integer detab7[32] = { 4,11,18,25,32,39,46,53,60,66,72,77,82,87,92, + 96,101,104,108,111,114,115,117,119,121,122,123,124,125,126,127, + 127 }; + static real descl[8] = { .6953f,.625f,.5781f,.5469f,.5312f,.5391f,.4688f, + .3828f }; + integer *ivp2h; + static integer deadd[8] = { 1152,-2816,-1536,-3584,-1280,-2432,768,-1920 } + ; + static integer qb[8] = { 511,511,1023,1023,1023,1023,2047,4095 }; + static integer nbit[10] = { 8,8,5,5,4,4,4,4,3,2 }; + static integer zrc[10] = { 0,0,0,0,0,3,0,2,0,0 }; + static integer bit[5] = { 2,4,8,16,32 }; + integer *iovoic; + integer *iavgp; + integer *iptold; + integer *erate; + integer *drc; + integer *dpit; + integer *drms; + + /* System generated locals */ + integer i__1, i__2; + + /* Builtin functions */ + integer pow_ii(integer *, integer *); + + /* Local variables */ + extern /* Subroutine */ int ham84_(integer *, integer *, integer *); + integer ipit, iout, i__, icorf, index, ivoic, ixcor, i1, i2, i4; + extern integer median_(integer *, integer *, integer *); + integer ishift, errcnt, lsb; + +/* $Log: decode.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:22:39 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:38 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Arguments */ +/* $Log: decode.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:22:39 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:38 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Function return value definitions */ + +/* Parameters/constants */ + +/* The variables below that are not Fortran PARAMETER's are */ +/* initialized with DATA statements, and then never modified. */ +/* The following are used regardless of CORRP's value. */ + +/* DETAU, NBIT, QB, DEADD, DETAB7, RMST, DESCL */ + +/* The following are used only if CORRP is .TRUE. */ + +/* ETHRS, ETHRS1, ETHRS2, ETHRS3, IVTAB, BIT, CORTH, ZRC */ + +/* Local variables that need not be saved */ + +/* The following are used regardless of CORRP's value */ +/* The following are used only if CORRP is .TRUE. */ + +/* Local state */ + +/* The following are used regardless of CORRP's value */ +/* The following are used only if CORRP is .TRUE. */ +/* I am guessing the initial values for IVP2H, IOVOIC, DRC, DPIT, */ +/* and DRMS. They should be checked to see if they are reasonable. +*/ +/* I'm also guessing for ERATE, but I think 0 is the right initial +*/ +/* value. */ + /* Parameter adjustments */ + if (irc) { + --irc; + } + if (voice) { + --voice; + } + if (rc) { + --rc; + } + + /* Function Body */ + + iptold = &(st->iptold); + first = &(st->first); + ivp2h = &(st->ivp2h); + iovoic = &(st->iovoic); + iavgp = &(st->iavgp); + erate = &(st->erate); + drc = &(st->drc[0]); + dpit = &(st->dpit[0]); + drms = &(st->drms[0]); + +/* DATA statements for "constants" defined above. */ +/* IF (LISTL.GE.3) WRITE(FDEBUG,800) IPITV,IRMS,(IRC(J),J=1,ORDER) */ +/* 800 FORMAT(1X,' <>',T32,6X,I6,I5,T50,10I8) */ +/* If no error correction, do pitch and voicing then jump to decode */ + i4 = detau[*ipitv]; + if (! contrl_1.corrp) { + voice[1] = 1; + voice[2] = 1; + if (*ipitv <= 1) { + voice[1] = 0; + } + if (*ipitv == 0 || *ipitv == 2) { + voice[2] = 0; + } + *pitch = i4; + if (*pitch <= 4) { + *pitch = *iptold; + } + if (voice[1] == 1 && voice[2] == 1) { + *iptold = *pitch; + } + if (voice[1] != voice[2]) { + *pitch = *iptold; + } + goto L900; + } +/* Do error correction pitch and voicing */ + if (i4 > 4) { + dpit[0] = i4; + ivoic = 2; + *iavgp = (*iavgp * 15 + i4 + 8) / 16; + } else { + ivoic = i4; + dpit[0] = *iavgp; + } + drms[0] = *irms; + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + drc[i__ * 3 - 3] = irc[i__]; + } +/* Determine index to IVTAB from V/UV decision */ +/* If error rate is high then use alternate table */ + index = (*ivp2h << 4) + (*iovoic << 2) + ivoic + 1; + i1 = ivtab[index - 1]; + ipit = i1 & 3; + icorf = i1 / 8; + if (*erate < ethrs) { + icorf /= 64; + } +/* Determine error rate: 4=high 1=low */ + ixcor = 4; + if (*erate < ethrs3) { + ixcor = 3; + } + if (*erate < ethrs2) { + ixcor = 2; + } + if (*erate < ethrs1) { + ixcor = 1; + } +/* Voice/unvoice decision determined from bits 0 and 1 of IVTAB */ + voice[1] = icorf / 2 & 1; + voice[2] = icorf & 1; +/* Skip decoding on first frame because present data not yet available */ + if (*first) { + *first = FALSE_; +/* Assign PITCH a "default" value on the first call, since */ +/* otherwise it would be left uninitialized. The two lines +*/ +/* below were copied from above, since it seemed like a */ +/* reasonable thing to do for the first call. */ + *pitch = i4; + if (*pitch <= 4) { + *pitch = *iptold; + } + goto L500; + } +/* If bit 4 of ICORF is set then correct RMS and RC(1) - RC(4). */ +/* Determine error rate and correct errors using a Hamming 8,4 code */ +/* during transition or unvoiced frame. If IOUT is negative, */ +/* more than 1 error occurred, use previous frame's parameters. */ + if ((icorf & bit[3]) != 0) { + errcnt = 0; + lsb = drms[1] & 1; + index = (drc[22] << 4) + drms[1] / 2; + ham84_(&index, &iout, &errcnt); + drms[1] = drms[2]; + if (iout >= 0) { + drms[1] = (iout << 1) + lsb; + } + for (i__ = 1; i__ <= 4; ++i__) { + if (i__ == 1) { + i1 = ((drc[25] & 7) << 1) + (drc[28] & 1); + } else { + i1 = drc[(9 - i__) * 3 - 2] & 15; + } + i2 = drc[(5 - i__) * 3 - 2] & 31; + lsb = i2 & 1; + index = (i1 << 4) + i2 / 2; + ham84_(&index, &iout, &errcnt); + if (iout >= 0) { + iout = (iout << 1) + lsb; + if ((iout & 16) == 16) { + iout += -32; + } + } else { + iout = drc[(5 - i__) * 3 - 1]; + } + drc[(5 - i__) * 3 - 2] = iout; + } +/* Determine error rate */ + *erate = *erate * .96875f + errcnt * 102; + } +/* Get unsmoothed RMS, RC's, and PITCH */ + *irms = drms[1]; + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + irc[i__] = drc[i__ * 3 - 2]; + } + if (ipit == 1) { + dpit[1] = dpit[2]; + } + if (ipit == 3) { + dpit[1] = dpit[0]; + } + *pitch = dpit[1]; +/* If bit 2 of ICORF is set then smooth RMS and RC's, */ + if ((icorf & bit[1]) != 0) { + if ((i__1 = drms[1] - drms[0], (real) abs(i__1)) >= corth[ixcor + 3] + && (i__2 = drms[1] - drms[2], (real) abs(i__2)) >= corth[ + ixcor + 3]) { + *irms = median_(&drms[2], &drms[1], drms); + } + for (i__ = 1; i__ <= 6; ++i__) { + if ((i__1 = drc[i__ * 3 - 2] - drc[i__ * 3 - 3], (real) abs(i__1)) + >= corth[ixcor + (i__ + 2 << 2) - 5] && (i__2 = drc[i__ * + 3 - 2] - drc[i__ * 3 - 1], (real) abs(i__2)) >= corth[ + ixcor + (i__ + 2 << 2) - 5]) { + irc[i__] = median_(&drc[i__ * 3 - 1], &drc[i__ * 3 - 2], &drc[ + i__ * 3 - 3]); + } + } + } +/* If bit 3 of ICORF is set then smooth pitch */ + if ((icorf & bit[2]) != 0) { + if ((i__1 = dpit[1] - dpit[0], (real) abs(i__1)) >= corth[ixcor - 1] + && (i__2 = dpit[1] - dpit[2], (real) abs(i__2)) >= corth[ + ixcor - 1]) { + *pitch = median_(&dpit[2], &dpit[1], dpit); + } + } +/* If bit 5 of ICORF is set then RC(5) - RC(10) are loaded with */ +/* values so that after quantization bias is removed in decode */ +/* the values will be zero. */ +L500: + if ((icorf & bit[4]) != 0) { + i__1 = contrl_1.order; + for (i__ = 5; i__ <= i__1; ++i__) { + irc[i__] = zrc[i__ - 1]; + } + } +/* House keeping - one frame delay */ + *iovoic = ivoic; + *ivp2h = voice[2]; + dpit[2] = dpit[1]; + dpit[1] = dpit[0]; + drms[2] = drms[1]; + drms[1] = drms[0]; + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + drc[i__ * 3 - 1] = drc[i__ * 3 - 2]; + drc[i__ * 3 - 2] = drc[i__ * 3 - 3]; + } +L900: +/* IF (LISTL.GE.3)WRITE(FDEBUG,801)VOICE,PITCH,IRMS,(IRC(J),J=1,ORDER) */ +/* 801 FORMAT(1X,'<>',T32,2I3,I6,I5,T50,10I8) */ +/* Decode RMS */ + *irms = rmst[(31 - *irms) * 2]; +/* Decode RC(1) and RC(2) from log-area-ratios */ +/* Protect from illegal coded value (-16) caused by bit errors */ + for (i__ = 1; i__ <= 2; ++i__) { + i2 = irc[i__]; + i1 = 0; + if (i2 < 0) { + i1 = 1; + i2 = -i2; + if (i2 > 15) { + i2 = 0; + } + } + i2 = detab7[i2 * 2]; + if (i1 == 1) { + i2 = -i2; + } + ishift = 15 - nbit[i__ - 1]; + irc[i__] = i2 * pow_ii(&c__2, &ishift); + } +/* Decode RC(3)-RC(10) to sign plus 14 bits */ + i__1 = contrl_1.order; + for (i__ = 3; i__ <= i__1; ++i__) { + i2 = irc[i__]; + ishift = 15 - nbit[i__ - 1]; + i2 *= pow_ii(&c__2, &ishift); + i2 += qb[i__ - 3]; + irc[i__] = i2 * descl[i__ - 3] + deadd[i__ - 3]; + } +/* IF (LISTL.GE.3) WRITE(FDEBUG,811) IRMS, (IRC(I),I=1,ORDER) */ +/* 811 FORMAT(1X,'<>',T45,I4,1X,10I8) */ +/* Scale RMS and RC's to reals */ + *rms = (real) (*irms); + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + rc[i__] = irc[i__] / 16384.f; + } + return 0; +} /* decode_ */ diff --git a/linphone/lpc10-1.5/deemp.c b/linphone/lpc10-1.5/deemp.c new file mode 100644 index 000000000..6f5f0f3a9 --- /dev/null +++ b/linphone/lpc10-1.5/deemp.c @@ -0,0 +1,142 @@ +/* + +$Log: deemp.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:23:46 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:34 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int deemp_(real *x, integer *n, struct lpc10_decoder_state *st); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ***************************************************************** */ + +/* DEEMP Version 48 */ + +/* $Log: deemp.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:23:46 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:32:34 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/20 15:54:37 jaf */ +/* Added comments about which indices of array arguments are read or */ +/* written. */ + +/* Added entry INITDEEMP to reinitialize the local state variables, if */ +/* desired. */ + +/* Revision 1.2 1996/03/14 22:11:13 jaf */ +/* Comments added explaining which of the local variables of this */ +/* subroutine need to be saved from one invocation to the next, and which */ +/* do not. */ + +/* Revision 1.1 1996/02/07 14:44:53 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* De-Emphasize output speech with 1 / ( 1 - .75z**-1 ) */ +/* cascaded with 200 Hz high pass filter */ +/* ( 1 - 1.9998z**-1 + z**-2 ) / ( 1 - 1.75z**-1 + .78z**-2 ) */ + +/* WARNING! The coefficients above may be out of date with the code */ +/* below. Either that, or some kind of transformation was performed */ +/* on the coefficients above to create the code below. */ + +/* Input: */ +/* N - Number of samples */ +/* Input/Output: */ +/* X - Speech */ +/* Indices 1 through N are read before being written. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITDEEMP. */ + +/* Subroutine */ int deemp_(real *x, integer *n, struct lpc10_decoder_state *st) +{ + /* Initialized data */ + + real *dei1; + real *dei2; + real *deo1; + real *deo2; + real *deo3; + + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + integer k; + real dei0; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Local state */ +/* All of the locals saved below were not given explicit initial */ +/* values in the original code. I think 0 is a safe choice. */ + /* Parameter adjustments */ + if (x) { + --x; + } + + /* Function Body */ + + dei1 = &(st->dei1); + dei2 = &(st->dei2); + deo1 = &(st->deo1); + deo2 = &(st->deo2); + deo3 = &(st->deo3); + + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + dei0 = x[k]; + r__1 = x[k] - *dei1 * 1.9998f + *dei2; + x[k] = r__1 + *deo1 * 2.5f - *deo2 * 2.0925f + *deo3 * .585f; + *dei2 = *dei1; + *dei1 = dei0; + *deo3 = *deo2; + *deo2 = *deo1; + *deo1 = x[k]; + } + return 0; +} /* deemp_ */ diff --git a/linphone/lpc10-1.5/difmag.c b/linphone/lpc10-1.5/difmag.c new file mode 100644 index 000000000..7a3589872 --- /dev/null +++ b/linphone/lpc10-1.5/difmag.c @@ -0,0 +1,121 @@ +/* + +$Log: difmag.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:32:31 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int difmag_(real *speech, integer *lpita, integer *tau, integer *ltau, integer *maxlag, real *amdf, integer *minptr, integer *maxptr); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************** */ + +/* DIFMAG Version 49 */ + +/* $Log: difmag.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:14 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:31 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/15 23:09:39 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 14:41:31 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:45:04 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Compute Average Magnitude Difference Function */ + +/* Inputs: */ +/* SPEECH - Low pass filtered speech */ +/* Indices MIN_N1 through MAX_N1+LPITA-1 are read, where */ +/* MIN_N1 = (MAXLAG - MAX_TAU)/2+1 MAX_TAU = max of TAU(I) for I=1,LTAU +*/ +/* MAX_N1 = (MAXLAG - MIN_TAU)/2+1 MIN_TAU = min of TAU(I) for I=1,LTAU +*/ +/* LPITA - Length of speech buffer */ +/* TAU - Table of lags */ +/* Indices 1 through LTAU read. */ +/* LTAU - Number of lag values to compute */ +/* MAXLAG - Maximum possible lag value */ +/* Outputs: */ +/* (All of these outputs are also read, but only after being written.) */ +/* AMDF - Average Magnitude Difference for each lag in TAU */ +/* Indices 1 through LTAU written */ +/* MINPTR - Index of minimum AMDF value */ +/* MAXPTR - Index of maximum AMDF value */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int difmag_(real *speech, integer *lpita, integer *tau, + integer *ltau, integer *maxlag, real *amdf, integer *minptr, integer * + maxptr) +{ + /* System generated locals */ + integer i__1, i__2; + real r__1; + + /* Local variables */ + integer i__, j, n1, n2; + real sum; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Local state */ +/* None */ + /* Parameter adjustments */ + --amdf; + --tau; + --speech; + + /* Function Body */ + *minptr = 1; + *maxptr = 1; + i__1 = *ltau; + for (i__ = 1; i__ <= i__1; ++i__) { + n1 = (*maxlag - tau[i__]) / 2 + 1; + n2 = n1 + *lpita - 1; + sum = 0.f; + i__2 = n2; + for (j = n1; j <= i__2; j += 4) { + sum += (r__1 = speech[j] - speech[j + tau[i__]], abs(r__1)); + } + amdf[i__] = sum; + if (amdf[i__] < amdf[*minptr]) { + *minptr = i__; + } + if (amdf[i__] > amdf[*maxptr]) { + *maxptr = i__; + } + } + return 0; +} /* difmag_ */ + diff --git a/linphone/lpc10-1.5/dyptrk.c b/linphone/lpc10-1.5/dyptrk.c new file mode 100644 index 000000000..168d2c3a6 --- /dev/null +++ b/linphone/lpc10-1.5/dyptrk.c @@ -0,0 +1,387 @@ +/* + +$Log: dyptrk.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:25:29 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:32:26 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int dyptrk_(real *amdf, integer *ltau, integer *minptr, integer *voice, integer *pitch, integer *midx, struct lpc10_encoder_state *st); +/* comlen contrl_ 12 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* ********************************************************************* */ + +/* DYPTRK Version 52 */ + +/* $Log: dyptrk.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:25:29 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:32:26 jaf + * Initial revision + * */ +/* Revision 1.5 1996/03/26 19:35:35 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.4 1996/03/19 18:03:22 jaf */ +/* Replaced the initialization "DATA P/60*DEPTH*0/" with "DATA P/120*0/", */ +/* because apparently Fortran (or at least f2c) can't handle expressions */ +/* like that. */ + +/* Revision 1.3 1996/03/19 17:38:32 jaf */ +/* Added comments about the local variables that should be saved from one */ +/* invocation to the next. None of them were given initial values in the */ +/* original code, but from my testing, it appears that initializing them */ +/* all to 0 works. */ + +/* Added entry INITDYPTRK to reinitialize these local variables. */ + +/* Revision 1.2 1996/03/13 16:32:17 jaf */ +/* Comments added explaining which of the local variables of this */ +/* subroutine need to be saved from one invocation to the next, and which */ +/* do not. */ + +/* WARNING! Some of them that should are never given initial values in */ +/* this code. Hopefully, Fortran 77 defines initial values for them, but */ +/* even so, giving them explicit initial values is preferable. */ + +/* Revision 1.1 1996/02/07 14:45:14 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Dynamic Pitch Tracker */ + +/* Input: */ +/* AMDF - Average Magnitude Difference Function array */ +/* Indices 1 through LTAU read, and MINPTR */ +/* LTAU - Number of lags in AMDF */ +/* MINPTR - Location of minimum AMDF value */ +/* VOICE - Voicing decision */ +/* Output: */ +/* PITCH - Smoothed pitch value, 2 frames delayed */ +/* MIDX - Initial estimate of current frame pitch */ +/* Compile time constant: */ +/* DEPTH - Number of frames to trace back */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITDYPTRK. */ + +/* Subroutine */ int dyptrk_(real *amdf, integer *ltau, integer * + minptr, integer *voice, integer *pitch, integer *midx, + struct lpc10_encoder_state *st) +{ + /* Initialized data */ + + real *s; + integer *p; + integer *ipoint; + real *alphax; + + /* System generated locals */ + integer i__1; + + /* Local variables */ + integer pbar; + real sbar; + integer path[2], iptr, i__, j; + real alpha, minsc, maxsc; + +/* Arguments */ +/* $Log: dyptrk.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:25:29 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:32:26 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Parameters/constants */ +/* Local variables that need not be saved */ +/* Note that PATH is only used for debugging purposes, and can be */ +/* removed. */ +/* Local state */ +/* It would be a bit more "general" to define S(LTAU), if Fortran */ +/* allows the argument of a function to be used as the dimension of +*/ +/* a local array variable. */ +/* IPOINT is always in the range 0 to DEPTH-1. */ +/* WARNING! */ + +/* In the original version of this subroutine, IPOINT, ALPHAX, */ +/* every element of S, and potentially any element of P with the */ +/* second index value .NE. IPTR were read without being given */ +/* initial values (all indices of P with second index equal to */ +/* IPTR are all written before being read in this subroutine). */ + +/* From examining the code carefully, it appears that all of these +*/ +/* should be saved from one invocation to the next. */ + +/* I've run lpcsim with the "-l 6" option to see all of the */ +/* debugging information that is printed out by this subroutine */ +/* below, and it appears that S, P, IPOINT, and ALPHAX are all */ +/* initialized to 0 (these initial values would likely be different +*/ +/* on different platforms, compilers, etc.). Given that the output +*/ +/* of the coder sounds reasonable, I'm going to initialize these */ +/* variables to 0 explicitly. */ + + s = &(st->s[0]); + p = &(st->p[0]); + ipoint = &(st->ipoint); + alphax = &(st->alphax); + + + /* Parameter adjustments */ + if (amdf) { + --amdf; + } + + /* Function Body */ + +/* Calculate the confidence factor ALPHA, used as a threshold slope in +*/ +/* SEESAW. If unvoiced, set high slope so that every point in P array +*/ +/* is marked as a potential pitch frequency. A scaled up version (ALPHAX +)*/ +/* is used to maintain arithmetic precision. */ + if (*voice == 1) { + *alphax = *alphax * .75f + amdf[*minptr] / 2.f; + } else { + *alphax *= .984375f; + } + alpha = *alphax / 16; + if (*voice == 0 && *alphax < 128.f) { + alpha = 8.f; + } +/* SEESAW: Construct a pitch pointer array and intermediate winner functio +n*/ +/* Left to right pass: */ + iptr = *ipoint + 1; + p[iptr * 60 - 60] = 1; + i__ = 1; + pbar = 1; + sbar = s[0]; + i__1 = *ltau; + for (i__ = 1; i__ <= i__1; ++i__) { + sbar += alpha; + if (sbar < s[i__ - 1]) { + s[i__ - 1] = sbar; + p[i__ + iptr * 60 - 61] = pbar; + } else { + sbar = s[i__ - 1]; + p[i__ + iptr * 60 - 61] = i__; + pbar = i__; + } + } +/* Right to left pass: */ + i__ = pbar - 1; + sbar = s[i__]; + while(i__ >= 1) { + sbar += alpha; + if (sbar < s[i__ - 1]) { + s[i__ - 1] = sbar; + p[i__ + iptr * 60 - 61] = pbar; + } else { + pbar = p[i__ + iptr * 60 - 61]; + i__ = pbar; + sbar = s[i__ - 1]; + } + --i__; + } +/* Update S using AMDF */ +/* Find maximum, minimum, and location of minimum */ + s[0] += amdf[1] / 2; + minsc = s[0]; + maxsc = minsc; + *midx = 1; + i__1 = *ltau; + for (i__ = 2; i__ <= i__1; ++i__) { + s[i__ - 1] += amdf[i__] / 2; + if (s[i__ - 1] > maxsc) { + maxsc = s[i__ - 1]; + } + if (s[i__ - 1] < minsc) { + *midx = i__; + minsc = s[i__ - 1]; + } + } +/* Subtract MINSC from S to prevent overflow */ + i__1 = *ltau; + for (i__ = 1; i__ <= i__1; ++i__) { + s[i__ - 1] -= minsc; + } + maxsc -= minsc; +/* Use higher octave pitch if significant null there */ + j = 0; + for (i__ = 20; i__ <= 40; i__ += 10) { + if (*midx > i__) { + if (s[*midx - i__ - 1] < maxsc / 4) { + j = i__; + } + } + } + *midx -= j; +/* TRACE: look back two frames to find minimum cost pitch estimate */ + j = *ipoint; + *pitch = *midx; + for (i__ = 1; i__ <= 2; ++i__) { + j = j % 2 + 1; + *pitch = p[*pitch + j * 60 - 61]; + path[i__ - 1] = *pitch; + } + +/* The following statement subtracts one from IPOINT, mod DEPTH. I +*/ +/* think the author chose to add DEPTH-1, instead of subtracting 1, +*/ +/* because then it will work even if MOD doesn't work as desired on +*/ +/* negative arguments. */ + + *ipoint = (*ipoint + 1) % 2; + return 0; +} /* dyptrk_ */ diff --git a/linphone/lpc10-1.5/encode.c b/linphone/lpc10-1.5/encode.c new file mode 100644 index 000000000..4c0f9d330 --- /dev/null +++ b/linphone/lpc10-1.5/encode.c @@ -0,0 +1,349 @@ +/* + +$Log: encode.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:32:21 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int encode_(integer *voice, integer *pitch, real *rms, real *rc, integer *ipitch, integer *irms, integer *irc); +/* comlen contrl_ 12 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* Table of constant values */ + +static integer c__2 = 2; + +/* ***************************************************************** */ + +/* ENCODE Version 54 */ + +/* $Log: encode.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:21 jaf + * Initial revision + * */ +/* Revision 1.5 1996/03/26 19:35:50 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.4 1996/03/21 00:26:29 jaf */ +/* Added the comment that this subroutine has no local state. */ + +/* In the last check-in, I forgot to mention that I had added comments */ +/* explaining which indices of array arguments are read or written. */ + +/* Revision 1.3 1996/03/21 00:22:39 jaf */ +/* Added comments explaining that all local arrays are effectively */ +/* constants. */ + +/* Revision 1.2 1996/03/13 18:48:33 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:45:29 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Quantize LPC parameters for transmission */ + +/* INPUTS: */ +/* VOICE - Half frame voicing decisions */ +/* Indices 1 through 2 read. */ +/* PITCH - Pitch */ +/* RMS - Energy */ +/* RC - Reflection coefficients */ +/* Indices 1 through ORDER read. */ +/* CORRP - Error Correction: TRUE = yes, FALSE = none */ +/* (this is defined in file control.fh) */ +/* OUTPUTS: */ +/* IPITCH - Coded pitch and voicing */ +/* IRMS - Quantized energy */ +/* IRC - Quantized reflection coefficients */ +/* Indices 1 through MAX(ORDER,2) written. */ +/* If CORRP is .TRUE., then indices 1 through 10 written */ +/* for unvoiced frames. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int encode_(integer *voice, integer *pitch, real *rms, real * + rc, integer *ipitch, integer *irms, integer *irc) +{ + /* Initialized data */ + + static integer enctab[16] = { 0,7,11,12,13,10,6,1,14,9,5,2,3,4,8,15 }; + static integer entau[60] = { 19,11,27,25,29,21,23,22,30,14,15,7,39,38,46, + 42,43,41,45,37,53,49,51,50,54,52,60,56,58,26,90,88,92,84,86,82,83, + 81,85,69,77,73,75,74,78,70,71,67,99,97,113,112,114,98,106,104,108, + 100,101,76 }; + static integer enadd[8] = { 1920,-768,2432,1280,3584,1536,2816,-1152 }; + static real enscl[8] = { .0204f,.0167f,.0145f,.0147f,.0143f,.0135f,.0125f, + .0112f }; + static integer enbits[8] = { 6,5,4,4,4,4,3,3 }; + static integer entab6[64] = { 0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3, + 3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,9,9, + 9,10,10,11,11,12,13,14,15 }; + static integer rmst[64] = { 1024,936,856,784,718,656,600,550,502,460,420, + 384,352,328,294,270,246,226,206,188,172,158,144,132,120,110,102, + 92,84,78,70,64,60,54,50,46,42,38,34,32,30,26,24,22,20,18,17,16,15, + 14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 }; + + /* System generated locals */ + integer i__1, i__2; + + /* Builtin functions */ + integer pow_ii(integer *, integer *); + + /* Local variables */ + integer idel, nbit, i__, j, i2, i3, mrk; + +/* $Log: encode.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:21 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Arguments */ +/* $Log: encode.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:21 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Parameters/constants */ +/* These arrays are not Fortran PARAMETER's, but they are defined */ +/* by DATA statements below, and their contents are never altered. +*/ +/* Local variables that need not be saved */ + /* Parameter adjustments */ + --irc; + --rc; + --voice; + + /* Function Body */ +/* Scale RMS and RC's to integers */ + *irms = *rms; + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { + irc[i__] = rc[i__] * 32768.f; + } +/* IF(LISTL.GE.3)WRITE(FDEBUG,800)VOICE,PITCH,IRMS,(IRC(I),I=1,ORDER) */ +/* 800 FORMAT(1X,/,' <>',T32,2I3,I6,I5,T50,10I8) */ +/* Encode pitch and voicing */ + if (voice[1] != 0 && voice[2] != 0) { + *ipitch = entau[*pitch - 1]; + } else { + if (contrl_1.corrp) { + *ipitch = 0; + if (voice[1] != voice[2]) { + *ipitch = 127; + } + } else { + *ipitch = (voice[1] << 1) + voice[2]; + } + } +/* Encode RMS by binary table search */ + j = 32; + idel = 16; + *irms = min(*irms,1023); + while(idel > 0) { + if (*irms > rmst[j - 1]) { + j -= idel; + } + if (*irms < rmst[j - 1]) { + j += idel; + } + idel /= 2; + } + if (*irms > rmst[j - 1]) { + --j; + } + *irms = 31 - j / 2; +/* Encode RC(1) and (2) as log-area-ratios */ + for (i__ = 1; i__ <= 2; ++i__) { + i2 = irc[i__]; + mrk = 0; + if (i2 < 0) { + i2 = -i2; + mrk = 1; + } + i2 /= 512; + i2 = min(i2,63); + i2 = entab6[i2]; + if (mrk != 0) { + i2 = -i2; + } + irc[i__] = i2; + } +/* Encode RC(3) - (10) linearly, remove bias then scale */ + i__1 = contrl_1.order; + for (i__ = 3; i__ <= i__1; ++i__) { + i2 = irc[i__] / 2; + i2 = (i2 + enadd[contrl_1.order + 1 - i__ - 1]) * enscl[ + contrl_1.order + 1 - i__ - 1]; +/* Computing MIN */ + i__2 = max(i2,-127); + i2 = min(i__2,127); + nbit = enbits[contrl_1.order + 1 - i__ - 1]; + i3 = 0; + if (i2 < 0) { + i3 = -1; + } + i2 /= pow_ii(&c__2, &nbit); + if (i3 == -1) { + --i2; + } + irc[i__] = i2; + } +/* Protect the most significant bits of the most */ +/* important parameters during non-voiced frames. */ +/* RC(1) - RC(4) are protected using 20 parity bits */ +/* replacing RC(5) - RC(10). */ + if (contrl_1.corrp) { + if (*ipitch == 0 || *ipitch == 127) { + irc[5] = enctab[(irc[1] & 30) / 2]; + irc[6] = enctab[(irc[2] & 30) / 2]; + irc[7] = enctab[(irc[3] & 30) / 2]; + irc[8] = enctab[(*irms & 30) / 2]; + irc[9] = enctab[(irc[4] & 30) / 2] / 2; + irc[10] = enctab[(irc[4] & 30) / 2] & 1; + } + } +/* IF(LISTL.GE.3)WRITE(FDEBUG,801)VOICE,IPITCH,IRMS,(IRC(J),J=1,ORDER) */ +/* 801 FORMAT(1X,'<>',T32,2I3,I6,I5,T50,10I8) */ + return 0; +} /* encode_ */ + diff --git a/linphone/lpc10-1.5/energy.c b/linphone/lpc10-1.5/energy.c new file mode 100644 index 000000000..995cbac47 --- /dev/null +++ b/linphone/lpc10-1.5/energy.c @@ -0,0 +1,91 @@ +/* + +$Log: energy.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:32:17 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int energy_(integer *len, real *speech, real *rms); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************* */ + +/* ENERGY Version 50 */ + +/* $Log: energy.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:17 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/18 21:17:41 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 16:46:02 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:45:40 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Compute RMS energy. */ + +/* Input: */ +/* LEN - Length of speech buffer */ +/* SPEECH - Speech buffer */ +/* Indices 1 through LEN read. */ +/* Output: */ +/* RMS - Root Mean Square energy */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int energy_(integer *len, real *speech, real *rms) +{ + /* System generated locals */ + integer i__1; + + /* Builtin functions */ + double sqrt(doublereal); + + /* Local variables */ + integer i__; + +/* Arguments */ +/* Local variables that need not be saved */ + /* Parameter adjustments */ + --speech; + + /* Function Body */ + *rms = 0.f; + i__1 = *len; + for (i__ = 1; i__ <= i__1; ++i__) { + *rms += speech[i__] * speech[i__]; + } + *rms = sqrt(*rms / *len); + return 0; +} /* energy_ */ + diff --git a/linphone/lpc10-1.5/f2c.h b/linphone/lpc10-1.5/f2c.h new file mode 100644 index 000000000..5193e277a --- /dev/null +++ b/linphone/lpc10-1.5/f2c.h @@ -0,0 +1,260 @@ +/* + +$Log: f2c.h,v $ +Revision 1.2 2005/11/30 20:07:31 smorlat +ready for 1.2.0 ? + +Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:26:28 jaf + * Any typedef defining a type that was used in lpc10_encoder_state or + * lpc10_decoder_state struct's was commented out here and added to + * lpc10.h. + * + * Revision 1.1 1996/08/19 22:32:13 jaf + * Initial revision + * + +*/ + +/* + * f2c.h + * + * SCCS ID: @(#)f2c.h 1.2 96/05/19 + */ + +/* f2c.h -- Standard Fortran to C header file */ + +/** barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed." + + - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */ + +#ifndef F2C_INCLUDE +#define F2C_INCLUDE + +#include "lpc10.h" + +/*typedef long int integer;*/ +/*typedef INT32 integer;*/ +/*typedef short int shortint;*/ +/*typedef INT16 shortint;*/ +/*typedef float real;*/ +/* doublereal only used for function arguments to sqrt, exp, etc. */ +typedef double doublereal; +/* 32 bits seems wasteful, but there really aren't that many logical + * variables around, and making them 32 bits could avoid word + * alignment problems, perhaps. */ +/*typedef long int logical;*/ +/*typedef INT32 logical;*/ +/* The following types are not used in the translated C code for the + * LPC-10 coder, but they might be needed by the definitions down + * below, so they don't cause compilation errors. */ +typedef char *address; +typedef struct { real r, i; } complex; +typedef struct { doublereal r, i; } doublecomplex; +typedef short int shortlogical; +typedef char logical1; +typedef char integer1; +/* typedef long long longint; */ /* system-dependent */ + +#define TRUE_ (1) +#define FALSE_ (0) + +/* Extern is for use with -E */ +#ifndef Extern +#define Extern extern +#endif + +/* I/O stuff */ + +#ifdef f2c_i2 +/* for -i2 */ +typedef short flag; +typedef short ftnlen; +typedef short ftnint; +#else +typedef long int flag; +typedef long int ftnlen; +typedef long int ftnint; +#endif + +/*external read, write*/ +typedef struct +{ flag cierr; + ftnint ciunit; + flag ciend; + char *cifmt; + ftnint cirec; +} cilist; + +/*internal read, write*/ +typedef struct +{ flag icierr; + char *iciunit; + flag iciend; + char *icifmt; + ftnint icirlen; + ftnint icirnum; +} icilist; + +/*open*/ +typedef struct +{ flag oerr; + ftnint ounit; + char *ofnm; + ftnlen ofnmlen; + char *osta; + char *oacc; + char *ofm; + ftnint orl; + char *oblnk; +} olist; + +/*close*/ +typedef struct +{ flag cerr; + ftnint cunit; + char *csta; +} cllist; + +/*rewind, backspace, endfile*/ +typedef struct +{ flag aerr; + ftnint aunit; +} alist; + +/* inquire */ +typedef struct +{ flag inerr; + ftnint inunit; + char *infile; + ftnlen infilen; + ftnint *inex; /*parameters in standard's order*/ + ftnint *inopen; + ftnint *innum; + ftnint *innamed; + char *inname; + ftnlen innamlen; + char *inacc; + ftnlen inacclen; + char *inseq; + ftnlen inseqlen; + char *indir; + ftnlen indirlen; + char *infmt; + ftnlen infmtlen; + char *inform; + ftnint informlen; + char *inunf; + ftnlen inunflen; + ftnint *inrecl; + ftnint *innrec; + char *inblank; + ftnlen inblanklen; +} inlist; + +#define VOID void + +union Multitype { /* for multiple entry points */ + integer1 g; + shortint h; + integer i; + /* longint j; */ + real r; + doublereal d; + complex c; + doublecomplex z; + }; + +typedef union Multitype Multitype; + +/*typedef long int Long;*/ /* No longer used; formerly in Namelist */ + +struct Vardesc { /* for Namelist */ + char *name; + char *addr; + ftnlen *dims; + int type; + }; +typedef struct Vardesc Vardesc; + +struct Namelist { + char *name; + Vardesc **vars; + int nvars; + }; +typedef struct Namelist Namelist; + +/* to avoid a conflict on netbsd 3.0 */ +#ifdef abs +#undef abs +#endif + +#define abs(x) ((x) >= 0 ? (x) : -(x)) +#define dabs(x) (doublereal)abs(x) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#define dmin(a,b) (doublereal)min(a,b) +#define dmax(a,b) (doublereal)max(a,b) + +/* procedure parameter types for -A and -C++ */ + +#define F2C_proc_par_types 1 +#ifdef __cplusplus +typedef int /* Unknown procedure type */ (*U_fp)(...); +typedef shortint (*J_fp)(...); +typedef integer (*I_fp)(...); +typedef real (*R_fp)(...); +typedef doublereal (*D_fp)(...), (*E_fp)(...); +typedef /* Complex */ VOID (*C_fp)(...); +typedef /* Double Complex */ VOID (*Z_fp)(...); +typedef logical (*L_fp)(...); +typedef shortlogical (*K_fp)(...); +typedef /* Character */ VOID (*H_fp)(...); +typedef /* Subroutine */ int (*S_fp)(...); +#else +typedef int /* Unknown procedure type */ (*U_fp)(); +typedef shortint (*J_fp)(); +typedef integer (*I_fp)(); +typedef real (*R_fp)(); +typedef doublereal (*D_fp)(), (*E_fp)(); +typedef /* Complex */ VOID (*C_fp)(); +typedef /* Double Complex */ VOID (*Z_fp)(); +typedef logical (*L_fp)(); +typedef shortlogical (*K_fp)(); +typedef /* Character */ VOID (*H_fp)(); +typedef /* Subroutine */ int (*S_fp)(); +#endif +/* E_fp is for real functions when -R is not specified */ +typedef VOID C_f; /* complex function */ +typedef VOID H_f; /* character function */ +typedef VOID Z_f; /* double complex function */ +typedef doublereal E_f; /* real function with -R not specified */ + +/* undef any lower-case symbols that your C compiler predefines, e.g.: */ + +#ifndef Skip_f2c_Undefs +#undef cray +#undef gcos +#undef mc68010 +#undef mc68020 +#undef mips +#undef pdp11 +#undef sgi +#undef sparc +#undef sun +#undef sun2 +#undef sun3 +#undef sun4 +#undef u370 +#undef u3b +#undef u3b2 +#undef u3b5 +#undef unix +#undef vax +#endif +#endif diff --git a/linphone/lpc10-1.5/f2clib.c b/linphone/lpc10-1.5/f2clib.c new file mode 100644 index 000000000..6bd8cdfb3 --- /dev/null +++ b/linphone/lpc10-1.5/f2clib.c @@ -0,0 +1,82 @@ +/* + +$Log: f2clib.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:32:10 jaf + * Initial revision + * + +*/ + +/* + * f2clib.c + * + * SCCS ID: @(#)f2clib.c 1.2 96/05/19 + */ + +#include "f2c.h" + +#ifdef KR_headers +integer pow_ii(ap, bp) integer *ap, *bp; +#else +integer pow_ii(integer *ap, integer *bp) +#endif +{ + integer pow, x, n; + unsigned long u; + + x = *ap; + n = *bp; + + if (n <= 0) { + if (n == 0 || x == 1) + return 1; + if (x != -1) + return x == 0 ? 1/x : 0; + n = -n; + } + u = n; + for(pow = 1; ; ) + { + if(u & 01) + pow *= x; + if(u >>= 1) + x *= x; + else + break; + } + return(pow); + } + + + +#ifdef KR_headers +double r_sign(a,b) real *a, *b; +#else +double r_sign(real *a, real *b) +#endif +{ +double x; +x = (*a >= 0 ? *a : - *a); +return( *b >= 0 ? x : -x); +} + + + +#ifdef KR_headers +double floor(); +integer i_nint(x) real *x; +#else +#undef abs +#include "math.h" +integer i_nint(real *x) +#endif +{ +return( (*x)>=0 ? + floor(*x + .5) : -floor(.5 - *x) ); +} diff --git a/linphone/lpc10-1.5/ham84.c b/linphone/lpc10-1.5/ham84.c new file mode 100644 index 000000000..0b2ab86d5 --- /dev/null +++ b/linphone/lpc10-1.5/ham84.c @@ -0,0 +1,114 @@ +/* + +$Log: ham84.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:32:07 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int ham84_(integer *input, integer *output, integer *errcnt); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ***************************************************************** */ + +/* HAM84 Version 45G */ + +/* $Log: ham84.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:07 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/21 15:26:00 jaf */ +/* Put comment header in standard form. */ + +/* Revision 1.2 1996/03/13 22:00:13 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:47:04 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Hamming 8,4 Decoder - can correct 1 out of seven bits */ +/* and can detect up to two errors. */ + +/* Input: */ +/* INPUT - Seven bit data word, 4 bits parameter and */ +/* 4 bits parity information */ +/* Input/Output: */ +/* ERRCNT - Sums errors detected by Hamming code */ +/* Output: */ +/* OUTPUT - 4 corrected parameter bits */ + +/* This subroutine is entered with an eight bit word in INPUT. The 8th */ +/* bit is parity and is stripped off. The remaining 7 bits address the */ +/* hamming 8,4 table and the output OUTPUT from the table gives the 4 */ +/* bits of corrected data. If bit 4 is set, no error was detected. */ +/* ERRCNT is the number of errors counted. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int ham84_(integer *input, integer *output, integer *errcnt) +{ + /* Initialized data */ + + static integer dactab[128] = { 16,0,0,3,0,5,14,7,0,9,14,11,14,13,30,14,0, + 9,2,7,4,7,7,23,9,25,10,9,12,9,14,7,0,5,2,11,5,21,6,5,8,11,11,27, + 12,5,14,11,2,1,18,2,12,5,2,7,12,9,2,11,28,12,12,15,0,3,3,19,4,13, + 6,3,8,13,10,3,13,29,14,13,4,1,10,3,20,4,4,7,10,9,26,10,4,13,10,15, + 8,1,6,3,6,5,22,6,24,8,8,11,8,13,6,15,1,17,2,1,4,1,6,15,8,1,10,15, + 12,15,15,31 }; + + integer i__, j, parity; + +/* Arguments */ +/* Parameters/constants */ +/* Local variables that need not be saved */ +/* Determine parity of input word */ + parity = *input & 255; + parity ^= parity / 16; + parity ^= parity / 4; + parity ^= parity / 2; + parity &= 1; + i__ = dactab[*input & 127]; + *output = i__ & 15; + j = i__ & 16; + if (j != 0) { +/* No errors detected in seven bits */ + if (parity != 0) { + ++(*errcnt); + } + } else { +/* One or two errors detected */ + ++(*errcnt); + if (parity == 0) { +/* Two errors detected */ + ++(*errcnt); + *output = -1; + } + } + return 0; +} /* ham84_ */ + diff --git a/linphone/lpc10-1.5/hp100.c b/linphone/lpc10-1.5/hp100.c new file mode 100644 index 000000000..51ce4665c --- /dev/null +++ b/linphone/lpc10-1.5/hp100.c @@ -0,0 +1,157 @@ +/* + +$Log: hp100.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:28:05 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:32:04 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int hp100_(real *speech, integer *start, integer *end, + struct lpc10_encoder_state *st); +extern int inithp100_(void); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************* */ + +/* HP100 Version 55 */ + +/* $Log: hp100.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:28:05 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:32:04 jaf + * Initial revision + * */ +/* Revision 1.6 1996/03/15 16:45:25 jaf */ +/* Rearranged a few comments. */ + +/* Revision 1.5 1996/03/14 23:20:54 jaf */ +/* Added comments about when INITHP100 should be used. */ + +/* Revision 1.4 1996/03/14 23:08:08 jaf */ +/* Added an entry named INITHP100 that initializes the local state of */ +/* subroutine HP100. */ + +/* Revision 1.3 1996/03/14 22:09:20 jaf */ +/* Comments added explaining which of the local variables of this */ +/* subroutine need to be saved from one invocation to the next, and which */ +/* do not. */ + +/* Revision 1.2 1996/02/12 15:05:54 jaf */ +/* Added lots of comments explaining why I changed one line, which was a */ +/* declaration with initializations. */ + +/* Revision 1.1 1996/02/07 14:47:12 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* 100 Hz High Pass Filter */ + +/* Jan 92 - corrected typo (1.937148 to 1.935715), */ +/* rounded coefficients to 7 places, */ +/* corrected and merged gain (.97466**4), */ +/* merged numerator into first two sections. */ + +/* Input: */ +/* start, end - Range of samples to filter */ +/* Input/Output: */ +/* speech(end) - Speech data. */ +/* Indices start through end are read and modified. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITHP100. */ +/* Subroutine */ int hp100_(real *speech, integer *start, integer *end, + struct lpc10_encoder_state *st) +{ + /* Temporary local copies of variables in lpc10_encoder_state. + I've only created these because it might cause the loop below + to execute a bit faster to access local variables, rather than + variables in the lpc10_encoder_state structure. It is just a + guess that it will be faster. */ + + real z11; + real z21; + real z12; + real z22; + + /* System generated locals */ + integer i__1; + + /* Local variables */ + integer i__; + real si, err; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Local state */ + /* Parameter adjustments */ + if (speech) { + --speech; + } + + /* Function Body */ + + z11 = st->z11; + z21 = st->z21; + z12 = st->z12; + z22 = st->z22; + + i__1 = *end; + for (i__ = *start; i__ <= i__1; ++i__) { + si = speech[i__]; + err = si + z11 * 1.859076f - z21 * .8648249f; + si = err - z11 * 2.f + z21; + z21 = z11; + z11 = err; + err = si + z12 * 1.935715f - z22 * .9417004f; + si = err - z12 * 2.f + z22; + z22 = z12; + z12 = err; + speech[i__] = si * .902428f; + } + + st->z11 = z11; + st->z21 = z21; + st->z12 = z12; + st->z22 = z22; + + return 0; +} /* hp100_ */ diff --git a/linphone/lpc10-1.5/invert.c b/linphone/lpc10-1.5/invert.c new file mode 100644 index 000000000..19cbb71ab --- /dev/null +++ b/linphone/lpc10-1.5/invert.c @@ -0,0 +1,175 @@ +/* + +$Log: invert.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:32:00 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int invert_(integer *order, real *phi, real *psi, real *rc); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* **************************************************************** */ + +/* INVERT Version 45G */ + +/* $Log: invert.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:00 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/18 20:52:47 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 16:51:32 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Eliminated a comment from the original, describing a local array X */ +/* that appeared nowhere in the code. */ + +/* Revision 1.1 1996/02/07 14:47:20 jaf */ +/* Initial revision */ + + +/* **************************************************************** */ + +/* Invert a covariance matrix using Choleski decomposition method. */ + +/* Input: */ +/* ORDER - Analysis order */ +/* PHI(ORDER,ORDER) - Covariance matrix */ +/* Indices (I,J) read, where ORDER .GE. I .GE. J .GE. 1.*/ +/* All other indices untouched. */ +/* PSI(ORDER) - Column vector to be predicted */ +/* Indices 1 through ORDER read. */ +/* Output: */ +/* RC(ORDER) - Pseudo reflection coefficients */ +/* Indices 1 through ORDER written, and then possibly read. +*/ +/* Internal: */ +/* V(ORDER,ORDER) - Temporary matrix */ +/* Same indices written as read from PHI. */ +/* Many indices may be read and written again after */ +/* initially being copied from PHI, but all indices */ +/* are written before being read. */ + +/* NOTE: Temporary matrix V is not needed and may be replaced */ +/* by PHI if the original PHI values do not need to be preserved. */ + +/* Subroutine */ int invert_(integer *order, real *phi, real *psi, real *rc) +{ + /* System generated locals */ + integer phi_dim1, phi_offset, i__1, i__2, i__3; + real r__1, r__2; + + /* Local variables */ + real save; + integer i__, j, k; + real v[100] /* was [10][10] */; + +/* Arguments */ +/* $Log: invert.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:32:00 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Parameters/constants */ +/* Local variables that need not be saved */ +/* Decompose PHI into V * D * V' where V is a triangular matrix whose */ +/* main diagonal elements are all 1, V' is the transpose of V, and */ +/* D is a vector. Here D(n) is stored in location V(n,n). */ + /* Parameter adjustments */ + --rc; + --psi; + phi_dim1 = *order; + phi_offset = phi_dim1 + 1; + phi -= phi_offset; + + /* Function Body */ + i__1 = *order; + for (j = 1; j <= i__1; ++j) { + i__2 = *order; + for (i__ = j; i__ <= i__2; ++i__) { + v[i__ + j * 10 - 11] = phi[i__ + j * phi_dim1]; + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + save = v[j + k * 10 - 11] * v[k + k * 10 - 11]; + i__3 = *order; + for (i__ = j; i__ <= i__3; ++i__) { + v[i__ + j * 10 - 11] -= v[i__ + k * 10 - 11] * save; + } + } +/* Compute intermediate results, which are similar to RC's */ + if ((r__1 = v[j + j * 10 - 11], abs(r__1)) < 1e-10f) { + goto L100; + } + rc[j] = psi[j]; + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + rc[j] -= rc[k] * v[j + k * 10 - 11]; + } + v[j + j * 10 - 11] = 1.f / v[j + j * 10 - 11]; + rc[j] *= v[j + j * 10 - 11]; +/* Computing MAX */ +/* Computing MIN */ + r__2 = rc[j]; + r__1 = min(r__2,.999f); + rc[j] = max(r__1,-.999f); + } + return 0; +/* Zero out higher order RC's if algorithm terminated early */ +L100: + i__1 = *order; + for (i__ = j; i__ <= i__1; ++i__) { + rc[i__] = 0.f; + } +/* Back substitute for PC's (if needed) */ +/* 110 DO J = ORDER,1,-1 */ +/* PC(J) = RC(J) */ +/* DO I = 1,J-1 */ +/* PC(J) = PC(J) - PC(I)*V(J,I) */ +/* END DO */ +/* END DO */ + return 0; +} /* invert_ */ + diff --git a/linphone/lpc10-1.5/irc2pc.c b/linphone/lpc10-1.5/irc2pc.c new file mode 100644 index 000000000..df563735e --- /dev/null +++ b/linphone/lpc10-1.5/irc2pc.c @@ -0,0 +1,133 @@ +/* + +$Log: irc2pc.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:56 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int irc2pc_(real *rc, real *pc, integer *order, real *gprime, real *g2pass); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ***************************************************************** */ + +/* IRC2PC Version 48 */ + +/* $Log: irc2pc.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:56 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/20 15:47:19 jaf */ +/* Added comments about which indices of array arguments are read or */ +/* written. */ + +/* Revision 1.2 1996/03/14 16:59:04 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:47:27 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Convert Reflection Coefficients to Predictor Coeficients */ + +/* Inputs: */ +/* RC - Reflection coefficients */ +/* Indices 1 through ORDER read. */ +/* ORDER - Number of RC's */ +/* GPRIME - Excitation modification gain */ +/* Outputs: */ +/* PC - Predictor coefficients */ +/* Indices 1 through ORDER written. */ +/* Indices 1 through ORDER-1 are read after being written. */ +/* G2PASS - Excitation modification sharpening factor */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int irc2pc_(real *rc, real *pc, integer *order, real *gprime, + real *g2pass) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Builtin functions */ + double sqrt(doublereal); + + /* Local variables */ + real temp[10]; + integer i__, j; + +/* Arguments */ +/* $Log: irc2pc.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:56 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Local variables that need not be saved */ + /* Parameter adjustments */ + --pc; + --rc; + + /* Function Body */ + *g2pass = 1.f; + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + *g2pass *= 1.f - rc[i__] * rc[i__]; + } + *g2pass = *gprime * sqrt(*g2pass); + pc[1] = rc[1]; + i__1 = *order; + for (i__ = 2; i__ <= i__1; ++i__) { + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + temp[j - 1] = pc[j] - rc[i__] * pc[i__ - j]; + } + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + pc[j] = temp[j - 1]; + } + pc[i__] = rc[i__]; + } + return 0; +} /* irc2pc_ */ + diff --git a/linphone/lpc10-1.5/ivfilt.c b/linphone/lpc10-1.5/ivfilt.c new file mode 100644 index 000000000..18e229b7d --- /dev/null +++ b/linphone/lpc10-1.5/ivfilt.c @@ -0,0 +1,118 @@ +/* + +$Log: ivfilt.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:53 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int ivfilt_(real *lpbuf, real *ivbuf, integer *len, integer *nsamp, real *ivrc); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************* */ + +/* IVFILT Version 48 */ + +/* $Log: ivfilt.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:53 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/15 21:36:29 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 00:01:00 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:47:34 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* 2nd order inverse filter, speech is decimated 4:1 */ + +/* Input: */ +/* LEN - Length of speech buffers */ +/* NSAMP - Number of samples to filter */ +/* LPBUF - Low pass filtered speech buffer */ +/* Indices LEN-NSAMP-7 through LEN read. */ +/* Output: */ +/* IVBUF - Inverse filtered speech buffer */ +/* Indices LEN-NSAMP+1 through LEN written. */ +/* IVRC - Inverse filter reflection coefficients (for voicing) */ +/* Indices 1 and 2 both written (also read, but only after writing). +*/ + +/* This subroutine has no local state. */ + +/* Subroutine */ int ivfilt_(real *lpbuf, real *ivbuf, integer *len, integer * + nsamp, real *ivrc) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + integer i__, j, k; + real r__[3], pc1, pc2; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Local state */ +/* None */ +/* Calculate Autocorrelations */ + /* Parameter adjustments */ + --ivbuf; + --lpbuf; + --ivrc; + + /* Function Body */ + for (i__ = 1; i__ <= 3; ++i__) { + r__[i__ - 1] = 0.f; + k = i__ - 1 << 2; + i__1 = *len; + for (j = (i__ << 2) + *len - *nsamp; j <= i__1; j += 2) { + r__[i__ - 1] += lpbuf[j] * lpbuf[j - k]; + } + } +/* Calculate predictor coefficients */ + pc1 = 0.f; + pc2 = 0.f; + ivrc[1] = 0.f; + ivrc[2] = 0.f; + if (r__[0] > 1e-10f) { + ivrc[1] = r__[1] / r__[0]; + ivrc[2] = (r__[2] - ivrc[1] * r__[1]) / (r__[0] - ivrc[1] * r__[1]); + pc1 = ivrc[1] - ivrc[1] * ivrc[2]; + pc2 = ivrc[2]; + } +/* Inverse filter LPBUF into IVBUF */ + i__1 = *len; + for (i__ = *len + 1 - *nsamp; i__ <= i__1; ++i__) { + ivbuf[i__] = lpbuf[i__] - pc1 * lpbuf[i__ - 4] - pc2 * lpbuf[i__ - 8]; + } + return 0; +} /* ivfilt_ */ + diff --git a/linphone/lpc10-1.5/lpc10.h b/linphone/lpc10-1.5/lpc10.h new file mode 100644 index 000000000..4ece9f07f --- /dev/null +++ b/linphone/lpc10-1.5/lpc10.h @@ -0,0 +1,228 @@ +/* + +$Log: lpc10.h,v $ +Revision 1.1.1.1 2001/11/19 19:50:13 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:47:31 jaf + * Initial revision + * + +*/ + +#ifndef __LPC10_H__ +#define __LPC10_H__ + +#define LPC10_SAMPLES_PER_FRAME 180 +#define LPC10_BITS_IN_COMPRESSED_FRAME 54 + + +/* + + The "#if defined"'s in this file are by no means intended to be + complete. They are what Nautilus uses, which has been successfully + compiled under DOS with the Microsoft C compiler, and under a few + versions of Unix with the GNU C compiler. + + */ + + +typedef short INT16; +typedef int INT32; + + +#if defined(__MSDOS__) || defined(MSDOS) +typedef int INT16; +typedef long INT32; +#endif + + + +/* The initial values for every member of this structure is 0, except + where noted in comments. */ + +/* These two lines are copied from f2c.h. There should be a more + elegant way of doing this than having the same declarations in two + files. */ + +typedef float real; +typedef INT32 integer; +typedef INT32 logical; +typedef INT16 shortint; + +struct lpc10_encoder_state { + /* State used only by function hp100 */ + real z11; + real z21; + real z12; + real z22; + + /* State used by function analys */ + real inbuf[540], pebuf[540]; + real lpbuf[696], ivbuf[312]; + real bias; + integer osbuf[10]; /* no initial value necessary */ + integer osptr; /* initial value 1 */ + integer obound[3]; + integer vwin[6] /* was [2][3] */; /* initial value vwin[4] = 307; vwin[5] = 462; */ + integer awin[6] /* was [2][3] */; /* initial value awin[4] = 307; awin[5] = 462; */ + integer voibuf[8] /* was [2][4] */; + real rmsbuf[3]; + real rcbuf[30] /* was [10][3] */; + real zpre; + + + /* State used by function onset */ + real n; + real d__; /* initial value 1.f */ + real fpc; /* no initial value necessary */ + real l2buf[16]; + real l2sum1; + integer l2ptr1; /* initial value 1 */ + integer l2ptr2; /* initial value 9 */ + integer lasti; /* no initial value necessary */ + logical hyst; /* initial value FALSE_ */ + + /* State used by function voicin */ + real dither; /* initial value 20.f */ + real snr; + real maxmin; + real voice[6] /* was [2][3] */; /* initial value is probably unnecessary */ + integer lbve, lbue, fbve, fbue; + integer ofbue, sfbue; + integer olbue, slbue; + /* Initial values: + lbve = 3000; + fbve = 3000; + fbue = 187; + ofbue = 187; + sfbue = 187; + lbue = 93; + olbue = 93; + slbue = 93; + snr = (real) (fbve / fbue << 6); + */ + + /* State used by function dyptrk */ + real s[60]; + integer p[120] /* was [60][2] */; + integer ipoint; + real alphax; + + /* State used by function chanwr */ + integer isync; + +}; + + +struct lpc10_decoder_state { + + /* State used by function decode */ + integer iptold; /* initial value 60 */ + logical first; /* initial value TRUE_ */ + integer ivp2h; + integer iovoic; + integer iavgp; /* initial value 60 */ + integer erate; + integer drc[30] /* was [3][10] */; + integer dpit[3]; + integer drms[3]; + + /* State used by function synths */ + real buf[360]; + integer buflen; /* initial value 180 */ + + /* State used by function pitsyn */ + integer ivoico; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + integer ipito; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + real rmso; /* initial value 1.f */ + real rco[10]; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + integer jsamp; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + logical first_pitsyn; /* initial value TRUE_ */ + + /* State used by function bsynz */ + integer ipo; + real exc[166]; + real exc2[166]; + real lpi1; + real lpi2; + real lpi3; + real hpi1; + real hpi2; + real hpi3; + real rmso_bsynz; + + /* State used by function random */ + integer j; /* initial value 2 */ + integer k; /* initial value 5 */ + shortint y[5]; /* initial value { -21161,-8478,30892,-10216,16950 } */ + + /* State used by function deemp */ + real dei1; + real dei2; + real deo1; + real deo2; + real deo3; + +}; + + + +/* + + Calling sequence: + + Call create_lpc10_encoder_state(), which returns a pointer to an + already initialized lpc10_encoder_state structure. + + lpc10_encode reads indices 0 through (LPC10_SAMPLES_PER_FRAME-1) of + array speech[], and writes indices 0 through + (LPC10_BITS_IN_COMPRESSED_FRAME-1) of array bits[], and both reads + and writes the lpc10_encoder_state structure contents. The + lpc10_encoder_state structure should *not* be initialized for every + frame of encoded speech. Once at the beginning of execution, done + automatically for you by create_lpc10_encoder_state(), is enough. + + init_lpc10_encoder_state() reinitializes the lpc10_encoder_state + structure. This might be useful if you are finished processing one + sound sample, and want to reuse the same lpc10_encoder_state + structure to process another sound sample. There might be other + uses as well. + + Note that the comments in the lpc10/lpcenc.c file imply that indices + 1 through 180 of array speech[] are read. These comments were + written for the Fortran version of the code, before it was + automatically converted to C by the conversion program f2c. f2c + seems to use the convention that the pointers to arrays passed as + function arguments point to the first index used in the Fortran + code, whatever index that might be (usually 1), and then it modifies + the pointer inside of the function, like so: + + if (speech) { + --speech; + } + + So that the code can access the first value at index 1 and the last + at index 180. This makes the translated C code "closer" to the + original Fortran code. + + The calling sequence for the decoder is similar to the encoder. The + only significant difference is that the array bits[] is read + (indices 0 through (LPC10_BITS_IN_COMPRESSED_FRAME-1)), and the + array speech[] is written (indices 0 through + (LPC10_SAMPLES_PER_FRAME-1)). + + */ + +struct lpc10_encoder_state * create_lpc10_encoder_state (); +void init_lpc10_encoder_state (struct lpc10_encoder_state *st); +int lpc10_encode (real *speech, INT32 *bits, struct lpc10_encoder_state *st); + +struct lpc10_decoder_state * create_lpc10_decoder_state (); +void init_lpc10_decoder_state (struct lpc10_decoder_state *st); +int lpc10_decode (INT32 *bits, real *speech, struct lpc10_decoder_state *st); + +#endif /* __LPC10_H__ */ diff --git a/linphone/lpc10-1.5/lpc10_wrapper.c b/linphone/lpc10-1.5/lpc10_wrapper.c new file mode 100644 index 000000000..333b81f89 --- /dev/null +++ b/linphone/lpc10-1.5/lpc10_wrapper.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include "lpc10_wrapper.h" +#include + +/* the public codec_info_t*/ + +struct codec_info LPC10codec_info= +{ + "LPC10-1.5", + LPC10_SAMPLES_PER_FRAME*2, /* size in bytes of the uncompressed frame*/ + ((LPC10_BITS_IN_COMPRESSED_FRAME/8) + 1), /* 7 bytes */ /* size in bytes of compressed frame*/ + 2400, /* bit rate*/ + {{ + 8000 + }}, /* audio sampling freq*/ + LPC10codec_new, /* codec constructor*/ + 115, /* payload type */ + "lpc10-15/8000/1", /*description */ + CODEC_AUDIO, /* type*/ + 0, /*usable, set later*/ + 1 /*usable for user, default value*/ +}; + +/* The return value of each of these calls is the same as that + returned by fread/fwrite, which should be the number of samples + successfully read/written, not the number of bytes. */ + +static int +read_16bit_samples(INT16 int16samples[], float speech[], int n) +{ + int i; + + /* Convert 16 bit integer samples to floating point values in the + range [-1,+1]. */ + + for (i = 0; i < n; i++) { + speech[i] = ((float) int16samples[i]) / 32768.0; + } + + return (n); +} + + + +static int +write_16bit_samples(INT16 int16samples[], float speech[], int n) +{ + int i; + float real_sample; + + /* Convert floating point samples in range [-1,+1] to 16 bit + integers. */ + for (i = 0; i < n; i++) { + real_sample = 32768.0 * speech[i]; + if (real_sample < -32768.0) { + int16samples[i] = -32768; + } else if (real_sample > 32767.0) { + int16samples[i] = 32767; + } else { + int16samples[i] = real_sample; + } + } + return (n); +} + +/* + +Write the bits in bits[0] through bits[len-1] to file f, in "packed" +format. + +bits is expected to be an array of len integer values, where each +integer is 0 to represent a 0 bit, and any other value represents a 1 +bit. This bit string is written to the file f in the form of several +8 bit characters. If len is not a multiple of 8, then the last +character is padded with 0 bits -- the padding is in the least +significant bits of the last byte. The 8 bit characters are "filled" +in order from most significant bit to least significant. + +*/ + +static void +write_bits(unsigned char *data, INT32 *bits, int len) +{ + int i; /* generic loop variable */ + unsigned char mask; /* The next bit position within the + variable "data" to place the next + bit. */ + + + /* Fill in the array bits. + * The first compressed output bit will be the most significant + * bit of the byte, so initialize mask to 0x80. The next byte of + * compressed data is initially 0, and the desired bits will be + * turned on below. + */ + mask = 0x80; + *data = 0; + + for (i = 0; i < len; i++) { + /* Turn on the next bit of output data, if necessary. */ + if (bits[i]) { + (*data) |= mask; + } + /* + * If the byte data is full, determined by mask becoming 0, + * then write the byte to the output file, and reinitialize + * data and mask for the next output byte. Also add the byte + * if (i == len-1), because if len is not a multiple of 8, + * then mask won't yet be 0. */ + mask >>= 1; + if ((mask == 0) || (i == len-1)) { + data++; + *data = 0; + mask = 0x80; + } + } +} + + + +/* + +Read bits from file f into bits[0] through bits[len-1], in "packed" +format. + +Read ceiling(len/8) characters from file f, if that many are available +to read, otherwise read to the end of the file. The first character's +8 bits, in order from MSB to LSB, are used to fill bits[0] through +bits[7]. The second character's bits are used to fill bits[8] through +bits[15], and so on. If ceiling(len/8) characters are available to +read, and len is not a multiple of 8, then some of the least +significant bits of the last character read are completely ignored. +Every entry of bits[] that is modified is changed to either a 0 or a +1. + +The number of bits successfully read is returned, and is always in the +range 0 to len, inclusive. If it is less than len, it will always be +a multiple of 8. + +*/ + +static int +read_bits(unsigned char *data, INT32 *bits, int len) +{ + int i,ind=0; /* generic loop variable */ + int c=0; + + /* Unpack the array bits into coded_frame. */ + for (i = 0; i < len; i++) { + if ((i % 8) == 0) { + c = (int)(data[ind]); + ind++; + } + if (c & (0x80 >> (i & 7))) { + bits[i] = 1; + } else { + bits[i] = 0; + } + } + return (len); +} + + + + +Codec *LPC10codec_new() +{ + LPC10Codec *obj; + + obj=(LPC10Codec*)malloc(sizeof(LPC10Codec)); + obj->baseclass._getinfo=&wlpc10_getinfo; + obj->baseclass._encode=&wlpc10_encode; + obj->baseclass._decode=&wlpc10_decode; + obj->baseclass._destroy=&wlpc10_destroy; + + obj->enc = create_lpc10_encoder_state(); + if (obj->enc == NULL) { + fprintf(stderr, "Couldn't allocate %d bytes for encoder state.\n", + sizeof(struct lpc10_encoder_state)); + return(NULL); + } + obj->dec = create_lpc10_decoder_state(); + if (obj->dec == NULL) { + fprintf(stderr, "Couldn't allocate %d bytes for decoder state.\n", + sizeof(struct lpc10_decoder_state)); + return(NULL); + } + return((Codec*)obj); +} + + + + +void wlpc10_getinfo(Codec *codec, struct codec_info *info) +{ + memcpy(info,&LPC10codec_info,sizeof(struct codec_info)); +} +void wlpc10_encode(Codec *codec, char *frame, char *data) +{ + float speech[LPC10_SAMPLES_PER_FRAME]; + INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; + LPC10Codec *obj=(LPC10Codec*)codec; /* we should make a few check to see if this codec is a LPC10...*/ + + read_16bit_samples((INT16*)frame, speech, LPC10_SAMPLES_PER_FRAME); + lpc10_encode(speech, bits, obj->enc); + write_bits(data, bits, LPC10_BITS_IN_COMPRESSED_FRAME); +} + +void wlpc10_decode(Codec *codec,char *data, char *frame) +{ + float speech[LPC10_SAMPLES_PER_FRAME]; + INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; + LPC10Codec *obj=(LPC10Codec*)codec; /* we should make a few check to see if this codec is a LPC10...*/ + + read_bits(data, bits, LPC10_BITS_IN_COMPRESSED_FRAME); + lpc10_decode(bits,speech, obj->dec); + write_16bit_samples((INT16*)frame, speech, LPC10_SAMPLES_PER_FRAME); +} + +void wlpc10_destroy(Codec *codec) +{ + LPC10Codec *obj=(LPC10Codec*)codec; /* we should make a few check to see if this codec is a LPC10...*/ + + free(obj->enc); + free(obj->dec); + free(obj); +} \ No newline at end of file diff --git a/linphone/lpc10-1.5/lpc10_wrapper.h b/linphone/lpc10-1.5/lpc10_wrapper.h new file mode 100644 index 000000000..73241b169 --- /dev/null +++ b/linphone/lpc10-1.5/lpc10_wrapper.h @@ -0,0 +1,34 @@ +#include "../console/codec.h" +#include "lpc10.h" + + +/* +int read_16bit_samples(INT16 int16samples[], float speech[], int n); +int write_16bit_samples(INT16 int16samples[], float speech[], int n); + + +void write_bits(unsigned char *data, INT32 *bits, int len); +int read_bits(unsigned char *data, INT32 *bits, int len); +*/ + +/* the following code has been added by Simon MORLAT to make lpc10 interface compatible with linphone*/ + +/*Class definition*/ + +typedef struct _LPC10Codec +{ + Codec baseclass; /* Codec must be the first element of the structure in order to have the object mechanism to work*/ + struct lpc10_encoder_state *enc; + struct lpc10_decoder_state *dec; +} LPC10Codec; + +/* this the constructor for derivate class LPC10Codec*/ +Codec *LPC10codec_new(); + +extern struct codec_info LPC10codec_info; + +/* these are the overrides for the base class 's functions*/ +void wlpc10_getinfo(Codec *codec,struct codec_info *info); +void wlpc10_encode(Codec *codec,char *frame, char *data); +void wlpc10_decode(Codec *codec,char *data, char *frame); +void wlpc10_destroy(Codec *codec); diff --git a/linphone/lpc10-1.5/lpcdec.c b/linphone/lpc10-1.5/lpcdec.c new file mode 100644 index 000000000..30cdba65b --- /dev/null +++ b/linphone/lpc10-1.5/lpcdec.c @@ -0,0 +1,273 @@ +/* + +$Log: lpcdec.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:30:11 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:48 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int lpcdec_(integer *bits, real *speech); +extern int initlpcdec_(void); +/* comlen contrl_ 12 */ +/*:ref: chanrd_ 14 5 4 4 4 4 4 */ +/*:ref: decode_ 14 7 4 4 4 4 4 6 6 */ +/*:ref: synths_ 14 6 4 4 6 6 6 4 */ +/*:ref: initdecode_ 14 0 */ +/*:ref: initsynths_ 14 0 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* Table of constant values */ + +static integer c__10 = 10; + +/* ***************************************************************** */ + +/* $Log: lpcdec.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:30:11 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:48 jaf + * Initial revision + * */ +/* Revision 1.1 1996/03/28 00:03:00 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Decode 54 bits to one frame of 180 speech samples. */ + +/* Input: */ +/* BITS - 54 encoded bits, stored 1 per array element. */ +/* Indices 1 through 53 read (SYNC bit ignored). */ +/* Output: */ +/* SPEECH - Speech encoded as real values in the range [-1,+1]. */ +/* Indices 1 through 180 written. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITLPCDEC. */ + +/* Subroutine */ int lpc10_decode(integer *bits, real *speech, + struct lpc10_decoder_state *st) +{ + integer irms, voice[2], pitch, ipitv; + extern /* Subroutine */ int decode_(integer *, integer *, integer *, + integer *, integer *, real *, real *, struct lpc10_decoder_state *); + real rc[10]; + extern /* Subroutine */ int chanrd_(integer *, integer *, integer *, + integer *, integer *), synths_(integer *, + integer *, real *, real *, real *, integer *, + struct lpc10_decoder_state *); + integer irc[10], len; + real rms; + +/* $Log: lpcdec.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:30:11 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:48 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Arguments */ +/* $Log: lpcdec.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:30:11 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:48 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Local variables that need not be saved */ +/* Uncoded speech parameters */ +/* Coded speech parameters */ +/* Others */ +/* Local state */ +/* None */ + /* Parameter adjustments */ + if (bits) { + --bits; + } + if (speech) { + --speech; + } + + /* Function Body */ + + chanrd_(&c__10, &ipitv, &irms, irc, &bits[1]); + decode_(&ipitv, &irms, irc, voice, &pitch, &rms, rc, st); + synths_(voice, &pitch, &rms, rc, &speech[1], &len, st); + return 0; +} /* lpcdec_ */ diff --git a/linphone/lpc10-1.5/lpcenc.c b/linphone/lpc10-1.5/lpcenc.c new file mode 100644 index 000000000..7805a0e8c --- /dev/null +++ b/linphone/lpc10-1.5/lpcenc.c @@ -0,0 +1,163 @@ +/* + +$Log: lpcenc.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:31:21 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:44 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int lpcenc_(real *speech, integer *bits); +extern int initlpcenc_(void); +/*:ref: prepro_ 14 2 6 4 */ +/*:ref: analys_ 14 5 6 4 4 6 6 */ +/*:ref: encode_ 14 7 4 4 6 6 4 4 4 */ +/*:ref: chanwr_ 14 5 4 4 4 4 4 */ +/*:ref: initprepro_ 14 0 */ +/*:ref: initanalys_ 14 0 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Table of constant values */ + +static integer c__180 = 180; +static integer c__10 = 10; + +/* ***************************************************************** */ + +/* $Log: lpcenc.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:31:21 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:44 jaf + * Initial revision + * */ +/* Revision 1.2 1996/03/28 00:01:22 jaf */ +/* Commented out some trace statements. */ + +/* Revision 1.1 1996/03/28 00:00:27 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Encode one frame of 180 speech samples to 54 bits. */ + +/* Input: */ +/* SPEECH - Speech encoded as real values in the range [-1,+1]. */ +/* Indices 1 through 180 read, and modified (by PREPRO). */ +/* Output: */ +/* BITS - 54 encoded bits, stored 1 per array element. */ +/* Indices 1 through 54 written. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITLPCENC. */ + +/* Subroutine */ int lpc10_encode(real *speech, integer *bits, + struct lpc10_encoder_state *st) +{ + integer irms, voice[2], pitch, ipitv; + real rc[10]; + extern /* Subroutine */ int encode_(integer *, integer *, real *, real *, + integer *, integer *, integer *), chanwr_(integer *, integer *, + integer *, integer *, integer *, struct lpc10_encoder_state *), + analys_(real *, integer *, + integer *, real *, real *, struct lpc10_encoder_state *), + prepro_(real *, integer *, struct lpc10_encoder_state *); + integer irc[10]; + real rms; + +/* Arguments */ +/* $Log: lpcenc.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:31:21 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Changed name of function from lpcenc_ to lpc10_encode, simply to make + * all lpc10 functions have more consistent naming with each other. + * + * Revision 1.1 1996/08/19 22:31:44 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Local variables that need not be saved */ +/* Uncoded speech parameters */ +/* Coded speech parameters */ +/* Local state */ +/* None */ + /* Parameter adjustments */ + if (speech) { + --speech; + } + if (bits) { + --bits; + } + + /* Function Body */ + prepro_(&speech[1], &c__180, st); + analys_(&speech[1], voice, &pitch, &rms, rc, st); + encode_(voice, &pitch, &rms, rc, &ipitv, &irms, irc); + chanwr_(&c__10, &ipitv, &irms, irc, &bits[1], st); + return 0; +} /* lpcenc_ */ diff --git a/linphone/lpc10-1.5/lpcini.c b/linphone/lpc10-1.5/lpcini.c new file mode 100644 index 000000000..6d88bfb75 --- /dev/null +++ b/linphone/lpc10-1.5/lpcini.c @@ -0,0 +1,399 @@ +/* + +$Log: lpcini.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:35:41 jaf + * Added functions for allocating and initializing lpc10_encoder_state + * and lpc10_decoder_state structures. + * + * Revision 1.1 1996/08/19 22:31:40 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int lpcini_(void); +/* comlen contrl_ 12 */ +/*:ref: initlpcenc_ 14 0 */ +/*:ref: initlpcdec_ 14 0 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +#include + +/* Common Block Declarations */ + +struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* ***************************************************************** */ + +/* $Log: lpcini.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:35:41 jaf + * Added functions for allocating and initializing lpc10_encoder_state + * and lpc10_decoder_state structures. + * + * Revision 1.1 1996/08/19 22:31:40 jaf + * Initial revision + * */ +/* Revision 1.1 1996/03/28 00:04:05 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Initialize COMMON block variables used by LPC-10 encoder and decoder, */ +/* and call initialization routines for both of them. */ + +/* Subroutine */ int lpcini_(void) +{ + +/* $Log: lpcini.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:35:41 jaf + * Added functions for allocating and initializing lpc10_encoder_state + * and lpc10_decoder_state structures. + * + * Revision 1.1 1996/08/19 22:31:40 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* $Log: lpcini.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:35:41 jaf + * Added functions for allocating and initializing lpc10_encoder_state + * and lpc10_decoder_state structures. + * + * Revision 1.1 1996/08/19 22:31:40 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ + contrl_1.order = 10; + contrl_1.lframe = 180; + contrl_1.corrp = TRUE_; + return 0; +} /* lpcini_ */ + + + +/* Allocate memory for, and initialize, the state that needs to be + kept from encoding one frame to the next for a single + LPC-10-compressed audio stream. Return 0 if malloc fails, + otherwise return pointer to new structure. */ + +struct lpc10_encoder_state * +create_lpc10_encoder_state() +{ + struct lpc10_encoder_state *st; + + st = (struct lpc10_encoder_state *) + malloc((unsigned) sizeof (struct lpc10_encoder_state)); + if (st != 0) { + init_lpc10_encoder_state(st); + } + return (st); +} + + + +void init_lpc10_encoder_state(struct lpc10_encoder_state *st) +{ + int i; + + lpcini_(); + + /* State used only by function hp100 */ + st->z11 = 0.0f; + st->z21 = 0.0f; + st->z12 = 0.0f; + st->z22 = 0.0f; + + /* State used by function analys */ + for (i = 0; i < 540; i++) { + st->inbuf[i] = 0.0f; + st->pebuf[i] = 0.0f; + } + for (i = 0; i < 696; i++) { + st->lpbuf[i] = 0.0f; + } + for (i = 0; i < 312; i++) { + st->ivbuf[i] = 0.0f; + } + st->bias = 0.0f; + /* integer osbuf[10]; /* no initial value necessary */ + st->osptr = 1; + for (i = 0; i < 3; i++) { + st->obound[i] = 0; + } + st->vwin[4] = 307; + st->vwin[5] = 462; + st->awin[4] = 307; + st->awin[5] = 462; + for (i = 0; i < 8; i++) { + st->voibuf[i] = 0; + } + for (i = 0; i < 3; i++) { + st->rmsbuf[i] = 0.0f; + } + for (i = 0; i < 30; i++) { + st->rcbuf[i] = 0.0f; + } + st->zpre = 0.0f; + + + /* State used by function onset */ + st->n = 0.0f; + st->d__ = 1.0f; + /* real fpc; /* no initial value necessary */ + for (i = 0; i < 16; i++) { + st->l2buf[i] = 0.0f; + } + st->l2sum1 = 0.0f; + st->l2ptr1 = 1; + st->l2ptr2 = 9; + /* integer lasti; /* no initial value necessary */ + st->hyst = FALSE_; + + /* State used by function voicin */ + st->dither = 20.0f; + st->maxmin = 0.0f; + for (i = 0; i < 6; i++) { + st->voice[i] = 0.0f; + } + st->lbve = 3000; + st->fbve = 3000; + st->fbue = 187; + st->ofbue = 187; + st->sfbue = 187; + st->lbue = 93; + st->olbue = 93; + st->slbue = 93; + st->snr = (real) (st->fbve / st->fbue << 6); + + /* State used by function dyptrk */ + for (i = 0; i < 60; i++) { + st->s[i] = 0.0f; + } + for (i = 0; i < 120; i++) { + st->p[i] = 0; + } + st->ipoint = 0; + st->alphax = 0.0f; + + /* State used by function chanwr */ + st->isync = 0; + +} + + + +/* Allocate memory for, and initialize, the state that needs to be + kept from decoding one frame to the next for a single + LPC-10-compressed audio stream. Return 0 if malloc fails, + otherwise return pointer to new structure. */ + +struct lpc10_decoder_state * +create_lpc10_decoder_state() +{ + struct lpc10_decoder_state *st; + + st = (struct lpc10_decoder_state *) + malloc((unsigned) sizeof (struct lpc10_decoder_state)); + if (st != 0) { + init_lpc10_decoder_state(st); + } + return (st); +} + + + +void init_lpc10_decoder_state(struct lpc10_decoder_state *st) +{ + int i; + + lpcini_(); + + /* State used by function decode */ + st->iptold = 60; + st->first = TRUE_; + st->ivp2h = 0; + st->iovoic = 0; + st->iavgp = 60; + st->erate = 0; + for (i = 0; i < 30; i++) { + st->drc[i] = 0; + } + for (i = 0; i < 3; i++) { + st->dpit[i] = 0; + st->drms[i] = 0; + } + + /* State used by function synths */ + for (i = 0; i < 360; i++) { + st->buf[i] = 0.0f; + } + st->buflen = 180; + + /* State used by function pitsyn */ + /* ivoico; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + /* ipito; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + st->rmso = 1.0f; + /* rco[10]; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + /* integer jsamp; /* no initial value necessary as long as first_pitsyn is initially TRUE_ */ + st->first_pitsyn = TRUE_; + + /* State used by function bsynz */ + st->ipo = 0; + for (i = 0; i < 166; i++) { + st->exc[i] = 0.0f; + st->exc2[i] = 0.0f; + } + st->lpi1 = 0.0f; + st->lpi2 = 0.0f; + st->lpi3 = 0.0f; + st->hpi1 = 0.0f; + st->hpi2 = 0.0f; + st->hpi3 = 0.0f; + st->rmso_bsynz = 0.0f; + + /* State used by function random */ + st->j = 2; + st->k = 5; + st->y[0] = (shortint) -21161; + st->y[1] = (shortint) -8478; + st->y[2] = (shortint) 30892; + st->y[3] = (shortint) -10216; + st->y[4] = (shortint) 16950; + + /* State used by function deemp */ + st->dei1 = 0.0f; + st->dei2 = 0.0f; + st->deo1 = 0.0f; + st->deo2 = 0.0f; + st->deo3 = 0.0f; +} diff --git a/linphone/lpc10-1.5/lpfilt.c b/linphone/lpc10-1.5/lpfilt.c new file mode 100644 index 000000000..218140c2e --- /dev/null +++ b/linphone/lpc10-1.5/lpfilt.c @@ -0,0 +1,113 @@ +/* + +$Log: lpfilt.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:35 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int lpfilt_(real *inbuf, real *lpbuf, integer *len, integer *nsamp); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* *********************************************************************** */ + +/* LPFILT Version 55 */ + +/* $Log: lpfilt.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:35 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/15 16:53:49 jaf */ +/* Just put comment header in standard form. */ + +/* Revision 1.2 1996/03/12 23:58:06 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:47:44 jaf */ +/* Initial revision */ + + +/* *********************************************************************** */ + +/* 31 Point Equiripple FIR Low-Pass Filter */ +/* Linear phase, delay = 15 samples */ + +/* Passband: ripple = 0.25 dB, cutoff = 800 Hz */ +/* Stopband: atten. = 40. dB, cutoff = 1240 Hz */ + +/* Inputs: */ +/* LEN - Length of speech buffers */ +/* NSAMP - Number of samples to filter */ +/* INBUF - Input speech buffer */ +/* Indices len-nsamp-29 through len are read. */ +/* Output: */ +/* LPBUF - Low passed speech buffer (must be different array than INBUF) */ +/* Indices len+1-nsamp through len are written. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int lpfilt_(real *inbuf, real *lpbuf, integer *len, integer * + nsamp) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + integer j; + real t; + +/* Arguments */ +/* Parameters/constants */ +/* Local variables that need not be saved */ +/* Local state */ +/* None */ + /* Parameter adjustments */ + --lpbuf; + --inbuf; + + /* Function Body */ + i__1 = *len; + for (j = *len + 1 - *nsamp; j <= i__1; ++j) { + t = (inbuf[j] + inbuf[j - 30]) * -.0097201988f; + t += (inbuf[j - 1] + inbuf[j - 29]) * -.0105179986f; + t += (inbuf[j - 2] + inbuf[j - 28]) * -.0083479648f; + t += (inbuf[j - 3] + inbuf[j - 27]) * 5.860774e-4f; + t += (inbuf[j - 4] + inbuf[j - 26]) * .0130892089f; + t += (inbuf[j - 5] + inbuf[j - 25]) * .0217052232f; + t += (inbuf[j - 6] + inbuf[j - 24]) * .0184161253f; + t += (inbuf[j - 7] + inbuf[j - 23]) * 3.39723e-4f; + t += (inbuf[j - 8] + inbuf[j - 22]) * -.0260797087f; + t += (inbuf[j - 9] + inbuf[j - 21]) * -.0455563702f; + t += (inbuf[j - 10] + inbuf[j - 20]) * -.040306855f; + t += (inbuf[j - 11] + inbuf[j - 19]) * 5.029835e-4f; + t += (inbuf[j - 12] + inbuf[j - 18]) * .0729262903f; + t += (inbuf[j - 13] + inbuf[j - 17]) * .1572008878f; + t += (inbuf[j - 14] + inbuf[j - 16]) * .2247288674f; + t += inbuf[j - 15] * .250535965f; + lpbuf[j] = t; + } + return 0; +} /* lpfilt_ */ + diff --git a/linphone/lpc10-1.5/median.c b/linphone/lpc10-1.5/median.c new file mode 100644 index 000000000..b6ee59aff --- /dev/null +++ b/linphone/lpc10-1.5/median.c @@ -0,0 +1,77 @@ +/* + +$Log: median.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:31 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern integer median_(integer *d1, integer *d2, integer *d3); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************* */ + +/* MEDIAN Version 45G */ + +/* $Log: median.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:31 jaf + * Initial revision + * */ +/* Revision 1.2 1996/03/14 22:30:22 jaf */ +/* Just rearranged the comments and local variable declarations a bit. */ + +/* Revision 1.1 1996/02/07 14:47:53 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Find median of three values */ + +/* Input: */ +/* D1,D2,D3 - Three input values */ +/* Output: */ +/* MEDIAN - Median value */ + +integer median_(integer *d1, integer *d2, integer *d3) +{ + /* System generated locals */ + integer ret_val; + +/* Arguments */ + ret_val = *d2; + if (*d2 > *d1 && *d2 > *d3) { + ret_val = *d1; + if (*d3 > *d1) { + ret_val = *d3; + } + } else if (*d2 < *d1 && *d2 < *d3) { + ret_val = *d1; + if (*d3 < *d1) { + ret_val = *d3; + } + } + return ret_val; +} /* median_ */ + diff --git a/linphone/lpc10-1.5/mload.c b/linphone/lpc10-1.5/mload.c new file mode 100644 index 000000000..004a05897 --- /dev/null +++ b/linphone/lpc10-1.5/mload.c @@ -0,0 +1,151 @@ +/* + +$Log: mload.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:25 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int mload_(integer *order, integer *awins, integer *awinf, real *speech, real *phi, real *psi); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ***************************************************************** */ + +/* MLOAD Version 48 */ + +/* $Log: mload.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:25 jaf + * Initial revision + * */ +/* Revision 1.5 1996/03/27 23:59:51 jaf */ +/* Added some more accurate comments about which indices of the argument */ +/* array SPEECH are read. I thought that this might be the cause of a */ +/* problem I've been having, but it isn't. */ + +/* Revision 1.4 1996/03/26 19:16:53 jaf */ +/* Commented out the code at the end that copied the lower triangular */ +/* half of PHI into the upper triangular half (making the resulting */ +/* matrix symmetric). The upper triangular half was never used by later */ +/* code in subroutine ANALYS. */ + +/* Revision 1.3 1996/03/18 21:16:00 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 16:47:41 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:48:01 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Load a covariance matrix. */ + +/* Input: */ +/* ORDER - Analysis order */ +/* AWINS - Analysis window start */ +/* AWINF - Analysis window finish */ +/* SPEECH(AWINF) - Speech buffer */ +/* Indices MIN(AWINS, AWINF-(ORDER-1)) through */ +/* MAX(AWINF, AWINS+(ORDER-1)) read. */ +/* As long as (AWINF-AWINS) .GE. (ORDER-1), */ +/* this is just indices AWINS through AWINF. */ +/* Output: */ +/* PHI(ORDER,ORDER) - Covariance matrix */ +/* Lower triangular half and diagonal written, and read.*/ +/* Upper triangular half untouched. */ +/* PSI(ORDER) - Prediction vector */ +/* Indices 1 through ORDER written, */ +/* and most are read after that. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int mload_(integer *order, integer *awins, integer *awinf, + real *speech, real *phi, real *psi) +{ + /* System generated locals */ + integer phi_dim1, phi_offset, i__1, i__2; + + /* Local variables */ + integer c__, i__, r__, start; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Load first column of triangular covariance matrix PHI */ + /* Parameter adjustments */ + --psi; + phi_dim1 = *order; + phi_offset = phi_dim1 + 1; + phi -= phi_offset; + --speech; + + /* Function Body */ + start = *awins + *order; + i__1 = *order; + for (r__ = 1; r__ <= i__1; ++r__) { + phi[r__ + phi_dim1] = 0.f; + i__2 = *awinf; + for (i__ = start; i__ <= i__2; ++i__) { + phi[r__ + phi_dim1] += speech[i__ - 1] * speech[i__ - r__]; + } + } +/* Load last element of vector PSI */ + psi[*order] = 0.f; + i__1 = *awinf; + for (i__ = start; i__ <= i__1; ++i__) { + psi[*order] += speech[i__] * speech[i__ - *order]; + } +/* End correct to get additional columns of PHI */ + i__1 = *order; + for (r__ = 2; r__ <= i__1; ++r__) { + i__2 = r__; + for (c__ = 2; c__ <= i__2; ++c__) { + phi[r__ + c__ * phi_dim1] = phi[r__ - 1 + (c__ - 1) * phi_dim1] - + speech[*awinf + 1 - r__] * speech[*awinf + 1 - c__] + + speech[start - r__] * speech[start - c__]; + } + } +/* End correct to get additional elements of PSI */ + i__1 = *order - 1; + for (c__ = 1; c__ <= i__1; ++c__) { + psi[c__] = phi[c__ + 1 + phi_dim1] - speech[start - 1] * speech[start + - 1 - c__] + speech[*awinf] * speech[*awinf - c__]; + } +/* Copy lower triangular section into upper (why bother?) */ +/* I'm commenting this out, since the upper triangular half of PHI +*/ +/* is never used by later code, unless a sufficiently high level of +*/ +/* tracing is turned on. */ +/* DO R = 1,ORDER */ +/* DO C = 1,R-1 */ +/* PHI(C,R) = PHI(R,C) */ +/* END DO */ +/* END DO */ + return 0; +} /* mload_ */ + diff --git a/linphone/lpc10-1.5/onset.c b/linphone/lpc10-1.5/onset.c new file mode 100644 index 000000000..e1b97a043 --- /dev/null +++ b/linphone/lpc10-1.5/onset.c @@ -0,0 +1,306 @@ +/* + +$Log: onset.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:37:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:31:18 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int onset_(real *pebuf, integer *osbuf, integer *osptr, integer *oslen, integer *sbufl, integer *sbufh, integer *lframe, struct lpc10_encoder_state *st); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Table of constant values */ + +static real c_b2 = 1.f; + +/* ****************************************************************** */ + +/* ONSET Version 49 */ + +/* $Log: onset.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:37:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:31:18 jaf + * Initial revision + * */ +/* Revision 1.5 1996/03/15 16:41:01 jaf */ +/* Just rearranged INITONSET assignment orders to be consistent with */ +/* order of DATA statements in ONSET. */ + +/* Revision 1.4 1996/03/15 15:48:27 jaf */ +/* Changed some comments, and only reordered the DATA statements (their */ +/* meaning wasn't changed). */ + +/* Revision 1.3 1996/03/14 23:53:06 jaf */ +/* Added an entry INITONSET that reinitializes the local state variables */ +/* of subroutine ONSET. */ + +/* Rearranged quite a few comments, adding more explaining which */ +/* arguments were inputs, and how the modified ones can be changed. */ + +/* Revision 1.2 1996/03/12 23:53:00 jaf */ +/* Lots of comments added about the local state of this subroutine that */ +/* must be saved from one invocation to the next. */ + +/* One constant 180 replaced with LFRAME, which should be "more general", */ +/* even though it would probably require many more changes than this to */ +/* get this coder to work for other frame sizes. */ + +/* Revision 1.1 1996/02/07 14:48:09 jaf */ +/* Initial revision */ + + +/* ****************************************************************** */ + +/* Floating point version */ + + +/* Detection of onsets in (or slightly preceding) the futuremost frame */ +/* of speech. */ + + +/* Input: */ +/* PEBUF(SBUFL:SBUFH) - Preemphasized speech */ +/* Indices SBUFH-LFRAME through SBUFH are read. */ +/* OSLEN - Maximum number of onsets that can be stored in OSBUF. */ +/* SBUFL, SBUFH - Range of PEBUF */ +/* LFRAME - length of a frame, in samples */ +/* Input/Output: */ +/* OSBUF(OSLEN) - Buffer which holds sorted indexes of onsets */ +/* Indices A through B are modified, where A */ +/* is the original value of OSPTR, and B is the final */ +/* value of OSPTR-1. B is at most OSLEN. */ +/* OSPTR - Free pointer into OSBUF */ +/* Initial value should be .LE. OSLEN+1. */ +/* If so, final value grows by one for each new onset */ +/* found, and final value will be .LE. OSLEN+1. */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this subroutine, or */ +/* reinitialize its state for any other reason, call the ENTRY INITONSET. */ + +/* Subroutine */ int onset_(real *pebuf, integer *osbuf, integer * + osptr, integer *oslen, integer *sbufl, integer *sbufh, integer * + lframe, struct lpc10_encoder_state *st) +{ + /* Initialized data */ + + real *n; + real *d__; + real *l2buf; + real *l2sum1; + integer *l2ptr1; + integer *l2ptr2; + logical *hyst; + + /* System generated locals */ + integer pebuf_offset, i__1; + real r__1; + + /* Builtin functions */ + double r_sign(real *, real *); + + /* Local variables */ + integer i__; + integer *lasti; + real l2sum2; + real *fpc; + +/* Arguments */ +/* $Log: onset.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:15 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:37:55 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:31:18 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Parameters/constants */ +/* Parameters for onset detection algorithm: */ +/* L2 Threshold for filtered slope of FPC (function of L2WID!) */ +/* L2LAG Lag due to both filters which compute filtered slope of FPC */ +/* L2WID Width of the filter which computes the slope of FPC */ +/* OSHYST The number of samples of slope(FPC) which must be below */ +/* the threshold before a new onset may be declared. */ +/* Local variables that need not be saved */ +/* Local state */ +/* Variables */ +/* N, D Numerator and denominator of prediction filters */ +/* FPC Current prediction coefs */ +/* L2BUF, L2SUM1, L2SUM2 State of slope filter */ +/* The only "significant" change I've made is to change L2SUM2 out +*/ +/* of the list of local variables that need to be saved, since it */ +/* didn't need to be. */ +/* L2SUM1 need not be, but avoiding saving it would require a small +*/ +/* change to the body of the code. See comments below for an */ +/* example of how the code could be changed to avoid saving L2SUM1. +*/ +/* FPC and LASTI are saved from one invocation to the next, but */ +/* they are not given initial values. This is acceptable, because +*/ +/* FPC will be assigned a value the first time that this function */ +/* is called after D is initialized to 1, since the formula to */ +/* change D will not change it to 0 in one step, and the IF (D */ +/* .NE. 0) statement will execute its THEN part, initializing FPC. +*/ + +/* LASTI's value will not be used until HYST is .TRUE., and */ +/* whenever HYST is changed from its initial value of .FALSE., */ +/* LASTI is assigned a value. */ +/* In a C version of this coder, it would be nice if all of these */ +/* saved things, in this and all other subroutines, could be stored +*/ +/* in a single struct lpc10_coder_state_t, initialized with a call +*/ +/* to a function like lpc10_init(&lpc10_coder_state). In this way, +*/ +/* a program that used these functions could conveniently alternate +*/ +/* coding more than one distinct audio stream. */ + + n = &(st->n); + d__ = &(st->d__); + fpc = &(st->fpc); + l2buf = &(st->l2buf[0]); + l2sum1 = &(st->l2sum1); + l2ptr1 = &(st->l2ptr1); + l2ptr2 = &(st->l2ptr2); + lasti = &(st->lasti); + hyst = &(st->hyst); + + /* Parameter adjustments */ + if (osbuf) { + --osbuf; + } + if (pebuf) { + pebuf_offset = *sbufl; + pebuf -= pebuf_offset; + } + + /* Function Body */ + +/* The following line subtracted a hard-coded "180" from LASTI, */ +/* instead of using a variable like LFRAME or a constant like */ +/* MAXFRM. I changed it to LFRAME, for "generality". */ + if (*hyst) { + *lasti -= *lframe; + } + i__1 = *sbufh; + for (i__ = *sbufh - *lframe + 1; i__ <= i__1; ++i__) { +/* Compute FPC; Use old FPC on divide by zero; Clamp FPC to +/- 1. +*/ + *n = (pebuf[i__] * pebuf[i__ - 1] + (*n) * 63.f) / 64.f; +/* Computing 2nd power */ + r__1 = pebuf[i__ - 1]; + *d__ = (r__1 * r__1 + (*d__) * 63.f) / 64.f; + if ((*d__) != 0.f) { + if (abs(*n) > (*d__)) { + *fpc = r_sign(&c_b2, n); + } else { + *fpc = (*n) / (*d__); + } + } +/* Filter FPC */ +/* In order to allow L2SUM1 not to be saved from one invocation +of */ +/* this subroutine to the next, one could change the sequence of + */ +/* assignments below, up to the IF statement, to the following. + In */ +/* addition, the initial value of L2PTR2 should be changed to */ +/* L2WID/2 instead of L2WID/2+1. */ + +/* L2SUM1 = L2BUF(L2PTR2) */ +/* L2PTR2 = MOD(L2PTR2,L2WID)+1 */ +/* L2SUM1 = L2SUM1 - L2BUF(L2PTR2) + FPC */ +/* L2BUF(L2PTR2) = L2SUM1 */ + +/* * The following lines didn't change from the original: */ +/* L2SUM2 = L2BUF(L2PTR1) */ +/* L2BUF(L2PTR1) = FPC */ +/* L2PTR1 = MOD(L2PTR1,L2WID)+1 */ + + l2sum2 = l2buf[*l2ptr1 - 1]; + *l2sum1 = *l2sum1 - l2buf[*l2ptr2 - 1] + *fpc; + l2buf[*l2ptr2 - 1] = *l2sum1; + l2buf[*l2ptr1 - 1] = *fpc; + *l2ptr1 = *l2ptr1 % 16 + 1; + *l2ptr2 = *l2ptr2 % 16 + 1; + if ((r__1 = *l2sum1 - l2sum2, abs(r__1)) > 1.7f) { + if (! (*hyst)) { +/* Ignore if buffer full */ + if (*osptr <= *oslen) { + osbuf[*osptr] = i__ - 9; + ++(*osptr); + } + *hyst = TRUE_; + } + *lasti = i__; +/* After one onset detection, at least OSHYST sample times m +ust go */ +/* by before another is allowed to occur. */ + } else if ((*hyst) && i__ - *lasti >= 10) { + *hyst = FALSE_; + } + } + return 0; +} /* onset_ */ diff --git a/linphone/lpc10-1.5/pitsyn.c b/linphone/lpc10-1.5/pitsyn.c new file mode 100644 index 000000000..a4765a7bb --- /dev/null +++ b/linphone/lpc10-1.5/pitsyn.c @@ -0,0 +1,556 @@ +/* + +$Log: pitsyn.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:40:12 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:31:12 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int pitsyn_(integer *order, integer *voice, integer *pitch, real *rms, real *rc, integer *lframe, integer *ivuv, integer *ipiti, real *rmsi, real *rci, integer *nout, real *ratio, struct lpc10_decoder_state *st); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ***************************************************************** */ + +/* PITSYN Version 53 */ + +/* $Log: pitsyn.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:40:12 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:31:12 jaf + * Initial revision + * */ +/* Revision 1.2 1996/03/25 18:49:07 jaf */ +/* Added commments about which indices of array arguments are read or */ +/* written. */ + +/* Rearranged local variable declarations to indicate which need to be */ +/* saved from one invocation to the next. Added entry INITPITSYN to */ +/* reinitialize local state variables, if desired. */ + +/* Added lots of comments about proving that the maximum number of pitch */ +/* periods (NOUT) that can be returned is 16. The call to STOP that */ +/* could happen if NOUT got too large was removed as a result. */ + +/* Also proved that the total number of samples returned from N calls, */ +/* each with identical values of LFRAME, will always be in the range */ +/* N*LFRAME-MAXPIT+1 to N*LFRAME. */ + +/* Revision 1.1 1996/02/07 14:48:18 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* Synthesize a single pitch epoch */ + +/* Input: */ +/* ORDER - Synthesis order (number of RC's) */ +/* VOICE - Half frame voicing decisions */ +/* Indices 1 through 2 read. */ +/* LFRAME - Length of speech buffer */ +/* Input/Output: */ +/* PITCH - Pitch */ +/* This value should be in the range MINPIT (20) to MAXPIT */ +/* (156), inclusive. */ +/* PITCH can be modified under some conditions. */ +/* RMS - Energy (can be modified) */ +/* RMS is changed to 1 if the value passed in is less than 1. */ +/* RC - Reflection coefficients */ +/* Indices 1 through ORDER can be temporarily overwritten with */ +/* RCO, and then replaced with original values, under some */ +/* conditions. */ +/* Output: */ +/* IVUV - Pitch epoch voicing decisions */ +/* Indices (I) of IVUV, IPITI, and RMSI are written, */ +/* and indices (J,I) of RCI are written, */ +/* where I ranges from 1 to NOUT, and J ranges from 1 to ORDER. */ +/* IPITI - Pitch epoch length */ +/* RMSI - Pitch epoch energy */ +/* RCI - Pitch epoch RC's */ +/* NOUT - Number of pitch periods in this frame */ +/* This is at least 0, at least 1 if MAXPIT .LT. LFRAME (this */ +/* is currently true on every call), and can never be more than */ +/* (LFRAME+MAXPIT-1)/PITCH, which is currently 16 with */ +/* LFRAME=180, MAXPIT=156, and PITCH .GE. 20, as SYNTHS */ +/* guarantees when it calls this subroutine. */ +/* RATIO - Previous to present energy ratio */ +/* Always assigned a value. */ + +/* Subroutine */ int pitsyn_(integer *order, integer *voice, + integer *pitch, real *rms, real *rc, integer *lframe, integer *ivuv, + integer *ipiti, real *rmsi, real *rci, integer *nout, real *ratio, + struct lpc10_decoder_state *st) +{ + /* Initialized data */ + + real *rmso; + logical *first; + + /* System generated locals */ + integer rci_dim1, rci_offset, i__1, i__2; + real r__1; + + /* Builtin functions */ + double log(doublereal), exp(doublereal); + + /* Local variables */ + real alrn, alro, yarc[10], prop; + integer i__, j, vflag, jused, lsamp; + integer *jsamp; + real slope; + integer *ipito; + real uvpit; + integer ip, nl, ivoice; + integer *ivoico; + integer istart; + real *rco; + real xxy; + +/* Arguments */ +/* $Log: pitsyn.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:40:12 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:31:12 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Local variables that need not be saved */ +/* LSAMP is initialized in the IF (FIRST) THEN clause, but it is */ +/* not used the first time through, and it is given a value before +*/ +/* use whenever FIRST is .FALSE., so it appears unnecessary to */ +/* assign it a value when FIRST is .TRUE. */ +/* Local state */ +/* FIRST - .TRUE. only on first call to PITSYN. */ +/* IVOICO - Previous VOICE(2) value. */ +/* IPITO - Previous PITCH value. */ +/* RMSO - Previous RMS value. */ +/* RCO - Previous RC values. */ + +/* JSAMP - If this routine is called N times with identical values of */ +/* LFRAME, then the total length of all pitch periods returned */ +/* is always N*LFRAME-JSAMP, and JSAMP is always in the range 0 +*/ +/* to MAXPIT-1 (see below for why this is so). Thus JSAMP is */ +/* the number of samples "left over" from the previous call to */ +/* PITSYN, that haven't been "used" in a pitch period returned */ +/* from this subroutine. Every time this subroutine is called, +*/ +/* it returns pitch periods with a total length of at most */ +/* LFRAME+JSAMP. */ + +/* IVOICO, IPITO, RCO, and JSAMP need not be assigned an initial value */ +/* with a DATA statement, because they are always initialized on the */ +/* first call to PITSYN. */ + +/* FIRST and RMSO should be initialized with DATA statements, because */ +/* even on the first call, they are used before being initialized. */ + /* Parameter adjustments */ + if (rc) { + --rc; + } + if (rci) { + rci_dim1 = *order; + rci_offset = rci_dim1 + 1; + rci -= rci_offset; + } + if (voice) { + --voice; + } + if (ivuv) { + --ivuv; + } + if (ipiti) { + --ipiti; + } + if (rmsi) { + --rmsi; + } + + /* Function Body */ + ivoico = &(st->ivoico); + ipito = &(st->ipito); + rmso = &(st->rmso); + rco = &(st->rco[0]); + jsamp = &(st->jsamp); + first = &(st->first_pitsyn); + + if (*rms < 1.f) { + *rms = 1.f; + } + if (*rmso < 1.f) { + *rmso = 1.f; + } + uvpit = 0.f; + *ratio = *rms / (*rmso + 8.f); + if (*first) { + lsamp = 0; + ivoice = voice[2]; + if (ivoice == 0) { + *pitch = *lframe / 4; + } + *nout = *lframe / *pitch; + *jsamp = *lframe - *nout * *pitch; + +/* SYNTHS only calls this subroutine with PITCH in the range +20 */ +/* to 156. LFRAME = MAXFRM = 180, so NOUT is somewhere in th +e */ +/* range 1 to 9. */ + +/* JSAMP is "LFRAME mod PITCH", so it is in the range 0 to */ +/* (PITCH-1), or 0 to MAXPIT-1=155, after the first call. */ + + i__1 = *nout; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *order; + for (j = 1; j <= i__2; ++j) { + rci[j + i__ * rci_dim1] = rc[j]; + } + ivuv[i__] = ivoice; + ipiti[i__] = *pitch; + rmsi[i__] = *rms; + } + *first = FALSE_; + } else { + vflag = 0; + lsamp = *lframe + *jsamp; + slope = (*pitch - *ipito) / (real) lsamp; + *nout = 0; + jused = 0; + istart = 1; + if (voice[1] == *ivoico && voice[2] == voice[1]) { + if (voice[2] == 0) { +/* SSUV - - 0 , 0 , 0 */ + *pitch = *lframe / 4; + *ipito = *pitch; + if (*ratio > 8.f) { + *rmso = *rms; + } + } +/* SSVC - - 1 , 1 , 1 */ + slope = (*pitch - *ipito) / (real) lsamp; + ivoice = voice[2]; + } else { + if (*ivoico != 1) { + if (*ivoico == voice[1]) { +/* UV2VC2 - - 0 , 0 , 1 */ + nl = lsamp - *lframe / 4; + } else { +/* UV2VC1 - - 0 , 1 , 1 */ + nl = lsamp - *lframe * 3 / 4; + } + ipiti[1] = nl / 2; + ipiti[2] = nl - ipiti[1]; + ivuv[1] = 0; + ivuv[2] = 0; + rmsi[1] = *rmso; + rmsi[2] = *rmso; + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + rci[i__ + rci_dim1] = rco[i__ - 1]; + rci[i__ + (rci_dim1 << 1)] = rco[i__ - 1]; + rco[i__ - 1] = rc[i__]; + } + slope = 0.f; + *nout = 2; + *ipito = *pitch; + jused = nl; + istart = nl + 1; + ivoice = 1; + } else { + if (*ivoico != voice[1]) { +/* VC2UV1 - - 1 , 0 , 0 */ + lsamp = *lframe / 4 + *jsamp; + } else { +/* VC2UV2 - - 1 , 1 , 0 */ + lsamp = *lframe * 3 / 4 + *jsamp; + } + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + yarc[i__ - 1] = rc[i__]; + rc[i__] = rco[i__ - 1]; + } + ivoice = 1; + slope = 0.f; + vflag = 1; + } + } +/* Here is the value of most variables that are used below, depending +on */ +/* the values of IVOICO, VOICE(1), and VOICE(2). VOICE(1) and VOICE(2 +) */ +/* are input arguments, and IVOICO is the value of VOICE(2) on the */ +/* previous call (see notes for the IF (NOUT .NE. 0) statement near th +e */ +/* end). Each of these three values is either 0 or 1. These three */ +/* values below are given as 3-bit long strings, in the order IVOICO, +*/ +/* VOICE(1), and VOICE(2). It appears that the code above assumes tha +t */ +/* the bit sequences 010 and 101 never occur, but I wonder whether a +*/ +/* large enough number of bit errors in the channel could cause such a + */ +/* thing to happen, and if so, could that cause NOUT to ever go over 1 +1? */ + +/* Note that all of the 180 values in the table are really LFRAME, but + */ +/* 180 has fewer characters, and it makes the table a little more */ +/* concrete. If LFRAME is ever changed, keep this in mind. Similarly +, */ +/* 135's are 3*LFRAME/4, and 45's are LFRAME/4. If LFRAME is not a */ +/* multiple of 4, then the 135 for NL-JSAMP is actually LFRAME-LFRAME/ +4, */ +/* and the 45 for NL-JSAMP is actually LFRAME-3*LFRAME/4. */ + +/* Note that LSAMP-JSAMP is given as the variable. This was just for +*/ +/* brevity, to avoid adding "+JSAMP" to all of the column entries. */ +/* Similarly for NL-JSAMP. */ + +/* Variable | 000 001 011,010 111 110 100,101 */ +/* ------------+-------------------------------------------------- */ +/* ISTART | 1 NL+1 NL+1 1 1 1 */ +/* LSAMP-JSAMP | 180 180 180 180 135 45 */ +/* IPITO | 45 PITCH PITCH oldPITCH oldPITCH oldPITCH */ +/* SLOPE | 0 0 0 seebelow 0 0 */ +/* JUSED | 0 NL NL 0 0 0 */ +/* PITCH | 45 PITCH PITCH PITCH PITCH PITCH */ +/* NL-JSAMP | -- 135 45 -- -- -- */ +/* VFLAG | 0 0 0 0 1 1 */ +/* NOUT | 0 2 2 0 0 0 */ +/* IVOICE | 0 1 1 1 1 1 */ + +/* while_loop | once once once once twice twice */ + +/* ISTART | -- -- -- -- JUSED+1 JUSED+1 */ +/* LSAMP-JSAMP | -- -- -- -- 180 180 */ +/* IPITO | -- -- -- -- oldPITCH oldPITCH */ +/* SLOPE | -- -- -- -- 0 0 */ +/* JUSED | -- -- -- -- ?? ?? */ +/* PITCH | -- -- -- -- PITCH PITCH */ +/* NL-JSAMP | -- -- -- -- -- -- */ +/* VFLAG | -- -- -- -- 0 0 */ +/* NOUT | -- -- -- -- ?? ?? */ +/* IVOICE | -- -- -- -- 0 0 */ + + +/* UVPIT is always 0.0 on the first pass through the DO WHILE (.TRUE.) + */ +/* loop below. */ + +/* The only possible non-0 value of SLOPE (in column 111) is */ +/* (PITCH-IPITO)/FLOAT(LSAMP) */ + +/* Column 101 is identical to 100. Any good properties we can prove +*/ +/* for 100 will also hold for 101. Similarly for 010 and 011. */ + +/* SYNTHS calls this subroutine with PITCH restricted to the range 20 +to */ +/* 156. IPITO is similarly restricted to this range, after the first +*/ +/* call. IP below is also restricted to this range, given the */ +/* definitions of IPITO, SLOPE, UVPIT, and that I is in the range ISTA +RT */ +/* to LSAMP. */ + + while(TRUE_) { + +/* JUSED is the total length of all pitch periods curr +ently */ +/* in the output arrays, in samples. */ + +/* An invariant of the DO I = ISTART,LSAMP loop below, + under */ +/* the condition that IP is always in the range 1 thro +ugh */ +/* MAXPIT, is: */ + +/* (I - MAXPIT) .LE. JUSED .LE. (I-1) */ + +/* Note that the final value of I is LSAMP+1, so that +after */ +/* the DO loop is complete, we know: */ + +/* (LSAMP - MAXPIT + 1) .LE. JUSED .LE. LSAMP */ + + i__1 = lsamp; + for (i__ = istart; i__ <= i__1; ++i__) { + r__1 = *ipito + slope * i__; + ip = r__1 + .5f; + if (uvpit != 0.f) { + ip = uvpit; + } + if (ip <= i__ - jused) { + ++(*nout); + +/* The following check is no longer nece +ssary, now that */ +/* we can prove that NOUT will never go +over 16. */ + +/* IF (NOUT .GT. 16) STOP 'PITSYN: too many epochs' +*/ + + ipiti[*nout] = ip; + *pitch = ip; + ivuv[*nout] = ivoice; + jused += ip; + prop = (jused - ip / 2) / (real) lsamp; + i__2 = *order; + for (j = 1; j <= i__2; ++j) { + alro = log((rco[j - 1] + 1) / (1 - rco[j - 1])); + alrn = log((rc[j] + 1) / (1 - rc[j])); + xxy = alro + prop * (alrn - alro); + xxy = exp(xxy); + rci[j + *nout * rci_dim1] = (xxy - 1) / (xxy + 1); + } + rmsi[*nout] = log(*rmso) + prop * (log(*rms) - log(*rmso)); + rmsi[*nout] = exp(rmsi[*nout]); + } + } + if (vflag != 1) { + goto L100; + } + +/* I want to prove what range UVPIT must lie in after +the */ +/* assignments to it below. To do this, I must determ +ine */ +/* what range (LSAMP-ISTART) must lie in, after the */ +/* assignments to ISTART and LSAMP below. */ + +/* Let oldLSAMP be the value of LSAMP at this point in + the */ +/* execution. This is 135+JSAMP in state 110, or 45+J +SAMP in */ +/* states 100 or 101. */ + +/* Given the loop invariant on JUSED above, we know th +at: */ + +/* (oldLSAMP - MAXPIT + 1) .LE. JUSED .LE. oldLSAMP */ + +/* ISTART is one more than this. */ + +/* Let newLSAMP be the value assigned to LSAMP below. + This */ +/* is 180+JSAMP. Thus (newLSAMP-oldLSAMP) is either 4 +5 or */ +/* 135, depending on the state. */ + +/* Thus, the range of newLSAMP-ISTART is: */ + +/* (newLSAMP-(oldLSAMP+1)) .LE. newLSAMP-ISTART */ +/* .LE. (newLSAMP-(oldLSAMP - MAXPIT + 2)) */ + +/* or: */ + +/* 46 .LE. newLSAMP-ISTART .LE. 133+MAXPIT .EQ. 289 */ + +/* Therefore, UVPIT is in the range 23 to 144 after th +e first */ +/* assignment to UVPIT below, and after the conditiona +l */ +/* assignment, it is in the range 23 to 90. */ + +/* The important thing is that it is in the range 20 t +o 156, */ +/* so that in the loop above, IP is always in this ran +ge. */ + + vflag = 0; + istart = jused + 1; + lsamp = *lframe + *jsamp; + slope = 0.f; + ivoice = 0; + uvpit = (real) ((lsamp - istart) / 2); + if (uvpit > 90.f) { + uvpit /= 2; + } + *rmso = *rms; + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + rc[i__] = yarc[i__ - 1]; + rco[i__ - 1] = yarc[i__ - 1]; + } + } +L100: + *jsamp = lsamp - jused; + } +/* Given that the maximum pitch period MAXPIT .LT. LFRAME (this is +*/ +/* currently true on every call, since SYNTHS always sets */ +/* LFRAME=180), NOUT will always be .GE. 1 at this point. */ + if (*nout != 0) { + *ivoico = voice[2]; + *ipito = *pitch; + *rmso = *rms; + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + rco[i__ - 1] = rc[i__]; + } + } + return 0; +} /* pitsyn_ */ diff --git a/linphone/lpc10-1.5/placea.c b/linphone/lpc10-1.5/placea.c new file mode 100644 index 000000000..0336f7fa3 --- /dev/null +++ b/linphone/lpc10-1.5/placea.c @@ -0,0 +1,218 @@ +/* + +$Log: placea.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:07 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int placea_(integer *ipitch, integer *voibuf, integer *obound, integer *af, integer *vwin, integer *awin, integer *ewin, integer *lframe, integer *maxwin); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* *********************************************************************** */ + +/* PLACEA Version 48 */ + +/* $Log: placea.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:07 jaf + * Initial revision + * */ +/* Revision 1.5 1996/03/19 20:41:55 jaf */ +/* Added some conditions satisfied by the output values in EWIN. */ + +/* Revision 1.4 1996/03/19 20:24:17 jaf */ +/* Added some conditions satisfied by the output values in AWIN. */ + +/* Revision 1.3 1996/03/18 21:40:04 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 16:43:09 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:48:31 jaf */ +/* Initial revision */ + + +/* *********************************************************************** */ +/* Input: */ +/* IPITCH */ +/* VOIBUF */ +/* Indices (2,AF-2), (1,AF-1), (2,AF-1), (1,AF), and (2,AF) read.*/ +/* All other indices untouched. */ +/* OBOUND */ +/* AF */ +/* VWIN */ +/* Indices (1,AF) and (2,AF) read. */ +/* All other indices untouched. */ +/* LFRAME */ +/* MAXWIN */ +/* Input/Output: */ +/* AWIN */ +/* Index (1,AF-1) read. */ +/* Indices (1,AF) and (2,AF) written, and then read. */ +/* All other indices untouched. */ +/* In all cases (except possibly one), the final values will */ +/* satisfy the condition: AWIN(2,AF)-AWIN(1,AF)+1 = MAXWIN. */ +/* In that other case, */ +/* AWIN(1,AF)=VWIN(1,AF) and AWIN(2,AF)=VWIN(2,AF). */ +/* Output: */ +/* EWIN */ +/* Indices (1,AF) and (2,AF) written. */ +/* All other indices untouched. */ +/* In all cases, the final values will satisfy the condition: */ +/* AWIN(1,AF) .LE. EWIN(1,AF) .LE. EWIN(2,AF) .LE. AWIN(2,AF) */ +/* In other words, the energy window is a sub-window of */ +/* the analysis window. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int placea_(integer *ipitch, integer *voibuf, integer * + obound, integer *af, integer *vwin, integer *awin, integer *ewin, + integer *lframe, integer *maxwin) +{ + /* System generated locals */ + real r__1; + + /* Builtin functions */ + integer i_nint(real *); + + /* Local variables */ + logical allv, winv; + integer i__, j, k, l, hrange; + logical ephase; + integer lrange; + +/* Arguments */ +/* Local variables that need not be saved */ + /* Parameter adjustments */ + ewin -= 3; + awin -= 3; + vwin -= 3; + --voibuf; + + /* Function Body */ + lrange = (*af - 2) * *lframe + 1; + hrange = *af * *lframe; +/* Place the Analysis window based on the voicing window */ +/* placement, onsets, tentative voicing decision, and pitch. */ + +/* Case 1: Sustained Voiced Speech */ +/* If the five most recent voicing decisions are */ +/* voiced, then the window is placed phase-synchronously with the */ +/* previous window, as close to the present voicing window if possible. +*/ +/* If onsets bound the voicing window, then preference is given to */ +/* a phase-synchronous placement which does not overlap these onsets. */ + +/* Case 2: Voiced Transition */ +/* If at least one voicing decision in AF is voicied, and there are no +*/ +/* onsets, then the window is placed as in case 1. */ + +/* Case 3: Unvoiced Speech or Onsets */ +/* If both voicing decisions in AF are unvoiced, or there are onsets, */ +/* then the window is placed coincident with the voicing window. */ + +/* Note: During phase-synchronous placement of windows, the length */ +/* is not altered from MAXWIN, since this would defeat the purpose */ +/* of phase-synchronous placement. */ +/* Check for case 1 and case 2 */ + allv = voibuf[(*af - 2 << 1) + 2] == 1; + allv = allv && voibuf[(*af - 1 << 1) + 1] == 1; + allv = allv && voibuf[(*af - 1 << 1) + 2] == 1; + allv = allv && voibuf[(*af << 1) + 1] == 1; + allv = allv && voibuf[(*af << 1) + 2] == 1; + winv = voibuf[(*af << 1) + 1] == 1 || voibuf[(*af << 1) + 2] == 1; + if (allv || winv && *obound == 0) { +/* APHASE: Phase synchronous window placement. */ +/* Get minimum lower index of the window. */ + i__ = (lrange + *ipitch - 1 - awin[(*af - 1 << 1) + 1]) / *ipitch; + i__ *= *ipitch; + i__ += awin[(*af - 1 << 1) + 1]; +/* L = the actual length of this frame's analysis window. */ + l = *maxwin; +/* Calculate the location where a perfectly centered window would star +t. */ + k = (vwin[(*af << 1) + 1] + vwin[(*af << 1) + 2] + 1 - l) / 2; +/* Choose the actual location to be the pitch multiple closest to this +. */ + r__1 = (real) (k - i__) / *ipitch; + awin[(*af << 1) + 1] = i__ + i_nint(&r__1) * *ipitch; + awin[(*af << 1) + 2] = awin[(*af << 1) + 1] + l - 1; +/* If there is an onset bounding the right of the voicing window and t +he */ +/* analysis window overlaps that, then move the analysis window backwa +rd */ +/* to avoid this onset. */ + if (*obound >= 2 && awin[(*af << 1) + 2] > vwin[(*af << 1) + 2]) { + awin[(*af << 1) + 1] -= *ipitch; + awin[(*af << 1) + 2] -= *ipitch; + } +/* Similarly for the left of the voicing window. */ + if ((*obound == 1 || *obound == 3) && awin[(*af << 1) + 1] < vwin[(* + af << 1) + 1]) { + awin[(*af << 1) + 1] += *ipitch; + awin[(*af << 1) + 2] += *ipitch; + } +/* If this placement puts the analysis window above HRANGE, then */ +/* move it backward an integer number of pitch periods. */ + while(awin[(*af << 1) + 2] > hrange) { + awin[(*af << 1) + 1] -= *ipitch; + awin[(*af << 1) + 2] -= *ipitch; + } +/* Similarly if the placement puts the analysis window below LRANGE. +*/ + while(awin[(*af << 1) + 1] < lrange) { + awin[(*af << 1) + 1] += *ipitch; + awin[(*af << 1) + 2] += *ipitch; + } +/* Make Energy window be phase-synchronous. */ + ephase = TRUE_; +/* Case 3 */ + } else { + awin[(*af << 1) + 1] = vwin[(*af << 1) + 1]; + awin[(*af << 1) + 2] = vwin[(*af << 1) + 2]; + ephase = FALSE_; + } +/* RMS is computed over an integer number of pitch periods in the analysis + */ +/*window. When it is not placed phase-synchronously, it is placed as clos +e*/ +/* as possible to onsets. */ + j = (awin[(*af << 1) + 2] - awin[(*af << 1) + 1] + 1) / *ipitch * *ipitch; + if (j == 0 || ! winv) { + ewin[(*af << 1) + 1] = vwin[(*af << 1) + 1]; + ewin[(*af << 1) + 2] = vwin[(*af << 1) + 2]; + } else if (! ephase && *obound == 2) { + ewin[(*af << 1) + 1] = awin[(*af << 1) + 2] - j + 1; + ewin[(*af << 1) + 2] = awin[(*af << 1) + 2]; + } else { + ewin[(*af << 1) + 1] = awin[(*af << 1) + 1]; + ewin[(*af << 1) + 2] = awin[(*af << 1) + 1] + j - 1; + } + return 0; +} /* placea_ */ + diff --git a/linphone/lpc10-1.5/placev.c b/linphone/lpc10-1.5/placev.c new file mode 100644 index 000000000..a385a75fa --- /dev/null +++ b/linphone/lpc10-1.5/placev.c @@ -0,0 +1,257 @@ +/* + +$Log: placev.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:31:02 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int placev_(integer *osbuf, integer *osptr, integer *oslen, integer *obound, integer *vwin, integer *af, integer *lframe, integer *minwin, integer *maxwin, integer *dvwinl, integer *dvwinh); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ****************************************************************** */ + +/* PLACEV Version 48 */ + +/* $Log: placev.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:31:02 jaf + * Initial revision + * */ +/* Revision 1.6 1996/03/19 20:42:19 jaf */ +/* Added some conditions satisfied by the output values in VWIN. */ + +/* Revision 1.5 1996/03/19 18:37:56 jaf */ +/* Strengthened the specification of which indices of VWIN are read and */ +/* written. */ + +/* Revision 1.4 1996/03/15 16:38:33 jaf */ +/* One tiny comment added. */ + +/* Revision 1.3 1996/03/15 16:36:13 jaf */ +/* Added comments giving In/Out status of arguments. */ + +/* Revision 1.2 1996/03/12 23:56:01 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:48:39 jaf */ +/* Initial revision */ + + +/* ****************************************************************** */ + +/* Input: */ +/* OSBUF Buffer which holds sorted indexes of onsets */ +/* I believe that only indices 1 through OSPTR-1 can be read. */ +/* OSLEN */ +/* OSPTR Free pointer into OSBUF */ +/* AF */ +/* LFRAME */ +/* MINWIN */ +/* MAXWIN */ +/* DVWINL */ +/* DVWINH (This argument is never used. Should it be?) */ +/* Input/Output: */ +/* VWIN Buffer of Voicing Window Positions (Modified) */ +/* Index (2,AF-1) is read. */ +/* Indices (1,AF) and (2,AF) are written, */ +/* and then possibly read. */ +/* All other indices are unused. */ +/* In all cases, the final values will satsify the condition:*/ +/* VWIN(2,AF)-VWIN(1,AF)+1 .LE. MAXWIN */ +/* I'm not certain yet, but they may also satisfy: */ +/* MINWIN .LE. VWIN(2,AF)-VWIN(1,AF)+1 */ +/* Output: */ +/* OBOUND This variable is set by this procedure and used */ +/* in placing analysis windows (PLACEA). Bit 1 */ +/* indicates whether an onset bounds the left side */ +/* of the voicing window, and bit 2 indicates whether */ +/* an onset bounds the right side of the voicing window. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int placev_(integer *osbuf, integer *osptr, integer *oslen, + integer *obound, integer *vwin, integer *af, integer *lframe, integer + *minwin, integer *maxwin, integer *dvwinl, integer *dvwinh) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + logical crit; + integer i__, q, osptr1, hrange, lrange; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Variables */ +/* LRANGE, HRANGE Range in which window is placed */ +/* OSPTR1 OSPTR excluding samples in 3F */ +/* Local state */ +/* None */ +/* Voicing Window Placement */ + +/* __________________ __________________ ______________ */ +/* | | | */ +/* | 1F | 2F | 3F ... */ +/* |__________________|__________________|______________ */ + +/* Previous | */ +/* Window | */ +/* ...________| */ + +/* | | */ +/* ------>| This window's placement range |<------ */ +/* | | */ + +/* There are three cases. Note that these are different from those */ +/* given in the LPC-10e phase 1 report. */ + +/* 1. If there are no onsets in this range, then the voicing window */ +/* is centered in the pitch window. If such a placement is not within +*/ +/* the window's placement range, then the window is placed in the left- +*/ +/* most portion of the placement range. Its length is always MAXWIN. */ + +/* 2. If the first onset is in 2F and there is sufficient room to place + */ +/* the window immediately before this onset, then the window is placed +*/ +/* there, and its length is set to the maximum possible under these */ +/* constraints. */ + +/* "Critical Region Exception": If there is another onset in 2F */ +/* such that a window can be placed between the two onsets, the */ +/* window is placed there (ie, as in case 3). */ + +/* 3. Otherwise, the window is placed immediately after the onset. The + */ +/* window's length */ +/* is the longest length that can fit in the range under these constraint +s,*/ +/* except that the window may be shortened even further to avoid overlapp +ing*/ +/* other onsets in the placement range. In any case, the window's length +*/ +/* is at least MINWIN. */ + +/* Note that the values of MINWIN and LFRAME must be chosen such */ +/* that case 2 = false implies case 3 = true. This means that */ +/* MINWIN <= LFRAME/2. If this were not the case, then a fourth case */ +/* would have to be added for when the window cannot fit either before +*/ +/* or after the onset. */ + +/* Note also that onsets which weren't in 2F last time may be in 1F this + */ +/* time, due to the filter delays in computing onsets. The result is tha +t*/ +/* occasionally a voicing window will overlap that onset. The only way +*/ +/* to circumvent this problem is to add more delay in processing input +*/ +/* speech. In the trade-off between delay and window-placement, window +*/ +/* placement lost. */ +/* Compute the placement range */ + /* Parameter adjustments */ + --osbuf; + vwin -= 3; + + /* Function Body */ +/* Computing MAX */ + i__1 = vwin[(*af - 1 << 1) + 2] + 1, i__2 = (*af - 2) * *lframe + 1; + lrange = max(i__1,i__2); + hrange = *af * *lframe; +/* Compute OSPTR1, so the following code only looks at relevant onsets. */ + for (osptr1 = *osptr - 1; osptr1 >= 1; --osptr1) { + if (osbuf[osptr1] <= hrange) { + goto L90; + } + } +L90: + ++osptr1; +/* Check for case 1 first (fast case): */ + if (osptr1 <= 1 || osbuf[osptr1 - 1] < lrange) { +/* Computing MAX */ + i__1 = vwin[(*af - 1 << 1) + 2] + 1; + vwin[(*af << 1) + 1] = max(i__1,*dvwinl); + vwin[(*af << 1) + 2] = vwin[(*af << 1) + 1] + *maxwin - 1; + *obound = 0; + } else { +/* Search backward in OSBUF for first onset in range. */ +/* This code relies on the above check being performed first. */ + for (q = osptr1 - 1; q >= 1; --q) { + if (osbuf[q] < lrange) { + goto L100; + } + } +L100: + ++q; +/* Check for case 2 (placement before onset): */ +/* Check for critical region exception: */ + i__1 = osptr1 - 1; + for (i__ = q + 1; i__ <= i__1; ++i__) { + if (osbuf[i__] - osbuf[q] >= *minwin) { + crit = TRUE_; + goto L105; + } + } + crit = FALSE_; +L105: +/* Computing MAX */ + i__1 = (*af - 1) * *lframe, i__2 = lrange + *minwin - 1; + if (! crit && osbuf[q] > max(i__1,i__2)) { + vwin[(*af << 1) + 2] = osbuf[q] - 1; +/* Computing MAX */ + i__1 = lrange, i__2 = vwin[(*af << 1) + 2] - *maxwin + 1; + vwin[(*af << 1) + 1] = max(i__1,i__2); + *obound = 2; +/* Case 3 (placement after onset) */ + } else { + vwin[(*af << 1) + 1] = osbuf[q]; +L110: + ++q; + if (q >= osptr1) { + goto L120; + } + if (osbuf[q] > vwin[(*af << 1) + 1] + *maxwin) { + goto L120; + } + if (osbuf[q] < vwin[(*af << 1) + 1] + *minwin) { + goto L110; + } + vwin[(*af << 1) + 2] = osbuf[q] - 1; + *obound = 3; + return 0; +L120: +/* Computing MIN */ + i__1 = vwin[(*af << 1) + 1] + *maxwin - 1; + vwin[(*af << 1) + 2] = min(i__1,hrange); + *obound = 1; + } + } + return 0; +} /* placev_ */ + diff --git a/linphone/lpc10-1.5/preemp.c b/linphone/lpc10-1.5/preemp.c new file mode 100644 index 000000000..49bdab705 --- /dev/null +++ b/linphone/lpc10-1.5/preemp.c @@ -0,0 +1,132 @@ +/* + +$Log: preemp.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:30:58 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int preemp_(real *inbuf, real *pebuf, integer *nsamp, real *coef, real *z__); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ******************************************************************* */ + +/* PREEMP Version 55 */ + +/* $Log: preemp.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:30:58 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/14 23:16:29 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/11 23:23:34 jaf */ +/* Added a bunch of comments to an otherwise simple subroutine. */ + +/* Revision 1.1 1996/02/07 14:48:48 jaf */ +/* Initial revision */ + + +/* ******************************************************************* */ + +/* Preemphasize speech with a single-zero filter. */ +/* (When coef = .9375, preemphasis is as in LPC43.) */ + +/* Inputs: */ +/* NSAMP - Number of samples to filter */ +/* INBUF - Input speech buffer */ +/* Indices 1 through NSAMP are read. */ +/* COEF - Preemphasis coefficient */ +/* Input/Output: */ +/* Z - Filter state */ +/* Output: */ +/* PEBUF - Preemphasized speech buffer (can be equal to INBUF) */ +/* Indices 1 through NSAMP are modified. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int preemp_(real *inbuf, real *pebuf, integer *nsamp, real * + coef, real *z__) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + real temp; + integer i__; + +/* Arguments */ +/* Local variables */ + +/* None of these need to have their values saved from one */ +/* invocation to the next. */ + +/* Logically, this subroutine computes the output sequence */ +/* pebuf(1:nsamp) defined by: */ + +/* pebuf(i) = inbuf(i) - coef * inbuf(i-1) */ + +/* where inbuf(0) is defined by the value of z given as input to */ +/* this subroutine. */ + +/* What is this filter's frequency response and phase response? */ + +/* Why is this filter applied to the speech? */ + +/* Could it be more efficient to apply multiple filters */ +/* simultaneously, by combining them into one equivalent filter? */ + +/* Are there ever cases when "factoring" one high-order filter into +*/ +/* multiple smaller-order filter actually reduces the number of */ +/* arithmetic operations needed to perform them? */ +/* When I first read this subroutine, I didn't understand why the */ +/* variable temp was used. It seemed that the statements in the do +*/ +/* loop could be replaced with the following: */ + +/* pebuf(i) = inbuf(i) - coef * z */ +/* z = inbuf(i) */ + +/* The reason for temp is so that even if pebuf and inbuf are the */ +/* same arrays in memory (i.e., they are aliased), then this */ +/* subroutine will still work correctly. I didn't realize this */ +/* until seeing the comment after PEBUF above that says "(can be */ +/* equal to INBUF)". */ + /* Parameter adjustments */ + --pebuf; + --inbuf; + + /* Function Body */ + i__1 = *nsamp; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = inbuf[i__] - *coef * *z__; + *z__ = inbuf[i__]; + pebuf[i__] = temp; +/* L10: */ + } + return 0; +} /* preemp_ */ + diff --git a/linphone/lpc10-1.5/prepro.c b/linphone/lpc10-1.5/prepro.c new file mode 100644 index 000000000..403dd8379 --- /dev/null +++ b/linphone/lpc10-1.5/prepro.c @@ -0,0 +1,105 @@ +/* + +$Log: prepro.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:40:51 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:30:54 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int prepro_(real *speech, integer *length, + struct lpc10_encoder_state *st) +/*:ref: hp100_ 14 3 6 4 4 */ +/*:ref: inithp100_ 14 0 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Table of constant values */ + +static integer c__1 = 1; + +/* ********************************************************************* */ + +/* PREPRO Version 48 */ + +/* $Log: prepro.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:40:51 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:30:54 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/14 23:22:56 jaf */ +/* Added comments about when INITPREPRO should be used. */ + +/* Revision 1.2 1996/03/14 23:09:27 jaf */ +/* Added an entry named INITPREPRO that initializes the local state of */ +/* this subroutine, and those it calls (if any). */ + +/* Revision 1.1 1996/02/07 14:48:54 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Pre-process input speech: */ + +/* Inputs: */ +/* LENGTH - Number of SPEECH samples */ +/* Input/Output: */ +/* SPEECH(LENGTH) - Speech data. */ +/* Indices 1 through LENGTH are read and modified. */ + +/* This subroutine has no local state maintained from one call to the */ +/* next, but HP100 does. If you want to switch to using a new audio */ +/* stream for this filter, or reinitialize its state for any other */ +/* reason, call the ENTRY INITPREPRO. */ + +/* Subroutine */ int prepro_(real *speech, integer *length, + struct lpc10_encoder_state *st) +{ + extern /* Subroutine */ int hp100_(real *, integer *, integer *, struct lpc10_encoder_state *); + +/* Arguments */ +/* High Pass Filter at 100 Hz */ + /* Parameter adjustments */ + if (speech) { + --speech; + } + + /* Function Body */ + hp100_(&speech[1], &c__1, length, st); + return 0; +} /* prepro_ */ diff --git a/linphone/lpc10-1.5/random.c b/linphone/lpc10-1.5/random.c new file mode 100644 index 000000000..e83fff3eb --- /dev/null +++ b/linphone/lpc10-1.5/random.c @@ -0,0 +1,113 @@ +/* + +$Log: random.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:41:32 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:30:49 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern integer random_(struct lpc10_decoder_state *st); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************** */ + +/* RANDOM Version 49 */ + +/* $Log: random.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:41:32 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:30:49 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/20 16:13:54 jaf */ +/* Rearranged comments a little bit, and added comments explaining that */ +/* even though there is local state here, there is no need to create an */ +/* ENTRY for reinitializing it. */ + +/* Revision 1.2 1996/03/14 22:25:29 jaf */ +/* Just rearranged the comments and local variable declarations a bit. */ + +/* Revision 1.1 1996/02/07 14:49:01 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Pseudo random number generator based on Knuth, Vol 2, p. 27. */ + +/* Function Return: */ +/* RANDOM - Integer variable, uniformly distributed over -32768 to 32767 */ + +/* This subroutine maintains local state from one call to the next. */ +/* In the context of the LPC10 coder, there is no reason to reinitialize */ +/* this local state when switching between audio streams, because its */ +/* results are only used to generate noise for unvoiced frames. */ + +integer random_(struct lpc10_decoder_state *st) +{ + /* Initialized data */ + + integer *j; + integer *k; + shortint *y; + + /* System generated locals */ + integer ret_val; + +/* Parameters/constants */ +/* Local state */ +/* The following is a 16 bit 2's complement addition, */ +/* with overflow checking disabled */ + + j = &(st->j); + k = &(st->k); + y = &(st->y[0]); + + y[*k - 1] += y[*j - 1]; + ret_val = y[*k - 1]; + --(*k); + if (*k <= 0) { + *k = 5; + } + --(*j); + if (*j <= 0) { + *j = 5; + } + return ret_val; +} /* random_ */ + diff --git a/linphone/lpc10-1.5/rcchk.c b/linphone/lpc10-1.5/rcchk.c new file mode 100644 index 000000000..008babb26 --- /dev/null +++ b/linphone/lpc10-1.5/rcchk.c @@ -0,0 +1,107 @@ +/* + +$Log: rcchk.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:30:41 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int rcchk_(integer *order, real *rc1f, real *rc2f); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************* */ + +/* RCCHK Version 45G */ + +/* $Log: rcchk.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:30:41 jaf + * Initial revision + * */ +/* Revision 1.4 1996/03/27 18:13:47 jaf */ +/* Commented out a call to subroutine ERROR. */ + +/* Revision 1.3 1996/03/18 15:48:53 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 16:55:22 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:49:08 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Check RC's, repeat previous frame's RC's if unstable */ + +/* Input: */ +/* ORDER - Number of RC's */ +/* RC1F - Previous frame's RC's */ +/* Indices 1 through ORDER may be read. */ +/* Input/Output: */ +/* RC2F - Present frame's RC's */ +/* Indices 1 through ORDER may be read, and written. */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int rcchk_(integer *order, real *rc1f, real *rc2f) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + integer i__; + +/* Arguments */ +/* Local variables that need not be saved */ + /* Parameter adjustments */ + --rc2f; + --rc1f; + + /* Function Body */ + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((r__1 = rc2f[i__], abs(r__1)) > .99f) { + goto L10; + } + } + return 0; +/* Note: In version embedded in other software, all calls to ERROR +*/ +/* should probably be removed. */ +L10: + +/* This call to ERROR is only needed for debugging purposes. */ + +/* CALL ERROR('RCCHK',2,I) */ + i__1 = *order; + for (i__ = 1; i__ <= i__1; ++i__) { + rc2f[i__] = rc1f[i__]; + } + return 0; +} /* rcchk_ */ + diff --git a/linphone/lpc10-1.5/synths.c b/linphone/lpc10-1.5/synths.c new file mode 100644 index 000000000..b126b8154 --- /dev/null +++ b/linphone/lpc10-1.5/synths.c @@ -0,0 +1,392 @@ +/* + +$Log: synths.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:42:59 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:30:33 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int synths_(integer *voice, integer *pitch, real *rms, real *rc, real *speech, integer *k, struct lpc10_decoder_state *st); +/* comlen contrl_ 12 */ +/*:ref: pitsyn_ 14 12 4 4 4 6 6 4 4 4 6 6 4 6 */ +/*:ref: irc2pc_ 14 5 6 6 4 6 6 */ +/*:ref: bsynz_ 14 7 6 4 4 6 6 6 6 */ +/*:ref: deemp_ 14 2 6 4 */ +/*:ref: initpitsyn_ 14 0 */ +/*:ref: initbsynz_ 14 0 */ +/*:ref: initdeemp_ 14 0 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/* Table of constant values */ + +static real c_b2 = .7f; + +/* ***************************************************************** */ + +/* SYNTHS Version 54 */ + +/* $Log: synths.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:42:59 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:30:33 jaf + * Initial revision + * */ +/* Revision 1.5 1996/03/26 19:31:58 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.4 1996/03/25 19:41:01 jaf */ +/* Changed so that MAXFRM samples are always returned in the output array */ +/* SPEECH. */ + +/* This required delaying the returned samples by MAXFRM sample times, */ +/* and remembering any "left over" samples returned by PITSYN from one */ +/* call of SYNTHS to the next. */ + +/* Changed size of SPEECH from 2*MAXFRM to MAXFRM. Removed local */ +/* variable SOUT. Added local state variables BUF and BUFLEN. */ + +/* Revision 1.3 1996/03/25 19:20:10 jaf */ +/* Added comments about the range of possible return values for argument */ +/* K, and increased the size of the arrays filled in by PITSYN from 11 to */ +/* 16, as has been already done inside of PITSYN. */ + +/* Revision 1.2 1996/03/22 00:18:18 jaf */ +/* Added comments explaining meanings of input and output parameters, and */ +/* indicating which array indices can be read or written. */ + +/* Added entry INITSYNTHS, which does nothing except call the */ +/* corresponding initialization entries for subroutines PITSYN, BSYNZ, */ +/* and DEEMP. */ + +/* Revision 1.1 1996/02/07 14:49:44 jaf */ +/* Initial revision */ + + +/* ***************************************************************** */ + +/* The note below is from the distributed version of the LPC10 coder. */ +/* The version of the code below has been modified so that SYNTHS always */ +/* has a constant frame length output of MAXFRM. */ + +/* Also, BSYNZ and DEEMP need not be modified to work on variable */ +/* positions within an array. It is only necessary to pass the first */ +/* index desired as the array argument. What actually gets passed is the */ +/* address of that array position, which the subroutine treats as the */ +/* first index of the array. */ + +/* This technique is used in subroutine ANALYS when calling PREEMP, so it */ +/* appears that multiple people wrote different parts of this LPC10 code, */ +/* and that they didn't necessarily have equivalent knowledge of Fortran */ +/* (not surprising). */ + +/* NOTE: There is excessive buffering here, BSYNZ and DEEMP should be */ +/* changed to operate on variable positions within SOUT. Also, */ +/* the output length parameter is bogus, and PITSYN should be */ +/* rewritten to allow a constant frame length output. */ + +/* Input: */ +/* VOICE - Half frame voicing decisions */ +/* Indices 1 through 2 read. */ +/* Input/Output: */ +/* PITCH - Pitch */ +/* PITCH is restricted to range 20 to 156, inclusive, */ +/* before calling subroutine PITSYN, and then PITSYN */ +/* can modify it further under some conditions. */ +/* RMS - Energy */ +/* Only use is for debugging, and passed to PITSYN. */ +/* See comments there for how it can be modified. */ +/* RC - Reflection coefficients */ +/* Indices 1 through ORDER restricted to range -.99 to .99, */ +/* before calling subroutine PITSYN, and then PITSYN */ +/* can modify it further under some conditions. */ +/* Output: */ +/* SPEECH - Synthesized speech samples. */ +/* Indices 1 through the final value of K are written. */ +/* K - Number of samples placed into array SPEECH. */ +/* This is always MAXFRM. */ + +/* Subroutine */ int synths_(integer *voice, integer *pitch, real * + rms, real *rc, real *speech, integer *k, struct lpc10_decoder_state *st) +{ + /* Initialized data */ + + real *buf; + integer *buflen; + + /* System generated locals */ + integer i__1; + real r__1, r__2; + + /* Local variables */ + real rmsi[16]; + integer nout, ivuv[16], i__, j; + extern /* Subroutine */ int deemp_(real *, integer *, struct lpc10_decoder_state *); + real ratio; + integer ipiti[16]; + extern /* Subroutine */ bsynz_(real *, integer *, + integer *, real *, real *, real *, real *, struct lpc10_decoder_state *), irc2pc_(real *, real * + , integer *, real *, real *); + real g2pass; + real pc[10]; + extern /* Subroutine */ int pitsyn_(integer *, integer *, integer *, real + *, real *, integer *, integer *, integer *, real *, real *, + integer *, real *, struct lpc10_decoder_state *); + real rci[160] /* was [10][16] */; + +/* $Log: synths.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:42:59 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:30:33 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:03:47 jaf */ +/* Removed definitions for any constants that were no longer used. */ + +/* Revision 1.2 1996/03/26 19:34:33 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:43:51 jaf */ +/* Initial revision */ + +/* LPC Configuration parameters: */ +/* Frame size, Prediction order, Pitch period */ +/* Arguments */ +/* $Log: synths.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:42:59 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_decoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_decoder_state(). + * + * Revision 1.1 1996/08/19 22:30:33 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Parameters/constants */ +/* Local variables that need not be saved */ +/* Local state */ +/* BUF is a buffer of speech samples that would have been returned +*/ +/* by the older version of SYNTHS, but the newer version doesn't, */ +/* so that the newer version can always return MAXFRM samples on */ +/* every call. This has the effect of delaying the return of */ +/* samples for one additional frame time. */ + +/* Indices 1 through BUFLEN contain samples that are left over from +*/ +/* the last call to SYNTHS. Given the way that PITSYN works, */ +/* BUFLEN should always be in the range MAXFRM-MAXPIT+1 through */ +/* MAXFRM, inclusive, after a call to SYNTHS is complete. */ + +/* On the first call to SYNTHS (or the first call after */ +/* reinitializing with the entry INITSYNTHS), BUFLEN is MAXFRM, and +*/ +/* a frame of silence is always returned. */ + /* Parameter adjustments */ + if (voice) { + --voice; + } + if (rc) { + --rc; + } + if (speech) { + --speech; + } + + /* Function Body */ + buf = &(st->buf[0]); + buflen = &(st->buflen); + +/* Computing MAX */ + i__1 = min(*pitch,156); + *pitch = max(i__1,20); + i__1 = contrl_1.order; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ +/* Computing MIN */ + r__2 = rc[i__]; + r__1 = min(r__2,.99f); + rc[i__] = max(r__1,-.99f); + } + pitsyn_(&contrl_1.order, &voice[1], pitch, rms, &rc[1], &contrl_1.lframe, + ivuv, ipiti, rmsi, rci, &nout, &ratio, st); + if (nout > 0) { + i__1 = nout; + for (j = 1; j <= i__1; ++j) { + +/* Add synthesized speech for pitch period J to the en +d of */ +/* BUF. */ + + irc2pc_(&rci[j * 10 - 10], pc, &contrl_1.order, &c_b2, &g2pass); + bsynz_(pc, &ipiti[j - 1], &ivuv[j - 1], &buf[*buflen], &rmsi[j - 1] + , &ratio, &g2pass, st); + deemp_(&buf[*buflen], &ipiti[j - 1], st); + *buflen += ipiti[j - 1]; + } + +/* Copy first MAXFRM samples from BUF to output array SPEECH +*/ +/* (scaling them), and then remove them from the beginning of + */ +/* BUF. */ + + for (i__ = 1; i__ <= 180; ++i__) { + speech[i__] = buf[i__ - 1] / 4096.f; + } + *k = 180; + *buflen += -180; + i__1 = *buflen; + for (i__ = 1; i__ <= i__1; ++i__) { + buf[i__ - 1] = buf[i__ + 179]; + } + } + return 0; +} /* synths_ */ diff --git a/linphone/lpc10-1.5/tbdm.c b/linphone/lpc10-1.5/tbdm.c new file mode 100644 index 000000000..845642845 --- /dev/null +++ b/linphone/lpc10-1.5/tbdm.c @@ -0,0 +1,176 @@ +/* + +$Log: tbdm.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:30:26 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int tbdm_(real *speech, integer *lpita, integer *tau, integer *ltau, real *amdf, integer *minptr, integer *maxptr, integer *mintau); +/*:ref: difmag_ 14 8 6 4 4 4 4 6 4 4 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* ********************************************************************** */ + +/* TBDM Version 49 */ + +/* $Log: tbdm.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:16 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:30:26 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/18 22:14:00 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 14:48:37 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:49:54 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/*TURBO DIFMAG: Compute High Resolution Average Magnitude Difference Function +*/ + +/* Note: There are several constants in here that appear to depend on a */ +/* particular TAU table. That's not a problem for the LPC10 coder, but */ +/* watch out if you change the contents of TAU in the subroutine ANALYS. */ + +/* Input: */ +/* SPEECH - Low pass filtered speech */ +/* Indices 1 through MAX+LPITA-1 are read, where: */ +/* MAX = (TAU(LTAU)-TAU(1))/2+1 */ +/* (If TAU(1) .LT. 39, then larger indices could be read */ +/* by the last call to DIFMAG below.) */ +/* LPITA - Length of speech buffer */ +/* TAU - Table of lags, sorted in increasing order. */ +/* Indices 1 through LTAU read. */ +/* LTAU - Number of lag values to compute */ +/* Output: */ +/* AMDF - Average Magnitude Difference for each lag in TAU */ +/* Indices 1 through LTAU written, and several might then be read.*/ +/* MINPTR - Index of minimum AMDF value */ +/* MAXPTR - Index of maximum AMDF value within +/- 1/2 octave of min */ +/* MINTAU - Lag corresponding to minimum AMDF value */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int tbdm_(real *speech, integer *lpita, integer *tau, + integer *ltau, real *amdf, integer *minptr, integer *maxptr, integer * + mintau) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + + /* Local variables */ + real amdf2[6]; + integer minp2, ltau2, maxp2, i__; + extern /* Subroutine */ int difmag_(real *, integer *, integer *, integer + *, integer *, real *, integer *, integer *); + integer minamd, ptr, tau2[6]; + +/* Arguments */ +/* REAL SPEECH(LPITA+TAU(LTAU)), AMDF(LTAU) */ +/* Stupid TOAST doesn't understand expressions */ +/* Local variables that need not be saved */ +/* Local state */ +/* None */ +/* Compute full AMDF using log spaced lags, find coarse minimum */ + /* Parameter adjustments */ + --speech; + --amdf; + --tau; + + /* Function Body */ + difmag_(&speech[1], lpita, &tau[1], ltau, &tau[*ltau], &amdf[1], minptr, + maxptr); + *mintau = tau[*minptr]; + minamd = amdf[*minptr]; +/* Build table containing all lags within +/- 3 of the AMDF minimum */ +/* excluding all that have already been computed */ + ltau2 = 0; + ptr = *minptr - 2; +/* Computing MAX */ + i__1 = *mintau - 3; +/* Computing MIN */ + i__3 = *mintau + 3, i__4 = tau[*ltau] - 1; + i__2 = min(i__3,i__4); + for (i__ = max(i__1,41); i__ <= i__2; ++i__) { + while(tau[ptr] < i__) { + ++ptr; + } + if (tau[ptr] != i__) { + ++ltau2; + tau2[ltau2 - 1] = i__; + } + } +/* Compute AMDF of the new lags, if there are any, and choose one */ +/* if it is better than the coarse minimum */ + if (ltau2 > 0) { + difmag_(&speech[1], lpita, tau2, <au2, &tau[*ltau], amdf2, &minp2, & + maxp2); + if (amdf2[minp2 - 1] < (real) minamd) { + *mintau = tau2[minp2 - 1]; + minamd = amdf2[minp2 - 1]; + } + } +/* Check one octave up, if there are any lags not yet computed */ + if (*mintau >= 80) { + i__ = *mintau / 2; + if ((i__ & 1) == 0) { + ltau2 = 2; + tau2[0] = i__ - 1; + tau2[1] = i__ + 1; + } else { + ltau2 = 1; + tau2[0] = i__; + } + difmag_(&speech[1], lpita, tau2, <au2, &tau[*ltau], amdf2, &minp2, & + maxp2); + if (amdf2[minp2 - 1] < (real) minamd) { + *mintau = tau2[minp2 - 1]; + minamd = amdf2[minp2 - 1]; + *minptr += -20; + } + } +/* Force minimum of the AMDF array to the high resolution minimum */ + amdf[*minptr] = (real) minamd; +/* Find maximum of AMDF within 1/2 octave of minimum */ +/* Computing MAX */ + i__2 = *minptr - 5; + *maxptr = max(i__2,1); +/* Computing MIN */ + i__1 = *minptr + 5; + i__2 = min(i__1,*ltau); + for (i__ = *maxptr + 1; i__ <= i__2; ++i__) { + if (amdf[i__] > amdf[*maxptr]) { + *maxptr = i__; + } + } + return 0; +} /* tbdm_ */ + diff --git a/linphone/lpc10-1.5/voicin.c b/linphone/lpc10-1.5/voicin.c new file mode 100644 index 000000000..0782404e7 --- /dev/null +++ b/linphone/lpc10-1.5/voicin.c @@ -0,0 +1,759 @@ +/* + +$Log: voicin.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:17 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.2 1996/08/20 20:45:00 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:30:14 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int voicin_(integer *vwin, real *inbuf, real *lpbuf, integer *buflim, integer *half, real *minamd, real *maxamd, integer *mintau, real *ivrc, integer *obound, integer *voibuf, integer *af, struct lpc10_encoder_state *st); +/* comlen contrl_ 12 */ +/*:ref: vparms_ 14 14 4 6 6 4 4 6 4 4 4 4 6 6 6 6 */ +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Common Block Declarations */ + +extern struct { + integer order, lframe; + logical corrp; +} contrl_; + +#define contrl_1 contrl_ + +/****************************************************************************/ + +/* VOICIN Version 52 */ + +/* $Log: voicin.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:17 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:45:00 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:30:14 jaf + * Initial revision + * */ +/* Revision 1.10 1996/03/29 17:59:14 jaf */ +/* Avoided using VALUE(9), although it shouldn't affect the function of */ +/* the code at all, because it was always multiplied by VDC(9,SNRL), */ +/* which is 0 for all values of SNRL. Still, if VALUE(9) had an initial */ +/* value of IEEE NaN, it might cause trouble (I don't know how IEEE */ +/* defines Nan * 0. It should either be NaN or 0.) */ + +/* Revision 1.9 1996/03/29 17:54:46 jaf */ +/* Added a few comments about the accesses made to argument array VOIBUF */ +/* and the local saved array VOICE. */ + +/* Revision 1.8 1996/03/27 18:19:54 jaf */ +/* Added an assignment to VSTATE that does not affect the function of the */ +/* program at all. The only reason I put it in was so that the tracing */ +/* statements at the end, when enabled, will print a consistent value for */ +/* VSTATE when HALF .EQ. 1, rather than a garbage value that could change */ +/* from one call to the next. */ + +/* Revision 1.7 1996/03/26 20:00:06 jaf */ +/* Removed the inclusion of the file "vcomm.fh", and put its contents */ +/* into this file. It was included nowhere else but here. */ + +/* Revision 1.6 1996/03/26 19:38:09 jaf */ +/* Commented out trace statements. */ + +/* Revision 1.5 1996/03/19 20:43:45 jaf */ +/* Added comments about which indices of OBOUND and VOIBUF can be */ +/* accessed, and whether they are read or written. VOIBUF is fairly */ +/* messy. */ + +/* Revision 1.4 1996/03/19 15:00:58 jaf */ +/* Moved the DATA statements for the *VDC* variables later, as it is */ +/* apparently illegal to have DATA statements before local variable */ +/* declarations. */ + +/* Revision 1.3 1996/03/19 00:10:49 jaf */ +/* Heavily commented the local variables that are saved from one */ +/* invocation to the next, and how the local variable FIRST is used to */ +/* avoid the need to assign most of them initial values with DATA */ +/* statements. */ + +/* A few should be initialized, but aren't. I've guessed initial values */ +/* for two of these, SFBUE and SLBUE, and I've convinced myself that for */ +/* VOICE, the effects of uninitialized values will die out after 2 or 3 */ +/* frame times. It would still be good to choose initial values for */ +/* these, but I don't know what reasonable values would be (0 comes to */ +/* mind). */ + +/* Revision 1.2 1996/03/13 16:09:28 jaf */ +/* Comments added explaining which of the local variables of this */ +/* subroutine need to be saved from one invocation to the next, and which */ +/* do not. */ + +/* WARNING! Some of them that should are never given initial values in */ +/* this code. Hopefully, Fortran 77 defines initial values for them, but */ +/* even so, giving them explicit initial values is preferable. */ + +/* WARNING! VALUE(9) is used, but never assigned a value. It should */ +/* probably be eliminated from the code. */ + +/* Revision 1.1 1996/02/07 14:50:28 jaf */ +/* Initial revision */ + + +/****************************************************************************/ + +/* Voicing Detection (VOICIN) makes voicing decisions for each half */ +/* frame of input speech. Tentative voicing decisions are made two frames*/ +/* in the future (2F) for each half frame. These decisions are carried */ +/* through one frame in the future (1F) to the present (P) frame where */ +/* they are examined and smoothed, resulting in the final voicing */ +/* decisions for each half frame. */ +/* The voicing parameter (signal measurement) column vector (VALUE) */ +/* is based on a rectangular window of speech samples determined by the */ +/* window placement algorithm. The voicing parameter vector contains the*/ +/* AMDF windowed maximum-to-minimum ratio, the zero crossing rate, energy*/ +/* measures, reflection coefficients, and prediction gains. The voicing */ +/* window is placed to avoid contamination of the voicing parameter vector*/ +/* with speech onsets. */ +/* The input signal is then classified as unvoiced (including */ +/* silence) or voiced. This decision is made by a linear discriminant */ +/* function consisting of a dot product of the voicing decision */ +/* coefficient (VDC) row vector with the measurement column vector */ +/* (VALUE). The VDC vector is 2-dimensional, each row vector is optimized*/ +/* for a particular signal-to-noise ratio (SNR). So, before the dot */ +/* product is performed, the SNR is estimated to select the appropriate */ +/* VDC vector. */ +/* The smoothing algorithm is a modified median smoother. The */ +/* voicing discriminant function is used by the smoother to determine how*/ +/* strongly voiced or unvoiced a signal is. The smoothing is further */ +/* modified if a speech onset and a voicing decision transition occur */ +/* within one half frame. In this case, the voicing decision transition */ +/* is extended to the speech onset. For transmission purposes, there are*/ +/* constraints on the duration and transition of voicing decisions. The */ +/* smoother takes these constraints into account. */ +/* Finally, the energy estimates are updated along with the dither */ +/* threshold used to calculate the zero crossing rate (ZC). */ + +/* Inputs: */ +/* VWIN - Voicing window limits */ +/* The indices read of arrays VWIN, INBUF, LPBUF, and BUFLIM */ +/* are the same as those read by subroutine VPARMS. */ +/* INBUF - Input speech buffer */ +/* LPBUF - Low-pass filtered speech buffer */ +/* BUFLIM - INBUF and LPBUF limits */ +/* HALF - Present analysis half frame number */ +/* MINAMD - Minimum value of the AMDF */ +/* MAXAMD - Maximum value of the AMDF */ +/* MINTAU - Pointer to the lag of the minimum AMDF value */ +/* IVRC(2) - Inverse filter's RC's */ +/* Only index 2 of array IVRC read under normal operation. */ +/* (Index 1 is also read when debugging is turned on.) */ +/* OBOUND - Onset boundary descriptions */ +/* Indices 1 through 3 read if (HALF .NE. 1), otherwise untouched. +*/ +/* AF - The analysis frame number */ +/* Output: */ +/* VOIBUF(2,0:AF) - Buffer of voicing decisions */ +/* Index (HALF,3) written. */ +/* If (HALF .EQ. 1), skip down to "Read (HALF,3)" below. */ +/* Indices (1,2), (2,1), (1,2), and (2,2) read. */ +/* One of the following is then done: */ +/* read (1,3) and possibly write (1,2) */ +/* read (1,3) and write (1,2) or (2,2) */ +/* write (2,1) */ +/* write (2,1) or (1,2) */ +/* read (1,0) and (1,3) and then write (2,2) or (1,1) */ +/* no reads or writes on VOIBUF */ +/* Finally, read (HALF,3) */ +/* Internal: */ +/* QS - Ratio of preemphasized to full-band energies */ +/* RC1 - First reflection coefficient */ +/* AR_B - Product of the causal forward and reverse pitch prediction gain +s*/ +/* AR_F - Product of the noncausal forward and rev. pitch prediction gain +s*/ +/* ZC - Zero crossing rate */ +/* DITHER - Zero crossing threshold level */ +/* MAXMIN - AMDF's 1 octave windowed maximum-to-minimum ratio */ +/* MINPTR - Location of minimum AMDF value */ +/* NVDC - Number of elements in each VDC vector */ +/* NVDCL - Number of VDC vectors */ +/* VDCL - SNR values corresponding to the set of VDC's */ +/* VDC - 2-D voicing decision coefficient vector */ +/* VALUE(9) - Voicing Parameters */ +/* VOICE(2,3)- History of LDA results */ +/* On every call when (HALF .EQ. 1), VOICE(*,I+1) is */ +/* shifted back to VOICE(*,I), for I=1,2. */ +/* VOICE(HALF,3) is written on every call. */ +/* Depending on several conditions, one or more of */ +/* (1,1), (1,2), (2,1), and (2,2) might then be read. */ +/* LBE - Ratio of low-band instantaneous to average energies */ +/* FBE - Ratio of full-band instantaneous to average energies */ +/* LBVE - Low band voiced energy */ +/* LBUE - Low band unvoiced energy */ +/* FBVE - Full band voiced energy */ +/* FBUE - Full band unvoiced energy */ +/* OFBUE - Previous full-band unvoiced energy */ +/* OLBUE - Previous low-band unvoiced energy */ +/* REF - Reference energy for initialization and DITHER threshold */ +/* SNR - Estimate of signal-to-noise ratio */ +/* SNR2 - Estimate of low-band signal-to-noise ratio */ +/* SNRL - SNR level number */ +/* OT - Onset transition present */ +/* VSTATE - Decimal interpretation of binary voicing classifications */ +/* FIRST - First call flag */ + +/* This subroutine maintains local state from one call to the next. If */ +/* you want to switch to using a new audio stream for this filter, or */ +/* reinitialize its state for any other reason, call the ENTRY */ +/* INITVOICIN. */ + +/* Subroutine */ int voicin_(integer *vwin, real *inbuf, real * + lpbuf, integer *buflim, integer *half, real *minamd, real *maxamd, + integer *mintau, real *ivrc, integer *obound, integer *voibuf, + integer *af, struct lpc10_encoder_state *st) +{ + /* Initialized data */ + + real *dither; + static real vdc[100] /* was [10][10] */ = { 0.f,1714.f,-110.f, + 334.f,-4096.f,-654.f,3752.f,3769.f,0.f,1181.f,0.f,874.f,-97.f, + 300.f,-4096.f,-1021.f,2451.f,2527.f,0.f,-500.f,0.f,510.f,-70.f, + 250.f,-4096.f,-1270.f,2194.f,2491.f,0.f,-1500.f,0.f,500.f,-10.f, + 200.f,-4096.f,-1300.f,2e3f,2e3f,0.f,-2e3f,0.f,500.f,0.f,0.f, + -4096.f,-1300.f,2e3f,2e3f,0.f,-2500.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f, + 0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f, + 0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f, + 0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f }; + static integer nvdcl = 5; + static real vdcl[10] = { 600.f,450.f,300.f,200.f,0.f,0.f,0.f,0.f,0.f,0.f } + ; + + /* System generated locals */ + integer inbuf_offset, lpbuf_offset, i__1, i__2; + real r__1, r__2; + + /* Builtin functions */ + integer i_nint(real *); + double sqrt(doublereal); + + /* Local variables */ + real ar_b__, ar_f__; + integer *lbve, *lbue, *fbve, *fbue; + integer snrl, i__; + integer *ofbue, *sfbue; + real *voice; + integer *olbue, *slbue; + real value[9]; + integer zc; + logical ot; + real qs; + real *maxmin; + integer vstate; + real rc1; + extern /* Subroutine */ int vparms_(integer *, real *, real *, integer *, + integer *, real *, integer *, integer *, integer *, integer *, + real *, real *, real *, real *); + integer fbe, lbe; + real *snr; + real snr2; + +/* Global Variables: */ +/* Arguments */ +/* $Log: voicin.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:17 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.2 1996/08/20 20:45:00 jaf + * Removed all static local variables that were SAVE'd in the Fortran + * code, and put them in struct lpc10_encoder_state that is passed as an + * argument. + * + * Removed init function, since all initialization is now done in + * init_lpc10_encoder_state(). + * + * Revision 1.1 1996/08/19 22:30:14 jaf + * Initial revision + * */ +/* Revision 1.3 1996/03/29 22:05:55 jaf */ +/* Commented out the common block variables that are not needed by the */ +/* embedded version. */ + +/* Revision 1.2 1996/03/26 19:34:50 jaf */ +/* Added comments indicating which constants are not needed in an */ +/* application that uses the LPC-10 coder. */ + +/* Revision 1.1 1996/02/07 14:44:09 jaf */ +/* Initial revision */ + +/* LPC Processing control variables: */ + +/* *** Read-only: initialized in setup */ + +/* Files for Speech, Parameter, and Bitstream Input & Output, */ +/* and message and debug outputs. */ + +/* Here are the only files which use these variables: */ + +/* lpcsim.f setup.f trans.f error.f vqsetup.f */ + +/* Many files which use fdebug are not listed, since it is only used in */ +/* those other files conditionally, to print trace statements. */ +/* integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* LPC order, Frame size, Quantization rate, Bits per frame, */ +/* Error correction */ +/* Subroutine SETUP is the only place where order is assigned a value, */ +/* and that value is 10. It could increase efficiency 1% or so to */ +/* declare order as a constant (i.e., a Fortran PARAMETER) instead of as +*/ +/* a variable in a COMMON block, since it is used in many places in the */ +/* core of the coding and decoding routines. Actually, I take that back. +*/ +/* At least when compiling with f2c, the upper bound of DO loops is */ +/* stored in a local variable before the DO loop begins, and then that is +*/ +/* compared against on each iteration. */ +/* Similarly for lframe, which is given a value of MAXFRM in SETUP. */ +/* Similarly for quant, which is given a value of 2400 in SETUP. quant */ +/* is used in only a few places, and never in the core coding and */ +/* decoding routines, so it could be eliminated entirely. */ +/* nbits is similar to quant, and is given a value of 54 in SETUP. */ +/* corrp is given a value of .TRUE. in SETUP, and is only used in the */ +/* subroutines ENCODE and DECODE. It doesn't affect the speed of the */ +/* coder significantly whether it is .TRUE. or .FALSE., or whether it is +*/ +/* a constant or a variable, since it is only examined once per frame. */ +/* Leaving it as a variable that is set to .TRUE. seems like a good */ +/* idea, since it does enable some error-correction capability for */ +/* unvoiced frames, with no change in the coding rate, and no noticeable +*/ +/* quality difference in the decoded speech. */ +/* integer quant, nbits */ +/* *** Read/write: variables for debugging, not needed for LPC algorithm +*/ + +/* Current frame, Unstable frames, Output clip count, Max onset buffer, +*/ +/* Debug listing detail level, Line count on listing page */ + +/* nframe is not needed for an embedded LPC10 at all. */ +/* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */ +/* ERROR, which is only called from RCCHK. When LPC10 is embedded into */ +/* an application, I would recommend removing the call to ERROR in RCCHK, +*/ +/* and remove ERROR and nunsfm completely. */ +/* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in +*/ +/* sread.f. When LPC10 is embedded into an application, one might want */ +/* to cause it to be incremented in a routine that takes the output of */ +/* SYNTHS and sends it to an audio device. It could be optionally */ +/* displayed, for those that might want to know what it is. */ +/* maxosp is never initialized to 0 in SETUP, although it probably should +*/ +/* be, and it is updated in subroutine ANALYS. I doubt that its value */ +/* would be of much interest to an application in which LPC10 is */ +/* embedded. */ +/* listl and lincnt are not needed for an embedded LPC10 at all. */ +/* integer nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */ +/* common /contrl/ quant, nbits */ +/* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */ +/* Parameters/constants */ +/* Voicing coefficient and Linear Discriminant Analysis variables: +*/ +/* Max number of VDC's and VDC levels */ +/* The following are not Fortran PARAMETER's, but they are */ +/* initialized with DATA statements, and never modified. */ +/* Actual number of VDC's and levels */ +/* Local variables that need not be saved */ +/* Note: */ + +/* VALUE(1) through VALUE(8) are assigned values, but VALUE(9) */ +/* never is. Yet VALUE(9) is read in the loop that begins "DO I = +*/ +/* 1, 9" below. I believe that this doesn't cause any problems in +*/ +/* this subroutine, because all VDC(9,*) array elements are 0, and +*/ +/* this is what is multiplied by VALUE(9) in all cases. Still, it +*/ +/* would save a multiplication to change the loop to "DO I = 1, 8". +*/ +/* Local state */ +/* WARNING! */ + +/* VOICE, SFBUE, and SLBUE should be saved from one invocation to */ +/* the next, but they are never given an initial value. */ + +/* Does Fortran 77 specify some default initial value, like 0, or */ +/* is it undefined? If it is undefined, then this code should be */ +/* corrected to specify an initial value. */ + +/* For VOICE, note that it is "shifted" in the statement that */ +/* begins "IF (HALF .EQ. 1) THEN" below. Also, uninitialized */ +/* values in the VOICE array can only affect entries in the VOIBUF +*/ +/* array that are for the same frame, or for an older frame. Thus +*/ +/* the effects of uninitialized values in VOICE cannot linger on */ +/* for more than 2 or 3 frame times. */ + +/* For SFBUE and SLBUE, the effects of uninitialized values can */ +/* linger on for many frame times, because their previous values */ +/* are exponentially decayed. Thus it is more important to choose +*/ +/* initial values for these variables. I would guess that a */ +/* reasonable initial value for SFBUE is REF/16, the same as used */ +/* for FBUE and OFBUE. Similarly, SLBUE can be initialized to */ +/* REF/32, the same as for LBUE and OLBUE. */ + +/* These guessed initial values should be validated by re-running */ +/* the modified program on some audio samples. */ + +/* Declare and initialize filters: */ + + dither = (&st->dither); + snr = (&st->snr); + maxmin = (&st->maxmin); + voice = (&st->voice[0]); + lbve = (&st->lbve); + lbue = (&st->lbue); + fbve = (&st->fbve); + fbue = (&st->fbue); + ofbue = (&st->ofbue); + olbue = (&st->olbue); + sfbue = (&st->sfbue); + slbue = (&st->slbue); + + /* Parameter adjustments */ + if (vwin) { + --vwin; + } + if (buflim) { + --buflim; + } + if (inbuf) { + inbuf_offset = buflim[1]; + inbuf -= inbuf_offset; + } + if (lpbuf) { + lpbuf_offset = buflim[3]; + lpbuf -= lpbuf_offset; + } + if (ivrc) { + --ivrc; + } + if (obound) { + --obound; + } + if (voibuf) { + --voibuf; + } + + /* Function Body */ + +/* The following variables are saved from one invocation to the */ +/* next, but are not initialized with DATA statements. This is */ +/* acceptable, because FIRST is initialized ot .TRUE., and the */ +/* first time that this subroutine is then called, they are all */ +/* given initial values. */ + +/* SNR */ +/* LBVE, LBUE, FBVE, FBUE, OFBUE, OLBUE */ + +/* MAXMIN is initialized on the first call, assuming that HALF */ +/* .EQ. 1 on first call. This is how ANALYS calls this subroutine. +*/ + +/* Voicing Decision Parameter vector (* denotes zero coefficient): */ + +/* * MAXMIN */ +/* LBE/LBVE */ +/* ZC */ +/* RC1 */ +/* QS */ +/* IVRC2 */ +/* aR_B */ +/* aR_F */ +/* * LOG(LBE/LBVE) */ +/* Define 2-D voicing decision coefficient vector according to the voicin +g*/ +/* parameter order above. Each row (VDC vector) is optimized for a speci +fic*/ +/* SNR. The last element of the vector is the constant. */ +/* E ZC RC1 Qs IVRC2 aRb aRf c */ + +/* The VOICE array contains the result of the linear discriminant functio +n*/ +/* (analog values). The VOIBUF array contains the hard-limited binary +*/ +/* voicing decisions. The VOICE and VOIBUF arrays, according to FORTRAN + */ +/* memory allocation, are addressed as: */ + +/* (half-frame number, future-frame number) */ + +/* | Past | Present | Future1 | Future2 | */ +/* | 1,0 | 2,0 | 1,1 | 2,1 | 1,2 | 2,2 | 1,3 | 2,3 | ---> time */ + +/* Update linear discriminant function history each frame: */ + if (*half == 1) { + voice[0] = voice[2]; + voice[1] = voice[3]; + voice[2] = voice[4]; + voice[3] = voice[5]; + *maxmin = *maxamd / max(*minamd,1.f); + } +/* Calculate voicing parameters twice per frame: */ + vparms_(&vwin[1], &inbuf[inbuf_offset], &lpbuf[lpbuf_offset], &buflim[1], + half, dither, mintau, &zc, &lbe, &fbe, &qs, &rc1, &ar_b__, & + ar_f__); +/* Estimate signal-to-noise ratio to select the appropriate VDC vector. +*/ +/* The SNR is estimated as the running average of the ratio of the */ +/* running average full-band voiced energy to the running average */ +/* full-band unvoiced energy. SNR filter has gain of 63. */ + r__1 = (*snr + *fbve / (real) max(*fbue,1)) * 63 / 64.f; + *snr = (real) i_nint(&r__1); + snr2 = *snr * *fbue / max(*lbue,1); +/* Quantize SNR to SNRL according to VDCL thresholds. */ + snrl = 1; + i__1 = nvdcl - 1; + for (snrl = 1; snrl <= i__1; ++snrl) { + if (snr2 > vdcl[snrl - 1]) { + goto L69; + } + } +/* (Note: SNRL = NVDCL here) */ +L69: +/* Linear discriminant voicing parameters: */ + value[0] = *maxmin; + value[1] = (real) lbe / max(*lbve,1); + value[2] = (real) zc; + value[3] = rc1; + value[4] = qs; + value[5] = ivrc[2]; + value[6] = ar_b__; + value[7] = ar_f__; +/* Evaluation of linear discriminant function: */ + voice[*half + 3] = vdc[snrl * 10 - 1]; + for (i__ = 1; i__ <= 8; ++i__) { + voice[*half + 3] += vdc[i__ + snrl * 10 - 11] * value[i__ - 1]; + } +/* Classify as voiced if discriminant > 0, otherwise unvoiced */ +/* Voicing decision for current half-frame: 1 = Voiced; 0 = Unvoiced */ + if (voice[*half + 3] > 0.f) { + voibuf[*half + 6] = 1; + } else { + voibuf[*half + 6] = 0; + } +/* Skip voicing decision smoothing in first half-frame: */ +/* Give a value to VSTATE, so that trace statements below will print +*/ +/* a consistent value from one call to the next when HALF .EQ. 1. */ +/* The value of VSTATE is not used for any other purpose when this is +*/ +/* true. */ + vstate = -1; + if (*half == 1) { + goto L99; + } +/* Voicing decision smoothing rules (override of linear combination): */ + +/* Unvoiced half-frames: At least two in a row. */ +/* -------------------- */ + +/* Voiced half-frames: At least two in a row in one frame. */ +/* ------------------- Otherwise at least three in a row. */ +/* (Due to the way transition frames are encoded) */ + +/* In many cases, the discriminant function determines how to smooth. */ +/* In the following chart, the decisions marked with a * may be overridden +.*/ + +/* Voicing override of transitions at onsets: */ +/* If a V/UV or UV/V voicing decision transition occurs within one-half +*/ +/* frame of an onset bounding a voicing window, then the transition is */ +/* moved to occur at the onset. */ + +/* P 1F */ +/* ----- ----- */ +/* 0 0 0 0 */ +/* 0 0 0* 1 (If there is an onset there) */ +/* 0 0 1* 0* (Based on 2F and discriminant distance) */ +/* 0 0 1 1 */ +/* 0 1* 0 0 (Always) */ +/* 0 1* 0* 1 (Based on discriminant distance) */ +/* 0* 1 1 0* (Based on past, 2F, and discriminant distance) */ +/* 0 1* 1 1 (If there is an onset there) */ +/* 1 0* 0 0 (If there is an onset there) */ +/* 1 0 0 1 */ +/* 1 0* 1* 0 (Based on discriminant distance) */ +/* 1 0* 1 1 (Always) */ +/* 1 1 0 0 */ +/* 1 1 0* 1* (Based on 2F and discriminant distance) */ +/* 1 1 1* 0 (If there is an onset there) */ +/* 1 1 1 1 */ + +/* Determine if there is an onset transition between P and 1F. */ +/* OT (Onset Transition) is true if there is an onset between */ +/* P and 1F but not after 1F. */ + ot = ((obound[1] & 2) != 0 || obound[2] == 1) && (obound[3] & 1) == 0; +/* Multi-way dispatch on voicing decision history: */ + vstate = (voibuf[3] << 3) + (voibuf[4] << 2) + (voibuf[5] << 1) + voibuf[ + 6]; + switch (vstate + 1) { + case 1: goto L99; + case 2: goto L1; + case 3: goto L2; + case 4: goto L99; + case 5: goto L4; + case 6: goto L5; + case 7: goto L6; + case 8: goto L7; + case 9: goto L8; + case 10: goto L99; + case 11: goto L10; + case 12: goto L11; + case 13: goto L99; + case 14: goto L13; + case 15: goto L14; + case 16: goto L99; + } +L1: + if (ot && voibuf[7] == 1) { + voibuf[5] = 1; + } + goto L99; +L2: + if (voibuf[7] == 0 || voice[2] < -voice[3]) { + voibuf[5] = 0; + } else { + voibuf[6] = 1; + } + goto L99; +L4: + voibuf[4] = 0; + goto L99; +L5: + if (voice[1] < -voice[2]) { + voibuf[4] = 0; + } else { + voibuf[5] = 1; + } + goto L99; +/* VOIBUF(2,0) must be 0 */ +L6: + if (voibuf[1] == 1 || voibuf[7] == 1 || voice[3] > voice[0]) { + voibuf[6] = 1; + } else { + voibuf[3] = 1; + } + goto L99; +L7: + if (ot) { + voibuf[4] = 0; + } + goto L99; +L8: + if (ot) { + voibuf[4] = 1; + } + goto L99; +L10: + if (voice[2] < -voice[1]) { + voibuf[5] = 0; + } else { + voibuf[4] = 1; + } + goto L99; +L11: + voibuf[4] = 1; + goto L99; +L13: + if (voibuf[7] == 0 && voice[3] < -voice[2]) { + voibuf[6] = 0; + } else { + voibuf[5] = 1; + } + goto L99; +L14: + if (ot && voibuf[7] == 0) { + voibuf[5] = 0; + } +/* GOTO 99 */ +L99: +/* Now update parameters: */ +/* ---------------------- */ + +/* During unvoiced half-frames, update the low band and full band unvoice +d*/ +/* energy estimates (LBUE and FBUE) and also the zero crossing */ +/* threshold (DITHER). (The input to the unvoiced energy filters is */ +/* restricted to be less than 10dB above the previous inputs of the */ +/* filters.) */ +/* During voiced half-frames, update the low-pass (LBVE) and all-pass */ +/* (FBVE) voiced energy estimates. */ + if (voibuf[*half + 6] == 0) { +/* Computing MIN */ + i__1 = fbe, i__2 = *ofbue * 3; + r__1 = (*sfbue * 63 + (min(i__1,i__2) << 3)) / 64.f; + *sfbue = i_nint(&r__1); + *fbue = *sfbue / 8; + *ofbue = fbe; +/* Computing MIN */ + i__1 = lbe, i__2 = *olbue * 3; + r__1 = (*slbue * 63 + (min(i__1,i__2) << 3)) / 64.f; + *slbue = i_nint(&r__1); + *lbue = *slbue / 8; + *olbue = lbe; + } else { + r__1 = (*lbve * 63 + lbe) / 64.f; + *lbve = i_nint(&r__1); + r__1 = (*fbve * 63 + fbe) / 64.f; + *fbve = i_nint(&r__1); + } +/* Set dither threshold to yield proper zero crossing rates in the */ +/* presence of low frequency noise and low level signal input. */ +/* NOTE: The divisor is a function of REF, the expected energies. */ +/* Computing MIN */ +/* Computing MAX */ + r__2 = sqrt((real) (*lbue * *lbve)) * 64 / 3000; + r__1 = max(r__2,1.f); + *dither = min(r__1,20.f); +/* Voicing decisions are returned in VOIBUF. */ + return 0; +} /* voicin_ */ diff --git a/linphone/lpc10-1.5/vparms.c b/linphone/lpc10-1.5/vparms.c new file mode 100644 index 000000000..63c25ea7a --- /dev/null +++ b/linphone/lpc10-1.5/vparms.c @@ -0,0 +1,243 @@ +/* + +$Log: vparms.c,v $ +Revision 1.1.1.1 2001/11/19 19:50:17 smorlat +First cvs. + +Revision 1.1.1.1 2001/08/08 21:29:08 simon +First import + + * Revision 1.1 1996/08/19 22:30:04 jaf + * Initial revision + * + +*/ + +#ifdef P_R_O_T_O_T_Y_P_E_S +extern int vparms_(integer *vwin, real *inbuf, real *lpbuf, integer *buflim, integer *half, real *dither, integer *mintau, integer *zc, integer *lbe, integer *fbe, real *qs, real *rc1, real *ar_b__, real *ar_f__); +#endif + +/* -- translated by f2c (version 19951025). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +#include "f2c.h" + +/* Table of constant values */ + +static real c_b2 = 1.f; + +/* ********************************************************************* */ + +/* VPARMS Version 50 */ + +/* $Log: vparms.c,v $ +/* Revision 1.1.1.1 2001/11/19 19:50:17 smorlat +/* First cvs. +/* +/* Revision 1.1.1.1 2001/08/08 21:29:08 simon +/* First import +/* + * Revision 1.1 1996/08/19 22:30:04 jaf + * Initial revision + * */ +/* Revision 1.6 1996/03/29 18:01:16 jaf */ +/* Added some more comments about the range of INBUF and LPBUF that can */ +/* be read. Note that it is possible for index VWIN(2)+1 to be read from */ +/* INBUF, which might be outside of its defined range, although that will */ +/* require more careful checking. */ + +/* Revision 1.5 1996/03/19 00:02:02 jaf */ +/* I just noticed that the argument DITHER is modified inside of this */ +/* subroutine. Comments were added explaining the possible final values. */ + +/* Revision 1.4 1996/03/18 22:22:59 jaf */ +/* Finishing the job I said I did with the last check-in comments. */ + +/* Revision 1.3 1996/03/18 22:22:17 jaf */ +/* Just added a few comments about which array indices of the arguments */ +/* are used, and mentioning that this subroutine has no local state. */ + +/* Revision 1.2 1996/03/13 15:02:58 jaf */ +/* Comments added explaining that none of the local variables of this */ +/* subroutine need to be saved from one invocation to the next. */ + +/* Revision 1.1 1996/02/07 14:50:42 jaf */ +/* Initial revision */ + + +/* ********************************************************************* */ + +/* Calculate voicing parameters: */ + +/* Input: */ +/* VWIN - Voicing window limits */ +/* Indices 1 through 2 read. */ +/* INBUF - Input speech buffer */ +/* Indices START-1 through STOP read, */ +/* where START and STOP are defined in the code (only written once). +*/ +/* Note that STOP can be as large as VWIN(2)+1 ! */ +/* LPBUF - Low pass filtered speech */ +/* Indices START-MINTAU through STOP+MINTAU read, */ +/* where START and STOP are defined in the code (only written once). +*/ +/* BUFLIM - Array bounds for INBUF and LPBUF */ +/* Indices 1 through 4 read. */ +/* HALF - Half frame (1 or 2) */ +/* MINTAU - Lag corresponding to minimum AMDF value (pitch estimate) */ +/* Input/Output: */ +/* DITHER - Zero crossing threshold */ +/* The resulting value might be the negation of the input */ +/* value. It might always be the same as the input value, */ +/* if the DO loop below always executes an even number of times. */ +/* Output: (all of them are written on every call) */ +/* ZC - Zero crossing rate */ +/* LBE - Low band energy (sum of magnitudes - SM) */ +/* FBE - Full band energy (SM) */ +/* QS - Ratio of 6 dB/oct preemphasized energy to full band energy */ +/* RC1 - First reflection coefficient */ +/* AR_B - Product of the causal forward and reverse pitch */ +/* prediction gains */ +/* AR_F - Product of the noncausal forward and reverse pitch */ +/* prediction gains */ +/* Internal: */ +/* OLDSGN - Previous sign of dithered signal */ +/* VLEN - Length of voicing window */ +/* START - Lower address of current half of voicing window */ +/* STOP - Upper address of current half of voicing window */ +/* E_0 - Energy of LPF speech (sum of squares - SS) */ +/* E_B - Energy of LPF speech backward one pitch period (SS) */ +/* E_F - Energy of LPF speech forward one pitch period (SS) */ +/* R_B - Autocovariance of LPF speech backward one pitch period */ +/* R_F - Autocovariance of LPF speech forward one pitch period */ +/* LP_RMS - Energy of LPF speech (sum of magnitudes - SM) */ +/* AP_RMS - Energy of all-pass speech (SM) */ +/* E_PRE - Energy of 6dB preemphasized speech (SM) */ +/* E0AP - Energy of all-pass speech (SS) */ + +/* This subroutine has no local state. */ + +/* Subroutine */ int vparms_(integer *vwin, real *inbuf, real *lpbuf, integer + *buflim, integer *half, real *dither, integer *mintau, integer *zc, + integer *lbe, integer *fbe, real *qs, real *rc1, real *ar_b__, real * + ar_f__) +{ + /* System generated locals */ + integer inbuf_offset, lpbuf_offset, i__1; + real r__1, r__2; + + /* Builtin functions */ + double r_sign(real *, real *); + integer i_nint(real *); + + /* Local variables */ + integer vlen, stop, i__; + real e_pre__; + integer start; + real ap_rms__, e_0__, oldsgn, lp_rms__, e_b__, e_f__, r_b__, r_f__, e0ap; + +/* Arguments */ +/* Local variables that need not be saved */ +/* Calculate zero crossings (ZC) and several energy and correlation */ +/* measures on low band and full band speech. Each measure is taken */ +/* over either the first or the second half of the voicing window, */ +/* depending on the variable HALF. */ + /* Parameter adjustments */ + --vwin; + --buflim; + lpbuf_offset = buflim[3]; + lpbuf -= lpbuf_offset; + inbuf_offset = buflim[1]; + inbuf -= inbuf_offset; + + /* Function Body */ + lp_rms__ = 0.f; + ap_rms__ = 0.f; + e_pre__ = 0.f; + e0ap = 0.f; + *rc1 = 0.f; + e_0__ = 0.f; + e_b__ = 0.f; + e_f__ = 0.f; + r_f__ = 0.f; + r_b__ = 0.f; + *zc = 0; + vlen = vwin[2] - vwin[1] + 1; + start = vwin[1] + (*half - 1) * vlen / 2 + 1; + stop = start + vlen / 2 - 1; + +/* I'll use the symbol HVL in the table below to represent the value */ +/* VLEN/2. Note that if VLEN is odd, then HVL should be rounded down, */ +/* i.e., HVL = (VLEN-1)/2. */ + +/* HALF START STOP */ + +/* 1 VWIN(1)+1 VWIN(1)+HVL */ +/* 2 VWIN(1)+HVL+1 VWIN(1)+2*HVL */ + +/* Note that if VLEN is even and HALF is 2, then STOP will be */ +/* VWIN(1)+VLEN = VWIN(2)+1. That could be bad, if that index of INBUF */ +/* is undefined. */ + + r__1 = inbuf[start - 1] - *dither; + oldsgn = r_sign(&c_b2, &r__1); + i__1 = stop; + for (i__ = start; i__ <= i__1; ++i__) { + lp_rms__ += (r__1 = lpbuf[i__], abs(r__1)); + ap_rms__ += (r__1 = inbuf[i__], abs(r__1)); + e_pre__ += (r__1 = inbuf[i__] - inbuf[i__ - 1], abs(r__1)); +/* Computing 2nd power */ + r__1 = inbuf[i__]; + e0ap += r__1 * r__1; + *rc1 += inbuf[i__] * inbuf[i__ - 1]; +/* Computing 2nd power */ + r__1 = lpbuf[i__]; + e_0__ += r__1 * r__1; +/* Computing 2nd power */ + r__1 = lpbuf[i__ - *mintau]; + e_b__ += r__1 * r__1; +/* Computing 2nd power */ + r__1 = lpbuf[i__ + *mintau]; + e_f__ += r__1 * r__1; + r_f__ += lpbuf[i__] * lpbuf[i__ + *mintau]; + r_b__ += lpbuf[i__] * lpbuf[i__ - *mintau]; + r__1 = inbuf[i__] + *dither; + if (r_sign(&c_b2, &r__1) != oldsgn) { + ++(*zc); + oldsgn = -oldsgn; + } + *dither = -(*dither); + } +/* Normalized short-term autocovariance coefficient at unit sample delay + */ + *rc1 /= max(e0ap,1.f); +/* Ratio of the energy of the first difference signal (6 dB/oct preemphas +is)*/ +/* to the energy of the full band signal */ +/* Computing MAX */ + r__1 = ap_rms__ * 2.f; + *qs = e_pre__ / max(r__1,1.f); +/* aR_b is the product of the forward and reverse prediction gains, */ +/* looking backward in time (the causal case). */ + *ar_b__ = r_b__ / max(e_b__,1.f) * (r_b__ / max(e_0__,1.f)); +/* aR_f is the same as aR_b, but looking forward in time (non causal case +).*/ + *ar_f__ = r_f__ / max(e_f__,1.f) * (r_f__ / max(e_0__,1.f)); +/* Normalize ZC, LBE, and FBE to old fixed window length of 180. */ +/* (The fraction 90/VLEN has a range of .58 to 1) */ + r__2 = (real) (*zc << 1); + r__1 = r__2 * (90.f / vlen); + *zc = i_nint(&r__1); +/* Computing MIN */ + r__1 = lp_rms__ / 4 * (90.f / vlen); + i__1 = i_nint(&r__1); + *lbe = min(i__1,32767); +/* Computing MIN */ + r__1 = ap_rms__ / 4 * (90.f / vlen); + i__1 = i_nint(&r__1); + *fbe = min(i__1,32767); + return 0; +} /* vparms_ */ + diff --git a/linphone/m4/.cvsignore b/linphone/m4/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/m4/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/m4/Makefile.am b/linphone/m4/Makefile.am new file mode 100644 index 000000000..562029e7c --- /dev/null +++ b/linphone/m4/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST= $(shell cd $(srcdir) && ls *.m4) + diff --git a/linphone/m4/codeset.m4 b/linphone/m4/codeset.m4 new file mode 100644 index 000000000..223955b45 --- /dev/null +++ b/linphone/m4/codeset.m4 @@ -0,0 +1,21 @@ +# codeset.m4 serial 2 (gettext-0.16) +dnl Copyright (C) 2000-2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, + [AC_TRY_LINK([#include ], + [char* cs = nl_langinfo(CODESET); return !cs;], + am_cv_langinfo_codeset=yes, + am_cv_langinfo_codeset=no) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE(HAVE_LANGINFO_CODESET, 1, + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/linphone/m4/exosip.m4 b/linphone/m4/exosip.m4 new file mode 100644 index 000000000..229687c80 --- /dev/null +++ b/linphone/m4/exosip.m4 @@ -0,0 +1,32 @@ +dnl -*- autoconf -*- +AC_DEFUN([LP_SETUP_EXOSIP],[ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([LP_CHECK_OSIP2]) + +dnl eXosip embeded stuff +EXOSIP_CFLAGS="$OSIP_CFLAGS -DOSIP_MT " +EXOSIP_LIBS="$OSIP_LIBS -leXosip2 " + +CPPFLAGS_save=$CPPFLAGS +CPPFLAGS=$OSIP_CFLAGS +AC_CHECK_HEADER([eXosip2/eXosip.h], ,AC_MSG_ERROR([Could not find eXosip2 headers !])) +CPPFLAGS=$CPPFLAGS_save + +dnl check for eXosip2 libs +LDFLAGS_save=$LDFLAGS +LDFLAGS=$OSIP_LIBS +LIBS_save=$LIBS +AC_CHECK_LIB([eXosip2],[eXosip_subscribe_remove], + [], + [AC_MSG_ERROR([Could not find eXosip2 library with version >= 3.0.2 !])], + [-losipparser2 -losip2 -lpthread]) +AC_CHECK_LIB([eXosip2],[eXosip_get_version], + [AC_DEFINE([HAVE_EXOSIP_GET_VERSION],[1],[Defined when eXosip_get_version is available])], + [], + [-losipparser2 -losip2 -lpthread]) +LIBS=$LIBS_save +LDFLAGS=$LDFLAGS_save + +AC_SUBST(EXOSIP_CFLAGS) +AC_SUBST(EXOSIP_LIBS) +]) diff --git a/linphone/m4/gettext.m4 b/linphone/m4/gettext.m4 new file mode 100644 index 000000000..91c345e99 --- /dev/null +++ b/linphone/m4/gettext.m4 @@ -0,0 +1,419 @@ +# gettext.m4 serial 59 (gettext-0.16.1) +dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2006. + +dnl Macro to add for using GNU gettext. + +dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). +dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The +dnl default (if it is not specified or empty) is 'no-libtool'. +dnl INTLSYMBOL should be 'external' for packages with no intl directory, +dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. +dnl If INTLSYMBOL is 'use-libtool', then a libtool library +dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, +dnl depending on --{enable,disable}-{shared,static} and on the presence of +dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library +dnl $(top_builddir)/intl/libintl.a will be created. +dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext +dnl implementations (in libc or libintl) without the ngettext() function +dnl will be ignored. If NEEDSYMBOL is specified and is +dnl 'need-formatstring-macros', then GNU gettext implementations that don't +dnl support the ISO C 99 formatstring macros will be ignored. +dnl INTLDIR is used to find the intl libraries. If empty, +dnl the value `$(top_builddir)/intl/' is used. +dnl +dnl The result of the configuration is one of three cases: +dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled +dnl and used. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 2) GNU gettext has been found in the system's C library. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 3) No internationalization, always use English msgid. +dnl Catalog format: none +dnl Catalog extension: none +dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. +dnl The use of .gmo is historical (it was needed to avoid overwriting the +dnl GNU format catalogs when building on a platform with an X/Open gettext), +dnl but we keep it in order not to force irrelevant filename changes on the +dnl maintainers. +dnl +AC_DEFUN([AM_GNU_GETTEXT], +[ + dnl Argument checking. + ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , + [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT +])])])])]) + ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , + [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT +])])])]) + define([gt_included_intl], + ifelse([$1], [external], + ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), + [yes])) + define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) + gt_NEEDS_INIT + AM_GNU_GETTEXT_NEED([$2]) + + AC_REQUIRE([AM_PO_SUBDIRS])dnl + ifelse(gt_included_intl, yes, [ + AC_REQUIRE([AM_INTL_SUBDIR])dnl + ]) + + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Sometimes libintl requires libiconv, so first search for libiconv. + dnl Ideally we would do this search only after the + dnl if test "$USE_NLS" = "yes"; then + dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT + dnl the configure script would need to contain the same shell code + dnl again, outside any 'if'. There are two solutions: + dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. + dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. + dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not + dnl documented, we avoid it. + ifelse(gt_included_intl, yes, , [ + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + ]) + + dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. + gt_INTL_MACOSX + + dnl Set USE_NLS. + AC_REQUIRE([AM_NLS]) + + ifelse(gt_included_intl, yes, [ + BUILD_INCLUDED_LIBINTL=no + USE_INCLUDED_LIBINTL=no + ]) + LIBINTL= + LTLIBINTL= + POSUB= + + dnl Add a version number to the cache macros. + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + ifelse(gt_included_intl, yes, [ + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + ]) + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If GNU gettext is available we use this. Else we have + dnl to fall back to GNU NLS library. + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], + [AC_TRY_LINK([#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings;], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], + [eval "$gt_func_gnugettext_libc=yes"], + [eval "$gt_func_gnugettext_libc=no"])]) + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl Sometimes libintl requires libiconv, so first search for libiconv. + ifelse(gt_included_intl, yes, , [ + AM_ICONV_LINK + ]) + dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL + dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) + dnl because that would add "-liconv" to LIBINTL and LTLIBINTL + dnl even if libiconv doesn't exist. + AC_LIB_LINKFLAGS_BODY([intl]) + AC_CACHE_CHECK([for GNU gettext in libintl], + [$gt_func_gnugettext_libintl], + [gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + dnl Now see whether libintl exists and does not depend on libiconv. + AC_TRY_LINK([#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *);], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], + [eval "$gt_func_gnugettext_libintl=yes"], + [eval "$gt_func_gnugettext_libintl=no"]) + dnl Now see whether libintl exists and depends on libiconv. + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *);], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], + [LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + ]) + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS"]) + fi + + dnl If an already present or preinstalled GNU gettext() is found, + dnl use it. But if this macro is used in GNU gettext, and GNU + dnl gettext is already preinstalled in libintl, we update this + dnl libintl. (Cf. the install rule in intl/Makefile.in.) + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + dnl Reset the values set by searching for libintl. + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + ifelse(gt_included_intl, yes, [ + if test "$gt_use_preinstalled_gnugettext" != "yes"; then + dnl GNU gettext is not found in the C library. + dnl Fall back on included GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + BUILD_INCLUDED_LIBINTL=yes + USE_INCLUDED_LIBINTL=yes + LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" + LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" + LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` + fi + + CATOBJEXT= + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions to use GNU gettext tools. + CATOBJEXT=.gmo + fi + ]) + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Some extra flags are needed during linking. + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + AC_DEFINE(ENABLE_NLS, 1, + [Define to 1 if translation of program messages to the user's native language + is requested.]) + else + USE_NLS=no + fi + fi + + AC_MSG_CHECKING([whether to use NLS]) + AC_MSG_RESULT([$USE_NLS]) + if test "$USE_NLS" = "yes"; then + AC_MSG_CHECKING([where the gettext function comes from]) + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + AC_MSG_RESULT([$gt_source]) + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + AC_MSG_CHECKING([how to link with libintl]) + AC_MSG_RESULT([$LIBINTL]) + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) + fi + + dnl For backward compatibility. Some packages may be using this. + AC_DEFINE(HAVE_GETTEXT, 1, + [Define if the GNU gettext() function is already present or preinstalled.]) + AC_DEFINE(HAVE_DCGETTEXT, 1, + [Define if the GNU dcgettext() function is already present or preinstalled.]) + fi + + dnl We need to process the po/ directory. + POSUB=po + fi + + ifelse(gt_included_intl, yes, [ + dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL + dnl to 'yes' because some of the testsuite requires it. + if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then + BUILD_INCLUDED_LIBINTL=yes + fi + + dnl Make all variables we use known to autoconf. + AC_SUBST(BUILD_INCLUDED_LIBINTL) + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATOBJEXT) + + dnl For backward compatibility. Some configure.ins may be using this. + nls_cv_header_intl= + nls_cv_header_libgt= + + dnl For backward compatibility. Some Makefiles may be using this. + DATADIRNAME=share + AC_SUBST(DATADIRNAME) + + dnl For backward compatibility. Some Makefiles may be using this. + INSTOBJEXT=.mo + AC_SUBST(INSTOBJEXT) + + dnl For backward compatibility. Some Makefiles may be using this. + GENCAT=gencat + AC_SUBST(GENCAT) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLOBJS= + if test "$USE_INCLUDED_LIBINTL" = yes; then + INTLOBJS="\$(GETTOBJS)" + fi + AC_SUBST(INTLOBJS) + + dnl Enable libtool support if the surrounding package wishes it. + INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix + AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) + ]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLLIBS="$LIBINTL" + AC_SUBST(INTLLIBS) + + dnl Make all documented variables known to autoconf. + AC_SUBST(LIBINTL) + AC_SUBST(LTLIBINTL) + AC_SUBST(POSUB) +]) + + +dnl Checks for special options needed on MacOS X. +dnl Defines INTL_MACOSX_LIBS. +AC_DEFUN([gt_INTL_MACOSX], +[ + dnl Check for API introduced in MacOS X 10.2. + AC_CACHE_CHECK([for CFPreferencesCopyAppValue], + gt_cv_func_CFPreferencesCopyAppValue, + [gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + AC_TRY_LINK([#include ], + [CFPreferencesCopyAppValue(NULL, NULL)], + [gt_cv_func_CFPreferencesCopyAppValue=yes], + [gt_cv_func_CFPreferencesCopyAppValue=no]) + LIBS="$gt_save_LIBS"]) + if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then + AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, + [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) + fi + dnl Check for API introduced in MacOS X 10.3. + AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, + [gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();], + [gt_cv_func_CFLocaleCopyCurrent=yes], + [gt_cv_func_CFLocaleCopyCurrent=no]) + LIBS="$gt_save_LIBS"]) + if test $gt_cv_func_CFLocaleCopyCurrent = yes; then + AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, + [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) + fi + INTL_MACOSX_LIBS= + if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" + fi + AC_SUBST([INTL_MACOSX_LIBS]) +]) + + +dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. +m4_define([gt_NEEDS_INIT], +[ + m4_divert_text([DEFAULTS], [gt_needs=]) + m4_define([gt_NEEDS_INIT], []) +]) + + +dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) +AC_DEFUN([AM_GNU_GETTEXT_NEED], +[ + m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) +]) + + +dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) +AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/linphone/m4/glibc2.m4 b/linphone/m4/glibc2.m4 new file mode 100644 index 000000000..e8f5bfe6e --- /dev/null +++ b/linphone/m4/glibc2.m4 @@ -0,0 +1,30 @@ +# glibc2.m4 serial 1 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.0 or newer. +# From Bruno Haible. + +AC_DEFUN([gt_GLIBC2], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, + ac_cv_gnu_library_2, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ >= 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2=yes, + ac_cv_gnu_library_2=no) + ] + ) + AC_SUBST(GLIBC2) + GLIBC2="$ac_cv_gnu_library_2" + ] +) diff --git a/linphone/m4/glibc21.m4 b/linphone/m4/glibc21.m4 new file mode 100644 index 000000000..d95fd9861 --- /dev/null +++ b/linphone/m4/glibc21.m4 @@ -0,0 +1,30 @@ +# glibc21.m4 serial 3 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.1 or newer. +# From Bruno Haible. + +AC_DEFUN([gl_GLIBC21], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, + ac_cv_gnu_library_2_1, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2_1=yes, + ac_cv_gnu_library_2_1=no) + ] + ) + AC_SUBST(GLIBC21) + GLIBC21="$ac_cv_gnu_library_2_1" + ] +) diff --git a/linphone/m4/iconv.m4 b/linphone/m4/iconv.m4 new file mode 100644 index 000000000..654c41589 --- /dev/null +++ b/linphone/m4/iconv.m4 @@ -0,0 +1,101 @@ +# iconv.m4 serial AM4 (gettext-0.11.3) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_func_iconv=yes) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_lib_iconv=yes + am_cv_func_iconv=yes) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST(LIBICONV) + AC_SUBST(LTLIBICONV) +]) + +AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL(am_cv_proto_iconv, [ + AC_TRY_COMPILE([ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif +], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([$]{ac_t:- + }[$]am_cv_proto_iconv) + AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, + [Define as const if the declaration of iconv() needs const.]) + fi +]) diff --git a/linphone/m4/ilbc.m4 b/linphone/m4/ilbc.m4 new file mode 100644 index 000000000..465f8506d --- /dev/null +++ b/linphone/m4/ilbc.m4 @@ -0,0 +1,33 @@ +AC_DEFUN([LP_CHECK_ILBC],[ + +AC_ARG_WITH( ilbc, + [ --with-ilbc Set prefix where ilbc headers and libs can be found (ex:/usr, /usr/local, none to disable ilbc support) [default=/usr] ], + [ ilbc_prefix=${withval}],[ ilbc_prefix="/usr" ]) + +if test "$ilbc_prefix" = "none" ; then + AC_MSG_NOTICE([iLBC codec support disabled. ]) +else + ILBC_CFLAGS=" -I${ilbc_prefix}/include/ilbc" + ILBC_LIBS="-L${ilbc_prefix}/lib -lilbc -lm" + CPPFLAGS_save=$CPPFLAGS + CPPFLAGS=$ILBC_CFLAGS + LDFLAGS_save=$LDFLAGS + LDFLAGS=$ILBC_LIBS + AC_CHECK_HEADERS(iLBC_decode.h,[AC_CHECK_LIB(ilbc,iLBC_decode,ilbc_found=yes,ilbc_found=no) + ],ilbc_found=no) + + CPPFLAGS=$CPPFLAGS_save + LDFLAGS=$LDFLAGS_save + + if test "$ilbc_found" = "no" ; then + AC_MSG_WARN([Could not find ilbc headers or libs. Please install ilbc package from http://www.linphone.org if you want iLBC codec support in linphone.]) + ILBC_CFLAGS= + ILBC_LIBS= + else + AC_DEFINE(HAVE_ILBC,1,[Defined when we have ilbc codec lib]) + AC_SUBST(ILBC_CFLAGS) + AC_SUBST(ILBC_LIBS) + fi +fi + +]) diff --git a/linphone/m4/intdiv0.m4 b/linphone/m4/intdiv0.m4 new file mode 100644 index 000000000..b8d78176a --- /dev/null +++ b/linphone/m4/intdiv0.m4 @@ -0,0 +1,70 @@ +# intdiv0.m4 serial 1 (gettext-0.11.3) +dnl Copyright (C) 2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gt_INTDIV0], +[ + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + + AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], + gt_cv_int_divbyzero_sigfpe, + [ + AC_TRY_RUN([ +#include +#include + +static void +#ifdef __cplusplus +sigfpe_handler (int sig) +#else +sigfpe_handler (sig) int sig; +#endif +{ + /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ + exit (sig != SIGFPE); +} + +int x = 1; +int y = 0; +int z; +int nan; + +int main () +{ + signal (SIGFPE, sigfpe_handler); +/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ +#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) + signal (SIGTRAP, sigfpe_handler); +#endif +/* Linux/SPARC yields signal SIGILL. */ +#if defined (__sparc__) && defined (__linux__) + signal (SIGILL, sigfpe_handler); +#endif + + z = x / y; + nan = y / y; + exit (1); +} +], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, + [ + # Guess based on the CPU. + case "$host_cpu" in + alpha* | i[34567]86 | m68k | s390*) + gt_cv_int_divbyzero_sigfpe="guessing yes";; + *) + gt_cv_int_divbyzero_sigfpe="guessing no";; + esac + ]) + ]) + case "$gt_cv_int_divbyzero_sigfpe" in + *yes) value=1;; + *) value=0;; + esac + AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, + [Define if integer division by zero raises signal SIGFPE.]) +]) diff --git a/linphone/m4/intl.m4 b/linphone/m4/intl.m4 new file mode 100644 index 000000000..dcefb118c --- /dev/null +++ b/linphone/m4/intl.m4 @@ -0,0 +1,259 @@ +# intl.m4 serial 3 (gettext-0.16) +dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2006. + +AC_PREREQ(2.52) + +dnl Checks for all prerequisites of the intl subdirectory, +dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, +dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. +AC_DEFUN([AM_INTL_SUBDIR], +[ + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + AC_REQUIRE([gt_GLIBC2])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([gl_VISIBILITY])dnl + AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl + AC_REQUIRE([AC_TYPE_LONG_LONG_INT])dnl + AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl + AC_REQUIRE([gt_TYPE_WCHAR_T])dnl + AC_REQUIRE([gt_TYPE_WINT_T])dnl + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gt_TYPE_INTMAX_T]) + AC_REQUIRE([gt_PRINTF_POSIX]) + AC_REQUIRE([gl_GLIBC21])dnl + AC_REQUIRE([gl_XSIZE])dnl + AC_REQUIRE([gt_INTL_MACOSX])dnl + + AC_CHECK_TYPE([ptrdiff_t], , + [AC_DEFINE([ptrdiff_t], [long], + [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) + ]) + AC_CHECK_HEADERS([stddef.h stdlib.h string.h]) + AC_CHECK_FUNCS([asprintf fwprintf putenv setenv setlocale snprintf wcslen]) + + dnl Use the _snprintf function only if it is declared (because on NetBSD it + dnl is defined as a weak alias of snprintf; we prefer to use the latter). + gt_CHECK_DECL(_snprintf, [#include ]) + gt_CHECK_DECL(_snwprintf, [#include ]) + + dnl Use the *_unlocked functions only if they are declared. + dnl (because some of them were defined without being declared in Solaris + dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built + dnl on Solaris 2.5.1 to run on Solaris 2.6). + dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. + gt_CHECK_DECL(getc_unlocked, [#include ]) + + case $gt_cv_func_printf_posix in + *yes) HAVE_POSIX_PRINTF=1 ;; + *) HAVE_POSIX_PRINTF=0 ;; + esac + AC_SUBST([HAVE_POSIX_PRINTF]) + if test "$ac_cv_func_asprintf" = yes; then + HAVE_ASPRINTF=1 + else + HAVE_ASPRINTF=0 + fi + AC_SUBST([HAVE_ASPRINTF]) + if test "$ac_cv_func_snprintf" = yes; then + HAVE_SNPRINTF=1 + else + HAVE_SNPRINTF=0 + fi + AC_SUBST([HAVE_SNPRINTF]) + if test "$ac_cv_func_wprintf" = yes; then + HAVE_WPRINTF=1 + else + HAVE_WPRINTF=0 + fi + AC_SUBST([HAVE_WPRINTF]) + + AM_LANGINFO_CODESET + gt_LC_MESSAGES + + dnl Compilation on mingw and Cygwin needs special Makefile rules, because + dnl 1. when we install a shared library, we must arrange to export + dnl auxiliary pointer variables for every exported variable, + dnl 2. when we install a shared library and a static library simultaneously, + dnl the include file specifies __declspec(dllimport) and therefore we + dnl must arrange to define the auxiliary pointer variables for the + dnl exported variables _also_ in the static library. + if test "$enable_shared" = yes; then + case "$host_os" in + cygwin*) is_woe32dll=yes ;; + *) is_woe32dll=no ;; + esac + else + is_woe32dll=no + fi + WOE32DLL=$is_woe32dll + AC_SUBST([WOE32DLL]) + + dnl Rename some macros and functions used for locking. + AH_BOTTOM([ +#define __libc_lock_t gl_lock_t +#define __libc_lock_define gl_lock_define +#define __libc_lock_define_initialized gl_lock_define_initialized +#define __libc_lock_init gl_lock_init +#define __libc_lock_lock gl_lock_lock +#define __libc_lock_unlock gl_lock_unlock +#define __libc_lock_recursive_t gl_recursive_lock_t +#define __libc_lock_define_recursive gl_recursive_lock_define +#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized +#define __libc_lock_init_recursive gl_recursive_lock_init +#define __libc_lock_lock_recursive gl_recursive_lock_lock +#define __libc_lock_unlock_recursive gl_recursive_lock_unlock +#define glthread_in_use libintl_thread_in_use +#define glthread_lock_init libintl_lock_init +#define glthread_lock_lock libintl_lock_lock +#define glthread_lock_unlock libintl_lock_unlock +#define glthread_lock_destroy libintl_lock_destroy +#define glthread_rwlock_init libintl_rwlock_init +#define glthread_rwlock_rdlock libintl_rwlock_rdlock +#define glthread_rwlock_wrlock libintl_rwlock_wrlock +#define glthread_rwlock_unlock libintl_rwlock_unlock +#define glthread_rwlock_destroy libintl_rwlock_destroy +#define glthread_recursive_lock_init libintl_recursive_lock_init +#define glthread_recursive_lock_lock libintl_recursive_lock_lock +#define glthread_recursive_lock_unlock libintl_recursive_lock_unlock +#define glthread_recursive_lock_destroy libintl_recursive_lock_destroy +#define glthread_once libintl_once +#define glthread_once_call libintl_once_call +#define glthread_once_singlethreaded libintl_once_singlethreaded +]) +]) + + +dnl Checks for the core files of the intl subdirectory: +dnl dcigettext.c +dnl eval-plural.h +dnl explodename.c +dnl finddomain.c +dnl gettextP.h +dnl gmo.h +dnl hash-string.h hash-string.c +dnl l10nflist.c +dnl libgnuintl.h.in (except the *printf stuff) +dnl loadinfo.h +dnl loadmsgcat.c +dnl localealias.c +dnl log.c +dnl plural-exp.h plural-exp.c +dnl plural.y +dnl Used by libglocale. +AC_DEFUN([gt_INTL_SUBDIR_CORE], +[ + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([gt_INTDIV0])dnl + AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl + AC_REQUIRE([gt_INTTYPES_PRI])dnl + AC_REQUIRE([gl_LOCK])dnl + + AC_TRY_LINK( + [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }], + [], + [AC_DEFINE([HAVE_BUILTIN_EXPECT], 1, + [Define to 1 if the compiler understands __builtin_expect.])]) + + AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h]) + AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \ + stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ + argz_next __fsetlocking]) + + dnl Use the *_unlocked functions only if they are declared. + dnl (because some of them were defined without being declared in Solaris + dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built + dnl on Solaris 2.5.1 to run on Solaris 2.6). + dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. + gt_CHECK_DECL(feof_unlocked, [#include ]) + gt_CHECK_DECL(fgets_unlocked, [#include ]) + + AM_ICONV + + dnl glibc >= 2.4 has a NL_LOCALE_NAME macro when _GNU_SOURCE is defined, + dnl and a _NL_LOCALE_NAME macro always. + AC_CACHE_CHECK([for NL_LOCALE_NAME macro], gt_cv_nl_locale_name, + [AC_TRY_LINK([#include +#include ], + [char* cs = nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES));], + gt_cv_nl_locale_name=yes, + gt_cv_nl_locale_name=no) + ]) + if test $gt_cv_nl_locale_name = yes; then + AC_DEFINE(HAVE_NL_LOCALE_NAME, 1, + [Define if you have and it defines the NL_LOCALE_NAME macro if _GNU_SOURCE is defined.]) + fi + + dnl intl/plural.c is generated from intl/plural.y. It requires bison, + dnl because plural.y uses bison specific features. It requires at least + dnl bison-1.26 because earlier versions generate a plural.c that doesn't + dnl compile. + dnl bison is only needed for the maintainer (who touches plural.y). But in + dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put + dnl the rule in general Makefile. Now, some people carelessly touch the + dnl files or have a broken "make" program, hence the plural.c rule will + dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not + dnl present or too old. + AC_CHECK_PROGS([INTLBISON], [bison]) + if test -z "$INTLBISON"; then + ac_verc_fail=yes + else + dnl Found it, now check the version. + AC_MSG_CHECKING([version of bison]) +changequote(<<,>>)dnl + ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; + 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) +changequote([,])dnl + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + esac + AC_MSG_RESULT([$ac_prog_version]) + fi + if test $ac_verc_fail = yes; then + INTLBISON=: + fi +]) + + +dnl gt_CHECK_DECL(FUNC, INCLUDES) +dnl Check whether a function is declared. +AC_DEFUN([gt_CHECK_DECL], +[ + AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, + [AC_TRY_COMPILE([$2], [ +#ifndef $1 + char *p = (char *) $1; +#endif +], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) + if test $ac_cv_have_decl_$1 = yes; then + gt_value=1 + else + gt_value=0 + fi + AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], + [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) +]) diff --git a/linphone/m4/intldir.m4 b/linphone/m4/intldir.m4 new file mode 100644 index 000000000..7a28843f6 --- /dev/null +++ b/linphone/m4/intldir.m4 @@ -0,0 +1,19 @@ +# intldir.m4 serial 1 (gettext-0.16) +dnl Copyright (C) 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +AC_PREREQ(2.52) + +dnl Tells the AM_GNU_GETTEXT macro to consider an intl/ directory. +AC_DEFUN([AM_GNU_GETTEXT_INTL_SUBDIR], []) diff --git a/linphone/m4/intmax.m4 b/linphone/m4/intmax.m4 new file mode 100644 index 000000000..ce7a8a49d --- /dev/null +++ b/linphone/m4/intmax.m4 @@ -0,0 +1,33 @@ +# intmax.m4 serial 3 (gettext-0.16) +dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether the system has the 'intmax_t' type, but don't attempt to +dnl find a replacement if it is lacking. + +AC_DEFUN([gt_TYPE_INTMAX_T], +[ + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, + [AC_TRY_COMPILE([ +#include +#include +#if HAVE_STDINT_H_WITH_UINTMAX +#include +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +#include +#endif +], [intmax_t x = -1; + return !x;], + gt_cv_c_intmax_t=yes, + gt_cv_c_intmax_t=no)]) + if test $gt_cv_c_intmax_t = yes; then + AC_DEFINE(HAVE_INTMAX_T, 1, + [Define if you have the 'intmax_t' type in or .]) + fi +]) diff --git a/linphone/m4/inttypes-pri.m4 b/linphone/m4/inttypes-pri.m4 new file mode 100644 index 000000000..7c7f89401 --- /dev/null +++ b/linphone/m4/inttypes-pri.m4 @@ -0,0 +1,36 @@ +# inttypes-pri.m4 serial 4 (gettext-0.16) +dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ(2.52) + +# Define PRI_MACROS_BROKEN if exists and defines the PRI* +# macros to non-string values. This is the case on AIX 4.3.3. + +AC_DEFUN([gt_INTTYPES_PRI], +[ + AC_CHECK_HEADERS([inttypes.h]) + if test $ac_cv_header_inttypes_h = yes; then + AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], + gt_cv_inttypes_pri_broken, + [ + AC_TRY_COMPILE([#include +#ifdef PRId32 +char *p = PRId32; +#endif +], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) + ]) + fi + if test "$gt_cv_inttypes_pri_broken" = yes; then + AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, + [Define if exists and defines unusable PRI* macros.]) + PRI_MACROS_BROKEN=1 + else + PRI_MACROS_BROKEN=0 + fi + AC_SUBST([PRI_MACROS_BROKEN]) +]) diff --git a/linphone/m4/inttypes.m4 b/linphone/m4/inttypes.m4 new file mode 100644 index 000000000..779bcea05 --- /dev/null +++ b/linphone/m4/inttypes.m4 @@ -0,0 +1,25 @@ +# inttypes.m4 serial 1 (gettext-0.11.4) +dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H if exists and doesn't clash with +# . + +AC_DEFUN([gt_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, + [ + AC_TRY_COMPILE( + [#include +#include ], + [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) + ]) + if test $gt_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, + [Define if exists and doesn't clash with .]) + fi +]) diff --git a/linphone/m4/inttypes_h.m4 b/linphone/m4/inttypes_h.m4 new file mode 100644 index 000000000..edc8ecb2d --- /dev/null +++ b/linphone/m4/inttypes_h.m4 @@ -0,0 +1,26 @@ +# inttypes_h.m4 serial 7 +dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, +# doesn't clash with , and declares uintmax_t. + +AC_DEFUN([gl_AC_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1; return !i;], + gl_cv_header_inttypes_h=yes, + gl_cv_header_inttypes_h=no)]) + if test $gl_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, + [Define if exists, doesn't clash with , + and declares uintmax_t. ]) + fi +]) diff --git a/linphone/m4/isc-posix.m4 b/linphone/m4/isc-posix.m4 new file mode 100644 index 000000000..74dc8f26d --- /dev/null +++ b/linphone/m4/isc-posix.m4 @@ -0,0 +1,24 @@ +# isc-posix.m4 serial 2 (gettext-0.11.2) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# This file is not needed with autoconf-2.53 and newer. Remove it in 2005. + +# This test replaces the one in autoconf. +# Currently this macro should have the same name as the autoconf macro +# because gettext's gettext.m4 (distributed in the automake package) +# still uses it. Otherwise, the use in gettext.m4 makes autoheader +# give these diagnostics: +# configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX +# configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX + +undefine([AC_ISC_POSIX]) + +AC_DEFUN([AC_ISC_POSIX], + [ + dnl This test replaces the obsolescent AC_ISC_POSIX kludge. + AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) + ] +) diff --git a/linphone/m4/lcmessage.m4 b/linphone/m4/lcmessage.m4 new file mode 100644 index 000000000..19aa77e4f --- /dev/null +++ b/linphone/m4/lcmessage.m4 @@ -0,0 +1,30 @@ +# lcmessage.m4 serial 4 (gettext-0.14.2) +dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995. + +# Check whether LC_MESSAGES is available in . + +AC_DEFUN([gt_LC_MESSAGES], +[ + AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) + if test $gt_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi +]) diff --git a/linphone/m4/lib-ld.m4 b/linphone/m4/lib-ld.m4 new file mode 100644 index 000000000..96c4e2c33 --- /dev/null +++ b/linphone/m4/lib-ld.m4 @@ -0,0 +1,110 @@ +# lib-ld.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(acl_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) diff --git a/linphone/m4/lib-link.m4 b/linphone/m4/lib-link.m4 new file mode 100644 index 000000000..f95b7ba88 --- /dev/null +++ b/linphone/m4/lib-link.m4 @@ -0,0 +1,644 @@ +# lib-link.m4 serial 9 (gettext-0.16) +dnl Copyright (C) 2001-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ(2.50) + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + undefine([Name]) + undefine([NAME]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. If found, it +dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and +dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIB[]NAME" + AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + undefine([Name]) + undefine([NAME]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, +dnl hardcode_direct, hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + dnl Tell automake >= 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE(rpath, + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib$1-prefix], +[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib + --without-lib$1-prefix don't search for lib$1 in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) diff --git a/linphone/m4/lib-prefix.m4 b/linphone/m4/lib-prefix.m4 new file mode 100644 index 000000000..a8684e17e --- /dev/null +++ b/linphone/m4/lib-prefix.m4 @@ -0,0 +1,185 @@ +# lib-prefix.m4 serial 5 (gettext-0.15) +dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing +dnl the basename of the libdir, either "lib" or "lib64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. The current + dnl practice is that on a system supporting 32-bit and 64-bit instruction + dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit + dnl libraries go under $prefix/lib. We determine the compiler's default + dnl mode by looking at the compiler's library search path. If at least + dnl of its elements ends in /lib64 or points to a directory whose absolute + dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the + dnl default, namely "lib". + acl_libdirstem=lib + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi +]) diff --git a/linphone/m4/lock.m4 b/linphone/m4/lock.m4 new file mode 100644 index 000000000..0224f2ff8 --- /dev/null +++ b/linphone/m4/lock.m4 @@ -0,0 +1,311 @@ +# lock.m4 serial 6 (gettext-0.16) +dnl Copyright (C) 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests for a multithreading library to be used. +dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, +dnl USE_PTH_THREADS, USE_WIN32_THREADS +dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use +dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with +dnl libtool). +dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for +dnl programs that really need multithread functionality. The difference +dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak +dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". +dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for +dnl multithread-safe programs. + +AC_DEFUN([gl_LOCK_EARLY], +[ + AC_REQUIRE([gl_LOCK_EARLY_BODY]) +]) + +dnl The guts of gl_LOCK_EARLY. Needs to be expanded only once. + +AC_DEFUN([gl_LOCK_EARLY_BODY], +[ + dnl Ordering constraints: This macro modifies CPPFLAGS in a way that + dnl influences the result of the autoconf tests that test for *_unlocked + dnl declarations, on AIX 5 at least. Therefore it must come early. + AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl + AC_BEFORE([$0], [gl_ARGP])dnl + + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems + dnl Check for multithreading. + AC_ARG_ENABLE(threads, +AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API]) +AC_HELP_STRING([--disable-threads], [build without multithread safety]), + [gl_use_threads=$enableval], + [case "$host_os" in + dnl Disable multithreading by default on OSF/1, because it interferes + dnl with fork()/exec(): When msgexec is linked with -lpthread, its child + dnl process gets an endless segmentation fault inside execvp(). + osf*) gl_use_threads=no ;; + *) gl_use_threads=yes ;; + esac + ]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # For using : + case "$host_os" in + osf*) + # On OSF/1, the compiler needs the flag -D_REENTRANT so that it + # groks . cc also understands the flag -pthread, but + # we don't use it because 1. gcc-2.95 doesn't understand -pthread, + # 2. putting a flag into CPPFLAGS that has an effect on the linker + # causes the AC_TRY_LINK test below to succeed unexpectedly, + # leading to wrong values of LIBTHREAD and LTLIBTHREAD. + CPPFLAGS="$CPPFLAGS -D_REENTRANT" + ;; + esac + # Some systems optimize for single-threaded programs by default, and + # need special flags to disable these optimizations. For example, the + # definition of 'errno' in . + case "$host_os" in + aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; + solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; + esac + fi +]) + +dnl The guts of gl_LOCK. Needs to be expanded only once. + +AC_DEFUN([gl_LOCK_BODY], +[ + AC_REQUIRE([gl_LOCK_EARLY_BODY]) + gl_threads_api=none + LIBTHREAD= + LTLIBTHREAD= + LIBMULTITHREAD= + LTLIBMULTITHREAD= + if test "$gl_use_threads" != no; then + dnl Check whether the compiler and linker support weak declarations. + AC_MSG_CHECKING([whether imported symbols can be declared weak]) + gl_have_weak=no + AC_TRY_LINK([extern void xyzzy (); +#pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes]) + AC_MSG_RESULT([$gl_have_weak]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that + # it groks . It's added above, in gl_LOCK_EARLY_BODY. + AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no) + if test "$gl_have_pthread_h" = yes; then + # Other possible tests: + # -lpthreads (FSU threads, PCthreads) + # -lgthreads + gl_have_pthread= + # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist + # in libc. IRIX 6.5 has the first one in both libc and libpthread, but + # the second one only in libpthread, and lock.c needs it. + AC_TRY_LINK([#include ], + [pthread_mutex_lock((pthread_mutex_t*)0); + pthread_mutexattr_init((pthread_mutexattr_t*)0);], + [gl_have_pthread=yes]) + # Test for libpthread by looking for pthread_kill. (Not pthread_self, + # since it is defined as a macro on OSF/1.) + if test -n "$gl_have_pthread"; then + # The program links fine without libpthread. But it may actually + # need to link with libpthread in order to create multiple threads. + AC_CHECK_LIB(pthread, pthread_kill, + [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread + # On Solaris and HP-UX, most pthread functions exist also in libc. + # Therefore pthread_in_use() needs to actually try to create a + # thread: pthread_create from libc will fail, whereas + # pthread_create will actually create a thread. + case "$host_os" in + solaris* | hpux*) + AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1, + [Define if the pthread_in_use() detection is hard.]) + esac + ]) + else + # Some library is needed. Try libpthread and libc_r. + AC_CHECK_LIB(pthread, pthread_kill, + [gl_have_pthread=yes + LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread + LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) + if test -z "$gl_have_pthread"; then + # For FreeBSD 4. + AC_CHECK_LIB(c_r, pthread_kill, + [gl_have_pthread=yes + LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r + LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) + fi + fi + if test -n "$gl_have_pthread"; then + gl_threads_api=posix + AC_DEFINE([USE_POSIX_THREADS], 1, + [Define if the POSIX multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if test $gl_have_weak = yes; then + AC_DEFINE([USE_POSIX_THREADS_WEAK], 1, + [Define if references to the POSIX multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the + # pthread_rwlock_* functions. + AC_CHECK_TYPE([pthread_rwlock_t], + [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1, + [Define if the POSIX multithreading library has read/write locks.])], + [], + [#include ]) + # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. + AC_TRY_COMPILE([#include ], + [#if __FreeBSD__ == 4 +error "No, in FreeBSD 4.0 recursive mutexes actually don't work." +#else +int x = (int)PTHREAD_MUTEX_RECURSIVE; +return !x; +#endif], + [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, + [Define if the defines PTHREAD_MUTEX_RECURSIVE.])]) + fi + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then + gl_have_solaristhread= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lthread" + AC_TRY_LINK([#include +#include ], + [thr_self();], + [gl_have_solaristhread=yes]) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_solaristhread"; then + gl_threads_api=solaris + LIBTHREAD=-lthread + LTLIBTHREAD=-lthread + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_SOLARIS_THREADS], 1, + [Define if the old Solaris multithreading library can be used.]) + if test $gl_have_weak = yes; then + AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1, + [Define if references to the old Solaris multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + fi + fi + if test "$gl_use_threads" = pth; then + gl_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_LINKFLAGS(pth) + gl_have_pth= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lpth" + AC_TRY_LINK([#include ], [pth_self();], gl_have_pth=yes) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_pth"; then + gl_threads_api=pth + LIBTHREAD="$LIBPTH" + LTLIBTHREAD="$LTLIBPTH" + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_PTH_THREADS], 1, + [Define if the GNU Pth multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if test $gl_have_weak = yes; then + AC_DEFINE([USE_PTH_THREADS_WEAK], 1, + [Define if references to the GNU Pth multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + else + CPPFLAGS="$gl_save_CPPFLAGS" + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then + if { case "$host_os" in + mingw*) true;; + *) false;; + esac + }; then + gl_threads_api=win32 + AC_DEFINE([USE_WIN32_THREADS], 1, + [Define if the Win32 multithreading API can be used.]) + fi + fi + fi + fi + AC_MSG_CHECKING([for multithread API to use]) + AC_MSG_RESULT([$gl_threads_api]) + AC_SUBST(LIBTHREAD) + AC_SUBST(LTLIBTHREAD) + AC_SUBST(LIBMULTITHREAD) + AC_SUBST(LTLIBMULTITHREAD) +]) + +AC_DEFUN([gl_LOCK], +[ + AC_REQUIRE([gl_LOCK_EARLY]) + AC_REQUIRE([gl_LOCK_BODY]) + gl_PREREQ_LOCK +]) + +# Prerequisites of lib/lock.c. +AC_DEFUN([gl_PREREQ_LOCK], [ + AC_REQUIRE([AC_C_INLINE]) +]) + +dnl Survey of platforms: +dnl +dnl Platform Available Compiler Supports test-lock +dnl flavours option weak result +dnl --------------- --------- --------- -------- --------- +dnl Linux 2.4/glibc posix -lpthread Y OK +dnl +dnl GNU Hurd/glibc posix +dnl +dnl FreeBSD 5.3 posix -lc_r Y +dnl posix -lkse ? Y +dnl posix -lpthread ? Y +dnl posix -lthr Y +dnl +dnl FreeBSD 5.2 posix -lc_r Y +dnl posix -lkse Y +dnl posix -lthr Y +dnl +dnl FreeBSD 4.0,4.10 posix -lc_r Y OK +dnl +dnl NetBSD 1.6 -- +dnl +dnl OpenBSD 3.4 posix -lpthread Y OK +dnl +dnl MacOS X 10.[123] posix -lpthread Y OK +dnl +dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK +dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK +dnl +dnl HP-UX 11 posix -lpthread N (cc) OK +dnl Y (gcc) +dnl +dnl IRIX 6.5 posix -lpthread Y 0.5 +dnl +dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK +dnl +dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK +dnl -lpthread (gcc) Y +dnl +dnl Cygwin posix -lpthread Y OK +dnl +dnl Any of the above pth -lpth 0.0 +dnl +dnl Mingw win32 N OK +dnl +dnl BeOS 5 -- +dnl +dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is +dnl turned off: +dnl OK if all three tests terminate OK, +dnl 0.5 if the first test terminates OK but the second one loops endlessly, +dnl 0.0 if the first test already loops endlessly. diff --git a/linphone/m4/longdouble.m4 b/linphone/m4/longdouble.m4 new file mode 100644 index 000000000..25590f470 --- /dev/null +++ b/linphone/m4/longdouble.m4 @@ -0,0 +1,31 @@ +# longdouble.m4 serial 2 (gettext-0.15) +dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether the compiler supports the 'long double' type. +dnl Prerequisite: AC_PROG_CC + +dnl This file is only needed in autoconf <= 2.59. Newer versions of autoconf +dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics. + +AC_DEFUN([gt_TYPE_LONGDOUBLE], +[ + AC_CACHE_CHECK([for long double], gt_cv_c_long_double, + [if test "$GCC" = yes; then + gt_cv_c_long_double=yes + else + AC_TRY_COMPILE([ + /* The Stardent Vistra knows sizeof(long double), but does not support it. */ + long double foo = 0.0; + /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ + int array [2*(sizeof(long double) >= sizeof(double)) - 1]; + ], , + gt_cv_c_long_double=yes, gt_cv_c_long_double=no) + fi]) + if test $gt_cv_c_long_double = yes; then + AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) + fi +]) diff --git a/linphone/m4/longlong.m4 b/linphone/m4/longlong.m4 new file mode 100644 index 000000000..3716c09f6 --- /dev/null +++ b/linphone/m4/longlong.m4 @@ -0,0 +1,48 @@ +# longlong.m4 serial 8 +dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_LONG_LONG_INT if 'long long int' works. +# This fixes a bug in Autoconf 2.60, but can be removed once we +# assume 2.61 everywhere. + +# Note: If the type 'long long int' exists but is only 32 bits large +# (as on some very old compilers), AC_TYPE_LONG_LONG_INT will not be +# defined. In this case you can treat 'long long int' like 'long int'. + +AC_DEFUN([AC_TYPE_LONG_LONG_INT], +[ + AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[long long int ll = 9223372036854775807ll; + long long int nll = -9223372036854775807LL; + typedef int a[((-9223372036854775807LL < 0 + && 0 < 9223372036854775807ll) + ? 1 : -1)]; + int i = 63;]], + [[long long int llmax = 9223372036854775807ll; + return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) + | (llmax / ll) | (llmax % ll));]])], + [ac_cv_type_long_long_int=yes], + [ac_cv_type_long_long_int=no])]) + if test $ac_cv_type_long_long_int = yes; then + AC_DEFINE([HAVE_LONG_LONG_INT], 1, + [Define to 1 if the system has the type `long long int'.]) + fi +]) + +# This macro is obsolescent and should go away soon. +AC_DEFUN([gl_AC_TYPE_LONG_LONG], +[ + AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) + ac_cv_type_long_long=$ac_cv_type_long_long_int + if test $ac_cv_type_long_long = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, + [Define if you have the 'long long' type.]) + fi +]) diff --git a/linphone/m4/nls.m4 b/linphone/m4/nls.m4 new file mode 100644 index 000000000..7967cc2f9 --- /dev/null +++ b/linphone/m4/nls.m4 @@ -0,0 +1,31 @@ +# nls.m4 serial 3 (gettext-0.15) +dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ(2.50) + +AC_DEFUN([AM_NLS], +[ + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) +]) diff --git a/linphone/m4/ortp.m4 b/linphone/m4/ortp.m4 new file mode 100644 index 000000000..e0f36efd1 --- /dev/null +++ b/linphone/m4/ortp.m4 @@ -0,0 +1,16 @@ +AC_DEFUN([LP_CHECK_ORTP],[ + +ortp_pkgconfig=true + +PKG_CHECK_MODULES([ORTP], [ortp], , [ortp_pkgconfig=false]) + +if test $ortp_pkgconfig = false; then + AC_CHECK_HEADER([ortp/ortp.h], ,AC_MSG_ERROR([Could not find oRTP headers !])) + LIBS_save=$LIBS + AC_CHECK_LIB([ortp], [ortp_init], , AC_MSG_ERROR([Could not find oRTP library])) + ORTP_LIBS='-lortp' + LIBS=$LIBS_save +fi +AC_SUBST([ORTP_LIBS]) +AC_SUBST([ORTP_CFLAGS]) +]) diff --git a/linphone/m4/osip.m4 b/linphone/m4/osip.m4 new file mode 100644 index 000000000..2c6c99a0b --- /dev/null +++ b/linphone/m4/osip.m4 @@ -0,0 +1,54 @@ +dnl -*- autoconf -*- +AC_DEFUN([LP_CHECK_OSIP2],[ + +AC_ARG_WITH( osip, + [ --with-osip Set prefix where osip can be found (ex:/usr or /usr/local)[default=/usr] ], + [ osip_prefix=${withval}],[ osip_prefix=/usr ]) + +dnl FC6's compat-osip2 headers live into "/usr/include/osip2-2.2.2", +dnl while libraries are "/usr/lib/libosipparser2-2.2.2.so*". +AC_ARG_WITH( osip-version,dnl +AC_HELP_STRING([--with-osip-version=VERSION], + [Set osip legacy version @<:@empty@:>@]), + [osip_legacy_version="-${withval}"], + [osip_legacy_version=""]) + +osip_pkgconfig=true +osip_pkgconfig_file=libosip2 +if test -n "$osip_legacy_version"; then + osip_pkgconfig_file=libosip2${osip_legacy_version} +fi + +PKG_CHECK_MODULES(OSIP, $osip_pkgconfig_file >= 3.0.0, ,osip_pkgconfig=false) + +if test $osip_pkgconfig = false; then + + if test -z "$osip_legacy_version"; then + OSIP_CFLAGS="-I${osip_prefix}/include" + else + OSIP_CFLAGS="-I${osip_prefix}/include/osip2${osip_legacy_version}" + fi + +dnl check osip2 headers + CPPFLAGS_save=$CPPFLAGS + CPPFLAGS=$OSIP_CFLAGS + AC_CHECK_HEADER([osip2/osip.h], ,AC_MSG_ERROR([Could not find osip2 headers !])) + CPPFLAGS=$CPPFLAGS_save + +dnl check for osip2 libs + OSIP_LIBS="-L$osip_prefix/lib -losipparser2${osip_legacy_version}" + LDFLAGS_save=$LDFLAGS + LDFLAGS=$OSIP_LIBS + LIBS_save=$LIBS + AC_CHECK_LIB(osip2${osip_legacy_version},osip_init, , AC_MSG_ERROR([Could not find osip2 library !]),[-losipparser2${osip_legacy_version} -lpthread]) + AC_CHECK_LIB(osipparser2${osip_legacy_version},osip_message_init, , AC_MSG_ERROR([Could not find osipparser2 library !]),[-lpthread]) +dnl AC_CHECK_LIB adds osip2 & osipparser2 to LIBS + OSIP_LIBS=$LIBS + LDFLAGS=$LDFLAGS_save + LIBS=$LIBS_save +fi + +AC_SUBST(OSIP_CFLAGS) +AC_SUBST(OSIP_LIBS) + +]) diff --git a/linphone/m4/po.m4 b/linphone/m4/po.m4 new file mode 100644 index 000000000..00133ef36 --- /dev/null +++ b/linphone/m4/po.m4 @@ -0,0 +1,428 @@ +# po.m4 serial 13 (gettext-0.15) +dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ(2.50) + +dnl Checks for all prerequisites of the po subdirectory. +AC_DEFUN([AM_PO_SUBDIRS], +[ + AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + AC_REQUIRE([AM_NLS])dnl + + dnl Perform the following tests also if --disable-nls has been given, + dnl because they are needed for "make dist" to work. + + dnl Search for GNU msgfmt in the PATH. + dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. + dnl The second test excludes FreeBSD msgfmt. + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + dnl Test whether it is GNU msgfmt >= 0.15. +changequote(,)dnl + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([MSGFMT_015]) +changequote(,)dnl + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([GMSGFMT_015]) + + dnl Search for GNU xgettext 0.12 or newer in the PATH. + dnl The first test excludes Solaris xgettext and early GNU xgettext versions. + dnl The second test excludes FreeBSD xgettext. + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + + dnl Test whether it is GNU xgettext >= 0.15. +changequote(,)dnl + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac +changequote([,])dnl + AC_SUBST([XGETTEXT_015]) + + dnl Search for GNU msgmerge 0.11 or newer in the PATH. + AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, + [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) + + dnl Installation directories. + dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we + dnl have to define it here, so that it can be used in po/Makefile. + test -n "$localedir" || localedir='${datadir}/locale' + AC_SUBST([localedir]) + + AC_CONFIG_COMMANDS([po-directories], [[ + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done]], + [# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + ]) +]) + +dnl Postprocesses a Makefile in a directory containing PO files. +AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], +[ + # When this code is run, in config.status, two variables have already been + # set: + # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, + # - LINGUAS is the value of the environment variable LINGUAS at configure + # time. + +changequote(,)dnl + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + # Find a way to echo strings without interpreting backslash. + if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='echo' + else + if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='printf %s\n' + else + echo_func () { + cat < "$ac_file.tmp" + if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + cat >> "$ac_file.tmp" < /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` + cat >> "$ac_file.tmp" <> "$ac_file.tmp" < +#include +/* The string "%2$d %1$d", with dollar characters protected from the shell's + dollar expansion (possibly an autoconf bug). */ +static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; +static char buf[100]; +int main () +{ + sprintf (buf, format, 33, 55); + return (strcmp (buf, "55 33") != 0); +}], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, + [ + AC_EGREP_CPP(notposix, [ +#if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ + notposix +#endif + ], gt_cv_func_printf_posix="guessing no", + gt_cv_func_printf_posix="guessing yes") + ]) + ]) + case $gt_cv_func_printf_posix in + *yes) + AC_DEFINE(HAVE_POSIX_PRINTF, 1, + [Define if your printf() function supports format strings with positions.]) + ;; + esac +]) diff --git a/linphone/m4/progtest.m4 b/linphone/m4/progtest.m4 new file mode 100644 index 000000000..a56365cd3 --- /dev/null +++ b/linphone/m4/progtest.m4 @@ -0,0 +1,92 @@ +# progtest.m4 serial 4 (gettext-0.14.2) +dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1996. + +AC_PREREQ(2.50) + +# Search path for a program which passes the given test. + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST], +[ +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + [[\\/]]* | ?:[[\\/]]*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in ifelse([$5], , $PATH, [$5]); do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) diff --git a/linphone/m4/readline.m4 b/linphone/m4/readline.m4 new file mode 100644 index 000000000..5293048ab --- /dev/null +++ b/linphone/m4/readline.m4 @@ -0,0 +1,37 @@ +################################################## +# Check for readline support. +################################################## + +AC_DEFUN([LP_CHECK_READLINE],[ + +AC_ARG_WITH( readline, + [ --with-readline Set prefix where gnu readline headers and libs can be found (ex:/usr, /usr/local) [default=/usr] ], + [ readline_prefix=${withval}],[ readline_prefix="/usr" ]) + +if test "$readline_prefix" != "/usr"; then + READLINE_CFLAGS="-I$readline_prefix/include" + READLINE_LIBS="-L$readline_prefix/lib" +fi + +CPPFLAGS_save=$CPPFLAGS +LIBS_save=$LIBS +CPPFLAGS="$CPPFLAGS $READLINE_CFLAGS" +LIBS="$LIBS $READLINE_LIBS" +AC_CHECK_HEADERS(readline.h readline/readline.h, readline_h_found=yes) +AC_CHECK_HEADERS(history.h readline/history.h) + +AC_CHECK_LIB(readline, readline, [readline_libs_found=yes],[],[-lncurses]) + +LIBS=$LIBS_save +CPPFLAGS=$CPPFLAGS_save + +if test "$readline_libs_found$readline_h_found" != "yesyes" ; then + AC_MSG_ERROR("Could not find libreadline headers or library") +fi + +READLINE_LIBS="$READLINE_LIBS -lreadline -lncurses" + + +AC_SUBST(READLINE_CFLAGS) +AC_SUBST(READLINE_LIBS) +]) diff --git a/linphone/m4/signed.m4 b/linphone/m4/signed.m4 new file mode 100644 index 000000000..048f59369 --- /dev/null +++ b/linphone/m4/signed.m4 @@ -0,0 +1,17 @@ +# signed.m4 serial 1 (gettext-0.10.40) +dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([bh_C_SIGNED], +[ + AC_CACHE_CHECK([for signed], bh_cv_c_signed, + [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)]) + if test $bh_cv_c_signed = no; then + AC_DEFINE(signed, , + [Define to empty if the C compiler doesn't support this keyword.]) + fi +]) diff --git a/linphone/m4/size_max.m4 b/linphone/m4/size_max.m4 new file mode 100644 index 000000000..bfba811eb --- /dev/null +++ b/linphone/m4/size_max.m4 @@ -0,0 +1,62 @@ +# size_max.m4 serial 5 +dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gl_SIZE_MAX], +[ + AC_CHECK_HEADERS(stdint.h) + dnl First test whether the system already has SIZE_MAX. + AC_MSG_CHECKING([for SIZE_MAX]) + AC_CACHE_VAL([gl_cv_size_max], [ + gl_cv_size_max= + AC_EGREP_CPP([Found it], [ +#include +#if HAVE_STDINT_H +#include +#endif +#ifdef SIZE_MAX +Found it +#endif +], gl_cv_size_max=yes) + if test -z "$gl_cv_size_max"; then + dnl Define it ourselves. Here we assume that the type 'size_t' is not wider + dnl than the type 'unsigned long'. Try hard to find a definition that can + dnl be used in a preprocessor #if, i.e. doesn't contain a cast. + _AC_COMPUTE_INT([sizeof (size_t) * CHAR_BIT - 1], size_t_bits_minus_1, + [#include +#include ], size_t_bits_minus_1=) + _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, + [#include ], fits_in_uint=) + if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then + if test $fits_in_uint = 1; then + dnl Even though SIZE_MAX fits in an unsigned int, it must be of type + dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. + AC_TRY_COMPILE([#include + extern size_t foo; + extern unsigned long foo; + ], [], fits_in_uint=0) + fi + dnl We cannot use 'expr' to simplify this expression, because 'expr' + dnl works only with 'long' integers in the host environment, while we + dnl might be cross-compiling from a 32-bit platform to a 64-bit platform. + if test $fits_in_uint = 1; then + gl_cv_size_max="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" + else + gl_cv_size_max="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" + fi + else + dnl Shouldn't happen, but who knows... + gl_cv_size_max='((size_t)~(size_t)0)' + fi + fi + ]) + AC_MSG_RESULT([$gl_cv_size_max]) + if test "$gl_cv_size_max" != yes; then + AC_DEFINE_UNQUOTED([SIZE_MAX], [$gl_cv_size_max], + [Define as the maximum value of type 'size_t', if the system doesn't define it.]) + fi +]) diff --git a/linphone/m4/stdint_h.m4 b/linphone/m4/stdint_h.m4 new file mode 100644 index 000000000..db9a8ac4c --- /dev/null +++ b/linphone/m4/stdint_h.m4 @@ -0,0 +1,26 @@ +# stdint_h.m4 serial 6 +dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_STDINT_H_WITH_UINTMAX if exists, +# doesn't clash with , and declares uintmax_t. + +AC_DEFUN([gl_AC_HEADER_STDINT_H], +[ + AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1; return !i;], + gl_cv_header_stdint_h=yes, + gl_cv_header_stdint_h=no)]) + if test $gl_cv_header_stdint_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, + [Define if exists, doesn't clash with , + and declares uintmax_t. ]) + fi +]) diff --git a/linphone/m4/uintmax_t.m4 b/linphone/m4/uintmax_t.m4 new file mode 100644 index 000000000..bf83ed746 --- /dev/null +++ b/linphone/m4/uintmax_t.m4 @@ -0,0 +1,30 @@ +# uintmax_t.m4 serial 9 +dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +AC_PREREQ(2.13) + +# Define uintmax_t to 'unsigned long' or 'unsigned long long' +# if it is not already defined in or . + +AC_DEFUN([gl_AC_TYPE_UINTMAX_T], +[ + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then + AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) + test $ac_cv_type_unsigned_long_long = yes \ + && ac_type='unsigned long long' \ + || ac_type='unsigned long' + AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, + [Define to unsigned long or unsigned long long + if and don't define.]) + else + AC_DEFINE(HAVE_UINTMAX_T, 1, + [Define if you have the 'uintmax_t' type in or .]) + fi +]) diff --git a/linphone/m4/ulonglong.m4 b/linphone/m4/ulonglong.m4 new file mode 100644 index 000000000..9fae98e3a --- /dev/null +++ b/linphone/m4/ulonglong.m4 @@ -0,0 +1,48 @@ +# ulonglong.m4 serial 6 +dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. +# This fixes a bug in Autoconf 2.60, but can be removed once we +# assume 2.61 everywhere. + +# Note: If the type 'unsigned long long int' exists but is only 32 bits +# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT +# will not be defined. In this case you can treat 'unsigned long long int' +# like 'unsigned long int'. + +AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], +[ + AC_CACHE_CHECK([for unsigned long long int], + [ac_cv_type_unsigned_long_long_int], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[unsigned long long int ull = 18446744073709551615ULL; + typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63;]], + [[unsigned long long int ullmax = 18446744073709551615ull; + return (ull << 63 | ull >> 63 | ull << i | ull >> i + | ullmax / ull | ullmax % ull);]])], + [ac_cv_type_unsigned_long_long_int=yes], + [ac_cv_type_unsigned_long_long_int=no])]) + if test $ac_cv_type_unsigned_long_long_int = yes; then + AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1, + [Define to 1 if the system has the type `unsigned long long int'.]) + fi +]) + +# This macro is obsolescent and should go away soon. +AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], +[ + AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) + ac_cv_type_unsigned_long_long=$ac_cv_type_unsigned_long_long_int + if test $ac_cv_type_unsigned_long_long = yes; then + AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, + [Define if you have the 'unsigned long long' type.]) + fi +]) diff --git a/linphone/m4/video.m4 b/linphone/m4/video.m4 new file mode 100644 index 000000000..73cdf9fdc --- /dev/null +++ b/linphone/m4/video.m4 @@ -0,0 +1,89 @@ +AC_DEFUN([LP_CHECK_DEP],[ + dnl $1=dependency description + dnl $2=dependency short name, will be suffixed with _CFLAGS and _LIBS + dnl $3=headers's place + dnl $4=lib's place + dnl $5=header to check + dnl $6=lib to check + dnl $7=function to check in library + + NAME=$2 + dep_headersdir=$3 + dep_libsdir=$4 + dep_header=$5 + dep_lib=$6 + dep_funclib=$7 + other_libs=$8 + + if test "$dep_headersdir" != "/usr/include" ; then + eval ${NAME}_CFLAGS=\"-I$dep_headersdir \" + fi + eval ${NAME}_LIBS=\"-L$dep_libsdir -l$dep_lib\" + + CPPFLAGS_save=$CPPFLAGS + LDFLAGS_save=$LDFLAGS + CPPFLAGS="-I$dep_headersdir " + LDFLAGS="-L$dep_libsdir " + + AC_CHECK_HEADERS([$dep_header],[AC_CHECK_LIB([$dep_lib],[$dep_funclib],found=yes,found=no, [$other_libs]) + ],found=no) + + if test "$found" = "yes" ; then + eval ${NAME}_found=yes + AC_DEFINE([HAVE_${NAME}],1,[Defined when we have found $1]) + AC_SUBST(${NAME}_CFLAGS) + AC_SUBST(${NAME}_LIBS) + else + eval ${NAME}_found=no + eval ${NAME}_CFLAGS= + eval ${NAME}_LIBS= + fi + CPPFLAGS=$CPPFLAGS_save + LDFLAGS=$LDFLAGS_save + +]) + + +AC_DEFUN([LP_CHECK_VIDEO],[ + + dnl conditionnal build of video support + AC_ARG_ENABLE(video, + [ --enable-video Turn on video support compiling: not functionnal for the moment], + [case "${enableval}" in + yes) video=true ;; + no) video=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;; + esac],[video=false]) + + AC_ARG_WITH( ffmpeg, + [ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ], + [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) + + AC_ARG_WITH( sdl, + [ --with-sdl Sets the installation prefix of libSDL, needed for video support. [default=/usr] ], + [ libsdldir=${withval}],[ libsdldir=/usr ]) + + if test "$video" = "true"; then + + dnl test for ffmpeg presence + dnl LP_CHECK_DEP([ffmpeg],[FFMPEG],[${ffmpegdir}/include/ffmpeg],[${ffmpegdir}/lib],[avcodec.h],[avcodec],[avcodec_init], [-lavutils -lm]) + dnl if test "$FFMPEG_found" = "no" ; then + dnl AC_MSG_ERROR([Could not find ffmpeg headers and library. This is mandatory for video support]) + dnl fi + PKG_CHECK_MODULES(FFMPEG, [libavcodec >= 50.0.0 ], , [ AC_MSG_ERROR([Could not find ffmpeg headers and library. This is mandatory for video support]) ]) + + LP_CHECK_DEP([SDL],[SDL],[${libsdldir}/include],[${libsdldir}/lib],[SDL/SDL.h],[SDL],[SDL_Init]) + if test "$SDL_found" = "no" ; then + AC_MSG_ERROR([Could not find libsdl headers and library. This is mandatory for video support]) + fi + + VIDEO_CFLAGS=" $FFMPEG_CFLAGS $SDL_CFLAGS" + VIDEO_LIBS=" $FFMPEG_LIBS $SDL_LIBS" + + AC_DEFINE(VIDEO_ENABLED,1,[Set when video support is enabled]) + + fi + + AC_SUBST(VIDEO_CFLAGS) + AC_SUBST(VIDEO_LIBS) +]) diff --git a/linphone/m4/visibility.m4 b/linphone/m4/visibility.m4 new file mode 100644 index 000000000..2ff6330aa --- /dev/null +++ b/linphone/m4/visibility.m4 @@ -0,0 +1,52 @@ +# visibility.m4 serial 1 (gettext-0.15) +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests whether the compiler supports the command-line option +dnl -fvisibility=hidden and the function and variable attributes +dnl __attribute__((__visibility__("hidden"))) and +dnl __attribute__((__visibility__("default"))). +dnl Does *not* test for __visibility__("protected") - which has tricky +dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on +dnl MacOS X. +dnl Does *not* test for __visibility__("internal") - which has processor +dnl dependent semantics. +dnl Does *not* test for #pragma GCC visibility push(hidden) - which is +dnl "really only recommended for legacy code". +dnl Set the variable CFLAG_VISIBILITY. +dnl Defines and sets the variable HAVE_VISIBILITY. + +AC_DEFUN([gl_VISIBILITY], +[ + AC_REQUIRE([AC_PROG_CC]) + CFLAG_VISIBILITY= + HAVE_VISIBILITY=0 + if test -n "$GCC"; then + AC_MSG_CHECKING([for simple visibility declarations]) + AC_CACHE_VAL(gl_cv_cc_visibility, [ + gl_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + AC_TRY_COMPILE( + [extern __attribute__((__visibility__("hidden"))) int hiddenvar; + extern __attribute__((__visibility__("default"))) int exportedvar; + extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); + extern __attribute__((__visibility__("default"))) int exportedfunc (void);], + [], + gl_cv_cc_visibility=yes, + gl_cv_cc_visibility=no) + CFLAGS="$gl_save_CFLAGS"]) + AC_MSG_RESULT([$gl_cv_cc_visibility]) + if test $gl_cv_cc_visibility = yes; then + CFLAG_VISIBILITY="-fvisibility=hidden" + HAVE_VISIBILITY=1 + fi + fi + AC_SUBST([CFLAG_VISIBILITY]) + AC_SUBST([HAVE_VISIBILITY]) + AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], + [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) +]) diff --git a/linphone/m4/wchar_t.m4 b/linphone/m4/wchar_t.m4 new file mode 100644 index 000000000..cde2129a9 --- /dev/null +++ b/linphone/m4/wchar_t.m4 @@ -0,0 +1,20 @@ +# wchar_t.m4 serial 1 (gettext-0.12) +dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wchar_t' type. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WCHAR_T], +[ + AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, + [AC_TRY_COMPILE([#include + wchar_t foo = (wchar_t)'\0';], , + gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) + if test $gt_cv_c_wchar_t = yes; then + AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) + fi +]) diff --git a/linphone/m4/wint_t.m4 b/linphone/m4/wint_t.m4 new file mode 100644 index 000000000..b8fff9c86 --- /dev/null +++ b/linphone/m4/wint_t.m4 @@ -0,0 +1,20 @@ +# wint_t.m4 serial 1 (gettext-0.12) +dnl Copyright (C) 2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wint_t' type. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WINT_T], +[ + AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, + [AC_TRY_COMPILE([#include + wint_t foo = (wchar_t)'\0';], , + gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) + if test $gt_cv_c_wint_t = yes; then + AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) + fi +]) diff --git a/linphone/m4/xsize.m4 b/linphone/m4/xsize.m4 new file mode 100644 index 000000000..85bb721e4 --- /dev/null +++ b/linphone/m4/xsize.m4 @@ -0,0 +1,13 @@ +# xsize.m4 serial 3 +dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_XSIZE], +[ + dnl Prerequisites of lib/xsize.h. + AC_REQUIRE([gl_SIZE_MAX]) + AC_REQUIRE([AC_C_INLINE]) + AC_CHECK_HEADERS(stdint.h) +]) diff --git a/linphone/make_exosip.sh b/linphone/make_exosip.sh new file mode 100755 index 000000000..bff5fa33f --- /dev/null +++ b/linphone/make_exosip.sh @@ -0,0 +1,22 @@ +#!/bin/sh +#this script pickups eXosip files usefull for linphone and put them into exosip/ . +if test -z $1 ; then + echo "make_exosip.sh " + exit 1 +fi + +exosip_src=$1 +for file in $exosip_src/src/*.c ; do + echo "processing $file ..." + sed -e 's/eXosip\/eXosip.h/eXosip.h/' -e 's/eXosip\/eXosip_cfg.h/eXosip_cfg.h/' $file > exosip/`basename $file` +done +for file in $exosip_src/src/*.h ; do + echo "processing $file ..." + sed -e 's/eXosip\/eXosip.h/eXosip.h/' -e 's/eXosip\/eXosip_cfg.h/eXosip_cfg.h/' $file > exosip/`basename $file` +done +for file in $exosip_src/include/eXosip/*.h ; do + echo "processing $file ..." + sed -e 's/eXosip\/eXosip.h/eXosip.h/' -e 's/eXosip\/eXosip_cfg.h/eXosip_cfg.h/' $file > exosip/`basename $file` +done + +echo "Finished !" diff --git a/linphone/media_api/.cvsignore b/linphone/media_api/.cvsignore new file mode 100644 index 000000000..e99558847 --- /dev/null +++ b/linphone/media_api/.cvsignore @@ -0,0 +1,3 @@ +.deps +Makefile +Makefile.in diff --git a/linphone/media_api/DESIGN.txt b/linphone/media_api/DESIGN.txt new file mode 100644 index 000000000..f7c9cfc1f --- /dev/null +++ b/linphone/media_api/DESIGN.txt @@ -0,0 +1,135 @@ +MEDIA API DESIGN DRAFT +********************** + + +The objective of the media_api is to construct and run the necessary +processing on audio and video data flows for a given call (two party call) or +conference. +The media_api must support calls where callmember can be remote as well +local hosted, in other words the media_api can be used inside linphone as +well as in sip conferencing server. The api must support multiples way of +getting media data: from disk, from rtp, from soundcard... +The media_api is object oriented in C, and is based on the mediastreamer library +to deal with audio or video signals, and on glib for types and usefull routines. + +The api must provide object and methods that describes the call, and then functions +that executes the processing (using the mediastreamer) that is necessary for the +call described. + +Proposed API: + +************************************************************************ +object: MediaFlow +This object reprensent a media that is shared between all members of the call, +for example voice. +methods: +MediaFlow *media_flow_new(char *id_string,gint type,gint duplex); +type can be FLOW_AUDIO, FLOW_VIDEO. +if duplex is 1, it means that the media flow is used by every member in both +receiving and sending mode. +id_string is just a string to identify the flow. + +void media_flow_destroy(MediaFlow *flow); +destructor + +************************************************************************** +object: CallMember +This object reprensent a member of a call. +methods: +CallMember *call_member_new(); + +gint call_member_setup_flow(CallMember *member, MediaFlow *flow, + char *rx_endpoint, char *tx_endpoint); + This is the most important function of the API. It describes the way each + call member receives and send a given media flow. + The MediaFlow "flow" is added to the list of flows used by the member "member". + rx_endpoint is a string that described how data is received by the call member. + It should be an url, for example "rtp://213.21.54.127:7080". In this case it + means that data will be received on port 7080 at ip address 213.21.54.127. + tx_endpoint is a string that described how data is sent by the call member. + The role of url is very important. They can be: + "rtp://213.21.54.127:7080" + "file://tmp/media.out" -a file on disk + "oss://0" -souncard 0 using oss api + "alsa://0" -soundcard 0 using alsa api. + In order to work, the call member must be part of a BasicCall, as well as + the flow must be part of the BasicCall too (using basic_call_add_flow()) + This function may (on the backend) create a MediaEndpoint object that stores + the rx_endpoint and tx_endpoint parameter. This object is added to: + -the list of MediaEndpoint maintained by the member (list per member) + -the list of MediaEndpoint maintained by the flow (list per flow) + + +************************************************************************** +object: BasicCall +This object handles simple calls (two party calls). It defines inside itself +two CallMember objects. +method: +BasicCall *basic_call_new(); + +CallMember *basic_call_get_member(BasicCall *call, gint member_number); + Returns a member of a BasicCall according to a number. + +void basic_call_add_flow(BasicCall *call, MediaFlow *flow); + Adds a flow to the call's list of flow. + +gint basic_call_start_flow(BasicCall *call, MediaFlow *flow); + This function construct the mediastreamer processing chain necessary to make + the call running, if not done, and runs it using ms_start() + +gint basic_call_stop_flow(BasicCall *call, MediaFlow *flow); + +gint basic_call_start_all_flows(BasicCall *call); + +void basic_call_destroy(BasicCall *call); + Destroy all data used by the call: call members, call flows. + +************************************************************************** +object: ConferenceCall +This object handles conference call (which are quite much complicated than basic +calls). But this object should have the same method as the BasicCall object. + +******************************************************************* + EXAMPLE +******************************************************************* + +Two party call between call member A on machine "linphone.org" and call member B on machine "home.com". +The media_api is running on "home.com". + + A (on linphone.org) B (on home.com) + +------>(send to rtp://home.com:7080 MSRTPReceiver------>Decode----->(send to oss:/0) + +------<(recv on rtp://linphone.org:7020 MSRTPSender<--------Encode<-----(read on oss://0) + +This is how to setup this call using the media_api: +BasicCall *call; +CallMember *memberA,*memberB; +MediaFlow *flow; + +/* create a basic call*/ +call=basic_call_new(); +/* get a pointer to the pre-define members of the call */ +memberA=basic_call_get_member(call,0); +memberB=basic_call_get_member(call,1); + +/* create a media flow */ +flow=media_flow_new("voice",FLOW_AUDIO,1); +/* tell that the flow is used by the call */ +basic_call_add_flow(call,flow); +/* tell how each member uses the flow (how is the interface ?)*/ +call_member_setup_flow(memberA,flow,"rtp://linphone.org:7020","rtp://home.com:7080"); +/* note: it is not efficient to do name resolution at this stage: that's why in reality numeric ip address +should be given instead of host name */ +call_member_setup_flow(memberB,flow,"oss://0","oss://0"); + +/* start the flow */ +basic_call_start_flow(call,flow); + +In case where the media api is running on another host called "toto" (in a media translator application for example), + the only thing that would change is the url given to memberB: tx="rtp://home.com:8820" for example and + rx="rtp://toto:9522". + +In the sipomatic application (the test application I use to test linphone (it answers to call and plays +a short annoucement)), I would write rx="file://path_to_annoucement.raw" and tx="file://dev/null" instead of +"oss://0". diff --git a/linphone/media_api/Makefile.am b/linphone/media_api/Makefile.am new file mode 100644 index 000000000..38dcf063f --- /dev/null +++ b/linphone/media_api/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to produce Makefile.in +if BUILD_MEDIA_API + +#the media_api library is the only one we have to build here +lib_LTLIBRARIES=libmedia_api.la + +#definition of the sources of libmedia_api +libmedia_api_la_SOURCES= basiccall.c callmember.c mediaflow.c + +# libmedia_api needs libmediastreamer +libmedia_api_la_LIBADD=$(top_srcdir)/mediastreamer/libmediastreamer.la + +#the media_api test program +bin_PROGRAMS=apitest + +apitest_SOURCES= apitest.c +# the test program links to libmedia_api +apitest_LDADD=libmedia_api.la + +endif + +DEFS=@DEFS@ @SOUNDDEFS@ -DDEBUG -DG_LOG_DOMAIN=\"MediaApi\" + +INCLUDES=-I$(top_srcdir)/mediastreamer \ + -I$(top_srcdir)/speex \ + -I$(top_srcdir)/gsmlib \ + $(ORTP_CFLAGS) \ + -I$(top_srcdir)/lpc10-1.5 \ + -I$(top_srcdir)/ffmpeg + + diff --git a/linphone/media_api/apitest.c b/linphone/media_api/apitest.c new file mode 100644 index 000000000..cd4ac9e33 --- /dev/null +++ b/linphone/media_api/apitest.c @@ -0,0 +1,36 @@ +#include "basiccall.h" +#include +static int flag = 1; +void stop(int sign){ + flag = 0; +} + + +int main(){ + BasicCall *call; + char *id; + CallMember *memberA, *memberB; + MediaFlow *flow, *flow1; + + signal(SIGINT, stop); + call = basic_call_new(); + memberA = basic_call_get_member(call,MemberA); + memberB = basic_call_get_member(call,MemberB); + + id = "test_voice"; + printf("\n"); + flow = media_flow_new(id, MEDIA_FLOW_VOICE); + + basic_call_add_flow(call, flow); + + call_member_setup_flow(memberA, flow, "file://temp", "oss://0"); + call_member_setup_flow(memberB, flow, "oss://0", "oss://0"); + + media_flow_setup_fd(flow, memberA, memberB, MEDIA_FLOW_HALF_DUPLEX); + basic_call_start_flow(call, flow); + + while(flag){ + sleep(1); + } + +} diff --git a/linphone/media_api/apitest.h b/linphone/media_api/apitest.h new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/media_api/basiccall.c b/linphone/media_api/basiccall.c new file mode 100644 index 000000000..8a0044754 --- /dev/null +++ b/linphone/media_api/basiccall.c @@ -0,0 +1,170 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "basiccall.h" +#include "../mediastreamer/mscodec.h" + +#define ONESYNC 10 +#define MULTISYNC 20 + +BasicCall *basic_call_new(){ + BasicCall *bc = (BasicCall*) g_malloc(sizeof(BasicCall)); + api_trace("basic_call_new: creating a basic call"); + bc->memberA = call_member_new("memberA"); + bc->memberB = call_member_new("memberB"); + return bc; +} + +CallMember *basic_call_get_member(BasicCall *call, int member_nu){ + api_trace("basic_call_get_member: called for %d",member_nu); + if(member_nu == MemberA){ + return call->memberA; + } + else if(member_nu == MemberB){ + return call->memberB; + } +} + +void basic_call_add_flow(BasicCall *call, MediaFlow *flow){ + api_trace("basic_call_add_flow: called for %s",flow->id); + call->flows = g_list_append( call->flows, flow); + return 1; +} + +int find_mediaflow(gconstpointer llist, gconstpointer flow){ + //MediaFlow *mf = (MediaFlow *) ((BasicCallFlow*)llist)->mediaFlow; + if(((MediaFlow*)flow)->id == ((MediaFlow*)llist)->id){ + return 0; + } + return 1; +} + +int basic_call_start_flow(BasicCall *call, MediaFlow *flow){ + int i=0; + int syncFlag=0; + int nFlowDirections; + MSSync *sync; + Members *source, *destination; + FlowDirections *fd; + GList *elem, *selem; + GList *snd_read = NULL, *snd_write = NULL, *filter = NULL; + + //Commented by Sharat + //This is initialized in media_api.c + //when should these functions be really called? + //ms_init(); + //ortp_init(); + + api_trace("basic_call_start_flow: called for flow %s", flow->id); + + elem = g_list_find_custom( call->flows, flow, &find_mediaflow); + if(elem == NULL){ + api_error("basic_call_start_flow: Called for unregistered mediaflow %s", flow->id); + } + + nFlowDirections = g_list_length(flow->flowDirections); + if(flow->type == MEDIA_FLOW_VOICE){ + syncFlag = ONESYNC; + sync = ms_timer_new(); + } + else{ + syncFlag = MULTISYNC; + } + + for(i=0;i< nFlowDirections; i++){ + + if(syncFlag == MULTISYNC){ + sync = ms_timer_new(); + } + fd = (FlowDirections*)g_list_nth_data(flow->flowDirections,i); + source = fd->source; + destination = fd->destination; + + media_flow_start_fd(fd, sync); + if(fd->type == MEDIA_FLOW_DUPLEX){ + switch(source->tx_endpoint->protocol){ + case MEDIA_ALSA: + case MEDIA_OSS: + snd_read = g_list_append(snd_read, fd->recv); + } + switch(destination->rx_endpoint->protocol){ + case MEDIA_ALSA: + case MEDIA_OSS: + snd_write = g_list_append(snd_write, fd->play); + } + + switch(destination->tx_endpoint->protocol){ + case MEDIA_ALSA: + case MEDIA_OSS: + snd_read = g_list_append(snd_read, fd->read); + } + + switch(source->rx_endpoint->protocol){ + case MEDIA_ALSA: + case MEDIA_OSS: + snd_write = g_list_append(snd_write, fd->send); + } + + } + else if(fd->type == MEDIA_FLOW_HALF_DUPLEX){ + + switch(source->tx_endpoint->protocol){ + case MEDIA_ALSA: + case MEDIA_OSS: + snd_read = g_list_append(snd_read, fd->recv); + } + switch(destination->rx_endpoint->protocol){ + case MEDIA_ALSA: + case MEDIA_OSS: + snd_write = g_list_append(snd_write, fd->play); + } + } + if(syncFlag == MULTISYNC){ + flow->sync = g_list_append(flow->sync, sync); + } + } + if(syncFlag == ONESYNC){ + ms_start(sync); + flow->sync = g_list_append(flow->sync, sync); + } + if(syncFlag == MULTISYNC){ + selem = flow->sync; + while(selem != NULL){ + ms_start(selem->data); + selem = g_list_next(selem); + } + } + filter = snd_read; + while(filter != NULL){ + ms_sound_read_start(MS_SOUND_READ((MSFilter*)filter->data)); + filter = g_list_next(filter); + } + + filter = snd_write; + while(filter != NULL){ + ms_sound_write_start(MS_SOUND_WRITE((MSFilter*)filter->data)); + filter = g_list_next(filter); + } + return 1; +} + +int basic_call_stop_flow(BasicCall *call, MediaFlow *flow){ + +} diff --git a/linphone/media_api/basiccall.h b/linphone/media_api/basiccall.h new file mode 100644 index 000000000..2351faccc --- /dev/null +++ b/linphone/media_api/basiccall.h @@ -0,0 +1,51 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common.h" +#include "mediaflow.h" +#include "callmember.h" + +//other includes required to be done here +#define MemberA 1 +#define MemberB 2 + + +struct _BasicCall{ + CallMember *memberA, *memberB; + GList *flows; //linked list of MediaFlows +}; + +typedef struct _BasicCall BasicCall; + + +BasicCall *basic_call_new(); + +CallMember *basic_call_get_member(BasicCall *call, int member_nu); + +void basic_call_add_flow(BasicCall *call, MediaFlow *flow); + +int basic_call_start_flow(BasicCall *call, MediaFlow *flow); + +int basic_call_stop_flow(BasicCall *call, MediaFlow *flow); + +int basic_call_start_all_flows(BasicCall *call); + +int basic_call_destroy(BasicCall *call); + diff --git a/linphone/media_api/callmember.c b/linphone/media_api/callmember.c new file mode 100644 index 000000000..643ba7b7c --- /dev/null +++ b/linphone/media_api/callmember.c @@ -0,0 +1,153 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include +#include "common.h" +#include "callmember.h" +#include "mediaflow.h" + + +CallMember *call_member_new(char *name){ + CallMember *member = (CallMember*) g_malloc(sizeof(CallMember)); + api_trace("call_member_new: creating %s", name); + member->name = name; + member->flows = NULL; + member->profile = NULL; + return member; +} + +int call_member_set_rtp_profile(CallMember *member, RtpProfile *profile){ + member->profile = profile; + return 1; +} + +int call_member_setup_flow(CallMember *member, MediaFlow *flow, char* rx, char *tx){ + Members *mem = (Members*) g_malloc(sizeof(Members)); + Flows *flows = (Flows*) g_malloc(sizeof(Flows)); + api_trace("call_member_setup_flow: setting up flow for: CallMember->%s , MediaFlow->%s", member->name, flow->id); + mem->member = member; + mem->rx_endpoint = parse_end_point(rx); + mem->tx_endpoint = parse_end_point(tx); + flow->members = g_list_append(flow->members, mem); + + flows->flow = flow; + flows->rx_endpoint = parse_end_point(rx); + flows->tx_endpoint = parse_end_point(tx); + member->flows = g_list_append(member->flows, flows); + return 1; +} + +EndPoint *parse_end_point(char *endpoint){ + EndPoint *result = (EndPoint*) g_malloc(sizeof(EndPoint)); + int i=0,len1,len2,len, tlen; + char *str2, temp[30], *host_str; + //api_trace("parse_end_point: parsing %s\n", endpoint); + result->pt = -1; + while(1){ + str2 = (char*) strpbrk(endpoint, ":"); + if(str2 == NULL){ + str2 = (char*) strpbrk(endpoint, ";"); + if(str2 == NULL){ + len = strlen(endpoint); + } + else{ + len1 = strlen(endpoint); + len2 = strlen(str2); + len = len1-len2; + } + } + else{ + len1 = strlen(endpoint); + len2 = strlen(str2); + len = len1-len2; + } + strncpy(temp,endpoint,len); + temp[len] = '\0'; + tlen = strlen(temp); + if((tlen >= 2)&&(temp[0] == '/')&&(temp[1] == '/')){ + host_str = remove_slash(temp); + } + switch(i){ + case 0: if(strcmp(temp,"rtp")==0){ + result->protocol=MEDIA_RTP; + } + else if(strcmp(temp,"oss")==0){ + result->protocol=MEDIA_OSS; + } + else if(strcmp(temp,"alsa")==0){ + result->protocol=MEDIA_ALSA; + } + else if(strcmp(temp,"file")==0){ + result->protocol=MEDIA_FILE; + } + break; + case 1: if(result->protocol==MEDIA_FILE){ + result->file=host_str; + } + else{ + result->host = host_str; + } + break; + case 2: result->port = to_digits(temp); + break; + case 3: result->pt = pt_digits(temp); + break; + default://result->options[result->nOptions++] = temp; + break; + } + if(str2 != NULL) endpoint = str2+1; + else break; + i++; + } + return result; +} + +int to_digits(char *str){ + int nu=0,a,len,i; + len = strlen(str); + for(i=0;i3)&&(str[0]=='p')&&(str[1]=='t')&&(str[2]=='=')){ + return to_digits(str+3); + } + else{ + api_warn("Wrong parameters passed in the endpoints"); + return 0; + //ERROR handling + } +} +char *remove_slash(char var[]){ + char *temp = (char*) g_malloc(10*sizeof(char)); + int len,i; + len=strlen(var); + for(i=2;i + +#define api_trace g_message +#define api_error g_error +#define api_warn g_warning + +#define MEDIA_FLOW_DUPLEX 1 +#define MEDIA_FLOW_HALF_DUPLEX 2 + +//Mediaflow type +#define MEDIA_FLOW_VIDEO 1 +#define MEDIA_FLOW_VOICE 2 + +//Mediaflow protocols +#define MEDIA_RTP 1 +#define MEDIA_OSS 2 +#define MEDIA_ALSA 3 +#define MEDIA_FILE 4 + +//Mediaflow codec function +#define MEDIA_API_DECODER 1 +#define MEDIA_API_ENCODER 2 + +#endif + + diff --git a/linphone/media_api/media_api.c b/linphone/media_api/media_api.c new file mode 100644 index 000000000..28ed3c1a3 --- /dev/null +++ b/linphone/media_api/media_api.c @@ -0,0 +1,69 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "media_api.h" + +/* non-standart payload types for oRTP */ +PayloadType lpc1015={ + PAYLOAD_AUDIO_PACKETIZED, + 8000, + 0, + NULL, + 0, + 2400, + "1015/8000/1" +}; + +PayloadType speex_nb={ + PAYLOAD_AUDIO_PACKETIZED, + 8000, + 0, + NULL, + 0, + 15000, + "speex/8000/1" +}; + +PayloadType speex_nb_lbr={ + PAYLOAD_AUDIO_PACKETIZED, + 8000, + 0, + NULL, + 0, + 8000, + "speex-lbr/8000/1" +}; + +void media_api_init() +{ + ortp_init(); + ortp_set_debug_file("oRTP",NULL); + rtp_profile_set_payload(&av_profile,115,&lpc1015); + rtp_profile_set_payload(&av_profile,110,&speex_nb); + rtp_profile_set_payload(&av_profile,111,&speex_nb_lbr); + rtp_profile_set_payload(&av_profile,101,&telephone_event); + ms_init(); + ms_speex_codec_init(); +#ifdef HAVE_AVCODEC + ms_AVCodec_init(); +#endif +} + + diff --git a/linphone/media_api/media_api.h b/linphone/media_api/media_api.h new file mode 100644 index 000000000..b7341fc4a --- /dev/null +++ b/linphone/media_api/media_api.h @@ -0,0 +1,69 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MEDIA_API_H +#define MEDIA_API_H + +/* some mediastreamer include files....*/ + +#include "ms.h" + +/* audio codecs ; all these header are not really required as we should use ms_codec_new..() to +create codec filters*/ +/*Commented by Sharath Udupa +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BUILD_FFMPEG +#include +#include */ +#endif + +/* some usefull filters of the mediastreamer */ +#include "mscopy.h" +#include "msfdispatcher.h" +#include "msqdispatcher.h" + +/* some synchronisation sources */ +#include +#include + +/* some streams sources and sinks */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + + + diff --git a/linphone/media_api/mediaflow.c b/linphone/media_api/mediaflow.c new file mode 100644 index 000000000..8ccdadb71 --- /dev/null +++ b/linphone/media_api/mediaflow.c @@ -0,0 +1,179 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "common.h" +#include "mediaflow.h" +#include "callmember.h" + + +MediaFlow *media_flow_new(char *id_string, int type){ + MediaFlow *flow = (MediaFlow *) g_malloc(sizeof(MediaFlow)); //malloc required? + api_trace("media_flow_new: creating %s",id_string); + flow->id = id_string; + flow->type = type; + flow->flowDirections = NULL; + flow->members = NULL; + return flow; +} + +int media_flow_destroy(MediaFlow *flow){ + g_free(flow); + return 1; +} + +int media_flow_setup_fd(MediaFlow *flow, CallMember* csource, CallMember *cdestination, int direction){ + GList *source, *destination; + char *dir; + FlowDirections *fd = (FlowDirections *) g_malloc(sizeof(FlowDirections)); + if(direction == MEDIA_FLOW_DUPLEX) dir = "DUPLEX"; + else if(direction == MEDIA_FLOW_HALF_DUPLEX) dir = "HALF_DUPLEX"; + api_trace("media_flow_setup_fd: setting up %s flow for %s , %s",dir, csource->name, cdestination->name); + source = g_list_find_custom(flow->members, csource, &find); + destination =g_list_find_custom(flow->members, cdestination, &find); + if(source == NULL){ + api_error("media_flow_setup_fd: Invalid source %s specified", csource->name); + } + if(destination == NULL){ + api_error("media_flow_setup_fd: Invalid destination %s specified", cdestination->name); + //ERROR handling to be done here + } + fd->source = (Members*)source->data; + fd->destination = (Members*)destination->data; + fd->type = direction; + flow->flowDirections = g_list_append(flow->flowDirections, fd); + return 1; +} + +int find(gconstpointer mem, gconstpointer cmember){ + if(!strcmp(((Members*)mem)->member->name, ((CallMember*)cmember)->name)){ + return 0; + } + return 1; +} + +int media_flow_start_fd(FlowDirections *fd, MSSync *sync){ + Members *source, *destination; + source = fd->source; + destination = fd->destination; + if(fd->type == MEDIA_FLOW_DUPLEX){ + fd->recv = set_MSFilter(source->tx_endpoint,1,fd); + fd->dec = set_CODECFilter(source->member->profile, source->tx_endpoint->pt,MEDIA_API_DECODER); + fd->play = set_MSFilter(destination->rx_endpoint,0,fd); + + ms_filter_add_link(fd->recv,fd->dec); + ms_filter_add_link(fd->dec,fd->play); + ms_sync_attach(sync, fd->recv); + + fd->read = set_MSFilter(destination->tx_endpoint,1,fd); + fd->enc = set_CODECFilter(destination->member->profile, destination->tx_endpoint->pt,MEDIA_API_ENCODER); + fd->send = set_MSFilter(source->rx_endpoint,0,fd); + + ms_filter_add_link(fd->read, fd->enc); + ms_filter_add_link(fd->enc, fd->send); + ms_sync_attach(sync, fd->read); + + } + else if(fd->type == MEDIA_FLOW_HALF_DUPLEX){ + + fd->recv = set_MSFilter(source->tx_endpoint,1,fd); + fd->dec = set_CODECFilter(sourcec->member->profile, source->tx_endpoint->pt,MEDIA_API_DECODER); + fd->play = set_MSFilter(destination->rx_endpoint,0,fd); + + ms_filter_add_link(fd->recv,fd->dec); + ms_filter_add_link(fd->dec,fd->play); + ms_sync_attach(sync, fd->recv); + } + return 1; +} + + +MSFilter *set_MSFilter(EndPoint *endpoint, int type, FlowDirections *fdir){ + MSFilter *filter; + RtpSession *rtps; + switch(endpoint->protocol){ + case MEDIA_RTP: + rtps = rtp_session_new(RTP_SESSION_RECVONLY); + rtp_session_set_local_addr(rtps,"0.0.0.0",8000); + rtp_session_set_scheduling_mode(rtps,0); + rtp_session_set_blocking_mode(rtps,0); + + if(type == 1){ + filter = ms_rtp_recv_new(); + ms_rtp_recv_set_session(MS_RTP_RECV(filter), rtps); + fdir->rtpSessions = g_list_append(fdir->rtpSessions, rtps); + return filter; + } + else{ + //ms_rtp_send_new + } + case MEDIA_OSS: + if(type == 1){ + filter = ms_oss_read_new(); + ms_sound_read_set_device(MS_SOUND_READ(filter),0); + return filter; + } + else{ + filter = ms_oss_write_new(); + ms_sound_write_set_device(MS_SOUND_WRITE(filter),0); + return filter; + } + case MEDIA_FILE: + if(type == 1){ + filter = ms_read_new(endpoint->file); + return filter; + } + if(type == 0){ + filter = ms_write_new(endpoint->file); + return filter; + } + + } +} + +MSFilter *set_CODECFilter(RtpProfile *profile, int pt, int mode){ + PayloadType *payload; + + switch(mode){ + case MEDIA_API_DECODER: + payload = rtp_profile_get_payload(profile, pt); + if(payload == NULL){ + api_error("media_api: undefined payload in URL\n"); + return NULL; + } + return ms_decoder_new_with_string_id(payload->mime_type); + + //Commented this to include the new RtpProfile + /*if(pt != -1) return ms_decoder_new_with_pt(pt); + *else return ms_copy_new(); + */ + case MEDIA_API_ENCODER: + + payload = rtp_profile_get_payload(profile, pt); + if(payload == NULL){ + api_error("media_api: undefined payload in URL\n"); + return NULL; + } + return ms_encoder_new_with_string_id(payload->mime_type); + /*if(pt != -1) return ms_encoder_new_with_pt(pt); + *else return ms_copy_new(); + */ + } +} + + diff --git a/linphone/media_api/mediaflow.h b/linphone/media_api/mediaflow.h new file mode 100644 index 000000000..598df4d98 --- /dev/null +++ b/linphone/media_api/mediaflow.h @@ -0,0 +1,68 @@ +/* + The objective of the media_api is to construct and run the necessary processing + on audio and video data flows for a given call (two party call) or conference. + Copyright (C) 2001 Sharath Udupa skuds@gmx.net + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a c:opy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct _MediaFlow{ + char *id; + int type; + GList *members; + GList *flowDirections; + GList *sync; //holds all the filters in this MediaFlow +}; + +typedef struct _MediaFlow MediaFlow; + +struct _Members{ + struct _CallMember *member; + struct _EndPoint *rx_endpoint; + struct _EndPoint *tx_endpoint; +}; + +typedef struct _Members Members; + +struct _FlowDirections{ + Members *source, *destination; + MSFilter *recv, + *dec, + *play; + MSFilter *read, //Filters used + *enc, //if type==DUPLEX + *send; + GList *rtpSessions; + int type; +}; + +typedef struct _FlowDirections FlowDirections; + + +MediaFlow *media_flow_new(char *id_string, int type); + +int media_flow_setup_fd(MediaFlow*, struct _CallMember *, struct _CallMember *, int); + +int media_flow_start_fd(FlowDirections *fd, MSSync *sync); + +int media_flow_destroy(MediaFlow *flow); + +/* Internal functions */ +int find(gconstpointer, gconstpointer); + +MSFilter *set_MSFilter(struct _EndPoint *, int, FlowDirections *); + +MSFilter *set_CODECFilter(RtpProfile* , int, int); + diff --git a/linphone/mediastreamer/.cvsignore b/linphone/mediastreamer/.cvsignore new file mode 100644 index 000000000..fd19c06ae --- /dev/null +++ b/linphone/mediastreamer/.cvsignore @@ -0,0 +1,16 @@ +*.lo +.deps +.libs +Makefile +Makefile.in +libmediastreamer.la +libmsspeex.la +mediastream +mstest +ring_test +test_alaw +test_gsm +test_lpc10 +test_mulaw +test_rtprecv +test_speex diff --git a/linphone/mediastreamer/Makefile.am b/linphone/mediastreamer/Makefile.am new file mode 100644 index 000000000..f472f0658 --- /dev/null +++ b/linphone/mediastreamer/Makefile.am @@ -0,0 +1,174 @@ +EXTRA_DIST=Makefile.ms + + +if BUILD_UGLIB +SUPPORTLIB=$(top_builddir)/support/libuglib.la +endif + + +#gdk video output +if BUILD_VIDEO +VIDEO_TESTPROGS=test_v4l test_videostream +#videoserver videoclient +endif + +if BUILD_TRUESPEECH + TRUESPEECH_SOURCES = mstruespeechencoder.c mstruespeechencoder.h \ + mstruespeechdecoder.c mstruespeechdecoder.h + TRUESPEECH_LIBADD = ../win32acm/libwin32acm.a + TRUESPEECH_TEST = test_truespeech + TRUESPEECH_INCLUDES = -I$(top_srcdir)/win32acm +endif + +if BUILD_MEDIASTREAMER + +noinst_LTLIBRARIES = libmediastreamer.la +endif + +useless_files=mstcpserv.c mstcpserv.h mstcpclient.c mstcpclient.h + +libmediastreamer_la_SOURCES=msfilter.c msfilter.h msutils.h waveheader.h\ + mscodec.c mscodec.h \ + mssoundread.c mssoundread.h \ + mssoundwrite.c mssoundwrite.h \ + msbuffer.c msbuffer.h \ + msqueue.c msqueue.h \ + msfifo.c msfifo.h \ + ms.c ms.h\ + mssync.c mssync.h \ + msnosync.c msnosync.h \ + msread.c msread.h \ + mswrite.c mswrite.h \ + mscopy.c mscopy.h \ + msosswrite.c msosswrite.h \ + msossread.c msossread.h \ + msringplayer.c msringplayer.h \ + msGSMencoder.c msGSMencoder.h \ + msGSMdecoder.c msGSMdecoder.h \ + msLPC10encoder.c msLPC10encoder.h \ + msLPC10decoder.c msLPC10decoder.h \ + msrtprecv.c msrtprecv.h \ + msrtpsend.c msrtpsend.h \ + msAlawenc.c msAlawenc.h g711common.h \ + msAlawdec.c msAlawdec.h g711common.h \ + msMUlawenc.c msMUlawenc.h g711common.h \ + msMUlawdec.c msMUlawdec.h g711common.h \ + mstimer.c mstimer.h \ + msqdispatcher.c msqdispatcher.h \ + msfdispatcher.c msfdispatcher.h \ + sndcard.c sndcard.h \ + osscard.c osscard.h\ + hpuxsndcard.c \ + alsacard.c alsacard.h \ + jackcard.c jackcard.h \ + audiostream.c mediastream.h \ + $(TRUESPEECH_SOURCES)\ + msspeexenc.c msspeexenc.h msspeexdec.c msspeexdec.h \ + $(VIDEO_SOURCES) + +if BUILD_VIDEO +libmediastreamer_la_SOURCES+=msv4l.c msv4l.h affine.c affine.h \ + msavencoder.c msavencoder.h\ + msavdecoder.c msavdecoder.h \ + videostream.c \ + msvideosource.c msvideosource.h \ + mssdlout.c mssdlout.h \ + rfc2429.h +endif + +libmediastreamer_la_LIBADD= $(GLIB_LIBS) \ + ../gsmlib/libgsm.la \ + ../lpc10-1.5/liblpc10.la \ + ../oRTP/src/libortp.la \ + $(JACK_LIBS)\ + $(SAMPLERATE_LIBS)\ + $(SUPPORTLIB) \ + $(ALSA_LIBS) \ + $(TRUESPEECH_LIBADD) \ + $(SPEEX_LIBS) \ + $(VIDEO_LIBS) + + + +if BUILD_MEDIASTREAMER +noinst_PROGRAMS=mstest ring_test test_gsm test_lpc10 test_alaw test_mulaw \ + test_speex \ + test_rtprecv \ + $(VIDEO_TESTPROGS) $(TRUESPEECH_TEST) + +libexec_PROGRAMS=mediastream +endif + + +# test program to test TrueSpeech encoder and decoder objects +test_truespeech_SOURCES=test_truespeech.c +test_truespeech_LDADD=libmediastreamer.la + +mstest_SOURCES=test.c +mstest_LDADD=libmediastreamer.la + +#test program to test MSRingPlayer object +ring_test_SOURCES=ring_test.c +ring_test_LDADD=libmediastreamer.la + +#test program to test GSM dec and enc objects +test_gsm_SOURCES=test_gsm.c +test_gsm_LDADD=libmediastreamer.la + +#test program to test speex dec and enc objects +test_speex_SOURCES=test_speex.c +test_speex_LDADD=libmediastreamer.la + +#test program to test LPC10-1.5 dec and enc objects +test_lpc10_SOURCES=test_lpc10.c +test_lpc10_LDADD=libmediastreamer.la + +#test program to test ALAW dec and enc objects +test_alaw_SOURCES=test_alaw.c +test_alaw_LDADD=libmediastreamer.la + +#test program to test MULAW dec and enc objects +test_mulaw_SOURCES=test_mulaw.c +test_mulaw_LDADD=libmediastreamer.la + + +#test program to test rtprecv object +test_rtprecv_SOURCES=test_rtprecv.c +test_rtprecv_LDADD=libmediastreamer.la + +#test program to test full video stream +test_videostream_SOURCES=test_videostream.c +test_videostream_LDADD=libmediastreamer.la + +#test program to test video4linux input plugin +test_v4l_SOURCES=test_v4l.c +test_v4l_LDADD=libmediastreamer.la + +#videoserver_SOURCES=videoserver.c +#videoserver_LDADD=libmediastreamer.la + +#videoclient_SOURCES=videoclient.c +#videoclient_LDADD=libmediastreamer.la + + +#the mediastream program that runs a processing that will be used in linphone +mediastream_SOURCES=mediastream.c +mediastream_LDADD=libmediastreamer.la + + +ORTP_CFLAGS=`cat $(top_builddir)/oRTP/ortp.defs` + +AM_CFLAGS=$(GLIB_CFLAGS) -DG_LOG_DOMAIN=\"MediaStreamer\" $(TRUESPEECH_CFLAGS) $(IPV6_CFLAGS) $(ORTP_CFLAGS) \ + $(VIDEO_CFLAGS) + +INCLUDES= -I$(top_srcdir) \ + -I$(top_srcdir)/mediastreamer \ + -I$(top_srcdir)/oRTP/include \ + -I$(top_srcdir)/gsmlib \ + -I$(top_srcdir)/lpc10-1.5 \ + $(SPEEX_CFLAGS) \ + $(TRUESPEECH_INCLUDES) + +linphone_includedir=$(includedir)/linphone + +linphone_include_HEADERS=sndcard.h diff --git a/linphone/mediastreamer/Makefile.ms b/linphone/mediastreamer/Makefile.ms new file mode 100644 index 000000000..8b7427c3c --- /dev/null +++ b/linphone/mediastreamer/Makefile.ms @@ -0,0 +1,34 @@ + +OBJEXT=o +AR = ar +RANLIB = ranlib +DEFS= -DG_LOG_DOMAIN=\"MediaStreamer\" +INCLUDES=-I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include/ \ + -I../gsmlib/ -I../lpc10-1.5 -I../oRTP +COMPILE= gcc $(DEFS) $(INCLUDES) +LIBTOOL=libtool +LDFLAGS=-L/usr/local/lib/ -lglib-1.3 -lgthread-1.3 -lpthread +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ + +libmediastreamer_a_OBJECTS = msfilter.$(OBJEXT) msbuffer.$(OBJEXT) \ +msqueue.$(OBJEXT) msfifo.$(OBJEXT) ms.$(OBJEXT) mssync.$(OBJEXT) \ +msnosync.$(OBJEXT) msread.$(OBJEXT) mswrite.$(OBJEXT) mscopy.$(OBJEXT) \ +msv4lsource.$(OBJEXT) msoss.$(OBJEXT) msosswrite.$(OBJEXT) \ +msossread.$(OBJEXT) msringplayer.$(OBJEXT) msGSMencoder.$(OBJEXT) \ +msGSMdecoder.$(OBJEXT) msLPC10encoder.$(OBJEXT) \ +msLPC10decoder.$(OBJEXT) + +all: libmediastreamer.a mstest + + +.c.o: + $(COMPILE) -c $< + +libmediastreamer.a: $(libmediastreamer_a_OBJECTS) + -rm -f libmediastreamer.a + $(AR) cru libmediastreamer.a $(libmediastreamer_a_OBJECTS) + $(RANLIB) libmediastreamer.a + + +mstest: test.o libmediastreamer.a + gcc -o mstest test.o libmediastreamer.a $(LDFLAGS) -Wl,-rpath /usr/local/lib diff --git a/linphone/mediastreamer/README b/linphone/mediastreamer/README new file mode 100644 index 000000000..1309f534b --- /dev/null +++ b/linphone/mediastreamer/README @@ -0,0 +1,3 @@ +Mediastreamer is the library that handle all media operations: rtp streaming +from file, from soundcard, with codec transcoding, and vice-versa;-). +And also video streaming in the future. diff --git a/linphone/mediastreamer/affine.c b/linphone/mediastreamer/affine.c new file mode 100644 index 000000000..99f33d782 --- /dev/null +++ b/linphone/mediastreamer/affine.c @@ -0,0 +1,144 @@ +/* + * affine.c -- Affine Transforms for 2d objects + * Copyright (C) 2002 Charles Yates + * Portions Copyright (C) 2003 Dan Dennedy + * ported from C++ to C + * wrote affine_scale() + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "affine.h" + +static inline void Multiply( affine_transform_t *this, affine_transform_t *that ) +{ + double output[2][2]; + register int i, j; + + for ( i = 0; i < 2; i ++ ) + for ( j = 0; j < 2; j ++ ) + output[ i ][ j ] = this->matrix[ i ][ 0 ] * that->matrix[ j ][ 0 ] + + this->matrix[ i ][ 1 ] * that->matrix[ j ][ 1 ]; + + this->matrix[ 0 ][ 0 ] = output[ 0 ][ 0 ]; + this->matrix[ 0 ][ 1 ] = output[ 0 ][ 1 ]; + this->matrix[ 1 ][ 0 ] = output[ 1 ][ 0 ]; + this->matrix[ 1 ][ 1 ] = output[ 1 ][ 1 ]; +} + +void affine_transform_init( affine_transform_t *this ) +{ + this->matrix[ 0 ][ 0 ] = 1; + this->matrix[ 0 ][ 1 ] = 0; + this->matrix[ 1 ][ 0 ] = 0; + this->matrix[ 1 ][ 1 ] = 1; +} + +// Rotate by a given angle +void affine_transform_rotate( affine_transform_t *this, double angle ) +{ + affine_transform_t affine; + affine.matrix[ 0 ][ 0 ] = cos( angle * M_PI / 180 ); + affine.matrix[ 0 ][ 1 ] = 0 - sin( angle * M_PI / 180 ); + affine.matrix[ 1 ][ 0 ] = sin( angle * M_PI / 180 ); + affine.matrix[ 1 ][ 1 ] = cos( angle * M_PI / 180 ); + Multiply( this, &affine ); +} + +// Shear by a given value +void affine_transform_shear( affine_transform_t *this, double shear ) +{ + affine_transform_t affine; + affine.matrix[ 0 ][ 0 ] = 1; + affine.matrix[ 0 ][ 1 ] = shear; + affine.matrix[ 1 ][ 0 ] = 0; + affine.matrix[ 1 ][ 1 ] = 1; + Multiply( this, &affine ); +} + +void affine_transform_scale( affine_transform_t *this, double sx, double sy ) +{ + affine_transform_t affine; + affine.matrix[ 0 ][ 0 ] = sx; + affine.matrix[ 0 ][ 1 ] = 0; + affine.matrix[ 1 ][ 0 ] = 0; + affine.matrix[ 1 ][ 1 ] = sy; + Multiply( this, &affine ); +} + +// Obtain the mapped x coordinate of the input +double affine_transform_mapx( affine_transform_t *this, int x, int y ) +{ + return this->matrix[0][0] * x + this->matrix[0][1] * y; +} + +// Obtain the mapped y coordinate of the input +double affine_transform_mapy( affine_transform_t *this, int x, int y ) +{ + return this->matrix[1][0] * x + this->matrix[1][1] * y; +} + +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +void affine_scale( const unsigned char *src, unsigned char *dest, int src_width, int src_height, int dest_width, int dest_height, int bpp ) +{ + affine_transform_t affine; + double scale_x = (double) dest_width / (double) src_width; + double scale_y = (double) dest_height / (double) src_height; + register unsigned char *d = dest; + register const unsigned char *s = src; + register int i, j, k, x, y; + + affine_transform_init( &affine ); + + if ( scale_x <= 1.0 && scale_y <= 1.0 ) + { + affine_transform_scale( &affine, scale_x, scale_y ); + + for( j = 0; j < src_height; j++ ) + for( i = 0; i < src_width; i++ ) + { + x = (int) ( affine_transform_mapx( &affine, i - src_width/2, j - src_height/2 ) ); + y = (int) ( affine_transform_mapy( &affine, i - src_width/2, j - src_height/2 ) ); + x += dest_width/2; + x = CLAMP( x, 0, dest_width); + y += dest_height/2; + y = CLAMP( y, 0, dest_height); + s = src + (j*src_width*bpp) + i*bpp; // + (bpp-1); + d = dest + y*dest_width*bpp + x*bpp; + for ( k = 0; k < bpp; k++ ) + *d++ = *s++; + } + } + else if ( scale_x > 1.0 && scale_y > 1.0 ) + { + affine_transform_scale( &affine, 1.0/scale_x, 1.0/scale_y ); + + for( y = 0; y < dest_height; y++ ) + for( x = 0; x < dest_width; x++ ) + { + i = (int) ( affine_transform_mapx( &affine, x - dest_width/2, y - dest_height/2 ) ); + j = (int) ( affine_transform_mapy( &affine, x - dest_width/2, y - dest_height/2 ) ); + i += src_width/2; + i = CLAMP( i, 0, dest_width); + j += src_height/2; + j = CLAMP( j, 0, dest_height); + s = src + (j*src_width*bpp) + i*bpp; // + (bpp-1); + d = dest + y*dest_width*bpp + x*bpp; + for ( k = 0; k < bpp; k++ ) + *d++ = *s++; + } + } +} diff --git a/linphone/mediastreamer/affine.h b/linphone/mediastreamer/affine.h new file mode 100644 index 000000000..620fdc9d3 --- /dev/null +++ b/linphone/mediastreamer/affine.h @@ -0,0 +1,43 @@ +/* + * affine.h -- Affine Transforms for 2d objects + * Copyright (C) 2002 Charles Yates + * Portions Copyright (C) 2003 Dan Dennedy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _AFFINE_H +#define _AFFINE_H + +#include + +/** Affine transforms for 2d image manipulation. Current provides shearing and + rotating support. +*/ + +typedef struct { + double matrix[2][2]; +} affine_transform_t; + +void affine_transform_init( affine_transform_t *this ); +void affine_transform_rotate( affine_transform_t *this, double angle ); +void affine_transform_shear( affine_transform_t *this, double shear ); +void affine_transform_scale( affine_transform_t *this, double sx, double sy ); +double affine_transform_mapx( affine_transform_t *this, int x, int y ); +double affine_transform_mapy( affine_transform_t *this, int x, int y ); +void affine_scale( const unsigned char *src, unsigned char *dest, int src_width, int src_height, int dest_width, int dest_height, int bpp ); + +#endif + diff --git a/linphone/mediastreamer/alsacard.c b/linphone/mediastreamer/alsacard.c new file mode 100644 index 000000000..03b88df75 --- /dev/null +++ b/linphone/mediastreamer/alsacard.c @@ -0,0 +1,653 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "alsacard.h" + +#ifdef HAVE_ALSA_ASOUNDLIB_H + +static gchar *over_pcmdev=NULL; + +#include "msossread.h" +#include "msosswrite.h" + +#include + +int __alsa_card_write(AlsaCard *obj,char *buf,int size); + +int alsa_set_params(AlsaCard *obj, int rw, int bits, int stereo, int rate) +{ + snd_pcm_hw_params_t *hwparams=NULL; + snd_pcm_sw_params_t *swparams=NULL; + snd_pcm_t *pcm_handle; + gint dir; + guint exact_uvalue; + gulong exact_ulvalue; + gint channels; +// gint fsize=0; + gint periods=8; + gint periodsize=256; + gint err; + int format; + + if (rw) { + pcm_handle=obj->write_handle; + } + else pcm_handle=obj->read_handle; + + /* Allocate the snd_pcm_hw_params_t structure on the stack. */ + snd_pcm_hw_params_alloca(&hwparams); + + /* Init hwparams with full configuration space */ + if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { + g_warning("alsa_set_params: Cannot configure this PCM device.\n"); + return(-1); + } + + if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { + g_warning("alsa_set_params: Error setting access.\n"); + return(-1); + } + /* Set sample format */ +#ifdef WORDS_BIGENDIAN + format=SND_PCM_FORMAT_S16_BE; +#else + format=SND_PCM_FORMAT_S16_LE; +#endif + if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) { + g_warning("alsa_set_params: Error setting format.\n"); + return(-1); + } + /* Set number of channels */ + if (stereo) channels=2; + else channels=1; + if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) { + g_warning("alsa_set_params: Error setting channels.\n"); + return(-1); + } + /* Set sample rate. If the exact rate is not supported */ + /* by the hardware, use nearest possible rate. */ + exact_uvalue=rate; + dir=0; + if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){ + g_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err)); + return -1; + } + if (dir != 0) { + g_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n " + "==> Using %d Hz instead.\n", rate, exact_uvalue); + } + /* choose greater period size when rate is high */ + periodsize=periodsize*(rate/8000); + + /* Set buffer size (in frames). The resulting latency is given by */ + /* latency = periodsize * periods / (rate * bytes_per_frame) */ + /* + fsize=periodsize * periods; + exact_value=fsize; + if ((err=snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,&exact_value)) < 0) { + g_warning("alsa_set_params: Error setting buffer size:%s",snd_strerror(err)); + return(-1); + } + if (fsize!= exact_value) { + g_warning("alsa_set_params: The buffer size %d is not supported by your hardware.\n " + "==> Using %d instead.\n", fsize, exact_value); + } + */ + /* set period size */ + exact_ulvalue=periodsize; + dir=0; + if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) { + g_warning("alsa_set_params: Error setting period size.\n"); + return(-1); + } + if (dir != 0) { + g_warning("alsa_set_params: The period size %d is not supported by your hardware.\n " + "==> Using %d instead.\n", periodsize, (int)exact_ulvalue); + } + periodsize=exact_ulvalue; + /* Set number of periods. Periods used to be called fragments. */ + exact_uvalue=periods; + dir=0; + if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) { + g_warning("alsa_set_params: Error setting periods.\n"); + return(-1); + } + if (dir != 0) { + g_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n " + "==> Using %d instead.\n", periods, exact_uvalue); + } + /* Apply HW parameter settings to */ + /* PCM device and prepare device */ + if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { + g_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err)); + return(-1); + } + /*prepare sw params */ + if (rw){ + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(pcm_handle, swparams); + if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){ + g_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err)); + return -1; + } + if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){ + g_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err)); + return(-1); + } + } + obj->frame_size=channels*(bits/8); + SND_CARD(obj)->bsize=periodsize*obj->frame_size; + //SND_CARD(obj)->bsize=4096; + obj->frames=periodsize; + g_message("alsa_set_params: blocksize=%i.",SND_CARD(obj)->bsize); + return SND_CARD(obj)->bsize; +} + +int alsa_card_open_r(AlsaCard *obj,int bits,int stereo,int rate) +{ + int bsize; + int err; + snd_pcm_t *pcm_handle; + gchar *pcmdev; + if (over_pcmdev!=NULL) pcmdev=over_pcmdev; + else pcmdev=obj->pcmdev; + + if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) { + g_warning("alsa_card_open_r: Error opening PCM device %s\n",obj->pcmdev ); + return -1; + } + g_return_val_if_fail(pcm_handle!=NULL,-1); + obj->read_handle=pcm_handle; + if ((bsize=alsa_set_params(obj,0,bits,stereo,rate))<0){ + snd_pcm_close(pcm_handle); + obj->read_handle=NULL; + return -1; + } + obj->readbuf=g_malloc0(bsize); + + err=snd_pcm_start(obj->read_handle); + if (err<0){ + g_warning("Cannot start read pcm: %s", snd_strerror(err)); + } + obj->readpos=0; + SND_CARD(obj)->bsize=bsize; + SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED; + return 0; +} + +int alsa_card_open_w(AlsaCard *obj,int bits,int stereo,int rate) +{ +// int err; + int bsize; + snd_pcm_t *pcm_handle; + gchar *pcmdev; + if (over_pcmdev!=NULL) pcmdev=over_pcmdev; + else pcmdev=obj->pcmdev; + + if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) { + g_warning("alsa_card_open_w: Error opening PCM device %s\n", obj->pcmdev); + return -1; + } + obj->write_handle=pcm_handle; + if ((bsize=alsa_set_params(obj,1,bits,stereo,rate))<0){ + snd_pcm_close(pcm_handle); + obj->write_handle=NULL; + return -1; + } + obj->writebuf=g_malloc0(bsize); + + obj->writepos=0; + SND_CARD(obj)->bsize=bsize; + SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED; + return 0; +} + + +void alsa_card_set_blocking_mode(AlsaCard *obj, gboolean yesno){ + if (obj->read_handle!=NULL) snd_pcm_nonblock(obj->read_handle,!yesno); + if (obj->write_handle!=NULL) snd_pcm_nonblock(obj->write_handle,!yesno); +} + +void alsa_card_close_r(AlsaCard *obj) +{ + if (obj->read_handle!=NULL){ + snd_pcm_close(obj->read_handle); + obj->read_handle=NULL; + g_free(obj->readbuf); + obj->readbuf=NULL; + } +} + +void alsa_card_close_w(AlsaCard *obj) +{ + if (obj->write_handle!=NULL){ + snd_pcm_close(obj->write_handle); + obj->write_handle=NULL; + g_free(obj->writebuf); + obj->writebuf=NULL; + } +} + +int alsa_card_probe(AlsaCard *obj,int bits,int stereo,int rate) +{ + int ret; + ret=alsa_card_open_w(obj,bits,stereo,rate); + if (ret<0) return -1; + ret=SND_CARD(obj)->bsize; + alsa_card_close_w(obj); + return ret; +} + + +void alsa_card_destroy(AlsaCard *obj) +{ + snd_card_uninit(SND_CARD(obj)); + g_free(obj->pcmdev); + if (obj->readbuf!=0) g_free(obj->readbuf); + if (obj->writebuf!=0) g_free(obj->writebuf); +} + +gboolean alsa_card_can_read(AlsaCard *obj) +{ + int frames; + g_return_val_if_fail(obj->read_handle!=NULL,0); + if (obj->readpos!=0) return TRUE; + if ((frames=snd_pcm_avail_update(obj->read_handle)>=obj->frames)) return 1; + //g_message("frames=%i",frames); + return 0; +} + + + +int __alsa_card_read(AlsaCard *obj,char *buf,int bsize) +{ + int err; + sigset_t set; + sigemptyset(&set); + sigaddset(&set,SIGALRM); + sigprocmask(SIG_BLOCK,&set,NULL); + err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size); + if (err<0) { + if (err!=-EPIPE){ + g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err)); + } + snd_pcm_prepare(obj->read_handle); + err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size); + if (err<0) g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err)); + } + sigprocmask(SIG_UNBLOCK,&set,NULL); + return err*obj->frame_size; +} + +int alsa_card_read(AlsaCard *obj,char *buf,int size) +{ + int err; + gint bsize=SND_CARD(obj)->bsize; + g_return_val_if_fail(obj->read_handle!=NULL,-1); + if (sizereadpos,size); + + if (obj->readpos==0){ + err=__alsa_card_read(obj,obj->readbuf,bsize); + } + + memcpy(buf,&obj->readbuf[obj->readpos],canread); + obj->readpos+=canread; + if (obj->readpos>=bsize) obj->readpos=0; + return canread; + }else{ + err=__alsa_card_read(obj,buf,size); + return err; + } + +} + +int __alsa_card_write(AlsaCard *obj,char *buf,int size) +{ + int err; + sigset_t set; + sigemptyset(&set); + sigaddset(&set,SIGALRM); + sigprocmask(SIG_BLOCK,&set,NULL); + if ((err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size))<0){ + if (err!=-EPIPE){ + g_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err)); + } + snd_pcm_prepare(obj->write_handle); + err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size); + if (err<0) g_warning("alsa_card_write: Error writing sound buffer (size=%i):%s",size,snd_strerror(err)); + + } + sigprocmask(SIG_UNBLOCK,&set,NULL); + return err; +} + +int alsa_card_write(AlsaCard *obj,char *buf,int size){ + int err; + gint bsize=SND_CARD(obj)->bsize; + g_return_val_if_fail(obj->write_handle!=NULL,-1); + if (size!=bsize || obj->writepos!=0) + { + gint canwrite; + gint totalwrite=0; + + while(1){ + canwrite=MIN(bsize-obj->writepos,size); + if (canwrite==0) + break; + memcpy(&obj->writebuf[obj->writepos],buf,canwrite); + obj->writepos+=canwrite; + if (obj->writepos>=bsize){ + err=__alsa_card_write(obj,obj->writebuf,bsize); + obj->writepos=0; + } + size-=canwrite; + buf+=canwrite; + totalwrite+=canwrite; + } + return totalwrite; + + }else{ + return __alsa_card_write(obj,buf,bsize); + } +} + +snd_mixer_t *alsa_mixer_open(AlsaCard *obj){ + snd_mixer_t *mixer=NULL; + int err; + err=snd_mixer_open(&mixer,0); + if (err<0){ + g_warning("Could not open alsa mixer: %s",snd_strerror(err)); + return NULL; + } + if ((err = snd_mixer_attach (mixer, obj->mixdev)) < 0){ + g_warning("Could not attach mixer to card: %s",snd_strerror(err)); + snd_mixer_close(mixer); + return NULL; + } + if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){ + g_warning("snd_mixer_selem_register: %s",snd_strerror(err)); + snd_mixer_close(mixer); + return NULL; + } + if ((err = snd_mixer_load (mixer)) < 0){ + g_warning("snd_mixer_load: %s",snd_strerror(err)); + snd_mixer_close(mixer); + return NULL; + } + obj->mixer=mixer; + return mixer; +} + +void alsa_mixer_close(AlsaCard *obj){ + snd_mixer_close(obj->mixer); + obj->mixer=NULL; +} + +typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction; + +static gint get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){ + long value=0; + const char *elemname; + snd_mixer_elem_t *elem; + int err; + long sndMixerPMin; + long sndMixerPMax; + long newvol; + elem=snd_mixer_first_elem(mixer); + while (elem!=NULL){ + elemname=snd_mixer_selem_get_name(elem); + //g_message("Found alsa mixer element %s.",elemname); + if (strcmp(elemname,name)==0){ + switch (action){ + case CAPTURE: + if (snd_mixer_selem_has_capture_volume(elem)){ + snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol); + newvol-=sndMixerPMin; + value=(100*newvol)/(sndMixerPMax-sndMixerPMin); + if (err<0) g_warning("Could not get capture volume for %s:%s",name,snd_strerror(err)); + //else g_message("Succesfully get capture level for %s.",elemname); + break; + } + break; + case PLAYBACK: + if (snd_mixer_selem_has_playback_volume(elem)){ + snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol); + newvol-=sndMixerPMin; + value=(100*newvol)/(sndMixerPMax-sndMixerPMin); + if (err<0) g_warning("Could not get playback volume for %s:%s",name,snd_strerror(err)); + //else g_message("Succesfully get playback level for %s.",elemname); + break; + } + break; + case CAPTURE_SWITCH: + + break; + case PLAYBACK_SWITCH: + + break; + } + } + elem=snd_mixer_elem_next(elem); + } + + return value; +} + + +static void set_mixer_element(snd_mixer_t *mixer,const char *name, gint level,MixerAction action){ + const char *elemname; + snd_mixer_elem_t *elem; + long sndMixerPMin; + long sndMixerPMax; + long newvol; + + elem=snd_mixer_first_elem(mixer); + + while (elem!=NULL){ + elemname=snd_mixer_selem_get_name(elem); + //g_message("Found alsa mixer element %s.",elemname); + if (strcmp(elemname,name)==0){ + switch(action){ + case CAPTURE: + if (snd_mixer_selem_has_capture_volume(elem)){ + snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin; + snd_mixer_selem_set_capture_volume_all(elem,newvol); + //g_message("Succesfully set capture level for %s.",elemname); + return; + } + break; + case PLAYBACK: + if (snd_mixer_selem_has_playback_volume(elem)){ + snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin; + snd_mixer_selem_set_playback_volume_all(elem,newvol); + //g_message("Succesfully set playback level for %s.",elemname); + return; + } + break; + case CAPTURE_SWITCH: + if (snd_mixer_selem_has_capture_switch(elem)){ + snd_mixer_selem_set_capture_switch_all(elem,level); + //g_message("Succesfully set capture switch for %s.",elemname); + } + break; + case PLAYBACK_SWITCH: + if (snd_mixer_selem_has_playback_switch(elem)){ + snd_mixer_selem_set_playback_switch_all(elem,level); + //g_message("Succesfully set capture switch for %s.",elemname); + } + break; + + } + } + elem=snd_mixer_elem_next(elem); + } + + return ; +} + + +void alsa_card_set_level(AlsaCard *obj,gint way,gint a) +{ + snd_mixer_t *mixer; + mixer=alsa_mixer_open(obj); + if (mixer==NULL) return ; + switch(way){ + case SND_CARD_LEVEL_GENERAL: + set_mixer_element(mixer,"Master",a,PLAYBACK); + break; + case SND_CARD_LEVEL_INPUT: + set_mixer_element(mixer,"Capture",a,CAPTURE); + break; + case SND_CARD_LEVEL_OUTPUT: + set_mixer_element(mixer,"PCM",a,PLAYBACK); + break; + default: + g_warning("oss_card_set_level: unsupported command."); + } + alsa_mixer_close(obj); +} + +gint alsa_card_get_level(AlsaCard *obj,gint way) +{ + snd_mixer_t *mixer; + gint value = -1; + mixer=alsa_mixer_open(obj); + if (mixer==NULL) return 0; + switch(way){ + case SND_CARD_LEVEL_GENERAL: + value=get_mixer_element(mixer,"Master",PLAYBACK); + break; + case SND_CARD_LEVEL_INPUT: + value=get_mixer_element(mixer,"Capture",CAPTURE); + break; + case SND_CARD_LEVEL_OUTPUT: + value=get_mixer_element(mixer,"PCM",PLAYBACK); + break; + default: + g_warning("oss_card_set_level: unsupported command."); + } + alsa_mixer_close(obj); + return value; +} + +void alsa_card_set_source(AlsaCard *obj,int source) +{ + snd_mixer_t *mixer; + mixer=alsa_mixer_open(obj); + if (mixer==NULL) return; + switch (source){ + case 'm': + set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH); + set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH); + break; + case 'l': + set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH); + set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH); + break; + } +} + +MSFilter *alsa_card_create_read_filter(AlsaCard *card) +{ + MSFilter *f=ms_oss_read_new(); + ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index); + return f; +} + +MSFilter *alsa_card_create_write_filter(AlsaCard *card) +{ + MSFilter *f=ms_oss_write_new(); + ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index); + return f; +} + + +SndCard * alsa_card_new(gint devid) +{ + AlsaCard * obj; + SndCard *base; + int err; + gchar *name=NULL; + + /* carefull: this is an alsalib call despite its name! */ + err=snd_card_get_name(devid,&name); + if (err<0) { + return NULL; + } + obj= g_new0(AlsaCard,1); + base= SND_CARD(obj); + snd_card_init(base); + + base->card_name=g_strdup_printf("%s (Advanced Linux Sound Architecture)",name); + base->_probe=(SndCardOpenFunc)alsa_card_probe; + base->_open_r=(SndCardOpenFunc)alsa_card_open_r; + base->_open_w=(SndCardOpenFunc)alsa_card_open_w; + base->_can_read=(SndCardPollFunc)alsa_card_can_read; + base->_set_blocking_mode=(SndCardSetBlockingModeFunc)alsa_card_set_blocking_mode; + base->_read=(SndCardIOFunc)alsa_card_read; + base->_write=(SndCardIOFunc)alsa_card_write; + base->_close_r=(SndCardCloseFunc)alsa_card_close_r; + base->_close_w=(SndCardCloseFunc)alsa_card_close_w; + base->_set_rec_source=(SndCardMixerSetRecSourceFunc)alsa_card_set_source; + base->_set_level=(SndCardMixerSetLevelFunc)alsa_card_set_level; + base->_get_level=(SndCardMixerGetLevelFunc)alsa_card_get_level; + base->_destroy=(SndCardDestroyFunc)alsa_card_destroy; + base->_create_read_filter=(SndCardCreateFilterFunc)alsa_card_create_read_filter; + base->_create_write_filter=(SndCardCreateFilterFunc)alsa_card_create_write_filter; + + + obj->pcmdev=g_strdup_printf("plughw:%i,0",devid); + obj->mixdev=g_strdup_printf("hw:%i",devid); + obj->readbuf=NULL; + obj->writebuf=NULL; + return base; +} + + +gint alsa_card_manager_init(SndCardManager *m, gint index) +{ + gint devindex; + gint found=0; + gchar *name=NULL; + for(devindex=0;indexcards[index]=alsa_card_new(devindex); + m->cards[index]->index=index; + found++; + index++; + } + } + return found; +} + +void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev){ + if (over_pcmdev!=NULL){ + g_free(over_pcmdev); + } + over_pcmdev=g_strdup(pcmdev); +} + +#endif diff --git a/linphone/mediastreamer/alsacard.h b/linphone/mediastreamer/alsacard.h new file mode 100644 index 000000000..df3372fb9 --- /dev/null +++ b/linphone/mediastreamer/alsacard.h @@ -0,0 +1,50 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include + +#ifdef HAVE_ALSA_ASOUNDLIB_H + +#include "sndcard.h" +#define ALSA_PCM_NEW_HW_PARAMS_API +#include +struct _AlsaCard +{ + SndCard parent; + gchar *pcmdev; + gchar *mixdev; + snd_pcm_t *read_handle; + snd_pcm_t *write_handle; + gint frame_size; + gint frames; + gchar *readbuf; + gint readpos; + gchar *writebuf; + gint writepos; + snd_mixer_t *mixer; +}; + +typedef struct _AlsaCard AlsaCard; + +SndCard *alsa_card_new(gint dev_id); +gint alsa_card_manager_init(SndCardManager *m, gint index); +void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev); + +#endif diff --git a/linphone/mediastreamer/audiostream.c b/linphone/mediastreamer/audiostream.c new file mode 100644 index 000000000..f129b064a --- /dev/null +++ b/linphone/mediastreamer/audiostream.c @@ -0,0 +1,340 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mediastream.h" +#ifdef INET6 + #include + #include + #include +#endif + + +#define MAX_RTP_SIZE 1500 + +/* this code is not part of the library itself, it is part of the mediastream program */ +void audio_stream_free(AudioStream *stream) +{ + RtpSession *s; + RtpSession *destroyed=NULL; + if (stream->rtprecv!=NULL) { + s=ms_rtp_recv_get_session(MS_RTP_RECV(stream->rtprecv)); + if (s!=NULL){ + destroyed=s; + rtp_session_destroy(s); + } + ms_filter_destroy(stream->rtprecv); + } + if (stream->rtpsend!=NULL) { + s=ms_rtp_send_get_session(MS_RTP_SEND(stream->rtpsend)); + if (s!=NULL){ + if (s!=destroyed) + rtp_session_destroy(s); + } + ms_filter_destroy(stream->rtpsend); + } + if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread); + if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite); + if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder); + if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder); + if (stream->timer!=NULL) ms_sync_destroy(stream->timer); + g_free(stream); +} + +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + +static void on_dtmf_received(RtpSession *s,gint dtmf,gpointer user_data) +{ + AudioStream *stream=(AudioStream*)user_data; + if (dtmf>15){ + g_warning("Unsupported telephone-event type."); + return; + } + g_message("Receiving dtmf %c.",dtmf_tab[dtmf]); + if (stream!=NULL){ + if (strcmp(stream->soundwrite->klass->name,"OssWrite")==0) + ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf_tab[dtmf]); + } +} + +static void on_timestamp_jump(RtpSession *s,guint32* ts, gpointer user_data) +{ + g_warning("The remote sip-phone has send data with a future timestamp: %u," + "resynchronising session.",*ts); + rtp_session_reset(s); +} + +static const char *ip4local="0.0.0.0"; +static const char *ip6local="::"; + +const char *get_local_addr_for(const char *remote) +{ + const char *ret; +#ifdef INET6 + struct addrinfo hints, *res0; + int err; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + err = getaddrinfo(remote,"8000", &hints, &res0); + if (err!=0) { + g_warning ("get_local_addr_for: %s", gai_strerror(err)); + return ip4local; + } + ret=(res0->ai_addr->sa_family==AF_INET6) ? ip6local : ip4local; + freeaddrinfo(res0); +#else + ret=ip4local; +#endif + return ret; +} + +void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport, + int payload,int jitt_comp, + RtpSession **recvsend){ + RtpSession *rtpr; + rtpr=rtp_session_new(RTP_SESSION_SENDRECV); + rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE); + rtp_session_set_profile(rtpr,profile); + rtp_session_set_local_addr(rtpr,get_local_addr_for(remip),locport); + if (remport>0) rtp_session_set_remote_addr(rtpr,remip,remport); + rtp_session_set_scheduling_mode(rtpr,0); + rtp_session_set_blocking_mode(rtpr,0); + rtp_session_set_payload_type(rtpr,payload); + rtp_session_set_jitter_compensation(rtpr,jitt_comp); + rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE); + /*rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);*/ + *recvsend=rtpr; +} + +void create_rtp_sessions(RtpProfile *profile, int locport,char *remip,int remport, + int payload,int jitt_comp, + RtpSession **recv, RtpSession **send){ + RtpSession *rtps,*rtpr; + /* creates two rtp filters to recv send streams (remote part)*/ + + rtps=rtp_session_new(RTP_SESSION_SENDONLY); + rtp_session_set_recv_buf_size(rtps,MAX_RTP_SIZE); + rtp_session_set_profile(rtps,profile); +#ifdef INET6 + rtp_session_set_local_addr(rtps,"::",locport+2); +#else + rtp_session_set_local_addr(rtps,"0.0.0.0",locport+2); +#endif + rtp_session_set_remote_addr(rtps,remip,remport); + rtp_session_set_scheduling_mode(rtps,0); + rtp_session_set_blocking_mode(rtps,0); + rtp_session_set_payload_type(rtps,payload); + rtp_session_set_jitter_compensation(rtps,jitt_comp); + + rtpr=rtp_session_new(RTP_SESSION_RECVONLY); + rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE); + rtp_session_set_profile(rtpr,profile); +#ifdef INET6 + rtp_session_set_local_addr(rtpr,"::",locport); +#else + rtp_session_set_local_addr(rtpr,"0.0.0.0",locport); +#endif + rtp_session_set_scheduling_mode(rtpr,0); + rtp_session_set_blocking_mode(rtpr,0); + rtp_session_set_send_payload_type(rtpr,payload); + rtp_session_set_recv_payload_type(rtpr,payload); + rtp_session_set_jitter_compensation(rtpr,jitt_comp); + rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,(unsigned long)NULL); + *recv=rtpr; + *send=rtps; + +} + + +AudioStream * audio_stream_start_full(RtpProfile *profile, int locport,char *remip,int remport, + int payload,int jitt_comp, gchar *infile, gchar *outfile, SndCard *playcard, SndCard *captcard) +{ + AudioStream *stream=g_new0(AudioStream,1); + RtpSession *rtps,*rtpr; + PayloadType *pt; + + //create_rtp_sessions(profile,locport,remip,remport,payload,jitt_comp,&rtpr,&rtps); + + create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr); + rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,(unsigned long)stream); + rtps=rtpr; + + stream->rtpsend=ms_rtp_send_new(); + ms_rtp_send_set_session(MS_RTP_SEND(stream->rtpsend),rtps); + stream->rtprecv=ms_rtp_recv_new(); + ms_rtp_recv_set_session(MS_RTP_RECV(stream->rtprecv),rtpr); + + + /* creates the local part */ + if (infile==NULL) stream->soundread=snd_card_create_read_filter(captcard); + else stream->soundread=ms_read_new(infile); + if (outfile==NULL) stream->soundwrite=snd_card_create_write_filter(playcard); + else stream->soundwrite=ms_write_new(outfile); + + /* creates the couple of encoder/decoder */ + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + g_error("audiostream.c: undefined payload type."); + return NULL; + } + stream->encoder=ms_encoder_new_with_string_id(pt->mime_type); + stream->decoder=ms_decoder_new_with_string_id(pt->mime_type); + if ((stream->encoder==NULL) || (stream->decoder==NULL)){ + /* big problem: we have not a registered codec for this payload...*/ + audio_stream_free(stream); + g_error("mediastream.c: No decoder available for payload %i.",payload); + return NULL; + } + /* give the sound filters some properties */ + ms_filter_set_property(stream->soundread,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); + ms_filter_set_property(stream->soundwrite,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); + + /* give the encoder/decoder some parameters*/ + ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); + ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate); + ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate); + ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate); + + ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->send_fmtp); + ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->recv_fmtp); + /* create the synchronisation source */ + stream->timer=ms_timer_new(); + + /* and then connect all */ + ms_filter_add_link(stream->soundread,stream->encoder); + ms_filter_add_link(stream->encoder,stream->rtpsend); + ms_filter_add_link(stream->rtprecv,stream->decoder); + ms_filter_add_link(stream->decoder,stream->soundwrite); + + ms_sync_attach(stream->timer,stream->soundread); + ms_sync_attach(stream->timer,stream->rtprecv); + + /* and start */ + ms_start(stream->timer); + + return stream; +} + +static int defcard=0; + +void audio_stream_set_default_card(int cardindex){ + defcard=cardindex; +} + +AudioStream * audio_stream_start_with_files(RtpProfile *prof,int locport,char *remip, + int remport,int profile,int jitt_comp,gchar *infile, gchar*outfile) +{ + return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,infile,outfile,NULL,NULL); +} + +AudioStream * audio_stream_start(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp) +{ + SndCard *sndcard; + sndcard=snd_card_manager_get_card(snd_card_manager,defcard); + return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,sndcard,sndcard); +} + +AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp,SndCard *playcard, SndCard *captcard) +{ + g_return_val_if_fail(playcard!=NULL,NULL); + g_return_val_if_fail(captcard!=NULL,NULL); + return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,playcard,captcard); +} + +void audio_stream_set_rtcp_information(AudioStream *st, const char *cname){ + if (st->send_session!=NULL){ + rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL,NULL,"linphone-" LINPHONE_VERSION, + "This is free software (GPL) !"); + } +} + +void audio_stream_stop(AudioStream * stream) +{ + + ms_stop(stream->timer); + ortp_global_stats_display(); + ms_sync_detach(stream->timer,stream->soundread); + ms_sync_detach(stream->timer,stream->rtprecv); + + ms_filter_remove_links(stream->soundread,stream->encoder); + ms_filter_remove_links(stream->encoder,stream->rtpsend); + ms_filter_remove_links(stream->rtprecv,stream->decoder); + ms_filter_remove_links(stream->decoder,stream->soundwrite); + + audio_stream_free(stream); +} + +RingStream * ring_start(gchar *file,gint interval,SndCard *sndcard) +{ + return ring_start_with_cb(file,interval,sndcard,NULL,NULL); +} + +RingStream * ring_start_with_cb(gchar *file,gint interval,SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data) +{ + RingStream *stream; + int tmp; + g_return_val_if_fail(sndcard!=NULL,NULL); + stream=g_new0(RingStream,1); + stream->source=ms_ring_player_new(file,interval); + if (stream->source==NULL) { + g_warning("Could not create ring player. Probably the ring file (%s) does not exist.",file); + return NULL; + } + if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data); + stream->sndwrite=snd_card_create_write_filter(sndcard); + ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_FREQ,&tmp); + ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_FREQ,&tmp); + ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_CHANNELS,&tmp); + ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_CHANNELS,&tmp); + stream->timer=ms_timer_new(); + ms_filter_add_link(stream->source,stream->sndwrite); + ms_sync_attach(stream->timer,stream->source); + ms_start(stream->timer); + return stream; +} + +void ring_stop(RingStream *stream) +{ + ms_stop(stream->timer); + ms_sync_detach(stream->timer,stream->source); + ms_sync_destroy(stream->timer); + ms_filter_remove_links(stream->source,stream->sndwrite); + ms_filter_destroy(stream->source); + ms_filter_destroy(stream->sndwrite); + g_free(stream); +} + +/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */ +gint test_audio_dev(int dev_id) +{ + gint err; + SndCard *sndcard=snd_card_manager_get_card(snd_card_manager,dev_id); + if (sndcard==NULL) return -1; + err=snd_card_probe(sndcard,16,0,8000); + return err; /* return latency in number of sample */ +} + +gint audio_stream_send_dtmf(AudioStream *stream, gchar dtmf) +{ + ms_rtp_send_dtmf(MS_RTP_SEND(stream->rtpsend), dtmf); + ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf); + return 0; +} diff --git a/linphone/mediastreamer/g711common.h b/linphone/mediastreamer/g711common.h new file mode 100644 index 000000000..3f5ad16fd --- /dev/null +++ b/linphone/mediastreamer/g711common.h @@ -0,0 +1,171 @@ +/* + * PCM - A-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * Wrapper for linphone Codec class by Simon Morlat + */ + +static inline int val_seg(int val) +{ + int r = 0; + val >>= 7; + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_alaw(int pcm_val) +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; + } else { + mask = 0x55; + pcm_val = -pcm_val; + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + } + + if (pcm_val < 256) + aval = pcm_val >> 4; + else { + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + } + return aval ^ mask; +} + +/* + * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM + * + */ +static inline int alaw_to_s16(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + t = a_val & 0x7f; + if (t < 16) + t = (t << 4) + 8; + else { + seg = (t >> 4) & 0x07; + t = ((t & 0x0f) << 4) + 0x108; + t <<= seg -1; + } + return ((a_val & 0x80) ? t : -t); +} +/* + * s16_to_ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + if (pcm_val < 0) { + pcm_val = 0x84 - pcm_val; + mask = 0x7f; + } else { + pcm_val += 0x84; + mask = 0xff; + } + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + return uval ^ mask; +} + +/* + * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +static inline int ulaw_to_s16(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & 0x0f) << 3) + 0x84; + t <<= (u_val & 0x70) >> 4; + + return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); +} diff --git a/linphone/mediastreamer/hpuxsndcard.c b/linphone/mediastreamer/hpuxsndcard.c new file mode 100644 index 000000000..8210e29d7 --- /dev/null +++ b/linphone/mediastreamer/hpuxsndcard.c @@ -0,0 +1,301 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "sndcard.h" +#include "osscard.h" + +#ifdef HAVE_SYS_AUDIO_H +#include + + +#include "msossread.h" +#include "msosswrite.h" + +#include +#include + + +int hpuxsnd_open(HpuxSndCard *obj, int bits,int stereo, int rate) +{ + int fd; + int p=0,cond=0; + int i=0; + int min_size=0,blocksize=512; + /* do a quick non blocking open to be sure that we are not going to be blocked here + for the eternity */ + fd=open(obj->dev_name,O_RDWR|O_NONBLOCK); + if (fd<0) return -EWOULDBLOCK; + close(fd); + /* open the device */ + fd=open(obj->dev_name,O_RDWR); + + g_return_val_if_fail(fd>0,-errno); + + ioctl(fd,AUDIO_RESET,0); + ioctl(fd,AUDIO_SET_SAMPLE_RATE,rate); + ioctl(fd,AUDIO_SET_CHANNELS,stereo); + p=AUDIO_FORMAT_LINEAR16BIT; + ioctl(fd,AUDIO_SET_DATA_FORMAT,p); + /* ioctl(fd,AUDIO_GET_RXBUFSIZE,&min_size); does not work ? */ + min_size=2048; + + g_message("dsp blocksize is %i.",min_size); + obj->fd=fd; + obj->readpos=0; + obj->writepos=0; + SND_CARD(obj)->bits=bits; + SND_CARD(obj)->stereo=stereo; + SND_CARD(obj)->rate=rate; + SND_CARD(obj)->bsize=min_size; + return fd; +} + +int hpux_snd_card_probe(HpuxSndCard *obj,int bits,int stereo,int rate) +{ + return 2048; +} + + +int hpux_snd_card_open(HpuxSndCard *obj,int bits,int stereo,int rate) +{ + int fd; + obj->ref++; + if (obj->fd==0){ + fd=hpuxsnd_open(obj,bits,stereo,rate); + if (fd<0) { + obj->fd=0; + obj->ref--; + return -1; + } + } + SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED; + return 0; +} + +void hpux_snd_card_close(HpuxSndCard *obj) +{ + int i; + obj->ref--; + if (obj->ref==0) { + close(obj->fd); + obj->fd=0; + SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED; + + } +} + +void hpux_snd_card_destroy(HpuxSndCard *obj) +{ + snd_card_uninit(SND_CARD(obj)); + g_free(obj->dev_name); + g_free(obj->mixdev_name); +} + +gboolean hpux_snd_card_can_read(HpuxSndCard *obj) +{ + struct timeval tout={0,0}; + int err; + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(obj->fd,&fdset); + err=select(obj->fd+1,&fdset,NULL,NULL,&tout); + if (err>0) return TRUE; + else return FALSE; +} + +int hpux_snd_card_read(HpuxSndCard *obj,char *buf,int size) +{ + int err; + gint bsize=SND_CARD(obj)->bsize; + if (sizereadpos,size); + if (obj->readbuf==NULL) obj->readbuf=g_malloc0(bsize); + if (obj->readpos==0){ + err=read(obj->fd,obj->readbuf,bsize); + if (err<0) { + g_warning("hpux_snd_card_read: read() failed:%s.",strerror(errno)); + return -1; + } + } + + memcpy(buf,&obj->readbuf[obj->readpos],canread); + obj->readpos+=canread; + if (obj->readpos>=bsize) obj->readpos=0; + return canread; + }else{ + err=read(obj->fd,buf,size); + if (err<0) { + g_warning("hpux_snd_card_read: read-2() failed:%s.",strerror(errno)); + } + return err; + } + +} + +int hpux_snd_card_write(HpuxSndCard *obj,char *buf,int size) +{ + int err; + gint bsize=SND_CARD(obj)->bsize; + if (sizewritepos,size); + if (obj->writebuf==NULL) obj->writebuf=g_malloc0(bsize); + + memcpy(&obj->writebuf[obj->writepos],buf,canwrite); + obj->writepos+=canwrite; + if (obj->writepos>=bsize){ + err=write(obj->fd,obj->writebuf,bsize); + } + return canwrite; + }else{ + return write(obj->fd,buf,bsize); + } +} + +#define SND_CARD_LEVEL_TO_HPUX_LEVEL(a) (((a)*2) - 100) +#define HPUX_LEVEL_TO_SND_CARD_LEVEL(a) (((a)+200)/2) +void hpux_snd_card_set_level(HpuxSndCard *obj,gint way,gint a) +{ + struct audio_gain gain; + int error,mix_fd; + + g_return_if_fail(obj->mixdev_name!=NULL); + memset(&gain,0,sizeof(struct audio_gain)); + switch(way){ + case SND_CARD_LEVEL_GENERAL: + gain.cgain[0].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a); + gain.cgain[1].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a); + break; + case SND_CARD_LEVEL_INPUT: + gain.cgain[0].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a); + gain.cgain[1].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a); + break; + case SND_CARD_LEVEL_OUTPUT: + gain.cgain[0].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a); + gain.cgain[1].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a); + break; + default: + g_warning("hpux_snd_card_set_level: unsupported command."); + return; + } + gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT; + mix_fd = open(obj->mixdev_name, O_WRONLY); + g_return_if_fail(mix_fd>0); + error=ioctl(mix_fd,AUDIO_SET_GAINS,&gain); + if (error<0){ + g_warning("hpux_snd_card_set_level: Could not set gains: %s",strerror(errno)); + } + close(mix_fd); +} + +gint hpux_snd_card_get_level(HpuxSndCard *obj,gint way) +{ + struct audio_gain gain; + int p=0,mix_fd,error; + g_return_if_fail(obj->mixdev_name!=NULL); + + gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT; + mix_fd = open(obj->mixdev_name, O_RDONLY); + g_return_if_fail(mix_fd>0); + error=ioctl(mix_fd,AUDIO_GET_GAINS,&gain); + if (error<0){ + g_warning("hpux_snd_card_set_level: Could not get gains: %s",strerror(errno)); + } + close(mix_fd); + + switch(way){ + case SND_CARD_LEVEL_GENERAL: + p=gain.cgain[0].monitor_gain; + break; + case SND_CARD_LEVEL_INPUT: + p=gain.cgain[0].receive_gain; + break; + case SND_CARD_LEVEL_OUTPUT: + p=gain.cgain[0].transmit_gain; + break; + default: + g_warning("hpux_snd_card_get_level: unsupported command."); + return -1; + } + return HPUX_LEVEL_TO_SND_CARD_LEVEL(p); +} + +void hpux_snd_card_set_source(HpuxSndCard *obj,int source) +{ + gint p=0; + gint mix_fd; + gint error=0; + g_return_if_fail(obj->mixdev_name!=NULL); + + mix_fd=open("/dev/audio",O_WRONLY); + g_return_if_fail(mix_fd>0); + switch(source){ + case 'm': + error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_MIKE); + break; + case 'l': + error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_LINE); + break; + default: + g_warning("hpux_snd_card_set_source: unsupported source."); + } + close(mix_fd); +} + +MSFilter *hpux_snd_card_create_read_filter(HpuxSndCard *card) +{ + MSFilter *f=ms_oss_read_new(); + ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index); + return f; +} + +MSFilter *hpux_snd_card_create_write_filter(HpuxSndCard *card) +{ + MSFilter *f=ms_oss_write_new(); + ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index); + return f; +} + + +SndCard * hpux_snd_card_new(char *devname, char *mixdev_name) +{ + HpuxSndCard * obj= g_new0(HpuxSndCard,1); + SndCard *base= SND_CARD(obj); + snd_card_init(base); + obj->dev_name=g_strdup(devname); + obj->mixdev_name=g_strdup( mixdev_name); + base->card_name=g_strdup(devname); + base->_probe=(SndCardOpenFunc)hpux_snd_card_probe; + base->_open_r=(SndCardOpenFunc)hpux_snd_card_open; + base->_open_w=(SndCardOpenFunc)hpux_snd_card_open; + base->_can_read=(SndCardPollFunc)hpux_snd_card_can_read; + base->_read=(SndCardIOFunc)hpux_snd_card_read; + base->_write=(SndCardIOFunc)hpux_snd_card_write; + base->_close_r=(SndCardCloseFunc)hpux_snd_card_close; + base->_close_w=(SndCardCloseFunc)hpux_snd_card_close; + base->_set_rec_source=(SndCardMixerSetRecSourceFunc)hpux_snd_card_set_source; + base->_set_level=(SndCardMixerSetLevelFunc)hpux_snd_card_set_level; + base->_get_level=(SndCardMixerGetLevelFunc)hpux_snd_card_get_level; + base->_destroy=(SndCardDestroyFunc)hpux_snd_card_destroy; + base->_create_read_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_read_filter; + base->_create_write_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_write_filter; + return base; +} + +#endif diff --git a/linphone/mediastreamer/jackcard.c b/linphone/mediastreamer/jackcard.c new file mode 100644 index 000000000..b929cce9e --- /dev/null +++ b/linphone/mediastreamer/jackcard.c @@ -0,0 +1,574 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + JACK support + Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk +*/ + +#include "jackcard.h" + +#ifdef __JACK_ENABLED__ + +#include "msossread.h" +#include "msosswrite.h" + +#include + +#define READBUFFERSIZE 524288 +#define WRITEBUFFERSIZE 524288 +#define BSIZE 512 + +/** + * jack_shutdown: + * @arg: + * + * This is the shutdown callback for this JACK application. + * It is called by JACK if the server ever shuts down or + * decides to disconnect the client. + * + */ +void +jack_shutdown (void *arg) +{ + JackCard* obj = (JackCard*) arg; + + obj->jack_running = FALSE; + obj->jack_active = FALSE; + obj->read.port = NULL; + if (obj->read.open) + obj->read.init = TRUE; + obj->write.port = NULL; + if (obj->write.open) + obj->write.init = TRUE; +} + +int samplerate(jack_nframes_t rate, void *arg) +{ + JackCard* obj = (JackCard*) arg; + int error; + + obj->rate = rate; + if (obj->read.open) { + obj->read.data.src_ratio = (double)obj->read.rate / (double)obj->rate; + obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio); + g_free(obj->read.data.data_in); + obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float)); + if (obj->read.src_state) + if ((error = src_set_ratio(obj->read.src_state, obj->read.data.src_ratio)) != 0) + g_warning("Error while resetting the write samplerate: %s", src_strerror(error)); + } + if (obj->write.open) { + obj->write.data.src_ratio = (double)obj->rate / (double)obj->write.rate; + obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio); + g_free(obj->write.data.data_out); + obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float)); + if (obj->write.src_state) + if ((error = src_set_ratio(obj->write.src_state, obj->write.data.src_ratio)) != 0) + g_warning("Error while resetting the write samplerate: %s", src_strerror(error)); + } + return 0; +} + +/* + * The process callback for this JACK application. + * It is called by JACK at the appropriate times. + * @nframes : + * @arg : + */ +int +process (jack_nframes_t nframes, void *arg) +{ + JackCard* obj = (JackCard*) arg; + sample_t *out; + sample_t *in; + + if (obj->clear && !obj->write.can_process) { + out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes); + memset (out, 0, nframes * sizeof(sample_t)); + obj->clear = FALSE; + } + + if (!obj->can_process) + return 0; + + if(obj->read.can_process) { + in = (sample_t *) jack_port_get_buffer (obj->read.port, nframes); + jack_ringbuffer_write (obj->read.buffer, (void *) in, sizeof(sample_t) * nframes); + } + + if (obj->write.can_process) { + out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes); + memset (out, 0, nframes * sizeof(sample_t)); + if (obj->clear && jack_ringbuffer_read_space(obj->write.buffer) == 0) { + obj->write.can_process = FALSE; + if (!obj->read.open) + obj->can_process = FALSE; + obj->clear = FALSE; + return 0; + } + jack_ringbuffer_read (obj->write.buffer, (void *) out, sizeof(sample_t) * nframes); + } + return 0; +} + +int jack_init(JackCard* obj) +{ + char* client_name; + int error; + + if (!obj->jack_running) { + obj->client = NULL; + client_name = g_strdup_printf("linphone-%u", g_random_int()); + if ((obj->client = jack_client_new (client_name)) == NULL) { + g_warning("cannot create jack client"); + g_free(client_name); + return -1; + } + g_message("Found Jack Daemon"); + g_free(client_name); + + /* tell the JACK server to call `process()' whenever + there is work to be done. + */ + jack_set_process_callback (obj->client, process, obj); + + /* tell the JACK server to call `jack_shutdown()' if + it ever shuts down, either entirely, or if it + just decides to stop calling us. + */ + jack_on_shutdown (obj->client, jack_shutdown, obj); + jack_set_sample_rate_callback (obj->client, samplerate, obj); + obj->rate = jack_get_sample_rate (obj->client); + if (obj->rate == 0) { + g_warning ("rate is 0???"); + if (jack_client_close(obj->client) != 0) + g_warning("could not close client"); + return -1; + } + obj->buffer_size = jack_get_buffer_size(obj->client); + obj->jack_running = TRUE; + } + + if (!obj->jack_active) { + if (jack_activate (obj->client)) { + g_warning("cannot activate jack client"); + return -1; + } else obj->jack_active = TRUE; + } + + if (obj->read.init) { + if (!obj->read.port && (obj->read.port = jack_port_register (obj->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))==NULL) { + g_warning("error while trying to register input port"); + return -1; + } + if (!obj->read.phys_ports && (obj->read.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) { + g_warning("Cannot find any physical capture ports\n"); + jack_port_unregister(obj->client, obj->read.port); + obj->read.port = NULL; + return -1; + } + if (!jack_port_connected(obj->read.port)) + if ((error = jack_connect (obj->client, obj->read.phys_ports[0], jack_port_name (obj->read.port))) != 0) { + g_warning("cannot connect input ports: %s -> %s\n", jack_port_name (obj->read.port), obj->read.phys_ports[0]); + if (error == EEXIST) g_warning("connection already made"); + else { + jack_port_unregister(obj->client, obj->read.port); + obj->read.port = NULL; + return -1; + } + } + obj->read.init = FALSE; + } + + if (obj->write.init) { + if (!obj->write.port && (obj->write.port = jack_port_register (obj->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0))==NULL) { + g_warning("error while trying to register output port"); + return -1; + } + if (!obj->write.phys_ports && (obj->write.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { + g_warning("Cannot find any physical playback ports\n"); + jack_port_unregister(obj->client, obj->write.port); + obj->write.port = NULL; + return -1; + } + if (!jack_port_connected(obj->write.port)) { + if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[0])) != 0) { + g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[0]); + if (error == EEXIST) g_warning("connection already made"); + else { + jack_port_unregister(obj->client, obj->write.port); + obj->write.port = NULL; + return -1; + } + } + if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[1])) != 0) { + g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[1]); + if (error == EEXIST) g_warning("connection already made"); + else { + jack_port_unregister(obj->client, obj->write.port); + obj->write.port = NULL; + return -1; + } + } + } + obj->write.init = FALSE; + } + return 0; +} + +int jack_card_open_r(JackCard *obj,int bits,int stereo,int rate) +{ + int channels = stereo + 1, bsize, error; + obj->read.init = TRUE; + if (jack_init(obj) != 0) return -1; + + obj->read.rate = rate; + obj->sample_size = bits / 8; + obj->frame_size = channels * obj->sample_size; + bsize = BSIZE; + obj->read.frames = bsize / 2; + SND_CARD(obj)->bsize = bsize; + SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED; + obj->read.channels = channels; + if ((obj->read.src_state = src_new (SRC_SINC_FASTEST, channels, &error)) == NULL) + g_warning("Error while initializing the samplerate converter: %s", src_strerror(error)); + obj->read.data.src_ratio = (double)rate / (double)obj->rate; + obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio); + obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float)); + obj->read.data.data_out = malloc(obj->read.frames*sizeof(float)); + obj->read.data.end_of_input = 0; + if (!obj->read.buffer) + obj->read.buffer = jack_ringbuffer_create(READBUFFERSIZE); + obj->read.can_process = TRUE; + obj->can_process = TRUE; + obj->read.open = TRUE; + obj->read.init = FALSE; + return 0; +} + +int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate) +{ + int channels = stereo + 1, bsize, err; + obj->write.init = TRUE; + if (jack_init(obj) != 0) return -1; + + obj->write.rate = rate; + obj->sample_size = bits / 8; + obj->frame_size = channels * obj->sample_size; + bsize = BSIZE; + obj->write.frames = bsize / 2; + SND_CARD(obj)->bsize = bsize; + SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED; + obj->write.channels = channels; + if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL) + g_warning("Error while initializing the samplerate converter: %s", src_strerror(err)); + obj->write.data.src_ratio = (double)obj->rate / (double)rate; + obj->write.data.data_in = malloc(obj->write.frames*sizeof(float)); + obj->write.data.end_of_input = 0; + obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio); + obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float)); + if (!obj->write.buffer) + obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE); + obj->write.can_process = TRUE; + obj->can_process = TRUE; + obj->write.open = TRUE; + obj->write.init = FALSE; + return 0; +} + +void jack_card_set_blocking_mode(JackCard *obj, gboolean yesno) +{ +} + +void jack_card_close_r(JackCard *obj) +{ + obj->read.open = FALSE; + obj->read.init = FALSE; + obj->read.can_process = FALSE; + if (!obj->write.open) + obj->can_process = FALSE; + if (obj->read.src_state) + obj->read.src_state = src_delete (obj->read.src_state); + g_free(obj->read.data.data_in); + g_free(obj->read.data.data_out); +} + +void jack_card_close_w(JackCard *obj) +{ + obj->write.open = FALSE; + obj->write.init = FALSE; + obj->clear = TRUE; + if (!obj->jack_running) { + obj->write.can_process = FALSE; + obj->can_process = FALSE; + } + if (obj->write.src_state) + obj->write.src_state = src_delete (obj->write.src_state); + g_free(obj->write.data.data_in); + g_free(obj->write.data.data_out); +} + +int jack_card_probe(JackCard *obj,int bits,int stereo,int rate) +{ + if (obj->jack_running) return BSIZE; + else if (jack_init(obj) == 0) return BSIZE; + else return -1; +} + +void jack_card_destroy(JackCard *obj) +{ + if (obj->jack_running) jack_client_close (obj->client); + snd_card_uninit(SND_CARD(obj)); + if (obj->read.buffer) { + jack_ringbuffer_free(obj->read.buffer); + obj->read.buffer = NULL; + } + if (obj->write.buffer) { + jack_ringbuffer_free(obj->write.buffer); + obj->write.buffer = NULL; + } + if (obj->read.phys_ports) { + g_free(obj->read.phys_ports); + obj->read.phys_ports = NULL; + } + if (obj->write.phys_ports) { + g_free(obj->write.phys_ports); + obj->write.phys_ports = NULL; + } +} + +gboolean jack_card_can_read(JackCard *obj) +{ + g_return_val_if_fail(obj->read.buffer!=NULL,0); + if (jack_ringbuffer_read_space(obj->read.buffer)>=(long)((double)obj->read.frames/obj->read.data.src_ratio)*sizeof(sample_t)) return TRUE; + else return FALSE; +} + +int jack_card_read(JackCard *obj,char *buf,int size) +{ + size_t bytes, can_read, i; + int error; + float norm, value; + + g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1); + if (jack_init(obj) != 0) return -1; + size /= 2; + can_read = MIN(size, obj->read.frames); + // can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer)); + can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t); + obj->read.can_process = FALSE; + bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read); + obj->read.can_process = TRUE; + obj->read.data.input_frames = bytes / sizeof(sample_t); + can_read = MIN(size, obj->read.frames); + obj->read.data.output_frames = can_read; + if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0) + g_warning("error while samplerate conversion. error: %s", src_strerror(error)); + norm = obj->read.level*obj->level*(float)0x8000; + for (i=0; i < obj->read.data.output_frames_gen; i++) { + value = obj->read.data.data_out[i]*norm; + if (value >= 32767.0) + ((short*)buf)[i] = 32767; + else if (value <= -32768.0) + ((short*)buf)[i] = -32768; + else + ((short*)buf)[i] = (short)value; + } + bytes = obj->read.data.output_frames_gen * 2; + return bytes; +} + +int jack_card_write(JackCard *obj,char *buf,int size) +{ + size_t bytes, can_write, i; + int error; + float norm; + + g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1); + if (jack_init(obj) != 0) return -1; + size /= 2; + can_write = MIN(size, obj->write.frames); + norm = obj->write.level*obj->level/(float)0x8000; + for (i=0; iwrite.data.data_in[i] = (float)((short*)buf)[i]*norm; + } + obj->write.data.input_frames = can_write; + if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0) + g_warning("error while samplerate conversion. error: %s", src_strerror(error)); + obj->write.can_process = FALSE; + bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen); + obj->write.can_process = TRUE; + return bytes; +} + +void jack_card_set_level(JackCard *obj,gint way,gint a) +{ + switch(way){ + case SND_CARD_LEVEL_GENERAL: + obj->level = (float)a / 100.0; + break; + case SND_CARD_LEVEL_INPUT: + obj->read.level = (float)a / 100.0; + break; + case SND_CARD_LEVEL_OUTPUT: + obj->write.level = (float)a / 100.0; + break; + default: + g_warning("jack_card_set_level: unsupported command."); + } +} + +gint jack_card_get_level(JackCard *obj,gint way) +{ + gint value = 0; + + switch(way){ + case SND_CARD_LEVEL_GENERAL: + value = (gint)(obj->level*100.0); + break; + case SND_CARD_LEVEL_INPUT: + value = (gint)(obj->read.level*100.0); + break; + case SND_CARD_LEVEL_OUTPUT: + value = (gint)(obj->write.level*100.0); + break; + default: + g_warning("jack_card_get_level: unsupported command."); + } + return value; +} + +void jack_card_set_source(JackCard *obj,int source) +{ +} + +MSFilter *jack_card_create_read_filter(JackCard *card) +{ + MSFilter *f=ms_oss_read_new(); + ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index); + return f; +} + +MSFilter *jack_card_create_write_filter(JackCard *card) +{ + MSFilter *f=ms_oss_write_new(); + ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index); + return f; +} +SndCard * jack_card_new(jack_client_t *client) +{ + JackCard * obj; + SndCard *base; + + obj= g_new0(JackCard,1); + + if (!client) return NULL; + obj->client = client; + obj->jack_running = TRUE; + obj->jack_active = FALSE; + obj->can_process = FALSE; + obj->clear = TRUE; + obj->write.can_process = FALSE; + obj->write.open = FALSE; + obj->write.init = TRUE; + obj->write.port = NULL; + obj->write.phys_ports = NULL; + obj->write.buffer = NULL; + obj->read.can_process = FALSE; + obj->read.open = FALSE; + obj->read.init = TRUE; + obj->read.port = NULL; + obj->read.phys_ports = NULL; + obj->read.buffer = NULL; + + /* tell the JACK server to call `process()' whenever + there is work to be done. + */ + jack_set_process_callback (client, process, obj); + + /* tell the JACK server to call `jack_shutdown()' if + it ever shuts down, either entirely, or if it + just decides to stop calling us. + */ + jack_on_shutdown (client, jack_shutdown, obj); + + jack_set_sample_rate_callback (client, samplerate, obj); + + obj->rate = jack_get_sample_rate (client); + obj->buffer_size = jack_get_buffer_size(obj->client); + + jack_init(obj); + + base= SND_CARD(obj); + snd_card_init(base); + +#ifdef HAVE_GLIB + base->card_name=g_strdup_printf("JACK client"); +#else + base->card_name=malloc(100); + snprintf(base->card_name, 100, "JACK client"); +#endif + + base->_probe=(SndCardOpenFunc)jack_card_probe; + base->_open_r=(SndCardOpenFunc)jack_card_open_r; + base->_open_w=(SndCardOpenFunc)jack_card_open_w; + base->_can_read=(SndCardPollFunc)jack_card_can_read; + base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode; + base->_read=(SndCardIOFunc)jack_card_read; + base->_write=(SndCardIOFunc)jack_card_write; + base->_close_r=(SndCardCloseFunc)jack_card_close_r; + base->_close_w=(SndCardCloseFunc)jack_card_close_w; + base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source; + base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level; + base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level; + base->_destroy=(SndCardDestroyFunc)jack_card_destroy; + base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter; + base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter; + + obj->read.buffer=NULL; + obj->write.buffer=NULL; + obj->buffer_size = 0; + obj->level = 1.0; + obj->write.level = 1.0; + obj->read.level = 1.0; + + return base; +} + + +gint jack_card_manager_init(SndCardManager *m, gint index) +{ + jack_client_t *client = NULL; + char* client_name; + + client_name=g_strdup_printf("linphone-%u", g_random_int()); + if ((client = jack_client_new (client_name))!= NULL) + { + g_message("Found Jack Daemon"); + g_free(client_name); + m->cards[index]=jack_card_new(client); + m->cards[index]->index=index; + return 1; + } else { + g_free(client_name); + return 0; + } +} + +#endif diff --git a/linphone/mediastreamer/jackcard.h b/linphone/mediastreamer/jackcard.h new file mode 100644 index 000000000..33ec46dc0 --- /dev/null +++ b/linphone/mediastreamer/jackcard.h @@ -0,0 +1,81 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + JACK support + Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk +*/ + +#ifndef JACK_CARD_H +#define JACK_CARD_H + +#include + +#ifdef __JACK_ENABLED__ + +#include "sndcard.h" + +#include +#include + +#include + +typedef jack_default_audio_sample_t sample_t; + +typedef struct { + jack_port_t *port; + const char **phys_ports; + float level; + jack_ringbuffer_t *buffer; + gint channels; + gint rate; + SRC_STATE* src_state; + SRC_DATA data; + size_t frames; + gboolean can_process; + gboolean open; + gboolean init; +} jackcard_mode_t; + +struct _JackCard +{ + SndCard parent; + + jack_client_t *client; + gboolean jack_running; + gboolean jack_active; + float level; + jack_nframes_t buffer_size; + gint sample_size; + gint frame_size; + gint rate; + gboolean can_process; + gboolean clear; + + jackcard_mode_t read, write; +}; + +typedef struct _JackCard JackCard; + +SndCard * jack_card_new(jack_client_t *client); + +gint jack_card_manager_init(SndCardManager *m, gint index); + +#endif + +#endif diff --git a/linphone/mediastreamer/mediastream.c b/linphone/mediastreamer/mediastream.c new file mode 100644 index 000000000..e88cf1902 --- /dev/null +++ b/linphone/mediastreamer/mediastream.c @@ -0,0 +1,144 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mediastream.h" + +#include +#include +#include +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond--; + if (cond<0) exit(-1); +} + +void parse_addr(gchar *addr, char **ip, int *port) +{ + char *semicolon; + gint iplen; + + *ip=NULL; + *port=0; + semicolon=strchr(addr,':'); + if (semicolon==NULL) return; + iplen=semicolon-addr; + *ip=g_malloc(iplen+1); + strncpy(*ip,addr,iplen); + (*ip)[iplen]='\0'; + *port=atoi(semicolon+1); +} + +char *usage="mediastream --local --remote --payload \n"; +void run_media_streams(gint localport, gchar *remote_ip, gint remoteport, gint payload); + +int main(int argc, char * argv[]) +{ + gint i; + gint localport=0,remoteport=0,payload=0; + gchar *ip; + gchar *tmp; + + /*create the rtp session */ + ortp_init(); + rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015); + rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb); + rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998); + if (argc<4) { + printf(usage); + return -1; + } + for (i=1;itype!=PAYLOAD_VIDEO){ + printf("Starting audio stream.\n"); + audio=audio_stream_start(&av_profile,localport,remote_ip,remoteport,payload,50); + }else{ +#ifdef VIDEO_ENABLED + printf("Starting video stream.\n"); + video=video_stream_start(&av_profile, + localport, + remote_ip, + remoteport, + payload, + 50, + TRUE, + "Video4Linux", + "/dev/video0"); +#else + printf("Error: video support not compiled.\n"); +#endif + } + while(cond) + { + /* sleep until we receive SIGINT */ + sleep(1); + ortp_global_stats_display(); + } + + printf("stoping all...\n"); + + if (audio) audio_stream_stop(audio); +#ifdef VIDEO_ENABLED + if (video) video_stream_stop(video); +#endif +} diff --git a/linphone/mediastreamer/mediastream.h b/linphone/mediastreamer/mediastream.h new file mode 100644 index 000000000..0298b64f4 --- /dev/null +++ b/linphone/mediastreamer/mediastream.h @@ -0,0 +1,133 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MEDIASTREAM_H +#define MEDIASTREAM_H + +#include "msrtprecv.h" +#include "msrtpsend.h" +#include "ms.h" +#include "msosswrite.h" +#include "msossread.h" +#include "msread.h" +#include "mswrite.h" +#include "mstimer.h" +#include "mscodec.h" +#include "msspeexdec.h" +#include "msringplayer.h" + + +struct _AudioStream +{ + MSSync *timer; + RtpSession *send_session; + RtpSession *recv_session; + MSFilter *soundread; + MSFilter *soundwrite; + MSFilter *encoder; + MSFilter *decoder; + MSFilter *rtprecv; + MSFilter *rtpsend; +}; + + +typedef struct _AudioStream AudioStream; + +struct _RingStream +{ + MSSync *timer; + MSFilter *source; + MSFilter *sndwrite; +}; + +typedef struct _RingStream RingStream; + +/* start a thread that does sampling->encoding->rtp_sending|rtp_receiving->decoding->playing */ +AudioStream *audio_stream_start (RtpProfile * prof, int locport, char *remip, + int remport, int profile, int jitt_comp); + +AudioStream *audio_stream_start_with_sndcards(RtpProfile * prof, int locport, char *remip4, + int remport, int profile, int jitt_comp, SndCard *playcard, SndCard *captcard); + +AudioStream *audio_stream_start_with_files (RtpProfile * prof, int locport, + char *remip4, int remport, + int profile, int jitt_comp, + gchar * infile, gchar * outfile); +void audio_stream_set_rtcp_information(AudioStream *st, const char *cname); + + +/* stop the above process*/ +void audio_stream_stop (AudioStream * stream); + +RingStream *ring_start (gchar * file, gint interval, SndCard *sndcard); +RingStream *ring_start_with_cb(gchar * file, gint interval, SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data); +void ring_stop (RingStream * stream); + +/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */ +gint test_audio_dev (int dev_id); + +/* send a dtmf */ +gint audio_stream_send_dtmf (AudioStream * stream, gchar dtmf); + +void audio_stream_set_default_card(int cardindex); + + +#ifdef VIDEO_ENABLED + +/***************** + Video Support + *****************/ + + + +struct _VideoStream +{ + MSSync *timer; + RtpSession *send_session; + RtpSession *recv_session; + MSFilter *source; + MSFilter *output; + MSFilter *encoder; + MSFilter *decoder; + MSFilter *rtprecv; + MSFilter *rtpsend; + gboolean show_local; +}; + + +typedef struct _VideoStream VideoStream; + +VideoStream *video_stream_start(RtpProfile *profile, int locport, char *remip4, int remport, + int payload, int jitt_comp, gboolean show_local, const gchar *source, const gchar *device); +void video_stream_set_rtcp_information(VideoStream *st, const char *cname); +void video_stream_stop (VideoStream * stream); + +VideoStream * video_preview_start(const gchar *source, const gchar *device); +void video_preview_stop(VideoStream *stream); + +VideoStream * video_stream_send_only_start(RtpProfile *profile, int locport, char *remip, int remport, + int payload, const gchar *source, const gchar *device); + +void video_stream_send_only_stop(VideoStream *stream); + +#endif + +#endif diff --git a/linphone/mediastreamer/ms.c b/linphone/mediastreamer/ms.c new file mode 100644 index 000000000..c9b9a86a0 --- /dev/null +++ b/linphone/mediastreamer/ms.c @@ -0,0 +1,394 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ms.h" +#include "sndcard.h" +#include "mscodec.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DLOPEN +#include +#endif + +#ifdef HAVE_GLIB +#include "gmodule.h" /* g_module_open() */ +#endif + +#define MS_PLUGINS_DIR PACKAGE_PLUGINS_DIR "/mediastreamer" + + +#ifdef VIDEO_ENABLED +extern void ms_video_source_register_all(); +#endif + +/** + * ms_init: + * + * + * Initialize the mediastreamer. This must be the first function called in a program + * using the mediastreamer library. + * + * + */ +void ms_init() +{ + if (!g_thread_supported()) g_thread_init (NULL); + + /* initialize the oss subsystem */ + snd_card_manager_init(snd_card_manager); + /* register the statically linked codecs */ + ms_codec_register_all(); +#ifdef VIDEO_ENABLED + ms_video_source_register_all(); +#endif + ms_load_plugins(MS_PLUGINS_DIR); +} + + +static gint compare(gconstpointer a, gconstpointer b) +{ + MSFilter *f1=(MSFilter*)a,*f2=(MSFilter*)b; + if (f1->klassklass) return -1; + if (f1->klass==f2->klass) return 0; + /* if f1->klass>f2->klass ....*/ + return 1; +} + +static GList *g_list_append_if_new(GList *l,gpointer data) +{ + GList *res=l; + if (g_list_find(res,data)==NULL) + res=g_list_append(res,data); + return(res); +} + +static GList *get_nexts(MSFilter *f,GList *l) +{ + int i; + MSFifo *fifo; + MSQueue *q; + GList *res=l; + + /* check fifos*/ + for (i=0;i klass->max_foutputs;i++) + { + fifo=f->outfifos[i]; + if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data); + } + /* check queues*/ + for (i=0;i klass->max_qoutputs;i++) + { + q=f->outqueues[i]; + if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data); + } + return(res); +} + +/* compile graphs attached to a sync source*/ +int ms_compile(MSSync *sync) +{ + int i; + GList *list1=NULL,*list2=NULL,*elem; + GList *proc_chain=NULL; + MSFilter *f; + + /* first free the old list if we are just updating*/ + if (sync->execution_list!=NULL) g_list_free(sync->execution_list); + /* get the list of filters attached to this sync*/ + for (i=0;ifilters;i++) + { + //printf("found filter !\n"); + list1=g_list_append(list1,sync->attached_filters[i]); + } + /* find the processing chain */ + while (list1!=NULL) + { + list2=NULL; + /* sort the list by types of filter*/ + list1=g_list_sort(list1,compare); + /* save into the processing chain list*/ + //printf("list1 :%i elements\n",g_list_length(list1)); + proc_chain=g_list_concat(proc_chain,list1); + /* get all following filters. They are appended to list2*/ + elem=list1; + while (elem!=NULL) + { + f=(MSFilter*)(elem->data); + /* check if filter 's status */ + if (f->klass->attributes & FILTER_CAN_SYNC) + { + sync->samples_per_tick=0; + } + list2=get_nexts(f,list2); + elem=g_list_next(elem); + } + list1=list2; + } + sync->execution_list=proc_chain; + sync->flags&=~MS_SYNC_NEED_UPDATE; + ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list)); + return 0; +} + +/*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/ +void *ms_thread_run(void *sync_ptr) +{ + MSSync *sync=(MSSync*) sync_ptr; + GList *filter; + MSFilter *f; + + + ms_sync_lock(sync); + while(sync->run) + { + //g_message("sync->run=%i",sync->run); + if (sync->samples_per_tick==0) ms_sync_suspend(sync); + if (sync->flags & MS_SYNC_NEED_UPDATE){ + ms_compile(sync); + ms_sync_setup(sync); + } + filter=sync->execution_list; + ms_sync_unlock(sync); + //ms_trace("Calling synchronisation"); + ms_sync_synchronize(sync); + while(filter!=NULL) + { + f=(MSFilter*)filter->data; + if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE) + { + /* execute it once */ + ms_trace("Running source filter %s.",f->klass->name); + ms_filter_process(f); + } + else + { + /* make the filter process its input data until it has no more */ + while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) ) + { + ms_trace("Running filter %s.",f->klass->name); + ms_filter_process(f); + } + } + filter=g_list_next(filter); + } + ms_sync_lock(sync); + } + g_cond_signal(sync->stop_cond); /* signal that the sync thread has finished */ + ms_sync_unlock(sync); + g_message("Mediastreamer processing thread is exiting."); + return NULL; +} + +/* stop the processing chain attached to a sync source.*/ +void ms_thread_stop(MSSync *sync) +{ + if (sync->thread!=NULL) + { + if (sync->samples_per_tick==0) + { + /* to wakeup the thread */ + //g_cond_signal(sync->thread_cond); + } + g_mutex_lock(sync->lock); + sync->run=0; + sync->thread=NULL; + g_cond_wait(sync->stop_cond,sync->lock); + g_mutex_unlock(sync->lock); + } + //g_message("ms_thread_stop() finished."); +} + +/** + * ms_start: + * @sync: A synchronisation source to be started. + * + * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync. + * + * + */ +void ms_start(MSSync *sync) +{ + if (sync->run==1) return; /*already running*/ + ms_compile(sync); + ms_sync_setup(sync); + /* this is to avoid race conditions, for example: + ms_start(sync); + ms_oss_write_start(ossw); + here tge ossw filter need to be compiled to run ms_oss_write_start() + */ + ms_trace("ms_start: creating new thread."); + sync->run=1; + sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL); + if (sync->thread==NULL){ + g_warning("Could not create thread !"); + } +} + +/** + * ms_stop: + * @sync: A synchronisation source to be stopped. + * + * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync. + * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start(). + * + * + */ +void ms_stop(MSSync *sync) +{ + ms_thread_stop(sync); + ms_sync_unsetup(sync); +} + + +gint ms_load_plugin(gchar *path) +{ +#ifdef HAVE_GLIB + g_module_open(path,0); +#endif + return 0; +} + +gchar * ms_proc_get_param(gchar *parameter) +{ + gchar *file; + int fd; + int err,len; + gchar *p,*begin,*end; + gchar *ret; + fd=open("/proc/cpuinfo",O_RDONLY); + if (fd<0){ + g_warning("Could not open /proc/cpuinfo."); + return NULL; + } + file=g_malloc(1024); + err=read(fd,file,1024); + file[err-1]='\0'; + /* find the parameter */ + p=strstr(file,parameter); + if (p==NULL){ + /* parameter not found */ + g_free(file); + return NULL; + } + /* find the following ':' */ + p=strchr(p,':'); + if (p==NULL){ + g_free(file); + return NULL; + } + /* find the value*/ + begin=p+2; + end=strchr(begin,'\n'); + if (end==NULL) end=strchr(begin,'\0'); + len=end-begin+1; + ret=g_malloc(len+1); + snprintf(ret,len,"%s",begin); + //printf("%s=%s\n",parameter,ret); + g_free(file); + return ret; +} + +gint ms_proc_get_type() +{ + static int proc_type=0; + gchar *value; + if (proc_type==0){ + value=ms_proc_get_param("cpu family"); + if (value!=NULL) { + proc_type=atoi(value); + g_free(value); + }else return -1; + } + return proc_type; +} + +gint ms_proc_get_speed() +{ + char *value; + static int proc_speed=0; + if (proc_speed==0){ + value=ms_proc_get_param("cpu MHz"); + if (value!=NULL){ + proc_speed=atoi(value); + g_free(value); + }else return -1; + } + //printf("proc_speed=%i\n",proc_speed); + return proc_speed; +} + +#define PLUGINS_EXT ".so" + +typedef void (*init_func_t)(void); + +void ms_load_plugins(const char *dir){ +#ifdef HAVE_DLOPEN + DIR *ds; + struct dirent *de; + char *fullpath; + ds=opendir(dir); + if (ds==NULL){ + g_warning("Cannot open directory %s: %s",dir,strerror(errno)); + return; + } + while( (de=readdir(ds))!=NULL){ + if (de->d_type==DT_REG && strstr(de->d_name,PLUGINS_EXT)!=NULL){ + void *handle; + fullpath=g_strdup_printf("%s/%s",dir,de->d_name); + g_message("Loading plugin %s...",fullpath); + + if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){ + g_warning("Fail to load plugin %s : %s",fullpath,dlerror()); + }else { + char *initroutine_name=g_malloc0(strlen(de->d_name)+10); + char *p; + void *initroutine; + strcpy(initroutine_name,de->d_name); + p=strstr(initroutine_name,PLUGINS_EXT); + strcpy(p,"_init"); + initroutine=dlsym(handle,initroutine_name); + if (initroutine!=NULL){ + init_func_t func=(init_func_t)initroutine; + func(); + g_message("Plugin loaded."); + }else{ + g_warning("Could not locate init routine of plugin %s",de->d_name); + } + g_free(initroutine_name); + } + g_free(fullpath); + } + } + closedir(ds); +#else + g_warning("no loadable plugin support: plugins cannot be loaded."); +#endif +} diff --git a/linphone/mediastreamer/ms.h b/linphone/mediastreamer/ms.h new file mode 100644 index 000000000..b214c776a --- /dev/null +++ b/linphone/mediastreamer/ms.h @@ -0,0 +1,81 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#ifndef MS_H +#define MS_H +#include "msfilter.h" +#include "mssync.h" + + +void ms_init(); + +/* compile graphs attached to a sync source*/ +int ms_compile(MSSync *source); + + +/* stop the processing chain attached to a sync source.*/ +void ms_thread_stop(MSSync *sync); + + +/** + * function_name:ms_thread_run + * @sync: The synchronization source for all the set of graphs to run. + * + * Execute the processing chain attached to a sync source. This function loops indefinitely. + * The media streamer programmer can choose to execute this function directly, or to call ms_start(), + * that will start a thread for the synchronisation source. + * + * Returns: no return value. + */ +void *ms_thread_run(void *sync); + + +/** + * function_name:ms_start + * @sync: A synchronisation source to be started. + * + * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync. + * + * Returns: no return value. + */ +void ms_start(MSSync *sync); + + +/** + * function_name:ms_stop + * @sync: A synchronisation source to be stopped. + * + * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync. + * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start(). + * + * Returns: no return value. + */ +void ms_stop(MSSync *sync); + + +gchar * ms_proc_get_param(gchar *parameter); +gint ms_proc_get_type(); +gint ms_proc_get_speed(); + +void ms_load_plugins(const char *dir); + +#endif diff --git a/linphone/mediastreamer/msAlawdec.c b/linphone/mediastreamer/msAlawdec.c new file mode 100644 index 000000000..0ce2f4ed0 --- /dev/null +++ b/linphone/mediastreamer/msAlawdec.c @@ -0,0 +1,132 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msAlawdec.h" +#include "g711common.h" + +extern MSFilter * ms_ALAWencoder_new(void); + +MSCodecInfo ALAWinfo={ + { + "ALAW codec", + 0, + MS_FILTER_AUDIO_CODEC, + ms_ALAWencoder_new, + "This is the classic A-law codec. Good quality, but only usable with high speed network connections." + }, + ms_ALAWencoder_new, + ms_ALAWdecoder_new, + 320, + 160, + 64000, + 8000, + 8, + "PCMA", + 1, + 1, +}; + +static MSALAWDecoderClass *ms_ALAWdecoder_class=NULL; + +MSFilter * ms_ALAWdecoder_new(void) +{ + MSALAWDecoder *r; + + r=g_new(MSALAWDecoder,1); + ms_ALAWdecoder_init(r); + if (ms_ALAWdecoder_class==NULL) + { + ms_ALAWdecoder_class=g_new(MSALAWDecoderClass,1); + ms_ALAWdecoder_class_init(ms_ALAWdecoder_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWdecoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_ALAWdecoder_init(MSALAWDecoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=ALAW_DECODER_RMAXGRAN; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS); + +} + +void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWDecoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo; + MS_FILTER_CLASS(klass)->max_finputs=MSALAWDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSALAWDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=ALAW_DECODER_RMAXGRAN; + MS_FILTER_CLASS(klass)->w_maxgran=ALAW_DECODER_WMAXGRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWdecoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWdecoder_process; +} + +void ms_ALAWdecoder_process(MSALAWDecoder *r) +{ + MSFifo *fi,*fo; + int inlen,outlen; + gchar *s,*d; + int i; + /* process output fifos, but there is only one for this class of filter*/ + + /* this is the simplest process function design: + the filter declares a r_mingran of ALAW_DECODER_RMAXGRAN, so the mediastreamer's + scheduler will call the process function each time there is ALAW_DECODER_RMAXGRAN + bytes to read in the input fifo. If there is more, then it will call it several + time in order to the fifo to be completetly processed. + This is very simple, but not very efficient because of the multiple call function + of MSFilterProcessFunc that may happen. + The MSAlawEncoder implements another design; see it. + */ + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + g_return_if_fail(fi!=NULL); + g_return_if_fail(fo!=NULL); + + inlen=ms_fifo_get_read_ptr(fi,ALAW_DECODER_RMAXGRAN,(void**)&s); + if (s==NULL) return; + outlen=ms_fifo_get_write_ptr(fo,ALAW_DECODER_WMAXGRAN,(void**)&d); + if (d!=NULL) + { + for(i=0;iklass=MS_FILTER_CLASS(ms_ALAWencoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_ALAWencoder_init(MSALAWEncoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=ALAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is + something to process */ + memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS); + +} + +void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWEncoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo; + MS_FILTER_CLASS(klass)->max_finputs=MSALAWENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSALAWENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=ALAW_ENCODER_RMAXGRAN; + MS_FILTER_CLASS(klass)->w_maxgran=ALAW_ENCODER_WMAXGRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWencoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWencoder_process; +} + +void ms_ALAWencoder_process(MSALAWEncoder *r) +{ + MSFifo *fi,*fo; + int inlen,outlen; + gchar *s,*d; + int i; + /* process output fifos, but there is only one for this class of filter*/ + + /* this is the sophisticated design of the process function: + Here the filter declares that it can be called as soon as there is something + to read on the input fifo by setting r_mingran=0. + Then it ask for the fifo to get as many data as possible by calling: + inlen=ms_fifo_get_read_ptr(fi,0,(void**)&s); + This avoid multiple call to the process function to process all data available + on the input fifo... but the writing of the process function is a bit + more difficult, because althoug ms_fifo_get_read_ptr() returns N bytes, + we cannot ask ms_fifo_get_write_ptr to return N bytes if + N>MS_FILTER_CLASS(klass)->w_maxgran. This is forbidden by the MSFifo + mechanism. + This is an open issue. + For the moment what is done here is that ms_fifo_get_write_ptr() is called + several time with its maximum granularity in order to try to write the output. + ... + One solution: + -create a new function ms_fifo_get_rw_ptr(fifo1,p1, fifo2,p2) to + return the number of bytes able to being processed according to the input + and output fifo, and their respective data pointers + */ + + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + + inlen=ms_fifo_get_read_ptr(fi,ALAW_ENCODER_RMAXGRAN,(void**)&s); + if (s==NULL) return; + outlen=ms_fifo_get_write_ptr(fo,ALAW_ENCODER_WMAXGRAN,(void**)&d); + if (d!=NULL) + { + for(i=0;iklass=MS_FILTER_CLASS(ms_GSMdecoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_GSMdecoder_init(MSGSMDecoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->inqueues=r->q_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=33; + memset(r->q_inputs,0,sizeof(MSFifo*)*MSGSMDECODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSGSMDECODER_MAX_INPUTS); + r->gsm_handle=gsm_create(); +} + +void ms_GSMdecoder_class_init(MSGSMDecoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"GSMDecoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&GSMinfo; + MS_FILTER_CLASS(klass)->max_qinputs=MSGSMDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSGSMDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->w_maxgran=2*160; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_GSMdecoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_GSMdecoder_process; +} + +void ms_GSMdecoder_process(MSGSMDecoder *r) +{ + MSFifo *fo; + MSQueue *qi; + void *d; + MSMessage *inm; + + /* process output fifos, but there is only one for this class of filter*/ + + qi=r->q_inputs[0]; + fo=r->f_outputs[0]; + inm=ms_queue_get(qi); + ms_fifo_get_write_ptr(fo,160*2,&d); + if (d!=NULL) + gsm_decode(r->gsm_handle,(guchar*)inm->data,(gsm_signal*)d); + ms_message_destroy(inm); +} + +void ms_GSMdecoder_uninit(MSGSMDecoder *obj) +{ + gsm_destroy(obj->gsm_handle); +} + +void ms_GSMdecoder_destroy( MSGSMDecoder *obj) +{ + ms_GSMdecoder_uninit(obj); + g_free(obj); +} diff --git a/linphone/mediastreamer/msGSMdecoder.h b/linphone/mediastreamer/msGSMdecoder.h new file mode 100644 index 000000000..2930d8197 --- /dev/null +++ b/linphone/mediastreamer/msGSMdecoder.h @@ -0,0 +1,64 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSGSMDECODER_H +#define MSGSMDECODER_H + +#include "msfilter.h" +#include "mscodec.h" +#include + +/*this is the class that implements a GSMdecoder filter*/ + +#define MSGSMDECODER_MAX_INPUTS 1 /* max output per filter*/ + + +typedef struct _MSGSMDecoder +{ + /* the MSGSMDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMDecoder object + in order to the object mechanism to work*/ + MSFilter filter; + MSQueue *q_inputs[MSGSMDECODER_MAX_INPUTS]; + MSFifo *f_outputs[MSGSMDECODER_MAX_INPUTS]; + gsm gsm_handle; +} MSGSMDecoder; + +typedef struct _MSGSMDecoderClass +{ + /* the MSGSMDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMDecoder class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSGSMDecoderClass; + +/* PUBLIC */ +#define MS_GSMDECODER(filter) ((MSGSMDecoder*)(filter)) +#define MS_GSMDECODER_CLASS(klass) ((MSGSMDecoderClass*)(klass)) +MSFilter * ms_GSMdecoder_new(void); + +/* FOR INTERNAL USE*/ +void ms_GSMdecoder_init(MSGSMDecoder *r); +void ms_GSMdecoder_class_init(MSGSMDecoderClass *klass); +void ms_GSMdecoder_destroy( MSGSMDecoder *obj); +void ms_GSMdecoder_process(MSGSMDecoder *r); + +extern MSCodecInfo GSMinfo; + +#endif diff --git a/linphone/mediastreamer/msGSMencoder.c b/linphone/mediastreamer/msGSMencoder.c new file mode 100644 index 000000000..8c085048c --- /dev/null +++ b/linphone/mediastreamer/msGSMencoder.c @@ -0,0 +1,98 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msGSMencoder.h" +#include "mscodec.h" + +extern MSCodecInfo GSMinfo; + +static MSGSMEncoderClass *ms_GSMencoder_class=NULL; + +MSFilter * ms_GSMencoder_new(void) +{ + MSGSMEncoder *r; + + r=g_new(MSGSMEncoder,1); + ms_GSMencoder_init(r); + if (ms_GSMencoder_class==NULL) + { + ms_GSMencoder_class=g_new(MSGSMEncoderClass,1); + ms_GSMencoder_class_init(ms_GSMencoder_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_GSMencoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_GSMencoder_init(MSGSMEncoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outqueues=r->q_outputs; + MS_FILTER(r)->r_mingran=2*160; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSGSMENCODER_MAX_INPUTS); + memset(r->q_outputs,0,sizeof(MSFifo*)*MSGSMENCODER_MAX_INPUTS); + r->gsm_handle=gsm_create(); +} + +void ms_GSMencoder_class_init(MSGSMEncoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"GSMEncoder"); + MS_FILTER_CLASS(klass)->max_finputs=MSGSMENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_qoutputs=MSGSMENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=2*160; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_GSMencoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_GSMencoder_process; + MS_FILTER_CLASS(klass)->info=MS_FILTER_INFO(&GSMinfo); +} + +void ms_GSMencoder_process(MSGSMEncoder *r) +{ + MSFifo *fi; + MSQueue *qo; + int err1; + void *s; + + /* process output fifos, but there is only one for this class of filter*/ + + fi=r->f_inputs[0]; + qo=r->q_outputs[0]; + err1=ms_fifo_get_read_ptr(fi,160*2,&s); + if (err1>0){ + MSMessage *m=ms_message_new(33); + gsm_encode(r->gsm_handle,(gsm_signal*)s,(gsm_byte*)m->data); + ms_queue_put(qo,m); + } + +} + +void ms_GSMencoder_uninit(MSGSMEncoder *obj) +{ + gsm_destroy(obj->gsm_handle); +} + +void ms_GSMencoder_destroy( MSGSMEncoder *obj) +{ + ms_GSMencoder_uninit(obj); + g_free(obj); +} diff --git a/linphone/mediastreamer/msGSMencoder.h b/linphone/mediastreamer/msGSMencoder.h new file mode 100644 index 000000000..aa466a64d --- /dev/null +++ b/linphone/mediastreamer/msGSMencoder.h @@ -0,0 +1,61 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSGSMENCODER_H +#define MSGSMENCODER_H + +#include "msfilter.h" +#include + +/*this is the class that implements a GSMencoder filter*/ + +#define MSGSMENCODER_MAX_INPUTS 1 /* max output per filter*/ + + +typedef struct _MSGSMEncoder +{ + /* the MSGSMEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMEncoder object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MSGSMENCODER_MAX_INPUTS]; + MSQueue *q_outputs[MSGSMENCODER_MAX_INPUTS]; + gsm gsm_handle; +} MSGSMEncoder; + +typedef struct _MSGSMEncoderClass +{ + /* the MSGSMEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMEncoder class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSGSMEncoderClass; + +/* PUBLIC */ +#define MS_GSMENCODER(filter) ((MSGSMEncoder*)(filter)) +#define MS_GSMENCODER_CLASS(klass) ((MSGSMEncoderClass*)(klass)) +MSFilter * ms_GSMencoder_new(void); + +/* FOR INTERNAL USE*/ +void ms_GSMencoder_init(MSGSMEncoder *r); +void ms_GSMencoder_class_init(MSGSMEncoderClass *klass); +void ms_GSMencoder_destroy( MSGSMEncoder *obj); +void ms_GSMencoder_process(MSGSMEncoder *r); + +#endif diff --git a/linphone/mediastreamer/msLPC10decoder.c b/linphone/mediastreamer/msLPC10decoder.c new file mode 100644 index 000000000..1d398bea9 --- /dev/null +++ b/linphone/mediastreamer/msLPC10decoder.c @@ -0,0 +1,129 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msLPC10decoder.h" +#include "msLPC10encoder.h" +#include +#include + +extern MSFilter * ms_LPC10encoder_new(void); + +MSCodecInfo LPC10info={ + { + "LPC10-15 codec", + 0, + MS_FILTER_AUDIO_CODEC, + ms_LPC10encoder_new, + "A low quality but very low bit rate codec from the U.S. Department of Defense." + }, + ms_LPC10encoder_new, + ms_LPC10decoder_new, + 360, + 7, + 2400, + 8000, + 115, + "1015", + 1, + 1, +}; + +static MSLPC10DecoderClass *ms_LPC10decoder_class=NULL; + +MSFilter * ms_LPC10decoder_new(void) +{ + MSLPC10Decoder *r; + + r=g_new(MSLPC10Decoder,1); + ms_LPC10decoder_init(r); + if (ms_LPC10decoder_class==NULL) + { + ms_LPC10decoder_class=g_new(MSLPC10DecoderClass,1); + ms_LPC10decoder_class_init(ms_LPC10decoder_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_LPC10decoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_LPC10decoder_init(MSLPC10Decoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=7; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSLPC10DECODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSLPC10DECODER_MAX_INPUTS); + r->lpc10_dec=create_lpc10_decoder_state(); +} + +void ms_LPC10decoder_class_init(MSLPC10DecoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"LPC10Dec"); + MS_FILTER_CLASS(klass)->max_finputs=MSLPC10DECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSLPC10DECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=7; + MS_FILTER_CLASS(klass)->w_maxgran=LPC10_SAMPLES_PER_FRAME*2; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_LPC10decoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_LPC10decoder_process; + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&LPC10info; +} + +void ms_LPC10decoder_process(MSLPC10Decoder *r) +{ + MSFifo *fi,*fo; + int err1; + void *s,*d; + float speech[LPC10_SAMPLES_PER_FRAME]; + INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; + + /* process output fifos, but there is only one for this class of filter*/ + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + if (fi!=NULL) + { + err1=ms_fifo_get_read_ptr(fi,7,&s); + if (err1>0) + { + err1=ms_fifo_get_write_ptr(fo,LPC10_SAMPLES_PER_FRAME*2,&d); + if (d!=NULL) + { + read_bits(s, bits, LPC10_BITS_IN_COMPRESSED_FRAME); + lpc10_decode(bits,speech, r->lpc10_dec); + write_16bit_samples((INT16*)d, speech, LPC10_SAMPLES_PER_FRAME); + } + } + } +} + +void ms_LPC10decoder_uninit(MSLPC10Decoder *obj) +{ + free(obj->lpc10_dec); +} + +void ms_LPC10decoder_destroy( MSLPC10Decoder *obj) +{ + ms_LPC10decoder_uninit(obj); + g_free(obj); +} diff --git a/linphone/mediastreamer/msLPC10decoder.h b/linphone/mediastreamer/msLPC10decoder.h new file mode 100644 index 000000000..59d9deca4 --- /dev/null +++ b/linphone/mediastreamer/msLPC10decoder.h @@ -0,0 +1,64 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSLPC10DECODER_H +#define MSLPC10DECODER_H + +#include +#include +#include + +/*this is the class that implements a LPC10decoder filter*/ + +#define MSLPC10DECODER_MAX_INPUTS 1 /* max output per filter*/ + + +typedef struct _MSLPC10Decoder +{ + /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Decoder object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MSLPC10DECODER_MAX_INPUTS]; + MSFifo *f_outputs[MSLPC10DECODER_MAX_INPUTS]; + struct lpc10_decoder_state *lpc10_dec; +} MSLPC10Decoder; + +typedef struct _MSLPC10DecoderClass +{ + /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Decoder class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSLPC10DecoderClass; + +/* PUBLIC */ +#define MS_LPC10DECODER(filter) ((MSLPC10Decoder*)(filter)) +#define MS_LPC10DECODER_CLASS(klass) ((MSLPC10DecoderClass*)(klass)) +MSFilter * ms_LPC10decoder_new(void); + +/* FOR INTERNAL USE*/ +void ms_LPC10decoder_init(MSLPC10Decoder *r); +void ms_LPC10decoder_class_init(MSLPC10DecoderClass *klass); +void ms_LPC10decoder_destroy( MSLPC10Decoder *obj); +void ms_LPC10decoder_process(MSLPC10Decoder *r); + +extern MSCodecInfo LPC10info; + +#endif diff --git a/linphone/mediastreamer/msLPC10encoder.c b/linphone/mediastreamer/msLPC10encoder.c new file mode 100644 index 000000000..2c083f364 --- /dev/null +++ b/linphone/mediastreamer/msLPC10encoder.c @@ -0,0 +1,251 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "msLPC10encoder.h" +#include + + +extern MSCodecInfo LPC10info; + +/* The return value of each of these calls is the same as that + returned by fread/fwrite, which should be the number of samples + successfully read/written, not the number of bytes. */ + +int +read_16bit_samples(INT16 int16samples[], float speech[], int n) +{ + int i; + + /* Convert 16 bit integer samples to floating point values in the + range [-1,+1]. */ + + for (i = 0; i < n; i++) { + speech[i] = ((float) int16samples[i]) / 32768.0; + } + + return (n); +} + + + +int +write_16bit_samples(INT16 int16samples[], float speech[], int n) +{ + int i; + float real_sample; + + /* Convert floating point samples in range [-1,+1] to 16 bit + integers. */ + for (i = 0; i < n; i++) { + real_sample = 32768.0 * speech[i]; + if (real_sample < -32768.0) { + int16samples[i] = -32768; + } else if (real_sample > 32767.0) { + int16samples[i] = 32767; + } else { + int16samples[i] = real_sample; + } + } + return (n); +} + +/* + +Write the bits in bits[0] through bits[len-1] to file f, in "packed" +format. + +bits is expected to be an array of len integer values, where each +integer is 0 to represent a 0 bit, and any other value represents a 1 +bit. This bit string is written to the file f in the form of several +8 bit characters. If len is not a multiple of 8, then the last +character is padded with 0 bits -- the padding is in the least +significant bits of the last byte. The 8 bit characters are "filled" +in order from most significant bit to least significant. + +*/ + +void +write_bits(unsigned char *data, INT32 *bits, int len) +{ + int i; /* generic loop variable */ + unsigned char mask; /* The next bit position within the + variable "data" to place the next + bit. */ + + + /* Fill in the array bits. + * The first compressed output bit will be the most significant + * bit of the byte, so initialize mask to 0x80. The next byte of + * compressed data is initially 0, and the desired bits will be + * turned on below. + */ + mask = 0x80; + *data = 0; + + for (i = 0; i < len; i++) { + /* Turn on the next bit of output data, if necessary. */ + if (bits[i]) { + (*data) |= mask; + } + /* + * If the byte data is full, determined by mask becoming 0, + * then write the byte to the output file, and reinitialize + * data and mask for the next output byte. Also add the byte + * if (i == len-1), because if len is not a multiple of 8, + * then mask won't yet be 0. */ + mask >>= 1; + if ((mask == 0) || (i == len-1)) { + data++; + *data = 0; + mask = 0x80; + } + } +} + + + +/* + +Read bits from file f into bits[0] through bits[len-1], in "packed" +format. + +Read ceiling(len/8) characters from file f, if that many are available +to read, otherwise read to the end of the file. The first character's +8 bits, in order from MSB to LSB, are used to fill bits[0] through +bits[7]. The second character's bits are used to fill bits[8] through +bits[15], and so on. If ceiling(len/8) characters are available to +read, and len is not a multiple of 8, then some of the least +significant bits of the last character read are completely ignored. +Every entry of bits[] that is modified is changed to either a 0 or a +1. + +The number of bits successfully read is returned, and is always in the +range 0 to len, inclusive. If it is less than len, it will always be +a multiple of 8. + +*/ + +int +read_bits(unsigned char *data, INT32 *bits, int len) +{ + int i,ind=0; /* generic loop variable */ + int c=0; + + /* Unpack the array bits into coded_frame. */ + for (i = 0; i < len; i++) { + if ((i % 8) == 0) { + c = (int)(data[ind]); + ind++; + } + if (c & (0x80 >> (i & 7))) { + bits[i] = 1; + } else { + bits[i] = 0; + } + } + return (len); +} + + + + +static MSLPC10EncoderClass *ms_LPC10encoder_class=NULL; + +MSFilter * ms_LPC10encoder_new(void) +{ + MSLPC10Encoder *r; + + r=g_new(MSLPC10Encoder,1); + ms_LPC10encoder_init(r); + if (ms_LPC10encoder_class==NULL) + { + ms_LPC10encoder_class=g_new(MSLPC10EncoderClass,1); + ms_LPC10encoder_class_init(ms_LPC10encoder_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_LPC10encoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_LPC10encoder_init(MSLPC10Encoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=LPC10_SAMPLES_PER_FRAME*2; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSLPC10ENCODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSLPC10ENCODER_MAX_INPUTS); + r->lpc10_enc=create_lpc10_encoder_state(); +} + +void ms_LPC10encoder_class_init(MSLPC10EncoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"LPC10Enc"); + MS_FILTER_CLASS(klass)->max_finputs=MSLPC10ENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSLPC10ENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=LPC10_SAMPLES_PER_FRAME*2; + MS_FILTER_CLASS(klass)->w_maxgran=7; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_LPC10encoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_LPC10encoder_process; + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&LPC10info; +} + +void ms_LPC10encoder_process(MSLPC10Encoder *r) +{ + MSFifo *fi,*fo; + int err1; + void *s,*d; + float speech[LPC10_SAMPLES_PER_FRAME]; + INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; + + /* process output fifos, but there is only one for this class of filter*/ + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + if (fi!=NULL) + { + err1=ms_fifo_get_read_ptr(fi,LPC10_SAMPLES_PER_FRAME*2,&s); + if (err1>0) + { + err1=ms_fifo_get_write_ptr(fo,7,&d); + if (d!=NULL) + { + read_16bit_samples((INT16*)s, speech, LPC10_SAMPLES_PER_FRAME); + lpc10_encode(speech, bits, r->lpc10_enc); + write_bits(d, bits, LPC10_BITS_IN_COMPRESSED_FRAME); + } + } + + } +} + +void ms_LPC10encoder_uninit(MSLPC10Encoder *obj) +{ + free(obj->lpc10_enc); +} + +void ms_LPC10encoder_destroy( MSLPC10Encoder *obj) +{ + ms_LPC10encoder_uninit(obj); + g_free(obj); +} diff --git a/linphone/mediastreamer/msLPC10encoder.h b/linphone/mediastreamer/msLPC10encoder.h new file mode 100644 index 000000000..4db164366 --- /dev/null +++ b/linphone/mediastreamer/msLPC10encoder.h @@ -0,0 +1,74 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSLPC10ENCODER_H +#define MSLPC10ENCODER_H + +#include "mscodec.h" + + +int +read_16bit_samples(gint16 int16samples[], float speech[], int n); + +int +write_16bit_samples(gint16 int16samples[], float speech[], int n); + +void +write_bits(unsigned char *data, gint32 *bits, int len); + +int +read_bits(unsigned char *data, gint32 *bits, int len); + + +/*this is the class that implements a LPC10encoder filter*/ + +#define MSLPC10ENCODER_MAX_INPUTS 1 /* max output per filter*/ + + +typedef struct _MSLPC10Encoder +{ + /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Encoder object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MSLPC10ENCODER_MAX_INPUTS]; + MSFifo *f_outputs[MSLPC10ENCODER_MAX_INPUTS]; + struct lpc10_encoder_state *lpc10_enc; +} MSLPC10Encoder; + +typedef struct _MSLPC10EncoderClass +{ + /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Encoder class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSLPC10EncoderClass; + +/* PUBLIC */ +#define MS_LPC10ENCODER(filter) ((MSLPC10Encoder*)(filter)) +#define MS_LPC10ENCODER_CLASS(klass) ((MSLPC10EncoderClass*)(klass)) +MSFilter * ms_LPC10encoder_new(void); + +/* FOR INTERNAL USE*/ +void ms_LPC10encoder_init(MSLPC10Encoder *r); +void ms_LPC10encoder_class_init(MSLPC10EncoderClass *klass); +void ms_LPC10encoder_destroy( MSLPC10Encoder *obj); +void ms_LPC10encoder_process(MSLPC10Encoder *r); + +#endif diff --git a/linphone/mediastreamer/msMUlawdec.c b/linphone/mediastreamer/msMUlawdec.c new file mode 100644 index 000000000..e15260c8a --- /dev/null +++ b/linphone/mediastreamer/msMUlawdec.c @@ -0,0 +1,130 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msMUlawdec.h" +#include "g711common.h" + +extern MSFilter * ms_MULAWencoder_new(void); + +MSCodecInfo MULAWinfo={ + { + "MULAW codec", + 0, + MS_FILTER_AUDIO_CODEC, + ms_MULAWencoder_new, + "This is the classic Mu-law codec. Good quality, but only usable with high speed network connections." + }, + ms_MULAWencoder_new, + ms_MULAWdecoder_new, + 320, + 160, + 64000, + 8000, + 0, + "PCMU", + 1, + 1 +}; + +static MSMULAWDecoderClass *ms_MULAWdecoder_class=NULL; + +MSFilter * ms_MULAWdecoder_new(void) +{ + MSMULAWDecoder *r; + + r=g_new(MSMULAWDecoder,1); + ms_MULAWdecoder_init(r); + if (ms_MULAWdecoder_class==NULL) + { + ms_MULAWdecoder_class=g_new(MSMULAWDecoderClass,1); + ms_MULAWdecoder_class_init(ms_MULAWdecoder_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWdecoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_MULAWdecoder_init(MSMULAWDecoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=MULAW_DECODER_RMAXGRAN; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS); + +} + +void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWDecoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo; + MS_FILTER_CLASS(klass)->max_finputs=MSMULAWDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=MULAW_DECODER_RMAXGRAN; + MS_FILTER_CLASS(klass)->w_maxgran=MULAW_DECODER_WMAXGRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWdecoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWdecoder_process; +} + +void ms_MULAWdecoder_process(MSMULAWDecoder *r) +{ + MSFifo *fi,*fo; + int inlen,outlen; + gchar *s,*d; + int i; + /* process output fifos, but there is only one for this class of filter*/ + + /* this is the simplest process function design: + the filter declares a r_mingran of MULAW_DECODER_RMAXGRAN, so the mediastreamer's + scheduler will call the process function each time there is MULAW_DECODER_RMAXGRAN + bytes to read in the input fifo. If there is more, then it will call it several + time in order to the fifo to be completetly processed. + This is very simple, but not very efficient because of the multiple call function + of MSFilterProcessFunc that may happen. + The MSAlawEncoder implements another design; see it. + */ + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + + inlen=ms_fifo_get_read_ptr(fi,MULAW_DECODER_RMAXGRAN,(void**)&s); + if (s==NULL) g_error("ms_MULAWdecoder_process: internal error."); + outlen=ms_fifo_get_write_ptr(fo,MULAW_DECODER_WMAXGRAN,(void**)&d); + if (d!=NULL) + { + for(i=0;iklass=MS_FILTER_CLASS(ms_MULAWencoder_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_MULAWencoder_init(MSMULAWEncoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=MULAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is + something to process */ + memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS); + +} + +void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWEncoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo; + MS_FILTER_CLASS(klass)->max_finputs=MSMULAWENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=MULAW_ENCODER_RMAXGRAN; + MS_FILTER_CLASS(klass)->w_maxgran=MULAW_ENCODER_WMAXGRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWencoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWencoder_process; +} + +void ms_MULAWencoder_process(MSMULAWEncoder *r) +{ + MSFifo *fi,*fo; + int inlen,outlen; + gchar *s,*d; + int i; + /* process output fifos, but there is only one for this class of filter*/ + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + inlen=ms_fifo_get_read_ptr(fi,MULAW_ENCODER_RMAXGRAN,(void**)&s); + outlen=ms_fifo_get_write_ptr(fo,MULAW_ENCODER_WMAXGRAN,(void**)&d); + if (d!=NULL) + { + for(i=0;i + +#include "msavdecoder.h" +#include "mscodec.h" +#include "rfc2429.h" + +extern MSFilter *ms_mpeg_encoder_new(); +extern MSFilter *ms_mpeg4_encoder_new(); +extern MSFilter *ms_h263p_encoder_new(); + + +MSCodecInfo MPEGinfo={ + { + "MPEG1 codec", + 0, + MS_FILTER_VIDEO_CODEC, + ms_mpeg_encoder_new, + "This is a MPEG1 codec taken from the ffmpeg project." + }, + ms_mpeg_encoder_new, + ms_mpeg_decoder_new, + 0, + 0, + 0, /*bitrate */ + 0, /*sample freq */ + 0, + "MPV", + 1, + 1 +}; + +MSCodecInfo h263pinfo={ + { + "H263 codec", + 0, + MS_FILTER_VIDEO_CODEC, + ms_h263p_encoder_new, + "This is a H263 codec taken from the ffmpeg project." + }, + ms_h263p_encoder_new, + ms_h263p_decoder_new, + 0, + 0, + 0, /*bitrate */ + 0, /*sample freq */ + 0, + "H263-1998", + 1, + 1 +}; + +MSCodecInfo MPEG4info={ + { + "MPEG4 codec", + 0, + MS_FILTER_VIDEO_CODEC, + ms_mpeg4_encoder_new, + "This is a MPEG4 codec taken from the ffmpeg project." + }, + ms_mpeg4_encoder_new, + ms_mpeg4_decoder_new, + 0, + 0, + 0, /*bitrate */ + 0, /*sample freq */ + 0, + "MP4V-ES", + 1, + 1 +}; + + +void ms_AVCodec_init() +{ + avcodec_init(); + avcodec_register_all(); + ms_filter_register((MSFilterInfo*)&h263pinfo); + //ms_filter_register((MSFilterInfo*)&MPEG4info); +} + + +static MSAVDecoderClass *ms_avdecoder_class=NULL; + +MSFilter *ms_mpeg_decoder_new() +{ + return ms_AVdecoder_new_with_codec(CODEC_ID_MPEG1VIDEO); +} + +MSFilter *ms_mpeg4_decoder_new() +{ + return ms_AVdecoder_new_with_codec(CODEC_ID_MPEG4); +} + +MSFilter *ms_h263p_decoder_new(){ + /* H263P decoder doesn't exist in libavcodec...*/ + return ms_AVdecoder_new_with_codec(CODEC_ID_H263); +} + +MSFilter * ms_AVdecoder_new_with_codec(enum CodecID codec_id) +{ + MSAVDecoder *enc; + + enc=g_malloc0(sizeof(MSAVDecoder)); + if (ms_avdecoder_class==NULL) + { + ms_avdecoder_class=g_malloc0(sizeof(MSAVDecoderClass)); + ms_AVdecoder_class_init(ms_avdecoder_class); + } + MS_FILTER(enc)->klass=(MSFilterClass*)ms_avdecoder_class; + ms_AVdecoder_init(enc,avcodec_find_decoder(codec_id)); + return MS_FILTER(enc); +} + + +void ms_AVdecoder_init(MSAVDecoder *dec, AVCodec *codec) +{ + gint error; + + ms_filter_init(MS_FILTER(dec)); + MS_FILTER(dec)->inqueues=dec->q_inputs; + MS_FILTER(dec)->outqueues=dec->q_outputs; + avcodec_get_context_defaults(&dec->av_context); + ms_AVdecoder_set_width(dec,VIDEO_SIZE_CIF_W); + ms_AVdecoder_set_height(dec,VIDEO_SIZE_CIF_H); + dec->av_codec=codec; + dec->av_opened=0; + dec->skip_gob=1; + dec->obufwrap=NULL; + dec->buf_size=0; +} + +void ms_AVdecoder_class_init(MSAVDecoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name( MS_FILTER_CLASS(klass),"AVdecoder"); + MS_FILTER_CLASS(klass)->max_qinputs=MSAVDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_qoutputs=MSAVDECODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=0; + MS_FILTER_CLASS(klass)->w_maxgran=0; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_AVdecoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_AVdecoder_process; +} + +void ms_AVdecoder_uninit(MSAVDecoder *dec) +{ + if (dec->obufwrap!=NULL) ms_buffer_destroy(dec->obufwrap); + if (dec->av_opened) avcodec_close(&dec->av_context); +} +void ms_AVdecoder_destroy( MSAVDecoder *obj) +{ + ms_AVdecoder_uninit(obj); + g_free(obj); +} + +gint ms_AVdecoder_set_format(MSAVDecoder *dec, gchar *fmt) +{ + gint format; + if (strcmp(fmt,"YUV420P")==0) format=PIX_FMT_YUV420P; + else if (strcmp(fmt,"YUV422")==0) format=PIX_FMT_YUV422; + else if (strcmp(fmt,"RGB24")==0) format=PIX_FMT_RGB24; + else if (strcmp(fmt,"BGR24")==0) format=PIX_FMT_BGR24; + else if (strcmp(fmt,"YUV422P")==0) format=PIX_FMT_YUV422P; + else if (strcmp(fmt,"YUV444P")==0) format=PIX_FMT_YUV444P; + else { + g_warning("ms_AVdecoder_set_format: unsupported format %s.",fmt); + return -1; + } + dec->output_pix_fmt=format; + return 0; +} + +void ms_AVdecoder_process(MSAVDecoder *r) +{ + AVFrame orig; + AVFrame transformed; + MSQueue *inq,*outq; + MSMessage *inm,*outm; + gint error; + gint got_picture; + gint len; + unsigned char *data; + AVCodecContext *ctx=&r->av_context; + gint gob_num; + + inq=r->q_inputs[0]; + outq=r->q_outputs[0]; + + /* get a picture from the input queue */ + inm=ms_queue_get(inq); + g_return_if_fail(inm!=NULL); + if (inm->size >= 2) + { + guint32 *p = (guint32*)inm->data; + char *ph=inm->data; + int PLEN; + gboolean P; + if (!r->av_opened){ + error=avcodec_open(&r->av_context, r->av_codec); + if (error!=0) g_warning("avcodec_open() failed: %i",error); + else r->av_opened=1; + } + P=rfc2429_get_P(ph); + PLEN=rfc2429_get_PLEN(ph); + /*printf("receiving new packet; P=%i; V=%i; PLEN=%i; PEBIT=%i\n",P,rfc2429_get_V(ph),PLEN,rfc2429_get_PEBIT(ph)); + */ + gob_num = (ntohl(*p) >> 10) & 0x1f; + ms_trace("gob %i, size %i", gob_num, inm->size); + ms_trace("ms_AVdecoder_process: received %08x %08x", ntohl(p[0]), ntohl(p[1])); + + /* remove H.263 Payload Header */ + if (PLEN>0){ + /* we ignore the redundant picture header and + directly go to the bitstream */ + inm->data+=PLEN; + inm->size-=PLEN; + } + if (P){ + inm->data[0]=inm->data[1]=0; + }else{ + /* no PSC omitted */ + inm->data+=2; + inm->size-=2; + } + + /* accumulate the video packet until we have the rtp markbit*/ + memcpy(r->buf_compressed + r->buf_size, inm->data, inm->size); + r->buf_size += inm->size; + + if (inm->markbit) + { + unsigned char *data = r->buf_compressed; + ms_trace("ms_AVdecoder_process: decoding %08x %08x %08x", ntohl(((unsigned int *)data)[0]), ntohl(((unsigned int *)data)[1]), ntohl(((unsigned int *)data)[2])); + while (r->buf_size > 0) { + len=avcodec_decode_video(&r->av_context,&orig,&got_picture,data,r->buf_size ); + if (len<0) { + ms_warning("ms_AVdecoder_process: error %i.",len); + break; + } + if (got_picture) { + /*g_message("ms_AVdecoder_process: got_picture: width=%i height=%i fmt=%i", + ctx->width,ctx->height,ctx->pix_fmt);*/ + /* set the image in the wanted format */ + outm=ms_message_alloc(); + if (r->obufwrap==NULL){ + r->obufwrap=ms_buffer_new(avpicture_get_size(r->output_pix_fmt,r->width,r->height)); + r->obufwrap->ref_count++; + } + ms_message_set_buf(outm,r->obufwrap); + avpicture_fill(&transformed,(unsigned char *)outm->data,r->output_pix_fmt,r->width,r->height); + img_convert(&transformed, r->output_pix_fmt, + &orig,ctx->pix_fmt,ctx->width,ctx->height); + ms_queue_put(outq,outm); + } + r->buf_size -= len; + data += len; + } + r->buf_size=0; + } + } + ms_message_destroy(inm); +} + + +void ms_AVdecoder_set_width(MSAVDecoder *av,gint w) +{ + /*av->av_context.width=av->width=w;*/ + av->width=w; +} + +void ms_AVdecoder_set_height(MSAVDecoder *av,gint h) +{ + /*av->av_context.height=av->height=h;*/ + av->height=h; +} diff --git a/linphone/mediastreamer/msavdecoder.h b/linphone/mediastreamer/msavdecoder.h new file mode 100644 index 000000000..ca449793a --- /dev/null +++ b/linphone/mediastreamer/msavdecoder.h @@ -0,0 +1,87 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSAVDECODER_H +#define MSAVDECODER_H + +#include "msfilter.h" + + +#include + +/*this is the class that implements a AVdecoder filter*/ + +#define MSAVDECODER_MAX_INPUTS 1 /* max output per filter*/ + + +struct _MSAVDecoder +{ + /* the MSAVDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVDecoder object + in order to the object mechanism to work*/ + MSFilter filter; + MSQueue *q_inputs[MSAVDECODER_MAX_INPUTS]; + MSQueue *q_outputs[MSAVDECODER_MAX_INPUTS]; + AVCodec *av_codec; /*the AVCodec from which this MSFilter is related */ + AVCodecContext av_context; /* the context of the AVCodec */ + gint av_opened; + int output_pix_fmt; + int width; + int height; + int skip_gob; + unsigned char buf_compressed[100000]; + int buf_size; + MSBuffer *obufwrap; /* alternate buffer, when format change is needed*/ +}; + +typedef struct _MSAVDecoder MSAVDecoder; + +struct _MSAVDecoderClass +{ + /* the MSAVDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVDecoder class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +}; + +typedef struct _MSAVDecoderClass MSAVDecoderClass; + +/* PUBLIC */ +#define MS_AVDECODER(filter) ((MSAVDecoder*)(filter)) +#define MS_AVDECODER_CLASS(klass) ((MSAVDecoderClass*)(klass)) + +MSFilter *ms_h263p_decoder_new(); +MSFilter *ms_mpeg_decoder_new(); +MSFilter *ms_mpeg4_decoder_new(); +MSFilter * ms_AVdecoder_new_with_codec(enum CodecID codec_id); + +gint ms_AVdecoder_set_format(MSAVDecoder *dec, gchar *fmt); +void ms_AVdecoder_set_width(MSAVDecoder *av,gint w); +void ms_AVdecoder_set_height(MSAVDecoder *av,gint h); + +/* FOR INTERNAL USE*/ +void ms_AVdecoder_init(MSAVDecoder *r, AVCodec *codec); +void ms_AVdecoder_uninit(MSAVDecoder *enc); +void ms_AVdecoder_class_init(MSAVDecoderClass *klass); +void ms_AVdecoder_destroy( MSAVDecoder *obj); +void ms_AVdecoder_process(MSAVDecoder *r); + +void ms_AVCodec_init(); + +#endif diff --git a/linphone/mediastreamer/msavencoder.c b/linphone/mediastreamer/msavencoder.c new file mode 100644 index 000000000..85a45cfa6 --- /dev/null +++ b/linphone/mediastreamer/msavencoder.c @@ -0,0 +1,258 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msavencoder.h" +#include "msutils.h" + +#ifdef _WIN32 +#include +#else +#include /* ntohl(3) */ +#endif + +extern MSCodecInfo MPEG4info; +extern MSCodecInfo MPEGinfo; +extern MSCodecInfo h263pinfo; + +static MSAVEncoderClass *ms_avencoder_class=NULL; +static void ms_AVencoder_rtp_callback (AVCodecContext *ctx,void *data, int size, int packet_number); + +MSFilter *ms_h263p_encoder_new() +{ + /* temporily prefer CODEC_ID_H263 to CODEC_ID_H263P since + ffmpeg does not comply to H233P at profile=0. + */ + return ms_AVencoder_new_with_codec(CODEC_ID_H263P,&h263pinfo); +} + +MSFilter *ms_mpeg_encoder_new() +{ + return ms_AVencoder_new_with_codec(CODEC_ID_MPEG1VIDEO, &MPEGinfo); +} + +MSFilter *ms_mpeg4_encoder_new() +{ + return ms_AVencoder_new_with_codec(CODEC_ID_MPEG4,&MPEG4info); +} + +MSFilter * ms_AVencoder_new_with_codec(enum CodecID codec_id, MSCodecInfo *info) +{ + MSAVEncoder *enc; + AVCodec *avc; + enc=g_malloc0(sizeof(MSAVEncoder)); + if (ms_avencoder_class==NULL) + { + ms_avencoder_class=g_malloc0(sizeof(MSAVEncoderClass)); + ms_AVencoder_class_init(ms_avencoder_class); + } + MS_FILTER(enc)->klass=(MSFilterClass*)ms_avencoder_class; + avc=avcodec_find_encoder(codec_id); + if (avc==NULL) g_error("unknown av codec."); + ms_AVencoder_init(enc,avc); + return MS_FILTER(enc); +} + + +void ms_AVencoder_init(MSAVEncoder *enc, AVCodec *codec) +{ + AVCodecContext *c=&enc->av_context; + + ms_filter_init(MS_FILTER(enc)); + MS_FILTER(enc)->inqueues=enc->q_inputs; + MS_FILTER(enc)->outqueues=enc->q_outputs; + /* put default values */ + memset(c, 0, sizeof(AVCodecContext)); + avcodec_get_context_defaults(c); + + /* put sample parameters */ + c->bit_rate = 50000; + /* resolution must be a multiple of two */ + c->width = VIDEO_SIZE_CIF_W; + c->height = VIDEO_SIZE_CIF_H; + ms_AVencoder_set_frame_rate(enc,15,1); + c->gop_size = 10; /* emit one intra frame every x frames */ + c->rtp_mode = 1; + c->rtp_payload_size = 1000; + c->opaque = (void *) enc; + c->rtp_callback = ms_AVencoder_rtp_callback; + c->pix_fmt=PIX_FMT_YUV420P; + + enc->av_opened=0; + enc->av_codec=codec; + enc->yuv_buf=NULL; + enc->comp_buf=NULL; + /*set default input format */ + ms_AVencoder_set_format(enc,"RGB24"); + enc->outm=NULL; +} + +void ms_AVencoder_class_init(MSAVEncoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + MS_FILTER_CLASS(klass)->info=0; + MS_FILTER_CLASS(klass)->max_qinputs=MSAVENCODER_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_qoutputs=MSAVENCODER_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=0; + MS_FILTER_CLASS(klass)->w_maxgran=0; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_AVencoder_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_AVencoder_process; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"AVEncoder"); + +} + +void ms_AVencoder_uninit(MSAVEncoder *enc) +{ + if (enc->av_opened) + avcodec_close(&enc->av_context); + if (enc->comp_buf!=NULL) { + ms_buffer_destroy(enc->comp_buf); + enc->comp_buf=NULL; + } + if (enc->yuv_buf!=NULL) { + ms_buffer_destroy(enc->yuv_buf); + enc->yuv_buf=NULL; + } + if (enc->outm!=NULL) ms_message_destroy(enc->outm); + +} +void ms_AVencoder_destroy( MSAVEncoder *obj) +{ + ms_AVencoder_uninit(obj); + g_free(obj); +} + + +void ms_AVencoder_set_frame_rate(MSAVEncoder *obj, gint frame_rate, gint frame_rate_base) +{ + obj->av_context.time_base.num = frame_rate; + obj->av_context.time_base.den = frame_rate_base; +} + +static void ms_AVencoder_rtp_callback (AVCodecContext *ctx, void *data, int size, int packet_number) +{ + MSAVEncoder *r = MS_AVENCODER(ctx->opaque); + MSQueue *outq = r->q_outputs[0]; + MSMessage *outm; + MSMessage *prev_outm=r->outm; + guint32 *p = (guint32 *) data; + gint gob_num = (ntohl(*p) >> 10) & 0x1f; + + /*g_message("ms_AVencoder_rtp_callback: packet %i, size %i, GOB number %i", packet_number, size, gob_num);*/ + ms_trace("ms_AVencoder_rtp_callback: received %08x %08x", ntohl(p[0]), ntohl(p[1])); + /* set the H.263 Payload Header (RFC 2429) ie H263-1998 */ + p[0] = ntohl( (0x04000000) | (ntohl(p[0]) & 0x0000ffff) ); /* P=1, V=0, PLEN=0 */ + ms_trace("ms_AVencoder_rtp_callback: sending %08x %08x", ntohl(p[0]), ntohl(p[1])); + outm = ms_message_new(size); + memcpy(outm->data,data,size); + r->outm=outm; + + /*g_message("output video packet of size %i",size);*/ + if (prev_outm) { + if (gob_num==0) prev_outm->markbit=TRUE; + ms_queue_put(outq, prev_outm); + } +} + +void ms_AVencoder_process(MSAVEncoder *r) +{ + AVFrame orig; + AVFrame pict; + AVCodecContext *c=&r->av_context; + MSQueue *inq,*outq; + MSMessage *inm,*outm; + gint error; + + inq=r->q_inputs[0]; + outq=r->q_outputs[0]; + + /* get a picture from the input queue */ + inm=ms_queue_get(inq); + g_return_if_fail(inm!=NULL); + + /* allocate a new image */ + if (r->yuv_buf==NULL){ + gint bsize = avpicture_get_size(c->pix_fmt,c->width,c->height); + r->yuv_buf=ms_buffer_new(bsize); + r->yuv_buf->ref_count++; + + r->comp_buf=ms_buffer_new(bsize/2); + r->comp_buf->ref_count++; + } + if (!r->av_opened || r->av_context.codec == NULL){ + error=avcodec_open(c, r->av_codec); + ms_trace("image format is %i.",c->pix_fmt); + if (error!=0) { + g_warning("avcodec_open() failed: %i",error); + return; + }else r->av_opened=1; + } + outm=ms_message_alloc(); + /* convert image if necessary */ + if (r->input_pix_fmt!=c->pix_fmt){ + ms_trace("Changing picture format."); + avpicture_fill((AVPicture*)&orig,inm->data,r->input_pix_fmt,c->width,c->height); + avpicture_fill((AVPicture*)&pict,r->yuv_buf->buffer,c->pix_fmt,c->width,c->height); + if (img_convert((AVPicture*)&pict,c->pix_fmt,(AVPicture*)&orig,r->input_pix_fmt,c->width,c->height) < 0) { + g_warning("img_convert failed"); + return; + } + //if (pict.data[0]==NULL) g_error("img_convert failed."); + ms_message_set_buf(outm,r->yuv_buf); + } + else + { + avpicture_fill((AVPicture*)&pict,inm->data,c->pix_fmt,c->width,c->height); + ms_message_set_buf(outm,inm->buffer); + } + /* timestamp used by ffmpeg, unset here */ + pict.pts=AV_NOPTS_VALUE; + error=avcodec_encode_video(c, r->comp_buf->buffer, r->comp_buf->size, &pict); + if (error<=0) ms_warning("ms_AVencoder_process: error %i.",error); + else { + ms_trace("ms_AVencoder_process: video encoding done"); + /* set the mark bit on the last packet, which contains the end of the frame */ + /* + MSMessage *last=ms_queue_peek_last(r->q_outputs[0]); + if (last!=NULL) last->markbit=TRUE; + else g_warning("No last packet ?"); + */ + } + if (r->q_outputs[1]!=NULL) ms_queue_put(r->q_outputs[1],outm); + else ms_message_destroy(outm); + ms_message_destroy(inm); +} + +gint ms_AVencoder_set_format(MSAVEncoder *enc, gchar *fmt) +{ + gint format; + if (strcmp(fmt,"YUV420P")==0) format=PIX_FMT_YUV420P; + else if (strcmp(fmt,"YUV422")==0) format=PIX_FMT_YUV422; + else if (strcmp(fmt,"RGB24")==0) format=PIX_FMT_RGB24; + else if (strcmp(fmt,"BGR24")==0) format=PIX_FMT_BGR24; + else if (strcmp(fmt,"YUV422P")==0) format=PIX_FMT_YUV422P; + else if (strcmp(fmt,"YUV444P")==0) format=PIX_FMT_YUV444P; + else { + g_warning("ms_AVdecoder_set_format: unsupported format %s.",fmt); + return -1; + } + enc->input_pix_fmt=format; + + return 0; +} diff --git a/linphone/mediastreamer/msavencoder.h b/linphone/mediastreamer/msavencoder.h new file mode 100644 index 000000000..429a4bd07 --- /dev/null +++ b/linphone/mediastreamer/msavencoder.h @@ -0,0 +1,92 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSAVENCODER_H +#define MSAVENCODER_H + +#include "msfilter.h" +#include "mscodec.h" +#include + +/*this is the class that implements a AVencoder filter*/ + +#define MSAVENCODER_MAX_INPUTS 1 /* max output per filter*/ +#define MSAVENCODER_MAX_OUTPUTS 2 + +struct _MSAVEncoder +{ + /* the MSAVEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVEncoder object + in order to the object mechanism to work*/ + MSFilter filter; + MSQueue *q_inputs[MSAVENCODER_MAX_INPUTS]; + MSQueue *q_outputs[MSAVENCODER_MAX_OUTPUTS]; + AVCodec *av_codec; /*the AVCodec from which this MSFilter is related */ + AVCodecContext av_context; /* the context of the AVCodec */ + gint input_pix_fmt; + gint av_opened; + MSBuffer *comp_buf; + MSBuffer *yuv_buf; + MSMessage *outm; +}; + +typedef struct _MSAVEncoder MSAVEncoder; +/* MSAVEncoder always outputs planar YUV and accept any incoming format you should setup using + ms_AVencoder_set_format() +q_outputs[0] is the compressed video stream output +q_outputs[1] is a YUV planar buffer of the image it receives in input. +*/ + + +struct _MSAVEncoderClass +{ + /* the MSAVEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVEncoder class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +}; + +typedef struct _MSAVEncoderClass MSAVEncoderClass; + +/* PUBLIC */ +#define MS_AVENCODER(filter) ((MSAVEncoder*)(filter)) +#define MS_AVENCODER_CLASS(klass) ((MSAVEncoderClass*)(klass)) + +MSFilter *ms_h263p_encoder_new(); +MSFilter *ms_mpeg_encoder_new(); +MSFilter *ms_mpeg4_encoder_new(); +MSFilter * ms_AVencoder_new_with_codec(enum CodecID codec_id, MSCodecInfo *info); + +gint ms_AVencoder_set_format(MSAVEncoder *enc, gchar *fmt); + +#define ms_AVencoder_set_width(av,w) (av)->av_context.width=(w) +#define ms_AVencoder_set_height(av,h) (av)->av_context.height=(h) +#define ms_AVencoder_set_bit_rate(av,r) (av)->av_context.bit_rate=(r) + +void ms_AVencoder_set_frame_rate(MSAVEncoder *enc, gint frame_rate, gint frame_rate_base); + +/* FOR INTERNAL USE*/ +void ms_AVencoder_init(MSAVEncoder *r, AVCodec *codec); +void ms_AVencoder_uninit(MSAVEncoder *enc); +void ms_AVencoder_class_init(MSAVEncoderClass *klass); +void ms_AVencoder_destroy( MSAVEncoder *obj); +void ms_AVencoder_process(MSAVEncoder *r); + + +#endif diff --git a/linphone/mediastreamer/msbuffer.c b/linphone/mediastreamer/msbuffer.c new file mode 100644 index 000000000..dedef45f4 --- /dev/null +++ b/linphone/mediastreamer/msbuffer.c @@ -0,0 +1,91 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msbuffer.h" +#include "msutils.h" +#include + + + +MSBuffer * ms_buffer_new(guint32 size) +{ + MSBuffer *buf; + buf=(MSBuffer*)g_malloc(sizeof(MSBuffer)+size); + buf->ref_count=0; + buf->size=size; + ms_trace("ms_buffer_new: Allocating buffer of %i bytes.",size); + /* allocate the data buffer: there is a lot of optmisation that can be done by using a pool of cached buffers*/ + buf->buffer=((char*)(buf))+sizeof(MSBuffer); /* to avoid to do two allocations, + buffer info and buffer are contigous.*/ + buf->freefn=NULL; + buf->freearg=NULL; + return(buf); +} + +MSBuffer *ms_buffer_new_with_buf(char *extbuf, int size,void (*freefn)(void *), void *freearg) +{ + MSBuffer *buf; + buf=(MSBuffer*)g_malloc(sizeof(MSBuffer)); + buf->ref_count=0; + buf->size=size; + buf->buffer=extbuf; + buf->freefn=freefn; + buf->freearg=freearg; + return(buf); +} + + +void ms_buffer_destroy(MSBuffer *buf) +{ + if (buf->freefn!=NULL) buf->freefn(buf->freearg); + g_free(buf); +} + +MSMessage *ms_message_alloc() +{ + MSMessage *m=g_malloc(sizeof(MSMessage)); + memset(m,0,sizeof(MSMessage)); + return m; +} + +MSMessage *ms_message_new(gint size) +{ + MSMessage *m=ms_message_alloc(); + MSBuffer *buf=ms_buffer_new(size); + ms_message_set_buf(m,buf); + return m; +} + +void ms_message_destroy(MSMessage *m) +{ + /* the buffer is freed if its ref_count goes to zero */ + if (m->buffer!=NULL){ + m->buffer->ref_count--; + if (m->buffer->ref_count==0) ms_buffer_destroy(m->buffer); + } + g_free(m); +} + +MSMessage * ms_message_dup(MSMessage *m) +{ + MSMessage *msg=ms_message_alloc(); + ms_message_set_buf(msg,m->buffer); + return msg; +} diff --git a/linphone/mediastreamer/msbuffer.h b/linphone/mediastreamer/msbuffer.h new file mode 100644 index 000000000..d182f1b80 --- /dev/null +++ b/linphone/mediastreamer/msbuffer.h @@ -0,0 +1,78 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSBUFFER_H +#define MSBUFFER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GLIB +#include +#else +#include +#endif + + +#define MS_BUFFER_LARGE 4092 + + +typedef struct _MSBuffer +{ + gchar *buffer; + guint32 size; + gint ref_count; + void (*freefn)(void *); + void *freearg; +}MSBuffer; + +MSBuffer * ms_buffer_new(guint32 size); +MSBuffer *ms_buffer_new_with_buf(char *extbuf, int size,void (*freefn)(void *), void *freearg); +void ms_buffer_destroy(MSBuffer *buf); + +struct _MSMessage +{ + MSBuffer *buffer; /* points to a MSBuffer */ + char *data; /*points to buffer->buffer */ + guint32 size; /* the size of the buffer to read in data. It may not be the + physical size (I mean buffer->buffer->size */ + struct _MSMessage *next; + struct _MSMessage *prev; /* MSMessage are queued into MSQueues */ + gboolean markbit; +}; + +typedef struct _MSMessage MSMessage; + +MSMessage *ms_message_new(gint size); + +#define ms_message_set_buf(m,b) do { (b)->ref_count++; (m)->buffer=(b); (m)->data=(b)->buffer; (m)->size=(b)->size; }while(0) +#define ms_message_unset_buf(m) do { (m)->buffer->ref_count--; (m)->buffer=NULL; (m)->size=0; (m)->data=NULL; } while(0) + +#define ms_message_size(m) (m)->size +void ms_message_destroy(MSMessage *m); + +MSMessage * ms_message_dup(MSMessage *m); + +/* allocate a single message without buffer */ +MSMessage *ms_message_alloc(); + +#endif diff --git a/linphone/mediastreamer/mscodec.c b/linphone/mediastreamer/mscodec.c new file mode 100644 index 000000000..092db1328 --- /dev/null +++ b/linphone/mediastreamer/mscodec.c @@ -0,0 +1,259 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mscodec.h" + +#ifndef _WIN32 +# include "msGSMdecoder.h" +# include "msLPC10decoder.h" +#endif +#include "msMUlawdec.h" +#include "msAlawdec.h" + +#ifdef TRUESPEECH +extern MSCodecInfo TrueSpeechinfo; +#endif + +#ifdef VIDEO_ENABLED +extern void ms_AVCodec_init(); +#endif + +#define UDP_HDR_SZ 8 +#define RTP_HDR_SZ 12 +#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ + + + + +/* register all statically linked codecs */ +void ms_codec_register_all() +{ +#ifndef _WIN32 + ms_filter_register(MS_FILTER_INFO(&GSMinfo)); + ms_filter_register(MS_FILTER_INFO(&LPC10info)); +#endif + ms_filter_register(MS_FILTER_INFO(&MULAWinfo)); + ms_filter_register(MS_FILTER_INFO(&ALAWinfo)); +#ifdef TRUESPEECH + ms_filter_register(MS_FILTER_INFO(&TrueSpeechinfo)); +#endif +#ifdef VIDEO_ENABLED + ms_AVCodec_init(); +#endif + +} + +/* returns a list of MSCodecInfo */ +GList * ms_codec_get_all_audio() +{ + GList *audio_codecs=NULL; + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if (info->type==MS_FILTER_AUDIO_CODEC){ + audio_codecs=g_list_append(audio_codecs,info); + } + elem=g_list_next(elem); + } + return audio_codecs; +} + + +MSCodecInfo * ms_audio_codec_info_get(gchar *name) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ( (info->type==MS_FILTER_AUDIO_CODEC) ){ + MSCodecInfo *codinfo=(MSCodecInfo *)info; + if (strcmp(codinfo->description,name)==0){ + return MS_CODEC_INFO(info); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +MSCodecInfo * ms_video_codec_info_get(gchar *name) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ( (info->type==MS_FILTER_VIDEO_CODEC) ){ + MSCodecInfo *codinfo=(MSCodecInfo *)info; + if (strcmp(codinfo->description,name)==0){ + return MS_CODEC_INFO(info); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +/* returns a list of MSCodecInfo */ +GList * ms_codec_get_all_video() +{ + GList *video_codecs=NULL; + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if (info->type==MS_FILTER_VIDEO_CODEC){ + video_codecs=g_list_append(video_codecs,info); + } + elem=g_list_next(elem); + } + return video_codecs; +} + +MSFilter * ms_encoder_new(gchar *name) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){ + MSCodecInfo *codinfo=(MSCodecInfo *)elem->data; + if (strcmp(info->name,name)==0){ + return codinfo->encoder(); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +MSFilter * ms_decoder_new(gchar *name) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){ + MSCodecInfo *codinfo=(MSCodecInfo *)elem->data; + if (strcmp(info->name,name)==0){ + return codinfo->decoder(); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +MSFilter * ms_encoder_new_with_pt(gint pt) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){ + MSCodecInfo *codinfo=(MSCodecInfo *)elem->data; + if (codinfo->pt==pt){ + return codinfo->encoder(); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +MSFilter * ms_decoder_new_with_pt(gint pt) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){ + MSCodecInfo *codinfo=(MSCodecInfo *)elem->data; + if (codinfo->pt==pt){ + return codinfo->decoder(); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +MSFilter * ms_decoder_new_with_string_id(gchar *id) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){ + MSCodecInfo *codinfo=(MSCodecInfo *)elem->data; + if (strcasecmp(codinfo->description,id)==0){ + return codinfo->decoder(); + } + } + elem=g_list_next(elem); + } + return NULL; +} + +MSFilter * ms_encoder_new_with_string_id(gchar *id) +{ + GList *elem=filter_list; + MSFilterInfo *info; + while (elem!=NULL) + { + info=(MSFilterInfo *)elem->data; + if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){ + MSCodecInfo *codinfo=(MSCodecInfo *)elem->data; + if (strcasecmp(codinfo->description,id)==0){ + return codinfo->encoder(); + } + } + elem=g_list_next(elem); + } + return NULL; +} +/* return 0 if codec can be used with bandwidth, -1 else*/ +int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth) +{ + double codec_band; + double npacket; + double packet_size; + + if (((MSFilterInfo*)codec)->type==MS_FILTER_AUDIO_CODEC) + { + /* calculate the total bandwdith needed by codec (including headers for rtp, udp, ip)*/ + /* number of packet per second*/ + npacket=2.0*(double)(codec->rate)/(double)(codec->fr_size); + packet_size=(double)(codec->dt_size)+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; + codec_band=packet_size*8.0*npacket; + } + else return -1; + return(codec_band +#include +#include +#include +#include +#include + +static MSCopyClass *ms_copy_class=NULL; + +MSFilter * ms_copy_new(void) +{ + MSCopy *r; + + r=g_new(MSCopy,1); + ms_copy_init(r); + if (ms_copy_class==NULL) + { + ms_copy_class=g_new(MSCopyClass,1); + ms_copy_class_init(ms_copy_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_copy_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_copy_init(MSCopy *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->r_mingran=MSCOPY_DEF_GRAN; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS); + memset(r->f_outputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS); +} + +void ms_copy_class_init(MSCopyClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"fifocopier"); + MS_FILTER_CLASS(klass)->max_finputs=MSCOPY_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSCOPY_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=MSCOPY_DEF_GRAN; + MS_FILTER_CLASS(klass)->w_maxgran=MSCOPY_DEF_GRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_copy_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_copy_process; +} + +void ms_copy_process(MSCopy *r) +{ + MSFifo *fi,*fo; + int err1; + gint gran=MS_FILTER(r)->klass->r_maxgran; + void *s,*d; + + /* process output fifos, but there is only one for this class of filter*/ + + fi=r->f_inputs[0]; + fo=r->f_outputs[0]; + if (fi!=NULL) + { + err1=ms_fifo_get_read_ptr(fi,gran,&s); + if (err1>0) err1=ms_fifo_get_write_ptr(fo,gran,&d); + if (err1>0) + { + memcpy(d,s,gran); + } + } +} + +void ms_copy_destroy( MSCopy *obj) +{ + g_free(obj); +} diff --git a/linphone/mediastreamer/mscopy.h b/linphone/mediastreamer/mscopy.h new file mode 100644 index 000000000..2b5749b99 --- /dev/null +++ b/linphone/mediastreamer/mscopy.h @@ -0,0 +1,61 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSCOPY_H +#define MSCOPY_H + +#include "msfilter.h" + + +/*this is the class that implements a copy filter*/ + +#define MSCOPY_MAX_INPUTS 1 /* max output per filter*/ + +#define MSCOPY_DEF_GRAN 64 /* the default granularity*/ + +typedef struct _MSCopy +{ + /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MSCOPY_MAX_INPUTS]; + MSFifo *f_outputs[MSCOPY_MAX_INPUTS]; +} MSCopy; + +typedef struct _MSCopyClass +{ + /* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSCopyClass; + +/* PUBLIC */ +#define MS_COPY(filter) ((MSCopy*)(filter)) +#define MS_COPY_CLASS(klass) ((MSCopyClass*)(klass)) +MSFilter * ms_copy_new(void); + +/* FOR INTERNAL USE*/ +void ms_copy_init(MSCopy *r); +void ms_copy_class_init(MSCopyClass *klass); +void ms_copy_destroy( MSCopy *obj); +void ms_copy_process(MSCopy *r); + +#endif diff --git a/linphone/mediastreamer/msfdispatcher.c b/linphone/mediastreamer/msfdispatcher.c new file mode 100644 index 000000000..692bbb7b0 --- /dev/null +++ b/linphone/mediastreamer/msfdispatcher.c @@ -0,0 +1,94 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a dispatcher of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msfdispatcher.h" + +static MSFdispatcherClass *ms_fdispatcher_class=NULL; + +MSFilter * ms_fdispatcher_new(void) +{ + MSFdispatcher *obj; + obj=g_malloc(sizeof(MSFdispatcher)); + if (ms_fdispatcher_class==NULL){ + ms_fdispatcher_class=g_malloc(sizeof(MSFdispatcherClass)); + ms_fdispatcher_class_init(ms_fdispatcher_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_fdispatcher_class); + ms_fdispatcher_init(obj); + return MS_FILTER(obj); +} + + +void ms_fdispatcher_init(MSFdispatcher *obj) +{ + ms_filter_init(MS_FILTER(obj)); + MS_FILTER(obj)->infifos=obj->f_inputs; + MS_FILTER(obj)->outfifos=obj->f_outputs; + MS_FILTER(obj)->r_mingran=MS_FDISPATCHER_DEF_GRAN; + memset(obj->f_inputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_INPUTS); + memset(obj->f_outputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_OUTPUTS); +} + + + +void ms_fdispatcher_class_init(MSFdispatcherClass *klass) +{ + MSFilterClass *parent_class=MS_FILTER_CLASS(klass); + ms_filter_class_init(parent_class); + ms_filter_class_set_name(parent_class,"fdispatcher"); + parent_class->max_finputs=MS_FDISPATCHER_MAX_INPUTS; + parent_class->max_foutputs=MS_FDISPATCHER_MAX_OUTPUTS; + parent_class->r_maxgran=MS_FDISPATCHER_DEF_GRAN; + parent_class->w_maxgran=MS_FDISPATCHER_DEF_GRAN; + parent_class->destroy=(MSFilterDestroyFunc)ms_fdispatcher_destroy; + parent_class->process=(MSFilterProcessFunc)ms_fdispatcher_process; +} + + +void ms_fdispatcher_destroy( MSFdispatcher *obj) +{ + g_free(obj); +} + +void ms_fdispatcher_process(MSFdispatcher *obj) +{ + gint i; + MSFifo *inf=obj->f_inputs[0]; + + + if (inf!=NULL){ + void *s,*d; + /* dispatch fifos */ + while ( ms_fifo_get_read_ptr(inf,MS_FDISPATCHER_DEF_GRAN,&s) >0 ){ + for (i=0;if_outputs[i]; + + if (outf!=NULL) + { + ms_fifo_get_write_ptr(outf,MS_FDISPATCHER_DEF_GRAN,&d); + if (d!=NULL) memcpy(d,s,MS_FDISPATCHER_DEF_GRAN); + } + } + } + } +} + + diff --git a/linphone/mediastreamer/msfdispatcher.h b/linphone/mediastreamer/msfdispatcher.h new file mode 100644 index 000000000..b1b457df5 --- /dev/null +++ b/linphone/mediastreamer/msfdispatcher.h @@ -0,0 +1,61 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a dispatcher of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSFDISPATCHER_H +#define MSFDISPATCHER_H + +#include "msfilter.h" + + +/*this is the class that implements a fdispatcher filter*/ + +#define MS_FDISPATCHER_MAX_INPUTS 1 +#define MS_FDISPATCHER_MAX_OUTPUTS 5 +#define MS_FDISPATCHER_DEF_GRAN 64 /* the default granularity*/ + +typedef struct _MSFdispatcher +{ + /* the MSFdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSFdispatcher object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MS_FDISPATCHER_MAX_INPUTS]; + MSFifo *f_outputs[MS_FDISPATCHER_MAX_OUTPUTS]; +} MSFdispatcher; + +typedef struct _MSFdispatcherClass +{ + /* the MSFdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSFdispatcher class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSFdispatcherClass; + +/* PUBLIC */ +#define MS_FDISPATCHER(filter) ((MSFdispatcher*)(filter)) +#define MS_FDISPATCHER_CLASS(klass) ((MSFdispatcherClass*)(klass)) +MSFilter * ms_fdispatcher_new(void); + +/* FOR INTERNAL USE*/ +void ms_fdispatcher_init(MSFdispatcher *r); +void ms_fdispatcher_class_init(MSFdispatcherClass *klass); +void ms_fdispatcher_destroy( MSFdispatcher *obj); +void ms_fdispatcher_process(MSFdispatcher *r); + +#endif diff --git a/linphone/mediastreamer/msfifo.c b/linphone/mediastreamer/msfifo.c new file mode 100644 index 000000000..871cf0a87 --- /dev/null +++ b/linphone/mediastreamer/msfifo.c @@ -0,0 +1,167 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "msutils.h" +#include "msfifo.h" + +MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset) +{ + MSFifo *fifo; + gint saved_offset=MAX(r_gran+r_offset,w_offset); + + g_return_val_if_fail(saved_offset<=(buf->size),NULL); + fifo=g_malloc(sizeof(MSFifo)); + fifo->buffer=buf; + fifo->r_gran=r_gran; + fifo->w_gran=w_gran; + fifo->begin=fifo->wr_ptr=fifo->rd_ptr=buf->buffer+saved_offset; + fifo->readsize=0; + fifo->size=fifo->writesize=buf->size-saved_offset; + fifo->saved_offset= saved_offset; + fifo->r_end=fifo->w_end=buf->buffer+buf->size; + fifo->pre_end=fifo->w_end-saved_offset; + buf->ref_count++; + fifo->prev_data=NULL; + fifo->next_data=NULL; + ms_trace("fifo base=%x, begin=%x, end=%x, saved_offset=%i, size=%i" + ,fifo->buffer->buffer,fifo->begin,fifo->w_end,fifo->saved_offset,fifo->size); + return(fifo); +} + +MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset, + gint min_fifo_size) +{ + MSFifo *fifo; + MSBuffer *buf; + gint saved_offset=MAX(r_gran+r_offset,w_offset); + gint fifo_size; + if (min_fifo_size==0) min_fifo_size=w_gran; + + /* we must allocate a fifo with a size multiple of min_fifo_size, + with a saved_offset */ + if (min_fifo_size>MS_BUFFER_LARGE) + fifo_size=(min_fifo_size) + saved_offset; + else fifo_size=(6*min_fifo_size) + saved_offset; + buf=ms_buffer_new(fifo_size); + fifo=ms_fifo_new(buf,r_gran,w_gran,r_offset,w_offset); + ms_trace("fifo_size=%i",fifo_size); + return(fifo); +} + +void ms_fifo_destroy( MSFifo *fifo) +{ + g_free(fifo); +} + +void ms_fifo_destroy_with_buffer(MSFifo *fifo) +{ + ms_buffer_destroy(fifo->buffer); + ms_fifo_destroy(fifo); +} + +gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr) +{ + gchar *rnext; + + *ret_ptr=NULL; + //ms_trace("ms_fifo_get_read_ptr: entering."); + g_return_val_if_fail(bsize<=fifo->r_gran,-EINVAL); + + if (bsize>fifo->readsize) + { + ms_trace("Not enough data: bsize=%i, readsize=%i",bsize,fifo->readsize); + return -1; + } + + rnext=fifo->rd_ptr+bsize; + if (rnext<=fifo->r_end){ + + *ret_ptr=fifo->rd_ptr; + fifo->rd_ptr=rnext; + }else{ + int unread=fifo->r_end-fifo->rd_ptr; + *ret_ptr=fifo->begin-unread; + memcpy(fifo->buffer->buffer,fifo->r_end-fifo->saved_offset,fifo->saved_offset); + fifo->rd_ptr=(char*)(*ret_ptr) + bsize; + fifo->r_end=fifo->w_end; /* this is important ! */ + ms_trace("moving read ptr to %x",fifo->rd_ptr); + + } + /* update write size*/ + fifo->writesize+=bsize; + fifo->readsize-=bsize; + return bsize; +} + + +void ms_fifo_update_write_ptr(MSFifo *fifo, gint written){ + gint reserved=fifo->wr_ptr-fifo->prev_wr_ptr; + gint unwritten; + g_return_if_fail(reserved>=0); + unwritten=reserved-written; + g_return_if_fail(unwritten>=0); + /* fix readsize and writesize */ + fifo->readsize-=unwritten; + fifo->writesize+=unwritten; + fifo->wr_ptr=fifo->prev_wr_ptr+written; +} + +gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr) +{ + gchar *wnext; + + *ret_ptr=NULL; + //ms_trace("ms_fifo_get_write_ptr: Entering."); + g_return_val_if_fail(bsize<=fifo->w_gran,-EINVAL); + if (bsize>fifo->writesize) + { + ms_trace("Not enough space: bsize=%i, writesize=%i",bsize,fifo->writesize); + *ret_ptr=NULL; + return -1; + } + wnext=fifo->wr_ptr+bsize; + if (wnext<=fifo->w_end){ + *ret_ptr=fifo->wr_ptr; + fifo->wr_ptr=wnext; + }else{ + *ret_ptr=fifo->begin; + fifo->r_end=fifo->wr_ptr; + fifo->wr_ptr=fifo->begin+bsize; + ms_trace("moving write ptr to %x",fifo->wr_ptr); + } + fifo->prev_wr_ptr=*ret_ptr; + /* update readsize*/ + fifo->readsize+=bsize; + fifo->writesize-=bsize; + //ms_trace("ms_fifo_get_write_ptr: readsize=%i, writesize=%i",fifo->readsize,fifo->writesize); + return bsize; +} + +gint ms_fifo_get_rw_ptr(MSFifo *f1,void **p1,gint minsize1, + MSFifo *f2,void **p2,gint minsize2) +{ + gint rbsize,wbsize; + + rbsize=MIN(f1->readsize,(f1->pre_end-f1->rd_ptr)); + wbsize=MIN(f2->writesize,(f2->w_end-f2->wr_ptr)); + return 0; +} diff --git a/linphone/mediastreamer/msfifo.h b/linphone/mediastreamer/msfifo.h new file mode 100644 index 000000000..fde1bece1 --- /dev/null +++ b/linphone/mediastreamer/msfifo.h @@ -0,0 +1,73 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef HAVE_GLIB +#include +#else +#include "glist.h" +#endif +#include "msbuffer.h" + +typedef struct _MSFifo +{ + gint r_gran; /*maximum granularity for reading*/ + gint w_gran; /*maximum granularity for writing*/ + gchar * rd_ptr; /* read pointer on the position where there is something to read on the MSBuffer */ + guint32 readsize; + gchar * wr_ptr; + gchar * prev_wr_ptr; + guint32 writesize; /* write pointer on the position where it is possible to write on the MSBuffer */ + gchar * begin; /* rd_ptr et wr_ptr must all be >=begin*/ + guint32 size; /* the length of the fifo, but this may not be equal to buffer->size*/ + guint32 saved_offset; + gchar * pre_end; /* the end of the buffer that is copied at the begginning when we wrap around*/ + gchar * w_end; /* when a wr ptr is expected to exceed end_offset, + it must be wrapped around to go at the beginning of the buffer. This is the end of the buffer*/ + gchar * r_end; /* this is the last position written at the end of the fifo. If a read ptr is expected to + exceed this pointer, it must be put at the begginning of the buffer */ + void *prev_data; /*user data, usually the writing MSFilter*/ + void *next_data; /* user data, usually the reading MSFilter */ + MSBuffer *buffer; +} MSFifo; + +/* constructor*/ +/* r_gran: max granularity for reading (in number of bytes)*/ +/* w_gran: max granularity for writing (in number of bytes)*/ +/* r_offset: number of bytes that are kept available behind read pointer (for recursive filters)*/ +/* w_offset: number of bytes that are kept available behind write pointer (for recursive filters)*/ +/* buf is a MSBuffer that should be compatible with the above parameter*/ +MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset); + +/*does the same that ms_fifo_new(), but also allocate a compatible buffer automatically*/ +MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset, gint min_buffer_size); + +void ms_fifo_destroy( MSFifo *fifo); + +void ms_fifo_destroy_with_buffer(MSFifo *fifo); + +/* get data to read */ +gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr); + +/* get a buffer to write*/ +gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr); + +/* in case the buffer got by ms_fifo_get_write_ptr() could not be filled completely, you must +tell it by using this function */ +void ms_fifo_update_write_ptr(MSFifo *fifo, gint written); diff --git a/linphone/mediastreamer/msfilter.c b/linphone/mediastreamer/msfilter.c new file mode 100644 index 000000000..c67e9f0e2 --- /dev/null +++ b/linphone/mediastreamer/msfilter.c @@ -0,0 +1,537 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include +#include "msfilter.h" + + + +void ms_filter_init(MSFilter *filter) +{ + filter->finputs=0; + filter->foutputs=0; + filter->qinputs=0; + filter->qoutputs=0; + filter->infifos=NULL; + filter->outfifos=NULL; + filter->inqueues=NULL; + filter->outqueues=NULL; + filter->lock=g_mutex_new(); + filter->min_fifo_size=0x7fff; + filter->notify_event=NULL; + filter->userdata=NULL; +} + +void ms_filter_uninit(MSFilter *filter) +{ + g_mutex_free(filter->lock); +} + +void ms_filter_class_init(MSFilterClass *filterclass) +{ + filterclass->name=NULL; + filterclass->max_finputs=0; + filterclass->max_foutputs=0; + filterclass->max_qinputs=0; + filterclass->max_qoutputs=0; + filterclass->r_maxgran=0; + filterclass->w_maxgran=0; + filterclass->r_offset=0; + filterclass->w_offset=0; + filterclass->set_property=NULL; + filterclass->get_property=NULL; + filterclass->setup=NULL; + filterclass->unsetup=NULL; + filterclass->process=NULL; + filterclass->destroy=NULL; + filterclass->attributes=0; + filterclass->ref_count=0; +} + +/* find output queue */ +gint find_oq(MSFilter *m1,MSQueue *oq) +{ + gint i; + + for (i=0;imax_qoutputs;i++){ + if (m1->outqueues[i]==oq) return i; + } + + return -1; +} + +/* find input queue */ +gint find_iq(MSFilter *m1,MSQueue *iq) +{ + gint i; + for (i=0;imax_qinputs;i++){ + if (m1->inqueues[i]==iq) return i; + } + return -1; +} + +/* find output fifo */ +gint find_of(MSFilter *m1,MSFifo *of) +{ + gint i; + for (i=0;imax_foutputs;i++){ + if (m1->outfifos[i]==of) return i; + } + + return -1; +} + +/* find input fifo */ +gint find_if(MSFilter *m1,MSFifo *inf) +{ + gint i; + + for (i=0;imax_finputs;i++){ + if (m1->infifos[i]==inf) return i; + } + + return -1; +} + +#define find_free_iq(_m1) find_iq(_m1,NULL) +#define find_free_oq(_m1) find_oq(_m1,NULL) +#define find_free_if(_m1) find_if(_m1,NULL) +#define find_free_of(_m1) find_of(_m1,NULL) + +int ms_filter_add_link(MSFilter *m1, MSFilter *m2) +{ + gint m1_q=-1; + gint m1_f=-1; + gint m2_q=-1; + gint m2_f=-1; + /* determine the type of link we can add */ + m1_q=find_free_oq(m1); + m1_f=find_free_of(m1); + m2_q=find_free_iq(m2); + m2_f=find_free_if(m2); + if ((m1_q!=-1) && (m2_q!=-1)){ + /* link with queues */ + ms_trace("m1_q=%i , m2_q=%i",m1_q,m2_q); + return ms_filter_link(m1,m1_q,m2,m2_q,LINK_QUEUE); + } + if ((m1_f!=-1) && (m2_f!=-1)){ + /* link with queues */ + ms_trace("m1_f=%i , m2_f=%i",m1_f,m2_f); + return ms_filter_link(m1,m1_f,m2,m2_f,LINK_FIFO); + } + g_warning("ms_filter_add_link: could not link."); + return -1; +} +/** + * ms_filter_link: + * @m1: A #MSFilter object. + * @pin1: The pin number on @m1. + * @m2: A #MSFilter object. + * @pin2: The pin number on @m2. + * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS. + * + * This function links two MSFilter object between them. It must be used to make chains of filters. + * All data outgoing from pin1 of m1 will go to the input pin2 of m2. + * The way to communicate can be fifos or queues, depending of the nature of the filters. Filters can have + * multiple queue pins and multiple fifo pins, but most of them have only one queue input/output or only one + * fifo input/output. Fifos are usally used by filters doing audio processing, while queues are used by filters doing + * video processing. + * + * Returns: 0 if successfull, a negative value reprensenting the errno.h error. + */ +int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, int linktype) +{ + MSQueue *q; + MSFifo *fifo; + + g_message("ms_filter_add_link: %s,%i -> %s,%i",m1->klass->name,pin1,m2->klass->name,pin2); + switch(linktype) + { + case LINK_QUEUE: + /* Are filter m1 and m2 able to accept more queues connections ?*/ + g_return_val_if_fail(m1->qoutputsmax_qoutputs,-EMLINK); + g_return_val_if_fail(m2->qinputsmax_qinputs,-EMLINK); + /* Are filter m1 and m2 valid with their inputs and outputs ?*/ + g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT); + g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT); + /* are the requested pins exists ?*/ + g_return_val_if_fail(pin1max_qoutputs,-EINVAL); + g_return_val_if_fail(pin2max_qinputs,-EINVAL); + /* are the requested pins free ?*/ + g_return_val_if_fail(m1->outqueues[pin1]==NULL,-EBUSY); + g_return_val_if_fail(m2->inqueues[pin2]==NULL,-EBUSY); + + q=ms_queue_new(); + m1->outqueues[pin1]=m2->inqueues[pin2]=q; + m1->qoutputs++; + m2->qinputs++; + q->prev_data=(void*)m1; + q->next_data=(void*)m2; + break; + case LINK_FIFO: + /* Are filter m1 and m2 able to accept more fifo connections ?*/ + g_return_val_if_fail(m1->foutputsmax_foutputs,-EMLINK); + g_return_val_if_fail(m2->finputsmax_finputs,-EMLINK); + /* Are filter m1 and m2 valid with their inputs and outputs ?*/ + g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT); + g_return_val_if_fail(m2->infifos!=NULL,-EFAULT); + /* are the requested pins exists ?*/ + g_return_val_if_fail(pin1max_foutputs,-EINVAL); + g_return_val_if_fail(pin2max_finputs,-EINVAL); + /* are the requested pins free ?*/ + g_return_val_if_fail(m1->outfifos[pin1]==NULL,-EBUSY); + g_return_val_if_fail(m2->infifos[pin2]==NULL,-EBUSY); + + if (MS_FILTER_GET_CLASS(m1)->attributes & FILTER_IS_SOURCE) + { + /* configure min_fifo_size */ + fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran, + MS_FILTER_GET_CLASS(m1)->w_maxgran, + MS_FILTER_GET_CLASS(m2)->r_offset, + MS_FILTER_GET_CLASS(m1)->w_offset, + MS_FILTER_GET_CLASS(m1)->w_maxgran); + m2->min_fifo_size=MS_FILTER_GET_CLASS(m1)->w_maxgran; + } + else + { + gint next_size; + ms_trace("ms_filter_add_link: min_fifo_size=%i",m1->min_fifo_size); + fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran, + MS_FILTER_GET_CLASS(m1)->w_maxgran, + MS_FILTER_GET_CLASS(m2)->r_offset, + MS_FILTER_GET_CLASS(m1)->w_offset, + m1->min_fifo_size); + if (MS_FILTER_GET_CLASS(m2)->r_maxgran>0){ + next_size=(m1->min_fifo_size* + (MS_FILTER_GET_CLASS(m2)->w_maxgran)) / + (MS_FILTER_GET_CLASS(m2)->r_maxgran); + }else next_size=m1->min_fifo_size; + ms_trace("ms_filter_add_link: next_size=%i",next_size); + m2->min_fifo_size=next_size; + } + + + m1->outfifos[pin1]=m2->infifos[pin2]=fifo; + m1->foutputs++; + m2->finputs++; + fifo->prev_data=(void*)m1; + fifo->next_data=(void*)m2; + break; + } + return 0; +} +/** + * ms_filter_unlink: + * @m1: A #MSFilter object. + * @pin1: The pin number on @m1. + * @m2: A #MSFilter object. + * @pin2: The pin number on @m2. + * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS. + * + * Unlink @pin1 of filter @m1 from @pin2 of filter @m2. @linktype specifies what type of connection is removed. + * + * Returns: 0 if successfull, a negative value reprensenting the errno.h error. + */ +int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype) +{ + switch(linktype) + { + case LINK_QUEUE: + /* Are filter m1 and m2 valid with their inputs and outputs ?*/ + g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT); + g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT); + /* are the requested pins exists ?*/ + g_return_val_if_fail(pin1max_qoutputs,-EINVAL); + g_return_val_if_fail(pin2max_qinputs,-EINVAL); + /* are the requested pins busy ?*/ + g_return_val_if_fail(m1->outqueues[pin1]!=NULL,-ENOENT); + g_return_val_if_fail(m2->inqueues[pin2]!=NULL,-ENOENT); + /* are the two pins connected together ?*/ + g_return_val_if_fail(m1->outqueues[pin1]==m2->inqueues[pin2],-EINVAL); + + ms_queue_destroy(m1->outqueues[pin1]); + m1->outqueues[pin1]=m2->inqueues[pin2]=NULL; + m1->qoutputs--; + m2->qinputs--; + + break; + case LINK_FIFO: + /* Are filter m1 and m2 valid with their inputs and outputs ?*/ + g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT); + g_return_val_if_fail(m2->infifos!=NULL,-EFAULT); + /* are the requested pins exists ?*/ + g_return_val_if_fail(pin1max_foutputs,-EINVAL); + g_return_val_if_fail(pin2max_finputs,-EINVAL); + /* are the requested pins busy ?*/ + g_return_val_if_fail(m1->outfifos[pin1]!=NULL,-ENOENT); + g_return_val_if_fail(m2->infifos[pin2]!=NULL,-ENOENT); + /* are the two pins connected together ?*/ + g_return_val_if_fail(m1->outfifos[pin1]==m2->infifos[pin2],-EINVAL); + ms_fifo_destroy_with_buffer(m1->outfifos[pin1]); + m1->outfifos[pin1]=m2->infifos[pin2]=NULL; + m1->foutputs--; + m2->finputs--; + break; + } + return 0; +} + +/** + *ms_filter_remove_links: + *@m1: a filter + *@m2: another filter. + * + * Removes all links between m1 and m2. + * + *Returns: 0 if one more link have been removed, -1 if not. +**/ +gint ms_filter_remove_links(MSFilter *m1, MSFilter *m2) +{ + int i,j; + int removed=-1; + MSQueue *qo; + MSFifo *fo; + /* takes all outputs of m1, and removes the one that goes to m2 */ + if (m1->outqueues!=NULL){ + for (i=0;imax_qoutputs;i++) + { + qo=m1->outqueues[i]; + if (qo!=NULL){ + MSFilter *rmf; + /* test if the queue connects to m2 */ + rmf=(MSFilter*)qo->next_data; + if (rmf==m2){ + j=find_iq(rmf,qo); + if (j==-1) g_error("Could not find input queue: impossible case."); + ms_filter_unlink(m1,i,m2,j,LINK_QUEUE); + removed=0; + } + } + } + } + if (m1->outfifos!=NULL){ + for (i=0;imax_foutputs;i++) + { + fo=m1->outfifos[i]; + if (fo!=NULL){ + MSFilter *rmf; + /* test if the queue connects to m2 */ + rmf=(MSFilter*)fo->next_data; + if (rmf==m2){ + j=find_if(rmf,fo); + if (j==-1) g_error("Could not find input fifo: impossible case."); + ms_filter_unlink(m1,i,m2,j,LINK_FIFO); + removed=0; + } + } + } + } + return removed; +} + +/** + * ms_filter_fifos_have_data: + * @f: a #MSFilter object. + * + * Tells if the filter has enough data in its input fifos in order to be executed succesfully. + * + * Returns: 1 if it can be executed, 0 else. + */ +gint ms_filter_fifos_have_data(MSFilter *f) +{ + gint i,j; + gint max_inputs=f->klass->max_finputs; + gint con_inputs=f->finputs; + MSFifo *fifo; + /* test fifos */ + for(i=0,j=0; (iinfifos[i]; + if (fifo!=NULL) + { + j++; + if (fifo->readsize==0) return 0; + if (fifo->readsize>=f->r_mingran) return 1; + } + } + return 0; +} + +/** + * ms_filter_queues_have_data: + * @f: a #MSFilter object. + * + * Tells if the filter has enough data in its input queues in order to be executed succesfully. + * + * Returns: 1 if it can be executed, 0 else. + */ +gint ms_filter_queues_have_data(MSFilter *f) +{ + gint i,j; + gint max_inputs=f->klass->max_qinputs; + gint con_inputs=f->qinputs; + MSQueue *q; + /* test queues */ + for(i=0,j=0; (iinqueues[i]; + if (q!=NULL) + { + j++; + if (ms_queue_can_get(q)) return 1; + } + } + return 0; +} + + + +void ms_filter_destroy(MSFilter *f) +{ + /* first check if the filter is disconnected from any others */ + g_return_if_fail(f->finputs==0); + g_return_if_fail(f->foutputs==0); + g_return_if_fail(f->qinputs==0); + g_return_if_fail(f->qoutputs==0); + f->klass->destroy(f); +} + +GList *filter_list=NULL; + +void ms_filter_register(MSFilterInfo *info) +{ + gpointer tmp; + tmp=g_list_find(filter_list,info); + if (tmp==NULL) filter_list=g_list_append(filter_list,(gpointer)info); +} + +void ms_filter_unregister(MSFilterInfo *info) +{ + filter_list=g_list_remove(filter_list,(gpointer)info); +} + +static gint compare_names(gpointer info, gpointer name) +{ + MSFilterInfo *i=(MSFilterInfo*) info; + return (strcmp(i->name,name)); +} + +MSFilterInfo * ms_filter_get_by_name(const gchar *name) +{ + GList *elem=g_list_find_custom(filter_list, + (gpointer)name,(GCompareFunc)compare_names); + if (elem!=NULL){ + return (MSFilterInfo*)elem->data; + } + return NULL; +} + + + +MSFilter * ms_filter_new_with_name(const gchar *name) +{ + MSFilterInfo *info=ms_filter_get_by_name(name); + if (info!=NULL) return info->constructor(); + g_warning("ms_filter_new_with_name: no filter named %s found.",name); + return NULL; +} + + +/* find the first codec in the left part of the stream */ +MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type) +{ + MSFilter *tmp=f; + MSFilterInfo *info; + + if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL)){ + tmp=(MSFilter*) tmp->infifos[0]->prev_data; + while(1){ + info=MS_FILTER_GET_CLASS(tmp)->info; + if (info!=NULL){ + if ( (info->type==type) ){ + return tmp; + } + } + if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL)) + tmp=(MSFilter*) tmp->infifos[0]->prev_data; + else break; + } + } + tmp=f; + if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL)){ + tmp=(MSFilter*) tmp->inqueues[0]->prev_data; + while(1){ + + info=MS_FILTER_GET_CLASS(tmp)->info; + if (info!=NULL){ + if ( (info->type==type)){ + return tmp; + } + }else g_warning("ms_filter_search_upstream_by_type: filter %s has no info." + ,MS_FILTER_GET_CLASS(tmp)->name); + if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL)) + tmp=(MSFilter*) tmp->inqueues[0]->prev_data; + else break; + } + } + return NULL; +} + + +int ms_filter_set_property(MSFilter *f, MSFilterProperty prop,void *value) +{ + if (f->klass->set_property!=NULL){ + return f->klass->set_property(f,prop,value); + } + return 0; +} + +int ms_filter_get_property(MSFilter *f, MSFilterProperty prop,void *value) +{ + if (f->klass->get_property!=NULL){ + return f->klass->get_property(f,prop,value); + } + return -1; +} + +void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata) +{ + filter->notify_event=func; + filter->userdata=userdata; +} + +void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg) +{ + if (filter->notify_event!=NULL){ + filter->notify_event(filter,event,arg,filter->userdata); + } +} + +void swap_buffer(gchar *buffer, gint len) +{ + int i; + gchar tmp; + for (i=0;i +#endif + +#ifdef HAVE_GLIB +#include +#else +#undef VERSION +#undef PACKAGE +#include +#endif + +#include +#include "msutils.h" +#include "msfifo.h" +#include "msqueue.h" + +struct _MSFilter; +/*this is the abstract object and class for all filter types*/ +typedef gint (*MSFilterNotifyFunc)(struct _MSFilter*, gint event, gpointer arg, gpointer userdata); + +struct _MSFilter +{ + struct _MSFilterClass *klass; + GMutex *lock; + guchar finputs; /* number of connected fifo inputs*/ + guchar foutputs; /* number of connected fifo outputs*/ + guchar qinputs; /* number of connected queue inputs*/ + guchar qoutputs; /* number of connected queue outputs*/ + gint min_fifo_size; /* set when linking*/ + gint r_mingran; /* read minimum granularity (for fifos). + It can be zero so that the filter can accept any size of reading data*/ + MSFifo **infifos; /*pointer to a table of pointer to input fifos*/ + MSFifo **outfifos; /*pointer to a table of pointer to output fifos*/ + MSQueue **inqueues; /*pointer to a table of pointer to input queues*/ + MSQueue **outqueues; /*pointer to a table of pointer to output queues*/ + MSFilterNotifyFunc notify_event; + gpointer userdata; +}; + +typedef struct _MSFilter MSFilter; + +typedef enum{ + MS_FILTER_PROPERTY_FREQ, /* value is int */ + MS_FILTER_PROPERTY_BITRATE, /*value is int */ + MS_FILTER_PROPERTY_CHANNELS,/*value is int */ + MS_FILTER_PROPERTY_FMTP /* value is string */ +}MSFilterProperty; + +#define MS_FILTER_PROPERTY_STRING_MAX_SIZE 256 + +typedef MSFilter * (*MSFilterNewFunc)(void); +typedef void (*MSFilterProcessFunc)(MSFilter *); +typedef void (*MSFilterDestroyFunc)(MSFilter *); +typedef int (*MSFilterPropertyFunc)(MSFilter *,int ,void*); +typedef void (*MSFilterSetupFunc)(MSFilter *, void *); /*2nd arg is the sync */ + +typedef struct _MSFilterClass +{ + struct _MSFilterInfo *info; /*pointer to a filter_info */ + gchar *name; + guchar max_finputs; /* maximum number of fifo inputs*/ + guchar max_foutputs; /* maximum number of fifo outputs*/ + guchar max_qinputs; /* maximum number of queue inputs*/ + guchar max_qoutputs; /* maximum number of queue outputs*/ + gint r_maxgran; /* read maximum granularity (for fifos)*/ + gint w_maxgran; /* write maximum granularity (for fifos)*/ + gint r_offset; /* size of kept samples behind read pointer (for fifos)*/ + gint w_offset; /* size of kept samples behind write pointer (for fifos)*/ + MSFilterPropertyFunc set_property; + MSFilterPropertyFunc get_property; + MSFilterSetupFunc setup; /* called when attaching to sync */ + void (*process)(MSFilter *filter); + MSFilterSetupFunc unsetup; /* called when detaching from sync */ + void (*destroy)(MSFilter *filter); + guint attributes; +#define FILTER_HAS_FIFOS (0x0001) +#define FILTER_HAS_QUEUES (0x0001<<1) +#define FILTER_IS_SOURCE (0x0001<<2) +#define FILTER_IS_SINK (0x0001<<3) +#define FILTER_CAN_SYNC (0x0001<<4) + guint ref_count; /*number of object using the class*/ +} MSFilterClass; + + + +#define MS_FILTER(obj) ((MSFilter*)obj) +#define MS_FILTER_CLASS(klass) ((MSFilterClass*)klass) +#define MS_FILTER_GET_CLASS(obj) ((MSFilterClass*)((MS_FILTER(obj)->klass))) + +void ms_filter_class_init(MSFilterClass *filterclass); +void ms_filter_init(MSFilter *filter); + +#define ms_filter_class_set_attr(filter,flag) ((filter)->attributes|=(flag)) +#define ms_filter_class_unset_attr(filter,flag) ((filter)->attributes&=~(flag)) + +#define ms_filter_class_set_name(__klass,__name) (__klass)->name=g_strdup((__name)) +#define ms_filter_class_set_info(_klass,_info) (_klass)->info=(_info) +/* public*/ + +#define ms_filter_process(filter) ((filter)->klass->process((filter))) + +#define ms_filter_lock(filter) g_mutex_lock((filter)->lock) +#define ms_filter_unlock(filter) g_mutex_unlock((filter)->lock) +/* low level connect functions */ +int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, gint linktype); +int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype); + +/* high level connect functions */ +int ms_filter_add_link(MSFilter *m1, MSFilter *m2); +int ms_filter_remove_links(MSFilter *m1, MSFilter *m2); + +void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata); +void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg); + +int ms_filter_set_property(MSFilter *f,MSFilterProperty property, void *value); +int ms_filter_get_property(MSFilter *f,MSFilterProperty property, void *value); + + +gint ms_filter_fifos_have_data(MSFilter *f); +gint ms_filter_queues_have_data(MSFilter *f); + +void ms_filter_uninit(MSFilter *obj); +void ms_filter_destroy(MSFilter *f); + +#define ms_filter_get_mingran(f) ((f)->r_mingran) +#define ms_filter_set_mingran(f,gran) ((f)->r_mingran=(gran)) + +#define LINK_DEFAULT 0 +#define LINK_FIFO 1 +#define LINK_QUEUE 2 + + +#define MSFILTER_VERSION(a,b,c) (((a)<<2)|((b)<<1)|(c)) + +enum _MSFilterType +{ + MS_FILTER_DISK_IO, + MS_FILTER_AUDIO_CODEC, + MS_FILTER_VIDEO_CODEC, + MS_FILTER_NET_IO, + MS_FILTER_VIDEO_IO, + MS_FILTER_AUDIO_IO, + MS_FILTER_OTHER +}; + +typedef enum _MSFilterType MSFilterType; + + +/* find the first codec in the left part of the stream */ +MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type); + +struct _MSFilterInfo +{ + gchar *name; + gint version; + MSFilterType type; + MSFilterNewFunc constructor; + char *description; /*some textual information*/ +}; + +typedef struct _MSFilterInfo MSFilterInfo; + +void ms_filter_register(MSFilterInfo *finfo); +void ms_filter_unregister(MSFilterInfo *finfo); +MSFilterInfo * ms_filter_get_by_name(const gchar *name); + +MSFilter * ms_filter_new_with_name(const gchar *name); + + + +extern GList *filter_list; +#define MS_FILTER_INFO(obj) ((MSFilterInfo*)obj) + +void swap_buffer(gchar *buffer, gint len); + + +#endif diff --git a/linphone/mediastreamer/msnosync.c b/linphone/mediastreamer/msnosync.c new file mode 100644 index 000000000..af5141c0b --- /dev/null +++ b/linphone/mediastreamer/msnosync.c @@ -0,0 +1,82 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msnosync.h" + +static MSNoSyncClass *ms_nosync_class=NULL; + +void ms_nosync_init(MSNoSync *sync) +{ + ms_sync_init(MS_SYNC(sync)); + MS_SYNC(sync)->attached_filters=sync->filters; + memset(sync->filters,0,MSNOSYNC_MAX_FILTERS*sizeof(MSFilter*)); + MS_SYNC(sync)->samples_per_tick=160; + sync->started=0; +} + +void ms_nosync_class_init(MSNoSyncClass *klass) +{ + ms_sync_class_init(MS_SYNC_CLASS(klass)); + MS_SYNC_CLASS(klass)->max_filters=MSNOSYNC_MAX_FILTERS; + MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_nosync_synchronize; + MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_nosync_destroy; + /* no need to overload these function*/ + MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic; + MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic; +} + +void ms_nosync_destroy(MSNoSync *nosync) +{ + g_free(nosync); +} + +/* the synchronization function that does nothing*/ +void ms_nosync_synchronize(MSNoSync *nosync) +{ + gint32 time; + if (nosync->started==0){ + gettimeofday(&nosync->start,NULL); + nosync->started=1; + } + gettimeofday(&nosync->current,NULL); + MS_SYNC(nosync)->ticks++; + /* update the time, we are supposed to work at 8000 Hz */ + time=((nosync->current.tv_sec-nosync->start.tv_sec)*1000) + + ((nosync->current.tv_usec-nosync->start.tv_usec)/1000); + MS_SYNC(nosync)->time=time; + return; +} + + +MSSync *ms_nosync_new() +{ + MSNoSync *nosync; + + nosync=g_malloc(sizeof(MSNoSync)); + ms_nosync_init(nosync); + if (ms_nosync_class==NULL) + { + ms_nosync_class=g_new(MSNoSyncClass,1); + ms_nosync_class_init(ms_nosync_class); + } + MS_SYNC(nosync)->klass=MS_SYNC_CLASS(ms_nosync_class); + return(MS_SYNC(nosync)); +} diff --git a/linphone/mediastreamer/msnosync.h b/linphone/mediastreamer/msnosync.h new file mode 100644 index 000000000..eef52d457 --- /dev/null +++ b/linphone/mediastreamer/msnosync.h @@ -0,0 +1,60 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mssync.h" + +#include +#define MSNOSYNC_MAX_FILTERS 10 + +/* MSNoSync derivates from MSSync base class*/ + +typedef struct _MSNoSync +{ + /* the MSSync must be the first field of the object in order to the object mechanism to work*/ + MSSync sync; + MSFilter *filters[MSNOSYNC_MAX_FILTERS]; + int started; + struct timeval start,current; +} MSNoSync; + + +typedef struct _MSNoSyncClass +{ + /* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/ + MSSyncClass parent_class; +} MSNoSyncClass; + + +/*private*/ + +void ms_nosync_init(MSNoSync *sync); +void ms_nosync_class_init(MSNoSyncClass *sync); + +void ms_nosync_destroy(MSNoSync *nosync); +void ms_nosync_synchronize(MSNoSync *nosync); + +/*public*/ + +/* casts a MSSync object into a MSNoSync */ +#define MS_NOSYNC(sync) ((MSNoSync*)(sync)) +/* casts a MSSync class into a MSNoSync class */ +#define MS_NOSYNC_CLASS(klass) ((MSNoSyncClass*)(klass)) + +MSSync *ms_nosync_new(); diff --git a/linphone/mediastreamer/msossread.c b/linphone/mediastreamer/msossread.c new file mode 100644 index 000000000..4f486f14b --- /dev/null +++ b/linphone/mediastreamer/msossread.c @@ -0,0 +1,150 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msossread.h" +#include "mssync.h" +#include +#include +#include +#include + +MSFilterInfo oss_read_info={ + "OSS read", + 0, + MS_FILTER_AUDIO_IO, + ms_oss_read_new, + NULL +}; + +static MSOssReadClass *msossreadclass=NULL; + +MSFilter * ms_oss_read_new() +{ + MSOssRead *w; + + if (msossreadclass==NULL) + { + msossreadclass=g_new(MSOssReadClass,1); + ms_oss_read_class_init( msossreadclass ); + } + + w=g_new(MSOssRead,1); + MS_FILTER(w)->klass=MS_FILTER_CLASS(msossreadclass); + ms_oss_read_init(w); + + return(MS_FILTER(w)); +} + +/* FOR INTERNAL USE*/ +void ms_oss_read_init(MSOssRead *w) +{ + ms_sound_read_init(MS_SOUND_READ(w)); + MS_FILTER(w)->outfifos=w->f_outputs; + MS_FILTER(w)->outfifos[0]=NULL; + w->devid=0; + w->sndcard=NULL; + w->freq=8000; +} + +gint ms_oss_read_set_property(MSOssRead *f,MSFilterProperty prop, void *value) +{ + switch(prop){ + case MS_FILTER_PROPERTY_FREQ: + f->freq=((gint*)value)[0]; + break; + default: + break; + } + return 0; +} +void ms_oss_read_class_init(MSOssReadClass *klass) +{ + ms_sound_read_class_init(MS_SOUND_READ_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_foutputs=1; /* one fifo output only */ + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_oss_read_setup; + MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_oss_read_stop; + MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_read_process; + MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_read_set_property; + MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_read_destroy; + MS_FILTER_CLASS(klass)->w_maxgran=MS_OSS_READ_MAX_GRAN; + MS_FILTER_CLASS(klass)->info=&oss_read_info; + MS_SOUND_READ_CLASS(klass)->set_device=(gint (*)(MSSoundRead*,gint))ms_oss_read_set_device; + MS_SOUND_READ_CLASS(klass)->start=(void (*)(MSSoundRead*))ms_oss_read_start; + MS_SOUND_READ_CLASS(klass)->stop=(void (*)(MSSoundRead*))ms_oss_read_stop; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssRead"); + //ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_CAN_SYNC|FILTER_IS_SOURCE); +} + +void ms_oss_read_destroy( MSOssRead *obj) +{ + g_free(obj); +} + +void ms_oss_read_process(MSOssRead *f) +{ + MSFifo *fifo; + char *p; + fifo=f->f_outputs[0]; + + g_return_if_fail(f->sndcard!=NULL); + g_return_if_fail(f->gran>0); + + if (snd_card_can_read(f->sndcard)){ + int got; + ms_fifo_get_write_ptr(fifo,f->gran,(void**)&p); + g_return_if_fail(p!=NULL); + got=snd_card_read(f->sndcard,p,f->gran); + if (got>=0 && got!=f->gran) ms_fifo_update_write_ptr(fifo,got); + } +} + + +void ms_oss_read_start(MSOssRead *r) +{ + g_return_if_fail(r->devid!=-1); + r->sndcard=snd_card_manager_get_card(snd_card_manager,r->devid); + g_return_if_fail(r->sndcard!=NULL); + /* open the device for an audio telephony signal with minimum latency */ + snd_card_open_r(r->sndcard,16,0,r->freq); + r->gran=(512*r->freq)/8000; + +} + +void ms_oss_read_stop(MSOssRead *w) +{ + g_return_if_fail(w->devid!=-1); + g_return_if_fail(w->sndcard!=NULL); + snd_card_close_r(w->sndcard); + w->sndcard=NULL; +} + + +void ms_oss_read_setup(MSOssRead *f, MSSync *sync) +{ + f->sync=sync; + ms_oss_read_start(f); +} + + +gint ms_oss_read_set_device(MSOssRead *r,gint devid) +{ + r->devid=devid; + return 0; +} diff --git a/linphone/mediastreamer/msossread.h b/linphone/mediastreamer/msossread.h new file mode 100644 index 000000000..89d5a40b1 --- /dev/null +++ b/linphone/mediastreamer/msossread.h @@ -0,0 +1,77 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef MSOSSREAD_H +#define MSOSSREAD_H + +#include "mssoundread.h" +#include "sndcard.h" +#include "mssync.h" + + +/*this is the class that implements oss writing sink filter*/ + +#define MS_OSS_READ_MAX_INPUTS 1 /* max output per filter*/ + +#define MS_OSS_READ_MAX_GRAN (512*2) /* the maximum granularity*/ + +struct _MSOssRead +{ + /* the MSOssRead derivates from MSSoundRead so the MSSoundRead object MUST be the first of the MSOssRead object + in order to the object mechanism to work*/ + MSSoundRead filter; + MSFifo *f_outputs[MS_OSS_READ_MAX_INPUTS]; + MSSync *sync; + SndCard *sndcard; + gint freq; + gint devid; /* the sound device id it depends on*/ + gint gran; + gint flags; +#define START_REQUESTED 1 +#define STOP_REQUESTED 2 +}; + +typedef struct _MSOssRead MSOssRead; + +struct _MSOssReadClass +{ + /* the MSOssRead derivates from MSSoundRead, so the MSSoundRead class MUST be the first of the MSOssRead class + in order to the class mechanism to work*/ + MSSoundReadClass parent_class; +}; + +typedef struct _MSOssReadClass MSOssReadClass; + +/* PUBLIC */ +#define MS_OSS_READ(filter) ((MSOssRead*)(filter)) +#define MS_OSS_READ_CLASS(klass) ((MSOssReadClass*)(klass)) +MSFilter * ms_oss_read_new(void); +gint ms_oss_read_set_device(MSOssRead *w,gint devid); +void ms_oss_read_start(MSOssRead *w); +void ms_oss_read_stop(MSOssRead *w); + +/* FOR INTERNAL USE*/ +void ms_oss_read_init(MSOssRead *r); +void ms_oss_read_class_init(MSOssReadClass *klass); +void ms_oss_read_destroy( MSOssRead *obj); +void ms_oss_read_process(MSOssRead *f); +void ms_oss_read_setup(MSOssRead *f, MSSync *sync); + + +#endif diff --git a/linphone/mediastreamer/msosswrite.c b/linphone/mediastreamer/msosswrite.c new file mode 100644 index 000000000..bfd78dc50 --- /dev/null +++ b/linphone/mediastreamer/msosswrite.c @@ -0,0 +1,249 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msosswrite.h" +#include "mssync.h" +#include +#include + +MSFilterInfo oss_write_info={ + "OSS write", + 0, + MS_FILTER_OTHER, + ms_oss_write_new, + NULL +}; + + +static MSOssWriteClass *msosswriteclass=NULL; + +MSFilter * ms_oss_write_new() +{ + MSOssWrite *w; + + if (msosswriteclass==NULL) + { + msosswriteclass=g_new(MSOssWriteClass,1); + ms_oss_write_class_init( msosswriteclass ); + } + w=g_new(MSOssWrite,1); + MS_FILTER(w)->klass=MS_FILTER_CLASS(msosswriteclass); + ms_oss_write_init(w); + return(MS_FILTER(w)); +} + +/* FOR INTERNAL USE*/ +void ms_oss_write_init(MSOssWrite *w) +{ + ms_sound_write_init(MS_SOUND_WRITE(w)); + MS_FILTER(w)->infifos=w->f_inputs; + MS_FILTER(w)->infifos[0]=NULL; + MS_FILTER(w)->r_mingran=512; /* very few cards can do that...*/ + w->devid=0; + w->sndcard=NULL; + w->freq=8000; + w->channels=1; + w->dtmf_time=-1; +} + +gint ms_oss_write_set_property(MSOssWrite *f,MSFilterProperty prop, void *value) +{ + switch(prop){ + case MS_FILTER_PROPERTY_FREQ: + f->freq=((gint*)value)[0]; + break; + case MS_FILTER_PROPERTY_CHANNELS: + f->channels=((gint*)value)[0]; + break; + default: + break; + } + return 0; +} + +void ms_oss_write_class_init(MSOssWriteClass *klass) +{ + ms_sound_write_class_init(MS_SOUND_WRITE_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_finputs=1; /* one fifo input only */ + MS_FILTER_CLASS(klass)->r_maxgran=MS_OSS_WRITE_DEF_GRAN; + MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_write_process; + MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_write_destroy; + MS_FILTER_CLASS(klass)->setup= (MSFilterSetupFunc)ms_oss_write_setup; + MS_FILTER_CLASS(klass)->unsetup= (MSFilterSetupFunc)ms_oss_write_stop; + MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_write_set_property; + MS_FILTER_CLASS(klass)->info=&oss_write_info; + MS_SOUND_WRITE_CLASS(klass)->set_device=(gint (*)(MSSoundWrite*,gint))ms_oss_write_set_device; + MS_SOUND_WRITE_CLASS(klass)->start=(void (*)(MSSoundWrite*))ms_oss_write_start; + MS_SOUND_WRITE_CLASS(klass)->stop=(void (*)(MSSoundWrite*))ms_oss_write_stop; + MS_SOUND_WRITE_CLASS(klass)->set_level=(void (*)(MSSoundWrite*, gint))ms_oss_write_set_level; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssWrite"); +} + +void ms_oss_write_destroy( MSOssWrite *obj) +{ + + g_free(obj); +} + +void ms_oss_write_process(MSOssWrite *f) +{ + MSFifo *fifo; + void *p; + int i; + gint gran=ms_filter_get_mingran(MS_FILTER(f)); + + /* always consume something */ + fifo=f->f_inputs[0]; + ms_fifo_get_read_ptr(fifo,gran,&p); + if (p==NULL) { + g_warning("Not enough data: gran=%i.",gran); + return; + } + g_return_if_fail(f->sndcard!=NULL); + if (f->dtmf_time!=-1){ + gint16 *buf=(gint16*)p; + /* generate a DTMF*/ + for(i=0;idtmf_time*f->lowfreq)); + buf[i]+=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->highfreq)); + f->dtmf_time++; + //printf("buf[%i]=%i\n",i,buf[i]); + } + if (f->dtmf_time>f->dtmf_duration) f->dtmf_time=-1; /*finished*/ + } + snd_card_write(f->sndcard,p,gran); +} + +void ms_oss_write_start(MSOssWrite *w) +{ + //gint bsize; + g_return_if_fail(w->devid!=-1); + w->sndcard=snd_card_manager_get_card(snd_card_manager,w->devid); + g_return_if_fail(w->sndcard!=NULL); + /* open the device for an audio telephony signal with minimum latency */ + snd_card_open_w(w->sndcard,16,w->channels==2,w->freq); + w->bsize=snd_card_get_bsize(w->sndcard); + //MS_FILTER(w)->r_mingran=w->bsize; + //ms_sync_set_samples_per_tick(MS_FILTER(w)->sync,bsize); +} + +void ms_oss_write_stop(MSOssWrite *w) +{ + g_return_if_fail(w->devid!=-1); + g_return_if_fail(w->sndcard!=NULL); + snd_card_close_w(w->sndcard); + w->sndcard=NULL; +} + +void ms_oss_write_set_level(MSOssWrite *w,gint a) +{ + +} + +gint ms_oss_write_set_device(MSOssWrite *w, gint devid) +{ + w->devid=devid; + return 0; +} + +void ms_oss_write_setup(MSOssWrite *r) +{ + //g_message("starting MSOssWrite.."); + ms_oss_write_start(r); +} + + + +void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf){ + + w->dtmf_duration=0.1*w->freq; + switch(dtmf){ + case '0': + w->lowfreq=941; + w->highfreq=1336; + break; + case '1': + w->lowfreq=697; + w->highfreq=1209; + break; + case '2': + w->lowfreq=697; + w->highfreq=1336; + break; + case '3': + w->lowfreq=697; + w->highfreq=1477; + break; + case '4': + w->lowfreq=770; + w->highfreq=1209; + break; + case '5': + w->lowfreq=770; + w->highfreq=1336; + break; + case '6': + w->lowfreq=770; + w->highfreq=1477; + break; + case '7': + w->lowfreq=852; + w->highfreq=1209; + break; + case '8': + w->lowfreq=852; + w->highfreq=1336; + break; + case '9': + w->lowfreq=852; + w->highfreq=1477; + break; + case '*': + w->lowfreq=941; + w->highfreq=1209; + break; + case '#': + w->lowfreq=941; + w->highfreq=1477; + break; + case 'A': + w->lowfreq=697; + w->highfreq=1633; + break; + case 'B': + w->lowfreq=770; + w->highfreq=1633; + break; + case 'C': + w->lowfreq=852; + w->highfreq=1633; + break; + case 'D': + w->lowfreq=941; + w->highfreq=1633; + break; + default: + g_warning("Not a dtmf key."); + return; + } + w->lowfreq=w->lowfreq/w->freq; + w->highfreq=w->highfreq/w->freq; + w->dtmf_time=0; +} diff --git a/linphone/mediastreamer/msosswrite.h b/linphone/mediastreamer/msosswrite.h new file mode 100644 index 000000000..d47753414 --- /dev/null +++ b/linphone/mediastreamer/msosswrite.h @@ -0,0 +1,78 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef MSOSSWRITE_H +#define MSOSSWRITE_H + +#include "mssoundwrite.h" +#include "sndcard.h" + +/*this is the class that implements oss writing sink filter*/ + +#define MS_OSS_WRITE_MAX_INPUTS 1 /* max output per filter*/ + +#define MS_OSS_WRITE_DEF_GRAN (512*2) /* the default granularity*/ + +struct _MSOssWrite +{ + /* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite object MUST be the first of the MSOssWrite object + in order to the object mechanism to work*/ + MSSoundWrite filter; + MSFifo *f_inputs[MS_OSS_WRITE_MAX_INPUTS]; + gint devid; /* the sound device id it depends on*/ + SndCard *sndcard; + gint bsize; + gint freq; + gint channels; + gdouble lowfreq; + gdouble highfreq; + gint dtmf_time; + gint dtmf_duration; +}; + +typedef struct _MSOssWrite MSOssWrite; + +struct _MSOssWriteClass +{ + /* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite class MUST be the first of the MSOssWrite class + in order to the class mechanism to work*/ + MSSoundWriteClass parent_class; +}; + +typedef struct _MSOssWriteClass MSOssWriteClass; + +/* PUBLIC */ +#define MS_OSS_WRITE(filter) ((MSOssWrite*)(filter)) +#define MS_OSS_WRITE_CLASS(klass) ((MSOssWriteClass*)(klass)) +MSFilter * ms_oss_write_new(void); +gint ms_oss_write_set_device(MSOssWrite *w,gint devid); +void ms_oss_write_start(MSOssWrite *w); +void ms_oss_write_stop(MSOssWrite *w); +void ms_oss_write_set_level(MSOssWrite *w, gint level); +void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf); + +/* FOR INTERNAL USE*/ +void ms_oss_write_init(MSOssWrite *r); +void ms_oss_write_setup(MSOssWrite *r); +void ms_oss_write_class_init(MSOssWriteClass *klass); +void ms_oss_write_destroy( MSOssWrite *obj); +void ms_oss_write_process(MSOssWrite *f); + + +#endif diff --git a/linphone/mediastreamer/msqdispatcher.c b/linphone/mediastreamer/msqdispatcher.c new file mode 100644 index 000000000..6bd073b9b --- /dev/null +++ b/linphone/mediastreamer/msqdispatcher.c @@ -0,0 +1,91 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a dispatcher of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msqdispatcher.h" + +static MSQdispatcherClass *ms_qdispatcher_class=NULL; + +MSFilter * ms_qdispatcher_new(void) +{ + MSQdispatcher *obj; + obj=g_malloc(sizeof(MSQdispatcher)); + if (ms_qdispatcher_class==NULL){ + ms_qdispatcher_class=g_malloc0(sizeof(MSQdispatcherClass)); + ms_qdispatcher_class_init(ms_qdispatcher_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_qdispatcher_class); + ms_qdispatcher_init(obj); + return MS_FILTER(obj); +} + + +void ms_qdispatcher_init(MSQdispatcher *obj) +{ + ms_filter_init(MS_FILTER(obj)); + + MS_FILTER(obj)->inqueues=obj->q_inputs; + MS_FILTER(obj)->outqueues=obj->q_outputs; + memset(obj->q_inputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_INPUTS); + memset(obj->q_outputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_OUTPUTS); +} + + + +void ms_qdispatcher_class_init(MSQdispatcherClass *klass) +{ + MSFilterClass *parent_class=MS_FILTER_CLASS(klass); + ms_filter_class_init(parent_class); + ms_filter_class_set_name(parent_class,"qdispatcher"); + parent_class->max_qinputs=MS_QDISPATCHER_MAX_INPUTS; + parent_class->max_qoutputs=MS_QDISPATCHER_MAX_OUTPUTS; + + parent_class->destroy=(MSFilterDestroyFunc)ms_qdispatcher_destroy; + parent_class->process=(MSFilterProcessFunc)ms_qdispatcher_process; +} + + +void ms_qdispatcher_destroy( MSQdispatcher *obj) +{ + g_free(obj); +} + +void ms_qdispatcher_process(MSQdispatcher *obj) +{ + gint i; + MSQueue *inq=obj->q_inputs[0]; + + if (inq!=NULL){ + MSQueue *outq; + MSMessage *m1,*m2; + while ( (m1=ms_queue_get(inq))!=NULL){ + /* dispatch incoming messages to output queues */ + for (i=0;iq_outputs[i]; + if (outq!=NULL){ + m2=ms_message_dup(m1); + ms_queue_put(outq,m2); + } + } + ms_message_destroy(m1); + } + } + +} diff --git a/linphone/mediastreamer/msqdispatcher.h b/linphone/mediastreamer/msqdispatcher.h new file mode 100644 index 000000000..3b0c566d9 --- /dev/null +++ b/linphone/mediastreamer/msqdispatcher.h @@ -0,0 +1,60 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a dispatcher of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSQDISPATCHER_H +#define MSQDISPATCHER_H + +#include "msfilter.h" + + +/*this is the class that implements a qdispatcher filter*/ + +#define MS_QDISPATCHER_MAX_INPUTS 1 +#define MS_QDISPATCHER_MAX_OUTPUTS 5 + +typedef struct _MSQdispatcher +{ + /* the MSQdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSQdispatcher object + in order to the object mechanism to work*/ + MSFilter filter; + MSQueue *q_inputs[MS_QDISPATCHER_MAX_INPUTS]; + MSQueue *q_outputs[MS_QDISPATCHER_MAX_OUTPUTS]; +} MSQdispatcher; + +typedef struct _MSQdispatcherClass +{ + /* the MSQdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSQdispatcher class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSQdispatcherClass; + +/* PUBLIC */ +#define MS_QDISPATCHER(filter) ((MSQdispatcher*)(filter)) +#define MS_QDISPATCHER_CLASS(klass) ((MSQdispatcherClass*)(klass)) +MSFilter * ms_qdispatcher_new(void); + +/* FOR INTERNAL USE*/ +void ms_qdispatcher_init(MSQdispatcher *r); +void ms_qdispatcher_class_init(MSQdispatcherClass *klass); +void ms_qdispatcher_destroy( MSQdispatcher *obj); +void ms_qdispatcher_process(MSQdispatcher *r); + +#endif diff --git a/linphone/mediastreamer/msqueue.c b/linphone/mediastreamer/msqueue.c new file mode 100644 index 000000000..703fab6cb --- /dev/null +++ b/linphone/mediastreamer/msqueue.c @@ -0,0 +1,58 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msqueue.h" +#include + +MSQueue * ms_queue_new() +{ + MSQueue *q=g_malloc(sizeof(MSQueue)); + memset(q,0,sizeof(MSQueue)); + return q; +} + +MSMessage *ms_queue_get(MSQueue *q) +{ + MSMessage *b=q->last; + if (b==NULL) return NULL; + q->last=b->prev; + if (b->prev==NULL) q->first=NULL; /* it was the only element of the queue*/ + q->size--; + b->next=b->prev=NULL; + return(b); +} + +void ms_queue_put(MSQueue *q, MSMessage *m) +{ + MSMessage *mtmp=q->first; + g_return_if_fail(m!=NULL); + q->first=m; + m->next=mtmp; + if (mtmp!=NULL) + { + mtmp->prev=m; + } + else q->last=m; /* it was the first element of the q */ + q->size++; +} + +MSMessage *ms_queue_peek_last(MSQueue *q){ + return q->last; +} diff --git a/linphone/mediastreamer/msqueue.h b/linphone/mediastreamer/msqueue.h new file mode 100644 index 000000000..10bb8791b --- /dev/null +++ b/linphone/mediastreamer/msqueue.h @@ -0,0 +1,51 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSQUEUE_H +#define MSQUEUE_H + +#include "msbuffer.h" + +/* for the moment these are stupid queues limited to one element*/ + +typedef struct _MSQueue +{ + MSMessage *first; + MSMessage *last; + gint size; + void *prev_data; /*user data, usually the writting filter*/ + void *next_data; /* user data, usually the reading filter*/ +}MSQueue; + + +MSQueue * ms_queue_new(); + +MSMessage *ms_queue_get(MSQueue *q); + +void ms_queue_put(MSQueue *q, MSMessage *m); + +MSMessage *ms_queue_peek_last(MSQueue *q); + +#define ms_queue_can_get(q) ( (q)->size!=0 ) + +#define ms_queue_destroy(q) g_free(q) + + +#endif diff --git a/linphone/mediastreamer/msread.c b/linphone/mediastreamer/msread.c new file mode 100644 index 000000000..f05e85e0d --- /dev/null +++ b/linphone/mediastreamer/msread.c @@ -0,0 +1,186 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msread.h" +#include "mssync.h" +#include +#include +#include +#include +#include + +static MSReadClass *ms_read_class=NULL; + +gint ms_read_open(MSRead *r, gchar *name); + +MSFilter * ms_read_new(char *name) +{ + MSRead *r; + + r=g_new(MSRead,1); + ms_read_init(r); + if (ms_read_class==NULL) + { + ms_read_class=g_new(MSReadClass,1); + ms_read_class_init(ms_read_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_read_class); + r->fd=-1; + if (name!=NULL) ms_read_open(r,name); + return(MS_FILTER(r)); +} + + + +gint ms_read_open(MSRead *r, gchar *name) +{ + gint fd; + fd=open(name,O_RDONLY); + if (fd<0) { + r->fd=-1; + g_warning("ms_read_new: cannot open %s : %s",name,strerror(errno)); + return -1; + } + r->fd=fd; + if (strstr(name,".wav")!=NULL){ + /* skip the header */ + lseek(fd,20,SEEK_SET); +#ifdef WORDS_BIGENDIAN + r->need_swap=1; +#else + r->need_swap=0; +#endif + } + r->state=MS_READ_STATE_STARTED; + return 0; +} + +/* FOR INTERNAL USE*/ +void ms_read_init(MSRead *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->outfifos=r->foutputs; + MS_FILTER(r)->outqueues=r->qoutputs; + memset(r->foutputs,0,sizeof(MSFifo*)*MSREAD_MAX_OUTPUTS); + memset(r->qoutputs,0,sizeof(MSQueue*)*MSREAD_MAX_OUTPUTS); + r->fd=-1; + r->gran=320; + r->state=MS_READ_STATE_STOPPED; + r->need_swap=0; + r->rate=8000; +} + +gint ms_read_set_property(MSRead *f,MSFilterProperty prop, void *value) +{ + switch(prop){ + case MS_FILTER_PROPERTY_FREQ: + f->rate=((gint*)value)[0]; + break; + default: + break; + } + return 0; +} + +void ms_read_class_init(MSReadClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskreader"); + ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE); + MS_FILTER_CLASS(klass)->max_foutputs=MSREAD_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->max_qoutputs=MSREAD_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->w_maxgran=MSREAD_DEF_GRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_read_destroy; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_read_setup; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_read_process; + MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_read_set_property; +} + +void ms_read_process(MSRead *r) +{ + MSFifo *f; + MSQueue *q; + MSMessage *msg=NULL; + int err; + gint gran=r->gran; + void *p; + + f=r->foutputs[0]; + if ((f!=NULL) && (r->state==MS_READ_STATE_STARTED)) + { + ms_fifo_get_write_ptr(f,gran,&p); + if (p!=NULL) + { + err=read(r->fd,p,gran); + if (err<0) + { + /* temp: */ + g_warning("ms_read_process: failed to read: %s.\n",strerror(errno)); + } + else if (errstate=MS_READ_STATE_STOPPED; + close(r->fd); + r->fd=-1; + } + if (r->need_swap) swap_buffer(p,gran); + } + } + /* process output queues*/ + q=r->qoutputs[0]; + if ((q!=NULL) && (r->fd>0)) + { + msg=ms_message_new(r->gran); + err=read(r->fd,msg->data,r->gran); + if (err>0){ + msg->size=err; + ms_queue_put(q,msg); + if (r->need_swap) swap_buffer(msg->data,r->gran); + }else{ + ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL); + ms_trace("End of file reached."); + r->state=MS_READ_STATE_STOPPED; + } + } +} + +void ms_read_destroy( MSRead *obj) +{ + if (obj->fd!=0) close(obj->fd); + g_free(obj); +} + +gint ms_read_close(MSRead *obj) +{ + if (obj->fd!=0) { + close(obj->fd); + obj->fd=-1; + obj->state=MS_READ_STATE_STOPPED; + } + return 0; +} + + +void ms_read_setup(MSRead *r, MSSync *sync) +{ + r->sync=sync; + r->gran=(r->rate*sync->interval/1000)*2; +} diff --git a/linphone/mediastreamer/msread.h b/linphone/mediastreamer/msread.h new file mode 100644 index 000000000..93177f38b --- /dev/null +++ b/linphone/mediastreamer/msread.h @@ -0,0 +1,80 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSREAD_H +#define MSREAD_H + +#include "msfilter.h" +#include "mssync.h" + +/*this is the class that implements file reading source filter*/ + +#define MSREAD_MAX_OUTPUTS 1 /* max output per filter*/ + +#define MSREAD_DEF_GRAN 640 /* the default granularity*/ + +typedef enum{ + MS_READ_STATE_STARTED, + MS_READ_STATE_STOPPED, + MS_READ_STATE_EOF +}MSReadState; + +typedef struct _MSRead +{ + /* the MSRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSRead object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *foutputs[MSREAD_MAX_OUTPUTS]; + MSQueue *qoutputs[MSREAD_MAX_OUTPUTS]; + MSSync *sync; + gint rate; + gint fd; /* the file descriptor of the file being read*/ + gint gran; /*granularity*/ /* for use with queues */ + gint need_swap; + gint state; +} MSRead; + +typedef struct _MSReadClass +{ + /* the MSRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSRead class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSReadClass; + +/* PUBLIC */ +#define MS_READ(filter) ((MSRead*)(filter)) +#define MS_READ_CLASS(klass) ((MSReadClass*)(klass)) +MSFilter * ms_read_new(char *name); +/* set the granularity for reading file on disk */ +#define ms_read_set_bufsize(filter,sz) (filter)->gran=(sz) + +/* FOR INTERNAL USE*/ +void ms_read_init(MSRead *r); +void ms_read_class_init(MSReadClass *klass); +void ms_read_destroy( MSRead *obj); +void ms_read_process(MSRead *r); +void ms_read_setup(MSRead *r, MSSync *sync); + +typedef enum{ + MS_READ_EVENT_EOF /* end of file */ +} MSReadEvent; + + +#endif diff --git a/linphone/mediastreamer/msringplayer.c b/linphone/mediastreamer/msringplayer.c new file mode 100644 index 000000000..dae8e7594 --- /dev/null +++ b/linphone/mediastreamer/msringplayer.c @@ -0,0 +1,255 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msringplayer.h" +#include "mssync.h" +#include +#include +#include +#include +#include +#include +#include + +#include "waveheader.h" + +#define WAVE_HEADER_OFFSET sizeof(wave_header_t) + +enum { PLAY_RING, PLAY_SILENCE}; + +static int supported_freq[6]={8000,11025,16000,22050,32000,44100}; + +gint ms_ring_player_set_property(MSRingPlayer *f,MSFilterProperty prop, void *value); + +gint freq_is_supported(gint freq){ + int i; + for (i=0;i<6;i++){ + if (abs(supported_freq[i]-freq)<50) return supported_freq[i]; + } + return 0; +} + +static MSRingPlayerClass *ms_ring_player_class=NULL; + +/** + * ms_ring_player_new: + * @name: The path to the 16-bit 8khz raw file to be played as a ring. + * @seconds: The number of seconds that separates two rings. + * + * Allocates a new MSRingPlayer object. + * + * + * Returns: a pointer the the object, NULL if name could not be open. + */ +MSFilter * ms_ring_player_new(char *name, gint seconds) +{ + MSRingPlayer *r; + int fd=-1; + + if ((name!=NULL) && (strlen(name)!=0)) + { + fd=open(name,O_RDONLY); + if (fd<0) + { + g_warning("ms_ring_player_new: failed to open %s.\n",name); + return NULL; + } + + }else { + g_warning("ms_ring_player_new: Bad file name"); + return NULL; + } + + r=g_new(MSRingPlayer,1); + ms_ring_player_init(r); + if (ms_ring_player_class==NULL) + { + ms_ring_player_class=g_new(MSRingPlayerClass,1); + ms_ring_player_class_init(ms_ring_player_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ring_player_class); + + r->fd=fd; + r->silence=seconds; + r->freq=8000; + if (strstr(name,".wav")!=NULL){ + wave_header_t header; + int freq,freq2; + /* read the header */ + size_t ret = read(fd,&header,sizeof(wave_header_t)); + assert( ret == sizeof(wave_header_t) ); + freq=wave_header_get_rate(&header); + if ((freq2=freq_is_supported(freq))>0){ + r->freq=freq2; + }else { + g_warning("Unsupported sampling rate %i",freq); + r->freq=8000; + } + r->channel=wave_header_get_channel(&header); + lseek(fd,WAVE_HEADER_OFFSET,SEEK_SET); +#ifdef WORDS_BIGENDIAN + r->need_swap=1; +#else + r->need_swap=0; +#endif + } + ms_ring_player_set_property(r, MS_FILTER_PROPERTY_FREQ,&r->freq); + r->state=PLAY_RING; + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_ring_player_init(MSRingPlayer *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->outfifos=r->foutputs; + MS_FILTER(r)->outqueues=r->qoutputs; + memset(r->foutputs,0,sizeof(MSFifo*)*MS_RING_PLAYER_MAX_OUTPUTS); + memset(r->qoutputs,0,sizeof(MSQueue*)*MS_RING_PLAYER_MAX_OUTPUTS); + r->fd=-1; + r->current_pos=0; + r->need_swap=0; + r->sync=NULL; +} + +gint ms_ring_player_set_property(MSRingPlayer *f,MSFilterProperty prop, void *value) +{ + switch(prop){ + case MS_FILTER_PROPERTY_FREQ: + f->rate=((gint*)value)[0]*2; + f->silence_bytes=f->silence*f->rate; + if (f->sync!=NULL) + f->gran=(f->rate*f->sync->interval/1000)*2; + break; + default: + break; + } + return 0; +} + +gint ms_ring_player_get_property(MSRingPlayer *f,MSFilterProperty prop, void *value) +{ + switch(prop){ + case MS_FILTER_PROPERTY_FREQ: + ((gint*)value)[0]=f->freq; + + break; + case MS_FILTER_PROPERTY_CHANNELS: + ((gint*)value)[0]=f->channel; + break; + default: + break; + } + return 0; +} + +gint ms_ring_player_get_sample_freq(MSRingPlayer *obj){ + return obj->freq; +} + + +void ms_ring_player_class_init(MSRingPlayerClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ringplay"); + ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE); + MS_FILTER_CLASS(klass)->max_foutputs=MS_RING_PLAYER_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->max_qoutputs=MS_RING_PLAYER_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->w_maxgran=MS_RING_PLAYER_DEF_GRAN; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ring_player_setup; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ring_player_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ring_player_process; + MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ring_player_set_property; + MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ring_player_get_property; +} + +void ms_ring_player_process(MSRingPlayer *r) +{ + MSFifo *f; + gint err; + gint processed=0; + gint gran=r->gran; + char *p; + + g_return_if_fail(gran>0); + /* process output fifos*/ + + f=r->foutputs[0]; + ms_fifo_get_write_ptr(f,gran,(void**)&p); + g_return_if_fail(p!=NULL); + for (processed=0;processedstate){ + case PLAY_RING: + err=read(r->fd,&p[processed],gran-processed); + if (err<0) + { + memset(&p[processed],0,gran-processed); + processed=gran; + g_warning("ms_ring_player_process: failed to read: %s.\n",strerror(errno)); + return; + } + else if (errcurrent_pos=r->silence_bytes; + lseek(r->fd,WAVE_HEADER_OFFSET,SEEK_SET); + r->state=PLAY_SILENCE; + ms_filter_notify_event(MS_FILTER(r),MS_RING_PLAYER_END_OF_RING_EVENT,NULL); + } + if (r->need_swap) swap_buffer(&p[processed],err); + processed+=err; + break; + case PLAY_SILENCE: + err=gran-processed; + if (r->current_pos>err){ + memset(&p[processed],0,err); + r->current_pos-=gran; + processed=gran; + }else{ + memset(&p[processed],0,r->current_pos); + processed+=r->current_pos; + r->state=PLAY_RING; + } + break; + } + } +} + +/** + * ms_ring_player_destroy: + * @obj: A valid MSRingPlayer object. + * + * Destroy a MSRingPlayer object. + * + * + */ + +void ms_ring_player_destroy( MSRingPlayer *obj) +{ + if (obj->fd!=0) close(obj->fd); + g_free(obj); +} + +void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync) +{ + r->sync=sync; + r->gran=(r->rate*r->sync->interval/1000)*r->channel; +} diff --git a/linphone/mediastreamer/msringplayer.h b/linphone/mediastreamer/msringplayer.h new file mode 100644 index 000000000..1f5e67daf --- /dev/null +++ b/linphone/mediastreamer/msringplayer.h @@ -0,0 +1,81 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSRINGPLAYER_H +#define MSRINGPLAYER_H + +#include "msfilter.h" +#include "mssync.h" + + +/*this is the class that implements file reading source filter*/ + +#define MS_RING_PLAYER_MAX_OUTPUTS 1 /* max output per filter*/ + +#define MS_RING_PLAYER_DEF_GRAN 8192 /* the default granularity*/ + +#define MS_RING_PLAYER_END_OF_RING_EVENT 1 + +struct _MSRingPlayer +{ + /* the MSRingPlayer derivates from MSFilter, so the MSFilter object MUST be the first of the MSRingPlayer object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *foutputs[MS_RING_PLAYER_MAX_OUTPUTS]; + MSQueue *qoutputs[MS_RING_PLAYER_MAX_OUTPUTS];\ + MSSync *sync; + gint gran; + gint freq; + gint rate; + gint channel; /* number of interleaved channels */ + gint silence; /* silence time between each ring, in seconds */ + gint state; + gint fd; /* the file descriptor of the file being read*/ + gint silence_bytes; /*silence in number of bytes between each ring */ + gint current_pos; + gint need_swap; +}; + +typedef struct _MSRingPlayer MSRingPlayer; + +struct _MSRingPlayerClass +{ + /* the MSRingPlayer derivates from MSFilter, so the MSFilter class MUST be the first of the MSRingPlayer class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +}; + +typedef struct _MSRingPlayerClass MSRingPlayerClass; + +/* PUBLIC */ +#define MS_RING_PLAYER(filter) ((MSRingPlayer*)(filter)) +#define MS_RING_PLAYER_CLASS(klass) ((MSRingPlayerClass*)(klass)) +MSFilter * ms_ring_player_new(char *name, gint seconds); +gint ms_ring_player_get_sample_freq(MSRingPlayer *obj); + + +/* FOR INTERNAL USE*/ +void ms_ring_player_init(MSRingPlayer *r); +void ms_ring_player_class_init(MSRingPlayerClass *klass); +void ms_ring_player_destroy( MSRingPlayer *obj); +void ms_ring_player_process(MSRingPlayer *r); +#define ms_ring_player_set_bufsize(filter,sz) (filter)->gran=(sz) +void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync); +#endif diff --git a/linphone/mediastreamer/msrtprecv.c b/linphone/mediastreamer/msrtprecv.c new file mode 100644 index 000000000..2c7d40a58 --- /dev/null +++ b/linphone/mediastreamer/msrtprecv.c @@ -0,0 +1,182 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msrtprecv.h" + + +/* some utilities to convert mblk_t to MSMessage and vice-versa */ +MSMessage *msgb_2_ms_message(mblk_t* mp){ + MSMessage *msg; + MSBuffer *msbuf; + if (mp->b_datap->ref_count!=1) return NULL; /* cannot handle properly non-unique buffers*/ + /* create a MSBuffer using the mblk_t buffer */ + msg=ms_message_alloc(); + msbuf=ms_buffer_new_with_buf(mp->b_datap->db_base,mp->b_datap->db_lim-mp->b_datap->db_base, + freemsg,mp); + ms_message_set_buf(msg,msbuf); + msg->size=mp->b_wptr-mp->b_rptr; + msg->data=mp->b_rptr; + return msg; +} + + +static MSRtpRecvClass *ms_rtp_recv_class=NULL; + +MSFilter * ms_rtp_recv_new(void) +{ + MSRtpRecv *r; + + r=g_new(MSRtpRecv,1); + ms_rtp_recv_init(r); + if (ms_rtp_recv_class==NULL) + { + ms_rtp_recv_class=g_new0(MSRtpRecvClass,1); + ms_rtp_recv_class_init(ms_rtp_recv_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_recv_class); + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_rtp_recv_init(MSRtpRecv *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->outfifos=r->f_outputs; + MS_FILTER(r)->outqueues=r->q_outputs; + memset(r->f_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS); + memset(r->q_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS); + r->rtpsession=NULL; + r->stream_started=0; + r->ignore=FALSE; + r->payload_expected=0; +} + +void ms_rtp_recv_class_init(MSRtpRecvClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPRecv"); + MS_FILTER_CLASS(klass)->max_qoutputs=MSRTPRECV_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->max_foutputs=MSRTPRECV_MAX_OUTPUTS; + MS_FILTER_CLASS(klass)->w_maxgran=MSRTPRECV_DEF_GRAN; + ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE); + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_recv_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_recv_process; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_recv_setup; +} + +void ms_rtp_recv_process(MSRtpRecv *r) +{ + MSFifo *fo; + MSQueue *qo; + MSSync *sync= r->sync; + void *d; + mblk_t *mp; + gint len; + gint gran=ms_sync_get_samples_per_tick(MS_SYNC(sync)); + + if (r->rtpsession==NULL) return; + /* process output fifo and output queue*/ + fo=r->f_outputs[0]; + if (fo!=NULL) + { + while( (mp=rtp_session_recvm_with_ts(r->rtpsession,r->prev_ts))!=NULL) { + /* try to get rtp packets and paste them to the output fifo */ + r->stream_started=1; + len=mp->b_cont->b_wptr-mp->b_cont->b_rptr; + ms_fifo_get_write_ptr(fo,len,&d); + if (d!=NULL){ + memcpy(d,mp->b_cont->b_rptr,len); + }else ms_warning("ms_rtp_recv_process: no space on output fifo !"); + freemsg(mp); + } + r->prev_ts+=gran; + + } + qo=r->q_outputs[0]; + if (qo!=NULL) + { + guint32 clock; + gint got=0; + /* we are connected with queues (surely for video)*/ + /* use the sync system time to compute a timestamp */ + PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->send_pt); + if (pt==NULL) { + ms_warning("ms_rtp_recv_process(): NULL RtpPayload- skipping."); + return; + } + clock=(guint32)(((double)sync->time*(double)pt->clock_rate)/1000.0); + /*g_message("Querying packet with timestamp %u",clock);*/ + /* get rtp packet, and send them through the output queue */ + while ( (mp=rtp_session_recvm_with_ts(r->rtpsession,clock))!=NULL ){ + MSMessage *msg; + mblk_t *mdata; + /*g_message("Got packet with timestamp %u",clock);*/ + got++; + r->stream_started=1; + if (!r->ignore){ + gboolean markbit=((rtp_header_t*)mp->b_rptr)->markbit; + mdata=mp->b_cont; + freeb(mp); + msg=msgb_2_ms_message(mdata); + msg->markbit=markbit; + ms_queue_put(qo,msg); + + }else{ + freemsg(mp); + } + } + } +} + +void ms_rtp_recv_destroy( MSRtpRecv *obj) +{ + g_free(obj); +} + +static void __payload_type_changed(RtpSession *session,MSRtpRecv *obj){ + int pt_num=rtp_session_get_recv_payload_type(session); + PayloadType *pt=rtp_profile_get_payload(rtp_session_get_profile(session),pt_num); + if (pt==NULL){ + /* sip phone should ignore payload types they don't understand */ + g_warning("Ignoring payload type %i",pt_num); + obj->ignore=TRUE; + }else{ + if (obj->ignore) g_warning("payload type is coming back to something known"); + obj->ignore=FALSE; + } +} + +RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session) +{ + RtpSession *old=obj->rtpsession; + obj->rtpsession=session; + rtp_session_signal_connect(session,"payload_type_changed",(RtpCallback)__payload_type_changed,(unsigned long)obj); + obj->prev_ts=0; + return old; +} + + +void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync) +{ + r->sync=sync; + r->stream_started=0; +} diff --git a/linphone/mediastreamer/msrtprecv.h b/linphone/mediastreamer/msrtprecv.h new file mode 100644 index 000000000..e2c91083f --- /dev/null +++ b/linphone/mediastreamer/msrtprecv.h @@ -0,0 +1,82 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSRTPRECV_H +#define MSRTPRECV_H + +#include "msfilter.h" +#include "mssync.h" + +/* because of a conflict between config.h from oRTP and config.h from linphone:*/ +#undef PACKAGE +#undef VERSION +#include + +/*this is the class that implements a copy filter*/ + +#define MSRTPRECV_MAX_OUTPUTS 1 /* max output per filter*/ + +#define MSRTPRECV_DEF_GRAN 320 /* the default granularity*/ + +struct _MSRtpRecv +{ + /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_outputs[MSRTPRECV_MAX_OUTPUTS]; + MSQueue *q_outputs[MSRTPRECV_MAX_OUTPUTS]; + MSSync *sync; + RtpSession *rtpsession; + guint32 prev_ts; + gint stream_started; + gint payload_expected; + gboolean ignore; +}; + +typedef struct _MSRtpRecv MSRtpRecv; + +struct _MSRtpRecvClass +{ + /* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +}; + +typedef struct _MSRtpRecvClass MSRtpRecvClass; + +/* PUBLIC */ +#define MS_RTP_RECV(filter) ((MSRtpRecv*)(filter)) +#define MS_RTP_RECV_CLASS(klass) ((MSRtpRecvClass*)(klass)) +MSFilter * ms_rtp_recv_new(void); +RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session); +#define ms_rtp_recv_unset_session(obj) (ms_rtp_recv_set_session((obj),NULL)) +#define ms_rtp_recv_get_session(obj) ((obj)->rtpsession) + + + +/* FOR INTERNAL USE*/ +void ms_rtp_recv_init(MSRtpRecv *r); +void ms_rtp_recv_class_init(MSRtpRecvClass *klass); +void ms_rtp_recv_destroy( MSRtpRecv *obj); +void ms_rtp_recv_process(MSRtpRecv *r); +void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync); + +#endif diff --git a/linphone/mediastreamer/msrtpsend.c b/linphone/mediastreamer/msrtpsend.c new file mode 100644 index 000000000..414bf597c --- /dev/null +++ b/linphone/mediastreamer/msrtpsend.c @@ -0,0 +1,213 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msrtpsend.h" +#include +#include "mssync.h" +#include "mscodec.h" + + + +static MSRtpSendClass *ms_rtp_send_class=NULL; + +MSFilter * ms_rtp_send_new(void) +{ + MSRtpSend *r; + + r=g_new(MSRtpSend,1); + + if (ms_rtp_send_class==NULL) + { + ms_rtp_send_class=g_new(MSRtpSendClass,1); + ms_rtp_send_class_init(ms_rtp_send_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_send_class); + ms_rtp_send_init(r); + return(MS_FILTER(r)); +} + + +void ms_rtp_send_init(MSRtpSend *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->inqueues=r->q_inputs; + MS_FILTER(r)->r_mingran=MSRTPSEND_DEF_GRAN; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS); + memset(r->q_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS); + r->rtpsession=NULL; + r->ts=0; + r->ts_inc=0; + r->flags=0; + r->delay=0; +} + +void ms_rtp_send_class_init(MSRtpSendClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPSend"); + MS_FILTER_CLASS(klass)->max_qinputs=MSRTPSEND_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_finputs=MSRTPSEND_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=MSRTPSEND_DEF_GRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_send_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_send_process; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_send_setup; +} + +void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size) +{ + r->ts_inc=ts_inc; + r->packet_size=payload_size; + if (r->ts_inc!=0) r->flags|=RTPSEND_CONFIGURED; + else r->flags&=~RTPSEND_CONFIGURED; + MS_FILTER(r)->r_mingran=payload_size; + /*g_message("ms_rtp_send_set_timing: ts_inc=%i",ts_inc);*/ +} + +guint32 get_new_timestamp(MSRtpSend *r,guint32 synctime) +{ + guint32 clockts; + /* use the sync system time to compute a timestamp */ + PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->send_pt); + g_return_val_if_fail(pt!=NULL,0); + clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0); + ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts); + if (r->flags & RTPSEND_CONFIGURED){ + if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(clockts,r->ts+(2*r->ts_inc) )){ + r->ts=clockts; + } + else r->ts+=r->ts_inc; + }else{ + r->ts=clockts; + } + return r->ts; +} + + +void ms_rtp_send_process(MSRtpSend *r) +{ + MSFifo *fi; + MSQueue *qi; + MSSync *sync= r->sync; + int gran=ms_sync_get_samples_per_tick(sync); + guint32 ts; + void *s; + guint skip; + guint32 synctime=sync->time; + + g_return_if_fail(gran>0); + if (r->rtpsession==NULL) return; + + ms_filter_lock(MS_FILTER(r)); + skip=r->delay!=0; + if (skip) r->delay--; + /* process output fifo and output queue*/ + fi=r->f_inputs[0]; + if (fi!=NULL) + { + ts=get_new_timestamp(r,synctime); + /* try to read r->packet_size bytes and send them in a rtp packet*/ + ms_fifo_get_read_ptr(fi,r->packet_size,&s); + if (!skip){ + rtp_session_send_with_ts(r->rtpsession,s,r->packet_size,ts); + ms_trace("len=%i, ts=%i ",r->packet_size,ts); + } + } + qi=r->q_inputs[0]; + if (qi!=NULL) + { + MSMessage *msg; + /* read a MSMessage and send it through the network*/ + while ( (msg=ms_queue_get(qi))!=NULL){ + ts=get_new_timestamp(r,synctime); + if (!skip) { + /*g_message("Sending packet with ts=%u",ts);*/ + mblk_t *packet=rtp_session_create_packet_with_data(r->rtpsession,msg->data,msg->size,NULL); + rtp_set_markbit(packet,msg->markbit); + rtp_session_sendm_with_ts(r->rtpsession,packet,ts); + + } + ms_message_destroy(msg); + } + } + ms_filter_unlock(MS_FILTER(r)); +} + +void ms_rtp_send_destroy( MSRtpSend *obj) +{ + g_free(obj); +} + +RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session) +{ + RtpSession *old=obj->rtpsession; + obj->rtpsession=session; + obj->ts=0; + obj->ts_inc=0; + return old; +} + +void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync) +{ + MSFilter *codec; + MSCodecInfo *info; + r->sync=sync; + codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_AUDIO_CODEC); + if (codec==NULL) codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_VIDEO_CODEC); + if (codec==NULL){ + g_warning("ms_rtp_send_setup: could not find upstream codec."); + return; + } + info=MS_CODEC_INFO(codec->klass->info); + if (info->info.type==MS_FILTER_AUDIO_CODEC){ + int ts_inc=info->fr_size/2; + int psize=info->dt_size; + if (ts_inc==0){ + /* dont'use the normal frame size: this is a variable frame size codec */ + /* use the MS_FILTER(codec)->r_mingran */ + ts_inc=MS_FILTER(codec)->r_mingran/2; + psize=0; + } + ms_rtp_send_set_timing(r,ts_inc,psize); + } +} + +gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf) +{ + gint res; + + if (r->rtpsession==NULL) return -1; + if (rtp_session_telephone_events_supported(r->rtpsession)==-1){ + g_warning("ERROR : telephone events not supported.\n"); + return -1; + } + + ms_filter_lock(MS_FILTER(r)); + g_message("Sending DTMF."); + res=rtp_session_send_dtmf(r->rtpsession, dtmf, r->ts); + if (res==0){ + //r->ts+=r->ts_inc; + r->delay+=2; + }else g_warning("Could not send dtmf."); + + ms_filter_unlock(MS_FILTER(r)); + + return res; +} diff --git a/linphone/mediastreamer/msrtpsend.h b/linphone/mediastreamer/msrtpsend.h new file mode 100644 index 000000000..072879acb --- /dev/null +++ b/linphone/mediastreamer/msrtpsend.h @@ -0,0 +1,85 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSRTPSEND_H +#define MSRTPSEND_H + +#include "msfilter.h" +#include "mssync.h" + +#undef PACKAGE +#undef VERSION +#include + + +/*this is the class that implements a sending through rtp filter*/ + +#define MSRTPSEND_MAX_INPUTS 1 /* max input per filter*/ + +#define MSRTPSEND_DEF_GRAN 160/* the default granularity*/ + +struct _MSRtpSend +{ + /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MSRTPSEND_MAX_INPUTS]; + MSQueue *q_inputs[MSRTPSEND_MAX_INPUTS]; + MSSync *sync; + RtpSession *rtpsession; + guint32 ts; + guint32 ts_inc; /* the timestamp increment */ + gint packet_size; + guint flags; + guint delay; /* number of _proccess call which must be skipped */ +#define RTPSEND_CONFIGURED (1) +}; + +typedef struct _MSRtpSend MSRtpSend; + +struct _MSRtpSendClass +{ + /* the MSRtpSend derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +}; + +typedef struct _MSRtpSendClass MSRtpSendClass; + +/* PUBLIC */ +#define MS_RTP_SEND(filter) ((MSRtpSend*)(filter)) +#define MS_RTP_SEND_CLASS(klass) ((MSRtpSendClass*)(klass)) +MSFilter * ms_rtp_send_new(void); +RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session); +#define ms_rtp_send_unset_session(obj) (ms_rtp_send_set_session((obj),NULL)) +#define ms_rtp_send_get_session(obj) ((obj)->rtpsession) +void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size); +gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf); + + +/* FOR INTERNAL USE*/ +void ms_rtp_send_init(MSRtpSend *r); +void ms_rtp_send_class_init(MSRtpSendClass *klass); +void ms_rtp_send_destroy( MSRtpSend *obj); +void ms_rtp_send_process(MSRtpSend *r); +void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync); + +#endif diff --git a/linphone/mediastreamer/mssdlout.c b/linphone/mediastreamer/mssdlout.c new file mode 100644 index 000000000..8e49cd338 --- /dev/null +++ b/linphone/mediastreamer/mssdlout.c @@ -0,0 +1,303 @@ +/*************************************************************************** + * mssdlout.c + * + * Mon Jul 11 16:17:59 2005 + * Copyright 2005 Simon Morlat + * Email simon dot morlat at linphone dot org + ****************************************************************************/ + +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mssdlout.h" + +MSSdlOutClass *ms_sdl_out_class=NULL; + +void ms_sdl_out_init(MSSdlOut *obj){ + ms_filter_init(MS_FILTER(obj)); + obj->width=VIDEO_SIZE_CIF_W; + obj->height=VIDEO_SIZE_CIF_H; + obj->format="RGB24"; + obj->use_yuv=FALSE; + obj->oldinm1=NULL; + MS_FILTER(obj)->inqueues=obj->input; +} + +void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt){ + obj->format=fmt; + if (strcmp(fmt,"YUV420P")==0) obj->use_yuv=TRUE; + else obj->use_yuv=FALSE; +} + +void ms_sdl_uninit_sdl(MSSdlOut *obj){ + if (obj->overlay!=NULL){ + SDL_FreeYUVOverlay(obj->overlay); + obj->overlay=NULL; + } + if (obj->screen!=NULL){ + SDL_FreeSurface(obj->screen); + obj->screen=NULL; + } + +} + +void ms_sdl_out_uninit(MSSdlOut *obj){ + ms_sdl_uninit_sdl(obj); +} + +void ms_sdl_out_destroy(MSSdlOut *obj){ + ms_sdl_out_uninit(obj); + if (obj->oldinm1!=NULL) ms_message_destroy(obj->oldinm1); + g_free(obj); +} + +void ms_sdl_init_sdl(MSSdlOut *obj){ + if (strcmp(obj->format,"RGB24")==0){ + }else{ + obj->use_yuv=TRUE; + } + obj->screen = SDL_SetVideoMode(obj->width, obj->height, 0,SDL_HWSURFACE|SDL_ANYFORMAT); + if ( obj->screen == NULL ) { + g_warning("Couldn't set video mode: %s\n", + SDL_GetError()); + return ; + } + if (obj->screen->flags & SDL_HWSURFACE) g_message("SDL surface created in hardware"); + SDL_WM_SetCaption("Linphone Video", NULL); + + if (obj->use_yuv){ + g_message("Using yuv overlay."); + obj->overlay=SDL_CreateYUVOverlay(obj->width,obj->height,SDL_IYUV_OVERLAY,obj->screen); + if (obj->overlay==NULL){ + g_warning("Couldn't create yuv overlay: %s\n", + SDL_GetError()); + }else{ + if (obj->overlay->hw_overlay) g_message("YUV overlay using hardware acceleration."); + } + } + +} + +static void resize_yuv_small(char *pict, int w, int h, int scale){ + int i,j,id,jd; + int nh,nw; + char *smallpict; + int ysize,usize,ydsize,udsize; + int smallpict_sz; + char *dptr,*sptr; + nw=w/scale; + nh=h/scale; + ysize=w*h; + usize=ysize/4; + ydsize=nw*nh; + udsize=ydsize/4; + smallpict_sz=(ydsize*3)/2; + smallpict=(char*)alloca(smallpict_sz); + memset(smallpict,0,smallpict_sz); + + + dptr=smallpict; + sptr=pict; + for (j=0,jd=0;jdata; + int i,j; + int jlim,ilim; + int off; + char *dptr; + + ilim=MIN(x+w,lay->w); + jlim=MIN(y+h,lay->h); + SDL_LockYUVOverlay(lay); + /* set Y */ + dptr=lay->pixels[0]; + for (j=y;jw; + for (i=x;ipixels[1]; + for (j=y/2;jw/2); + for (i=x/2;ipixels[2]; + for (j=y/2;jw/2); + for (i=x/2;idata; + int ysize=lay->w*lay->h; + int usize; + w2=lay->w/2; + h2=lay->h/2; + usize=w2*h2; + SDL_LockYUVOverlay(lay); + memcpy(lay->pixels[0],data,ysize); + memcpy(lay->pixels[1],data+ysize,usize); + memcpy(lay->pixels[2],data+ysize+usize,usize); + SDL_UnlockYUVOverlay(lay); +} + +#define SCALE_FACTOR 6 + +void ms_sdl_out_process(MSSdlOut *obj){ + MSQueue *q0=obj->input[0]; + MSQueue *q1=obj->input[1]; + MSMessage *inm0=NULL; + MSMessage *inm1=NULL; + int err; + SDL_Rect smallrect; + SDL_Rect rect; + rect.w=obj->width; + rect.h=obj->height; + rect.x=0; + rect.y=0; + smallrect.w=obj->width/SCALE_FACTOR; + smallrect.h=obj->height/SCALE_FACTOR; + smallrect.x=obj->width - smallrect.w ; + smallrect.y=obj->height -smallrect.h; + + if (obj->screen==NULL){ + ms_sdl_init_sdl(obj); + } + + if (q0!=NULL) + inm0=ms_queue_get(q0); + if (q1!=NULL) + inm1=ms_queue_get(q1); + + if (inm0!=NULL){ + SDL_Surface *surf; + if (obj->use_yuv){ + + fill_overlay(obj->overlay,inm0); + + }else { + surf=SDL_CreateRGBSurfaceFrom(inm0->data,obj->width,obj->height,24,obj->width*3,0,0,0,0); + + err=SDL_BlitSurface(surf,NULL,obj->screen,NULL); + if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError()); + SDL_FreeSurface(surf); + } + ms_message_destroy(inm0); + } + if (inm1!=NULL){ + /* this message is blitted on the right,bottom corner of the screen */ + SDL_Surface *surf; + + if (obj->use_yuv){ + resize_yuv_small(inm1->data,rect.w,rect.h,SCALE_FACTOR); + fill_overlay_at_pos(obj->overlay,inm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h); + }else { + surf=SDL_CreateRGBSurfaceFrom(inm1->data,obj->width,obj->height,24,obj->width*3,0,0,0,0); + + err=SDL_BlitSurface(surf,NULL,obj->screen,&smallrect); + if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError()); + SDL_FreeSurface(surf); + } + if (obj->oldinm1!=NULL) { + ms_message_destroy(obj->oldinm1); + } + obj->oldinm1=inm1; + + }else{ + /* this is the case were we have only inm0, we have to redisplay inm1 */ + if (obj->use_yuv){ + if (obj->oldinm1!=NULL){ + fill_overlay_at_pos(obj->overlay,obj->oldinm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h); + } + } + } + + if (obj->use_yuv) SDL_DisplayYUVOverlay(obj->overlay,&rect); + SDL_UpdateRect(obj->screen,0,0,obj->width,obj->height); + +} + +void ms_sdl_out_class_init(MSSdlOutClass *klass){ + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_sdl_out_process; + MS_FILTER_CLASS(klass)->max_qinputs=2; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_sdl_out_destroy; + MS_FILTER_CLASS(klass)->name="MSSdlOut"; + /* Initialize the SDL library */ + if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, + "Couldn't initialize SDL: %s\n", SDL_GetError()); + return; + } + /* Clean up on exit */ + atexit(SDL_Quit); +} + +MSFilter * ms_sdl_out_new(void){ + MSSdlOut *obj=g_new0(MSSdlOut,1); + if (ms_sdl_out_class==NULL){ + ms_sdl_out_class=g_new0(MSSdlOutClass,1); + ms_sdl_out_class_init(ms_sdl_out_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_sdl_out_class); + ms_sdl_out_init(obj); + return MS_FILTER(obj); +} diff --git a/linphone/mediastreamer/mssdlout.h b/linphone/mediastreamer/mssdlout.h new file mode 100644 index 000000000..fd6ec547a --- /dev/null +++ b/linphone/mediastreamer/mssdlout.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * mssdlout.h + * + * Mon Jul 11 16:18:55 2005 + * Copyright 2005 Simon Morlat + * Email simon dot morlat at linphone dot org + ****************************************************************************/ + +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef mssdlout_h +#define mssdlout_h + +#include "msfilter.h" + +#include +#include + +struct _MSSdlOut +{ + MSFilter parent; + MSQueue *input[2]; + gint width,height; + const gchar *format; + SDL_Surface *screen; + SDL_Overlay *overlay; + MSMessage *oldinm1; + gboolean use_yuv; +}; + + +typedef struct _MSSdlOut MSSdlOut; + +struct _MSSdlOutClass +{ + MSFilterClass parent_class; +}; + +typedef struct _MSSdlOutClass MSSdlOutClass; + +MSFilter * ms_sdl_out_new(void); +void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt); + +#define MS_SDL_OUT(obj) ((MSSdlOut*)obj) + +#endif diff --git a/linphone/mediastreamer/mssmpeg.c b/linphone/mediastreamer/mssmpeg.c new file mode 100644 index 000000000..5eb2cd9f3 --- /dev/null +++ b/linphone/mediastreamer/mssmpeg.c @@ -0,0 +1,181 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mssmpeg.h" +#include +#include + + +static MSSmpegClass *ms_smpeg_class=NULL; + + +int seek_mpeg_data(struct SDL_RWops *context, int offset, int whence) +{ + MSSmpeg *obj=context->hidden.unknown.data1; + g_message("Entering seek function offset=%i whence=%i",offset,whence); + switch (whence) + { + case SEEK_SET: + obj->pos=offset; + break; + case SEEK_CUR: + return obj->pos; + break; + case SEEK_END: + return obj->end_pos; + break; + } + return 0; +} + +int read_mpeg_data(struct SDL_RWops *context, void *ptr, int size, int maxnum) +{ + MSSmpeg *obj=context->hidden.unknown.data1; + gint bytes; + g_message("Entering read function: size=%i maxnum=%i",size,maxnum); + if (obj->pos>=obj->end_pos) + { + g_message("End of file"); + return 0; + } + if (obj->current==NULL) + { + g_message("Nothing to read."); + return 0; + } + bytes=MIN(maxnum,obj->current->size); + memcpy(ptr,obj->current->data,bytes); + obj->pos+=bytes; + //obj->current; + return bytes; +} + +void ms_smpeg_init(MSSmpeg *obj) +{ + gint error; + ms_filter_init(MS_FILTER(obj)); + MS_FILTER(obj)->inqueues=obj->input; + obj->surface = SDL_SetVideoMode ( 400, 400,0 , SDL_HWSURFACE ); + if (obj->surface==NULL) + { + g_error("Could not create a SDL surface"); + } + /* + error=pipe(obj->fd); + if (error<0) + { + g_error("Could not create pipe !"); + } + fcntl(obj->fd[1],F_SETFL,O_NONBLOCK); + */ + obj->rwops=SDL_AllocRW(); + obj->rwops->read=read_mpeg_data; + obj->rwops->seek=seek_mpeg_data; + obj->rwops->hidden.unknown.data1=(void*)obj; + obj->pos=0; + obj->end_pos=0; +} + +void ms_smpeg_class_init(MSSmpegClass *klass) +{ + int error; + ms_filter_class_init(MS_FILTER_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_qinputs=1; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_smpeg_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_smpeg_process; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MSSmpeg"); + error=SDL_Init(SDL_INIT_VIDEO); + if (error<0){ + g_error("Could not initialize SDL !"); + } + +} + +void ms_smpeg_uninit(MSSmpeg *obj) +{ + +} + +MSFilter * ms_smpeg_new() +{ + MSSmpeg *obj=g_malloc(sizeof(MSSmpeg)); + + if (ms_smpeg_class==NULL) + { + ms_smpeg_class=g_malloc(sizeof(MSSmpegClass)); + ms_smpeg_class_init(ms_smpeg_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_smpeg_class); + ms_smpeg_init(obj); + return MS_FILTER(obj); +} + +void ms_smpeg_start(MSSmpeg *obj) +{ + //SMPEG_play(obj->handle); + obj->first_time=1; + obj->run_cond=1; +} + +void ms_smpeg_stop(MSSmpeg *obj) +{ + SMPEG_stop(obj->handle); + obj->run_cond=0; +} + +void ms_smpeg_process(MSSmpeg *obj) +{ + MSQueue *q=obj->input[0]; + MSMessage *m; + SMPEG_Info info; + + while((m=ms_queue_get(q))!=NULL) + { + g_message("Getting new buffer"); + if (obj->run_cond) + { + obj->current=m; + obj->end_pos+=m->size; + if (obj->first_time) + { + obj->handle=SMPEG_new_rwops(obj->rwops,NULL,0); + if (obj->handle==NULL){ + g_error("Could not create smpeg object."); + } + SMPEG_setdisplay(obj->handle,obj->surface,NULL,NULL); + obj->first_time=0; + //SMPEG_play(obj->handle); + } + SMPEG_getinfo(obj->handle, &info ); + g_message("Current frame is %i",info.current_frame); + SMPEG_renderFrame(obj->handle, info.current_frame+1); + } + ms_message_destroy(m); + obj->current=NULL; + } +} + +void ms_smpeg_destroy(MSSmpeg *obj) +{ + ms_smpeg_uninit(obj); + g_free(obj); +} + diff --git a/linphone/mediastreamer/mssmpeg.h b/linphone/mediastreamer/mssmpeg.h new file mode 100644 index 000000000..331414f81 --- /dev/null +++ b/linphone/mediastreamer/mssmpeg.h @@ -0,0 +1,70 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSSMPEG_H +#define MSSMPEG_H + + +#include "ms.h" +#include "msfilter.h" + +#include +#include + +struct _MSSmpeg +{ + MSFilter parent; + MSQueue *input[1]; + SMPEG *handle; + SDL_Surface *surface; + SDL_RWops *rwops; + int run_cond; + int first_time; + MSMessage *current; + int pos; + int end_pos; +}; + + +typedef struct _MSSmpeg MSSmpeg; + +struct _MSSmpegClass +{ + MSFilterClass parent_class; +}; + +typedef struct _MSSmpegClass MSSmpegClass; + + +#define MS_SMPEG(obj) ((MSSmpeg*)(obj)) +#define MS_SMPEG_CLASS(klass) ((MSSmpegClass*)(klass)) + +void ms_smpeg_init(MSSmpeg *obj); +void ms_smpeg_class_init(MSSmpegClass *klass); +void ms_smpeg_uninit(MSSmpeg *obj); + +MSFilter * ms_smpeg_new(); +void ms_smpeg_start(MSSmpeg *obj); +void ms_smpeg_stop(MSSmpeg *obj); + + +void ms_smpeg_destroy(MSSmpeg *obj); +void ms_smpeg_process(MSSmpeg *obj); +#endif \ No newline at end of file diff --git a/linphone/mediastreamer/mssoundread.c b/linphone/mediastreamer/mssoundread.c new file mode 100644 index 000000000..c77107a3a --- /dev/null +++ b/linphone/mediastreamer/mssoundread.c @@ -0,0 +1,38 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation + + */ + +#include "mssoundread.h" + + +void ms_sound_read_init(MSSoundRead *w) +{ + ms_filter_init(MS_FILTER(w)); + +} + +void ms_sound_read_class_init(MSSoundReadClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_foutputs=1; /* one fifo output only */ + + ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SOURCE); +} + diff --git a/linphone/mediastreamer/mssoundread.h b/linphone/mediastreamer/mssoundread.h new file mode 100644 index 000000000..7f2cab938 --- /dev/null +++ b/linphone/mediastreamer/mssoundread.h @@ -0,0 +1,80 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef MSSOUNDREAD_H +#define MSSOUNDREAD_H + +#include "msfilter.h" +#include "mssync.h" + + + +struct _MSSoundRead +{ + /* the MSOssRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssRead object + in order to the object mechanism to work*/ + MSFilter filter; +}; + +typedef struct _MSSoundRead MSSoundRead; + +struct _MSSoundReadClass +{ + /* the MSOssRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssRead class + in order to the class mechanism to work*/ + MSFilterClass parent_class; + gint (*set_device)(MSSoundRead *, gint devid); + void (*start)(MSSoundRead *); + void (*stop)(MSSoundRead*); + void (*set_level)(MSSoundRead *, gint a); +}; + +typedef struct _MSSoundReadClass MSSoundReadClass; + +/* PUBLIC */ +#define MS_SOUND_READ(filter) ((MSSoundRead*)(filter)) +#define MS_SOUND_READ_CLASS(klass) ((MSSoundReadClass*)(klass)) + +static inline int ms_sound_read_set_device(MSSoundRead *r,gint devid) +{ + return MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->set_device(r,devid); +} + +static inline void ms_sound_read_start(MSSoundRead *r) +{ + MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->start(r); +} + +static inline void ms_sound_read_stop(MSSoundRead *w) +{ + MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->stop(w); +} + +static inline void ms_sound_read_set_level(MSSoundRead *w,gint a) +{ + MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->set_level(w,a); +} + +/* FOR INTERNAL USE*/ +void ms_sound_read_init(MSSoundRead *r); +void ms_sound_read_class_init(MSSoundReadClass *klass); + + +#endif + diff --git a/linphone/mediastreamer/mssoundwrite.c b/linphone/mediastreamer/mssoundwrite.c new file mode 100644 index 000000000..f1b765ab0 --- /dev/null +++ b/linphone/mediastreamer/mssoundwrite.c @@ -0,0 +1,38 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation + + */ + +#include "mssoundwrite.h" + + +void ms_sound_write_init(MSSoundWrite *w) +{ + ms_filter_init(MS_FILTER(w)); + +} + +void ms_sound_write_class_init(MSSoundWriteClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_finputs=1; /* one fifo output only */ + + ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SINK); +} + diff --git a/linphone/mediastreamer/mssoundwrite.h b/linphone/mediastreamer/mssoundwrite.h new file mode 100644 index 000000000..e6d79874e --- /dev/null +++ b/linphone/mediastreamer/mssoundwrite.h @@ -0,0 +1,80 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef MSSOUNDWRITE_H +#define MSSOUNDWRITE_H + +#include "msfilter.h" +#include "mssync.h" + + + +struct _MSSoundWrite +{ + /* the MSOssWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssWrite object + in order to the object mechanism to work*/ + MSFilter filter; +}; + +typedef struct _MSSoundWrite MSSoundWrite; + +struct _MSSoundWriteClass +{ + /* the MSOssWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssWrite class + in order to the class mechanism to work*/ + MSFilterClass parent_class; + gint (*set_device)(MSSoundWrite *, gint devid); + void (*start)(MSSoundWrite *); + void (*stop)(MSSoundWrite*); + void (*set_level)(MSSoundWrite *, gint a); +}; + +typedef struct _MSSoundWriteClass MSSoundWriteClass; + +/* PUBLIC */ +#define MS_SOUND_WRITE(filter) ((MSSoundWrite*)(filter)) +#define MS_SOUND_WRITE_CLASS(klass) ((MSSoundWriteClass*)(klass)) + +static inline int ms_sound_write_set_device(MSSoundWrite *r,gint devid) +{ + return MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->set_device(r,devid); +} + +static inline void ms_sound_write_start(MSSoundWrite *r) +{ + MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->start(r); +} + +static inline void ms_sound_write_stop(MSSoundWrite *w) +{ + MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->stop(w); +} + +static inline void ms_sound_write_set_level(MSSoundWrite *w,gint a) +{ + MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->set_level(w,a); +} + +/* FOR INTERNAL USE*/ +void ms_sound_write_init(MSSoundWrite *r); +void ms_sound_write_class_init(MSSoundWriteClass *klass); + + +#endif + diff --git a/linphone/mediastreamer/msspeexdec.c b/linphone/mediastreamer/msspeexdec.c new file mode 100644 index 000000000..df6021250 --- /dev/null +++ b/linphone/mediastreamer/msspeexdec.c @@ -0,0 +1,215 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msspeexdec.h" + +#ifdef HAVE_GLIB +#include +#endif + +extern MSFilter * ms_speex_enc_new(); + +MSCodecInfo speex_info= +{ + { + "Speex codec", + 0, + MS_FILTER_AUDIO_CODEC, + ms_speex_dec_new, + "A high quality variable bit-rate codec from Jean Marc Valin and David Rowe." + }, + ms_speex_enc_new, + ms_speex_dec_new, + 0, /*frame size */ + 0, + 8000, /*minimal bitrate */ + -1, /* sampling frequency */ + 110, /* payload type */ + "speex", + 1, + 1 +}; + + + +void ms_speex_codec_init() +{ + + ms_filter_register(MS_FILTER_INFO(&speex_info)); + //ms_filter_register(MS_FILTER_INFO(&speex_lbr_info)); +} + +#ifdef HAVE_GLIB +gchar * g_module_check_init(GModule *module) +{ + ms_speex_codec_init(); + + return NULL; +} +#else +gchar * g_module_check_init() +{ + ms_speex_codec_init(); + + return NULL; +} +#endif + +static MSSpeexDecClass * ms_speex_dec_class=NULL; +//static MSSpeexDecClass * ms_speexnb_dec_class=NULL; + +MSFilter * ms_speex_dec_new() +{ + MSSpeexDec *obj=g_new(MSSpeexDec,1); + + if (ms_speex_dec_class==NULL){ + ms_speex_dec_class=g_new(MSSpeexDecClass,1); + ms_speex_dec_class_init(ms_speex_dec_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_dec_class); + + ms_speex_dec_init(obj); + return MS_FILTER(obj); +} + +void ms_speex_dec_init(MSSpeexDec *obj) +{ + ms_filter_init(MS_FILTER(obj)); + obj->initialized=0; + MS_FILTER(obj)->outfifos=obj->outf; + MS_FILTER(obj)->inqueues=obj->inq; + obj->outf[0]=NULL; + obj->inq[0]=NULL; + obj->frequency=8000; /*default value */ + +} + +void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode) +{ + int pf=1; + + obj->speex_state=speex_decoder_init((SpeexMode*)mode); + speex_bits_init(&obj->bits); + /* enable the perceptual post filter */ + speex_decoder_ctl(obj->speex_state,SPEEX_SET_PF, &pf); + + speex_mode_query((SpeexMode*)mode, SPEEX_MODE_FRAME_SIZE, &obj->frame_size); + + obj->initialized=1; +} + +int ms_speex_dec_set_property(MSSpeexDec *obj, MSFilterProperty prop, int *value) +{ + if (obj->initialized){ + /* we are called when speex is running !! forbid that! */ + ms_warning("ms_speex_dec_set_property: cannot call this function when running!"); + return -1; + } + switch(prop){ + case MS_FILTER_PROPERTY_FREQ: + obj->frequency=value[0]; + break; + default: + break; + } + return 0; +} + +void ms_speex_dec_setup(MSSpeexDec *obj) +{ + const SpeexMode *mode; + g_message("Speex decoder setup: freq=%i",obj->frequency); + if ( obj->frequency< 16000) mode=&speex_nb_mode; + else mode=&speex_wb_mode; + ms_speex_dec_init_core(obj,mode); +} + +void ms_speex_dec_unsetup(MSSpeexDec *obj) +{ + ms_speex_dec_uninit_core(obj); +} + +void ms_speex_dec_class_init(MSSpeexDecClass *klass) +{ + gint frame_size=0; + + ms_filter_class_init(MS_FILTER_CLASS(klass)); + /* use the largest frame size to configure fifos */ + speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size); + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_dec_process; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_dec_setup; + MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_dec_unsetup; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_dec_destroy; + MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_dec_set_property; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexDecoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info; + MS_FILTER_CLASS(klass)->max_foutputs=1; + MS_FILTER_CLASS(klass)->max_qinputs=1; + MS_FILTER_CLASS(klass)->w_maxgran=frame_size*2; + ms_trace("ms_speex_dec_class_init: w_maxgran is %i.",MS_FILTER_CLASS(klass)->w_maxgran); +} + +void ms_speex_dec_uninit_core(MSSpeexDec *obj) +{ + speex_decoder_destroy(obj->speex_state); + speex_bits_destroy(&obj->bits); + obj->initialized=0; +} + +void ms_speex_dec_uninit(MSSpeexDec *obj) +{ + +} + +void ms_speex_dec_destroy(MSSpeexDec *obj) +{ + ms_speex_dec_uninit(obj); + g_free(obj); +} + +void ms_speex_dec_process(MSSpeexDec *obj) +{ + MSFifo *outf=obj->outf[0]; + MSQueue *inq=obj->inq[0]; + gint16 *output; + gint gran=obj->frame_size*2; + MSMessage *m; + + g_return_if_fail(inq!=NULL); + g_return_if_fail(outf!=NULL); + + m=ms_queue_get(inq); + g_return_if_fail(m!=NULL); + speex_bits_reset(&obj->bits); + ms_fifo_get_write_ptr(outf,gran,(void**)&output); + g_return_if_fail(output!=NULL); + if (m->data!=NULL){ + + speex_bits_read_from(&obj->bits,m->data,m->size); + /* decode */ + speex_decode_int(obj->speex_state,&obj->bits,(short*)output); + }else{ + /* we have a missing packet */ + speex_decode_int(obj->speex_state,NULL,(short*)output); + } + ms_message_destroy(m); + +} diff --git a/linphone/mediastreamer/msspeexdec.h b/linphone/mediastreamer/msspeexdec.h new file mode 100644 index 000000000..de60745b9 --- /dev/null +++ b/linphone/mediastreamer/msspeexdec.h @@ -0,0 +1,69 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSSPEEXDEC_H +#define MSSPEEXDEC_H + +#include "mscodec.h" +#include + +struct _MSSpeexDec +{ + MSFilter parent; + MSQueue *inq[1]; /* speex has an input q because it can be variable bit rate */ + MSFifo *outf[1]; + void *speex_state; + SpeexBits bits; + int frequency; + int frame_size; + int initialized; +}; + +typedef struct _MSSpeexDec MSSpeexDec; + + +struct _MSSpeexDecClass +{ + MSFilterClass parent; +}; + +typedef struct _MSSpeexDecClass MSSpeexDecClass; + + +#define MS_SPEEX_DEC(o) ((MSSpeexDec*)(o)) +#define MS_SPEEX_DEC_CLASS(o) ((MSSpeexDecClass*)(o)) + +/* call this before if don't load the plugin dynamically */ +void ms_speex_codec_init(); + +/* mediastreamer compliant constructor */ +MSFilter * ms_speex_dec_new(); + +void ms_speex_dec_init(MSSpeexDec *obj); +void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode); +void ms_speex_dec_class_init(MSSpeexDecClass *klass); +void ms_speex_dec_uninit(MSSpeexDec *obj); +void ms_speex_dec_uninit_core(MSSpeexDec *obj); + +void ms_speex_dec_process(MSSpeexDec *obj); +void ms_speex_dec_destroy(MSSpeexDec *obj); + +#endif diff --git a/linphone/mediastreamer/msspeexenc.c b/linphone/mediastreamer/msspeexenc.c new file mode 100644 index 000000000..903269ecb --- /dev/null +++ b/linphone/mediastreamer/msspeexenc.c @@ -0,0 +1,187 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#include "msspeexenc.h" +#include "ms.h" +extern MSCodecInfo speex_info; + +static MSSpeexEncClass * ms_speex_enc_class=NULL; + +MSFilter * ms_speex_enc_new() +{ + MSSpeexEnc *obj=g_new(MSSpeexEnc,1); + + if (ms_speex_enc_class==NULL){ + ms_speex_enc_class=g_new(MSSpeexEncClass,1); + ms_speex_enc_class_init(ms_speex_enc_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_enc_class); + ms_speex_enc_init(MS_SPEEX_ENC(obj)); + return MS_FILTER(obj); +} + +void ms_speex_enc_init(MSSpeexEnc *obj) +{ + ms_filter_init(MS_FILTER(obj)); + MS_FILTER(obj)->infifos=obj->inf; + MS_FILTER(obj)->outqueues=obj->outq; + obj->inf[0]=NULL; + obj->outq[0]=NULL; + obj->frequency=8000; + obj->bitrate=30000; + obj->initialized=0; +} + +void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint bitrate) +{ + int proc_type, proc_speed; + gchar *proc_vendor; + int tmp; + int frame_size; + + obj->speex_state=speex_encoder_init((SpeexMode*)mode); + speex_bits_init(&obj->bits); + + if (bitrate>0) { + bitrate++; + speex_encoder_ctl(obj->speex_state, SPEEX_SET_BITRATE, &bitrate); + g_message("Setting speex output bitrate less or equal than %i",bitrate-1); + } + + proc_speed=ms_proc_get_speed(); + proc_vendor=ms_proc_get_param("vendor_id"); + if (proc_speed<0 || proc_vendor==NULL){ + g_warning("Can't guess processor features: setting speex encoder to its lowest complexity."); + tmp=1; + speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp); + }else if ((proc_speed!=-1) && (proc_speed<200)){ + g_warning("A cpu speed less than 200 Mhz is not enough: let's reduce the complexity of the speex codec."); + tmp=1; + speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp); + }else if (proc_vendor!=NULL) { + if (strncmp(proc_vendor,"GenuineIntel",strlen("GenuineIntel"))==0){ + proc_type=ms_proc_get_type(); + if (proc_type==5){ + g_warning("A pentium I is not enough fast for speex codec in normal mode: let's reduce its complexity."); + tmp=1; + speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp); + } + } + g_free(proc_vendor); + } + /* guess the used input frame size */ + speex_mode_query((SpeexMode*)mode, SPEEX_MODE_FRAME_SIZE, &frame_size); + MS_FILTER(obj)->r_mingran=frame_size*2; + ms_trace("ms_speex_init: using frame size of %i.",MS_FILTER(obj)->r_mingran); + + obj->initialized=1; +} + +/* must be called before the encoder is running*/ +int ms_speex_enc_set_property(MSSpeexEnc *obj,int property,int *value) +{ + if (obj->initialized){ + /* we are called when speex is running !! forbid that! */ + ms_warning("ms_speex_enc_set_property: cannot call this function when running!"); + return -1; + } + switch(property){ + case MS_FILTER_PROPERTY_FREQ: + obj->frequency=value[0]; + break; + case MS_FILTER_PROPERTY_BITRATE: /* to specify max bitrate */ + obj->bitrate=value[0]; + break; + } + return 0; +} + +void ms_speex_enc_setup(MSSpeexEnc *obj) +{ + const SpeexMode *mode; + g_message("Speex encoder setup: freq=%i",obj->frequency); + if ( obj->frequency< 16000) mode=&speex_nb_mode; + else mode=&speex_wb_mode; + ms_speex_enc_init_core(obj,mode,obj->bitrate); + +} + +void ms_speex_enc_unsetup(MSSpeexEnc *obj) +{ + ms_speex_enc_uninit_core(obj); +} + +void ms_speex_enc_class_init(MSSpeexEncClass *klass) +{ + gint frame_size=0; + + ms_filter_class_init(MS_FILTER_CLASS(klass)); + /* we take the larger (wb) frame size */ + speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size); + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_enc_process; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_enc_destroy; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_enc_setup; + MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_enc_unsetup; + MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_enc_set_property; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexEncoder"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info; + MS_FILTER_CLASS(klass)->max_finputs=1; + MS_FILTER_CLASS(klass)->max_qoutputs=1; + MS_FILTER_CLASS(klass)->r_maxgran=frame_size*2; + ms_trace("ms_speex_enc_class_init: r_maxgran is %i.",MS_FILTER_CLASS(klass)->r_maxgran); +} + +void ms_speex_enc_uninit_core(MSSpeexEnc *obj) +{ + if (obj->initialized){ + speex_encoder_destroy(obj->speex_state); + speex_bits_destroy(&obj->bits); + obj->initialized=0; + } +} + +void ms_speex_enc_destroy(MSSpeexEnc *obj) +{ + ms_speex_enc_uninit_core(obj); + g_free(obj); +} + +void ms_speex_enc_process(MSSpeexEnc *obj) +{ + MSFifo *inf=obj->inf[0]; + MSQueue *outq=obj->outq[0]; + gint16 *input; + gint gran=MS_FILTER(obj)->r_mingran; + MSMessage *m; + + g_return_if_fail(inf!=NULL); + g_return_if_fail(outq!=NULL); + + ms_fifo_get_read_ptr(inf,gran,(void**)&input); + g_return_if_fail(input!=NULL); + /* encode */ + speex_bits_reset(&obj->bits); + speex_encode_int(obj->speex_state,(short*)input,&obj->bits); + m=ms_message_new(speex_bits_nbytes(&obj->bits)); + m->size=speex_bits_write(&obj->bits,m->data,m->size); + ms_queue_put(outq,m); +} diff --git a/linphone/mediastreamer/msspeexenc.h b/linphone/mediastreamer/msspeexenc.h new file mode 100644 index 000000000..e7f145c82 --- /dev/null +++ b/linphone/mediastreamer/msspeexenc.h @@ -0,0 +1,66 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSSPEEXENC_H +#define MSSPEEXENC_H + +#include "mscodec.h" +#include + +struct _MSSpeexEnc +{ + MSFilter parent; + MSFifo *inf[1]; + MSQueue *outq[1]; /* speex has an output q because it can be variable bit rate */ + void *speex_state; + SpeexBits bits; + int frequency; + int bitrate; + int initialized; +}; + +typedef struct _MSSpeexEnc MSSpeexEnc; + + +struct _MSSpeexEncClass +{ + MSFilterClass parent; +}; + +typedef struct _MSSpeexEncClass MSSpeexEncClass; + + +#define MS_SPEEX_ENC(o) ((MSSpeexEnc*)(o)) +#define MS_SPEEX_ENC_CLASS(o) ((MSSpeexEncClass*)(o)) + +/* generic constructor */ +MSFilter * ms_speex_enc_new(); + +void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint quality); +void ms_speex_enc_uninit_core(MSSpeexEnc *obj); +void ms_speex_enc_init(MSSpeexEnc *obj); +void ms_speex_enc_class_init(MSSpeexEncClass *klass); + + +void ms_speex_enc_process(MSSpeexEnc *obj); +void ms_speex_enc_destroy(MSSpeexEnc *obj); + +#endif diff --git a/linphone/mediastreamer/mssync.c b/linphone/mediastreamer/mssync.c new file mode 100644 index 000000000..c0d078138 --- /dev/null +++ b/linphone/mediastreamer/mssync.c @@ -0,0 +1,194 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mssync.h" +#include + +/* TODO: + -define an uninit function that free the mutex +*/ + +/** + * function_name:ms_sync_get_bytes_per_tick + * @sync: A #MSSync object. + * + * Returns the number of bytes per tick. This is a usefull information for sources, so + * that they can know how much data they must deliver each time they are called. + * + */ + +/* private */ +void ms_sync_init(MSSync *sync) +{ + sync->klass=NULL; + sync->lock=g_mutex_new(); + sync->thread_cond=g_cond_new(); + sync->stop_cond=g_cond_new(); + sync->attached_filters=NULL; + sync->execution_list=NULL; + sync->filters=0; + sync->run=0; + sync->flags=0; + sync->samples_per_tick=0; + sync->ticks=0; + sync->time=0; + sync->thread=NULL; +} + +void ms_sync_class_init(MSSyncClass *klass) +{ + klass->max_filters=0; + klass->synchronize=NULL; + klass->attach=ms_sync_attach_generic; + klass->detach=ms_sync_detach_generic; + klass->destroy=NULL; +} + +/* public*/ + + +/** + * ms_sync_attach: + * @sync: A #MSSync object. + * @f: A #MSFilter object. + * + * Attach a chain of filters to a synchronisation source @sync. Filter @f must be the first filter of the processing chain. + * In order to be run, each chain of filter must be attached to a synchronisation source, that will be responsible for scheduling + * the processing. Multiple chains can be attached to a single synchronisation. + * + * Returns: 0 if successfull, a negative value reprensenting the errno.h error. + */ +int ms_sync_attach(MSSync *sync,MSFilter *f) +{ + gint err; + ms_sync_lock(sync); + err=sync->klass->attach(sync,f); + ms_sync_update(sync); + ms_sync_unlock(sync); + return(err); +} + +int ms_sync_attach_generic(MSSync *sync,MSFilter *f) +{ + int i; + //printf("attr: %i\n",f->klass->attributes); + g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL); + g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT); + + + /* find a free place to attach*/ + for (i=0;iklass->max_filters;i++) + { + if (sync->attached_filters[i]==NULL) + { + sync->attached_filters[i]=f; + sync->filters++; + ms_trace("Filter succesfully attached to sync."); + return 0; + } + } + g_warning("No more link on sync !"); + return(-EMLINK); +} + +/** + * ms_sync_detach: + * @sync: A #MSSync object. + * @f: A #MSFilter object. + * + * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain. + * The processing chain will no more be executed. + * + * Returns: 0 if successfull, a negative value reprensenting the errno.h error. + */ +int ms_sync_detach(MSSync *sync,MSFilter *f) +{ + gint err; + ms_sync_lock(sync); + err=sync->klass->detach(sync,f); + ms_sync_update(sync); + ms_sync_unlock(sync); + return(err); +} + +int ms_sync_detach_generic(MSSync *sync,MSFilter *f) +{ + int i; + g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL); + g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT); + for (i=0;ifilters;i++) + { + if (sync->attached_filters[i]==f) + { + sync->attached_filters[i]=NULL; + sync->filters--; + return 0; + } + } + return(-EMLINK); +} + +void ms_sync_set_samples_per_tick(MSSync *sync,gint size) +{ + if (sync->samples_per_tick==0) + { + sync->samples_per_tick=size; + g_cond_signal(sync->thread_cond); + } + else sync->samples_per_tick=size; +} + +/* call the setup func of each filter attached to the graph */ +void ms_sync_setup(MSSync *sync) +{ + GList *elem=sync->execution_list; + MSFilter *f; + while(elem!=NULL){ + f=(MSFilter*)elem->data; + if (f->klass->setup!=NULL){ + f->klass->setup(f,sync); + } + elem=g_list_next(elem); + } +} + +/* call the unsetup func of each filter attached to the graph */ +void ms_sync_unsetup(MSSync *sync) +{ + GList *elem=sync->execution_list; + MSFilter *f; + while(elem!=NULL){ + f=(MSFilter*)elem->data; + if (f->klass->unsetup!=NULL){ + f->klass->unsetup(f,sync); + } + elem=g_list_next(elem); + } +} + + +int ms_sync_uninit(MSSync *sync) +{ + g_mutex_free(sync->lock); + g_cond_free(sync->thread_cond); + g_cond_free(sync->stop_cond); + return 0; +} + diff --git a/linphone/mediastreamer/mssync.h b/linphone/mediastreamer/mssync.h new file mode 100644 index 000000000..012c068f7 --- /dev/null +++ b/linphone/mediastreamer/mssync.h @@ -0,0 +1,136 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MS_SYNC_H +#define MS_SYNC_H + + +#include "msfilter.h" + +struct _MSSync +{ + struct _MSSyncClass *klass; + GMutex *lock; + MSFilter **attached_filters; /* pointer to a table of pointer of filters*/ + GList *execution_list; /* the list of filters to be executed. This is filled with compilation */ + gint filters; /*number of filters attached to the sync */ + gint run; /* flag to indicate whether the sync must be run or not */ + GThread * thread; /* the thread ressource if this sync is run by a thread*/ + GCond *thread_cond; + GCond *stop_cond; + guint32 flags; + gint interval; /* in miliseconds*/ +#define MS_SYNC_NEED_UPDATE (0x0001) /* a modification has occured in the processing chains + attached to this sync; so the execution list has to be updated */ + guint samples_per_tick; /* number of bytes produced by sources of the processing chains*/ + guint32 ticks; + guint32 time; /* a time since the start of the sync expressed in milisec*/ +}; + +typedef struct _MSSync MSSync; + +typedef void (*MSSyncDestroyFunc)(MSSync*); +typedef void (*MSSyncSyncFunc)(MSSync*); +typedef int (*MSSyncAttachFunc)(MSSync*,MSFilter*); +typedef int (*MSSyncDetachFunc)(MSSync*,MSFilter*); + +typedef struct _MSSyncClass +{ + gint max_filters; /* the maximum number of filters that can be attached to this sync*/ + MSSyncSyncFunc synchronize; + MSSyncDestroyFunc destroy; + MSSyncAttachFunc attach; + MSSyncDetachFunc detach; +} MSSyncClass; + +/* private */ +void ms_sync_init(MSSync *sync); +void ms_sync_class_init(MSSyncClass *klass); + +int ms_sync_attach_generic(MSSync *sync,MSFilter *f); +int ms_sync_detach_generic(MSSync *sync,MSFilter *f); + +/* public*/ + +#define MS_SYNC(sync) ((MSSync*)(sync)) +#define MS_SYNC_CLASS(klass) ((MSSyncClass*)(klass)) + +#define ms_sync_synchronize(_sync) \ +do \ +{ \ + MSSync *__sync=_sync; \ + __sync->ticks++; \ + ((__sync)->klass->synchronize((__sync))); \ +}while(0) + +void ms_sync_setup(MSSync *sync); + +void ms_sync_unsetup(MSSync *sync); + +#define ms_sync_update(sync) (sync)->flags|=MS_SYNC_NEED_UPDATE + +#define ms_sync_get_samples_per_tick(sync) ((sync)->samples_per_tick) + +void ms_sync_set_samples_per_tick(MSSync *sync,gint size); + +#define ms_sync_get_tick_count(sync) ((sync)->ticks) + +#define ms_sync_suspend(sync) g_cond_wait((sync)->thread_cond,(sync)->lock) + +#define ms_sync_lock(sync) g_mutex_lock((sync)->lock) + +#define ms_sync_unlock(sync) g_mutex_unlock((sync)->lock) + +#define ms_sync_trylock(sync) g_mutex_trylock((sync)->lock) + +/** + * function_name:ms_sync_attach + * @sync: A #MSSync object. + * @f: A #MSFilter object. + * + * Attach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain. + * + * Returns: 0 if successfull, a negative value reprensenting the errno.h error. + */ +int ms_sync_attach(MSSync *sync,MSFilter *f); + +/** + * ms_sync_detach: + * @sync: A #MSSync object. + * @f: A #MSFilter object. + * + * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain. + * The processing chain will no more be executed. + * + * Returns: 0 if successfull, a negative value reprensenting the errno.h error. + */ +int ms_sync_detach(MSSync *sync,MSFilter *f); + +int ms_sync_uninit(MSSync *sync); + +#define ms_sync_start(sync) ms_start((sync)) +#define ms_sync_stop(sync) ms_stop((sync)) + + +/*destroy*/ +#define ms_sync_destroy(sync) (sync)->klass->destroy((sync)) + + +#endif diff --git a/linphone/mediastreamer/mstcpclient.c b/linphone/mediastreamer/mstcpclient.c new file mode 100644 index 000000000..abeb5f8ad --- /dev/null +++ b/linphone/mediastreamer/mstcpclient.c @@ -0,0 +1,137 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mstcpclient.h" +#include +#include +#include +#include + + +void ms_tcp_client_process(MSTcpClient *r); +void ms_tcp_client_init(MSTcpClient *r); +void ms_tcp_client_destroy(MSTcpClient *r); +void ms_tcp_client_class_init(MSTcpClientClass *klass); + +static MSTcpClientClass *ms_tcp_client_class=NULL; + +MSFilter * ms_tcp_client_new(void) +{ + MSTcpClient *r; + + r=g_new(MSTcpClient,1); + + if (ms_tcp_client_class==NULL) + { + ms_tcp_client_class=g_new(MSTcpClientClass,1); + ms_tcp_client_class_init(ms_tcp_client_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_tcp_client_class); + ms_tcp_client_init(r); + return(MS_FILTER(r)); +} + + +void ms_tcp_client_init(MSTcpClient *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->outqueues=r->q_outputs; + memset(r->q_outputs,0,sizeof(MSQueue*)); + r->sock=-1; + r->msg=NULL; +} + + +int ms_tcp_client_connect(MSTcpClient *obj, const char *addr, int port){ + struct addrinfo hints; + struct addrinfo *res; + char service[40]; + int err; + sprintf(service,"%i",port); + memset(&hints,0,sizeof(hints)); + hints.ai_family=PF_UNSPEC; + hints.ai_socktype=SOCK_STREAM; + err=getaddrinfo(addr,service,&hints,&res); + if (err!=0){ + g_warning("getaddrinfo error: %s",gai_strerror(err)); + return -1; + } + obj->sock=socket(res->ai_family,res->ai_socktype,0); + if (obj->sock<0){ + g_warning("fail to create socket: %s",strerror(errno)); + return -1; + } + err=connect(obj->sock,res->ai_addr,res->ai_addrlen); + if (err<0){ + g_warning("Could not connect to %s:%i : %s",addr,port,strerror(errno)); + close(obj->sock); + obj->sock=-1; + return -1; + } + return 0; +} + +void ms_tcp_client_class_init(MSTcpClientClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"TcpClient"); + MS_FILTER_CLASS(klass)->max_qoutputs=1; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_tcp_client_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_tcp_client_process; + ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE); +} + + + +void ms_tcp_client_process(MSTcpClient *r) +{ + static const int rcvsz=5000; + int err; + if (r->sock>0){ + if (r->msg==NULL){ + r->msg=ms_message_new(rcvsz); + memset(r->msg->data,0,rcvsz); + } + err=recv(r->sock,r->msg->data,rcvsz,MSG_DONTWAIT); + if (err<0 && errno!=EWOULDBLOCK && errno!=EAGAIN){ + g_warning("recv error: %s",strerror(errno)); + }else if (err>0){ + r->msg->size=err; + ms_queue_put(r->q_outputs[0],r->msg); + printf("output new message %p,%i\n",r->msg->data,r->msg->size); + r->msg=NULL; + + } + } +} + +void ms_tcp_client_uninit( MSTcpClient *obj){ + if (obj->sock>0) close(obj->sock); + if (obj->msg!=NULL) ms_message_destroy(obj->msg); +} + +void ms_tcp_client_destroy( MSTcpClient *obj) +{ + ms_tcp_client_uninit(obj); + g_free(obj); +} + + + diff --git a/linphone/mediastreamer/mstcpclient.h b/linphone/mediastreamer/mstcpclient.h new file mode 100644 index 000000000..639593cd6 --- /dev/null +++ b/linphone/mediastreamer/mstcpclient.h @@ -0,0 +1,50 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef mstcpclient_h +#define mstcpclient_h + +#include "msfilter.h" + +/* According to earlier standards */ +#include +#include +#include + + +struct _MSTcpClient{ + MSFilter parent; + MSQueue *q_outputs[1]; + int sock; + MSMessage *msg; +}; + +typedef struct _MSTcpClient MSTcpClient; + +struct _MSTcpClientClass{ + MSFilterClass parent; +}; + +typedef struct _MSTcpClientClass MSTcpClientClass; + +MSFilter *ms_tcp_client_new(); +int ms_tcp_client_connect(MSTcpClient *obj, const char *addr, int port); +#define MS_TCP_CLIENT(o) ((MSTcpClient*)(o)) +#endif diff --git a/linphone/mediastreamer/mstcpserv.c b/linphone/mediastreamer/mstcpserv.c new file mode 100644 index 000000000..9bbd61db7 --- /dev/null +++ b/linphone/mediastreamer/mstcpserv.c @@ -0,0 +1,174 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mstcpserv.h" +#include +#include +#include +#include + +#include +#include + + +void ms_tcp_serv_process(MSTcpServ *r); +void ms_tcp_serv_init(MSTcpServ *r, int port); +void ms_tcp_serv_destroy(MSTcpServ *r); +void ms_tcp_serv_class_init(MSTcpServClass *klass); + +static MSTcpServClass *ms_tcp_serv_class=NULL; + +MSFilter * ms_tcp_serv_new(void) +{ + MSTcpServ *r; + + r=g_new(MSTcpServ,1); + + if (ms_tcp_serv_class==NULL) + { + ms_tcp_serv_class=g_new(MSTcpServClass,1); + ms_tcp_serv_class_init(ms_tcp_serv_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_tcp_serv_class); + ms_tcp_serv_init(r,5800); + return(MS_FILTER(r)); +} + + +void ms_tcp_serv_init(MSTcpServ *r, int port) +{ + struct addrinfo *res; + struct addrinfo hints; + char service[20]; + int err; + int val=1; + + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->inqueues=r->q_inputs; + memset(r->q_inputs,0,sizeof(MSQueue*)); + memset(&r->set,0,sizeof(fd_set)); + r->maxfd=0; + r->asock=socket(PF_INET,SOCK_STREAM,0); + if (r->asock<0){ + g_warning("Could not create socket: %s",strerror(errno)); + return; + } + err=fcntl(r->asock,F_SETFL,O_NONBLOCK); + if (err<0){ + g_warning("Could not non blocking flag on socket: %s",strerror(errno)); + return; + } + err=setsockopt(r->asock,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int)); + if (err<0){ + g_warning("Could not set socket reusable: %s",strerror(errno)); + return; + } + sprintf(service,"%i",port); + memset(&hints,0,sizeof(hints)); + hints.ai_family=PF_UNSPEC; + hints.ai_socktype=SOCK_STREAM; + if (err=getaddrinfo("0.0.0.0",service,&hints,&res)!=0){ + g_warning("Could not getaddrinfo: %s",gai_strerror(err)); + return; + } + err=bind(r->asock,(struct sockaddr *)res->ai_addr,res->ai_addrlen); + freeaddrinfo(res); + if (err<0){ + g_warning("Could not bind socket: %s",strerror(errno)); + return; + } + err=listen(r->asock,10); + if (err<0){ + g_warning("Could not listen: %s",strerror(errno)); + return; + } +} + +void ms_tcp_serv_class_init(MSTcpServClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"TcpServ"); + MS_FILTER_CLASS(klass)->max_qinputs=1; + MS_FILTER_CLASS(klass)->max_finputs=0; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_tcp_serv_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_tcp_serv_process; +} + +static void accept_new_clients(MSTcpServ *r){ + int sock; + struct sockaddr_storage ss; + socklen_t len=sizeof(ss); + int val=1; + int err; + + sock=accept(r->asock,(struct sockaddr*)&ss,&len); + if (sock<0){ + if (errno!=EWOULDBLOCK && errno!=EAGAIN) g_warning("Could not accept connection: %s",strerror(errno)); + return; + } + FD_SET(sock,&r->set); + err=setsockopt(sock,SOL_TCP,TCP_NODELAY,&val,sizeof(int)); + if (err<0){ + g_warning("Could not set tcp nodelay option: %s",strerror(errno)); + } + if (r->maxfdmaxfd=sock; + printf("New client accepted.\n"); +} + + +void ms_tcp_serv_process(MSTcpServ *r) +{ + MSMessage *msg; + int err; + g_return_if_fail(r->asock>0); + /*printf("ms_tcp_serv_process\n");*/ + /* first accept incoming connections */ + accept_new_clients(r); + /* send data to all clients */ + msg=ms_queue_get(r->q_inputs[0]); + if (msg!=NULL){ + int i; + for (i=0;imaxfd+1;i++){ + if (FD_ISSET(i,&r->set)){ + err=send(i,msg->data,msg->size,0); + if (err<0){ + FD_CLR(i,&r->set); + close(i); + g_message("Client disconnected."); + } + } + } + ms_message_destroy(msg); + } + +} + +void ms_tcp_serv_uninit( MSTcpServ *obj){ + if (obj->asock>0) close(obj->asock); +} + +void ms_tcp_serv_destroy( MSTcpServ *obj) +{ + ms_tcp_serv_uninit(obj); + g_free(obj); +} + + + diff --git a/linphone/mediastreamer/mstcpserv.h b/linphone/mediastreamer/mstcpserv.h new file mode 100644 index 000000000..1ed6eb3b8 --- /dev/null +++ b/linphone/mediastreamer/mstcpserv.h @@ -0,0 +1,33 @@ +#ifndef mstcpserver_h +#define mstcpserver_h + +#include "msfilter.h" + +/* According to earlier standards */ +#include +#include +#include + + +struct _MSTcpServ{ + MSFilter parent; + MSQueue *q_inputs[1]; + fd_set set; + int maxfd; + int asock; +}; + +typedef struct _MSTcpServ MSTcpServ; + +struct _MSTcpServClass{ + MSFilterClass parent; +}; + +typedef struct _MSTcpServClass MSTcpServClass; + +MSFilter *ms_tcp_serv_new(); +#define MS_TCP_SERV(o) ((MSTcpServ*)(o)) + + +#endif + diff --git a/linphone/mediastreamer/mstimer.c b/linphone/mediastreamer/mstimer.c new file mode 100644 index 000000000..25200a913 --- /dev/null +++ b/linphone/mediastreamer/mstimer.c @@ -0,0 +1,114 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mstimer.h" +#include +#include +#include +#include + +static MSTimerClass *ms_timer_class=NULL; + + +void ms_timer_init(MSTimer *sync) +{ + ms_sync_init(MS_SYNC(sync)); + MS_SYNC(sync)->attached_filters=sync->filters; + memset(sync->filters,0,MSTIMER_MAX_FILTERS*sizeof(MSFilter*)); + MS_SYNC(sync)->samples_per_tick=80; + ms_timer_set_interval(sync,10); + sync->state=MS_TIMER_STOPPED; +} + +void ms_timer_class_init(MSTimerClass *klass) +{ + ms_sync_class_init(MS_SYNC_CLASS(klass)); + MS_SYNC_CLASS(klass)->max_filters=MSTIMER_MAX_FILTERS; + MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_timer_synchronize; + MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_timer_destroy; + /* no need to overload these function*/ + MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic; + MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic; +} + +void ms_timer_destroy(MSTimer *timer) +{ + g_free(timer); +} + + +void ms_timer_synchronize(MSTimer *timer) +{ + //printf("ticks=%i \n",MS_SYNC(timer)->ticks); + if (timer->state==MS_TIMER_STOPPED){ + timer->state=MS_TIMER_RUNNING; + gettimeofday(&timer->orig,NULL); + timer->sync.time=0; + } + else { + gint32 diff,time; + struct timeval tv,cur; + + timer->sync.time+=timer->milisec; + + gettimeofday(&cur,NULL); + time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 ); + while((diff = timer->sync.time-time) > 0) + { + tv.tv_sec = timer->milisec/1000; + tv.tv_usec = (timer->milisec%1000)*1000; + select(0,NULL,NULL,NULL,&tv); + gettimeofday(&cur,NULL); + time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 ); + } + if (diff<-50) g_warning("Must catchup %i miliseconds.",-diff); + } + + return; +} + + +MSSync *ms_timer_new() +{ + MSTimer *timer; + + timer=g_malloc(sizeof(MSTimer)); + ms_timer_init(timer); + if (ms_timer_class==NULL) + { + ms_timer_class=g_new(MSTimerClass,1); + ms_timer_class_init(ms_timer_class); + } + MS_SYNC(timer)->klass=MS_SYNC_CLASS(ms_timer_class); + return(MS_SYNC(timer)); +} + +void ms_timer_set_interval(MSTimer *timer, int milisec) +{ + + MS_SYNC(timer)->ticks=0; + MS_SYNC(timer)->interval=milisec; + timer->interval.tv_sec=milisec/1000; + timer->interval.tv_usec=(milisec % 1000)*1000; + timer->milisec=milisec; + + +} diff --git a/linphone/mediastreamer/mstimer.h b/linphone/mediastreamer/mstimer.h new file mode 100644 index 000000000..5c7e8edee --- /dev/null +++ b/linphone/mediastreamer/mstimer.h @@ -0,0 +1,68 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef MSTIMER_H +#define MSTIMER_H + +#include "mssync.h" +#include + +#define MSTIMER_MAX_FILTERS 10 + +/* MSTimer derivates from MSSync base class*/ + +typedef struct _MSTimer +{ + /* the MSSync must be the first field of the object in order to the object mechanism to work*/ + MSSync sync; + MSFilter *filters[MSTIMER_MAX_FILTERS]; + gint milisec; /* the interval */ + struct timeval interval; + struct timeval orig; + gint state; +} MSTimer; + + +typedef struct _MSTimerClass +{ + /* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/ + MSSyncClass parent_class; +} MSTimerClass; + + +/*private*/ +#define MS_TIMER_RUNNING 1 +#define MS_TIMER_STOPPED 0 +void ms_timer_init(MSTimer *sync); +void ms_timer_class_init(MSTimerClass *sync); + +void ms_timer_destroy(MSTimer *timer); +void ms_timer_synchronize(MSTimer *timer); + +/*public*/ +void ms_timer_set_interval(MSTimer *timer, gint milisec); + +/* casts a MSSync object into a MSTimer */ +#define MS_TIMER(sync) ((MSTimer*)(sync)) +/* casts a MSSync class into a MSTimer class */ +#define MS_TIMER_CLASS(klass) ((MSTimerClass*)(klass)) + +MSSync *ms_timer_new(); + +#endif diff --git a/linphone/mediastreamer/mstruespeechdecoder.c b/linphone/mediastreamer/mstruespeechdecoder.c new file mode 100644 index 000000000..aba6e0645 --- /dev/null +++ b/linphone/mediastreamer/mstruespeechdecoder.c @@ -0,0 +1,152 @@ +/* + Copyright 2003 Robert W. Brewer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mstruespeechdecoder.h" +#include "mscodec.h" + +MSCodecInfo TrueSpeechinfo = +{ + { + "TrueSpeech codec", + 0, + MS_FILTER_AUDIO_CODEC, + ms_truespeechencoder_new, + "This is a proprietary codec by the DSP Group that is used in some " + "Windows applications. It has a good quality and bitrate. " + "It requires the Windows DLLs tssoft32.acm and " + "tsd32.dll to be available." + }, + ms_truespeechencoder_new, + ms_truespeechdecoder_new, + 480, + 32, + 8536, + 8000, + 116, + "TSP0", + 1, + 1, +}; + + +static MSTrueSpeechDecoderClass *ms_truespeechdecoder_class = 0; + +/* FOR INTERNAL USE*/ +void ms_truespeechdecoder_init(MSTrueSpeechDecoder *r); +void ms_truespeechdecoder_class_init(MSTrueSpeechDecoderClass *klass); +void ms_truespeechdecoder_destroy(MSTrueSpeechDecoder *obj); +void ms_truespeechdecoder_process(MSTrueSpeechDecoder *r); + +MSFilter * ms_truespeechdecoder_new(void) +{ + MSTrueSpeechDecoder *r = 0; + + if (!ms_truespeechdecoder_class) + { + ms_truespeechdecoder_class = g_new(MSTrueSpeechDecoderClass, 1); + ms_truespeechdecoder_class_init(ms_truespeechdecoder_class); + } + + r = g_new(MSTrueSpeechDecoder, 1); + MS_FILTER(r)->klass = MS_FILTER_CLASS(ms_truespeechdecoder_class); + ms_truespeechdecoder_init(r); + return MS_FILTER(r); +} + + +/* FOR INTERNAL USE*/ +void ms_truespeechdecoder_init(MSTrueSpeechDecoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos = r->f_inputs; + MS_FILTER(r)->outfifos = r->f_outputs; + + WAVEFORMATEX* wf = ms_truespeechencoder_wf_create(); + + r->codec = win32codec_create(wf, 0); + free(wf); + + MS_FILTER(r)->r_mingran = r->codec->min_insize; + + MS_FILTER_CLASS(ms_truespeechdecoder_class)->r_maxgran = + r->codec->min_insize; + MS_FILTER_CLASS(ms_truespeechdecoder_class)->w_maxgran = + r->codec->min_outsize; + + memset(r->f_inputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT); + memset(r->f_outputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT); +} + +void ms_truespeechdecoder_class_init(MSTrueSpeechDecoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass), "TrueSpeechDecoder"); + MS_FILTER_CLASS(klass)->max_finputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT; + MS_FILTER_CLASS(klass)->max_foutputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT; + MS_FILTER_CLASS(klass)->r_maxgran = 0; /* filled in by first instance */ + MS_FILTER_CLASS(klass)->w_maxgran = 0; /* filled in by first instance */ + MS_FILTER_CLASS(klass)->destroy = (MSFilterDestroyFunc)ms_truespeechdecoder_destroy; + MS_FILTER_CLASS(klass)->process = (MSFilterProcessFunc)ms_truespeechdecoder_process; + MS_FILTER_CLASS(klass)->info = MS_FILTER_INFO(&TrueSpeechinfo); + klass->driver = win32codec_create_driver(TRUESPEECH_DLL, + TRUESPEECH_FORMAT_TAG, 0); +} + +void ms_truespeechdecoder_process(MSTrueSpeechDecoder *r) +{ + MSFifo *fi,*fo; + gint err1; + void *s,*d; + + /* process output fifos, but there is only one for this class of filter*/ + + fi = r->f_inputs[0]; + fo = r->f_outputs[0]; + if (fi) + { + err1 = ms_fifo_get_read_ptr(fi, r->codec->min_insize, &s); + if (err1 > 0) + { + err1 = ms_fifo_get_write_ptr(fo, r->codec->min_outsize, &d); + if (d) + { + signed long n; + n = win32codec_convert(r->codec, + s, r->codec->min_insize, + d, r->codec->min_outsize); + } + } + + } +} + + + +void ms_truespeechdecoder_uninit(MSTrueSpeechDecoder *obj) +{ + win32codec_destroy(obj->codec); +} + +void ms_truespeechdecoder_destroy(MSTrueSpeechDecoder *obj) +{ + ms_truespeechdecoder_uninit(obj); + g_free(obj); +} + + diff --git a/linphone/mediastreamer/mstruespeechdecoder.h b/linphone/mediastreamer/mstruespeechdecoder.h new file mode 100644 index 000000000..624774365 --- /dev/null +++ b/linphone/mediastreamer/mstruespeechdecoder.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2003 Robert W. Brewer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSTRUESPEECHDECODER_H +#define MSTRUESPEECHDECODER_H + +#include "msfilter.h" +#include "mstruespeechencoder.h" + + + +typedef struct _MSTrueSpeechDecoder +{ + /* the MSTrueSpeechDecoder derives from MSFilter, so the MSFilter + object MUST be the first of the MSTrueSpeechDecoder object + in order for the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT]; + MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT]; + Win32Codec* codec; +} MSTrueSpeechDecoder; + +typedef struct _MSTrueSpeechDecoderClass +{ + /* the MSTrueSpeechDecoder derives from MSFilter, + so the MSFilter class MUST be the first of the MSTrueSpechDecoder + class + in order for the class mechanism to work*/ + MSFilterClass parent_class; + Win32CodecDriver* driver; +} MSTrueSpeechDecoderClass; + +/* PUBLIC */ +#define MS_TRUESPEECHDECODER(filter) ((MSTrueSpechMDecoder*)(filter)) +#define MS_TRUESPEECHDECODER_CLASS(klass) ((MSTrueSpeechDecoderClass*)(klass)) +MSFilter * ms_truespeechdecoder_new(void); + + +#endif diff --git a/linphone/mediastreamer/mstruespeechencoder.c b/linphone/mediastreamer/mstruespeechencoder.c new file mode 100644 index 000000000..0b00c0c35 --- /dev/null +++ b/linphone/mediastreamer/mstruespeechencoder.c @@ -0,0 +1,161 @@ +/* + Copyright 2003 Robert W. Brewer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mstruespeechencoder.h" +#include "mscodec.h" + +#define TRUESPEECH_CBSIZE 32 + +extern MSCodecInfo TrueSpeechinfo; + +static MSTrueSpeechEncoderClass *ms_truespeechencoder_class = 0; + +/* FOR INTERNAL USE*/ +void ms_truespeechencoder_init(MSTrueSpeechEncoder *r); +void ms_truespeechencoder_class_init(MSTrueSpeechEncoderClass *klass); +void ms_truespeechencoder_destroy(MSTrueSpeechEncoder *obj); +void ms_truespeechencoder_process(MSTrueSpeechEncoder *r); + +MSFilter * ms_truespeechencoder_new(void) +{ + MSTrueSpeechEncoder *r = 0; + + if (!ms_truespeechencoder_class) + { + ms_truespeechencoder_class = g_new(MSTrueSpeechEncoderClass, 1); + ms_truespeechencoder_class_init(ms_truespeechencoder_class); + } + + r = g_new(MSTrueSpeechEncoder, 1); + MS_FILTER(r)->klass = MS_FILTER_CLASS(ms_truespeechencoder_class); + ms_truespeechencoder_init(r); + return MS_FILTER(r); +} + + +/* FOR INTERNAL USE*/ +void ms_truespeechencoder_init(MSTrueSpeechEncoder *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos = r->f_inputs; + MS_FILTER(r)->outfifos = r->f_outputs; + + WAVEFORMATEX* wf = ms_truespeechencoder_wf_create(); + + r->codec = win32codec_create(wf, 1); + free(wf); + + MS_FILTER(r)->r_mingran = r->codec->min_insize; + + MS_FILTER_CLASS(ms_truespeechencoder_class)->r_maxgran = + r->codec->min_insize; + MS_FILTER_CLASS(ms_truespeechencoder_class)->w_maxgran = + r->codec->min_outsize; + + memset(r->f_inputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT); + memset(r->f_outputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT); +} + +void ms_truespeechencoder_class_init(MSTrueSpeechEncoderClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass), "TrueSpeechEncoder"); + MS_FILTER_CLASS(klass)->max_finputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT; + MS_FILTER_CLASS(klass)->max_foutputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT; + MS_FILTER_CLASS(klass)->r_maxgran = 0; /* filled in by first instance */ + MS_FILTER_CLASS(klass)->w_maxgran = 0; /* filled in by first instance */ + MS_FILTER_CLASS(klass)->destroy = (MSFilterDestroyFunc)ms_truespeechencoder_destroy; + MS_FILTER_CLASS(klass)->process = (MSFilterProcessFunc)ms_truespeechencoder_process; + MS_FILTER_CLASS(klass)->info = MS_FILTER_INFO(&TrueSpeechinfo); + klass->driver = win32codec_create_driver(TRUESPEECH_DLL, + TRUESPEECH_FORMAT_TAG, 1); +} + +void ms_truespeechencoder_process(MSTrueSpeechEncoder *r) +{ + MSFifo *fi,*fo; + int err1; + void *s,*d; + + /* process output fifos, but there is only one for this class of filter*/ + + fi = r->f_inputs[0]; + fo = r->f_outputs[0]; + if (fi) + { + err1 = ms_fifo_get_read_ptr(fi, r->codec->min_insize, &s); + if (err1 > 0) + { + err1 = ms_fifo_get_write_ptr(fo, r->codec->min_outsize, &d); + if (d) + { + signed long n; + + n = win32codec_convert(r->codec, + s, r->codec->min_insize, + d, r->codec->min_outsize); + } + } + + } +} + + + +void ms_truespeechencoder_uninit(MSTrueSpeechEncoder *obj) +{ + win32codec_destroy(obj->codec); +} + +void ms_truespeechencoder_destroy(MSTrueSpeechEncoder *obj) +{ + ms_truespeechencoder_uninit(obj); + g_free(obj); +} + + +WAVEFORMATEX* ms_truespeechencoder_wf_create() +{ + WAVEFORMATEX* ts_wf = 0; + long* iptr = 0; + + ts_wf = malloc(sizeof(WAVEFORMATEX) + TRUESPEECH_CBSIZE); + if (!ts_wf) + { + return 0; + } + + memset(ts_wf, 0, sizeof(*ts_wf) + TRUESPEECH_CBSIZE); + + ts_wf->wFormatTag = TRUESPEECH_FORMAT_TAG; + ts_wf->nChannels = 1; + ts_wf->nSamplesPerSec = 8000; + ts_wf->wBitsPerSample = 1; + ts_wf->nBlockAlign = 32; + ts_wf->nAvgBytesPerSec = 1067; + ts_wf->cbSize = TRUESPEECH_CBSIZE; + + /* write extra data needed by TrueSpeech codec found + from examining a TrueSpeech .wav file header + */ + iptr = (long*)(ts_wf + 1); + *iptr = 0x00f00001; + + return ts_wf; +} diff --git a/linphone/mediastreamer/mstruespeechencoder.h b/linphone/mediastreamer/mstruespeechencoder.h new file mode 100644 index 000000000..04e40bb8b --- /dev/null +++ b/linphone/mediastreamer/mstruespeechencoder.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2003 Robert W. Brewer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSTRUESPEECHENCODER_H +#define MSTRUESPEECHENCODER_H + +#include "msfilter.h" +#include + + +#define MS_TRUESPEECH_CODEC_MAX_IN_OUT 1 /* max inputs/outputs per filter*/ + +#define TRUESPEECH_FORMAT_TAG 0x22 +#define TRUESPEECH_DLL "tssoft32.acm" + +typedef struct _MSTrueSpeechEncoder +{ + /* the MSTrueSpeechEncoder derives from MSFilter, so the MSFilter + object MUST be the first of the MSTrueSpeechEncoder object + in order for the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT]; + MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT]; + Win32Codec* codec; +} MSTrueSpeechEncoder; + +typedef struct _MSTrueSpeechEncoderClass +{ + /* the MSTrueSpeechEncoder derives from MSFilter, + so the MSFilter class MUST be the first of the MSTrueSpechEncoder + class + in order for the class mechanism to work*/ + MSFilterClass parent_class; + Win32CodecDriver* driver; +} MSTrueSpeechEncoderClass; + +/* PUBLIC */ +#define MS_TRUESPEECHENCODER(filter) ((MSTrueSpechMEncoder*)(filter)) +#define MS_TRUESPEECHENCODER_CLASS(klass) ((MSTrueSpeechEncoderClass*)(klass)) +MSFilter * ms_truespeechencoder_new(void); + +/* for internal use only */ +WAVEFORMATEX* ms_truespeechencoder_wf_create(); + + +#endif diff --git a/linphone/mediastreamer/msutils.h b/linphone/mediastreamer/msutils.h new file mode 100644 index 000000000..012b87d81 --- /dev/null +++ b/linphone/mediastreamer/msutils.h @@ -0,0 +1,61 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef MSUTILS_H +#define MSUTILS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GLIB +#include +#else +#include +#endif +#include + +#ifndef ENODATA +/* this is for freeBSD .*/ +#define ENODATA EWOULDBLOCK +#endif + +#ifdef MS_DEBUG + +#define ms_trace g_message + +#else + +#define ms_trace(...) +#endif + +#define ms_warning g_warning +#define ms_error g_error + +#define VIDEO_SIZE_CIF_W 352 +#define VIDEO_SIZE_CIF_H 288 +#define VIDEO_SIZE_QCIF_W 176 +#define VIDEO_SIZE_QCIF_H 144 +#define VIDEO_SIZE_4CIF_W 704 +#define VIDEO_SIZE_4CIF_H 576 +#define VIDEO_SIZE_MAX_W VIDEO_SIZE_4CIF_W +#define VIDEO_SIZE_MAX_H VIDEO_SIZE_4CIF_H + + +#endif diff --git a/linphone/mediastreamer/msv4l.c b/linphone/mediastreamer/msv4l.c new file mode 100644 index 000000000..b661a25af --- /dev/null +++ b/linphone/mediastreamer/msv4l.c @@ -0,0 +1,522 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msv4l.h" +#include +#include +#include +#include +#include +#include +#include +#include + +char *v4l_palette_string[17]={ + "none", + "GREY", /* Linear greyscale */ + "HI240", /* High 240 cube (BT848) */ + "RGB565", /* 565 16 bit RGB */ + "RGB24", /* 24bit RGB */ + "RGB32", /* 32bit RGB */ + "RGB555", /* 555 15bit RGB */ + "YUV422", /* YUV422 capture */ + "YUYV", + "UYVY", /* The great thing about standards is ... */ + "YUV420", + "YUV411", /* YUV411 capture */ + "RAW", /* RAW capture (BT848) */ + "YUV422P", /* YUV 4:2:2 Planar */ + "YUV411P", /* YUV 4:1:1 Planar */ + "YUV420P", /* YUV 4:2:0 Planar */ + "YUV410P", /* YUV 4:1:0 Planar */ +}; + +#define V4L_PALETTE_TO_STRING(pal) v4l_palette_string[(pal)] + +static int v4l_string_to_enum(const char *format){ + if (strcmp(format,"RGB24")==0) return VIDEO_PALETTE_RGB24; + if (strcmp(format,"YUV420P")==0) return VIDEO_PALETTE_YUV420P; + g_error("unsupported format, fixme"); + return -1; +} + +MSFilterInfo v4l_info= +{ + "Video4Linux", + 0, + MS_FILTER_VIDEO_IO, + ms_v4l_new, + NULL +}; + + +static MSV4lClass *ms_v4l_class=NULL; + +MSFilter * ms_v4l_new() +{ + MSV4l *obj; + obj=g_malloc0(sizeof(MSV4l)); + if (ms_v4l_class==NULL) + { + ms_v4l_class=g_malloc0(sizeof(MSV4lClass)); + ms_v4l_class_init(ms_v4l_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_v4l_class); + ms_v4l_init(obj); + return MS_FILTER(obj); +} + +void ms_v4l_init(MSV4l *obj) +{ + ms_video_source_init(MS_VIDEO_SOURCE(obj)); + /* initialize the static buffer */ + obj->use_mmap=0; + obj->fd=-1; + obj->device = g_strdup("/dev/video0"); + obj->count=0; + obj->allocdbuf=NULL; + obj->grab_image=FALSE; + obj->image_grabbed=NULL; + obj->cond=g_cond_new(); + obj->stopcond=g_cond_new(); + obj->v4lthread=NULL; + obj->thread_exited=FALSE; + obj->frame=0; + MS_VIDEO_SOURCE(obj)->format="YUV420P"; /*default value */ + MS_VIDEO_SOURCE(obj)->width = VIDEO_SIZE_CIF_W; /*default value */ + MS_VIDEO_SOURCE(obj)->height = VIDEO_SIZE_CIF_H; /*default value */ +} + +void ms_v4l_class_init(MSV4lClass *klass) +{ + ms_video_source_class_init(MS_VIDEO_SOURCE_CLASS(klass)); + MS_VIDEO_SOURCE_CLASS(klass)->start=(void (*)(MSVideoSource *))ms_v4l_start; + MS_VIDEO_SOURCE_CLASS(klass)->stop=(void (*)(MSVideoSource *))ms_v4l_stop; + MS_VIDEO_SOURCE_CLASS(klass)->set_device=(int (*)(MSVideoSource*,const gchar*))ms_v4l_set_device; + MS_FILTER_CLASS(klass)->process=(void (*)(MSFilter *))v4l_process; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_v4l_destroy; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"msv4l"); + MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&v4l_info; +} + +void *v4l_thread(MSV4l *obj); + +void ms_v4l_start(MSV4l *obj) +{ + int err; + ms_filter_lock(MS_FILTER(obj)); + obj->fd=open(obj->device,O_RDONLY); + if (obj->fd<0) + { + g_warning("MSV4l: cannot open video device: %s.",strerror(errno)); + MS_VIDEO_SOURCE(obj)->format="RGB24"; + }else{ + err=v4l_configure(obj); + if (err<0) + { + g_warning("MSV4l: could not get configuration of video device"); + } + } + obj->thread_exited=FALSE; + obj->v4lthread=g_thread_create((GThreadFunc)v4l_thread,(gpointer)obj,FALSE,NULL); + while(!obj->thread_run) g_cond_wait(obj->cond,MS_FILTER(obj)->lock); + ms_filter_unlock(MS_FILTER(obj)); +} + +void ms_v4l_stop(MSV4l *obj) +{ + ms_filter_lock(MS_FILTER(obj)); + obj->thread_run=FALSE; + obj->grab_image=FALSE; + g_cond_signal(obj->cond); + while(!obj->thread_exited) g_cond_wait(obj->stopcond,MS_FILTER(obj)->lock); + if (obj->fd>0) + { + close(obj->fd); + obj->fd=-1; + if (!obj->use_mmap){ + if (obj->allocdbuf!=NULL) ms_buffer_destroy(obj->allocdbuf); + obj->allocdbuf=NULL; + }else + { + munmap(obj->mmapdbuf,obj->vmbuf.size); + obj->mmapdbuf=NULL; + } + obj->image_grabbed=NULL; + } + + obj->v4lthread=NULL; + ms_filter_unlock(MS_FILTER(obj)); +} + +int ms_v4l_set_device(MSV4l *obj, const gchar *device) +{ + if (obj->device!=NULL) g_free(obj->device); + obj->device=g_strdup(device); + return 0; +} + +void ms_v4l_set_size(MSV4l *obj, gint width, gint height) +{ + gint err; + gboolean restart = FALSE; + + if (obj->fd == -1) + { + obj->fd = open(obj->device, O_RDONLY); + if (obj->fd < 0) + { + g_warning("MSV4l: cannot open video device: %s.",strerror(errno)); + return; + } + } else + restart = TRUE; + + ms_filter_lock(MS_FILTER(obj)); + err = ioctl(obj->fd, VIDIOCGCAP, &obj->cap); + if (err != 0) + { + g_warning("MSV4l: cannot get device capabilities: %s.",strerror(errno)); + return; + } + if (width <= obj->cap.maxwidth && width >= obj->cap.minwidth && + height <= obj->cap.maxheight && height >= obj->cap.minheight) + { + MS_VIDEO_SOURCE(obj)->width = width; + MS_VIDEO_SOURCE(obj)->height = height; + } + ms_filter_unlock(MS_FILTER(obj)); + + if (restart) + { + ms_v4l_stop(obj); + ms_v4l_start(obj); + } + +} + +static gboolean try_format(MSV4l *obj, struct video_picture *pict, int palette, int depth){ + int err; + pict->palette=palette; + pict->depth=depth; + pict->contrast=25000; + err=ioctl(obj->fd,VIDIOCSPICT,pict); + if (err<0){ + g_warning("Could not set picture properties: %s",strerror(errno)); + return FALSE; + } + return TRUE; +} + +int v4l_configure(MSV4l *f) +{ + gint err; + gint i; + struct video_channel *chan=&f->channel; + struct video_picture *pict=&f->pict; + struct video_mmap *vmap=&f->vmap; + struct video_mbuf *vmbuf=&f->vmbuf; +// struct video_capture *vcap=&f->vcap; + int found=0; + + err=ioctl(f->fd,VIDIOCGCAP,&f->cap); + if (err!=0) + { + g_warning("MSV4l: cannot get device capabilities: %s.",strerror(errno)); + return -1; + } + MS_VIDEO_SOURCE(f)->dev_name=f->cap.name; + + for (i=0;icap.channels;i++) + { + chan->channel=i; + err=ioctl(f->fd,VIDIOCGCHAN,chan); + if (err==0) + { + g_message("Getting video channel %s",chan->name); + switch(chan->type){ + case VIDEO_TYPE_TV: + g_message("Channel is a TV."); + break; + case VIDEO_TYPE_CAMERA: + g_message("Channel is a camera"); + break; + default: + g_warning("unknown video channel type."); + } + found=1; + break; /* find the first channel */ + } + } + if (found) g_message("A valid video channel was found."); + /* select this channel */ + ioctl(f->fd,VIDIOCSCHAN,chan); + + /* set/get the resolution */ + err = -1; + + /* + if (f->cap.type & VID_TYPE_SUBCAPTURE) { + struct video_capture vcap; + vcap.x = vcap.y = 0; + vcap.width = MS_VIDEO_SOURCE(f)->width; + vcap.height = MS_VIDEO_SOURCE(f)->height; + err = ioctl(f->fd, VIDIOCSCAPTURE, &vcap); + + } + */ + + /* get picture properties */ + err=ioctl(f->fd,VIDIOCGPICT,pict); + if (err<0){ + g_warning("Could not get picture properties: %s",strerror(errno)); + return -1; + } + g_message("Default picture properties: brightness=%i,hue=%i,colour=%i,contrast=%i,depth=%i, palette=%i.", + pict->brightness,pict->hue,pict->colour, pict->contrast,pict->depth, pict->palette); + /* trying YUV420P format:*/ + if (try_format(f,pict,VIDEO_PALETTE_YUV420P,16)){ + g_message("Driver supports YUV420P, using that format."); + MS_VIDEO_SOURCE(f)->format="YUV420P"; + }else{ + g_message("Driver does not support YUV420P, trying RGB24..."); + if (try_format(f, pict,VIDEO_PALETTE_RGB24,24)){ + g_message("Driver supports RGB24, using that format."); + MS_VIDEO_SOURCE(f)->format="RGB24"; + }else{ + g_error("Unsupported video formats."); + } + } + + f->bsize=(pict->depth/8) * MS_VIDEO_SOURCE(f)->width* MS_VIDEO_SOURCE(f)->height; + + /* try to get mmap properties */ + err=ioctl(f->fd,VIDIOCGMBUF,vmbuf); + if (err<0){ + g_warning("Could not get mmap properties: %s",strerror(errno)); + f->use_mmap=0; + }else + { + if (vmbuf->size>0){ + f->use_mmap=1; + /* do the mmap */ + f->mmapdbuf=mmap((void*)f,vmbuf->size,PROT_READ,MAP_SHARED,f->fd,0); + if (f->mmapdbuf==(void*)-1) { + g_warning("Could not mmap. Using read instead: %s",strerror(errno)); + f->use_mmap=0; + f->mmapdbuf=NULL; + }else { + /* initialize the mediastreamer buffers */ + gint i; + g_message("Using %i-frames mmap'd buffer.",vmbuf->frames); + for(i=0;iframes;i++){ + f->img[i].buffer=f->mmapdbuf+vmbuf->offsets[i]; + f->img[i].size=vmbuf->offsets[1]; + f->img[i].ref_count=1; + } + f->frame=0; + } + } else g_warning("This device cannot support mmap."); + } + + /* initialize the video map structure */ + vmap->width=MS_VIDEO_SOURCE(f)->width; + vmap->height=MS_VIDEO_SOURCE(f)->height; + vmap->format=v4l_string_to_enum(MS_VIDEO_SOURCE(f)->format); + vmap->frame=0; + return 0; +} + +#define BPP 3 +static inline +void crop( guchar *src, gint s_width, gint s_height, guchar *dest, gint d_width, gint d_height) +{ + register int i; + register int stride = d_width*BPP; + register guchar *s = src, *d = dest; + s += ((s_height - d_height)/2 * s_width * BPP) + ((s_width - d_width)/2 * BPP); + for (i = 0; i < d_height; i++, d += stride, s += s_width * BPP) + memcpy( d, s, stride); +} + +MSBuffer * v4l_grab_image_mmap(MSV4l *obj){ + struct video_mmap *vmap=&obj->vmap; + struct video_mbuf *vmbuf=&obj->vmbuf; + int err; + int syncframe; + int jitter=vmbuf->frames-1; + obj->query_frame=(obj->frame) % vmbuf->frames; + /*g_message("v4l_mmap_process: query_frame=%i", + obj->query_frame);*/ + vmap->frame=obj->query_frame; + err=ioctl(obj->fd,VIDIOCMCAPTURE,vmap); + if (err<0) { + g_warning("v4l_mmap_process: error in VIDIOCMCAPTURE: %s.",strerror(errno)); + return NULL; + } + /*g_message("v4l_mmap_process: query_frame=%i done", + obj->query_frame);*/ + syncframe=(obj->frame-jitter); + obj->frame++; + if (syncframe>=0){ + syncframe=syncframe%vmbuf->frames; + g_message("Syncing on frame %i",syncframe); + err=ioctl(obj->fd,VIDIOCSYNC,&syncframe); + if (err<0) { + g_warning("v4l_mmap_process: error in VIDIOCSYNC: %s.",strerror(errno)); + return NULL; + } + /*g_message("got frame %i",syncframe);*/ + }else { + return NULL; + } + /* not particularly efficient - hope for a capture source that + provides subcapture or setting window */ + /* + if (obj->width != MS_VIDEO_SOURCE(obj)->width || obj->height != MS_VIDEO_SOURCE(obj)->height){ + guchar tmp[obj->bsize]; + crop((guchar*) obj->img[syncframe].buffer, obj->width, obj->height, tmp, + MS_VIDEO_SOURCE(obj)->width, MS_VIDEO_SOURCE(obj)->height); + memcpy(obj->img[syncframe].buffer, tmp, MS_VIDEO_SOURCE(obj)->width * + MS_VIDEO_SOURCE(obj)->height * obj->pict.depth/8); + } + */ + return &obj->img[syncframe]; +} + +MSBuffer *v4l_grab_image_read(MSV4l *obj){ + int err; + if (obj->allocdbuf==NULL){ + obj->allocdbuf=ms_buffer_new(obj->bsize); + obj->allocdbuf->ref_count++; + } + { + err=read(obj->fd,obj->allocdbuf->buffer,obj->bsize); + if (err<0){ + g_warning("MSV4l: Fail to read(): %s",strerror(errno)); + return NULL; + } + } + return obj->allocdbuf; +} + + +MSBuffer * v4l_make_mire(MSV4l *obj){ + gchar *data; + int i,j,line,pos; + int patternw=obj->parent.width/6; + int patternh=obj->parent.height/6; + int red,green=0,blue=0; + if (obj->allocdbuf==NULL){ + obj->allocdbuf=ms_buffer_new(obj->parent.width*obj->parent.height*3); + obj->allocdbuf->ref_count++; + } + data=obj->allocdbuf->buffer; + for (i=0;iparent.height;++i){ + line=i*obj->parent.width*3; + if ( ((i+obj->count)/patternh) & 0x1) red=255; + else red= 0; + for (j=0;jparent.width;++j){ + pos=line+(j*3); + + if ( ((j+obj->count)/patternw) & 0x1) blue=255; + else blue= 0; + + data[pos]=red; + data[pos+1]=green; + data[pos+2]=blue; + } + } + obj->count++; + usleep(60000); + return obj->allocdbuf; +} + + +void *v4l_thread(MSV4l *obj){ + GMutex *mutex=MS_FILTER(obj)->lock; + g_mutex_lock(mutex); + obj->thread_run=TRUE; + g_cond_signal(obj->cond); + while(obj->thread_run){ + g_cond_wait(obj->cond,mutex); + if (obj->grab_image){ + MSBuffer *grabbed; + g_mutex_unlock(mutex); + if (obj->fd>0){ + if (obj->use_mmap){ + grabbed=v4l_grab_image_mmap(obj); + }else{ + grabbed=v4l_grab_image_read(obj); + } + }else grabbed=v4l_make_mire(obj); + g_mutex_lock(mutex); + if (grabbed){ + obj->image_grabbed=grabbed; + obj->grab_image=FALSE; + } + } + } + g_cond_signal(obj->stopcond); + obj->thread_exited=TRUE; + g_mutex_unlock(mutex); + return NULL; +} + + + + +void v4l_process(MSV4l * obj) +{ + GMutex *mutex=MS_FILTER(obj)->lock; + g_mutex_lock(mutex); + if (obj->image_grabbed!=NULL){ + MSMessage *m=ms_message_alloc(); + ms_message_set_buf(m,obj->image_grabbed); + ms_queue_put(MS_FILTER(obj)->outqueues[0],m); + obj->image_grabbed=NULL; + }else{ + obj->grab_image=TRUE; + g_cond_signal(obj->cond); + } + g_mutex_unlock(mutex); +} + +void ms_v4l_uninit(MSV4l *obj) +{ + if (obj->device!=NULL) { + g_free(obj->device); + obj->device=NULL; + } + if (obj->v4lthread!=NULL) ms_v4l_stop(obj); + if (obj->allocdbuf!=NULL) { + ms_buffer_destroy(obj->allocdbuf); + obj->allocdbuf=NULL; + } + g_cond_free(obj->cond); + g_cond_free(obj->stopcond); + ms_filter_uninit(MS_FILTER(obj)); +} + +void ms_v4l_destroy(MSV4l *obj) +{ + ms_v4l_uninit(obj); + g_free(obj); +} diff --git a/linphone/mediastreamer/msv4l.h b/linphone/mediastreamer/msv4l.h new file mode 100644 index 000000000..b0262b3a9 --- /dev/null +++ b/linphone/mediastreamer/msv4l.h @@ -0,0 +1,92 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSV4L_H +#define MSV4L_H + +#include "msvideosource.h" +#include +#include + +struct _MSV4l +{ + MSVideoSource parent; + int fd; + char *device; + struct video_capability cap; + struct video_channel channel; + struct video_window win; + struct video_picture pict; + struct video_mmap vmap; + struct video_mbuf vmbuf; + struct video_capture vcap; + gint bsize; + gint use_mmap; + gint frame; + guint query_frame; + gchar *mmapdbuf; /* the mmap'd buffer */ + MSBuffer img[VIDEO_MAX_FRAME]; /* the buffer wrappers used for mmaps */ + MSBuffer *allocdbuf; /* the buffer allocated for read() and mire */ + gint count; + MSBuffer *image_grabbed; + GCond *cond; + GCond *stopcond; + GThread *v4lthread; + gboolean grab_image; + gboolean thread_run; + gboolean thread_exited; +}; + +typedef struct _MSV4l MSV4l; + + +struct _MSV4lClass +{ + MSVideoSourceClass parent_class; + +}; + +typedef struct _MSV4lClass MSV4lClass; + + +/* PUBLIC API */ +#define MS_V4L(v) ((MSV4l*)(v)) +#define MS_V4L_CLASS(k) ((MSV4lClass*)(k)) +MSFilter * ms_v4l_new(); + +void ms_v4l_start(MSV4l *obj); +void ms_v4l_stop(MSV4l *obj); +int ms_v4l_set_device(MSV4l *f, const gchar *device); +void ms_v4l_set_size(MSV4l *v4l, gint w, gint h); + +/* PRIVATE API */ +void ms_v4l_init(MSV4l *obj); +void ms_v4l_class_init(MSV4lClass *klass); +int v4l_configure(MSV4l *f); + +void v4l_process(MSV4l *obj); + +void ms_v4l_uninit(MSV4l *obj); + +void ms_v4l_destroy(MSV4l *obj); + +extern MSFilterInfo v4l_info; + +#endif diff --git a/linphone/mediastreamer/msvideooutput.c b/linphone/mediastreamer/msvideooutput.c new file mode 100644 index 000000000..c09c33aea --- /dev/null +++ b/linphone/mediastreamer/msvideooutput.c @@ -0,0 +1,495 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msvideooutput.h" +#include "msvideosource.h" +#include "affine.h" +#include "msavdecoder.h" +#include "msutils.h" +#include + +#ifndef XV_YV12 +#define XV_YV12 0x32315659 +#endif + +#ifndef XV_YUY2 +#define XV_YUY2 0x32595559 +#endif + +#ifndef XV_UYVY +#define XV_UYVY 0x59565955 +#endif + +#ifndef XV_I420 +#define XV_I420 0x30323449 +#endif + +static MSVideoOutputClass *ms_video_output_class=NULL; + + +gboolean xv_init (MSVideoOutput *obj) +{ + gboolean got_port = FALSE; + unsigned int count; + XvAdaptorInfo *adaptor; + + obj->xv_shminfo.shmaddr = NULL; + obj->xv_window = gdk_x11_drawable_get_xid(obj->window); + obj->xv_display = (Display*) gdk_x11_drawable_get_xdisplay(obj->window); + + if ( XvQueryAdaptors(obj->xv_display, obj->xv_window, &count, &adaptor) == Success ) + { + unsigned int n, i; + + for (n = 0; !got_port && n < count; ++n) + { + for ( obj->xv_port = adaptor[n].base_id; + obj->xv_port < adaptor[n].base_id + adaptor[n].num_ports; + obj->xv_port++ ) + { + if (XvGrabPort(obj->xv_display, obj->xv_port, CurrentTime) == 0) + { + int formats; + XvImageFormatValues *list; + + list = XvListImageFormats( obj->xv_display, obj->xv_port, &formats); + for ( i = 0; i < formats; i ++ ) { + if ( list[i].id == XV_I420 && !got_port ) + got_port = TRUE; + } + if ( got_port ) + break; + else + XvUngrabPort( obj->xv_display, obj->xv_port, CurrentTime ); + } + } + } + if ( got_port ) + { + obj->xv_gc = XCreateGC(obj->xv_display, obj->xv_window, 0, &obj->xv_values); + + obj->xv_image = (XvImage *) XvShmCreateImage( obj->xv_display, obj->xv_port, XV_I420, 0, obj->width, obj->height, &obj->xv_shminfo); + if (obj->xv_image == NULL) { + g_message("Unable to allocate XvImage, falling back to GDK output"); + XvUngrabPort( obj->xv_display, obj->xv_port, CurrentTime ); + obj->xv_port = 0; + return FALSE; + } + else { + g_message("allocated XvImage with size %i", obj->xv_image->data_size); + } + + obj->xv_shminfo.shmid = shmget( IPC_PRIVATE, obj->xv_image->data_size, IPC_CREAT | 0777); + obj->xv_shminfo.shmaddr = (char *) shmat( obj->xv_shminfo.shmid, 0, 0); + obj->xv_image->data = obj->xv_shminfo.shmaddr; + obj->xv_shminfo.readOnly = 0; + if (!XShmAttach( (Display*) gdk_x11_get_default_xdisplay(), &obj->xv_shminfo)) { + got_port = FALSE; + } + shmctl(obj->xv_shminfo.shmid, IPC_RMID, 0); + } + else obj->xv_port = 0; + } + else { + got_port = FALSE; + obj->xv_port = 0; + } + return got_port; +} + + +void xv_uninit(MSVideoOutput *obj) +{ + if ( obj->xv_port ) { + XvUngrabPort( obj->xv_display, obj->xv_port, CurrentTime ); + } + + if (obj->xv_image != NULL) + XvStopVideo(obj->xv_display, obj->xv_port, obj->xv_window); + + if (obj->xv_shminfo.shmaddr != NULL) { + XShmDetach(obj->xv_display, &obj->xv_shminfo); + shmctl(obj->xv_shminfo.shmid, IPC_RMID, 0); + shmdt(obj->xv_shminfo.shmaddr); + } + if (obj->xv_image != NULL) + XFree(obj->xv_image); +} + +void ms_video_output_init(MSVideoOutput *obj) +{ + gint error; + GdkWindowAttr attr; + MSVideoOutputClass *klass=MS_VIDEO_OUTPUT_CLASS(MS_FILTER(obj)->klass); + memset(&attr,0,sizeof(attr)); + attr.title="linphone video"; + attr.window_type=GDK_WINDOW_CHILD; + attr.wclass=GDK_INPUT_OUTPUT; + attr.x=0; + attr.y=0; + attr.width = VIDEO_SIZE_CIF_W; + attr.height = VIDEO_SIZE_CIF_H; + attr.visual=klass->visual; + attr.colormap=klass->colormap; + attr.override_redirect = TRUE; + ms_filter_init(MS_FILTER(obj)); + MS_FILTER(obj)->inqueues=obj->input; + obj->window=gdk_window_new(NULL,&attr,GDK_WA_TITLE|GDK_WA_X|GDK_WA_Y|GDK_WA_COLORMAP|GDK_WA_VISUAL); + if (obj->window==NULL) + { + g_error("Could not create gdk video window"); + } + obj->gc=gdk_gc_new(obj->window); + gdk_window_show(obj->window); + gdk_flush(); + //gdk_window_withdraw(obj->window); + obj->width = VIDEO_SIZE_CIF_W; + obj->height = VIDEO_SIZE_CIF_H; + obj->prev_h=0; + obj->prev_w=0; + + obj->bpp = 3/2; + obj->bufsize=obj->width*obj->height*obj->bpp; + obj->palette = "YUV420P"; + obj->active=TRUE; +} + +void ms_video_output_setup(MSVideoOutput *vo, MSSync *sync) +{ +#if 0 + /* tries to find the video source of the stream */ + MSFilter *vs; + vs=ms_filter_search_upstream_by_type(MS_FILTER(vo),MS_FILTER_VIDEO_IO); + if (vs != NULL) { + /* get video source properties */ + vo->width=MS_VIDEO_SOURCE(vs)->width; + vo->height=MS_VIDEO_SOURCE(vs)->height; + vo->palette=MS_VIDEO_SOURCE(vs)->format; + ms_video_output_set_size(vo,vo->width,vo->height); + } else + g_warning("ms_video_output_setup: could not find the video source."); + + if (xv_init(vo) == FALSE && vo->palette!=NULL && strcmp(vo->palette, "RGB24") != 0) { + /* tell our upstream codec to use RGB too! */ + vs=ms_filter_search_upstream_by_type(MS_FILTER(vo),MS_FILTER_VIDEO_CODEC); + if (vs != NULL) { + ms_trace("found upstream codec"); + vo->palette = "RGB24"; + vo->bpp = 3; + vo->bufsize = vo->width*vo->height*vo->bpp; + ms_AVdecoder_set_format(MS_AVDECODER(vs), "RGB24"); + }else{ + g_warning("ms_video_output_setup: could not find the video codec."); + } + } +#endif +} + + +void ms_video_output_class_init(MSVideoOutputClass *klass) +{ + gint status; + ms_filter_class_init(MS_FILTER_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_qinputs=2; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_video_output_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_video_output_process; + MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_video_output_setup; + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MSVideoOutput"); + status=gdk_init_check(0,NULL); + if (status==0){ + g_error("Failed to initialize gdk."); + } + gdk_rgb_init(); + gdk_rgb_set_verbose(1); + klass->visual=gdk_rgb_get_visual(); + klass->colormap=gdk_rgb_get_cmap(); +} + +void ms_video_output_uninit(MSVideoOutput *obj) +{ + xv_uninit(obj); + gdk_gc_destroy(obj->gc); + gdk_window_destroy(obj->window); + gdk_flush(); +} + +MSFilter * ms_video_output_new() +{ + MSVideoOutput *obj=g_malloc0(sizeof(MSVideoOutput)); + + if (ms_video_output_class==NULL) + { + ms_video_output_class=g_malloc0(sizeof(MSVideoOutputClass)); + ms_video_output_class_init(ms_video_output_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_video_output_class); + ms_video_output_init(obj); + return MS_FILTER(obj); +} + +void ms_video_output_start(MSVideoOutput *obj) +{ + ms_filter_lock(MS_FILTER(obj)); + obj->active=TRUE; + ms_filter_unlock(MS_FILTER(obj)); +} + +void ms_video_output_stop(MSVideoOutput *obj) +{ + ms_filter_lock(MS_FILTER(obj)); + obj->active=FALSE; + ms_filter_unlock(MS_FILTER(obj)); +} + +void ms_video_output_set_title(MSVideoOutput *obj,gchar *title) +{ + g_return_if_fail(obj->window); + gdk_threads_enter(); + gdk_window_set_title(obj->window,title); + gdk_flush(); + gdk_threads_leave(); +} + +void ms_video_output_set_size(MSVideoOutput *obj,gint width, gint height) +{ + gdk_threads_enter(); + obj->width=width; + obj->height=height; + obj->bufsize=width*height*obj->bpp; + gdk_window_resize(obj->window,width,height); + gdk_flush(); + gdk_threads_leave(); +} + +void ms_video_output_set_format(MSVideoOutput *obj, const char *fmt){ + obj->palette=fmt; +} + +static inline +void composite( guchar *dest, gint d_width, gint d_height, gint d_x, gint d_y, guchar *src, gint s_width, gint s_height, gint bpp) +{ + register gint i; + register gint s_stride = s_width*bpp; + register gint d_stride = d_width*bpp; + register guchar *s = src, *d = dest; + d += (d_y * d_stride) + (d_x * bpp); + for (i = 0; i < s_height; i++, s += s_stride, d += d_stride) + memcpy( d, s, s_stride); +} + +static inline void ntohl_block(guint32 *buf, int len) +{ + register int i; + for (i=0; i>10);\ + g = y - ((u*352 + v*731) >> 10);\ + b = y + ((u*1814) >> 10);\ + r = r < 0 ? 0 : r;\ + g = g < 0 ? 0 : g;\ + b = b < 0 ? 0 : b;\ + r = r > 255 ? 255 : r;\ + g = g > 255 ? 255 : g;\ + b = b > 255 ? 255 : b + + +static inline +void yv12_to_rgb24 (unsigned char *src, unsigned char *dest, int width, int height) +{ + register int i,j; + register int y0, y1, u, v; + register int r, g, b; + register unsigned char *s[3]; + s[0] = src; + s[1] = s[0] + width*height; + s[2] = s[1] + width*height/4; + + for (i = 0; i < height; i++) { + for (j = 0; j < width/2; j++) { + y0 = *(s[0])++; + y1 = *(s[0])++; + if (i % 2 == 0 ) { + u = *(s[1])++ - 128; + v = *(s[2])++ - 128; + } + YUV2RGB (y0, u, v, r, g, b); + *dest++ = r; + *dest++ = g; + *dest++ = b; + YUV2RGB (y1, u, v, r, g, b); + *dest++ = r; + *dest++ = g; + *dest++ = b; + } + } +} + + +#define PIP_FACTOR 5.0 + +void ms_video_output_process(MSVideoOutput *obj) +{ + MSQueue *q=obj->input[0]; + MSMessage *m; + GdkPixbuf *pb_pip = NULL; + guchar buf[VIDEO_SIZE_MAX_W*VIDEO_SIZE_MAX_H*3], buf2[VIDEO_SIZE_MAX_W*VIDEO_SIZE_MAX_H*3]; + + ms_filter_lock(MS_FILTER(obj)); + if (obj->active==FALSE){ + ms_filter_unlock(MS_FILTER(obj)); + while((m=ms_queue_get(q))!=NULL) ms_message_destroy(m); + return; + } + + while((m=ms_queue_get(q))!=NULL) + { + ms_trace("Getting new buffer"); + if (m->size >= obj->bufsize) + { + gint w=VIDEO_SIZE_CIF_W, h=VIDEO_SIZE_CIF_H; + + gdk_threads_enter(); + gdk_window_get_geometry(obj->window, NULL, NULL, &w, &h, NULL); + if (w != obj->prev_w || h != obj->prev_h) { + gdk_window_resize(obj->window,w,h); + gdk_window_clear(obj->window); + obj->prev_w = w; + obj->prev_h = h; + } + gdk_flush(); + if (obj->xv_port != 0 && strcmp(obj->palette, "YUV420P") == 0) { + int imageWidth = obj->width * obj->width / VIDEO_SIZE_MAX_W; + int imageHeight = obj->height * obj->height / VIDEO_SIZE_MAX_H; + double ratioWidth = (double)w / (double)imageWidth; + double ratioHeight = (double)h / (double)imageHeight; + int width, height, x, y; + if (ratioHeight < ratioWidth) { + width = (int)( imageWidth * ratioHeight ); + height = (int)( imageHeight * ratioHeight ); + } else { + width = (int)( imageWidth * ratioWidth ); + height = (int)( imageHeight * ratioWidth ); + } + x = ( w - width ) / 2; + y = ( h - height ) / 2; + + memcpy( obj->xv_image->data, m->data, obj->xv_image->data_size ); + if (obj->input[1] != NULL) { + MSMessage *m = ms_queue_get(obj->input[1]); + + if (m != NULL) { + /* CAUTION: this is very tricky planar scaling and compositing! */ + affine_scale((const unsigned char *)m->data, buf, + obj->width, obj->height, obj->width/PIP_FACTOR, obj->height/PIP_FACTOR, 1); + + affine_scale( (const unsigned char *) m->data + obj->width * obj->height, + buf + (int)(obj->width/PIP_FACTOR * obj->height/PIP_FACTOR), + obj->width/2, obj->height/2, obj->width/PIP_FACTOR/2, obj->height/PIP_FACTOR/2, 1); + + affine_scale( (const unsigned char *) m->data + (int)(obj->width * obj->height * 5/4), + buf + (int)(obj->width/PIP_FACTOR * obj->height/PIP_FACTOR * 5/4), + obj->width/2, obj->height/2, obj->width/PIP_FACTOR/2, obj->height/PIP_FACTOR/2, 1); + + ms_message_destroy(m); + + composite( obj->xv_image->data, obj->width, obj->height, obj->width-obj->width/PIP_FACTOR-6, 6, + buf, obj->width/PIP_FACTOR, obj->height/PIP_FACTOR, 1); + + composite( obj->xv_image->data + (int)(obj->width * obj->height), + obj->width/2, obj->height/2, obj->width/2 - obj->width/PIP_FACTOR/2 - 3, 3, + buf + (int)(obj->width/PIP_FACTOR * obj->height/PIP_FACTOR), + obj->width/PIP_FACTOR/2, obj->height/PIP_FACTOR/2, 1); + + composite( obj->xv_image->data + (int)(obj->width * obj->height * 5/4), + obj->width/2, obj->height/2, obj->width/2 - obj->width/PIP_FACTOR/2 - 3, 3, + buf + (int)(obj->width/PIP_FACTOR * obj->height/PIP_FACTOR * 5/4), + obj->width/PIP_FACTOR/2, obj->height/PIP_FACTOR/2, 1); + } + } + XvShmPutImage(obj->xv_display, obj->xv_port, obj->xv_window, obj->xv_gc, obj->xv_image, + 0, 0, obj->width, obj->height, + x, y, width, height, FALSE ); + XFlush(obj->xv_display); + } + else + { + GdkPixbuf *pb, *pb_scaled; + + if (strcmp(obj->palette, "RGB24") == 0) { + pb = gdk_pixbuf_new_from_data( m->data, GDK_COLORSPACE_RGB, + FALSE, 8, obj->width, obj->height, obj->width*3, NULL, NULL); + } else { + /* convert the YUV420P image to RGB24 ourselves */ + yv12_to_rgb24(m->data, buf2, obj->width, obj->height); + pb = gdk_pixbuf_new_from_data(buf2, GDK_COLORSPACE_RGB, + FALSE, 8, obj->width, obj->height, obj->width*3, NULL, NULL); + } + + pb_scaled = gdk_pixbuf_scale_simple(pb, w, h, GDK_INTERP_BILINEAR); + if (obj->input[1] != NULL) { + MSMessage *m = ms_queue_get(obj->input[1]); + + if (m != NULL) { + GdkPixbuf *pb; + /* XXX: assumes the pip video source is always YV12 */ + yv12_to_rgb24(m->data, buf, obj->width, obj->height); + + pb = gdk_pixbuf_new_from_data( buf, GDK_COLORSPACE_RGB, + FALSE, 8, obj->width, obj->height, obj->width*3, NULL, NULL); + if (pb_pip != NULL) + gdk_pixbuf_unref(pb_pip); + pb_pip = gdk_pixbuf_scale_simple(pb, w/PIP_FACTOR, h/PIP_FACTOR, GDK_INTERP_BILINEAR); + ms_message_destroy(m); + gdk_pixbuf_unref(pb); + } + if (pb_pip != NULL) { + gdk_pixbuf_composite(pb_pip, pb_scaled, + w-w/PIP_FACTOR-5, 5, w/PIP_FACTOR, h/PIP_FACTOR, + w-w/PIP_FACTOR-5, 5, 1.0, 1.0, + GDK_INTERP_BILINEAR, 255); + } + } + gdk_pixbuf_render_to_drawable(pb_scaled, obj->window, obj->gc, 0, 0, 0, 0, + w, h, GDK_RGB_DITHER_NONE, 0, 0); + + gdk_flush(); + gdk_pixbuf_unref(pb); + gdk_pixbuf_unref(pb_scaled); + } + gdk_threads_leave(); + } + else g_warning("Image is too small for current window"); + ms_message_destroy(m); + } + ms_filter_unlock(MS_FILTER(obj)); +} + +void ms_video_output_destroy(MSVideoOutput *obj) +{ + ms_video_output_uninit(obj); + g_free(obj); +} diff --git a/linphone/mediastreamer/msvideooutput.h b/linphone/mediastreamer/msvideooutput.h new file mode 100644 index 000000000..6f7835791 --- /dev/null +++ b/linphone/mediastreamer/msvideooutput.h @@ -0,0 +1,86 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef MSVIDEOOUTPUT_H +#define MSVIDEOOUTPUT_H + + +#include "ms.h" +#include "msfilter.h" +#include +#include +#include +#include +#include +#include + +struct _MSVideoOutput +{ + MSFilter parent; + MSQueue *input[2]; + GdkWindow *window; + GdkGC *gc; + GdkImage *image; + gint width,height; + gint bufsize; + const gchar *palette; + gdouble bpp; + gint prev_w, prev_h; + Display *xv_display; + Window xv_window; + GC xv_gc; + XGCValues xv_values; + XvImage *xv_image; + unsigned int xv_port; + XShmSegmentInfo xv_shminfo; + gboolean active; +}; + + +typedef struct _MSVideoOutput MSVideoOutput; + +struct _MSVideoOutputClass +{ + MSFilterClass parent_class; + GdkVisual *visual; + GdkColormap *colormap; +}; + +typedef struct _MSVideoOutputClass MSVideoOutputClass; + + +#define MS_VIDEO_OUTPUT(obj) ((MSVideoOutput*)(obj)) +#define MS_VIDEO_OUTPUT_CLASS(klass) ((MSVideoOutputClass*)(klass)) + +void ms_video_output_init(MSVideoOutput *obj); +void ms_video_output_class_init(MSVideoOutputClass *klass); +void ms_video_output_uninit(MSVideoOutput *obj); + +MSFilter * ms_video_output_new(); +void ms_video_output_set_format(MSVideoOutput *obj, const char *fmt); +void ms_video_output_set_size(MSVideoOutput *obj,gint width, gint height); +void ms_video_output_start(MSVideoOutput *obj); +void ms_video_output_stop(MSVideoOutput *obj); +void ms_video_output_set_title(MSVideoOutput *obj,gchar *title); + +void ms_video_output_destroy(MSVideoOutput *obj); +void ms_video_output_process(MSVideoOutput *obj); +#endif diff --git a/linphone/mediastreamer/msvideosource.c b/linphone/mediastreamer/msvideosource.c new file mode 100644 index 000000000..fad63d12c --- /dev/null +++ b/linphone/mediastreamer/msvideosource.c @@ -0,0 +1,99 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "msvideosource.h" +#include "mediastream.h" + +#ifdef __linux +#include "msv4l.h" +#endif +#ifdef HAVE_LIBDC1394 +#include "msdc1394.h" +#endif + +/* register all statically linked codecs */ +void ms_video_source_register_all() +{ +#ifdef __linux + ms_filter_register(&v4l_info); +#endif +#ifdef HAVE_LIBDC1394 + ms_filter_register(MS_FILTER_INFO(&dc1394_info)); +#endif +} + +void ms_video_source_class_init(MSVideoSourceClass *klass) +{ + /* init base class first*/ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + /* then init videosource specific things*/ + MS_FILTER_CLASS(klass)->max_qoutputs=MSVIDEOSOURCE_MAX_OUTPUTS; + ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE|FILTER_HAS_QUEUES); +} + +void ms_video_source_init(MSVideoSource *obj) +{ + ms_filter_init(MS_FILTER(obj)); + MS_FILTER(obj)->outqueues=obj->outputs; + obj->width = VIDEO_SIZE_CIF_W; + obj->height = VIDEO_SIZE_CIF_H; +} + +void ms_video_source_start(MSVideoSource *f) +{ + MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->start(f); +} + +void ms_video_source_stop(MSVideoSource *f) +{ + MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->stop(f); +} + +int ms_video_source_set_device(MSVideoSource *f, const gchar *device) +{ + return MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_device(f,device); +} + +gchar* ms_video_source_get_device_name(MSVideoSource *f) +{ + return f->dev_name; +} + +void ms_video_source_set_size(MSVideoSource *f, gint width, gint height) +{ + if (MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_size) + MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_size(f, width, height); +} + +void ms_video_source_set_frame_rate(MSVideoSource *f, gint frame_rate, gint frame_rate_base) +{ + if (MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_frame_rate) + MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_frame_rate(f, frame_rate, frame_rate_base); + else{ + f->frame_rate=frame_rate; + f->frame_rate_base=frame_rate_base; + } +} + +gchar* ms_video_source_get_format(MSVideoSource *f) +{ + return f->format; +} diff --git a/linphone/mediastreamer/msvideosource.h b/linphone/mediastreamer/msvideosource.h new file mode 100644 index 000000000..9a27f836c --- /dev/null +++ b/linphone/mediastreamer/msvideosource.h @@ -0,0 +1,74 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSVIDEOSOURCE_H +#define MSVIDEOSOURCE_H + + +#include "msfilter.h" + +/* this is the video input abstract class */ + +#define MSVIDEOSOURCE_MAX_OUTPUTS 1 /* max output per filter*/ + +typedef struct _MSVideoSource +{ + /* the MSVideoSource derivates from MSFilter, so the MSFilter object MUST be the first of the MSVideoSource object + in order to the object mechanism to work*/ + MSFilter filter; + MSQueue *outputs[MSVIDEOSOURCE_MAX_OUTPUTS]; + gchar *dev_name; + gint width, height; + gchar *format; + gint frame_rate; + gint frame_rate_base; +} MSVideoSource; + +typedef struct _MSVideoSourceClass +{ + /* the MSVideoSource derivates from MSFilter, so the MSFilter class MUST be the first of the MSVideoSource class + in order to the class mechanism to work*/ + MSFilterClass parent_class; + gint (*set_device)(MSVideoSource *s, const gchar *name); + void (*start)(MSVideoSource *s); + void (*stop)(MSVideoSource *s); + void (*set_size)(MSVideoSource *s, gint width, gint height); + void (*set_frame_rate)(MSVideoSource *s, gint frame_rate, gint frame_rate_base); +} MSVideoSourceClass; + +/* PUBLIC */ +void ms_video_source_register_all(); +int ms_video_source_set_device(MSVideoSource *f, const gchar *device); +gchar* ms_video_source_get_device_name(MSVideoSource *f); +void ms_video_source_start(MSVideoSource *f); +void ms_video_source_stop(MSVideoSource *f); +void ms_video_source_set_size(MSVideoSource *f, gint width, gint height); +void ms_video_source_set_frame_rate(MSVideoSource *f, gint frame_rate, gint frame_rate_base); +gchar* ms_video_source_get_format(MSVideoSource *f); + +#define MS_VIDEO_SOURCE(obj) ((MSVideoSource*)(obj)) +#define MS_VIDEO_SOURCE_CLASS(klass) ((MSVideoSourceClass*)(klass)) + + +/* FOR INTERNAL USE*/ +void ms_video_source_init(MSVideoSource *f); +void ms_video_source_class_init(MSVideoSourceClass *klass); + +#endif diff --git a/linphone/mediastreamer/mswrite.c b/linphone/mediastreamer/mswrite.c new file mode 100644 index 000000000..d548736fc --- /dev/null +++ b/linphone/mediastreamer/mswrite.c @@ -0,0 +1,129 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mswrite.h" +#include +#include +#include +#include +#include +#include +#include + +static MSWriteClass *ms_write_class=NULL; + +#ifdef _WIN32 +# define FILEPERMS (S_IRUSR|S_IWUSR) +#else +# define FILEPERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) +#endif + +MSFilter * ms_write_new(char *name) +{ + MSWrite *r; + int fd=-1; + + r=g_new(MSWrite,1); + ms_write_init(r); + if (ms_write_class==NULL) + { + ms_write_class=g_new(MSWriteClass,1); + ms_write_class_init(ms_write_class); + } + MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_write_class); + if ((name!=NULL) && (strlen(name)!=0)) + { + fd=open(name,O_WRONLY | O_CREAT | O_TRUNC,FILEPERMS); + if (fd<0) g_error("ms_write_new: failed to open %s.\n",name); + } + r->fd=fd; + return(MS_FILTER(r)); +} + + +/* FOR INTERNAL USE*/ +void ms_write_init(MSWrite *r) +{ + ms_filter_init(MS_FILTER(r)); + MS_FILTER(r)->infifos=r->f_inputs; + MS_FILTER(r)->inqueues=r->q_inputs; + MS_FILTER(r)->r_mingran=MSWRITE_MIN_GRAN; + memset(r->f_inputs,0,sizeof(MSFifo*)*MSWRITE_MAX_INPUTS); + memset(r->q_inputs,0,sizeof(MSQueue*)*MSWRITE_MAX_INPUTS); + r->fd=-1; +} + +void ms_write_class_init(MSWriteClass *klass) +{ + ms_filter_class_init(MS_FILTER_CLASS(klass)); + ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskwriter"); + MS_FILTER_CLASS(klass)->max_finputs=MSWRITE_MAX_INPUTS; + MS_FILTER_CLASS(klass)->max_qinputs=MSWRITE_MAX_INPUTS; + MS_FILTER_CLASS(klass)->r_maxgran=MSWRITE_DEF_GRAN; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_write_destroy; + MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_write_process; +} + +void ms_write_process(MSWrite *r) +{ + MSFifo *f; + MSQueue *q; + MSMessage *buf=NULL; + int i,j,err1,err2; + gint gran=ms_filter_get_mingran(MS_FILTER(r)); + void *p; + + /* process output fifos*/ + for (i=0,j=0;(iklass->max_finputs)&&(jfinputs);i++) + { + f=r->f_inputs[i]; + if (f!=NULL) + { + if ( (err1=ms_fifo_get_read_ptr(f,gran,&p))>0 ) + { + + err2=write(r->fd,p,gran); + if (err2<0) g_warning("ms_write_process: failed to write: %s.\n",strerror(errno)); + } + j++; + } + } + /* process output queues*/ + for (i=0,j=0;(iklass->max_qinputs)&&(jqinputs);i++) + { + q=r->q_inputs[i]; + if (q!=NULL) + { + while ( (buf=ms_queue_get(q))!=NULL ){ + int ret = write(r->fd,buf->data,buf->size); + assert( ret == buf->size ); + j++; + ms_message_destroy(buf); + } + } + } +} + +void ms_write_destroy( MSWrite *obj) +{ + if (obj->fd!=0) close(obj->fd); + g_free(obj); +} + diff --git a/linphone/mediastreamer/mswrite.h b/linphone/mediastreamer/mswrite.h new file mode 100644 index 000000000..cd766d10f --- /dev/null +++ b/linphone/mediastreamer/mswrite.h @@ -0,0 +1,63 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSWRITE_H +#define MSWRITE_H + +#include "msfilter.h" + + +/*this is the class that implements writing reading sink filter*/ + +#define MSWRITE_MAX_INPUTS 1 /* max output per filter*/ + +#define MSWRITE_DEF_GRAN 512 /* the default granularity*/ +#define MSWRITE_MIN_GRAN 64 + +typedef struct _MSWrite +{ + /* the MSWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSWrite object + in order to the object mechanism to work*/ + MSFilter filter; + MSFifo *f_inputs[MSWRITE_MAX_INPUTS]; + MSQueue *q_inputs[MSWRITE_MAX_INPUTS]; + gint fd; /* the file descriptor of the file being written*/ +} MSWrite; + +typedef struct _MSWriteClass +{ + /* the MSWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSWrite class + in order to the class mechanism to work*/ + MSFilterClass parent_class; +} MSWriteClass; + +/* PUBLIC */ +#define MS_WRITE(filter) ((MSWrite*)(filter)) +#define MS_WRITE_CLASS(klass) ((MSWriteClass*)(klass)) +MSFilter * ms_write_new(char *name); + +/* FOR INTERNAL USE*/ +void ms_write_init(MSWrite *r); +void ms_write_class_init(MSWriteClass *klass); +void ms_write_destroy( MSWrite *obj); +void ms_write_process(MSWrite *r); + +#endif + diff --git a/linphone/mediastreamer/msxine.c b/linphone/mediastreamer/msxine.c new file mode 100644 index 000000000..f5f407c2e --- /dev/null +++ b/linphone/mediastreamer/msxine.c @@ -0,0 +1,189 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msxine.h" +#include "stdlib.h" + + +static MSXineClass *ms_xine_class=NULL; + +static void change_window_size(void *user_data, + int video_width, int video_height, + int *dest_x, int *dest_y, + int *dest_height, int *dest_width) +{ + MSXine *obj=(MSXine*)user_data; + XLockDisplay(obj->vis.display); + g_message("entering change window size!!!!"); + g_message("video_width=%i, video_height=%i",video_width,video_height); + sleep(1); + fflush(NULL); + XUnlockDisplay(obj->vis.display); + +} + +void calc_dest_size (void *this, + int video_width, int video_height, + int *dest_width, int *dest_height) { + g_message("entering video_window_calc_dest_size() !"); + *dest_width=video_width; + *dest_height=video_height; +} +void ms_xine_init(MSXine *obj) +{ + MSXineClass *klass=MS_XINE_CLASS(MS_FILTER(obj)->klass); + double res_h,res_v; + XSetWindowAttributes att; + ao_driver_t *ao_driver; + XGCValues xgcv; + + + ms_filter_init(MS_FILTER(obj)); + MS_FILTER(obj)->inqueues=obj->input; + memset(&obj->vis,0,sizeof(x11_visual_t)); + /* create an X11 window */ + obj->vis.display=XOpenDisplay(NULL); + obj->vis.screen=DefaultScreen(obj->vis.display); + + res_h = (DisplayWidth (obj->vis.display, obj->vis.screen)*1000 + / DisplayWidthMM (obj->vis.display, obj->vis.screen)); + res_v = (DisplayHeight (obj->vis.display, obj->vis.screen)*1000 + / DisplayHeightMM (obj->vis.display, obj->vis.screen)); + obj->vis.display_ratio = res_h / res_v; + if (fabs(obj->vis.display_ratio - 1.0) < 0.01) { + /* + * we have a display with *almost* square pixels (<1% error), + * to avoid time consuming software scaling in video_out_xshm, + * correct this to the exact value of 1.0 and pretend we have + * perfect square pixels. + */ + obj->vis.display_ratio = 1.0; + } + + att.colormap=DefaultColormap(obj->vis.display,obj->vis.screen); + att.background_pixel = BlackPixel(obj->vis.display,obj->vis.screen); + att.border_pixel = BlackPixel(obj->vis.display,obj->vis.screen); + obj->vis.d=XCreateWindow(obj->vis.display,RootWindow(obj->vis.display,obj->vis.screen),0,0,1000,800,0, + DefaultDepth(obj->vis.display,obj->vis.screen),CopyFromParent, + DefaultVisual(obj->vis.display,obj->vis.screen), + CWColormap | CWBackPixel | CWBorderPixel, + &att); + XMapWindow(obj->vis.display,obj->vis.d); + XSync(obj->vis.display,False); + XSetStandardProperties(obj->vis.display, obj->vis.d, + "Linphone video display", "Linphone video display", None, NULL, 0, 0); + XCreateGC(obj->vis.display, obj->vis.d, 0L, &xgcv); + + //XMapRaised(obj->vis.display,obj->vis.d); + //sleep(1); + //XFlush(obj->vis.display); + + /* select the first available output plugin type*/ + obj->vo_driver=xine_load_video_output_plugin(klass->config, + klass->video_plugins[0], + VISUAL_TYPE_X11, + &obj->vis); + if (obj->vo_driver==NULL){ + g_error("Could not load a xine output plugin."); + } + else g_message("New vo driver %x created.",obj->vo_driver); + ao_driver=xine_load_audio_output_plugin(klass->config,"esd"); + if (ao_driver==NULL) g_message("Could not load audio output plugin"); + + /* set some callbacks */ + obj->vis.user_data=(void*)obj; + obj->vis.request_dest_size=change_window_size; + obj->vis.calc_dest_size=calc_dest_size; + + /* initializing a xine engine*/ + obj->engine=xine_init(obj->vo_driver,ao_driver,klass->config); + if (obj->engine==NULL){ + g_error("Could not create a new xine engine"); + } + + obj->vo_driver->gui_data_exchange (obj->vo_driver, + GUI_DATA_EX_DRAWABLE_CHANGED, + (void*)obj->vis.d); +} + +void ms_xine_class_init(MSXineClass *klass) +{ + int i; + + ms_filter_class_init(MS_FILTER_CLASS(klass)); + MS_FILTER_CLASS(klass)->max_qinputs=1; + MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_xine_destroy; + /* read xine config file */ + klass->config=config_file_init(NULL); + if (klass->config==NULL){ + g_error("Could not read xine config file"); + } + /* list available video output plugins */ + klass->video_plugins=xine_list_video_output_plugins(VISUAL_TYPE_X11); + g_message("Xine video plugins for X11 are:"); + i=0; + while (klass->video_plugins[i]!=NULL) + { + g_message("\t- %s",klass->video_plugins[i]); + i++; + } + +} + +MSFilter * ms_xine_new() +{ + MSXine *obj=g_malloc(sizeof(MSXine)); + + if (ms_xine_class==NULL) + { + ms_xine_class=g_malloc(sizeof(MSXineClass)); + ms_xine_class_init(ms_xine_class); + } + MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_xine_class); + ms_xine_init(obj); + return MS_FILTER(obj); +} + +void ms_xine_start(MSXine *obj) +{ + xine_play(obj->engine, + "file://cdrom/Videos/(smr)shrek-ts(1of2).avi", + 0,0); +} + +void ms_xine_uninit(MSXine *obj) +{ + xine_exit(obj->engine); + free(obj->vo_driver); + XDestroyWindow(obj->vis.display,obj->vis.d); +} + +void ms_xine_stop(MSXine *obj) +{ + xine_stop(obj->engine); +} + + +void ms_xine_destroy(MSXine *obj) +{ + ms_xine_uninit(obj); + g_free(obj); +} + diff --git a/linphone/mediastreamer/msxine.h b/linphone/mediastreamer/msxine.h new file mode 100644 index 000000000..dd897bb57 --- /dev/null +++ b/linphone/mediastreamer/msxine.h @@ -0,0 +1,69 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MSXINE_H +#define MSXINE_H + + +#include "ms.h" +#include "msfilter.h" + +#include +#include +#include + +struct _MSXine +{ + MSFilter parent; + MSQueue *input[1]; + x11_visual_t vis; + vo_driver_t *vo_driver; + xine_t *engine; +}; + + +typedef struct _MSXine MSXine; + +struct _MSXineClass +{ + MSFilterClass parent_class; + config_values_t *config; + char **video_plugins; + +}; + +typedef struct _MSXineClass MSXineClass; + + +#define MS_XINE(obj) ((MSXine*)(obj)) +#define MS_XINE_CLASS(klass) ((MSXineClass*)(klass)) + +void ms_xine_init(MSXine *obj); +void ms_xine_class_init(MSXineClass *klass); +void ms_xine_uninit(MSXine *obj); + +MSFilter * ms_xine_new(); +void ms_xine_start(MSXine *obj); +void ms_xine_stop(MSXine *obj); + + +void ms_xine_destroy(MSXine *obj); + +#endif \ No newline at end of file diff --git a/linphone/mediastreamer/osscard.c b/linphone/mediastreamer/osscard.c new file mode 100644 index 000000000..c0cb7a53b --- /dev/null +++ b/linphone/mediastreamer/osscard.c @@ -0,0 +1,498 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "osscard.h" + +#include "msossread.h" +#include "msosswrite.h" + +#ifdef HAVE_SYS_SOUNDCARD_H +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#if 0 +void * oss_thread(OssCard *obj) +{ + gint i; + gint err; + g_message("oss_thread: starting **********"); + while(1){ + for(i=0;ilock); + if (obj->ref==0){ + g_cond_signal(obj->cond); + g_mutex_unlock(obj->lock); + g_thread_exit(NULL); + } + g_mutex_unlock(obj->lock); + obj->readindex=i; + + err=read(obj->fd,obj->readbuf[i],SND_CARD(obj)->bsize); + if (err<0) g_warning("oss_thread: read() error:%s.",strerror(errno)); + obj->writeindex=i; + write(obj->fd,obj->writebuf[i],SND_CARD(obj)->bsize); + memset(obj->writebuf[i],0,SND_CARD(obj)->bsize); + } + } +} +#endif +int oss_open(OssCard *obj, int bits,int stereo, int rate) +{ + int fd; + int p=0,cond=0; + int i=0; + int min_size=0,blocksize=512; + int err; + + //g_message("opening sound device"); + fd=open(obj->dev_name,O_RDWR|O_NONBLOCK); + if (fd<0) return -EWOULDBLOCK; + /* unset nonblocking mode */ + /* We wanted non blocking open but now put it back to normal ; thanks Xine !*/ + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK); + + /* reset is maybe not needed but takes time*/ + /*ioctl(fd, SNDCTL_DSP_RESET, 0); */ + + +#ifdef WORDS_BIGENDIAN + p=AFMT_U16_BE; +#else + p=AFMT_U16_LE; +#endif + + err=ioctl(fd,SNDCTL_DSP_SETFMT,&p); + if (err<0){ + g_warning("oss_open: can't set sample format:%s.",strerror(errno)); + } + + + p = bits; /* 16 bits */ + err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p); + if (err<0){ + g_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno)); + } + + p = rate; /* rate in khz*/ + err=ioctl(fd, SNDCTL_DSP_SPEED, &p); + if (err<0){ + g_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno)); + } + + p = stereo; /* stereo or not */ + err=ioctl(fd, SNDCTL_DSP_STEREO, &p); + if (err<0){ + g_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno)); + } + + if (rate==16000) blocksize=4096; /* oss emulation is not very good at 16khz */ + else blocksize=blocksize*(rate/8000); + ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); + + /* try to subdivide BLKSIZE to reach blocksize if necessary */ + if (min_size>blocksize) + { + cond=1; + p=min_size/blocksize; + while(cond) + { + i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p); + //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno); + if ((i==0) || (p==1)) cond=0; + else p=p/2; + } + } + ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); + if (min_size>blocksize) + { + g_warning("dsp block size set to %i.",min_size); + }else{ + /* no need to access the card with less latency than needed*/ + min_size=blocksize; + } + + g_message("dsp blocksize is %i.",min_size); + + /* start recording !!! Alex */ + { + int fl,res; + + fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT; + res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl); + if (res<0) g_warning("OSS_TRIGGER: %s",strerror(errno)); + } + + obj->fd=fd; + obj->readpos=0; + obj->writepos=0; + SND_CARD(obj)->bits=bits; + SND_CARD(obj)->stereo=stereo; + SND_CARD(obj)->rate=rate; + SND_CARD(obj)->bsize=min_size; + return fd; +} + +int oss_card_probe(OssCard *obj,int bits,int stereo,int rate) +{ + + int fd; + int p=0,cond=0; + int i=0; + int min_size=0,blocksize=512; + + if (obj->fd>0) return SND_CARD(obj)->bsize; + fd=open(obj->dev_name,O_RDWR|O_NONBLOCK); + if (fd<0) { + g_warning("oss_card_probe: can't open %s: %s.",obj->dev_name,strerror(errno)); + return -1; + } + ioctl(fd, SNDCTL_DSP_RESET, 0); + + p = bits; /* 16 bits */ + ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p); + + p = stereo; /* number of channels */ + ioctl(fd, SNDCTL_DSP_CHANNELS, &p); + + p = rate; /* rate in khz*/ + ioctl(fd, SNDCTL_DSP_SPEED, &p); + + ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); + + /* try to subdivide BLKSIZE to reach blocksize if necessary */ + if (min_size>blocksize) + { + cond=1; + p=min_size/blocksize; + while(cond) + { + i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p); + //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno); + if ((i==0) || (p==1)) cond=0; + else p=p/2; + } + } + ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); + if (min_size>blocksize) + { + g_warning("dsp block size set to %i.",min_size); + }else{ + /* no need to access the card with less latency than needed*/ + min_size=blocksize; + } + close(fd); + return min_size; +} + + +int oss_card_open(OssCard *obj,int bits,int stereo,int rate) +{ + int fd; + obj->ref++; + if (obj->fd==0){ + fd=oss_open(obj,bits,stereo,rate); + if (fd<0) { + obj->fd=0; + obj->ref--; + return -1; + } + } + + obj->readbuf=g_malloc0(SND_CARD(obj)->bsize); + obj->writebuf=g_malloc0(SND_CARD(obj)->bsize); + + SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED; + return 0; +} + +void oss_card_close(OssCard *obj) +{ + obj->ref--; + if (obj->ref==0) { + close(obj->fd); + obj->fd=0; + SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED; + g_free(obj->readbuf); + obj->readbuf=NULL; + g_free(obj->writebuf); + obj->writebuf=NULL; + + } +} + +void oss_card_destroy(OssCard *obj) +{ + snd_card_uninit(SND_CARD(obj)); + g_free(obj->dev_name); + g_free(obj->mixdev_name); + if (obj->readbuf!=NULL) g_free(obj->readbuf); + if (obj->writebuf!=NULL) g_free(obj->writebuf); +} + +gboolean oss_card_can_read(OssCard *obj) +{ + struct timeval tout={0,0}; + int err; + fd_set fdset; + if (obj->readpos!=0) return TRUE; + FD_ZERO(&fdset); + FD_SET(obj->fd,&fdset); + err=select(obj->fd+1,&fdset,NULL,NULL,&tout); + if (err>0) return TRUE; + else return FALSE; +} + +int oss_card_read(OssCard *obj,char *buf,int size) +{ + int err; + gint bsize=SND_CARD(obj)->bsize; + if (sizereadpos,size); + if (obj->readpos==0){ + err=read(obj->fd,obj->readbuf,bsize); + if (err<0) { + g_warning("oss_card_read: read() failed:%s.",strerror(errno)); + return -1; + } + } + + memcpy(buf,&obj->readbuf[obj->readpos],canread); + obj->readpos+=canread; + if (obj->readpos>=bsize) obj->readpos=0; + return canread; + }else{ + err=read(obj->fd,buf,size); + if (err<0) { + g_warning("oss_card_read: read-2() failed:%s.",strerror(errno)); + } + return err; + } + +} + +int oss_card_write(OssCard *obj,char *buf,int size) +{ + int err; + gint bsize=SND_CARD(obj)->bsize; + + if (sizewritepos,size); + memcpy(&obj->writebuf[obj->writepos],buf,canwrite); + obj->writepos+=canwrite; + if (obj->writepos>=bsize){ + err=write(obj->fd,obj->writebuf,bsize); + obj->writepos=0; + } + return canwrite; + }else{ + return write(obj->fd,buf,bsize); + } +} + +void oss_card_set_level(OssCard *obj,gint way,gint a) +{ + int p,mix_fd; + int osscmd; + g_return_if_fail(obj->mixdev_name!=NULL); +#ifdef HAVE_SYS_SOUNDCARD_H + switch(way){ + case SND_CARD_LEVEL_GENERAL: + osscmd=SOUND_MIXER_VOLUME; + break; + case SND_CARD_LEVEL_INPUT: + osscmd=SOUND_MIXER_IGAIN; + break; + case SND_CARD_LEVEL_OUTPUT: + osscmd=SOUND_MIXER_PCM; + break; + default: + g_warning("oss_card_set_level: unsupported command."); + return; + } + p=(((int)a)<<8 | (int)a); + mix_fd = open(obj->mixdev_name, O_WRONLY); + ioctl(mix_fd,MIXER_WRITE(osscmd), &p); + close(mix_fd); +#endif +} + +gint oss_card_get_level(OssCard *obj,gint way) +{ + int p=0,mix_fd; + int osscmd; + g_return_val_if_fail(obj->mixdev_name!=NULL,-1); +#ifdef HAVE_SYS_SOUNDCARD_H + switch(way){ + case SND_CARD_LEVEL_GENERAL: + osscmd=SOUND_MIXER_VOLUME; + break; + case SND_CARD_LEVEL_INPUT: + osscmd=SOUND_MIXER_IGAIN; + break; + case SND_CARD_LEVEL_OUTPUT: + osscmd=SOUND_MIXER_PCM; + break; + default: + g_warning("oss_card_get_level: unsupported command."); + return -1; + } + mix_fd = open(obj->mixdev_name, O_RDONLY); + ioctl(mix_fd,MIXER_READ(SOUND_MIXER_VOLUME), &p); + close(mix_fd); +#endif + return p>>8; +} + +void oss_card_set_source(OssCard *obj,int source) +{ + gint p=0; + gint mix_fd; + g_return_if_fail(obj->mixdev_name!=NULL); +#ifdef HAVE_SYS_SOUNDCARD_H + if (source == 'c') + p = 1 << SOUND_MIXER_CD; + if (source == 'l') + p = 1 << SOUND_MIXER_LINE; + if (source == 'm') + p = 1 << SOUND_MIXER_MIC; + + + mix_fd = open(obj->mixdev_name, O_WRONLY); + ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p); + close(mix_fd); +#endif +} + +MSFilter *oss_card_create_read_filter(OssCard *card) +{ + MSFilter *f=ms_oss_read_new(); + ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index); + return f; +} + +MSFilter *oss_card_create_write_filter(OssCard *card) +{ + MSFilter *f=ms_oss_write_new(); + ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index); + return f; +} + + +SndCard * oss_card_new(char *devname, char *mixdev_name) +{ + OssCard * obj= g_new0(OssCard,1); + SndCard *base= SND_CARD(obj); + snd_card_init(base); + obj->dev_name=g_strdup(devname); + obj->mixdev_name=g_strdup( mixdev_name); +#ifdef HAVE_GLIB + base->card_name=g_strdup_printf("%s (Open Sound System)",devname); +#else + base->card_name=malloc(100); + snprintf(base->card_name, 100, "%s (Open Sound System)",devname); +#endif + base->_probe=(SndCardOpenFunc)oss_card_probe; + base->_open_r=(SndCardOpenFunc)oss_card_open; + base->_open_w=(SndCardOpenFunc)oss_card_open; + base->_can_read=(SndCardPollFunc)oss_card_can_read; + base->_read=(SndCardIOFunc)oss_card_read; + base->_write=(SndCardIOFunc)oss_card_write; + base->_close_r=(SndCardCloseFunc)oss_card_close; + base->_close_w=(SndCardCloseFunc)oss_card_close; + base->_set_rec_source=(SndCardMixerSetRecSourceFunc)oss_card_set_source; + base->_set_level=(SndCardMixerSetLevelFunc)oss_card_set_level; + base->_get_level=(SndCardMixerGetLevelFunc)oss_card_get_level; + base->_destroy=(SndCardDestroyFunc)oss_card_destroy; + base->_create_read_filter=(SndCardCreateFilterFunc)oss_card_create_read_filter; + base->_create_write_filter=(SndCardCreateFilterFunc)oss_card_create_write_filter; + return base; +} + +#define DSP_NAME "/dev/dsp" +#define MIXER_NAME "/dev/mixer" + +gint oss_card_manager_init(SndCardManager *manager, gint tabindex) +{ + gchar *devname; + gchar *mixername; + gint devindex=0; + gint found=0; + + /* search for /dev/dsp and /dev/mixer */ +#ifdef HAVE_GLIB + if (g_file_test(DSP_NAME,G_FILE_TEST_EXISTS)){ + tabindex++; + devindex++; + manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME); + manager->cards[0]->index=0; + found++; + g_message("Found /dev/dsp."); + } + for (;tabindexcards[tabindex]=oss_card_new(devname,mixername); + manager->cards[tabindex]->index=tabindex; + tabindex++; + found++; + } + g_free(devname); + g_free(mixername); + } +#else + if (access(DSP_NAME,F_OK)==0){ + tabindex++; + devindex++; + manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME); + manager->cards[0]->index=0; + found++; + g_message("Found /dev/dsp."); + } + for (;tabindexcards[tabindex]=oss_card_new(devname,mixername); + manager->cards[tabindex]->index=tabindex; + tabindex++; + found++; + } + g_free(devname); + g_free(mixername); + } +#endif + if (tabindex==0) g_warning("No sound cards found !"); + return found; +} + + +#endif diff --git a/linphone/mediastreamer/osscard.h b/linphone/mediastreamer/osscard.h new file mode 100644 index 000000000..30b96c23c --- /dev/null +++ b/linphone/mediastreamer/osscard.h @@ -0,0 +1,47 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* An implementation of SndCard : the OssCard */ + +#ifndef OSS_CARD_H +#define OSS_CARD_H + +#include "sndcard.h" + +#define OSS_CARD_BUFFERS 3 +struct _OssCard +{ + SndCard parent; + gchar *dev_name; /* /dev/dsp0 for example */ + gchar *mixdev_name; /* /dev/mixer0 for example */ + gint fd; /* the file descriptor of the open soundcard, 0 if not open*/ + gint ref; + gchar *readbuf; + gint readpos; + gchar *writebuf; + gint writepos; +}; + +typedef struct _OssCard OssCard; + +SndCard * oss_card_new(char *devname, char *mixdev_name); + +typedef OssCard HpuxSndCard; + +#endif diff --git a/linphone/mediastreamer/rfc2429.h b/linphone/mediastreamer/rfc2429.h new file mode 100644 index 000000000..1dee9c43e --- /dev/null +++ b/linphone/mediastreamer/rfc2429.h @@ -0,0 +1,46 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef rfc2429_h +#define rfc2429_h + +#define MAKE_MASK(bits) ( (1<<(bits)) -1 ) + +static inline unsigned int rfc2429_get_P(const char *header){ + return (header[0]>>2) & 0x1; +} + +static inline unsigned int rfc2429_get_V(const char *header){ + return (header[0]>>1) & 0x1; +} + +static inline unsigned int rfc2429_get_PLEN(const char *header){ + unsigned short *p=(unsigned short*)header; + return (ntohs(p[0])>>3) & MAKE_MASK(6); +} + +static inline unsigned int rfc2429_get_PEBIT(const char *header){ + unsigned short *p=(unsigned short*)header; + return ntohs(p[0]) & MAKE_MASK(3); +} + + +#endif diff --git a/linphone/mediastreamer/ring_test.c b/linphone/mediastreamer/ring_test.c new file mode 100644 index 000000000..3d8293e11 --- /dev/null +++ b/linphone/mediastreamer/ring_test.c @@ -0,0 +1,63 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msringplayer.h" +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "mstimer.h" +#include + + +#define READFILE "../share/rings/orig.wav" +#define WRITEFILE "/tmp/mediaout" + +int main() +{ + MSFilter *play,*copy,*rec; + MSSync *timer; + int i=0; + SndCard *card; + ms_init(); + + card=snd_card_manager_get_card(snd_card_manager,2); + play=ms_ring_player_new(READFILE,2); + //play=ms_oss_read_new(0); + rec=snd_card_create_write_filter(card); + copy=ms_copy_new(); + timer=ms_timer_new(); + + ms_filter_add_link(play,copy); + ms_filter_add_link(copy,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + + while(1) + { + ms_sound_write_set_level(MS_SOUND_WRITE(rec),i); + i+=10; + sleep(1); + if (i>100) i=0; + } + return 0; +} diff --git a/linphone/mediastreamer/sndcard.c b/linphone/mediastreamer/sndcard.c new file mode 100644 index 000000000..f438d1510 --- /dev/null +++ b/linphone/mediastreamer/sndcard.c @@ -0,0 +1,209 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "sndcard.h" +#include "msfilter.h" + +void snd_card_init(SndCard *obj) +{ + memset(obj,0,sizeof(SndCard)); +} + +void snd_card_uninit(SndCard *obj) +{ + if (obj->card_name!=NULL) g_free(obj->card_name); +} + +const gchar *snd_card_get_identifier(SndCard *obj) +{ + return obj->card_name; +} + +int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate) +{ + g_return_val_if_fail(obj->_open_r!=NULL,-1); + g_message("Opening sound card [%s] in capture mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits); + return obj->_open_r(obj,bits,stereo,rate); +} +int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate) +{ + g_return_val_if_fail(obj->_open_w!=NULL,-1); + g_message("Opening sound card [%s] in playback mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits); + return obj->_open_w(obj,bits,stereo,rate); +} + +gboolean snd_card_can_read(SndCard *obj){ + g_return_val_if_fail(obj->_can_read!=NULL,-1); + return obj->_can_read(obj); +} + +void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno){ + g_return_if_fail(obj->_set_blocking_mode!=NULL); + obj->_set_blocking_mode(obj,yesno); +} + +int snd_card_read(SndCard *obj,char *buffer,int size) +{ + g_return_val_if_fail(obj->_read!=NULL,-1); + return obj->_read(obj,buffer,size); +} +int snd_card_write(SndCard *obj,char *buffer,int size) +{ + g_return_val_if_fail(obj->_write!=NULL,-1); + return obj->_write(obj,buffer,size); +} + +int snd_card_get_bsize(SndCard *obj) +{ + if (obj->flags & SND_CARD_FLAGS_OPENED){ + return obj->bsize; + } + return -1; +} + +void snd_card_close_r(SndCard *obj) +{ + g_return_if_fail(obj->_close_r!=NULL); + g_message("Closing reading channel of soundcard."); + obj->_close_r(obj); +} + +void snd_card_close_w(SndCard *obj) +{ + g_return_if_fail(obj->_close_w!=NULL); + g_message("Closing writing channel of soundcard."); + obj->_close_w(obj); +} + +gint snd_card_probe(SndCard *obj,int bits, int stereo, int rate) +{ + g_return_val_if_fail(obj->_probe!=NULL,-1); + return obj->_probe(obj,bits,stereo,rate); +} + +void snd_card_set_rec_source(SndCard *obj, int source) +{ + g_return_if_fail(obj->_set_rec_source!=NULL); + obj->_set_rec_source(obj,source); +} + +void snd_card_set_level(SndCard *obj, int way, int level) +{ + g_return_if_fail(obj->_set_level!=NULL); + obj->_set_level(obj,way,level); +} + +gint snd_card_get_level(SndCard *obj,int way) +{ + g_return_val_if_fail(obj->_get_level!=NULL,-1); + return obj->_get_level(obj,way); +} + + +MSFilter * snd_card_create_read_filter(SndCard *obj) +{ + g_return_val_if_fail(obj->_create_read_filter!=NULL,NULL); + return obj->_create_read_filter(obj); +} +MSFilter * snd_card_create_write_filter(SndCard *obj) +{ + g_return_val_if_fail(obj->_create_write_filter!=NULL,NULL); + return obj->_create_write_filter(obj); +} + + +#ifdef HAVE_SYS_AUDIO_H +gint sys_audio_manager_init(SndCardManager *manager, gint index) +{ + /* this is a quick shortcut, as multiple soundcards on HPUX does not happen + very often... */ + manager->cards[index]=hpux_snd_card_new("/dev/audio","/dev/audio"); + return 1; +} + +#endif + +#include "osscard.h" +#include "alsacard.h" +#include "jackcard.h" + +#ifdef HAVE_SYS_SOUNDCARD_H +/* in osscard.c */ +gint oss_card_manager_init(SndCardManager *manager, gint tabindex); +#endif + +void snd_card_manager_init(SndCardManager *manager) +{ + gint index=0; + gint tmp=0; + memset(manager,0,sizeof(SndCardManager)); + #ifdef HAVE_SYS_SOUNDCARD_H + tmp=oss_card_manager_init(manager,index); + index+=tmp; + if (index>=MAX_SND_CARDS) return; + #endif + #ifdef __ALSA_ENABLED__ + tmp=alsa_card_manager_init(manager,index); + index+=tmp; + if (index>=MAX_SND_CARDS) return; + #endif + #ifdef __JACK_ENABLED__ + tmp=jack_card_manager_init(manager,index); + index+=tmp; + if (index>=MAX_SND_CARDS) return; + #endif + #ifdef HAVE_SYS_AUDIO_H + tmp=sys_audio_manager_init(manager,index); + index+=tmp; + #endif +} + + + + + +SndCard * snd_card_manager_get_card(SndCardManager *manager,int index) +{ + g_return_val_if_fail(index>=0,NULL); + g_return_val_if_fail(indexMAX_SND_CARDS) return NULL; + return manager->cards[index]; +} + +SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index) +{ + int i; + for (i=0;icards[i]==NULL) continue; + card_name=manager->cards[i]->card_name; + if (card_name==NULL) continue; + if (strcmp(card_name,cardname)==0){ + *index=i; + return manager->cards[i]; + } + } + g_warning("No card %s found.",cardname); + return NULL; +} + +SndCardManager _snd_card_manager; +SndCardManager *snd_card_manager=&_snd_card_manager; diff --git a/linphone/mediastreamer/sndcard.h b/linphone/mediastreamer/sndcard.h new file mode 100644 index 000000000..7441b5707 --- /dev/null +++ b/linphone/mediastreamer/sndcard.h @@ -0,0 +1,145 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#ifndef SNDCARD_H +#define SNDCARD_H + +#undef PACKAGE +#undef VERSION +#ifdef HAVE_CONFIG_H +# include +#endif +#undef PACKAGE +#undef VERSION + +#ifdef HAVE_GLIB +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* the base class for all soundcards: SndCard */ +struct _SndCard; + +typedef int (*SndCardOpenFunc)(struct _SndCard*,int, int, int); +typedef void (*SndCardSetBlockingModeFunc)(struct _SndCard*, gboolean ); +typedef void (*SndCardCloseFunc)(struct _SndCard*); +typedef gint (*SndCardIOFunc)(struct _SndCard*,char *,int); +typedef void (*SndCardDestroyFunc)(struct _SndCard*); +typedef gboolean (*SndCardPollFunc)(struct _SndCard*); +typedef gint (*SndCardMixerGetLevelFunc)(struct _SndCard*,gint); +typedef void (*SndCardMixerSetRecSourceFunc)(struct _SndCard*,gint); +typedef void (*SndCardMixerSetLevelFunc)(struct _SndCard*,gint ,gint); +typedef struct _MSFilter * (*SndCardCreateFilterFunc)(struct _SndCard *); + +struct _SndCard +{ + gchar *card_name; /* SB16 PCI for example */ + gint index; + gint bsize; + gint rate; + gint stereo; + gint bits; + gint flags; +#define SND_CARD_FLAGS_OPENED 1 + SndCardOpenFunc _probe; + SndCardOpenFunc _open_r; + SndCardOpenFunc _open_w; + SndCardSetBlockingModeFunc _set_blocking_mode; + SndCardPollFunc _can_read; + SndCardIOFunc _read; + SndCardIOFunc _write; + SndCardCloseFunc _close_r; + SndCardCloseFunc _close_w; + SndCardMixerGetLevelFunc _get_level; + SndCardMixerSetLevelFunc _set_level; + SndCardMixerSetRecSourceFunc _set_rec_source; + SndCardCreateFilterFunc _create_read_filter; + SndCardCreateFilterFunc _create_write_filter; + SndCardDestroyFunc _destroy; +}; + + +typedef struct _SndCard SndCard; + +void snd_card_init(SndCard *obj); +void snd_card_uninit(SndCard *obj); +gint snd_card_probe(SndCard *obj, int bits, int stereo, int rate); +int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate); +int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate); +int snd_card_get_bsize(SndCard *obj); +gboolean snd_card_can_read(SndCard *obj); +int snd_card_read(SndCard *obj,char *buffer,int size); +int snd_card_write(SndCard *obj,char *buffer,int size); +void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno); +void snd_card_close_r(SndCard *obj); +void snd_card_close_w(SndCard *obj); + +void snd_card_set_rec_source(SndCard *obj, int source); /* source='l' or 'm'*/ +void snd_card_set_level(SndCard *obj, int way, int level); +gint snd_card_get_level(SndCard *obj,int way); + +const gchar *snd_card_get_identifier(SndCard *obj); + +struct _MSFilter * snd_card_create_read_filter(SndCard *sndcard); +struct _MSFilter * snd_card_create_write_filter(SndCard *sndcard); + + +#define SND_CARD_LEVEL_GENERAL 1 +#define SND_CARD_LEVEL_INPUT 2 +#define SND_CARD_LEVEL_OUTPUT 3 + + +int snd_card_destroy(SndCard *obj); + +#define SND_CARD(obj) ((SndCard*)(obj)) + + + + +/* SndCardManager */ + +#define MAX_SND_CARDS 20 + + +struct _SndCardManager +{ + SndCard *cards[MAX_SND_CARDS]; +}; + +typedef struct _SndCardManager SndCardManager; + +void snd_card_manager_init(SndCardManager *manager); +SndCard * snd_card_manager_get_card(SndCardManager *manager,int index); +SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index); + +extern SndCardManager *snd_card_manager; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/mediastreamer/test.c b/linphone/mediastreamer/test.c new file mode 100644 index 000000000..a24c3f4dd --- /dev/null +++ b/linphone/mediastreamer/test.c @@ -0,0 +1,91 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msringplayer.h" +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "mstimer.h" +#include +#include + +#define READFILE "../share/rings/orig.wav" +#define WRITEFILE "/tmp/mediaout" + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + + +int main(int argc, char *argv[]) +{ + MSFilter *play,*copy,*rec; + MSSync *timer; + int i=0; + int tmp; + char *ring; + + ms_init(); + + if (argc>1){ + ring=argv[1]; + }else ring= READFILE; + + play=ms_ring_player_new(ring,2); + //play=ms_oss_read_new(0); + rec=snd_card_create_write_filter(snd_card_manager_get_card(snd_card_manager,1)); + copy=ms_copy_new(); + + ms_filter_get_property(play,MS_FILTER_PROPERTY_FREQ,&tmp); + g_message("Playing at rate %i.",tmp); + ms_filter_set_property(rec,MS_FILTER_PROPERTY_FREQ,&tmp); + ms_filter_get_property(play,MS_FILTER_PROPERTY_CHANNELS,&tmp); + g_message("Playing with %i channels",tmp); + ms_filter_set_property(rec,MS_FILTER_PROPERTY_CHANNELS,&tmp); + + timer=ms_timer_new(); + ms_sync_start(timer); + + ms_filter_add_link(play,copy); + ms_filter_add_link(copy,rec); + ms_sync_attach(timer,play); + + + while(cond) + { + sleep(1); + } + ms_sync_detach(timer,play); + ms_sync_stop(timer); + ms_sync_destroy(timer); + + ms_filter_remove_links(play,copy); + ms_filter_remove_links(copy,rec); + ms_filter_destroy(play); + ms_filter_destroy(copy); + ms_filter_destroy(rec); + + return 0; +} diff --git a/linphone/mediastreamer/test_alaw.c b/linphone/mediastreamer/test_alaw.c new file mode 100644 index 000000000..243ceca8c --- /dev/null +++ b/linphone/mediastreamer/test_alaw.c @@ -0,0 +1,90 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "mstimer.h" +#include "msAlawdec.h" +#include "msAlawenc.h" + +#include +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *play,*enc,*dec,*rec; + MSSync *timer; + + ms_init(); + signal(SIGINT,stop_handler); + + play=ms_oss_read_new(); + rec=ms_oss_write_new(); + + ms_sound_read_set_device(MS_SOUND_READ(play),0); + ms_sound_write_set_device(MS_SOUND_WRITE(rec),0); + + enc=ms_ALAWencoder_new(); + dec=ms_ALAWdecoder_new(); + timer=ms_timer_new(); + + ms_filter_add_link(play,enc); + ms_filter_add_link(enc,dec); + ms_filter_add_link(dec,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + + ms_sound_read_start(MS_SOUND_READ(play)); + ms_sound_write_start(MS_SOUND_WRITE(rec)); + while(cond) + { + sleep(1); + } + + ms_sound_read_stop(MS_SOUND_READ(play)); + ms_sound_write_stop(MS_SOUND_WRITE(rec)); + + printf("stoping sync...\n"); + ms_stop(timer); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,enc); + ms_filter_remove_links(enc,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(enc); + ms_filter_destroy(dec); + ms_filter_destroy(rec); + ms_sync_destroy(timer); + return 0; +} diff --git a/linphone/mediastreamer/test_gsm.c b/linphone/mediastreamer/test_gsm.c new file mode 100644 index 000000000..1e2350b15 --- /dev/null +++ b/linphone/mediastreamer/test_gsm.c @@ -0,0 +1,85 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "mstimer.h" +#include "msGSMdecoder.h" +#include "msGSMencoder.h" + +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *play,*enc,*dec,*rec; + MSSync *timer; + + ms_init(); + signal(SIGINT,stop_handler); + + play=ms_oss_read_new(); + rec=ms_oss_write_new(); + ms_sound_read_set_device(MS_SOUND_READ(play),0); + ms_sound_write_set_device(MS_SOUND_WRITE(rec),0); + + enc=ms_GSMencoder_new(); + dec=ms_GSMdecoder_new(); + timer=ms_timer_new(); + + ms_filter_add_link(play,enc); + ms_filter_add_link(enc,dec); + ms_filter_add_link(dec,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + ms_sound_read_start(MS_SOUND_READ(play)); + ms_sound_write_start(MS_SOUND_WRITE(rec)); + while(cond) + { + sleep(1); + } + ms_sound_read_stop(MS_SOUND_READ(play)); + ms_sound_write_stop(MS_SOUND_WRITE(rec)); + printf("stoping sync...\n"); + ms_stop(timer); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,enc); + ms_filter_remove_links(enc,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(enc); + ms_filter_destroy(dec); + ms_filter_destroy(rec); + ms_sync_destroy(timer); + return 0; +} diff --git a/linphone/mediastreamer/test_lpc10.c b/linphone/mediastreamer/test_lpc10.c new file mode 100644 index 000000000..bb39f9df3 --- /dev/null +++ b/linphone/mediastreamer/test_lpc10.c @@ -0,0 +1,89 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "mstimer.h" +#include "msLPC10decoder.h" +#include "msLPC10encoder.h" + +#include +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *play,*enc,*dec,*rec; + MSSync *timer; + + ms_init(); + signal(SIGINT,stop_handler); + + play=ms_oss_read_new(); + rec=ms_oss_write_new(); + + ms_sound_read_set_device(MS_SOUND_READ(play),0); + ms_sound_write_set_device(MS_SOUND_WRITE(rec),0); + + enc=ms_LPC10encoder_new(); + dec=ms_LPC10decoder_new(); + timer=ms_timer_new(); + + ms_filter_add_link(play,enc); + ms_filter_add_link(enc,dec); + ms_filter_add_link(dec,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + ms_sound_read_start(MS_SOUND_READ(play)); + ms_sound_write_start(MS_SOUND_WRITE(rec)); + + while(cond) + { + sleep(1); + } + ms_sound_read_stop(MS_SOUND_READ(play)); + ms_sound_write_stop(MS_SOUND_WRITE(rec)); + + printf("stoping sync...\n"); + ms_stop(timer); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,enc); + ms_filter_remove_links(enc,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(enc); + ms_filter_destroy(dec); + ms_filter_destroy(rec); + ms_sync_destroy(timer); + return 0; +} diff --git a/linphone/mediastreamer/test_mulaw.c b/linphone/mediastreamer/test_mulaw.c new file mode 100644 index 000000000..9962e8601 --- /dev/null +++ b/linphone/mediastreamer/test_mulaw.c @@ -0,0 +1,87 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "msnosync.h" +#include "mstimer.h" +#include "msMUlawdec.h" +#include "msMUlawenc.h" + +#include +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *play,*enc,*dec,*rec; + MSSync *timer; + + ms_init(); + signal(SIGINT,stop_handler); + + play=ms_oss_read_new(); + rec=ms_oss_write_new(); + ms_sound_read_set_device(MS_SOUND_READ(play),0); + ms_sound_write_set_device(MS_SOUND_WRITE(rec),0); + + enc=ms_MULAWencoder_new(); + dec=ms_MULAWdecoder_new(); + timer=ms_timer_new(); + + ms_filter_add_link(play,enc); + ms_filter_add_link(enc,dec); + ms_filter_add_link(dec,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + ms_sound_read_start(MS_SOUND_READ(play)); + ms_sound_write_start(MS_SOUND_WRITE(rec)); + while(cond) + { + sleep(1); + } + ms_sound_read_stop(MS_SOUND_READ(play)); + ms_sound_write_stop(MS_SOUND_WRITE(rec)); + printf("stoping sync...\n"); + ms_stop(timer); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,enc); + ms_filter_remove_links(enc,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(enc); + ms_filter_destroy(dec); + ms_filter_destroy(rec); + ms_sync_destroy(timer); + return 0; +} diff --git a/linphone/mediastreamer/test_rtprecv.c b/linphone/mediastreamer/test_rtprecv.c new file mode 100644 index 000000000..d6ba66513 --- /dev/null +++ b/linphone/mediastreamer/test_rtprecv.c @@ -0,0 +1,99 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "msrtprecv.h" +#include "ms.h" +#include "mswrite.h" +#include "msosswrite.h" +#include "msMUlawdec.h" +#include "mstimer.h" +#include "msfdispatcher.h" + +#include +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *play,*dec,*rec,*filerec,*dis; + MSSync *timer; + RtpSession *rtps; + + /*create the rtp session */ + ortp_init(); + rtps=rtp_session_new(RTP_SESSION_RECVONLY); + rtp_session_set_local_addr(rtps,"0.0.0.0",8000); + rtp_session_set_scheduling_mode(rtps,0); + rtp_session_set_blocking_mode(rtps,0); + + ms_init(); + signal(SIGINT,stop_handler); + + play=ms_rtp_recv_new(); + rec=ms_oss_write_new(); + ms_sound_write_set_device(MS_SOUND_WRITE(rec),0); + dec=ms_MULAWdecoder_new(); + filerec=ms_write_new("/tmp/rtpstream"); + dis=ms_fdispatcher_new(); + timer=ms_timer_new(); + + ms_rtp_recv_set_session(MS_RTP_RECV(play),rtps); + + ms_filter_add_link(play,dec); + ms_filter_add_link(dec,dis); + ms_filter_add_link(dis,rec); + ms_filter_add_link(dis,filerec); + ms_sync_attach(timer,play); + printf("gran=%i\n",MS_SYNC(timer)->samples_per_tick); + + ms_start(timer); + ms_sound_write_start(MS_SOUND_WRITE(rec)); + while(cond) + { + sleep(1); + } + + printf("stoping sync...\n"); + ms_stop(timer); + ms_sound_write_stop(MS_SOUND_WRITE(rec)); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(dec); + ms_filter_destroy(rec); + ms_filter_destroy(dis); + ms_filter_destroy(filerec); + + rtp_session_destroy(rtps); + ms_sync_destroy(timer); + ortp_global_stats_display(); + + return 0; +} diff --git a/linphone/mediastreamer/test_smpeg.c b/linphone/mediastreamer/test_smpeg.c new file mode 100644 index 000000000..a1e2c436e --- /dev/null +++ b/linphone/mediastreamer/test_smpeg.c @@ -0,0 +1,70 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "ms.h" +#include "msfilter.h" +#include "mssmpeg.h" +#include +#include +#include +#include "mstimer.h" +#include "msread.h" + +int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *source; + MSFilter *smpeg_filter; + MSSync *timer; + + timer=ms_timer_new(); + ms_timer_set_interval(MS_TIMER(timer),100); + + smpeg_filter=ms_smpeg_new(); + source=ms_read_new("/cdrom/Videos/Queen - Bohemian Rhapsody.mpg"); + ms_filter_add_link(source,smpeg_filter); + ms_sync_attach(timer,source); + signal(SIGINT,stop_handler); + + ms_start(timer); + ms_smpeg_start(MS_SMPEG(smpeg_filter)); + while (cond){ + sleep (1); + } + g_message("Exiting..."); + ms_smpeg_stop(MS_SMPEG(smpeg_filter)); + ms_stop(timer); + ms_sync_detach(timer,source); + ms_filter_remove_links(source,smpeg_filter); + ms_sync_destroy(timer); + ms_filter_destroy(smpeg_filter); + ms_filter_destroy(source); + g_message("End of test program."); + return 0; +} + + diff --git a/linphone/mediastreamer/test_speex.c b/linphone/mediastreamer/test_speex.c new file mode 100644 index 000000000..06726104c --- /dev/null +++ b/linphone/mediastreamer/test_speex.c @@ -0,0 +1,88 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "sndcard.h" +#include "mscopy.h" +#include "mstimer.h" +#include "msspeexdec.h" +#include "msspeexenc.h" + +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +int main() +{ + MSFilter *play,*enc,*dec,*rec; + MSSync *timer; + SndCard *card; + int rate=16000; + + ms_init(); + signal(SIGINT,stop_handler); + /* get the first card */ + card=snd_card_manager_get_card(snd_card_manager,0); + if (card==NULL) g_error("No sound card detected."); + + play=snd_card_create_read_filter(card); + rec=snd_card_create_write_filter(card); + + enc=ms_speex_enc_new(); + dec=ms_speex_dec_new(); + + ms_filter_set_property(play,MS_FILTER_PROPERTY_FREQ,&rate); + ms_filter_set_property(rec,MS_FILTER_PROPERTY_FREQ,&rate); + ms_filter_set_property(enc,MS_FILTER_PROPERTY_FREQ,&rate); + ms_filter_set_property(dec,MS_FILTER_PROPERTY_FREQ,&rate); + timer=ms_timer_new(); + + ms_filter_add_link(play,enc); + ms_filter_add_link(enc,dec); + ms_filter_add_link(dec,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + while(cond) + { + sleep(1); + } + printf("stoping sync...\n"); + ms_stop(timer); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,enc); + ms_filter_remove_links(enc,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(enc); + ms_filter_destroy(dec); + ms_filter_destroy(rec); + ms_sync_destroy(timer); + return 0; +} diff --git a/linphone/mediastreamer/test_truespeech.c b/linphone/mediastreamer/test_truespeech.c new file mode 100644 index 000000000..4e734fac4 --- /dev/null +++ b/linphone/mediastreamer/test_truespeech.c @@ -0,0 +1,91 @@ + /* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ms.h" + +#include "msosswrite.h" +#include "msossread.h" +#include "mscopy.h" +#include "mstimer.h" +#include "mstruespeechdecoder.h" +#include "mstruespeechencoder.h" + +#include +#include +#include +#include + +static int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + + +int main() +{ + MSFilter *play,*enc,*dec,*rec; + MSSync *timer; + + ms_init(); + signal(SIGINT,stop_handler); + + play=ms_oss_read_new(); + rec=ms_oss_write_new(); + + ms_sound_read_set_device(MS_SOUND_READ(play),0); + ms_sound_write_set_device(MS_SOUND_WRITE(rec),0); + + enc=ms_truespeechencoder_new(); + dec=ms_truespeechdecoder_new(); + timer=ms_timer_new(); + + ms_filter_add_link(play,enc); + ms_filter_add_link(enc,dec); + ms_filter_add_link(dec,rec); + ms_sync_attach(timer,play); + + ms_start(timer); + + ms_sound_read_start(MS_SOUND_READ(play)); + ms_sound_write_start(MS_SOUND_WRITE(rec)); + while(cond) + { + sleep(1); + } + + ms_sound_read_stop(MS_SOUND_READ(play)); + ms_sound_write_stop(MS_SOUND_WRITE(rec)); + + printf("stoping sync...\n"); + ms_stop(timer); + printf("unlinking filters...\n"); + ms_filter_remove_links(play,enc); + ms_filter_remove_links(enc,dec); + ms_filter_remove_links(dec,rec); + printf("destroying filters...\n"); + ms_filter_destroy(play); + ms_filter_destroy(dec); + ms_filter_destroy(enc); + ms_filter_destroy(rec); + ms_sync_destroy(timer); + return 0; +} diff --git a/linphone/mediastreamer/test_v4l.c b/linphone/mediastreamer/test_v4l.c new file mode 100644 index 000000000..9b51e82fb --- /dev/null +++ b/linphone/mediastreamer/test_v4l.c @@ -0,0 +1,32 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mediastream.h" + + +int main() +{ + VideoStream *v; + ms_init(); + v=video_preview_start("Video4Linux","/dev/video0"); + sleep(15); + video_preview_stop(v); + return 0; +} diff --git a/linphone/mediastreamer/test_videostream.c b/linphone/mediastreamer/test_videostream.c new file mode 100644 index 000000000..1289971ad --- /dev/null +++ b/linphone/mediastreamer/test_videostream.c @@ -0,0 +1,45 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mediastream.h" +#include + +static gboolean cond=TRUE; + +static void stop_handler(int signum){ + cond=FALSE; +} + +int main() +{ + VideoStream *v; + ortp_init(); + rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998); + ms_init(); + signal(SIGINT,stop_handler); + v=video_stream_start(&av_profile,6000,"127.0.0.1",6000, 98, 60, TRUE, "Video4Linux","/dev/video0"); + while(cond) { + ortp_global_stats_display(); + sleep(1); + } + video_stream_stop(v); + ortp_exit(); + return 0; +} diff --git a/linphone/mediastreamer/test_xine.c b/linphone/mediastreamer/test_xine.c new file mode 100644 index 000000000..1eb7bc3dc --- /dev/null +++ b/linphone/mediastreamer/test_xine.c @@ -0,0 +1,45 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "ms.h" +#include "msfilter.h" +#include "msxine.h" +#include + + + +int main() +{ + MSFilter *xinefilter1,*xinefilter2; + + xinefilter1=ms_xine_new(); + //xinefilter2=ms_xine_new(); + //sleep(10); + ms_xine_start(MS_XINE(xinefilter1)); + sleep(15); + ms_xine_stop(MS_XINE(xinefilter1)); + ms_filter_destroy(xinefilter1); + //ms_filter_destroy(xinefilter2); + g_message("End of test program."); + return 0; +} + + diff --git a/linphone/mediastreamer/videoclient.c b/linphone/mediastreamer/videoclient.c new file mode 100644 index 000000000..3f24b86e2 --- /dev/null +++ b/linphone/mediastreamer/videoclient.c @@ -0,0 +1,60 @@ +#include "ms.h" +#include "msavdecoder.h" +#include "mstcpclient.h" +#include "mssdlout.h" +#include "mstimer.h" +#include + + +static gboolean running=TRUE; + +static void sighandler(int signum){ + running=FALSE; +} + +int main(int argc, char *argv[]){ + MSFilter *source,*decoder,*output; + MSSync *sync; + + if (argc<3){ + fprintf(stderr,"videoclient \n"); + return -1; + } + + signal(SIGINT,sighandler); + + ms_init(); + + source=ms_tcp_client_new(); + ms_tcp_client_connect(MS_TCP_CLIENT(source),argv[1],atoi(argv[2])); + + decoder=ms_h263_decoder_new(); + ms_AVdecoder_set_format(MS_AVDECODER(decoder),"YUV420P"); + + output=ms_sdl_out_new(); + ms_sdl_out_set_format(MS_SDL_OUT(output),"YUV420P"); + + ms_filter_add_link(source,decoder); + ms_filter_add_link(decoder,output); + + sync=ms_timer_new(); + + ms_sync_attach(sync,source); + + ms_start(sync); + + while(running) sleep(1); + + ms_stop(sync); + + ms_sync_detach(sync,source); + + ms_filter_remove_links(source,decoder); + ms_filter_remove_links(decoder,output); + + ms_filter_destroy(source); + ms_filter_destroy(decoder); + ms_filter_destroy(output); + return 0; +} + diff --git a/linphone/mediastreamer/videoserver.c b/linphone/mediastreamer/videoserver.c new file mode 100644 index 000000000..dc2070e9c --- /dev/null +++ b/linphone/mediastreamer/videoserver.c @@ -0,0 +1,56 @@ +#include "ms.h" +#include "msv4l.h" +#include "msavencoder.h" +#include "mstcpserv.h" +#include "mstimer.h" +#include + + +static gboolean running=TRUE; + +static void sighandler(int signum){ + running=FALSE; +} + +int main(int arg, char *argv[]){ + MSFilter *source,*encoder,*sender; + MSSync *sync; + + signal(SIGINT,sighandler); + + ms_init(); + + source=ms_v4l_new(); + ms_v4l_set_device(MS_V4L(source),"/dev/video0"); + ms_v4l_start(MS_V4L(source)); + + encoder=ms_h263_encoder_new(); + + sender=ms_tcp_serv_new(); + + ms_filter_add_link(source,encoder); + ms_filter_add_link(encoder,sender); + + sync=ms_timer_new(); + + ms_sync_attach(sync,source); + + ms_start(sync); + + while(running) sleep(1); + + ms_stop(sync); + + ms_sync_detach(sync,source); + + ms_v4l_stop(MS_V4L(source)); + + ms_filter_remove_links(source,encoder); + ms_filter_remove_links(encoder,sender); + + ms_filter_destroy(source); + ms_filter_destroy(encoder); + ms_filter_destroy(sender); + return 0; +} + diff --git a/linphone/mediastreamer/videostream.c b/linphone/mediastreamer/videostream.c new file mode 100644 index 000000000..d512b849b --- /dev/null +++ b/linphone/mediastreamer/videostream.c @@ -0,0 +1,346 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "mediastream.h" +#include "msvideosource.h" +#include "msavdecoder.h" +#include "msavencoder.h" +#include "msnosync.h" +#include "mssdlout.h" + +#define USE_SDL + +extern void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport, + int payload,int jitt_comp, + RtpSession **recvsend); + +#define MAX_RTP_SIZE UDP_MAX_SIZE + +#ifdef VIDEO_ENABLED + +/* this code is not part of the library itself, it is part of the mediastream program */ +void video_stream_free (VideoStream * stream) +{ + RtpSession *recvs, *sends; + if (stream->rtprecv != NULL) + { + recvs = ms_rtp_recv_get_session (MS_RTP_RECV (stream->rtprecv)); + if (recvs != NULL) + { + rtp_session_destroy (recvs); + } + ms_filter_destroy (stream->rtprecv); + } + if (stream->rtpsend != NULL) + { + sends = ms_rtp_send_get_session (MS_RTP_SEND (stream->rtpsend)); + if (sends != NULL && sends!=recvs) + { + rtp_session_destroy (sends); + } + ms_filter_destroy (stream->rtpsend); + } + if (stream->source != NULL) + ms_filter_destroy (stream->source); + if (stream->output != NULL) + ms_filter_destroy (stream->output); + if (stream->decoder != NULL) + ms_filter_destroy (stream->decoder); + if (stream->encoder != NULL) + ms_filter_destroy (stream->encoder); + if (stream->timer != NULL) + ms_sync_destroy (stream->timer); + g_free (stream); +} + + +VideoStream * +video_stream_start (RtpProfile *profile, int locport, char *remip, int remport, + int payload, int jitt_comp, gboolean show_local, + const gchar *source, const gchar *device) +{ + VideoStream *stream = g_new0 (VideoStream, 1); + RtpSession *rtps, *rtpr; + PayloadType *pt; + gchar *format; + gint width = VIDEO_SIZE_CIF_W; + gint height = VIDEO_SIZE_CIF_H; + float fps; + + create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr); + rtp_session_enable_adaptive_jitter_compensation(rtpr,FALSE); + rtps=rtpr; + ms_trace("sending video to %s:%i", remip4, remport); + + /* creates two rtp filters to recv send streams (remote part) */ + rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE); + stream->rtpsend = ms_rtp_send_new (); + if (remport>0) ms_rtp_send_set_session (MS_RTP_SEND (stream->rtpsend), rtps); + + + stream->rtprecv = ms_rtp_recv_new (); + ms_rtp_recv_set_session (MS_RTP_RECV (stream->rtprecv), rtpr); + + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + g_error("videostream.c: undefined payload type."); + return NULL; + } + ms_trace("videostream.c: getting codecs for %s", pt->mime_type); + + /* creates the filters */ + stream->source = ms_filter_new_with_name(source); + if (stream->source == NULL){ + g_error("videostream.c: failed to create video source %s.", source); + return NULL; + } + +#ifdef USE_SDL + stream->output=ms_sdl_out_new(); +#else + stream->output = MS_FILTER(ms_video_output_new ()); +#endif + stream->encoder=ms_encoder_new_with_string_id(pt->mime_type); + g_message("Video encoder created: %x",stream->encoder); + stream->decoder=ms_decoder_new_with_string_id(pt->mime_type); + if ((stream->encoder==NULL) || (stream->decoder==NULL)){ + /* big problem: we have not a registered codec for this payload...*/ + video_stream_free(stream); + g_error("videostream.c: No codecs available for payload %i.",payload); + return NULL; + } + + /* configure the filters */ + ms_video_source_set_device(MS_VIDEO_SOURCE(stream->source), device); + ms_video_source_set_size(MS_VIDEO_SOURCE(stream->source), width, height); + ms_video_source_set_frame_rate(MS_VIDEO_SOURCE(stream->source), 8, 1); + fps = MS_VIDEO_SOURCE(stream->source)->frame_rate / MS_VIDEO_SOURCE(stream->source)->frame_rate_base; + ms_video_source_start(MS_VIDEO_SOURCE(stream->source)); + format = ms_video_source_get_format(MS_VIDEO_SOURCE(stream->source)); + + ms_AVencoder_set_format (MS_AVENCODER (stream->encoder), format); + ms_AVencoder_set_width(MS_AVENCODER(stream->encoder), width); + ms_AVencoder_set_height(MS_AVENCODER(stream->encoder), height); + /* bitrate is based upon 30fps? adjust by our possibly lower framerate REVISIT later */ + /*ms_AVencoder_set_bit_rate(MS_AVENCODER(stream->encoder), pt->normal_bitrate * 30 / fps );*/ + ms_AVdecoder_set_format (MS_AVDECODER (stream->decoder), "YUV420P"); + ms_AVdecoder_set_width(MS_AVDECODER(stream->decoder), width); + ms_AVdecoder_set_height(MS_AVDECODER(stream->decoder), height); +#ifdef USE_SDL + /* we suppose our decoder and pin1 of encoder always outputs YUV420P */ + ms_sdl_out_set_format(MS_SDL_OUT(stream->output),"YUV420P"); +#else + ms_video_output_set_size (MS_VIDEO_OUTPUT (stream->output), width, height); +#endif + + /* and then connect all */ + ms_filter_add_link (stream->source, stream->encoder); + ms_filter_add_link (stream->encoder, stream->rtpsend); + + ms_filter_add_link (stream->rtprecv, stream->decoder); + ms_filter_add_link (stream->decoder, stream->output); + if (show_local) + ms_filter_add_link(stream->encoder,stream->output); + + /* create the synchronisation source */ + stream->timer = ms_timer_new(); + ms_sync_attach (stream->timer, stream->source); + ms_sync_attach (stream->timer, stream->rtprecv); + + /* and start */ + ms_start (stream->timer); + stream->show_local=show_local; + return stream; +} + + + +void +video_stream_stop (VideoStream * stream) +{ + + ms_stop (stream->timer); + ms_video_source_stop (MS_VIDEO_SOURCE(stream->source)); + ms_sync_detach (stream->timer, stream->source); + ms_sync_detach (stream->timer, stream->rtprecv); + + ms_filter_remove_links(stream->source,stream->encoder); + ms_filter_remove_links (stream->encoder, + stream->rtpsend); + + ms_filter_remove_links (stream->rtprecv, + stream->decoder); + ms_filter_remove_links (stream->decoder, + stream->output); + if (stream->show_local) { + ms_filter_remove_links (stream->encoder, + stream->output); + } + video_stream_free (stream); +} + + +void video_stream_set_rtcp_information(VideoStream *st, const char *cname){ + if (st->send_session!=NULL){ + rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL,NULL,"linphone-" LINPHONE_VERSION, + "This is free software (GPL) !"); + } +} + + + +VideoStream * video_preview_start(const gchar *source, const gchar *device){ + VideoStream *stream = g_new0 (VideoStream, 1); + gchar *format; + gint width = VIDEO_SIZE_CIF_W; + gint height = VIDEO_SIZE_CIF_H; + + /* creates the filters */ + stream->source = ms_filter_new_with_name(source); + if (stream->source == NULL){ + g_error("videostream.c: failed to create video source %s.", source); + return NULL; + } +#ifdef USE_SDL + stream->output=ms_sdl_out_new(); +#else + stream->output = ms_video_output_new (); +#endif + /* configure the filters */ + ms_video_source_set_device(MS_VIDEO_SOURCE(stream->source), device); + ms_video_source_set_size(MS_VIDEO_SOURCE(stream->source), width, height); + ms_video_source_set_frame_rate(MS_VIDEO_SOURCE(stream->source), 8, 1); + + ms_video_source_start(MS_VIDEO_SOURCE(stream->source)); + format = ms_video_source_get_format(MS_VIDEO_SOURCE(stream->source)); + +#ifdef USE_SDL + ms_sdl_out_set_format(MS_SDL_OUT(stream->output),format); +#else + ms_video_output_set_format(MS_VIDEO_OUTPUT(stream->output),format); + ms_video_output_set_size (MS_VIDEO_OUTPUT (stream->output), width, height); + ms_video_output_set_title(MS_VIDEO_OUTPUT(stream->output),"Linphone Video"); +#endif + /* and then connect all */ + ms_filter_add_link (stream->source, stream->output); + /* create the synchronisation source */ + stream->timer = ms_timer_new(); + ms_sync_attach (stream->timer, stream->source); + + /* and start */ + ms_start (stream->timer); + + return stream; +} + +void video_preview_stop(VideoStream *stream){ + ms_stop (stream->timer); + ms_video_source_stop (MS_VIDEO_SOURCE(stream->source)); + ms_sync_detach (stream->timer, stream->source); + ms_filter_remove_links(stream->source,stream->output); + video_stream_free(stream); +} + + +VideoStream * video_stream_send_only_start(RtpProfile *profile, int locport, char *remip, int remport, + int payload, const gchar *source, const gchar *device) +{ + VideoStream *stream = g_new0 (VideoStream, 1); + RtpSession *rtps, *rtpr; + PayloadType *pt; + gchar *format; + gint width = VIDEO_SIZE_CIF_W; + gint height = VIDEO_SIZE_CIF_H; + float fps; + + create_duplex_rtpsession(profile,locport,remip,remport,payload,40,&rtpr); + rtp_session_enable_adaptive_jitter_compensation(rtpr,FALSE); + rtps=rtpr; + ms_trace("sending video to %s:%i", remip4, remport); + + /* creates two rtp filters to recv send streams (remote part) */ + rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE); + stream->rtpsend = ms_rtp_send_new (); + if (remport>0) ms_rtp_send_set_session (MS_RTP_SEND (stream->rtpsend), rtps); + + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + g_error("videostream.c: undefined payload type."); + return NULL; + } + ms_trace("videostream.c: getting codecs for %s", pt->mime_type); + + /* creates the filters */ + stream->source = ms_filter_new_with_name(source); + if (stream->source == NULL){ + g_error("videostream.c: failed to create video source %s.", source); + return NULL; + } + + stream->encoder=ms_encoder_new_with_string_id(pt->mime_type); + g_message("Video encoder created: %x",stream->encoder); + if ((stream->encoder==NULL) ){ + /* big problem: we have not a registered codec for this payload...*/ + video_stream_free(stream); + g_error("videostream.c: No codecs available for payload %i.",payload); + return NULL; + } + + /* configure the filters */ + ms_video_source_set_device(MS_VIDEO_SOURCE(stream->source), device); + ms_video_source_set_size(MS_VIDEO_SOURCE(stream->source), width, height); + ms_video_source_set_frame_rate(MS_VIDEO_SOURCE(stream->source), 8, 1); + fps = MS_VIDEO_SOURCE(stream->source)->frame_rate / MS_VIDEO_SOURCE(stream->source)->frame_rate_base; + ms_video_source_start(MS_VIDEO_SOURCE(stream->source)); + format = ms_video_source_get_format(MS_VIDEO_SOURCE(stream->source)); + + ms_AVencoder_set_format (MS_AVENCODER (stream->encoder), format); + ms_AVencoder_set_width(MS_AVENCODER(stream->encoder), width); + ms_AVencoder_set_height(MS_AVENCODER(stream->encoder), height); + /* bitrate is based upon 30fps? adjust by our possibly lower framerate */ + /*ms_AVencoder_set_bit_rate(MS_AVENCODER(stream->encoder), pt->normal_bitrate * 30 / fps );*/ + + /* and then connect all */ + ms_filter_add_link (stream->source, stream->encoder); + ms_filter_add_link (stream->encoder, stream->rtpsend); + + /* create the synchronisation source */ + stream->timer = ms_timer_new(); + ms_sync_attach (stream->timer, stream->source); + + /* and start */ + ms_start (stream->timer); + return stream; +} + +void video_stream_send_only_stop(VideoStream *stream){ + ms_stop (stream->timer); + ms_video_source_stop (MS_VIDEO_SOURCE(stream->source)); + ms_sync_detach (stream->timer, stream->source); + + ms_filter_remove_links(stream->source,stream->encoder); + ms_filter_remove_links (stream->encoder, + stream->rtpsend); + + video_stream_free(stream); +} + +#endif diff --git a/linphone/mediastreamer/waveheader.h b/linphone/mediastreamer/waveheader.h new file mode 100644 index 000000000..405948d6f --- /dev/null +++ b/linphone/mediastreamer/waveheader.h @@ -0,0 +1,111 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* the following code was taken from a free software utility that I don't remember the name. */ +/* sorry */ + + + +#include "ms.h" +#ifndef waveheader_h +#define waveheader_h + +typedef struct uint16scheme +{ + unsigned char lo_byte; + unsigned char hi_byte; +} uint16scheme_t; + +typedef struct uint32scheme +{ + guint16 lo_int; + guint16 hi_int; +} uint32scheme_t; + + +/* all integer in wav header must be read in least endian order */ +inline guint16 _readuint16(guint16 a) +{ + guint16 res; + uint16scheme_t *tmp1=(uint16scheme_t*)&a; + + ((uint16scheme_t *)(&res))->lo_byte=tmp1->hi_byte; + ((uint16scheme_t *)(&res))->hi_byte=tmp1->lo_byte; + return res; +} + +inline guint32 _readuint32(guint32 a) +{ + guint32 res; + uint32scheme_t *tmp1=(uint32scheme_t*)&a; + + ((uint32scheme_t *)(&res))->lo_int=_readuint16(tmp1->hi_int); + ((uint32scheme_t *)(&res))->hi_int=_readuint16(tmp1->lo_int); + return res; +} + +#ifdef WORDS_BIGENDIAN +#define le_uint32(a) (_readuint32((a))) +#define le_uint16(a) (_readuint16((a))) +#define le_int16(a) ( (gint16) _readuint16((guint16)((a))) ) +#else +#define le_uint32(a) (a) +#define le_uint16(a) (a) +#define le_int16(a) (a) +#endif + +typedef struct _riff_t { + char riff[4] ; /* "RIFF" (ASCII characters) */ + guint32 len ; /* Length of package (binary, little endian) */ + char wave[4] ; /* "WAVE" (ASCII characters) */ +} riff_t; + +/* The FORMAT chunk */ + +typedef struct _format_t { + char fmt[4] ; /* "fmt_" (ASCII characters) */ + guint32 len ; /* length of FORMAT chunk (always 0x10) */ + guint16 que ; /* Always 0x01 */ + guint16 channel ; /* Channel numbers (0x01 = mono, 0x02 = stereo) */ + guint32 rate ; /* Sample rate (binary, in Hz) */ + guint32 bps ; /* Bytes Per Second */ + guint16 bpsmpl ; /* bytes per sample: 1 = 8 bit Mono, + 2 = 8 bit Stereo/16 bit Mono, + 4 = 16 bit Stereo */ + guint16 bitpspl ; /* bits per sample */ +} format_t; + +/* The DATA chunk */ + +typedef struct _data_t { + char data[4] ; /* "data" (ASCII characters) */ + int len ; /* length of data */ +} data_t; + +typedef struct _wave_header_t +{ + riff_t riff_chunk; + format_t format_chunk; + data_t data_chunk; +} wave_header_t; + +#define wave_header_get_rate(header) le_uint32((header)->format_chunk.rate) +#define wave_header_get_channel(header) le_uint16((header)->format_chunk.channel) + +#endif diff --git a/linphone/mediastreamer2/.cvsignore b/linphone/mediastreamer2/.cvsignore new file mode 100644 index 000000000..6be2672d9 --- /dev/null +++ b/linphone/mediastreamer2/.cvsignore @@ -0,0 +1,30 @@ +*.la +*.lo +.deps +.libs +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +intltool-extract +intltool-merge +intltool-update +libtool +ltmain.sh +mediastreamer-config.h +mediastreamer-config.h.in +mediastreamer.pc +mediastreamer2.spec +missing +mkinstalldirs +stamp-h1 diff --git a/linphone/mediastreamer2/.indent.pro b/linphone/mediastreamer2/.indent.pro new file mode 100644 index 000000000..0f9555875 --- /dev/null +++ b/linphone/mediastreamer2/.indent.pro @@ -0,0 +1,4 @@ +-kr +--use-tabs +--tab-size4 + diff --git a/linphone/mediastreamer2/AUTHORS b/linphone/mediastreamer2/AUTHORS new file mode 100644 index 000000000..ff6dbf174 --- /dev/null +++ b/linphone/mediastreamer2/AUTHORS @@ -0,0 +1 @@ +Simon MORLAT \ No newline at end of file diff --git a/linphone/mediastreamer2/COPYING b/linphone/mediastreamer2/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/linphone/mediastreamer2/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/linphone/mediastreamer2/ChangeLog b/linphone/mediastreamer2/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/mediastreamer2/INSTALL b/linphone/mediastreamer2/INSTALL new file mode 100644 index 000000000..23e5f25d0 --- /dev/null +++ b/linphone/mediastreamer2/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/linphone/mediastreamer2/Makefile.am b/linphone/mediastreamer2/Makefile.am new file mode 100644 index 000000000..fb246149b --- /dev/null +++ b/linphone/mediastreamer2/Makefile.am @@ -0,0 +1,54 @@ + +EXTRA_DIST=mediastreamer-config.h.in pkg.list autogen.sh mediastreamer.pc.in mediastreamer2.spec.in mediastreamer2.spec Makefile.macosx + +SUBDIRS=src build include tests help + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = mediastreamer.pc + +## oRTP packaging methods: + +# `make rpm' + +.phony: rpm + +rpm: + $(MAKE) dist +# + TAR_OPTIONS=--wildcards rpmbuild -ta --clean --rmsource --rmspec $(PACKAGE)-$(VERSION).tar.gz + +# `make package' + +if WITH_EPM + +.PHONY: package + +PKG_NAME = $(PACKAGE)-$(VERSION)-$(RELEASE) +BUILDROOT=`pwd`/epm-install + +package: $(srcdir)/pkg.list $(srcdir)/configure + [ -n "$(BUILDROOT)" ] && rm -rf $(BUILDROOT)/* + [ -n "$(PKG_NAME).*" ] && rm -f $(PKG_NAME).* + $(MAKE) install DESTDIR=$(BUILDROOT) + $(MKEPMLIST) -u $(SYS_USER) -g $(SYS_GROUP) --prefix $(prefix) \ + $(BUILDROOT)/$(prefix) > files.list + $(EPM) -v -f native -g -n -a $(ARCH) --keep-files --output-dir pkg \ + srcdir=$(srcdir) \ + top_srcdir=$(top_srcdir) \ + top_builddir=$(top_builddir) \ + PACKAGE=$(PACKAGE) \ + SUMMARY="$(SUMMARY)" \ + VERSION=$(ORTP_PKGCONFIG_VERSION) \ + RELEASE=$(RELEASE) \ + LICENSE="$(LICENSE)" \ + VENDOR="$(VENDOR)" \ + PACKAGER="$(PACKAGER)" \ + $(PACKAGE) $(srcdir)/pkg.list + rm -rf $(BUILDROOT) + mv -f pkg/$(PACKAGE)-$(ORTP_PKGCONFIG_VERSION)-$(RELEASE).$(EPM_PKG_EXT) $(PKG_NAME).$(ARCH).$(EPM_PKG_EXT) + +clean-local: + rm -rf pkg $(BUILDROOT) + rm -f files.list + +endif WITH_EPM diff --git a/linphone/mediastreamer2/Makefile.macosx b/linphone/mediastreamer2/Makefile.macosx new file mode 100644 index 000000000..bff389626 --- /dev/null +++ b/linphone/mediastreamer2/Makefile.macosx @@ -0,0 +1,76 @@ +# MacOS X Temporary make file +# H.M 2007.05.23 + +SPEEXDIR = ../../../speex-1.2beta1 +GSMDIR = ../../../gsm-1.0-pl12 +ORTPDIR = ../../oRTP + +INCPATH = -I../include -I$(ORTPDIR)/include -I$(SPEEXDIR)/include -I$(GSMDIR)/inc/ +LIBPATH = -L. -L../../../gsm-1.0-pl12/lib +FRAMEWORK = -framework CoreAudio -framework AudioToolbox -framework Carbon -framework AudioUnit +CFLUGS = -g $(INCPATH) -DWORDS_BIGENDIAN -DDEBUG +#CFLUGS = $(INCPATH) -DWORDS_BIGENDIAN + + +LIBOBJ = mscommon.o msqueue.o msfilerec.o msfilter.o msspeex.o mssndcard.o alaw.o ulaw.o msconf.o msjoin.o msrtp.o ice.o tee.o gsm.o speexec.o audiostream.o msticker.o macsnd.o msfileplayer.o +DYLIB = libms.dylib + +all: echo + +echo: ../tests/echo.c $(DYLIB) + cc -c $(CFLUGS) ../tests/echo.c + cc -o echo $(FRAMEWORK) $(LIBPATH) echo.o $(DYLIB) -lortp -lspeex -lgsm + +clean: + rm -rf *.o *.dylib + +$(DYLIB): $(LIBOBJ) libortp.dylib libspeex.dylib + cc -o $(DYLIB) $(FRAMEWORK) -dynamiclib -compatibility_version 1 -current_version 1 $(LIBOBJ) $(LIBPATH) -lortp -lspeex -lgsm + +libortp.dylib: + cp $(ORTPDIR)/src/.libs/libortp.dylib . + install_name_tool -id @executable_path/libortp.dylib libortp.dylib + +libspeex.dylib: + cp $(SPEEXDIR)/libspeex/.libs/libspeex.dylib . + install_name_tool -id @executable_path/libspeex.dylib libspeex.dylib + +msfileplayer.o: msfileplayer.c + gcc -c $(CFLUGS) msfileplayer.c +msticker.o: msticker.c + gcc -c $(CFLUGS) msticker.c +audiostream.o: audiostream.c + gcc -c $(CFLUGS) audiostream.c +speexec.o: speexec.c + gcc -c $(CFLUGS) speexec.c +gsm.o: gsm.c + gcc -c $(CFLUGS) gsm.c +tee.o: tee.c + gcc -c $(CFLUGS) tee.c +ice.o: ice.c + gcc -c $(CFLUGS) ice.c +msrtp.o: msrtp.c + gcc -c $(CFLUGS) msrtp.c +msjoin.o: msjoin.c + gcc -c $(CFLUGS) msjoin.c +msconf.o: msconf.c + gcc -c $(CFLUGS) msconf.c +msfilter.o: msfilter.c + gcc -c $(CFLUGS) msfilter.c +alaw.o: alaw.c + gcc -c $(CFLUGS) alaw.c +ulaw.o: ulaw.c + gcc -c $(CFLUGS) ulaw.c +msfilerec.o: msfilerec.c + gcc -c $(CFLUGS) msfilerec.c +msspeex.o: msspeex.c + gcc -c $(CFLUGS) msspeex.c +mssndcard.o: mssndcard.c + gcc -c $(CFLUGS) mssndcard.c +msqueue.o: msqueue.c + gcc -c $(CFLUGS) msqueue.c +macsnd.o: macsnd.c + gcc -c $(CFLUGS) macsnd.c + +mscommon.o: mscommon.c + gcc -c $(CFLUGS) -DPACKAGE_PLUGINS_DIR=\".\" mscommon.c diff --git a/linphone/mediastreamer2/NEWS b/linphone/mediastreamer2/NEWS new file mode 100644 index 000000000..fd52fd517 --- /dev/null +++ b/linphone/mediastreamer2/NEWS @@ -0,0 +1,23 @@ +mediastreamer-2.2.1: 25, january 2008 + * video output resizing + * 4CIF and VGA support + * bugfixes + * added snow codec (experimental) + * enable setting of max rtp payload size for all encoders + +mediastreamer-2.2.0: 19, November 2007 + * new "no webcam" screen + * bandwidth settings improvements + * new REQ_VFU command to request a video encoder to send an I-frame + (implemented for ffmpeg based encoders) + * contributed macosx sound support + * new MSVolume filter to make sound power measurements + * rate control of ffmpeg video codecs + +mediastreamer-2.1.0: 23, January 2007 + * add support for Video4Linux V2 cameras + * support for mpjeg cameras + * webcam support on windows operational + * video window display ok on windows + * fix bug with quickcam driver on linux + * bandwidth setting improvements. diff --git a/linphone/mediastreamer2/README b/linphone/mediastreamer2/README new file mode 100644 index 000000000..f76f4f53d --- /dev/null +++ b/linphone/mediastreamer2/README @@ -0,0 +1,94 @@ +Project : mediastreamer2 - a modular sound and video processing and streaming +Email : simon.morlat_at_linphone.org +License : GPL +Home Page : http://savannah.gnu.org/projects/linphone + +Mediastreamer2 is a GPL licensed library to make audio and +video real-time streaming and processing. Written in pure C, +it is based upon the ortp library. + +Design: +------ + +Using mediastreamer2 will allow you to chain filters in a graph. Each +filter will be responsible for doing some kind of processing and will +deliver data to the next filter. As an example, you could get some +data from network and unpack it in an RTP filter. This RTP filter will +deliver the data to a decoder (speex, G711...) which will deliver it +to a filter that is able to play the PCM data or record it into a .wav +file. + +There is a doxygen documentation for more information. + +Features: +-------- + +mediastreamer2 already provides a large set of filters. +Here is a complete list of built-in filters. + + All supported platforms: + * RTP receiver + * RTP sender + * tee (duplicate data) + + Audio Filters: + * audio capture + * audio playback + * mme API (windows) + * alsa API (linux) + * oss API (linux) + * arts API (linux) + * portaudio API (macosx and other) + * macsnd API (native macosx API -please do more testing...-) + * several audio encoder/decoder: PCMU, PCMA, speex, gsm + * wav file reader. + * wav file recorder. + * resampler. + * conference bridge. + * volume analyser. + * acoustic echo canceller. + * dtmf generation filter. + + Video Filters: + * video capture + * v4w API (windows) + * directshow API (windows) + * video4linux API (linux) + * video display + * v4w API (windows) + * SDL API (linux, macosx...) + * several audio encoder/decoder: H263-1998, MP4V-ES, theora + * image resizer. + * format converter. (RBG24, I420...) + + Plugin Filters: + * iLBC decoder/encoder. + +Note that, you can build your own components/filters to do your +own processing or support other codecs. + +Installation procedure: +----------------------- + +The program is known to run on linux, but might work +on any unix and windows systems. + + $> ./configure + $> make + $> su -c 'make install' + +Contact information: +-------------------- + +For more information on mediastreamer2, any contributions, or any remarks, +you can contact me at . Commercial licensing +is also provided through antisip (http://www.antisip.com or jack_at_atosc.org). + +Use the *linphone* mailing list for question about mediastreamer2. + . + +Subscribe by writing to: + with a subject set to "subscribe". + + + diff --git a/linphone/mediastreamer2/acinclude.m4 b/linphone/mediastreamer2/acinclude.m4 new file mode 100644 index 000000000..a2aa2feaf --- /dev/null +++ b/linphone/mediastreamer2/acinclude.m4 @@ -0,0 +1,121 @@ +dnl -*- autoconf -*- +AC_DEFUN([MS_CHECK_DEP],[ + dnl $1=dependency description + dnl $2=dependency short name, will be suffixed with _CFLAGS and _LIBS + dnl $3=headers's place + dnl $4=lib's place + dnl $5=header to check + dnl $6=lib to check + dnl $7=function to check in library + + dep_name=$2 + dep_headersdir=$3 + dep_libsdir=$4 + dep_header=$5 + dep_lib=$6 + dep_funclib=$7 + other_libs=$8 + + CPPFLAGS_save=$CPPFLAGS + LDFLAGS_save=$LDFLAGS + CPPFLAGS=`echo "-I$dep_headersdir"|sed -e "s:-I/usr/include[\ ]*$::"` + LIBS="-l$dep_lib" + LDFLAGS=`echo "-L$dep_libsdir"|sed -e "s:-L/usr/lib\(64\)*[\ ]*::"` + + $2_CFLAGS="$CPPFLAGS" + $2_LIBS="$LDFLAGS $LIBS" + + AC_CHECK_HEADERS([$dep_header],[AC_CHECK_LIB([$dep_lib],[$dep_funclib],found=yes,found=no, [$other_libs]) + ],found=no) + + if test "$found" = "yes" ; then + eval $2_found=yes + else + eval $2_found=no + eval $2_CFLAGS= + eval $2_LIBS= + fi + AC_SUBST($2_CFLAGS) + AC_SUBST($2_LIBS) + CPPFLAGS=$CPPFLAGS_save + LDFLAGS=$LDFLAGS_save +]) + + +AC_DEFUN([MS_CHECK_VIDEO],[ + + dnl conditionnal build of video support + AC_ARG_ENABLE(video, + [ --enable-video Turn on video support compiling], + [case "${enableval}" in + yes) video=true ;; + no) video=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;; + esac],[video=true]) + + AC_ARG_WITH( ffmpeg, + [ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ], + [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) + + AC_ARG_WITH( sdl, + [ --with-sdl Sets the installation prefix of libSDL, needed for video support. [default=/usr] ], + [ libsdldir=${withval}],[ libsdldir=/usr ]) + + if test "$video" = "true"; then + + dnl test for ffmpeg presence + PKG_CHECK_MODULES(FFMPEG, [libavcodec >= 50.0.0 ],ffmpeg_found=yes , ffmpeg_found=no) + dnl workaround for debian... + PKG_CHECK_MODULES(FFMPEG, [libavcodec >= 0d.50.0.0 ], ffmpeg_found=yes, ffmpeg_found=no) + if test x$ffmpeg_found = xno ; then + AC_MSG_ERROR([Could not find ffmpeg headers and library. This is mandatory for video support]) + fi + + dnl check for new/old ffmpeg header file layout + CPPFLAGS_save=$CPPFLAGS + CPPFLAGS=$FFMPEG_CFLAGS + AC_CHECK_HEADERS(libavcodec/avcodec.h) + CPPFLAGS=$CPPFLAGS_save + + dnl to workaround a bug on debian and ubuntu, check if libavcodec needs -lvorbisenc to compile + AC_CHECK_LIB(avcodec,avcodec_register_all, novorbis=yes , [ + LIBS="$LIBS -lvorbisenc" + ], $FFMPEG_LIBS ) + + dnl when swscale feature is not provided by + dnl libswscale, its features are swallowed by + dnl libavcodec, but without swscale.h and without any + dnl declaration into avcodec.h (this is to be + dnl considered as an ffmpeg bug). + dnl + dnl #if defined(HAVE_LIBAVCODEC_AVCODEC_H) && !defined(HAVE_LIBSWSCALE_SWSCALE_H) + dnl # include "swscale.h" // private linhone swscale.h + dnl #endif + CPPFLAGS_save=$CPPFLAGS + CPPFLAGS=$FFMPEG_CFLAGS + AC_CHECK_HEADERS(libswscale/swscale.h) + CPPFLAGS=$CPPFLAGS_save + + PKG_CHECK_MODULES(SWSCALE, [libswscale >= 0.5.0 ], [echo "We have libswscale"], + [echo "We don't have libswscale, let's hope its symbols are in libavcodec"] ) + + MS_CHECK_DEP([SDL],[SDL],[${libsdldir}/include],[${libsdldir}/lib],[SDL/SDL.h],[SDL],[SDL_Init]) + if test "$SDL_found" = "no" ; then + AC_MSG_ERROR([Could not find libsdl headers and library. This is mandatory for video support]) + fi + + PKG_CHECK_MODULES(THEORA, [theora >= 1.0alpha7 ], [have_theora=yes], + [have_theora=no]) + AC_CHECK_HEADERS(X11/Xlib.h) + + VIDEO_CFLAGS=" $FFMPEG_CFLAGS $SDL_CFLAGS -DVIDEO_ENABLED " + VIDEO_LIBS=" $FFMPEG_LIBS $SWSCALE_LIBS $SDL_LIBS" + + if test "${ac_cv_header_X11_Xlib_h}" = "yes" ; then + VIDEO_LIBS="$VIDEO_LIBS -lX11" + fi + fi + + AC_SUBST(VIDEO_CFLAGS) + AC_SUBST(VIDEO_LIBS) +]) diff --git a/linphone/mediastreamer2/autogen.sh b/linphone/mediastreamer2/autogen.sh new file mode 100755 index 000000000..d7d269423 --- /dev/null +++ b/linphone/mediastreamer2/autogen.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +AM_VERSION="1.9" +if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then + # automake-1.9 (recommended) is not available on Fedora 8 + AUTOMAKE=automake + ACLOCAL=aclocal +else + ACLOCAL=aclocal-${AM_VERSION} + AUTOMAKE=automake-${AM_VERSION} +fi + +echo "Generating build scripts in mediastreamer..." +set -x +libtoolize --copy --force +autoheader +$ACLOCAL +$AUTOMAKE --force-missing --add-missing --copy +autoconf diff --git a/linphone/mediastreamer2/build/.cvsignore b/linphone/mediastreamer2/build/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/mediastreamer2/build/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/mediastreamer2/build/Makefile.am b/linphone/mediastreamer2/build/Makefile.am new file mode 100755 index 000000000..4718144ae --- /dev/null +++ b/linphone/mediastreamer2/build/Makefile.am @@ -0,0 +1 @@ +SUBDIRS= win32native win32-novideo wince diff --git a/linphone/mediastreamer2/build/win32-novideo/.cvsignore b/linphone/mediastreamer2/build/win32-novideo/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/mediastreamer2/build/win32-novideo/Makefile.am b/linphone/mediastreamer2/build/win32-novideo/Makefile.am new file mode 100755 index 000000000..b8a8dc25a --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=alldescs.h mediastreamer2.vcproj mediastream.vcproj mediastreamer2.def + diff --git a/linphone/mediastreamer2/build/win32-novideo/alldescs.h b/linphone/mediastreamer2/build/win32-novideo/alldescs.h new file mode 100755 index 000000000..9f7534ac3 --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/alldescs.h @@ -0,0 +1,66 @@ +#include "mediastreamer2/msfilter.h" + +extern MSFilterDesc ms_alaw_dec_desc; +extern MSFilterDesc ms_alaw_enc_desc; +extern MSFilterDesc ms_ulaw_dec_desc; +extern MSFilterDesc ms_ulaw_enc_desc; +extern MSFilterDesc ms_file_player_desc; +extern MSFilterDesc ms_rtp_send_desc; +extern MSFilterDesc ms_rtp_recv_desc; +extern MSFilterDesc ms_dtmf_gen_desc; +extern MSFilterDesc ms_file_rec_desc; +extern MSFilterDesc ms_speex_dec_desc; +extern MSFilterDesc ms_speex_enc_desc; +extern MSFilterDesc ms_gsm_dec_desc; +extern MSFilterDesc ms_gsm_enc_desc; +extern MSFilterDesc ms_speex_ec_desc; +extern MSFilterDesc ms_tee_desc; +extern MSFilterDesc ms_conf_desc; +//extern MSFilterDesc alsa_write_desc; +//extern MSFilterDesc alsa_read_desc; +//extern MSFilterDesc oss_read_desc; +//extern MSFilterDesc oss_write_desc; +//extern MSFilterDesc ms_arts_read_desc; +//extern MSFilterDesc ms_arts_write_desc; +//extern MSFilterDesc ms_v4l_desc; +//extern MSFilterDesc ms_sdl_out_desc; +//extern MSFilterDesc ms_h263_enc_desc; +//extern MSFilterDesc ms_h263_dec_desc; +extern MSFilterDesc ms_join_desc; +extern MSFilterDesc ms_resample_desc; +extern MSFilterDesc ms_volume_desc; +MSFilterDesc * ms_filter_descs[]={ +&ms_alaw_dec_desc, +&ms_alaw_enc_desc, +&ms_ulaw_dec_desc, +&ms_ulaw_enc_desc, +&ms_file_player_desc, +&ms_rtp_send_desc, +&ms_rtp_recv_desc, +&ms_dtmf_gen_desc, +&ms_file_rec_desc, +&ms_speex_dec_desc, +&ms_speex_enc_desc, +&ms_gsm_dec_desc, +&ms_gsm_enc_desc, +&ms_speex_ec_desc, +&ms_tee_desc, +&ms_conf_desc, +//&alsa_write_desc, +//&alsa_read_desc, +//&oss_read_desc, +//&oss_write_desc, +//&ms_arts_read_desc, +//&ms_arts_write_desc, +//&ms_v4l_desc, +//&ms_sdl_out_desc, +//&ms_h263_enc_desc, +//&ms_h263_dec_desc, +&ms_join_desc, +#ifndef DISABLE_RESAMPLE +&ms_resample_desc, +#endif +&ms_volume_desc, +NULL +}; + diff --git a/linphone/mediastreamer2/build/win32-novideo/mediastream.dev b/linphone/mediastreamer2/build/win32-novideo/mediastream.dev new file mode 100755 index 000000000..111434f53 --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/mediastream.dev @@ -0,0 +1,59 @@ +[Project] +FileName=mediastream.dev +Name=mediastream +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DINET6 _@@_-DORTP_INET6 _@@_-DORTP_STATIC_@@_-D_WORKAROUND_MINGW32_BUGS_@@_-D_WIN32_WINNT=0x0501 _@@_-DDISABLE_RESAMPLE_@@_-Wall -Werror_@@_-g_@@_ +CppCompiler= +Linker=mediastreamer2.lib_@@_-lortp_@@_-lgsm_@@_-lspeex_@@_-lws2_32_@@_-liphlpapi_@@_-lwinmm_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=mediastream.exe +HostApplication= +Folders= +CommandLine=--local 8000 --remote 127.0.0.1:8000 --payload 0 +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\tests\mediastream.c +CompileCpp=0 +Folder=mediastream +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/linphone/mediastreamer2/build/win32-novideo/mediastream.vcproj b/linphone/mediastreamer2/build/win32-novideo/mediastream.vcproj new file mode 100755 index 000000000..b44c28431 --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/mediastream.vcproj @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def new file mode 100755 index 000000000..72fb5c03c --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def @@ -0,0 +1,70 @@ +LIBRARY mediastreamer2 + +EXPORTS + + ms_init + ms_exit + ms_reload_snd_card + + ms_filter_new + ms_filter_new_from_desc + ms_filter_destroy + ms_filter_create_encoder + ms_filter_create_decoder + ms_filter_call_method + ms_filter_call_method_noarg + ms_filter_link + ms_filter_unlink + ms_filter_preprocess + ms_filter_postprocess + ms_filter_register + ms_filter_codec_supported + + ms_snd_card_create_reader + ms_snd_card_create_writer + ms_snd_card_get_name + ms_snd_card_get_string_id + ms_snd_card_manager_get + ms_snd_card_manager_get_default_card + ms_snd_card_manager_get_card + ms_snd_card_manager_get_list + ms_snd_card_dup + ms_snd_card_destroy + + ms_ticker_new + ms_ticker_destroy + ms_ticker_attach + ms_ticker_detach + ms_ticker_set_time_func + ms_ticker_print_graphs + + ms_bufferizer_init + ms_bufferizer_uninit + ms_bufferizer_read + ms_bufferizer_put + ms_bufferizer_put_from_queue + + audio_stream_start + audio_stream_stop + audio_stream_free + create_duplex_rtpsession + + ms_load_plugins + ms_filter_set_notify_callback + + ms_sleep + ms_filter_new_from_name + + ms_queue_init + + ms_list_free + ms_list_for_each + ms_list_append + ms_list_remove + ms_filter_set_notify_callback + + ice_sound_send_stun_request + ice_process_stun_message + ms_discover_mtu + ms_set_mtu + \ No newline at end of file diff --git a/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.dev b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.dev new file mode 100755 index 000000000..5163f16b7 --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.dev @@ -0,0 +1,419 @@ +[Project] +FileName=mediastreamer2.dev +Name=mediastreamer2 +UnitCount=36 +Type=2 +Ver=1 +ObjFiles= +Includes=../../../oRTP/include;../../include;c:/Dev-Cpp/include/gsm;. +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DINET6 _@@_-DORTP_INET6 _@@_-D_WORKAROUND_MINGW32_BUGS_@@_-D_WIN32_WINNT=0x0501 _@@_-DWINSND_BUFLEN=512_@@_-DMAX_WAVEHDR=12_@@_-DDISABLE_RESAMPLE_@@_-Wall -Werror -g_@@_ +CppCompiler= +Linker=-lortp_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=mediastreamer2.lib +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=..\..\include\mediastreamer2\waveheader.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\..\include\mediastreamer2\allfilters.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\..\include\mediastreamer2\dtmfgen.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\..\include\mediastreamer2\ice.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\..\include\mediastreamer2\mediastream.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\include\mediastreamer2\mscommon.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\..\include\mediastreamer2\msfileplayer.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\..\include\mediastreamer2\msfilerec.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\include\mediastreamer2\msfilter.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\include\mediastreamer2\msqueue.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\..\include\mediastreamer2\msrtp.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\..\include\mediastreamer2\mssndcard.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\..\include\mediastreamer2\msticker.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\..\include\mediastreamer2\msv4l.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\..\include\mediastreamer2\msvideo.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\..\src\alaw.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\..\src\audiostream.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\..\src\dtmfgen.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\..\src\gsm.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\..\src\ice.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\..\src\mscommon.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\..\src\msconf.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\..\src\msfileplayer_win.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\..\src\msfilerec_win.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\..\src\msfilter.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\..\src\msqueue.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\..\src\msrtp.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\..\src\mssndcard.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\..\src\msspeex.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\..\src\msticker.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\..\src\speexec.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\..\src\tee.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\..\src\ulaw.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\..\src\msjoin.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\..\src\winsnd2.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=..\..\src\winsnd2.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit34] +FileName=alldescs.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.vcproj b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.vcproj new file mode 100755 index 000000000..68a99b15f --- /dev/null +++ b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.vcproj @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/mediastreamer2/build/win32native/.cvsignore b/linphone/mediastreamer2/build/win32native/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/mediastreamer2/build/win32native/Makefile.am b/linphone/mediastreamer2/build/win32native/Makefile.am new file mode 100755 index 000000000..9aed018f4 --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=alldescs.h mediastreamer2.vcproj mediastream.vcproj videodisplay.vcproj mediastreamer2.def + diff --git a/linphone/mediastreamer2/build/win32native/alldescs.h b/linphone/mediastreamer2/build/win32native/alldescs.h new file mode 100755 index 000000000..ba01dbfda --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/alldescs.h @@ -0,0 +1,90 @@ +#include "mediastreamer2/msfilter.h" + +extern MSFilterDesc ms_alaw_dec_desc; +extern MSFilterDesc ms_alaw_enc_desc; +extern MSFilterDesc ms_ulaw_dec_desc; +extern MSFilterDesc ms_ulaw_enc_desc; +extern MSFilterDesc ms_file_player_desc; +extern MSFilterDesc ms_rtp_send_desc; +extern MSFilterDesc ms_rtp_recv_desc; +extern MSFilterDesc ms_dtmf_gen_desc; +extern MSFilterDesc ms_file_rec_desc; +extern MSFilterDesc ms_speex_dec_desc; +extern MSFilterDesc ms_speex_enc_desc; +extern MSFilterDesc ms_gsm_dec_desc; +extern MSFilterDesc ms_gsm_enc_desc; +extern MSFilterDesc ms_speex_ec_desc; +extern MSFilterDesc ms_tee_desc; +extern MSFilterDesc ms_conf_desc; +//extern MSFilterDesc alsa_write_desc; +//extern MSFilterDesc alsa_read_desc; +//extern MSFilterDesc oss_read_desc; +//extern MSFilterDesc oss_write_desc; +//extern MSFilterDesc ms_arts_read_desc; +//extern MSFilterDesc ms_arts_write_desc; +extern MSFilterDesc ms_v4w_desc; +extern MSFilterDesc ms_video_out_desc; +extern MSFilterDesc ms_h263_enc_desc; +extern MSFilterDesc ms_h263_dec_desc; +extern MSFilterDesc ms_mpeg4_enc_desc; +extern MSFilterDesc ms_mpeg4_dec_desc; +extern MSFilterDesc ms_snow_enc_desc; +extern MSFilterDesc ms_snow_dec_desc; +extern MSFilterDesc ms_theora_enc_desc; +extern MSFilterDesc ms_theora_dec_desc; +//extern MSFilterDesc pasnd_read_desc; +//extern MSFilterDesc pasnd_write_desc; +extern MSFilterDesc ms_size_conv_desc; +extern MSFilterDesc ms_pix_conv_desc; +extern MSFilterDesc ms_join_desc; +extern MSFilterDesc ms_resample_desc; +extern MSFilterDesc ms_volume_desc; +extern MSFilterDesc ms_static_image_desc; +extern MSFilterDesc ms_mire_desc; +MSFilterDesc * ms_filter_descs[]={ +&ms_alaw_dec_desc, +&ms_alaw_enc_desc, +&ms_ulaw_dec_desc, +&ms_ulaw_enc_desc, +&ms_file_player_desc, +&ms_rtp_send_desc, +&ms_rtp_recv_desc, +&ms_dtmf_gen_desc, +&ms_file_rec_desc, +&ms_speex_dec_desc, +&ms_speex_enc_desc, +&ms_gsm_dec_desc, +&ms_gsm_enc_desc, +&ms_speex_ec_desc, +&ms_tee_desc, +&ms_conf_desc, +//&alsa_write_desc, +//&alsa_read_desc, +//&oss_read_desc, +//&oss_write_desc, +//&ms_arts_read_desc, +//&ms_arts_write_desc, +&ms_v4w_desc, +&ms_video_out_desc, +&ms_h263_enc_desc, +&ms_h263_dec_desc, +&ms_mpeg4_enc_desc, +&ms_mpeg4_dec_desc, +&ms_snow_enc_desc, +&ms_snow_dec_desc, +&ms_theora_enc_desc, +&ms_theora_dec_desc, +//&pasnd_read_desc, +//&pasnd_write_desc, +&ms_size_conv_desc, +&ms_pix_conv_desc, +&ms_join_desc, +#ifndef NORESAMPLE +&ms_resample_desc, +#endif +&ms_volume_desc, +&ms_static_image_desc, +&ms_mire_desc, +NULL +}; + diff --git a/linphone/mediastreamer2/build/win32native/mediastream.dev b/linphone/mediastreamer2/build/win32native/mediastream.dev new file mode 100755 index 000000000..30a4e63ed --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/mediastream.dev @@ -0,0 +1,72 @@ +[Project] +FileName=mediastream.dev +Name=mediastream +UnitCount=1 +Type=1 +Ver=3 +IsCpp=1 +Folders= +CommandLine=--local 8000 --remote 127.0.0.1:8000 --payload 0 +CompilerSettings=0000000000000000000000 +PchHead=-1 +PchSource=-1 +ProfilesCount=1 +ProfileIndex=0 + +[Unit1] +FileName=..\..\tests\mediastream.c +CompileCpp=0 +Folder=mediastream +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 + +[Profile1] +ProfileName=Default Profile +Type=1 +ObjFiles= +Includes=../../include;../../../oRTP/include +Libs=../../../oRTP/build/win32native;../../../../linphone-deps/lib +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DINET6 _@@_-DORTP_INET6 _@@_-DORTP_STATIC_@@_-D_WORKAROUND_MINGW32_BUGS_@@_-D_WIN32_WINNT=0x0501 _@@_-DDISABLE_RESAMPLE_@@_-DVIDEO_ENABLED_@@_-Wall -Werror_@@_-g_@@_ +CppCompiler= +Linker=libmediastreamer2.a_@@_-lortp_@@_-lgsm_@@_-lspeex_@@_-lws2_32_@@_-liphlpapi_@@_-lwinmm_@@_-lavcodec_@@_-lavutil_@@_-ltheora_@@_-logg_@@_-lvfw32_@@__@@_ +PreprocDefines= +CompilerSettings=0000000000000000000000 +Icon= +ExeOutput= +ObjectOutput=Default Profile +OverrideOutput=0 +OverrideOutputName=mediastream.exe +HostApplication= +CommandLine=--local 8000 --remote 127.0.0.1:8000 --payload 0 +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + diff --git a/linphone/mediastreamer2/build/win32native/mediastream.vcproj b/linphone/mediastreamer2/build/win32native/mediastream.vcproj new file mode 100755 index 000000000..1dd3ec7b0 --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/mediastream.vcproj @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/mediastreamer2/build/win32native/mediastreamer2.def b/linphone/mediastreamer2/build/win32native/mediastreamer2.def new file mode 100755 index 000000000..9fe06c1b1 --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/mediastreamer2.def @@ -0,0 +1,99 @@ +LIBRARY mediastreamer2 + +EXPORTS + + ms_init + ms_exit + ms_reload_snd_card + + ms_filter_new + ms_filter_new_from_desc + ms_filter_destroy + ms_filter_create_encoder + ms_filter_create_decoder + ms_filter_call_method + ms_filter_call_method_noarg + ms_filter_link + ms_filter_unlink + ms_filter_preprocess + ms_filter_postprocess + ms_filter_codec_supported + + ms_snd_card_create_reader + ms_snd_card_create_writer + ms_snd_card_get_name + ms_snd_card_get_string_id + ms_snd_card_manager_get + ms_snd_card_manager_get_default_card + ms_snd_card_manager_get_card + ms_snd_card_manager_get_list + ms_snd_card_dup + ms_snd_card_destroy + + ms_ticker_new + ms_ticker_destroy + ms_ticker_attach + ms_ticker_detach + ms_ticker_set_time_func + ms_filter_register + ms_ticker_print_graphs + + ms_bufferizer_init + ms_bufferizer_uninit + ms_bufferizer_read + ms_bufferizer_put + ms_bufferizer_put_from_queue + + audio_stream_start + audio_stream_stop + audio_stream_free + create_duplex_rtpsession + + ms_load_plugins + + ms_display_new + ms_display_set_window_id + ms_display_destroy + + video_preview_stop + video_preview_start + video_stream_new + video_stream_start + video_stream_stop + + ms_is_ipv6 + + ms_queue_flush + + yuv_buf_alloc + yuv_buf_init_from_mblk + yuv_buf_init_from_mblk_with_size + + ms_sleep + ms_filter_new_from_name + + ms_queue_init + + rfc3984_init + rfc3984_uninit + rfc3984_pack + rfc3984_unpack + rfc3984_set_mode + + ms_list_free + ms_list_for_each + ms_list_append + ms_list_remove + ms_filter_set_notify_callback + + ice_sound_send_stun_request + ice_process_stun_message + + ms_web_cam_manager_get_default_cam + ms_web_cam_manager_get + + video_stream_iterate + ms_discover_mtu + ms_set_mtu + + \ No newline at end of file diff --git a/linphone/mediastreamer2/build/win32native/mediastreamer2.dev b/linphone/mediastreamer2/build/win32native/mediastreamer2.dev new file mode 100755 index 000000000..ce8a0df85 --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/mediastreamer2.dev @@ -0,0 +1,603 @@ +[Project] +FileName=mediastreamer2.dev +Name=mediastreamer2 +UnitCount=54 +Type=2 +Ver=3 +IsCpp=1 +Folders= +CommandLine= +CompilerSettings=0000000000100000000000 +PchHead=-1 +PchSource=-1 +ProfilesCount=1 +ProfileIndex=0 + +[Unit1] +FileName=..\..\include\mediastreamer2\waveheader.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\..\include\mediastreamer2\allfilters.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\..\include\mediastreamer2\dtmfgen.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\..\include\mediastreamer2\ice.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\..\include\mediastreamer2\mediastream.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\include\mediastreamer2\mscommon.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\..\include\mediastreamer2\msfileplayer.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\..\include\mediastreamer2\msfilerec.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\include\mediastreamer2\msfilter.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\include\mediastreamer2\msqueue.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\..\include\mediastreamer2\msrtp.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\..\include\mediastreamer2\mssndcard.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\..\include\mediastreamer2\msticker.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\..\include\mediastreamer2\msv4l.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\..\include\mediastreamer2\msvideo.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\..\src\alaw.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\..\src\audiostream.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\..\src\dtmfgen.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\..\src\gsm.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\..\src\ice.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\..\src\mscommon.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\..\src\msconf.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\..\src\msfileplayer_win.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\..\src\msfilerec_win.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\..\src\msfilter.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\..\src\msqueue.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\..\src\msrtp.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\..\src\mssndcard.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\..\src\msspeex.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\..\src\msticker.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\..\src\speexec.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\..\src\tee.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\..\src\ulaw.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\..\src\msjoin.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\..\src\pixconv.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=..\..\src\rfc2429.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 +UnitCount=48 + +[Unit34] +FileName=alldescs.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\..\src\sizeconv.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\..\src\videodec.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\..\src\videoenc.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit41] +FileName=..\..\src\videoout.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit42] +FileName=..\..\src\winsnd2.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit43] +FileName=..\..\src\videostream.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit44] +FileName=..\..\src\winvideo.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit45] +FileName=..\..\src\vfw-missing.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit46] +FileName=..\..\src\theora.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit47] +FileName=..\..\include\mediastreamer2\msvideoout.h +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Profile1] +ProfileName=Default Profile +Type=3 +ObjFiles= +Includes=../../../oRTP/include;../../include;c:/Dev-Cpp/include/gsm;.;../../../../linphone-deps/include +Libs=../../../../linphone-deps/lib;../../../oRTP/build/win32native +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-ggdb_@@_-DINET6 _@@_-DORTP_INET6 _@@_-D_WORKAROUND_MINGW32_BUGS_@@_-D_WIN32_WINNT=0x0501 _@@_-DNOSDL_@@_-DVIDEO_ENABLED_@@_-DNORESAMPLE_@@_-Wall _@@_-DHAVE_LIBAVCODEC_AVCODEC_H_@@_ +CppCompiler= +Linker=-lortp_@@_-lavcodec_@@_-lavutil_@@_-ltheora_@@_-lspeex_@@_-lgsm_@@_-lws2_32_@@_-lwinmm_@@_-lvfw32_@@_-logg_@@__@@_ +PreprocDefines= +CompilerSettings=0000000000010000000000 +Icon= +ExeOutput=..\WIN32N~1 +ObjectOutput=Default Profile +OverrideOutput=0 +OverrideOutputName=libmediastreamer2.a +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + +[Unit48] +FileName=..\..\src\nowebcam.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c nowebcam.c -o "Default Profile/nowebcam.o" $(CFLAGS) + +[Unit49] +FileName=..\..\src\msvolume.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c msvolume.c -o "Default Profile/msvolume.o" $(CFLAGS) + +[Unit50] +FileName=..\..\src\msvideo.c +CompileCpp=1 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit51] +FileName=..\..\src\mswebcam.c +CompileCpp=1 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit52] +FileName=..\..\src\mire.c +CompileCpp=1 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit53] +FileName=..\..\src\mtu.c +CompileCpp=0 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c mtu.c -o "Default Profile/mtu.o" $(CFLAGS) + +[Unit54] +FileName=..\..\src\rfc3984.c +CompileCpp=1 +Folder=mediastreamer2 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/linphone/mediastreamer2/build/win32native/mediastreamer2.vcproj b/linphone/mediastreamer2/build/win32native/mediastreamer2.vcproj new file mode 100755 index 000000000..45c369001 --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/mediastreamer2.vcproj @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/mediastreamer2/build/win32native/videodisplay.vcproj b/linphone/mediastreamer2/build/win32native/videodisplay.vcproj new file mode 100755 index 000000000..8e764601d --- /dev/null +++ b/linphone/mediastreamer2/build/win32native/videodisplay.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/mediastreamer2/build/wince/.cvsignore b/linphone/mediastreamer2/build/wince/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/mediastreamer2/build/wince/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/mediastreamer2/build/wince/Makefile.am b/linphone/mediastreamer2/build/wince/Makefile.am new file mode 100755 index 000000000..07d97c86e --- /dev/null +++ b/linphone/mediastreamer2/build/wince/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=alldescs.h mediastreamer2.vcproj mediastreamer2.def + diff --git a/linphone/mediastreamer2/build/wince/alldescs.h b/linphone/mediastreamer2/build/wince/alldescs.h new file mode 100644 index 000000000..380326fa1 --- /dev/null +++ b/linphone/mediastreamer2/build/wince/alldescs.h @@ -0,0 +1,62 @@ +#include "mediastreamer2/msfilter.h" + +extern MSFilterDesc ms_alaw_dec_desc; +extern MSFilterDesc ms_alaw_enc_desc; +extern MSFilterDesc ms_ulaw_dec_desc; +extern MSFilterDesc ms_ulaw_enc_desc; +extern MSFilterDesc ms_file_player_desc; +extern MSFilterDesc ms_rtp_send_desc; +extern MSFilterDesc ms_rtp_recv_desc; +extern MSFilterDesc ms_dtmf_gen_desc; +extern MSFilterDesc ms_file_rec_desc; +extern MSFilterDesc ms_speex_dec_desc; +extern MSFilterDesc ms_speex_enc_desc; +//extern MSFilterDesc ms_gsm_dec_desc; +//extern MSFilterDesc ms_gsm_enc_desc; +extern MSFilterDesc ms_speex_ec_desc; +extern MSFilterDesc ms_tee_desc; +extern MSFilterDesc ms_conf_desc; +//extern MSFilterDesc alsa_write_desc; +//extern MSFilterDesc alsa_read_desc; +//extern MSFilterDesc oss_read_desc; +//extern MSFilterDesc oss_write_desc; +//extern MSFilterDesc ms_arts_read_desc; +//extern MSFilterDesc ms_arts_write_desc; +//extern MSFilterDesc ms_v4l_desc; +extern MSFilterDesc ms_v4w_desc; +//extern MSFilterDesc ms_sdl_out_desc; +//extern MSFilterDesc ms_h263_enc_desc; +//extern MSFilterDesc ms_h263_dec_desc; +extern MSFilterDesc ms_join_desc; +MSFilterDesc * ms_filter_descs[]={ +&ms_alaw_dec_desc, +&ms_alaw_enc_desc, +&ms_ulaw_dec_desc, +&ms_ulaw_enc_desc, +&ms_file_player_desc, +&ms_rtp_send_desc, +&ms_rtp_recv_desc, +&ms_dtmf_gen_desc, +&ms_file_rec_desc, +&ms_speex_dec_desc, +&ms_speex_enc_desc, +//&ms_gsm_dec_desc, +//&ms_gsm_enc_desc, +&ms_speex_ec_desc, +&ms_tee_desc, +&ms_conf_desc, +//&alsa_write_desc, +//&alsa_read_desc, +//&oss_read_desc, +//&oss_write_desc, +//&ms_arts_read_desc, +//&ms_arts_write_desc, +//&ms_v4l_desc, +&ms_v4w_desc, +//&ms_sdl_out_desc, +//&ms_h263_enc_desc, +//&ms_h263_dec_desc, +&ms_join_desc, +NULL +}; + diff --git a/linphone/mediastreamer2/build/wince/mediastreamer2.def b/linphone/mediastreamer2/build/wince/mediastreamer2.def new file mode 100644 index 000000000..4d9606b0a --- /dev/null +++ b/linphone/mediastreamer2/build/wince/mediastreamer2.def @@ -0,0 +1,52 @@ +LIBRARY mediastreamer2 + +EXPORTS + + ms_init + ms_exit + ms_reload_snd_card + + ms_filter_new + ms_filter_new_from_desc + ms_filter_destroy + ms_filter_create_encoder + ms_filter_create_decoder + ms_filter_call_method + ms_filter_call_method_noarg + ms_filter_link + ms_filter_unlink + ms_filter_preprocess + ms_filter_postprocess + ms_filter_register + ms_filter_codec_supported + + ms_snd_card_create_reader + ms_snd_card_create_writer + ms_snd_card_get_name + ms_snd_card_get_string_id + ms_snd_card_manager_get + ms_snd_card_manager_get_default_card + ms_snd_card_manager_get_card + ms_snd_card_manager_get_list + ms_snd_card_dup + ms_snd_card_destroy + + ms_ticker_new + ms_ticker_destroy + ms_ticker_attach + ms_ticker_detach + ms_ticker_set_time_func + ms_ticker_print_graphs + + + ms_bufferizer_init + ms_bufferizer_uninit + ms_bufferizer_read + ms_bufferizer_put + ms_bufferizer_put_from_queue + + ms_load_plugins + + audio_stream_start + ms_discover_mtu + ms_set_mtu diff --git a/linphone/mediastreamer2/build/wince/mediastreamer2.vcproj b/linphone/mediastreamer2/build/wince/mediastreamer2.vcproj new file mode 100644 index 000000000..7bfb50013 --- /dev/null +++ b/linphone/mediastreamer2/build/wince/mediastreamer2.vcproj @@ -0,0 +1,1017 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/mediastreamer2/configure.ac b/linphone/mediastreamer2/configure.ac new file mode 100644 index 000000000..ccc8b1248 --- /dev/null +++ b/linphone/mediastreamer2/configure.ac @@ -0,0 +1,482 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([mediastreamer],[2.2.0]) + +AC_MSG_NOTICE([$PACKAGE_NAME-$PACKAGE_VERSION A mediastreaming library for telephony application.]) +AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)]) + +AC_CANONICAL_SYSTEM + +dnl Source packaging numbers +MEDIASTREAMER_MAJOR_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f1) +MEDIASTREAMER_MINOR_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f2) +MEDIASTREAMER_MICRO_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f3) +MEDIASTREAMER_EXTRA_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f4) + +LIBMEDIASTREAMER_SO_CURRENT=0 dnl increment this number when you add/change/remove an interface +LIBMEDIASTREAMER_SO_REVISION=1 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT +LIBMEDIASTREAMER_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface + +LIBMEDIASTREAMER_SO_VERSION=$LIBMEDIASTREAMER_SO_CURRENT:$LIBMEDIASTREAMER_SO_REVISION:$LIBMEDIASTREAMER_SO_AGE +MEDIASTREAMER_VERSION=${MEDIASTREAMER_MAJOR_VERSION}.${MEDIASTREAMER_MINOR_VERSION}.${MEDIASTREAMER_MICRO_VERSION} + +if test -n "$MEDIASTREAMER_EXTRA_VERSION" ; then + MEDIASTREAMER_VERSION="${MEDIASTREAMER_VERSION}.${MEDIASTREAMER_EXTRA_VERSION}" +fi + +AC_SUBST(LIBMEDIASTREAMER_SO_VERSION) +AC_SUBST(MEDIASTREAMER_VERSION) + +PACKAGE=mediastreamer + +OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` +AC_MSG_RESULT([Building Package on ${OS}]) + +AM_INIT_AUTOMAKE([tar-ustar]) +AC_CONFIG_HEADERS(mediastreamer-config.h) +AC_DEFINE_UNQUOTED(MEDIASTREAMER_MAJOR_VERSION,$MEDIASTREAMER_MAJOR_VERSION, [major version]) +AC_DEFINE_UNQUOTED(MEDIASTREAMER_MINOR_VERSION,$MEDIASTREAMER_MINOR_VERSION, [minor version]) +AC_DEFINE_UNQUOTED(MEDIASTREAMER_MICRO_VERSION,$MEDIASTREAMER_MICRO_VERSION, [micro version]) +AC_DEFINE_UNQUOTED(MEDIASTREAMER_VERSION,"$MEDIASTREAMER_VERSION",[MEDIASTREAMER version number]) + +AC_SUBST([mkdir_p]) + +AC_MSG_CHECKING([warning make an error on compilation]) +AC_ARG_ENABLE(strict, +[ --enable-strict Enable error on compilation warning [default=no]], +[wall_werror=$enableval], +[wall_werror=no] +) + +CFLAGS="-DORTP_INET6 $CFLAGS " + +dnl enable ipv6 support +AC_ARG_ENABLE(ipv6, + [ --enable-ipv6 Turn on ipv6 support], + [case "${enableval}" in + yes) ipv6=true;; + no) ipv6=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ipv6) ;; + esac],[ipv6=true]) +if test x$ipv6 = xtrue ; then + CFLAGS="$CFLAGS -DINET6" +fi + + +AC_ARG_ENABLE(debug, + [ --enable-debug=[yes/no] enables the display of traces showing the execution of the library. [default=yes]], + [case "${enableval}" in + yes) debug_enabled=yes;; + no) debug_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-debug");; + esac], + [debug_enabled=no] ) + + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) + +if test "$GCC" != "yes" ; then + case $target_os in + *hpux*) + dnl we are probably using HPUX cc compiler, so add a +O2 to CFLAGS + CFLAGS="$CFLAGS +O2 -g " + ;; + esac +else + CFLAGS="$CFLAGS -Wall" +fi + + + +if test $debug_enabled = "yes"; then + CFLAGS="$CFLAGS -g -DDEBUG" +else + CFLAGS="$CFLAGS -O2 -g " +fi + +dnl Checks for header files. +AC_HEADER_STDC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_HEADER_TIME +AC_WORDS_BIGENDIAN +if test x$ac_cv_c_bigendian = xyes ; then + CFLAGS="$CFLAGS -D_BIGENDIAN " +fi + +if test $GCC = yes && test $wall_werror = yes; then + CFLAGS="$CFLAGS -Werror " +fi + +macosx_found=no + +dnl add thread flags +case $OS in + darwin*) + MSPLUGINS_CFLAGS="" + MSPLUGINS_LIBS="-dynamiclib" + macosx_found=yes + ;; + *) + MSPLUGINS_CFLAGS="-pthread" + MSPLUGINS_LIBS="-shared -pthread" + CFLAGS="$CFLAGS -pthread -D_REENTRANT" + LIBS="$LIBS -pthread -lpthread" + ;; +esac + +AM_CONDITIONAL(BUILD_MACOSX, test x$macosx_found = xyes) + +AC_SUBST(MSPLUGINS_CFLAGS) +AC_SUBST(MSPLUGINS_LIBS) + +AC_CHECK_LIB(rt,clock_gettime,[LIBS="$LIBS -lrt"]) + +dnl ********************************* +dnl various checks for soundcard apis +dnl ********************************* + +found_sound=no + +AC_CHECK_HEADERS(soundcard.h sys/soundcard.h machine/soundcard.h sys/audio.h) +if test "${ac_cv_header_sys_soundcard_h}" = "yes" || \ + test "${ac_cv_header_soundcard_h}" = "yes" || \ + test "${ac_cv_header_sys_audio_h}" = "yes" || \ + test "${ac_cv_header_machine_soundcard_h}" = "yes"; then + found_sound=yes +fi + +AM_CONDITIONAL(BUILD_OSS, test x$found_sound = xyes) + +dnl conditionnal build of ALSA support +AC_ARG_ENABLE(alsa, + [ --enable-alsa Turn on alsa native support compiling], + [case "${enableval}" in + yes) alsa=true ;; + no) alsa=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsa) ;; + esac],[alsa=true]) + +if test "$alsa" = "true"; then + AC_CHECK_HEADERS(alsa/asoundlib.h, + [ AC_CHECK_LIB(asound,snd_pcm_open, + [ ALSA_LIBS="-lasound" + found_sound=yes + AC_DEFINE(__ALSA_ENABLED__,1,[defined if alsa support is available]) + alsa_enabled=true + ]) + ] + ) +fi +AC_SUBST(ALSA_LIBS) + +AM_CONDITIONAL(BUILD_ALSA, test x$alsa_enabled = xtrue) + + +AC_ARG_ENABLE(artsc, + [ --enable-artsc Turn on artsc (kde) sound input/output (auto) ], + [case "${enableval}" in + yes) artsc=true ;; + no) artsc=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-artsc) ;; + esac],[artsc=true]) + +arts_enabled=false + +if test "$artsc" = "true" ; then + + dnl check for arts (kde sound daemon) support + PKG_CHECK_MODULES(ARTS, [artsc],[ + dnl New detection + arts_enabled=true + ],[ + dnl Old detection + if test x$artsc = xtrue ; then + AC_CHECK_HEADERS(kde/artsc/artsc.h, + [ AC_CHECK_LIB(artsc,arts_init, + [ ARTS_LIBS="-lartsc" + arts_enabled=true + ]) + ] + ) + fi + AC_SUBST(ARTS_LIBS) + ]) +fi + +if test x$arts_enabled = xtrue; then + found_sound=yes + AC_DEFINE(__ARTS_ENABLED__,1,[defined if arts support is available]) +fi + +AM_CONDITIONAL(BUILD_ARTS, test x$arts_enabled = xtrue) + +AC_ARG_ENABLE(portaudio, + [ --enable-portaudio Turn on portaudio native support compiling], + [case "${enableval}" in + yes) portaudio=true ;; + no) portaudio=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;; + esac],[portaudio=false]) + +if test "$portaudio" = "true"; then + AC_CHECK_HEADERS(portaudio.h, + [ AC_CHECK_LIB(portaudio,Pa_Initialize, + [ PORTAUDIO_LIBS="-lportaudio" + found_sound=yes + AC_DEFINE(__PORTAUDIO_ENABLED__,1,[defined if portaudio support is available]) + portaudio_enabled=true + ]) + ] + ) +fi + +AC_SUBST(PORTAUDIO_LIBS) +AM_CONDITIONAL(BUILD_PORTAUDIO, test x$portaudio_enabled = xtrue) + +AC_ARG_ENABLE(macsnd, + [ --enable-macsnd Turn on native macosx sound support], + [case "${enableval}" in + yes) macsnd=true ;; + no) macsnd=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-macsnd) ;; + esac],[macsnd=false]) + +if test "$macsnd" = "true"; then + AC_DEFINE(__MACSND_ENABLED__,1,[defined if native macosx sound support is available]) + macsnd_enabled=true + found_sound=yes +fi + +AM_CONDITIONAL(BUILD_MACSND, test x$macsnd_enabled = xtrue) + +AC_ARG_ENABLE(macaqsnd, + [ --enable-macaqsnd Turn on native macosx Audio Queue sound support], + [case "${enableval}" in + yes) macaqsnd=true ;; + no) macaqsnd=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-macaqsnd) ;; + esac],[macaqsnd=false]) + +if test "$macsnd" = "true"; then + AC_DEFINE(__MAC_AQ_ENABLED__,1,[defined if native macosx AQ sound support is available]) + macaqsnd_enabled=true + found_sound=yes +fi + +AM_CONDITIONAL(BUILD_MACAQSND, test x$macaqsnd_enabled = xtrue) + +dnl Check for samplerate libraries +dnl Check for jack libraries (sound output plugin) +PKG_CHECK_MODULES(JACK,jack >= 0.15.0, +[ + dnl we' found jack devel files + PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.0.13, + [AC_DEFINE(__JACK_ENABLED__,1,[Jack support]) + found_sound=yes + jack_found=yes] , + [echo "libsamplerate not found, jack support disabled."]) + AC_SUBST(SAMPLERATE_CFLAGS) + AC_SUBST(SAMPLERATE_LIBS) +], +[echo "No jack support."] ) + +if test x$jack_found = xno ; then + dnl reset flags + JACK_CFLAGS= + JACK_LIBS= + SAMPLERATE_CFLAGS= + SAMPLERATE_LIBS= +fi + +AC_SUBST(JACK_CFLAGS) +AC_SUBST(JACK_LIBS) + +if test "$found_sound" = "no"; then + AC_MSG_ERROR([Could not find a support sound driver API]) +fi + + +dnl ************************************* +dnl check for various codecs libraries +dnl ************************************* + +dnl check for installed version of speex +PKG_CHECK_MODULES(SPEEX, speex >= 1.1.12, + [ AC_DEFINE(HAVE_SPEEX_NOISE,1,[tells whether the noise arg of speex_echo_cancel can be used]) ], + [try_other_speex=yes] +) +PKG_CHECK_MODULES(SPEEX, speex >= 1.1.6, build_speex=yes) +PKG_CHECK_MODULES(SPEEXDSP, speexdsp >= 1.2beta3, + [SPEEX_LIBS="$SPEEX_LIBS $SPEEXDSP_LIBS"], [ + AC_MSG_NOTICE([No speexdsp library found.]) +] +) +AC_SUBST(SPEEX_CFLAGS) +AC_SUBST(SPEEX_LIBS) +AM_CONDITIONAL(BUILD_SPEEX, test x$build_speex = xyes ) + +dnl check for gsm +build_gsm=no +AC_ARG_WITH( gsm, + [ --with-gsm Sets the installation prefix of gsm codec library [default=/usr] ], + [ gsmdir=${withval}],[ gsmdir=/usr ]) + +if test x"$gsmdir" != xno ; then + test x"$gmsdir" = xyes && gsmdir=/usr + MS_CHECK_DEP([gsm codec],[GSM],[${gsmdir}/include], + [${gsmdir}/lib],[gsm/gsm.h],[gsm],[gsm_create]) + if test "$GSM_found" = "yes" ; then + build_gsm=yes + fi +else + build_gsm=no +fi +AM_CONDITIONAL(BUILD_GSM, test x$build_gsm = xyes ) + +build_resample=false +AC_CHECK_LIB(resample,resample_open,[LIBS="$LIBS -lresample"; build_resample=yes]) +AM_CONDITIONAL(BUILD_RESAMPLE, test x$build_resample = xyes ) + +MS_CHECK_VIDEO +AM_CONDITIONAL(BUILD_VIDEO, test "$video" = "true") +AM_CONDITIONAL(BUILD_THEORA, test "$have_theora" = "yes") + +dnl ********************************************* +dnl setup oRTP dependency +dnl ********************************************* +AC_ARG_ENABLE(external-ortp, + [ --enable-external-ortp Use external oRTP library], + [case "${enableval}" in + yes) external_ortp=true ;; + no) external_ortp=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;; + esac],[external_ortp=false]) + +if test "$external_ortp" = 'false'; then + if test -e $srcdir/../oRTP/include/ortp/ortp.h ; then + echo "building from linphone source tree, using ../oRTP/include/ortp/ortp.h" + ORTP_CFLAGS="-I\$(top_srcdir)/../oRTP/include" + ORTP_LIBS="\$(top_builddir)/../oRTP/src/libortp.la" + if test x$ac_cv_c_bigendian = xyes ; then + ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN" + fi + else + external_ortp=true + fi +fi +if test "$external_ortp" = 'true'; then + PKG_CHECK_MODULES(ORTP, ortp >= 0.9.0, , + [ AC_MSG_ERROR([Couldn't find ortp library]) ] ) +fi +AC_SUBST(ORTP_CFLAGS) +AC_SUBST(ORTP_LIBS) + + +dnl check dlopen support in headers and libraries, so that we can use mediastreamer plugins +AC_CHECK_HEADERS(dlfcn.h) +have_dlopen=false +AC_CHECK_LIB(dl,dlopen,[LIBS="$LIBS -ldl"; have_dlopen=true]) +AC_CHECK_FUNC(dlopen,[have_dlopen=true]) +if test "$have_dlopen" = "true" ; then + AC_DEFINE(HAVE_DLOPEN,1,[Defined if dlopen() is availlable]) +fi + +dnl check various things +AC_FUNC_ALLOCA + +dnl define path of plugins: +PACKAGE_PLUGINS_DIR=`eval echo $prefix/lib/mediastreamer/plugins` +AC_DEFINE_UNQUOTED(PACKAGE_PLUGINS_DIR, "$PACKAGE_PLUGINS_DIR" ,[path of plugins]) +AC_SUBST(PACKAGE_PLUGINS_DIR) + +PACKAGE_DATA_DIR=`eval echo $prefix/share` +AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "$PACKAGE_DATA_DIR" ,[path of data]) +AC_SUBST(PACKAGE_DATA_DIR) + +dnl check for video4linux headers +AC_CHECK_HEADERS(linux/videodev.h linux/videodev2.h) + + +dnl ################################################## +dnl # Check for ESP Packager +dnl ################################################## + +AC_PATH_PROG(EPM,epm,false) +AC_PATH_PROG(MKEPMLIST,mkepmlist,false) +AC_PATH_PROG(EPMINSTALL,epminstall,false) +AM_CONDITIONAL(WITH_EPM,test $EPM != false && test $MKEPMLIST != false && test $EPMINSTALL != false) + + +# Preferred packaging system, as per EPM terminology +case $target in +*-*-linux*) + if test -f /etc/debian_version ; then + EPM_PKG_EXT=deb + else + EPM_PKG_EXT=rpm + fi + ;; +*-hp-hpux*) + EPM_PKG_EXT=depot.gz;; +*-dec-osf*) + EPM_PKG_EXT=setld;; +esac +AC_SUBST(EPM_PKG_EXT) + +# System software User & Group names +case $target in +*-*-linux*) + SYS_USER=root + SYS_GROUP=root + ;; +*-*-hpux*|*-dec-osf*) + SYS_USER=bin + SYS_GROUP=bin + ;; +esac +AC_SUBST(SYS_USER) +AC_SUBST(SYS_GROUP) + +# CPU Architecture +case $target_cpu in +i?86) ARCH=i386;; +*) ARCH=$target_cpu;; +esac +AC_SUBST(ARCH) + +# Various other packaging variables, that can be over-ridden ad `make +# package' time +SUMMARY="A mediastreaming library." +AC_SUBST(SUMMARY) +PACKAGER=anonymous +AC_SUBST(PACKAGER) +LICENSE=GPL +AC_SUBST(LICENSE) +VENDOR=Linphone +AC_SUBST(VENDOR) +RELEASE=1 +AC_SUBST(RELEASE) + + +AC_OUTPUT( +Makefile +include/Makefile +include/mediastreamer2/Makefile +src/Makefile +tests/Makefile +build/Makefile +build/win32native/Makefile +build/win32-novideo/Makefile +build/wince/Makefile +mediastreamer.pc +mediastreamer2.spec +help/Makefile +help/DoxyFile +help/doxygen.dox +) diff --git a/linphone/mediastreamer2/help/DoxyFile.in b/linphone/mediastreamer2/help/DoxyFile.in new file mode 100644 index 000000000..e14d2f4e4 --- /dev/null +++ b/linphone/mediastreamer2/help/DoxyFile.in @@ -0,0 +1,233 @@ +# Doxyfile 1.4.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = mediastreamer2 +PROJECT_NUMBER = @MEDIASTREAMER_VERSION@ +OUTPUT_DIRECTORY = help/doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = help/ \ + include/ +FILE_PATTERNS = *.h \ + *.c \ + *.dox +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = . +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 1 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = include/ +INCLUDE_FILE_PATTERNS = *.h +PREDEFINED = DOXYGEN +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/linphone/mediastreamer2/help/Makefile.am b/linphone/mediastreamer2/help/Makefile.am new file mode 100644 index 000000000..25e92d69d --- /dev/null +++ b/linphone/mediastreamer2/help/Makefile.am @@ -0,0 +1,4 @@ + +EXTRA_DIST = DoxyFile.in doxygen.dox.in + +all: DoxyFile doxygen.dox diff --git a/linphone/mediastreamer2/help/doxygen.dox.in b/linphone/mediastreamer2/help/doxygen.dox.in new file mode 100644 index 000000000..422876b86 --- /dev/null +++ b/linphone/mediastreamer2/help/doxygen.dox.in @@ -0,0 +1,187 @@ +/** + * @mainpage + * Project Website: http://savannah.gnu.org/projects/linphone + * + * @verbinclude README + * + */ + +/** + * @defgroup mediastreamer2 mediastreamer2 library - a modular sound and video processing and streaming + * @brief mediastreamer2 Version @MEDIASTREAMER_VERSION@ + * + * @see http://savannah.gnu.org/projects/linphone + * + * @section what_is_it What is mediastreamer2 + * + * mediastreamer2 is a powerful engine to make audio and video streams. + * mediastreamer2 is GPL (COPYING). Please understand the licencing details + * before using it! + * + * For any use of this library beyond the rights granted to you by the + * GPL license, please contact antisip at . + * + * @section definitions Some definitions. + * + * Filter: + * A filter is a mediastreamer2 component that process data. A filter + * have 0 or several INPUT pins and 0 or several OUTPUT pins. + * Here is a list of possible use of filters: + *
+ *   capture audio or video data.
+ *   play audio or display video data.
+ *   send or receive RTP data.
+ *   encode or decode audio or video data.
+ *   transform (resize video, resample audio...) data.
+ *   duplicate any kind of data.
+ *   mix audio/video data.
+ * 
+ * Graph: + * A graph is a manager of filters connected together. It will transfer + * data from OUTPUT pins to INPUT pins and will be responsible for + * running filters. + * + * @section when_do_i_use_mediastreamer2 How do I use mediastremer2? + * + * Mediastreamer2 can be used for a lot of different purpose. The primary + * use is to manage RTP audio and video session. You will need to use + * the API to build filters, link them together in a graph. Then the + * ticker API will help you to start and stop the graph. + * + * Basic graph sample: + * + *
+ *  AUDIO CAPTURE   -->   ENCODE  -->     RTP
+ *      FILTER      -->   FILTER  -->    FILTER
+ * 
+ * + * + * The above graph is composed of three filters. The first one has no input: + * tt captures audio data directly from the drivers and provide it to the + * OUTPUT pin. This data is sent to the INPUT pin of the encoder which of + * course encode the data and send it to its OUTPUT pin. This pin is connected + * to the INPUT pin of a filter capable to build and send RTP packets. + * + * The modular design helps you to encode in many different format just by + * replacing the "ENCODE FILTER" with another one. mediastreamer2 contains + * internal support for g711u, g711a, speex and gsm. You can add new encoding + * format by implementing new filters which can then be dynamically loaded. + * + * @section list_of_filters List of existing filters. + * + * mediastreamer2 already provides a large set of filters. Here is a complete + * list of built-in filters. + * + *
+ * All supported platforms:
+ *   RTP receiver
+ *   RTP sender
+ *   tee (duplicate data)
+ *
+ * Audio Filters:
+ *   audio capture
+ *   audio playback
+ *     mme API (windows)
+ *     alsa API (linux)
+ *     oss API (linux)
+ *     arts API (linux)
+ *     portaudio API (macosx and other)
+ *   macsnd API (native macosx API -please do more testing...-)
+ *   several audio encoder/decoder: PCMU, PCMA, speex, gsm
+ *   wav file reader.
+ *   wav file recorder.
+ *   resampler.
+ *   conference bridge.
+ *   volume analyser.
+ *   acoustic echo canceller.
+ *   dtmf generation filter.
+ *
+ * Video Filters:
+ *   video capture
+ *     v4w API (windows)
+ *     directshow API (windows)
+ *     video4linux API (linux)
+ *   video display
+ *     v4w API (windows)
+ *     SDL API (linux, macosx...)
+ *   several audio encoder/decoder: H263-1998, MP4V-ES, theora
+ *   image resizer.
+ *   format converter. (RBG24, I420...)
+ *
+ * Plugin Filters:
+ *  iLBC decoder/encoder.
+ * 
+ * + * @section what_thanks Thanks + * + * Thanks to all the contributors and to all bug reporters. + * Enjoy mediastreamer2! + * + */ + +/** + * @defgroup mediastreamer2_api Mediastreamer2 API + * @brief All API to manage mediastreamer2 library. + * + */ + +/** + * @defgroup mediastreamer2_init Init API - manage mediastreamer2 library. + * @ingroup mediastreamer2_api + * @brief Init API to manage mediastreamer2 library. + * + * This file provide the API needed to initialize + * and reset the mediastreamer2 library. + */ + +/** + * @defgroup mediastreamer2_soundcard Sound Card API - manage audio capture/play filters. + * @ingroup mediastreamer2_api + * @brief Sound Card API to manage audio capture/play filters. + * + * This file provide the API needed to manage + * soundcard filters. + */ + +/** + * @defgroup mediastreamer2_filter Filter API - manage mediastreamer2 filters. + * @ingroup mediastreamer2_api + * @brief Filter API to manage mediastreamer2 filters. + * + * This file provide the API needed to create, link, + * unlink, find and destroy filter. + * + * It also provides definitions if you wish to implement + * your own filters. + */ + +/** + * @defgroup mediastreamer2_ticker Ticker API - manage mediastreamer2 graphs. + * @ingroup mediastreamer2_api + * @brief Ticker API to manage mediastreamer2 graphs. + * + * This file provide the API needed to create, start + * and stop a graph. + */ + + +/** + * @page mediastreamer2_readme README + * @verbinclude README + */ + +/** + * @page mediastreamer2_install INSTALL + * @verbinclude INSTALL + */ + +/** + * @page mediastreamer2_license COPYING + * @verbinclude COPYING + */ + +/** + * @page mediastreamer2_changelog ChangeLog + * @verbinclude ChangeLog + */ + diff --git a/linphone/mediastreamer2/help/ht0-buildagraph.dox b/linphone/mediastreamer2/help/ht0-buildagraph.dox new file mode 100644 index 000000000..9acc3b0e5 --- /dev/null +++ b/linphone/mediastreamer2/help/ht0-buildagraph.dox @@ -0,0 +1,153 @@ +/** + * @defgroup howto0_samplegraph Howto 1: build a sample audio graph. + * @ingroup mediastreamer2 + +

Initialize mediastreamer2

+ +When using mediastreamer2, your first task is to initialize the +library: + +
+	##include 
+
+	int i;
+
+	i=ms_init();
+	if (i!=0)
+	  return -1;
+
+
+ +Mediastreamer2 provides internal components which are called filters. Those +filters must be linked together so that OUTPUT from one filter is sent to +INPUT of the other filters. + +Usually, filters are used for processing audio or video data. They could +capture data, play/draw data, encode/decode data, mix data (conference), +transform data (echo canceller). One of the most important filter is the +RTP filters that are able to send and receive RTP data. + +

Graph sample

+ +If you are using mediastreamer2, you probably want to do Voice Over IP +and get a graph providing a 2 way communication. This 2 graphs are very +simple: + +This first graph shows the filters needed to capture data from a sound +card, encode them and send it through an RTP session. + +
+             AUDIO    ->    ENCODER   ->   RTP
+            CAPTURE   ->              ->  SENDER
+
+ + This second graph shows the filters needed to receive data from an RTP +session decode it and send it to the playback device. + +
+        RTP      ->    DECODER   ->   DTMF       ->   AUDIO
+       RECEIVER  ->              ->  GENERATION  ->  PLAYBACK
+
+ +

Code to initiate the filters of the Graph sample

+ +Note that the NULL/error checks are not done for better reading. +To build the graph, you'll need some information: you need to +select the sound card and of course have an RTP session created +with oRTP. + +
+	MSSndCard *sndcard;
+	sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
+
+        /* audio capture filter */
+	MSFilter *soundread=ms_snd_card_create_reader(captcard);
+	MSFilter *soundwrite=ms_snd_card_create_writer(playcard);
+
+	MSFilter *encoder=ms_filter_create_encoder("PCMU");
+	MSFilter *decoder=ms_filter_create_decoder("PCMU");
+
+	MSFilter *rtpsend=ms_filter_new(MS_RTP_SEND_ID);
+	MSFilter *rtprecv=ms_filter_new(MS_RTP_RECV_ID);
+
+	RtpSession *rtp_session = *** your_ortp_session *** ;
+
+	ms_filter_call_method(rtpsend,MS_RTP_SEND_SET_SESSION,rtp_session);
+	ms_filter_call_method(rtprecv,MS_RTP_RECV_SET_SESSION,rtp_session);
+
+	MSFilter *dtmfgen=ms_filter_new(MS_DTMF_GEN_ID);
+
+ +In most cases, the above graph is not enough: you'll need to configure +filter's options. As an example, you need to set sampling rate of sound +cards' filters: + +
+        int sr = 8000;
+	int chan=1;
+	ms_filter_call_method(soundread,MS_FILTER_SET_SAMPLE_RATE,&sr);
+	ms_filter_call_method(soundwrite,MS_FILTER_SET_SAMPLE_RATE,&sr);
+	ms_filter_call_method(stream->encoder,MS_FILTER_SET_SAMPLE_RATE,&sr);
+	ms_filter_call_method(stream->decoder,MS_FILTER_SET_SAMPLE_RATE,&sr);
+
+	ms_filter_call_method(soundwrite,MS_FILTER_SET_NCHANNELS, &chan);
+
+        /* if you have some fmtp parameters (from SDP for example!)
+        char *fmtp1 = ** get your fmtp line **;
+        char *fmtp2 = ** get your fmtp line **;
+	ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP, (void*)fmtp1);
+	ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)fmtp2);
+
+ + +

Code to link the filters and run the graph sample

+ +
+	ms_filter_link(stream->soundread,0,stream->encoder,0);
+	ms_filter_link(stream->encoder,0,stream->rtpsend,0);
+
+	ms_filter_link(stream->rtprecv,0,stream->decoder,0);
+	ms_filter_link(stream->decoder,0,stream->dtmfgen,0);
+	ms_filter_link(stream->dtmfgen,0,stream->soundwrite,0);	
+
+ +Then you need to 'attach' the filters to a ticker. A ticker is a graph +manager responsible for running filters. + +In the above case, there is 2 independant graph within the ticker: you +need to attach the first element of each graph (the one that does not +contains any INPUT pins) + +
+	/* create ticker */
+	MSTicker *ticker=ms_ticker_new();
+
+	ms_ticker_attach(ticker,soundread);
+	ms_ticker_attach(ticker,rtprecv);
+
+ +

Code to unlink the filters and stop the graph sample

+ +
+	ms_ticker_detach(ticker,soundread);
+	ms_ticker_detach(ticker,rtprecv);
+
+	ms_filter_unlink(stream->soundread,0,stream->encoder,0);
+	ms_filter_unlink(stream->encoder,0,stream->rtpsend,0);
+
+	ms_filter_unlink(stream->rtprecv,0,stream->decoder,0);
+	ms_filter_unlink(stream->decoder,0,stream->dtmfgen,0);
+	ms_filter_unlink(stream->dtmfgen,0,stream->soundwrite,0);
+
+	if (rtp_session!=NULL) rtp_session_destroy(rtp_session);
+	if (rtpsend!=NULL) ms_filter_destroy(rtpsend);
+	if (rtprecv!=NULL) ms_filter_destroy(rtprecv);
+	if (soundread!=NULL) ms_filter_destroy(soundread);
+	if (soundwrite!=NULL) ms_filter_destroy(soundwrite);
+	if (encoder!=NULL) ms_filter_destroy(encoder);
+	if (decoder!=NULL) ms_filter_destroy(decoder);
+	if (dtmfgen!=NULL) ms_filter_destroy(dtmfgen);
+	if (ticker!=NULL) ms_ticker_destroy(ticker);
+
+ +*/ \ No newline at end of file diff --git a/linphone/mediastreamer2/include/.cvsignore b/linphone/mediastreamer2/include/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/mediastreamer2/include/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/mediastreamer2/include/Makefile.am b/linphone/mediastreamer2/include/Makefile.am new file mode 100644 index 000000000..c7b5d9316 --- /dev/null +++ b/linphone/mediastreamer2/include/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=mediastreamer2 diff --git a/linphone/mediastreamer2/include/mediastreamer2/.cvsignore b/linphone/mediastreamer2/include/mediastreamer2/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/mediastreamer2/include/mediastreamer2/Makefile.am b/linphone/mediastreamer2/include/mediastreamer2/Makefile.am new file mode 100644 index 000000000..9671e50e7 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/Makefile.am @@ -0,0 +1,26 @@ + +mediastreamer2_includedir=$(includedir)/mediastreamer2 + +mediastreamer2_include_HEADERS= ice.h \ + msfilter.h \ + msqueue.h \ + mscommon.h \ + allfilters.h \ + msticker.h \ + msrtp.h \ + dtmfgen.h \ + msfilerec.h \ + msfileplayer.h \ + mssndcard.h \ + mediastream.h \ + msv4l.h \ + msvideo.h \ + waveheader.h \ + msvideoout.h \ + msvolume.h \ + mstee.h \ + rfc3984.h \ + mswebcam.h + +EXTRA_DIST=$(mediastreamer2_include_HEADERS) + diff --git a/linphone/mediastreamer2/include/mediastreamer2/allfilters.h b/linphone/mediastreamer2/include/mediastreamer2/allfilters.h new file mode 100644 index 000000000..15659cfb2 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/allfilters.h @@ -0,0 +1,88 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef allfilters_h +#define allfilters_h + +/* this is the enum where to add your own filter id. +Please take care of always add new IDs at the end in order to preserve the binary interface*/ +/*this id is used for type checking of methods, events with filters */ +/*it must be used also to create filters */ +typedef enum MSFilterId{ + MS_FILTER_NOT_SET_ID, + MS_FILTER_PLUGIN_ID, /* no type checking will be performed on plugins */ + MS_FILTER_BASE_ID, + MS_ALSA_READ_ID, + MS_ALSA_WRITE_ID, + MS_OSS_READ_ID, + MS_OSS_WRITE_ID, + MS_ULAW_ENC_ID, + MS_ULAW_DEC_ID, + MS_ALAW_ENC_ID, + MS_ALAW_DEC_ID, + MS_RTP_SEND_ID, + MS_RTP_RECV_ID, + MS_FILE_PLAYER_ID, + MS_FILE_REC_ID, + MS_DTMF_GEN_ID, + MS_SPEEX_ENC_ID, + MS_SPEEX_DEC_ID, + MS_GSM_ENC_ID, + MS_GSM_DEC_ID, + MS_V4L_ID, + MS_SDL_OUT_ID, + MS_H263_ENC_ID, + MS_H263_DEC_ID, + MS_ARTS_READ_ID, + MS_ARTS_WRITE_ID, + MS_WINSND_READ_ID, + MS_WINSND_WRITE_ID, + MS_SPEEX_EC_ID, + MS_PIX_CONV_ID, + MS_TEE_ID, + MS_SIZE_CONV_ID, + MS_CONF_ID, + MS_THEORA_ENC_ID, + MS_THEORA_DEC_ID, + MS_PASND_READ_ID, + MS_PASND_WRITE_ID, + MS_MPEG4_ENC_ID, + MS_MPEG4_DEC_ID, + MS_MJPEG_DEC_ID, + MS_JOIN_ID, + MS_RESAMPLE_ID, + MS_VIDEO_OUT_ID, + MS_VOLUME_ID, + MS_SNOW_DEC_ID, + MS_SNOW_ENC_ID, + MS_CA_READ_ID, + MS_CA_WRITE_ID, +#ifdef __DIRECTSOUND_ENABLED__ + MS_WINSNDDS_READ_ID, + MS_WINSNDDS_WRITE_ID, +#endif + MS_STATIC_IMAGE_ID, + MS_V4L2_CAPTURE_ID, + MS_H263_OLD_DEC_ID, + MS_H263_OLD_ENC_ID, + MS_MIRE_ID +} MSFilterId; + + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/dtmfgen.h b/linphone/mediastreamer2/include/mediastreamer2/dtmfgen.h new file mode 100644 index 000000000..0ea4b930d --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/dtmfgen.h @@ -0,0 +1,29 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef dtmfgen_h +#define dtmfgen_h + +#include "msfilter.h" + +#define MS_DTMF_GEN_PUT MS_FILTER_METHOD(MS_DTMF_GEN_ID,0,const char) + +extern MSFilterDesc ms_dtmf_gen_desc; + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/ice.h b/linphone/mediastreamer2/include/mediastreamer2/ice.h new file mode 100644 index 000000000..76d5aa2aa --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/ice.h @@ -0,0 +1,74 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef ice_hh +#define ice_hh + +#include "ortp/stun_udp.h" +#include "ortp/stun.h" +#include "ortp/ortp.h" + +/* list of state for STUN connectivity check */ +#define TESTING 0 +#define WAITING 1 +#define RECV_VALID 2 +#define SEND_VALID 3 +#define VALID 4 +#define INVALID 5 + +struct SdpCandidate { + int seq_num; + char candidate_id[256]; + char password[256]; + + char fqdn[256]; + char ipaddr[256]; + int port; + + int mapped_port; + int peer_derived; /* 0: local 1: stun 2: turn */ + + float priority; +}; + +struct CandidatePair { + + struct SdpCandidate local_candidate; + struct SdpCandidate remote_candidate; + int max_sn; + int min_sn; + char max_candidate_id[256]; + UInt128 tid; + int connectivity_check; +}; + + +#ifdef __cplusplus +extern "C"{ +#endif + +int ice_sound_send_stun_request(RtpSession *session, struct CandidatePair *remote_candidates, int round); + +int ice_process_stun_message(RtpSession *session, struct CandidatePair *remote_candidates, OrtpEvent *evt); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h new file mode 100644 index 000000000..a6dfa28cd --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h @@ -0,0 +1,155 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef MEDIASTREAM_H +#define MEDIASTREAM_H + +#include "msfilter.h" +#include "msticker.h" +#include "mssndcard.h" +#include "mswebcam.h" +#include "ortp/ortp.h" +#include "ortp/event.h" + +struct _AudioStream +{ + MSTicker *ticker; + RtpSession *session; + MSFilter *soundread; + MSFilter *soundwrite; + MSFilter *encoder; + MSFilter *decoder; + MSFilter *rtprecv; + MSFilter *rtpsend; + MSFilter *dtmfgen; + MSFilter *ec;/*echo canceler*/ + unsigned int last_packet_count; + time_t last_packet_time; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _AudioStream AudioStream; + +struct _RingStream +{ + MSTicker *ticker; + MSFilter *source; + MSFilter *sndwrite; +}; + +typedef struct _RingStream RingStream; + + + +/* start a thread that does sampling->encoding->rtp_sending|rtp_receiving->decoding->playing */ +AudioStream *audio_stream_start (RtpProfile * prof, int locport, const char *remip, + int remport, int payload_type, int jitt_comp, bool_t echo_cancel); + +AudioStream *audio_stream_start_with_sndcards(RtpProfile * prof, int locport, const char *remip4, int remport, int payload_type, int jitt_comp, MSSndCard *playcard, MSSndCard *captcard, bool_t echocancel); + +int audio_stream_start_with_files (AudioStream * stream, RtpProfile * prof, + const char *remip, int remport, int rem_rtcp_port, + int pt, int jitt_comp, + const char * infile, const char * outfile); + +void audio_stream_play(AudioStream *st, const char *name); +void audio_stream_record(AudioStream *st, const char *name); + +void audio_stream_set_rtcp_information(AudioStream *st, const char *cname, const char *tool); + +/* those two function do the same as audio_stream_start() but in two steps +this is useful to make sure that sockets are open before sending an invite; +or to start to stream only after receiving an ack.*/ +AudioStream *audio_stream_new(int locport, bool_t ipv6); +int audio_stream_start_now(AudioStream * stream, RtpProfile * prof, const char *remip, int remport, int rem_rtcp_port, int payload_type, int jitt_comp,MSSndCard *playcard, MSSndCard *captcard, bool_t echo_cancel); +void audio_stream_set_relay_session_id(AudioStream *stream, const char *relay_session_id); +/*returns true if we are still receiving some data from remote end in the last timeout seconds*/ +bool_t audio_stream_alive(AudioStream * stream, int timeout); + +/* stop the above process*/ +void audio_stream_stop (AudioStream * stream); + +RingStream *ring_start (const char * file, int interval, MSSndCard *sndcard); +RingStream *ring_start_with_cb(const char * file, int interval, MSSndCard *sndcard, MSFilterNotifyFunc func, void * user_data); +void ring_stop (RingStream * stream); + + +/* send a dtmf */ +int audio_stream_send_dtmf (AudioStream * stream, char dtmf); + +void audio_stream_set_default_card(int cardindex); + + +/***************** + Video Support + *****************/ + + +struct _VideoStream +{ + MSTicker *ticker; + RtpSession *session; + MSFilter *source; + MSFilter *predec; + MSFilter *pixconv; + MSFilter *tee; + MSFilter *output; + MSFilter *encoder; + MSFilter *decoder; + MSFilter *rtprecv; + MSFilter *rtpsend; + OrtpEvQueue *evq; + bool_t adapt_bitrate; +}; + + +typedef struct _VideoStream VideoStream; +VideoStream *video_stream_new(int locport, bool_t use_ipv6); +void video_stream_enable_adaptive_bitrate_control(VideoStream *s, bool_t yesno); +int video_stream_start(VideoStream * stream, RtpProfile *profile, const char *remip, int remport, int rem_rtcp_port, + int payload, int jitt_comp, MSWebCam *device); +void video_stream_set_relay_session_id(VideoStream *stream, const char *relay_session_id); +void video_stream_set_rtcp_information(VideoStream *st, const char *cname, const char *tool); +/*function to call periodically to handle various events */ +void video_stream_iterate(VideoStream *stream); +void video_stream_send_vfu(VideoStream *stream); +void video_stream_stop (VideoStream * stream); + +VideoStream * video_preview_start(MSWebCam *device); +void video_preview_stop(VideoStream *stream); + +int video_stream_recv_only_start(VideoStream * stream, RtpProfile *profile, const char *remip, int remport, int payload, int jitt_comp); +int video_stream_send_only_start(VideoStream * stream, RtpProfile *profile, const char *remip, int remport, + int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *device); +void video_stream_recv_only_stop(VideoStream *stream); +void video_stream_send_only_stop(VideoStream *stream); + + +bool_t ms_is_ipv6(const char *address); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/mscommon.h b/linphone/mediastreamer2/include/mediastreamer2/mscommon.h new file mode 100644 index 000000000..122070508 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/mscommon.h @@ -0,0 +1,210 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef mscommon_h +#define mscommon_h + +#include + +#define ms_malloc ortp_malloc +#define ms_malloc0 ortp_malloc0 +#define ms_realloc ortp_realloc +#define ms_new ortp_new +#define ms_new0 ortp_new0 +#define ms_free ortp_free +#define ms_strdup ortp_strdup +#define ms_strdup_printf ortp_strdup_printf + +#define ms_mutex_t ortp_mutex_t +#define ms_mutex_init ortp_mutex_init +#define ms_mutex_destroy ortp_mutex_destroy +#define ms_mutex_lock ortp_mutex_lock +#define ms_mutex_unlock ortp_mutex_unlock + +#define ms_cond_t ortp_cond_t +#define ms_cond_init ortp_cond_init +#define ms_cond_wait ortp_cond_wait +#define ms_cond_signal ortp_cond_signal +#define ms_cond_broadcast ortp_cond_broadcast +#define ms_cond_destroy ortp_cond_destroy + +#ifdef WIN32 +static inline void ms_debug(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_DEBUG, fmt, args); + va_end (args); +} +#else +#ifdef DEBUG +static inline void ms_debug(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_DEBUG, fmt, args); + va_end (args); +} +#else +#define ms_debug(...) +#endif +#endif + + + +#define ms_message ortp_message +#define ms_warning ortp_warning +#define ms_error ortp_error +#define ms_fatal ortp_fatal + +#define ms_return_val_if_fail(_expr_,_ret_)\ + if (!(_expr_)) { ms_error("assert "#_expr_ "failed"); return (_ret_);} + +#define ms_return_if_fail(_expr_) \ + if (!(_expr_)){ ms_error("assert "#_expr_ "failed"); return ;} + +#define ms_thread_t ortp_thread_t +#define ms_thread_create ortp_thread_create +#define ms_thread_join ortp_thread_join +#define ms_thread_exit ortp_thread_exit + +struct _MSList { + struct _MSList *next; + struct _MSList *prev; + void *data; +}; + +typedef struct _MSList MSList; + + +#define ms_list_next(elem) ((elem)->next) + + +#ifdef __cplusplus +extern "C"{ +#endif + +MSList * ms_list_append(MSList *elem, void * data); +MSList * ms_list_prepend(MSList *elem, void * data); +MSList * ms_list_free(MSList *elem); +MSList * ms_list_concat(MSList *first, MSList *second); +MSList * ms_list_remove(MSList *first, void *data); +int ms_list_size(const MSList *first); +void ms_list_for_each(const MSList *list, void (*func)(void *)); +void ms_list_for_each2(const MSList *list, void (*func)(void *, void *), void *user_data); +MSList *ms_list_remove_link(MSList *list, MSList *elem); +MSList *ms_list_find(MSList *list, void *data); +MSList *ms_list_find_custom(MSList *list, int (*compare_func)(const void *, const void*), void *user_data); +void * ms_list_nth_data(const MSList *list, int index); +int ms_list_position(const MSList *list, MSList *elem); +int ms_list_index(const MSList *list, void *data); +MSList *ms_list_insert_sorted(MSList *list, void *data, int (*compare_func)(const void *, const void*)); +MSList *ms_list_insert(MSList *list, MSList *before, void *data); +MSList *ms_list_copy(const MSList *list); + +#undef MIN +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#undef MAX +#define MAX(a,b) ((a)>(b) ? (a) : (b)) + +/** + * @file mscommon.h + * @brief mediastreamer2 mscommon.h include file + * + * This file provide the API needed to initialize + * and reset the mediastreamer2 library. + * + */ + +/** + * @defgroup mediastreamer2_init Init API - manage mediastreamer2 library. + * @ingroup mediastreamer2_api + * @{ + */ + + +/** + * Initialize the mediastreamer2 library. + * + * This must be called once before calling any other API. + */ +void ms_init(void); + +/** + * Load plugins from a specific directory. + * + * @param directory A directory where plugins library are available. + * + * Returns: >0 if successfull, 0 if not plugins loaded, -1 otherwise. + */ +int ms_load_plugins(const char *directory); + +/** + * Release resource allocated in the mediastreamer2 library. + * + * This must be called once before closing program. + */ +void ms_exit(void); + +struct _MSSndCardDesc; + +/** + * This can be called when new sound cards have been added. + * + * Warning: It must NOT be called if one filter is currently created. + * You have to unlink, destroy everything before doing this. + * + * @param snd_desc A MSSndCardDesc description. + */ +void ms_reload_snd_card(struct _MSSndCardDesc *snd_desc); + +void ms_sleep(int seconds); + +/** + * The max payload size allowed. + * Filters that generate data that can be sent through RTP should make packets + * whose size is below ms_get_payload_max_size(). + * The default value is 1440 computed as the standart internet MTU minus IPv6 header, + * UDP header and RTP header. As IPV4 header is smaller than IPv6 header, this + * value works for both. + * +**/ +int ms_get_payload_max_size(); + +void ms_set_payload_max_size(int size); + +/** + * Returns the network Max Transmission Unit to reach destination_host. + * This will attempt to send one or more big packets to destination_host, to a random port. + * Those packets are filled with zeroes. +**/ +int ms_discover_mtu(const char *destination_host); + +/** + * Set mediastreamer default mtu, used to compute the default RTP max payload size. + * This function will call ms_set_payload_max_size(mtu-[ipv6 header size]). +**/ +void ms_set_mtu(int mtu); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msfileplayer.h b/linphone/mediastreamer2/include/mediastreamer2/msfileplayer.h new file mode 100644 index 000000000..8e1931448 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msfileplayer.h @@ -0,0 +1,43 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef msfileplayer_h +#define msfileplayer_h + +#include "msfilter.h" + + +/*methods*/ +#define MS_FILE_PLAYER_OPEN MS_FILTER_METHOD(MS_FILE_PLAYER_ID,0,const char*) +#define MS_FILE_PLAYER_START MS_FILTER_METHOD_NO_ARG(MS_FILE_PLAYER_ID,1) +#define MS_FILE_PLAYER_STOP MS_FILTER_METHOD_NO_ARG(MS_FILE_PLAYER_ID,2) +#define MS_FILE_PLAYER_CLOSE MS_FILTER_METHOD_NO_ARG(MS_FILE_PLAYER_ID,3) +/* set loop mode: + -1: no looping, + 0: loop at end of file, + x>0, loop after x miliseconds after eof +*/ +#define MS_FILE_PLAYER_LOOP MS_FILTER_METHOD(MS_FILE_PLAYER_ID,4,int) +#define MS_FILE_PLAYER_DONE MS_FILTER_METHOD(MS_FILE_PLAYER_ID,5,int) +#define MS_FILE_PLAYER_BIG_BUFFER MS_FILTER_METHOD(MS_FILE_PLAYER_ID,6,int) + +/*events*/ +#define MS_FILE_PLAYER_EOF MS_FILTER_EVENT_NO_ARG(MS_FILE_PLAYER_ID,0) + +#endif + diff --git a/linphone/mediastreamer2/include/mediastreamer2/msfilerec.h b/linphone/mediastreamer2/include/mediastreamer2/msfilerec.h new file mode 100644 index 000000000..b46cb38ac --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msfilerec.h @@ -0,0 +1,33 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef msfilerec_h +#define msfilerec_h + +#include "msfilter.h" + +extern MSFilterDesc ms_file_rec_desc; + +#define MS_FILE_REC_OPEN MS_FILTER_METHOD(MS_FILE_REC_ID,0,const char) +#define MS_FILE_REC_START MS_FILTER_METHOD_NO_ARG(MS_FILE_REC_ID,1) +#define MS_FILE_REC_STOP MS_FILTER_METHOD_NO_ARG(MS_FILE_REC_ID,2) +#define MS_FILE_REC_CLOSE MS_FILTER_METHOD_NO_ARG(MS_FILE_REC_ID,3) + + + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msfilter.h b/linphone/mediastreamer2/include/mediastreamer2/msfilter.h new file mode 100644 index 000000000..e4712a964 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msfilter.h @@ -0,0 +1,405 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef msfilter_h +#define msfilter_h + +#include "mscommon.h" +#include "msqueue.h" +#include "allfilters.h" + +/** + * @file msfilter.h + * @brief mediastreamer2 msfilter.h include file + * + * This file provide the API needed to create, link, + * unlink, find and destroy filter. + * + * It also provides definitions if you wish to implement + * your own filters. + * + */ + +/** + * @defgroup mediastreamer2_filter Filter API - manage mediastreamer2 filters. + * @ingroup mediastreamer2_api + * @{ + */ + +/** + * Structure for filter's methods (init, preprocess, process, postprocess, uninit). + * @var MSFilterFunc + */ +typedef void (*MSFilterFunc)(struct _MSFilter *f); + +/** + * Structure for filter's methods used to set filter's options. + * @var MSFilterMethodFunc + */ +typedef int (*MSFilterMethodFunc)(struct _MSFilter *f, void *arg); + +/** + * Structure for filter's methods used as a callback to notify events. + * @var MSFilterNotifyFunc + */ +typedef void (*MSFilterNotifyFunc)(void *userdata , unsigned int id, void *arg); + +struct _MSFilterMethod{ + int id; + MSFilterMethodFunc method; +}; + + +/** + * Structure for holding filter's methods to set filter's options. + * @var MSFilterMethod + */ +typedef struct _MSFilterMethod MSFilterMethod; + +enum _MSFilterCategory{ + MS_FILTER_OTHER, + MS_FILTER_ENCODER, + MS_FILTER_DECODER +}; + +/** + * Structure to describe filter's category. + *
+ *     MS_FILTER_OTHER
+ *     MS_FILTER_ENCODER
+ *     MS_FILTER_DECODER
+ * 
+ * @var MSFilterCategory + */ +typedef enum _MSFilterCategory MSFilterCategory; + +struct _MSFilterDesc{ + MSFilterId id; /* the id declared in allfilters.h */ + const char *name; /* filter name */ + const char *text; /*some descriptive text*/ + MSFilterCategory category; + const char *enc_fmt; /* must be set if MS_FILTER_ENCODER/MS_FILTER_DECODER */ + int ninputs; /*number of inputs */ + int noutputs; /*number of outputs */ + MSFilterFunc init; + MSFilterFunc preprocess; /* called once before processing */ + MSFilterFunc process; /* called every tick to do the filter's job*/ + MSFilterFunc postprocess; /*called once after processing */ + MSFilterFunc uninit; + MSFilterMethod *methods; +}; + +/** + * Structure for filter's description. + * @var MSFilterDesc + */ +typedef struct _MSFilterDesc MSFilterDesc; + +struct _MSFilter{ + MSFilterDesc *desc; + /*protected attributes */ + ms_mutex_t lock; + MSQueue **inputs; + MSQueue **outputs; + MSFilterNotifyFunc notify; + void *notify_ud; + void *data; + struct _MSTicker *ticker; + /*private attributes */ + uint32_t last_tick; + bool_t seen; +}; + + + +/** + * Structure to create/link/unlink/destroy filter's object. + * @var MSFilter + */ +typedef struct _MSFilter MSFilter; + + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * Register a filter description. (plugins use only!) + * + * When you build your own plugin, this method will + * add the encoder or decoder to the internal list + * of supported codec. Then, this plugin can be used + * transparently from the application. + * + * ms_filter_get_encoder, ms_filter_get_decoder, + * ms_filter_create_encoder, ms_filter_create_decoder + * and ms_filter_codec_supported + * can then be used as if the codec was internally. + * supported. + * + * @param desc a filter description. + */ +void ms_filter_register(MSFilterDesc *desc); + +/** + * Retrieve encoders according to codec name. + * + * Internal supported codecs: + * PCMU, PCMA, speex, gsm + * Existing Public plugins: + * iLBC + * + * @param mime A string indicating the codec. + * + * Returns: a MSFilterDesc if successfull, NULL otherwise. + */ +MSFilterDesc * ms_filter_get_encoder(const char *mime); + +/** + * Retrieve decoders according to codec name. + * + * Internal supported codecs: + * PCMU, PCMA, speex, gsm + * Existing Public plugins: + * iLBC + * + * @param mime A string indicating the codec. + * + * Returns: a MSFilterDesc if successfull, NULL otherwise. + */ +MSFilterDesc * ms_filter_get_decoder(const char *mime); + +/** + * Create encoder filter according to codec name. + * + * Internal supported codecs: + * PCMU, PCMA, speex, gsm + * Existing Public plugins: + * iLBC + * + * @param mime A string indicating the codec. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +MSFilter * ms_filter_create_encoder(const char *mime); + +/** + * Create decoder filter according to codec name. + * + * Internal supported codecs: + * PCMU, PCMA, speex, gsm + * Existing Public plugins: + * iLBC + * + * @param mime A string indicating the codec. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +MSFilter * ms_filter_create_decoder(const char *mime); + +/** + * Check if a encode or decode filter exists for a codec name. + * + * Internal supported codecs: + * PCMU, PCMA, speex, gsm + * Existing Public plugins: + * iLBC + * + * @param mime A string indicating the codec. + * + * Returns: TRUE if successfull, FALSE otherwise. + */ +bool_t ms_filter_codec_supported(const char *mime); + +/** + * Create decoder filter according to a filter's MSFilterId. + * + * @param id A MSFilterId identifier for the filter. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +MSFilter *ms_filter_new(MSFilterId id); + +/** + * Create decoder filter according to a filter's name. + * + * @param name A name for the filter. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +MSFilter *ms_filter_new_from_name(const char *name); + +/** + * Create decoder filter according to a filter's description. + * + * The primary use is to create your own filter's in your + * application and avoid registration inside mediastreamer2. + * + * @param desc A MSFilterDesc for the filter. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +MSFilter *ms_filter_new_from_desc(MSFilterDesc *desc); + +/** + * Link one OUTPUT pin from a filter to an INPUT pin of another filter. + * + * All data coming from the OUTPUT pin of one filter will be distributed + * to the INPUT pin of the second filter. + * + * @param f1 A MSFilter object containing the OUTPUT pin + * @param pin1 An index of an OUTPUT pin. + * @param f2 A MSFilter object containing the INPUT pin + * @param pin2 An index of an INPUT pin. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +int ms_filter_link(MSFilter *f1, int pin1, MSFilter *f2, int pin2); + +/** + * Unlink one OUTPUT pin from a filter to an INPUT pin of another filter. + * + * @param f1 A MSFilter object containing the OUTPUT pin + * @param pin1 An index of an OUTPUT pin. + * @param f2 A MSFilter object containing the INPUT pin + * @param pin2 An index of an INPUT pin. + * + * Returns: a MSFilter if successfull, NULL otherwise. + */ +int ms_filter_unlink(MSFilter *f1, int pin1, MSFilter *f2, int pin2); + +/** + * Call a filter's method to set or get options. + * + * @param f A MSFilter object. + * @param id A private filter ID for the option. + * @param arg A private user data for the filter. + * + * Returns: 0 if successfull, -1 otherwise. + */ +int ms_filter_call_method(MSFilter *f, unsigned int id, void *arg); + +/** + * Call a filter's method to set options. + * + * @param f A MSFilter object. + * @param id A private filter ID for the option. + * + * Returns: 0 if successfull, -1 otherwise. + */ +int ms_filter_call_method_noarg(MSFilter *f, unsigned int id); + +/** + * Set a callback on filter's to be informed of private filter's event. + * + * @param f A MSFilter object. + * @param fn A MSFilterNotifyFunc that will be called. + * @param userdata A pointer to private data. + * + * Returns: 0 if successfull, -1 otherwise. + */ +void ms_filter_set_notify_callback(MSFilter *f, MSFilterNotifyFunc fn, void *userdata); + +/** + * Get MSFilterId's filter. + * + * @param f A MSFilter object. + * + * Returns: MSFilterId if successfull, -1 otherwise. + */ +MSFilterId ms_filter_get_id(MSFilter *f); + +/** + * Destroy a filter object. + * + * @param f A MSFilter object. + * + */ +void ms_filter_destroy(MSFilter *f); + +/* I define the id taking the lower bits of the address of the MSFilterDesc object, +the method index (_cnt_) and the argument size */ +/* I hope using this to avoid type mismatch (calling a method on the wrong filter)*/ +#define MS_FILTER_METHOD_ID(_id_,_cnt_,_argsize_) \ + ( (((unsigned long)(_id_)) & 0xFFFF)<<16 | (_cnt_<<8) | (_argsize_ & 0xFF )) + +#define MS_FILTER_METHOD(_id_,_count_,_argtype_) \ + MS_FILTER_METHOD_ID(_id_,_count_,sizeof(_argtype_)) + +#define MS_FILTER_METHOD_NO_ARG(_id_,_count_) \ + MS_FILTER_METHOD_ID(_id_,_count_,0) + + +#define MS_FILTER_BASE_METHOD(_count_,_argtype_) \ + MS_FILTER_METHOD_ID(MS_FILTER_BASE_ID,_count_,sizeof(_argtype_)) + +#define MS_FILTER_BASE_METHOD_NO_ARG(_count_) \ + MS_FILTER_METHOD_ID(MS_FILTER_BASE_ID,_count_,0) + +#define MS_FILTER_EVENT(_id_,_count_,_argtype_) \ + MS_FILTER_METHOD_ID(_id_,_count_,sizeof(_argtype_)) + +#define MS_FILTER_EVENT_NO_ARG(_id_,_count_)\ + MS_FILTER_METHOD_ID(_id_,_count_,0) + +/* some MSFilter base methods:*/ +#define MS_FILTER_SET_SAMPLE_RATE MS_FILTER_BASE_METHOD(0,int) +#define MS_FILTER_GET_SAMPLE_RATE MS_FILTER_BASE_METHOD(1,int) +#define MS_FILTER_SET_BITRATE MS_FILTER_BASE_METHOD(2,int) +#define MS_FILTER_GET_BITRATE MS_FILTER_BASE_METHOD(3,int) +#define MS_FILTER_GET_NCHANNELS MS_FILTER_BASE_METHOD(5,int) +#define MS_FILTER_SET_NCHANNELS MS_FILTER_BASE_METHOD(6,int) +#define MS_FILTER_ADD_FMTP MS_FILTER_BASE_METHOD(7,const char) +#define MS_FILTER_ADD_ATTR MS_FILTER_BASE_METHOD(8,const char) +#define MS_FILTER_SET_MTU MS_FILTER_BASE_METHOD(9,int) +#define MS_FILTER_GET_MTU MS_FILTER_BASE_METHOD(10,int) + +#define MS_FILTER_SET_FRAMESIZE MS_FILTER_BASE_METHOD(11,int) +#define MS_FILTER_SET_FILTERLENGTH MS_FILTER_BASE_METHOD(12,int) +#define MS_FILTER_SET_OUTPUT_SAMPLE_RATE MS_FILTER_BASE_METHOD(13,int) +#define MS_FILTER_ENABLE_DIRECTMODE MS_FILTER_BASE_METHOD(14,int) +#define MS_FILTER_ENABLE_VAD MS_FILTER_BASE_METHOD(15,int) +#define MS_FILTER_GET_STAT_DISCARDED MS_FILTER_BASE_METHOD(16,int) +#define MS_FILTER_GET_STAT_MISSED MS_FILTER_BASE_METHOD(17,int) +#define MS_FILTER_GET_STAT_INPUT MS_FILTER_BASE_METHOD(18,int) +#define MS_FILTER_GET_STAT_OUTPUT MS_FILTER_BASE_METHOD(19,int) +#define MS_FILTER_ENABLE_AGC MS_FILTER_BASE_METHOD(20,int) + +/** @} */ + +/*private methods*/ +void ms_filter_process(MSFilter *f); +void ms_filter_preprocess(MSFilter *f, struct _MSTicker *t); +void ms_filter_postprocess(MSFilter *f); +bool_t ms_filter_inputs_have_data(MSFilter *f); +void ms_filter_notify(MSFilter *f, unsigned int id, void *arg); +void ms_filter_notify_no_arg(MSFilter *f, unsigned int id); +#define ms_filter_lock(f) ms_mutex_lock(&(f)->lock) +#define ms_filter_unlock(f) ms_mutex_unlock(&(f)->lock) +void ms_filter_unregister_all(void); + +#ifdef __cplusplus +} +#endif + +/* used by awk script in Makefile.am to generate alldescs.c */ +#define MS_FILTER_DESC_EXPORT(desc) + + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msqueue.h b/linphone/mediastreamer2/include/mediastreamer2/msqueue.h new file mode 100644 index 000000000..2c819ff83 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msqueue.h @@ -0,0 +1,113 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef MSQUEUE_H +#define MSQUEUE_H + +#include "ortp/str_utils.h" + +/* for the moment these are stupid queues limited to one element*/ + +typedef struct _MSCPoint{ + struct _MSFilter *filter; + int pin; +} MSCPoint; + +typedef struct _MSQueue +{ + queue_t q; + MSCPoint prev; + MSCPoint next; +}MSQueue; + + +MSQueue * ms_queue_new(struct _MSFilter *f1, int pin1, struct _MSFilter *f2, int pin2 ); + +static inline mblk_t *ms_queue_get(MSQueue *q){ + return getq(&q->q); +} + +static inline void ms_queue_put(MSQueue *q, mblk_t *m){ + putq(&q->q,m); + return; +} + +static inline mblk_t * ms_queue_peek_last(MSQueue *q){ + return qlast(&q->q); +} + +static inline bool_t ms_queue_empty(MSQueue *q){ + return qempty(&q->q); +} + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*init a queue on stack*/ +void ms_queue_init(MSQueue *q); + +void ms_queue_flush(MSQueue *q); + +void ms_queue_destroy(MSQueue *q); + +#define mblk_set_timestamp_info(m,ts) (m)->reserved1=(ts); +#define mblk_get_timestamp_info(m) ((m)->reserved1) +#define mblk_set_marker_info(m,bit) (m)->reserved2=((m)->reserved2|bit) +#define mblk_get_marker_info(m) ((m)->reserved2&0x1) +#define mblk_set_rate(m,bits) (m)->reserved2=((m)->reserved2|(bits)<<1) +#define mblk_get_rate(m) (((m)->reserved2>>1)&0x3) +#define mblk_set_payload_type(m,bits) (m)->reserved2=((m)->reserved2|(bits<<3)) +#define mblk_get_payload_type(m) (((m)->reserved2>>3)&0xFF) + + +struct _MSBufferizer{ + queue_t q; + int size; +}; + +typedef struct _MSBufferizer MSBufferizer; + +/*allocates and initialize */ +MSBufferizer * ms_bufferizer_new(void); + +/*initialize in memory */ +void ms_bufferizer_init(MSBufferizer *obj); + +void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); + +/* put every mblk_t from q, into the bufferizer */ +void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q); + +int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); + +/* returns the number of bytes available in the bufferizer*/ +static inline int ms_bufferizer_get_avail(MSBufferizer *obj){ + return obj->size; +} + +void ms_bufferizer_uninit(MSBufferizer *obj); + +void ms_bufferizer_destroy(MSBufferizer *obj); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msrtp.h b/linphone/mediastreamer2/include/mediastreamer2/msrtp.h new file mode 100644 index 000000000..76a4e1c3b --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msrtp.h @@ -0,0 +1,48 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef msrtp_hh +#define msrtp_hh + +#include "msfilter.h" +#include "ice.h" +#include "ortp/ortp.h" + +#define MS_RTP_RECV_SET_SESSION MS_FILTER_METHOD(MS_RTP_RECV_ID,0,RtpSession*) + +#define MS_RTP_SEND_SET_SESSION MS_FILTER_METHOD(MS_RTP_SEND_ID,0,RtpSession*) + +#define MS_RTP_SEND_SEND_DTMF MS_FILTER_METHOD(MS_RTP_SEND_ID,1,const char) + +#define MS_RTP_RECV_SET_CANDIDATEPAIRS MS_FILTER_METHOD(MS_RTP_RECV_ID,1,struct CandidatePair*) + +#define MS_RTP_SEND_SET_CANDIDATEPAIRS MS_FILTER_METHOD(MS_RTP_SEND_ID,2,struct CandidatePair*) + +#define MS_RTP_SEND_MUTE_MIC MS_FILTER_METHOD_NO_ARG(MS_RTP_SEND_ID,3) + +#define MS_RTP_SEND_UNMUTE_MIC MS_FILTER_METHOD_NO_ARG(MS_RTP_SEND_ID,4) + +#define MS_RTP_SEND_SET_RELAY_SESSION_ID MS_FILTER_METHOD(MS_RTP_RECV_ID,5,const char *) + + +extern MSFilterDesc ms_rtp_send_desc; +extern MSFilterDesc ms_rtp_recv_desc; + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h b/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h new file mode 100644 index 000000000..9a8995b82 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h @@ -0,0 +1,357 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef sndcard_h +#define sndcard_h + +#include "mscommon.h" + +/** + * @file mssndcard.h + * @brief mediastreamer2 mssndcard.h include file + * + * This file provide the API needed to manage + * soundcard filters. + * + */ + +/** + * @defgroup mediastreamer2_soundcard Sound Card API - manage audio capture/play filters. + * @ingroup mediastreamer2_api + * @{ + */ + +struct _MSSndCardManager{ + MSList *cards; +}; + +/** + * Structure for sound card manager object. + * @var MSSndCardManager + */ +typedef struct _MSSndCardManager MSSndCardManager; + +enum _MSSndCardMixerElem{ + MS_SND_CARD_MASTER, + MS_SND_CARD_PLAYBACK, + MS_SND_CARD_CAPTURE +}; + +/** + * Structure for sound card mixer values. + * @var MSSndCardMixerElem + */ +typedef enum _MSSndCardMixerElem MSSndCardMixerElem; + +enum _MSSndCardCapture { + MS_SND_CARD_MIC, + MS_SND_CARD_LINE +}; + +/** + * Structure for sound card capture source values. + * @var MSSndCardCapture + */ +typedef enum _MSSndCardCapture MSSndCardCapture; + +struct _MSSndCard; + +typedef void (*MSSndCardDetectFunc)(MSSndCardManager *obj); +typedef void (*MSSndCardInitFunc)(struct _MSSndCard *obj); +typedef void (*MSSndCardUninitFunc)(struct _MSSndCard *obj); +typedef void (*MSSndCardSetLevelFunc)(struct _MSSndCard *obj, MSSndCardMixerElem e, int percent); +typedef void (*MSSndCardSetCaptureFunc)(struct _MSSndCard *obj, MSSndCardCapture e); +typedef int (*MSSndCardGetLevelFunc)(struct _MSSndCard *obj, MSSndCardMixerElem e); +typedef struct _MSFilter * (*MSSndCardCreateReaderFunc)(struct _MSSndCard *obj); +typedef struct _MSFilter * (*MSSndCardCreateWriterFunc)(struct _MSSndCard *obj); +typedef struct _MSSndCard * (*MSSndCardDuplicateFunc)(struct _MSSndCard *obj); + +struct _MSSndCardDesc{ + const char *driver_type; + MSSndCardDetectFunc detect; + MSSndCardInitFunc init; + MSSndCardSetLevelFunc set_level; + MSSndCardGetLevelFunc get_level; + MSSndCardSetCaptureFunc set_capture; + MSSndCardCreateReaderFunc create_reader; + MSSndCardCreateWriterFunc create_writer; + MSSndCardUninitFunc uninit; + MSSndCardDuplicateFunc duplicate; + +}; + +/** + * Structure for sound card description object. + * @var MSSndCardDesc + */ +typedef struct _MSSndCardDesc MSSndCardDesc; + +#define MS_SND_CARD_CAP_CAPTURE (1) +#define MS_SND_CARD_CAP_PLAYBACK (1<<1) + +struct _MSSndCard{ + MSSndCardDesc *desc; + char *name; + char *id; + unsigned int capabilities; + void *data; +}; + +/** + * Structure for sound card object. + * @var MSSndCard + */ +typedef struct _MSSndCard MSSndCard; + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @defgroup mediastreamer2_soundcardmanager Sound Card Manager API + * @ingroup mediastreamer2_soundcard + * @{ + */ + +/** + * Retreive a sound card manager object. + * + * Returns: MSSndCardManager if successfull, NULL otherwise. + */ +MSSndCardManager * ms_snd_card_manager_get(void); + +/** + * Destroy a sound card manager object. + * + */ +void ms_snd_card_manager_destroy(void); + +/** + * Retreive a sound card object based on its name. + * + * @param m A sound card manager containing sound cards. + * @param id A name for card to search. + * + * Returns: MSSndCard if successfull, NULL otherwise. + */ +MSSndCard * ms_snd_card_manager_get_card(MSSndCardManager *m, const char *id); + +/** + * Retreive the default sound card object. + * + * @param m A sound card manager containing sound cards. + * + * Returns: MSSndCard if successfull, NULL otherwise. + */ +MSSndCard * ms_snd_card_manager_get_default_card(MSSndCardManager *m); + +/** + * Retreive the list of sound card objects. + * + * @param m A sound card manager containing sound cards. + * + * Returns: MSList of cards if successfull, NULL otherwise. + */ +const MSList * ms_snd_card_manager_get_list(MSSndCardManager *m); + +/** + * Add a sound card object in a sound card manager's list. + * + * @param m A sound card manager containing sound cards. + * @param c A sound card object. + * + */ +void ms_snd_card_manager_add_card(MSSndCardManager *m, MSSndCard *c); + +/** + * Register a sound card description in a sound card manager. + * + * @param m A sound card manager containing sound cards. + * @param desc A sound card description object. + * + */ +void ms_snd_card_manager_register_desc(MSSndCardManager *m, MSSndCardDesc *desc); + +/** @} */ + +/** + * @defgroup mediastreamer2_soundcardfilter Sound Card Filter API + * @ingroup mediastreamer2_soundcard + * @{ + */ + +/** + * Create an INPUT filter based on the selected sound card. + * + * @param obj A sound card object. + * + * Returns: A MSFilter if successfull, NULL otherwise. + */ +struct _MSFilter * ms_snd_card_create_reader(MSSndCard *obj); + +/** + * Create an OUPUT filter based on the selected sound card. + * + * @param obj A sound card object. + * + * Returns: A MSFilter if successfull, NULL otherwise. + */ +struct _MSFilter * ms_snd_card_create_writer(MSSndCard *obj); + +/** + * Create a new sound card object. + * + * @param desc A sound card description object. + * + * Returns: MSSndCard if successfull, NULL otherwise. + */ +MSSndCard * ms_snd_card_new(MSSndCardDesc *desc); + +/** + * Destroy sound card object. + * + * @param obj A MSSndCard object. + */ +void ms_snd_card_destroy(MSSndCard *obj); + +/** + * Duplicate a sound card object. + * + * This helps to open several time a sound card. + * + * @param card A sound card object. + * + * Returns: MSSndCard if successfull, NULL otherwise. + */ +MSSndCard * ms_snd_card_dup(MSSndCard *card); + +/** + * Retreive a sound card's driver type string. + * + * Internal driver types are either: "OSS, ALSA, WINSND, PASND, CA" + * + * @param obj A sound card object. + * + * Returns: a string if successfull, NULL otherwise. + */ +const char *ms_snd_card_get_driver_type(const MSSndCard *obj); + +/** + * Retreive a sound card's name. + * + * @param obj A sound card object. + * + * Returns: a string if successfull, NULL otherwise. + */ +const char *ms_snd_card_get_name(const MSSndCard *obj); + +/** + * Retreive sound card's name ($driver_type: $name). + * + * @param obj A sound card object. + * + * Returns: A string if successfull, NULL otherwise. + */ +const char *ms_snd_card_get_string_id(MSSndCard *obj); + + +/** + * Retreive sound card's capabilities. + * + *
+ *   MS_SND_CARD_CAP_CAPTURE
+ *   MS_SND_CARD_CAP_PLAYBACK
+ *   MS_SND_CARD_CAP_CAPTURE|MS_SND_CARD_CAP_PLAYBACK
+ * 
+ * + * @param obj A sound card object. + * + * Returns: A unsigned int if successfull, 0 otherwise. + */ +unsigned int ms_snd_card_get_capabilities(const MSSndCard *obj); + +/** + * Set some mixer level value. + * + *
+ *   MS_SND_CARD_MASTER,
+ *   MS_SND_CARD_PLAYBACK,
+ *   MS_SND_CARD_CAPTURE
+ * 
+ * Note: not implemented on all sound card filters. + * + * @param obj A sound card object. + * @param e A sound card mixer object. + * @param percent A volume level. + * + */ +void ms_snd_card_set_level(MSSndCard *obj, MSSndCardMixerElem e, int percent); + +/** + * Get some mixer level value. + * + *
+ *   MS_SND_CARD_MASTER,
+ *   MS_SND_CARD_PLAYBACK,
+ *   MS_SND_CARD_CAPTURE
+ * 
+ * Note: not implemented on all sound card filters. + * + * @param obj A sound card object. + * @param e A sound card mixer object. + * + * Returns: A int if successfull, 0 otherwise. + */ +int ms_snd_card_get_level(MSSndCard *obj, MSSndCardMixerElem e); + +/** + * Set some source for capture. + * + *
+ *   MS_SND_CARD_MIC,
+ *   MS_SND_CARD_LINE
+ * 
+ * Note: not implemented on all sound card filters. + * + * @param obj A sound card object. + * @param c A sound card capture value. + * + * Returns: A int if successfull, 0 otherwise. + */ +void ms_snd_card_set_capture(MSSndCard *obj, MSSndCardCapture c); + +/** + * Create a alsa card with user supplied pcm name and mixer name. + * @param pcmdev The pcm device name following alsa conventions (ex: plughw:0) + * @param mixdev The mixer device name following alsa conventions. + * + * Returns: a MSSndCard object, NULL if alsa support is not available. + */ +MSSndCard * ms_alsa_card_new_custom(const char *pcmdev, const char *mixdev); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/mstee.h b/linphone/mediastreamer2/include/mediastreamer2/mstee.h new file mode 100644 index 000000000..dd418bfda --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/mstee.h @@ -0,0 +1,30 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef mstee_h +#define mstee_h + +#include "msfilter.h" + +/*mute/unmute some outputs of the MSTee */ +#define MS_TEE_UNMUTE MS_FILTER_METHOD(MS_TEE_ID,0,int) +#define MS_TEE_MUTE MS_FILTER_METHOD(MS_TEE_ID,1,int) + + + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msticker.h b/linphone/mediastreamer2/include/mediastreamer2/msticker.h new file mode 100644 index 000000000..d13bc2e30 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msticker.h @@ -0,0 +1,145 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef MS_TICKER_H +#define MS_TICKER_H + + +#include "msfilter.h" +#include "mscommon.h" + +/** + * @file msticker.h + * @brief mediastreamer2 msticker.h include file + * + * This file provide the API needed to create, start + * and stop a graph. + * + */ + +/** + * @defgroup mediastreamer2_ticker Ticker API - manage mediastreamer2 graphs. + * @ingroup mediastreamer2_api + * @{ + */ + + +/** + * Structure for method getting time in miliseconds from an external source. + * @var MSTickerTimeFunc + */ +typedef uint64_t (*MSTickerTimeFunc)(void *); + +struct _MSTicker +{ + ms_mutex_t lock; + ms_cond_t cond; + MSList *execution_list; /* the list of source filters to be executed.*/ + ms_thread_t thread; /* the thread ressource*/ + int interval; /* in miliseconds*/ + int exec_id; + uint32_t ticks; + uint64_t time; /* a time since the start of the ticker expressed in milisec*/ + uint64_t orig; /* a relative time to take in account difference between time base given by consecutive get_cur_time_ptr() functions.*/ + MSTickerTimeFunc get_cur_time_ptr; + void *get_cur_time_data; + bool_t run; /* flag to indicate whether the ticker must be run or not */ +#ifdef WIN32_TIMERS + HANDLE TimeEvent; +#endif +}; + +/** + * Structure for ticker object. + * @var MSTicker + */ +typedef struct _MSTicker MSTicker; + + +#ifdef __cplusplus +extern "C"{ +#endif + + +/** + * Create a ticker that will be used to start + * and stop a graph. + * + * Returns: MSTicker * if successfull, NULL otherwise. + */ +MSTicker *ms_ticker_new(void); + +/** + * Attach a chain of filters to a ticker. + * The processing chain will be executed until ms_ticker_detach + * will be called. + * + * @param ticker A #MSTicker object. + * @param f A #MSFilter object. + * + * Returns: 0 if successfull, -1 otherwise. + */ +int ms_ticker_attach(MSTicker *ticker,MSFilter *f); + +/** + * Dettach a chain of filters to a ticker. + * The processing chain will no more be executed. + * + * @param ticker A #MSTicker object. + * @param f A #MSFilter object. + * + * + * Returns: 0 if successfull, -1 otherwise. + */ +int ms_ticker_detach(MSTicker *ticker,MSFilter *f); + +/** + * Destroy a ticker. + * + * @param ticker A #MSTicker object. + * + */ +void ms_ticker_destroy(MSTicker *ticker); + +/** + * Destroy a ticker. + * + * @param ticker A #MSTicker object. + * @param func A replacement method for calculating "current time" + * @param user_data Any pointer to user private data. + */ +void ms_ticker_set_time_func(MSTicker *ticker, MSTickerTimeFunc func, void *user_data); + +/** + * Print on stdout all filters of a ticker. (INTERNAL: DO NOT USE) + * + * @param ticker A #MSTicker object. + */ +void ms_ticker_print_graphs(MSTicker *ticker); + +/* private functions:*/ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msv4l.h b/linphone/mediastreamer2/include/mediastreamer2/msv4l.h new file mode 100644 index 000000000..2d7056d0b --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msv4l.h @@ -0,0 +1,30 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef msv4l_h +#define msv4l_h + +#include "msfilter.h" + +#define MS_V4L_START MS_FILTER_METHOD_NO_ARG(MS_V4L_ID,0) +#define MS_V4L_STOP MS_FILTER_METHOD_NO_ARG(MS_V4L_ID,1) +#define MS_V4L_SET_DEVICE MS_FILTER_METHOD(MS_V4L_ID,2,int) +#define MS_V4L_SET_IMAGE MS_FILTER_METHOD(MS_V4L_ID,3,char) + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msvideo.h b/linphone/mediastreamer2/include/mediastreamer2/msvideo.h new file mode 100644 index 000000000..8e6d892a9 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msvideo.h @@ -0,0 +1,117 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef msvideo_h +#define msvideo_h + +#include "msfilter.h" + +/* some global constants for video MSFilter(s) */ +#define MS_VIDEO_SIZE_CIF_W 352 +#define MS_VIDEO_SIZE_CIF_H 288 +#define MS_VIDEO_SIZE_QCIF_W 176 +#define MS_VIDEO_SIZE_QCIF_H 144 +#define MS_VIDEO_SIZE_4CIF_W 704 +#define MS_VIDEO_SIZE_4CIF_H 576 + +#define MS_VIDEO_SIZE_QQVGA_W 160 +#define MS_VIDEO_SIZE_QQVGA_H 120 + +#define MS_VIDEO_SIZE_QVGA_W 320 +#define MS_VIDEO_SIZE_QVGA_H 240 + +#define MS_VIDEO_SIZE_VGA_W 640 +#define MS_VIDEO_SIZE_VGA_H 480 + +#define MS_VIDEO_SIZE_720P_W 1280 +#define MS_VIDEO_SIZE_720P_H 720 + + +#define MS_VIDEO_SIZE_NS1_W 324 +#define MS_VIDEO_SIZE_NS1_H 248 + +#define MS_VIDEO_SIZE_MAX_W MS_VIDEO_SIZE_720P_W +#define MS_VIDEO_SIZE_MAX_H MS_VIDEO_SIZE_720P_H + +typedef struct MSVideoSize{ + int width,height; +} MSVideoSize; + +typedef struct MSRect{ + int x,y,w,h; +} MSRect; + +#define MS_VIDEO_SIZE_CIF (MSVideoSize){MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H} +#define MS_VIDEO_SIZE_QCIF (MSVideoSize){MS_VIDEO_SIZE_QCIF_W,MS_VIDEO_SIZE_QCIF_H} +#define MS_VIDEO_SIZE_4CIF (MSVideoSize){MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} + +#define MS_VIDEO_SIZE_QQVGA (MSVideoSize){MS_VIDEO_SIZE_QQVGA_W,MS_VIDEO_SIZE_QQVGA_H} +#define MS_VIDEO_SIZE_QVGA (MSVideoSize){MS_VIDEO_SIZE_QVGA_W,MS_VIDEO_SIZE_QVGA_H} +#define MS_VIDEO_SIZE_VGA (MSVideoSize){MS_VIDEO_SIZE_VGA_W,MS_VIDEO_SIZE_VGA_H} + +#define MS_VIDEO_SIZE_720P (MSVideoSize){MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H} + +#define MS_VIDEO_SIZE_NS1 (MSVideoSize){MS_VIDEO_SIZE_NS1_W,MS_VIDEO_SIZE_NS1_H} + +typedef enum{ + MS_YUV420P, + MS_YUYV, + MS_RGB24, + MS_MJPEG, + MS_UYVY, + MS_YUY2 /* -> same as MS_YUYV */ +}MSPixFmt; + +typedef struct _MSPicture{ + int w,h; + uint8_t *planes[4]; /*we usually use 3 planes, 4th is for compatibility */ + int strides[4]; /*with ffmpeg's swscale.h */ +}MSPicture; + +typedef struct _MSPicture YuvBuf; /*for backward compatibility*/ + +#ifdef __cplusplus +extern "C"{ +#endif + +int ms_pix_fmt_to_ffmpeg(MSPixFmt fmt); +MSPixFmt ffmpeg_pix_fmt_to_ms(int fmt); +void ms_ffmpeg_check_init(void); +int yuv_buf_init_from_mblk(MSPicture *buf, mblk_t *m); +void yuv_buf_init_from_mblk_with_size(MSPicture *buf, mblk_t *m, int w, int h); +mblk_t * yuv_buf_alloc(MSPicture *buf, int w, int h); +void yuv_buf_copy(uint8_t *src_planes[], const int src_strides[], + uint8_t *dst_planes[], const int dst_strides[3], MSVideoSize roi); +#ifdef __cplusplus +} +#endif + +#define MS_FILTER_SET_VIDEO_SIZE MS_FILTER_BASE_METHOD(100,MSVideoSize) +#define MS_FILTER_GET_VIDEO_SIZE MS_FILTER_BASE_METHOD(101,MSVideoSize) + +#define MS_FILTER_SET_PIX_FMT MS_FILTER_BASE_METHOD(102,MSPixFmt) +#define MS_FILTER_GET_PIX_FMT MS_FILTER_BASE_METHOD(103,MSPixFmt) + +#define MS_FILTER_SET_FPS MS_FILTER_BASE_METHOD(104,float) +#define MS_FILTER_GET_FPS MS_FILTER_BASE_METHOD(105,float) + +/* request a video-fast-update (=I frame for H263,MP4V-ES) to a video encoder*/ +#define MS_FILTER_REQ_VFU MS_FILTER_BASE_METHOD_NO_ARG(106) + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msvideoout.h b/linphone/mediastreamer2/include/mediastreamer2/msvideoout.h new file mode 100644 index 000000000..0d2eee84d --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msvideoout.h @@ -0,0 +1,93 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef msvideoout_h +#define msvideoout_h + +#include +#include + + +struct _MSDisplay; + +typedef enum _MSDisplayEventType{ + MS_DISPLAY_RESIZE_EVENT +}MSDisplayEventType; + +typedef struct _MSDisplayEvent{ + MSDisplayEventType evtype; + int w,h; +}MSDisplayEvent; + +typedef struct _MSDisplayDesc{ + /*init requests setup of the display window at the proper size, given + in frame_buffer argument. Memory buffer (data,strides) must be fulfilled + at return. init() might be called several times upon screen resize*/ + bool_t (*init)(struct _MSDisplay *, MSPicture *frame_buffer); + void (*lock)(struct _MSDisplay *);/*lock before writing to the framebuffer*/ + void (*unlock)(struct _MSDisplay *);/*unlock after writing to the framebuffer*/ + void (*update)(struct _MSDisplay *); /*display the picture to the screen*/ + void (*uninit)(struct _MSDisplay *); + bool_t (*pollevent)(struct _MSDisplay *, MSDisplayEvent *ev); +}MSDisplayDesc; + +typedef struct _MSDisplay{ + MSDisplayDesc *desc; + long window_id; /*window id if the display should use an existing window*/ + void *data; +} MSDisplay; + + +#define ms_display_init(d,fbuf) (d)->desc->init(d,fbuf) +#define ms_display_lock(d) if ((d)->desc->lock) (d)->desc->lock(d) +#define ms_display_unlock(d) if ((d)->desc->unlock) (d)->desc->unlock(d) +#define ms_display_update(d) if ((d)->desc->update) (d)->desc->update(d) +bool_t ms_display_poll_event(MSDisplay *d, MSDisplayEvent *ev); + +extern MSDisplayDesc ms_sdl_display_desc; + +#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(MEDIASTREAMER_STATIC) +#ifdef MEDIASTREAMER2_EXPORTS + #define MSVAR_DECLSPEC __declspec(dllexport) +#else + #define MSVAR_DECLSPEC __declspec(dllimport) +#endif +#else + #define MSVAR_DECLSPEC extern +#endif + +#ifdef __cplusplus +extern "C"{ +#endif + +MSVAR_DECLSPEC MSDisplayDesc ms_win_display_desc; + +MSDisplay *ms_display_new(MSDisplayDesc *desc); +void ms_display_set_window_id(MSDisplay *d, long window_id); +void ms_display_destroy(MSDisplay *d); + +#define MS_VIDEO_OUT_SET_DISPLAY MS_FILTER_METHOD(MS_VIDEO_OUT_ID,0,MSDisplay*) +#define MS_VIDEO_OUT_HANDLE_RESIZING MS_FILTER_METHOD_NO_ARG(MS_VIDEO_OUT_ID,1) +#define MS_VIDEO_OUT_SET_CORNER MS_FILTER_METHOD(MS_VIDEO_OUT_ID,2,int*) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/msvolume.h b/linphone/mediastreamer2/include/mediastreamer2/msvolume.h new file mode 100644 index 000000000..e02744f04 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/msvolume.h @@ -0,0 +1,30 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef msvolume_h +#define msvolume_h + +#include "msfilter.h" + +/*returns a volume meter in db0 (max=0 db0)*/ +#define MS_VOLUME_GET MS_FILTER_METHOD(MS_VOLUME_ID,0,float) + +extern MSFilterDesc ms_volume_desc; + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/mswebcam.h b/linphone/mediastreamer2/include/mediastreamer2/mswebcam.h new file mode 100644 index 000000000..b0e11d599 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/mswebcam.h @@ -0,0 +1,226 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef webcam_h +#define webcam_h + +#include "mscommon.h" + +/** + * @file mswebcam.h + * @brief mediastreamer2 mswebcam.h include file + * + * This file provide the API needed to manage + * soundcard filters. + * + */ + +/** + * @defgroup mediastreamer2_soundcard Sound Card API - manage audio capture/play filters. + * @ingroup mediastreamer2_api + * @{ + */ + +struct _MSWebCamManager{ + MSList *cams; +}; + +/** + * Structure for webcam manager object. + * @var MSWebCamManager + */ +typedef struct _MSWebCamManager MSWebCamManager; + + +struct _MSWebCam; + +typedef void (*MSWebCamDetectFunc)(MSWebCamManager *obj); +typedef void (*MSWebCamInitFunc)(struct _MSWebCam *obj); +typedef void (*MSWebCamUninitFunc)(struct _MSWebCam *obj); +typedef struct _MSFilter * (*MSWebCamCreateReaderFunc)(struct _MSWebCam *obj); + +struct _MSWebCamDesc{ + const char *driver_type; + MSWebCamDetectFunc detect; + MSWebCamInitFunc init; + MSWebCamCreateReaderFunc create_reader; + MSWebCamUninitFunc uninit; +}; + +/** + * Structure for sound card description object. + * @var MSWebCamDesc + */ +typedef struct _MSWebCamDesc MSWebCamDesc; + +struct _MSWebCam{ + MSWebCamDesc *desc; + char *name; + char *id; + void *data; +}; + +/** + * Structure for sound card object. + * @var MSWebCam + */ +typedef struct _MSWebCam MSWebCam; + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @defgroup mediastreamer2_webcammanager WebCam Manager API + * @ingroup mediastreamer2_webcam + * @{ + */ + +/** + * Retreive a webcam manager object. + * + * Returns: MSWebCamManager if successfull, NULL otherwise. + */ +MSWebCamManager * ms_web_cam_manager_get(void); + +/** + * Destroy a sound card manager object. + * + */ +void ms_web_cam_manager_destroy(void); + +/** + * Retreive a sound card object based on its name. + * + * @param m A sound card manager containing sound cards. + * @param id A name for card to search. + * + * Returns: MSWebCam if successfull, NULL otherwise. + */ +MSWebCam * ms_web_cam_manager_get_cam(MSWebCamManager *m, const char *id); + +/** + * Retreive the default sound card object. + * + * @param m A sound card manager containing sound cards. + * + * Returns: MSWebCam if successfull, NULL otherwise. + */ +MSWebCam * ms_web_cam_manager_get_default_cam(MSWebCamManager *m); + +/** + * Retreive the list of webcam objects. + * + * @param m A webcam manager containing webcams. + * + * Returns: MSList of cards if successfull, NULL otherwise. + */ +const MSList * ms_web_cam_manager_get_list(MSWebCamManager *m); + +/** + * Add a sound card object in a sound card manager's list. + * + * @param m A sound card manager containing sound cards. + * @param c A sound card object. + * + */ +void ms_web_cam_manager_add_cam(MSWebCamManager *m, MSWebCam *c); + +/** + * Register a sound card description in a sound card manager. + * + * @param m A sound card manager containing sound cards. + * @param desc A sound card description object. + * + */ +void ms_web_cam_manager_register_desc(MSWebCamManager *m, MSWebCamDesc *desc); + +/** @} */ + +/** + * @defgroup mediastreamer2_webcamfilter Sound Card Filter API + * @ingroup mediastreamer2_webcam + * @{ + */ + +/** + * Create an INPUT filter based on the selected camera. + * + * @param obj A sound card object. + * + * Returns: A MSFilter if successfull, NULL otherwise. + */ +struct _MSFilter * ms_web_cam_create_reader(MSWebCam *obj); + +/** + * Create a new webcam object. + * + * @param desc A webcam description object. + * + * Returns: MSWebCam if successfull, NULL otherwise. + */ +MSWebCam * ms_web_cam_new(MSWebCamDesc *desc); + +/** + * Destroy webcam object. + * + * @param obj A MSWebCam object. + */ +void ms_web_cam_destroy(MSWebCam *obj); + + +/** + * Retreive a webcam's driver type string. + * + * Internal driver types are either: "V4L V4LV2" + * + * @param obj A webcam object. + * + * Returns: a string if successfull, NULL otherwise. + */ +const char *ms_web_cam_get_driver_type(const MSWebCam *obj); + +/** + * Retreive a webcam's name. + * + * @param obj A webcam object. + * + * Returns: a string if successfull, NULL otherwise. + */ +const char *ms_web_cam_get_name(const MSWebCam *obj); + +/** + * Retreive webcam's id: ($driver_type: $name). + * + * @param obj A webcam object. + * + * Returns: A string if successfull, NULL otherwise. + */ +const char *ms_web_cam_get_string_id(MSWebCam *obj); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/linphone/mediastreamer2/include/mediastreamer2/rfc3984.h b/linphone/mediastreamer2/include/mediastreamer2/rfc3984.h new file mode 100644 index 000000000..aa9a45127 --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/rfc3984.h @@ -0,0 +1,60 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef rfc3984_h +#define rfc3984_h + +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msqueue.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +typedef struct Rfc3984Context{ + MSQueue q; + mblk_t *m; + int maxsz; + uint32_t last_ts; + uint8_t mode; + bool_t stap_a_allowed; + uint8_t reserved; +} Rfc3984Context; + +void rfc3984_init(Rfc3984Context *ctx); + +void rfc3984_set_mode(Rfc3984Context *ctx, int mode); + +/* some stupid phones don't decode STAP-A packets ...*/ +void rfc3984_enable_stap_a(Rfc3984Context *ctx, bool_t yesno); + +/*process NALUs and pack them into rtp payloads */ +void rfc3984_pack(Rfc3984Context *ctx, MSQueue *naluq, MSQueue *rtpq, uint32_t ts); + +/*process incoming rtp data and output NALUs, whenever possible*/ +void rfc3984_unpack(Rfc3984Context *ctx, mblk_t *im, MSQueue *naluq); + +void rfc3984_uninit(Rfc3984Context *ctx); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/linphone/mediastreamer2/include/mediastreamer2/waveheader.h b/linphone/mediastreamer2/include/mediastreamer2/waveheader.h new file mode 100644 index 000000000..015bf65ef --- /dev/null +++ b/linphone/mediastreamer2/include/mediastreamer2/waveheader.h @@ -0,0 +1,90 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* the following code was taken from a free software utility that I don't remember the name. */ +/* sorry */ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#ifndef waveheader_h +#define waveheader_h + +/* all integer in wav header must be read in least endian order */ +static inline uint16_t swap16(uint16_t a) +{ + return ((a & 0xFF) << 8) | ((a & 0xFF00) >> 8); +} + +static inline uint32_t swap32(uint32_t a) +{ + return ((a & 0xFF) << 24) | ((a & 0xFF00) << 8) | + ((a & 0xFF0000) >> 8) | ((a & 0xFF000000) >> 24); +} + +#ifdef WORDS_BIGENDIAN +#define le_uint32(a) (swap32((a))) +#define le_uint16(a) (swap16((a))) +#define le_int16(a) ( (int16_t) swap16((uint16_t)((a))) ) +#else +#define le_uint32(a) (a) +#define le_uint16(a) (a) +#define le_int16(a) (a) +#endif + +typedef struct _riff_t { + char riff[4] ; /* "RIFF" (ASCII characters) */ + uint32_t len ; /* Length of package (binary, little endian) */ + char wave[4] ; /* "WAVE" (ASCII characters) */ +} riff_t; + +/* The FORMAT chunk */ + +typedef struct _format_t { + char fmt[4] ; /* "fmt_" (ASCII characters) */ + uint32_t len ; /* length of FORMAT chunk (always 0x10) */ + uint16_t type; /* codec type*/ + uint16_t channel ; /* Channel numbers (0x01 = mono, 0x02 = stereo) */ + uint32_t rate ; /* Sample rate (binary, in Hz) */ + uint32_t bps ; /* Average Bytes Per Second */ + uint16_t blockalign ; /*number of bytes per sample */ + uint16_t bitpspl ; /* bits per sample */ +} format_t; + +/* The DATA chunk */ + +typedef struct _data_t { + char data[4] ; /* "data" (ASCII characters) */ + int len ; /* length of data */ +} data_t; + +typedef struct _wave_header_t +{ + riff_t riff_chunk; + format_t format_chunk; + data_t data_chunk; +} wave_header_t; + + +#define wave_header_get_rate(header) le_uint32((header)->format_chunk.rate) +#define wave_header_get_channel(header) le_uint16((header)->format_chunk.channel) +#define wave_header_get_bpsmpl(header) \ + le_uint16((header)->format_chunk.blockalign) +#endif diff --git a/linphone/mediastreamer2/mediastreamer.pc.in b/linphone/mediastreamer2/mediastreamer.pc.in new file mode 100644 index 000000000..e2c6106ef --- /dev/null +++ b/linphone/mediastreamer2/mediastreamer.pc.in @@ -0,0 +1,11 @@ +# This is a comment +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ + +Name: mediastreamer +Description: A mediastreaming library for telephony applications +Depends: ortp +Version: @MEDIASTREAMER_VERSION@ +Libs: -L@libdir@ -lmediastreamer +Cflags: -I@includedir@ diff --git a/linphone/mediastreamer2/mediastreamer2.spec.in b/linphone/mediastreamer2/mediastreamer2.spec.in new file mode 100644 index 000000000..ff1e4492e --- /dev/null +++ b/linphone/mediastreamer2/mediastreamer2.spec.in @@ -0,0 +1,81 @@ +# -*- rpm-spec -*- +# +# mediastreamer2 -- A mediastreaming library for telephony applications +# + +%ifarch %ix86 +%define mediastreamer2_cpu pentium4 +%endif + +Summary: Audio/Video real-time streaming +Name: mediastreamer2 +Version: @MEDIASTREAMER2_PKGCONFIG_VERSION@ +Release: 1 +License: LGPL +Group: Applications/Communications +URL: http://linphone.org/mediastreamer2/ +Source0: %{name}-@MEDIASTREAMER2_PKGCONFIG_VERSION@.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot +%ifarch %ix86 +BuildArch: i686 +%endif + +%description +Mediastreamer2 is a GPL licensed library to make audio and video +real-time streaming and processing. Written in pure C, it is based +upon the oRTP library. + +%package devel +Summary: Headers, libraries and docs for the mediastreamer2 library +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Mediastreamer2 is a GPL licensed library to make audio and video +real-time streaming and processing. Written in pure C, it is based +upon the ortp library. + +This package contains header files and development libraries needed to +develop programs using the mediastreamer2 library. + +%ifarch %ix86 +%define mediastreamer2_arch_cflags -malign-double -march=i686 -mcpu=%{mediastreamer2_cpu} +%else +# Must be non-empty +%define mediastreamer2_arch_cflags -Wall +%endif +%define mediastreamer2_cflags %mediastreamer2_arch_cflags -Wall -g -pipe -pthread -O3 -fomit-frame-pointer -fno-schedule-insns -fschedule-insns2 -fstrict-aliasing + +%prep +%setup -q + +%build +%configure \ +--enable-gtk-doc=no \ +--enable-shared --enable-static +make -j$RPM_BUILD_NCPUS CFLAGS="%mediastreamer2_cflags" CXXFLAGS="%mediastreamer2_cflags" + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%doc AUTHORS COPYING ChangeLog INSTALL NEWS README TODO +%{_libdir}/*.so.* + +%files devel +%defattr(-,root,root,-) +%doc docs/html +%{_libdir}/*.la +%{_libdir}/*.a +%{_libdir}/*.so +%{_libdir}/pkgconfig/*.pc +%{_includedir} + +%changelog +* Tue Oct 25 2005 Francois-Xavier Kowalski +- Add to mediastreamer2 distribution with "make rpm" target diff --git a/linphone/mediastreamer2/pkg.list b/linphone/mediastreamer2/pkg.list new file mode 100644 index 000000000..cee1171f7 --- /dev/null +++ b/linphone/mediastreamer2/pkg.list @@ -0,0 +1,43 @@ +# -*- rpm-spec -*- ############################################################ +# +# EPM list file. See epm(1) and epm.list(5) for details +# +############################################################################### + +%product ${SUMMARY} +%version ${VERSION} +%release ${RELEASE} +%description ${SUMMARY} +%vendor ${VENDOR} +%copyright ${LICENSE} +%license ${LICENSE} +%readme ${srcdir}/README +%packager ${PACKAGER} + +%system linux + +# Compress man pages +%define __spec_install_post /usr/lib/rpm/brp-compress || : + +# Package all-in one: should be split later on... +%provides ortp-devel + +%postinstall << EOF +ldconfig 2>&1 | logger -i -s -t ${PACKAGE} +makewhatis -u -w 2>&1 | logger -i -s -t ${PACKAGE} +EOF + +%postremove << EOF +ldconfig 2>&1 | logger -i -s -t ${PACKAGE} +makewhatis -u -w 2>&1 | logger -i -s -t ${PACKAGE} +EOF + +%system hpux + +%system all + +%include files.list + +%provides mediastreamer2 +%replaces mediastreamer2 + diff --git a/linphone/mediastreamer2/plugins/.cvsignore b/linphone/mediastreamer2/plugins/.cvsignore new file mode 100644 index 000000000..6cecb663c --- /dev/null +++ b/linphone/mediastreamer2/plugins/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +plugins.mk diff --git a/linphone/mediastreamer2/plugins/msilbc/AUTHORS b/linphone/mediastreamer2/plugins/msilbc/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/mediastreamer2/plugins/msilbc/COPYING b/linphone/mediastreamer2/plugins/msilbc/COPYING new file mode 100644 index 000000000..623b6258a --- /dev/null +++ b/linphone/mediastreamer2/plugins/msilbc/COPYING @@ -0,0 +1,340 @@ + 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/linphone/mediastreamer2/plugins/msilbc/ChangeLog b/linphone/mediastreamer2/plugins/msilbc/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/mediastreamer2/plugins/msilbc/INSTALL b/linphone/mediastreamer2/plugins/msilbc/INSTALL new file mode 100644 index 000000000..23e5f25d0 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msilbc/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/linphone/mediastreamer2/plugins/msilbc/Makefile.am b/linphone/mediastreamer2/plugins/msilbc/Makefile.am new file mode 100644 index 000000000..34b360d4c --- /dev/null +++ b/linphone/mediastreamer2/plugins/msilbc/Makefile.am @@ -0,0 +1,11 @@ +EXTRA_DIST=ilbc-rfc3951.tar.gz + +plugindir=$(PACKAGE_PLUGINS_DIR) + +plugin_LTLIBRARIES=libmsilbc.la + +libmsilbc_la_SOURCES=ilbc.c + +libmsilbc_la_LIBADD=$(ILBC_LIBS) + +AM_CFLAGS=$(ILBC_CFLAGS) \ No newline at end of file diff --git a/linphone/mediastreamer2/plugins/msilbc/NEWS b/linphone/mediastreamer2/plugins/msilbc/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/mediastreamer2/plugins/msilbc/README b/linphone/mediastreamer2/plugins/msilbc/README new file mode 100644 index 000000000..e18f0b05a --- /dev/null +++ b/linphone/mediastreamer2/plugins/msilbc/README @@ -0,0 +1,13 @@ + + +* compile and install the ilbc source: + tar -xvzf ilbc-rfc3951.tar.gz + cd ilbc-rfc2951 + ./configure --prefix=/usr && make + make install (as root) + cd .. + +* compile and install the plugin: + ./configure --prefix= + make + make install diff --git a/linphone/mediastreamer2/plugins/msilbc/configure.ac b/linphone/mediastreamer2/plugins/msilbc/configure.ac new file mode 100644 index 000000000..d8418f211 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msilbc/configure.ac @@ -0,0 +1,152 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([msilbc],[2.0.0]) + +AM_INIT_AUTOMAKE([tar-ustar]) + +AC_CANONICAL_SYSTEM + +AC_MSG_CHECKING([warning make an error on compilation]) +AC_ARG_ENABLE(strict, +[ --enable-strict Enable error on compilation warning [default=yes]], +[wall_werror=$enableval], +[wall_werror=yes] +) + + +AC_ARG_ENABLE(debug, + [ --enable-debug=[yes/no] enables the display of traces showing the execution of the library. [default=yes]], + [case "${enableval}" in + yes) debug_enabled=yes;; + no) debug_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-debug");; + esac], + [debug_enabled=no] ) + + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) + +if test "$GCC" != "yes" ; then + case $host_os in + *hpux*) + dnl we are probably using HPUX cc compiler, so add a +O2 to CFLAGS + CFLAGS="$CFLAGS +O2 -g " + ;; + esac +else + CFLAGS="$CFLAGS -Wall" +fi + + + +if test $debug_enabled = "yes"; then + CFLAGS="$CFLAGS -DDEBUG" +fi + +dnl Checks for header files. +AC_HEADER_STDC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_HEADER_TIME +AC_WORDS_BIGENDIAN +if test x$ac_cv_c_bigendian = xyes ; then + CFLAGS="$CFLAGS -D_BIGENDIAN" +fi + +if test $GCC = yes && test $wall_werror = yes; then + CFLAGS="$CFLAGS -Werror " +fi + +PKG_CHECK_MODULES(MEDIASTREAMER, mediastreamer >= 2.0.0) + +AC_ARG_WITH( ilbc, + [ --with-ilbc Sets the installation prefix of ilbc codec, [default=/usr] ], + [ ilbcdir=${withval}],[ ilbcdir=/usr ]) + +if test "$ilbcdir" != "/usr" ; then + ILBC_CFLAGS="$ilbcdir/include" + ILBC_LIBS="$ilbcdir/lib" +fi +ILBC_LIBS="$ILBC_LIBS -lilbc" + +AC_SUBST(ILBC_CFLAGS) +AC_SUBST(ILBC_LIBS) + +CFLAGS="$CFLAGS \$(MEDIASTREAMER_CFLAGS) " +LIBS="$LIBS \$(MEDIASTREAMER_LIBS) " +LDFLAGS="$LDFLAGS -rdynamic " + +dnl define path of plugins: +PACKAGE_PLUGINS_DIR=`eval echo $prefix/lib/mediastreamer/plugins` +AC_DEFINE_UNQUOTED(PACKAGE_PLUGINS_DIR, "$PACKAGE_PLUGINS_DIR" ,[path of plugins]) +AC_SUBST(PACKAGE_PLUGINS_DIR) + +dnl ################################################## +dnl # Check for ESP Packager +dnl ################################################## + +AC_PATH_PROG(EPM,epm,false) +AC_PATH_PROG(MKEPMLIST,mkepmlist,false) +AC_PATH_PROG(EPMINSTALL,epminstall,false) +AM_CONDITIONAL(WITH_EPM,test $EPM != false && test $MKEPMLIST != false && test $EPMINSTALL != false) + + +# Preferred packaging system, as per EPM terminology +case $target in +*-*-linux*) + if test -f /etc/debian_version ; then + EPM_PKG_EXT=deb + else + EPM_PKG_EXT=rpm + fi + ;; +*-hp-hpux*) + EPM_PKG_EXT=depot.gz;; +*-dec-osf*) + EPM_PKG_EXT=setld;; +esac +AC_SUBST(EPM_PKG_EXT) + +# System software User & Group names +case $target in +*-*-linux*) + SYS_USER=root + SYS_GROUP=root + ;; +*-*-hpux*|*-dec-osf*) + SYS_USER=bin + SYS_GROUP=bin + ;; +esac +AC_SUBST(SYS_USER) +AC_SUBST(SYS_GROUP) + +# CPU Architecture +case $target_cpu in +i?86) ARCH=i386;; +*) ARCH=$target_cpu;; +esac +AC_SUBST(ARCH) + +# Various other packaging variables, that can be over-ridden ad `make +# package' time +SUMMARY="A mediastreamer plugin." +AC_SUBST(SUMMARY) +PACKAGER=anonymous +AC_SUBST(PACKAGER) +LICENSE=GPL +AC_SUBST(LICENSE) +VENDOR=Linphone +AC_SUBST(VENDOR) +RELEASE=1 +AC_SUBST(RELEASE) + + +AC_OUTPUT( +Makefile +) diff --git a/linphone/mediastreamer2/plugins/msilbc/ilbc-rfc3951.tar.gz b/linphone/mediastreamer2/plugins/msilbc/ilbc-rfc3951.tar.gz new file mode 100644 index 000000000..e5160f402 Binary files /dev/null and b/linphone/mediastreamer2/plugins/msilbc/ilbc-rfc3951.tar.gz differ diff --git a/linphone/mediastreamer2/plugins/msilbc/ilbc.c b/linphone/mediastreamer2/plugins/msilbc/ilbc.c new file mode 100644 index 000000000..9a6b43e38 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msilbc/ilbc.c @@ -0,0 +1,283 @@ +/* + NO LICENSE +*/ +#include +#include + +#include "mediastreamer2/msfilter.h" + +typedef struct EncState{ + int nsamples; + int nbytes; + int ms_per_frame; + int ptime; + uint32_t ts; + MSBufferizer bufferizer; + iLBC_Enc_Inst_t ilbc_enc; +}EncState; + +static void enc_init(MSFilter *f){ + EncState *s=ms_new(EncState,1); + s->nsamples=BLOCKL_20MS; + s->nbytes=NO_OF_BYTES_20MS; + s->ms_per_frame=20; + s->ptime=0; + s->ts=0; + ms_bufferizer_init(&s->bufferizer); + f->data=s; +} + +static void enc_uninit(MSFilter *f){ + EncState *s=(EncState*)f->data; + ms_bufferizer_uninit(&s->bufferizer); + ms_free(f->data); +} + +static void enc_preprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + initEncode(&s->ilbc_enc,s->ms_per_frame); +} + +static int enc_add_fmtp(MSFilter *f, void *arg){ + char buf[64]; + const char *fmtp=(const char *)arg; + EncState *s=(EncState*)f->data; + + memset(buf, '\0', sizeof(buf)); + fmtp_get_value(fmtp, "mode", buf, sizeof(buf)); + if (buf[0]=='\0'){ + ms_warning("unsupported fmtp parameter (%s)!", fmtp); + } + else if (strstr(buf,"20")!=NULL){ + s->nsamples=BLOCKL_20MS; + s->nbytes=NO_OF_BYTES_20MS; + s->ms_per_frame=20; + }else if (strstr(buf,"30")!=NULL){ + s->nsamples=BLOCKL_30MS; + s->nbytes=NO_OF_BYTES_30MS; + s->ms_per_frame=30; + } + return 0; +} + +static int enc_add_attr(MSFilter *f, void *arg){ + const char *fmtp=(const char *)arg; + EncState *s=(EncState*)f->data; + if (strstr(fmtp,"ptime:20")!=NULL){ + s->ptime=20; + }else if (strstr(fmtp,"ptime:30")!=NULL){ + s->ptime=30; + }else if (strstr(fmtp,"ptime:40")!=NULL){ + s->ptime=40; + }else if (strstr(fmtp,"ptime:60")!=NULL){ + s->ptime=60; + }else if (strstr(fmtp,"ptime:80")!=NULL){ + s->ptime=80; + }else if (strstr(fmtp,"ptime:90")!=NULL){ + s->ptime=90; + }else if (strstr(fmtp,"ptime:100")!=NULL){ + s->ptime=100; + }else if (strstr(fmtp,"ptime:120")!=NULL){ + s->ptime=120; + }else if (strstr(fmtp,"ptime:140")!=NULL){ + s->ptime=140; + } + return 0; +} + +static void enc_process(MSFilter *f){ + EncState *s=(EncState*)f->data; + mblk_t *im,*om; + int size=s->nsamples*2; + int16_t samples[1610]; /* BLOCKL_MAX * 7 is the largest size for ptime == 140 */ + float samples2[BLOCKL_MAX]; + int i; + int frame_per_packet=1; + + if (s->ptime>=20 && s->ms_per_frame>0 && s->ptime%s->ms_per_frame==0) + { + frame_per_packet = s->ptime/s->ms_per_frame; + } + + if (frame_per_packet<=0) + frame_per_packet=1; + if (frame_per_packet>7) /* 7*20 == 140 ms max */ + frame_per_packet=7; + + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + ms_bufferizer_put(&s->bufferizer,im); + } + while(ms_bufferizer_read(&s->bufferizer,(uint8_t*)samples,size*frame_per_packet)==(size*frame_per_packet)){ + int k; + om=allocb(s->nbytes*frame_per_packet,0); + for (k=0;knsamples;i++){ + samples2[i]=samples[i+(s->nsamples*k)]; + } + iLBC_encode((uint8_t*)om->b_wptr,samples2,&s->ilbc_enc); + om->b_wptr+=s->nbytes; + s->ts+=s->nsamples; + } + mblk_set_timestamp_info(om,s->ts-s->nsamples); + ms_queue_put(f->outputs[0],om); + } +} + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_ADD_FMTP, enc_add_fmtp }, + { MS_FILTER_ADD_ATTR, enc_add_attr}, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_ilbc_enc_desc={ + MS_FILTER_PLUGIN_ID, + "MSIlbcEnc", + "iLBC encoder", + MS_FILTER_ENCODER, + "iLBC", + 1, + 1, + enc_init, + enc_preprocess, + enc_process, + NULL, + enc_uninit, + enc_methods +}; + +#else + +MSFilterDesc ms_ilbc_enc_desc={ + .id=MS_FILTER_PLUGIN_ID, + .name="MSIlbcEnc", + .text="iLBC encoder", + .category=MS_FILTER_ENCODER, + .enc_fmt="iLBC", + .ninputs=1, + .noutputs=1, + .init=enc_init, + .preprocess=enc_preprocess, + .process=enc_process, + .uninit=enc_uninit, + .methods=enc_methods +}; + +#endif + +typedef struct DecState{ + int nsamples; + int nbytes; + int ms_per_frame; + iLBC_Dec_Inst_t ilbc_dec; +}DecState; + + +static void dec_init(MSFilter *f){ + DecState *s=ms_new(DecState,1); + s->nsamples=0; + s->nbytes=0; + s->ms_per_frame=0; + f->data=s; +} + +static void dec_uninit(MSFilter *f){ + ms_free(f->data); +} + +static void dec_process(MSFilter *f){ + DecState *s=(DecState*)f->data; + mblk_t *im,*om; + int nbytes; + float samples[BLOCKL_MAX]; + int i; + + while ((im=ms_queue_get(f->inputs[0]))!=NULL){ + nbytes=msgdsize(im); + if (nbytes<=0) + return; + if (nbytes%38!=0 && nbytes%50!=0) + return; + if (nbytes%38==0 && s->nbytes!=NO_OF_BYTES_20MS) + { + /* not yet configured, or misconfigured */ + s->ms_per_frame=20; + s->nbytes=NO_OF_BYTES_20MS; + s->nsamples=BLOCKL_20MS; + initDecode(&s->ilbc_dec,s->ms_per_frame,0); + } + else if (nbytes%50==0 && s->nbytes!=NO_OF_BYTES_30MS) + { + /* not yet configured, or misconfigured */ + s->ms_per_frame=30; + s->nbytes=NO_OF_BYTES_30MS; + s->nsamples=BLOCKL_30MS; + initDecode(&s->ilbc_dec,s->ms_per_frame,0); + } + if (s->nbytes>0 && nbytes>=s->nbytes){ + int frame_per_packet = nbytes/s->nbytes; + int k; + + for (k=0;knsamples*2,0); + iLBC_decode(samples,(uint8_t*)im->b_rptr+(k*s->nbytes),&s->ilbc_dec,1); + for (i=0;insamples;i++,om->b_wptr+=2){ + *((int16_t*)om->b_wptr)=samples[i]; + } + ms_queue_put(f->outputs[0],om); + } + }else{ + ms_warning("bad iLBC frame !"); + } + freemsg(im); + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_ilbc_dec_desc={ + MS_FILTER_PLUGIN_ID, + "MSIlbcDec", + "iLBC decoder", + MS_FILTER_DECODER, + "iLBC", + 1, + 1, + dec_init, + NULL, + dec_process, + NULL, + dec_uninit, + NULL +}; + +#else + +MSFilterDesc ms_ilbc_dec_desc={ + .id=MS_FILTER_PLUGIN_ID, + .name="MSIlbcDec", + .text="iLBC decoder", + .category=MS_FILTER_DECODER, + .enc_fmt="iLBC", + .ninputs=1, + .noutputs=1, + .init=dec_init, + .process=dec_process, + .uninit=dec_uninit +}; + +#endif + +#ifdef _MSC_VER +#define MS_PLUGIN_DECLARE(type) __declspec(dllexport) type +#else +#define MS_PLUGIN_DECLARE(type) type +#endif + +MS_PLUGIN_DECLARE(void) libmsilbc_init(){ + ms_filter_register(&ms_ilbc_enc_desc); + ms_filter_register(&ms_ilbc_dec_desc); +} diff --git a/linphone/mediastreamer2/plugins/msx264/AUTHORS b/linphone/mediastreamer2/plugins/msx264/AUTHORS new file mode 100644 index 000000000..16d2ea646 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/AUTHORS @@ -0,0 +1 @@ +Simon Morlat \ No newline at end of file diff --git a/linphone/mediastreamer2/plugins/msx264/COPYING b/linphone/mediastreamer2/plugins/msx264/COPYING new file mode 100644 index 000000000..623b6258a --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/COPYING @@ -0,0 +1,340 @@ + 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/linphone/mediastreamer2/plugins/msx264/ChangeLog b/linphone/mediastreamer2/plugins/msx264/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/mediastreamer2/plugins/msx264/INSTALL b/linphone/mediastreamer2/plugins/msx264/INSTALL new file mode 100644 index 000000000..d3c5b40a9 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/INSTALL @@ -0,0 +1,237 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/linphone/mediastreamer2/plugins/msx264/Makefile.am b/linphone/mediastreamer2/plugins/msx264/Makefile.am new file mode 100644 index 000000000..5cb64b1c7 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/Makefile.am @@ -0,0 +1,3 @@ +EXTRA_DIST=autogen.sh + +SUBDIRS=src diff --git a/linphone/mediastreamer2/plugins/msx264/NEWS b/linphone/mediastreamer2/plugins/msx264/NEWS new file mode 100644 index 000000000..5b0622361 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/NEWS @@ -0,0 +1,2 @@ +Wednesday August 20, 2008: msx264-1.1.0 + - compiled together with x264-snapshot-20080421-2245+multislicing-patch.tar.gz, allows packetization-mode=0 diff --git a/linphone/mediastreamer2/plugins/msx264/README b/linphone/mediastreamer2/plugins/msx264/README new file mode 100644 index 000000000..6836540f6 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/README @@ -0,0 +1,17 @@ +msx264 - a GPL plugin to bring video H264 encoding/decoding capabilities to mediastreamer2 applications. +It is based on ffmpeg for decoding and x264 for encoding. + +It works with any version of x264. However if you want better performance and interroperability, it is +highly recommended to use a modified x264 version patched with the patch mentionned here: +http://mailman.videolan.org/pipermail/x264-devel/2008-April/004427.html + +Unfortunately for bad reasons this patch hasn't been merged by x264 developpers, and no more applies with +recent versions. + +This patch enables multi-slicing, ie smaller video packets that fit into the network mtu. +It enable RFC3984 packetization-mode=0 to work. +A x264 version modified by this patch can be found here: +http://download.savannah.gnu.org/releases/linphone/plugins/sources/x264-snapshot-20080421-2245+multislicing-patch.tar.gz + +So compile x264-snapshot-20080421-2245+multislicing-patch.tar.gz with ./configure && make && make install +Then compile msx264 with ./configure --enable-hacked-x264 && make && make install diff --git a/linphone/mediastreamer2/plugins/msx264/autogen.sh b/linphone/mediastreamer2/plugins/msx264/autogen.sh new file mode 100755 index 000000000..d342f286b --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/autogen.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +#AM_VERSION=1.10 +#1.9 was the recommended version +if test -n "$AM_VERSION" ; then + ACLOCAL=aclocal-${AM_VERSION} + AUTOMAKE=automake-${AM_VERSION} +else + ACLOCAL=aclocal + AUTOMAKE=automake +fi + +echo "Generating build scripts in this mediastreamer plugin" +set -x +libtoolize --copy --force +$ACLOCAL +$AUTOMAKE --force-missing --add-missing --copy +autoconf +rm -rf config.cache + diff --git a/linphone/mediastreamer2/plugins/msx264/configure.ac b/linphone/mediastreamer2/plugins/msx264/configure.ac new file mode 100644 index 000000000..ce3083822 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/configure.ac @@ -0,0 +1,143 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([msx264],[1.1.2]) + +AM_INIT_AUTOMAKE([tar-ustar]) + +AC_CANONICAL_SYSTEM + +AC_MSG_CHECKING([warning make an error on compilation]) +AC_ARG_ENABLE(strict, +[ --enable-strict Enable error on compilation warning [default=yes]], +[wall_werror=$enableval], +[wall_werror=yes] +) + + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) + + +CFLAGS="$CFLAGS -Wall" + + +dnl Checks for header files. +AC_HEADER_STDC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_HEADER_TIME +AC_WORDS_BIGENDIAN +if test x$ac_cv_c_bigendian = xyes ; then + CFLAGS="$CFLAGS -D_BIGENDIAN" +fi + +if test $GCC = yes && test $wall_werror = yes; then + CFLAGS="$CFLAGS -Werror " +fi + +PKG_CHECK_MODULES(MEDIASTREAMER, mediastreamer >= 2.1.0) + +PKG_CHECK_MODULES(X264, x264 >= 0.58.0) + +AC_ARG_ENABLE(hacked-x264, +[ --enable-hacked-x264 Turn on compilation over a patched x264 that allows multislicing [default=no]], +[hacked_x264=$enableval], +[hacked_x264=no] +) + +dnl test for ffmpeg presence +PKG_CHECK_MODULES(FFMPEG, [libavcodec >= 50.0.0 ],ffmpeg_found=yes , ffmpeg_found=no) +dnl workaround for debian... +PKG_CHECK_MODULES(FFMPEG, [libavcodec >= 0d.50.0.0 ], ffmpeg_found=yes, ffmpeg_found=no) +if test x$ffmpeg_found = xno ; then + AC_MSG_ERROR([Could not find ffmpeg headers and library. This is mandatory for video support]) +fi + +dnl check for new/old ffmpeg header file layout +CPPFLAGS_save=$CPPFLAGS +CPPFLAGS=$FFMPEG_CFLAGS +AC_CHECK_HEADERS(libavcodec/avcodec.h) +CPPFLAGS=$CPPFLAGS_save + +CFLAGS="$CFLAGS \$(MEDIASTREAMER_CFLAGS) \$(FFMPEG_CFLAGS)" +if test "$hacked_x264" = "yes" ; then + AC_MSG_WARN([Trying to compile with multislicing patched version of X264]) + CFLAGS="$CFLAGS -DHACKED_X264" +fi + +LIBS="$LIBS \$(X264_LIBS) " +LDFLAGS="$LDFLAGS -rdynamic " + +dnl define path of plugins: +PACKAGE_PLUGINS_DIR="\$(libdir)/mediastreamer/plugins" +AC_SUBST(PACKAGE_PLUGINS_DIR) + +dnl ################################################## +dnl # Check for ESP Packager +dnl ################################################## + +AC_PATH_PROG(EPM,epm,false) +AC_PATH_PROG(MKEPMLIST,mkepmlist,false) +AC_PATH_PROG(EPMINSTALL,epminstall,false) +AM_CONDITIONAL(WITH_EPM,test $EPM != false && test $MKEPMLIST != false && test $EPMINSTALL != false) + + +# Preferred packaging system, as per EPM terminology +case $target in +*-*-linux*) + if test -f /etc/debian_version ; then + EPM_PKG_EXT=deb + else + EPM_PKG_EXT=rpm + fi + ;; +*-hp-hpux*) + EPM_PKG_EXT=depot.gz;; +*-dec-osf*) + EPM_PKG_EXT=setld;; +esac +AC_SUBST(EPM_PKG_EXT) + +# System software User & Group names +case $target in +*-*-linux*) + SYS_USER=root + SYS_GROUP=root + ;; +*-*-hpux*|*-dec-osf*) + SYS_USER=bin + SYS_GROUP=bin + ;; +esac +AC_SUBST(SYS_USER) +AC_SUBST(SYS_GROUP) + +# CPU Architecture +case $target_cpu in +i?86) ARCH=i386;; +*) ARCH=$target_cpu;; +esac +AC_SUBST(ARCH) + +# Various other packaging variables, that can be over-ridden ad `make +# package' time +SUMMARY="A H264 codec mediastreamer plugin" +AC_SUBST(SUMMARY) +PACKAGER=anonymous +AC_SUBST(PACKAGER) +LICENSE=GPL +AC_SUBST(LICENSE) +VENDOR=Linphone +AC_SUBST(VENDOR) +RELEASE=1 +AC_SUBST(RELEASE) + + +AC_OUTPUT( +Makefile +src/Makefile +) diff --git a/linphone/mediastreamer2/plugins/msx264/msx264.dev b/linphone/mediastreamer2/plugins/msx264/msx264.dev new file mode 100755 index 000000000..c27baaaa2 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/msx264.dev @@ -0,0 +1,95 @@ +[Project] +FileName=msx264.dev +Name=msx264 +UnitCount=1 +PchHead=-1 +PchSource=-1 +Ver=3 +IsCpp=1 +ProfilesCount=2 +ProfileIndex=0 +Folders= + +[Unit1] +FileName=src\msx264.c +CompileCpp=0 +Folder=msx264 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription= +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 + +[Profile1] +ProfileName=MingW 3.4.2 +Type=3 +ObjFiles= +Includes=../../include;../../../oRTP/include;../../../../linphone-deps/include +Libs=../../../../linphone-deps/lib;../../../mediastreamer2/build/win32native;../../../oRTP/build/win32native +ResourceIncludes= +MakeIncludes= +Compiler=-DBUILDING_DLL=1_@@_-DORTP_INET6_@@_-DHAVE_LIBAVCODEC_AVCODEC_H_@@_-DHACKED_X264_@@_ +CppCompiler=-DBUILDING_DLL=1_@@_ +Linker=-no-undefined_@@_--enable-runtime-pseudo-reloc_@@_-lx264_@@_-lmediastreamer2_@@_-lortp_@@_-lavcodec_@@_ +PreprocDefines= +CompilerSettings=0000000001001000000000 +Icon= +ExeOutput= +ObjectOutput=Output\MingW +OverrideOutput=1 +OverrideOutputName=libmsx264.dll +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + +[Profile2] +ProfileName=Visual C++ 2005 +Type=3 +ObjFiles= +Includes= +Libs= +ResourceIncludes= +MakeIncludes= +Compiler=/DBUILDING_DLL=1 +CppCompiler=/DBUILDING_DLL=1 +Linker= +PreprocDefines= +CompilerSettings=000000000000010000000000000000000000 +Icon= +ExeOutput=Output\Visual C++ 2005 +ObjectOutput=Objects\Visual C++ 2005 +OverrideOutput=0 +OverrideOutputName= +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=1 +compilerType=1 + diff --git a/linphone/mediastreamer2/plugins/msx264/msx264.iss b/linphone/mediastreamer2/plugins/msx264/msx264.iss new file mode 100755 index 000000000..faeea2fe0 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/msx264.iss @@ -0,0 +1,35 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=msx264 +AppVerName=msx264 H.264 plugin for linphone. Plugin version is 1.1.2. +AppPublisher=linphone.org +AppPublisherURL=http://www.linphone.org +AppSupportURL=http://www.linphone.org +AppUpdatesURL=http://www.linphone.org +DefaultDirName={pf}\Linphone +DefaultGroupName=Linphone +LicenseFile=C:\Documents and Settings\simorl.EMEA\cvs\linphone\mediastreamer2\plugins\msx264\COPYING +InfoBeforeFile=C:\Documents and Settings\simorl.EMEA\cvs\linphone\mediastreamer2\plugins\msx264\README +OutputBaseFilename=setup +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +;Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "C:\Documents and Settings\simorl.EMEA\cvs\linphone\mediastreamer2\plugins\msx264\libmsx264.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +;Name: "{group}\Linphone"; Filename: "{app}\linphone-wx.exe" ; WorkingDir: "{app}" +;Name: "{userdesktop}\Linphone"; Filename: "{app}\linphone-wx.exe"; WorkingDir: "{app}" ; Tasks: desktopicon + +[Run] +;Filename: "{app}\linphone-wx.exe"; Description: "{cm:LaunchProgram,Linphone}"; WorkingDir: "{app}" ; Flags: nowait postinstall skipifsilent + diff --git a/linphone/mediastreamer2/plugins/msx264/src/Makefile.am b/linphone/mediastreamer2/plugins/msx264/src/Makefile.am new file mode 100644 index 000000000..88b3f2415 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/src/Makefile.am @@ -0,0 +1,6 @@ +pluginsdir=$(PACKAGE_PLUGINS_DIR) + +plugins_LTLIBRARIES=libmsx264.la + +libmsx264_la_SOURCES=msx264.c + diff --git a/linphone/mediastreamer2/plugins/msx264/src/msx264.c b/linphone/mediastreamer2/plugins/msx264/src/msx264.c new file mode 100644 index 000000000..327500281 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msx264/src/msx264.c @@ -0,0 +1,517 @@ +/* +mediastreamer2 x264 plugin +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/rfc3984.h" + +#include "ortp/b64.h" + +#include + +#ifdef HAVE_LIBAVCODEC_AVCODEC_H +#include +#include +#else +#include +#include +#endif + +#define REMOVE_PREVENTING_BYTES 1 + +typedef struct _EncData{ + x264_t *enc; + MSVideoSize vsize; + int bitrate; + float fps; + int mode; + uint64_t framenum; + Rfc3984Context packer; + bool_t generate_keyframe; +}EncData; + + +static void enc_init(MSFilter *f){ + EncData *d=ms_new(EncData,1); + d->enc=NULL; + d->bitrate=384000; + d->vsize=MS_VIDEO_SIZE_CIF; + d->fps=30; + d->mode=0; + d->framenum=0; + d->generate_keyframe=FALSE; + f->data=d; +} + +static void enc_uninit(MSFilter *f){ + EncData *d=(EncData*)f->data; + ms_free(d); +} + +static void enc_preprocess(MSFilter *f){ + EncData *d=(EncData*)f->data; + x264_param_t params; + rfc3984_init(&d->packer); + rfc3984_set_mode(&d->packer,d->mode); + rfc3984_enable_stap_a(&d->packer,FALSE); + x264_param_default(¶ms); + params.i_width=d->vsize.width; + params.i_height=d->vsize.height; + params.i_fps_num=(int)d->fps; + params.i_fps_den=1; +#ifdef HACKED_X264 + ms_message("Lucky guy, you have a hacked x264 lib that allows multislicing !"); + params.slice_size_threshold=ms_get_payload_max_size()-100; /*-100 security margin*/ +#endif + /*params.i_level_idc=10;*/ + params.rc.i_rc_method = X264_RC_ABR; + params.rc.i_bitrate=(int)( ( ((float)d->bitrate)*0.8)/1000.0); + params.rc.f_rate_tolerance=0.1; + params.rc.i_vbv_max_bitrate=(int) (((float)d->bitrate)*0.9/1000.0); + params.rc.i_vbv_buffer_size=params.rc.i_vbv_max_bitrate; + params.rc.f_vbv_buffer_init=0.5; + params.b_repeat_headers=1; + params.b_cabac=0;//disable cabac to be baseline + params.i_bframe=0;/*no B frames*/ + d->enc=x264_encoder_open(¶ms); + if (d->enc==NULL) ms_error("Fail to create x264 encoder."); + d->framenum=0; +} + +static void x264_nals_to_msgb(x264_nal_t *xnals, int num_nals, MSQueue * nalus){ + int i; + mblk_t *m; + /*int bytes;*/ + for (i=0;ib_wptr, &bytes, 0, &xnals[i] ); + m->b_wptr+=bytes; + */ + *m->b_wptr=( 0x00 << 7 ) | ( xnals[i].i_ref_idc << 5 ) | xnals[i].i_type; + m->b_wptr++; + memcpy(m->b_wptr,xnals[i].p_payload,xnals[i].i_payload); + m->b_wptr+=xnals[i].i_payload; + if (xnals[i].i_type==7) { + ms_message("A SPS is being sent."); + }else if (xnals[i].i_type==8) { + ms_message("A PPS is being sent."); + } + ms_queue_put(nalus,m); + } +} + +static void enc_process(MSFilter *f){ + EncData *d=(EncData*)f->data; + uint32_t ts=f->ticker->time*90LL; + mblk_t *im; + MSPicture pic; + MSQueue nalus; + ms_queue_init(&nalus); + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + if (yuv_buf_init_from_mblk(&pic,im)==0){ + x264_picture_t xpic; + x264_picture_t oxpic; + x264_nal_t *xnals=NULL; + int num_nals=0; + + if (d->generate_keyframe){ + xpic.i_type=X264_TYPE_IDR; + d->generate_keyframe=FALSE; + }else xpic.i_type=X264_TYPE_AUTO; + xpic.i_qpplus1=0; + xpic.i_pts=d->framenum; + xpic.img.i_csp=X264_CSP_I420; + xpic.img.i_plane=3; + xpic.img.i_stride[0]=pic.strides[0]; + xpic.img.i_stride[1]=pic.strides[1]; + xpic.img.i_stride[2]=pic.strides[2]; + xpic.img.i_stride[3]=0; + xpic.img.plane[0]=pic.planes[0]; + xpic.img.plane[1]=pic.planes[1]; + xpic.img.plane[2]=pic.planes[2]; + xpic.img.plane[3]=0; + if (x264_encoder_encode(d->enc,&xnals,&num_nals,&xpic,&oxpic)==0){ + x264_nals_to_msgb(xnals,num_nals,&nalus); + rfc3984_pack(&d->packer,&nalus,f->outputs[0],ts); + d->framenum++; + }else{ + ms_error("x264_encoder_encode() error."); + } + } + freemsg(im); + } +} + +static void enc_postprocess(MSFilter *f){ + EncData *d=(EncData*)f->data; + rfc3984_uninit(&d->packer); + if (d->enc!=NULL){ + x264_encoder_close(d->enc); + d->enc=NULL; + } +} + +static int enc_set_br(MSFilter *f, void *arg){ + EncData *d=(EncData*)f->data; + d->bitrate=*(int*)arg; + if (d->bitrate>=384000){ + d->vsize=MS_VIDEO_SIZE_CIF; + d->fps=30; + }else if (d->bitrate>=256000){ + d->vsize=MS_VIDEO_SIZE_CIF; + d->fps=15; + }else if (d->bitrate>=128000){ + d->vsize=MS_VIDEO_SIZE_CIF; + d->fps=15; + }else if (d->bitrate>=64000){ + d->vsize=MS_VIDEO_SIZE_CIF; + d->fps=10; + }else if (d->bitrate>=32000){ + d->vsize=MS_VIDEO_SIZE_QCIF; + d->fps=10; + }else{ + d->vsize=MS_VIDEO_SIZE_QCIF; + d->fps=5; + } + ms_message("bitrate set to %i",d->bitrate); + return 0; +} + +static int enc_set_fps(MSFilter *f, void *arg){ + EncData *d=(EncData*)f->data; + d->fps=*(float*)arg; + return 0; +} + +static int enc_get_fps(MSFilter *f, void *arg){ + EncData *d=(EncData*)f->data; + *(float*)arg=d->fps; + return 0; +} + +static int enc_get_vsize(MSFilter *f, void *arg){ + EncData *d=(EncData*)f->data; + *(MSVideoSize*)arg=d->vsize; + return 0; +} + +static int enc_add_fmtp(MSFilter *f, void *arg){ + EncData *d=(EncData*)f->data; + const char *fmtp=(const char *)arg; + char value[12]; + if (fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){ + d->mode=atoi(value); + ms_message("packetization-mode set to %i",d->mode); + } + return 0; +} + +static int enc_req_vfu(MSFilter *f, void *arg){ + EncData *d=(EncData*)f->data; + d->generate_keyframe=TRUE; + return 0; +} + + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_SET_FPS , enc_set_fps }, + { MS_FILTER_SET_BITRATE , enc_set_br }, + { MS_FILTER_GET_FPS , enc_get_fps }, + { MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize }, + { MS_FILTER_ADD_FMTP , enc_add_fmtp }, + { MS_FILTER_REQ_VFU , enc_req_vfu }, + { 0 , NULL } +}; + +static MSFilterDesc x264_enc_desc={ + .id=MS_FILTER_PLUGIN_ID, + .name="MSX264Enc", + .text="A H264 encoder based on x264 project.", + .category=MS_FILTER_ENCODER, + .enc_fmt="H264", + .ninputs=1, + .noutputs=1, + .init=enc_init, + .preprocess=enc_preprocess, + .process=enc_process, + .postprocess=enc_postprocess, + .uninit=enc_uninit, + .methods=enc_methods +}; + +typedef struct _DecData{ + mblk_t *yuv_msg; + mblk_t *sps,*pps; + Rfc3984Context unpacker; + MSPicture outbuf; + struct SwsContext *sws_ctx; + AVCodecContext av_context; + unsigned int packet_num; + uint8_t bitstream[65000]; +}DecData; + +static void ffmpeg_init(){ + static bool_t done=FALSE; + if (!done){ + avcodec_init(); + avcodec_register_all(); + done=TRUE; + } +} + +static void dec_open(DecData *d){ + AVCodec *codec; + int error; + codec=avcodec_find_decoder(CODEC_ID_H264); + if (codec==NULL) ms_fatal("Could not find H264 decoder in ffmpeg."); + avcodec_get_context_defaults(&d->av_context); + error=avcodec_open(&d->av_context,codec); + if (error!=0){ + ms_fatal("avcodec_open() failed."); + } +} + +static void dec_init(MSFilter *f){ + DecData *d=(DecData*)ms_new(DecData,1); + ffmpeg_init(); + d->yuv_msg=NULL; + d->sps=NULL; + d->pps=NULL; + d->sws_ctx=NULL; + rfc3984_init(&d->unpacker); + d->packet_num=0; + dec_open(d); + d->outbuf.w=0; + d->outbuf.h=0; + f->data=d; +} + +static void dec_reinit(DecData *d){ + avcodec_close(&d->av_context); + dec_open(d); +} + +static void dec_uninit(MSFilter *f){ + DecData *d=(DecData*)f->data; + rfc3984_uninit(&d->unpacker); + avcodec_close(&d->av_context); + if (d->yuv_msg) freemsg(d->yuv_msg); + if (d->sps) freemsg(d->sps); + if (d->pps) freemsg(d->pps); + ms_free(d); +} + +static mblk_t *get_as_yuvmsg(MSFilter *f, DecData *s, AVFrame *orig){ + AVCodecContext *ctx=&s->av_context; + + if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){ + if (s->sws_ctx!=NULL){ + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + freemsg(s->yuv_msg); + s->yuv_msg=NULL; + } + ms_message("Getting yuv picture of %ix%i",ctx->width,ctx->height); + s->yuv_msg=yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height); + s->outbuf.w=ctx->width; + s->outbuf.h=ctx->height; + s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt, + ctx->width,ctx->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, + NULL, NULL, NULL); + } + if (sws_scale(s->sws_ctx,orig->data,orig->linesize, 0, + ctx->height, s->outbuf.planes, s->outbuf.strides)<0){ + ms_error("%s: error in sws_scale().",f->desc->name); + } + return dupmsg(s->yuv_msg); +} + +static void update_sps(DecData *d, mblk_t *sps){ + if (d->sps) + freemsg(d->sps); + d->sps=dupb(sps); +} + +static void update_pps(DecData *d, mblk_t *pps){ + if (d->pps) + freemsg(d->pps); + d->pps=dupb(pps); +} + +static bool_t check_sps_pps_change(DecData *d, mblk_t *sps, mblk_t *pps){ + bool_t ret1=FALSE,ret2=FALSE; + if (d->sps){ + if (sps){ + ret1=(msgdsize(sps)!=msgdsize(d->sps)) || (memcmp(d->sps->b_rptr,sps->b_rptr,msgdsize(sps))!=0); + if (ret1) { + update_sps(d,sps); + ms_message("SPS changed !"); + } + } + }else if (sps) { + ms_message("Receiving first SPS"); + update_sps(d,sps); + } + if (d->pps){ + if (pps){ + ret2=(msgdsize(pps)!=msgdsize(d->pps)) || (memcmp(d->pps->b_rptr,pps->b_rptr,msgdsize(pps))!=0); + if (ret2) { + update_sps(d,pps); + ms_message("PPS changed ! %i,%i",msgdsize(pps),msgdsize(d->pps)); + } + } + }else if (pps) { + ms_message("Receiving first PPS"); + update_pps(d,pps); + } + return ret1 || ret2; +} + +static int nalusToFrame(DecData *d, MSQueue *naluq, uint8_t *bitstream, int size, bool_t *new_sps_pps){ + mblk_t *im; + uint8_t *dst=bitstream,*src; + bool_t start_picture=TRUE; + uint8_t nalu_type; + *new_sps_pps=FALSE; + while((im=ms_queue_get(naluq))!=NULL){ + src=im->b_rptr; + nalu_type=(*src) & ((1<<5)-1); + if (nalu_type==7) + *new_sps_pps=check_sps_pps_change(d,im,NULL) || *new_sps_pps; + if (nalu_type==8) + *new_sps_pps=check_sps_pps_change(d,NULL,im) || *new_sps_pps; + if (start_picture || nalu_type==7/*SPS*/ || nalu_type==8/*PPS*/ ){ + *dst++=0; + start_picture=FALSE; + } + /*prepend nal marker*/ + *dst++=0; + *dst++=0; + *dst++=1; + *dst++=*src++; + while(src<(im->b_wptr-3)){ +#ifdef REMOVE_PREVENTING_BYTES + if (src[0]==0 && src[1]==0 && src[2]<=3){ + *dst++=0; + *dst++=0; + *dst++=3; + src+=2; + } +#endif + *dst++=*src++; + } + *dst++=*src++; + *dst++=*src++; + *dst++=*src++; + freemsg(im); + } + return dst-bitstream; +} + +static void dec_process(MSFilter *f){ + DecData *d=(DecData*)f->data; + mblk_t *im; + MSQueue nalus; + AVFrame orig; + ms_queue_init(&nalus); + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + /*push the sps/pps given in sprop-parameter-sets if any*/ + if (d->packet_num==0 && d->sps && d->pps){ + mblk_set_timestamp_info(d->sps,mblk_get_timestamp_info(im)); + mblk_set_timestamp_info(d->pps,mblk_get_timestamp_info(im)); + rfc3984_unpack(&d->unpacker,d->sps,&nalus); + rfc3984_unpack(&d->unpacker,d->pps,&nalus); + d->sps=NULL; + d->pps=NULL; + } + rfc3984_unpack(&d->unpacker,im,&nalus); + if (!ms_queue_empty(&nalus)){ + int size; + uint8_t *p,*end; + bool_t need_reinit=FALSE; + + size=nalusToFrame(d,&nalus,d->bitstream,sizeof(d->bitstream),&need_reinit); + if (need_reinit) + dec_reinit(d); + p=d->bitstream; + end=d->bitstream+size; + while (end-p>0) { + int len; + int got_picture=0; + avcodec_get_frame_defaults(&orig); + len=avcodec_decode_video(&d->av_context,&orig,&got_picture,p,end-p); + if (len<=0) { + ms_warning("ms_AVdecoder_process: error %i.",len); + break; + } + if (got_picture) { + ms_queue_put(f->outputs[0],get_as_yuvmsg(f,d,&orig)); + } + p+=len; + } + } + d->packet_num++; + } +} + +static int dec_add_fmtp(MSFilter *f, void *arg){ + DecData *d=(DecData*)f->data; + const char *fmtp=(const char *)arg; + char value[256]; + if (fmtp_get_value(fmtp,"sprop-parameter-sets",value,sizeof(value))){ + char * b64_sps=value; + char * b64_pps=strchr(value,','); + if (b64_pps){ + *b64_pps='\0'; + ++b64_pps; + ms_message("Got sprop-parameter-sets : sps=%s , pps=%s",b64_sps,b64_pps); + d->sps=allocb(sizeof(value),0); + d->sps->b_wptr+=b64_decode(b64_sps,strlen(b64_sps),d->sps->b_wptr,sizeof(value)); + d->pps=allocb(sizeof(value),0); + d->pps->b_wptr+=b64_decode(b64_pps,strlen(b64_pps),d->pps->b_wptr,sizeof(value)); + } + } + return 0; +} + +static MSFilterMethod h264_dec_methods[]={ + { MS_FILTER_ADD_FMTP , dec_add_fmtp }, + { 0 , NULL } +}; + +static MSFilterDesc h264_dec_desc={ + .id=MS_FILTER_PLUGIN_ID, + .name="MSH264Dec", + .text="A H264 decoder based on ffmpeg project.", + .category=MS_FILTER_DECODER, + .enc_fmt="H264", + .ninputs=1, + .noutputs=1, + .init=dec_init, + .process=dec_process, + .uninit=dec_uninit, + .methods=h264_dec_methods +}; + +void libmsx264_init(void){ + ms_filter_register(&x264_enc_desc); + ms_filter_register(&h264_dec_desc); +} diff --git a/linphone/mediastreamer2/src/.cvsignore b/linphone/mediastreamer2/src/.cvsignore new file mode 100644 index 000000000..9c4a34a80 --- /dev/null +++ b/linphone/mediastreamer2/src/.cvsignore @@ -0,0 +1,8 @@ +Makefile.in +Makefile +.libs +.deps +*.la +*.lo +alldescs.h +filterdescs.txt diff --git a/linphone/mediastreamer2/src/Makefile.am b/linphone/mediastreamer2/src/Makefile.am new file mode 100644 index 000000000..5d4e03694 --- /dev/null +++ b/linphone/mediastreamer2/src/Makefile.am @@ -0,0 +1,136 @@ + +EXTRA_DIST= winsnd2.c winsnd.c winvideo.c winvideods.c wincevideods.c dxfilter.h dxfilter.cpp msfileplayer_win.c msfilerec_win.c winsndds.cpp nowebcamCIF.jpg + +BUILT_SOURCES=alldescs.h + +CLEANFILES=alldescs.h filterdescs.txt + +INCLUDES=-I$(top_srcdir)/include/ + +lib_LTLIBRARIES=libmediastreamer.la + +libmediastreamer_la_SOURCES= mscommon.c \ + msfilter.c \ + msqueue.c \ + msticker.c \ + alaw.c \ + ulaw.c \ + mssndcard.c \ + msfileplayer.c \ + msrtp.c \ + dtmfgen.c \ + msfilerec.c \ + ice.c \ + tee.c \ + msconf.c \ + msjoin.c \ + g711common.h \ + msvolume.c \ + mswebcam.c \ + mtu.c + + +libmediastreamer_la_SOURCES+=audiostream.c + +if BUILD_RESAMPLE +libmediastreamer_la_SOURCES+=msresample.c +endif + +if BUILD_ALSA +libmediastreamer_la_SOURCES+=alsa.c +endif + +if BUILD_OSS +libmediastreamer_la_SOURCES+=oss.c +endif + +if BUILD_ARTS +libmediastreamer_la_SOURCES+=arts.c +endif + +if BUILD_PORTAUDIO +libmediastreamer_la_SOURCES+=pasnd.c +endif + +if BUILD_MACSND +libmediastreamer_la_SOURCES+=macsnd.c +endif + +if BUILD_MACAQSND +libmediastreamer_la_SOURCES+=aqsnd.c +endif + + +if BUILD_VIDEO + +if BUILD_MACOSX +libmediastreamer_la_SOURCES+=msv4m.c +else +libmediastreamer_la_SOURCES+=msv4l.c msv4l2.c +endif + +libmediastreamer_la_SOURCES+= sdlout.c \ + videoenc.c \ + videodec.c \ + pixconv.c \ + sizeconv.c \ + rfc2429.h \ + nowebcam.c nowebcam.h \ + videoout.c \ + msvideo.c \ + rfc3984.c \ + mire.c \ + swscale.h ffmpeg-priv.h + +libmediastreamer_la_SOURCES+=videostream.c + +endif + +if BUILD_THEORA +libmediastreamer_la_SOURCES+=theora.c +endif + +if BUILD_SPEEX +libmediastreamer_la_SOURCES+=msspeex.c speexec.c +endif + +if BUILD_GSM +libmediastreamer_la_SOURCES+=gsm.c +endif + +alldescs.h: Makefile.am $(libmediastreamer_la_SOURCES) + builddir=`pwd` && cd $(srcdir) && \ + awk 'BEGIN { FS="[()]" ; }; /^\t*MS_FILTER_DESC_EXPORT/{ printf("%s\n", $$2) } ' > $$builddir/filterdescs.txt $(libmediastreamer_la_SOURCES) && \ + awk 'BEGIN { print("#include \"mediastreamer2/msfilter.h\"\n") } { printf("extern MSFilterDesc %s;\n",$$1) } ' $$builddir/filterdescs.txt > $$builddir/$@ && \ + awk 'BEGIN { print("MSFilterDesc * ms_filter_descs[]={") } { printf("&%s,\n",$$1) } END{ print("NULL\n};\n") } ' $$builddir/filterdescs.txt >> $$builddir/$@ + + +libmediastreamer_la_LIBADD= $(ORTP_LIBS) \ + $(PORTAUDIO_LIBS) \ + $(ALSA_LIBS) \ + $(ARTS_LIBS) \ + $(SPEEX_LIBS) \ + $(GSM_LIBS) \ + $(THEORA_LIBS) + +libmediastreamer_la_LDFLAGS=-rdynamic + +if BUILD_VIDEO +libmediastreamer_la_LIBADD+=$(VIDEO_LIBS) +endif + + +AM_CFLAGS= -I$(top_srcdir) \ + $(ORTP_CFLAGS) \ + $(SPEEX_CFLAGS) \ + $(GSM_CFLAGS) \ + $(STRICT_OPTIONS) + +if BUILD_VIDEO +AM_CFLAGS+=$(VIDEO_CFLAGS) +endif + +imgdir=$(datadir)/images/ + +img_DATA=nowebcamCIF.jpg + diff --git a/linphone/mediastreamer2/src/alaw.c b/linphone/mediastreamer2/src/alaw.c new file mode 100644 index 000000000..ff07ce1da --- /dev/null +++ b/linphone/mediastreamer2/src/alaw.c @@ -0,0 +1,222 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" +#include "g711common.h" + +typedef struct _AlawEncData{ + MSBufferizer *bz; + int ptime; + uint32_t ts; +} AlawEncData; + +static AlawEncData * alaw_enc_data_new(){ + AlawEncData *obj=(AlawEncData *)ms_new(AlawEncData,1); + obj->bz=ms_bufferizer_new(); + obj->ptime=0; + obj->ts=0; + return obj; +} + +static void alaw_enc_data_destroy(AlawEncData *obj){ + ms_bufferizer_destroy(obj->bz); + ms_free(obj); +} + +static void alaw_enc_init(MSFilter *obj){ + obj->data=alaw_enc_data_new(); +} + +static void alaw_enc_uninit(MSFilter *obj){ + alaw_enc_data_destroy((AlawEncData*)obj->data); +} + +static void alaw_enc_process(MSFilter *obj){ + AlawEncData *dt=(AlawEncData*)obj->data; + MSBufferizer *bz=dt->bz; + uint8_t buffer[2240]; + int frame_per_packet=2; + int size_of_pcm=320; + + mblk_t *m; + + if (dt->ptime>=10) + { + frame_per_packet = dt->ptime/10; + } + + if (frame_per_packet<=0) + frame_per_packet=1; + if (frame_per_packet>14) /* 7*20 == 140 ms max */ + frame_per_packet=14; + + size_of_pcm = 160*frame_per_packet; /* ex: for 20ms -> 160*2==320 */ + + while((m=ms_queue_get(obj->inputs[0]))!=NULL){ + ms_bufferizer_put(bz,m); + } + while (ms_bufferizer_read(bz,buffer,size_of_pcm)==size_of_pcm){ + mblk_t *o=allocb(size_of_pcm/2,0); + int i; + for (i=0;ib_wptr=s16_to_alaw(((int16_t*)buffer)[i]); + o->b_wptr++; + } + mblk_set_timestamp_info(o,dt->ts); + dt->ts+=size_of_pcm/2; + ms_queue_put(obj->outputs[0],o); + } +} + +static int enc_add_fmtp(MSFilter *f, void *arg){ + const char *fmtp=(const char *)arg; + AlawEncData *s=(AlawEncData*)f->data; + char tmp[30]; + if (fmtp_get_value(fmtp,"ptime",tmp,sizeof(tmp))){ + s->ptime=atoi(tmp); + ms_message("MSAlawEnc: got ptime=%i",s->ptime); + } + return 0; +} + +static int enc_add_attr(MSFilter *f, void *arg){ + const char *fmtp=(const char *)arg; + AlawEncData *s=(AlawEncData*)f->data; + if (strstr(fmtp,"ptime:10")!=NULL){ + s->ptime=10; + }else if (strstr(fmtp,"ptime:20")!=NULL){ + s->ptime=20; + }else if (strstr(fmtp,"ptime:30")!=NULL){ + s->ptime=30; + }else if (strstr(fmtp,"ptime:40")!=NULL){ + s->ptime=40; + }else if (strstr(fmtp,"ptime:50")!=NULL){ + s->ptime=50; + }else if (strstr(fmtp,"ptime:60")!=NULL){ + s->ptime=60; + }else if (strstr(fmtp,"ptime:70")!=NULL){ + s->ptime=70; + }else if (strstr(fmtp,"ptime:80")!=NULL){ + s->ptime=80; + }else if (strstr(fmtp,"ptime:90")!=NULL){ + s->ptime=90; + }else if (strstr(fmtp,"ptime:100")!=NULL){ + s->ptime=100; + }else if (strstr(fmtp,"ptime:110")!=NULL){ + s->ptime=110; + }else if (strstr(fmtp,"ptime:120")!=NULL){ + s->ptime=120; + }else if (strstr(fmtp,"ptime:130")!=NULL){ + s->ptime=130; + }else if (strstr(fmtp,"ptime:140")!=NULL){ + s->ptime=140; + } + return 0; +} + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_ADD_ATTR , enc_add_attr}, + { MS_FILTER_ADD_FMTP , enc_add_fmtp}, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_alaw_enc_desc={ + MS_ALAW_ENC_ID, + "MSAlawEnc", + "ITU-G.711 alaw encoder", + MS_FILTER_ENCODER, + "pcma", + 1, + 1, + alaw_enc_init, + NULL, + alaw_enc_process, + NULL, + alaw_enc_uninit, + enc_methods +}; + +#else + +MSFilterDesc ms_alaw_enc_desc={ + .id=MS_ALAW_ENC_ID, + .name="MSAlawEnc", + .text="ITU-G.711 alaw encoder", + .category=MS_FILTER_ENCODER, + .enc_fmt="pcma", + .ninputs=1, + .noutputs=1, + .init=alaw_enc_init, + .process=alaw_enc_process, + .uninit=alaw_enc_uninit, + .methods=enc_methods +}; + +#endif + +static void alaw_dec_process(MSFilter *obj){ + mblk_t *m; + while((m=ms_queue_get(obj->inputs[0]))!=NULL){ + mblk_t *o; + msgpullup(m,-1); + o=allocb((m->b_wptr-m->b_rptr)*2,0); + for(;m->b_rptrb_wptr;m->b_rptr++,o->b_wptr+=2){ + *((int16_t*)(o->b_wptr))=alaw_to_s16(*m->b_rptr); + } + freemsg(m); + ms_queue_put(obj->outputs[0],o); + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_alaw_dec_desc={ + MS_ALAW_DEC_ID, + "MSAlawDec", + "ITU-G.711 alaw decoder", + MS_FILTER_DECODER, + "pcma", + 1, + 1, + NULL, + NULL, + alaw_dec_process, + NULL, + NULL +}; + +#else + +MSFilterDesc ms_alaw_dec_desc={ + .id=MS_ALAW_DEC_ID, + .name="MSAlawDec", + .text="ITU-G.711 alaw decoder", + .category=MS_FILTER_DECODER, + .enc_fmt="pcma", + .ninputs=1, + .noutputs=1, + .process=alaw_dec_process, +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_alaw_dec_desc) +MS_FILTER_DESC_EXPORT(ms_alaw_enc_desc) diff --git a/linphone/mediastreamer2/src/alsa.c b/linphone/mediastreamer2/src/alsa.c new file mode 100644 index 000000000..8dd3f25f3 --- /dev/null +++ b/linphone/mediastreamer2/src/alsa.c @@ -0,0 +1,948 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + + +#include + + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/mssndcard.h" + +//#define THREADED_VERSION + +/*in case of troubles with a particular driver, try incrementing ALSA_PERIOD_SIZE +to 512, 1024, 2048, 4096... +then try incrementing the number of periods*/ +#define ALSA_PERIODS 8 +#define ALSA_PERIOD_SIZE 256 + +/*uncomment the following line if you have problems with an alsa driver +having sound quality trouble:*/ +/*#define EPIPE_BUGFIX 1*/ + +static MSSndCard * alsa_card_new(int id); +static MSSndCard *alsa_card_duplicate(MSSndCard *obj); +static MSFilter * ms_alsa_read_new(const char *dev); +static MSFilter * ms_alsa_write_new(const char *dev); + + +struct _AlsaData{ + char *pcmdev; + char *mixdev; +}; + +typedef struct _AlsaData AlsaData; + + +static int alsa_set_params(snd_pcm_t *pcm_handle, int rw, int bits, int stereo, int rate) +{ + snd_pcm_hw_params_t *hwparams=NULL; + snd_pcm_sw_params_t *swparams=NULL; + int dir; + uint exact_uvalue; + unsigned long exact_ulvalue; + int channels; + int periods=ALSA_PERIODS; + int periodsize=ALSA_PERIOD_SIZE; + int err; + int format; + + /* Allocate the snd_pcm_hw_params_t structure on the stack. */ + snd_pcm_hw_params_alloca(&hwparams); + + /* Init hwparams with full configuration space */ + if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { + ms_warning("alsa_set_params: Cannot configure this PCM device."); + return -1; + } + + if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { + ms_warning("alsa_set_params: Error setting access."); + return -1; + } + /* Set sample format */ + format=SND_PCM_FORMAT_S16; + if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) { + ms_warning("alsa_set_params: Error setting format."); + return -1; + } + /* Set number of channels */ + if (stereo) channels=2; + else channels=1; + if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) { + ms_warning("alsa_set_params: Error setting channels."); + return -1; + } + /* Set sample rate. If the exact rate is not supported */ + /* by the hardware, use nearest possible rate. */ + exact_uvalue=rate; + dir=0; + if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){ + ms_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err)); + return -1; + } + if (dir != 0) { + ms_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n " + "==> Using %d Hz instead.", rate, exact_uvalue); + } + /* choose greater period size when rate is high */ + periodsize=periodsize*(rate/8000); + + /* Set buffer size (in frames). The resulting latency is given by */ + /* latency = periodsize * periods / (rate * bytes_per_frame) */ + /* set period size */ + exact_ulvalue=periodsize; + dir=0; + if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) { + ms_warning("alsa_set_params: Error setting period size."); + return -1; + } + if (dir != 0) { + ms_warning("alsa_set_params: The period size %d is not supported by your hardware.\n " + "==> Using %d instead.", periodsize, (int)exact_ulvalue); + } + ms_warning("alsa_set_params: periodsize:%d Using %d", periodsize, (int)exact_ulvalue); + periodsize=exact_ulvalue; + /* Set number of periods. Periods used to be called fragments. */ + exact_uvalue=periods; + dir=0; + if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) { + ms_warning("alsa_set_params: Error setting periods."); + return -1; + } + ms_warning("alsa_set_params: period:%d Using %d", periods, exact_uvalue); + if (dir != 0) { + ms_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n " + "==> Using %d instead.", periods, exact_uvalue); + } + /* Apply HW parameter settings to */ + /* PCM device and prepare device */ + if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { + ms_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err)); + return -1; + } + /*prepare sw params */ + if (rw){ + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(pcm_handle, swparams); + if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){ + ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err)); + } + if ((err=snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,periodsize*periods ))<0){ + ms_warning("alsa_set_params: Error setting stop threshold:%s",snd_strerror(err)); + } + if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){ + ms_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err)); + return -1; + } + } + return 0; +} + +#ifdef EPIPE_BUGFIX +static void alsa_fill_w (snd_pcm_t *pcm_handle) +{ + snd_pcm_hw_params_t *hwparams=NULL; + int channels; + snd_pcm_uframes_t buffer_size; + int buffer_size_bytes; + void *buffer; + + /* Allocate the snd_pcm_hw_params_t structure on the stack. */ + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_hw_params_current(pcm_handle, hwparams); + + /* get channels */ + snd_pcm_hw_params_get_channels (hwparams, &channels); + + /* get buffer size */ + snd_pcm_hw_params_get_buffer_size (hwparams, &buffer_size); + + /* fill half */ + buffer_size /= 2; + + /* allocate buffer assuming 2 bytes per sample */ + buffer_size_bytes = buffer_size * channels * 2; + buffer = alloca (buffer_size_bytes); + memset (buffer, 0, buffer_size_bytes); + + /* write data */ + snd_pcm_writei(pcm_handle, buffer, buffer_size); +} +#endif + +static snd_pcm_t * alsa_open_r(const char *pcmdev,int bits,int stereo,int rate) +{ + snd_pcm_t *pcm_handle; + int err; + + ms_message("alsa_open_r: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo); + + +#ifndef THREADED_VERSION + if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) { + ms_warning("alsa_open_r: Error opening PCM device %s",pcmdev ); + return NULL; + } +#else + /* want blocking mode for threaded version */ + if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,0) < 0) { + ms_warning("alsa_open_r: Error opening PCM device %s",pcmdev ); + return NULL; + } +#endif + if (alsa_set_params(pcm_handle,0,bits,stereo,rate)<0){ + snd_pcm_close(pcm_handle); + return NULL; + } + err=snd_pcm_start(pcm_handle); + if (err<0){ + ms_warning("snd_pcm_start() failed: %s", snd_strerror(err)); + } + return pcm_handle; +} + +static snd_pcm_t * alsa_open_w(const char *pcmdev,int bits,int stereo,int rate) +{ + snd_pcm_t *pcm_handle; + + if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) { + ms_warning("alsa_open_w: Error opening PCM device %s",pcmdev ); + return NULL; + } + if (alsa_set_params(pcm_handle,1,bits,stereo,rate)<0){ + snd_pcm_close(pcm_handle); + return NULL; + } + return pcm_handle; +} + +static int alsa_can_read(snd_pcm_t *dev, int frames) +{ + snd_pcm_sframes_t avail; + int err; + + avail = snd_pcm_avail_update(dev); + ms_debug("*** %s %d %d", __FUNCTION__, (long)avail, frames); + if (avail < 0) { + ms_error("snd_pcm_avail_update: %s", snd_strerror(avail)); // most probably -EPIPE + /* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN + FIXME: handle other error conditions*/ + ms_error("*** alsa_can_read fixup, trying to recover"); + snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/ + err = snd_pcm_recover(dev, avail, 0); + if (err){ + ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err)); + return -1; + } + err = snd_pcm_start(dev); + if (err){ + ms_error("snd_pcm_start() failed with err %d: %s", err, snd_strerror(err)); + return -1; + } + ms_message("Recovery done"); + } + return avail; +} + +static int alsa_read(snd_pcm_t *handle,unsigned char *buf,int nsamples) +{ + int err; + err=snd_pcm_readi(handle,buf,nsamples); + if (err<0) { + ms_warning("alsa_read: snd_pcm_readi() returned %i",err); + if (err==-EPIPE){ + snd_pcm_prepare(handle); + err=snd_pcm_readi(handle,buf,nsamples); + if (err<0) ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err)); + }else if (err!=-EWOULDBLOCK){ + ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err)); + } + }else if (err==0){ + ms_warning("alsa_read: snd_pcm_readi() returned 0"); + } + return err; +} + + +static int alsa_write(snd_pcm_t *handle,unsigned char *buf,int nsamples) +{ + int err; + if ((err=snd_pcm_writei(handle,buf,nsamples))<0){ + if (err==-EPIPE){ + snd_pcm_prepare(handle); +#ifdef EPIPE_BUGFIX + alsa_fill_w (handle); +#endif + err=snd_pcm_writei(handle,buf,nsamples); + if (err<0) ms_warning("alsa_card_write: Error writing sound buffer (nsamples=%i):%s",nsamples,snd_strerror(err)); + }else if (err!=-EWOULDBLOCK){ + ms_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err)); + } + }else if (err!=nsamples) { + ms_debug("Only %i samples written instead of %i",err,nsamples); + } + return err; +} + + +static snd_mixer_t *alsa_mixer_open(const char *mixdev){ + snd_mixer_t *mixer=NULL; + int err; + err=snd_mixer_open(&mixer,0); + if (err<0){ + ms_warning("Could not open alsa mixer: %s",snd_strerror(err)); + return NULL; + } + if ((err = snd_mixer_attach (mixer, mixdev)) < 0){ + ms_warning("Could not attach mixer to card: %s",snd_strerror(err)); + snd_mixer_close(mixer); + return NULL; + } + if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){ + ms_warning("snd_mixer_selem_register: %s",snd_strerror(err)); + snd_mixer_close(mixer); + return NULL; + } + if ((err = snd_mixer_load (mixer)) < 0){ + ms_warning("snd_mixer_load: %s",snd_strerror(err)); + snd_mixer_close(mixer); + return NULL; + } + return mixer; +} + +static void alsa_mixer_close(snd_mixer_t *mix){ + snd_mixer_close(mix); +} + +typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction; + +static int get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){ + long value=0; + const char *elemname; + snd_mixer_elem_t *elem; + int err; + long sndMixerPMin=0; + long sndMixerPMax=0; + long newvol=0; + elem=snd_mixer_first_elem(mixer); + while (elem!=NULL){ + elemname=snd_mixer_selem_get_name(elem); + //ms_message("Found alsa mixer element %s.",elemname); + if (strcmp(elemname,name)==0){ + switch (action){ + case CAPTURE: + if (snd_mixer_selem_has_capture_volume(elem)){ + snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol); + newvol-=sndMixerPMin; + value=(100*newvol)/(sndMixerPMax-sndMixerPMin); + if (err<0) ms_warning("Could not get capture volume for %s:%s",name,snd_strerror(err)); + //else ms_message("Successfully get capture level for %s.",elemname); + break; + } + break; + case PLAYBACK: + if (snd_mixer_selem_has_playback_volume(elem)){ + snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol); + newvol-=sndMixerPMin; + value=(100*newvol)/(sndMixerPMax-sndMixerPMin); + if (err<0) ms_warning("Could not get playback volume for %s:%s",name,snd_strerror(err)); + //else ms_message("Successfully get playback level for %s.",elemname); + break; + } + break; + case CAPTURE_SWITCH: + + break; + case PLAYBACK_SWITCH: + + break; + } + } + elem=snd_mixer_elem_next(elem); + } + + return value; +} + + +static void set_mixer_element(snd_mixer_t *mixer,const char *name, int level,MixerAction action){ + const char *elemname; + snd_mixer_elem_t *elem; + long sndMixerPMin=0; + long sndMixerPMax=0; + long newvol=0; + + elem=snd_mixer_first_elem(mixer); + + while (elem!=NULL){ + elemname=snd_mixer_selem_get_name(elem); + //ms_message("Found alsa mixer element %s.",elemname); + if (strcmp(elemname,name)==0){ + switch(action){ + case CAPTURE: + if (snd_mixer_selem_has_capture_volume(elem)){ + snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin; + snd_mixer_selem_set_capture_volume_all(elem,newvol); + //ms_message("Successfully set capture level for %s.",elemname); + return; + } + break; + case PLAYBACK: + if (snd_mixer_selem_has_playback_volume(elem)){ + snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax); + newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin; + snd_mixer_selem_set_playback_volume_all(elem,newvol); + //ms_message("Successfully set playback level for %s.",elemname); + return; + } + break; + case CAPTURE_SWITCH: + if (snd_mixer_selem_has_capture_switch(elem)){ + snd_mixer_selem_set_capture_switch_all(elem,level); + //ms_message("Successfully set capture switch for %s.",elemname); + } + break; + case PLAYBACK_SWITCH: + if (snd_mixer_selem_has_playback_switch(elem)){ + snd_mixer_selem_set_playback_switch_all(elem,level); + //ms_message("Successfully set capture switch for %s.",elemname); + } + break; + + } + } + elem=snd_mixer_elem_next(elem); + } + + return ; +} + + +static void alsa_card_set_level(MSSndCard *obj,MSSndCardMixerElem e,int a) +{ + snd_mixer_t *mixer; + AlsaData *ad=(AlsaData*)obj->data; + mixer=alsa_mixer_open(ad->mixdev); + if (mixer==NULL) return ; + switch(e){ + case MS_SND_CARD_MASTER: + set_mixer_element(mixer,"Master",a,PLAYBACK); + break; + case MS_SND_CARD_CAPTURE: + set_mixer_element(mixer,"Capture",a,CAPTURE); + break; + case MS_SND_CARD_PLAYBACK: + set_mixer_element(mixer,"PCM",a,PLAYBACK); + break; + default: + ms_warning("alsa_card_set_level: unsupported command."); + } + alsa_mixer_close(mixer); +} + +static int alsa_card_get_level(MSSndCard *obj, MSSndCardMixerElem e) +{ + snd_mixer_t *mixer; + AlsaData *ad=(AlsaData*)obj->data; + int value = -1; + mixer=alsa_mixer_open(ad->mixdev); + if (mixer==NULL) return 0; + switch(e){ + case MS_SND_CARD_MASTER: + value=get_mixer_element(mixer,"Master",PLAYBACK); + break; + case MS_SND_CARD_CAPTURE: + value=get_mixer_element(mixer,"Capture",CAPTURE); + break; + case MS_SND_CARD_PLAYBACK: + value=get_mixer_element(mixer,"PCM",PLAYBACK); + break; + default: + ms_warning("alsa_card_set_level: unsupported command."); + } + alsa_mixer_close(mixer); + return value; +} + +static void alsa_card_set_source(MSSndCard *obj,MSSndCardCapture source) +{ + snd_mixer_t *mixer; + AlsaData *ad=(AlsaData*)obj->data; + mixer=alsa_mixer_open(ad->mixdev); + if (mixer==NULL) return; + switch (source){ + case MS_SND_CARD_MIC: + set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH); + set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH); + break; + case MS_SND_CARD_LINE: + set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH); + set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH); + break; + } + alsa_mixer_close(mixer); +} + +static MSFilter *alsa_card_create_reader(MSSndCard *card) +{ + AlsaData *ad=(AlsaData*)card->data; + MSFilter *f=ms_alsa_read_new(ad->pcmdev); + return f; +} + +static MSFilter *alsa_card_create_writer(MSSndCard *card) +{ + AlsaData *ad=(AlsaData*)card->data; + MSFilter *f=ms_alsa_write_new(ad->pcmdev); + return f; +} + + +static void alsa_card_init(MSSndCard *obj){ + AlsaData *ad=ms_new0(AlsaData,1); + obj->data=ad; +} + +static void alsa_card_uninit(MSSndCard *obj){ + AlsaData *ad=(AlsaData*)obj->data; + if (ad->pcmdev!=NULL) ms_free(ad->pcmdev); + if (ad->mixdev!=NULL) ms_free(ad->mixdev); + ms_free(ad); +} + +static void alsa_card_detect(MSSndCardManager *m){ + int i; + for (i=-1;i<10;i++){ + MSSndCard *card=alsa_card_new(i); + if (card!=NULL) + ms_snd_card_manager_add_card(m,card); + } +} + +MSSndCardDesc alsa_card_desc={ + .driver_type="ALSA", + .detect=alsa_card_detect, + .init=alsa_card_init, + .set_level=alsa_card_set_level, + .get_level=alsa_card_get_level, + .set_capture=alsa_card_set_source, + .create_reader=alsa_card_create_reader, + .create_writer=alsa_card_create_writer, + .uninit=alsa_card_uninit, + .duplicate=alsa_card_duplicate +}; + +static MSSndCard *alsa_card_duplicate(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&alsa_card_desc); + AlsaData* dcard=(AlsaData*)card->data; + AlsaData* dobj=(AlsaData*)obj->data; + card->name=ms_strdup(obj->name); + card->id=ms_strdup(obj->id); + dcard->pcmdev=ms_strdup(dobj->pcmdev); + dcard->mixdev=ms_strdup(dobj->mixdev); + return card; +} + +MSSndCard * ms_alsa_card_new_custom(const char *pcmdev, const char *mixdev){ + MSSndCard * obj; + AlsaData *ad; + obj=ms_snd_card_new(&alsa_card_desc); + ad=(AlsaData*)obj->data; + obj->name=ms_strdup(pcmdev); + ad->pcmdev=ms_strdup(pcmdev); + ad->mixdev=ms_strdup(mixdev); + return obj; +} + +static MSSndCard * alsa_card_new(int id) +{ + MSSndCard * obj; + char *name=NULL; + AlsaData *ad; + int err; + if (id!=-1){ + err=snd_card_get_name(id,&name); + if (err<0) { + return NULL; + } + } + obj=ms_snd_card_new(&alsa_card_desc); + ad=(AlsaData*)obj->data; + if (id==-1) { + /* the default pcm device */ + obj->name=ms_strdup("default device"); + ad->pcmdev=ms_strdup("default"); + ad->mixdev=ms_strdup("default"); + }else{ + /* remove trailing spaces from card name */ + char *pos1, *pos2; + pos1=ms_strdup(name); + pos2=pos1+strlen(pos1)-1; + for (; pos2>pos1 && *pos2==' '; pos2--) *pos2='\0'; + obj->name=pos1; + ad->pcmdev=ms_strdup_printf("default:%i",id); + ad->mixdev=ms_strdup_printf("default:%i",id); + } + free(name); + /*ms_message("alsa device %s found",obj->name);*/ + return obj; +} + +struct _AlsaReadData{ + char *pcmdev; + snd_pcm_t *handle; + int rate; + int nchannels; + +#ifdef THREADED_VERSION + ms_thread_t thread; + ms_mutex_t mutex; + MSBufferizer * bufferizer; + bool_t read_started; + bool_t write_started; +#endif +}; + +typedef struct _AlsaReadData AlsaReadData; + +void alsa_read_init(MSFilter *obj){ + AlsaReadData *ad=ms_new(AlsaReadData,1); + ad->pcmdev=NULL; + ad->handle=NULL; + ad->rate=8000; + ad->nchannels=1; + obj->data=ad; + +#ifdef THREADED_VERSION + ad->read_started=FALSE; + ad->write_started=FALSE; + ad->bufferizer=ms_bufferizer_new(); + ms_mutex_init(&ad->mutex,NULL); + ad->thread=0; +#endif +} + +#ifdef THREADED_VERSION + +static void * alsa_write_thread(void *p){ + AlsaReadData *ad=(AlsaReadData*)p; + int samples=(160*ad->rate)/8000; + int err; + int count=0; + mblk_t *om=NULL; + struct timeval timeout; + if (ad->handle==NULL && ad->pcmdev!=NULL){ + ad->handle=alsa_open_r(ad->pcmdev,16,ad->nchannels==2,ad->rate); + } + if (ad->handle==NULL) return NULL; + + while (ad->read_started) + { + count = alsa_can_read(ad->handle,samples); + if (count==24) + { /* keep this value for this driver */ } + else if (count<=0) + { + count = samples; + } + else if (count>0) + { + //ms_warning("%i count", count); + //count = samples; + } + + int size=count*2; + om=allocb(size,0); + + if ((err=alsa_read(ad->handle,om->b_wptr,count))<=0) + { + ms_warning("nothing to read"); + //ms_warning("Fail to read samples %i", count); + continue; + } + //ms_warning(" read %i", err); + + size=err*2; + om->b_wptr+=size; + + ms_mutex_lock(&ad->mutex); + ms_bufferizer_put(ad->bufferizer,om); + ms_mutex_unlock(&ad->mutex); + + if (count==24) + { + timeout.tv_sec = 0; + timeout.tv_usec = 2000; + select(0, 0, NULL, NULL, &timeout ); + } + else + { + /* select will be less active than locking on "read" */ + timeout.tv_sec = 0; + timeout.tv_usec = 5000; + select(0, 0, NULL, NULL, &timeout ); + } + } + + if (ad->handle!=NULL) snd_pcm_close(ad->handle); + ad->handle=NULL; + return NULL; +} + +static void alsa_start_r(AlsaReadData *d){ + if (d->read_started==FALSE){ + d->read_started=TRUE; + ms_thread_create(&d->thread,NULL,alsa_write_thread,d); + }else d->read_started=TRUE; +} + +static void alsa_stop_r(AlsaReadData *d){ + d->read_started=FALSE; + if (d->thread!=0) + { + ms_thread_join(d->thread,NULL); + d->thread=0; + } +} +#endif + +#ifdef THREADED_VERSION +void alsa_read_preprocess(MSFilter *obj){ + AlsaReadData *ad=(AlsaReadData*)obj->data; + alsa_start_r(ad); +} +#endif + +void alsa_read_postprocess(MSFilter *obj){ + AlsaReadData *ad=(AlsaReadData*)obj->data; +#ifdef THREADED_VERSION + alsa_stop_r(ad); +#endif + if (ad->handle!=NULL) snd_pcm_close(ad->handle); + ad->handle=NULL; +} + +void alsa_read_uninit(MSFilter *obj){ + AlsaReadData *ad=(AlsaReadData*)obj->data; +#ifdef THREADED_VERSION + alsa_stop_r(ad); +#endif + if (ad->pcmdev!=NULL) ms_free(ad->pcmdev); + if (ad->handle!=NULL) snd_pcm_close(ad->handle); +#ifdef THREADED_VERSION + ms_bufferizer_destroy(ad->bufferizer); + ms_mutex_destroy(&ad->mutex); +#endif + ms_free(ad); +} + +#ifndef THREADED_VERSION +void alsa_read_process(MSFilter *obj){ + AlsaReadData *ad=(AlsaReadData*)obj->data; + int samples=(128*ad->rate)/8000; + int err; + mblk_t *om=NULL; + if (ad->handle==NULL && ad->pcmdev!=NULL){ + ad->handle=alsa_open_r(ad->pcmdev,16,ad->nchannels==2,ad->rate); + } + if (ad->handle==NULL) return; + while (alsa_can_read(ad->handle,samples)>=samples){ + + int size=samples*2; + om=allocb(size,0); + if ((err=alsa_read(ad->handle,om->b_wptr,samples))<=0) { + ms_warning("Fail to read samples"); + freemsg(om); + return; + } + size=err*2; + om->b_wptr+=size; + /*ms_message("alsa_read_process: Outputing %i bytes",size);*/ + ms_queue_put(obj->outputs[0],om); + } +} +#endif + +#ifdef THREADED_VERSION +void alsa_read_process(MSFilter *obj){ + AlsaReadData *ad=(AlsaReadData*)obj->data; + mblk_t *om=NULL; + int samples=(160*ad->rate)/8000; + + ms_mutex_lock(&ad->mutex); + while (ms_bufferizer_get_avail(ad->bufferizer)>=samples*2){ + + om=allocb(samples*2,0); + ms_bufferizer_read(ad->bufferizer,om->b_wptr,samples*2); + om->b_wptr+=samples*2; + /*ms_message("alsa_read_process: Outputing %i bytes",size);*/ + ms_queue_put(obj->outputs[0],om); + } + ms_mutex_unlock(&ad->mutex); +} +#endif + +static int alsa_read_set_sample_rate(MSFilter *obj, void *param){ + AlsaReadData *ad=(AlsaReadData*)obj->data; + ad->rate=*((int*)param); + return 0; +} + +static int alsa_read_set_nchannels(MSFilter *obj, void *param){ + AlsaReadData *ad=(AlsaReadData*)obj->data; + ad->nchannels=*((int*)param); + return 0; +} + +MSFilterMethod alsa_read_methods[]={ + {MS_FILTER_SET_SAMPLE_RATE, alsa_read_set_sample_rate}, + {MS_FILTER_SET_SAMPLE_RATE, alsa_read_set_nchannels}, + {0,NULL} +}; + +MSFilterDesc alsa_read_desc={ + .id=MS_ALSA_READ_ID, + .name="MSAlsaRead", + .text="Alsa sound source", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .init=alsa_read_init, +#ifdef THREADED_VERSION + .preprocess=alsa_read_preprocess, +#endif + .process=alsa_read_process, + .postprocess=alsa_read_postprocess, + .uninit=alsa_read_uninit, + .methods=alsa_read_methods +}; + +static MSFilter * ms_alsa_read_new(const char *dev){ + MSFilter *f=ms_filter_new_from_desc(&alsa_read_desc); + AlsaReadData *ad=(AlsaReadData*)f->data; + ad->pcmdev=ms_strdup(dev); + return f; +} + +typedef struct _AlsaReadData AlsaWriteData; + +void alsa_write_init(MSFilter *obj){ + AlsaWriteData *ad=ms_new(AlsaWriteData,1); + ad->pcmdev=NULL; + ad->handle=NULL; + ad->rate=8000; + ad->nchannels=1; + obj->data=ad; +} + +void alsa_write_postprocess(MSFilter *obj){ + AlsaReadData *ad=(AlsaReadData*)obj->data; + if (ad->handle!=NULL) snd_pcm_close(ad->handle); + ad->handle=NULL; +} + +void alsa_write_uninit(MSFilter *obj){ + AlsaWriteData *ad=(AlsaWriteData*)obj->data; + if (ad->pcmdev!=NULL) ms_free(ad->pcmdev); + if (ad->handle!=NULL) snd_pcm_close(ad->handle); + ms_free(ad); +} + +int alsa_write_set_sample_rate(MSFilter *obj, void *data){ + int *rate=(int*)data; + AlsaWriteData *ad=(AlsaWriteData*)obj->data; + ad->rate=*rate; + return 0; +} + +int alsa_write_set_nchannels(MSFilter *obj, void *data){ + int *n=(int*)data; + AlsaWriteData *ad=(AlsaWriteData*)obj->data; + ad->nchannels=*n; + return 0; +} + +void alsa_write_process(MSFilter *obj){ + AlsaWriteData *ad=(AlsaWriteData*)obj->data; + mblk_t *im=NULL; + int size; + int samples; + int err; + if (ad->handle==NULL && ad->pcmdev!=NULL){ + ad->handle=alsa_open_w(ad->pcmdev,16,ad->nchannels==2,ad->rate); +#ifdef EPIPE_BUGFIX + alsa_fill_w (ad->pcmdev); +#endif + } + if (ad->handle==NULL) { + ms_queue_flush(obj->inputs[0]); + return; + } + while ((im=ms_queue_get(obj->inputs[0]))!=NULL){ + while((size=im->b_wptr-im->b_rptr)>0){ + samples=size/(2*ad->nchannels); + err=alsa_write(ad->handle,im->b_rptr,samples); + if (err>0) { + im->b_rptr+=err*(2*ad->nchannels); + } + else break; + } + freemsg(im); + } +} + +MSFilterMethod alsa_write_methods[]={ + {MS_FILTER_SET_SAMPLE_RATE, alsa_write_set_sample_rate}, + {MS_FILTER_SET_NCHANNELS, alsa_write_set_nchannels}, + {0,NULL} +}; + +MSFilterDesc alsa_write_desc={ + .id=MS_ALSA_WRITE_ID, + .name="MSAlsaWrite", + .text="Alsa sound output", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=0, + .init=alsa_write_init, + .process=alsa_write_process, + .postprocess=alsa_write_postprocess, + .uninit=alsa_write_uninit, + .methods=alsa_write_methods +}; + + +static MSFilter * ms_alsa_write_new(const char *dev){ + MSFilter *f=ms_filter_new_from_desc(&alsa_write_desc); + AlsaWriteData *ad=(AlsaWriteData*)f->data; + ad->pcmdev=ms_strdup(dev); + return f; +} + + +MS_FILTER_DESC_EXPORT(alsa_write_desc) + +MS_FILTER_DESC_EXPORT(alsa_read_desc) + diff --git a/linphone/mediastreamer2/src/arts.c b/linphone/mediastreamer2/src/arts.c new file mode 100644 index 000000000..e20ca884a --- /dev/null +++ b/linphone/mediastreamer2/src/arts.c @@ -0,0 +1,205 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" + +extern MSSndCardDesc arts_card_desc; + +static int arts_users=0; +static void check_arts_init(){ + if (arts_users==0){ + arts_init(); + } + arts_users++; +} + +static void check_arts_uninit(){ + arts_users--; + if (arts_users==0){ + arts_free(); + } +} + + +typedef struct ArtsState{ + int rate; + int nchannels; + int bits; + int bsize; + arts_stream_t stream; + mblk_t *msg; +} ArtsState; + +static void reader_init(MSFilter *f){ + ArtsState *s=ms_new(ArtsState,1); + s->rate=8000; + s->nchannels=1; + s->bits=16; + s->bsize=512; + s->stream=NULL; + s->msg=NULL; + f->data=s; +} + +static void reader_uninit(MSFilter *f){ + ArtsState *s=(ArtsState *)f->data; + ms_free(s); +} + +static void configure(arts_stream_t stream){ + int ret; + int latency=50; + ret=arts_stream_set(stream,ARTS_P_BUFFER_TIME,latency); + if (ret!=latency) ms_message("Arts set latency to %i",ret); + arts_stream_set(stream,ARTS_P_BLOCKING,0); +} + +static void reader_preprocess(MSFilter *f){ + ArtsState *s=(ArtsState *)f->data; + check_arts_init(); + s->stream=arts_record_stream(s->rate,s->bits,s->nchannels, "linphone"); + s->bsize=512*s->rate/8000; + if (s->stream!=NULL) configure(s->stream); +} + +static void reader_process(MSFilter *f){ + int err; + ArtsState *s=(ArtsState *)f->data; + if (s->stream!=NULL){ + mblk_t *om=s->msg; + if (om==NULL) om=allocb(s->bsize,0); + err=arts_read(s->stream,om->b_wptr,s->bsize); + if (err>0){ + om->b_wptr+=err; + ms_queue_put(f->outputs[0],om); + om=NULL; + } + s->msg=om; + } +} + +static void reader_postprocess(MSFilter *f){ + ArtsState *s=(ArtsState *)f->data; + if (s->stream) arts_close_stream(s->stream); + s->stream=NULL; + check_arts_uninit(); +} + +static void writer_preprocess(MSFilter *f){ + ArtsState *s=(ArtsState *)f->data; + check_arts_init(); + s->stream=arts_play_stream(s->rate,s->bits,s->nchannels, "linphone"); + s->bsize=512*s->rate/8000; + if (s->stream!=NULL) configure(s->stream); +} + +static void writer_process(MSFilter *f){ + ArtsState *s=(ArtsState *)f->data; + int err; + mblk_t *im; + + if (s->stream==NULL){ + ms_queue_flush(f->inputs[0]); + return; + } + while ((im=ms_queue_get(f->inputs[0]))!=NULL){ + err=arts_write(s->stream,im->b_rptr,im->b_wptr-im->b_rptr); + if (err<0){ + ms_warning("arts_write error"); + } + freemsg(im); + } +} + +static int reader_set_sr(MSFilter *f, void *arg){ + ArtsState *s=(ArtsState *)f->data; + s->rate=*(int*)arg; + return 0; +} + +static int reader_set_nchannels(MSFilter *f, void *arg){ + ArtsState *s=(ArtsState *)f->data; + s->nchannels=*(int*)arg; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , reader_set_sr }, + { MS_FILTER_SET_NCHANNELS , reader_set_nchannels }, + { 0 , NULL } +}; + +MSFilterDesc ms_arts_read_desc={ + .id=MS_ARTS_READ_ID, + .name="MSArtsRead", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .init=reader_init, + .preprocess=reader_preprocess, + .process=reader_process, + .postprocess=reader_postprocess, + .uninit=reader_uninit, + .methods=methods +}; + +MSFilterDesc ms_arts_write_desc={ + .id=MS_ARTS_WRITE_ID, + .name="MSArtsWrite", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=0, + .init=reader_init, /*the read and the write method do the same*/ + .preprocess=writer_preprocess, + .process=writer_process, + .postprocess=reader_postprocess,/*the read and the write method do the same*/ + .uninit=reader_uninit,/*the read and the write method do the same*/ + .methods=methods /*the read and the write method do the same*/ +}; + +static void arts_card_detect(MSSndCardManager *m){ + if (arts_init()==0){ + MSSndCard *card=ms_snd_card_new(&arts_card_desc); + card->name=ms_strdup("arts driver"); + ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + arts_free(); + } +} + +static MSFilter * arts_card_create_reader(MSSndCard *card){ + return ms_filter_new(MS_ARTS_READ_ID); +} + +static MSFilter * arts_card_create_writer(MSSndCard *card){ + return ms_filter_new(MS_ARTS_WRITE_ID); +} + +MSSndCardDesc arts_card_desc={ + .driver_type="aRts", + .detect=arts_card_detect, + .create_reader=arts_card_create_reader, + .create_writer=arts_card_create_writer, + .duplicate=NULL +}; + +MS_FILTER_DESC_EXPORT(ms_arts_read_desc) +MS_FILTER_DESC_EXPORT(ms_arts_write_desc) diff --git a/linphone/mediastreamer2/src/audiostream.c b/linphone/mediastreamer2/src/audiostream.c new file mode 100644 index 000000000..d024657a0 --- /dev/null +++ b/linphone/mediastreamer2/src/audiostream.c @@ -0,0 +1,426 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mediastream.h" + +#include "mediastreamer2/dtmfgen.h" +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msrtp.h" +#include "mediastreamer2/msfileplayer.h" +#include "mediastreamer2/msfilerec.h" + +#ifdef INET6 + #include +#ifndef WIN32 + #include + #include +#endif +#endif + + +#define MAX_RTP_SIZE 1500 + + +/* this code is not part of the library itself, it is part of the mediastream program */ +void audio_stream_free(AudioStream *stream) +{ + if (stream->session!=NULL) rtp_session_destroy(stream->session); + if (stream->rtpsend!=NULL) ms_filter_destroy(stream->rtpsend); + if (stream->rtprecv!=NULL) ms_filter_destroy(stream->rtprecv); + if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread); + if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite); + if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder); + if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder); + if (stream->dtmfgen!=NULL) ms_filter_destroy(stream->dtmfgen); + if (stream->ec!=NULL) ms_filter_destroy(stream->ec); + if (stream->ticker!=NULL) ms_ticker_destroy(stream->ticker); + ms_free(stream); +} + +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + +static void on_dtmf_received(RtpSession *s, int dtmf, void * user_data) +{ + MSFilter *dtmfgen=(MSFilter*)user_data; + if (dtmf>15){ + ms_warning("Unsupported telephone-event type."); + return; + } + ms_message("Receiving dtmf %c.",dtmf_tab[dtmf]); + if (dtmfgen!=NULL){ + ms_filter_call_method(dtmfgen,MS_DTMF_GEN_PUT,&dtmf_tab[dtmf]); + } +} + +#if 0 + +static void on_timestamp_jump(RtpSession *s,uint32_t* ts, void * user_data) +{ + ms_warning("The remote sip-phone has send data with a future timestamp: %u," + "resynchronising session.",*ts); + rtp_session_reset(s); +} + +#endif + + +bool_t ms_is_ipv6(const char *remote){ + bool_t ret=FALSE; +#ifdef INET6 + struct addrinfo hints, *res0; + + int err; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + err = getaddrinfo(remote,"8000", &hints, &res0); + if (err!=0) { + ms_warning ("get_local_addr_for: %s", gai_strerror(err)); + return FALSE; + } + ret=(res0->ai_addr->sa_family==AF_INET6); + freeaddrinfo(res0); +#endif + return ret; +} + +RtpSession * create_duplex_rtpsession( int locport, bool_t ipv6){ + RtpSession *rtpr; + rtpr=rtp_session_new(RTP_SESSION_SENDRECV); + rtp_session_set_recv_buf_size(rtpr,MAX_RTP_SIZE); + rtp_session_set_scheduling_mode(rtpr,0); + rtp_session_set_blocking_mode(rtpr,0); + rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE); + rtp_session_set_symmetric_rtp(rtpr,TRUE); + rtp_session_set_local_addr(rtpr,ipv6 ? "::" : "0.0.0.0",locport); + rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)rtp_session_resync,(long)NULL); + rtp_session_signal_connect(rtpr,"ssrc_changed",(RtpCallback)rtp_session_resync,(long)NULL); + return rtpr; +} + +bool_t audio_stream_alive(AudioStream * stream, int timeout){ + RtpSession *session=stream->session; + const rtp_stats_t *stats=rtp_session_get_stats(session); + if (stats->recv!=0){ + if (stats->recv!=stream->last_packet_count){ + stream->last_packet_count=stats->recv; + stream->last_packet_time=time(NULL); + }else{ + if (time(NULL)-stream->last_packet_time>timeout){ + /* more than timeout seconds of inactivity*/ + return FALSE; + } + } + } + return TRUE; +} + +/*this function must be called from the MSTicker thread: +it replaces one filter by another one. +This is a dirty hack that works anyway. +It would be interesting to have something that does the job +simplier within the MSTicker api +*/ +void audio_stream_change_decoder(AudioStream *stream, int payload){ + RtpSession *session=stream->session; + RtpProfile *prof=rtp_session_get_profile(session); + PayloadType *pt=rtp_profile_get_payload(prof,payload); + if (pt!=NULL){ + MSFilter *dec=ms_filter_create_decoder(pt->mime_type); + if (dec!=NULL){ + ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0); + ms_filter_unlink(stream->decoder,0,stream->dtmfgen,0); + ms_filter_postprocess(stream->decoder); + ms_filter_destroy(stream->decoder); + stream->decoder=dec; + if (pt->recv_fmtp!=NULL) + ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); + ms_filter_link (stream->rtprecv, 0, stream->decoder, 0); + ms_filter_link (stream->decoder,0 , stream->dtmfgen, 0); + ms_filter_preprocess(stream->decoder,stream->ticker); + + }else{ + ms_warning("No decoder found for %s",pt->mime_type); + } + }else{ + ms_warning("No payload defined with number %i",payload); + } +} + +static void payload_type_changed(RtpSession *session, unsigned long data){ + AudioStream *stream=(AudioStream*)data; + int pt=rtp_session_get_recv_payload_type(stream->session); + audio_stream_change_decoder(stream,pt); +} + + +int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *remip,int remport, + int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile, + MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec) +{ + RtpSession *rtps=stream->session; + PayloadType *pt; + int tmp; + + rtp_session_set_profile(rtps,profile); + if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port); + rtp_session_set_payload_type(rtps,payload); + rtp_session_set_jitter_compensation(rtps,jitt_comp); + + if (remport>0) + ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,rtps); + stream->rtprecv=ms_filter_new(MS_RTP_RECV_ID); + ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,rtps); + stream->session=rtps; + + stream->dtmfgen=ms_filter_new(MS_DTMF_GEN_ID); + rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)on_dtmf_received,(unsigned long)stream->dtmfgen); + rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)payload_type_changed,(unsigned long)stream); + + /* creates the local part */ + if (captcard!=NULL) stream->soundread=ms_snd_card_create_reader(captcard); + else { + stream->soundread=ms_filter_new(MS_FILE_PLAYER_ID); + if (infile!=NULL) audio_stream_play(stream,infile); + } + if (playcard!=NULL) stream->soundwrite=ms_snd_card_create_writer(playcard); + else { + stream->soundwrite=ms_filter_new(MS_FILE_REC_ID); + if (outfile!=NULL) audio_stream_record(stream,outfile); + } + + /* creates the couple of encoder/decoder */ + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + ms_error("audiostream.c: undefined payload type."); + return -1; + } + stream->encoder=ms_filter_create_encoder(pt->mime_type); + stream->decoder=ms_filter_create_decoder(pt->mime_type); + if ((stream->encoder==NULL) || (stream->decoder==NULL)){ + /* big problem: we have not a registered codec for this payload...*/ + ms_error("mediastream.c: No decoder available for payload %i.",payload); + return -1; + } + + if (use_ec) { + stream->ec=ms_filter_new(MS_SPEEX_EC_ID); + ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate); + } + + /* give the sound filters some properties */ + ms_filter_call_method(stream->soundread,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate); + ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate); + tmp=1; + ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_NCHANNELS, &tmp); + + /* give the encoder/decoder some parameters*/ + ms_filter_call_method(stream->encoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate); + if (pt->normal_bitrate>0){ + ms_message("Setting audio encoder network bitrate to %i",pt->normal_bitrate); + ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate); + } + ms_filter_call_method(stream->decoder,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate); + + if (pt->send_fmtp!=NULL) ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp); + if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); + + /* and then connect all */ + /* tip: draw yourself the picture if you don't understand */ + if (stream->ec){ + ms_filter_link(stream->soundread,0,stream->ec,1); + ms_filter_link(stream->ec,1,stream->encoder,0); + ms_filter_link(stream->dtmfgen,0,stream->ec,0); + ms_filter_link(stream->ec,0,stream->soundwrite,0); + }else{ + ms_filter_link(stream->soundread,0,stream->encoder,0); + ms_filter_link(stream->dtmfgen,0,stream->soundwrite,0); + } + + ms_filter_link(stream->encoder,0,stream->rtpsend,0); + ms_filter_link(stream->rtprecv,0,stream->decoder,0); + ms_filter_link(stream->decoder,0,stream->dtmfgen,0); + + /* create ticker */ + stream->ticker=ms_ticker_new(); + + ms_ticker_attach(stream->ticker,stream->soundread); + ms_ticker_attach(stream->ticker,stream->rtprecv); + + return 0; +} + + +int audio_stream_start_with_files(AudioStream *stream, RtpProfile *prof,const char *remip, int remport, + int rem_rtcp_port, int pt,int jitt_comp, const char *infile, const char * outfile) +{ + return audio_stream_start_full(stream,prof,remip,remport,rem_rtcp_port,pt,jitt_comp,infile,outfile,NULL,NULL,FALSE); +} + +AudioStream * audio_stream_start(RtpProfile *prof,int locport,const char *remip,int remport,int profile,int jitt_comp,bool_t use_ec) +{ + MSSndCard *sndcard; + AudioStream *stream; + sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); + if (sndcard==NULL) + return NULL; + stream=audio_stream_new(locport, ms_is_ipv6(remip)); + if (audio_stream_start_full(stream,prof,remip,remport,remport+1,profile,jitt_comp,NULL,NULL,sndcard,sndcard,use_ec)==0) return stream; + audio_stream_free(stream); + return NULL; +} + +AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,const char *remip,int remport,int profile,int jitt_comp,MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec) +{ + AudioStream *stream; + if (playcard==NULL) { + ms_error("No playback card."); + return NULL; + } + if (captcard==NULL) { + ms_error("No capture card."); + return NULL; + } + stream=audio_stream_new(locport, ms_is_ipv6(remip)); + if (audio_stream_start_full(stream,prof,remip,remport,remport+1,profile,jitt_comp,NULL,NULL,playcard,captcard,use_ec)==0) return stream; + audio_stream_free(stream); + return NULL; +} + +void audio_stream_set_rtcp_information(AudioStream *st, const char *cname, const char *tool){ + if (st->session!=NULL){ + rtp_session_set_source_description(st->session,cname,NULL,NULL,NULL,NULL,tool , "This is free software (GPL) !"); + } +} + +void audio_stream_play(AudioStream *st, const char *name){ + if (ms_filter_get_id(st->soundread)==MS_FILE_PLAYER_ID){ + ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_CLOSE); + ms_filter_call_method(st->soundread,MS_FILE_PLAYER_OPEN,(void*)name); + ms_filter_call_method_noarg(st->soundread,MS_FILE_PLAYER_START); + }else{ + ms_error("Cannot play file: the stream hasn't been started with" + " audio_stream_start_with_files"); + } +} + +void audio_stream_record(AudioStream *st, const char *name){ + if (ms_filter_get_id(st->soundwrite)==MS_FILE_REC_ID){ + ms_filter_call_method_noarg(st->soundwrite,MS_FILE_REC_CLOSE); + ms_filter_call_method(st->soundwrite,MS_FILE_REC_OPEN,(void*)name); + ms_filter_call_method_noarg(st->soundwrite,MS_FILE_REC_START); + }else{ + ms_error("Cannot record file: the stream hasn't been started with" + " audio_stream_start_with_files"); + } +} + + +AudioStream *audio_stream_new(int locport, bool_t ipv6){ + AudioStream *stream=(AudioStream *)ms_new0(AudioStream,1); + stream->session=create_duplex_rtpsession(locport,ipv6); + stream->rtpsend=ms_filter_new(MS_RTP_SEND_ID); + return stream; +} + +int audio_stream_start_now(AudioStream *stream, RtpProfile * prof, const char *remip, int remport, int rem_rtcp_port, int payload_type, int jitt_comp, MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec){ + return audio_stream_start_full(stream,prof,remip,remport,rem_rtcp_port, + payload_type,jitt_comp,NULL,NULL,playcard,captcard,use_ec); +} + +void audio_stream_set_relay_session_id(AudioStream *stream, const char *id){ + ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id); +} + +void audio_stream_stop(AudioStream * stream) +{ + if (stream->ticker){ + ms_ticker_detach(stream->ticker,stream->soundread); + ms_ticker_detach(stream->ticker,stream->rtprecv); + + rtp_stats_display(rtp_session_get_stats(stream->session),"Audio session's RTP statistics"); + + if (stream->ec!=NULL){ + ms_filter_unlink(stream->soundread,0,stream->ec,1); + ms_filter_unlink(stream->ec,1,stream->encoder,0); + ms_filter_unlink(stream->dtmfgen,0,stream->ec,0); + ms_filter_unlink(stream->ec,0,stream->soundwrite,0); + }else{ + ms_filter_unlink(stream->soundread,0,stream->encoder,0); + ms_filter_unlink(stream->dtmfgen,0,stream->soundwrite,0); + } + + ms_filter_unlink(stream->encoder,0,stream->rtpsend,0); + ms_filter_unlink(stream->rtprecv,0,stream->decoder,0); + ms_filter_unlink(stream->decoder,0,stream->dtmfgen,0); + } + audio_stream_free(stream); +} + +RingStream * ring_start(const char *file, int interval, MSSndCard *sndcard){ + return ring_start_with_cb(file,interval,sndcard,NULL,NULL); +} + +RingStream * ring_start_with_cb(const char *file,int interval,MSSndCard *sndcard, MSFilterNotifyFunc func,void * user_data) +{ + RingStream *stream; + int tmp; + stream=(RingStream *)ms_new0(RingStream,1); + stream->source=ms_filter_new(MS_FILE_PLAYER_ID); + if (ms_filter_call_method(stream->source,MS_FILE_PLAYER_OPEN,(void*)file)<0){ + ms_filter_destroy(stream->source); + ms_free(stream); + return NULL; + } + ms_filter_call_method(stream->source,MS_FILE_PLAYER_LOOP,&interval); + ms_filter_call_method_noarg(stream->source,MS_FILE_PLAYER_START); + if (func!=NULL) + ms_filter_set_notify_callback(stream->source,func,user_data); + stream->sndwrite=ms_snd_card_create_writer(sndcard); + ms_filter_call_method(stream->source,MS_FILTER_GET_SAMPLE_RATE,&tmp); + ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&tmp); + ms_filter_call_method(stream->source,MS_FILTER_GET_NCHANNELS,&tmp); + ms_filter_call_method(stream->sndwrite,MS_FILTER_SET_NCHANNELS,&tmp); + stream->ticker=ms_ticker_new(); + ms_filter_link(stream->source,0,stream->sndwrite,0); + ms_ticker_attach(stream->ticker,stream->source); + return stream; +} + +void ring_stop(RingStream *stream){ + ms_ticker_detach(stream->ticker,stream->source); + ms_filter_unlink(stream->source,0,stream->sndwrite,0); + ms_ticker_destroy(stream->ticker); + ms_filter_destroy(stream->source); + ms_filter_destroy(stream->sndwrite); + ms_free(stream); +} + + +int audio_stream_send_dtmf(AudioStream *stream, char dtmf) +{ + ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SEND_DTMF,&dtmf); + ms_filter_call_method(stream->dtmfgen,MS_DTMF_GEN_PUT,&dtmf); + return 0; +} diff --git a/linphone/mediastreamer2/src/dtmfgen.c b/linphone/mediastreamer2/src/dtmfgen.c new file mode 100644 index 000000000..0390986fd --- /dev/null +++ b/linphone/mediastreamer2/src/dtmfgen.c @@ -0,0 +1,204 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/dtmfgen.h" + + +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +struct DtmfGenState{ + int rate; + int dur; + int pos; + float highfreq; + float lowfreq; + char dtmf; +}; + +typedef struct DtmfGenState DtmfGenState; + +static void dtmfgen_init(MSFilter *f){ + DtmfGenState *s=(DtmfGenState *)ms_new(DtmfGenState,1); + s->rate=8000; + s->dur=s->rate/10; + s->pos=0; + s->dtmf=0; + f->data=s; +} + +static void dtmfgen_uninit(MSFilter *f){ + ms_free(f->data); +} + +static int dtmfgen_put(MSFilter *f, void *arg){ + DtmfGenState *s=(DtmfGenState*)f->data; + const char *dtmf=(char*)arg; + s->pos=0; + switch(dtmf[0]){ + case '0': + s->lowfreq=941; + s->highfreq=1336; + break; + case '1': + s->lowfreq=697; + s->highfreq=1209; + break; + case '2': + s->lowfreq=697; + s->highfreq=1336; + break; + case '3': + s->lowfreq=697; + s->highfreq=1477; + break; + case '4': + s->lowfreq=770; + s->highfreq=1209; + break; + case '5': + s->lowfreq=770; + s->highfreq=1336; + break; + case '6': + s->lowfreq=770; + s->highfreq=1477; + break; + case '7': + s->lowfreq=852; + s->highfreq=1209; + break; + case '8': + s->lowfreq=852; + s->highfreq=1336; + break; + case '9': + s->lowfreq=852; + s->highfreq=1477; + break; + case '*': + s->lowfreq=941; + s->highfreq=1209; + break; + case '#': + s->lowfreq=941; + s->highfreq=1477; + break; + case 'A': + s->lowfreq=697; + s->highfreq=1633; + break; + case 'B': + s->lowfreq=770; + s->highfreq=1633; + break; + case 'C': + s->lowfreq=852; + s->highfreq=1633; + break; + case 'D': + s->lowfreq=941; + s->highfreq=1633; + break; + default: + ms_warning("Not a dtmf key."); + return -1; + } + s->lowfreq=s->lowfreq/s->rate; + s->highfreq=s->highfreq/s->rate; + + s->dtmf=dtmf[0]; + return 0; +} + +static int dtmfgen_set_rate(MSFilter *f, void *arg){ + DtmfGenState *s=(DtmfGenState*)f->data; + s->rate=*((int*)arg); + s->dur=s->rate/10; + return 0; +} + +static void dtmfgen_process(MSFilter *f){ + mblk_t *m; + DtmfGenState *s=(DtmfGenState*)f->data; + + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + if (s->dtmf!=0){ + int nsamples=(m->b_wptr-m->b_rptr)/2; + int i; + int16_t *sample=(int16_t*)m->b_rptr; + for (i=0;iposdur;i++,s->pos++){ + sample[i]=(int16_t)(10000.0*sin(2*M_PI*(float)s->pos*s->lowfreq)); + sample[i]+=(int16_t)(10000.0*sin(2*M_PI*(float)s->pos*s->highfreq)); + } + if (s->pos==s->dur){ + s->pos=0; + s->dtmf=0; + } + } + ms_queue_put(f->outputs[0],m); + } +} + +MSFilterMethod dtmfgen_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , dtmfgen_set_rate }, + { MS_DTMF_GEN_PUT , dtmfgen_put }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_dtmf_gen_desc={ + MS_DTMF_GEN_ID, + "MSDtmfGen", + "DTMF generator", + MS_FILTER_OTHER, + NULL, + 1, + 1, + dtmfgen_init, + NULL, + dtmfgen_process, + NULL, + dtmfgen_uninit, + dtmfgen_methods +}; + +#else + +MSFilterDesc ms_dtmf_gen_desc={ + .id=MS_DTMF_GEN_ID, + .name="MSDtmfGen", + .text="DTMF generator", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=1, + .init=dtmfgen_init, + .process=dtmfgen_process, + .uninit=dtmfgen_uninit, + .methods=dtmfgen_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_dtmf_gen_desc) + diff --git a/linphone/mediastreamer2/src/dxfilter.cpp b/linphone/mediastreamer2/src/dxfilter.cpp new file mode 100644 index 000000000..db3627fc6 --- /dev/null +++ b/linphone/mediastreamer2/src/dxfilter.cpp @@ -0,0 +1,880 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#if !defined(_WIN32_WCE) //Allready defined for wince +#define UNICODE +#endif + +#include +#include + +#if !defined(_WIN32_WCE) +#include "qedit.h" +#endif +#include "dxfilter.h" + +#pragma warning(disable: 4800) + + +const AMOVIESETUP_PIN psudDXFilterPins[] = +{ { L"Input" // strName + , FALSE // bRendered + , FALSE // bOutput + , FALSE // bZero + , FALSE // bMany + , &CLSID_NULL // clsConnectsToFilter + , L"" // strConnectsToPin + , 0 // nTypes + , NULL // lpTypes + } +, { L"Output" // strName + , FALSE // bRendered + , TRUE // bOutput + , FALSE // bZero + , FALSE // bMany + , &CLSID_NULL // clsConnectsToFilter + , L"" // strConnectsToPin + , 0 // nTypes + , NULL // lpTypes + } +}; + +const AMOVIESETUP_FILTER sudDXFilter = +{ &CLSID_DXFilter // clsID +, L"DXFilter for mediastreamer2" // strName +, MERIT_DO_NOT_USE // dwMerit +, 2 // nPins +, psudDXFilterPins }; // lpPin + + +// Needed for the CreateInstance mechanism +CFactoryTemplate g_Templates[]= +{ + { L"DirectX Filter for mediastreamer2" + , &CLSID_DXFilter + , CDXFilter::CreateInstance + , NULL + , &sudDXFilter } + +}; + +int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]); + + +//////////////////////////////////////////////////////////////////////// +// +// Exported entry points for registration and unregistration +// (in this case they only call through to default implementations). +// +//////////////////////////////////////////////////////////////////////// + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +// +// DllEntryPoint +// +extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD dwReason, + LPVOID lpReserved) +{ + return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); +} + +// +// CreateInstance +// +// Provide the way for COM to create a CDXFilter object +// +CUnknown * WINAPI CDXFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr) +{ + /* ASSERT(phr); */ + + // assuming we don't want to modify the data + CDXFilter *pNewObject = new CDXFilter(punk, phr, FALSE); + + if(pNewObject == NULL) { + if (phr) + *phr = E_OUTOFMEMORY; + } + + return pNewObject; + +} // CreateInstance + + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +CDXFilter::CDXFilter( IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData ) + : CTransInPlaceFilter( TEXT("DXFilter"), (IUnknown*) pOuter, + CLSID_DXFilter, phr +#if !defined(_WIN32_WCE) + ,(BOOL)ModifiesData +#endif + ) + , m_callback( NULL ) +{ + // this is used to override the input pin with our own + m_pInput = (CTransInPlaceInputPin*) new CDXFilterInPin( this, phr ); + if( !m_pInput ) + { + if (phr) + *phr = E_OUTOFMEMORY; + } + + // Ensure that the output pin gets created. This is necessary because our + // SetDeliveryBuffer() method assumes that the input/output pins are created, but + // the output pin isn't created until GetPin() is called. The + // CTransInPlaceFilter::GetPin() method will create the output pin, since we + // have not already created one. + IPin *pOutput = GetPin(1); + // The pointer is not AddRef'ed by GetPin(), so don't release it +} + +STDMETHODIMP CDXFilter::NonDelegatingQueryInterface( REFIID riid, void ** ppv) +{ + CheckPointer(ppv,E_POINTER); + + if(riid == IID_IDXFilter) { + return GetInterface((IDXFilter *) this, ppv); + } + else { + return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv); + } +} + + +//---------------------------------------------------------------------------- +// This is where you force the sample grabber to connect with one type +// or the other. What you do here is crucial to what type of data your +// app will be dealing with in the sample grabber's callback. For instance, +// if you don't enforce right-side-up video in this call, you may not get +// right-side-up video in your callback. It all depends on what you do here. +//---------------------------------------------------------------------------- + +HRESULT CDXFilter::CheckInputType( const CMediaType * pmt ) +{ + CheckPointer(pmt,E_POINTER); + CAutoLock lock( &m_Lock ); + + // if the major type is not set, then accept anything + + GUID g = *m_mtAccept.Type( ); + if( g == GUID_NULL ) + { + return NOERROR; + } + + // if the major type is set, don't accept anything else + + if( g != *pmt->Type( ) ) + { + return VFW_E_INVALID_MEDIA_TYPE; + } + + // subtypes must match, if set. if not set, accept anything + VIDEOINFO *pvi = (VIDEOINFO *)pmt->Format(); + + g = *m_mtAccept.Subtype( ); + if( g == GUID_NULL ) + { + return NOERROR; + } +#if 0 + if( MEDIASUBTYPE_RGB24 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_YVU9 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Y411 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Y41P == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_YUY2 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_YVYU == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_UYVY == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Y211 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_YV12 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_CLJR == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_IF09 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_CPLA == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MJPG == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_TVMJ == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_WAKE == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_CFCC == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_IJPG == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Plum == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB1 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB1 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB1 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB4 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB8 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB565 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB555 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB24 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_RGB32 == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Overlay == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MPEG1Packet == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MPEG1Payload == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MPEG1AudioPayload == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIATYPE_MPEG1SystemStream == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MPEG1System == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MPEG1VideoCD == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_MPEG1Video == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Avi == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_Asf == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_QTMovie == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_QTRpza == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_QTSmc == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_QTRle == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_QTJpeg == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_PCM == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_WAVE == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_AU == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_AIFF == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_DssVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVBI == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; + if( MEDIASUBTYPE_VPVideo == *pmt->Subtype( ) ) + return VFW_E_INVALID_MEDIA_TYPE; +#endif + + if( g != *pmt->Subtype( ) ) + { + return VFW_E_INVALID_MEDIA_TYPE; + } + + // format types must match, if one is set + + g = *m_mtAccept.FormatType( ); + if( g == GUID_NULL ) + { + return NOERROR; + } + if( g != *pmt->FormatType( ) ) + { + return VFW_E_INVALID_MEDIA_TYPE; + } + + // at this point, for this sample code, this is good enough, + // but you may want to make it more strict + + //compare sizes + //VIDEOINFO *pvi = (VIDEOINFO *)pmt->Format(); + VIDEOINFO *pvi2 = (VIDEOINFO *)m_mtAccept.Format(); + if (pvi2==NULL) + return NOERROR; + + if (pvi==NULL) + return VFW_E_INVALID_MEDIA_TYPE; +#if !defined(_WIN32_WCE) + if (pvi->bmiHeader.biCompression!=pvi2->bmiHeader.biCompression) + return VFW_E_INVALID_MEDIA_TYPE; +#endif + if (pvi->bmiHeader.biBitCount!=pvi2->bmiHeader.biBitCount) + return VFW_E_INVALID_MEDIA_TYPE; + if (pvi->bmiHeader.biWidth!=pvi2->bmiHeader.biWidth) + return VFW_E_INVALID_MEDIA_TYPE; + if (pvi->bmiHeader.biHeight!=pvi2->bmiHeader.biHeight) + return VFW_E_INVALID_MEDIA_TYPE; + if (pvi->bmiHeader.biSizeImage!=pvi2->bmiHeader.biSizeImage) + return VFW_E_INVALID_MEDIA_TYPE; + + return NOERROR; +} + + +//---------------------------------------------------------------------------- +// This bit is almost straight out of the base classes. +// We override this so we can handle Transform( )'s error +// result differently. +//---------------------------------------------------------------------------- + +HRESULT CDXFilter::Receive( IMediaSample * pms ) +{ + CheckPointer(pms,E_POINTER); + + HRESULT hr; + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + + if (pProps->dwStreamId != AM_STREAM_MEDIA) + { + if( m_pOutput->IsConnected() ) + return m_pOutput->Deliver(pms); + else + return NOERROR; + } + +#if !defined(_WIN32_WCE) + if (UsingDifferentAllocators()) + { + // We have to copy the data. + + pms = Copy(pms); + + if (pms == NULL) + { + return E_UNEXPECTED; + } + } +#endif + + // have the derived class transform the data + hr = Transform(pms); + + if (FAILED(hr)) + { + //DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); +#if !defined(_WIN32_WCE) + if (UsingDifferentAllocators()) + { + pms->Release(); + } +#endif + return hr; + } + + if (hr == NOERROR) + { + hr = m_pOutput->Deliver(pms); + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. +#if !defined(_WIN32_WCE) + if (UsingDifferentAllocators()) + { + pms->Release(); + } +#endif + return hr; +} + + +//---------------------------------------------------------------------------- +// Transform +//---------------------------------------------------------------------------- + +HRESULT CDXFilter::Transform ( IMediaSample * pms ) +{ + CheckPointer(pms,E_POINTER); + CAutoLock lock( &m_Lock ); + + if( m_callback ) + { + REFERENCE_TIME StartTime, StopTime; + pms->GetTime( &StartTime, &StopTime); + + StartTime += m_pInput->CurrentStartTime( ); + StopTime += m_pInput->CurrentStartTime( ); + + BOOL * pTypeChanged = &((CDXFilterInPin*) m_pInput)->m_bMediaTypeChanged; + + HRESULT hr = m_callback( pms, &StartTime, &StopTime, *pTypeChanged ); + + *pTypeChanged = FALSE; // now that we notified user, we can clear it + + return hr; + } + + return NOERROR; +} + + +//---------------------------------------------------------------------------- +// SetAcceptedMediaType +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilter::SetAcceptedMediaType( const CMediaType * pmt ) +{ + CAutoLock lock( &m_Lock ); + + if( !pmt ) + { + m_mtAccept = CMediaType( ); + return NOERROR; + } + + HRESULT hr; +#if !defined(_WIN32_WCE) + hr = CopyMediaType( &m_mtAccept, pmt ); +#else + hr=S_OK; + CopyMediaType( &m_mtAccept, pmt ); +#endif + return hr; +} + +//---------------------------------------------------------------------------- +// GetAcceptedMediaType +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilter::GetConnectedMediaType( CMediaType * pmt ) +{ + if( !m_pInput || !m_pInput->IsConnected( ) ) + { + return VFW_E_NOT_CONNECTED; + } + + return m_pInput->ConnectionMediaType( pmt ); +} + + +//---------------------------------------------------------------------------- +// SetCallback +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilter::SetCallback( SAMPLECALLBACK Callback ) +{ + CAutoLock lock( &m_Lock ); + + m_callback = Callback; + + return NOERROR; +} + + +//---------------------------------------------------------------------------- +// inform the input pin of the allocator buffer we wish to use. See the +// input pin's SetDeliverBuffer method for comments. +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilter::SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer ) +{ + // have the input/output pins been created? + if( !InputPin( ) || !OutputPin( ) ) + { + return E_POINTER; + } + + // they can't be connected if we're going to be changing delivery buffers + // + if( InputPin( )->IsConnected( ) || OutputPin( )->IsConnected( ) ) + { + return E_INVALIDARG; + } + + return ((CDXFilterInPin*)m_pInput)->SetDeliveryBuffer( props, m_pBuffer ); +} + + +//---------------------------------------------------------------------------- +// used to help speed input pin connection times. We return a partially +// specified media type - only the main type is specified. If we return +// anything BUT a major type, some codecs written improperly will crash +//---------------------------------------------------------------------------- + +HRESULT CDXFilterInPin::GetMediaType( int iPosition, CMediaType * pMediaType ) +{ + CheckPointer(pMediaType,E_POINTER); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + *pMediaType = CMediaType( ); + pMediaType->SetType( ((CDXFilter*)m_pFilter)->m_mtAccept.Type( ) ); + + return S_OK; +} + + +//---------------------------------------------------------------------------- +// override the CTransInPlaceInputPin's method, and return a new enumerator +// if the input pin is disconnected. This will allow GetMediaType to be +// called. If we didn't do this, EnumMediaTypes returns a failure code +// and GetMediaType is never called. +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilterInPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + + // if the output pin isn't connected yet, offer the possibly + // partially specified media type that has been set by the user + + if( !((CDXFilter*)m_pTIPFilter)->OutputPin( )->IsConnected() ) + { + // Create a new reference counted enumerator + + *ppEnum = new CEnumMediaTypes( this, NULL ); + + return (*ppEnum) ? NOERROR : E_OUTOFMEMORY; + } + + // if the output pin is connected, offer it's fully qualified media type + + return ((CDXFilter*)m_pTIPFilter)->OutputPin( )->GetConnected()->EnumMediaTypes( ppEnum ); +} + + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilterInPin::NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly ) +{ + if( m_pPrivateAllocator ) + { + if( pAllocator != m_pPrivateAllocator ) + { + return E_FAIL; + } + else + { +#if !defined(_WIN32_WCE) + // if the upstream guy wants to be read only and we don't, then that's bad + // if the upstream guy doesn't request read only, but we do, that's okay + if( bReadOnly && !DXFilter( )->IsReadOnly( ) ) + { + return E_FAIL; + } +#endif + } + } + + return CTransInPlaceInputPin::NotifyAllocator( pAllocator, bReadOnly ); +} + + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +STDMETHODIMP CDXFilterInPin::GetAllocator( IMemAllocator **ppAllocator ) +{ + if( m_pPrivateAllocator ) + { + CheckPointer(ppAllocator,E_POINTER); + + *ppAllocator = m_pPrivateAllocator; + m_pPrivateAllocator->AddRef( ); + return NOERROR; + } + else + { + return CTransInPlaceInputPin::GetAllocator( ppAllocator ); + } +} + +//---------------------------------------------------------------------------- +// GetAllocatorRequirements: The upstream filter calls this to get our +// filter's allocator requirements. If the app has set the buffer, then +// we return those props. Otherwise, we use the default TransInPlace behavior. +//---------------------------------------------------------------------------- + +HRESULT CDXFilterInPin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps ) +{ + CheckPointer(pProps,E_POINTER); + + if (m_pPrivateAllocator) + { + *pProps = m_allocprops; + return S_OK; + } + else + { + return CTransInPlaceInputPin::GetAllocatorRequirements(pProps); + } +} + + + + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HRESULT CDXFilterInPin::SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * pBuffer ) +{ + // don't allow more than one buffer + + if( props.cBuffers != 1 ) + { + return E_INVALIDARG; + } + if( !pBuffer ) + { + return E_POINTER; + } + + m_allocprops = props; + m_pBuffer = pBuffer; + + // If there is an existing allocator, make sure that it is released + // to prevent a memory leak + if (m_pPrivateAllocator) + { + m_pPrivateAllocator->Release(); + m_pPrivateAllocator = NULL; + } + + HRESULT hr = S_OK; + + m_pPrivateAllocator = new CDXFilterAllocator( this, &hr ); + if( !m_pPrivateAllocator ) + { + return E_OUTOFMEMORY; + } + + m_pPrivateAllocator->AddRef( ); + return hr; +} + + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +HRESULT CDXFilterInPin::SetMediaType( const CMediaType *pmt ) +{ + m_bMediaTypeChanged = TRUE; + + return CTransInPlaceInputPin::SetMediaType( pmt ); +} + + +//---------------------------------------------------------------------------- +// don't allocate the memory, just use the buffer the app provided +//---------------------------------------------------------------------------- + +HRESULT CDXFilterAllocator::Alloc( ) +{ + // look at the base class code to see where this came from! + + CAutoLock lck(this); + + // Check he has called SetProperties + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + // If the requirements haven't changed then don't reallocate + if (hr == S_FALSE) { + /* ASSERT(m_pBuffer); */ + return NOERROR; + } + /* ASSERT(hr == S_OK); we use this fact in the loop below */ + + // Free the old resources + if (m_pBuffer) { + ReallyFree(); + } + + // Compute the aligned size + LONG lAlignedSize = m_lSize + m_lPrefix; + if (m_lAlignment > 1) + { + LONG lRemainder = lAlignedSize % m_lAlignment; + if (lRemainder != 0) + { + lAlignedSize += (m_lAlignment - lRemainder); + } + } + + // Create the contiguous memory block for the samples + // making sure it's properly aligned (64K should be enough!) + /* ASSERT(lAlignedSize % m_lAlignment == 0); */ + + // don't create the buffer - use what was passed to us + // + m_pBuffer = m_pPin->m_pBuffer; + + if (m_pBuffer == NULL) { + return E_OUTOFMEMORY; + } + + LPBYTE pNext = m_pBuffer; + CMediaSample *pSample; + + /* ASSERT(m_lAllocated == 0); */ + + // Create the new samples - we have allocated m_lSize bytes for each sample + // plus m_lPrefix bytes per sample as a prefix. We set the pointer to + // the memory after the prefix - so that GetPointer() will return a pointer + // to m_lSize bytes. + for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) + { + pSample = new CMediaSample( + NAME("Sample Grabber memory media sample"), + this, + &hr, + pNext + m_lPrefix, // GetPointer() value + m_lSize); // not including prefix + + /* ASSERT(SUCCEEDED(hr)); */ + if (pSample == NULL) + return E_OUTOFMEMORY; + + // This CANNOT fail + m_lFree.Add(pSample); + } + + m_bChanged = FALSE; + return NOERROR; +} + + +//---------------------------------------------------------------------------- +// don't really free the memory +//---------------------------------------------------------------------------- + +void CDXFilterAllocator::ReallyFree() +{ + // look at the base class code to see where this came from! + + // Should never be deleting this unless all buffers are freed + + /* ASSERT(m_lAllocated == m_lFree.GetCount()); */ + + // Free up all the CMediaSamples + + CMediaSample *pSample; + for (;;) + { + pSample = m_lFree.RemoveHead(); + if (pSample != NULL) + { + delete pSample; + } + else + { + break; + } + } + + m_lAllocated = 0; + + // don't free the buffer - let the app do it +} + + +//---------------------------------------------------------------------------- +// SetProperties: Called by the upstream filter to set the allocator +// properties. The application has already allocated the buffer, so we reject +// anything that is not compatible with that, and return the actual props. +//---------------------------------------------------------------------------- + +HRESULT CDXFilterAllocator::SetProperties( + ALLOCATOR_PROPERTIES *pRequest, + ALLOCATOR_PROPERTIES *pActual +) +{ + HRESULT hr = CMemAllocator::SetProperties(pRequest, pActual); + + if (FAILED(hr)) + { + return hr; + } + + ALLOCATOR_PROPERTIES *pRequired = &(m_pPin->m_allocprops); + if (pRequest->cbAlign != pRequired->cbAlign) + { + return VFW_E_BADALIGN; + } + if (pRequest->cbPrefix != pRequired->cbPrefix) + { + return E_FAIL; + } + if (pRequest->cbBuffer > pRequired->cbBuffer) + { + return E_FAIL; + } + if (pRequest->cBuffers > pRequired->cBuffers) + { + return E_FAIL; + } + + *pActual = *pRequired; + + m_lCount = pRequired->cBuffers; + m_lSize = pRequired->cbBuffer; + m_lAlignment = pRequired->cbAlign; + m_lPrefix = pRequired->cbPrefix; + + return S_OK; +} diff --git a/linphone/mediastreamer2/src/dxfilter.h b/linphone/mediastreamer2/src/dxfilter.h new file mode 100644 index 000000000..cc63f0de9 --- /dev/null +++ b/linphone/mediastreamer2/src/dxfilter.h @@ -0,0 +1,231 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +// {4D6410BE-7643-4f43-B55F-8821A6FFB50A} +DEFINE_GUID(CLSID_DXFilter, +0x4d6410be, 0x7643, 0x4f43, 0xb5, 0x5f, 0x88, 0x21, 0xa6, 0xff, 0xb5, 0xa); + +// {52A7F345-CD92-442c-89C1-632C16AD5003} +DEFINE_GUID(IID_IDXFilter, +0x52a7f345, 0xcd92, 0x442c, 0x89, 0xc1, 0x63, 0x2c, 0x16, 0xad, 0x50, 0x3); + + +// We define a callback typedef for this example. +// Normally, you would make the DXFilter support a COM interface, +// and in one of its methods you would pass in a pointer to a COM interface +// used for calling back. See the DirectX documentation for the DXFilter +// for more information. + +typedef HRESULT (*SAMPLECALLBACK) ( + IMediaSample * pSample, + REFERENCE_TIME * StartTime, + REFERENCE_TIME * StopTime, + BOOL TypeChanged ); + + +// We define the interface the app can use to program us +MIDL_INTERFACE("6B652FFF-11FE-4FCE-92AD-0266B5D7C78F") +IDXFilter : public IUnknown +{ + public: + + virtual HRESULT STDMETHODCALLTYPE SetAcceptedMediaType( + const CMediaType *pType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType( + CMediaType *pType) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + SAMPLECALLBACK Callback) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetDeliveryBuffer( + ALLOCATOR_PROPERTIES props, + BYTE *pBuffer) = 0; +}; + + +class CDXFilterInPin; +class CDXFilter; + +//---------------------------------------------------------------------------- +// This is a special allocator that KNOWS that the person who is creating it +// will only create one of them. It allocates CMediaSamples that only +// reference the buffer location that is set in the pin's renderer's +// data variable +//---------------------------------------------------------------------------- + +class CDXFilterAllocator : public CMemAllocator +{ + friend class CDXFilterInPin; + friend class CDXFilter; + +protected: + + // our pin who created us + // + CDXFilterInPin * m_pPin; + +public: + + CDXFilterAllocator( CDXFilterInPin * pParent, HRESULT *phr ) + : CMemAllocator( TEXT("DXFilterAllocator\0"), NULL, phr ) + , m_pPin( pParent ) + { + }; + + ~CDXFilterAllocator( ) + { + // wipe out m_pBuffer before we try to delete it. It's not an allocated + // buffer, and the default destructor will try to free it! + m_pBuffer = NULL; + } + + HRESULT Alloc( ); + + void ReallyFree(); + + // Override this to reject anything that does not match the actual buffer + // that was created by the application + STDMETHODIMP SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual); + +}; + +//---------------------------------------------------------------------------- +// we override the input pin class so we can provide a media type +// to speed up connection times. When you try to connect a filesourceasync +// to a transform filter, DirectShow will insert a splitter and then +// start trying codecs, both audio and video, video codecs first. If +// your sample grabber's set to connect to audio, unless we do this, it +// will try all the video codecs first. Connection times are sped up x10 +// for audio with just this minor modification! +//---------------------------------------------------------------------------- + +class CDXFilterInPin : public CTransInPlaceInputPin +{ + friend class CDXFilterAllocator; + friend class CDXFilter; + + CDXFilterAllocator * m_pPrivateAllocator; + ALLOCATOR_PROPERTIES m_allocprops; + BYTE * m_pBuffer; + BOOL m_bMediaTypeChanged; + +protected: + + CDXFilter * DXFilter( ) { return (CDXFilter*) m_pFilter; } + HRESULT SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer ); + +public: + + CDXFilterInPin( CTransInPlaceFilter * pFilter, HRESULT * pHr ) + : CTransInPlaceInputPin( TEXT("DXFilterInputPin\0"), pFilter, pHr, L"Input\0" ) + , m_pPrivateAllocator( NULL ) + , m_pBuffer( NULL ) + , m_bMediaTypeChanged( FALSE ) + { + memset( &m_allocprops, 0, sizeof( m_allocprops ) ); + } + + ~CDXFilterInPin( ) + { + if( m_pPrivateAllocator ) delete m_pPrivateAllocator; + } + + // override to provide major media type for fast connects + + HRESULT GetMediaType( int iPosition, CMediaType *pMediaType ); + + // override this or GetMediaType is never called + + STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); + + // override this to refuse any allocators besides + // the one the user wants, if this is set + + STDMETHODIMP NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly ); + + // override this so we always return the special allocator, if necessary + + STDMETHODIMP GetAllocator( IMemAllocator **ppAllocator ); + + HRESULT SetMediaType( const CMediaType *pmt ); + + // we override this to tell whoever's upstream of us what kind of + // properties we're going to demand to have + // + STDMETHODIMP GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps ); + + + +}; + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- + +class CDXFilter : public CTransInPlaceFilter, + public IDXFilter +{ + friend class CDXFilterInPin; + friend class CDXFilterAllocator; + +protected: + + CMediaType m_mtAccept; + SAMPLECALLBACK m_callback; + CCritSec m_Lock; // serialize access to our data + +#if !defined(_WIN32_WCE) + BOOL IsReadOnly( ) { return !m_bModifiesData; } +#endif + + // PURE, override this to ensure we get + // connected with the right media type + HRESULT CheckInputType( const CMediaType * pmt ); + + // PURE, override this to callback + // the user when a sample is received + HRESULT Transform( IMediaSample * pms ); + + // override this so we can return S_FALSE directly. + // The base class CTransInPlace + // Transform( ) method is called by it's + // Receive( ) method. There is no way + // to get Transform( ) to return an S_FALSE value + // (which means "stop giving me data"), + // to Receive( ) and get Receive( ) to return S_FALSE as well. + + HRESULT Receive( IMediaSample * pms ); + +public: + + static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr); + + // Expose IDXFilter + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + DECLARE_IUNKNOWN; + + CDXFilter( IUnknown * pOuter, HRESULT * pHr, BOOL ModifiesData ); + + // IDXFilter + STDMETHODIMP SetAcceptedMediaType( const CMediaType * pmt ); + STDMETHODIMP GetConnectedMediaType( CMediaType * pmt ); + STDMETHODIMP SetCallback( SAMPLECALLBACK Callback ); + STDMETHODIMP SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer ); +}; diff --git a/linphone/mediastreamer2/src/ffmpeg-priv.h b/linphone/mediastreamer2/src/ffmpeg-priv.h new file mode 100644 index 000000000..eb5fcf471 --- /dev/null +++ b/linphone/mediastreamer2/src/ffmpeg-priv.h @@ -0,0 +1,48 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef FFMPEG_PRIV_H +#define FFMPEG_PRIV_H + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#if defined(HAVE_LIBAVCODEC_AVCODEC_H) +/* new layout */ +# include +# include +#else +/* old layout */ +# include +# include +#endif + +#if defined(HAVE_LIBSWSCALE_SWSCALE_H) +/* new layout */ +# include +# elif !defined(HAVE_LIBAVCODEC_AVCODEC_H) +/* old layout */ +# include +#else +/* swscale.h not delivered: use linphone private version */ +# include "swscale.h" +#endif + +#endif /* FFMPEG_PRIV_H */ diff --git a/linphone/mediastreamer2/src/g711common.h b/linphone/mediastreamer2/src/g711common.h new file mode 100644 index 000000000..3f2c9e330 --- /dev/null +++ b/linphone/mediastreamer2/src/g711common.h @@ -0,0 +1,171 @@ +/* + * PCM - A-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * Wrapper for linphone Codec class by Simon Morlat + */ + +static inline int val_seg(int val) +{ + int r = 0; + val >>= 7; + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_alaw(int pcm_val) +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; + } else { + mask = 0x55; + pcm_val = -pcm_val; + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + } + + if (pcm_val < 256) + aval = pcm_val >> 4; + else { + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + } + return aval ^ mask; +} + +/* + * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM + * + */ +static inline int alaw_to_s16(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + t = a_val & 0x7f; + if (t < 16) + t = (t << 4) + 8; + else { + seg = (t >> 4) & 0x07; + t = ((t & 0x0f) << 4) + 0x108; + t <<= seg -1; + } + return ((a_val & 0x80) ? t : -t); +} +/* + * s16_to_ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + if (pcm_val < 0) { + pcm_val = 0x84 - pcm_val; + mask = 0x7f; + } else { + pcm_val += 0x84; + mask = 0xff; + } + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + return uval ^ mask; +} + +/* + * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +static inline int ulaw_to_s16(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & 0x0f) << 3) + 0x84; + t <<= (u_val & 0x70) >> 4; + + return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); +} diff --git a/linphone/mediastreamer2/src/gsm.c b/linphone/mediastreamer2/src/gsm.c new file mode 100644 index 000000000..575a79bc0 --- /dev/null +++ b/linphone/mediastreamer2/src/gsm.c @@ -0,0 +1,165 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" + +#include + +typedef struct EncState{ + gsm state; + uint32_t ts; + MSBufferizer *bufferizer; +} EncState; + +static void enc_init(MSFilter *f){ + EncState *s=(EncState *)ms_new(EncState,1); + s->state=gsm_create(); + s->ts=0; + s->bufferizer=ms_bufferizer_new(); + f->data=s; +} + +static void enc_uninit(MSFilter *f){ + EncState *s=(EncState*)f->data; + gsm_destroy(s->state); + ms_bufferizer_destroy(s->bufferizer); + ms_free(s); +} + + + +static void enc_process(MSFilter *f){ + EncState *s=(EncState*)f->data; + mblk_t *im; + int16_t buf[160]; + + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + ms_bufferizer_put(s->bufferizer,im); + } + while(ms_bufferizer_read(s->bufferizer,(uint8_t*)buf,sizeof(buf))==sizeof(buf)) { + mblk_t *om=allocb(33,0); + gsm_encode(s->state,(gsm_signal*)buf,(gsm_byte*)om->b_wptr); + om->b_wptr+=33; + mblk_set_timestamp_info(om,s->ts); + ms_queue_put(f->outputs[0],om); + s->ts+=sizeof(buf)/2; + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_gsm_enc_desc={ + MS_GSM_ENC_ID, + "MSGsmEnc", + "The GSM full-rate codec", + MS_FILTER_ENCODER, + "gsm", + 1, + 1, + enc_init, + NULL, + enc_process, + NULL, + enc_uninit, + NULL +}; + +#else + +MSFilterDesc ms_gsm_enc_desc={ + .id=MS_GSM_ENC_ID, + .name="MSGsmEnc", + .text="The GSM full-rate codec", + .category=MS_FILTER_ENCODER, + .enc_fmt="gsm", + .ninputs=1, + .noutputs=1, + .init=enc_init, + .process=enc_process, + .uninit=enc_uninit, +}; + +#endif + +static void dec_init(MSFilter *f){ + f->data=gsm_create(); +} + +static void dec_uninit(MSFilter *f){ + gsm s=(gsm)f->data; + gsm_destroy(s); +} + + +static void dec_process(MSFilter *f){ + gsm s=(gsm)f->data; + mblk_t *im; + mblk_t *om; + const int frsz=160*2; + + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + om=allocb(frsz,0); + if (gsm_decode(s,(gsm_byte*)im->b_rptr,(gsm_signal*)om->b_wptr)<0){ + ms_warning("gsm_decode error!"); + freemsg(om); + }else{ + om->b_wptr+=frsz; + ms_queue_put(f->outputs[0],om); + } + freemsg(im); + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_gsm_dec_desc={ + MS_GSM_DEC_ID, + "MSGsmDec", + "The GSM codec", + MS_FILTER_DECODER, + "gsm", + 1, + 1, + dec_init, + NULL, + dec_process, + NULL, + dec_uninit, + NULL +}; + +#else + +MSFilterDesc ms_gsm_dec_desc={ + .id=MS_GSM_DEC_ID, + .name="MSGsmDec", + .text="The GSM codec", + .category=MS_FILTER_DECODER, + .enc_fmt="gsm", + .ninputs=1, + .noutputs=1, + .init=dec_init, + .process=dec_process, + .uninit=dec_uninit +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_gsm_dec_desc) +MS_FILTER_DESC_EXPORT(ms_gsm_enc_desc) diff --git a/linphone/mediastreamer2/src/ice.c b/linphone/mediastreamer2/src/ice.c new file mode 100644 index 000000000..6259728bc --- /dev/null +++ b/linphone/mediastreamer2/src/ice.c @@ -0,0 +1,556 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#ifdef __APPLE__ +#include +#endif +#include +#include +#endif + +#include "mediastreamer2/ice.h" +#include "mediastreamer2/mscommon.h" + +static void +ice_sendtest( Socket myFd, StunAddress4 *dest, + const StunAtrString *username, const StunAtrString *password, + int testNum, bool_t verbose , UInt128 *tid); + +static void +ice_sendtest( Socket myFd, StunAddress4 *dest, + const StunAtrString *username, const StunAtrString *password, + int testNum, bool_t verbose , UInt128 *tid) +{ + bool_t changePort=FALSE; + bool_t changeIP=FALSE; + bool_t discard=FALSE; + + StunMessage req; + char buf[STUN_MAX_MESSAGE_SIZE]; + int len = STUN_MAX_MESSAGE_SIZE; + + switch (testNum) + { + case 1: + case 10: + case 11: + break; + case 2: + /* changePort=TRUE; */ + changeIP=TRUE; + break; + case 3: + changePort=TRUE; + break; + case 4: + changeIP=TRUE; + break; + case 5: + discard=TRUE; + break; + default: + printf("Test %i is unkown\n", testNum); + return ; /* error */ + } + + memset(&req, 0, sizeof(StunMessage)); + + stunBuildReqSimple( &req, username, + changePort , changeIP , + testNum ); + + len = stunEncodeMessage( &req, buf, len, password,verbose ); + + memcpy(tid , &(req.msgHdr.id), sizeof(req.msgHdr.id)); + + sendMessage( myFd, buf, len, dest->addr, dest->port, verbose ); +} + +int ice_sound_send_stun_request(RtpSession *session, struct CandidatePair *remote_candidates, int round) +{ + int roll=250; +#if 0 + /* in "passive" mode (UA not behind a NATor behind a full cone NAT), + wait a few delay before sending the first STUN request: + this help to traverse */ + if (session->setup_passive>0) + { + return 0; + } +#endif + + if (remote_candidates==NULL) + return 0; + + if (round>500) + roll=2*roll; + + if (round%roll==50 || round==10) + { + int pos; + +#if 0 + /* do this only with application that support this */ + if (osip_strncasecmp(remote_useragent, "linphone/", 8)!=0) + { + /* use stun only with linphone to linphone softphone */ + return 0; + } +#endif + + for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) + { + int media_socket = rtp_session_get_rtp_socket(session); + StunAddress4 stunServerAddr; + StunAtrString username; + StunAtrString password; + bool_t res; + int pad_size; + + struct CandidatePair *cand_pair = &remote_candidates[pos]; + username.sizeValue = 0; + password.sizeValue = 0; + + /* set username to L3:1:R2:1 */ + snprintf(username.value, sizeof(username.value), "%s:%i:%s:%i", + cand_pair->local_candidate.candidate_id, + 1, + cand_pair->remote_candidate.candidate_id, + 1); + username.sizeValue = (UInt16)strlen(username.value); + pad_size = username.sizeValue % 4; + + username.value[username.sizeValue]='\0'; + username.value[username.sizeValue+1]='\0'; + username.value[username.sizeValue+2]='\0'; + username.value[username.sizeValue+3]='\0'; + + username.sizeValue = username.sizeValue + 4 - pad_size; + + snprintf(password.value, sizeof(password.value), "%s", + cand_pair->remote_candidate.password); + password.sizeValue = (UInt16)strlen(password.value); + +#if 0 + pad_size = password.sizeValue%4; + password.value[password.sizeValue]='\0'; + password.value[password.sizeValue+1]='\0'; + password.value[password.sizeValue+2]='\0'; + password.value[password.sizeValue+3]='\0'; + password.sizeValue = password.sizeValue + pad_size; +#endif + + res = stunParseServerName(cand_pair->remote_candidate.ipaddr, + &stunServerAddr); + if ( res == TRUE ) + { + stunServerAddr.port = cand_pair->remote_candidate.port; + ice_sendtest(media_socket, &stunServerAddr, &username, &password, 1, 0/*FALSE*/, + &(cand_pair->tid)); + } + } + } + + return 0; +} + +static int +_ice_get_localip_for (struct sockaddr_storage *saddr, size_t saddr_len, char *loc, int size) +{ + int err, tmp; + int sock; + struct sockaddr_storage addr; + socklen_t addr_len; + + strcpy (loc, "127.0.0.1"); /* always fallback to local loopback */ + + sock = socket (saddr->ss_family, SOCK_DGRAM, 0); + tmp = 1; + err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &tmp, sizeof (int)); + if (err < 0) + { + ms_error("ice.c: Error in setsockopt"); + closesocket (sock); + return -1; + } + err = connect (sock, (struct sockaddr*)saddr, saddr_len); + if (err < 0) + { + ms_error("ice.c: Error in connect"); + closesocket (sock); + return -1; + } + addr_len = sizeof (addr); + err = getsockname (sock, (struct sockaddr *) &addr, (socklen_t*)&addr_len); + if (err != 0) + { + ms_error("ice.c: Error in getsockname"); + closesocket (sock); + return -1; + } + + err = getnameinfo ((struct sockaddr *) &addr, addr_len, loc, size, NULL, 0, NI_NUMERICHOST); + if (err != 0) + { + ms_error("ice.c: Error in getnameinfo"); + closesocket (sock); + return -1; + } + closesocket (sock); + /* ms_message("ice.c: Outgoing interface for sending STUN answer is %s", loc); */ + return 0; +} + +int ice_process_stun_message(RtpSession *session, struct CandidatePair *remote_candidates, OrtpEvent *evt) +{ + int switch_to_address = -1; + StunMessage msg; + bool_t res; + int already_worked_once=-1; + OrtpEventData *evt_data = ortp_event_get_data(evt); + mblk_t *mp = evt_data->packet; + struct sockaddr_in *udp_remote; + char src6host[NI_MAXHOST]; + int recvport = 0; + int i; + + udp_remote = (struct sockaddr_in*)&evt_data->ep->addr; + + memset( &msg, 0 , sizeof(msg) ); + res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg, 0); + if (!res) + { + ms_error("ice.c: Malformed STUN packet."); + return -1; + } + + memset (src6host, 0, sizeof (src6host)); + + { + struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr; + if (aaddr->ss_family==AF_INET) + recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port); + else + recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port); + } + i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen, + src6host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (i != 0) + { + ms_error("ice.c: Error with getnameinfo"); + } else + { + if (msg.msgHdr.msgType == BindRequestMsg) + ms_message("ice.c: Request received from: %s:%i", + src6host, recvport); + else + ms_message("ice.c: Answer received from: %s:%i", + src6host, recvport); + } + + if (remote_candidates!=NULL) { + int pos; + for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) + { + struct CandidatePair *cand_pair = &remote_candidates[pos]; +#ifdef RESTRICTIVE_ICE + if (cand_pair->connectivity_check == VALID + ||cand_pair->connectivity_check == RECV_VALID) + { + already_worked_once=pos; + break; + } +#else + if (cand_pair->connectivity_check == VALID + ||cand_pair->connectivity_check == RECV_VALID + ||cand_pair->connectivity_check == SEND_VALID) + { + already_worked_once=pos; + break; + } +#endif + } + } + + if (msg.msgHdr.msgType == BindRequestMsg) + { + StunMessage resp; + StunAddress4 dest; + StunAtrString hmacPassword; + StunAddress4 from; + StunAddress4 secondary; + StunAddress4 myAddr; + StunAddress4 myAltAddr; + bool_t changePort = FALSE; + bool_t changeIp = FALSE; + struct sockaddr_storage name; + socklen_t namelen; + char localip[128]; + int rtp_socket; + memset(&name, '\0', sizeof(struct sockaddr_storage)); + memset(localip, '\0', sizeof(localip)); + _ice_get_localip_for ((struct sockaddr_storage*)&evt_data->ep->addr, evt_data->ep->addrlen, localip, 128); + + from.addr = ntohl(udp_remote->sin_addr.s_addr); + from.port = ntohs(udp_remote->sin_port); + + secondary.addr = 0; + secondary.port = 0; + + namelen = sizeof(struct sockaddr_storage); + rtp_socket = rtp_session_get_rtp_socket(session); + i = getsockname(rtp_socket, (struct sockaddr*)&name, &namelen); + if (i!=0) + { + ms_error("ice.c: getsockname failed."); + return -1; + } + + myAddr.port = ntohs (((struct sockaddr_in*)&name)->sin_port); + i = stunParseHostName(localip, &myAddr.addr, &myAddr.port, myAddr.port); + if (!i) + { + ms_error("ice.c: stunParseHostName failed."); + return -1; + } + myAddr.port = ntohs (((struct sockaddr_in*)&name)->sin_port); + + /* changed-address set to local address/port */ + myAltAddr = myAddr; + dest.addr = 0; + dest.port = 0; + + res = stunServerProcessMsg((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, + &from, + &secondary, + &myAddr, + &myAltAddr, + &resp, + &dest, + &hmacPassword, + &changePort, + &changeIp, + FALSE ); + + if (!res) + { + ms_error("ice.c: Failed to process STUN request."); + return -1; + } + + if (changePort == TRUE || changeIp == TRUE) + { + ms_error("ice.c: STUN request with changePort or changeIP refused."); + return -1; + } + + res=TRUE; + if ( dest.addr == 0 ) res=FALSE; + if ( dest.port == 0 ) res=FALSE; + if (!res) + { + ms_error("ice.c: Missing destination value for response."); + return -1; + } + + + if (msg.hasUsername!=TRUE || msg.username.sizeValue<=0) + { + /* reply 430 */ + ms_error("ice.c: Missing or bad username value."); + return -1; + } + + /* + USERNAME is considered valid if its topmost portion (the part up to, + but not including the second colon) corresponds to a transport address + ID known to the agent. + */ + if (remote_candidates!=NULL) { + int pos; + for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) + { + char username[256]; + struct CandidatePair *cand_pair = &remote_candidates[pos]; + size_t len = strlen(cand_pair->remote_candidate.candidate_id); + + if (cand_pair->connectivity_check == VALID) + { + break; + } + + memset(username, '\0', sizeof(username)); + snprintf(username, sizeof(username), "%s:%i:%s:%i", + cand_pair->remote_candidate.candidate_id, + 1, + cand_pair->local_candidate.candidate_id, + 1); + + if (len+3remote_candidate.candidate_id, len)==0) + { + char tmp[10]; + int k; + snprintf(tmp, 10, "%s", msg.username.value + len +1); + for (k=0;k<10;k++) + { + if (tmp[k]=='\0') + break; + if (tmp[k]==':') + { + tmp[k]='\0'; + break; + } + } + k = atoi(tmp); + /* TODO support for 2 stream RTP+RTCP */ + if (k>0 && k<10 && k==1) + { + /* candidate-id found! */ +#if 0 + ms_message("ice.c: Find candidate id (index=%i) for incoming STUN request.", pos); +#endif + + if (strncmp(msg.username.value, username, strlen(username))==0) + { +#ifdef RESTRICTIVE_ICE + ms_message("ice.c: Valid STUN request received (to=%s:%i from=%s:%i).", + cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port, + src6host, recvport); + /* We can't be sure the remote end will receive our answer: + connection could be only one way... + */ + if (cand_pair->connectivity_check != VALID) + { + switch_to_address = pos; + } +#else + switch_to_address = pos; +#endif + if (cand_pair->connectivity_check == RECV_VALID + || cand_pair->connectivity_check == VALID) + { + if (cand_pair->connectivity_check != VALID) + { + switch_to_address = pos; + ms_message("ice.c: candidate id (index=%i) moved in VALID state (stunbindingrequest received).", pos); + cand_pair->connectivity_check = VALID; + } + } + else + cand_pair->connectivity_check = SEND_VALID; + + /* we have a VALID one */ + } + } + } + } + } + + /* + The password associated with that transport address ID is used to verify + the MESSAGE-INTEGRITY attribute, if one was present in the request. + */ + + + { + char buf[STUN_MAX_MESSAGE_SIZE]; + int len = sizeof(buf); + len = stunEncodeMessage( &resp, buf, len, &hmacPassword,FALSE ); + if (len) + sendMessage( rtp_socket, buf, len, dest.addr, dest.port, FALSE ); + } + } + else + { + /* set state to RECV-VALID or VALID */ + StunMessage resp; + StunAddress4 mappedAddr; + memset(&resp, 0, sizeof(StunMessage)); + res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, + &resp, FALSE ); + if (!res) + { + ms_error("ice.c: Bad format for STUN answer."); + return -1; + } + + mappedAddr = resp.mappedAddress.ipv4; + + if (remote_candidates!=NULL) { + int pos; + for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) + { + struct CandidatePair *cand_pair = &remote_candidates[pos]; + + if (memcmp(&(cand_pair->tid), &(resp.msgHdr.id), sizeof(resp.msgHdr.id))==0) + { + /* Youhouhouhou */ + if (cand_pair->connectivity_check != VALID) + { + switch_to_address = pos; + } +#if 0 + ms_message("ice.c: Valid STUN answer received (to=%s:%i from=%s:%i)", + cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port, + src6host, recvport); +#endif + if (cand_pair->connectivity_check == SEND_VALID + || cand_pair->connectivity_check == VALID) + { + if (cand_pair->connectivity_check != VALID) + { + ms_message("ice.c: Switch to VALID mode for (to=%s:%i from=%s:%i)", + cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port, + src6host, recvport); + cand_pair->connectivity_check = VALID; + } + } + else + cand_pair->connectivity_check = RECV_VALID; + } + } + } + } + + if (remote_candidates==NULL) { + ms_warning("ice.c: STUN connectivity check is disabled but we received a STUN message (%s:%i)\n", + src6host, recvport); + return 0; + } + if (switch_to_address == -1) + return 0; + + { + /* skip symmetric RTP if any previous connection is working */ + if (switch_to_addressrtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen); + session->rtp.rem_addrlen=evt_data->ep->addrlen; + } + } + return 0; +} + diff --git a/linphone/mediastreamer2/src/macsnd.c b/linphone/mediastreamer2/src/macsnd.c new file mode 100644 index 000000000..da44fc3f9 --- /dev/null +++ b/linphone/mediastreamer2/src/macsnd.c @@ -0,0 +1,702 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* this file is specifically distributed under a BSD license */ + +/** +* Copyright (C) 2007 Hiroki Mori (himori@users.sourceforge.net) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**/ +#include +#include +#include + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" + +MSFilter *ms_ca_read_new(MSSndCard *card); +MSFilter *ms_ca_write_new(MSSndCard *card); + +typedef struct CAData{ + char *pcmdev; + char *mixdev; + AudioUnit caOutAudioUnit; + AudioUnit caInAudioUnit; + AudioStreamBasicDescription caOutASBD; + AudioStreamBasicDescription caInASBD; + AURenderCallbackStruct caOutRenderCallback; + AURenderCallbackStruct caInRenderCallback; + AudioConverterRef caOutConverter; + AudioConverterRef caInConverter; + int pcmfd; + int rate; + int bits; + ms_mutex_t mutex; + queue_t rq; + MSBufferizer * bufferizer; + bool_t read_started; + bool_t write_started; + bool_t stereo; + void *caSourceBuffer; + AudioBufferList *fAudioBuffer, *fMSBuffer; +} CAData; + +// Convenience function to dispose of our audio buffers +void DestroyAudioBufferList(AudioBufferList* list) +{ + UInt32 i; + + if(list) { + for(i = 0; i < list->mNumberBuffers; i++) { + if(list->mBuffers[i].mData) + free(list->mBuffers[i].mData); + } + free(list); + } +} + +// Convenience function to allocate our audio buffers +AudioBufferList *AllocateAudioBufferList(UInt32 numChannels, UInt32 size) +{ + AudioBufferList* list; + UInt32 i; + + list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer)); + if(list == NULL) + return NULL; + + list->mNumberBuffers = numChannels; + for(i = 0; i < numChannels; ++i) { + list->mBuffers[i].mNumberChannels = 1; + list->mBuffers[i].mDataByteSize = size; + list->mBuffers[i].mData = malloc(size); + if(list->mBuffers[i].mData == NULL) { + DestroyAudioBufferList(list); + return NULL; + } + } + return list; +} + +OSStatus writeACInputProc ( + AudioConverterRef inAudioConverter, + UInt32 *ioNumberDataPackets, + AudioBufferList *ioData, + AudioStreamPacketDescription **outDataPacketDescription, + void* inUserData) +{ + OSStatus err = noErr; + CAData *d=(CAData*)inUserData; + UInt32 packetSize = (d->bits / 8) * (d->stereo ? 2 : 1); +// ms_error("writeACInputProc %d", *ioNumberDataPackets); + + if(*ioNumberDataPackets) { + if(d->caSourceBuffer != NULL) { + free(d->caSourceBuffer); + d->caSourceBuffer = NULL; + } + + d->caSourceBuffer = (void *) calloc (1, *ioNumberDataPackets * packetSize); + + ioData->mBuffers[0].mData = d->caSourceBuffer; // tell the Audio Converter where it's source data is + + ms_mutex_lock(&d->mutex); + int readsize = ms_bufferizer_read(d->bufferizer,d->caSourceBuffer,*ioNumberDataPackets * packetSize); + ms_mutex_unlock(&d->mutex); + if(readsize != *ioNumberDataPackets * packetSize) { + /* ms_error("ms_bufferizer_read error request = %d result = %d", *ioNumberDataPackets * packetSize, readsize); */ + memset(d->caSourceBuffer, 0, *ioNumberDataPackets * packetSize); + ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets * packetSize; // tell the Audio Converter how much source data there is + } else { + ioData->mBuffers[0].mDataByteSize = readsize; // tell the Audio Converter how much source data there is + } + } + + return err; +} + +OSStatus readACInputProc (AudioConverterRef inAudioConverter, + UInt32* ioNumberDataPackets, + AudioBufferList* ioData, + AudioStreamPacketDescription** ioASPD, + void* inUserData) +{ + CAData *d=(CAData*)inUserData; + AudioBufferList* l_inputABL = d->fAudioBuffer; + UInt32 totalInputBufferSizeBytes = ((*ioNumberDataPackets) * sizeof (float)); + int counter = d->caInASBD.mChannelsPerFrame; + ioData->mNumberBuffers = d->caInASBD.mChannelsPerFrame; + + while (--counter >= 0) { + AudioBuffer* l_ioD_AB = &(ioData->mBuffers[counter]); + l_ioD_AB->mNumberChannels = 1; + l_ioD_AB->mData = (float*)(l_inputABL->mBuffers[counter].mData); + l_ioD_AB->mDataByteSize = totalInputBufferSizeBytes; + } + + return (noErr); +} + +OSStatus readRenderProc(void *inRefCon, + AudioUnitRenderActionFlags *inActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumFrames, + AudioBufferList *ioData) +{ + CAData *d=(CAData*)inRefCon; + OSStatus err = noErr; + + // Render into audio buffer + err = AudioUnitRender(d->caInAudioUnit, inActionFlags, inTimeStamp, inBusNumber, + inNumFrames, d->fAudioBuffer); + if(err != noErr) + ms_error("AudioUnitRender %d size = %d", err, d->fAudioBuffer->mBuffers[0].mDataByteSize); + + UInt32 AvailableOutputBytes = inNumFrames * sizeof (float); + UInt32 propertySize = sizeof (AvailableOutputBytes); + err = AudioConverterGetProperty (d->caInConverter, + kAudioConverterPropertyCalculateOutputBufferSize, + &propertySize, + &AvailableOutputBytes); + + if(err != noErr) + ms_error("AudioConverterGetProperty %d", err); + + UInt32 ActualOutputFrames = AvailableOutputBytes / sizeof (short); + err = AudioConverterFillComplexBuffer (d->caInConverter, + (AudioConverterComplexInputDataProc)(readACInputProc), + inRefCon, + &ActualOutputFrames, + d->fMSBuffer, + NULL); + if(err != noErr) + ms_error("readRenderProc:AudioConverterFillComplexBuffer %08x mNumberBuffers = %d", err, ioData->mNumberBuffers); + + mblk_t *rm=NULL; + rm=allocb(d->fMSBuffer->mBuffers[0].mDataByteSize,0); + memcpy(rm->b_wptr, d->fMSBuffer->mBuffers[0].mData, d->fMSBuffer->mBuffers[0].mDataByteSize); +// memset(rm->b_wptr, 0, d->fMSBuffer->mBuffers[0].mDataByteSize); + rm->b_wptr+=d->fMSBuffer->mBuffers[0].mDataByteSize; + ms_mutex_lock(&d->mutex); + putq(&d->rq,rm); + ms_mutex_unlock(&d->mutex); + rm=NULL; + + return err; +} + +OSStatus writeRenderProc(void *inRefCon, + AudioUnitRenderActionFlags *inActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumFrames, + AudioBufferList *ioData) +{ + OSStatus err= noErr; + void *inInputDataProcUserData=NULL; + CAData *d=(CAData*)inRefCon; + if(d->write_started != FALSE) { + AudioStreamPacketDescription* outPacketDescription = NULL; + err = AudioConverterFillComplexBuffer(d->caOutConverter, writeACInputProc, inRefCon, + &inNumFrames, ioData, outPacketDescription); + if(err != noErr) + ms_error("writeRenderProc:AudioConverterFillComplexBuffer err %08x %d", err, ioData->mNumberBuffers); + } + return err; +} + +static void ca_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent) +{ + CAData *d=(CAData*)card->data; +} + +static int ca_get_level(MSSndCard *card, MSSndCardMixerElem e) +{ + CAData *d=(CAData*)card->data; + return 0; +} + +static void ca_set_source(MSSndCard *card, MSSndCardCapture source) +{ + CAData *d=(CAData*)card->data; +} + +static void ca_init(MSSndCard *card){ + ms_debug("ca_init"); + OSStatus err; + UInt32 param; + AudioDeviceID fInputDeviceID; + CAData *d=ms_new(CAData,1); + + ComponentDescription desc; + + // Get Default Output audio unit + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + Component comp = FindNextComponent(NULL, &desc); + if (comp == NULL) return; + + err = OpenAComponent(comp, &d->caOutAudioUnit); + if(err != noErr) return; + + // Get Default Input audio unit + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_HALOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = FindNextComponent(NULL, &desc); + if (comp == NULL) return; + + err = OpenAComponent(comp, &d->caInAudioUnit); + if(err != noErr) return; + + AudioUnitInitialize(d->caOutAudioUnit); + AudioUnitInitialize(d->caInAudioUnit); + + UInt32 asbdsize = sizeof(AudioStreamBasicDescription); + memset((char *)&d->caOutASBD, 0, asbdsize); + memset((char *)&d->caInASBD, 0, asbdsize); + + // Setup Output audio unit + OSStatus result = AudioUnitGetProperty (d->caOutAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 0, + &d->caOutASBD, + &asbdsize); + + result = AudioUnitSetProperty (d->caOutAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &d->caOutASBD, + asbdsize); + + // Setup Input audio unit + // Enable input on the AUHAL + param = 1; + result = AudioUnitSetProperty(d->caInAudioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + 1, + ¶m, + sizeof(UInt32)); + +// Select the default input device + param = sizeof(AudioDeviceID); + result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, + ¶m, + &fInputDeviceID); + + // Set the current device to the default input unit. + result = AudioUnitSetProperty(d->caInAudioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &fInputDeviceID, + sizeof(AudioDeviceID)); + + AudioStreamBasicDescription tmpASBD; + result = AudioUnitGetProperty (d->caInAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &tmpASBD, + &asbdsize); + + int fAudioChannels = 1; + d->caInASBD.mChannelsPerFrame = fAudioChannels; + d->caInASBD.mSampleRate = tmpASBD.mSampleRate; + d->caInASBD.mFormatID = kAudioFormatLinearPCM; + d->caInASBD.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | + kAudioFormatFlagIsNonInterleaved; + if (d->caInASBD.mFormatID == kAudioFormatLinearPCM && fAudioChannels == 1) + d->caInASBD.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + d->caInASBD.mFormatFlags = kAudioFormatFlagIsFloat; + if (htonl(0x1234) == 0x1234) + d->caInASBD.mFormatFlags |= kAudioFormatFlagIsBigEndian; + d->caInASBD.mBitsPerChannel = sizeof(Float32) * 8; + d->caInASBD.mBytesPerFrame = d->caInASBD.mBitsPerChannel / 8; + d->caInASBD.mFramesPerPacket = 1; + d->caInASBD.mBytesPerPacket = d->caInASBD.mBytesPerFrame; + + err = AudioUnitSetProperty(d->caInAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &d->caInASBD, + sizeof(AudioStreamBasicDescription)); + + d->caSourceBuffer=NULL; + + // Get the number of frames in the IO buffer(s) + param = sizeof(UInt32); + UInt32 fAudioSamples; + result = AudioUnitGetProperty(d->caInAudioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &fAudioSamples, + ¶m); + if(err != noErr) + { + fprintf(stderr, "failed to get audio sample size\n"); + return; + } + // Allocate our low device audio buffers + d->fAudioBuffer = AllocateAudioBufferList(d->caInASBD.mChannelsPerFrame, + fAudioSamples * d->caInASBD.mBytesPerFrame); + if(d->fAudioBuffer == NULL) + { + fprintf(stderr, "failed to allocate buffers\n"); + return; + } + // Allocate our low device audio buffers + d->fMSBuffer = AllocateAudioBufferList(d->caInASBD.mChannelsPerFrame, + fAudioSamples * d->caInASBD.mBytesPerFrame); + if(d->fMSBuffer == NULL) + { + fprintf(stderr, "failed to allocate buffers\n"); + return; + } + + d->pcmdev=NULL; + d->mixdev=NULL; + d->pcmfd=-1; + d->read_started=FALSE; + d->write_started=FALSE; + d->bits=16; + d->rate=8000; + d->stereo=FALSE; + qinit(&d->rq); + d->bufferizer=ms_bufferizer_new(); + ms_mutex_init(&d->mutex,NULL); + card->data=d; +} + +static void ca_uninit(MSSndCard *card){ + CAData *d=(CAData*)card->data; + if (d->pcmdev!=NULL) ms_free(d->pcmdev); + if (d->mixdev!=NULL) ms_free(d->mixdev); + ms_bufferizer_destroy(d->bufferizer); + flushq(&d->rq,0); + ms_mutex_destroy(&d->mutex); + ms_free(d); +} + +static void ca_detect(MSSndCardManager *m); +static MSSndCard *ca_duplicate(MSSndCard *obj); + +MSSndCardDesc ca_card_desc={ + .driver_type="CA", + .detect=ca_detect, + .init=ca_init, + .set_level=ca_set_level, + .get_level=ca_get_level, + .set_capture=ca_set_source, + .create_reader=ms_ca_read_new, + .create_writer=ms_ca_write_new, + .uninit=ca_uninit, + .duplicate=ca_duplicate +}; + +static MSSndCard *ca_duplicate(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&ca_card_desc); + CAData *dcard=(CAData*)card->data; + CAData *dobj=(CAData*)obj->data; + dcard->pcmdev=ms_strdup(dobj->pcmdev); + dcard->mixdev=ms_strdup(dobj->mixdev); + card->name=ms_strdup(obj->name); + return card; +} + +static MSSndCard *ca_card_new(){ + MSSndCard *card=ms_snd_card_new(&ca_card_desc); + card->name=ms_strdup("Core Audio"); + return card; +} + +static void ca_detect(MSSndCardManager *m){ + ms_debug("ca_detect"); + MSSndCard *card=ca_card_new(); + ms_snd_card_manager_add_card(m,card); +} + +static void ca_start_r(MSSndCard *card){ + OSStatus err= noErr; + CAData *d=(CAData*)card->data; + ms_debug("ca_start_r"); + + if (d->read_started==FALSE){ + AudioStreamBasicDescription outASBD; + outASBD = d->caInASBD; + outASBD.mSampleRate = d->rate; + outASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + if (htonl(0x1234) == 0x1234) + outASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + outASBD.mBytesPerPacket = (d->bits / 8) * outASBD.mChannelsPerFrame; + outASBD.mBytesPerFrame = (d->bits / 8) * outASBD.mChannelsPerFrame; + outASBD.mFramesPerPacket = 1; + outASBD.mBitsPerChannel = d->bits; + + err = AudioConverterNew( &d->caInASBD, &outASBD, &d->caInConverter); + if(err != noErr) + ms_error("AudioConverterNew %x %d", err, outASBD.mBytesPerFrame); + else + CAShow(d->caInConverter); + + d->caInRenderCallback.inputProc = readRenderProc; + d->caInRenderCallback.inputProcRefCon = d; + err = AudioUnitSetProperty(d->caInAudioUnit, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, + 0, + &d->caInRenderCallback, + sizeof(AURenderCallbackStruct)); + + if(AudioOutputUnitStart(d->caInAudioUnit) == noErr) + d->read_started = TRUE; + } +} + +static void ca_stop_r(MSSndCard *card){ + CAData *d=(CAData*)card->data; + OSErr err; + if(d->read_started == TRUE) { + if(AudioOutputUnitStop(d->caInAudioUnit) == noErr) + d->read_started=FALSE; + } +} + +static void ca_start_w(MSSndCard *card){ + OSStatus err= noErr; + ms_debug("ca_start_w"); + CAData *d=(CAData*)card->data; + if (d->write_started==FALSE){ + AudioStreamBasicDescription inASBD; + inASBD = d->caOutASBD; + inASBD.mSampleRate = d->rate; + inASBD.mFormatID = kAudioFormatLinearPCM; + // http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/Reference/reference.html + inASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + if (htonl(0x1234) == 0x1234) + inASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + inASBD.mChannelsPerFrame = d->stereo ? 2 : 1; + inASBD.mBytesPerPacket = (d->bits / 8) * inASBD.mChannelsPerFrame; + inASBD.mBytesPerFrame = (d->bits / 8) * inASBD.mChannelsPerFrame; + inASBD.mFramesPerPacket = 1; + inASBD.mBitsPerChannel = d->bits; + + + err = AudioConverterNew( &inASBD, &d->caOutASBD, &d->caOutConverter); + if(err != noErr) + ms_error("AudioConverterNew %x %d", err, inASBD.mBytesPerFrame); + else + CAShow(d->caOutConverter); + + if (inASBD.mChannelsPerFrame == 1 && d->caOutASBD.mChannelsPerFrame == 2) + { + if (d->caOutConverter) + { + // This should be as large as the number of output channels, + // each element specifies which input channel's data is routed to that output channel + SInt32 channelMap[] = { 0, 0 }; + err = AudioConverterSetProperty(d->caOutConverter, kAudioConverterChannelMap, 2*sizeof(SInt32), channelMap); + } + } + + memset((char*)&d->caOutRenderCallback, 0, sizeof(AURenderCallbackStruct)); + d->caOutRenderCallback.inputProc = writeRenderProc; + d->caOutRenderCallback.inputProcRefCon = d; + err = AudioUnitSetProperty (d->caOutAudioUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &d->caOutRenderCallback, + sizeof(AURenderCallbackStruct)); + if(err != noErr) + ms_error("AudioUnitSetProperty %x", err); + + if(err == noErr) { + if(AudioOutputUnitStart(d->caOutAudioUnit) == noErr) + d->write_started=TRUE; + } + } +} + +static void ca_stop_w(MSSndCard *card){ + CAData *d=(CAData*)card->data; + OSErr err; + if(d->write_started == TRUE) { + if(AudioOutputUnitStop(d->caOutAudioUnit) == noErr) + d->write_started=FALSE; + } +} + +static mblk_t *ca_get(MSSndCard *card){ + CAData *d=(CAData*)card->data; + mblk_t *m; + ms_mutex_lock(&d->mutex); + m=getq(&d->rq); + ms_mutex_unlock(&d->mutex); + return m; +} + +static void ca_put(MSSndCard *card, mblk_t *m){ + CAData *d=(CAData*)card->data; + ms_mutex_lock(&d->mutex); + ms_bufferizer_put(d->bufferizer,m); + ms_mutex_unlock(&d->mutex); +} + + +static void ca_read_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + ca_start_r(card); +} + +static void ca_read_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + ca_stop_r(card); +} + +static void ca_read_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=ca_get(card))!=NULL){ + ms_queue_put(f->outputs[0],m); + } +} + +static void ca_write_preprocess(MSFilter *f){ + ms_debug("ca_write_preprocess"); + MSSndCard *card=(MSSndCard*)f->data; + ca_start_w(card); +} + +static void ca_write_postprocess(MSFilter *f){ + ms_debug("ca_write_postprocess"); + MSSndCard *card=(MSSndCard*)f->data; + ca_stop_w(card); +} + +static void ca_write_process(MSFilter *f){ +// ms_debug("ca_write_process"); + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + ca_put(card,m); + } +} + +static int set_rate(MSFilter *f, void *arg){ + ms_debug("set_rate %d", *((int*)arg)); + MSSndCard *card=(MSSndCard*)f->data; + CAData *d=(CAData*)card->data; + d->rate=*((int*)arg); + return 0; +} + +static int set_nchannels(MSFilter *f, void *arg){ + ms_debug("set_nchannels %d", *((int*)arg)); + MSSndCard *card=(MSSndCard*)f->data; + CAData *d=(CAData*)card->data; + d->stereo=(*((int*)arg)==2); + return 0; +} + +static MSFilterMethod ca_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , set_rate }, + { MS_FILTER_SET_NCHANNELS , set_nchannels }, + { 0 , NULL } +}; + +MSFilterDesc ca_read_desc={ + .id=MS_CA_READ_ID, + .name="MSCARead", + .text="Sound capture filter for MacOS X Core Audio drivers", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .preprocess=ca_read_preprocess, + .process=ca_read_process, + .postprocess=ca_read_postprocess, + .methods=ca_methods +}; + + +MSFilterDesc ca_write_desc={ + .id=MS_CA_WRITE_ID, + .name="MSCAWrite", + .text="Sound playback filter for MacOS X Core Audio drivers", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=0, + .preprocess=ca_write_preprocess, + .process=ca_write_process, + .postprocess=ca_write_postprocess, + .methods=ca_methods +}; + +MSFilter *ms_ca_read_new(MSSndCard *card){ + ms_debug("ms_ca_read_new"); + MSFilter *f=ms_filter_new_from_desc(&ca_read_desc); + f->data=card; + return f; +} + + +MSFilter *ms_ca_write_new(MSSndCard *card){ + ms_debug("ms_ca_write_new"); + MSFilter *f=ms_filter_new_from_desc(&ca_write_desc); + f->data=card; + return f; +} + +MS_FILTER_DESC_EXPORT(ca_read_desc) +MS_FILTER_DESC_EXPORT(ca_write_desc) diff --git a/linphone/mediastreamer2/src/mire.c b/linphone/mediastreamer2/src/mire.c new file mode 100644 index 000000000..eda05eb28 --- /dev/null +++ b/linphone/mediastreamer2/src/mire.c @@ -0,0 +1,164 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/mswebcam.h" + + +typedef struct _MireData{ + MSVideoSize vsize; + MSPicture pict; + int index; + uint64_t starttime; + float fps; + mblk_t *pic; +}MireData; + +void mire_init(MSFilter *f){ + MireData *d=(MireData*)ms_new(MireData,1); + d->vsize.width=MS_VIDEO_SIZE_CIF_W; + d->vsize.height=MS_VIDEO_SIZE_CIF_H; + d->fps=15; + d->index=0; + d->starttime=0; + d->pic=NULL; + f->data=d; +} + +void mire_uninit(MSFilter *f){ + ms_free(f->data); +} + +void mire_preprocess(MSFilter *f){ + MireData *d=(MireData*)f->data; + d->pic=yuv_buf_alloc(&d->pict,d->vsize.width,d->vsize.height); + memset(d->pic->b_rptr,0,d->pic->b_wptr-d->pic->b_rptr); + d->starttime=f->ticker->time; +} + +void plane_draw(uint8_t *p, int w, int h, int lsz, int index){ + int i,j; + for(i=0;ipict.planes[0],d->pict.w,d->pict.h,d->pict.strides[0],d->index*2); + plane_draw(d->pict.planes[1],d->pict.w/2,d->pict.h/2,d->pict.strides[1],d->index); + plane_draw(d->pict.planes[2],d->pict.w/2,d->pict.h/2,d->pict.strides[2],d->index); +} + +void mire_process(MSFilter *f){ + MireData *d=(MireData*)f->data; + float elapsed=f->ticker->time-d->starttime; + if ((elapsed*d->fps/1000.0)>d->index){ + mire_draw(d); + ms_queue_put(f->outputs[0],dupb(d->pic)); + d->index++; + } +} + +void mire_postprocess(MSFilter *f){ + MireData *d=(MireData*)f->data; + if (d->pic) { + freemsg(d->pic); + d->pic=NULL; + } +} + +int mire_set_vsize(MSFilter *f, void* data){ + MireData *d=(MireData*)f->data; + d->vsize=*(MSVideoSize*)data; + return 0; +} + +int mire_set_fps(MSFilter *f, void* data){ + MireData *d=(MireData*)f->data; + d->fps=*(float*)data; + return 0; +} + +int mire_get_fmt(MSFilter *f, void* data){ + *(MSPixFmt*)data=MS_YUV420P; + return 0; +} + +MSFilterMethod mire_methods[]={ + { MS_FILTER_SET_VIDEO_SIZE, mire_set_vsize }, + { MS_FILTER_SET_FPS , mire_set_fps }, + { MS_FILTER_GET_PIX_FMT , mire_get_fmt }, + { 0,0 } +}; + +MSFilterDesc ms_mire_desc={ + MS_MIRE_ID, + "MSMire", + "A filter that outputs synthetic moving picture", + MS_FILTER_OTHER, + NULL, + 0, + 1, + mire_init, + mire_preprocess, + mire_process, + mire_postprocess, + mire_uninit, + mire_methods +}; + +MS_FILTER_DESC_EXPORT(ms_mire_desc) + +static void mire_detect(MSWebCamManager *obj); + +static void mire_cam_init(MSWebCam *cam){ + cam->name=ms_strdup("Mire (synthetic moving picture)"); +} + + +static MSFilter *mire_create_reader(MSWebCam *obj){ + return ms_filter_new_from_desc(&ms_mire_desc); +} + +MSWebCamDesc mire_desc={ + "Mire", + &mire_detect, + &mire_cam_init, + &mire_create_reader, + NULL +}; + +static void mire_detect(MSWebCamManager *obj){ + char *debug=getenv("DEBUG"); + if (debug && atoi(debug)==1){ + MSWebCam *cam=ms_web_cam_new(&mire_desc); + ms_web_cam_manager_add_cam(obj,cam); + } +} + diff --git a/linphone/mediastreamer2/src/mscommon.c b/linphone/mediastreamer2/src/mscommon.c new file mode 100644 index 000000000..46d21055e --- /dev/null +++ b/linphone/mediastreamer2/src/mscommon.c @@ -0,0 +1,593 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msfilter.h" + +#include "alldescs.h" +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/mswebcam.h" + +#if !defined(_WIN32_WCE) +#include +#endif +#ifndef WIN32 +#include +#else +#ifndef PACKAGE_PLUGINS_DIR +#if defined(WIN32) || defined(_WIN32_WCE) +#define PACKAGE_PLUGINS_DIR "plugins\\" +#else +#define PACKAGE_PLUGINS_DIR "." +#endif +#endif +#endif +#ifdef HAVE_DLOPEN +#include +#endif + +#ifdef __APPLE__ +#import +#include +#endif + +MSList *ms_list_new(void *data){ + MSList *new_elem=(MSList *)ms_new(MSList,1); + new_elem->prev=new_elem->next=NULL; + new_elem->data=data; + return new_elem; +} + +MSList * ms_list_append(MSList *elem, void * data){ + MSList *new_elem=ms_list_new(data); + MSList *it=elem; + if (elem==NULL) return new_elem; + while (it->next!=NULL) it=ms_list_next(it); + it->next=new_elem; + new_elem->prev=it; + return elem; +} + +MSList * ms_list_prepend(MSList *elem, void *data){ + MSList *new_elem=ms_list_new(data); + if (elem!=NULL) { + new_elem->next=elem; + elem->prev=new_elem; + } + return new_elem; +} + + +MSList * ms_list_concat(MSList *first, MSList *second){ + MSList *it=first; + if (it==NULL) return second; + while(it->next!=NULL) it=ms_list_next(it); + it->next=second; + second->prev=it; + return first; +} + +MSList * ms_list_free(MSList *list){ + MSList *elem = list; + MSList *tmp; + if (list==NULL) return NULL; + while(elem->next!=NULL) { + tmp = elem; + elem = elem->next; + ms_free(tmp); + } + ms_free(elem); + return NULL; +} + +MSList * ms_list_remove(MSList *first, void *data){ + MSList *it; + it=ms_list_find(first,data); + if (it) return ms_list_remove_link(first,it); + else { + ms_warning("ms_list_remove: no element with %p data was in the list", data); + return first; + } +} + +int ms_list_size(const MSList *first){ + int n=0; + while(first!=NULL){ + ++n; + first=first->next; + } + return n; +} + +void ms_list_for_each(const MSList *list, void (*func)(void *)){ + for(;list!=NULL;list=list->next){ + func(list->data); + } +} + +void ms_list_for_each2(const MSList *list, void (*func)(void *, void *), void *user_data){ + for(;list!=NULL;list=list->next){ + func(list->data,user_data); + } +} + +MSList *ms_list_remove_link(MSList *list, MSList *elem){ + MSList *ret; + if (elem==list){ + ret=elem->next; + elem->prev=NULL; + elem->next=NULL; + if (ret!=NULL) ret->prev=NULL; + ms_free(elem); + return ret; + } + elem->prev->next=elem->next; + if (elem->next!=NULL) elem->next->prev=elem->prev; + elem->next=NULL; + elem->prev=NULL; + ms_free(elem); + return list; +} + +MSList *ms_list_find(MSList *list, void *data){ + for(;list!=NULL;list=list->next){ + if (list->data==data) return list; + } + return NULL; +} + +MSList *ms_list_find_custom(MSList *list, int (*compare_func)(const void *, const void*), void *user_data){ + for(;list!=NULL;list=list->next){ + if (compare_func(list->data,user_data)==0) return list; + } + return NULL; +} + +void * ms_list_nth_data(const MSList *list, int index){ + int i; + for(i=0;list!=NULL;list=list->next,++i){ + if (i==index) return list->data; + } + ms_error("ms_list_nth_data: no such index in list."); + return NULL; +} + +int ms_list_position(const MSList *list, MSList *elem){ + int i; + for(i=0;list!=NULL;list=list->next,++i){ + if (elem==list) return i; + } + ms_error("ms_list_position: no such element in list."); + return -1; +} + +int ms_list_index(const MSList *list, void *data){ + int i; + for(i=0;list!=NULL;list=list->next,++i){ + if (data==list->data) return i; + } + ms_error("ms_list_index: no such element in list."); + return -1; +} + +MSList *ms_list_insert_sorted(MSList *list, void *data, int (*compare_func)(const void *, const void*)){ + MSList *it,*previt=NULL; + MSList *nelem; + MSList *ret=list; + if (list==NULL) return ms_list_append(list,data); + else{ + nelem=ms_list_new(data); + for(it=list;it!=NULL;it=it->next){ + previt=it; + if (compare_func(data,it->data)<=0){ + nelem->prev=it->prev; + nelem->next=it; + if (it->prev!=NULL) + it->prev->next=nelem; + else{ + ret=nelem; + } + it->prev=nelem; + return ret; + } + } + previt->next=nelem; + nelem->prev=previt; + } + return ret; +} + +MSList *ms_list_insert(MSList *list, MSList *before, void *data){ + MSList *elem; + if (list==NULL || before==NULL) return ms_list_append(list,data); + for(elem=list;elem!=NULL;elem=ms_list_next(elem)){ + if (elem==before){ + if (elem->prev==NULL) + return ms_list_prepend(list,data); + else{ + MSList *nelem=ms_list_new(data); + nelem->prev=elem->prev; + nelem->next=elem; + elem->prev->next=nelem; + elem->prev=nelem; + } + } + } + return list; +} + +MSList *ms_list_copy(const MSList *list){ + MSList *copy=NULL; + const MSList *iter; + for(iter=list;iter!=NULL;iter=ms_list_next(iter)){ + copy=ms_list_append(copy,iter->data); + } + return copy; +} + + +#ifdef __APPLE__ +#define PLUGINS_EXT ".dylib" +#else +#define PLUGINS_EXT ".so" +#endif + +typedef void (*init_func_t)(void); + +int ms_load_plugins(const char *dir){ + int num=0; +#if defined(WIN32) && !defined(_WIN32_WCE) + WIN32_FIND_DATA FileData; + HANDLE hSearch; + char szDirPath[1024]; + char szPluginFile[1024]; + BOOL fFinished = FALSE; + + snprintf(szDirPath, sizeof(szDirPath), "%s", dir); + // Create a new directory. +#if 0 + if (!CreateDirectory(szDirPath, NULL)) + { + ms_message("plugins directory already exist (%s).", szDirPath); + } +#endif + + // Start searching for .TXT files in the current directory. + + snprintf(szDirPath, sizeof(szDirPath), "%s\\*.dll", dir); + hSearch = FindFirstFile(szDirPath, &FileData); + if (hSearch == INVALID_HANDLE_VALUE) + { + ms_message("no plugin (*.dll) found in %s.", szDirPath); + return 0; + } + snprintf(szDirPath, sizeof(szDirPath), "%s", dir); + + while (!fFinished) + { + /* load library */ + HINSTANCE os_handle; + UINT em; + em = SetErrorMode (SEM_FAILCRITICALERRORS); + + snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, FileData.cFileName); + os_handle = LoadLibraryEx (szPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (os_handle==NULL) + { + os_handle = LoadLibraryEx (szPluginFile, NULL, 0); + } + SetErrorMode (em); + if (os_handle==NULL) + ms_warning("Fail to load plugin %s :", szPluginFile); + else + { + init_func_t initroutine; + char szPluginName[256]; + char szMethodName[256]; + snprintf(szPluginName, 256, "%s", FileData.cFileName); + szPluginName[strlen(szPluginName)-4]='\0'; + snprintf(szMethodName, 256, "%s_init", szPluginName); + initroutine = (init_func_t) GetProcAddress (os_handle, szMethodName); + if (initroutine!=NULL){ + initroutine(); + ms_message("Plugin loaded."); + num++; + }else{ + ms_warning("Could not locate init routine of plugin %s", szPluginFile); + } + } + + + if (!FindNextFile(hSearch, &FileData)) + { + if (GetLastError() == ERROR_NO_MORE_FILES) + { + fFinished = TRUE; + } + else + { + ms_error("couldn't find next plugin dll."); + fFinished = TRUE; + } + } + } + + // Close the search handle. + + FindClose(hSearch); + +#elif HAVE_DLOPEN + DIR *ds; + struct dirent *de; + char *fullpath; + ds=opendir(dir); + if (ds==NULL){ + ms_message("Cannot open directory %s: %s",dir,strerror(errno)); + return -1; + } + while( (de=readdir(ds))!=NULL){ + if (de->d_type==DT_REG && strstr(de->d_name,PLUGINS_EXT)!=NULL){ + void *handle; + fullpath=ms_strdup_printf("%s/%s",dir,de->d_name); + ms_message("Loading plugin %s...",fullpath); + + if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){ + ms_warning("Fail to load plugin %s : %s",fullpath,dlerror()); + }else { + char *initroutine_name=ms_malloc0(strlen(de->d_name)+10); + char *p; + void *initroutine=NULL; + strcpy(initroutine_name,de->d_name); + p=strstr(initroutine_name,PLUGINS_EXT); + if (p!=NULL) + { + strcpy(p,"_init"); + initroutine=dlsym(handle,initroutine_name); + } + +#ifdef __APPLE__ + if (initroutine==NULL){ + /* on macosx: library name are libxxxx.1.2.3.dylib */ + /* -> MUST remove the .1.2.3 */ + p=strstr(initroutine_name,"."); + if (p!=NULL) + { + strcpy(p,"_init"); + initroutine=dlsym(handle,initroutine_name); + } + } +#endif + + if (initroutine!=NULL){ + init_func_t func=(init_func_t)initroutine; + func(); + ms_message("Plugin loaded."); + num++; + }else{ + ms_warning("Could not locate init routine of plugin %s",de->d_name); + } + ms_free(initroutine_name); + } + ms_free(fullpath); + } + } + closedir(ds); +#else + ms_warning("no loadable plugin support: plugins cannot be loaded."); + num=-1; +#endif + return num; +} + + +#ifdef __ALSA_ENABLED__ +extern MSSndCardDesc alsa_card_desc; +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +extern MSSndCardDesc oss_card_desc; +#endif + +#ifdef __ARTS_ENABLED__ +extern MSSndCardDesc arts_card_desc; +#endif + +#ifdef WIN32 +extern MSSndCardDesc winsnd_card_desc; +#endif + +#ifdef __DIRECTSOUND_ENABLED__ +extern MSSndCardDesc winsndds_card_desc; +#endif + +#ifdef __MACSND_ENABLED__ +extern MSSndCardDesc ca_card_desc; +#endif + +#ifdef __PORTAUDIO_ENABLED__ +extern MSSndCardDesc pasnd_card_desc; +#endif + +#ifdef __MAC_AQ_ENABLED__ +extern MSSndCardDesc aq_card_desc; +#endif + +static MSSndCardDesc * ms_snd_card_descs[]={ +#ifdef __ALSA_ENABLED__ + &alsa_card_desc, +#endif +#ifdef HAVE_SYS_SOUNDCARD_H + &oss_card_desc, +#endif +#ifdef __ARTS_ENABLED__ + &arts_card_desc, +#endif +#ifdef WIN32 + &winsnd_card_desc, +#endif +#ifdef __DIRECTSOUND_ENABLED__ + &winsndds_card_desc, +#endif +#ifdef __PORTAUDIO_ENABLED__ + &pasnd_card_desc, +#endif +#ifdef __MACSND_ENABLED__ + &ca_card_desc, +#endif +#ifdef __MAC_AQ_ENABLED__ + &aq_card_desc, +#endif + NULL +}; + +#ifdef VIDEO_ENABLED + +#ifdef __linux +extern MSWebCamDesc v4l_desc; +#endif + +#ifdef HAVE_LINUX_VIDEODEV2_H +extern MSWebCamDesc v4l2_desc; +#endif + +#ifdef WIN32 +extern MSWebCamDesc ms_v4w_cam_desc; +#endif + +extern MSWebCamDesc static_image_desc; +extern MSWebCamDesc mire_desc; + +static MSWebCamDesc * ms_web_cam_descs[]={ +#ifdef HAVE_LINUX_VIDEODEV2_H + &v4l2_desc, +#endif +#ifdef __linux + &v4l_desc, +#endif +#ifdef WIN32 + &ms_v4w_cam_desc, +#endif + &mire_desc, + &static_image_desc, + NULL +}; + +#endif + +void ms_init(){ + int i; + MSSndCardManager *cm; +#ifdef __APPLE__ + NSApplicationLoad(); +#endif + +#if !defined(_WIN32_WCE) + if (getenv("MEDIASTREAMER_DEBUG")!=NULL){ + ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + } +#endif + ms_message("Registering all filters..."); + /* register builtin MSFilter's */ + for (i=0;ms_filter_descs[i]!=NULL;i++){ + ms_filter_register(ms_filter_descs[i]); + } + ms_message("Registering all soundcard handlers"); + cm=ms_snd_card_manager_get(); + for (i=0;ms_snd_card_descs[i]!=NULL;i++){ + ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]); + } + +#ifdef VIDEO_ENABLED + ms_message("Registering all webcam handlers"); + { + MSWebCamManager *wm; + wm=ms_web_cam_manager_get(); + for (i=0;ms_web_cam_descs[i]!=NULL;i++){ + ms_web_cam_manager_register_desc(wm,ms_web_cam_descs[i]); + } + } +#endif + ms_message("Loading plugins"); + ms_load_plugins(PACKAGE_PLUGINS_DIR); + ms_message("ms_init() done"); +} + +void ms_exit(){ + ms_filter_unregister_all(); + ms_snd_card_manager_destroy(); +#ifdef VIDEO_ENABLED + ms_web_cam_manager_destroy(); +#endif +} + +void ms_reload_snd_card(MSSndCardDesc *snd_desc){ + MSSndCardManager *cm; + int i; + + ms_snd_card_manager_destroy(); + + ms_message("Registering all soundcard handlers"); + if (snd_desc!=NULL) + { + cm=ms_snd_card_manager_get(); + if (cm!=NULL) + ms_snd_card_manager_register_desc(cm,snd_desc); + return; + } + + /*register SndCardDesc */ + cm=ms_snd_card_manager_get(); + for (i=0;ms_snd_card_descs[i]!=NULL;i++){ + ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]); + } + + return; +} + +void ms_sleep(int seconds){ +#ifdef WIN32 + Sleep(seconds*1000); +#else + struct timespec ts,rem; + int err; + ts.tv_sec=seconds; + ts.tv_nsec=0; + do { + err=nanosleep(&ts,&rem); + ts=rem; + }while(err==-1 && errno==EINTR); +#endif +} + +#define DEFAULT_MAX_PAYLOAD_SIZE 1440 + +static int max_payload_size=DEFAULT_MAX_PAYLOAD_SIZE; + +int ms_get_payload_max_size(){ + return max_payload_size; +} + +void ms_set_payload_max_size(int size){ + if (size<=0) size=DEFAULT_MAX_PAYLOAD_SIZE; + max_payload_size=size; +} diff --git a/linphone/mediastreamer2/src/msconf.c b/linphone/mediastreamer2/src/msconf.c new file mode 100644 index 000000000..80113ae78 --- /dev/null +++ b/linphone/mediastreamer2/src/msconf.c @@ -0,0 +1,590 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" + +#if defined(_WIN32_WCE) +#define DISABLE_SPEEX +#endif + +#ifndef DISABLE_SPEEX +#include +#endif + +#ifndef CONF_GRAN_MAX +#define CONF_GRAN_MAX 12 /* limit for 'too much data' */ +#endif + +//#ifndef CONF_GRAN +//#define CONF_GRAN (160*4) +//#endif +#define CONF_NSAMPLES 160*4*4 /* (CONF_GRAN/2) */ +#ifndef CONF_MAX_PINS +#define CONF_MAX_PINS 32 +#endif + +typedef struct Channel{ + MSBufferizer buff; + int16_t input[CONF_NSAMPLES]; + bool_t has_contributed; + bool_t is_used; + int count; + int missed; + + int stat_discarded; + int stat_missed; + int stat_processed; + +#ifndef DISABLE_SPEEX + SpeexPreprocessState *speex_pp; +#endif + +} Channel; + +typedef struct ConfState{ + Channel channels[CONF_MAX_PINS]; + int sum[CONF_NSAMPLES]; + int enable_directmode; + int enable_vad; + int agc_level; + int mix_mode; + int samplerate; + + int adaptative_msconf_buf; + int conf_gran; + int conf_nsamples; +} ConfState; + + +static void channel_init(ConfState *s, Channel *chan, int pos){ + ms_bufferizer_init(&chan->buff); +#ifndef DISABLE_SPEEX + //chan->speex_pp = speex_preprocess_state_init((s->conf_gran/2) *(s->samplerate/8000), s->samplerate); + chan->speex_pp = speex_preprocess_state_init(s->conf_gran/2, s->samplerate); + if (chan->speex_pp!=NULL) { + float f; + int val; + val=1; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DENOISE, &val); + /* enable VAD only on incoming RTP stream */ + if (pos%2==1) + { + val=1; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_VAD, &val); + } + /* enable AGC only on local soundcard */ + if (s->agc_level>0 && pos==0) + { + val=1; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC, &val); + f=s->agc_level; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); +#if 0 + val=40; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &val); +#endif + } + else + { + val=0; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC, &val); + f=8000; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); + } + val=0; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB, &val); + f=.4; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); + f=.3; + speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); + } +#endif +} + +static void channel_uninit(Channel *chan){ + ms_bufferizer_uninit(&chan->buff); +#ifndef DISABLE_SPEEX + if (chan->speex_pp!=NULL) + speex_preprocess_state_destroy(chan->speex_pp); + chan->speex_pp=NULL; +#endif +} + +static void conf_init(MSFilter *f){ + ConfState *s=(ConfState *)ms_new0(ConfState,1); + int i; + s->samplerate=8000; + s->conf_gran=((16 * s->samplerate) / 800) *2; + s->conf_nsamples=s->conf_gran/2; + for (i=0;ichannels[i], i); + s->enable_directmode=FALSE; + s->enable_vad=TRUE; + s->agc_level=0; + s->mix_mode=TRUE; + s->adaptative_msconf_buf=2; + f->data=s; +} + +static void conf_uninit(MSFilter *f){ + ConfState *s=(ConfState*)f->data; + int i; + for (i=0;ichannels[i]); + ms_free(f->data); +} + +static void conf_preprocess(MSFilter *f){ + ConfState *s=(ConfState*)f->data; + int i; + for (i=0;ichannels[i].is_used=FALSE; + s->channels[i].missed=0; + s->channels[i].stat_discarded=0; + s->channels[i].stat_missed=0; + s->channels[i].stat_processed=0; + } +} + +static bool_t should_process(MSFilter *f, ConfState *s){ + Channel *chan; + int active_channel=0; + int i; + + if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>s->conf_gran + && s->channels[0].is_used==FALSE) + { + /* soundread has just started */ + s->channels[0].is_used=TRUE; + } + else if (s->channels[0].is_used==FALSE) + { + return FALSE; + } + + /* count active channel */ + for (i=1;ichannels[i]; + if (chan->is_used == TRUE) + { + active_channel++; + } + } + + if (active_channel<=1) /* disable mix mode when it's not needed */ + s->mix_mode = FALSE; + else + s->mix_mode = TRUE; + + if (s->enable_directmode==FALSE) + { + s->mix_mode = TRUE; + } + + if (s->mix_mode == FALSE) + return FALSE; + + if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>=s->conf_gran) + { + return TRUE; + } + return FALSE; +} + +static void conf_sum(ConfState *s){ + int i,j; + Channel *chan; + memset(s->sum,0,s->conf_nsamples*sizeof(int)); + + chan=&s->channels[0]; + if (s->adaptative_msconf_buf*s->conf_granbuff)) + { + i = ms_bufferizer_get_avail(&chan->buff)/s->conf_gran; + if (i>5) + ms_message("Increasing buffer because sound card is late. (nb_buf=%i /old=%i)", i, s->adaptative_msconf_buf); + s->adaptative_msconf_buf=i; + if (s->adaptative_msconf_buf>10) + { + while (ms_bufferizer_get_avail(&chan->buff)> s->conf_gran*6) + { + ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran); + ms_message("Deleting extra sound card data %i", ms_bufferizer_get_avail(&chan->buff)); + } + } + } + else if (s->adaptative_msconf_buf*s->conf_gran>ms_bufferizer_get_avail(&chan->buff)) + { + if (s->adaptative_msconf_buf>3) + { + s->adaptative_msconf_buf--; + s->adaptative_msconf_buf=ms_bufferizer_get_avail(&chan->buff)/s->conf_gran; + //ms_message("decreasing buffer because sound card is in advance. (nb_buf=%i)", s->adaptative_msconf_buf); + } + } + + if (s->adaptative_msconf_buf>6) + s->adaptative_msconf_buf=6; + + for (i=0;ichannels[i]; + + /* skip soundread and short buffer entry */ +#if 0 + if (i>0 + && ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran*s->adaptative_msconf_buf) + { + while (ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran*2) +#endif + if (i>0 + && ms_bufferizer_get_avail(&chan->buff)> s->conf_gran + && ms_bufferizer_get_avail(&chan->buff)> (ms_bufferizer_get_avail(&s->channels[0].buff)+s->conf_gran*6) ) + { + while (ms_bufferizer_get_avail(&chan->buff)> (ms_bufferizer_get_avail(&s->channels[0].buff)) ) + { + ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran); + /* we want to remove 4 packets (40ms) in a near future: */ +#ifndef DISABLE_SPEEX + if (chan->speex_pp!=NULL && s->enable_vad==TRUE) + { + int vad; + vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL); + if (vad==1) + break; /* voice detected: process as usual */ + if (ms_bufferizer_get_avail(&chan->buff)conf_gran) + break; /* no more data to remove */ + ms_message("No voice detected: discarding sample. (idx=%i - bufsize=%i sncardbufsize=%i)", + i, ms_bufferizer_get_avail(&chan->buff), ms_bufferizer_get_avail(&s->channels[0].buff)); + } + if (ms_bufferizer_get_avail(&chan->buff) == (ms_bufferizer_get_avail(&s->channels[0].buff))) + ms_message("same data in soundcard and incoming rtp. (idx=%i - bufsize=%i sncardbufsize=%i)", + i, ms_bufferizer_get_avail(&chan->buff), ms_bufferizer_get_avail(&s->channels[0].buff)); +#endif + chan->stat_discarded++; + } + + for(j=0;jconf_nsamples;++j){ + s->sum[j]+=chan->input[j]; + } + chan->has_contributed=TRUE; + chan->stat_processed++; + } + else if (ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran) + { + ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran); +#ifndef DISABLE_SPEEX + if (chan->speex_pp!=NULL && s->enable_vad==TRUE) + { + int vad; + vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL); + } +#endif + + for(j=0;jconf_nsamples;++j){ + s->sum[j]+=chan->input[j]; + } + chan->has_contributed=TRUE; + chan->stat_processed++; + } else { + chan->stat_missed++; + if (i>0 && chan->is_used == TRUE) + { + chan->missed++; + /* delete stream if data is missing since a long time */ + if (chan->missed>15) + { + chan->is_used=FALSE; + ms_message("msconf: deleted contributing stream (pin=%i)", i); + } + /* couldn't we add confort noise for those outputs? */ + } + chan->has_contributed=FALSE; + } + } + return; +} + +static inline int16_t saturate(int sample){ + if (sample>32000) + sample=32000; + else if (sample<-32000) + sample=-32000; + return (int16_t)sample; +} + +static mblk_t * conf_output(ConfState *s, Channel *chan){ + mblk_t *m=allocb(s->conf_gran,0); + int i; + int tmp; + if (chan->has_contributed==TRUE){ + for (i=0;iconf_nsamples;++i){ + tmp=s->sum[i]-(int)chan->input[i]; + *((int16_t*)m->b_wptr)=saturate(tmp); + m->b_wptr+=2; + } + }else{ + for (i=0;iconf_nsamples;++i){ + tmp=s->sum[i]; + *((int16_t*)m->b_wptr)=saturate(tmp); + m->b_wptr+=2; + } + } + return m; +} + +static void conf_dispatch(MSFilter *f, ConfState *s){ + int i; + Channel *chan; + mblk_t *m; + //memset(s->sum,0,s->conf_nsamples*sizeof(int)); + for (i=0;ioutputs[i]!=NULL){ + chan=&s->channels[i]; + m=conf_output(s,chan); + ms_queue_put(f->outputs[i],m); + } + } +} + +static void conf_process(MSFilter *f){ + int i; + ConfState *s=(ConfState*)f->data; + Channel *chan; + Channel *chan0; + /*read from all inputs and put into bufferizers*/ + for (i=0;iinputs[i]!=NULL){ + chan=&s->channels[i]; + ms_bufferizer_put_from_queue(&chan->buff,f->inputs[i]); + if (ms_bufferizer_get_avail(&chan->buff)>0) + { + chan->missed=0; /* reset counter of missed packet */ + if (i>0 && chan->is_used==FALSE) + { + chan->is_used=TRUE; + ms_message("msconf: new contributing stream", ms_bufferizer_get_avail(&chan->buff)); + } + } + } + } + + /*do the job */ + while(should_process(f,s)==TRUE){ + conf_sum(s); + conf_dispatch(f,s); + } + + /* mixer is disabled! -> copy A->B and B->A*/ + if (s->mix_mode == FALSE) + { + /* get the soundread data and copy it to pinX */ + for (i=1;iinputs[i]!=NULL){ + chan0=&s->channels[0]; + chan=&s->channels[i]; + if (chan->is_used==TRUE) + { + while (ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran)==s->conf_gran) + { + if (f->outputs[0]!=NULL) + { + /* send in pin0 */ + mblk_t *m=allocb(s->conf_gran,0); + memcpy(m->b_wptr, chan->input, s->conf_gran); + m->b_wptr+=s->conf_gran; + ms_queue_put(f->outputs[0],m); + } + } + } + + if (chan0->is_used==TRUE) + { + while (ms_bufferizer_read(&chan0->buff,(uint8_t*)chan0->input,s->conf_gran)==s->conf_gran) + { + if (f->outputs[i]!=NULL) + { + /* send in pinI */ + mblk_t *m=allocb(s->conf_gran,0); + memcpy(m->b_wptr, chan0->input, s->conf_gran); + m->b_wptr+=s->conf_gran; + ms_queue_put(f->outputs[i],m); + } + } + } + break; + } + } + } + +} + +static void conf_postprocess(MSFilter *f){ + int i; + ConfState *s=(ConfState*)f->data; + Channel *chan; + /*read from all inputs and put into bufferizers*/ + for (i=0;iinputs[i]!=NULL){ + chan=&s->channels[i]; + ms_bufferizer_uninit(&chan->buff); + ms_bufferizer_init(&chan->buff); + } + } +} +static int msconf_set_sr(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + int i; + + s->samplerate = *(int*)arg; + s->conf_gran = ((16 * s->samplerate) / 800) *2; + s->conf_nsamples=s->conf_gran/2; + for (i=0;ichannels[i]); + for (i=0;ichannels[i], i); + return 0; +} + +static int msconf_enable_directmode(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + s->enable_directmode = *(int*)arg; + return 0; +} + +static int msconf_enable_agc(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + int i; + s->agc_level = *(int*)arg; + + for (i=0;ichannels[i]); + for (i=0;ichannels[i], i); + return 0; +} + +static int msconf_enable_vad(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + int i; + s->enable_vad = *(int*)arg; + + for (i=0;ichannels[i]); + for (i=0;ichannels[i], i); + return 0; +} + +static int msconf_get_stat_discarded(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + Channel *chan; + int i; + i = *(int*)arg; + /*read from all inputs and put into bufferizers*/ + if (i<0 || i>CONF_MAX_PINS) + return -1; + + if (f->inputs[i]!=NULL){ + chan=&s->channels[i]; + return chan->stat_discarded; + } + return -1; +} + +static int msconf_get_stat_missed(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + Channel *chan; + int i; + i = *(int*)arg; + /*read from all inputs and put into bufferizers*/ + if (i<0 || i>CONF_MAX_PINS) + return -1; + + if (f->inputs[i]!=NULL){ + chan=&s->channels[i]; + return chan->stat_missed; + } + return -1; +} + +static int msconf_get_stat_processed(MSFilter *f, void *arg){ + ConfState *s=(ConfState*)f->data; + Channel *chan; + int i; + i = *(int*)arg; + /*read from all inputs and put into bufferizers*/ + if (i<0 || i>CONF_MAX_PINS) + return -1; + + if (f->inputs[i]!=NULL){ + chan=&s->channels[i]; + return chan->stat_processed; + } + return -1; +} + +static MSFilterMethod msconf_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE, msconf_set_sr }, + { MS_FILTER_ENABLE_DIRECTMODE, msconf_enable_directmode }, + { MS_FILTER_ENABLE_VAD, msconf_enable_vad }, + { MS_FILTER_ENABLE_AGC, msconf_enable_agc }, + { MS_FILTER_GET_STAT_DISCARDED, msconf_get_stat_discarded }, + { MS_FILTER_GET_STAT_MISSED, msconf_get_stat_missed }, + { MS_FILTER_GET_STAT_OUTPUT, msconf_get_stat_processed }, + { 0 , NULL} +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_conf_desc={ + MS_CONF_ID, + "MSConf", + "A filter to make conferencing", + MS_FILTER_OTHER, + NULL, + CONF_MAX_PINS, + CONF_MAX_PINS, + conf_init, + conf_preprocess, + conf_process, + conf_postprocess, + conf_uninit, + msconf_methods +}; + +#else + +MSFilterDesc ms_conf_desc={ + .id=MS_CONF_ID, + .name="MSConf", + .text="A filter to make conferencing", + .category=MS_FILTER_OTHER, + .ninputs=CONF_MAX_PINS, + .noutputs=CONF_MAX_PINS, + .init=conf_init, + .preprocess=conf_preprocess, + .process=conf_process, + .postprocess=conf_postprocess, + .uninit=conf_uninit, + .methods=msconf_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_conf_desc) diff --git a/linphone/mediastreamer2/src/msfileplayer.c b/linphone/mediastreamer2/src/msfileplayer.c new file mode 100644 index 000000000..c166e5db4 --- /dev/null +++ b/linphone/mediastreamer2/src/msfileplayer.c @@ -0,0 +1,304 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfileplayer.h" +#include "mediastreamer2/waveheader.h" +#include "mediastreamer2/msticker.h" + + +static int player_close(MSFilter *f, void *arg); + +typedef enum { + CLOSED, + STARTED, + STOPPED +} PlayerState; + +struct _PlayerData{ + int fd; + PlayerState state; + int rate; + int nchannels; + int hsize; + int loop_after; + int pause_time; + bool_t swap; +}; + +typedef struct _PlayerData PlayerData; + +static void player_init(MSFilter *f){ + PlayerData *d=ms_new(PlayerData,1); + d->fd=-1; + d->state=CLOSED; + d->swap=FALSE; + d->rate=8000; + d->nchannels=1; + d->hsize=0; + d->loop_after=-1; /*by default, don't loop*/ + d->pause_time=0; + f->data=d; +} + +static int read_wav_header(PlayerData *d){ + + char header1[sizeof(riff_t)]; + char header2[sizeof(format_t)]; + char header3[sizeof(data_t)]; + int count; + + riff_t *riff_chunk=(riff_t*)header1; + format_t *format_chunk=(format_t*)header2; + data_t *data_chunk=(data_t*)header3; + + unsigned long len=0; + + len = read(d->fd, header1, sizeof(header1)) ; + if (len != sizeof(header1)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + + if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){ + ms_warning("Wrong wav header (not RIFF/WAV)"); + return -1; + } + + len = read(d->fd, header2, sizeof(header2)) ; + if (len != sizeof(header2)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + + d->rate=le_uint32(format_chunk->rate); + d->nchannels=le_uint16(format_chunk->channel); + + if (format_chunk->len-0x10>0) + { + lseek(d->fd,(format_chunk->len-0x10),SEEK_CUR); + } + + d->hsize=sizeof(wave_header_t)-0x10+format_chunk->len; + + len = read(d->fd, header3, sizeof(header3)) ; + if (len != sizeof(header3)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + count=0; + while (strncmp(data_chunk->data, "data", 4)!=0 && count<30) + { + ms_warning("skipping chunk=%s len=%i", data_chunk->data, data_chunk->len); + lseek(d->fd,data_chunk->len,SEEK_CUR); + count++; + d->hsize=d->hsize+len+data_chunk->len; + + len = read(d->fd, header3, sizeof(header3)) ; + if (len != sizeof(header3)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + } +#ifdef WORDS_BIGENDIAN + if (le_uint16(format_chunk->blockalign)==le_uint16(format_chunk->channel) * 2) + d->swap=TRUE; +#endif + return 0; +} + +static int player_open(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + int fd; + const char *file=(const char*)arg; + + if (d->fd>=0){ + player_close(f,NULL); + } + if ((fd=open(file,O_RDONLY))==-1){ + ms_warning("Failed to open %s",file); + return -1; + } + d->state=STOPPED; + d->fd=fd; + if (strstr(file,".wav")!=NULL) read_wav_header(d); + ms_message("%s opened: rate=%i,channel=%i",file,d->rate,d->nchannels); + return 0; +} + +static int player_start(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + if (d->state==STOPPED) + d->state=STARTED; + return 0; +} + +static int player_stop(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + ms_filter_lock(f); + if (d->state==STARTED){ + d->state=STOPPED; + lseek(d->fd,d->hsize,SEEK_SET); + } + ms_filter_unlock(f); + return 0; +} + +static int player_close(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + player_stop(f,NULL); + if (d->fd>=0) close(d->fd); + d->fd=-1; + d->state=CLOSED; + return 0; +} + +static void player_uninit(MSFilter *f){ + PlayerData *d=(PlayerData*)f->data; + if (d->fd>=0) player_close(f,NULL); + ms_free(d); +} + +static void swap_bytes(unsigned char *bytes, int len){ + int i; + unsigned char tmp; + for(i=0;idata; + int bytes=2*(f->ticker->interval*d->rate*d->nchannels)/1000; + ms_filter_lock(f); + if (d->state==STARTED){ + int err; + mblk_t *om=allocb(bytes,0); + if (d->pause_time>0){ + err=bytes; + memset(om->b_wptr,0,bytes); + d->pause_time-=f->ticker->interval; + }else{ + err=read(d->fd,om->b_wptr,bytes); + if (d->swap) swap_bytes(om->b_wptr,bytes); + } + if (err>=0){ + if (err!=0){ + om->b_wptr+=bytes; + ms_queue_put(f->outputs[0],om); + }else freemsg(om); + if (errfd,d->hsize,SEEK_SET); + + /* special value for playing file only once */ + if (d->loop_after==-2) + { + d->state=STOPPED; + ms_filter_unlock(f); + return; + } + + if (d->loop_after>=0){ + d->pause_time=d->loop_after; + } + } + }else{ + ms_warning("Fail to read %i bytes: %s",bytes,strerror(errno)); + } + } + ms_filter_unlock(f); +} + +static int player_get_sr(MSFilter *f, void*arg){ + PlayerData *d=(PlayerData*)f->data; + *((int*)arg)=d->rate; + return 0; +} + +static int player_loop(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + d->loop_after=*((int*)arg); + return 0; +} + +static int player_eof(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + if (d->fd<0 && d->state==CLOSED) + *((int*)arg) = TRUE; /* 1 */ + else + *((int*)arg) = FALSE; /* 0 */ + return 0; +} + +static int player_get_nch(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + *((int*)arg)=d->nchannels; + return 0; +} + +static MSFilterMethod player_methods[]={ + { MS_FILE_PLAYER_OPEN, player_open }, + { MS_FILE_PLAYER_START, player_start }, + { MS_FILE_PLAYER_STOP, player_stop }, + { MS_FILE_PLAYER_CLOSE, player_close }, + { MS_FILTER_GET_SAMPLE_RATE, player_get_sr}, + { MS_FILTER_GET_NCHANNELS, player_get_nch }, + { MS_FILE_PLAYER_LOOP, player_loop }, + { MS_FILE_PLAYER_DONE, player_eof }, + { 0, NULL } +}; + +#ifdef WIN32 + +MSFilterDesc ms_file_player_desc={ + MS_FILE_PLAYER_ID, + "MSFilePlayer", + "Raw files and wav reader", + MS_FILTER_OTHER, + NULL, + 0, + 1, + player_init, + NULL, + player_process, + NULL, + player_uninit, + player_methods +}; + +#else + +MSFilterDesc ms_file_player_desc={ + .id=MS_FILE_PLAYER_ID, + .name="MSFilePlayer", + .text="Raw files and wav reader", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .init=player_init, + .process=player_process, + .uninit=player_uninit, + .methods=player_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_file_player_desc) diff --git a/linphone/mediastreamer2/src/msfileplayer_win.c b/linphone/mediastreamer2/src/msfileplayer_win.c new file mode 100644 index 000000000..5331802a9 --- /dev/null +++ b/linphone/mediastreamer2/src/msfileplayer_win.c @@ -0,0 +1,369 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfileplayer.h" +#include "mediastreamer2/waveheader.h" +#include "mediastreamer2/msticker.h" + + +typedef enum { + CLOSED, + STARTED, + STOPPED +} PlayerState; + +struct _PlayerData{ + HANDLE fd; + PlayerState state; + int rate; + int nchannels; + int hsize; + int loop_after; + int pause_time; + bool_t swap; + + int stat; + int big_buffer; /* ouput less & bigger buffer. (default => no change) */ +}; + +typedef struct _PlayerData PlayerData; + +static void player_init(MSFilter *f){ + PlayerData *d=(PlayerData *)ms_new(PlayerData,1); + d->fd=INVALID_HANDLE_VALUE; + d->state=CLOSED; + d->swap=FALSE; + d->rate=8000; + d->nchannels=1; + d->hsize=0; + d->loop_after=-1; + d->pause_time=0; + d->stat=-1; + d->big_buffer=1; + f->data=d; +} + +static int read_wav_header(PlayerData *d){ + + char header1[sizeof(riff_t)]; + char header2[sizeof(format_t)]; + char header3[sizeof(data_t)]; + int count; + + riff_t *riff_chunk=(riff_t*)header1; + format_t *format_chunk=(format_t*)header2; + data_t *data_chunk=(data_t*)header3; + + unsigned long len=0; + BOOL res; + + res = ReadFile(d->fd, header1, sizeof(header1), &len, NULL) ; + if (!res || len != sizeof(header1)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + + if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){ + ms_warning("Wrong wav header (not RIFF/WAV)"); + return -1; + } + + res = ReadFile(d->fd, header2, sizeof(header2), &len, NULL) ; + if (!res || len != sizeof(header2)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + + d->rate=le_uint32(format_chunk->rate); + d->nchannels=le_uint16(format_chunk->channel); + + if (format_chunk->len-0x10>0) + { + SetFilePointer(d->fd, (format_chunk->len-0x10), NULL, FILE_CURRENT); + } + + d->hsize=sizeof(wave_header_t)-0x10+format_chunk->len; + + res = ReadFile(d->fd, header3, sizeof(header3), &len, NULL) ; + if (!res || len != sizeof(header3)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + count=0; + while (strncmp(data_chunk->data, "data", 4)!=0 && count<30) + { + SetFilePointer(d->fd, data_chunk->len, NULL, FILE_CURRENT); + count++; + d->hsize=d->hsize+len+data_chunk->len; + + res = ReadFile(d->fd, header3, sizeof(header3), &len, NULL) ; + if (!res || len != sizeof(header3)){ + ms_warning("Wrong wav header: cannot read file"); + return -1; + } + } +#ifdef WORDS_BIGENDIAN + d->swap=TRUE; +#endif + return 0; +} + +static int player_open(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + HANDLE fd; + const char *file=(const char*)arg; +#if defined(_WIN32_WCE) + fd = CreateFile((LPCWSTR)file, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); +#else + fd = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); +#endif + if (fd==INVALID_HANDLE_VALUE){ + ms_warning("Failed to open %s",file); + return -1; + } + d->state=STOPPED; + d->fd=fd; + if (strstr(file,".wav")!=NULL) read_wav_header(d); + return 0; +} + +static int player_close(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + if (d->fd!=INVALID_HANDLE_VALUE) CloseHandle(d->fd); + d->fd=NULL; + d->state=CLOSED; + d->stat=-1; + return 0; +} + +static int player_start(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + if (d->state==STOPPED) + d->state=STARTED; + return 0; +} + +static int player_stop(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + if (d->state==STARTED){ + d->state=STOPPED; + d->stat=-1; + SetFilePointer(d->fd, d->hsize, NULL, FILE_BEGIN); + //read_wav_header(d); + } + return 0; +} + +static void player_uninit(MSFilter *f){ + PlayerData *d=(PlayerData*)f->data; + if (d->fd!=INVALID_HANDLE_VALUE) player_close(f,NULL); + ms_free(d); +} + +static void player_process(MSFilter *f){ + PlayerData *d=(PlayerData*)f->data; + int bytes =d->big_buffer * 2*(f->ticker->interval*d->rate*d->nchannels)/1000;; + + if (d->big_buffer>1) + { + /* when starting reading a file: prepare more data + so that sound card buffer will never remain empty. + */ + d->stat++; + if (d->stat>3) + { + if (d->stat%(d->big_buffer)!=0) + return; + } + } + + if (d->state==STARTED){ + unsigned long err; + mblk_t *om=allocb(bytes,0); + if (d->pause_time>0){ + err=bytes; + memset(om->b_wptr,0,bytes); + d->pause_time-=f->ticker->interval; + }else{ + BOOL res; + err=0; + res = ReadFile(d->fd, om->b_wptr, bytes, &err, NULL) ; + } + if (err>=0){ + if (err==bytes){ + om->b_wptr+=err; + ms_queue_put(f->outputs[0],om); + } + else if (err>0){ + BOOL res; + + om->b_wptr+=err; + + ms_filter_notify_no_arg(f,MS_FILE_PLAYER_EOF); + SetFilePointer(d->fd, d->hsize, NULL, FILE_BEGIN); + //read_wav_header(d); + + /* special value for playing file only once */ + if (d->loop_after==-2) + { + player_close(f,NULL); + return; + } + + if (d->loop_after>0) + { + d->stat=-1; + d->pause_time=d->loop_after; + } + else + { + bytes=bytes-err; + err=0; + res = ReadFile(d->fd, om->b_wptr, bytes, &err, NULL); + if (err>0){ + om->b_wptr+=err; + } + } + + ms_queue_put(f->outputs[0],om); + } + else if (err==0){ + BOOL res; + ms_filter_notify_no_arg(f,MS_FILE_PLAYER_EOF); + SetFilePointer(d->fd, d->hsize, NULL, FILE_BEGIN); + + if (d->loop_after==-2) + { + player_close(f,NULL); + return; + } + + if (d->loop_after>0) + { + d->stat=-1; + d->pause_time=d->loop_after; + } + else + { + bytes=bytes-err; + err=0; + res = ReadFile(d->fd, om->b_wptr, bytes, &err, NULL); + if (err>0){ + om->b_wptr+=err; + ms_queue_put(f->outputs[0],om); + return; + } + } + freemsg(om); + + }else freemsg(om); + }else{ +#if !defined(_WIN32_WCE) + ms_warning("Fail to read %i bytes: %s",bytes,strerror(errno)); +#else + ms_warning("Fail to read %i bytes: %i",bytes,WSAGetLastError()); +#endif + } + } +} + +static int player_get_sr(MSFilter *f, void*arg){ + PlayerData *d=(PlayerData*)f->data; + *((int*)arg)=d->rate; + return 0; +} + +static int player_loop(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + d->loop_after=*((int*)arg); + return 0; +} + +static int player_set_big_buffer(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + d->big_buffer=*((int*)arg); + return 0; +} + +static int player_eof(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + if (d->fd==NULL && d->state==CLOSED) + *((int*)arg) = TRUE; /* 1 */ + else + *((int*)arg) = FALSE; /* 0 */ + return 0; +} + +static int player_get_nch(MSFilter *f, void *arg){ + PlayerData *d=(PlayerData*)f->data; + *((int*)arg)=d->nchannels; + return 0; +} + +static MSFilterMethod player_methods[]={ + { MS_FILE_PLAYER_OPEN, player_open }, + { MS_FILE_PLAYER_START, player_start }, + { MS_FILE_PLAYER_STOP, player_stop }, + { MS_FILE_PLAYER_CLOSE, player_close }, + { MS_FILTER_GET_SAMPLE_RATE, player_get_sr}, + { MS_FILTER_GET_NCHANNELS, player_get_nch }, + { MS_FILE_PLAYER_LOOP, player_loop }, + { MS_FILE_PLAYER_DONE, player_eof }, + { MS_FILE_PLAYER_BIG_BUFFER, player_set_big_buffer }, + { 0, NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_file_player_desc={ + MS_FILE_PLAYER_ID, + "MSFilePlayer", + "Raw files and wav reader", + MS_FILTER_OTHER, + NULL, + 0, + 1, + player_init, + NULL, + player_process, + NULL, + player_uninit, + player_methods +}; + +#else + +MSFilterDesc ms_file_player_desc={ + .id=MS_FILE_PLAYER_ID, + .name="MSFilePlayer", + .text="Raw files and wav reader", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .init=player_init, + .process=player_process, + .uninit=player_uninit, + .methods=player_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_file_player_desc) diff --git a/linphone/mediastreamer2/src/msfilerec.c b/linphone/mediastreamer2/src/msfilerec.c new file mode 100644 index 000000000..fc548ed49 --- /dev/null +++ b/linphone/mediastreamer2/src/msfilerec.c @@ -0,0 +1,200 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilerec.h" +#include "mediastreamer2/waveheader.h" + +#include +#include +#include + +static int rec_close(MSFilter *f, void *arg); + +typedef enum{ + Closed, + Stopped, + Started +} State; + +typedef struct RecState{ + int fd; + int rate; + int size; + State state; +} RecState; + +static void rec_init(MSFilter *f){ + RecState *s=ms_new(RecState,1); + s->fd=-1; + s->rate=8000; + s->size=0; + s->state=Closed; + f->data=s; +} + +static void rec_process(MSFilter *f){ + RecState *s=(RecState*)f->data; + mblk_t *m; + int err; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + mblk_t *it=m; + ms_mutex_lock(&f->lock); + if (s->state==Started){ + while(it!=NULL){ + int len=it->b_wptr-it->b_rptr; + if ((err=write(s->fd,it->b_rptr,len))!=len){ + if (err<0) + ms_warning("MSFileRec: fail to write %i bytes: %s",len,strerror(errno)); + } + it=it->b_cont; + s->size+=len; + } + } + ms_mutex_unlock(&f->lock); + freemsg(m); + } +} + +static int rec_open(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + const char *filename=(const char*)arg; + if (s->fd>=0) rec_close(f,NULL); + ms_mutex_lock(&f->lock); + s->fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); + if (s->fd<0){ + ms_warning("Cannot open %s: %s",filename,strerror(errno)); + ms_mutex_unlock(&f->lock); + return -1; + } + s->state=Stopped; + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_start(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->state=Started; + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_stop(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->state=Stopped; + ms_mutex_unlock(&f->lock); + return 0; +} + +static void write_wav_header(int fd, int rate,int size){ + wave_header_t header; + memcpy(&header.riff_chunk.riff,"RIFF",4); + header.riff_chunk.len=le_uint32(size+32); + memcpy(&header.riff_chunk.wave,"WAVE",4); + + memcpy(&header.format_chunk.fmt,"fmt ",4); + header.format_chunk.len=le_uint32(0x10); + header.format_chunk.type=le_uint16(0x1); + header.format_chunk.channel=le_uint16(0x1); + header.format_chunk.rate=le_uint32(rate); + header.format_chunk.bps=le_uint32(rate*2); + header.format_chunk.blockalign=le_uint16(2); + header.format_chunk.bitpspl=le_uint16(16); + + memcpy(&header.data_chunk.data,"data",4); + header.data_chunk.len=le_uint32(size); + lseek(fd,0,SEEK_SET); + if (write(fd,&header,sizeof(header))!=sizeof(header)){ + ms_warning("Fail to write wav header."); + } +} + +static int rec_close(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->state=Closed; + if (s->fd>=0) { + write_wav_header(s->fd,s->rate, s->size); + close(s->fd); + s->fd=-1; + } + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_set_sr(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->rate=*((int*)arg); + ms_mutex_unlock(&f->lock); + return 0; +} + +static void rec_uninit(MSFilter *f){ + RecState *s=(RecState*)f->data; + if (s->fd>=0) rec_close(f,NULL); + ms_free(s); +} + +static MSFilterMethod rec_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE, rec_set_sr }, + { MS_FILE_REC_OPEN , rec_open }, + { MS_FILE_REC_START , rec_start }, + { MS_FILE_REC_STOP , rec_stop }, + { MS_FILE_REC_CLOSE , rec_close }, + { 0 , NULL } +}; + +#ifdef WIN32 + +MSFilterDesc ms_file_rec_desc={ + MS_FILE_REC_ID, + "MSFileRec", + "Wav file recorder", + MS_FILTER_OTHER, + NULL, + 1, + 0, + rec_init, + NULL, + rec_process, + NULL, + rec_uninit, + rec_methods +}; + +#else + +MSFilterDesc ms_file_rec_desc={ + .id=MS_FILE_REC_ID, + .name="MSFileRec", + .text="Wav file recorder", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=0, + .init=rec_init, + .process=rec_process, + .uninit=rec_uninit, + .methods=rec_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_file_rec_desc) diff --git a/linphone/mediastreamer2/src/msfilerec_win.c b/linphone/mediastreamer2/src/msfilerec_win.c new file mode 100644 index 000000000..07b069351 --- /dev/null +++ b/linphone/mediastreamer2/src/msfilerec_win.c @@ -0,0 +1,237 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilerec.h" +#include "mediastreamer2/waveheader.h" + +#if !defined(_WIN32_WCE) +#include +#include +#include +#endif + + +typedef enum{ + Closed, + Stopped, + Started +} State; + +typedef struct RecState{ + HANDLE fd; + int rate; + int size; + State state; + char filename[256]; +} RecState; + +static void rec_init(MSFilter *f){ + RecState *s=(RecState *)ms_new(RecState,1); + s->fd=INVALID_HANDLE_VALUE; + s->rate=8000; + s->size=0; + s->state=Closed; + f->data=s; +} + +static void rec_process(MSFilter *f){ + RecState *s=(RecState*)f->data; + mblk_t *m; + int err; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + mblk_t *it=m; + ms_mutex_lock(&f->lock); + if (s->state==Started){ + while(it!=NULL){ + int len=it->b_wptr-it->b_rptr; + DWORD byte_written=0; + if ((err=WriteFile(s->fd,it->b_rptr,len, &byte_written, NULL))!=len){ + if (err<0) + { +#if !defined(_WIN32_WCE) + ms_warning("MSFileRec: fail to write %i bytes: %s",len,strerror(errno)); +#else + ms_warning("MSFileRec: fail to write %i bytes: %i",len,WSAGetLastError()); +#endif + } + } + it=it->b_cont; + s->size+=len; + } + } + ms_mutex_unlock(&f->lock); + freemsg(m); + } +} + +static void write_wav_header(int rate,int size, char *filename){ + wave_header_t header; + DWORD bytes_written=0; + HANDLE fd; + memcpy(&header.riff_chunk.riff,"RIFF",4); + header.riff_chunk.len=le_uint32(size+32); + memcpy(&header.riff_chunk.wave,"WAVE",4); + + memcpy(&header.format_chunk.fmt,"fmt ",4); + header.format_chunk.len=le_uint32(0x10); + header.format_chunk.type=le_uint16(0x1); + header.format_chunk.channel=le_uint16(0x1); + header.format_chunk.rate=le_uint32(rate); + header.format_chunk.bps=le_uint32(rate*2); + header.format_chunk.blockalign=le_uint16(2); + header.format_chunk.bitpspl=le_uint16(16); + + memcpy(&header.data_chunk.data,"data",4); + header.data_chunk.len=le_uint32(size); + + /* TODO: replace with "lseek" equivalent for windows */ +#if defined(_WIN32_WCE) + fd=CreateFile((LPCWSTR)filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); +#else + fd=CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); +#endif + if (fd==INVALID_HANDLE_VALUE){ +#if !defined(_WIN32_WCE) + ms_warning("Cannot open %s: %s",filename,strerror(errno)); +#else + ms_warning("Cannot open %s: %i",filename,WSAGetLastError()); +#endif + return; + } + WriteFile(fd,&header,sizeof(header), &bytes_written, NULL); + if (bytes_written!=sizeof(header)){ + ms_warning("Fail to write wav header."); + } + CloseHandle(fd); +} + +static int rec_open(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + const char *filename=(const char*)arg; + ms_mutex_lock(&f->lock); + snprintf(s->filename, sizeof(s->filename), "%s", filename); +#if defined(_WIN32_WCE) + s->fd=CreateFile((LPCWSTR)filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); +#else + s->fd=CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); +#endif + if (s->fd==INVALID_HANDLE_VALUE){ +#if !defined(_WIN32_WCE) + ms_warning("Cannot open %s: %s",filename,strerror(errno)); +#else + ms_warning("Cannot open %s: %i",filename,WSAGetLastError()); +#endif + ms_mutex_unlock(&f->lock); + return -1; + } + + s->state=Stopped; + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_start(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->state=Started; + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_stop(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->state=Stopped; + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_close(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->state=Closed; + if (s->fd!=INVALID_HANDLE_VALUE) { + CloseHandle(s->fd); + write_wav_header(s->rate, s->size, s->filename); + s->fd=INVALID_HANDLE_VALUE; + s->size=0; + } + ms_mutex_unlock(&f->lock); + return 0; +} + +static int rec_set_sr(MSFilter *f, void *arg){ + RecState *s=(RecState*)f->data; + ms_mutex_lock(&f->lock); + s->rate=*((int*)arg); + ms_mutex_unlock(&f->lock); + return 0; +} + +static void rec_uninit(MSFilter *f){ + RecState *s=(RecState*)f->data; + if (s->fd!=INVALID_HANDLE_VALUE) rec_close(f,NULL); + ms_free(s); +} + +static MSFilterMethod rec_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE, rec_set_sr }, + { MS_FILE_REC_OPEN , rec_open }, + { MS_FILE_REC_START , rec_start }, + { MS_FILE_REC_STOP , rec_stop }, + { MS_FILE_REC_CLOSE , rec_close }, + { 0 , NULL } +}; + +#ifdef WIN32 + +MSFilterDesc ms_file_rec_desc={ + MS_FILE_REC_ID, + "MSFileRec", + "Wav file recorder", + MS_FILTER_OTHER, + NULL, + 1, + 0, + rec_init, + NULL, + rec_process, + NULL, + rec_uninit, + rec_methods +}; + +#else + +MSFilterDesc ms_file_rec_desc={ + .id=MS_FILE_REC_ID, + .name="MSFileRec", + .text="Wav file recorder", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=0, + .init=rec_init, + .process=rec_process, + .uninit=rec_uninit, + .methods=rec_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_file_rec_desc) diff --git a/linphone/mediastreamer2/src/msfilter.c b/linphone/mediastreamer2/src/msfilter.c new file mode 100644 index 000000000..5358156d6 --- /dev/null +++ b/linphone/mediastreamer2/src/msfilter.c @@ -0,0 +1,235 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/mscommon.h" + +static MSList *desc_list=NULL; + +void ms_filter_register(MSFilterDesc *desc){ + if (desc->id==MS_FILTER_NOT_SET_ID){ + ms_fatal("MSFilterId for %s not set !",desc->name); + } + /*lastly registered encoder/decoders may replace older ones*/ + desc_list=ms_list_prepend(desc_list,desc); +} + +void ms_filter_unregister_all(){ + if (desc_list!=NULL) ms_list_free(desc_list); +} + +bool_t ms_filter_codec_supported(const char *mime){ + if (ms_filter_get_encoder(mime)!=NULL + && ms_filter_get_decoder(mime)!=NULL) return TRUE; + return FALSE; +} + +MSFilterDesc * ms_filter_get_encoder(const char *mime){ + MSList *elem; + for (elem=desc_list;elem!=NULL;elem=ms_list_next(elem)){ + MSFilterDesc *desc=(MSFilterDesc*)elem->data; + if (desc->category==MS_FILTER_ENCODER && + strcasecmp(desc->enc_fmt,mime)==0){ + return desc; + } + } + return NULL; +} + +MSFilterDesc * ms_filter_get_decoder(const char *mime){ + MSList *elem; + for (elem=desc_list;elem!=NULL;elem=ms_list_next(elem)){ + MSFilterDesc *desc=(MSFilterDesc*)elem->data; + if (desc->category==MS_FILTER_DECODER && + strcasecmp(desc->enc_fmt,mime)==0){ + return desc; + } + } + return NULL; +} + +MSFilter * ms_filter_create_encoder(const char *mime){ + MSFilterDesc *desc=ms_filter_get_encoder(mime); + if (desc!=NULL) return ms_filter_new_from_desc(desc); + return NULL; +} + +MSFilter * ms_filter_create_decoder(const char *mime){ + MSFilterDesc *desc=ms_filter_get_decoder(mime); + if (desc!=NULL) return ms_filter_new_from_desc(desc); + return NULL; +} + +MSFilter *ms_filter_new_from_desc(MSFilterDesc *desc){ + MSFilter *obj; + obj=(MSFilter *)ms_new0(MSFilter,1); + ms_mutex_init(&obj->lock,NULL); + obj->desc=desc; + if (desc->ninputs>0) obj->inputs=(MSQueue**)ms_new0(MSQueue*,desc->ninputs); + if (desc->noutputs>0) obj->outputs=(MSQueue**)ms_new0(MSQueue*,desc->noutputs); + if (desc->ninputs==0 && desc->noutputs==0) + ms_fatal("A filter cannot have no inputs and outputs"); + if (obj->desc->init!=NULL) + obj->desc->init(obj); + return obj; +} + +MSFilter *ms_filter_new(MSFilterId id){ + MSList *elem; + if (id==MS_FILTER_PLUGIN_ID){ + ms_warning("cannot create plugin filters with ms_filter_new_from_id()"); + return NULL; + } + for (elem=desc_list;elem!=NULL;elem=ms_list_next(elem)){ + MSFilterDesc *desc=(MSFilterDesc*)elem->data; + if (desc->id==id){ + return ms_filter_new_from_desc(desc); + } + } + ms_error("No such filter with id %i",id); + return NULL; +} + +MSFilter *ms_filter_new_from_name(const char *filter_name){ + MSList *elem; + for (elem=desc_list;elem!=NULL;elem=ms_list_next(elem)){ + MSFilterDesc *desc=(MSFilterDesc*)elem->data; + if (strcmp(desc->name,filter_name)==0){ + return ms_filter_new_from_desc(desc); + } + } + ms_error("No such filter with name %s",filter_name); + return NULL; +} + + +MSFilterId ms_filter_get_id(MSFilter *f){ + return f->desc->id; +} + +int ms_filter_link(MSFilter *f1, int pin1, MSFilter *f2, int pin2){ + MSQueue *q; + ms_return_val_if_fail(pin1desc->noutputs, -1); + ms_return_val_if_fail(pin2desc->ninputs, -1); + ms_return_val_if_fail(f1->outputs[pin1]==NULL,-1); + ms_return_val_if_fail(f2->inputs[pin2]==NULL,-1); + q=ms_queue_new(f1,pin1,f2,pin2); + f1->outputs[pin1]=q; + f2->inputs[pin2]=q; + ms_message("ms_filter_link: %s:%p,%i-->%s:%p,%i",f1->desc->name,f1,pin1,f2->desc->name,f2,pin2); + return 0; +} + +int ms_filter_unlink(MSFilter *f1, int pin1, MSFilter *f2, int pin2){ + MSQueue *q; + ms_return_val_if_fail(f1, -1); + ms_return_val_if_fail(f2, -1); + ms_return_val_if_fail(pin1desc->noutputs, -1); + ms_return_val_if_fail(pin2desc->ninputs, -1); + ms_return_val_if_fail(f1->outputs[pin1]!=NULL,-1); + ms_return_val_if_fail(f2->inputs[pin2]!=NULL,-1); + ms_return_val_if_fail(f1->outputs[pin1]==f2->inputs[pin2],-1); + q=f1->outputs[pin1]; + f1->outputs[pin1]=f2->inputs[pin2]=0; + ms_queue_destroy(q); + ms_message("ms_filter_unlink: %s:%p,%i-->%s:%p,%i",f1->desc->name,f1,pin1,f2->desc->name,f2,pin2); + return 0; +} + +#define MS_FILTER_METHOD_GET_FID(id) (((id)>>16) & 0xFFFF) + +int ms_filter_call_method(MSFilter *f, unsigned int id, void *arg){ + MSFilterMethod *methods=f->desc->methods; + int i; + unsigned int magic=MS_FILTER_METHOD_GET_FID(id); + if (magic!=MS_FILTER_BASE_ID && magic!=f->desc->id) { + ms_fatal("Bad method definition in filter %s",f->desc->name); + return -1; + } + for(i=0;methods!=NULL && methods[i].method!=NULL; i++){ + unsigned int mm=MS_FILTER_METHOD_GET_FID(methods[i].id); + if (mm!=f->desc->id && mm!=MS_FILTER_BASE_ID) { + ms_fatal("MSFilter method mismatch: bad call."); + return -1; + } + if (methods[i].id==id){ + return methods[i].method(f,arg); + } + } + if (magic!=MS_FILTER_BASE_ID) ms_error("no such method on filter %s",f->desc->name); + return -1; +} + +int ms_filter_call_method_noarg(MSFilter *f, unsigned int id){ + return ms_filter_call_method(f,id,NULL); +} + +void ms_filter_set_notify_callback(MSFilter *f, MSFilterNotifyFunc fn, void *ud){ + f->notify=fn; + f->notify_ud=ud; +} + +void ms_filter_destroy(MSFilter *f){ + if (f->desc->uninit!=NULL) + f->desc->uninit(f); + if (f->inputs!=NULL) ms_free(f->inputs); + if (f->outputs!=NULL) ms_free(f->outputs); + ms_mutex_destroy(&f->lock); + ms_free(f); +} + + +void ms_filter_process(MSFilter *f){ + ms_debug("Executing process of filter %s:%p",f->desc->name,f); + f->desc->process(f); +} + +void ms_filter_preprocess(MSFilter *f, struct _MSTicker *t){ + f->seen=FALSE; + f->last_tick=0; + f->ticker=t; + if (f->desc->preprocess!=NULL) + f->desc->preprocess(f); +} + +void ms_filter_postprocess(MSFilter *f){ + if (f->desc->postprocess!=NULL) + f->desc->postprocess(f); + f->seen=FALSE; + f->ticker=NULL; +} + +bool_t ms_filter_inputs_have_data(MSFilter *f){ + int i; + for(i=0;idesc->ninputs;i++){ + MSQueue *q=f->inputs[i]; + if (q!=NULL && q->q.q_mcount>0) return TRUE; + } + return FALSE; +} + +void ms_filter_notify(MSFilter *f, unsigned int id, void *arg){ + if (f->notify!=NULL) + f->notify(f->notify_ud,id,arg); +} + +void ms_filter_notify_no_arg(MSFilter *f, unsigned int id){ + if (f->notify!=NULL) + f->notify(f->notify_ud,id,NULL); +} diff --git a/linphone/mediastreamer2/src/msjoin.c b/linphone/mediastreamer2/src/msjoin.c new file mode 100644 index 000000000..3e5e4ab60 --- /dev/null +++ b/linphone/mediastreamer2/src/msjoin.c @@ -0,0 +1,72 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" + +static void join_process(MSFilter *f){ + mblk_t *im; + if (f->inputs[0]!=NULL) + { + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + ms_queue_put(f->outputs[0],im); + } + } + if (f->inputs[1]!=NULL) + { + while((im=ms_queue_get(f->inputs[1]))!=NULL){ + int payload; + payload=mblk_set_payload_type(im, 123); + ms_queue_put(f->outputs[0],im); + } + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_join_desc={ + MS_JOIN_ID, + "MSJoin", + "A filter that send several inputs to one output.", + MS_FILTER_OTHER, + NULL, + 2, + 1, + NULL, + NULL, + join_process, + NULL, + NULL, + NULL +}; + +#else + +MSFilterDesc ms_join_desc={ + .id=MS_JOIN_ID, + .name="MSJoin", + .text="A filter that send several inputs to one output.", + .category=MS_FILTER_OTHER, + .ninputs=2, + .noutputs=1, + .process=join_process +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_join_desc) diff --git a/linphone/mediastreamer2/src/msqueue.c b/linphone/mediastreamer2/src/msqueue.c new file mode 100644 index 000000000..f9b7b6a1b --- /dev/null +++ b/linphone/mediastreamer2/src/msqueue.c @@ -0,0 +1,112 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msqueue.h" +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msvideo.h" +#include + +MSQueue * ms_queue_new(struct _MSFilter *f1, int pin1, struct _MSFilter *f2, int pin2 ){ + MSQueue *q=(MSQueue*)ms_new(MSQueue,1); + qinit(&q->q); + q->prev.filter=f1; + q->prev.pin=pin1; + q->next.filter=f2; + q->next.pin=pin2; + return q; +} + +void ms_queue_init(MSQueue *q){ + q->prev.filter=0; + q->prev.pin=0; + q->next.filter=0; + q->next.pin=0; + qinit(&q->q); +} + +void ms_queue_destroy(MSQueue *q){ + flushq(&q->q,0); + ms_free(q); +} + +void ms_queue_flush(MSQueue *q){ + flushq(&q->q,0); +} + + +void ms_bufferizer_init(MSBufferizer *obj){ + qinit(&obj->q); + obj->size=0; +} + +MSBufferizer * ms_bufferizer_new(){ + MSBufferizer *obj=(MSBufferizer *)ms_new(MSBufferizer,1); + ms_bufferizer_init(obj); + return obj; +} + +void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m){ + obj->size+=msgdsize(m); + putq(&obj->q,m); +} + +void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q){ + mblk_t *m; + while((m=ms_queue_get(q))!=NULL){ + ms_bufferizer_put(obj,m); + } +} + +int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen){ + if (obj->size>=datalen){ + int sz=0; + int cplen; + mblk_t *m=peekq(&obj->q); + /*we can return something */ + while(szb_wptr-m->b_rptr,datalen-sz); + memcpy(data+sz,m->b_rptr,cplen); + sz+=cplen; + m->b_rptr+=cplen; + if (m->b_rptr==m->b_wptr){ + /* check cont */ + if (m->b_cont!=NULL) { + m=m->b_cont; + } + else{ + mblk_t *remove=getq(&obj->q); + freemsg(remove); + m=peekq(&obj->q); + } + } + } + obj->size-=datalen; + return datalen; + } + return 0; +} + +void ms_bufferizer_uninit(MSBufferizer *obj){ + flushq(&obj->q,0); +} + +void ms_bufferizer_destroy(MSBufferizer *obj){ + ms_bufferizer_uninit(obj); + ms_free(obj); +} diff --git a/linphone/mediastreamer2/src/msresample.c b/linphone/mediastreamer2/src/msresample.c new file mode 100644 index 000000000..4fb710083 --- /dev/null +++ b/linphone/mediastreamer2/src/msresample.c @@ -0,0 +1,245 @@ + +#include "mediastreamer2/msfilter.h" + +#include + +typedef struct _ResampleData{ + MSBufferizer *bz; + uint32_t ts; + uint32_t input_rate; + uint32_t output_rate; + + void *handle; + float factor; + int nb_unprocessed; +} ResampleData; + +static ResampleData * resample_data_new(){ + ResampleData *obj=(ResampleData *)ms_new(ResampleData,1); + obj->bz=ms_bufferizer_new(); + obj->ts=0; + obj->input_rate=8000; + obj->output_rate=16000; + + obj->nb_unprocessed=0; + obj->factor=obj->output_rate/obj->input_rate; + return obj; +} + +static void resample_data_destroy(ResampleData *obj){ + ms_bufferizer_destroy(obj->bz); + ms_free(obj); +} + +static void resample_init(MSFilter *obj){ + obj->data=resample_data_new(); +} + +static void resample_uninit(MSFilter *obj){ + resample_data_destroy((ResampleData*)obj->data); +} + +static void resample_preprocess(MSFilter *obj){ + ResampleData *dt=(ResampleData*)obj->data; + + dt->handle = resample_open(1, dt->factor, dt->factor); +} + +static void resample_postprocess(MSFilter *obj){ + ResampleData *dt=(ResampleData*)obj->data; + resample_close(dt->handle); +} + +static void resample_process_ms2(MSFilter *obj){ + ResampleData *dt=(ResampleData*)obj->data; + MSBufferizer *bz=dt->bz; + uint8_t buffer[2240]; + int size_of_input; + int size_of_output; + + mblk_t *m; + + if (dt->output_rate==dt->input_rate) + { + while((m=ms_queue_get(obj->inputs[0]))!=NULL){ + ms_queue_put(obj->outputs[0],m); + } + return; + } + + if (dt->input_rateoutput_rate) + size_of_input=320; + else + size_of_input=320; + size_of_output = (size_of_input * dt->output_rate)/dt->input_rate; + + while((m=ms_queue_get(obj->inputs[0]))!=NULL){ + ms_bufferizer_put(bz,m); + } + while (ms_bufferizer_read(bz,buffer,size_of_input)==size_of_input){ +#if 0 + mblk_t *obl=allocb(size_of_output,0); + + int outpos, o, srcused; + int srcpos; + int fwidth; + + int expectedlen = (int)(size_of_input * dt->factor); + int dstlen = expectedlen + 1000; + float in[1280]; + float out[2560]; + + short *data = (short*)buffer; + int i; + /* Convert the samples to floats */ + for (i = dt->nb_unprocessed; i < size_of_input; i++) + in[i] = (float) data[i-dt->nb_unprocessed]; + dt->nb_unprocessed=0; + + outpos = 0; + srcpos = 0; + for(;;) { + int srcBlock = MIN(size_of_input-srcpos, size_of_input); + int lastFlag = (srcBlock == size_of_input-srcpos); + + o = resample_process(dt->handle, dt->factor, + &in[srcpos], srcBlock, + lastFlag, &srcused, + &out[outpos], MIN(dstlen-outpos, size_of_input * dt->factor + 10)); + srcpos += srcused; + if (o >= 0) + outpos += o; + if (o < 0 || (o == 0 && srcpos == size_of_input)) + break; + } + + if (outpos>0 && outpos<=size_of_output) + { + //resample + data = (short*)obl->b_wptr; + for (i = 0; i < outpos/2; i++) + { + /* bound checks! */ + int bc=(short) out[i]; + if (bc < -32768) + bc = -32768; + else if (bc > 32767) + bc = 32767; + *data = bc; + data++; + } + + obl->b_wptr=obl->b_wptr+outpos; + dt->ts+=160; + ms_queue_put(obj->outputs[0],obl); + } + else + { + ms_warning("resample failed!"); + freeb(obl); + } +#else + mblk_t *obl=allocb(size_of_output,0); + + int srcused; + int o; + + float in[1280]; + float out[2560]; + + short *data = (short*)buffer; + int i; + /* Convert the samples to floats */ + for (i = 0; i < size_of_input/2; i++) + in[i] = (float) data[i-dt->nb_unprocessed]; + + o = resample_process(dt->handle, dt->factor, + &in[0], size_of_input/2, + 0, &srcused, + &out[0], size_of_output/2); + + if (o>0 && o<=size_of_output/2) + { + data = (short*)obl->b_wptr; + for (i = 0; i < o; i++) + { + /* bound checks! */ + int bc=(short) out[i]; + if (bc < -32768) + bc = -32768; + else if (bc > 32767) + bc = 32767; + data[i] = bc; + } + obl->b_wptr=obl->b_wptr+(o*2); /* size_of_output; */ + mblk_set_timestamp_info(obl,dt->ts); + dt->ts+=160; + ms_queue_put(obj->outputs[0],obl); + } + else + { + ms_warning("resample failed!"); + freeb(obl); + } +#endif + } +} + +int ms_resample_set_sr(MSFilter *obj, void *arg){ + ResampleData *dt=(ResampleData*)obj->data; + dt->input_rate=((int*)arg)[0]; + dt->factor=((float)dt->output_rate/(float)dt->input_rate); + return 0; +} + +int ms_resample_set_output_sr(MSFilter *obj, void *arg){ + ResampleData *dt=(ResampleData*)obj->data; + dt->output_rate=((int*)arg)[0]; + dt->factor=((float)dt->output_rate/(float)dt->input_rate); + return 0; +} + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , ms_resample_set_sr }, + { MS_FILTER_SET_OUTPUT_SAMPLE_RATE , ms_resample_set_output_sr }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_resample_desc={ + MS_RESAMPLE_ID, + "MSResample", + "frequency resampler", + MS_FILTER_OTHER, + NULL, + 1, + 1, + resample_init, + resample_preprocess, + resample_process_ms2, + resample_postprocess, + resample_uninit, + enc_methods +}; + +#else + +MSFilterDesc ms_resample_desc={ + .id=MS_RESAMPLE_ID, + .name="MSResample", + .text="frequency resampler", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=1, + .init=resample_init, + .preprocess=resample_preprocess, + .process=resample_process_ms2, + .postprocess=resample_postprocess, + .uninit=resample_uninit, + .methods=enc_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_resample_desc) diff --git a/linphone/mediastreamer2/src/msrtp.c b/linphone/mediastreamer2/src/msrtp.c new file mode 100644 index 000000000..58f5353a6 --- /dev/null +++ b/linphone/mediastreamer2/src/msrtp.c @@ -0,0 +1,441 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msrtp.h" +#include "mediastreamer2/msticker.h" + +#include "ortp/telephonyevents.h" +#include "ortp/b64.h" + +struct SenderData { + RtpSession *session; + struct CandidatePair *cpair; /* table of 10 cpair */ + int round; + uint32_t tsoff; + uint32_t skip_until; + int rate; + char dtmf; + char relay_session_id[64]; + int relay_session_id_size; + unsigned int last_rsi_time; + bool_t skip; + bool_t mute_mic; +}; + +typedef struct SenderData SenderData; + +static void sender_init(MSFilter * f) +{ + SenderData *d = (SenderData *)ms_new(SenderData, 1); + + d->session = NULL; + d->cpair = NULL; + d->round = 0; + d->tsoff = 0; + d->skip_until = 0; + d->skip = FALSE; + d->rate = 8000; + d->dtmf = 0; + d->mute_mic=FALSE; + d->relay_session_id_size=0; + d->last_rsi_time=0; + f->data = d; +} + +static void sender_uninit(MSFilter * f) +{ + SenderData *d = (SenderData *) f->data; + + ms_free(d); +} + +static int sender_send_dtmf(MSFilter * f, void *arg) +{ + const char *dtmf = (const char *) arg; + SenderData *d = (SenderData *) f->data; + + ms_mutex_lock(&f->lock); + d->dtmf = dtmf[0]; + ms_mutex_unlock(&f->lock); + return 0; +} + +static int sender_set_sdpcandidates(MSFilter * f, void *arg) +{ + SenderData *d = (SenderData *) f->data; + struct CandidatePair *scs = NULL; + + if (d == NULL) + return -1; + + scs = (struct CandidatePair *) arg; + d->cpair = scs; + return 0; +} + +static int sender_set_session(MSFilter * f, void *arg) +{ + SenderData *d = (SenderData *) f->data; + RtpSession *s = (RtpSession *) arg; + PayloadType *pt = + rtp_profile_get_payload(rtp_session_get_profile(s), + rtp_session_get_send_payload_type(s)); + if (pt != NULL) { + d->rate = pt->clock_rate; + } else { + ms_warning("Sending undefined payload type ?"); + } + d->session = s; + return 0; +} + +static int sender_mute_mic(MSFilter * f, void *arg) +{ + SenderData *d = (SenderData *) f->data; + ms_filter_lock(f); + d->mute_mic=TRUE; + ms_filter_unlock(f); + return 0; +} + +static int sender_unmute_mic(MSFilter * f, void *arg) +{ + SenderData *d = (SenderData *) f->data; + ms_filter_lock(f); + d->mute_mic=FALSE; + ms_filter_unlock(f); + return 0; +} + +static int sender_set_relay_session_id(MSFilter *f, void*arg){ + SenderData *d = (SenderData *) f->data; + const char *tmp=(const char *)arg; + d->relay_session_id_size=b64_decode(tmp, strlen(tmp), d->relay_session_id, sizeof(d->relay_session_id)); + return 0; +} + +/* the goal of that function is to return a absolute timestamp closest to real time, with respect of given packet_ts, which is a relative to an undefined origin*/ +static uint32_t get_cur_timestamp(MSFilter * f, uint32_t packet_ts) +{ + SenderData *d = (SenderData *) f->data; +#if !defined(_WIN32_WCE) + uint32_t curts = (f->ticker->time * d->rate) / 1000LL; +#else + uint32_t curts = (f->ticker->time * d->rate) / ((uint64_t)1000); +#endif + int diff; + int delta = d->rate / 50; /*20 ms at 8000Hz */ + uint32_t netts; + + netts = packet_ts + d->tsoff; + diff = curts - netts; + +#ifdef AMD_HACK + if (diff > delta) { + d->tsoff = curts - packet_ts; + netts = packet_ts + d->tsoff; + ms_message("synchronizing timestamp, diff=%i", diff); + } + else if (diff < -delta) { + /* d->tsoff = curts - packet_ts; */ + /* hardware clock is going slower than sound card on my PDA... */ + } +#else + if ((diff > delta) || (diff < -(delta * 5))) { + d->tsoff = curts - packet_ts; + netts = packet_ts + d->tsoff; + ms_message("synchronizing timestamp, diff=%i", diff); + } +#endif + + /*ms_message("returned ts=%u, orig_ts=%u",netts,packet_ts); */ + return netts; +} + +static void sender_process(MSFilter * f) +{ + SenderData *d = (SenderData *) f->data; + RtpSession *s = d->session; + + struct CandidatePair *cp = d->cpair; + mblk_t *im; + uint32_t timestamp; + + if (s == NULL){ + ms_queue_flush(f->inputs[0]); + return; + } + + if (d->relay_session_id_size>0 && + ( (f->ticker->time-d->last_rsi_time)>5000 || d->last_rsi_time==0) ) { + ms_message("relay session id sent in RTCP APP"); + rtp_session_send_rtcp_APP(s,0,"RSID",d->relay_session_id,d->relay_session_id_size); + d->last_rsi_time=f->ticker->time; + } + + while ((im = ms_queue_get(f->inputs[0])) != NULL) { + mblk_t *header; + + timestamp = get_cur_timestamp(f, mblk_get_timestamp_info(im)); + ms_filter_lock(f); + if (d->dtmf != 0) { + rtp_session_send_dtmf(s, d->dtmf, timestamp); + ms_debug("RFC2833 dtmf sent."); + d->dtmf = 0; + d->skip_until = timestamp + (3 * 160); + d->skip = TRUE; + freemsg(im); + }else if (d->skip) { + ms_debug("skipping.."); + if (RTP_TIMESTAMP_IS_NEWER_THAN(timestamp, d->skip_until)) { + d->skip = FALSE; + } + freemsg(im); + }else{ + if (d->mute_mic==FALSE) + { + int pt = mblk_get_payload_type(im); + header = rtp_session_create_packet(s, 12, NULL, 0); + if (pt>0) + rtp_set_payload_type(header, pt); + rtp_set_markbit(header, mblk_get_marker_info(im)); + header->b_cont = im; + rtp_session_sendm_with_ts(s, header, timestamp); + } + else + { + freemsg(im); + } + } + ms_filter_unlock(f); + } + + /* regularly send STUN request */ + ice_sound_send_stun_request(s, cp, d->round); + d->round++; +} + +static MSFilterMethod sender_methods[] = { + {MS_RTP_SEND_MUTE_MIC, sender_mute_mic}, + {MS_RTP_SEND_UNMUTE_MIC, sender_unmute_mic}, + {MS_RTP_SEND_SET_SESSION, sender_set_session}, + {MS_RTP_SEND_SEND_DTMF, sender_send_dtmf}, + {MS_RTP_SEND_SET_CANDIDATEPAIRS, sender_set_sdpcandidates}, + {MS_RTP_SEND_SET_RELAY_SESSION_ID, sender_set_relay_session_id}, + {0, NULL} +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_rtp_send_desc = { + MS_RTP_SEND_ID, + "MSRtpSend", + "RTP output filter", + MS_FILTER_OTHER, + NULL, + 1, + 0, + sender_init, + NULL, + sender_process, + NULL, + sender_uninit, + sender_methods +}; + +#else + +MSFilterDesc ms_rtp_send_desc = { + .id = MS_RTP_SEND_ID, + .name = "MSRtpSend", + .text = "RTP output filter", + .category = MS_FILTER_OTHER, + .ninputs = 1, + .noutputs = 0, + .init = sender_init, + .process = sender_process, + .uninit = sender_uninit, + .methods = sender_methods +}; + +#endif + +struct ReceiverData { + RtpSession *session; + OrtpEvQueue *ortp_event; + struct CandidatePair *cpair; /* table of 10 cpair */ + int rate; +}; + +typedef struct ReceiverData ReceiverData; + +static void receiver_init(MSFilter * f) +{ + ReceiverData *d = (ReceiverData *)ms_new(ReceiverData, 1); + + d->ortp_event = ortp_ev_queue_new(); + d->session = NULL; + d->cpair = NULL; + d->rate = 8000; + f->data = d; +} + +static void receiver_postprocess(MSFilter * f) +{ + ReceiverData *d = (ReceiverData *) f->data; + if (d->session!=NULL && d->ortp_event!=NULL) + rtp_session_unregister_event_queue(d->session, d->ortp_event); +} + +static void receiver_uninit(MSFilter * f) +{ + ReceiverData *d = (ReceiverData *) f->data; + if (d->ortp_event!=NULL) + ortp_ev_queue_destroy(d->ortp_event); + ms_free(f->data); +} + +static int receiver_set_session(MSFilter * f, void *arg) +{ + ReceiverData *d = (ReceiverData *) f->data; + RtpSession *s = (RtpSession *) arg; + PayloadType *pt = rtp_profile_get_payload(rtp_session_get_profile(s), + rtp_session_get_recv_payload_type + (s)); + if (pt != NULL) { + d->rate = pt->clock_rate; + } else { + ms_warning("Receiving undefined payload type ?"); + } + d->session = s; + + return 0; +} + +static int receiver_set_sdpcandidates(MSFilter * f, void *arg) +{ + ReceiverData *d = (ReceiverData *) f->data; + struct CandidatePair *scs = NULL; + + if (d == NULL) + return -1; + + scs = (struct CandidatePair *) arg; + d->cpair = scs; + return 0; +} + +static void receiver_preprocess(MSFilter * f){ + ReceiverData *d = (ReceiverData *) f->data; + if (d->session){ + PayloadType *pt=rtp_profile_get_payload( + rtp_session_get_profile(d->session), + rtp_session_get_recv_payload_type(d->session)); + if (pt){ + if (pt->type!=PAYLOAD_VIDEO) + rtp_session_flush_sockets(d->session); + } + } + if (d->session!=NULL && d->ortp_event!=NULL) + rtp_session_register_event_queue(d->session, d->ortp_event); +} + +static void receiver_process(MSFilter * f) +{ + ReceiverData *d = (ReceiverData *) f->data; + mblk_t *m; + uint32_t timestamp; + + if (d->session == NULL) + return; + + timestamp = (f->ticker->time * d->rate) / ((uint64_t)1000); + while ((m = rtp_session_recvm_with_ts(d->session, timestamp)) != NULL) { + mblk_set_timestamp_info(m, rtp_get_timestamp(m)); + mblk_set_marker_info(m, rtp_get_markbit(m)); + mblk_set_payload_type(m, rtp_get_payload_type(m)); + rtp_get_payload(m,&m->b_rptr); + ms_queue_put(f->outputs[0], m); + } + + /* check received STUN request */ + if (d->ortp_event!=NULL) + { + OrtpEvent *evt = ortp_ev_queue_get(d->ortp_event); + + while (evt != NULL) { + if (ortp_event_get_type(evt) == + ORTP_EVENT_STUN_PACKET_RECEIVED) { + ice_process_stun_message(d->session, d->cpair, evt); + } + if (ortp_event_get_type(evt) == + ORTP_EVENT_TELEPHONE_EVENT) { + } + + ortp_event_destroy(evt); + evt = ortp_ev_queue_get(d->ortp_event); + } + } +} + +static MSFilterMethod receiver_methods[] = { + {MS_RTP_RECV_SET_SESSION, receiver_set_session}, + {MS_RTP_RECV_SET_CANDIDATEPAIRS, receiver_set_sdpcandidates}, + {0, NULL} +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_rtp_recv_desc = { + MS_RTP_RECV_ID, + "MSRtpRecv", + "RTP input filter", + MS_FILTER_OTHER, + NULL, + 0, + 1, + receiver_init, + receiver_preprocess, + receiver_process, + receiver_postprocess, + receiver_uninit, + receiver_methods +}; + +#else + +MSFilterDesc ms_rtp_recv_desc = { + .id = MS_RTP_RECV_ID, + .name = "MSRtpRecv", + .text = "RTP input filter", + .category = MS_FILTER_OTHER, + .ninputs = 0, + .noutputs = 1, + .init = receiver_init, + .preprocess = receiver_preprocess, + .process = receiver_process, + .postprocess=receiver_postprocess, + .uninit = receiver_uninit, + .methods = receiver_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_rtp_send_desc) +MS_FILTER_DESC_EXPORT(ms_rtp_recv_desc) diff --git a/linphone/mediastreamer2/src/mssndcard.c b/linphone/mediastreamer2/src/mssndcard.c new file mode 100644 index 000000000..caba4c99f --- /dev/null +++ b/linphone/mediastreamer2/src/mssndcard.c @@ -0,0 +1,168 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/mssndcard.h" +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +static MSSndCardManager *scm=NULL; + +static MSSndCardManager * create_manager(){ + MSSndCardManager *obj=(MSSndCardManager *)ms_new(MSSndCardManager,1); + obj->cards=NULL; + return obj; +} + +void ms_snd_card_manager_destroy(void){ + if (scm!=NULL){ + ms_list_for_each(scm->cards,(void (*)(void*))ms_snd_card_destroy); + ms_list_free(scm->cards); + } + ms_free(scm); + scm=NULL; +} + +MSSndCardManager * ms_snd_card_manager_get(void){ + if (scm==NULL) scm=create_manager(); + return scm; +} + +MSSndCard * ms_snd_card_manager_get_card(MSSndCardManager *m, const char *id){ + MSList *elem; + for (elem=m->cards;elem!=NULL;elem=elem->next){ + MSSndCard *card=(MSSndCard*)elem->data; + if (id==NULL) return card; + if (strcmp(ms_snd_card_get_string_id(card),id)==0) return card; + } + if (id!=NULL) ms_warning("no card with id %s",id); + return NULL; +} + +MSSndCard * ms_snd_card_manager_get_default_card(MSSndCardManager *m){ + /*return the first card that has the capture+playback capability */ + MSList *elem; + for (elem=m->cards;elem!=NULL;elem=elem->next){ + MSSndCard *card=(MSSndCard*)elem->data; + if (card->capabilities==(MS_SND_CARD_CAP_CAPTURE|MS_SND_CARD_CAP_PLAYBACK)) + return card; + } + return NULL; +} + +const MSList * ms_snd_card_manager_get_list(MSSndCardManager *m){ + return m->cards; +} + +void ms_snd_card_manager_add_card(MSSndCardManager *m, MSSndCard *c){ + ms_message("Card %s added",ms_snd_card_get_string_id(c)); + m->cards=ms_list_append(m->cards,c); +} + +void ms_snd_card_manager_register_desc(MSSndCardManager *m, MSSndCardDesc *desc){ + if (desc->detect!=NULL) + desc->detect(m); +} + +MSSndCard * ms_snd_card_dup(MSSndCard *card){ + MSSndCard *obj=NULL; + if (card->desc->duplicate!=NULL) + obj=card->desc->duplicate(card); + return obj; +} + +MSSndCard * ms_snd_card_new(MSSndCardDesc *desc){ + MSSndCard *obj=(MSSndCard *)ms_new(MSSndCard,1); + obj->desc=desc; + obj->name=NULL; + obj->data=NULL; + obj->id=NULL; + obj->capabilities=MS_SND_CARD_CAP_CAPTURE|MS_SND_CARD_CAP_PLAYBACK; + if (desc->init!=NULL) + desc->init(obj); + return obj; +} + +const char *ms_snd_card_get_driver_type(const MSSndCard *obj){ + return obj->desc->driver_type; +} + +const char *ms_snd_card_get_name(const MSSndCard *obj){ + return obj->name; +} + +unsigned int ms_snd_card_get_capabilities(const MSSndCard *obj){ + return obj->capabilities; +} + +const char *ms_snd_card_get_string_id(MSSndCard *obj){ + if (obj->id==NULL) obj->id=ms_strdup_printf("%s: %s",obj->desc->driver_type,obj->name); + return obj->id; +} + +void ms_snd_card_set_level(MSSndCard *obj, MSSndCardMixerElem e, int percent){ + if (obj->desc->set_level!=NULL) + obj->desc->set_level(obj,e,percent); + else ms_warning("ms_snd_card_set_capture: unimplemented by %s wrapper",obj->desc->driver_type); +} + +int ms_snd_card_get_level(MSSndCard *obj, MSSndCardMixerElem e){ + if (obj->desc->get_level!=NULL) + return obj->desc->get_level(obj,e); + else { + ms_warning("ms_snd_card_set_capture: unimplemented by %s wrapper",obj->desc->driver_type); + return -1; + } +} + +void ms_snd_card_set_capture(MSSndCard *obj, MSSndCardCapture c){ + if (obj->desc->set_capture!=NULL) + obj->desc->set_capture(obj,c); + else ms_warning("ms_snd_card_set_capture: unimplemented by %s wrapper",obj->desc->driver_type); +} + +struct _MSFilter * ms_snd_card_create_reader(MSSndCard *obj){ + if (obj->desc->create_reader!=NULL) + return obj->desc->create_reader(obj); + else ms_warning("ms_snd_card_create_reader: unimplemented by %s wrapper",obj->desc->driver_type); + return NULL; +} + +struct _MSFilter * ms_snd_card_create_writer(MSSndCard *obj){ + if (obj->desc->create_writer!=NULL) + return obj->desc->create_writer(obj); + else ms_warning("ms_snd_card_create_writer: unimplemented by %s wrapper",obj->desc->driver_type); + return NULL; +} + +void ms_snd_card_destroy(MSSndCard *obj){ + if (obj->desc->uninit!=NULL) obj->desc->uninit(obj); + if (obj->name!=NULL) ms_free(obj->name); + if (obj->id!=NULL) ms_free(obj->id); + ms_free(obj); +} + +#ifdef __linux +#ifndef __ALSA_ENABLED__ +MSSndCard * ms_alsa_card_new_custom(const char *pcmdev, const char *mixdev){ + ms_warning("Alsa support not available in this build of mediastreamer2"); + return NULL; +} +#endif +#endif diff --git a/linphone/mediastreamer2/src/msspeex.c b/linphone/mediastreamer2/src/msspeex.c new file mode 100644 index 000000000..10eb58d83 --- /dev/null +++ b/linphone/mediastreamer2/src/msspeex.c @@ -0,0 +1,565 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" + +#include + +#ifdef WIN32 +#include /* for alloca */ +#endif + +typedef struct EncState{ + int rate; + int bitrate; + int maxbitrate; + int ptime; + int vbr; + int cng; + int mode; + int frame_size; + void *state; + uint32_t ts; + MSBufferizer *bufferizer; +} EncState; + +static void enc_init(MSFilter *f){ + EncState *s=(EncState *)ms_new(EncState,1); + s->rate=8000; + s->bitrate=-1; + s->maxbitrate=-1; + s->ptime=0; + s->mode=0; + s->vbr=1; + s->cng=0; + s->frame_size=0; + s->state=0; + s->ts=0; + s->bufferizer=ms_bufferizer_new(); + f->data=s; +} + +static void enc_uninit(MSFilter *f){ + EncState *s=(EncState*)f->data; + if (s==NULL) + return; + ms_bufferizer_destroy(s->bufferizer); + if (s->state!=NULL) + speex_encoder_destroy(s->state); + ms_free(s); +} + +static void enc_preprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + const SpeexMode *mode=NULL; + int _mode=0; + + switch(s->rate){ + case 8000: + _mode = SPEEX_MODEID_NB; /* rate = 8000Hz */ + break; + case 16000: + _mode = SPEEX_MODEID_WB; /* rate = 16000Hz */ + break; + /* should be supported in the future */ + case 32000: + _mode = SPEEX_MODEID_UWB; /* rate = 32000Hz */ + break; + default: + ms_error("Unsupported rate for speex encoder (back to default rate=8000)."); + s->rate=8000; + } + /* warning: speex_lib_get_mode() is not available on speex<1.1.12 */ + mode = speex_lib_get_mode(_mode); + + if (mode==NULL) + return; + s->state=speex_encoder_init(mode); + + if (s->vbr==1) + { + if (speex_encoder_ctl(s->state,SPEEX_SET_VBR,&s->vbr)!=0){ + ms_error("Could not set vbr mode to speex encoder."); + } + /* implicit VAD */ + speex_encoder_ctl (s->state, SPEEX_SET_DTX, &s->vbr); + } + else if (s->vbr==2) + { + int vad=1; + /* VAD */ + speex_encoder_ctl (s->state, SPEEX_SET_VAD, &vad); + speex_encoder_ctl (s->state, SPEEX_SET_DTX, &vad); + } + else if (s->cng==1) + { + speex_encoder_ctl (s->state, SPEEX_SET_VAD, &s->cng); + } + + if (s->rate==8000){ + if (s->mode!=0){/* mode is set*/ + if (s->mode<=0 || s->mode>=9) + s->mode = 3; /* default mode */ + + if (s->mode==1) + s->bitrate = 2150; + else if (s->mode==2) + s->bitrate = 5950; + else if (s->mode==3) + s->bitrate = 8000; + else if (s->mode==4) + s->bitrate = 11000; + else if (s->mode==5) + s->bitrate = 15000; + else if (s->mode==6) + s->bitrate = 18200; + else if (s->mode==7) + s->bitrate = 24600; + else if (s->mode==8) + s->bitrate = 3950; + + if (s->bitrate!=-1){ + if (speex_encoder_ctl(s->state,SPEEX_SET_BITRATE,&s->bitrate)!=0){ + ms_error("Could not set bitrate %i to speex encoder.",s->bitrate); + } + } + } + } + else if (s->rate==16000){ + if (s->mode!=0){ + int q=0; + s->bitrate = -1; /* 28000; */ + if (s->mode<=0 || s->mode>=8) + s->mode = 6; /* default mode */ + /* no table exist for wide and ultra: + From libspeex/mode.c, those values seems to make sense... */ + if (s->mode<=5) + q=5; + else if (s->mode==5) + q=6; + else if (s->mode==6) + q=8; + else if (s->mode>=7) + q=10; + + if (speex_encoder_ctl(s->state,SPEEX_SET_QUALITY,&q)!=0){ + ms_error("Could not set quality %i to speex encoder.",q); + } + } + } + else + { + if (s->mode!=0){ + int q=0; + s->bitrate = -1; /* 28000; */ + if (s->mode<=0 || s->mode>=8) + s->mode = 6; /* default mode */ + /* no table exist for wide and ultra: + From libspeex/mode.c, those values seems to make sense... */ + if (s->mode<=5) + q=5; + else if (s->mode==5) + q=6; + else if (s->mode==6) + q=8; + else if (s->mode>=7) + q=10; + + if (speex_encoder_ctl(s->state,SPEEX_SET_QUALITY,&q)!=0){ + ms_error("Could not set quality %i to speex encoder.",q); + } + } + } + + if (s->maxbitrate>0){ + /* convert from network bitrate to codec bitrate:*/ + /* ((nbr/(50*8)) -20-12-8)*50*8*/ + int cbr=(((float)s->maxbitrate/(50.0*8))-20-12-8)*50*8; + if (speex_encoder_ctl(s->state,SPEEX_SET_BITRATE,&cbr)!=0){ + ms_error("Could not set maxbitrate %i to speex encoder.",s->bitrate); + } + } + if (speex_encoder_ctl(s->state,SPEEX_GET_BITRATE,&s->bitrate)!=0){ + ms_error("Could not get bitrate %i to speex encoder.",s->bitrate); + } + else ms_message("Using bitrate %i for speex encoder.",s->bitrate); + + speex_mode_query(mode,SPEEX_MODE_FRAME_SIZE,&s->frame_size); +} + +static void enc_process(MSFilter *f){ + EncState *s=(EncState*)f->data; + mblk_t *im; + int nbytes; + uint8_t *buf; + int frame_per_packet=1; + + if (s->frame_size<=0) + return; + + if (s->ptime>=20) + { + frame_per_packet = s->ptime/20; + } + + if (frame_per_packet<=0) + frame_per_packet=1; + if (frame_per_packet>7) /* 7*20 == 140 ms max */ + frame_per_packet=7; + + nbytes=s->frame_size*2; + buf=(uint8_t*)alloca(nbytes*frame_per_packet); + + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + ms_bufferizer_put(s->bufferizer,im); + } + while(ms_bufferizer_read(s->bufferizer,buf,nbytes*frame_per_packet)==nbytes*frame_per_packet){ + mblk_t *om=allocb(nbytes*frame_per_packet,0);//too large... + int k; + SpeexBits bits; + speex_bits_init(&bits); + for (k=0;kstate,(int16_t*)(buf + (k*s->frame_size*2)),&bits); + s->ts+=s->frame_size; + } + speex_bits_insert_terminator(&bits); + k=speex_bits_write(&bits, (char*)om->b_wptr, nbytes*frame_per_packet); + om->b_wptr+=k; + + mblk_set_timestamp_info(om,s->ts-s->frame_size); + ms_queue_put(f->outputs[0],om); + speex_bits_destroy(&bits); + } +} + +static void enc_postprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + speex_encoder_destroy(s->state); + s->state=NULL; +} + +static int enc_set_sr(MSFilter *f, void *arg){ + EncState *s=(EncState*)f->data; + /* TODO: should be done with fmtp parameter */ + s->rate=((int*)arg)[0]; + return 0; +} + +static int enc_set_br(MSFilter *f, void *arg){ + EncState *s=(EncState*)f->data; + s->maxbitrate=((int*)arg)[0]; + return 0; +} + +static int enc_add_fmtp(MSFilter *f, void *arg){ + char buf[64]; + const char *fmtp=(const char *)arg; + EncState *s=(EncState*)f->data; + + memset(buf, '\0', sizeof(buf)); + fmtp_get_value(fmtp, "sr", buf, sizeof(buf)); + if (buf[0]=='\0'){ + } + else { + s->rate = atoi(buf); + } + + memset(buf, '\0', sizeof(buf)); + fmtp_get_value(fmtp, "ebw", buf, sizeof(buf)); + if (buf[0]=='\0'){ + } + else if (strstr(buf,"narrow")!=NULL){ + s->rate = 8000; + } + else if (strstr(buf,"wide")!=NULL){ + s->rate = 16000; + } + else if (strstr(buf,"ultra")!=NULL){ + s->rate = 32000; + } + + memset(buf, '\0', sizeof(buf)); + fmtp_get_value(fmtp, "vbr", buf, sizeof(buf)); + if (buf[0]=='\0'){ + } + else if (strstr(buf,"off")!=NULL){ + s->vbr=0; + } + else if (strstr(buf,"on")!=NULL){ + s->vbr=1; + } + else if (strstr(buf,"vad")!=NULL){ + s->vbr=2; + } + + memset(buf, '\0', sizeof(buf)); + fmtp_get_value(fmtp, "cng", buf, sizeof(buf)); + if (buf[0]=='\0'){ + } + else if (strstr(buf,"off")!=NULL){ + s->cng=0; + } + else if (strstr(buf,"on")!=NULL){ + s->vbr=1; + } + + memset(buf, '\0', sizeof(buf)); + fmtp_get_value(fmtp, "mode", buf, sizeof(buf)); + if (buf[0]=='\0'){ + } + else if (strstr(buf,"any")!=NULL){ + s->mode=10; + } + else { + s->mode = atoi(buf); + if (s->mode<=0 || s->mode>=8) + s->mode = 3; + } + return 0; +} + +static int enc_add_attr(MSFilter *f, void *arg){ + const char *fmtp=(const char *)arg; + EncState *s=(EncState*)f->data; + if (strstr(fmtp,"ptime:10")!=NULL){ + s->ptime=20; + }else if (strstr(fmtp,"ptime:20")!=NULL){ + s->ptime=20; + }else if (strstr(fmtp,"ptime:30")!=NULL){ + s->ptime=40; /* not allowed */ + }else if (strstr(fmtp,"ptime:40")!=NULL){ + s->ptime=40; + }else if (strstr(fmtp,"ptime:50")!=NULL){ + s->ptime=60; + }else if (strstr(fmtp,"ptime:60")!=NULL){ + s->ptime=60; + }else if (strstr(fmtp,"ptime:70")!=NULL){ + s->ptime=80; + }else if (strstr(fmtp,"ptime:80")!=NULL){ + s->ptime=80; + }else if (strstr(fmtp,"ptime:90")!=NULL){ + s->ptime=100; /* not allowed */ + }else if (strstr(fmtp,"ptime:100")!=NULL){ + s->ptime=100; + }else if (strstr(fmtp,"ptime:110")!=NULL){ + s->ptime=120; + }else if (strstr(fmtp,"ptime:120")!=NULL){ + s->ptime=120; + }else if (strstr(fmtp,"ptime:130")!=NULL){ + s->ptime=140; + }else if (strstr(fmtp,"ptime:140")!=NULL){ + s->ptime=140; + } + return 0; +} + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , enc_set_sr }, + { MS_FILTER_SET_BITRATE , enc_set_br }, + { MS_FILTER_ADD_FMTP , enc_add_fmtp }, + { MS_FILTER_ADD_ATTR , enc_add_attr}, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_speex_enc_desc={ + MS_SPEEX_ENC_ID, + "MSSpeexEnc", + "The free and wonderful speex codec", + MS_FILTER_ENCODER, + "speex", + 1, + 1, + enc_init, + enc_preprocess, + enc_process, + enc_postprocess, + enc_uninit, + enc_methods +}; + +#else + +MSFilterDesc ms_speex_enc_desc={ + .id=MS_SPEEX_ENC_ID, + .name="MSSpeexEnc", + .text="The free and wonderful speex codec", + .category=MS_FILTER_ENCODER, + .enc_fmt="speex", + .ninputs=1, + .noutputs=1, + .init=enc_init, + .preprocess=enc_preprocess, + .postprocess=enc_postprocess, + .process=enc_process, + .uninit=enc_uninit, + .methods=enc_methods +}; + +#endif + +typedef struct DecState{ + int rate; + int penh; + int frsz; + void *state; +} DecState; + +static void dec_init(MSFilter *f){ + DecState *s=(DecState *)ms_new(DecState,1); + s->rate=8000; + s->frsz=0; + s->state=NULL; + s->penh=1; + f->data=s; +} + +static void dec_uninit(MSFilter *f){ + DecState *s=(DecState*)f->data; + if (s==NULL) + return; + if (s->state!=NULL) + speex_decoder_destroy(s->state); + ms_free(s); +} + +static void dec_preprocess(MSFilter *f){ + DecState *s=(DecState*)f->data; + const SpeexMode *mode=NULL; + int modeid; + switch(s->rate){ + case 8000: + modeid = SPEEX_MODEID_NB; /* rate = 8000Hz */ + break; + case 16000: + modeid = SPEEX_MODEID_WB; /* rate = 16000Hz */ + break; + /* should be supported in the future */ + case 32000: + modeid = SPEEX_MODEID_UWB; /* rate = 32000Hz */ + break; + default: + ms_error("Unsupported rate for speex decoder (back to default rate=8000)."); + modeid=SPEEX_MODEID_NB; + } + /* warning: speex_lib_get_mode() is not available on speex<1.1.12 */ + mode = speex_lib_get_mode(modeid); + s->state=speex_decoder_init(mode); + speex_mode_query(mode,SPEEX_MODE_FRAME_SIZE,&s->frsz); + if (s->penh==1) + speex_decoder_ctl (s->state, SPEEX_SET_ENH, &s->penh); +} + +static void dec_postprocess(MSFilter *f){ + DecState *s=(DecState*)f->data; + speex_decoder_destroy(s->state); + s->state=NULL; +} + +static int dec_set_sr(MSFilter *f, void *arg){ + DecState *s=(DecState*)f->data; + s->rate=((int*)arg)[0]; + return 0; +} + +static void dec_process(MSFilter *f){ + DecState *s=(DecState*)f->data; + mblk_t *im; + mblk_t *om; + int err; + int frame_per_packet; + SpeexBits bits; + int bytes=s->frsz*2; + speex_bits_init(&bits); + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + speex_bits_reset(&bits); + speex_bits_read_from(&bits,(char*)im->b_rptr,im->b_wptr-im->b_rptr); + om=allocb(bytes*7,0); + /* support for multiple frame (max=7 frames???) in one RTP packet */ + for (frame_per_packet=0;frame_per_packet<7;frame_per_packet++) + { + int i; + err=speex_decode_int(s->state,&bits,(int16_t*)(om->b_wptr+(frame_per_packet*320))); + + i = speex_bits_remaining(&bits); + if (i<10) /* this seems to work: don't know why. */ + break; + } + if (err==0){ + om->b_wptr+=bytes*(frame_per_packet+1); + ms_queue_put(f->outputs[0],om); + }else { + if (err==-1) + ms_warning("speex end of stream"); + else if (err==-2) + ms_warning("speex corrupted stream"); + freemsg(om); + } + freemsg(im); + } + speex_bits_destroy(&bits); +} + +static MSFilterMethod dec_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , dec_set_sr }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_speex_dec_desc={ + MS_SPEEX_DEC_ID, + "MSSpeexDec", + "The free and wonderful speex codec", + MS_FILTER_DECODER, + "speex", + 1, + 1, + dec_init, + dec_preprocess, + dec_process, + dec_postprocess, + dec_uninit, + dec_methods +}; + +#else + +MSFilterDesc ms_speex_dec_desc={ + .id=MS_SPEEX_DEC_ID, + .name="MSSpeexDec", + .text="The free and wonderful speex codec", + .category=MS_FILTER_DECODER, + .enc_fmt="speex", + .ninputs=1, + .noutputs=1, + .init=dec_init, + .preprocess=dec_preprocess, + .postprocess=dec_postprocess, + .process=dec_process, + .uninit=dec_uninit, + .methods=dec_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_speex_dec_desc) +MS_FILTER_DESC_EXPORT(ms_speex_enc_desc) diff --git a/linphone/mediastreamer2/src/msticker.c b/linphone/mediastreamer2/src/msticker.c new file mode 100644 index 000000000..0f8a336d6 --- /dev/null +++ b/linphone/mediastreamer2/src/msticker.c @@ -0,0 +1,468 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + + +#include "mediastreamer2/msticker.h" + + +void * ms_ticker_run(void *s); +static uint64_t get_cur_time(void *); + +void ms_ticker_start(MSTicker *s){ + s->run=TRUE; + ms_thread_create(&s->thread,NULL,ms_ticker_run,s); +} + + +void ms_ticker_init(MSTicker *ticker) +{ + ms_mutex_init(&ticker->lock,NULL); + ticker->execution_list=NULL; + ticker->ticks=1; + ticker->time=0; + ticker->interval=10; + ticker->run=FALSE; + ticker->exec_id=0; + ticker->get_cur_time_ptr=&get_cur_time; + ticker->get_cur_time_data=NULL; +#ifdef WIN32_TIMERS + ticker->TimeEvent=NULL; +#endif + ms_ticker_start(ticker); +} + +MSTicker *ms_ticker_new(){ + MSTicker *obj=(MSTicker *)ms_new(MSTicker,1); + ms_ticker_init(obj); + return obj; +} + +void ms_ticker_stop(MSTicker *s){ + ms_mutex_lock(&s->lock); + s->run=FALSE; + ms_mutex_unlock(&s->lock); + ms_thread_join(s->thread,NULL); +} + + +void ms_ticker_uninit(MSTicker *ticker) +{ + ms_ticker_stop(ticker); + ms_mutex_destroy(&ticker->lock); +} + +void ms_ticker_destroy(MSTicker *ticker){ + ms_ticker_uninit(ticker); + ms_free(ticker); +} + +static void find_filters(MSList **filters, MSFilter *f ){ + int i; + MSQueue *link; + if (f==NULL) ms_fatal("Bad graph."); + /*ms_message("seeing %s, seen=%i",f->desc->name,f->seen);*/ + if (f->seen){ + return; + } + f->seen=TRUE; + *filters=ms_list_append(*filters,f); + /* go upstream */ + for(i=0;idesc->ninputs;i++){ + link=f->inputs[i]; + if (link!=NULL) find_filters(filters,link->prev.filter); + } + /* go downstream */ + for(i=0;idesc->noutputs;i++){ + link=f->outputs[i]; + if (link!=NULL) find_filters(filters,link->next.filter); + } +} + +static MSList *get_sources(MSList *filters){ + MSList *sources=NULL; + MSFilter *f; + for(;filters!=NULL;filters=filters->next){ + f=(MSFilter*)filters->data; + if (f->desc->ninputs==0){ + sources=ms_list_append(sources,f); + } + } + return sources; +} + +int ms_ticker_attach(MSTicker *ticker,MSFilter *f) +{ + MSList *sources=NULL; + MSList *filters=NULL; + MSList *it; + + if (f->ticker!=NULL) { + ms_message("Filter %s is already being scheduled; nothing to do.",f->desc->name); + return 0; + } + + find_filters(&filters,f); + sources=get_sources(filters); + if (sources==NULL){ + ms_fatal("No sources found around filter %s",f->desc->name); + ms_list_free(filters); + return -1; + } + /*run preprocess on each filter: */ + for(it=filters;it!=NULL;it=it->next) + ms_filter_preprocess((MSFilter*)it->data,ticker); + ms_mutex_lock(&ticker->lock); + ticker->execution_list=ms_list_concat(ticker->execution_list,sources); + ms_mutex_unlock(&ticker->lock); + ms_list_free(filters); + return 0; +} + + + +int ms_ticker_detach(MSTicker *ticker,MSFilter *f){ + MSList *sources=NULL; + MSList *filters=NULL; + MSList *it; + + if (f->ticker==NULL) { + ms_message("Filter %s is not scheduled; nothing to do.",f->desc->name); + return 0; + } + + ms_mutex_lock(&ticker->lock); + + find_filters(&filters,f); + sources=get_sources(filters); + if (sources==NULL){ + ms_fatal("No sources found around filter %s",f->desc->name); + ms_list_free(filters); + ms_mutex_unlock(&ticker->lock); + return -1; + } + + for(it=sources;it!=NULL;it=ms_list_next(it)){ + ticker->execution_list=ms_list_remove(ticker->execution_list,it->data); + } + ms_mutex_unlock(&ticker->lock); + ms_list_for_each(filters,(void (*)(void*))ms_filter_postprocess); + ms_list_free(filters); + ms_list_free(sources); + return 0; +} + + +static bool_t filter_can_process(MSFilter *f, int tick){ + /* look if filters before this one have run */ + int i; + MSQueue *l; + for(i=0;idesc->ninputs;i++){ + l=f->inputs[i]; + if (l!=NULL){ + if (l->prev.filter->last_tick!=tick) return FALSE; + } + } + return TRUE; +} + +static void call_process(MSFilter *f){ + bool_t process_done=FALSE; + if (f->desc->ninputs==0){ + ms_filter_process(f); + }else{ + while (ms_filter_inputs_have_data(f)) { + if (process_done){ + ms_warning("Re-scheduling filter %s: all data should be consumed in one process call, so fix it.",f->desc->name); + } + ms_filter_process(f); + process_done=TRUE; + } + } +} + +static void run_graph(MSFilter *f, MSTicker *s, MSList **unschedulable, bool_t force_schedule){ + int i; + MSQueue *l; + if (f->last_tick!=s->ticks ){ + if (filter_can_process(f,s->ticks) || force_schedule) { + /* this is a candidate */ + f->last_tick=s->ticks; + call_process(f); + /* now recurse to next filters */ + for(i=0;idesc->noutputs;i++){ + l=f->outputs[i]; + if (l!=NULL){ + run_graph(l->next.filter,s,unschedulable, force_schedule); + } + } + }else{ + /* this filter has not all inputs that have been filled by filters before it. */ + *unschedulable=ms_list_prepend(*unschedulable,f); + } + } +} + +static void run_graphs(MSTicker *s, MSList *execution_list, bool_t force_schedule){ + MSList *it; + MSList *unschedulable=NULL; + for(it=execution_list;it!=NULL;it=it->next){ + run_graph((MSFilter*)it->data,s,&unschedulable,force_schedule); + } + /* filters that are part of a loop haven't been called in process() because one of their input refers to a filter that could not be scheduled (because they could not be scheduled themselves)... Do you understand ?*/ + /* we resolve this by simply assuming that they must be called anyway + for the loop to run correctly*/ + /* we just recall run_graphs on them, as if they were source filters */ + if (unschedulable!=NULL) { + run_graphs(s,unschedulable,TRUE); + ms_list_free(unschedulable); + } +} + +#ifdef __MACH__ +#include +#include +#endif + +static uint64_t get_cur_time(void *unused){ +#if defined(_WIN32_WCE) + DWORD timemillis = GetTickCount(); + return timemillis; +#elif defined(WIN32) + return timeGetTime() ; +#elif defined(__MACH__) && defined(__GNUC__) && (__GNUC__ >= 3) + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec*1000LL) + (tv.tv_usec/1000LL); +#elif defined(__MACH__) + struct timespec ts; + struct timeb time_val; + + ftime (&time_val); + ts.tv_sec = time_val.time; + ts.tv_nsec = time_val.millitm * 1000000; + return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL); +#else + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME,&ts)<0){ + ms_fatal("clock_gettime() doesn't work: %s",strerror(errno)); + } + return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL); +#endif +} + +static void sleepMs(int ms){ +#ifdef WIN32 + Sleep(ms); +#else + struct timespec ts; + ts.tv_sec=0; + ts.tv_nsec=ms*1000000LL; + nanosleep(&ts,NULL); +#endif +} + +static int set_high_prio(void){ + int precision=2; +#ifdef WIN32 + MMRESULT mm; + TIMECAPS ptc; + mm=timeGetDevCaps(&ptc,sizeof(ptc)); + if (mm==0){ + if (ptc.wPeriodMinticks=1; + ms_mutex_lock(&s->lock); + s->orig=s->get_cur_time_ptr(s->get_cur_time_data); + + while(s->run){ + s->ticks++; + run_graphs(s,s->execution_list,FALSE); + s->time+=s->interval; + while(1){ + realtime=s->get_cur_time_ptr(s->get_cur_time_data)-s->orig; + ms_mutex_unlock(&s->lock); + diff=s->time-realtime; + if (diff>0){ + /* sleep until next tick */ + sleepMs(diff); + }else{ + late=-diff; + if (late>s->interval*5 && late>lastlate){ + ms_warning("We are late of %d miliseconds.",late); + } + lastlate=late; + break; /*exit the while loop */ + } + ms_mutex_lock(&s->lock); + } + ms_mutex_lock(&s->lock); + } + ms_mutex_unlock(&s->lock); + unset_high_prio(precision); + ms_message("MSTicker thread exiting"); + + ms_thread_exit(NULL); + return NULL; +} + +#else + +void * ms_ticker_run(void *arg) +{ + MSTicker *s=(MSTicker*)arg; + uint64_t realtime; + int precision=2; + UINT timerId; + + precision = set_high_prio(); + + s->TimeEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + + s->ticks=1; + ms_mutex_lock(&s->lock); + s->orig=s->get_cur_time_ptr(s->get_cur_time_data); + + timerId = timeSetEvent (s->interval, precision, s->TimeEvent, 0, + TIME_PERIODIC | TIME_CALLBACK_EVENT_SET); + while(s->run){ + DWORD err; + + s->ticks++; + run_graphs(s,s->execution_list,FALSE); + + /* elapsed time since origin */ + s->time = s->get_cur_time_ptr(s->get_cur_time_data)- s->orig; + + ms_mutex_unlock(&s->lock); + err = WaitForSingleObject (s->TimeEvent, s->interval*1000 ); /* wake up each diff */ + if (err==WAIT_FAILED) + ms_message("WaitForSingleObject is failing"); + + ms_mutex_lock(&s->lock); + } + ms_mutex_unlock(&s->lock); + timeKillEvent (timerId); + CloseHandle (s->TimeEvent); + s->TimeEvent=NULL; + unset_high_prio(precision); + ms_message("MSTicker thread exiting"); + ms_thread_exit(NULL); + return NULL; +} + +#endif + +void ms_ticker_set_time_func(MSTicker *ticker, MSTickerTimeFunc func, void *user_data){ + if (func==NULL) func=get_cur_time; + /*ms_mutex_lock(&ticker->lock);*/ + ticker->get_cur_time_ptr=func; + ticker->get_cur_time_data=user_data; + /*re-set the origin to take in account that previous function ptr and the + new one may return different times*/ + ticker->orig=func(user_data)-ticker->time; + /*ms_mutex_unlock(&ticker->lock);*/ + ms_message("ms_ticker_set_time_func: ticker updated."); +} + +static void print_graph(MSFilter *f, MSTicker *s, MSList **unschedulable, bool_t force_schedule){ + int i; + MSQueue *l; + if (f->last_tick!=s->ticks ){ + if (filter_can_process(f,s->ticks) || force_schedule) { + /* this is a candidate */ + f->last_tick=s->ticks; + ms_message("print_graphs: %s", f->desc->name); + /* now recurse to next filters */ + for(i=0;idesc->noutputs;i++){ + l=f->outputs[i]; + if (l!=NULL){ + print_graph(l->next.filter,s,unschedulable, force_schedule); + } + } + }else{ + /* this filter has not all inputs that have been filled by filters before it. */ + *unschedulable=ms_list_prepend(*unschedulable,f); + } + } +} + +static void print_graphs(MSTicker *s, MSList *execution_list, bool_t force_schedule){ + MSList *it; + MSList *unschedulable=NULL; + for(it=execution_list;it!=NULL;it=it->next){ + print_graph((MSFilter*)it->data,s,&unschedulable,force_schedule); + } + /* filters that are part of a loop haven't been called in process() because one of their input refers to a filter that could not be scheduled (because they could not be scheduled themselves)... Do you understand ?*/ + /* we resolve this by simply assuming that they must be called anyway + for the loop to run correctly*/ + /* we just recall run_graphs on them, as if they were source filters */ + if (unschedulable!=NULL) { + print_graphs(s,unschedulable,TRUE); + ms_list_free(unschedulable); + } +} + +void ms_ticker_print_graphs(MSTicker *ticker){ + print_graphs(ticker,ticker->execution_list,FALSE); +} diff --git a/linphone/mediastreamer2/src/msv4l.c b/linphone/mediastreamer2/src/msv4l.c new file mode 100644 index 000000000..07e9e123d --- /dev/null +++ b/linphone/mediastreamer2/src/msv4l.c @@ -0,0 +1,1034 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef __linux + +#include "mediastreamer-config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_LINUX_VIDEODEV2_H +#include +#endif + +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msv4l.h" +#include "mediastreamer2/mswebcam.h" +#include "nowebcam.h" + +/* From: Logitech QuickCam USB driver */ +#define QC_IOCTLBASE 220 +/* Get enable workaround for bugs, bitfield */ +#define VIDIOCQCGCOMPATIBLE _IOR ('v',QC_IOCTLBASE+10,int) +/* Set enable workaround for bugs, bitfield */ +#define VIDIOCQCSCOMPATIBLE _IOWR('v',QC_IOCTLBASE+10,int) + +#ifndef VIDIOSFPS +#define VIDIOSFPS _IOW('v',BASE_VIDIOCPRIVATE+20, int) +#endif + +typedef struct V4lState{ + int fd; + ms_thread_t thread; + char *dev; + char *mmapdbuf; + int msize;/*mmapped size*/ + MSVideoSize vsize; + MSVideoSize got_vsize; + int pix_fmt; + int int_pix_fmt; /*internal pixel format */ + mblk_t *frames[VIDEO_MAX_FRAME]; + mblk_t *mire; + queue_t rq; + ms_mutex_t mutex; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + int queued; + bool_t run; + bool_t usemire; + bool_t v4lv2; /*we interface with a V4Lv2 driver */ + bool_t force_v1; + bool_t auto_started; +}V4lState; + +static void *v4l_thread(void *s); +static int v4l_configure(V4lState *s); + +#ifdef HAVE_LINUX_VIDEODEV2_H + +static bool_t v4lv2_try_format(V4lState *s, int fmtid){ + struct v4l2_format fmt; + + memset(&fmt,0,sizeof(fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = s->vsize.width; + fmt.fmt.pix.height = s->vsize.height; + fmt.fmt.pix.pixelformat = fmtid; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + + if (ioctl (s->fd, VIDIOC_S_FMT, &fmt)<0){ + return FALSE; + } + s->got_vsize.width=s->vsize.width; + s->got_vsize.height=s->vsize.height; + return TRUE; +} + +static int v4lv2_configure(V4lState *s) +{ + struct v4l2_capability cap; + + if (ioctl (s->fd, VIDIOC_QUERYCAP, &cap)<0) { + ms_message("Not a v4lv2 driver."); + return -1; + } + + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + ms_error("%s is not a video capture device\n",s->dev); + return -1; + } + + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + ms_error("%s does not support streaming i/o\n",s->dev); + return -1; + } + + if (v4lv2_try_format(s,V4L2_PIX_FMT_YUV420)){ + s->pix_fmt=MS_YUV420P; + s->int_pix_fmt=V4L2_PIX_FMT_YUV420; + ms_message("v4lv2: YUV420P choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_NV12)){ + s->pix_fmt=MS_YUV420P; + s->int_pix_fmt=V4L2_PIX_FMT_NV12; + ms_message("v4lv2: V4L2_PIX_FMT_NV12 choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_MJPEG)){ + s->pix_fmt=MS_MJPEG; + s->int_pix_fmt=V4L2_PIX_FMT_MJPEG; + ms_message("v4lv2: MJPEG choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_YUYV)){ + s->pix_fmt=MS_YUYV; + s->int_pix_fmt=V4L2_PIX_FMT_YUYV; + ms_message("v4lv2: V4L2_PIX_FMT_YUYV choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_RGB24)){ + s->pix_fmt=MS_RGB24; + s->int_pix_fmt=V4L2_PIX_FMT_RGB24; + ms_message("v4lv2: RGB24 choosen"); + }else{ + ms_error("Could not find supported pixel format."); + return -1; + } + return 0; +} + +static int v4lv2_do_mmap(V4lState *s){ + struct v4l2_requestbuffers req; + int i; + enum v4l2_buf_type type; + + memset(&req,0,sizeof(req)); + + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (ioctl (s->fd, VIDIOC_REQBUFS, &req)<0) { + ms_error("Error requesting info on mmap'd buffers: %s",strerror(errno)); + return -1; + } + + for (i=0; ifd, VIDIOC_QUERYBUF, &buf)<0){ + ms_error("Could not VIDIOC_QUERYBUF : %s",strerror(errno)); + return -1; + } + + start=mmap (NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + s->fd, buf.m.offset); + + if (start==NULL){ + ms_error("Could not mmap: %s",strerror(errno)); + } + msg=esballoc(start,buf.length,0,NULL); + /* adjust to real size of picture*/ + if (s->pix_fmt==MS_RGB24) + msg->b_wptr+=s->vsize.width*s->vsize.height*3; + else + msg->b_wptr+=(s->vsize.width*s->vsize.height*3)/2; + + s->frames[i]=msg; + } + s->frame_max=req.count; + /* + for (i = 0; i < s->frame_max; ++i) { + struct v4l2_buffer buf; + + memset(&buf,0,sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + if (-1==ioctl (s->fd, VIDIOC_QBUF, &buf)){ + ms_error("VIDIOC_QBUF failed: %s",strerror(errno)); + } + } + */ + /*start capture immediately*/ + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 ==ioctl (s->fd, VIDIOC_STREAMON, &type)){ + ms_error("VIDIOC_STREAMON failed: %s",strerror(errno)); + return -1; + } + return 0; +} + +static mblk_t * v4lv2_grab_image(V4lState *s){ + struct v4l2_buffer buf; + unsigned int k; + memset(&buf,0,sizeof(buf)); + mblk_t *ret=NULL; + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + if (s->queued){ + if (ioctl(s->fd, VIDIOC_DQBUF, &buf)<0) { + switch (errno) { + case EAGAIN: + case EIO: + /* Could ignore EIO, see spec. */ + break; + default: + ms_warning("VIDIOC_DQBUF failed: %s",strerror(errno)); + } + }else{ + if (buf.index >= s->frame_max){ + ms_error("buf.index>=s->max_frames !"); + return NULL; + } + s->queued--; + /*decrement ref count of dequeued buffer */ + ret=s->frames[buf.index]; + ret->b_datap->db_ref--; + if (buf.bytesused<=30){ + ms_warning("Ignoring empty buffer..."); + return NULL; + } + } + } + + /*queue buffers whose ref count has dropped to 1, because they are not + still used anywhere in the filter chain */ + for(k=0;kframe_max;++k){ + if (s->frames[k]->b_datap->db_ref==1){ + buf.index=k; + if (-1==ioctl (s->fd, VIDIOC_QBUF, &buf)) + ms_warning("VIDIOC_QBUF %i failed: %s",k, strerror(errno)); + else { + /*increment ref count of queued buffer*/ + s->frames[k]->b_datap->db_ref++; + s->queued++; + } + } + } + return ret; +} + +#endif + +static void v4l_init(MSFilter *f){ + V4lState *s=ms_new0(V4lState,1); + s->fd=-1; + s->run=FALSE; + s->v4lv2=FALSE; + s->mmapdbuf=NULL; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + s->pix_fmt=MS_RGB24; + s->dev=ms_strdup("/dev/video0"); + qinit(&s->rq); + s->mire=NULL; + ms_mutex_init(&s->mutex,NULL); + s->start_time=0; + s->frame_count=-1; + s->fps=15; + s->usemire=(getenv("DEBUG")!=NULL); + s->queued=0; + s->force_v1=FALSE; + s->auto_started=FALSE; + f->data=s; +} + +/* we try not to close the /dev/videoX device to workaround a bug of linux kernel. +The bug is this one: +One thread opens /dev/videoX, and mmap()s some pages to get data from the camera. +Then several threads are created (using clone) and automatically get a reference to the mmap'd page, thus a reference to the file_struct of the opened file descriptor. +Then when the first thread closes and unmap() the file descriptor, the .release method of the driver is not called because there are still some threads owning the reference to the mmap'd pages. +As far as I understand. +If all threads are correctly pthread_join()ed, then the file descriptor is closed correctly. +But unfortunately when using alsa dmix/asym plugins, some threads are started by those plugins and are kept alive (or zombie) for some time after the mmap()/close(). +*/ + +static int v4l_fd=-1; +static bool_t reuse_fd=FALSE; +static char *v4l_devname=NULL; + +static int v4l_start(MSFilter *f, void *arg) +{ + V4lState *s=(V4lState*)f->data; + int err=0; + if (v4l_fd>=0 && reuse_fd){ + if (strcmp(v4l_devname,s->dev)==0 ){ + /*use this one!*/ + ms_message("v4l_start: reusing previous file descriptor."); + s->fd=v4l_fd; + }else{ + ms_message("closing cached fd"); + close(v4l_fd); + v4l_fd=-1; + ms_free(v4l_devname); + v4l_devname=NULL; + } + } + if (s->fd==-1){ + s->fd=open(s->dev,O_RDWR); + ms_message("v4l_start: open, fd=%i",s->fd); + if (s->fd>=0){ + v4l_fd=s->fd; + v4l_devname=ms_strdup(s->dev); + } + } + if (s->fd<0){ + ms_error("MSV4l: cannot open video device (%s): %s.",s->dev,strerror(errno)); + if (!s->usemire){ + s->pix_fmt=MS_YUV420P; + s->fps=1; + } + return -1; + }else{ +#ifdef HAVE_LINUX_VIDEODEV2_H + if (s->force_v1 || v4lv2_configure(s)<0) {/*might not be V4LV2 */ +#else + if (1){ +#endif + struct video_capability vidcap; + err=v4l_configure(s); + if (err<0) + { + ms_error("MSV4l: could not get configuration of video device"); + close(s->fd); + s->fd=-1; + return -1; + } + if (!s->force_v1) reuse_fd=TRUE; + + err=ioctl(s->fd, VIDIOCGCAP, &vidcap); + if (err==0) + { + ms_message("MSV4l: Webcam is %s.", vidcap.name); + if (strcasecmp(vidcap.name, "Logitech QuickCam USB")==0) + { + int comp_arg=0; + err=ioctl(s->fd, VIDIOCQCSCOMPATIBLE, &comp_arg); + if (err==0) + { + ms_message("MSV4l: compatibility mode disabled for %s.", vidcap.name); + } + } + } + }else{ + ms_message("Device is a video4linux V2 one."); + s->v4lv2=TRUE; + reuse_fd=FALSE; + } + } + return 0; +} + +static void v4l_start_capture(V4lState *s){ + if (s->fd>=0){ + s->run=TRUE; + ms_thread_create(&s->thread,NULL,v4l_thread,s); + } +} + +static int v4l_stop(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + if (s->fd>=0){ + if (!reuse_fd){ + if (close(s->fd)<0){ + ms_warning("MSV4l: Could not close(): %s",strerror(errno)); + } + ms_message("v4l fd %i closed",s->fd); + } + s->fd=-1; + s->frame_count=-1; + } + return 0; +} + +static void v4l_stop_capture(V4lState *s){ + if (s->run){ + s->run=FALSE; + ms_thread_join(s->thread,NULL); + ms_message("v4l thread has joined."); + flushq(&s->rq,0); + } +} + + +static void v4l_uninit(MSFilter *f){ + V4lState *s=(V4lState*)f->data; + if (s->fd>=0) v4l_stop(f,NULL); + ms_free(s->dev); + flushq(&s->rq,0); + ms_mutex_destroy(&s->mutex); + freemsg(s->mire); + ms_free(s); +} + +static bool_t try_format(int fd, struct video_picture *pict, int palette, int depth){ + int err; + pict->palette=palette; + pict->depth=depth; + err=ioctl(fd,VIDIOCSPICT,pict); + if (err<0){ + ms_warning("Could not set picture properties: %s",strerror(errno)); + return FALSE; + } + return TRUE; +} + +static int v4l_do_mmap(V4lState *s){ + struct video_mbuf vmbuf; + int err,i; + memset(&vmbuf,0,sizeof(vmbuf)); + /* try to get mmap properties */ + err=ioctl(s->fd,VIDIOCGMBUF,&vmbuf); + if (err<0){ + ms_error("Could not get mmap properties: %s",strerror(errno)); + return -1; + }else { + if (vmbuf.size>0){ + /* do the mmap */ + s->msize=vmbuf.size; + s->frame_max=vmbuf.frames; + } else { + ms_error("This device cannot support mmap."); + return -1; + } + } + s->mmapdbuf=mmap(NULL,s->msize,PROT_READ,MAP_SHARED,s->fd,0); + if (s->mmapdbuf==(void*)-1) { + /* for non-mmu arch */ + s->mmapdbuf=mmap(NULL,s->msize,PROT_READ,MAP_PRIVATE,s->fd,0); + if (s->mmapdbuf==(void*)-1) { + ms_error("Could not mmap: %s",strerror(errno)); + s->mmapdbuf=NULL; + return -1; + } + } + /* initialize the mediastreamer buffers */ + ms_message("Using %i-frames mmap'd buffer at %p, len %i", + s->frame_max, s->mmapdbuf,s->msize); + for(i=0;iframe_max;i++){ + mblk_t *buf=esballoc((uint8_t*)s->mmapdbuf+vmbuf.offsets[i],vmbuf.offsets[1],0,NULL); + /* adjust to real size of picture*/ + if (s->pix_fmt==MS_RGB24) + buf->b_wptr+=s->vsize.width*s->vsize.height*3; + else + buf->b_wptr+=(s->vsize.width*s->vsize.height*3)/2; + s->frames[i]=buf; + } + s->frame_ind=0; + return 0; +} + +static bool_t try_size(V4lState *s, MSVideoSize vsize){ + struct video_window win; + int err; + memset(&win,0,sizeof(win)); + /*set picture size */ + win.x=win.y=0; + win.width=vsize.width; + win.height=vsize.height; + win.flags=0; + win.clips=NULL; + win.clipcount=0; + + ms_message("Trying to set capture size to %ix%i", vsize.width,vsize.height); + err=ioctl(s->fd,VIDIOCSWIN,&win); + if (err<0){ + ms_warning("Could not set window size: %s",strerror(errno)); + return FALSE; + } + + err=ioctl(s->fd, VIDIOCGWIN, &win); + if (err<0){ + ms_warning("Could not get window size: %s",strerror(errno)); + return FALSE; + } + s->vsize.width=vsize.width; + s->vsize.height=vsize.height; + + if (s->vsize.width!=win.width || s->vsize.height!=win.height){ + ms_warning("Capture size is not what we expected: asked for %ix%i and get %ix%i",s->vsize.width,s->vsize.height, win.width, win.height); + } + s->got_vsize.width=win.width; + s->got_vsize.height=win.height; + ms_message("Capture size set to %ix%i", s->got_vsize.width,s->got_vsize.height); + return TRUE; +} + +static int v4l_configure(V4lState *s) +{ + struct video_channel chan; + struct video_picture pict; + struct video_capability cap; + int err; + int i; + int fps = 0; + int found=0; + + memset(&chan,0,sizeof(chan)); + memset(&pict,0,sizeof(pict)); + memset(&cap,0,sizeof(cap)); + + err=ioctl(s->fd,VIDIOCGCAP,&cap); + if (err!=0) + { + ms_warning("MSV4l: cannot get device capabilities: %s.",strerror(errno)); + return -1; + } + + ms_message("Found %s device. (maxsize=%ix%i)",cap.name, cap.maxwidth, cap.maxheight); + for (i=0;ifd,VIDIOCGCHAN,&chan); + if (err==0) + { + ms_message("Getting video channel %s",chan.name); + switch(chan.type){ + case VIDEO_TYPE_TV: + ms_message("Channel is a TV."); + break; + case VIDEO_TYPE_CAMERA: + ms_message("Channel is a camera"); + break; + default: + ms_warning("unknown video channel type."); + } + found=1; + break; /* find the first channel */ + } + } + if (found) ms_message("A valid video channel was found."); + /* select this channel */ + ioctl(s->fd,VIDIOCSCHAN,&chan); + + /* get picture properties */ + err=ioctl(s->fd,VIDIOCGPICT,&pict); + if (err<0){ + ms_warning("Could not get picture properties: %s",strerror(errno)); + return -1; + } + ms_message("Default picture properties: brightness=%i,hue=%i,colour=%i,contrast=%i,depth=%i, palette=%i.", + pict.brightness,pict.hue,pict.colour, pict.contrast,pict.depth, pict.palette); + + /* trying color format */ + if (try_format(s->fd,&pict,VIDEO_PALETTE_YUV420P,16)){ + ms_message("Driver supports YUV420P, using that format."); + s->pix_fmt=MS_YUV420P; + }else if (try_format(s->fd, &pict,VIDEO_PALETTE_RGB24,24)){ + ms_message("Driver supports RGB24, using that format."); + s->pix_fmt=MS_RGB24; + }else if (try_format(s->fd, &pict,VIDEO_PALETTE_YUV422, 16)){ + ms_message("Driver supports YUV422, using that format."); + s->pix_fmt=MS_YUYV; + }else if (try_format(s->fd, &pict,VIDEO_PALETTE_UYVY, 16)){ + ms_message("Driver supports UYVY, using that format."); + s->pix_fmt=MS_UYVY; + }else{ + ms_fatal("Unsupported video pixel format."); + return -1; + } + + if (!try_size(s,s->vsize)) { + if (!try_size(s,MS_VIDEO_SIZE_NS1)){ + if (!try_size(s,MS_VIDEO_SIZE_VGA)){ + if (!try_size(s,MS_VIDEO_SIZE_CIF)) { + if (!try_size(s,MS_VIDEO_SIZE_QCIF)) { + if (!try_size(s,MS_VIDEO_SIZE_QVGA)) { + return -1; + } + } + } + } + } + } + + /* Try HW frame rate control */ + fps = s->fps; + if (ioctl(s->fd, VIDIOSFPS, &fps) < 0 ) + ms_message("v4l_configure: cannot set HW frame rate control"); + else + ms_message("v4l_configure: set HW fps to be : %d", fps); + + return 0; +} + + +int ms_to_v4l_pix_fmt(MSPixFmt p){ + switch(p){ + case MS_YUV420P: + return VIDEO_PALETTE_YUV420P; + case MS_RGB24: + return VIDEO_PALETTE_RGB24; + case MS_YUYV: + return VIDEO_PALETTE_YUV422; + case MS_UYVY: + return VIDEO_PALETTE_UYVY; + default: + ms_fatal("unsupported pix fmt"); + return -1; + } +} + +static void plane_copy(uint8_t *dest, int dw, int dh, uint8_t *src, int sw, int sh, int bpp){ + int diffw=dw-sw; + int diffh=dh-sh; + int dlsize=dw*bpp; + int slsize=sw*bpp; + int i; + int dstartx=(diffw>0) ? diffw/2 : 0; + int dstarty=(diffh>0) ? diffh/2 : 0; + int sstartx=(diffw<0) ? diffw/2 : 0; + int sstarty=(diffh<0) ? diffh/2 : 0; + uint8_t *tmp1=dest; + uint8_t *tmp2=src; + + /* copy orig into dest */ + tmp2+=sstarty*slsize; + tmp1+=dstarty*dlsize; + for(i=dstarty;ivsize.width*s->vsize.height; + mblk_t *newpic; + if (s->pix_fmt==MS_YUV420P) size=size*3/2; + else if (s->pix_fmt==MS_YUYV) size=size*2; + else if (s->pix_fmt==MS_UYVY) size=size*2; + else if (s->pix_fmt==MS_RGB24) size=size*3; + else ms_fatal("crop_or_pad: unsupported pixel format."); + newpic=allocb(size,0); + memset(newpic->b_wptr,0,size); + pic_copy(newpic->b_wptr, s->vsize.width, s->vsize.height, + pic->b_rptr,s->got_vsize.width,s->got_vsize.height,s->pix_fmt); + newpic->b_wptr+=size; + return newpic; +} + +static mblk_t * v4l_grab_image_mmap(V4lState *s){ + struct video_mmap vmap; + int err; + int syncframe; + int jitter=s->frame_max-1; + int query_frame; + mblk_t *ret; + vmap.width=s->got_vsize.width; + vmap.height=s->got_vsize.height; + vmap.format=ms_to_v4l_pix_fmt(s->pix_fmt); + + query_frame=(s->frame_ind) % s->frame_max; + /*ms_message("v4l_mmap_process: query_frame=%i", + obj->query_frame);*/ + vmap.frame=query_frame; + err=ioctl(s->fd,VIDIOCMCAPTURE,&vmap); + if (err<0) { + ms_warning("v4l_grab_image_mmap: error in VIDIOCMCAPTURE: %s.",strerror(errno)); + usleep(10000); + return NULL; + } + /*g_message("v4l_mmap_process: query_frame=%i done", + obj->query_frame);*/ + syncframe=(s->frame_ind-jitter); + s->frame_ind++; + if (syncframe>=0){ + syncframe=syncframe%s->frame_max; + /*ms_message("Syncing on frame %i",syncframe);*/ + err=ioctl(s->fd,VIDIOCSYNC,&syncframe); + if (err<0) { + ms_warning("v4l_grab_image_mmap: error in VIDIOCSYNC: %s.",strerror(errno)); + return NULL; + } + /*g_message("got frame %i",syncframe);*/ + }else { + return NULL; + } + ret=s->frames[syncframe]; + /* crop or pad picture if obtained size is not what we want */ + if (s->vsize.width!=s->got_vsize.width){ + ret=crop_or_pad(s,ret); + } + return ret; +} + +static mblk_t * v4l_make_mire(V4lState *s){ + unsigned char *data; + int i,j,line,pos; + int patternw=s->vsize.width/6; + int patternh=s->vsize.height/6; + int red,green=0,blue=0; + if (s->mire==NULL){ + s->mire=allocb(s->vsize.width*s->vsize.height*3,0); + s->mire->b_wptr=s->mire->b_datap->db_lim; + } + data=s->mire->b_rptr; + for (i=0;ivsize.height;++i){ + line=i*s->vsize.width*3; + if ( ((i+s->frame_ind)/patternh) & 0x1) red=255; + else red= 0; + for (j=0;jvsize.width;++j){ + pos=line+(j*3); + + if ( ((j+s->frame_ind)/patternw) & 0x1) blue=255; + else blue= 0; + + data[pos]=red; + data[pos+1]=green; + data[pos+2]=blue; + } + } + s->frame_ind++; + return s->mire; +} + +static mblk_t * v4l_make_nowebcam(V4lState *s){ + if (s->mire==NULL && s->frame_ind==0){ + s->mire=ms_load_nowebcam(&s->vsize, -1); + } + s->frame_ind++; + return s->mire; +} + +static void v4l_purge(V4lState *s){ + int i; + int err; + int jitter=s->frame_max-1; + for (i=s->frame_ind-jitter;iframe_ind;++i){ + int syncframe=i%s->frame_max; + ms_message("syncing last frame"); + err=ioctl(s->fd,VIDIOCSYNC,&syncframe); + if (err<0) { + ms_warning("v4l_mmap_process: error in VIDIOCSYNC: %s.",strerror(errno)); + } + } +} + +#ifdef HAVE_LINUX_VIDEODEV2_H +static void v4lv2_purge(V4lState *s){ + struct v4l2_buffer buf; + memset(&buf,0,sizeof(buf)); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + for(;s->queued>0;s->queued--){ + if (ioctl(s->fd, VIDIOC_DQBUF, &buf)==-1){ + ms_warning("v4lv2_purge: Could not DQ buffer: %s",strerror(errno)); + } + } +} +#endif + +static void v4l_do_munmap(V4lState *s){ + int i; +#ifdef HAVE_LINUX_VIDEODEV2_H + enum v4l2_buf_type type; + if (s->v4lv2){ + v4lv2_purge(s); + /*stop capture immediately*/ + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 ==ioctl (s->fd, VIDIOC_STREAMOFF, &type)){ + ms_error("VIDIOC_STREAMOFF failed: %s",strerror(errno)); + } + } +#endif + if (!s->v4lv2){ + v4l_purge(s); + } + if (s->mmapdbuf!=NULL){ + if (munmap(s->mmapdbuf,s->msize)<0){ + ms_warning("MSV4l: Fail to unmap: %s",strerror(errno)); + } + ms_message("munmap() done (%p,%i)",s->mmapdbuf,s->msize); + s->mmapdbuf=NULL; + } + s->msize=0; + for(i=0;iframe_max;++i){ + if (s->v4lv2){ + mblk_t *msg=s->frames[i]; + int len=msg->b_datap->db_lim-msg->b_datap->db_base; + if (munmap(msg->b_datap->db_base,len)<0){ + ms_warning("MSV4l: Fail to unmap: %s",strerror(errno)); + } + } + freemsg(s->frames[i]); + s->frames[i]=NULL; + } +} + + +static void *v4l_thread(void *ptr){ + V4lState *s=(V4lState*)ptr; + int err=-1; + ms_message("v4l_thread starting"); + if (s->v4lv2){ +#ifdef HAVE_LINUX_VIDEODEV2_H + err=v4lv2_do_mmap(s); +#endif + }else{ + err=v4l_do_mmap(s); + } + if (err<0){ + ms_thread_exit(NULL); + } + while(s->run){ + mblk_t *m; +#ifdef HAVE_LINUX_VIDEODEV2_H + if (s->v4lv2) + m=v4lv2_grab_image(s); + else +#endif + m=v4l_grab_image_mmap(s); + + if (s->vsize.width!=s->got_vsize.width){ + if (m){ + /* mblock was allocated by crop or pad! */ + ms_mutex_lock(&s->mutex); + putq(&s->rq,m); + ms_mutex_unlock(&s->mutex); + }else{ + ms_error("grabbing failed !"); + } + } else if (m!=NULL) { + mblk_t *dm=dupmsg(m); + ms_mutex_lock(&s->mutex); + putq(&s->rq,dm); + ms_mutex_unlock(&s->mutex); + } + } + v4l_do_munmap(s); + ms_message("v4l_thread exited."); + ms_thread_exit(NULL); +} + + +static void v4l_process(MSFilter * obj){ + V4lState *s=(V4lState*)obj->data; + uint32_t timestamp; + int cur_frame; + if (s->frame_count==-1){ + s->start_time=obj->ticker->time; + s->frame_count=0; + } + cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame>=s->frame_count){ + mblk_t *om=NULL; + ms_mutex_lock(&s->mutex); + /*keep the most recent frame if several frames have been captured */ + if (s->fd!=-1){ + om=getq(&s->rq); + }else{ + if (s->usemire){ + om=dupmsg(v4l_make_mire(s)); + }else { + mblk_t *tmpm=v4l_make_nowebcam(s); + if (tmpm) om=dupmsg(tmpm); + } + } + ms_mutex_unlock(&s->mutex); + if (om!=NULL){ + timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/ + mblk_set_timestamp_info(om,timestamp); + mblk_set_marker_info(om,TRUE); + ms_queue_put(obj->outputs[0],om); + /*ms_message("picture sent");*/ + s->frame_count++; + } + }else flushq(&s->rq,0); +} + +static void v4l_preprocess(MSFilter *f){ + V4lState *s=(V4lState*)f->data; + if (s->fd==-1){ + s->auto_started=TRUE; + v4l_start(f,NULL); + v4l_start_capture(s); + } +} + +static void v4l_postprocess(MSFilter *f){ + V4lState *s=(V4lState*)f->data; + if (s->auto_started){ + v4l_stop_capture(s); + v4l_stop(f,NULL); + } +} + +static int v4l_set_fps(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + s->fps=*((float*)arg); + s->frame_count=-1; + return 0; +} + +static int v4l_get_pix_fmt(MSFilter *f,void *arg){ + V4lState *s=(V4lState*)f->data; + MSPixFmt res; + if (s->fd==-1){ + v4l_start(f,NULL); + res=s->pix_fmt; + v4l_stop(f,NULL); + }else res=s->pix_fmt; + *((MSPixFmt*)arg)=res; + return 0; +} + +static int v4l_set_vsize(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + s->vsize=*((MSVideoSize*)arg); + return 0; +} + +static int v4l_get_vsize(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + *(MSVideoSize*)arg=s->vsize; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , v4l_set_fps }, + { MS_FILTER_GET_PIX_FMT , v4l_get_pix_fmt }, + { MS_FILTER_SET_VIDEO_SIZE, v4l_set_vsize }, + { MS_V4L_START , v4l_start }, + { MS_V4L_STOP , v4l_stop }, + { MS_FILTER_GET_VIDEO_SIZE, v4l_get_vsize }, + { 0 , NULL } +}; + +MSFilterDesc ms_v4l_desc={ + .id=MS_V4L_ID, + .name="MSV4l", + .text="A video4linux compatible source filter to stream pictures.", + .ninputs=0, + .noutputs=1, + .category=MS_FILTER_OTHER, + .init=v4l_init, + .preprocess=v4l_preprocess, + .process=v4l_process, + .postprocess=v4l_postprocess, + .uninit=v4l_uninit, + .methods=methods +}; + +MS_FILTER_DESC_EXPORT(ms_v4l_desc) + +static MSFilter *v4l_create_reader(MSWebCam *obj){ + MSFilter *f=ms_filter_new_from_desc(&ms_v4l_desc); + V4lState *s=(V4lState*)f->data; + s->force_v1=TRUE; + return f; +} + +static void v4l_detect(MSWebCamManager *obj); + +static void v4l_cam_init(MSWebCam *cam){ + +} + +MSWebCamDesc v4l_desc={ + "V4L", + &v4l_detect, + &v4l_cam_init, + &v4l_create_reader, + NULL +}; + +static void v4l_detect(MSWebCamManager *obj){ + struct video_capability cap; + const char *devname="/dev/video0"; + int fd=open(devname,O_RDWR); + if (fd!=-1){ + if (ioctl (fd, VIDIOCGCAP, &cap)==0) { + /* is a V4Lv1 */ + MSWebCam *cam=ms_web_cam_new(&v4l_desc); + cam->name=ms_strdup(devname); + ms_web_cam_manager_add_cam(obj,cam); + } + close(fd); + } +} + + +#endif diff --git a/linphone/mediastreamer2/src/msv4l2.c b/linphone/mediastreamer2/src/msv4l2.c new file mode 100644 index 000000000..3b8f1bf1f --- /dev/null +++ b/linphone/mediastreamer2/src/msv4l2.c @@ -0,0 +1,455 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer-config.h" + +#ifdef HAVE_LINUX_VIDEODEV2_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/mswebcam.h" + +typedef struct V4l2State{ + int fd; + char *dev; + char *mmapdbuf; + int msize;/*mmapped size*/ + MSVideoSize vsize; + MSVideoSize got_vsize; + int pix_fmt; + int int_pix_fmt; /*internal pixel format */ + mblk_t *frames[VIDEO_MAX_FRAME]; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + int queued; + bool_t run; +}V4l2State; + +static int v4l2_open(V4l2State *s){ + int fd=open(s->dev,O_RDWR|O_NONBLOCK); + if (fd==-1){ + ms_error("Could not open %s: %s",s->dev,strerror(errno)); + return -1; + } + s->fd=fd; + return 0; +} + +static int v4l2_close(V4l2State *s){ + if (s->fd!=-1){ + close(s->fd); + s->fd=-1; + } + return 0; +} + +static bool_t v4lv2_try_format(V4l2State *s, int fmtid){ + struct v4l2_format fmt; + + memset(&fmt,0,sizeof(fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = s->vsize.width; + fmt.fmt.pix.height = s->vsize.height; + fmt.fmt.pix.pixelformat = fmtid; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + + if (ioctl (s->fd, VIDIOC_S_FMT, &fmt)<0){ + return FALSE; + } + return TRUE; +} + +static int v4l2_configure(V4l2State *s){ + struct v4l2_capability cap; + struct v4l2_format fmt; + + if (ioctl (s->fd, VIDIOC_QUERYCAP, &cap)<0) { + ms_message("Not a v4lv2 driver."); + return -1; + } + + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + ms_error("%s is not a video capture device\n",s->dev); + return -1; + } + + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + ms_error("%s does not support streaming i/o\n",s->dev); + return -1; + } + + if (v4lv2_try_format(s,V4L2_PIX_FMT_YUV420)){ + s->pix_fmt=MS_YUV420P; + s->int_pix_fmt=V4L2_PIX_FMT_YUV420; + ms_message("v4lv2: YUV420P choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_NV12)){ + s->pix_fmt=MS_YUV420P; + s->int_pix_fmt=V4L2_PIX_FMT_NV12; + ms_message("v4lv2: V4L2_PIX_FMT_NV12 choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_MJPEG)){ + s->pix_fmt=MS_MJPEG; + s->int_pix_fmt=V4L2_PIX_FMT_MJPEG; + ms_message("v4lv2: MJPEG choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_YUYV)){ + s->pix_fmt=MS_YUYV; + s->int_pix_fmt=V4L2_PIX_FMT_YUYV; + ms_message("v4lv2: V4L2_PIX_FMT_YUYV choosen"); + }else if (v4lv2_try_format(s,V4L2_PIX_FMT_RGB24)){ + s->pix_fmt=MS_RGB24; + s->int_pix_fmt=V4L2_PIX_FMT_RGB24; + ms_message("v4lv2: RGB24 choosen"); + }else{ + ms_error("Could not find supported pixel format."); + return -1; + } + memset(&fmt,0,sizeof(fmt)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (ioctl (s->fd, VIDIOC_G_FMT, &fmt)<0){ + ms_error("VIDIOC_G_FMT failed: %s",strerror(errno)); + }else{ + ms_message("Size of picture is %ix%i",fmt.fmt.pix.width,fmt.fmt.pix.height); + } + + return 0; +} + +static int v4l2_do_mmap(V4l2State *s){ + struct v4l2_requestbuffers req; + int i; + enum v4l2_buf_type type; + + memset(&req,0,sizeof(req)); + + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (ioctl (s->fd, VIDIOC_REQBUFS, &req)<0) { + ms_error("Error requesting info on mmap'd buffers: %s",strerror(errno)); + return -1; + } + + for (i=0; ifd, VIDIOC_QUERYBUF, &buf)<0){ + ms_error("Could not VIDIOC_QUERYBUF : %s",strerror(errno)); + return -1; + } + + start=mmap (NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + s->fd, buf.m.offset); + + if (start==NULL){ + ms_error("Could not mmap: %s",strerror(errno)); + } + msg=esballoc(start,buf.length,0,NULL); + msg->b_wptr+=buf.length; + s->frames[i]=msg; + } + s->frame_max=req.count; + /* + for (i = 0; i < s->frame_max; ++i) { + struct v4l2_buffer buf; + + memset(&buf,0,sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + if (-1==ioctl (s->fd, VIDIOC_QBUF, &buf)){ + ms_error("VIDIOC_QBUF failed: %s",strerror(errno)); + } + } + */ + /*start capture immediately*/ + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 ==ioctl (s->fd, VIDIOC_STREAMON, &type)){ + ms_error("VIDIOC_STREAMON failed: %s",strerror(errno)); + return -1; + } + return 0; +} + +static mblk_t * v4lv2_grab_image(V4l2State *s){ + struct v4l2_buffer buf; + unsigned int k; + memset(&buf,0,sizeof(buf)); + mblk_t *ret=NULL; + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + /*queue buffers whose ref count is 1, because they are not + still used anywhere in the filter chain */ + for(k=0;kframe_max;++k){ + if (s->frames[k]->b_datap->db_ref==1){ + buf.index=k; + if (-1==ioctl (s->fd, VIDIOC_QBUF, &buf)) + ms_warning("VIDIOC_QBUF %i failed: %s",k, strerror(errno)); + else { + ms_debug("v4l2: queue buf %i",k); + /*increment ref count of queued buffer*/ + s->frames[k]->b_datap->db_ref++; + s->queued++; + } + } + } + + if (s->queued){ + struct pollfd fds; + memset(&fds,0,sizeof(fds)); + fds.events=POLLIN; + fds.fd=s->fd; + /*check with poll if there is something to read */ + if (poll(&fds,1,0)==1 && fds.revents==POLLIN){ + if (ioctl(s->fd, VIDIOC_DQBUF, &buf)<0) { + switch (errno) { + case EAGAIN: + case EIO: + /* Could ignore EIO, see spec. */ + break; + default: + ms_warning("VIDIOC_DQBUF failed: %s",strerror(errno)); + } + }else{ + s->queued--; + ms_debug("v4l2: de-queue buf %i",buf.index); + /*decrement ref count of dequeued buffer */ + ret=s->frames[buf.index]; + ret->b_datap->db_ref--; + if (buf.index >= s->frame_max){ + ms_error("buf.index>=s->max_frames !"); + return NULL; + } + if (buf.bytesused<=30){ + ms_warning("Ignoring empty buffer..."); + return NULL; + } + ret->b_wptr=ret->b_rptr+buf.bytesused; + } + } + } + return ret; +} + +static void v4l2_do_munmap(V4l2State *s){ + int i; + enum v4l2_buf_type type; + /*stop capture immediately*/ + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 ==ioctl (s->fd, VIDIOC_STREAMOFF, &type)){ + ms_error("VIDIOC_STREAMOFF failed: %s",strerror(errno)); + } + + for(i=0;iframe_max;++i){ + mblk_t *msg=s->frames[i]; + int len=msg->b_datap->db_lim-msg->b_datap->db_base; + if (munmap(msg->b_datap->db_base,len)<0){ + ms_warning("MSV4l2: Fail to unmap: %s",strerror(errno)); + } + freemsg(s->frames[i]); + s->frames[i]=NULL; + } +} + + + +static void v4l2_init(MSFilter *f){ + V4l2State *s=ms_new0(V4l2State,1); + s->dev=ms_strdup("/dev/video0"); + s->fd=-1; + s->vsize=MS_VIDEO_SIZE_CIF; + s->fps=15; + f->data=s; +} + +static void v4l2_uninit(MSFilter *f){ + V4l2State *s=(V4l2State*)f->data; + ms_free(s->dev); + ms_free(s); +} + +static void v4l2_process(MSFilter *f){ + V4l2State *s=(V4l2State*)f->data; + uint32_t elapsed; + if (s->fd==-1){ + if (v4l2_open(s)==0 && v4l2_configure(s)==0 && v4l2_do_mmap(s)==0){ + ms_message("V4L2 video capture started."); + }else{ + v4l2_close(s); + } + s->start_time=f->ticker->time; + } + if (s->fd!=-1){ + /*see it is necessary to output a frame:*/ + elapsed=f->ticker->time-s->start_time; + if (((float)elapsed*s->fps/1000.0)>s->frame_count){ + mblk_t *m; + m=v4lv2_grab_image(s); + if (m){ + mblk_t *om=dupb(m); + mblk_set_marker_info(om,(s->pix_fmt==MS_MJPEG)); + ms_queue_put(f->outputs[0],om); + s->frame_count++; + } + } + } +} + +static void v4l2_postprocess(MSFilter *f){ + V4l2State *s=(V4l2State*)f->data; + if (s->fd!=-1){ + v4l2_do_munmap(s); + v4l2_close(s); + } +} + +static int v4l2_set_fps(MSFilter *f, void *arg){ + V4l2State *s=(V4l2State*)f->data; + s->fps=*(float*)arg; + return 0; +} + +static int v4l2_set_vsize(MSFilter *f, void *arg){ + V4l2State *s=(V4l2State*)f->data; + s->vsize=*(MSVideoSize*)arg; + return 0; +} + +static int v4l2_get_vsize(MSFilter *f, void *arg){ + V4l2State *s=(V4l2State*)f->data; + *(MSVideoSize*)arg=s->vsize; + return 0; +} + +static int v4l2_get_pixfmt(MSFilter *f, void *arg){ + V4l2State *s=(V4l2State*)f->data; + if (s->fd==-1){ + if (v4l2_open(s)==0){ + v4l2_configure(s); + *(MSPixFmt*)arg=s->pix_fmt; + v4l2_close(s); + return 0; + }else return -1; + } + *(MSPixFmt*)arg=s->pix_fmt; + return 0; +} + +static int v4l2_set_devfile(MSFilter *f, void *arg){ + V4l2State *s=(V4l2State*)f->data; + if (s->dev) ms_free(s->dev); + s->dev=ms_strdup((char*)arg); + return 0; +} + +static MSFilterMethod v4l2_methods[]={ + { MS_FILTER_SET_FPS , v4l2_set_fps }, + { MS_FILTER_SET_VIDEO_SIZE, v4l2_set_vsize }, + { MS_FILTER_GET_VIDEO_SIZE, v4l2_get_vsize }, + { MS_FILTER_GET_PIX_FMT , v4l2_get_pixfmt }, + { 0 , NULL } +}; + +MSFilterDesc ms_v4l2_desc={ + .id=MS_V4L2_CAPTURE_ID, + .name="MSV4L2Capture", + .text="A filter to grab pictures from Video4Linux2-powered cameras", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .init=v4l2_init, + .process=v4l2_process, + .postprocess=v4l2_postprocess, + .uninit=v4l2_uninit, + .methods=v4l2_methods +}; + +MS_FILTER_DESC_EXPORT(ms_v4l2_desc) + +static MSFilter *v4l2_create_reader(MSWebCam *obj){ + MSFilter *f=ms_filter_new(MS_V4L2_CAPTURE_ID); + v4l2_set_devfile(f,obj->name); + return f; +} + +static void v4l2_detect(MSWebCamManager *obj); + +static void v4l2_cam_init(MSWebCam *cam){ +} + +MSWebCamDesc v4l2_desc={ + "V4L2", + &v4l2_detect, + &v4l2_cam_init, + &v4l2_create_reader, + NULL +}; + +static void v4l2_detect(MSWebCamManager *obj){ + struct v4l2_capability cap; + char devname[32]; + int i; + for(i=0;i<10;++i){ + int fd; + snprintf(devname,sizeof(devname),"/dev/video%i",i); + fd=open(devname,O_RDWR); + if (fd!=-1){ + if (ioctl (fd, VIDIOC_QUERYCAP, &cap)==0) { + /* is a V4LV2 */ + MSWebCam *cam=ms_web_cam_new(&v4l2_desc); + cam->name=ms_strdup(devname); + ms_web_cam_manager_add_cam(obj,cam); + } + close(fd); + } + } +} + + +#endif diff --git a/linphone/mediastreamer2/src/msv4m.c b/linphone/mediastreamer2/src/msv4m.c new file mode 100644 index 000000000..12ba947f9 --- /dev/null +++ b/linphone/mediastreamer2/src/msv4m.c @@ -0,0 +1,508 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef __APPLE__ + +#include "mediastreamer-config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msv4l.h" +#include "nowebcam.h" + +// build for carbon +#define TARGET_API_MAC_CARBON 1 + +#if __APPLE_CC__ + #include + #include +#else + #include + #include + #include + + #include +#endif + +typedef struct V4lState{ + SeqGrabComponent seqgrab; + SGChannel sgchanvideo; + GWorldPtr pgworld; + ImageSequence decomseq; + + char *mmapdbuf; + int msize;/*mmapped size*/ + MSVideoSize vsize; + MSVideoSize got_vsize; + int pix_fmt; + int int_pix_fmt; /*internal pixel format */ + mblk_t *mire; + queue_t rq; + ms_mutex_t mutex; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + int queued; + bool_t run; + bool_t usemire; +}V4lState; + +static void v4m_init(MSFilter *f){ + V4lState *s=ms_new0(V4lState,1); + s->seqgrab=NULL; + s->sgchanvideo=NULL; + s->pgworld=NULL; + s->decomseq=0; + + s->run=FALSE; + s->mmapdbuf=NULL; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + s->pix_fmt=MS_RGB24; + qinit(&s->rq); + s->mire=NULL; + ms_mutex_init(&s->mutex,NULL); + s->start_time=0; + s->frame_count=-1; + s->fps=15; + s->usemire=(getenv("DEBUG")!=NULL); + s->queued=0; + f->data=s; +} + + +#define BailErr(x) {err = x; if(err != noErr) goto bail;} + +pascal OSErr sgdata_callback(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon); +pascal OSErr sgdata_callback(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon) +{ +#pragma unused(offset,chRefCon,time,writeType) + + CodecFlags ignore; + V4lState *s=(V4lState *)refCon; + ComponentResult err = noErr; + + if (!s) goto bail; + + Rect boundsRect = {0, 0, s->vsize.height, s->vsize.width}; /* 240 , 320*/ + if (s->pgworld) { + + if (s->decomseq == 0) { + Rect sourceRect = { 0, 0 }; + MatrixRecord scaleMatrix; + ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); + + err = SGGetChannelSampleDescription(c,(Handle)imageDesc); + BailErr(err); + + // make a scaling matrix for the sequence + sourceRect.right = (**imageDesc).width; + sourceRect.bottom = (**imageDesc).height; + RectMatrix(&scaleMatrix, &sourceRect, &boundsRect); + + err = DecompressSequenceBegin(&s->decomseq, // pointer to field to receive unique ID for sequence + imageDesc, // handle to image description structure + s->pgworld, // port for the DESTINATION image + NULL, // graphics device handle, if port is set, set to NULL + NULL, // source rectangle defining the portion of the image to decompress + &scaleMatrix, // transformation matrix + srcCopy, // transfer mode specifier + NULL, // clipping region in dest. coordinate system to use as a mask + 0, // flags + codecNormalQuality, // accuracy in decompression + bestSpeedCodec); // compressor identifier or special identifiers ie. bestSpeedCodec + BailErr(err); + + DisposeHandle((Handle)imageDesc); + imageDesc = NULL; + } + + // decompress a frame into the GWorld - can queue a frame for async decompression when passed in a completion proc + // once the image is in the GWorld it can be manipulated at will + err = DecompressSequenceFrameS(s->decomseq, // sequence ID returned by DecompressSequenceBegin + p, // pointer to compressed image data + len, // size of the buffer + 0, // in flags + &ignore, // out flags + NULL); // async completion proc + BailErr(err); + + { + unsigned line; + mblk_t *buf; + int size = s->vsize.width * s->vsize.height * 3; + buf=allocb(size,0); + + PixMap * pixmap = *GetGWorldPixMap(s->pgworld); + uint8_t * data; + unsigned rowBytes = pixmap->rowBytes & (((unsigned short) 0xFFFF) >> 2); + unsigned pixelSize = pixmap->pixelSize / 8; // Pixel size in bytes + unsigned lineOffset = rowBytes - s->vsize.width * pixelSize; + + data = (uint8_t *) GetPixBaseAddr(GetGWorldPixMap(s->pgworld)); + + for (line = 0 ; line < s->vsize.height ; line++) { + unsigned offset = line * (s->vsize.width * pixelSize + lineOffset); + memcpy(buf->b_wptr + ((line * s->vsize.width) * pixelSize), data + offset, (rowBytes - lineOffset)); + } + + if (s->pix_fmt==MS_RGB24) + { + /* Conversion from top down bottom up (BGR to RGB and flip) */ + unsigned long Index,nPixels; + unsigned char *blue; + unsigned char tmp; + short iPixelSize; + + blue=buf->b_wptr; + + nPixels=s->vsize.width*s->vsize.height; + iPixelSize=24/8; + + for(Index=0;Index!=nPixels;Index++) // For each pixel + { + tmp=*blue; + *blue=*(blue+2); + *(blue+2)=tmp; + blue+=iPixelSize; + } + } + + buf->b_wptr+=size; + //ms_mutex_lock(&s->mutex); /* called during SGIdle? */ + putq(&s->rq, buf); + //ms_mutex_unlock(&s->mutex); + } + } + +bail: + return err; +} + +static int v4m_close(V4lState *s) +{ + if(s->seqgrab) + CloseComponent(s->seqgrab); + s->seqgrab=NULL; + if (s->decomseq) + CDSequenceEnd(s->decomseq); + s->decomseq=NULL; + if (s->pgworld!=NULL) + DisposeGWorld(s->pgworld); + s->pgworld=NULL; + return 0; +} + +static int sequence_grabber_start(V4lState *s) +{ + int err; + Rect theRect = {0, 0, s->vsize.height, s->vsize.width}; + + err = QTNewGWorld(&(s->pgworld), // returned GWorld + k24BGRPixelFormat, + &theRect, // bounding rectangle + 0, // color table + NULL, // graphic device handle + 0); // flags + if (err!=noErr) + { + return -1; + } + + if(!LockPixels(GetPortPixMap(s->pgworld))) + { + v4m_close(s); + return -1; + } + + s->seqgrab = OpenDefaultComponent(SeqGrabComponentType, 0); + err = SGInitialize(s->seqgrab); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + err = SGSetDataRef(s->seqgrab, 0, 0, seqGrabDontMakeMovie); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + err = SGSetGWorld(s->seqgrab, s->pgworld, GetMainDevice()); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + err = SGNewChannel(s->seqgrab, VideoMediaType, &s->sgchanvideo); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + err = SGSetChannelBounds(s->sgchanvideo, &theRect); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + err = SGSetChannelUsage(s->sgchanvideo, seqGrabRecord); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + err = SGSetDataProc(s->seqgrab,NewSGDataUPP(sgdata_callback),(long)s); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + err = SGStartRecord(s->seqgrab); + if (err!=noErr) + { + v4m_close(s); + return -1; + } + + return 0; +} + +static int v4m_start(MSFilter *f, void *arg) +{ + V4lState *s=(V4lState*)f->data; + int err=0; + + err = sequence_grabber_start(s); + + if (err!=0) + { + s->pix_fmt=MS_YUV420P; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + return 0; + } + + ms_message("v4m video device opened."); + s->pix_fmt=MS_RGB24; + + return 0; +} + +static void v4m_start_capture(V4lState *s){ + if (s->seqgrab!=NULL){ + s->run=TRUE; + } +} + +static int v4m_stop(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + if (s->seqgrab!=NULL){ + ms_mutex_lock(&s->mutex); + SGStop(s->seqgrab); + v4m_close(s); + flushq(&s->rq,0); + ms_mutex_unlock(&s->mutex); + } + return 0; +} + +static void v4m_stop_capture(V4lState *s){ + if (s->run){ + s->run=FALSE; + ms_message("v4m capture stopped."); + } +} + + +static void v4m_uninit(MSFilter *f){ + V4lState *s=(V4lState*)f->data; + if (s->seqgrab!=NULL) v4m_stop(f,NULL); + //ms_free(s->dev); + flushq(&s->rq,0); + ms_mutex_destroy(&s->mutex); + freemsg(s->mire); + ms_free(s); +} + +static mblk_t * v4m_make_mire(V4lState *s){ + unsigned char *data; + int i,j,line,pos; + int patternw=s->vsize.width/6; + int patternh=s->vsize.height/6; + int red,green=0,blue=0; + if (s->mire==NULL){ + s->mire=allocb(s->vsize.width*s->vsize.height*3,0); + s->mire->b_wptr=s->mire->b_datap->db_lim; + } + data=s->mire->b_rptr; + for (i=0;ivsize.height;++i){ + line=i*s->vsize.width*3; + if ( ((i+s->frame_ind)/patternh) & 0x1) red=255; + else red= 0; + for (j=0;jvsize.width;++j){ + pos=line+(j*3); + + if ( ((j+s->frame_ind)/patternw) & 0x1) blue=255; + else blue= 0; + + data[pos]=red; + data[pos+1]=green; + data[pos+2]=blue; + } + } + s->frame_ind++; + return s->mire; +} + +static mblk_t * v4m_make_nowebcam(V4lState *s){ + if (s->mire==NULL && s->frame_ind==0){ + s->mire=ms_load_nowebcam(&s->vsize, -1); + } + s->frame_ind++; + return s->mire; +} + +static void v4m_process(MSFilter * obj){ + V4lState *s=(V4lState*)obj->data; + uint32_t timestamp; + int cur_frame; + if (s->frame_count==-1){ + s->start_time=obj->ticker->time; + s->frame_count=0; + } + + ms_mutex_lock(&s->mutex); + + if (s->seqgrab!=NULL) + { + SGIdle(s->seqgrab); + } + + cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame>=s->frame_count){ + mblk_t *om=NULL; + /*keep the most recent frame if several frames have been captured */ + if (s->seqgrab!=NULL){ + om=getq(&s->rq); + }else{ + if (s->pix_fmt==MS_YUV420P + && s->vsize.width==MS_VIDEO_SIZE_CIF_W + && s->vsize.height==MS_VIDEO_SIZE_CIF_H) + { + if (s->usemire){ + om=dupmsg(v4m_make_mire(s)); + }else { + mblk_t *tmpm=v4m_make_nowebcam(s); + if (tmpm) om=dupmsg(tmpm); + } + } + } + if (om!=NULL){ + timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/ + mblk_set_timestamp_info(om,timestamp); + mblk_set_marker_info(om,TRUE); + ms_queue_put(obj->outputs[0],om); + /*ms_message("picture sent");*/ + s->frame_count++; + } + }else flushq(&s->rq,0); + + ms_mutex_unlock(&s->mutex); +} + +static void v4m_preprocess(MSFilter *f){ + V4lState *s=(V4lState*)f->data; + v4m_start_capture(s); +} + +static void v4m_postprocess(MSFilter *f){ + V4lState *s=(V4lState*)f->data; + v4m_stop_capture(s); +} + +static int v4m_set_fps(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + s->fps=*((float*)arg); + s->frame_count=-1; + return 0; +} + +static int v4m_get_pix_fmt(MSFilter *f,void *arg){ + V4lState *s=(V4lState*)f->data; + *((MSPixFmt*)arg) = s->pix_fmt; + return 0; +} + +static int v4m_set_vsize(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + s->vsize=*((MSVideoSize*)arg); + return 0; +} + +static int v4m_get_vsize(MSFilter *f, void *arg){ + V4lState *s=(V4lState*)f->data; + *(MSVideoSize*)arg=s->vsize; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , v4m_set_fps }, + { MS_FILTER_GET_PIX_FMT , v4m_get_pix_fmt }, + { MS_FILTER_SET_VIDEO_SIZE, v4m_set_vsize }, + { MS_V4L_START , v4m_start }, + { MS_V4L_STOP , v4m_stop }, + { MS_FILTER_GET_VIDEO_SIZE, v4m_get_vsize }, + { 0 , NULL } +}; + +MSFilterDesc ms_v4l_desc={ + .id=MS_V4L_ID, + .name="MSV4m", + .text="A video for macosx compatible source filter to stream pictures.", + .ninputs=0, + .noutputs=1, + .category=MS_FILTER_OTHER, + .init=v4m_init, + .preprocess=v4m_preprocess, + .process=v4m_process, + .postprocess=v4m_postprocess, + .uninit=v4m_uninit, + .methods=methods +}; + +MS_FILTER_DESC_EXPORT(ms_v4l_desc) + +#endif diff --git a/linphone/mediastreamer2/src/msvideo.c b/linphone/mediastreamer2/src/msvideo.c new file mode 100644 index 000000000..df26f3175 --- /dev/null +++ b/linphone/mediastreamer2/src/msvideo.c @@ -0,0 +1,104 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msvideo.h" + +static void yuv_buf_init(YuvBuf *buf, int w, int h, uint8_t *ptr){ + int ysize,usize; + ysize=w*h; + usize=ysize/4; + buf->w=w; + buf->h=h; + buf->planes[0]=ptr; + buf->planes[1]=buf->planes[0]+ysize; + buf->planes[2]=buf->planes[1]+usize; + buf->strides[0]=w; + buf->strides[1]=w/2; + buf->strides[2]=buf->strides[1]; +} + +int yuv_buf_init_from_mblk(YuvBuf *buf, mblk_t *m){ + int size=m->b_wptr-m->b_rptr; + int w,h; + if (size==(MS_VIDEO_SIZE_QCIF_W*MS_VIDEO_SIZE_QCIF_H*3)/2){ + w=MS_VIDEO_SIZE_QCIF_W; + h=MS_VIDEO_SIZE_QCIF_H; + }else if (size==(MS_VIDEO_SIZE_CIF_W*MS_VIDEO_SIZE_CIF_H*3)/2){ + w=MS_VIDEO_SIZE_CIF_W; + h=MS_VIDEO_SIZE_CIF_H; + }else if (size==(MS_VIDEO_SIZE_QQVGA_W*MS_VIDEO_SIZE_QQVGA_H*3)/2){ + w=MS_VIDEO_SIZE_QQVGA_W; + h=MS_VIDEO_SIZE_QQVGA_H; + }else if (size==(MS_VIDEO_SIZE_QVGA_W*MS_VIDEO_SIZE_QVGA_H*3)/2){ + w=MS_VIDEO_SIZE_QVGA_W; + h=MS_VIDEO_SIZE_QVGA_H; + }else if (size==(MS_VIDEO_SIZE_VGA_W*MS_VIDEO_SIZE_VGA_H*3)/2){ + w=MS_VIDEO_SIZE_VGA_W; + h=MS_VIDEO_SIZE_VGA_H; + }else if (size==(MS_VIDEO_SIZE_4CIF_W*MS_VIDEO_SIZE_4CIF_H*3)/2){ + w=MS_VIDEO_SIZE_4CIF_W; + h=MS_VIDEO_SIZE_4CIF_H; + }else if (size==(MS_VIDEO_SIZE_720P_W*MS_VIDEO_SIZE_720P_H*3)/2){ + w=MS_VIDEO_SIZE_720P_W; + h=MS_VIDEO_SIZE_720P_H; + }else if (size==(MS_VIDEO_SIZE_NS1_W*MS_VIDEO_SIZE_NS1_H*3)/2){ + w=MS_VIDEO_SIZE_NS1_W; + h=MS_VIDEO_SIZE_NS1_H; + }else if (size==(160*112*3)/2){/*format used by econf*/ + w=160; + h=112; + }else { + ms_error("Unsupported image size: size=%i (bug somewhere !)",size); + return -1; + } + yuv_buf_init(buf,w,h,m->b_rptr); + return 0; +} + +void yuv_buf_init_from_mblk_with_size(YuvBuf *buf, mblk_t *m, int w, int h){ + yuv_buf_init(buf,w,h,m->b_rptr); +} + +mblk_t * yuv_buf_alloc(YuvBuf *buf, int w, int h){ + int size=(w*h*3)/2; + mblk_t *msg=allocb(size,0); + yuv_buf_init(buf,w,h,msg->b_wptr); + msg->b_wptr+=size; + return msg; +} + +static void plane_copy(const uint8_t *src_plane, int src_stride, + uint8_t *dst_plane, int dst_stride, MSVideoSize roi){ + int i; + for(i=0;i + +static const float max_e=32767*32767; +static const float coef=0.1; + +typedef struct Volume{ + float energy; +}Volume; + +static void volume_init(MSFilter *f){ + f->data=ms_new0(Volume,1); +} + +static void volume_uninit(MSFilter *f){ + ms_free(f->data); +} + +static int volume_get(MSFilter *f, void *arg){ + float *farg=(float*)arg; + Volume *v=(Volume*)f->data; + *farg=10*log10f(v->energy/max_e); + return 0; +} + +static void volume_process(MSFilter *f){ + mblk_t *m; + int16_t *sample; + Volume *v=(Volume*)f->data; + float en=v->energy; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + for ( sample=(int16_t*)m->b_rptr; + sample<(int16_t*)m->b_wptr; + ++sample){ + float s=*sample; + en=(s*s*coef) + (1.0-coef)*en; + } + ms_queue_put(f->outputs[0],m); + } + v->energy=en; +} + +static MSFilterMethod methods[]={ + { MS_VOLUME_GET , volume_get }, + { 0 , NULL } +}; + +#ifndef _MSC_VER +MSFilterDesc ms_volume_desc={ + .name="MSVolume", + .text="A filter to make level measurements on 16 bits pcm audio stream", + .id=MS_VOLUME_ID, + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=1, + .init=volume_init, + .uninit=volume_uninit, + .process=volume_process, + .methods=methods +}; +#else +MSFilterDesc ms_volume_desc={ + MS_VOLUME_ID, + "MSVolume", + "A filter to make level measurements on 16 bits pcm audio stream", + MS_FILTER_OTHER, + NULL, + 1, + 1, + volume_init, + NULL, + volume_process, + NULL, + volume_uninit, + methods +}; +#endif diff --git a/linphone/mediastreamer2/src/mswebcam.c b/linphone/mediastreamer2/src/mswebcam.c new file mode 100644 index 000000000..8cdd75719 --- /dev/null +++ b/linphone/mediastreamer2/src/mswebcam.c @@ -0,0 +1,116 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/mswebcam.h" +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/msfilter.h" + +static MSWebCamManager *scm=NULL; + +static MSWebCamManager * create_manager(){ + MSWebCamManager *obj=(MSWebCamManager *)ms_new(MSWebCamManager,1); + obj->cams=NULL; + return obj; +} + +void ms_web_cam_manager_destroy(void){ + if (scm!=NULL){ + ms_list_for_each(scm->cams,(void (*)(void*))ms_web_cam_destroy); + ms_list_free(scm->cams); + } + ms_free(scm); + scm=NULL; +} + +MSWebCamManager * ms_web_cam_manager_get(void){ + if (scm==NULL) scm=create_manager(); + return scm; +} + +MSWebCam * ms_web_cam_manager_get_cam(MSWebCamManager *m, const char *id){ + MSList *elem; + for (elem=m->cams;elem!=NULL;elem=elem->next){ + MSWebCam *cam=(MSWebCam*)elem->data; + if (id==NULL) return cam; + if (strcmp(ms_web_cam_get_string_id(cam),id)==0) return cam; + } + if (id!=NULL) ms_warning("no camera with id %s",id); + return NULL; +} + +MSWebCam * ms_web_cam_manager_get_default_cam(MSWebCamManager *m){ + if (m->cams!=NULL) + return (MSWebCam*)m->cams->data; + return NULL; +} + +const MSList * ms_web_cam_manager_get_list(MSWebCamManager *m){ + return m->cams; +} + +void ms_web_cam_manager_add_cam(MSWebCamManager *m, MSWebCam *c){ + ms_message("Webcam %s added",ms_web_cam_get_string_id(c)); + m->cams=ms_list_append(m->cams,c); +} + +void ms_web_cam_manager_register_desc(MSWebCamManager *m, MSWebCamDesc *desc){ + if (desc->detect!=NULL) + desc->detect(m); +} + +MSWebCam * ms_web_cam_new(MSWebCamDesc *desc){ + MSWebCam *obj=(MSWebCam *)ms_new(MSWebCam,1); + obj->desc=desc; + obj->name=NULL; + obj->data=NULL; + obj->id=NULL; + if (desc->init!=NULL) + desc->init(obj); + return obj; +} + +const char *ms_web_cam_get_driver_type(const MSWebCam *obj){ + return obj->desc->driver_type; +} + +const char *ms_web_cam_get_name(const MSWebCam *obj){ + return obj->name; +} + +const char *ms_web_cam_get_string_id(MSWebCam *obj){ + if (obj->id==NULL) obj->id=ms_strdup_printf("%s: %s",obj->desc->driver_type,obj->name); + return obj->id; +} + +struct _MSFilter * ms_web_cam_create_reader(MSWebCam *obj){ + if (obj->desc->create_reader!=NULL) + return obj->desc->create_reader(obj); + else ms_warning("ms_web_cam_create_reader: unimplemented by %s wrapper",obj->desc->driver_type); + return NULL; +} + +void ms_web_cam_destroy(MSWebCam *obj){ + if (obj->desc->uninit!=NULL) obj->desc->uninit(obj); + if (obj->name!=NULL) ms_free(obj->name); + if (obj->id!=NULL) ms_free(obj->id); + ms_free(obj); +} diff --git a/linphone/mediastreamer2/src/mtu.c b/linphone/mediastreamer2/src/mtu.c new file mode 100644 index 000000000..74a3e5e91 --- /dev/null +++ b/linphone/mediastreamer2/src/mtu.c @@ -0,0 +1,236 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +/* mtu.c : discover the mtu automatically */ + +#include "mediastreamer2/mscommon.h" + + +#if defined(WIN32) + +HINSTANCE m_IcmpInst = NULL; + +typedef struct ip_option_information { + UCHAR Ttl; + UCHAR Tos; + UCHAR Flags; + UCHAR OptionsSize; + PUCHAR OptionsData; +} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION; + +typedef BOOL (WINAPI *ICMPCLOSEHANDLE)(HANDLE IcmpHandle); +typedef HANDLE (WINAPI *ICMPCREATEFILE)(VOID); +typedef DWORD (WINAPI *ICMPSENDECHO)(HANDLE IcmpHandle,ULONG DestinationAddress, LPVOID RequestData, WORD RequestSize, PIP_OPTION_INFORMATION RequestOptions, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout); + +ICMPCLOSEHANDLE pIcmpCloseHandle = NULL; +ICMPCREATEFILE pIcmpCreateFile = NULL; +ICMPSENDECHO pIcmpSendEcho = NULL; + +#define IP_FLAG_DF 0x2 // Don't fragment this packet. +#define IP_OPT_ROUTER_ALERT 0x94 // Router Alert Option + +#define IP_STATUS_BASE 11000 +#define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9) +#define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10) + +static int mtus[] = { + 1500, // Ethernet, Point-to-Point (default) + 1492, // IEEE 802.3 + 1006, // SLIP, ARPANET + 576, // X.25 Networks + 544, // DEC IP Portal + 512, // NETBIOS + 508, // IEEE 802/Source-Rt Bridge, ARCNET + 296, // Point-to-Point (low delay) + 68, // Official minimum + 0 +}; + +int ms_discover_mtu(const char *host) +{ + int i; + + struct addrinfo hints,*ai=NULL; + char port[10]; + char ipaddr[INET6_ADDRSTRLEN]; + int err; + + HANDLE hIcmp; + unsigned long target_addr; + + struct ip_option_information ip_opts; + unsigned char reply_buffer[10000]; + + if (!m_IcmpInst) + { + m_IcmpInst = LoadLibrary("icmp.dll"); + if (m_IcmpInst) + { + pIcmpCloseHandle = (ICMPCLOSEHANDLE)GetProcAddress(m_IcmpInst, "IcmpCloseHandle"); + pIcmpCreateFile = (ICMPCREATEFILE) GetProcAddress(m_IcmpInst, "IcmpCreateFile"); + pIcmpSendEcho = (ICMPSENDECHO) GetProcAddress(m_IcmpInst, "IcmpSendEcho"); + } + } + + hIcmp = pIcmpCreateFile(); + + memset(&hints,0,sizeof(hints)); + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_DGRAM; + + snprintf(port,sizeof(port),"0"); + err=getaddrinfo(host,port,&hints,&ai); + if (err!=0){ + pIcmpCloseHandle( hIcmp ); + ms_error("getaddrinfo(): error\n"); + return -1; + } + getnameinfo (ai->ai_addr, ai->ai_addrlen, ipaddr, sizeof (ipaddr), port, + sizeof (port), NI_NUMERICHOST | NI_NUMERICSERV); + freeaddrinfo(ai); + + target_addr=inet_addr(ipaddr); + + + /* Prepare the IP options */ + memset(&ip_opts,0,sizeof(ip_opts)); + ip_opts.Ttl=30; + ip_opts.Flags = IP_FLAG_DF | IP_OPT_ROUTER_ALERT; + + + // ignore icmpbuff data contents + for (i=0;mtus[i]!=0;i++) + { + char icmpbuff[2048]; + char *icmp_data = icmpbuff; + + int status = -1; + if (pIcmpSendEcho) + status=pIcmpSendEcho(hIcmp, + target_addr, + (LPVOID)icmp_data, + mtus[i]-60, /* icmp_data_size */ + &ip_opts, + reply_buffer, + sizeof(reply_buffer), + 3000L); // 5 seconds + if (status || GetLastError() == IP_REQ_TIMED_OUT) + { + pIcmpCloseHandle( hIcmp ); + return mtus[i]; + } + } + + pIcmpCloseHandle( hIcmp ); + + return -1; +} + +#elif defined(__linux) + +#include +#include +#include +#include +#include +#include +#include + +#ifndef IP_MTU +#define IP_MTU 14 +#endif + +int ms_discover_mtu(const char *host){ + int sock; + int err,mtu=0,new_mtu; + socklen_t optlen; + char buf[1500-28]={0}; + char port[10]; + struct addrinfo hints,*ai=NULL; + int rand_port; + int retry=0; + struct timeval tv; + + memset(&hints,0,sizeof(hints)); + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_DGRAM; + + gettimeofday(&tv,NULL); + srandom(tv.tv_usec); + rand_port=random() & 0xFFFF; + if (rand_port<1000) rand_port+=1000; + snprintf(port,sizeof(port),"%i",rand_port); + err=getaddrinfo(host,port,&hints,&ai); + if (err!=0){ + ms_error("getaddrinfo(): %s\n",gai_strerror(err)); + return -1; + } + sock=socket(PF_INET,SOCK_DGRAM,0); + + mtu=IP_PMTUDISC_DO; + optlen=sizeof(mtu); + err=setsockopt(sock,IPPROTO_IP,IP_MTU_DISCOVER,&mtu,optlen); + if (err!=0){ + ms_error("setsockopt(): %s",strerror(errno)); + return -1; + } + err=connect(sock,ai->ai_addr,ai->ai_addrlen); + freeaddrinfo(ai); + if (err!=0){ + ms_error("connect(): %s",strerror(errno)); + return -1; + } + mtu=sizeof(buf); + do{ + send(sock,buf,mtu,0); + usleep(500000);/*wait for an icmp message come back */ + err=getsockopt(sock,IPPROTO_IP,IP_MTU,&new_mtu,&optlen); + if (err!=0){ + ms_error("getsockopt(): %s",strerror(errno)); + return -1; + }else{ + ms_message("Partial MTU discovered : %i",new_mtu); + if (new_mtu==mtu) break; + else mtu=new_mtu; + } + retry++; + }while(retry<10); + + ms_message("mtu to %s is %i",host,mtu); + return mtu; +} + +#else + +int ms_discover_mtu(const char*host){ + ms_warning("mtu discovery not implemented."); + return -1; +} + +#endif + + +void ms_set_mtu(int mtu){ + /*60= IPv6+UDP+RTP overhead */ + if (mtu>60){ + if (mtu>1500) mtu=1500;/*limit to 1500, the mediastreamer2 buffer are not large enough anyway*/ + ms_set_payload_max_size(mtu-60); + }else ms_set_payload_max_size(0); +} diff --git a/linphone/mediastreamer2/src/nowebcam.c b/linphone/mediastreamer2/src/nowebcam.c new file mode 100644 index 000000000..0b3bae8ff --- /dev/null +++ b/linphone/mediastreamer2/src/nowebcam.c @@ -0,0 +1,217 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/mswebcam.h" + +#include "ffmpeg-priv.h" + +#include + +#ifdef WIN32 +#include +#include +#include +#include +#include +#endif + +static mblk_t *jpeg2yuv(uint8_t *jpgbuf, int bufsize, MSVideoSize *reqsize){ + AVCodecContext av_context; + int got_picture=0; + AVFrame orig; + AVPicture dest; + mblk_t *ret; + struct SwsContext *sws_ctx; + + avcodec_get_context_defaults(&av_context); + if (avcodec_open(&av_context,avcodec_find_decoder(CODEC_ID_MJPEG))<0){ + ms_error("jpeg2yuv: avcodec_open failed"); + return NULL; + } + if (avcodec_decode_video(&av_context,&orig,&got_picture,jpgbuf,bufsize)<0){ + ms_error("jpeg2yuv: avcodec_decode_video failed"); + avcodec_close(&av_context); + return NULL; + } + ret=allocb(avpicture_get_size(PIX_FMT_YUV420P,reqsize->width,reqsize->height),0); + ret->b_wptr=ret->b_datap->db_lim; + avpicture_fill(&dest,ret->b_rptr,PIX_FMT_YUV420P,reqsize->width,reqsize->height); + + sws_ctx=sws_getContext(av_context.width,av_context.height,PIX_FMT_YUV420P, + reqsize->width,reqsize->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, + NULL, NULL, NULL); + if (sws_scale(sws_ctx,orig.data,orig.linesize,0,av_context.height,dest.data,dest.linesize)<0){ + ms_error("jpeg2yuv: sws_scale() failed."); + } + sws_freeContext(sws_ctx); + avcodec_close(&av_context); + return ret; +} + +mblk_t *ms_load_jpeg_as_yuv(const char *jpgpath, MSVideoSize *reqsize){ + mblk_t *m=NULL; + struct stat statbuf; + uint8_t *jpgbuf; +#if !defined(_MSC_VER) + int fd=open(jpgpath,O_RDONLY); +#else + int fd=_open(jpgpath,O_RDONLY); +#endif + if (fd!=-1){ + fstat(fd,&statbuf); + jpgbuf=(uint8_t*)alloca(statbuf.st_size); +#if !defined(_MSC_VER) + read(fd,jpgbuf,statbuf.st_size); +#else + _read(fd,jpgbuf,statbuf.st_size); +#endif + m=jpeg2yuv(jpgbuf,statbuf.st_size,reqsize); + }else{ + ms_error("Cannot load %s",jpgpath); + } + return m; +} + +#ifndef PACKAGE_DATA_DIR +#define PACKAGE_DATA_DIR "." +#endif + +#ifndef NOWEBCAM_JPG +#define NOWEBCAM_JPG "nowebcamCIF" +#endif + +mblk_t *ms_load_nowebcam(MSVideoSize *reqsize, int idx){ + char tmp[256]; + if (idx<0) + snprintf(tmp, sizeof(tmp), "%s/images/%s.jpg", PACKAGE_DATA_DIR, NOWEBCAM_JPG); + else + snprintf(tmp, sizeof(tmp), "%s/images/%s%i.jpg", PACKAGE_DATA_DIR, NOWEBCAM_JPG, idx); + return ms_load_jpeg_as_yuv(tmp,reqsize); +} + +typedef struct _SIData{ + MSVideoSize vsize; + int index; + uint64_t lasttime; + mblk_t *pic; +}SIData; + +void static_image_init(MSFilter *f){ + SIData *d=(SIData*)ms_new(SIData,1); + d->vsize.width=MS_VIDEO_SIZE_CIF_W; + d->vsize.height=MS_VIDEO_SIZE_CIF_H; + d->index=-1; + d->lasttime=0; + d->pic=NULL; + f->data=d; +} + +void static_image_uninit(MSFilter *f){ + ms_free(f->data); +} + +void static_image_preprocess(MSFilter *f){ + SIData *d=(SIData*)f->data; + d->pic=ms_load_nowebcam(&d->vsize,d->index); +} + +void static_image_process(MSFilter *f){ + SIData *d=(SIData*)f->data; + /*output a frame every second*/ + if ((f->ticker->time - d->lasttime>1000) || d->lasttime==0){ + if (d->pic) ms_queue_put(f->outputs[0],dupb(d->pic)); + d->lasttime=f->ticker->time; + } +} + +void static_image_postprocess(MSFilter *f){ + SIData *d=(SIData*)f->data; + if (d->pic) { + freemsg(d->pic); + d->pic=NULL; + } +} + +int static_image_set_vsize(MSFilter *f, void* data){ + SIData *d=(SIData*)f->data; + d->vsize=*(MSVideoSize*)data; + return 0; +} + +int static_image_get_pix_fmt(MSFilter *f, void *data){ + *(MSPixFmt*)data=MS_YUV420P; + return 0; +} + +MSFilterMethod static_image_methods[]={ + { MS_FILTER_SET_VIDEO_SIZE, static_image_set_vsize }, + { MS_FILTER_GET_PIX_FMT, static_image_get_pix_fmt }, + { 0,0 } +}; + +MSFilterDesc ms_static_image_desc={ + MS_STATIC_IMAGE_ID, + "MSStaticImage", + "A filter that outputs a static image.", + MS_FILTER_OTHER, + NULL, + 0, + 1, + static_image_init, + static_image_preprocess, + static_image_process, + static_image_postprocess, + static_image_uninit, + static_image_methods +}; + +MS_FILTER_DESC_EXPORT(ms_static_image_desc) + +static void static_image_detect(MSWebCamManager *obj); + +static void static_image_cam_init(MSWebCam *cam){ + cam->name=ms_strdup("Static picture"); +} + + +static MSFilter *static_image_create_reader(MSWebCam *obj){ + return ms_filter_new_from_desc(&ms_static_image_desc); +} + +MSWebCamDesc static_image_desc={ + "StaticImage", + &static_image_detect, + &static_image_cam_init, + &static_image_create_reader, + NULL +}; + +static void static_image_detect(MSWebCamManager *obj){ + MSWebCam *cam=ms_web_cam_new(&static_image_desc); + ms_web_cam_manager_add_cam(obj,cam); +} + diff --git a/linphone/mediastreamer2/src/nowebcam.h b/linphone/mediastreamer2/src/nowebcam.h new file mode 100644 index 000000000..b77ec505d --- /dev/null +++ b/linphone/mediastreamer2/src/nowebcam.h @@ -0,0 +1,28 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef nowebcam_h +#define nowebcam_h + +mblk_t *ms_load_jpeg_as_yuv(const char *path, MSVideoSize *reqsize); +mblk_t *ms_load_nowebcam(MSVideoSize *reqsize, int idx); + +#endif + diff --git a/linphone/mediastreamer2/src/nowebcamCIF.jpg b/linphone/mediastreamer2/src/nowebcamCIF.jpg new file mode 100644 index 000000000..2ab8bdc2a Binary files /dev/null and b/linphone/mediastreamer2/src/nowebcamCIF.jpg differ diff --git a/linphone/mediastreamer2/src/oss.c b/linphone/mediastreamer2/src/oss.c new file mode 100644 index 000000000..bca032fd7 --- /dev/null +++ b/linphone/mediastreamer2/src/oss.c @@ -0,0 +1,597 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ALLOCA_H /*FreeBSD does not have alloca.h*/ +#include +#endif + +MSFilter *ms_oss_read_new(MSSndCard *card); +MSFilter *ms_oss_write_new(MSSndCard *card); + +static int oss_open(const char *devname, int bits,int stereo, int rate, int *minsz) +{ + int fd; + int p=0,cond=0; + int i=0; + int min_size=0,blocksize=512; + int err; + int frag; + audio_buf_info info; + + //g_message("opening sound device"); + fd=open(devname,O_RDWR|O_NONBLOCK); + if (fd<0) return -EWOULDBLOCK; + /* unset nonblocking mode */ + /* We wanted non blocking open but now put it back to normal ; thanks Xine !*/ + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK); + + /* reset is maybe not needed but takes time*/ + /*ioctl(fd, SNDCTL_DSP_RESET, 0); */ + + /* This code is used to limit the internal buffer of the sound + card so that no internal delay can occur in the sound card */ + frag = ( ( 32767 << 16 ) | 7 ); + if( ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &frag ) ) { + ms_warning("oss_open: can't set fragment size:%s.",strerror(errno)); + } + + p=AFMT_S16_NE; + + err=ioctl(fd,SNDCTL_DSP_SETFMT,&p); + if (err<0){ + ms_warning("oss_open: can't set sample format:%s.",strerror(errno)); + } + + + p = bits; /* 16 bits */ + err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p); + if (err<0){ + ms_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno)); + } + + p = rate; /* rate in khz*/ + err=ioctl(fd, SNDCTL_DSP_SPEED, &p); + if (err<0){ + ms_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno)); + } + + p = stereo; /* stereo or not */ + err=ioctl(fd, SNDCTL_DSP_STEREO, &p); + if (err<0){ + ms_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno)); + } + + if (rate==16000) blocksize=4096; /* oss emulation is not very good at 16khz */ + else blocksize=blocksize*(rate/8000); + ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); + + /* try to subdivide BLKSIZE to reach blocksize if necessary */ + if (min_size>blocksize) + { + cond=1; + p=min_size/blocksize; + while(cond) + { + i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p); + //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno); + if ((i==0) || (p==1)) cond=0; + else p=p/2; + } + } + ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); + if (min_size>blocksize) + { + ms_warning("dsp block size set to %i.",min_size); + }else{ + /* no need to access the card with less latency than needed*/ + min_size=blocksize; + } + + ms_message("/dev/dsp opened: rate=%i,bits=%i,stereo=%i blocksize=%i.", + rate,bits,stereo,min_size); + + if( ioctl( fd, SNDCTL_DSP_GETISPACE, &info ) == -1 ) { + ms_warning("oss_open: can't get ispace:%s.",strerror(errno)); + } + else{ + ms_warning("oss_open: audio buffer size: %i.", info.fragsize * sizeof( short )); + } + + + /* start recording !!! Alex */ + { + int fl,res; + + fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT; + res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl); + if (res<0) ms_warning("OSS_TRIGGER: %s",strerror(errno)); + } + *minsz=min_size; + return fd; +} + +typedef struct OssData{ + char *pcmdev; + char *mixdev; + int pcmfd; + int rate; + int bits; + ms_thread_t thread; + ms_mutex_t mutex; + queue_t rq; + MSBufferizer * bufferizer; + bool_t read_started; + bool_t write_started; + bool_t stereo; +} OssData; + +static void oss_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent) +{ + OssData *d=(OssData*)card->data; + int p,mix_fd; + int osscmd; + if (d->mixdev==NULL) return; + switch(e){ + case MS_SND_CARD_MASTER: + osscmd=SOUND_MIXER_VOLUME; + break; + case MS_SND_CARD_CAPTURE: + osscmd=SOUND_MIXER_IGAIN; + break; + case MS_SND_CARD_PLAYBACK: + osscmd=SOUND_MIXER_PCM; + break; + default: + ms_warning("oss_card_set_level: unsupported command."); + return; + } + p=(((int)percent)<<8 | (int)percent); + mix_fd = open(d->mixdev, O_WRONLY); + ioctl(mix_fd,MIXER_WRITE(osscmd), &p); + close(mix_fd); +} + +static int oss_get_level(MSSndCard *card, MSSndCardMixerElem e) +{ + OssData *d=(OssData*)card->data; + int p=0,mix_fd; + int osscmd; + if (d->mixdev==NULL) return -1; + switch(e){ + case MS_SND_CARD_MASTER: + osscmd=SOUND_MIXER_VOLUME; + break; + case MS_SND_CARD_CAPTURE: + osscmd=SOUND_MIXER_IGAIN; + break; + case MS_SND_CARD_PLAYBACK: + osscmd=SOUND_MIXER_PCM; + break; + default: + ms_warning("oss_card_get_level: unsupported command."); + return -1; + } + mix_fd = open(d->mixdev, O_RDONLY); + ioctl(mix_fd,MIXER_READ(osscmd), &p); + close(mix_fd); + return p>>8; +} + +static void oss_set_source(MSSndCard *card, MSSndCardCapture source) +{ + OssData *d=(OssData*)card->data; + int p=0; + int mix_fd; + if (d->mixdev==NULL) return; + + switch(source){ + case MS_SND_CARD_MIC: + p = 1 << SOUND_MIXER_MIC; + break; + case MS_SND_CARD_LINE: + p = 1 << SOUND_MIXER_LINE; + break; + } + + mix_fd = open(d->mixdev, O_WRONLY); + ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p); + close(mix_fd); +} + +static void oss_init(MSSndCard *card){ + OssData *d=ms_new(OssData,1); + d->pcmdev=NULL; + d->mixdev=NULL; + d->pcmfd=-1; + d->read_started=FALSE; + d->write_started=FALSE; + d->bits=16; + d->rate=8000; + d->stereo=FALSE; + qinit(&d->rq); + d->bufferizer=ms_bufferizer_new(); + ms_mutex_init(&d->mutex,NULL); + card->data=d; +} + +static void oss_uninit(MSSndCard *card){ + OssData *d=(OssData*)card->data; + if (d->pcmdev!=NULL) ms_free(d->pcmdev); + if (d->mixdev!=NULL) ms_free(d->mixdev); + ms_bufferizer_destroy(d->bufferizer); + flushq(&d->rq,0); + ms_mutex_destroy(&d->mutex); + ms_free(d); +} + +#define DSP_NAME "/dev/dsp" +#define MIXER_NAME "/dev/mixer" + +static void oss_detect(MSSndCardManager *m); +static MSSndCard *oss_duplicate(MSSndCard *obj); + +MSSndCardDesc oss_card_desc={ + .driver_type="OSS", + .detect=oss_detect, + .init=oss_init, + .set_level=oss_set_level, + .get_level=oss_get_level, + .set_capture=oss_set_source, + .create_reader=ms_oss_read_new, + .create_writer=ms_oss_write_new, + .uninit=oss_uninit, + .duplicate=oss_duplicate +}; + +static MSSndCard *oss_duplicate(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&oss_card_desc); + OssData *dcard=(OssData*)card->data; + OssData *dobj=(OssData*)obj->data; + dcard->pcmdev=ms_strdup(dobj->pcmdev); + dcard->mixdev=ms_strdup(dobj->mixdev); + card->name=ms_strdup(obj->name); + return card; +} + +static MSSndCard *oss_card_new(const char *pcmdev, const char *mixdev){ + MSSndCard *card=ms_snd_card_new(&oss_card_desc); + OssData *d=(OssData*)card->data; + d->pcmdev=ms_strdup(pcmdev); + d->mixdev=ms_strdup(mixdev); + card->name=ms_strdup(pcmdev); + return card; +} + +static void oss_detect(MSSndCardManager *m){ + int i; + char pcmdev[sizeof(DSP_NAME)+3]; + char mixdev[sizeof(MIXER_NAME)+3]; + if (access(DSP_NAME,F_OK)==0){ + MSSndCard *card=oss_card_new(DSP_NAME,MIXER_NAME); + ms_snd_card_manager_add_card(m,card); + card=oss_card_new(DSP_NAME,MIXER_NAME); + ms_snd_card_manager_add_card(m,card); + } + for(i=0;i<10;i++){ + snprintf(pcmdev,sizeof(pcmdev),"%s%i",DSP_NAME,i); + snprintf(mixdev,sizeof(mixdev),"%s%i",MIXER_NAME,i); + if (access(pcmdev,F_OK)==0){ + MSSndCard *card=oss_card_new(pcmdev,mixdev); + ms_snd_card_manager_add_card(m,card); + } + } +} + +static void * oss_thread(void *p){ + MSSndCard *card=(MSSndCard*)p; + OssData *d=(OssData*)card->data; + int bsize=0; + uint8_t *rtmpbuff=NULL; + uint8_t *wtmpbuff=NULL; + int err; + mblk_t *rm=NULL; + d->pcmfd=oss_open(d->pcmdev,d->bits,d->stereo,d->rate,&bsize); + if (d->pcmfd>=0){ + rtmpbuff=(uint8_t*)malloc(bsize); + wtmpbuff=(uint8_t*)malloc(bsize); + if(rtmpbuff == NULL || wtmpbuff == NULL) { + free(rtmpbuff); + free(wtmpbuff); + return NULL; + } + } + while(d->read_started || d->write_started){ + if (d->pcmfd>=0){ + if (d->read_started){ + struct timeval timeout; + fd_set read_fds; + audio_buf_info info; + if (rm==NULL) rm=allocb(bsize,0); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + FD_ZERO( &read_fds ); + FD_SET( d->pcmfd, &read_fds ); + if( select( d->pcmfd + 1, &read_fds, NULL, NULL, &timeout ) == -1 ) { + } + if (FD_ISSET( d->pcmfd, &read_fds ) && ioctl( d->pcmfd, SNDCTL_DSP_GETISPACE, &info ) != -1) + { + if (info.bytes>=bsize) + { + err=read(d->pcmfd,rm->b_wptr,bsize); + if (err<0){ + ms_warning("Fail to read %i bytes from soundcard: %s", + bsize,strerror(errno)); + }else{ + rm->b_wptr+=err; + ms_mutex_lock(&d->mutex); + putq(&d->rq,rm); + ms_mutex_unlock(&d->mutex); + rm=NULL; + } + } + else + { + timeout.tv_sec = 0; + timeout.tv_usec = 5000; + select(0, 0, NULL, NULL, &timeout ); + } + } + else + { + timeout.tv_sec = 0; + timeout.tv_usec = 5000; + select(0, 0, NULL, NULL, &timeout ); + } + }else { + int sz = read(d->pcmfd,rtmpbuff,bsize); + if( sz!=bsize) ms_warning("sound device read returned %i !",sz); + } + if (d->write_started){ + + audio_buf_info info; + if( ms_bufferizer_get_avail(d->bufferizer)>=bsize && ioctl( d->pcmfd, SNDCTL_DSP_GETOSPACE, &info ) == 0 ) { + if( info.fragstotal - info.fragments > 15 ) { + static int c=0; + /* drop the fragment if the buffer starts to fill up */ + /* we got too much data: I prefer to empty the incoming buffer */ + while (ms_bufferizer_get_avail(d->bufferizer)>bsize*4){ + ms_mutex_lock(&d->mutex); + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + ms_mutex_unlock(&d->mutex); + c=c+err*4; + ms_warning("drop fragment when buffer gets too much data (%i - discarded:%i)", info.fragstotal - info.fragments, c); + if (err==0) + break; + } + + }else { + ms_mutex_lock(&d->mutex); + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + ms_mutex_unlock(&d->mutex); + err=write(d->pcmfd,wtmpbuff,bsize); + if (err<0){ + ms_warning("Fail to write %i bytes from soundcard: %s", + bsize,strerror(errno)); + } + } + } + + }else { + int sz; + memset(wtmpbuff,0,bsize); + sz = write(d->pcmfd,wtmpbuff,bsize); + if( sz!=bsize) ms_warning("sound device write returned %i !",sz); + } + }else usleep(20000); + } + if (d->pcmfd>=0) { + close(d->pcmfd); + d->pcmfd=-1; + } + free(rtmpbuff); + free(wtmpbuff); + if (rm!=NULL) freemsg(rm); + /*reset to default parameters */ + d->bits=16; + d->rate=8000; + d->stereo=FALSE; + return NULL; +} + +static void oss_start_r(MSSndCard *card){ + OssData *d=(OssData*)card->data; + ms_mutex_lock(&d->mutex); + if (d->read_started==FALSE && d->write_started==FALSE){ + d->read_started=TRUE; + ms_thread_create(&d->thread,NULL,oss_thread,card); + }else d->read_started=TRUE; + flushq(&d->rq,0); + ms_mutex_unlock(&d->mutex); +} + +static void oss_stop_r(MSSndCard *card){ + OssData *d=(OssData*)card->data; + d->read_started=FALSE; + if (d->write_started==FALSE){ + ms_thread_join(d->thread,NULL); + } +} + +static void _flush_buffer(MSBufferizer *obj){ + flushq(&obj->q,0); + obj->size=0; +} + +static void oss_start_w(MSSndCard *card){ + OssData *d=(OssData*)card->data; + ms_mutex_lock(&d->mutex); + if (d->read_started==FALSE && d->write_started==FALSE){ + d->write_started=TRUE; + ms_thread_create(&d->thread,NULL,oss_thread,card); + }else{ + d->write_started=TRUE; + } + _flush_buffer(d->bufferizer); + ms_mutex_unlock(&d->mutex); +} + +static void oss_stop_w(MSSndCard *card){ + OssData *d=(OssData*)card->data; + d->write_started=FALSE; + if (d->read_started==FALSE){ + ms_thread_join(d->thread,NULL); + } +} + +static mblk_t *oss_get(MSSndCard *card){ + OssData *d=(OssData*)card->data; + mblk_t *m; + ms_mutex_lock(&d->mutex); + m=getq(&d->rq); + ms_mutex_unlock(&d->mutex); + return m; +} + +static void oss_put(MSSndCard *card, mblk_t *m){ + OssData *d=(OssData*)card->data; + ms_mutex_lock(&d->mutex); + ms_bufferizer_put(d->bufferizer,m); + ms_mutex_unlock(&d->mutex); +} + + +static void oss_read_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + oss_start_r(card); +} + +static void oss_read_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + oss_stop_r(card); +} + +static void oss_read_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=oss_get(card))!=NULL){ + ms_queue_put(f->outputs[0],m); + } +} + +static void oss_write_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + oss_start_w(card); +} + +static void oss_write_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + oss_stop_w(card); +} + +static void oss_write_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + oss_put(card,m); + } +} + +static int set_rate(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + OssData *d=(OssData*)card->data; + d->rate=*((int*)arg); + return 0; +} + +static int set_nchannels(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + OssData *d=(OssData*)card->data; + d->stereo=(*((int*)arg)==2); + return 0; +} + +static MSFilterMethod oss_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , set_rate }, + { MS_FILTER_SET_NCHANNELS , set_nchannels }, + { 0 , NULL } +}; + +MSFilterDesc oss_read_desc={ + .id=MS_OSS_READ_ID, + .name="MSOssRead", + .text="Sound capture filter for OSS drivers", + .category=MS_FILTER_OTHER, + .ninputs=0, + .noutputs=1, + .preprocess=oss_read_preprocess, + .process=oss_read_process, + .postprocess=oss_read_postprocess, + .methods=oss_methods +}; + + +MSFilterDesc oss_write_desc={ + .id=MS_OSS_WRITE_ID, + .name="MSOssWrite", + .text="Sound playback filter for OSS drivers", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=0, + .preprocess=oss_write_preprocess, + .process=oss_write_process, + .postprocess=oss_write_postprocess, + .methods=oss_methods +}; + +MSFilter *ms_oss_read_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&oss_read_desc); + f->data=card; + return f; +} + + +MSFilter *ms_oss_write_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&oss_write_desc); + f->data=card; + return f; +} + +MS_FILTER_DESC_EXPORT(oss_read_desc) +MS_FILTER_DESC_EXPORT(oss_write_desc) diff --git a/linphone/mediastreamer2/src/pasnd.c b/linphone/mediastreamer2/src/pasnd.c new file mode 100644 index 000000000..c4b411faa --- /dev/null +++ b/linphone/mediastreamer2/src/pasnd.c @@ -0,0 +1,594 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" + +#include "portaudio.h" + +MSFilter *ms_pasnd_read_new(MSSndCard *card); +MSFilter *ms_pasnd_write_new(MSSndCard *card); + +typedef struct PASndData{ + char *pcmdev; + char *mixdev; + int sound_err; + char waveoutbuffer[30][3200]; + PaStream *waveoutdev; + + PaStream *waveindev; + + int rate; + int bits; + ms_thread_t thread; + ms_mutex_t mutex; + queue_t rq; + MSBufferizer * bufferizer; + bool_t read_started; + bool_t write_started; + bool_t stereo; + + SpeexPreprocessState *pst; +} PASndData; + +int SpeakerCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + PASndData *device = (PASndData*)userData; + uint8_t *wtmpbuff=NULL; + int err; + + memset(outputBuffer,0, framesPerBuffer*2); + if (!device->read_started && !device->write_started) + { + return 0; + } + + wtmpbuff=(uint8_t*)alloca(framesPerBuffer*2); + + memset(outputBuffer,0, framesPerBuffer*2); + + ms_mutex_lock(&device->mutex); + + /* remove extra buffer when latency is increasing: + this often happen with USB device */ + if (device->bufferizer->size>=320*6){ + ms_warning("Extra data for sound card (total:%i %ims)", + device->bufferizer->size, (device->bufferizer->size*20)/320); + err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2); + err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2); + err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2); + err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2); + err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2); + ms_warning("Extra data for sound card removed (total:%i %ims)", + device->bufferizer->size, (device->bufferizer->size*20)/320); + } + + err=ms_bufferizer_read(device->bufferizer,wtmpbuff,framesPerBuffer*2); + ms_mutex_unlock(&device->mutex); + if (err==framesPerBuffer*2) + { + memcpy (outputBuffer, wtmpbuff, framesPerBuffer*2); + } + + return 0; +} + +int WaveInCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + PASndData *device = (PASndData*)userData; + + if (!device->read_started && !device->write_started) + { + return 0; + } + + ms_mutex_lock(&device->mutex); + if (device->read_started) + { + int vad; + mblk_t *rm=NULL; + if (rm==NULL) rm=allocb(framesPerBuffer*2,0); + memcpy(rm->b_wptr,inputBuffer, framesPerBuffer*2); + + if (device->pst!=NULL) + { + vad = speex_preprocess(device->pst, (spx_int16_t *)rm->b_wptr, NULL); +#if 0 + if (vad!=1) + ms_message("WaveInCallback : %d", vad); +#endif + } + + rm->b_wptr+=framesPerBuffer*2; + + putq(&device->rq,rm); + rm=NULL; + } + ms_mutex_unlock(&device->mutex); + + return 0; +} + +static int pasnd_open(PASndData *device, int devnumber, int bits,int stereo, int rate, int *minsz) +{ + PaStreamParameters outputParameters; + PaStreamParameters inputParameters; + PaError err; + + const PaHostApiInfo *pa_hai = Pa_GetHostApiInfo(Pa_GetDefaultHostApi()); + + ms_warning("pasnd_open : opening default input device: name=%s (%i)", + pa_hai->name, pa_hai->defaultInputDevice); + ms_warning("pasnd_open : opening default output device name=%s (%i)", + pa_hai->name, pa_hai->defaultOutputDevice); + + outputParameters.device = devnumber; /* default output device */ + outputParameters.device = pa_hai->defaultOutputDevice; + outputParameters.channelCount = 1; /* stereo output */ + outputParameters.sampleFormat = paInt16; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &device->waveoutdev, /* stream */ + NULL, /* no input */ + &outputParameters, // + rate, // double sampleRate + 160*(rate/8000), //unsigned long framesPerBuffer + paClipOff, + SpeakerCallback, //PortAudioCallback *callback + (void *) device); //void *userData + + if (err != paNoError) + { + ms_warning("Failed to open out device. (Pa_OpenDefaultStream:0x%i)", err); + return -1; + } + + inputParameters.device = devnumber; /* default input device */ + inputParameters.device = pa_hai->defaultInputDevice; + inputParameters.channelCount = 1; /* stereo input */ + inputParameters.sampleFormat = paInt16; /* 32 bit floating point input */ + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &device->waveindev, //PortAudioStream** stream + &inputParameters, /* input param*/ + NULL, /* output param */ + rate, // double sampleRate + 160*(rate/8000), //unsigned long framesPerBuffer + paClipOff, + WaveInCallback, //PortAudioCallback *callback + (void *) device); //void *userData + + + if (err != paNoError) + { + ms_warning("Failed to open in device. (Pa_OpenDefaultStream:0x%i)", err); + return -1; + } + + err = Pa_StartStream( device->waveoutdev ); + if( err != paNoError ) + { + ms_warning("Failed to start out device. (Pa_StartStream:0x%i)", err); + return -1; + } + + device->pst = speex_preprocess_state_init((device->rate/8000 * 320)/2, device->rate); + if (device->pst!=NULL) { + float f; + int i=1; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_VAD, &i); + i=1; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DENOISE, &i); + i=0; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC, &i); + f=8000; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); + i=0; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i); + f=.4; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); + f=.3; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); + } + + err = Pa_StartStream( device->waveindev ); + if( err != paNoError ) + { + ms_warning("Failed to start in device: trying default device. (Pa_StartStream:0x%i)", err); + return -1; + } + + *minsz=device->rate/8000 * 320; + return 0; +} + +static void pasnd_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent) +{ + PASndData *d=(PASndData*)card->data; + + if (d->mixdev==NULL) return; + switch(e){ + case MS_SND_CARD_MASTER: + return; + break; + case MS_SND_CARD_CAPTURE: + break; + case MS_SND_CARD_PLAYBACK: + break; + default: + ms_warning("pasnd_card_set_level: unsupported command."); + return; + } +} + +static int pasnd_get_level(MSSndCard *card, MSSndCardMixerElem e) +{ + PASndData *d=(PASndData*)card->data; + + if (d->mixdev==NULL) return -1; + switch(e){ + case MS_SND_CARD_MASTER: + return 60; + break; + case MS_SND_CARD_CAPTURE: + break; + case MS_SND_CARD_PLAYBACK: + break; + default: + ms_warning("pasnd_card_get_level: unsupported command."); + return -1; + } + return -1; +} + +static void pasnd_set_source(MSSndCard *card, MSSndCardCapture source) +{ + PASndData *d=(PASndData*)card->data; + if (d->mixdev==NULL) return; + + switch(source){ + case MS_SND_CARD_MIC: + break; + case MS_SND_CARD_LINE: + break; + } +} + +static void pasnd_init(MSSndCard *card){ + PASndData *d=ms_new(PASndData,1); + memset(d, 0, sizeof(PASndData)); + d->pcmdev=NULL; + d->mixdev=NULL; + d->sound_err=-1; /* not opened */ + d->read_started=FALSE; + d->write_started=FALSE; + d->bits=16; + d->rate=8000; + d->stereo=FALSE; + qinit(&d->rq); + d->bufferizer=ms_bufferizer_new(); + ms_mutex_init(&d->mutex,NULL); + card->data=d; + d->pst=0; +} + +static void pasnd_uninit(MSSndCard *card){ + PASndData *d=(PASndData*)card->data; + if (d==NULL) + return; + if (d->pcmdev!=NULL) ms_free(d->pcmdev); + if (d->mixdev!=NULL) ms_free(d->mixdev); + ms_bufferizer_destroy(d->bufferizer); + flushq(&d->rq,0); + + ms_mutex_destroy(&d->mutex); + + if (d->pst!=NULL) + speex_preprocess_state_destroy(d->pst); + + ms_free(d); +} + +#define DSP_NAME "/dev/dsp" +#define MIXER_NAME "/dev/mixer" + +static void pasnd_detect(MSSndCardManager *m); +static MSSndCard *pasnd_duplicate(MSSndCard *obj); + +MSSndCardDesc pasnd_card_desc={ + "PASND", + pasnd_detect, + pasnd_init, + pasnd_set_level, + pasnd_get_level, + pasnd_set_source, + ms_pasnd_read_new, + ms_pasnd_write_new, + pasnd_uninit, + pasnd_duplicate +}; + +static MSSndCard *pasnd_duplicate(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&pasnd_card_desc); + PASndData *dcard=(PASndData*)card->data; + PASndData *dobj=(PASndData*)obj->data; + dcard->pcmdev=ms_strdup(dobj->pcmdev); + dcard->mixdev=ms_strdup(dobj->mixdev); + card->name=ms_strdup(obj->name); + return card; +} + +static MSSndCard *pasnd_card_new(const char *pcmdev, const char *mixdev){ + MSSndCard *card=ms_snd_card_new(&pasnd_card_desc); + PASndData *d=(PASndData*)card->data; + d->pcmdev=ms_strdup(pcmdev); + d->mixdev=ms_strdup(mixdev); + card->name=ms_strdup(pcmdev); + return card; +} + +static void pasnd_detect(MSSndCardManager *m){ + int err = 0; + unsigned int numDevices; + const PaDeviceInfo *pdi; + char pcmdev[1024]; + char mixdev[1024]; + int i; + + err = Pa_Initialize(); + if( err != paNoError ) + { + ms_warning("PortAudio error: %s\n", Pa_GetErrorText( err ) ); + return; + } + + numDevices = Pa_GetDeviceCount(); + + for( i=0; iname); + snprintf(mixdev,sizeof(mixdev),"%s",pdi->name); + if (i == 0) + { + card=pasnd_card_new(pcmdev,mixdev); + ms_snd_card_manager_add_card(m,card); + } + card=pasnd_card_new(pcmdev,mixdev); + ms_snd_card_manager_add_card(m,card); + } + } +} + +static void pasnd_closedriver(PASndData *d) +{ + if (d->sound_err==0) { + + int err = Pa_StopStream( d->waveindev ); + if( err != paNoError ) + { + ms_warning("Failed to stop device. (Pa_StopStream:0x%i)", err); + } + + err = Pa_CloseStream( d->waveindev); + if( err != paNoError ) + { + ms_warning("failed to close recording sound card (Pa_CloseStream:0x%i)", err); + } + else + { + ms_message("successfully closed recording sound card"); + } + + err = Pa_StopStream( d->waveoutdev ); + if( err != paNoError ) + { + ms_warning("Failed to stop device. (Pa_StopStream:0x%i)", err); + } + + err = Pa_CloseStream( d->waveoutdev ); + if( err != paNoError ) + { + ms_error("failed to stop recording sound card (Pa_CloseStream:0x%i)", err); + } + else + { + ms_message("successfully stopped recording sound card"); + } + + + d->sound_err=-1; + } +} + +static void pasnd_start_r(MSSndCard *card){ + PASndData *d=(PASndData*)card->data; + if (d->read_started==FALSE && d->write_started==FALSE){ + int bsize=0; + d->read_started=TRUE; + d->sound_err=pasnd_open(d, 0, d->bits,d->stereo,d->rate,&bsize); + }else d->read_started=TRUE; +} + +static void pasnd_stop_r(MSSndCard *card){ + PASndData *d=(PASndData*)card->data; + d->read_started=FALSE; + if (d->write_started==FALSE){ + /* ms_thread_join(d->thread,NULL); */ + pasnd_closedriver(d); + } +} + +static void pasnd_start_w(MSSndCard *card){ + PASndData *d=(PASndData*)card->data; + if (d->read_started==FALSE && d->write_started==FALSE){ + int bsize=0; + d->write_started=TRUE; + d->sound_err=pasnd_open(d, 0, d->bits,d->stereo,d->rate,&bsize); + }else{ + d->write_started=TRUE; + } +} + +static void pasnd_stop_w(MSSndCard *card){ + PASndData *d=(PASndData*)card->data; + d->write_started=FALSE; + if (d->read_started==FALSE){ + /* ms_thread_join(d->thread,NULL); */ + pasnd_closedriver(d); + } +} + +static mblk_t *pasnd_get(MSSndCard *card){ + PASndData *d=(PASndData*)card->data; + mblk_t *m; + ms_mutex_lock(&d->mutex); + m=getq(&d->rq); + ms_mutex_unlock(&d->mutex); + return m; +} + +static void pasnd_put(MSSndCard *card, mblk_t *m){ + PASndData *d=(PASndData*)card->data; + ms_mutex_lock(&d->mutex); + ms_bufferizer_put(d->bufferizer,m); + ms_mutex_unlock(&d->mutex); +} + + +static void pasnd_read_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + pasnd_start_r(card); +} + +static void pasnd_read_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + pasnd_stop_r(card); +} + +static void pasnd_read_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=pasnd_get(card))!=NULL){ + ms_queue_put(f->outputs[0],m); + } +} + +static void pasnd_write_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + pasnd_start_w(card); +} + +static void pasnd_write_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + pasnd_stop_w(card); +} + +static void pasnd_write_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + pasnd_put(card,m); + } +} + +static int set_rate(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + PASndData *d=(PASndData*)card->data; + d->rate=*((int*)arg); + return 0; +} + +static int set_nchannels(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + PASndData *d=(PASndData*)card->data; + d->stereo=(*((int*)arg)==2); + return 0; +} + +static MSFilterMethod pasnd_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , set_rate }, + { MS_FILTER_SET_NCHANNELS , set_nchannels }, + { 0 , NULL } +}; + +MSFilterDesc pasnd_read_desc={ + MS_PASND_READ_ID, + "MSPasndRead", + "Sound capture filter for Port Audio Sound drivers", + MS_FILTER_OTHER, + NULL, + 0, + 1, + NULL, + pasnd_read_preprocess, + pasnd_read_process, + pasnd_read_postprocess, + NULL, + pasnd_methods +}; + + +MSFilterDesc pasnd_write_desc={ + MS_PASND_WRITE_ID, + "MSPasndWrite", + "Sound playback filter for Port Audio Sound drivers", + MS_FILTER_OTHER, + NULL, + 1, + 0, + NULL, + pasnd_write_preprocess, + pasnd_write_process, + pasnd_write_postprocess, + NULL, + pasnd_methods +}; + +MSFilter *ms_pasnd_read_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&pasnd_read_desc); + f->data=card; + return f; +} + + +MSFilter *ms_pasnd_write_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&pasnd_write_desc); + f->data=card; + return f; +} + +MS_FILTER_DESC_EXPORT(pasnd_read_desc) +MS_FILTER_DESC_EXPORT(pasnd_write_desc) diff --git a/linphone/mediastreamer2/src/pixconv.c b/linphone/mediastreamer2/src/pixconv.c new file mode 100644 index 000000000..a6bf135bc --- /dev/null +++ b/linphone/mediastreamer2/src/pixconv.c @@ -0,0 +1,200 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msvideo.h" + +#include "ffmpeg-priv.h" + +extern void ms_ffmpeg_check_init(); + +#ifndef PIX_FMT_YUYV422 +#define PIX_FMT_YUYV422 PIX_FMT_YUV422 +#endif + +int ms_pix_fmt_to_ffmpeg(MSPixFmt fmt){ + switch(fmt){ + case MS_RGB24: + return PIX_FMT_RGB24; + case MS_YUV420P: + return PIX_FMT_YUV420P; + case MS_YUYV: + return PIX_FMT_YUYV422; + case MS_UYVY: + return PIX_FMT_UYVY422; + case MS_YUY2: + return PIX_FMT_YUYV422; /* <- same as MS_UYVY */ + default: + ms_fatal("format not supported."); + return -1; + } + return -1; +} + +MSPixFmt ffmpeg_pix_fmt_to_ms(int fmt){ + switch(fmt){ + case PIX_FMT_RGB24: + return MS_RGB24; + case PIX_FMT_YUV420P: + return MS_YUV420P; + case PIX_FMT_YUYV422: + return MS_YUYV; + case PIX_FMT_UYVY422: + return MS_UYVY; /* same as MS_YUY2 */ + default: + ms_fatal("format not supported."); + return MS_YUV420P; /* default */ + } + return MS_YUV420P; /* default */ +} + +typedef struct PixConvState{ + YuvBuf outbuf; + mblk_t *yuv_msg; + struct SwsContext *sws_ctx; + MSVideoSize size; + enum PixelFormat in_fmt; + enum PixelFormat out_fmt; +}PixConvState; + +static void pixconv_init(MSFilter *f){ + PixConvState *s=(PixConvState *)ms_new(PixConvState,1); + s->yuv_msg=NULL; + s->size.width = MS_VIDEO_SIZE_CIF_W; + s->size.height = MS_VIDEO_SIZE_CIF_H; + s->in_fmt=PIX_FMT_YUV420P; + s->out_fmt=PIX_FMT_YUV420P; + s->sws_ctx=NULL; + f->data=s; + ms_ffmpeg_check_init(); +} + +static void pixconv_uninit(MSFilter *f){ + PixConvState *s=(PixConvState*)f->data; + if (s->sws_ctx!=NULL){ + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + } + if (s->yuv_msg!=NULL) freemsg(s->yuv_msg); + ms_free(s); +} + +static mblk_t * pixconv_alloc_mblk(PixConvState *s){ + if (s->yuv_msg!=NULL){ + int ref=s->yuv_msg->b_datap->db_ref; + if (ref==1){ + return dupmsg(s->yuv_msg); + }else{ + /*the last msg is still referenced by somebody else*/ + ms_message("Somebody still retaining yuv buffer (ref=%i)",ref); + freemsg(s->yuv_msg); + s->yuv_msg=NULL; + } + } + s->yuv_msg=yuv_buf_alloc(&s->outbuf,s->size.width,s->size.height); + return dupmsg(s->yuv_msg); +} + +static void pixconv_process(MSFilter *f){ + mblk_t *im,*om; + PixConvState *s=(PixConvState*)f->data; + + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + if (s->in_fmt==s->out_fmt){ + om=im; + }else{ + AVPicture inbuf; + avpicture_fill(&inbuf,im->b_rptr,s->in_fmt,s->size.width,s->size.height); + om=pixconv_alloc_mblk(s); + if (s->sws_ctx==NULL){ + s->sws_ctx=sws_getContext(s->size.width,s->size.height, + s->in_fmt,s->size.width,s->size.height, + s->out_fmt,SWS_FAST_BILINEAR, + NULL, NULL, NULL); + } + if (sws_scale(s->sws_ctx,inbuf.data,inbuf.linesize, 0, + s->size.height, s->outbuf.planes, s->outbuf.strides)<0){ + ms_error("MSPixConv: Error in sws_scale()."); + } + freemsg(im); + } + if (om!=NULL) ms_queue_put(f->outputs[0],om); + } +} + +static int pixconv_set_vsize(MSFilter *f, void*arg){ + PixConvState *s=(PixConvState*)f->data; + s->size=*(MSVideoSize*)arg; + return 0; +} + +static int pixconv_set_pixfmt(MSFilter *f, void *arg){ + MSPixFmt fmt=*(MSPixFmt*)arg; + PixConvState *s=(PixConvState*)f->data; + s->in_fmt=(enum PixelFormat)ms_pix_fmt_to_ffmpeg(fmt); + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_VIDEO_SIZE, pixconv_set_vsize }, + { MS_FILTER_SET_PIX_FMT, pixconv_set_pixfmt }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_pix_conv_desc={ + MS_PIX_CONV_ID, + "MSPixConv", + "A pixel format converter", + MS_FILTER_OTHER, + NULL, + 1, + 1, + pixconv_init, + NULL, + pixconv_process, + NULL, + pixconv_uninit, + methods +}; + +#else + +MSFilterDesc ms_pix_conv_desc={ + .id=MS_PIX_CONV_ID, + .name="MSPixConv", + .text="A pixel format converter", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=1, + .init=pixconv_init, + .process=pixconv_process, + .uninit=pixconv_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_pix_conv_desc) + diff --git a/linphone/mediastreamer2/src/rfc2429.h b/linphone/mediastreamer2/src/rfc2429.h new file mode 100644 index 000000000..414b2ea56 --- /dev/null +++ b/linphone/mediastreamer2/src/rfc2429.h @@ -0,0 +1,50 @@ +/* + The mediastreamer library aims at providing modular media processing and I/O + for linphone, but also for any telephony application. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef rfc2429_h +#define rfc2429_h + +#define MAKE_MASK(bits) ( (1<<(bits)) -1 ) + +static inline unsigned int rfc2429_get_P(const uint8_t *header){ + return (header[0]>>2) & 0x1; +} + +static inline void rfc2429_set_P(uint8_t *header, bool_t val){ + header[0]=header[0] | ( (val&0x1)<<2); +} + +static inline unsigned int rfc2429_get_V(const uint8_t *header){ + return (header[0]>>1) & 0x1; +} + +static inline unsigned int rfc2429_get_PLEN(const uint8_t *header){ + unsigned short *p=(unsigned short*)header; + return (ntohs(p[0])>>3) & MAKE_MASK(6); +} + +static inline unsigned int rfc2429_get_PEBIT(const uint8_t *header){ + unsigned short *p=(unsigned short*)header; + return ntohs(p[0]) & MAKE_MASK(3); +} + + +#endif diff --git a/linphone/mediastreamer2/src/rfc3984.c b/linphone/mediastreamer2/src/rfc3984.c new file mode 100644 index 000000000..ffb2895b8 --- /dev/null +++ b/linphone/mediastreamer2/src/rfc3984.c @@ -0,0 +1,321 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/rfc3984.h" +#include "mediastreamer2/msfilter.h" + +#define TYPE_FU_A 28 /*fragmented unit 0x1C*/ +#define TYPE_STAP_A 24 /*single time aggregation packet 0x18*/ + + +static inline void nal_header_init(uint8_t *h, uint8_t nri, uint8_t type){ + *h=((nri&0x3)<<5) | (type & ((1<<5)-1)); +} + +static inline uint8_t nal_header_get_type(const uint8_t *h){ + return (*h) & ((1<<5)-1); +} + +static inline uint8_t nal_header_get_nri(const uint8_t *h){ + return ((*h) >> 5) & 0x3; +} + +void rfc3984_init(Rfc3984Context *ctx){ + ms_queue_init(&ctx->q); + ctx->m=NULL; + ctx->maxsz=ms_get_payload_max_size(); + ctx->mode=0; + ctx->last_ts=0x943FEA43;/*some random value*/ + ctx->stap_a_allowed=TRUE; +} + +void rfc3984_set_max_payload_size(Rfc3984Context *ctx, int size){ + ctx->maxsz=size; +} + +static void send_packet(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t marker){ + mblk_set_timestamp_info(m,ts); + mblk_set_marker_info(m,marker); + ms_queue_put(rtpq,m); +} + +static void put_nal_size(mblk_t *m, uint16_t sz){ + uint16_t size=htons(sz); + *(uint16_t*)m->b_wptr=size; + m->b_wptr+=2; +} + +static mblk_t * prepend_stapa(mblk_t *m){ + mblk_t *hm=allocb(3,0); + nal_header_init(hm->b_wptr,nal_header_get_nri(m->b_rptr),TYPE_STAP_A); + hm->b_wptr+=1; + put_nal_size(hm,msgdsize(m)); + hm->b_cont=m; + return hm; +} + +static mblk_t * concat_nalus(mblk_t *m1, mblk_t *m2){ + mblk_t *l=allocb(2,0); + /*eventually append a stap-A header to m1, if not already done*/ + if (nal_header_get_type(m1->b_rptr)!=TYPE_STAP_A){ + m1=prepend_stapa(m1); + } + put_nal_size(l,msgdsize(m2)); + l->b_cont=m2; + concatb(m1,l); + return m1; +} + +static mblk_t *prepend_fu_indicator_and_header(mblk_t *m, uint8_t indicator, + bool_t start, bool_t end, uint8_t type){ + mblk_t *h=allocb(2,0); + h->b_wptr[0]=indicator; + h->b_wptr[1]=((start&0x1)<<7)|((end&0x1)<<6)|type; + h->b_wptr+=2; + h->b_cont=m; + if (start) m->b_rptr++;/*skip original nalu header */ + return h; +} + +static void frag_nalu_and_send(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker, int maxsize){ + mblk_t *m; + int payload_max_size=maxsize-2;/*minus FUA header*/ + uint8_t fu_indicator; + uint8_t type=nal_header_get_type(nalu->b_rptr); + uint8_t nri=nal_header_get_nri(nalu->b_rptr); + bool_t start=TRUE; + + nal_header_init(&fu_indicator,nri,TYPE_FU_A); + while(nalu->b_wptr-nalu->b_rptr>payload_max_size){ + m=dupb(nalu); + nalu->b_rptr+=payload_max_size; + m->b_wptr=nalu->b_rptr; + m=prepend_fu_indicator_and_header(m,fu_indicator,start,FALSE,type); + send_packet(rtpq,ts,m,FALSE); + start=FALSE; + } + /*send last packet */ + m=prepend_fu_indicator_and_header(nalu,fu_indicator,FALSE,TRUE,type); + send_packet(rtpq,ts,m,marker); +} + +static void rfc3984_pack_mode_0(Rfc3984Context *ctx, MSQueue *naluq, MSQueue *rtpq, uint32_t ts){ + mblk_t *m; + bool_t end; + int size; + while((m=ms_queue_get(naluq))!=NULL){ + end=ms_queue_empty(naluq); + size=m->b_wptr-m->b_rptr; + if (size>ctx->maxsz){ + ms_warning("This H264 packet does not fit into mtu: size=%i",size); + } + send_packet(rtpq,ts,m,end); + } +} + +/*process NALUs and pack them into rtp payloads */ +static void rfc3984_pack_mode_1(Rfc3984Context *ctx, MSQueue *naluq, MSQueue *rtpq, uint32_t ts){ + mblk_t *m,*prevm=NULL; + int prevsz=0,sz; + bool_t end; + while((m=ms_queue_get(naluq))!=NULL){ + end=ms_queue_empty(naluq); + sz=m->b_wptr-m->b_rptr; + if (ctx->stap_a_allowed){ + if (prevm!=NULL){ + if ((prevsz+sz)<(ctx->maxsz-2)){ + prevm=concat_nalus(prevm,m); + m=NULL; + prevsz+=sz+2;/*+2 for the stapa size field*/ + continue; + }else{ + /*send prevm packet: either single nal or STAP-A*/ + if (prevm->b_cont!=NULL){ + ms_debug("Sending STAP-A"); + }else + ms_debug("Sending previous msg as single NAL"); + send_packet(rtpq,ts,prevm,FALSE); + prevm=NULL; + prevsz=0; + } + } + if (sz<(ctx->maxsz/2)){ + /*try to aggregate it with next packet*/ + prevm=m; + prevsz=sz+3; /*STAP-A header + size*/ + m=NULL; + }else{ + + /*send as single nal or FU-A*/ + if (sz>ctx->maxsz){ + ms_debug("Sending FU-A packets"); + frag_nalu_and_send(rtpq,ts,m,end, ctx->maxsz); + }else{ + ms_debug("Sending Single NAL"); + send_packet(rtpq,ts,m,end); + } + } + }else{ + if (sz>ctx->maxsz){ + ms_debug("Sending FU-A packets"); + frag_nalu_and_send(rtpq,ts,m,end, ctx->maxsz); + }else{ + ms_debug("Sending Single NAL"); + send_packet(rtpq,ts,m,end); + } + } + } + if (prevm){ + ms_debug("Sending Single NAL (2)"); + send_packet(rtpq,ts,prevm,TRUE); + } +} + +static mblk_t * aggregate_fua(Rfc3984Context *ctx, mblk_t *im){ + mblk_t *om=NULL; + uint8_t fu_header; + uint8_t nri,type; + bool_t start,end; + fu_header=im->b_rptr[1]; + type=nal_header_get_type(&fu_header); + start=fu_header>>7; + end=(fu_header>>6)&0x1; + if (start){ + nri=nal_header_get_nri(im->b_rptr); + if (ctx->m!=NULL){ + ms_error("receiving FU-A start while previous FU-A is not " + "finished"); + freemsg(ctx->m); + ctx->m=NULL; + } + im->b_rptr++; + nal_header_init(im->b_rptr,nri,type); + ctx->m=im; + }else{ + if (ctx->m!=NULL){ + im->b_rptr+=2; + concatb(ctx->m,im); + }else{ + ms_error("Receiving continuation FU packet but no start."); + freemsg(im); + } + } + if (end && ctx->m){ + msgpullup(ctx->m,-1); + om=ctx->m; + ctx->m=NULL; + } + return om; +} + +/*process incoming rtp data and output NALUs, whenever possible*/ +void rfc3984_unpack(Rfc3984Context *ctx, mblk_t *im, MSQueue *out){ + uint8_t type=nal_header_get_type(im->b_rptr); + uint8_t *p; + int marker = mblk_get_marker_info(im); + uint32_t ts=mblk_get_timestamp_info(im); + + if (ctx->last_ts!=ts){ + /*a new frame is arriving, in case the marker bit was not set in previous frame, output it now*/ + /* unless this is a FU-A (workarond some other apps bugs)*/ + ctx->last_ts=ts; + if (ctx->m==NULL){ + while(!ms_queue_empty(&ctx->q)){ + ms_queue_put(out,ms_queue_get(&ctx->q)); + } + } + } + + if (im->b_cont) msgpullup(im,-1); + + if (type==TYPE_STAP_A){ + ms_debug("Receiving STAP-A"); + /*split into nalus*/ + uint16_t sz; + uint8_t *buf=(uint8_t*)&sz; + mblk_t *nal; + for(p=im->b_rptr+1;pb_wptr;){ + buf[0]=p[0]; + buf[1]=p[1]; + sz=ntohs(sz); + nal=dupb(im); + p+=2; + nal->b_rptr=p; + p+=sz; + nal->b_wptr=p; + if (p>im->b_wptr){ + ms_error("Malformed STAP-A packet"); + freemsg(nal); + break; + } + ms_queue_put(&ctx->q,nal); + } + freemsg(im); + }else if (type==TYPE_FU_A){ + ms_debug("Receiving FU-A"); + mblk_t *o=aggregate_fua(ctx,im); + if (o) ms_queue_put(&ctx->q,o); + }else{ + if (ctx->m){ + /*discontinued FU-A, purge it*/ + freemsg(ctx->m); + ctx->m=NULL; + } + /*single nal unit*/ + ms_debug("Receiving single NAL"); + ms_queue_put(&ctx->q,im); + } + + if (marker){ + ctx->last_ts=ts; + ms_debug("Marker bit set"); + /*end of frame, output everything*/ + while(!ms_queue_empty(&ctx->q)){ + ms_queue_put(out,ms_queue_get(&ctx->q)); + } + } +} + + +void rfc3984_pack(Rfc3984Context *ctx, MSQueue *naluq, MSQueue *rtpq, uint32_t ts){ + switch(ctx->mode){ + case 0: + rfc3984_pack_mode_0(ctx,naluq,rtpq,ts); + break; + case 1: + rfc3984_pack_mode_1(ctx,naluq,rtpq,ts); + break; + default: + ms_error("Bad or unsupported mode %i",ctx->mode); + } +} + +void rfc3984_uninit(Rfc3984Context *ctx){ + ms_queue_flush(&ctx->q); + if (ctx->m) freemsg(ctx->m); + ctx->m=NULL; +} + +void rfc3984_set_mode(Rfc3984Context *ctx, int mode){ + ctx->mode=mode; +} + +void rfc3984_enable_stap_a(Rfc3984Context *ctx, bool_t yesno){ + ctx->stap_a_allowed=yesno; +} diff --git a/linphone/mediastreamer2/src/sdlout.c b/linphone/mediastreamer2/src/sdlout.c new file mode 100644 index 000000000..641e57a97 --- /dev/null +++ b/linphone/mediastreamer2/src/sdlout.c @@ -0,0 +1,375 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msvideo.h" + +#include +#include + +typedef struct SdlOut +{ + MSVideoSize size; + MSVideoSize local_size; /*size of local preview */ + MSPixFmt format; + SDL_Surface *screen; + SDL_Overlay *overlay; + mblk_t *smallb; + int scale_factor; + bool_t lsize_init; +} SdlOut; + + +#define SCALE_FACTOR 6 + +static bool_t sdl_initialized=FALSE; + +static void sdl_out_init(MSFilter *f){ + SdlOut *obj=ms_new(SdlOut,1); + obj->size.width = MS_VIDEO_SIZE_CIF_W; + obj->size.height = MS_VIDEO_SIZE_CIF_H; + obj->local_size.width = MS_VIDEO_SIZE_CIF_W; + obj->local_size.height = MS_VIDEO_SIZE_CIF_H; + obj->lsize_init=FALSE; + obj->scale_factor=SCALE_FACTOR; + obj->format=MS_RGB24; + obj->screen=NULL; + obj->overlay=NULL; + obj->smallb=NULL; + +#if !defined(WIN32) && !defined(__APPLE__) + if (!sdl_initialized){ + + /* Initialize the SDL library */ + if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + ms_error("Couldn't initialize SDL: %s", SDL_GetError()); + return; + } + /* Clean up on exit */ + atexit(SDL_Quit); + sdl_initialized=TRUE; + } +#endif + f->data=obj; +} + +static void sdl_destroy_window(SdlOut *obj){ + if (obj->overlay!=NULL){ + SDL_FreeYUVOverlay(obj->overlay); + obj->overlay=NULL; + } + if (obj->screen!=NULL){ + SDL_FreeSurface(obj->screen); + obj->screen=NULL; + } +} + +static void sdl_out_uninit(MSFilter *f){ + SdlOut *s=(SdlOut*)f->data; + sdl_destroy_window(s); + if (s->smallb!=NULL) freemsg(s->smallb); + ms_free(s); +} + +static void sdl_create_window(SdlOut *obj){ + obj->screen = SDL_SetVideoMode(obj->size.width, obj->size.height, 0,SDL_SWSURFACE); + if ( obj->screen == NULL ) { + ms_warning("Couldn't set video mode: %s\n", + SDL_GetError()); + return ; + } + if (obj->screen->flags & SDL_HWSURFACE) ms_message("SDL surface created in hardware"); + SDL_WM_SetCaption("Linphone Video", NULL); + + if (obj->format==MS_YUV420P){ + ms_message("Using yuv overlay."); + obj->overlay=SDL_CreateYUVOverlay(obj->size.width,obj->size.height,SDL_YV12_OVERLAY,obj->screen); + if (obj->overlay==NULL){ + ms_warning("Couldn't create yuv overlay: %s\n", + SDL_GetError()); + return; + }else{ + if (obj->overlay->hw_overlay) ms_message("YUV overlay using hardware acceleration."); + } + } +} + +mblk_t * resize_yuv_small(unsigned char *pict, int w, int h, int scale){ + int i,j,id,jd; + int nh,nw; + unsigned char *smallpict; + int ysize,usize,ydsize,udsize; + int smallpict_sz; + unsigned char *dptr,*sptr; + mblk_t *smallb; + nw=w/scale; + nh=h/scale; + ysize=w*h; + usize=ysize/4; + ydsize=nw*nh; + udsize=ydsize/4; + smallpict_sz=(ydsize*3)/2; + smallb=allocb(smallpict_sz,0); + smallpict=smallb->b_wptr; + smallb->b_wptr+=smallpict_sz; + + dptr=smallpict; + sptr=pict; + for (j=0,jd=0;jb_rptr; + int i,j; + int jlim,ilim; + int off; + unsigned char *dptr; + + ilim=MIN(x+w,lay->w); + jlim=MIN(y+h,lay->h); + SDL_LockYUVOverlay(lay); + /* set Y */ + dptr=lay->pixels[0]; + for (j=y;jw; + for (i=x;ipixels[2]; + for (j=y/2;jw/2); + for (i=x/2;ipixels[1]; + for (j=y/2;jw/2); + for (i=x/2;ib_rptr; + int ysize=lay->pitches[0]*lay->h; + int usize; + w2=lay->w/2; + h2=lay->h/2; + usize=w2*h2; + SDL_LockYUVOverlay(lay); + memcpy(lay->pixels[0],data,ysize); + memcpy(lay->pixels[2],data+ysize,usize); + memcpy(lay->pixels[1],data+ysize+usize,usize); + SDL_UnlockYUVOverlay(lay); +} + +static void sdl_out_process(MSFilter *f){ + SdlOut *obj=(SdlOut*)f->data; + mblk_t *inm0=NULL; + mblk_t *inm1=NULL; + int err; + SDL_Rect smallrect; + SDL_Rect rect; + bool_t got_preview=FALSE; + +#if defined(WIN32) || defined(__APPLE__) + if (!sdl_initialized){ + + /* Initialize the SDL library */ + if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + ms_error("Couldn't initialize SDL: %s", SDL_GetError()); + return; + } + /* Clean up on exit */ + atexit(SDL_Quit); + sdl_initialized=TRUE; + } +#endif + + if (obj->screen==NULL){ + sdl_create_window(obj); + } + + rect.w=obj->size.width; + rect.h=obj->size.height; + rect.x=0; + rect.y=0; + smallrect.w=obj->size.width/SCALE_FACTOR; + smallrect.h=obj->size.height/SCALE_FACTOR; + smallrect.x=obj->size.width - smallrect.w ; + smallrect.y=obj->size.height -smallrect.h; + + + while (f->inputs[0]!=NULL && (inm0=ms_queue_get(f->inputs[0]))!=NULL){ + SDL_Surface *surf; + if (obj->format==MS_YUV420P){ + fill_overlay(obj->overlay,inm0); + }else { + surf=SDL_CreateRGBSurfaceFrom(inm0->b_rptr,obj->size.width,obj->size.height,24,obj->size.width*3,0,0,0,0); + + err=SDL_BlitSurface(surf,NULL,obj->screen,NULL); + if (err<0) ms_warning("Fail to blit surface: %s",SDL_GetError()); + SDL_FreeSurface(surf); + } + freemsg(inm0); + } + while (f->inputs[1]!=NULL && (inm1=ms_queue_get(f->inputs[1]))!=NULL){ + /* this message is blitted on the right,bottom corner of the screen */ + SDL_Surface *surf; + got_preview=TRUE; + if (!obj->lsize_init){ + /*attempt to guess the video size of the local preview buffer*/ + int bsize=msgdsize(inm1); + if (bsize<(MS_VIDEO_SIZE_CIF_W*MS_VIDEO_SIZE_CIF_H*3/2)){ + /*surely qcif ?*/ + obj->local_size.width=MS_VIDEO_SIZE_QCIF_W; + obj->local_size.height=MS_VIDEO_SIZE_QCIF_H; + ms_message("preview is in QCIF."); + obj->scale_factor=SCALE_FACTOR/2; + } + obj->lsize_init=TRUE; + } + if (obj->format==MS_YUV420P){ + if (obj->smallb!=NULL) { + freemsg(obj->smallb); + } + obj->smallb=resize_yuv_small(inm1->b_rptr,obj->local_size.width,obj->local_size.height,obj->scale_factor); + fill_overlay_at_pos(obj->overlay,obj->smallb,smallrect.x, smallrect.y, smallrect.w, smallrect.h); + freemsg(inm1); + }else { + surf=SDL_CreateRGBSurfaceFrom(inm1->b_rptr,obj->size.width,obj->size.height,24,obj->size.width*3,0,0,0,0); + + err=SDL_BlitSurface(surf,NULL,obj->screen,&smallrect); + if (err<0) ms_warning("Fail to blit surface: %s",SDL_GetError()); + SDL_FreeSurface(surf); + } + } + if (!got_preview){ + /* this is the case were we have only inm0, we have to redisplay inm1 */ + if (obj->format==MS_YUV420P){ + if (obj->smallb!=NULL){ + fill_overlay_at_pos(obj->overlay,obj->smallb,smallrect.x, smallrect.y, smallrect.w, smallrect.h); + } + } + } + + if (obj->format==MS_YUV420P) SDL_DisplayYUVOverlay(obj->overlay,&rect); + else SDL_UpdateRect(obj->screen,0,0,obj->size.width,obj->size.height); + +#if defined(WIN32) || defined(__APPLE__) + { + SDL_Event event; + SDL_PollEvent(&event); + } +#endif +} + +static int sdl_out_set_pix_fmt(MSFilter *f,void *arg){ + SdlOut *s=(SdlOut*)f->data; + s->format=*(MSPixFmt*)arg; + return 0; +} + +static int sdl_out_set_vsize(MSFilter *f,void *arg){ + SdlOut *s=(SdlOut*)f->data; + s->size=*(MSVideoSize*)arg; + s->local_size=*(MSVideoSize*)arg; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_PIX_FMT , sdl_out_set_pix_fmt}, + { MS_FILTER_SET_VIDEO_SIZE , sdl_out_set_vsize }, + { 0 ,NULL} +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_sdl_out_desc={ + MS_SDL_OUT_ID, + "MSSdlOut", + "A video display window using SDL", + MS_FILTER_OTHER, + NULL, + 2, + 0, + sdl_out_init, + NULL, + sdl_out_process, + NULL, + sdl_out_uninit, + methods +}; + +#else + +MSFilterDesc ms_sdl_out_desc={ + .id=MS_SDL_OUT_ID, + .name="MSSdlOut", + .text="A video display window using SDL", + .category=MS_FILTER_OTHER, + .ninputs=2, + .noutputs=0, + .init=sdl_out_init, + .process=sdl_out_process, + .uninit=sdl_out_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_sdl_out_desc) diff --git a/linphone/mediastreamer2/src/sizeconv.c b/linphone/mediastreamer2/src/sizeconv.c new file mode 100644 index 000000000..9e34ba819 --- /dev/null +++ b/linphone/mediastreamer2/src/sizeconv.c @@ -0,0 +1,235 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msvideo.h" + +#include "ffmpeg-priv.h" + +typedef struct SizeConvState{ + MSVideoSize target_vsize; + MSVideoSize in_vsize; + YuvBuf outbuf; + struct SwsContext *sws_ctx; + mblk_t *om; + + float fps; + float start_time; + int frame_count; + queue_t rq; +} SizeConvState; + + +/*this MSFilter will do on the fly picture size conversion. It attempts to guess the picture size from the yuv buffer size. YUV420P is assumed on input. +For now it only supports QCIF->CIF, QVGA->CIF and CIF->CIF (does nothing in this case)*/ + +static void size_conv_init(MSFilter *f){ + SizeConvState *s=(SizeConvState *)ms_new(SizeConvState,1); + s->target_vsize.width = MS_VIDEO_SIZE_CIF_W; + s->target_vsize.height = MS_VIDEO_SIZE_CIF_H; + s->in_vsize.width=0; + s->in_vsize.height=0; + s->sws_ctx=NULL; + s->om=NULL; + s->start_time=0; + s->frame_count=-1; + s->fps=-1; /* default to process ALL frames */ + qinit(&s->rq); + f->data=s; +} + +static void size_conv_uninit(MSFilter *f){ + SizeConvState *s=(SizeConvState*)f->data; + ms_free(s); +} + +static void size_conv_postprocess(MSFilter *f){ + SizeConvState *s=(SizeConvState*)f->data; + if (s->sws_ctx!=NULL) { + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + } + if (s->om!=NULL){ + freemsg(s->om); + s->om=NULL; + } + flushq(&s->rq,0); +} + +static mblk_t *size_conv_alloc_mblk(SizeConvState *s){ + if (s->om!=NULL){ + int ref=s->om->b_datap->db_ref; + if (ref==1){ + return dupmsg(s->om); + }else{ + /*the last msg is still referenced by somebody else*/ + ms_message("size_conv_alloc_mblk: Somebody still retaining yuv buffer (ref=%i)",ref); + freemsg(s->om); + s->om=NULL; + } + } + s->om=yuv_buf_alloc(&s->outbuf,s->target_vsize.width,s->target_vsize.height); + return dupmsg(s->om); +} + +static struct SwsContext * get_resampler(SizeConvState *s, int w, int h){ + if (s->in_vsize.width!=w || + s->in_vsize.height!=h || s->sws_ctx==NULL){ + if (s->sws_ctx!=NULL){ + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + } + s->sws_ctx=sws_getContext(w,h,PIX_FMT_YUV420P, + s->target_vsize.width,s->target_vsize.height,PIX_FMT_YUV420P, + SWS_FAST_BILINEAR,NULL, NULL, NULL); + s->in_vsize.width=w; + s->in_vsize.height=h; + } + return s->sws_ctx; +} + +static void size_conv_process(MSFilter *f){ + SizeConvState *s=(SizeConvState*)f->data; + YuvBuf inbuf; + mblk_t *im; + int cur_frame; + + ms_filter_lock(f); + + if (s->frame_count==-1){ + s->start_time=f->ticker->time; + s->frame_count=0; + } + while((im=ms_queue_get(f->inputs[0]))!=NULL ){ + putq(&s->rq, im); + } + + cur_frame=((f->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame<=s->frame_count && s->fps>=0) { + /* too much frame */ + while(s->rq.q_mcount>1){ + ms_message("MSSizeConv: extra frame removed."); + im=getq(&s->rq); + freemsg(im); + } + ms_filter_unlock(f); + return; + } + + if (cur_frame>s->frame_count && s->fps>=0) { + /*keep the most recent frame if several frames have been captured */ + while(s->rq.q_mcount>1){ + ms_message("MSSizeConv: extra frame removed."); + im=getq(&s->rq); + freemsg(im); + } + } + while((im=getq(&s->rq))!=NULL ){ + if (yuv_buf_init_from_mblk(&inbuf,im)==0){ + if (inbuf.w==s->target_vsize.width && + inbuf.h==s->target_vsize.height){ + ms_queue_put(f->outputs[0],im); + }else{ + struct SwsContext *sws_ctx=get_resampler(s,inbuf.w,inbuf.h); + mblk_t *om=size_conv_alloc_mblk(s); + if (sws_scale(sws_ctx,inbuf.planes,inbuf.strides, 0, + inbuf.h, s->outbuf.planes, s->outbuf.strides)<0){ + ms_error("MSSizeConv: error in sws_scale()."); + } + ms_queue_put(f->outputs[0],om); + freemsg(im); + } + s->frame_count++; + }else freemsg(im); + } + + ms_filter_unlock(f); +} + + +static int sizeconv_set_vsize(MSFilter *f, void*arg){ + SizeConvState *s=(SizeConvState*)f->data; + ms_filter_lock(f); + s->target_vsize=*(MSVideoSize*)arg; + freemsg(s->om); + s->om=NULL; + if (s->sws_ctx!=NULL) { + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + } + ms_filter_unlock(f); + return 0; +} + +static int sizeconv_set_fps(MSFilter *f, void *arg){ + SizeConvState *s=(SizeConvState*)f->data; + s->fps=*((float*)arg); + s->frame_count=-1; /* reset counter used for fps */ + return 0; +} + + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , sizeconv_set_fps }, + { MS_FILTER_SET_VIDEO_SIZE, sizeconv_set_vsize }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_size_conv_desc={ + MS_SIZE_CONV_ID, + "MSSizeConv", + "A video size converter", + MS_FILTER_OTHER, + NULL, + 1, + 1, + size_conv_init, + NULL, + size_conv_process, + size_conv_postprocess, + size_conv_uninit, + methods +}; + +#else + +MSFilterDesc ms_size_conv_desc={ + .id=MS_SIZE_CONV_ID, + .name="MSSizeConv", + .text="a small video size converter", + .ninputs=1, + .noutputs=1, + .init=size_conv_init, + .process=size_conv_process, + .postprocess=size_conv_postprocess, + .uninit=size_conv_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_size_conv_desc) + diff --git a/linphone/mediastreamer2/src/speexec.c b/linphone/mediastreamer2/src/speexec.c new file mode 100644 index 000000000..6a3a4e164 --- /dev/null +++ b/linphone/mediastreamer2/src/speexec.c @@ -0,0 +1,249 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" + +#include +#include + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#ifdef WIN32 +#include /* for alloca */ +#endif + +static const int framesize=128; +static const int filter_length=2048; /*250 ms*/ + +typedef struct SpeexECState{ + SpeexEchoState *ecstate; + MSBufferizer in[2]; + int framesize; + int filterlength; + int samplerate; + SpeexPreprocessState *den; + int ref; + int echo; + int out; +}SpeexECState; + +static void speex_ec_init(MSFilter *f){ + SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1); + + s->samplerate=8000; + s->framesize=framesize; + s->filterlength=filter_length; + + ms_bufferizer_init(&s->in[0]); + ms_bufferizer_init(&s->in[1]); + s->ecstate=speex_echo_state_init(s->framesize,s->filterlength); + s->den = speex_preprocess_state_init(s->framesize, s->samplerate); + + f->data=s; +} + +static void speex_ec_uninit(MSFilter *f){ + SpeexECState *s=(SpeexECState*)f->data; + ms_bufferizer_uninit(&s->in[0]); + ms_bufferizer_uninit(&s->in[1]); + speex_echo_state_destroy(s->ecstate); + if (s->den!=NULL) + speex_preprocess_state_destroy(s->den); + + ms_free(s); +} + +/* inputs[0]= reference signal (sent to soundcard) + inputs[1]= echo signal (read from soundcard) +*/ + + +static void speex_ec_process(MSFilter *f){ + SpeexECState *s=(SpeexECState*)f->data; + int nbytes=s->framesize*2; + uint8_t *in1; + mblk_t *om0,*om1; +#ifdef HAVE_SPEEX_NOISE + spx_int32_t *noise=(spx_int32_t*)alloca(nbytes*sizeof(spx_int32_t)+1); +#else + float *noise=NULL; +#endif +#ifdef AMD_WIN32_HACK + static int count=0; +#endif + + /*read input and put in bufferizers*/ + ms_bufferizer_put_from_queue(&s->in[0],f->inputs[0]); + ms_bufferizer_put_from_queue(&s->in[1],f->inputs[1]); + + in1=(uint8_t*)alloca(nbytes); + + ms_debug("speexec: in0=%i, in1=%i",ms_bufferizer_get_avail(&s->in[0]),ms_bufferizer_get_avail(&s->in[1])); + + while (ms_bufferizer_get_avail(&s->in[0])>=nbytes && ms_bufferizer_get_avail(&s->in[1])>=nbytes){ + om0=allocb(nbytes,0); + ms_bufferizer_read(&s->in[0],(uint8_t*)om0->b_wptr,nbytes); + /* we have reference signal */ + /* the reference signal is sent through outputs[0]*/ + + om0->b_wptr+=nbytes; + ms_queue_put(f->outputs[0],om0); + + ms_bufferizer_read(&s->in[1],in1,nbytes); + /* we have echo signal */ + om1=allocb(nbytes,0); + speex_echo_cancel(s->ecstate,(short*)in1,(short*)om0->b_rptr,(short*)om1->b_wptr,(spx_int32_t*)noise); + if (s->den!=NULL && noise!=NULL) + speex_preprocess(s->den, (short*)om1->b_wptr, (spx_int32_t*)noise); + + om1->b_wptr+=nbytes; + ms_queue_put(f->outputs[1],om1); +#ifdef AMD_WIN32_HACK + count++; + if (count==100*3) + { + ms_message("periodic reset of echo canceller."); + speex_echo_state_reset(s->ecstate); + count=0; + } +#endif + } + + if (ms_bufferizer_get_avail(&s->in[0])> 4*320*(s->samplerate/8000)) /* above 4*20ms -> useless */ + { + /* reset evrything */ + ms_warning("speexec: -reset of echo canceller- in0=%i, in1=%i",ms_bufferizer_get_avail(&s->in[0]),ms_bufferizer_get_avail(&s->in[1])); + flushq(&s->in[1].q,0); + flushq(&s->in[0].q,0); + ms_bufferizer_init(&s->in[0]); + ms_bufferizer_init(&s->in[1]); + speex_echo_state_reset(s->ecstate); + } + + while (ms_bufferizer_get_avail(&s->in[1])> 4*320*(s->samplerate/8000)){ + om1=allocb(nbytes,0); + ms_bufferizer_read(&s->in[1],(uint8_t*)om1->b_wptr,nbytes); + om1->b_wptr+=nbytes; + ms_queue_put(f->outputs[1],om1); + ms_message("too much echo signal, sending anyway."); + speex_echo_state_reset(s->ecstate); + } + +} + +static int speex_ec_set_sr(MSFilter *f, void *arg){ +#ifdef SPEEX_ECHO_SET_SAMPLING_RATE + SpeexECState *s=(SpeexECState*)f->data; + + s->samplerate = *(int*)arg; + + if (s->ecstate==NULL) + speex_echo_state_destroy(s->ecstate); + if (s->den!=NULL) + speex_preprocess_state_destroy(s->den); + + s->ecstate=speex_echo_state_init(s->framesize,s->filterlength); + speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate); + s->den = speex_preprocess_state_init(s->framesize, s->samplerate); +#else + ms_error("Speex echocanceler does not support 16Khz sampling rate in this version!"); +#endif + return 0; +} + +static int speex_ec_set_framesize(MSFilter *f, void *arg){ + SpeexECState *s=(SpeexECState*)f->data; + s->framesize = *(int*)arg; + + if (s->ecstate==NULL) + speex_echo_state_destroy(s->ecstate); + if (s->den!=NULL) + speex_preprocess_state_destroy(s->den); + + s->ecstate=speex_echo_state_init(s->framesize,s->filterlength); +#ifdef SPEEX_ECHO_SET_SAMPLING_RATE + speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate); +#endif + s->den = speex_preprocess_state_init(s->framesize, s->samplerate); + return 0; +} + +static int speex_ec_set_filterlength(MSFilter *f, void *arg){ + SpeexECState *s=(SpeexECState*)f->data; + s->filterlength = *(int*)arg; + + if (s->ecstate==NULL) + speex_echo_state_destroy(s->ecstate); + if (s->den!=NULL) + speex_preprocess_state_destroy(s->den); + + s->ecstate=speex_echo_state_init(s->framesize,s->filterlength); +#ifdef SPEEX_ECHO_SET_SAMPLING_RATE + speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate); +#endif + s->den = speex_preprocess_state_init(s->framesize, s->samplerate); + + return 0; +} + +static MSFilterMethod speex_ec_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE, speex_ec_set_sr }, + { MS_FILTER_SET_FRAMESIZE, speex_ec_set_framesize }, + { MS_FILTER_SET_FILTERLENGTH, speex_ec_set_filterlength }, + { 0 , NULL} +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_speex_ec_desc={ + MS_SPEEX_EC_ID, + "MSSpeexEC", + "Echo canceler using speex library", + MS_FILTER_OTHER, + NULL, + 2, + 2, + speex_ec_init, + NULL, + speex_ec_process, + NULL, + speex_ec_uninit, + speex_ec_methods +}; + +#else + +MSFilterDesc ms_speex_ec_desc={ + .id=MS_SPEEX_EC_ID, + .name="MSSpeexEC", + .text="Echo canceler using speex library", + .category=MS_FILTER_OTHER, + .ninputs=2, + .noutputs=2, + .init=speex_ec_init, + .process=speex_ec_process, + .uninit=speex_ec_uninit, + .methods=speex_ec_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_speex_ec_desc) diff --git a/linphone/mediastreamer2/src/swscale.h b/linphone/mediastreamer2/src/swscale.h new file mode 100644 index 000000000..a0c735b69 --- /dev/null +++ b/linphone/mediastreamer2/src/swscale.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2001-2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FFMPEG_SWSCALE_H +#define FFMPEG_SWSCALE_H + +/** + * @file swscale.h + * @brief + * external api for the swscale stuff + */ + +#include "libavutil/avutil.h" + +#define LIBSWSCALE_VERSION_MAJOR 0 +#define LIBSWSCALE_VERSION_MINOR 5 +#define LIBSWSCALE_VERSION_MICRO 1 + +#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT + +#define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) + +/* values for the flags, the stuff on the command line is different */ +#define SWS_FAST_BILINEAR 1 +#define SWS_BILINEAR 2 +#define SWS_BICUBIC 4 +#define SWS_X 8 +#define SWS_POINT 0x10 +#define SWS_AREA 0x20 +#define SWS_BICUBLIN 0x40 +#define SWS_GAUSS 0x80 +#define SWS_SINC 0x100 +#define SWS_LANCZOS 0x200 +#define SWS_SPLINE 0x400 + +#define SWS_SRC_V_CHR_DROP_MASK 0x30000 +#define SWS_SRC_V_CHR_DROP_SHIFT 16 + +#define SWS_PARAM_DEFAULT 123456 + +#define SWS_PRINT_INFO 0x1000 + +//the following 3 flags are not completely implemented +//internal chrominace subsampling info +#define SWS_FULL_CHR_H_INT 0x2000 +//input subsampling info +#define SWS_FULL_CHR_H_INP 0x4000 +#define SWS_DIRECT_BGR 0x8000 +#define SWS_ACCURATE_RND 0x40000 + +#define SWS_CPU_CAPS_MMX 0x80000000 +#define SWS_CPU_CAPS_MMX2 0x20000000 +#define SWS_CPU_CAPS_3DNOW 0x40000000 +#define SWS_CPU_CAPS_ALTIVEC 0x10000000 +#define SWS_CPU_CAPS_BFIN 0x01000000 + +#define SWS_MAX_REDUCE_CUTOFF 0.002 + +#define SWS_CS_ITU709 1 +#define SWS_CS_FCC 4 +#define SWS_CS_ITU601 5 +#define SWS_CS_ITU624 5 +#define SWS_CS_SMPTE170M 5 +#define SWS_CS_SMPTE240M 7 +#define SWS_CS_DEFAULT 5 + + + +// when used for filters they must have an odd number of elements +// coeffs cannot be shared between vectors +typedef struct { + double *coeff; + int length; +} SwsVector; + +// vectors can be shared +typedef struct { + SwsVector *lumH; + SwsVector *lumV; + SwsVector *chrH; + SwsVector *chrV; +} SwsFilter; + +struct SwsContext; + +void sws_freeContext(struct SwsContext *swsContext); + +struct SwsContext *sws_getContext(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat, int flags, + SwsFilter *srcFilter, SwsFilter *dstFilter, double *param); +int sws_scale(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY, + int srcSliceH, uint8_t* dst[], int dstStride[]); +int sws_scale_ordered(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY, + int srcSliceH, uint8_t* dst[], int dstStride[]) attribute_deprecated; + + +int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], int srcRange, const int table[4], int dstRange, int brightness, int contrast, int saturation); +int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table, int *srcRange, int **table, int *dstRange, int *brightness, int *contrast, int *saturation); +SwsVector *sws_getGaussianVec(double variance, double quality); +SwsVector *sws_getConstVec(double c, int length); +SwsVector *sws_getIdentityVec(void); +void sws_scaleVec(SwsVector *a, double scalar); +void sws_normalizeVec(SwsVector *a, double height); +void sws_convVec(SwsVector *a, SwsVector *b); +void sws_addVec(SwsVector *a, SwsVector *b); +void sws_subVec(SwsVector *a, SwsVector *b); +void sws_shiftVec(SwsVector *a, int shift); +SwsVector *sws_cloneVec(SwsVector *a); + +void sws_printVec(SwsVector *a); +void sws_freeVec(SwsVector *a); + +SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur, + float lumaSarpen, float chromaSharpen, + float chromaHShift, float chromaVShift, + int verbose); +void sws_freeFilter(SwsFilter *filter); + +struct SwsContext *sws_getCachedContext(struct SwsContext *context, + int srcW, int srcH, int srcFormat, + int dstW, int dstH, int dstFormat, int flags, + SwsFilter *srcFilter, SwsFilter *dstFilter, double *param); + +#endif /* FFMPEG_SWSCALE_H */ diff --git a/linphone/mediastreamer2/src/tee.c b/linphone/mediastreamer2/src/tee.c new file mode 100644 index 000000000..fd300fef0 --- /dev/null +++ b/linphone/mediastreamer2/src/tee.c @@ -0,0 +1,110 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/mstee.h" + +#define MS_TEE_NOUTPUTS 10 + +typedef struct _TeeData{ + bool_t muted[MS_TEE_NOUTPUTS]; +}TeeData; + +static void tee_init(MSFilter *f){ + f->data=ms_new0(TeeData,1); +} + +static void tee_uninit(MSFilter *f){ + ms_free(f->data); +} + +static void tee_process(MSFilter *f){ + TeeData *d=(TeeData*)f->data; + mblk_t *im; + int i; + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + for(i=0;idesc->noutputs;i++){ + if (f->outputs[i]!=NULL && !d->muted[i]) + ms_queue_put(f->outputs[i],dupmsg(im)); + } + freemsg(im); + } +} + +static int tee_mute(MSFilter *f, void *arg){ + TeeData *d=(TeeData*)f->data; + int pin=((int*)arg)[0]; + if (pin>=0 && pinmuted[pin]=TRUE; + return 0; + } + return -1; +} + +static int tee_unmute(MSFilter *f, void *arg){ + TeeData *d=(TeeData*)f->data; + int pin=((int*)arg)[0]; + if (pin>=0 && pinmuted[pin]=FALSE; + return 0; + } + return -1; +} + +static MSFilterMethod tee_methods[]={ + { MS_TEE_MUTE , tee_mute }, + { MS_TEE_UNMUTE , tee_unmute }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_tee_desc={ + MS_TEE_ID, + "MSTee", + "A filter that reads from input and copy to its multiple outputs.", + MS_FILTER_OTHER, + NULL, + 1, + MS_TEE_NOUTPUTS, + tee_init, + NULL, + tee_process, + NULL, + tee_uninit, + tee_methods +}; + +#else + +MSFilterDesc ms_tee_desc={ + .id=MS_TEE_ID, + .name="MSTee", + .text="A filter that reads from input and copy to its multiple outputs.", + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=MS_TEE_NOUTPUTS, + .init=tee_init, + .process=tee_process, + .uninit=tee_uninit, + .methods=tee_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_tee_desc) diff --git a/linphone/mediastreamer2/src/theora.c b/linphone/mediastreamer2/src/theora.c new file mode 100644 index 000000000..f43282eb0 --- /dev/null +++ b/linphone/mediastreamer2/src/theora.c @@ -0,0 +1,582 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msvideo.h" + +#include + +typedef struct EncState{ + theora_state tstate; + theora_info tinfo; + yuv_buffer yuv; + mblk_t *packed_conf; + uint64_t start_time; + uint64_t conf_time; + unsigned int mtu; +} EncState; + +static void enc_init(MSFilter *f){ + EncState *s=(EncState *)ms_new(EncState,1); + theora_info_init(&s->tinfo); + s->tinfo.width=MS_VIDEO_SIZE_CIF_W; + s->tinfo.height=MS_VIDEO_SIZE_CIF_H; + s->tinfo.frame_width=MS_VIDEO_SIZE_CIF_W; + s->tinfo.frame_height=MS_VIDEO_SIZE_CIF_H; + s->tinfo.offset_x=0; + s->tinfo.offset_y=0; + s->tinfo.target_bitrate=500000; + s->tinfo.pixelformat=OC_PF_420; + s->tinfo.fps_numerator=15; + s->tinfo.fps_denominator=1; + s->tinfo.aspect_numerator=1; + s->tinfo.aspect_denominator=1; + s->tinfo.colorspace=OC_CS_UNSPECIFIED; + s->tinfo.dropframes_p=0; + s->tinfo.quick_p=1; + s->tinfo.quality=63; + s->tinfo.keyframe_auto_p=1; + s->tinfo.keyframe_frequency=64; + s->tinfo.keyframe_frequency_force=64; + s->tinfo.keyframe_data_target_bitrate=s->tinfo.target_bitrate*1.2; + s->tinfo.keyframe_auto_threshold=80; + s->tinfo.keyframe_mindistance=8; + s->tinfo.noise_sensitivity=1; + s->packed_conf=NULL; + s->start_time=0; + s->conf_time=0; + s->mtu=ms_get_payload_max_size()-6; + f->data=s; +} + +static void enc_uninit(MSFilter *f){ + EncState *s=(EncState*)f->data; + theora_info_clear(&s->tinfo); + ms_free(s); +} + +static int enc_set_vsize(MSFilter *f, void*data){ + MSVideoSize *vs=(MSVideoSize*)data; + EncState *s=(EncState*)f->data; + s->tinfo.width=vs->width; + s->tinfo.height=vs->height; + s->tinfo.frame_width=vs->width; + s->tinfo.frame_height=vs->height; + return 0; +} + +static int enc_get_vsize(MSFilter *f, void *data){ + EncState *s=(EncState*)f->data; + MSVideoSize *vs=(MSVideoSize*)data; + vs->width=s->tinfo.width; + vs->height=s->tinfo.height; + return 0; +} + +static int enc_add_attr(MSFilter *f, void*data){ + /*const char *attr=(const char*)data; + EncState *s=(EncState*)f->data;*/ + return 0; +} + +static int enc_set_fps(MSFilter *f, void *data){ + float *fps=(float*)data; + EncState *s=(EncState*)f->data; + s->tinfo.fps_numerator=*fps; + s->tinfo.keyframe_frequency=(*fps)*5; + s->tinfo.keyframe_frequency_force=(*fps)*5; + return 0; +} + +static int enc_get_fps(MSFilter *f, void *data){ + EncState *s=(EncState*)f->data; + float *fps=(float*)data; + *fps=s->tinfo.fps_numerator; + return 0; +} + +static int enc_set_br(MSFilter *f, void*data){ + int br=*(int*)data; + EncState *s=(EncState*)f->data; + MSVideoSize vsize; + float fps; + float codecbr=(float)br; + vsize.width=s->tinfo.width; + vsize.height=s->tinfo.height; + fps=s->tinfo.fps_numerator; + s->tinfo.target_bitrate=codecbr*0.8; + s->tinfo.keyframe_data_target_bitrate=codecbr; + /*those default settings would need to be affined*/ + if (br>=512000){ + vsize.width = MS_VIDEO_SIZE_CIF_W; + vsize.height = MS_VIDEO_SIZE_CIF_H; + s->tinfo.quality=32; + fps=15; + }else if (br>=256000){ + vsize.width = MS_VIDEO_SIZE_CIF_W; + vsize.height = MS_VIDEO_SIZE_CIF_H; + s->tinfo.quality=5; + fps=12; + }else if(br>=128000){ + vsize.width=MS_VIDEO_SIZE_QCIF_W; + vsize.height=MS_VIDEO_SIZE_QCIF_H; + s->tinfo.quality=20; + fps=10; + }else if(br>=64000){ + vsize.width=MS_VIDEO_SIZE_QCIF_W; + vsize.height=MS_VIDEO_SIZE_QCIF_H; + s->tinfo.quality=7; + fps=7; + } + enc_set_vsize(f,&vsize); + enc_set_fps(f,&fps); + return 0; +} + +static int enc_set_mtu(MSFilter *f, void*data){ + EncState *s=(EncState*)f->data; + s->mtu=*(int*)data; + return 0; +} + +#define THEORA_RAW_DATA 0 +#define THEORA_PACKED_CONF 1 +#define THEORA_COMMENT 2 +#define THEORA_RESERVED 3 + +#define NOT_FRAGMENTED 0 +#define START_FRAGMENT 1 +#define CONT_FRAGMENT 2 +#define END_FRAGMENT 3 + + +static inline void payload_header_set(uint8_t *buf, uint32_t ident, uint8_t ft, uint8_t tdt, uint8_t pkts){ + uint32_t tmp; + tmp=((ident&0xFFFFFF)<<8) | ((ft&0x3)<<6) | ((tdt&0x3)<<4) | (pkts&0xf); + *((uint32_t*)buf)=htonl(tmp); +} + +static inline uint32_t payload_header_get_ident(uint8_t *buf){ + uint32_t *tmp=(uint32_t*)buf; + return (ntohl(*tmp)>>8) & 0xFFFFFF; +} + +static inline uint32_t payload_header_get_tdt(uint8_t *buf){ + uint32_t *tmp=(uint32_t*)buf; + return ((ntohl(*tmp))>>4) & 0x3; +} + +static inline uint32_t payload_header_get_ft(uint8_t *buf){ + uint32_t *tmp=(uint32_t*)buf; + return ((ntohl(*tmp))>>6) & 0x3; +} + +static inline uint32_t payload_header_get_pkts(uint8_t *buf){ + uint32_t *tmp=(uint32_t*)buf; + return ntohl(*tmp) & 0xf; +} + +static int create_packed_conf(EncState *s){ + ogg_packet p; + theora_state *tstate=&s->tstate; + mblk_t *h,*t; + if (theora_encode_header(tstate,&p)!=0){ + ms_error("theora_encode_header() error."); + return -1; + } + h=allocb(p.bytes,0); + memcpy(h->b_wptr,p.packet,p.bytes); + h->b_wptr+=p.bytes; + if (theora_encode_tables(tstate,&p)!=0){ + ms_error("theora_encode_tables error."); + freemsg(h); + return -1; + } + t=allocb(p.bytes,0); + memcpy(t->b_wptr,p.packet,p.bytes); + t->b_wptr+=p.bytes; + h->b_cont=t; + msgpullup(h,-1); + s->packed_conf=h; + return 0; +} + +static void enc_preprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + int err; + if ((err=theora_encode_init(&s->tstate,&s->tinfo))!=0){ + ms_error("error in theora_encode_init() : %i !",err); + } + s->yuv.y_width=s->tinfo.width; + s->yuv.y_height=s->tinfo.height; + s->yuv.y_stride=s->tinfo.width; + s->yuv.uv_width=s->tinfo.width/2; + s->yuv.uv_height=s->tinfo.height/2; + s->yuv.uv_stride=s->tinfo.width/2; + create_packed_conf(s); + s->conf_time=0; + s->start_time=f->ticker->time; +} + +static void enc_postprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + theora_clear(&s->tstate); + + //If preprocess is called after postprocess, + //then we loose all info... + //theora_info_clear(&s->tinfo); + + if (s->packed_conf) { + freemsg(s->packed_conf); + s->packed_conf=NULL; + } +} + +static void enc_fill_yuv(yuv_buffer *yuv, mblk_t *im){ + yuv->y=(uint8_t*)im->b_rptr; + yuv->u=(uint8_t*)im->b_rptr+(yuv->y_stride*yuv->y_height); + yuv->v=(uint8_t*)yuv->u+(yuv->uv_stride*yuv->uv_height); +} + + +static void packetize_and_send(MSFilter *f, EncState *s, mblk_t *om, uint32_t timestamp, uint8_t tdt){ + mblk_t *packet; + mblk_t *h; + int npackets=0; + static const int ident=0xdede; + while(om!=NULL){ + if (om->b_wptr-om->b_rptr>=s->mtu){ + packet=dupb(om); + packet->b_wptr=packet->b_rptr+s->mtu; + om->b_rptr=packet->b_wptr; + }else { + packet=om; + om=NULL; + } + ++npackets; + h=allocb(6,0); + if (npackets==1){ + if (om==NULL) + payload_header_set(h->b_wptr,ident,NOT_FRAGMENTED,tdt,1); + else + payload_header_set(h->b_wptr,ident,START_FRAGMENT,tdt,1); + }else{ + if (om==NULL) + payload_header_set(h->b_wptr,ident,END_FRAGMENT,tdt,1); + else + payload_header_set(h->b_wptr,ident,CONT_FRAGMENT,tdt,1); + } + h->b_wptr+=4; + *((uint16_t*)h->b_wptr)=htons(msgdsize(packet)); + h->b_wptr+=2; + h->b_cont=packet; + mblk_set_timestamp_info(h,timestamp); + ms_debug("sending theora frame of size %i",msgdsize(h)); + ms_queue_put(f->outputs[0],h); + } +} + +bool_t need_send_conf(EncState *s, uint64_t elapsed){ +#ifdef AMD_HACK + if (elapsed<5000 && elapsed>=s->conf_time){ + s->conf_time+=500; + return TRUE; + } +#else + /*send immediately then 10 seconds later */ + if ( (elapsed<1000 && s->conf_time==0) + || (elapsed>10000 && s->conf_time==1)){ + s->conf_time++; + return TRUE; + } +#endif + return FALSE; +} + +static void enc_process(MSFilter *f){ + mblk_t *im,*om; + ogg_packet op; + EncState *s=(EncState*)f->data; + uint64_t timems=f->ticker->time; + uint32_t timestamp=timems*90; + uint64_t elapsed=timems-s->start_time; + while((im=ms_queue_get(f->inputs[0]))!=NULL){ + /*for the firsts frames only send theora packed conf*/ + om=NULL; + + if (need_send_conf(s,elapsed)){ + if (s->packed_conf) { + om=dupmsg(s->packed_conf); + ms_message("sending theora packed conf (%i bytes)",msgdsize(om)); + packetize_and_send(f,s,om,timestamp,THEORA_PACKED_CONF); + }else { + ms_error("No packed conf to send."); + } + }else{ + enc_fill_yuv(&s->yuv,im); + ms_debug("subtmitting yuv frame to theora encoder..."); + if (theora_encode_YUVin(&s->tstate,&s->yuv)!=0){ + ms_error("theora_encode_YUVin error."); + }else{ + if (theora_encode_packetout(&s->tstate,0,&op)==1){ + ms_debug("Got theora coded frame"); + om=allocb(op.bytes,0); + memcpy(om->b_wptr,op.packet,op.bytes); + om->b_wptr+=op.bytes; + packetize_and_send(f,s,om,timestamp,THEORA_RAW_DATA); + } + } + } + freemsg(im); + } +} + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize }, + { MS_FILTER_SET_FPS, enc_set_fps }, + { MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize }, + { MS_FILTER_GET_FPS, enc_get_fps }, + { MS_FILTER_ADD_ATTR, enc_add_attr }, + { MS_FILTER_SET_BITRATE, enc_set_br }, + { MS_FILTER_SET_MTU, enc_set_mtu }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_theora_enc_desc={ + MS_THEORA_ENC_ID, + "MSTheoraEnc", + "The theora video encoder from xiph.org", + MS_FILTER_ENCODER, + "theora", + 1, + 1, + enc_init, + enc_preprocess, + enc_process, + enc_postprocess, + enc_uninit, + enc_methods +}; + +#else + +MSFilterDesc ms_theora_enc_desc={ + .id=MS_THEORA_ENC_ID, + .name="MSTheoraEnc", + .text="The open-source and royalty-free 'theora' video codec from xiph.org", + .category=MS_FILTER_ENCODER, + .enc_fmt="theora", + .ninputs=1, + .noutputs=1, + .init=enc_init, + .preprocess=enc_preprocess, + .process=enc_process, + .postprocess=enc_postprocess, + .uninit=enc_uninit, + .methods=enc_methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_theora_enc_desc) + +typedef struct DecState{ + theora_state tstate; + theora_info tinfo; + mblk_t *yuv; + mblk_t *curframe; + bool_t ready; +}DecState; + +static void dec_init(MSFilter *f){ + DecState *s=(DecState *)ms_new(DecState,1); + s->ready=FALSE; + theora_info_init(&s->tinfo); + s->yuv=NULL; + s->curframe=NULL; + f->data=s; +} + +static void dec_uninit(MSFilter *f){ + DecState *s=(DecState*)f->data; + if (s->yuv!=NULL) freemsg(s->yuv); + if (s->curframe!=NULL) freemsg(s->curframe); + theora_info_clear(&s->tinfo); + ms_free(s); +} + +static bool_t dec_init_theora(DecState *s, ogg_packet *op){ + theora_comment tcom; + static const int ident_packet_size=42; + theora_comment_init(&tcom); + tcom.vendor="dummy"; + op->b_o_s=1; + if (theora_decode_header(&s->tinfo,&tcom,op)==0){ + op->packet+=ident_packet_size; + op->bytes-=ident_packet_size; + /*recall once to decode tables*/ + if (theora_decode_header(&s->tinfo,&tcom,op)==0){ + if (theora_decode_init(&s->tstate,&s->tinfo)==0){ + ms_debug("theora decoder ready, pixfmt=%i", + s->tinfo.pixelformat); + return TRUE; + } + }else{ + ms_warning("error decoding theora tables"); + } + }else{ + ms_warning("error decoding theora header"); + } + return FALSE; +} +/* remove payload header and agregates fragmented packets */ +static mblk_t *dec_unpacketize(MSFilter *f, DecState *s, mblk_t *im, int *tdt){ + uint8_t ft; + *tdt=payload_header_get_tdt((uint8_t*)im->b_rptr); + ft=payload_header_get_ft((uint8_t*)im->b_rptr); + im->b_rptr+=6; + + if (ft==NOT_FRAGMENTED) return im; + if (ft==START_FRAGMENT){ + if (s->curframe!=NULL) + freemsg(s->curframe); + s->curframe=im; + }else if (ft==CONT_FRAGMENT){ + if (s->curframe!=NULL) + concatb(s->curframe,im); + else + freemsg(im); + }else{/*end fragment*/ + if (s->curframe!=NULL){ + mblk_t *ret; + concatb(s->curframe,im); + msgpullup(s->curframe,-1); + ret=s->curframe; + s->curframe=NULL; + return ret; + }else + freemsg(im); + } + return NULL; +} + +static void dec_process_frame(MSFilter *f, DecState *s, ogg_packet *op){ + yuv_buffer yuv; + if (theora_decode_packetin(&s->tstate,op)==0){ + if (theora_decode_YUVout(&s->tstate,&yuv)==0){ + mblk_t *om; + int i; + int ylen=yuv.y_width*yuv.y_height; + int uvlen=yuv.uv_width*yuv.uv_height; + ms_debug("Got yuv buffer from theora decoder"); + if (s->yuv==NULL){ + int len=(ylen)+(2*uvlen); + s->yuv=allocb(len,0); + } + om=dupb(s->yuv); + for(i=0;ib_wptr,yuv.y+yuv.y_stride*i,yuv.y_width); + om->b_wptr+=yuv.y_width; + } + for(i=0;ib_wptr,yuv.u+yuv.uv_stride*i,yuv.uv_width); + om->b_wptr+=yuv.uv_width; + } + for(i=0;ib_wptr,yuv.v+yuv.uv_stride*i,yuv.uv_width); + om->b_wptr+=yuv.uv_width; + } + ms_queue_put(f->outputs[0],om); + } + }else{ + ms_warning("theora decoding error"); + } +} + +static void dec_process(MSFilter *f){ + mblk_t *im; + mblk_t *m; + ogg_packet op; + int tdt; + DecState *s=(DecState*)f->data; + while( (im=ms_queue_get(f->inputs[0]))!=0) { + m=dec_unpacketize(f,s,im,&tdt); + if (m!=NULL){ + /* now in im we have only the theora data*/ + op.packet=(uint8_t*)m->b_rptr; + op.bytes=m->b_wptr-m->b_rptr; + op.b_o_s=0; + op.e_o_s=0; + op.granulepos=0; + op.packetno=0; + if (tdt!=THEORA_RAW_DATA) /*packed conf*/ { + if (!s->ready){ + if (dec_init_theora(s,&op)) + s->ready=TRUE; + } + }else{ + if (s->ready){ + dec_process_frame(f,s,&op); + }else{ + ms_warning("skipping theora packet because decoder was not initialized yet with theora header and tables"); + } + } + freemsg(m); + } + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_theora_dec_desc={ + MS_THEORA_DEC_ID, + "MSTheoraDec", + "The theora video decoder from xiph.org", + MS_FILTER_DECODER, + "theora", + 1, + 1, + dec_init, + NULL, + dec_process, + NULL, + dec_uninit, + NULL +}; + +#else + +MSFilterDesc ms_theora_dec_desc={ + .id=MS_THEORA_DEC_ID, + .name="MSTheoraDec", + .text="The theora video decoder from xiph.org", + .category=MS_FILTER_DECODER, + .enc_fmt="theora", + .ninputs=1, + .noutputs=1, + .init=dec_init, + .process=dec_process, + .uninit=dec_uninit +}; + +#endif +MS_FILTER_DESC_EXPORT(ms_theora_dec_desc) diff --git a/linphone/mediastreamer2/src/ulaw.c b/linphone/mediastreamer2/src/ulaw.c new file mode 100644 index 000000000..de1c6788e --- /dev/null +++ b/linphone/mediastreamer2/src/ulaw.c @@ -0,0 +1,227 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msfilter.h" +#include "g711common.h" + +typedef struct _UlawEncData{ + MSBufferizer *bz; + int ptime; + uint32_t ts; +} UlawEncData; + +static UlawEncData * ulaw_enc_data_new(){ + UlawEncData *obj=(UlawEncData *)ms_new(UlawEncData,1); + obj->bz=ms_bufferizer_new(); + obj->ptime=0; + obj->ts=0; + return obj; +} + +static void ulaw_enc_data_destroy(UlawEncData *obj){ + ms_bufferizer_destroy(obj->bz); + ms_free(obj); +} + +static void ulaw_enc_init(MSFilter *obj){ + obj->data=ulaw_enc_data_new(); +} + +static void ulaw_enc_uninit(MSFilter *obj){ + ulaw_enc_data_destroy((UlawEncData*)obj->data); +} + +static void ulaw_enc_process(MSFilter *obj){ + UlawEncData *dt=(UlawEncData*)obj->data; + MSBufferizer *bz=dt->bz; + uint8_t buffer[2240]; + int frame_per_packet=2; + int size_of_pcm=320; + + mblk_t *m; + + if (dt->ptime>=10) + { + frame_per_packet = dt->ptime/10; + } + + if (frame_per_packet<=0) + frame_per_packet=1; + if (frame_per_packet>14) /* 7*20 == 140 ms max */ + frame_per_packet=14; + + size_of_pcm = 160*frame_per_packet; /* ex: for 20ms -> 160*2==320 */ + + while((m=ms_queue_get(obj->inputs[0]))!=NULL){ + ms_bufferizer_put(bz,m); + } + + while (ms_bufferizer_read(bz,buffer,size_of_pcm)==size_of_pcm){ + mblk_t *o=allocb(size_of_pcm/2,0); + int i; + for (i=0;ib_wptr=s16_to_ulaw(((int16_t*)buffer)[i]); + o->b_wptr++; + } + mblk_set_timestamp_info(o,dt->ts); + dt->ts+=size_of_pcm/2; + ms_queue_put(obj->outputs[0],o); + } +} + +static int enc_add_fmtp(MSFilter *f, void *arg){ + const char *fmtp=(const char *)arg; + UlawEncData *s=(UlawEncData*)f->data; + char val[30]; + if (fmtp_get_value(fmtp,"ptime",val,sizeof(val))){ + s->ptime=atoi(val); + ms_message("MSUlawEnc: got ptime=%i",s->ptime); + } + return 0; +} + + +static int enc_add_attr(MSFilter *f, void *arg){ + const char *fmtp=(const char *)arg; + UlawEncData *s=(UlawEncData*)f->data; + if (strstr(fmtp,"ptime:10")!=NULL){ + s->ptime=10; + }else if (strstr(fmtp,"ptime:20")!=NULL){ + s->ptime=20; + }else if (strstr(fmtp,"ptime:30")!=NULL){ + s->ptime=30; + }else if (strstr(fmtp,"ptime:40")!=NULL){ + s->ptime=40; + }else if (strstr(fmtp,"ptime:50")!=NULL){ + s->ptime=50; + }else if (strstr(fmtp,"ptime:60")!=NULL){ + s->ptime=60; + }else if (strstr(fmtp,"ptime:70")!=NULL){ + s->ptime=70; + }else if (strstr(fmtp,"ptime:80")!=NULL){ + s->ptime=80; + }else if (strstr(fmtp,"ptime:90")!=NULL){ + s->ptime=90; + }else if (strstr(fmtp,"ptime:100")!=NULL){ + s->ptime=100; + }else if (strstr(fmtp,"ptime:110")!=NULL){ + s->ptime=110; + }else if (strstr(fmtp,"ptime:120")!=NULL){ + s->ptime=120; + }else if (strstr(fmtp,"ptime:130")!=NULL){ + s->ptime=130; + }else if (strstr(fmtp,"ptime:140")!=NULL){ + s->ptime=140; + } + return 0; +} + +static MSFilterMethod enc_methods[]={ + { MS_FILTER_ADD_ATTR , enc_add_attr}, + { MS_FILTER_ADD_FMTP , enc_add_fmtp}, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_ulaw_enc_desc={ + MS_ULAW_ENC_ID, + "MSUlawEnc", + "ITU-G.711 ulaw encoder", + MS_FILTER_ENCODER, + "pcmu", + 1, + 1, + ulaw_enc_init, + NULL, + ulaw_enc_process, + NULL, + ulaw_enc_uninit, + enc_methods +}; + +#else + +MSFilterDesc ms_ulaw_enc_desc={ + .id=MS_ULAW_ENC_ID, + .name="MSUlawEnc", + .text="ITU-G.711 ulaw encoder", + .category=MS_FILTER_ENCODER, + .enc_fmt="pcmu", + .ninputs=1, + .noutputs=1, + .init=ulaw_enc_init, + .process=ulaw_enc_process, + .uninit=ulaw_enc_uninit, + .methods=enc_methods +}; + +#endif + +static void ulaw_dec_process(MSFilter *obj){ + mblk_t *m; + while((m=ms_queue_get(obj->inputs[0]))!=NULL){ + mblk_t *o; + msgpullup(m,-1); + o=allocb((m->b_wptr-m->b_rptr)*2,0); + for(;m->b_rptrb_wptr;m->b_rptr++,o->b_wptr+=2){ + *((int16_t*)(o->b_wptr))=ulaw_to_s16(*m->b_rptr); + } + freemsg(m); + ms_queue_put(obj->outputs[0],o); + } +} + +#ifdef _MSC_VER + +MSFilterDesc ms_ulaw_dec_desc={ + MS_ULAW_DEC_ID, + "MSUlawDec", + "ITU-G.711 ulaw decoder", + MS_FILTER_DECODER, + "pcmu", + 1, + 1, + NULL, + NULL, + ulaw_dec_process, + NULL, + NULL, + NULL +}; + +#else + +MSFilterDesc ms_ulaw_dec_desc={ + .id=MS_ULAW_DEC_ID, + .name="MSUlawDec", + .text="ITU-G.711 ulaw decoder", + .category=MS_FILTER_DECODER, + .enc_fmt="pcmu", + .ninputs=1, + .noutputs=1, + .process=ulaw_dec_process, +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_ulaw_dec_desc) +MS_FILTER_DESC_EXPORT(ms_ulaw_enc_desc) + + diff --git a/linphone/mediastreamer2/src/vfw-missing.h b/linphone/mediastreamer2/src/vfw-missing.h new file mode 100755 index 000000000..155cd0cc1 --- /dev/null +++ b/linphone/mediastreamer2/src/vfw-missing.h @@ -0,0 +1,264 @@ +#ifndef vfw_missing_h +#define vfw_missing_h + +typedef struct videohdr_tag { + LPBYTE lpData; /* pointer to locked data buffer */ + DWORD dwBufferLength; /* Length of data buffer */ + DWORD dwBytesUsed; /* Bytes actually used */ + DWORD dwTimeCaptured; /* Milliseconds from start of stream */ + DWORD_PTR dwUser; /* for client's use */ + DWORD dwFlags; /* assorted flags (see defines) */ + DWORD_PTR dwReserved[4]; /* reserved for driver */ +} VIDEOHDR, NEAR *PVIDEOHDR, FAR * LPVIDEOHDR; + +typedef struct tagCaptureParms { + DWORD dwRequestMicroSecPerFrame; // Requested capture rate + BOOL fMakeUserHitOKToCapture; // Show "Hit OK to cap" dlg? + UINT wPercentDropForError; // Give error msg if > (10%) + BOOL fYield; // Capture via background task? + DWORD dwIndexSize; // Max index size in frames (32K) + UINT wChunkGranularity; // Junk chunk granularity (2K) + BOOL fUsingDOSMemory; // Use DOS buffers? + UINT wNumVideoRequested; // # video buffers, If 0, autocalc + BOOL fCaptureAudio; // Capture audio? + UINT wNumAudioRequested; // # audio buffers, If 0, autocalc + UINT vKeyAbort; // Virtual key causing abort + BOOL fAbortLeftMouse; // Abort on left mouse? + BOOL fAbortRightMouse; // Abort on right mouse? + BOOL fLimitEnabled; // Use wTimeLimit? + UINT wTimeLimit; // Seconds to capture + BOOL fMCIControl; // Use MCI video source? + BOOL fStepMCIDevice; // Step MCI device? + DWORD dwMCIStartTime; // Time to start in MS + DWORD dwMCIStopTime; // Time to stop in MS + BOOL fStepCaptureAt2x; // Perform spatial averaging 2x + UINT wStepCaptureAverageFrames; // Temporal average n Frames + DWORD dwAudioBufferSize; // Size of audio bufs (0 = default) + BOOL fDisableWriteCache; // Attempt to disable write cache + UINT AVStreamMaster; // Which stream controls length? +} CAPTUREPARMS, *PCAPTUREPARMS, FAR *LPCAPTUREPARMS; + +#ifdef __cplusplus +/* SendMessage in C++*/ +#define AVICapSM(hwnd,m,w,l) ( (::IsWindow(hwnd)) ? ::SendMessage(hwnd,m,w,l) : 0) +#else +/* SendMessage in C */ +#define AVICapSM(hwnd,m,w,l) ( (IsWindow(hwnd)) ? SendMessage(hwnd,m,w,l) : 0) +#endif /* __cplusplus */ + +#define WM_CAP_START WM_USER + +// start of unicode messages +#define WM_CAP_UNICODE_START WM_USER+100 + +#define WM_CAP_GET_CAPSTREAMPTR (WM_CAP_START+ 1) + +#define WM_CAP_SET_CALLBACK_ERRORW (WM_CAP_UNICODE_START+ 2) +#define WM_CAP_SET_CALLBACK_STATUSW (WM_CAP_UNICODE_START+ 3) +#define WM_CAP_SET_CALLBACK_ERRORA (WM_CAP_START+ 2) +#define WM_CAP_SET_CALLBACK_STATUSA (WM_CAP_START+ 3) +#ifdef UNICODE +#define WM_CAP_SET_CALLBACK_ERROR WM_CAP_SET_CALLBACK_ERRORW +#define WM_CAP_SET_CALLBACK_STATUS WM_CAP_SET_CALLBACK_STATUSW +#else +#define WM_CAP_SET_CALLBACK_ERROR WM_CAP_SET_CALLBACK_ERRORA +#define WM_CAP_SET_CALLBACK_STATUS WM_CAP_SET_CALLBACK_STATUSA +#endif + + +#define WM_CAP_SET_CALLBACK_YIELD (WM_CAP_START+ 4) +#define WM_CAP_SET_CALLBACK_FRAME (WM_CAP_START+ 5) +#define WM_CAP_SET_CALLBACK_VIDEOSTREAM (WM_CAP_START+ 6) +#define WM_CAP_SET_CALLBACK_WAVESTREAM (WM_CAP_START+ 7) +#define WM_CAP_GET_USER_DATA (WM_CAP_START+ 8) +#define WM_CAP_SET_USER_DATA (WM_CAP_START+ 9) + +#define WM_CAP_DRIVER_CONNECT (WM_CAP_START+ 10) +#define WM_CAP_DRIVER_DISCONNECT (WM_CAP_START+ 11) + +#define WM_CAP_DRIVER_GET_NAMEA (WM_CAP_START+ 12) +#define WM_CAP_DRIVER_GET_VERSIONA (WM_CAP_START+ 13) +#define WM_CAP_DRIVER_GET_NAMEW (WM_CAP_UNICODE_START+ 12) +#define WM_CAP_DRIVER_GET_VERSIONW (WM_CAP_UNICODE_START+ 13) +#ifdef UNICODE +#define WM_CAP_DRIVER_GET_NAME WM_CAP_DRIVER_GET_NAMEW +#define WM_CAP_DRIVER_GET_VERSION WM_CAP_DRIVER_GET_VERSIONW +#else +#define WM_CAP_DRIVER_GET_NAME WM_CAP_DRIVER_GET_NAMEA +#define WM_CAP_DRIVER_GET_VERSION WM_CAP_DRIVER_GET_VERSIONA +#endif + +#define WM_CAP_DRIVER_GET_CAPS (WM_CAP_START+ 14) + +#define WM_CAP_FILE_SET_CAPTURE_FILEA (WM_CAP_START+ 20) +#define WM_CAP_FILE_GET_CAPTURE_FILEA (WM_CAP_START+ 21) +#define WM_CAP_FILE_SAVEASA (WM_CAP_START+ 23) +#define WM_CAP_FILE_SAVEDIBA (WM_CAP_START+ 25) +#define WM_CAP_FILE_SET_CAPTURE_FILEW (WM_CAP_UNICODE_START+ 20) +#define WM_CAP_FILE_GET_CAPTURE_FILEW (WM_CAP_UNICODE_START+ 21) +#define WM_CAP_FILE_SAVEASW (WM_CAP_UNICODE_START+ 23) +#define WM_CAP_FILE_SAVEDIBW (WM_CAP_UNICODE_START+ 25) +#ifdef UNICODE +#define WM_CAP_FILE_SET_CAPTURE_FILE WM_CAP_FILE_SET_CAPTURE_FILEW +#define WM_CAP_FILE_GET_CAPTURE_FILE WM_CAP_FILE_GET_CAPTURE_FILEW +#define WM_CAP_FILE_SAVEAS WM_CAP_FILE_SAVEASW +#define WM_CAP_FILE_SAVEDIB WM_CAP_FILE_SAVEDIBW +#else +#define WM_CAP_FILE_SET_CAPTURE_FILE WM_CAP_FILE_SET_CAPTURE_FILEA +#define WM_CAP_FILE_GET_CAPTURE_FILE WM_CAP_FILE_GET_CAPTURE_FILEA +#define WM_CAP_FILE_SAVEAS WM_CAP_FILE_SAVEASA +#define WM_CAP_FILE_SAVEDIB WM_CAP_FILE_SAVEDIBA +#endif + +// out of order to save on ifdefs +#define WM_CAP_FILE_ALLOCATE (WM_CAP_START+ 22) +#define WM_CAP_FILE_SET_INFOCHUNK (WM_CAP_START+ 24) + +#define WM_CAP_EDIT_COPY (WM_CAP_START+ 30) + +#define WM_CAP_SET_AUDIOFORMAT (WM_CAP_START+ 35) +#define WM_CAP_GET_AUDIOFORMAT (WM_CAP_START+ 36) + +#define WM_CAP_DLG_VIDEOFORMAT (WM_CAP_START+ 41) +#define WM_CAP_DLG_VIDEOSOURCE (WM_CAP_START+ 42) +#define WM_CAP_DLG_VIDEODISPLAY (WM_CAP_START+ 43) +#define WM_CAP_GET_VIDEOFORMAT (WM_CAP_START+ 44) +#define WM_CAP_SET_VIDEOFORMAT (WM_CAP_START+ 45) +#define WM_CAP_DLG_VIDEOCOMPRESSION (WM_CAP_START+ 46) + +#define WM_CAP_SET_PREVIEW (WM_CAP_START+ 50) +#define WM_CAP_SET_OVERLAY (WM_CAP_START+ 51) +#define WM_CAP_SET_PREVIEWRATE (WM_CAP_START+ 52) +#define WM_CAP_SET_SCALE (WM_CAP_START+ 53) +#define WM_CAP_GET_STATUS (WM_CAP_START+ 54) +#define WM_CAP_SET_SCROLL (WM_CAP_START+ 55) + +#define WM_CAP_GRAB_FRAME (WM_CAP_START+ 60) +#define WM_CAP_GRAB_FRAME_NOSTOP (WM_CAP_START+ 61) + +#define WM_CAP_SEQUENCE (WM_CAP_START+ 62) +#define WM_CAP_SEQUENCE_NOFILE (WM_CAP_START+ 63) +#define WM_CAP_SET_SEQUENCE_SETUP (WM_CAP_START+ 64) +#define WM_CAP_GET_SEQUENCE_SETUP (WM_CAP_START+ 65) + +#define WM_CAP_SET_MCI_DEVICEA (WM_CAP_START+ 66) +#define WM_CAP_GET_MCI_DEVICEA (WM_CAP_START+ 67) +#define WM_CAP_SET_MCI_DEVICEW (WM_CAP_UNICODE_START+ 66) +#define WM_CAP_GET_MCI_DEVICEW (WM_CAP_UNICODE_START+ 67) +#ifdef UNICODE +#define WM_CAP_SET_MCI_DEVICE WM_CAP_SET_MCI_DEVICEW +#define WM_CAP_GET_MCI_DEVICE WM_CAP_GET_MCI_DEVICEW +#else +#define WM_CAP_SET_MCI_DEVICE WM_CAP_SET_MCI_DEVICEA +#define WM_CAP_GET_MCI_DEVICE WM_CAP_GET_MCI_DEVICEA +#endif + + + +#define WM_CAP_STOP (WM_CAP_START+ 68) +#define WM_CAP_ABORT (WM_CAP_START+ 69) + +#define WM_CAP_SINGLE_FRAME_OPEN (WM_CAP_START+ 70) +#define WM_CAP_SINGLE_FRAME_CLOSE (WM_CAP_START+ 71) +#define WM_CAP_SINGLE_FRAME (WM_CAP_START+ 72) + +#define WM_CAP_PAL_OPENA (WM_CAP_START+ 80) +#define WM_CAP_PAL_SAVEA (WM_CAP_START+ 81) +#define WM_CAP_PAL_OPENW (WM_CAP_UNICODE_START+ 80) +#define WM_CAP_PAL_SAVEW (WM_CAP_UNICODE_START+ 81) +#ifdef UNICODE +#define WM_CAP_PAL_OPEN WM_CAP_PAL_OPENW +#define WM_CAP_PAL_SAVE WM_CAP_PAL_SAVEW +#else +#define WM_CAP_PAL_OPEN WM_CAP_PAL_OPENA +#define WM_CAP_PAL_SAVE WM_CAP_PAL_SAVEA +#endif + +#define WM_CAP_PAL_PASTE (WM_CAP_START+ 82) +#define WM_CAP_PAL_AUTOCREATE (WM_CAP_START+ 83) +#define WM_CAP_PAL_MANUALCREATE (WM_CAP_START+ 84) + +// Following added post VFW 1.1 +#define WM_CAP_SET_CALLBACK_CAPCONTROL (WM_CAP_START+ 85) + + +// Defines end of the message range +#define WM_CAP_UNICODE_END WM_CAP_PAL_SAVEW +#define WM_CAP_END WM_CAP_UNICODE_END + +#define capSetCallbackOnError(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_ERROR, 0, (LPARAM)(LPVOID)(fpProc))) +#define capSetCallbackOnStatus(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_STATUS, 0, (LPARAM)(LPVOID)(fpProc))) +#define capSetCallbackOnYield(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_YIELD, 0, (LPARAM)(LPVOID)(fpProc))) +#define capSetCallbackOnFrame(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_FRAME, 0, (LPARAM)(LPVOID)(fpProc))) +#define capSetCallbackOnVideoStream(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, (LPARAM)(LPVOID)(fpProc))) +#define capSetCallbackOnWaveStream(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, (LPARAM)(LPVOID)(fpProc))) +#define capSetCallbackOnCapControl(hwnd, fpProc) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_CALLBACK_CAPCONTROL, 0, (LPARAM)(LPVOID)(fpProc))) + +#define capSetUserData(hwnd, lUser) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_USER_DATA, 0, (LPARAM)lUser)) +#define capGetUserData(hwnd) (AVICapSM(hwnd, WM_CAP_GET_USER_DATA, 0, 0)) + +#define capDriverConnect(hwnd, i) ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, (WPARAM)(i), 0L)) +#define capDriverDisconnect(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_DISCONNECT, (WPARAM)0, 0L)) +#define capDriverGetName(hwnd, szName, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_GET_NAME, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capDriverGetVersion(hwnd, szVer, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_GET_VERSION, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPTSTR)(szVer))) +#define capDriverGetCaps(hwnd, s, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_DRIVER_GET_CAPS, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPDRIVERCAPS)(s))) + +#define capFileSetCaptureFile(hwnd, szName) ((BOOL)AVICapSM(hwnd, WM_CAP_FILE_SET_CAPTURE_FILE, 0, (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capFileGetCaptureFile(hwnd, szName, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_FILE_GET_CAPTURE_FILE, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capFileAlloc(hwnd, dwSize) ((BOOL)AVICapSM(hwnd, WM_CAP_FILE_ALLOCATE, 0, (LPARAM)(DWORD)(dwSize))) +#define capFileSaveAs(hwnd, szName) ((BOOL)AVICapSM(hwnd, WM_CAP_FILE_SAVEAS, 0, (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capFileSetInfoChunk(hwnd, lpInfoChunk) ((BOOL)AVICapSM(hwnd, WM_CAP_FILE_SET_INFOCHUNK, (WPARAM)0, (LPARAM)(LPCAPINFOCHUNK)(lpInfoChunk))) +#define capFileSaveDIB(hwnd, szName) ((BOOL)AVICapSM(hwnd, WM_CAP_FILE_SAVEDIB, 0, (LPARAM)(LPVOID)(LPTSTR)(szName))) + +#define capEditCopy(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_EDIT_COPY, 0, 0L)) + +#define capSetAudioFormat(hwnd, s, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_AUDIOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPWAVEFORMATEX)(s))) +#define capGetAudioFormat(hwnd, s, wSize) ((DWORD)AVICapSM(hwnd, WM_CAP_GET_AUDIOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPWAVEFORMATEX)(s))) +#define capGetAudioFormatSize(hwnd) ((DWORD)AVICapSM(hwnd, WM_CAP_GET_AUDIOFORMAT, (WPARAM)0, (LPARAM)0L)) + +#define capDlgVideoFormat(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_DLG_VIDEOFORMAT, 0, 0L)) +#define capDlgVideoSource(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_DLG_VIDEOSOURCE, 0, 0L)) +#define capDlgVideoDisplay(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_DLG_VIDEODISPLAY, 0, 0L)) +#define capDlgVideoCompression(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_DLG_VIDEOCOMPRESSION, 0, 0L)) + +#define capGetVideoFormat(hwnd, s, wSize) ((DWORD)AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(s))) +#define capGetVideoFormatSize(hwnd) ((DWORD)AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, 0, 0L)) +#define capSetVideoFormat(hwnd, s, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_VIDEOFORMAT, (WPARAM)(wSize), (LPARAM)(LPVOID)(s))) + +#define capPreview(hwnd, f) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_PREVIEW, (WPARAM)(BOOL)(f), 0L)) +#define capPreviewRate(hwnd, wMS) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_PREVIEWRATE, (WPARAM)(wMS), 0)) +#define capOverlay(hwnd, f) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_OVERLAY, (WPARAM)(BOOL)(f), 0L)) +#define capPreviewScale(hwnd, f) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_SCALE, (WPARAM)(BOOL)f, 0L)) +#define capGetStatus(hwnd, s, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_GET_STATUS, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPSTATUS)(s))) +#define capSetScrollPos(hwnd, lpP) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_SCROLL, (WPARAM)0, (LPARAM)(LPPOINT)(lpP))) + +#define capGrabFrame(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_GRAB_FRAME, (WPARAM)0, (LPARAM)0L)) +#define capGrabFrameNoStop(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_GRAB_FRAME_NOSTOP, (WPARAM)0, (LPARAM)0L)) + +#define capCaptureSequence(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_SEQUENCE, (WPARAM)0, (LPARAM)0L)) +#define capCaptureSequenceNoFile(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_SEQUENCE_NOFILE, (WPARAM)0, (LPARAM)0L)) +#define capCaptureStop(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_STOP, (WPARAM)0, (LPARAM)0L)) +#define capCaptureAbort(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_ABORT, (WPARAM)0, (LPARAM)0L)) + +#define capCaptureSingleFrameOpen(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_SINGLE_FRAME_OPEN, (WPARAM)0, (LPARAM)0L)) +#define capCaptureSingleFrameClose(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_SINGLE_FRAME_CLOSE, (WPARAM)0, (LPARAM)0L)) +#define capCaptureSingleFrame(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_SINGLE_FRAME, (WPARAM)0, (LPARAM)0L)) + +#define capCaptureGetSetup(hwnd, s, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_GET_SEQUENCE_SETUP, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPTUREPARMS)(s))) +#define capCaptureSetSetup(hwnd, s, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_SEQUENCE_SETUP, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPCAPTUREPARMS)(s))) + +#define capSetMCIDeviceName(hwnd, szName) ((BOOL)AVICapSM(hwnd, WM_CAP_SET_MCI_DEVICE, 0, (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capGetMCIDeviceName(hwnd, szName, wSize) ((BOOL)AVICapSM(hwnd, WM_CAP_GET_MCI_DEVICE, (WPARAM)(wSize), (LPARAM)(LPVOID)(LPTSTR)(szName))) + +#define capPaletteOpen(hwnd, szName) ((BOOL)AVICapSM(hwnd, WM_CAP_PAL_OPEN, 0, (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capPaletteSave(hwnd, szName) ((BOOL)AVICapSM(hwnd, WM_CAP_PAL_SAVE, 0, (LPARAM)(LPVOID)(LPTSTR)(szName))) +#define capPalettePaste(hwnd) ((BOOL)AVICapSM(hwnd, WM_CAP_PAL_PASTE, (WPARAM) 0, (LPARAM)0L)) +#define capPaletteAuto(hwnd, iFrames, iColors) ((BOOL)AVICapSM(hwnd, WM_CAP_PAL_AUTOCREATE, (WPARAM)(iFrames), (LPARAM)(DWORD)(iColors))) +#define capPaletteManual(hwnd, fGrab, iColors) ((BOOL)AVICapSM(hwnd, WM_CAP_PAL_MANUALCREATE, (WPARAM)(fGrab), (LPARAM)(DWORD)(iColors))) + +#define AVSTREAMMASTER_AUDIO 0 /* Audio master (VFW 1.0, 1.1) */ +#define AVSTREAMMASTER_NONE 1 /* No master */ + + +#endif + diff --git a/linphone/mediastreamer2/src/videodec.c b/linphone/mediastreamer2/src/videodec.c new file mode 100644 index 000000000..2793ffef1 --- /dev/null +++ b/linphone/mediastreamer2/src/videodec.c @@ -0,0 +1,464 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "ffmpeg-priv.h" + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msvideo.h" +#include "rfc2429.h" + + +extern void ms_ffmpeg_check_init(); + +typedef struct DecState{ + AVCodecContext av_context; + AVCodec *av_codec; + enum CodecID codec; + mblk_t *input; + YuvBuf outbuf; + mblk_t *yuv_msg; + struct SwsContext *sws_ctx; + int output_pix_fmt; + uint8_t dci[512]; + int dci_size; + bool_t snow_initialized; +}DecState; + + +static void dec_init(MSFilter *f, enum CodecID cid){ + DecState *s=(DecState *)ms_new0(DecState,1); + ms_ffmpeg_check_init(); + + avcodec_get_context_defaults(&s->av_context); + s->av_codec=NULL; + s->codec=cid; + s->input=NULL; + s->yuv_msg=NULL; + s->output_pix_fmt=PIX_FMT_YUV420P; + s->snow_initialized=FALSE; + s->outbuf.w=0; + s->outbuf.h=0; + s->sws_ctx=NULL; + f->data=s; + + s->av_codec=avcodec_find_decoder(s->codec); + if (s->av_codec==NULL){ + ms_error("Could not find decoder %i!",s->codec); + } + /* + s->av_context.width=MS_VIDEO_SIZE_QCIF_W; + s->av_context.height=MS_VIDEO_SIZE_QCIF_H; + */ +} + +static void dec_h263_init(MSFilter *f){ + dec_init(f,CODEC_ID_H263); +} + +static void dec_mpeg4_init(MSFilter *f){ + dec_init(f,CODEC_ID_MPEG4); +} + +static void dec_mjpeg_init(MSFilter *f){ + dec_init(f,CODEC_ID_MJPEG); +} + +static void dec_snow_init(MSFilter *f){ + dec_init(f,CODEC_ID_SNOW); +} + +static void dec_uninit(MSFilter *f){ + DecState *s=(DecState*)f->data; + if (s->input!=NULL) freemsg(s->input); + if (s->yuv_msg!=NULL) freemsg(s->yuv_msg); + if (s->sws_ctx!=NULL){ + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + } + ms_free(s); +} + +static int dec_add_fmtp(MSFilter *f, void *data){ + const char *fmtp=(const char*)data; + DecState *s=(DecState*)f->data; + char config[512]; + if (fmtp_get_value(fmtp,"config",config,sizeof(config))){ + /*convert hexa decimal config string into a bitstream */ + int i,j,max=strlen(config); + char octet[3]; + octet[2]=0; + for(i=0,j=0;idci[j]=strtol(octet,NULL,16); + } + s->dci_size=j; + ms_message("Got mpeg4 config string: %s",config); + } + return 0; +} + +static void dec_preprocess(MSFilter *f){ + DecState *s=(DecState*)f->data; + int error; + /* we must know picture size before initializing snow decoder*/ + if (s->codec!=CODEC_ID_SNOW){ + error=avcodec_open(&s->av_context, s->av_codec); + if (error!=0) ms_error("avcodec_open() failed: %i",error); + if (s->codec==CODEC_ID_MPEG4 && s->dci_size>0){ + s->av_context.extradata=s->dci; + s->av_context.extradata_size=s->dci_size; + } + } +} + +static void dec_postprocess(MSFilter *f){ + DecState *s=(DecState*)f->data; + if (s->av_context.codec!=NULL){ + avcodec_close(&s->av_context); + s->av_context.codec=NULL; + } +} + +static mblk_t * skip_rfc2190_header(mblk_t *inm){ + if (msgdsize(inm) >= 4) { + uint8_t *ph = inm->b_rptr; + int F = (ph[0]>>7) & 0x1; + int P = (ph[0]>>6) & 0x1; + if (F == 0) inm->b_rptr += 4; // mode A + else if (P == 0) inm->b_rptr += 8; // mode B + else inm->b_rptr += 12; // mode C + } else { + freemsg(inm); + inm=NULL; + } + return inm; +} + +static mblk_t * skip_rfc2429_header(mblk_t *inm){ + if (msgdsize(inm) >= 2){ + uint32_t *p = (uint32_t*)inm->b_rptr; + uint8_t *ph=inm->b_rptr; + int PLEN; + int gob_num; + bool_t P; + + P=rfc2429_get_P(ph); + PLEN=rfc2429_get_PLEN(ph); + /*printf("receiving new packet; P=%i; V=%i; PLEN=%i; PEBIT=%i\n",P,rfc2429_get_V(ph),PLEN,rfc2429_get_PEBIT(ph)); + */ + gob_num = (ntohl(*p) >> 10) & 0x1f; + /*ms_message("gob %i, size %i", gob_num, msgdsize(inm)); + ms_message("ms_AVdecoder_process: received %08x %08x", ntohl(p[0]), ntohl(p[1]));*/ + + /* remove H.263 Payload Header */ + if (PLEN>0){ + /* we ignore the redundant picture header and + directly go to the bitstream */ + inm->b_rptr+=PLEN; + } + if (P){ + inm->b_rptr[0]=inm->b_rptr[1]=0; + }else{ + /* no PSC omitted */ + inm->b_rptr+=2; + } + return inm; + }else freemsg(inm); + return NULL; +} + +static mblk_t * parse_snow_header(DecState *s,mblk_t *inm){ + if (msgdsize(inm) >= 4){ + uint32_t h = ntohl(*(uint32_t*)inm->b_rptr); + if (!s->snow_initialized){ + int error; + s->av_context.width=h>>16; + s->av_context.height=h&0xffff; + error=avcodec_open(&s->av_context, s->av_codec); + if (error!=0) ms_error("avcodec_open() failed for snow: %i",error); + else { + s->snow_initialized=TRUE; + ms_message("Snow decoder initialized,size=%ix%i", + s->av_context.width, + s->av_context.height); + } + } + inm->b_rptr+=4; + return inm; + }else { + freemsg(inm); + return NULL; + } +} + +static mblk_t *get_as_yuvmsg(MSFilter *f, DecState *s, AVFrame *orig){ + AVCodecContext *ctx=&s->av_context; + + if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){ + if (s->sws_ctx!=NULL){ + sws_freeContext(s->sws_ctx); + s->sws_ctx=NULL; + } + s->yuv_msg=yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height); + s->outbuf.w=ctx->width; + s->outbuf.h=ctx->height; + s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt, + ctx->width,ctx->height,s->output_pix_fmt,SWS_FAST_BILINEAR, + NULL, NULL, NULL); + } + if (sws_scale(s->sws_ctx,orig->data,orig->linesize, 0, + ctx->height, s->outbuf.planes, s->outbuf.strides)<0){ + ms_error("%s: error in sws_scale().",f->desc->name); + } + return dupmsg(s->yuv_msg); +} + +static void dec_process_frame(MSFilter *f, mblk_t *inm){ + DecState *s=(DecState*)f->data; + AVFrame orig; + int got_picture; + /* get a picture from the input queue */ + + if (f->desc->id==MS_H263_DEC_ID) inm=skip_rfc2429_header(inm); + else if (f->desc->id==MS_H263_OLD_DEC_ID) inm=skip_rfc2190_header(inm); + else if (s->codec==CODEC_ID_SNOW && s->input==NULL) inm=parse_snow_header(s,inm); + if (inm){ + /* accumulate the video packet until we have the rtp markbit*/ + if (s->input==NULL){ + s->input=inm; + }else{ + concatb(s->input,inm); + } + + if (mblk_get_marker_info(inm)){ + mblk_t *frame; + int remain,len; + /*ms_message("got marker bit !");*/ + /*append some padding bytes for ffmpeg to safely + read extra bytes...*/ + msgpullup(s->input,msgdsize(s->input)+8); + frame=s->input; + s->input=NULL; + while ( (remain=frame->b_wptr-frame->b_rptr)> 0) { + len=avcodec_decode_video(&s->av_context,&orig,&got_picture,(uint8_t*)frame->b_rptr,remain ); + if (len<=0) { + ms_warning("ms_AVdecoder_process: error %i.",len); + break; + } + if (got_picture) { + ms_queue_put(f->outputs[0],get_as_yuvmsg(f,s,&orig)); + } + frame->b_rptr+=len; + } + freemsg(frame); + } + } +} + +static void dec_process(MSFilter *f){ + mblk_t *inm; + while((inm=ms_queue_get(f->inputs[0]))!=0){ + dec_process_frame(f,inm); + } +} + + +static MSFilterMethod methods[]={ + { MS_FILTER_ADD_FMTP , dec_add_fmtp }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_h263_dec_desc={ + MS_H263_DEC_ID, + "MSH263Dec", + "A H.263 decoder using ffmpeg library", + MS_FILTER_DECODER, + "H263-1998", + 1, + 1, + dec_h263_init, + dec_preprocess, + dec_process, + dec_postprocess, + dec_uninit, + methods +}; + +MSFilterDesc ms_h263_old_dec_desc={ + MS_H263_DEC_ID, + "MSH263OldDec", + "A H.263 decoder using ffmpeg library", + MS_FILTER_DECODER, + "H263", + 1, + 1, + dec_h263_init, + dec_preprocess, + dec_process, + dec_postprocess, + dec_uninit, + methods +}; + + +MSFilterDesc ms_mpeg4_dec_desc={ + MS_MPEG4_DEC_ID, + "MSMpeg4Dec", + "A MPEG4 decoder using ffmpeg library", + MS_FILTER_DECODER, + "MP4V-ES", + 1, + 1, + dec_mpeg4_init, + dec_preprocess, + dec_process, + dec_postprocess, + dec_uninit, + methods +}; + +MSFilterDesc ms_mjpeg_dec_desc={ + MS_MJPEG_DEC_ID, + "MSMJpegDec", + "A MJPEG decoder using ffmpeg library", + MS_FILTER_DECODER, + "MJPEG", + 1, + 1, + dec_mjpeg_init, + dec_preprocess, + dec_process, + dec_postprocess, + dec_uninit, + methods +}; + +MSFilterDesc ms_snow_dec_desc={ + MS_SNOW_DEC_ID, + "MSSnowDec", + "A snow decoder using ffmpeg library", + MS_FILTER_DECODER, + "snow", + 1, + 1, + dec_snow_init, + dec_preprocess, + dec_process, + dec_postprocess, + dec_uninit, + methods +}; + +#else + +MSFilterDesc ms_h263_dec_desc={ + .id=MS_H263_DEC_ID, + .name="MSH263Dec", + .text="A H.263 decoder using ffmpeg library", + .category=MS_FILTER_DECODER, + .enc_fmt="H263-1998", + .ninputs=1, + .noutputs=1, + .init=dec_h263_init, + .preprocess=dec_preprocess, + .process=dec_process, + .postprocess=dec_postprocess, + .uninit=dec_uninit, + .methods= methods +}; + +MSFilterDesc ms_h263_old_dec_desc={ + .id=MS_H263_OLD_DEC_ID, + .name="MSH263OldDec", + .text="A H.263 decoder using ffmpeg library", + .category=MS_FILTER_DECODER, + .enc_fmt="H263", + .ninputs=1, + .noutputs=1, + .init=dec_h263_init, + .preprocess=dec_preprocess, + .process=dec_process, + .postprocess=dec_postprocess, + .uninit=dec_uninit, + .methods= methods +}; + + +MSFilterDesc ms_mpeg4_dec_desc={ + .id=MS_MPEG4_DEC_ID, + .name="MSMpeg4Dec", + .text="A MPEG4 decoder using ffmpeg library", + .category=MS_FILTER_DECODER, + .enc_fmt="MP4V-ES", + .ninputs=1, + .noutputs=1, + .init=dec_mpeg4_init, + .preprocess=dec_preprocess, + .process=dec_process, + .postprocess=dec_postprocess, + .uninit=dec_uninit, + .methods= methods +}; + +MSFilterDesc ms_mjpeg_dec_desc={ + .id=MS_MJPEG_DEC_ID, + .name="MSMJpegDec", + .text="A MJEPG decoder using ffmpeg library", + .category=MS_FILTER_DECODER, + .enc_fmt="MJPEG", + .ninputs=1, + .noutputs=1, + .init=dec_mjpeg_init, + .preprocess=dec_preprocess, + .process=dec_process, + .postprocess=dec_postprocess, + .uninit=dec_uninit, + .methods= methods +}; + +MSFilterDesc ms_snow_dec_desc={ + .id=MS_SNOW_DEC_ID, + .name="MSSnowDec", + .text="A snow decoder using ffmpeg library", + .category=MS_FILTER_DECODER, + .enc_fmt="x-snow", + .ninputs=1, + .noutputs=1, + .init=dec_snow_init, + .preprocess=dec_preprocess, + .process=dec_process, + .postprocess=dec_postprocess, + .uninit=dec_uninit, + .methods= methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_mpeg4_dec_desc) +MS_FILTER_DESC_EXPORT(ms_h263_dec_desc) +MS_FILTER_DESC_EXPORT(ms_h263_old_dec_desc) +MS_FILTER_DESC_EXPORT(ms_mjpeg_dec_desc) +MS_FILTER_DESC_EXPORT(ms_snow_dec_desc) diff --git a/linphone/mediastreamer2/src/videoenc.c b/linphone/mediastreamer2/src/videoenc.c new file mode 100644 index 000000000..0b1004762 --- /dev/null +++ b/linphone/mediastreamer2/src/videoenc.c @@ -0,0 +1,703 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#ifdef HAVE_LIBAVCODEC_AVCODEC_H +#include +#else +#include +#endif +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" + +#ifdef _WIN32 +#include +#else +#include /* ntohl(3) */ +#endif + +#include "rfc2429.h" + +static bool_t avcodec_initialized=FALSE; + +void ms_ffmpeg_check_init(){ + if(!avcodec_initialized){ + avcodec_init(); + avcodec_register_all(); + avcodec_initialized=TRUE; + } +} + +typedef struct EncState{ + AVCodecContext av_context; + AVCodec *av_codec; + enum CodecID codec; + mblk_t *comp_buf; + MSVideoSize vsize; + int mtu; /* network maximum transmission unit in bytes */ + int profile; + float fps; + int maxbr; + int qmin; + bool_t req_vfu; +}EncState; + +static int enc_set_fps(MSFilter *f, void *arg){ + EncState *s=(EncState*)f->data; + s->fps=*(float*)arg; + return 0; +} + +static int enc_get_fps(MSFilter *f, void *arg){ + EncState *s=(EncState*)f->data; + *(float*)arg=s->fps; + return 0; +} + +static int enc_set_vsize(MSFilter *f,void *arg){ + EncState *s=(EncState*)f->data; + s->vsize=*(MSVideoSize*)arg; + return 0; +} + +static int enc_get_vsize(MSFilter *f,void *arg){ + EncState *s=(EncState*)f->data; + *(MSVideoSize*)arg=s->vsize; + return 0; +} + +static int enc_set_mtu(MSFilter *f,void *arg){ + EncState *s=(EncState*)f->data; + s->mtu=*(int*)arg; + return 0; +} + +static bool_t parse_video_fmtp(const char *fmtp, float *fps, MSVideoSize *vsize){ + char *tmp=ms_strdup(fmtp); + char *semicolon; + char *equal; + bool_t ret=TRUE; + + ms_message("parsing %s",fmtp); + /*extract fisrt pair */ + if ((semicolon=strchr(tmp,';'))!=NULL){ + *semicolon='\0'; + } + if ((equal=strchr(tmp,'='))!=NULL){ + int divider; + *equal='\0'; + if (strcasecmp(tmp,"CIF")==0){ + if (vsize->width>=MS_VIDEO_SIZE_CIF_W){ + vsize->width=MS_VIDEO_SIZE_CIF_W; + vsize->height=MS_VIDEO_SIZE_CIF_H; + } + }else if (strcasecmp(tmp,"QCIF")==0){ + vsize->width=MS_VIDEO_SIZE_QCIF_W; + vsize->height=MS_VIDEO_SIZE_QCIF_H; + }else{ + ms_warning("unsupported video size %s",tmp); + ret=FALSE; + } + divider=atoi(equal+1); + if (divider!=0){ + float newfps=29.97/divider; + if (*fps>newfps) *fps=newfps; + }else{ + ms_warning("Could not find video fps"); + ret=FALSE; + } + }else ret=FALSE; + ms_free(tmp); + return ret; +} + +static int enc_add_fmtp(MSFilter *f,void *arg){ + EncState *s=(EncState*)f->data; + const char *fmtp=(const char*)arg; + char val[10]; + if (fmtp_get_value(fmtp,"profile",val,sizeof(val))){ + s->profile=atoi(val); + }else parse_video_fmtp(fmtp,&s->fps,&s->vsize); + return 0; +} + +static int enc_req_vfu(MSFilter *f, void *unused){ + EncState *s=(EncState*)f->data; + s->req_vfu=TRUE; + return 0; +} + +static void enc_init(MSFilter *f, enum CodecID codec) +{ + EncState *s=(EncState *)ms_new(EncState,1); + f->data=s; + ms_ffmpeg_check_init(); + s->profile=0;/*always default to profile 0*/ + s->comp_buf=allocb(32000,0); + s->fps=15; + s->mtu=ms_get_payload_max_size()-2;/*-2 for the H263 payload header*/ + s->maxbr=500000; + s->codec=codec; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + s->qmin=2; + s->req_vfu=FALSE; + s->av_context.codec=NULL; +} + +static void enc_h263_init(MSFilter *f){ + enc_init(f,CODEC_ID_H263P); +} + +static void enc_mpeg4_init(MSFilter *f){ + enc_init(f,CODEC_ID_MPEG4); +} + +static void enc_snow_init(MSFilter *f){ + enc_init(f,CODEC_ID_SNOW); +} + +static void prepare(EncState *s){ + AVCodecContext *c=&s->av_context; + avcodec_get_context_defaults(c); + /* put codec parameters */ + c->bit_rate=(float)s->maxbr*0.7; + c->bit_rate_tolerance=(float)c->bit_rate/(s->fps-1); + + if (s->codec!=CODEC_ID_SNOW && s->maxbr<256000){ + /*snow does not like 1st pass rate control*/ + /*and rate control eats too much cpu with CIF high fps pictures*/ + c->rc_max_rate=(float)s->maxbr*0.8; + c->rc_min_rate=c->bit_rate; + c->rc_buffer_size=c->rc_max_rate; + }else{ + /*use qmin instead*/ + c->qmin=s->qmin; + } + + ms_message("Codec bitrate set to %i",c->bit_rate); + c->width = s->vsize.width; + c->height = s->vsize.height; + c->time_base.num = 1; + c->time_base.den = (int)s->fps; + c->gop_size=(int)s->fps*5; /*emit I frame every 5 seconds*/ + c->pix_fmt=PIX_FMT_YUV420P; + + if (s->codec==CODEC_ID_SNOW){ + c->strict_std_compliance=-2; + } + +} + +static void prepare_h263(EncState *s){ + AVCodecContext *c=&s->av_context; + /* we don't use the rtp_callback but use rtp_mode that forces ffmpeg to insert + Start Codes as much as possible in the bitstream */ + c->rtp_mode = 1; + c->rtp_payload_size = s->mtu/2; + if (s->profile==0){ + s->codec=CODEC_ID_H263; + }else{ + c->flags|=CODEC_FLAG_H263P_UMV; + c->flags|=CODEC_FLAG_AC_PRED; + c->flags|=CODEC_FLAG_H263P_SLICE_STRUCT; + /* + c->flags|=CODEC_FLAG_OBMC; + c->flags|=CODEC_FLAG_AC_PRED; + */ + s->codec=CODEC_ID_H263P; + } +} + +static void prepare_mpeg4(EncState *s){ + AVCodecContext *c=&s->av_context; + c->max_b_frames=0; /*don't use b frames*/ + c->flags|=CODEC_FLAG_AC_PRED; + c->flags|=CODEC_FLAG_H263P_UMV; + /*c->flags|=CODEC_FLAG_QPEL;*/ /*don't enable this one: this forces profile_level to advanced simple profile */ + c->flags|=CODEC_FLAG_4MV; + c->flags|=CODEC_FLAG_GMC; + c->flags|=CODEC_FLAG_LOOP_FILTER; + c->flags|=CODEC_FLAG_H263P_SLICE_STRUCT; +} + +static void enc_uninit(MSFilter *f){ + EncState *s=(EncState*)f->data; + if (s->comp_buf!=NULL) freemsg(s->comp_buf); + ms_free(s); +} +#if 0 +static void enc_set_rc(EncState *s, AVCodecContext *c){ + int factor=c->width/MS_VIDEO_SIZE_QCIF_W; + c->rc_min_rate=0; + c->bit_rate=400; /* this value makes around 100kbit/s at QCIF=2 */ + c->rc_max_rate=c->bit_rate+1; + c->rc_buffer_size=20000*factor; /* food recipe */ +} +#endif + +static void enc_preprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + int error; + prepare(s); + if (s->codec==CODEC_ID_H263P || s->codec==CODEC_ID_H263) + prepare_h263(s); + else if (s->codec==CODEC_ID_MPEG4) + prepare_mpeg4(s); + else if (s->codec==CODEC_ID_SNOW){ + /**/ + }else { + ms_error("Unsupported codec id %i",s->codec); + return; + } + s->av_codec=avcodec_find_encoder(s->codec); + if (s->av_codec==NULL){ + ms_error("could not find encoder for codec id %i",s->codec); + return; + } + error=avcodec_open(&s->av_context, s->av_codec); + if (error!=0) { + ms_error("avcodec_open() failed: %i",error); + return; + } + ms_debug("image format is %i.",s->av_context.pix_fmt); + ms_message("qmin=%i qmax=%i",s->av_context.qmin,s->av_context.qmax); +} + +static void enc_postprocess(MSFilter *f){ + EncState *s=(EncState*)f->data; + if (s->av_context.codec!=NULL){ + avcodec_close(&s->av_context); + s->av_context.codec=NULL; + } +} + +static void add_rfc2190_header(mblk_t **packet, AVCodecContext *context){ + mblk_t *header; + header = allocb(4, 0); + memset(header->b_wptr, 0, 4); + // assume video size is CIF or QCIF + if (context->width == 352 && context->height == 288) header->b_wptr[1] = 0x60; + else header->b_wptr[1] = 0x40; + if (context->coded_frame->pict_type != FF_I_TYPE) header->b_wptr[1] |= 0x10; + header->b_wptr += 4; + header->b_cont = *packet; + *packet = header; +} + +static int get_gbsc(uint8_t *psc, uint8_t *end) +{ + int len = end-psc; + uint32_t buf; + int i, j, k; + k = len; + for (i = 2; i < len-4; i++) { + buf = *((uint32_t *)(psc+i)); + for (j = 0; j < 8; j++) { + if (((buf >> j) & 0x00FCFFFF) == 0x00800000) {/*PSC*/ + i += 2; + k=i; + break; + } else if (((buf >> j) & 0x0080FFFF) == 0x00800000) {/*GBSC*/ + i += 2; + k = i; + break; + } + } + } + return k; +} + +static void rfc2190_generate_packets(MSFilter *f, EncState *s, mblk_t *frame, uint32_t timestamp){ + mblk_t *packet=NULL; + + while (frame->b_rptrb_wptr){ + packet=dupb(frame); + frame->b_rptr=packet->b_wptr=packet->b_rptr+get_gbsc(packet->b_rptr, MIN(packet->b_rptr+s->mtu,frame->b_wptr)); + add_rfc2190_header(&packet, &s->av_context); + mblk_set_timestamp_info(packet,timestamp); + ms_queue_put(f->outputs[0],packet); + } + /* the marker bit is set on the last packet, if any.*/ + mblk_set_marker_info(packet,TRUE); +} + +static void mpeg4_fragment_and_send(MSFilter *f,EncState *s,mblk_t *frame, uint32_t timestamp){ + uint8_t *rptr; + mblk_t *packet=NULL; + int len; + for (rptr=frame->b_rptr;rptrb_wptr;){ + len=MIN(s->mtu,(frame->b_wptr-rptr)); + packet=dupb(frame); + packet->b_rptr=rptr; + packet->b_wptr=rptr+len; + mblk_set_timestamp_info(packet,timestamp); + ms_queue_put(f->outputs[0],packet); + rptr+=len; + } + /*set marker bit on last packet*/ + mblk_set_marker_info(packet,TRUE); +} + +static void rfc4629_generate_follow_on_packets(MSFilter *f, EncState *s, mblk_t *frame, uint32_t timestamp, uint8_t *psc, uint8_t *end, bool_t last_packet){ + mblk_t *packet; + int len=end-psc; + + packet=dupb(frame); + packet->b_rptr=psc; + packet->b_wptr=end; + /*ms_message("generating packet of size %i",end-psc);*/ + rfc2429_set_P(psc,1); + mblk_set_timestamp_info(packet,timestamp); + + + if (len>s->mtu){ + /*need to slit the packet using "follow-on" packets */ + /*compute the number of packets need (rounded up)*/ + int num=(len+s->mtu-1)/s->mtu; + int i; + uint8_t *pos; + /*adjust the first packet generated*/ + pos=packet->b_wptr=packet->b_rptr+s->mtu; + ms_queue_put(f->outputs[0],packet); + ms_debug("generating %i follow-on packets",num); + for (i=1;ib_rptr=pos; + pos=packet->b_wptr=MIN(pos+s->mtu,end); + header=allocb(2,0); + header->b_wptr[0]=0; + header->b_wptr[1]=0; + header->b_wptr+=2; + /*no P bit is set */ + header->b_cont=packet; + packet=header; + mblk_set_timestamp_info(packet,timestamp); + ms_queue_put(f->outputs[0],packet); + } + }else ms_queue_put(f->outputs[0],packet); + /* the marker bit is set on the last packet, if any.*/ + mblk_set_marker_info(packet,last_packet); +} + +/* returns the last psc position just below packet_size */ +static uint8_t *get_psc(uint8_t *begin,uint8_t *end, int packet_size){ + int i; + uint8_t *ret=NULL; + uint8_t *p; + if (begin==end) return NULL; + for(i=1,p=begin+1;pticker->time*90LL; + + if (s->codec==CODEC_ID_MPEG4 || s->codec==CODEC_ID_SNOW) + { + mpeg4_fragment_and_send(f,s,frame,timestamp); + return; + } + + ms_debug("processing frame of size %i",frame->b_wptr-frame->b_rptr); + if (f->desc->id==MS_H263_ENC_ID){ + lastpsc=frame->b_rptr; + while(1){ + psc=get_psc(lastpsc+2,frame->b_wptr,s->mtu); + if (psc!=NULL){ + rfc4629_generate_follow_on_packets(f,s,frame,timestamp,lastpsc,psc,FALSE); + lastpsc=psc; + }else break; + } + /* send the end of frame */ + rfc4629_generate_follow_on_packets(f,s,frame, timestamp,lastpsc,frame->b_wptr,TRUE); + }else if (f->desc->id==MS_H263_OLD_ENC_ID){ + rfc2190_generate_packets(f,s,frame,timestamp); + }else{ + ms_fatal("Ca va tres mal."); + } +} + +static void process_frame(MSFilter *f, mblk_t *inm){ + EncState *s=(EncState*)f->data; + AVFrame pict; + AVCodecContext *c=&s->av_context; + int error; + mblk_t *comp_buf=s->comp_buf; + int comp_buf_sz=comp_buf->b_datap->db_lim-comp_buf->b_datap->db_base; + + /* convert image if necessary */ + avcodec_get_frame_defaults(&pict); + avpicture_fill((AVPicture*)&pict,(uint8_t*)inm->b_rptr,c->pix_fmt,c->width,c->height); + + /* timestamp used by ffmpeg, unset here */ + pict.pts=AV_NOPTS_VALUE; + if (s->req_vfu){ + pict.pict_type=FF_I_TYPE; + s->req_vfu=FALSE; + } + comp_buf->b_rptr=comp_buf->b_wptr=comp_buf->b_datap->db_base; + if (s->codec==CODEC_ID_SNOW){ + //prepend picture size + uint32_t header=((s->vsize.width&0xffff)<<16) | (s->vsize.height&0xffff); + *(uint32_t*)comp_buf->b_wptr=htonl(header); + comp_buf->b_wptr+=4; + comp_buf_sz-=4; + } + error=avcodec_encode_video(c, (uint8_t*)comp_buf->b_wptr,comp_buf_sz, &pict); + if (error<=0) ms_warning("ms_AVencoder_process: error %i.",error); + else{ + if (c->coded_frame->pict_type==FF_I_TYPE){ + ms_message("Emitting I-frame"); + } + comp_buf->b_wptr+=error; + split_and_send(f,s,comp_buf); + } + freemsg(inm); +} + +static void enc_process(MSFilter *f){ + mblk_t *inm; + EncState *s=(EncState*)f->data; + if (s->av_context.codec==NULL) { + ms_queue_flush(f->inputs[0]); + return; + } + ms_filter_lock(f); + while((inm=ms_queue_get(f->inputs[0]))!=0){ + process_frame(f,inm); + } + ms_filter_unlock(f); +} + + +static int enc_get_br(MSFilter *f, void *arg){ + EncState *s=(EncState*)f->data; + *(int*)arg=s->maxbr; + return 0; +} + +static int enc_set_br(MSFilter *f, void *arg){ + EncState *s=(EncState*)f->data; + bool_t snow=s->codec==CODEC_ID_SNOW; + s->maxbr=*(int*)arg; + if (s->maxbr>=512000){ + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + s->fps=17; + }else if (s->maxbr>=256000){ + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + s->fps=10; + s->qmin=3; + }else if (s->maxbr>=128000){ + s->vsize.width=MS_VIDEO_SIZE_QCIF_W; + s->vsize.height=MS_VIDEO_SIZE_QCIF_H; + s->fps=10; + s->qmin=3; + }else if (s->maxbr>=64000){ + s->vsize.width=MS_VIDEO_SIZE_QCIF_W; + s->vsize.height=MS_VIDEO_SIZE_QCIF_H; + s->fps=snow ? 7 : 5; + s->qmin=snow ? 4 : 5; + }else{ + s->vsize.width=MS_VIDEO_SIZE_QCIF_W; + s->vsize.height=MS_VIDEO_SIZE_QCIF_H; + s->fps=5; + s->qmin=5; + } + if (s->av_context.codec!=NULL){ + /*apply new settings dynamically*/ + ms_filter_lock(f); + enc_postprocess(f); + enc_preprocess(f); + ms_filter_lock(f); + } + return 0; +} + + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , enc_set_fps }, + { MS_FILTER_GET_FPS , enc_get_fps }, + { MS_FILTER_SET_VIDEO_SIZE , enc_set_vsize }, + { MS_FILTER_GET_VIDEO_SIZE , enc_get_vsize }, + { MS_FILTER_ADD_FMTP , enc_add_fmtp }, + { MS_FILTER_SET_BITRATE , enc_set_br }, + { MS_FILTER_GET_BITRATE , enc_get_br }, + { MS_FILTER_SET_MTU , enc_set_mtu }, + { MS_FILTER_REQ_VFU , enc_req_vfu }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_h263_enc_desc={ + MS_H263_ENC_ID, + "MSH263Enc", + "A video H.263 encoder using ffmpeg library.", + MS_FILTER_ENCODER, + "H263-1998", + 1, /*MS_YUV420P is assumed on this input */ + 1, + enc_h263_init, + enc_preprocess, + enc_process, + enc_postprocess, + enc_uninit, + methods +}; + +MSFilterDesc ms_h263_old_enc_desc={ + MS_H263_OLD_ENC_ID, + "MSH263OldEnc", + "A video H.263 encoder using ffmpeg library. It is compliant with old RFC2190 spec.", + MS_FILTER_ENCODER, + "H263", + 1, /*MS_YUV420P is assumed on this input */ + 1, + enc_h263_init, + enc_preprocess, + enc_process, + enc_postprocess, + enc_uninit, + methods +}; + +MSFilterDesc ms_mpeg4_enc_desc={ + MS_MPEG4_ENC_ID, + "MSMpeg4Enc", + "A video MPEG4 encoder using ffmpeg library.", + MS_FILTER_ENCODER, + "MP4V-ES", + 1, /*MS_YUV420P is assumed on this input */ + 1, + enc_mpeg4_init, + enc_preprocess, + enc_process, + enc_postprocess, + enc_uninit, + methods +}; + +MSFilterDesc ms_snow_enc_desc={ + MS_SNOW_ENC_ID, + "MSSnowEnc", + "A video snow encoder using ffmpeg library.", + MS_FILTER_ENCODER, + "x-snow", + 1, /*MS_YUV420P is assumed on this input */ + 1, + enc_snow_init, + enc_preprocess, + enc_process, + enc_postprocess, + enc_uninit, + methods +}; + +#else + +MSFilterDesc ms_h263_enc_desc={ + .id=MS_H263_ENC_ID, + .name="MSH263Enc", + .text="A video H.263 encoder using ffmpeg library.", + .category=MS_FILTER_ENCODER, + .enc_fmt="H263-1998", + .ninputs=1, /*MS_YUV420P is assumed on this input */ + .noutputs=1, + .init=enc_h263_init, + .preprocess=enc_preprocess, + .process=enc_process, + .postprocess=enc_postprocess, + .uninit=enc_uninit, + .methods=methods +}; + +MSFilterDesc ms_h263_old_enc_desc={ + .id=MS_H263_OLD_ENC_ID, + .name="MSH263Enc", + .text="A video H.263 encoder using ffmpeg library, compliant with old RFC2190 spec.", + .category=MS_FILTER_ENCODER, + .enc_fmt="H263", + .ninputs=1, /*MS_YUV420P is assumed on this input */ + .noutputs=1, + .init=enc_h263_init, + .preprocess=enc_preprocess, + .process=enc_process, + .postprocess=enc_postprocess, + .uninit=enc_uninit, + .methods=methods +}; + +MSFilterDesc ms_mpeg4_enc_desc={ + .id=MS_MPEG4_ENC_ID, + .name="MSMpeg4Enc", + .text="A video MPEG4 encoder using ffmpeg library.", + .category=MS_FILTER_ENCODER, + .enc_fmt="MP4V-ES", + .ninputs=1, /*MS_YUV420P is assumed on this input */ + .noutputs=1, + .init=enc_mpeg4_init, + .preprocess=enc_preprocess, + .process=enc_process, + .postprocess=enc_postprocess, + .uninit=enc_uninit, + .methods=methods +}; + +MSFilterDesc ms_snow_enc_desc={ + .id=MS_SNOW_ENC_ID, + .name="MSSnowEnc", + .text="The snow codec is royalty-free and is open-source. \n" + "It uses innovative techniques that makes it one of the best video " + "codec. It is implemented within the ffmpeg project.\n" + "However it is under development and compatibility with other versions " + "cannot be guaranteed.", + .category=MS_FILTER_ENCODER, + .enc_fmt="x-snow", + .ninputs=1, /*MS_YUV420P is assumed on this input */ + .noutputs=1, + .init=enc_snow_init, + .preprocess=enc_preprocess, + .process=enc_process, + .postprocess=enc_postprocess, + .uninit=enc_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_mpeg4_enc_desc) +MS_FILTER_DESC_EXPORT(ms_h263_enc_desc) +MS_FILTER_DESC_EXPORT(ms_h263_old_enc_desc) +MS_FILTER_DESC_EXPORT(ms_snow_enc_desc) + diff --git a/linphone/mediastreamer2/src/videoout.c b/linphone/mediastreamer2/src/videoout.c new file mode 100644 index 000000000..bee29a67a --- /dev/null +++ b/linphone/mediastreamer2/src/videoout.c @@ -0,0 +1,884 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msvideoout.h" + +#include "ffmpeg-priv.h" + +static int video_out_handle_resize(MSFilter *f, void *arg); + +bool_t ms_display_poll_event(MSDisplay *d, MSDisplayEvent *ev){ + if (d->desc->pollevent) + return d->desc->pollevent(d,ev); + else return FALSE; +} + +#ifndef WIN32 + +#include +#include + +static bool_t sdl_initialized=FALSE; + +static ms_mutex_t sdl_mutex; + +static SDL_Surface *sdl_screen=0; + +#ifdef HAVE_X11_XLIB_H + +#include + +static void sdl_show_window(bool_t show){ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + if ( SDL_GetWMInfo(&info) ) { + if ( info.subsystem == SDL_SYSWM_X11 ) { + Display *display; + Window window; + + info.info.x11.lock_func(); + display = info.info.x11.display; + window = info.info.x11.wmwindow; + if (show) + XMapWindow(display,window); + else + XUnmapWindow(display,window); + info.info.x11.unlock_func(); + } + } +} + +#else + +static void sdl_show_window(bool_t show){ + ms_warning("SDL window show/hide not implemented"); +} + +#endif + +static SDL_Overlay * sdl_create_window(int w, int h){ + SDL_Overlay *lay; + sdl_screen = SDL_SetVideoMode(w,h, 0,SDL_SWSURFACE|SDL_RESIZABLE); + if (sdl_screen == NULL ) { + ms_warning("Couldn't set video mode: %s\n", + SDL_GetError()); + return NULL; + } + if (sdl_screen->flags & SDL_HWSURFACE) ms_message("SDL surface created in hardware"); + SDL_WM_SetCaption("Linphone Video", NULL); + ms_message("Using yuv overlay."); + lay=SDL_CreateYUVOverlay(w,h,SDL_YV12_OVERLAY,sdl_screen); + if (lay==NULL){ + ms_warning("Couldn't create yuv overlay: %s\n", + SDL_GetError()); + return NULL; + }else{ + if (lay->hw_overlay) ms_message("YUV overlay using hardware acceleration."); + } + return lay; +} + +static bool_t sdl_display_init(MSDisplay *obj, MSPicture *fbuf){ + SDL_Overlay *lay; + if (!sdl_initialized){ + /* Initialize the SDL library */ + if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + ms_error("Couldn't initialize SDL: %s", SDL_GetError()); + return FALSE; + } + /* Clean up on exit */ + atexit(SDL_Quit); + sdl_initialized=TRUE; + ms_mutex_init(&sdl_mutex,NULL); + } + if (obj->data!=NULL) + SDL_FreeYUVOverlay((SDL_Overlay*)obj->data); + + lay=sdl_create_window(fbuf->w, fbuf->h); + if (lay){ + fbuf->planes[0]=lay->pixels[0]; + fbuf->planes[1]=lay->pixels[2]; + fbuf->planes[2]=lay->pixels[1]; + fbuf->strides[0]=lay->pitches[0]; + fbuf->strides[1]=lay->pitches[2]; + fbuf->strides[2]=lay->pitches[1]; + obj->data=lay; + sdl_show_window(TRUE); + return TRUE; + } + return FALSE; +} + +static void sdl_display_lock(MSDisplay *obj){ + ms_mutex_lock(&sdl_mutex); + SDL_LockYUVOverlay((SDL_Overlay*)obj->data); + ms_mutex_unlock(&sdl_mutex); +} + +static void sdl_display_unlock(MSDisplay *obj){ + SDL_Overlay *lay=(SDL_Overlay*)obj->data; + ms_mutex_lock(&sdl_mutex); + SDL_UnlockYUVOverlay(lay); + ms_mutex_unlock(&sdl_mutex); +} + +static void sdl_display_update(MSDisplay *obj){ + SDL_Rect rect; + SDL_Overlay *lay=(SDL_Overlay*)obj->data; + rect.x=0; + rect.y=0; + rect.w=lay->w; + rect.h=lay->h; + ms_mutex_lock(&sdl_mutex); + SDL_DisplayYUVOverlay(lay,&rect); + ms_mutex_unlock(&sdl_mutex); +} + +static bool_t sdl_poll_event(MSDisplay *obj, MSDisplayEvent *ev){ + SDL_Event event; + static MSDisplayEvent last_ev; + static struct timeval tv; + static bool_t got_rs_ev=FALSE; + struct timeval cur; + int elapsed; + bool_t ret=FALSE; + ms_mutex_lock(&sdl_mutex); + if (SDL_PollEvent(&event)){ + ms_mutex_unlock(&sdl_mutex); + switch(event.type){ + case SDL_VIDEORESIZE: + last_ev.evtype=MS_DISPLAY_RESIZE_EVENT; + last_ev.w=event.resize.w; + last_ev.h=event.resize.h; + got_rs_ev=TRUE; + gettimeofday(&tv,NULL); + break; + default: + break; + } + }else ms_mutex_unlock(&sdl_mutex); + if (got_rs_ev){ + gettimeofday(&cur,NULL); + elapsed=((cur.tv_sec-tv.tv_sec)*1000) + ((cur.tv_usec-tv.tv_usec)/1000); + if (elapsed>1000){ + got_rs_ev=FALSE; + *ev=last_ev; + ret=TRUE; + } + } + return ret; +} + +static void sdl_display_uninit(MSDisplay *obj){ + SDL_Overlay *lay=(SDL_Overlay*)obj->data; + if (lay==NULL) + return; + if (lay!=NULL) + SDL_FreeYUVOverlay(lay); + if (sdl_screen!=NULL){ + SDL_FreeSurface(sdl_screen); + sdl_screen=NULL; + } + sdl_show_window(FALSE); +} + +MSDisplayDesc ms_sdl_display_desc={ + .init=sdl_display_init, + .lock=sdl_display_lock, + .unlock=sdl_display_unlock, + .update=sdl_display_update, + .uninit=sdl_display_uninit, + .pollevent=sdl_poll_event +}; + +#else + +#include + + +typedef struct _WinDisplay{ + HWND window; + HDRAWDIB ddh; + MSPicture fb; + MSDisplayEvent last_rsz; + uint8_t *rgb; + int rgb_len; + bool_t new_ev; +}WinDisplay; + +static LRESULT CALLBACK window_proc( + HWND hwnd, // handle to window + UINT uMsg, // message identifier + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + switch(uMsg){ + case WM_DESTROY: + break; + case WM_SIZE: + if (wParam==SIZE_RESTORED){ + int h=(lParam>>16) & 0xffff; + int w=lParam & 0xffff; + MSDisplay *obj; + WinDisplay *wd; + ms_message("Resized to %i,%i",w,h); + obj=(MSDisplay*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + if (obj!=NULL){ + wd=(WinDisplay*)obj->data; + wd->last_rsz.evtype=MS_DISPLAY_RESIZE_EVENT; + wd->last_rsz.w=w; + wd->last_rsz.h=h; + wd->new_ev=TRUE; + }else{ + ms_error("Could not retrieve MSDisplay from window !"); + } + } + break; + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + return 0; +} + +static HWND create_window(int w, int h) +{ + WNDCLASS wc; + HINSTANCE hInstance = GetModuleHandle(NULL); + HWND hwnd; + RECT rect; + wc.style = 0 ; + wc.lpfnWndProc = window_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = NULL; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(hInstance, IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "Video Window"; + + if(!RegisterClass(&wc)) + { + /* already registred! */ + } + rect.left=100; + rect.top=100; + rect.right=rect.left+w; + rect.bottom=rect.top+h; + if (!AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW|WS_VISIBLE /*WS_CAPTION WS_TILED|WS_BORDER*/,FALSE)){ + ms_error("AdjustWindowRect failed."); + } + ms_message("AdjustWindowRect: %li,%li %li,%li",rect.left,rect.top,rect.right,rect.bottom); + hwnd=CreateWindow("Video Window", "Video window", WS_OVERLAPPEDWINDOW|WS_VISIBLE , + CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left,rect.bottom-rect.top, + NULL, NULL, hInstance, NULL); + if (hwnd==NULL){ + ms_error("Fail to create video window"); + } + return hwnd; +} + +static bool_t win_display_init(MSDisplay *obj, MSPicture *fbuf){ + WinDisplay *wd=(WinDisplay*)obj->data; + int ysize,usize; + + if (wd!=NULL) + { + if (wd->ddh) DrawDibClose(wd->ddh); + wd->ddh=NULL; + if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]); + wd->fb.planes[0]=NULL; + wd->fb.planes[1]=NULL; + wd->fb.planes[2]=NULL; + if (wd->rgb) ms_free(wd->rgb); + wd->rgb=NULL; + wd->rgb_len=0; + } + else + wd=(WinDisplay*)ms_new0(WinDisplay,1); + + obj->data=wd; + + wd->fb.w=fbuf->w; + wd->fb.h=fbuf->h; + + if (wd->window==NULL){ + if (obj->window_id!=0){ + void *p; + wd->window=(HWND)obj->window_id; + p=(void*)GetWindowLongPtr(wd->window,GWLP_USERDATA); + if (p!=NULL){ + ms_error("Gulp: this externally supplied windows seems to " + "already have a userdata ! resizing will crash !"); + }else SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj); + }else{ + wd->window=create_window(wd->fb.w,wd->fb.h); + if (wd->window!=NULL) SetWindowLongPtr(wd->window,GWLP_USERDATA,(LONG_PTR)obj); + else return FALSE; + } + } + + if (wd->ddh==NULL) wd->ddh=DrawDibOpen(); + if (wd->ddh==NULL){ + ms_error("DrawDibOpen() failed."); + return FALSE; + } + /*allocate yuv and rgb buffers*/ + if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]); + if (wd->rgb) ms_free(wd->rgb); + ysize=wd->fb.w*wd->fb.h; + usize=ysize/4; + fbuf->planes[0]=wd->fb.planes[0]=(uint8_t*)ms_malloc0(ysize+2*usize); + fbuf->planes[1]=wd->fb.planes[1]=wd->fb.planes[0]+ysize; + fbuf->planes[2]=wd->fb.planes[2]=wd->fb.planes[1]+usize; + fbuf->strides[0]=wd->fb.strides[0]=wd->fb.w; + fbuf->strides[1]=wd->fb.strides[1]=wd->fb.w/2; + fbuf->strides[2]=wd->fb.strides[2]=wd->fb.w/2; + + wd->rgb_len=ysize*3; + wd->rgb=(uint8_t*)ms_malloc0(wd->rgb_len); + return TRUE; +} + +typedef struct rgb{ + uint8_t r,g,b; +} rgb_t; + +typedef struct yuv{ + uint8_t y,u,v; +} yuv_t; + + + +static void yuv420p_to_rgb(MSPicture *src, uint8_t *rgb){ + struct SwsContext *sws; + int rgb_stride=-src->w*3; + uint8_t *p; + + p=rgb+(src->w*3*(src->h-1)); + sws=sws_getContext(src->w,src->h,PIX_FMT_YUV420P, + src->w,src->h,PIX_FMT_RGB24, + 0, NULL, NULL, NULL); + if (sws_scale(sws,src->planes,src->strides, 0, + 0, &p, &rgb_stride)<0){ + ms_error("Error in 420->rgb sws_scale()."); + } + sws_freeContext(sws); + + /*revert colors*/ + { + int i,j,stride; + rgb_t pix; + stride=src->w*3; + p=rgb; + for(i=0;ih;++i){ + for(j=0;jdata; + HDC hdc; + BITMAPINFOHEADER bi; + RECT rect; + bool_t ret; + if (wd->window==NULL) return; + hdc=GetDC(wd->window); + if (hdc==NULL) { + ms_error("Could not get window dc"); + return; + } + yuv420p_to_rgb(&wd->fb, wd->rgb); + memset(&bi,0,sizeof(bi)); + bi.biSize=sizeof(bi); + GetClientRect(wd->window,&rect); + /* + bi.biWidth=wd->fb.w; + bi.biHeight=wd->fb.h; + bi.biPlanes=3; + bi.biBitCount=12; + bi.biCompression=MAKEFOURCC('I','4','2','0'); + bi.biSizeImage=(wd->fb.w*wd->fb.h*3)/2; + */ + bi.biWidth=wd->fb.w; + bi.biHeight=wd->fb.h; + bi.biPlanes=1; + bi.biBitCount=24; + bi.biCompression=BI_RGB; + bi.biSizeImage=wd->rgb_len; + + //if (bi.biHeight>rect.bottom) + // bi.biHeight=rect.bottom; + //bi.biSizeImage=(bi.biWidth*bi.biHeight)*3; + + ret=DrawDibDraw(wd->ddh,hdc,0,0, + //bi.biWidth,bi.biHeight, + rect.right,rect.bottom, + &bi,wd->rgb, + //0,0,rect.right,rect.bottom,0); + 0,0,bi.biWidth,bi.biHeight,0); + + if (!ret) ms_error("DrawDibDraw failed."); + ReleaseDC(NULL,hdc); +} + +static void win_display_uninit(MSDisplay *obj){ + WinDisplay *wd=(WinDisplay*)obj->data; + if (wd==NULL) + return; + if (wd->window && !obj->window_id) DestroyWindow(wd->window); + if (wd->ddh) DrawDibClose(wd->ddh); + if (wd->fb.planes[0]) ms_free(wd->fb.planes[0]); + if (wd->rgb) ms_free(wd->rgb); + ms_free(wd); +} + +bool_t win_display_pollevent(MSDisplay *d, MSDisplayEvent *ev){ + WinDisplay *wd=(WinDisplay*)d->data; + if (wd->new_ev){ + wd->new_ev=FALSE; + *ev=wd->last_rsz; + return TRUE; + } + return FALSE; +} + +#ifdef _MSC_VER + +extern MSDisplayDesc ms_win_display_desc={ + win_display_init, + NULL, + NULL, + win_display_update, + win_display_uninit, + win_display_pollevent +}; + +#else + +MSDisplayDesc ms_win_display_desc={ + .init=win_display_init, + .update=win_display_update, + .uninit=win_display_uninit, + .pollevent=win_display_pollevent +}; + +#endif + +#endif + +MSDisplay *ms_display_new(MSDisplayDesc *desc){ + MSDisplay *obj=(MSDisplay *)ms_new0(MSDisplay,1); + obj->desc=desc; + obj->data=NULL; + return obj; +} + +void ms_display_set_window_id(MSDisplay *d, long id){ + d->window_id=id; +} + +void ms_display_destroy(MSDisplay *obj){ + obj->desc->uninit(obj); + ms_free(obj); +} + +typedef struct VideoOut +{ + AVRational ratio; + MSPicture fbuf; + MSPicture local_pic; + MSRect local_rect; + mblk_t *local_msg; + MSPicture tmp_local_pic; + mblk_t *tmp_local_msg; + int corner; + struct SwsContext *sws1; + struct SwsContext *sws2; + MSDisplay *display; + bool_t own_display; + bool_t ready; +} VideoOut; + + +#define SCALE_FACTOR 6 + +static void set_corner(VideoOut *s, int corner) +{ + s->corner=corner; + s->local_pic.w=s->fbuf.w/SCALE_FACTOR; + s->local_pic.h=s->fbuf.h/SCALE_FACTOR; + s->tmp_local_pic.h = s->local_pic.h; + s->tmp_local_pic.w = s->local_pic.w; + if (corner==1) + { + /* top left corner */ + s->local_rect.x=0; + s->local_rect.y=0; + s->local_rect.w=s->local_pic.w; + s->local_rect.h=s->local_pic.h; + } + else if (corner==2) + { + /* top right corner */ + s->local_rect.x=s->fbuf.w-s->local_pic.w; + s->local_rect.y=0; + s->local_rect.w=s->local_pic.w; + s->local_rect.h=s->local_pic.h; + } + else if (corner==3) + { + /* bottom left corner */ + s->local_rect.x=0; + s->local_rect.y=s->fbuf.h-s->local_pic.h; + s->local_rect.w=s->local_pic.w; + s->local_rect.h=s->local_pic.h; + } + else + { + /* default: bottom right corner */ + /* corner can be set to -1: to disable the self view... */ + s->local_rect.x=s->fbuf.w-s->local_pic.w; + s->local_rect.y=s->fbuf.h-s->local_pic.h; + s->local_rect.w=s->local_pic.w; + s->local_rect.h=s->local_pic.h; + } +} + +static void set_vsize(VideoOut *s, MSVideoSize *sz){ + if (s->ratio.num!=0){ + sz->width=sz->width & (~0x1); + sz->height=sz->width*s->ratio.den/s->ratio.num; + } + s->fbuf.w=sz->width; + s->fbuf.h=sz->height; + set_corner(s, s->corner); +} + +static void video_out_init(MSFilter *f){ + VideoOut *obj=(VideoOut*)ms_new(VideoOut,1); + MSVideoSize def_size; + obj->ratio.num=11; + obj->ratio.den=9; + def_size.width=MS_VIDEO_SIZE_CIF_W; + def_size.height=MS_VIDEO_SIZE_CIF_H; + obj->local_msg=NULL; + obj->tmp_local_msg=NULL; + obj->corner=0; + obj->sws1=NULL; + obj->sws2=NULL; + obj->display=NULL; + obj->own_display=FALSE; + obj->ready=FALSE; + set_vsize(obj,&def_size); + f->data=obj; +} + + +static void video_out_uninit(MSFilter *f){ + VideoOut *obj=(VideoOut*)f->data; + if (obj->display!=NULL && obj->own_display) + ms_display_destroy(obj->display); + if (obj->sws1!=NULL){ + sws_freeContext(obj->sws1); + obj->sws1=NULL; + } + if (obj->sws2!=NULL){ + sws_freeContext(obj->sws2); + obj->sws2=NULL; + } + ms_free(obj); +} + + +static void video_out_preprocess(MSFilter *f){ + VideoOut *obj=(VideoOut*)f->data; + if (obj->display==NULL){ +#ifndef WIN32 + obj->display=ms_display_new(&ms_sdl_display_desc); +#else + obj->display=ms_display_new(&ms_win_display_desc); +#endif + obj->own_display=TRUE; + } + if (!ms_display_init(obj->display,&obj->fbuf)){ + if (obj->own_display) ms_display_destroy(obj->display); + obj->display=NULL; + } + if (obj->sws1!=NULL){ + sws_freeContext(obj->sws1); + obj->sws1=NULL; + } + if (obj->sws2!=NULL){ + sws_freeContext(obj->sws2); + obj->sws2=NULL; + } + if (obj->local_msg!=NULL) { + freemsg(obj->local_msg); + obj->local_msg=NULL; + } + if (obj->tmp_local_msg!=NULL) { + freemsg(obj->tmp_local_msg); + obj->tmp_local_msg=NULL; + } + obj->ready=TRUE; +} + +static void video_out_postprocess(MSFilter *f){ +} + +static void mirror(unsigned char* dst,unsigned char* src,int dststride,int srcstride,int w,int h){ + int y; + for(y=0;ydata; + mblk_t *inm; + +#ifdef WIN32 + video_out_handle_resize(f, NULL); +#endif + + ms_filter_lock(f); + if (obj->display==NULL){ + ms_filter_unlock(f); + if (f->inputs[0]!=NULL) + ms_queue_flush(f->inputs[0]); + if (f->inputs[1]!=NULL) + ms_queue_flush(f->inputs[1]); + return; + } + /*get most recent message and draw it*/ + if (f->inputs[1]!=NULL && (inm=ms_queue_peek_last(f->inputs[1]))!=0) { + + if (obj->corner==-1) + { + if (obj->tmp_local_msg!=NULL) { + freemsg(obj->tmp_local_msg); + obj->tmp_local_msg=NULL; + } + if (obj->local_msg!=NULL) { + freemsg(obj->local_msg); + obj->local_msg=NULL; + } + } + else + { + MSPicture src; + if (yuv_buf_init_from_mblk(&src,inm)==0){ + + if (obj->sws2==NULL){ + obj->sws2=sws_getContext(src.w,src.h,PIX_FMT_YUV420P, + obj->local_pic.w,obj->local_pic.h,PIX_FMT_YUV420P, + SWS_FAST_BILINEAR, NULL, NULL, NULL); + } + obj->tmp_local_pic.h = obj->local_pic.h; + obj->tmp_local_pic.w = obj->local_pic.w; + if (obj->tmp_local_msg==NULL){ + obj->tmp_local_msg=yuv_buf_alloc(&obj->tmp_local_pic, + obj->tmp_local_pic.w,obj->tmp_local_pic.h); + } + if (obj->local_msg==NULL){ + obj->local_msg=yuv_buf_alloc(&obj->local_pic, + obj->local_pic.w,obj->local_pic.h); + } + if (sws_scale(obj->sws2,src.planes,src.strides, 0, + src.h, obj->tmp_local_pic.planes, obj->tmp_local_pic.strides)<0){ + ms_error("Error in sws_scale()."); + } + + mirror(obj->local_pic.planes[0],obj->tmp_local_pic.planes[0], + obj->local_pic.strides[0],obj->tmp_local_pic.strides[0], + obj->local_pic.w,obj->local_pic.h); + mirror(obj->local_pic.planes[1],obj->tmp_local_pic.planes[1], + obj->local_pic.strides[1],obj->tmp_local_pic.strides[1], + obj->local_pic.w>>1,obj->local_pic.h>>1); + mirror(obj->local_pic.planes[2],obj->tmp_local_pic.planes[2], + obj->local_pic.strides[2],obj->tmp_local_pic.strides[2], + obj->local_pic.w>>1,obj->local_pic.h>>1); + } + } + ms_queue_flush(f->inputs[1]); + } + + if (f->inputs[0]!=NULL && (inm=ms_queue_peek_last(f->inputs[0]))!=0) { + MSPicture src; + if (yuv_buf_init_from_mblk(&src,inm)==0){ + if (obj->sws1==NULL){ + obj->sws1=sws_getContext(src.w,src.h,PIX_FMT_YUV420P, + obj->fbuf.w,obj->fbuf.h,PIX_FMT_YUV420P, + SWS_FAST_BILINEAR, NULL, NULL, NULL); + } + ms_display_lock(obj->display); + if (sws_scale(obj->sws1,src.planes,src.strides, 0, + src.h, obj->fbuf.planes, obj->fbuf.strides)<0){ + ms_error("Error in sws_scale()."); + } + ms_display_unlock(obj->display); + } + ms_queue_flush(f->inputs[0]); + } + /*copy resized local view into main buffer, at bottom left corner:*/ + if (obj->local_msg!=NULL){ + MSPicture corner=obj->fbuf; + MSVideoSize roi; + roi.width=obj->local_pic.w; + roi.height=obj->local_pic.h; + corner.w=obj->local_pic.w; + corner.h=obj->local_pic.h; + corner.planes[0]+=obj->local_rect.x+(obj->local_rect.y*corner.strides[0]); + corner.planes[1]+=(obj->local_rect.x/2)+((obj->local_rect.y/2)*corner.strides[1]); + corner.planes[2]+=(obj->local_rect.x/2)+((obj->local_rect.y/2)*corner.strides[2]); + ms_display_lock(obj->display); + yuv_buf_copy(obj->local_pic.planes,obj->local_pic.strides, + corner.planes,corner.strides,roi); + ms_display_unlock(obj->display); + } + + ms_display_update(obj->display); + ms_filter_unlock(f); +} + +static int video_out_set_vsize(MSFilter *f,void *arg){ + VideoOut *s=(VideoOut*)f->data; + bool_t reconfigure; + ms_filter_lock(f); + reconfigure=s->ready; + set_vsize(s,(MSVideoSize*)arg); + if (reconfigure) video_out_preprocess(f); + ms_filter_unlock(f); + return 0; +} + +static int video_out_set_display(MSFilter *f,void *arg){ + VideoOut *s=(VideoOut*)f->data; + s->display=(MSDisplay*)arg; + return 0; +} + +static int video_out_handle_resize(MSFilter *f, void *arg){ + VideoOut *s=(VideoOut*)f->data; + MSDisplay *disp=s->display; + if (disp!=NULL){ + MSDisplayEvent ev; + if (ms_display_poll_event(disp,&ev)){ + if (ev.evtype==MS_DISPLAY_RESIZE_EVENT){ + MSVideoSize sz; + sz.width=ev.w; + sz.height=ev.h; +#ifndef WIN32 + video_out_set_vsize(f,&sz); +#endif + } + } + } + return 0; +} + +static int video_out_set_corner(MSFilter *f,void *arg){ + VideoOut *s=(VideoOut*)f->data; + set_corner(s, *(int*)arg); +#if 1 + ms_filter_lock(f); + ms_display_lock(s->display); + { + int w=s->fbuf.w; + int h=s->fbuf.h; + int ysize=w*h; + int usize=ysize/4; + + memset(s->fbuf.planes[0], 0, ysize); + memset(s->fbuf.planes[1], 0, usize); + memset(s->fbuf.planes[2], 0, usize); + } + ms_display_unlock(s->display); + ms_filter_unlock(f); +#endif + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_VIDEO_SIZE , video_out_set_vsize }, + { MS_VIDEO_OUT_SET_DISPLAY , video_out_set_display}, + { MS_VIDEO_OUT_HANDLE_RESIZING , video_out_handle_resize}, + { MS_VIDEO_OUT_SET_CORNER , video_out_set_corner}, + { 0 ,NULL} +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_video_out_desc={ + MS_VIDEO_OUT_ID, + "MSVideoOut", + "A generic video display", + MS_FILTER_OTHER, + NULL, + 2, + 0, + video_out_init, + video_out_preprocess, + video_out_process, + video_out_postprocess, + video_out_uninit, + methods +}; + +#else + +MSFilterDesc ms_video_out_desc={ + .id=MS_VIDEO_OUT_ID, + .name="MSVideoOut", + .text="A generic video display", + .category=MS_FILTER_OTHER, + .ninputs=2, + .noutputs=0, + .init=video_out_init, + .preprocess=video_out_preprocess, + .process=video_out_process, + .postprocess=video_out_postprocess, + .uninit=video_out_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_video_out_desc) diff --git a/linphone/mediastreamer2/src/videostream.c b/linphone/mediastreamer2/src/videostream.c new file mode 100644 index 000000000..30a1df479 --- /dev/null +++ b/linphone/mediastreamer2/src/videostream.c @@ -0,0 +1,520 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msrtp.h" + + +#if (defined(WIN32) || defined(_WIN32_WCE)) +/* avoid double declaration of ms_win_display_desc */ +#define MS_VIDEO_OUT_HANDLE_RESIZING MS_FILTER_METHOD_NO_ARG(MS_VIDEO_OUT_ID,1) +#else +#include "mediastreamer2/msvideoout.h" +#endif + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +extern RtpSession * create_duplex_rtpsession( int locport, bool_t ipv6); + +#define MAX_RTP_SIZE UDP_MAX_SIZE + +/* this code is not part of the library itself, it is part of the mediastream program */ +void video_stream_free (VideoStream * stream) +{ + if (stream->session!=NULL){ + rtp_session_unregister_event_queue(stream->session,stream->evq); + rtp_session_destroy(stream->session); + } + if (stream->rtprecv != NULL) + ms_filter_destroy (stream->rtprecv); + if (stream->rtpsend!=NULL) + ms_filter_destroy (stream->rtpsend); + if (stream->source != NULL) + ms_filter_destroy (stream->source); + if (stream->output != NULL) + ms_filter_destroy (stream->output); + if (stream->decoder != NULL) + ms_filter_destroy (stream->decoder); + if (stream->encoder != NULL) + ms_filter_destroy (stream->encoder); + if (stream->pixconv!=NULL) + ms_filter_destroy(stream->pixconv); + if (stream->tee!=NULL) + ms_filter_destroy(stream->tee); + if (stream->ticker != NULL) + ms_ticker_destroy (stream->ticker); + if (stream->evq!=NULL) + ortp_ev_queue_destroy(stream->evq); + ms_free (stream); +} + +/*this function must be called from the MSTicker thread: +it replaces one filter by another one. +This is a dirty hack that works anyway. +It would be interesting to have something that does the job +simplier within the MSTicker api +*/ +void video_stream_change_decoder(VideoStream *stream, int payload){ + RtpSession *session=stream->session; + RtpProfile *prof=rtp_session_get_profile(session); + PayloadType *pt=rtp_profile_get_payload(prof,payload); + if (pt!=NULL){ + MSFilter *dec=ms_filter_create_decoder(pt->mime_type); + if (dec!=NULL){ + ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0); + ms_filter_unlink(stream->decoder,0,stream->output,0); + ms_filter_postprocess(stream->decoder); + ms_filter_destroy(stream->decoder); + stream->decoder=dec; + if (pt->recv_fmtp!=NULL) + ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); + ms_filter_link (stream->rtprecv, 0, stream->decoder, 0); + ms_filter_link (stream->decoder,0 , stream->output, 0); + ms_filter_preprocess(stream->decoder,stream->ticker); + + }else{ + ms_warning("No decoder found for %s",pt->mime_type); + } + }else{ + ms_warning("No payload defined with number %i",payload); + } +} + +static void video_stream_adapt_bitrate(VideoStream *stream, int jitter, float lost){ + if (stream->encoder!=NULL){ + if (lost>10){ + int bitrate=0; + int new_bitrate; + ms_warning("Remote reports bad receiving experience, trying to reduce bitrate of video encoder."); + + ms_filter_call_method(stream->encoder,MS_FILTER_GET_BITRATE,&bitrate); + if (bitrate==0){ + ms_error("Video encoder does not implement MS_FILTER_GET_BITRATE."); + return; + } + if (bitrate>=20000){ + new_bitrate=bitrate-10000; + ms_warning("Encoder bitrate reduced from %i to %i b/s.",bitrate,new_bitrate); + ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&new_bitrate); + }else{ + ms_warning("Video encoder bitrate already at minimum."); + } + + } + } +} + +static void video_steam_process_rtcp(VideoStream *stream, mblk_t *m){ + do{ + if (rtcp_is_SR(m)){ + const report_block_t *rb; + ms_message("video_steam_process_rtcp: receiving RTCP SR"); + rb=rtcp_SR_get_report_block(m,0); + if (rb){ + unsigned int ij; + float flost; + ij=report_block_get_interarrival_jitter(rb); + flost=100.0*report_block_get_fraction_lost(rb)/256.0; + ms_message("interarrival jitter=%u , lost packets percentage since last report=%f ",ij,flost); + if (stream->adapt_bitrate) video_stream_adapt_bitrate(stream,ij,flost); + } + } + }while(rtcp_next_packet(m)); +} + +void video_stream_iterate(VideoStream *stream){ + if (stream->output!=NULL) + ms_filter_call_method_noarg(stream->output, + MS_VIDEO_OUT_HANDLE_RESIZING); + if (stream->evq){ + OrtpEvent *ev=ortp_ev_queue_get(stream->evq); + if (ev!=NULL){ + if (ortp_event_get_type(ev)==ORTP_EVENT_RTCP_PACKET_RECEIVED){ + OrtpEventData *evd=ortp_event_get_data(ev); + video_steam_process_rtcp(stream,evd->packet); + } + ortp_event_destroy(ev); + } + } +} + +static void payload_type_changed(RtpSession *session, unsigned long data){ + VideoStream *stream=(VideoStream*)data; + int pt=rtp_session_get_recv_payload_type(stream->session); + video_stream_change_decoder(stream,pt); +} + +VideoStream *video_stream_new(int locport, bool_t use_ipv6){ + VideoStream *stream = (VideoStream *)ms_new0 (VideoStream, 1); + stream->session=create_duplex_rtpsession(locport,use_ipv6); + stream->evq=ortp_ev_queue_new(); + stream->rtpsend=ms_filter_new(MS_RTP_SEND_ID); + rtp_session_register_event_queue(stream->session,stream->evq); + return stream; +} + +void video_stream_set_relay_session_id(VideoStream *stream, const char *id){ + ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id); +} + + +void video_stream_enable_adaptive_bitrate_control(VideoStream *s, bool_t yesno){ + s->adapt_bitrate=yesno; +} + +int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *remip, int remport, + int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *cam) +{ + PayloadType *pt; + RtpSession *rtps=stream->session; + MSPixFmt format; + MSVideoSize vsize; + float fps=15; + + vsize.height=MS_VIDEO_SIZE_CIF_H; + vsize.width=MS_VIDEO_SIZE_CIF_W; + + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + ms_error("videostream.c: undefined payload type."); + return -1; + } + stream->encoder=ms_filter_create_encoder(pt->mime_type); + stream->decoder=ms_filter_create_decoder(pt->mime_type); + if ((stream->encoder==NULL) || (stream->decoder==NULL)){ + /* big problem: we have not a registered codec for this payload...*/ + ms_error("videostream.c: No codecs available for payload %i:%s.",payload,pt->mime_type); + return -1; + } + + rtp_session_set_profile(rtps,profile); + if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port); + rtp_session_set_payload_type(rtps,payload); + rtp_session_set_jitter_compensation(rtps,jitt_comp); + + rtp_session_signal_connect(stream->session,"payload_type_changed", + (RtpCallback)payload_type_changed,(unsigned long)stream); + + rtp_session_set_recv_buf_size(stream->session,MAX_RTP_SIZE); + + /* creates two rtp filters to recv send streams (remote part) */ + if (remport>0) ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,stream->session); + + stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID); + ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,stream->session); + + /* creates the filters */ + stream->source = ms_web_cam_create_reader(cam); + stream->tee = ms_filter_new(MS_TEE_ID); + stream->output=ms_filter_new(MS_VIDEO_OUT_ID); + + + + if (pt->normal_bitrate>0){ + ms_message("Limiting bitrate of video encoder to %i bits/s",pt->normal_bitrate); + ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate); + } + /* set parameters to the encoder and decoder*/ + if (pt->send_fmtp){ + ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp); + ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,pt->send_fmtp); + } + ms_filter_call_method(stream->encoder,MS_FILTER_GET_VIDEO_SIZE,&vsize); + ms_filter_call_method(stream->encoder,MS_FILTER_GET_FPS,&fps); + ms_message("Setting vsize=%ix%i, fps=%f",vsize.width,vsize.height,fps); + /* configure the filters */ + ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps); + ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize); + + /* get the output format for webcam reader */ + ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format); + if (format==MS_MJPEG){ + stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID); + }else{ + stream->pixconv = ms_filter_new(MS_PIX_CONV_ID); + /*set it to the pixconv */ + ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format); + ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vsize); + } + /*force the decoder to output YUV420P */ + format=MS_YUV420P; + ms_filter_call_method(stream->decoder,MS_FILTER_SET_PIX_FMT,&format); + + + /*ask the video display to always output CIF */ + vsize.height=MS_VIDEO_SIZE_CIF_H; + vsize.width=MS_VIDEO_SIZE_CIF_W; + + ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&vsize); + ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format); + + if (pt->recv_fmtp!=NULL) + ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); + + /* and then connect all */ + ms_filter_link (stream->source, 0, stream->pixconv, 0); + ms_filter_link (stream->pixconv, 0, stream->tee, 0); + ms_filter_link (stream->tee, 0 ,stream->encoder, 0 ); + ms_filter_link (stream->encoder,0, stream->rtpsend,0); + + ms_filter_link (stream->rtprecv, 0, stream->decoder, 0); + ms_filter_link (stream->decoder,0 , stream->output, 0); + /* the source video must be send for preview */ + ms_filter_link(stream->tee,1,stream->output,1); + + /* create the ticker */ + stream->ticker = ms_ticker_new(); + /* attach it the graph */ + ms_ticker_attach (stream->ticker, stream->source); + return 0; +} + +void video_stream_send_vfu(VideoStream *stream){ + if (stream->encoder) + ms_filter_call_method_noarg(stream->encoder,MS_FILTER_REQ_VFU); +} + +void +video_stream_stop (VideoStream * stream) +{ + if (stream->ticker){ + ms_ticker_detach(stream->ticker,stream->source); + + rtp_stats_display(rtp_session_get_stats(stream->session),"Video session's RTP statistics"); + + ms_filter_unlink(stream->source,0,stream->pixconv,0); + ms_filter_unlink(stream->pixconv,0,stream->tee,0); + ms_filter_unlink(stream->tee,0,stream->encoder,0); + ms_filter_unlink(stream->encoder, 0, stream->rtpsend,0); + ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0); + ms_filter_unlink(stream->decoder,0,stream->output,0); + ms_filter_unlink(stream->tee,1,stream->output,1); + } + video_stream_free (stream); +} + + +void video_stream_set_rtcp_information(VideoStream *st, const char *cname, const char *tool){ + if (st->session!=NULL){ + rtp_session_set_source_description(st->session,cname,NULL,NULL,NULL,NULL,tool, + "This is free software (GPL) !"); + } +} + + + +VideoStream * video_preview_start(MSWebCam *device){ + VideoStream *stream = (VideoStream *)ms_new0 (VideoStream, 1); + MSPixFmt format; + MSVideoSize vsize; + vsize.width=MS_VIDEO_SIZE_CIF_W; + vsize.height=MS_VIDEO_SIZE_CIF_H; + + /* creates the filters */ + stream->source = ms_web_cam_create_reader(device); + stream->output = ms_filter_new(MS_VIDEO_OUT_ID); + + /* configure the filters */ + ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format); + ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&vsize); + + if (format==MS_MJPEG){ + stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID); + }else{ + stream->pixconv=ms_filter_new(MS_PIX_CONV_ID); + ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format); + ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vsize); + } + format=MS_YUV420P; + ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format); + ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&vsize); + /* and then connect all */ + ms_filter_link(stream->source,0, stream->pixconv,0); + ms_filter_link(stream->pixconv,0,stream->output,0); + /* create the ticker */ + stream->ticker = ms_ticker_new(); + ms_ticker_attach (stream->ticker, stream->source); + return stream; +} + +void video_preview_stop(VideoStream *stream){ + ms_ticker_detach(stream->ticker, stream->source); + ms_filter_unlink(stream->source,0,stream->pixconv,0); + ms_filter_unlink(stream->pixconv,0,stream->output,0); + + video_stream_free(stream); +} + + +int video_stream_send_only_start(VideoStream* stream, RtpProfile *profile, const char *remip, int remport, + int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *device){ + PayloadType *pt; + MSPixFmt format; + MSVideoSize vsize; + RtpSession *rtps=stream->session; + float fps=15; + + vsize.width=MS_VIDEO_SIZE_CIF_W; + vsize.height=MS_VIDEO_SIZE_CIF_H; + + rtp_session_set_profile(rtps,profile); + if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port); + rtp_session_set_payload_type(rtps,payload); + rtp_session_set_jitter_compensation(rtps,jitt_comp); + + /* creates rtp filter to send streams (remote part) */ + rtp_session_set_recv_buf_size(rtps,MAX_RTP_SIZE); + stream->rtpsend =ms_filter_new(MS_RTP_SEND_ID); + if (remport>0) ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,stream->session); + + /* creates the filters */ + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + video_stream_free(stream); + ms_error("videostream.c: undefined payload type."); + return -1; + } + stream->encoder=ms_filter_create_encoder(pt->mime_type); + if ((stream->encoder==NULL)){ + /* big problem: we have not a registered codec for this payload...*/ + video_stream_free(stream); + ms_error("videostream.c: No codecs available for payload %i.",payload); + return -1; + } + + /* creates the filters */ + stream->source = ms_web_cam_create_reader(device); + stream->pixconv= ms_filter_new(MS_PIX_CONV_ID); + + + /* configure the filters */ + if (pt->send_fmtp) + ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp); + ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate); + ms_filter_call_method(stream->encoder,MS_FILTER_GET_FPS,&fps); + ms_filter_call_method(stream->encoder,MS_FILTER_GET_VIDEO_SIZE,&vsize); + + ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps); + ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize); + + /* get the output format for webcam reader */ + ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format); + /*set it to the pixconv */ + ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format); + ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vsize); + + ms_message("vsize=%ix%i, fps=%f, send format: %s, capture format: %d, bitrate: %d", + vsize.width,vsize.height,fps,pt->send_fmtp,format, pt->normal_bitrate); + + /* and then connect all */ + ms_filter_link (stream->source, 0, stream->pixconv, 0); + ms_filter_link (stream->pixconv, 0, stream->encoder, 0); + ms_filter_link (stream->encoder,0, stream->rtpsend,0); + + /* create the ticker */ + stream->ticker = ms_ticker_new(); + /* attach it the graph */ + ms_ticker_attach (stream->ticker, stream->source); + return 0; +} + +void video_stream_send_only_stop(VideoStream *stream){ + if (stream->ticker){ + ms_ticker_detach (stream->ticker, stream->source); + ms_filter_unlink(stream->source,0,stream->pixconv,0); + ms_filter_unlink(stream->pixconv,0,stream->encoder,0); + ms_filter_unlink(stream->encoder,0,stream->rtpsend,0); + } + video_stream_free(stream); +} + +int video_stream_recv_only_start (VideoStream *stream, RtpProfile *profile, const char *remip, int remport,int payload, int jitt_comp){ + PayloadType *pt; + MSPixFmt format; + MSVideoSize vsize; + RtpSession *rtps=stream->session; + + vsize.width=MS_VIDEO_SIZE_CIF_W; + vsize.height=MS_VIDEO_SIZE_CIF_H; + + rtp_session_set_profile(rtps,profile); + if (remport>0) rtp_session_set_remote_addr(rtps,remip,remport); + rtp_session_set_payload_type(rtps,payload); + rtp_session_set_jitter_compensation(rtps,jitt_comp); + + /* creates rtp filters to recv streams */ + rtp_session_set_recv_buf_size(rtps,MAX_RTP_SIZE); + stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID); + ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,rtps); + + /* creates the filters */ + pt=rtp_profile_get_payload(profile,payload); + if (pt==NULL){ + ms_error("videostream.c: undefined payload type."); + return -1; + } + stream->decoder=ms_filter_create_decoder(pt->mime_type); + if (stream->decoder==NULL){ + /* big problem: we have not a registered codec for this payload...*/ + ms_error("videostream.c: No codecs available for payload %i:%s.",payload,pt->mime_type); + return -1; + } + stream->output=ms_filter_new(MS_VIDEO_OUT_ID); + + /*force the decoder to output YUV420P */ + format=MS_YUV420P; + /*ask the size-converter to always output CIF */ + vsize.width=MS_VIDEO_SIZE_CIF_W; + vsize.height=MS_VIDEO_SIZE_CIF_H; + ms_message("Setting output vsize=%ix%i",vsize.width,vsize.height); + + ms_filter_call_method(stream->decoder,MS_FILTER_SET_PIX_FMT,&format); + ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format); + ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&vsize); + + if (pt->recv_fmtp!=NULL) { + ms_message("pt->recv_fmtp: %s", pt->recv_fmtp); + ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); + } + + /* and then connect all */ + ms_filter_link (stream->rtprecv, 0, stream->decoder, 0); + ms_filter_link (stream->decoder,0 , stream->output, 0); + + /* create the ticker */ + stream->ticker = ms_ticker_new(); + /* attach it the graph */ + ms_ticker_attach (stream->ticker, stream->rtprecv); + return 0; +} + +void video_stream_recv_only_stop (VideoStream * stream){ + if (stream->ticker!=NULL){ + ms_ticker_detach(stream->ticker, stream->rtprecv); + rtp_stats_display(rtp_session_get_stats(stream->session),"Video session's RTP statistics"); + ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0); + ms_filter_unlink(stream->decoder,0,stream->output,0); + } + video_stream_free (stream); +} + diff --git a/linphone/mediastreamer2/src/wincevideods.c b/linphone/mediastreamer2/src/wincevideods.c new file mode 100644 index 000000000..160cbb6ee --- /dev/null +++ b/linphone/mediastreamer2/src/wincevideods.c @@ -0,0 +1,998 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +//#define AYMERIC_TEST +#define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA + +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msv4l.h" + +#include +#include "nowebcam.h" +#if 0 +#include +#endif + +#include +#include +#include + +#include +//#include +#include "dxfilter.h" +#if 0 +#include +#endif +#include +#include + +typedef struct V4wState{ + + char dev[512]; + int devidx; + + CComPtr m_pGraph; + CComPtr m_pBuilder; + CComPtr m_pControl; + CDXFilter *m_pDXFilter; + CComPtr m_pIDXFilter; + CComPtr m_pNullRenderer; + CComPtr m_pDeviceFilter; + DWORD rotregvalue; + + MSVideoSize vsize; + int pix_fmt; + mblk_t *mire[10]; + queue_t rq; + ms_mutex_t mutex; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + bool_t running; + bool_t startwith_yuv_bug; /* avoid bug with USB vimicro cards. */ +}V4wState; + +static V4wState *s_callback=NULL; + +static void dummy(void*p){ +} + +HRESULT ( Callback)(IMediaSample* pSample, REFERENCE_TIME* sTime, REFERENCE_TIME* eTime, BOOL changed) +{ + BYTE *byte_buf=NULL; + mblk_t *buf; + + V4wState *s = s_callback; + if (s==NULL) + return S_OK; + + HRESULT hr = pSample->GetPointer(&byte_buf); + if (FAILED(hr)) + { + return S_OK; + } + + int size = pSample->GetActualDataLength(); + if (size>+1000) + { + buf=allocb(size,0); + memcpy(buf->b_wptr, byte_buf, size); + if (s->pix_fmt==MS_RGB24) + { + /* Conversion from top down bottom up (BGR to RGB and flip) */ + unsigned long Index,nPixels; + unsigned char *blue; + unsigned char tmp; + short iPixelSize; + + blue=buf->b_wptr; + + nPixels=s->vsize.width*s->vsize.height; + iPixelSize=24/8; + + for(Index=0;Index!=nPixels;Index++) // For each pixel + { + tmp=*blue; + *blue=*(blue+2); + *(blue+2)=tmp; + blue+=iPixelSize; + } + + unsigned char *pLine1, *pLine2; + int iLineLen,iIndex; + + iLineLen=s->vsize.width*iPixelSize; + pLine1=buf->b_wptr; + pLine2=&(buf->b_wptr)[iLineLen * (s->vsize.height - 1)]; + + for( ;pLine1b_wptr+=size; + + ms_mutex_lock(&s->mutex); + putq(&s->rq, buf); + ms_mutex_unlock(&s->mutex); + + } + return S_OK; +} + +HRESULT GetFirstCameraDriver( WCHAR *pwzName ) { + HRESULT hr = S_OK; + HANDLE handle = NULL; + DEVMGR_DEVICE_INFORMATION di; + GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A, + 0x93, 0x3E, 0x4D, 0x7E, 0x3C, 0x86 }; + + if( pwzName == NULL ) { + return E_POINTER; + } + + di.dwSize = sizeof(di); + + handle = FindFirstDevice( DeviceSearchByGuid, &guidCamera, &di ); + if(( handle == NULL ) || ( di.hDevice == NULL )) { + return S_FALSE; + } + + StringCchCopy( pwzName, MAX_PATH, di.szLegacyName ); + + FindClose( handle ); + return hr; +} + +struct VAR_LIST +{ + VARIANT var; + VAR_LIST *pNext; + BSTR pBSTRName; +}; + +class CPropertyBag : public IPropertyBag +{ +public: + CPropertyBag(); + ~CPropertyBag(); + + HRESULT STDMETHODCALLTYPE + Read( + LPCOLESTR pszPropName, + VARIANT *pVar, + IErrorLog *pErrorLog + ); + + + HRESULT STDMETHODCALLTYPE + Write( + LPCOLESTR pszPropName, + VARIANT *pVar + ); + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv); + +private: + ULONG _refCount; + VAR_LIST *pVar; +}; + +CPropertyBag::CPropertyBag() : _refCount(1), pVar(0) +{ +} + +CPropertyBag::~CPropertyBag() +{ + VAR_LIST *pTemp = pVar; + HRESULT hr = S_OK; + + while(pTemp) + { + VAR_LIST *pDel = pTemp; + VariantClear(&pTemp->var); + SysFreeString(pTemp->pBSTRName); + pTemp = pTemp->pNext; + delete pDel; + } + +} + +HRESULT STDMETHODCALLTYPE +CPropertyBag::Read(LPCOLESTR pszPropName, + VARIANT *_pVar, + IErrorLog *pErrorLog) +{ + VAR_LIST *pTemp = pVar; + HRESULT hr = S_OK; + + while(pTemp) + { + if(0 == wcscmp(pszPropName, pTemp->pBSTRName)) + { + hr = VariantCopy(_pVar, &pTemp->var); + break; + } + pTemp = pTemp->pNext; + } + return hr; +} + + +HRESULT STDMETHODCALLTYPE +CPropertyBag::Write(LPCOLESTR pszPropName, + VARIANT *_pVar) +{ + HRESULT hr = S_OK; + VAR_LIST *pTemp = new VAR_LIST(); + ASSERT(pTemp); + + if( !pTemp ) + { + return E_OUTOFMEMORY; + } + + VariantInit(&pTemp->var); + pTemp->pBSTRName = SysAllocString(pszPropName); + pTemp->pNext = pVar; + pVar = pTemp; + return VariantCopy(&pTemp->var, _pVar); +} + +ULONG STDMETHODCALLTYPE +CPropertyBag::AddRef() +{ + return InterlockedIncrement((LONG *)&_refCount); +} + +ULONG STDMETHODCALLTYPE +CPropertyBag::Release() +{ + ASSERT(_refCount != 0xFFFFFFFF); + ULONG ret = InterlockedDecrement((LONG *)&_refCount); + if(!ret) + delete this; + return ret; +} + +HRESULT STDMETHODCALLTYPE +CPropertyBag::QueryInterface(REFIID riid, void** ppv) +{ + if(!ppv) + return E_POINTER; + if(riid == IID_IPropertyBag) + *ppv = static_cast(this); + else + return *ppv = 0, E_NOINTERFACE; + + return AddRef(), S_OK; +} + +static int v4w_open_videodevice(V4wState *s, int format, MSVideoSize *vsize) +{ + // Initialize COM + CoInitialize(NULL); + + // get a Graph + HRESULT hr=s->m_pGraph.CoCreateInstance(CLSID_FilterGraph); + if(FAILED(hr)) + { + return -1; + } + + // get a CaptureGraphBuilder2 +#if !defined(_WIN32_WCE) + hr=s->m_pBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder2); +#else + hr=s->m_pBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder); +#endif + if(FAILED(hr)) + { + return -2; + } + + // connect capture graph builder with the graph + s->m_pBuilder->SetFiltergraph(s->m_pGraph); + + // get mediacontrol so we can start and stop the filter graph + hr=s->m_pGraph.QueryInterface(&(s->m_pControl)); + if(FAILED(hr)) + { + return -3; + } + + // get DXFilter + s->m_pDXFilter = new CDXFilter(NULL, &hr, FALSE); + if(s->m_pDXFilter==NULL) + { + return -4; + } + s->m_pDXFilter->AddRef(); + if(FAILED(hr)) + { + return -4; + } + + CMediaType mt; + mt.SetType(&MEDIATYPE_Video); + + if (format==MS_YUV420P) + { + GUID m = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0')); + mt.SetSubtype(&m); + mt.SetSubtype(&MEDIASUBTYPE_YV12); + } + else //if (format==MS_RGB24) + { + mt.SetSubtype(&MEDIASUBTYPE_RGB24); + } + + //mt.SetSubtype(&MEDIASUBTYPE_IYUV); + //mt.SetSubtype(&MEDIASUBTYPE_YUYV); + //mt.SetSubtype(&MEDIASUBTYPE_RGB24); + //mt.SetSampleSize(); + mt.formattype = FORMAT_VideoInfo; + mt.SetTemporalCompression(FALSE); + + VIDEOINFO *pvi = (VIDEOINFO *) + mt.AllocFormatBuffer(sizeof(VIDEOINFO)); + if (NULL == pvi) + return E_OUTOFMEMORY; + ZeroMemory(pvi, sizeof(VIDEOINFO)); + if (format==MS_YUV420P) + { + pvi->bmiHeader.biCompression = MAKEFOURCC('I','4','2','0'); + pvi->bmiHeader.biCompression = MAKEFOURCC('Y','V','1','2'); + pvi->bmiHeader.biBitCount = 12; + } + else + { + pvi->bmiHeader.biCompression = BI_RGB; + pvi->bmiHeader.biBitCount = 24; + } + pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pvi->bmiHeader.biWidth = vsize->width; + pvi->bmiHeader.biHeight = vsize->height; + pvi->bmiHeader.biPlanes = 1; + pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader); + pvi->bmiHeader.biClrImportant = 0; + mt.SetSampleSize(pvi->bmiHeader.biSizeImage); + mt.SetFormat((BYTE*)pvi, sizeof(VIDEOINFO)); + + hr = s->m_pDXFilter->SetAcceptedMediaType(&mt); + if(FAILED(hr)) + { + return -5; + } + + hr = s->m_pDXFilter->SetCallback(Callback); + if(FAILED(hr)) + { + return -6; + } + + hr = s->m_pDXFilter->QueryInterface(IID_IBaseFilter, + (LPVOID *)&s->m_pIDXFilter); + if(FAILED(hr)) + { + return -7; + } + + hr = s->m_pGraph->AddFilter(s->m_pIDXFilter, L"DXFilter Filter"); + if(FAILED(hr)) + { + return -8; + } + +#ifdef WM6 + ICreateDevEnum *pCreateDevEnum = NULL; + IEnumMoniker *pEnumMoniker = NULL; + IMoniker *pMoniker = NULL; + + ULONG nFetched = 0; + + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + IID_ICreateDevEnum, (PVOID *)&pCreateDevEnum); + if(FAILED(hr)) + { + return -9; + } + + hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, + &pEnumMoniker, 0); + if (FAILED(hr) || pEnumMoniker == NULL) { + //printf("no device\n"); + return -10; + } + + pEnumMoniker->Reset(); + + hr = pEnumMoniker->Next(1, &pMoniker, &nFetched); + if(FAILED(hr) || pMoniker==NULL) + { + return -11; + } + + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&s->m_pDeviceFilter ); + if(FAILED(hr)) + { + return -12; + } + + s->m_pGraph->AddFilter(s->m_pDeviceFilter, L"Device Filter"); + + pMoniker->Release(); + pEnumMoniker->Release(); + pCreateDevEnum->Release(); +#else + WCHAR wzDeviceName[ MAX_PATH + 1 ]; + CComVariant varCamName; + CPropertyBag PropBag; + CComPtr pPropertyBag; + GetFirstCameraDriver(wzDeviceName); + + hr = s->m_pDeviceFilter.CoCreateInstance( CLSID_VideoCapture ); + if (FAILED(hr)) + { + return -8; + } + + s->m_pDeviceFilter.QueryInterface( &pPropertyBag ); + varCamName = wzDeviceName; + if(( varCamName.vt == VT_BSTR ) == NULL ) { + return E_OUTOFMEMORY; + } + PropBag.Write( L"VCapName", &varCamName ); + pPropertyBag->Load( &PropBag, NULL ); + pPropertyBag.Release(); + + hr = s->m_pGraph->AddFilter( s->m_pDeviceFilter, L"Video capture source" ); +#endif + + if (FAILED(hr)) + { + return -8; + } + + // get null renderer + s->m_pNullRenderer = NULL; +#if 0 + hr=s->m_pNullRenderer.CoCreateInstance(CLSID_NullRenderer); + if(FAILED(hr)) + { + return -13; + } +#endif + if (s->m_pNullRenderer!=NULL) + { + s->m_pGraph->AddFilter(s->m_pNullRenderer, L"Null Renderer"); + } + + hr = s->m_pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, + &MEDIATYPE_Video, s->m_pDeviceFilter, s->m_pIDXFilter, s->m_pNullRenderer); + if (FAILED(hr)) + { + //hr = s->m_pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, + // &MEDIATYPE_Video, s->m_pDeviceFilter, s->m_pIDXFilter, s->m_pNullRenderer); + if (FAILED(hr)) + { + return -14; + } + } + + //m_pDXFilter->SetBufferSamples(TRUE); + + + // Create the System Device Enumerator. +IFilterMapper *pMapper = NULL; +//IEnumMoniker *pEnum = NULL; +IEnumRegFilters *pEnum = NULL; + +hr = CoCreateInstance(CLSID_FilterMapper, + NULL, CLSCTX_INPROC, IID_IFilterMapper, + (void **) &pMapper); + +if (FAILED(hr)) +{ + // Error handling omitted for clarity. +} + +GUID arrayInTypes[2]; +arrayInTypes[0] = MEDIATYPE_Video; +arrayInTypes[1] = MEDIASUBTYPE_dvsd; + +hr = pMapper->EnumMatchingFilters( + &pEnum, + MERIT_HW_COMPRESSOR, // Minimum merit. + FALSE, // At least one input pin? + MEDIATYPE_NULL, + MEDIASUBTYPE_NULL, + FALSE, // Must be a renderer? + FALSE, // At least one output pin? + MEDIATYPE_NULL, + MEDIASUBTYPE_NULL); + +// Enumerate the monikers. +//IMoniker *pMoniker; +REGFILTER *pMoniker; +ULONG cFetched; +while (pEnum->Next(1, &pMoniker, &cFetched) == S_OK) +{ + IPropertyBag *pPropBag = NULL; +#if 0 + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void **)&pPropBag); + + if (SUCCEEDED(hr)) + { + // To retrieve the friendly name of the filter, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) + { + // Display the name in your UI somehow. + } + VariantClear(&varName); + + // To create an instance of the filter, do the following: + IBaseFilter *pFilter; + hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter); + // Now add the filter to the graph. Remember to release pFilter later. + + // Clean up. + pPropBag->Release(); + } + pMoniker->Release(); +#endif + +} + +// Clean up. +pMapper->Release(); +pEnum->Release(); + + + + + s_callback = s; + hr = s->m_pControl->Run(); + if(FAILED(hr)) + { + return -15; + } + + s->rotregvalue=1; + s->pix_fmt = format; + s->vsize.height = vsize->height; + s->vsize.width = vsize->width; + return 0; +} + +static void v4w_init(MSFilter *f){ + V4wState *s=(V4wState *)ms_new0(V4wState,1); + int idx; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + //s->pix_fmt=MS_RGB24; + s->pix_fmt=MS_YUV420P; + + s->rotregvalue = 0; + s->m_pGraph=NULL; + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pDXFilter=NULL; + s->m_pIDXFilter=NULL; + s->m_pDeviceFilter=NULL; + + qinit(&s->rq); + for (idx=0;idx<10;idx++) + { + s->mire[idx]=NULL; + } + ms_mutex_init(&s->mutex,NULL); + s->start_time=0; + s->frame_count=-1; + s->fps=15; + + f->data=s; +} + +static int try_format(V4wState *s, int format, MSVideoSize *vsize) +{ + int i = v4w_open_videodevice(s, format, vsize); + if (i==-14) + { + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + } + return i; +} + +static int _v4w_start(V4wState *s, void *arg) +{ + MSVideoSize try_vsize; + int tryformat; + int i; + s->frame_count=-1; + + if (s->pix_fmt==MS_YUV420P) + tryformat = MS_RGB24; + else if (s->pix_fmt==MS_RGB24) + tryformat = MS_YUV420P; + + try_vsize.height = s->vsize.height; + try_vsize.width = s->vsize.width; + i = try_format(s, s->pix_fmt, &try_vsize); + if (i==-14) + { + /* try second format with same size */ + i = try_format(s, tryformat, &try_vsize); + } + + /* try both format with CIF size */ + if (i==-14 && s->vsize.height!=MS_VIDEO_SIZE_CIF_H) + { + try_vsize.height = MS_VIDEO_SIZE_CIF_H; + try_vsize.width = MS_VIDEO_SIZE_CIF_W; + i = try_format(s, s->pix_fmt, &try_vsize); + if (i==-14) + { + i = try_format(s, tryformat, &try_vsize); + } + } + if (i==-14 && s->vsize.height!=MS_VIDEO_SIZE_QCIF_H) + { + try_vsize.height = MS_VIDEO_SIZE_QCIF_H; + try_vsize.width = MS_VIDEO_SIZE_QCIF_W; + i = try_format(s, s->pix_fmt, &try_vsize); + if (i==-14) + { + i = try_format(s, tryformat, &try_vsize); + } + } + if (i==-14 && s->vsize.height!=MS_VIDEO_SIZE_VGA_H) + { + try_vsize.height = MS_VIDEO_SIZE_VGA_H; + try_vsize.width = MS_VIDEO_SIZE_VGA_W; + i = try_format(s, s->pix_fmt, &try_vsize); + if (i==-14) + { + i = try_format(s, tryformat, &try_vsize); + } + } + + if (i==-14 && s->vsize.height!=MS_VIDEO_SIZE_QVGA_H) + { + try_vsize.height = MS_VIDEO_SIZE_QVGA_H; + try_vsize.width = MS_VIDEO_SIZE_QVGA_W; + i = try_format(s, s->pix_fmt, &try_vsize); + if (i==-14) + { + i = try_format(s, tryformat, &try_vsize); + } + } + + if (i==0) + { + if (s->pix_fmt==MS_YUV420P) + ms_message("Using YUV420P"); + else if (s->pix_fmt==MS_RGB24) + ms_message("Using RGB24"); + } + + if (s->rotregvalue==0){ + //RemoveGraphFromRot(s->rotregvalue); + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + s_callback = NULL; + flushq(&s->rq,0); + ms_message("v4w: graph not started (err=%i)", i); + s->rotregvalue=0; + } + return i; +} + +static int _v4w_stop(V4wState *s, void *arg){ + s->frame_count=-1; + if (s->rotregvalue>0){ + HRESULT hr = s->m_pControl->Stop(); + if(FAILED(hr)) + { + ms_message("v4w: could not stop graph"); + } + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + //RemoveGraphFromRot(s->rotregvalue); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + s_callback = NULL; + flushq(&s->rq,0); + ms_message("v4w: graph destroyed"); + s->rotregvalue=0; + } + return 0; +} + + +static int v4w_start(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + _v4w_start(s, NULL); + return 0; +} + +static int v4w_stop(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + _v4w_stop(s, NULL); + return 0; +} + + +static void v4w_uninit(MSFilter *f){ + V4wState *s=(V4wState*)f->data; + int idx; + flushq(&s->rq,0); + ms_mutex_destroy(&s->mutex); + for (idx=0;idx<10;idx++) + { + if (s->mire[idx]==NULL) + break; + freemsg(s->mire[idx]); + } + if (s->rotregvalue>0){ + HRESULT hr = s->m_pControl->Stop(); + if(FAILED(hr)) + { + ms_message("v4w: could not stop graph"); + } + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + //RemoveGraphFromRot(s->rotregvalue); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + s_callback = NULL; + flushq(&s->rq,0); + ms_message("v4w: graph destroyed"); + s->rotregvalue=0; + } + ms_free(s); +} + +static mblk_t * v4w_make_nowebcam(V4wState *s){ +#if defined(_WIN32_WCE) + return NULL; +#else + int idx; + int count; + if (s->mire[0]==NULL && s->frame_ind==0){ + /* load several images to fake a movie */ + for (idx=0;idx<10;idx++) + { + s->mire[idx]=ms_load_nowebcam(&s->vsize, idx); + if (s->mire[idx]==NULL) + break; + } + if (idx==0) + s->mire[0]=ms_load_nowebcam(&s->vsize, -1); + } + for (count=0;count<10;count++) + { + if (s->mire[count]==NULL) + break; + } + + s->frame_ind++; + if (count==0) + return NULL; + + idx = s->frame_ind%count; + if (s->mire[idx]!=NULL) + return s->mire[idx]; + return s->mire[0]; +#endif +} + +static void v4w_preprocess(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + s->running=TRUE; + if (s->rotregvalue==0) + s->fps=1; +} + +static void v4w_postprocess(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + s->running=FALSE; +} + +static void v4w_process(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + mblk_t *m; + uint32_t timestamp; + int cur_frame; + + if (s->frame_count==-1){ + s->start_time=obj->ticker->time; + s->frame_count=0; + } + + + cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame>s->frame_count){ + mblk_t *om=NULL; + ms_mutex_lock(&s->mutex); + /*keep the most recent frame if several frames have been captured */ + if (s->rotregvalue!=0){ + while((m=getq(&s->rq))!=NULL){ + if (om!=NULL) freemsg(om); + om=m; + } + }else { + mblk_t *nowebcam = v4w_make_nowebcam(s); + if (nowebcam!=NULL) + om=dupmsg(nowebcam); + } + ms_mutex_unlock(&s->mutex); + if (om!=NULL){ + timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/ + mblk_set_timestamp_info(om,timestamp); + ms_queue_put(obj->outputs[0],om); + /*ms_message("picture sent");*/ + } + s->frame_count++; + } +} + + + +static int v4w_set_fps(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->fps=*((float*)arg); + return 0; +} + +static int v4w_get_pix_fmt(MSFilter *f,void *arg){ + V4wState *s=(V4wState*)f->data; + *((MSPixFmt*)arg) = (MSPixFmt)s->pix_fmt; + return 0; +} + +static int v4w_set_vsize(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->vsize=*((MSVideoSize*)arg); + return 0; +} + +static int v4w_get_vsize(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + MSVideoSize *vs=(MSVideoSize*)arg; + vs->width=s->vsize.width; + vs->height=s->vsize.height; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , v4w_set_fps }, + { MS_FILTER_GET_PIX_FMT , v4w_get_pix_fmt }, + { MS_FILTER_SET_VIDEO_SIZE, v4w_set_vsize }, + { MS_FILTER_GET_VIDEO_SIZE, v4w_get_vsize }, + { MS_V4L_START , v4w_start }, + { MS_V4L_STOP , v4w_stop }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_v4w_desc={ + MS_V4L_ID, + "MSV4w", + "A video4windows compatible source filter to stream pictures.", + MS_FILTER_OTHER, + NULL, + 0, + 1, + v4w_init, + v4w_preprocess, + v4w_process, + v4w_postprocess, + v4w_uninit, + methods +}; + +#else + +MSFilterDesc ms_v4w_desc={ + .id=MS_V4L_ID, + .name="MSV4w", + .text="A video4windows compatible source filter to stream pictures.", + .ninputs=0, + .noutputs=1, + .category=MS_FILTER_OTHER, + .init=v4w_init, + .preprocess=v4w_preprocess, + .process=v4w_process, + .postprocess=v4w_postprocess, + .uninit=v4w_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_v4w_desc) diff --git a/linphone/mediastreamer2/src/winsnd.c b/linphone/mediastreamer2/src/winsnd.c new file mode 100644 index 000000000..c4c1e6b7e --- /dev/null +++ b/linphone/mediastreamer2/src/winsnd.c @@ -0,0 +1,970 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#if defined(_WIN32_WCE) +#define DISABLE_SPEEX +#endif + +#ifndef WINSND_BUFLEN +#define WINSND_BUFLEN 320 +#endif + +#ifndef MAX_WAVEHDR +#define MAX_WAVEHDR 6 +#endif + +#ifndef DISABLE_SPEEX +#include +#endif + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" + +#ifdef WIN32 +#include /* for alloca */ +#endif + +#include +#ifdef _MSC_VER +#include +#endif +#include + +MSFilter *ms_winsnd_read_new(MSSndCard *card); +MSFilter *ms_winsnd_write_new(MSSndCard *card); + +typedef struct WinSndData{ + char *pcmdev; + char *mixdev; + int devid; + + int sound_err; + WAVEFORMATEX wfx; +#ifdef CONTROLVOLUME + DWORD dwOldVolume; +#endif + WAVEHDR waveouthdr[30]; + char waveoutbuffer[30][3200]; + HWAVEOUT waveoutdev; + int buffer_playing; + int pos_whdr; + + WAVEHDR waveinhdr[30]; + HWAVEIN waveindev; + char waveinbuffer[30][3200]; + + int rate; + int bits; + ms_thread_t thread; + ms_mutex_t mutex; + queue_t rq; + MSBufferizer * bufferizer; + bool_t read_started; + bool_t write_started; + bool_t stereo; + +#ifndef DISABLE_SPEEX + SpeexPreprocessState *pst; +#endif + + uint64_t bytes_read; + int32_t stat_input; + int32_t stat_output; + int32_t stat_notplayed; +} WinSndData; + +static uint64_t winsnd_get_cur_time( void *data){ + WinSndData *d=(WinSndData*)data; + uint64_t curtime=(d->bytes_read*1000)/(d->rate*(d->bits/8)*((d->stereo==FALSE) ? 1 : 2)); + ms_debug("winsnd_get_cur_time: bytes_read=%lu, rate=%i, bits=%i, stereo=%i return %lu\n", + (unsigned long)d->bytes_read,d->rate,d->bits,d->stereo,(unsigned long)curtime); + return curtime; +} + +static void CALLBACK +SpeakerCallback (HWAVEOUT _waveoutdev, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + WAVEHDR *wHdr; + WinSndData *device; + + switch (uMsg) + { + case WOM_OPEN: + ms_message("SpeakerCallback : WOM_OPEN"); + break; + case WOM_CLOSE: + ms_message("SpeakerCallback : WOM_CLOSE"); + break; + case WOM_DONE: + wHdr = (WAVEHDR *) dwParam1; + device = (WinSndData *)dwInstance; + device->buffer_playing--; + if (device->stat_output==0) + { + device->stat_input=1; /* reset */ + device->stat_notplayed=0; + } + device->stat_output++; + break; + default: + break; + } +} + +static void CALLBACK +WaveInCallback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, + DWORD dwParam2) +{ + WAVEHDR *wHdr; + MMRESULT mr = NOERROR; + WinSndData *device; + + device = (WinSndData *)dwInstance; + + switch (uMsg) + { + case MM_WOM_DONE: + wHdr = (WAVEHDR *) dwParam1; + /* A waveform-audio data block has been played and + can now be freed. */ + ms_message("WaveInCallback : MM_WOM_DONE"); + waveInUnprepareHeader (waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR)); + break; + + case WIM_OPEN: + ms_message("WaveInCallback : WIM_OPEN"); + break; + case WIM_CLOSE: + ms_message("WaveInCallback : WIM_CLOSE"); + break; + case WIM_DATA: + wHdr = (WAVEHDR *) dwParam1; + + device->bytes_read+=wHdr->dwBytesRecorded; + + if (!device->read_started && !device->write_started) + { + mr = waveInUnprepareHeader (device->waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR)); + ms_warning("WaveInCallback : unprepare header (waveInUnprepareHeader:0x%i)", mr); + return; + } + + if (wHdr->dwBufferLength!=wHdr->dwBytesRecorded) + { + mr = waveInAddBuffer (device->waveindev, + wHdr, + sizeof (device->waveinhdr[wHdr->dwUser])); + if (mr != MMSYSERR_NOERROR) + { + ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr); + } + return; + } + ms_mutex_lock(&device->mutex); + if (device->read_started) + { + mblk_t *rm=NULL; + if (rm==NULL) rm=allocb(wHdr->dwBufferLength,0); + memcpy(rm->b_wptr,wHdr->lpData, wHdr->dwBufferLength); + +#ifndef DISABLE_SPEEX + if (device->pst!=NULL) + { + int vad; + //memset(rm->b_wptr,0, wHdr->dwBufferLength); + + vad = speex_preprocess(device->pst, (short*)rm->b_wptr, NULL); +#if 0 + if (vad!=1) + ms_message("WaveInCallback : %d", vad); +#endif + } + +#endif + rm->b_wptr+=wHdr->dwBufferLength; + putq(&device->rq,rm); + device->stat_input++; + rm=NULL; + } + ms_mutex_unlock(&device->mutex); + + mr = waveInAddBuffer (device->waveindev, + wHdr, + sizeof (device->waveinhdr[wHdr->dwUser])); + if (mr != MMSYSERR_NOERROR) + { + ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr); + return; + } + } +} + +static int winsnd_open(WinSndData *device, int devnumber, int bits,int stereo, int rate, int *minsz) +{ + MMRESULT mr = NOERROR; + DWORD dwFlag; + int i; + int channel = 1; + if (stereo>0) + channel = stereo; + device->wfx.wFormatTag = WAVE_FORMAT_PCM; + device->wfx.cbSize = 0; + device->wfx.nAvgBytesPerSec = 16000; + device->wfx.nBlockAlign = 2; + device->wfx.nChannels = channel; + device->wfx.nSamplesPerSec = rate; /* 8000; */ + device->wfx.wBitsPerSample = bits; + + + dwFlag = CALLBACK_FUNCTION; + if (devnumber != WAVE_MAPPER) + dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION; + mr = waveOutOpen (&(device->waveoutdev), devnumber, &(device->wfx), (DWORD) SpeakerCallback, + (DWORD)device, dwFlag); + if (mr != NOERROR) + { + ms_warning("Failed to open device: trying default device. (waveOutOpen:0x%i)", mr); + dwFlag = CALLBACK_FUNCTION; + mr = waveOutOpen (&(device->waveoutdev), WAVE_MAPPER, &(device->wfx), (DWORD) SpeakerCallback, + (DWORD)device, dwFlag); + } + if (mr != NOERROR) + { + ms_warning("Failed to open windows sound device. (waveOutOpen:0x%i)", mr); + return -1; + } + +#if 0 +#define MM_WOM_SETSECONDARYGAINCLASS (WM_USER) +#define MM_WOM_SETSECONDARYGAINLIMIT (WM_USER+1) +#define MM_WOM_FORCESPEAKER (WM_USER+2) + + bool bSpeaker=TRUE; + mr = waveOutMessage(device->waveoutdev, MM_WOM_FORCESPEAKER, bSpeaker, 0); + if (mr != NOERROR) + { + ms_warning("Failed to use earphone. (waveOutMessage:0x%i)", mr); + return -1; + } + + typedef HRESULT (* _SetSpeakerMode)(DWORD mode); + _SetSpeakerMode pfnSetSpeakerMode; + + HINSTANCE hDll = LoadLibrary(L"\\windows\\ossvcs.dll"); + //_debug(L"ossvcs.dll h=%X",hDll); + pfnSetSpeakerMode = (_SetSpeakerMode)GetProcAddress(hDll,(LPCTSTR)218); + if (pfnSetSpeakerMode) + { + //_debug(L"SetSpeakerMode imported."); + DWORD sm = 0; + //_debug(L"SpeakerMode set to %d", sm); + pfnSetSpeakerMode(sm); + } + //else + //_debug(L"pfnSetSpeakerMode import failed."); + FreeLibrary(hDll); +#endif + +#ifdef CONTROLVOLUME + mr = waveOutGetVolume(device->waveoutdev, &device->dwOldVolume); + if (mr != NOERROR) + { + ms_warning("Failed to get volume device. (waveOutGetVolume:0x%i)", mr); + } + + mr = waveOutSetVolume(device->waveoutdev, 0xFFFFFFFF); + if (mr != NOERROR) + { + ms_warning("Failed to set volume device. (waveOutSetVolume:0x%i)", mr); + } +#endif + + /* prepare windows buffers */ + + for (i = 0; i < MAX_WAVEHDR; i++) + { + memset (&(device->waveouthdr[i]), 0, sizeof (device->waveouthdr[i])); + device->waveouthdr[i].lpData = device->waveoutbuffer[i]; + /* BUG: on ne connait pas la taille des frames a recevoir... + on utilise enc_frame_per_packet au lien de dec_frame_per_packet */ + + device->waveouthdr[i].dwBufferLength = device->rate/8000 * WINSND_BUFLEN; + /* 480 pour 98 (speex) */ + device->waveouthdr[i].dwFlags = 0; + device->waveouthdr[i].dwUser = i; + + mr = waveOutPrepareHeader (device->waveoutdev, &(device->waveouthdr[i]), + sizeof (device->waveouthdr[i])); + if (mr != MMSYSERR_NOERROR){ + ms_warning("Failed to prepare windows sound device. (waveOutPrepareHeader:0x%i)", mr); + } + else + { + ms_message("Sound Header prepared %i for windows sound device. (waveOutPrepareHeader)", i); + } + } + + + /* Init Microphone device */ + dwFlag = CALLBACK_FUNCTION; + if (devnumber != WAVE_MAPPER) + dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION; + mr = waveInOpen (&(device->waveindev), devnumber, &(device->wfx), + (DWORD) WaveInCallback, (DWORD)device, dwFlag); + if (mr != NOERROR) + { + ms_warning("Failed to open device: trying default device. (waveInOpen:0x%i)", mr); + dwFlag = CALLBACK_FUNCTION; + mr = waveInOpen (&(device->waveindev), WAVE_MAPPER, &(device->wfx), + (DWORD) WaveInCallback, (DWORD)device, dwFlag); + } + + if (mr != NOERROR) + { + ms_warning("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr); + return -1; + } + + + + for (i = 0; i < MAX_WAVEHDR; i++) + { + memset (&(device->waveinhdr[i]), 0, sizeof (device->waveinhdr[i])); + device->waveinhdr[i].lpData = device->waveinbuffer[i]; + /* frameSize */ + device->waveinhdr[i].dwBufferLength = device->rate/8000 * WINSND_BUFLEN; + device->waveinhdr[i].dwFlags = 0; + device->waveinhdr[i].dwUser = i; + mr = waveInPrepareHeader (device->waveindev, &(device->waveinhdr[i]), + sizeof (device->waveinhdr[i])); + if (mr == MMSYSERR_NOERROR){ + mr = waveInAddBuffer (device->waveindev, &(device->waveinhdr[i]), + sizeof (device->waveinhdr[i])); + if (mr == MMSYSERR_NOERROR) + { + ms_message("Sound Header prepared %i for windows sound device. (waveInAddBuffer)", i); + } + else + { + ms_warning("Failed to prepare windows sound device. (waveInAddBuffer:0x%i)", mr); + } + } + else + { + ms_warning("Failed to prepare windows sound device. (waveInPrepareHeader:0x%i)", mr); + } + } + +#ifndef DISABLE_SPEEX +#if 0 + device->pst = speex_preprocess_state_init((device->rate/8000 * 320)/2, device->rate); + if (device->pst!=NULL) { + float f; + i=1; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_VAD, &i); + i=1; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DENOISE, &i); + i=0; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC, &i); + f=8000; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); + i=0; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i); + f=.4; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); + f=.3; + speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); + } +#endif +#endif + + mr = waveInStart (device->waveindev); + if (mr != MMSYSERR_NOERROR) + { + ms_warning("Failed to start recording on windows sound device. (waveInStart:0x%i)", mr); + return -1; + } + + *minsz=device->rate/8000 * 320; + return 0; +} + +static void winsnd_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent) +{ + WinSndData *d=(WinSndData*)card->data; + MMRESULT mr = NOERROR; + DWORD dwVolume = 0xFFFF; + dwVolume = ((0xFFFF) * percent) / 100; + + if (d->mixdev==NULL) return; + switch(e){ + case MS_SND_CARD_MASTER: + mr = waveOutSetVolume(d->waveoutdev, dwVolume); + if (mr != MMSYSERR_NOERROR) + { + ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr); + return; + } + return; + break; +#if 0 + case MS_SND_CARD_CAPTURE: + wincmd=SOUND_MIXER_IGAIN; + break; + case MS_SND_CARD_PLAYBACK: + wincmd=SOUND_MIXER_PCM; + break; +#endif + default: + ms_warning("winsnd_card_set_level: unsupported command."); + return; + } +} + +static int winsnd_get_level(MSSndCard *card, MSSndCardMixerElem e) +{ + WinSndData *d=(WinSndData*)card->data; + MMRESULT mr = NOERROR; + DWORD dwVolume = 0x0000; + + if (d->mixdev==NULL) return -1; + switch(e){ + case MS_SND_CARD_MASTER: + mr=waveOutGetVolume(d->waveoutdev, &dwVolume); + // Transform to 0 to 100 scale + //dwVolume = (dwVolume *100) / (0xFFFF); + return 60; + break; +#if 0 + case MS_SND_CARD_CAPTURE: + osscmd=SOUND_MIXER_IGAIN; + break; + case MS_SND_CARD_PLAYBACK: + osscmd=SOUND_MIXER_PCM; + break; +#endif + default: + ms_warning("winsnd_card_get_level: unsupported command."); + return -1; + } + return -1; +} + +static void winsnd_set_source(MSSndCard *card, MSSndCardCapture source) +{ + WinSndData *d=(WinSndData*)card->data; + if (d->mixdev==NULL) return; + + switch(source){ + case MS_SND_CARD_MIC: + break; + case MS_SND_CARD_LINE: + break; + } +} + +static void winsnd_init(MSSndCard *card){ + WinSndData *d=(WinSndData*)ms_new(WinSndData,1); + memset(d, 0, sizeof(WinSndData)); + d->bytes_read=0; + d->pcmdev=NULL; + d->mixdev=NULL; + d->sound_err=-1; /* not opened */ + d->read_started=FALSE; + d->write_started=FALSE; + d->bits=16; + d->rate=8000; + d->stereo=FALSE; + qinit(&d->rq); + d->bufferizer=ms_bufferizer_new(); + ms_mutex_init(&d->mutex,NULL); + card->data=d; +#ifndef DISABLE_SPEEX + d->pst=0; +#endif + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; +} + +static void winsnd_uninit(MSSndCard *card){ + WinSndData *d=(WinSndData*)card->data; + if (d==NULL) + return; + if (d->pcmdev!=NULL) ms_free(d->pcmdev); + if (d->mixdev!=NULL) ms_free(d->mixdev); + ms_bufferizer_destroy(d->bufferizer); + flushq(&d->rq,0); + + ms_mutex_destroy(&d->mutex); + +#ifndef DISABLE_SPEEX + if (d->pst!=NULL) + speex_preprocess_state_destroy(d->pst); +#endif + + ms_free(d); +} + +#define DSP_NAME "/dev/dsp" +#define MIXER_NAME "/dev/mixer" + +static void winsnd_detect(MSSndCardManager *m); +static MSSndCard *winsnd_dup(MSSndCard *obj); + +MSSndCardDesc winsnd_card_desc={ + "WINSND", + winsnd_detect, + winsnd_init, + winsnd_set_level, + winsnd_get_level, + winsnd_set_source, + ms_winsnd_read_new, + ms_winsnd_write_new, + winsnd_uninit, + winsnd_dup +}; + +static MSSndCard *winsnd_dup(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&winsnd_card_desc); + WinSndData *dcard=(WinSndData*)card->data; + WinSndData *dobj=(WinSndData*)obj->data; + dcard->pcmdev=ms_strdup(dobj->pcmdev); + dcard->mixdev=ms_strdup(dobj->mixdev); + dcard->devid=dobj->devid; + card->name=ms_strdup(obj->name); + return card; +} + +static MSSndCard *winsnd_card_new(const char *pcmdev, const char *mixdev, int id){ + MSSndCard *card=ms_snd_card_new(&winsnd_card_desc); + WinSndData *d=(WinSndData*)card->data; + d->pcmdev=ms_strdup(pcmdev); + d->mixdev=ms_strdup(mixdev); + card->name=ms_strdup(pcmdev); + d->devid=id; + return card; +} + +static void winsnd_detect(MSSndCardManager *m){ + MMRESULT mr = NOERROR; + unsigned int nInDevices = waveInGetNumDevs (); + unsigned int item; + char pcmdev[1024]; + char mixdev[1024]; + + for (item = 0; item < nInDevices; item++) + { + WAVEINCAPS caps; + mr = waveInGetDevCaps (item, &caps, sizeof (WAVEINCAPS)); + if (mr == MMSYSERR_NOERROR) + { + MSSndCard *card; + snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname); + snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname); + if (item == 0) + { + card=winsnd_card_new(pcmdev,mixdev, item-1); + ms_snd_card_manager_add_card(m,card); + } + card=winsnd_card_new(pcmdev,mixdev, item); + ms_snd_card_manager_add_card(m,card); + } + } +#if 0 + nInDevices = mixerGetNumDevs (); + for (item = 0; item < nInDevices; item++) + { + MIXERCAPS caps; + mr = mixerGetDevCaps (item, &caps, sizeof (MIXERCAPS)); + if (mr == MMSYSERR_NOERROR) + { + snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname); + snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname); + } + } +#endif +} + +static void * winsnd_thread(void *p){ + MSSndCard *card=(MSSndCard*)p; + WinSndData *d=(WinSndData*)card->data; + int bsize=d->rate/8000 * 320; + uint8_t *rtmpbuff=NULL; + uint8_t *wtmpbuff=NULL; + int err; + + MMRESULT mr = NOERROR; + int pos_whdr=0; + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->sound_err=winsnd_open(d, d->devid, d->bits,d->stereo,d->rate,&bsize); + if (d->sound_err==0){ + rtmpbuff=(uint8_t*)alloca(bsize); + wtmpbuff=(uint8_t*)alloca(bsize); + } + while(d->read_started || d->write_started){ + if (d->sound_err==0){ + if (d->write_started){ +#if 0 + if (d->stat_output>0 && d->buffer_playing==0) + { + ms_error("No data currently playing in sound card" ); + } + if (d->stat_output>0 && (d->stat_input-d->stat_output>10 || d->stat_input-d->stat_output<-10)) + ms_error("Not perfectly synchronized (input-output=%i)", d->stat_input-d->stat_output); +#endif + + while (d->buffer_playing<6 && d->buffer_playingmutex); + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + ms_mutex_unlock(&d->mutex); + if (err!=bsize) + break; + + ms_mutex_lock(&d->mutex); + /* write to sound devide! */ + memcpy (d->waveouthdr[pos_whdr].lpData, wtmpbuff, bsize); + + mr = waveOutWrite (d->waveoutdev, + &(d->waveouthdr[pos_whdr]), + sizeof (d->waveouthdr[pos_whdr])); + + if (mr != MMSYSERR_NOERROR) + { + if (mr == WAVERR_STILLPLAYING) + { + /* retry later */ + /* data should go back to queue */ + /* TODO */ + ms_warning("sound device write STILL_PLAYING (waveOutWrite:0x%i)", mr); + } + else + { + ms_warning("sound device write returned (waveOutWrite:0x%i)", mr); + } + } + else + { + d->buffer_playing++; + pos_whdr++; + if (pos_whdr == MAX_WAVEHDR) + pos_whdr = 0; /* loop over the prepared blocks */ + } + ms_mutex_unlock(&d->mutex); + + + if (err<0){ +#if !defined(_WIN32_WCE) + ms_warning("Fail to write %i bytes from soundcard: %s", + bsize,strerror(errno)); +#else + ms_warning("Fail to write %i bytes from soundcard: %i", + bsize,WSAGetLastError()); +#endif + } + } + + if (d->buffer_playing==6 || d->buffer_playing==MAX_WAVEHDR) + { + int discarded=0; + ms_mutex_lock(&d->mutex); + while (d->bufferizer->size>=bsize){ + discarded++; + d->stat_notplayed++; + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + } + ms_mutex_unlock(&d->mutex); + if (discarded>0) + ms_error("Extra data for sound card removed (%ims), (playing: %i) (input-output: %i)", (discarded*20*320)/320, d->buffer_playing, d->stat_input - d->stat_output); + } +#if !defined(_WIN32_WCE) + Sleep(5); +#endif +#if defined(_WIN32_WCE) + Sleep(10); +#endif + }else { + int discarded=0; + /* don't think this is usefull, anyway... */ + ms_mutex_lock(&d->mutex); + while (d->bufferizer->size>=bsize){ + discarded++; + err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); + } + ms_mutex_unlock(&d->mutex); + if (discarded>0) + ms_error("Extra data for sound card removed (%ims), (playing: %i) (input-output: %i)", (discarded*20)/320, d->buffer_playing, d->stat_input - d->stat_output); + Sleep(10); + } + }else Sleep(10); + } + if (d->sound_err==0) { + int i; + int count=0; + /* close sound card */ + ms_error("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->buffer_playing, d->stat_input - d->stat_output, d->stat_notplayed); + + /* unprepare buffer */ + for (i = 0; i < MAX_WAVEHDR; i++) + { + int counttry=0; + for (counttry=0;counttry<10;counttry++) + { + mr = waveInUnprepareHeader (d->waveindev, + &(d->waveinhdr[i]), + sizeof (d->waveinhdr[i])); + if (mr != MMSYSERR_NOERROR) + { + ms_error("Failed to unprepared %i buffer from sound card (waveInUnprepareHeader:0x%i", count, mr); + Sleep (20); + } else + { + count++; + ms_message("successfully unprepared %i buffer from sound card.", count); + break; + } + } + } + ms_warning("unprepared %i buffer from sound card.", count); + + mr = waveInStop (d->waveindev); + if (mr != MMSYSERR_NOERROR) + { + ms_error("failed to stop recording sound card (waveInStop:0x%i)", mr); + } else + { + ms_message("successfully stopped recording sound card"); + } + + mr = waveInReset (d->waveindev); + if (mr != MMSYSERR_NOERROR) + { + ms_warning("failed to reset recording sound card (waveInReset:0x%i)", mr); + } else + { + ms_message("successful reset of recording sound card"); + } + + mr = waveInClose (d->waveindev); + if (mr != MMSYSERR_NOERROR) + { + ms_warning("failed to close recording sound card (waveInClose:0x%i)", mr); + } else + { + ms_message("successfully closed recording sound card"); + } + d->sound_err=-1; + } + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + return NULL; +} + +static void winsnd_start_r(MSSndCard *card){ + WinSndData *d=(WinSndData*)card->data; + if (d->read_started==FALSE && d->write_started==FALSE){ + d->read_started=TRUE; + ms_thread_create(&d->thread,NULL,winsnd_thread,card); + }else d->read_started=TRUE; +} + +static void winsnd_stop_r(MSSndCard *card){ + WinSndData *d=(WinSndData*)card->data; + d->read_started=FALSE; + if (d->write_started==FALSE){ + ms_thread_join(d->thread,NULL); + } +} + +static void winsnd_start_w(MSSndCard *card){ + WinSndData *d=(WinSndData*)card->data; + if (d->read_started==FALSE && d->write_started==FALSE){ + d->write_started=TRUE; + ms_thread_create(&d->thread,NULL,winsnd_thread,card); + }else{ + d->write_started=TRUE; + } +} + +static void winsnd_stop_w(MSSndCard *card){ + WinSndData *d=(WinSndData*)card->data; + d->write_started=FALSE; + if (d->read_started==FALSE){ + ms_thread_join(d->thread,NULL); + } +#ifdef CONTROLVOLUME + waveOutSetVolume(d->waveoutdev, d->dwOldVolume); +#endif +} + +static mblk_t *winsnd_get(MSSndCard *card){ + WinSndData *d=(WinSndData*)card->data; + mblk_t *m; + ms_mutex_lock(&d->mutex); + m=getq(&d->rq); + ms_mutex_unlock(&d->mutex); + return m; +} + +static void winsnd_put(MSSndCard *card, mblk_t *m){ + WinSndData *d=(WinSndData*)card->data; + ms_mutex_lock(&d->mutex); + ms_bufferizer_put(d->bufferizer,m); + ms_mutex_unlock(&d->mutex); +} + + +static void winsnd_read_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + winsnd_start_r(card); + ms_ticker_set_time_func(f->ticker,winsnd_get_cur_time,card->data); +} + +static void winsnd_read_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + ms_ticker_set_time_func(f->ticker,NULL,NULL); + winsnd_stop_r(card); +} + +static void winsnd_read_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + while((m=winsnd_get(card))!=NULL){ + ms_queue_put(f->outputs[0],m); + } +} + +static void winsnd_write_preprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + winsnd_start_w(card); +} + +static void winsnd_write_postprocess(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + winsnd_stop_w(card); +} + +static void winsnd_write_process(MSFilter *f){ + MSSndCard *card=(MSSndCard*)f->data; + mblk_t *m; + + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + winsnd_put(card,m); + } +} + +static int set_rate(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + WinSndData *d=(WinSndData*)card->data; + d->rate=*((int*)arg); + return 0; +} + +static int set_nchannels(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + WinSndData *d=(WinSndData*)card->data; + d->stereo=(*((int*)arg)==2); + return 0; +} + +static int winsnd_get_stat_input(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + WinSndData *d=(WinSndData*)card->data; + + return d->stat_input; +} + +static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + WinSndData *d=(WinSndData*)card->data; + + return d->stat_output; +} + +static int winsnd_get_stat_discarded(MSFilter *f, void *arg){ + MSSndCard *card=(MSSndCard*)f->data; + WinSndData *d=(WinSndData*)card->data; + + return d->stat_notplayed; +} + +static MSFilterMethod winsnd_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , set_rate }, + { MS_FILTER_SET_NCHANNELS , set_nchannels }, + { MS_FILTER_GET_STAT_INPUT, winsnd_get_stat_input }, + { MS_FILTER_GET_STAT_OUTPUT, winsnd_get_stat_ouptut }, + { MS_FILTER_GET_STAT_DISCARDED, winsnd_get_stat_discarded }, + { 0 , NULL } +}; + +MSFilterDesc winsnd_read_desc={ + MS_WINSND_READ_ID, + "MSWinSndRead", + "Sound capture filter for Windows Sound drivers", + MS_FILTER_OTHER, + NULL, + 0, + 1, + NULL, + winsnd_read_preprocess, + winsnd_read_process, + winsnd_read_postprocess, + NULL, + winsnd_methods +}; + + +MSFilterDesc winsnd_write_desc={ + MS_WINSND_WRITE_ID, + "MSWinSndWrite", + "Sound playback filter for Windows Sound drivers", + MS_FILTER_OTHER, + NULL, + 1, + 0, + NULL, + winsnd_write_preprocess, + winsnd_write_process, + winsnd_write_postprocess, + NULL, + winsnd_methods +}; + +MSFilter *ms_winsnd_read_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc); + f->data=card; + return f; +} + + +MSFilter *ms_winsnd_write_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc); + f->data=card; + return f; +} + +MS_FILTER_DESC_EXPORT(winsnd_read_desc) +MS_FILTER_DESC_EXPORT(winsnd_write_desc) diff --git a/linphone/mediastreamer2/src/winsnd2.c b/linphone/mediastreamer2/src/winsnd2.c new file mode 100755 index 000000000..f6eb242a6 --- /dev/null +++ b/linphone/mediastreamer2/src/winsnd2.c @@ -0,0 +1,852 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" + +#include +#ifdef _MSC_VER +#include +#endif +#include + +#if defined(_WIN32_WCE) +//#define DISABLE_SPEEX +//#define WCE_OPTICON_WORKAROUND 1000 +#endif +#ifndef DISABLE_SPEEX +#include +#endif + +#define WINSND_NBUFS 10 +#define WINSND_OUT_NBUFS 20 +#define WINSND_NSAMPLES 320 +#define WINSND_MINIMUMBUFFER 5 + +static MSFilter *ms_winsnd_read_new(MSSndCard *card); +static MSFilter *ms_winsnd_write_new(MSSndCard *card); + +typedef struct WinSndCard{ + int in_devid; + int out_devid; +}WinSndCard; + +static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){ + MMRESULT mr = MMSYSERR_NOERROR; + DWORD dwVolume = 0xFFFF; + dwVolume = ((0xFFFF) * percent) / 100; + + switch(e){ + case MS_SND_CARD_MASTER: + /*mr = waveOutSetVolume(d->waveoutdev, dwVolume); */ + if (mr != MMSYSERR_NOERROR) + { + ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr); + return; + } + break; + case MS_SND_CARD_CAPTURE: + break; + case MS_SND_CARD_PLAYBACK: + break; + default: + ms_warning("winsnd_card_set_level: unsupported command."); + } +} + +static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){ + switch(e){ + case MS_SND_CARD_MASTER: + /*mr=waveOutGetVolume(d->waveoutdev, &dwVolume);*/ + /* Transform to 0 to 100 scale*/ + /*dwVolume = (dwVolume *100) / (0xFFFF);*/ + return 60; + break; + case MS_SND_CARD_CAPTURE: + break; + case MS_SND_CARD_PLAYBACK: + break; + default: + ms_warning("winsnd_card_get_level: unsupported command."); + return -1; + } + return -1; +} + +static void winsndcard_set_source(MSSndCard *card, MSSndCardCapture source){ + + switch(source){ + case MS_SND_CARD_MIC: + break; + case MS_SND_CARD_LINE: + break; + } +} + +static void winsndcard_init(MSSndCard *card){ + WinSndCard *c=(WinSndCard *)ms_new(WinSndCard,1); + card->data=c; +} + +static void winsndcard_uninit(MSSndCard *card){ + ms_free(card->data); +} + +static void winsndcard_detect(MSSndCardManager *m); +static MSSndCard *winsndcard_dup(MSSndCard *obj); + +MSSndCardDesc winsnd_card_desc={ + "WINSND", + winsndcard_detect, + winsndcard_init, + winsndcard_set_level, + winsndcard_get_level, + winsndcard_set_source, + ms_winsnd_read_new, + ms_winsnd_write_new, + winsndcard_uninit, + winsndcard_dup +}; + +static MSSndCard *winsndcard_dup(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&winsnd_card_desc); + card->name=ms_strdup(obj->name); + card->data=ms_new(WinSndCard,1); + memcpy(card->data,obj->data,sizeof(WinSndCard)); + return card; +} + +static MSSndCard *winsndcard_new(const char *name, int in_dev, int out_dev, unsigned cap){ + MSSndCard *card=ms_snd_card_new(&winsnd_card_desc); + WinSndCard *d=(WinSndCard*)card->data; + card->name=ms_strdup(name); + d->in_devid=in_dev; + d->out_devid=out_dev; + card->capabilities=cap; + return card; +} + +static void add_or_update_card(MSSndCardManager *m, const char *name, int indev, int outdev, unsigned int capability){ + MSSndCard *card; + const MSList *elem=ms_snd_card_manager_get_list(m); + for(;elem!=NULL;elem=elem->next){ + card=(MSSndCard*)elem->data; + if (strcmp(card->name,name)==0){ + /*update already entered card */ + WinSndCard *d=(WinSndCard*)card->data; + card->capabilities|=capability; + if (indev!=-1) + d->in_devid=indev; + if (outdev!=-1) + d->out_devid=outdev; + + return; + } + } + /* add this new card:*/ + ms_snd_card_manager_add_card(m,winsndcard_new(name,indev,outdev,capability)); +} + +static void winsndcard_detect(MSSndCardManager *m){ + MMRESULT mr = NOERROR; + unsigned int nOutDevices = waveOutGetNumDevs (); + unsigned int nInDevices = waveInGetNumDevs (); + unsigned int item; + + if (nOutDevices>nInDevices) + nInDevices = nOutDevices; + + for (item = 0; item < nInDevices; item++){ + + WAVEINCAPS incaps; + WAVEOUTCAPS outcaps; + mr = waveInGetDevCaps (item, &incaps, sizeof (WAVEINCAPS)); + if (mr == MMSYSERR_NOERROR) + { +#if defined(_WIN32_WCE) + char card[256]; + snprintf(card, sizeof(card), "Input card %i", item); + add_or_update_card(m,card,item,-1,MS_SND_CARD_CAP_CAPTURE); + /* _tprintf(L"new card: %s", incaps.szPname); */ +#else + add_or_update_card(m,incaps.szPname,item,-1,MS_SND_CARD_CAP_CAPTURE); +#endif + } + mr = waveOutGetDevCaps (item, &outcaps, sizeof (WAVEOUTCAPS)); + if (mr == MMSYSERR_NOERROR) + { +#if defined(_WIN32_WCE) + char card[256]; + snprintf(card, sizeof(card), "Output card %i", item); + add_or_update_card(m,card,-1,item,MS_SND_CARD_CAP_PLAYBACK); + /* _tprintf(L"new card: %s", outcaps.szPname); */ +#else + add_or_update_card(m,outcaps.szPname,-1,item,MS_SND_CARD_CAP_PLAYBACK); +#endif + } + } +} + + +typedef struct WinSnd{ + int dev_id; + HWAVEIN indev; + HWAVEOUT outdev; + WAVEFORMATEX wfx; + WAVEHDR hdrs_read[WINSND_NBUFS]; + WAVEHDR hdrs_write[WINSND_OUT_NBUFS]; + queue_t rq; + ms_mutex_t mutex; + unsigned int bytes_read; + unsigned int nbufs_playing; + bool_t running; + + int32_t stat_input; + int32_t stat_output; + int32_t stat_notplayed; + + int32_t stat_minimumbuffer; + + queue_t write_rq; +#ifndef DISABLE_SPEEX + SpeexPreprocessState *pst; + int pst_frame_size; +#endif + int ready; + int workaround; /* workaround for opticon audio device */ +}WinSnd; + +static void winsnd_apply_settings(WinSnd *d){ + d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8; + d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign; +} + +static uint64_t winsnd_get_cur_time( void *data){ + WinSnd *d=(WinSnd*)data; + uint64_t curtime=((uint64_t)d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec; + /* ms_debug("winsnd_get_cur_time: bytes_read=%u return %lu\n",d->bytes_read,(unsigned long)curtime); */ + return curtime; +} + + +static void winsnd_init(MSFilter *f){ + WinSnd *d=(WinSnd *)ms_new0(WinSnd,1); + d->wfx.wFormatTag = WAVE_FORMAT_PCM; + d->wfx.cbSize = 0; + d->wfx.nAvgBytesPerSec = 16000; + d->wfx.nBlockAlign = 2; + d->wfx.nChannels = 1; + d->wfx.nSamplesPerSec = 8000; + d->wfx.wBitsPerSample = 16; + qinit(&d->rq); + qinit(&d->write_rq); +#ifndef DISABLE_SPEEX + d->pst=NULL; + d->pst_frame_size=0; +#endif + d->ready=0; + d->workaround=0; + ms_mutex_init(&d->mutex,NULL); + f->data=d; + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->stat_minimumbuffer=WINSND_MINIMUMBUFFER; +} + +static void winsnd_uninit(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + flushq(&d->rq,0); + flushq(&d->write_rq,0); +#ifndef DISABLE_SPEEX + if (d->pst!=NULL) + speex_preprocess_state_destroy(d->pst); + d->pst=NULL; + d->pst_frame_size=0; +#endif + d->ready=0; + d->workaround=0; + ms_mutex_destroy(&d->mutex); + ms_free(f->data); +} + +static void add_input_buffer(WinSnd *d, WAVEHDR *hdr, int buflen){ + mblk_t *m=allocb(buflen,0); + MMRESULT mr; + memset(hdr,0,sizeof(*hdr)); + if (buflen==0) ms_error("add_input_buffer: buflen=0 !"); + hdr->lpData=(LPSTR)m->b_wptr; + hdr->dwBufferLength=buflen; + hdr->dwFlags = 0; + hdr->dwUser = (DWORD)m; + mr = waveInPrepareHeader (d->indev,hdr,sizeof(*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInPrepareHeader() error"); + return ; + } + mr=waveInAddBuffer(d->indev,hdr,sizeof(*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInAddBuffer() error"); + return ; + } +} + +static void CALLBACK +read_callback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, + DWORD dwParam2) +{ + WAVEHDR *wHdr=(WAVEHDR *) dwParam1; + MSFilter *f=(MSFilter *)dwInstance; + WinSnd *d=(WinSnd*)f->data; + mblk_t *m; + int bsize; + switch (uMsg){ + case WIM_OPEN: + ms_debug("read_callback : WIM_OPEN"); + break; + case WIM_CLOSE: + ms_debug("read_callback : WIM_CLOSE"); + break; + case WIM_DATA: + bsize=wHdr->dwBytesRecorded; + if (bsize<=0) { +#if 0 + if (d->running==TRUE) /* avoid adding buffer back when calling waveInReset */ + { + MMRESULT mr; + mr=waveInAddBuffer(d->indev,wHdr,sizeof(*wHdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInAddBuffer() error"); + return ; + } + ms_warning("read_callback : EMPTY DATA, WIM_DATA (%p,%i)",wHdr,bsize); + } + m=(mblk_t*)wHdr->dwUser; + wHdr->dwUser=0; + freemsg(m); + return; +#endif + } + + /* ms_warning("read_callback : WIM_DATA (%p,%i)",wHdr,bsize); */ + m=(mblk_t*)wHdr->dwUser; + m->b_wptr+=bsize; + wHdr->dwUser=0; + ms_mutex_lock(&d->mutex); + putq(&d->rq,m); + ms_mutex_unlock(&d->mutex); + d->bytes_read+=wHdr->dwBufferLength; + d->stat_input++; + d->stat_input++; +#ifdef WIN32_TIMERS + if (f->ticker->TimeEvent!=NULL) + SetEvent(f->ticker->TimeEvent); +#endif + break; + } +} + + +static void winsnd_read_preprocess(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + MMRESULT mr; + int i; + int bsize; + DWORD dwFlag; + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->stat_minimumbuffer=WINSND_MINIMUMBUFFER; + + winsnd_apply_settings(d); + /* Init Microphone device */ + dwFlag = CALLBACK_FUNCTION; + if (d->dev_id != WAVE_MAPPER) + dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION; + mr = waveInOpen (&d->indev, d->dev_id, &d->wfx, + (DWORD) read_callback, (DWORD)f, dwFlag); + if (mr != MMSYSERR_NOERROR) + { + ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr); + mr = waveInOpen (&d->indev, WAVE_MAPPER, &d->wfx, + (DWORD) read_callback, (DWORD)d, CALLBACK_FUNCTION); + if (mr != MMSYSERR_NOERROR) + { + d->indev=NULL; + ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr); + return ; + } + } + bsize=WINSND_NSAMPLES*d->wfx.nAvgBytesPerSec/8000; + ms_debug("Using input buffers of %i bytes",bsize); + for(i=0;ihdrs_read[i]; + add_input_buffer(d,hdr,bsize); + } + d->running=TRUE; + mr=waveInStart(d->indev); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInStart() error"); + return ; + } + ms_ticker_set_time_func(f->ticker,winsnd_get_cur_time,d); +} + +static void winsnd_read_postprocess(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + MMRESULT mr; + int i; + ms_ticker_set_time_func(f->ticker,NULL,NULL); + d->running=FALSE; + mr=waveInStop(d->indev); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInStop() error"); + return ; + } + mr=waveInReset(d->indev); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInReset() error"); + return ; + } + for(i=0;ihdrs_read[i]; + if (hdr->dwFlags & WHDR_PREPARED) + { + mr = waveInUnprepareHeader(d->indev,hdr,sizeof (*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInUnPrepareHeader() error"); + } + } + } + mr = waveInClose(d->indev); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveInClose() error"); + return ; + } + + ms_message("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->stat_input - d->stat_output, d->stat_notplayed); + flushq(&d->rq,0); +} + +static void winsnd_read_process(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + mblk_t *m; + int i; + ms_mutex_lock(&d->mutex); + while((m=getq(&d->rq))!=NULL){ + ms_queue_put(f->outputs[0],m); + } + ms_mutex_unlock(&d->mutex); + for(i=0;ihdrs_read[i]; + if (hdr->dwUser==0) { + MMRESULT mr; + mr=waveInUnprepareHeader(d->indev,hdr,sizeof(*hdr)); + if (mr!=MMSYSERR_NOERROR) + ms_warning("winsnd_read_process: Fail to unprepare header!"); + add_input_buffer(d,hdr,hdr->dwBufferLength); + } + } +} + +static void CALLBACK +write_callback(HWAVEOUT outdev, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + WAVEHDR *hdr=(WAVEHDR *) dwParam1; + WinSnd *d=(WinSnd*)dwInstance; + + switch (uMsg){ + case WOM_OPEN: + break; + case WOM_CLOSE: + case WOM_DONE: + if (hdr){ + d->nbufs_playing--; + } + if (d->stat_output==0) + { + d->stat_input=1; /* reset */ + d->stat_notplayed=0; + } + d->stat_output++; + break; + } +} + +static void winsnd_write_preprocess(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + MMRESULT mr; + DWORD dwFlag; + int i; + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->stat_minimumbuffer=WINSND_MINIMUMBUFFER; + + winsnd_apply_settings(d); + /* Init Microphone device */ + dwFlag = CALLBACK_FUNCTION; + if (d->dev_id != WAVE_MAPPER) + dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION; + mr = waveOutOpen (&d->outdev, d->dev_id, &d->wfx, + (DWORD) write_callback, (DWORD)d, dwFlag); + if (mr != MMSYSERR_NOERROR) + { + ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr); + mr = waveOutOpen (&d->outdev, WAVE_MAPPER, &d->wfx, + (DWORD) write_callback, (DWORD)d, CALLBACK_FUNCTION); + if (mr != MMSYSERR_NOERROR) + { + ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr); + d->outdev=NULL; + return ; + } + } + for(i=0;ihdrs_write[i]; + hdr->dwFlags=0; + hdr->dwUser=0; + } +} + +static void winsnd_write_postprocess(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + MMRESULT mr; + int i; + if (d->outdev==NULL) return; + mr=waveOutReset(d->outdev); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveOutReset() error"); + return ; + } + for(i=0;ihdrs_write[i]; + mblk_t *old; + if (hdr->dwFlags & WHDR_DONE){ + mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveOutUnprepareHeader error"); + } + old=(mblk_t*)hdr->dwUser; + if (old) freemsg(old); + hdr->dwUser=0; + } + } + mr=waveOutClose(d->outdev); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveOutClose() error"); + return ; + } + ms_message("Shutting down sound device (playing: %i) (d->write_rq.q_mcount=%i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->write_rq.q_mcount, d->stat_input - d->stat_output, d->stat_notplayed); + flushq(&d->write_rq,0); + d->ready=0; + d->workaround=0; + +#ifndef DISABLE_SPEEX + if (d->pst!=NULL) + speex_preprocess_state_destroy(d->pst); + d->pst=NULL; + d->pst_frame_size=0; +#endif +} + +static void winsnd_write_process(MSFilter *f){ + WinSnd *d=(WinSnd*)f->data; + mblk_t *m,*old; + MMRESULT mr; + int i; + int discarded=0; + int possible_size=0; + + if (d->outdev==NULL) { + ms_queue_flush(f->inputs[0]); + return; + } + + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + possible_size = msgdsize(m); +#ifndef DISABLE_SPEEX + if (d->pst_frame_size==0) + { + d->pst_frame_size=possible_size; + + d->pst = speex_preprocess_state_init(d->pst_frame_size/2, d->wfx.nSamplesPerSec); + if (d->pst!=NULL) { + float f; + i=1; + speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_VAD, &i); + i=0; + speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DENOISE, &i); + i=0; + speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC, &i); + f=8000; + speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); + i=0; + speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i); + } + } +#endif + + putq(&d->write_rq,m); + } + +#ifdef AMD_HACK + /* too many sound card are crappy on windows... */ + d->stat_minimumbuffer=15; + if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ + d->stat_minimumbuffer=8; +#endif + + if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ + { + if (d->nbufs_playing+d->write_rq.q_mcount<4) + { + d->ready=0; + } + } + else + { + if (d->nbufs_playing+d->write_rq.q_mcount<7) + { + d->ready=0; + } + } +#if defined(WCE_OPTICON_WORKAROUND) + if (d->workaround==0) + { + d->workaround=1; + Sleep(WCE_OPTICON_WORKAROUND); + } +#endif + + while((m=peekq(&d->write_rq))!=NULL){ + +#ifndef DISABLE_SPEEX + int vad=1; + if (d->pst!=NULL && msgdsize(m)==d->pst_frame_size && d->pst_frame_size<=4096) + { + char tmp[4096]; + memcpy(tmp, m->b_rptr, msgdsize(m)); + vad = speex_preprocess(d->pst, (short*)tmp, NULL); + + if (d->ready==0) + { + if (vad==0) + { + int missing; + missing = 10 - d->write_rq.q_mcount - d->nbufs_playing; + if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ + missing = 6 - d->write_rq.q_mcount - d->nbufs_playing; + + ms_message("WINSND trouble: inserting %i silence", missing); + while(missing>0) + { + old=dupb(m); + putq(&d->write_rq,old); + missing--; + } + } + d->ready=1; + } + } +#else + if (d->ready==0) + { + int missing; + missing = 10 - d->write_rq.q_mcount - d->nbufs_playing; + if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ + missing = 6 - d->write_rq.q_mcount - d->nbufs_playing; + ms_message("WINSND trouble: inserting %i silence", missing); + while(missing>0) + { + old=dupb(m); + putq(&d->write_rq,old); + missing--; + } + d->ready=1; + } +#endif + + for(i=0;istat_minimumbuffer;++i){ + WAVEHDR *hdr=&d->hdrs_write[i]; + if (hdr->dwFlags & WHDR_DONE){ + old=(mblk_t*)hdr->dwUser; + mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveOutUnprepareHeader error"); + } + freemsg(old); + hdr->dwUser=0; + } + if (hdr->dwUser==0){ + hdr->lpData=(LPSTR)m->b_rptr; + hdr->dwBufferLength=msgdsize(m); + hdr->dwFlags = 0; + hdr->dwUser = (DWORD)m; + mr = waveOutPrepareHeader(d->outdev,hdr,sizeof(*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveOutPrepareHeader() error"); + getq(&d->write_rq); + freemsg(m); + discarded++; + d->stat_notplayed++; + break; + } + mr=waveOutWrite(d->outdev,hdr,sizeof(*hdr)); + if (mr != MMSYSERR_NOERROR){ + ms_error("waveOutWrite() error"); + getq(&d->write_rq); + freemsg(m); + discarded++; + d->stat_notplayed++; + break; + }else { + getq(&d->write_rq); + d->nbufs_playing++; + /* ms_debug("waveOutWrite() done"); */ + } + break; + } + } + if (i==d->stat_minimumbuffer){ + //ms_error("winsnd_write_process: All buffers are busy."); +#ifndef DISABLE_SPEEX + if (d->pst==NULL) + { + /* initial behavior (detection in process?) */ + getq(&d->write_rq); + freemsg(m); + } + else + { + if (vad==0) + { + getq(&d->write_rq); + freemsg(m); + ms_message("WINSND trouble: silence removed"); + } + } +#else + getq(&d->write_rq); + freemsg(m); +#endif + + discarded++; + d->stat_notplayed++; + + break; + } + } +} + +static int set_rate(MSFilter *f, void *arg){ + WinSnd *d=(WinSnd*)f->data; + d->wfx.nSamplesPerSec=*((int*)arg); + return 0; +} + +static int set_nchannels(MSFilter *f, void *arg){ + WinSnd *d=(WinSnd*)f->data; + d->wfx.nChannels=*((int*)arg); + return 0; +} + +static int winsnd_get_stat_input(MSFilter *f, void *arg){ + WinSnd *d=(WinSnd*)f->data; + return d->stat_input; +} + +static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){ + WinSnd *d=(WinSnd*)f->data; + + return d->stat_output; +} + +static int winsnd_get_stat_discarded(MSFilter *f, void *arg){ + WinSnd *d=(WinSnd*)f->data; + + return d->stat_notplayed; +} + +static MSFilterMethod winsnd_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , set_rate }, + { MS_FILTER_SET_NCHANNELS , set_nchannels }, + { MS_FILTER_GET_STAT_INPUT, winsnd_get_stat_input }, + { MS_FILTER_GET_STAT_OUTPUT, winsnd_get_stat_ouptut }, + { MS_FILTER_GET_STAT_DISCARDED, winsnd_get_stat_discarded }, + { 0 , NULL } +}; + +MSFilterDesc winsnd_read_desc={ + MS_WINSND_READ_ID, + "MSWinSndRead", + "Sound capture filter for Windows Sound drivers", + MS_FILTER_OTHER, + NULL, + 0, + 1, + winsnd_init, + winsnd_read_preprocess, + winsnd_read_process, + winsnd_read_postprocess, + winsnd_uninit, + winsnd_methods +}; + + +MSFilterDesc winsnd_write_desc={ + MS_WINSND_WRITE_ID, + "MSWinSndWrite", + "Sound playback filter for Windows Sound drivers", + MS_FILTER_OTHER, + NULL, + 1, + 0, + winsnd_init, + winsnd_write_preprocess, + winsnd_write_process, + winsnd_write_postprocess, + winsnd_uninit, + winsnd_methods +}; + +MSFilter *ms_winsnd_read_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc); + WinSndCard *wc=(WinSndCard*)card->data; + WinSnd *d=(WinSnd*)f->data; + d->dev_id=wc->in_devid; + return f; +} + + +MSFilter *ms_winsnd_write_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc); + WinSndCard *wc=(WinSndCard*)card->data; + WinSnd *d=(WinSnd*)f->data; + d->dev_id=wc->out_devid; + return f; +} + +MS_FILTER_DESC_EXPORT(winsnd_read_desc) +MS_FILTER_DESC_EXPORT(winsnd_write_desc) diff --git a/linphone/mediastreamer2/src/winsndds.cpp b/linphone/mediastreamer2/src/winsndds.cpp new file mode 100644 index 000000000..e5bf576e8 --- /dev/null +++ b/linphone/mediastreamer2/src/winsndds.cpp @@ -0,0 +1,845 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef __DIRECTSOUND_ENABLED__ + +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/msticker.h" + +#include +#ifdef _MSC_VER +#include +#endif +#include + +#include + +#define WINSNDDS_NBUFS 10 +#define WINSNDDS_NSAMPLES 160 +#define WINSNDDS_MINIMUMBUFFER 5 + +static MSFilter *ms_winsndds_read_new(MSSndCard *card); +static MSFilter *ms_winsndds_write_new(MSSndCard *card); + +static HMODULE ms_lib_instance=NULL; +static HRESULT (WINAPI *ms_DllGetClassObject)(REFCLSID , REFIID , LPVOID *); + +static HRESULT (WINAPI *ms_DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); +static HRESULT (WINAPI *ms_DirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID); + +static HRESULT (WINAPI *ms_DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN); +static HRESULT (WINAPI *ms_DirectSoundCaptureEnumerate)(LPDSENUMCALLBACKA, LPVOID); + +typedef struct WinSndDsCard{ + int in_devid; + int out_devid; + GUID in_guid; + GUID out_guid; +}WinSndDsCard; + + +static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){ + MMRESULT mr = MMSYSERR_NOERROR; + DWORD dwVolume = 0xFFFF; + dwVolume = ((0xFFFF) * percent) / 100; + + switch(e){ + case MS_SND_CARD_MASTER: + /*mr = waveOutSetVolume(d->waveoutdev, dwVolume); */ + if (mr != MMSYSERR_NOERROR) + { + ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr); + return; + } + break; + case MS_SND_CARD_CAPTURE: + break; + case MS_SND_CARD_PLAYBACK: + break; + default: + ms_warning("winsndds_card_set_level: unsupported command."); + } +} + +static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){ + switch(e){ + case MS_SND_CARD_MASTER: + /*mr=waveOutGetVolume(d->waveoutdev, &dwVolume);*/ + /* Transform to 0 to 100 scale*/ + /*dwVolume = (dwVolume *100) / (0xFFFF);*/ + return 60; + break; + case MS_SND_CARD_CAPTURE: + break; + case MS_SND_CARD_PLAYBACK: + break; + default: + ms_warning("winsndds_card_get_level: unsupported command."); + return -1; + } + return -1; +} + +static void winsnddscard_set_source(MSSndCard *card, MSSndCardCapture source){ + + switch(source){ + case MS_SND_CARD_MIC: + break; + case MS_SND_CARD_LINE: + break; + } +} + +static void winsnddscard_init(MSSndCard *card){ + WinSndDsCard *c=(WinSndDsCard *)ms_new(WinSndDsCard,1); + card->data=c; +} + +static void winsnddscard_uninit(MSSndCard *card){ + ms_free(card->data); +} + +static void winsnddscard_detect(MSSndCardManager *m); +static MSSndCard *winsnddscard_dup(MSSndCard *obj); + +MSSndCardDesc winsndds_card_desc={ + "WINSNDDS", + winsnddscard_detect, + winsnddscard_init, + winsnddscard_set_level, + winsnddscard_get_level, + winsnddscard_set_source, + ms_winsndds_read_new, + ms_winsndds_write_new, + winsnddscard_uninit, + winsnddscard_dup +}; + +static MSSndCard *winsnddscard_dup(MSSndCard *obj){ + MSSndCard *card=ms_snd_card_new(&winsndds_card_desc); + card->name=ms_strdup(obj->name); + card->data=ms_new(WinSndDsCard,1); + memcpy(card->data,obj->data,sizeof(WinSndDsCard)); + return card; +} + +static MSSndCard *winsnddscard_new(const char *name, LPGUID lpguid, int in_dev, int out_dev, unsigned cap){ + MSSndCard *card=ms_snd_card_new(&winsndds_card_desc); + WinSndDsCard *d=(WinSndDsCard*)card->data; + card->name=ms_strdup(name); + d->in_devid=in_dev; + d->out_devid=out_dev; + card->capabilities=cap; + if (out_dev!=-1) + { + if (lpguid!=NULL) + memcpy(&d->out_guid, lpguid, sizeof(GUID)); + else + memset(&d->out_guid, 0, sizeof(GUID)); + } + else + { + if (lpguid!=NULL) + memcpy(&d->in_guid, lpguid, sizeof(GUID)); + else + memset(&d->in_guid, 0, sizeof(GUID)); + } + return card; +} + +static void add_or_update_card(MSSndCardManager *m, const char *name, LPGUID lpguid, int indev, int outdev, unsigned int capability){ + MSSndCard *card; + const MSList *elem=ms_snd_card_manager_get_list(m); + for(;elem!=NULL;elem=elem->next){ + card=(MSSndCard*)elem->data; + if (strcmp(card->name,name)==0){ + /*update already entered card */ + WinSndDsCard *d=(WinSndDsCard*)card->data; + card->capabilities|=capability; + if (indev!=-1) + d->in_devid=indev; + if (outdev!=-1) + d->out_devid=outdev; + + if (outdev!=-1) + { + if (lpguid!=NULL) + memcpy(&d->out_guid, lpguid, sizeof(GUID)); + else + memset(&d->out_guid, 0, sizeof(GUID)); + } + if (indev!=-1) + { + if (lpguid!=NULL) + memcpy(&d->in_guid, lpguid, sizeof(GUID)); + else + memset(&d->in_guid, 0, sizeof(GUID)); + } + return; + } + } + /* add this new card:*/ + ms_snd_card_manager_add_card(m,winsnddscard_new(name,lpguid, indev,outdev,capability)); +} + +static BOOL CALLBACK enumerate_capture_devices_callback(LPGUID lpGUID, + LPCTSTR lpszDesc, + LPCTSTR lpszDrvName, + LPVOID lpContext ) +{ + MSSndCardManager *m = (MSSndCardManager*)lpContext; + static int dev_index=0; + + if ( lpGUID == NULL ) /* primary device */ + { + char snd_card_name[256]; + snprintf(snd_card_name, 256, "ds: %s", lpszDesc); + add_or_update_card(m,snd_card_name,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE); + dev_index++; + } + else + { + char snd_card_name[256]; + snprintf(snd_card_name, 256, "ds: %s", lpszDesc); + add_or_update_card(m,snd_card_name,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE); + dev_index++; + } + + return true; +} + +static BOOL CALLBACK enumerate_playback_devices_callback(LPGUID lpGUID, + LPCTSTR lpszDesc, + LPCTSTR lpszDrvName, + LPVOID lpContext ) +{ + MSSndCardManager *m = (MSSndCardManager*)lpContext; + static int dev_index=0; + + if ( lpGUID == NULL ) /* primary device */ + { + char snd_card_name[256]; + snprintf(snd_card_name, 256, "ds: %s", lpszDesc); + + add_or_update_card(m,snd_card_name,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK); + dev_index++; + } + else + { + char snd_card_name[256]; + snprintf(snd_card_name, 256, "ds: %s", lpszDesc); + + add_or_update_card(m,snd_card_name,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK); + dev_index++; + } + + return true; +} + +static void winsnddscard_detect(MSSndCardManager *m){ + MMRESULT mr = NOERROR; + + if (ms_lib_instance==NULL) + { + ms_lib_instance = LoadLibrary("dsound.dll"); + if( ms_lib_instance == NULL ) + { + /* error */ + ms_debug("winsnddscard_init: no support for dsound (missing dsound.dll)\n"); + return; + } + + ms_DllGetClassObject =(HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *)) + GetProcAddress( ms_lib_instance, "DllGetClassObject" ); + + ms_DirectSoundCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN)) + GetProcAddress( ms_lib_instance, "DirectSoundCreate" ); + + ms_DirectSoundEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) + GetProcAddress( ms_lib_instance, "DirectSoundEnumerateA" ); + + ms_DirectSoundCaptureCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN)) + GetProcAddress( ms_lib_instance, "DirectSoundCaptureCreate" ); + + ms_DirectSoundCaptureEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) + GetProcAddress( ms_lib_instance, "DirectSoundCaptureEnumerateA" ); + + if( ms_DllGetClassObject == NULL || + ms_DirectSoundCreate == NULL || + ms_DirectSoundEnumerate == NULL || + ms_DirectSoundCaptureEnumerate == NULL || + ms_DirectSoundCaptureCreate == NULL ) + { + /* error */ + ms_debug("winsnddscard_init: no support for dsound\n"); + return; + } + } + + ms_DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)enumerate_capture_devices_callback, (void *)m ); + ms_DirectSoundEnumerate( (LPDSENUMCALLBACK)enumerate_playback_devices_callback, (void *)m ); +} + + +typedef struct WinSndDs{ + int dev_id; + GUID in_guid; + GUID out_guid; + + ms_thread_t thread; + ms_mutex_t thread_lock; + ms_cond_t thread_cond; + bool_t thread_running; + + MSBufferizer output_buff; + LPDIRECTSOUND lpDirectSound; + LPDIRECTSOUNDBUFFER lpDirectSoundOutputBuffer; + DWORD outputBufferWriteOffsetBytes; /* last write position */ + double dsw_framesWritten; + + LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; + LPDIRECTSOUNDCAPTUREBUFFER lpDirectSoundInputBuffer; + UINT readOffset; /* last read position */ + UINT inputSize; + + int framesPerDSBuffer; + + WAVEFORMATEX wfx; + queue_t rq; + ms_mutex_t mutex; + unsigned int bytes_read; + unsigned int nbufs_playing; + + int32_t stat_input; + int32_t stat_output; + int32_t stat_notplayed; + + int32_t stat_minimumbuffer; +}WinSndDs; + +void * +winsndds_read_thread(void *arg) +{ + WinSndDs *d=(WinSndDs*)arg; + + ms_mutex_lock(&d->thread_lock); + ms_cond_signal(&d->thread_cond); + ms_mutex_unlock(&d->thread_lock); + + while(d->thread_running) + { + HRESULT hr; + DWORD capturePos; + DWORD readPos; + long filled = 0; + long bytesFilled = 0; + LPBYTE lpInBuf1 = NULL; + LPBYTE lpInBuf2 = NULL; + DWORD dwInSize1 = 0; + DWORD dwInSize2 = 0; + + hr = IDirectSoundCaptureBuffer_GetCurrentPosition( d->lpDirectSoundInputBuffer, + &capturePos, &readPos ); + if( hr != DS_OK ) + { + continue; + } + + filled = readPos - d->readOffset; + if( filled < 0 ) filled += d->inputSize; // unwrap offset + bytesFilled = filled; + + hr = IDirectSoundCaptureBuffer_Lock ( d->lpDirectSoundInputBuffer, + d->readOffset, bytesFilled, + (void **) &lpInBuf1, &dwInSize1, + (void **) &lpInBuf2, &dwInSize2, 0); + if (hr != DS_OK) + { + Sleep(10); + continue; + } + + if (dwInSize1==0) + { + Sleep(10); + } + else if (dwInSize1>=bytesFilled) + { + mblk_t *m=allocb(bytesFilled,0); + memcpy(m->b_rptr, lpInBuf1, bytesFilled); + m->b_wptr+=bytesFilled; + ms_mutex_lock(&d->mutex); + putq(&d->rq,m); + ms_mutex_unlock(&d->mutex); + d->bytes_read+=bytesFilled; + } + else + { + mblk_t *m=allocb(bytesFilled,0); + memcpy(m->b_rptr, lpInBuf1, dwInSize1); + memcpy(m->b_rptr+dwInSize1, lpInBuf2, dwInSize2); + m->b_wptr+=bytesFilled; + ms_mutex_lock(&d->mutex); + putq(&d->rq,m); + ms_mutex_unlock(&d->mutex); + d->bytes_read+=bytesFilled; + } + + d->readOffset = (d->readOffset + bytesFilled) % d->inputSize; + + IDirectSoundCaptureBuffer_Unlock( d->lpDirectSoundInputBuffer, + lpInBuf1, dwInSize1, lpInBuf2, dwInSize2); + } + + ms_mutex_lock(&d->thread_lock); + ms_cond_signal(&d->thread_cond); + ms_mutex_unlock(&d->thread_lock); + ms_thread_exit(NULL); + return NULL; +} + +static void winsndds_apply_settings(WinSndDs *d){ + d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8; + d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign; +} + +static uint64_t winsndds_get_cur_time( void *data){ + WinSndDs *d=(WinSndDs*)data; + uint64_t curtime=((uint64_t)d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec; + /* ms_debug("winsndds_get_cur_time: bytes_read=%u return %lu\n",d->bytes_read,(unsigned long)curtime); */ + return curtime; +} + + +static void winsndds_init(MSFilter *f){ + WinSndDs *d=(WinSndDs *)ms_new0(WinSndDs,1); + d->wfx.wFormatTag = WAVE_FORMAT_PCM; + d->wfx.cbSize = 0; + d->wfx.nAvgBytesPerSec = 16000; + d->wfx.nBlockAlign = 2; + d->wfx.nChannels = 1; + d->wfx.nSamplesPerSec = 8000; + d->wfx.wBitsPerSample = 16; + qinit(&d->rq); + ms_mutex_init(&d->mutex,NULL); + f->data=d; + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->stat_minimumbuffer=WINSNDDS_MINIMUMBUFFER; + + d->framesPerDSBuffer = 4096*3; //320 * (8000 / 1000); + + d->thread = NULL; + ms_mutex_init(&d->thread_lock,NULL); + ms_cond_init(&d->thread_cond,NULL); + d->thread_running = FALSE; + + ms_bufferizer_init(&d->output_buff); +} + +static void winsndds_uninit(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + + d->thread = NULL; + d->thread_running = FALSE; + ms_cond_destroy(&d->thread_cond); + ms_mutex_destroy(&d->thread_lock); + ms_bufferizer_uninit(&d->output_buff); + + flushq(&d->rq,0); + ms_mutex_destroy(&d->mutex); + ms_free(f->data); +} + +static void winsndds_read_preprocess(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + DSCBUFFERDESC captureDesc; + HRESULT hr; + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->stat_minimumbuffer=WINSNDDS_MINIMUMBUFFER; + + winsndds_apply_settings(d); + ms_DirectSoundCaptureCreate( &d->in_guid, &d->lpDirectSoundCapture, NULL ); + + d->inputSize = d->framesPerDSBuffer * 1 * sizeof(short); + + ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); + captureDesc.dwSize = sizeof(DSCBUFFERDESC); + captureDesc.dwFlags = 0; + captureDesc.dwBufferBytes = d->framesPerDSBuffer * 1 * sizeof(short); //bytesPerBuffer; + captureDesc.lpwfxFormat = &d->wfx; + // Create the capture buffer + if ((hr = IDirectSoundCapture_CreateCaptureBuffer( d->lpDirectSoundCapture, + &captureDesc, &d->lpDirectSoundInputBuffer, NULL)) != DS_OK) + { + return; /* hr; */ + } + d->readOffset = 0; // reset last read position to start of buffer + + hr = IDirectSoundCaptureBuffer_Start( d->lpDirectSoundInputBuffer, DSCBSTART_LOOPING ); + + ms_ticker_set_time_func(f->ticker,winsndds_get_cur_time,d); + + d->thread_running=TRUE; + ms_thread_create(&d->thread,NULL,winsndds_read_thread,d); + ms_mutex_lock(&d->thread_lock); + ms_cond_wait(&d->thread_cond,&d->thread_lock); + ms_mutex_unlock(&d->thread_lock); + + return; /* DS_OK; */ +} + +static void winsndds_read_postprocess(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + + ms_mutex_lock(&d->thread_lock); + d->thread_running=FALSE; + ms_cond_wait(&d->thread_cond,&d->thread_lock); + ms_mutex_unlock(&d->thread_lock); + ms_thread_join(d->thread,NULL); + + ms_ticker_set_time_func(f->ticker,NULL,NULL); + + if( d->lpDirectSoundInputBuffer ) + { + IDirectSoundCaptureBuffer_Stop( d->lpDirectSoundInputBuffer ); + IDirectSoundCaptureBuffer_Release( d->lpDirectSoundInputBuffer ); + d->lpDirectSoundInputBuffer = NULL; + } + + if( d->lpDirectSoundCapture ) + { + IDirectSoundCapture_Release( d->lpDirectSoundCapture ); + d->lpDirectSoundCapture = NULL; + } + + ms_message("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->stat_input - d->stat_output, d->stat_notplayed); + flushq(&d->rq,0); +} + +static void winsndds_read_process(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + mblk_t *m; + + ms_mutex_lock(&d->mutex); + while((m=getq(&d->rq))!=NULL){ + ms_queue_put(f->outputs[0],m); + } + ms_mutex_unlock(&d->mutex); +} + +static void winsndds_write_preprocess(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + + DWORD dwDataLen; + DWORD playCursor; + HWND hWnd; + HRESULT hr; + LPDIRECTSOUNDBUFFER pPrimaryBuffer; + DSBUFFERDESC primaryDesc; + DSBUFFERDESC secondaryDesc; + unsigned char* pDSBuffData; + + + d->stat_input=0; + d->stat_output=0; + d->stat_notplayed=0; + d->stat_minimumbuffer=WINSNDDS_MINIMUMBUFFER; + + winsndds_apply_settings(d); + + + ms_DirectSoundCreate( &d->out_guid, &d->lpDirectSound, NULL ); + + + hWnd = GetDesktopWindow(); + if ((hr = IDirectSound_SetCooperativeLevel( d->lpDirectSound, + hWnd, DSSCL_EXCLUSIVE)) != DS_OK) + { + return ; + } + + ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); + primaryDesc.dwSize = sizeof(DSBUFFERDESC); + primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth + primaryDesc.dwBufferBytes = 0; + primaryDesc.lpwfxFormat = NULL; + // Create the buffer + if ((hr = IDirectSound_CreateSoundBuffer( d->lpDirectSound, + &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) + { + return ;//hr; + } + + if ((hr = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &d->wfx)) != DS_OK) + { + return ;//hr; + } + + // Setup the secondary buffer description + ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); + secondaryDesc.dwSize = sizeof(DSBUFFERDESC); + secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + secondaryDesc.dwBufferBytes = d->framesPerDSBuffer * 1 * sizeof(short); //bytesPerBuffer; + secondaryDesc.lpwfxFormat = &d->wfx; + // Create the secondary buffer + if ((hr = IDirectSound_CreateSoundBuffer( d->lpDirectSound, + &secondaryDesc, &d->lpDirectSoundOutputBuffer, NULL)) != DS_OK) + { + return ;//hr; + } + + // Lock the DS buffer + if ((hr = IDirectSoundBuffer_Lock( d->lpDirectSoundOutputBuffer, 0, + d->framesPerDSBuffer * 1 * sizeof(short), + (LPVOID*)&pDSBuffData, + &dwDataLen, NULL, 0, 0)) != DS_OK) + { + return ;//hr; + } + + // Zero the DS buffer + ZeroMemory(pDSBuffData, dwDataLen); + // Unlock the DS buffer + if ((hr = IDirectSoundBuffer_Unlock( d->lpDirectSoundOutputBuffer, + pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) + { + return ;//hr; + } + + // Let DSound set the starting write position because if we set it to zero, it looks like the + // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. + hr = IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer, + &playCursor, &d->outputBufferWriteOffsetBytes ); + if( hr != DS_OK ) + { + return ;//hr; + } + + hr = IDirectSoundBuffer_SetCurrentPosition( d->lpDirectSoundOutputBuffer, 0 ); + if( hr != DS_OK ) + { + return ;//hr; + } + hr = IDirectSoundBuffer_Play( d->lpDirectSoundOutputBuffer, 0, 0, DSBPLAY_LOOPING); + if( hr != DS_OK ) + { + return ;//hr; + } + + return ;//hr; +} + +static void winsndds_write_postprocess(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + + if( d->lpDirectSoundOutputBuffer ) + { + IDirectSoundBuffer_Stop( d->lpDirectSoundOutputBuffer ); + IDirectSoundBuffer_Release( d->lpDirectSoundOutputBuffer ); + d->lpDirectSoundOutputBuffer = NULL; + } + + if( d->lpDirectSound ) + { + IDirectSound_Release( d->lpDirectSound ); + d->lpDirectSound = NULL; + } + + ms_message("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->stat_input - d->stat_output, d->stat_notplayed); +} + +static void winsndds_write_process(MSFilter *f){ + WinSndDs *d=(WinSndDs*)f->data; + int discarded=0; + static int fillme=0; + + if (d->lpDirectSound==NULL) { + ms_queue_flush(f->inputs[0]); + return; + } + + ms_bufferizer_put_from_queue(&d->output_buff,f->inputs[0]); + + if (fillme==0) + { + if (ms_bufferizer_get_avail(&d->output_buff)>=4096*3) + { + fillme=1; + return; + } + return; + } + + int msize = 4096;// 1280; + while (ms_bufferizer_get_avail(&d->output_buff)>=msize) + { + LPBYTE lpOutBuf1 = NULL; + LPBYTE lpOutBuf2 = NULL; + DWORD dwOutSize1 = 0; + DWORD dwOutSize2 = 0; + HRESULT hr; + char input[4096]; + + hr = IDirectSoundBuffer_Lock ( d->lpDirectSoundOutputBuffer, + d->outputBufferWriteOffsetBytes, msize, //bytesToXfer, + (void **) &lpOutBuf1, &dwOutSize1, + (void **) &lpOutBuf2, &dwOutSize2, DSBLOCK_FROMWRITECURSOR); + if (hr != DS_OK) + { + ms_error("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n", hr); + continue; + } + + if (dwOutSize1==0) + { + ms_error("no free room to play sample\n"); + } + else if (dwOutSize1+dwOutSize2!=msize) + { + ms_bufferizer_read(&d->output_buff,(uint8_t*)input,dwOutSize1+dwOutSize2); + memcpy(lpOutBuf1, input, dwOutSize1); + memcpy(lpOutBuf2, input+dwOutSize1, dwOutSize2); + } + else if (dwOutSize1>=msize) + { + ms_bufferizer_read(&d->output_buff,(uint8_t*)input,msize); + memcpy(lpOutBuf1, input, msize); + } + else + { + ms_bufferizer_read(&d->output_buff,(uint8_t*)input,msize); + memcpy(lpOutBuf1, input, dwOutSize1); + memcpy(lpOutBuf2, input+dwOutSize1, dwOutSize2); + } + + IDirectSoundBuffer_Unlock( d->lpDirectSoundOutputBuffer, + lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2); + if (dwOutSize1==0) + break; + if (dwOutSize1+dwOutSize2!=msize) + break; + } + + if (discarded>0) + ms_warning("Extra data for sound card removed (%i buf), (playing: %i) (input-output: %i)", discarded, d->nbufs_playing, d->stat_input - d->stat_output); +} + +static int set_rate(MSFilter *f, void *arg){ + WinSndDs *d=(WinSndDs*)f->data; + d->wfx.nSamplesPerSec=*((int*)arg); + return 0; +} + +static int set_nchannels(MSFilter *f, void *arg){ + WinSndDs *d=(WinSndDs*)f->data; + d->wfx.nChannels=*((int*)arg); + return 0; +} + +static int winsndds_get_stat_input(MSFilter *f, void *arg){ + WinSndDs *d=(WinSndDs*)f->data; + return d->stat_input; +} + +static int winsndds_get_stat_ouptut(MSFilter *f, void *arg){ + WinSndDs *d=(WinSndDs*)f->data; + + return d->stat_output; +} + +static int winsndds_get_stat_discarded(MSFilter *f, void *arg){ + WinSndDs *d=(WinSndDs*)f->data; + + return d->stat_notplayed; +} + +static MSFilterMethod winsndds_methods[]={ + { MS_FILTER_SET_SAMPLE_RATE , set_rate }, + { MS_FILTER_SET_NCHANNELS , set_nchannels }, + { MS_FILTER_GET_STAT_INPUT, winsndds_get_stat_input }, + { MS_FILTER_GET_STAT_OUTPUT, winsndds_get_stat_ouptut }, + { MS_FILTER_GET_STAT_DISCARDED, winsndds_get_stat_discarded }, + { 0 , NULL } +}; + +MSFilterDesc winsndds_read_desc={ + MS_WINSNDDS_READ_ID, + "MSWinSndRead", + "Sound capture filter for Windows Sound drivers", + MS_FILTER_OTHER, + NULL, + 0, + 1, + winsndds_init, + winsndds_read_preprocess, + winsndds_read_process, + winsndds_read_postprocess, + winsndds_uninit, + winsndds_methods +}; + + +MSFilterDesc winsndds_write_desc={ + MS_WINSNDDS_WRITE_ID, + "MSWinSndWrite", + "Sound playback filter for Windows Sound drivers", + MS_FILTER_OTHER, + NULL, + 1, + 0, + winsndds_init, + winsndds_write_preprocess, + winsndds_write_process, + winsndds_write_postprocess, + winsndds_uninit, + winsndds_methods +}; + +MSFilter *ms_winsndds_read_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&winsndds_read_desc); + WinSndDsCard *wc=(WinSndDsCard*)card->data; + WinSndDs *d=(WinSndDs*)f->data; + d->dev_id=wc->in_devid; + memcpy(&d->in_guid, &wc->in_guid, sizeof(GUID)); + memcpy(&d->out_guid, &wc->out_guid, sizeof(GUID)); + return f; +} + + +MSFilter *ms_winsndds_write_new(MSSndCard *card){ + MSFilter *f=ms_filter_new_from_desc(&winsndds_write_desc); + WinSndDsCard *wc=(WinSndDsCard*)card->data; + WinSndDs *d=(WinSndDs*)f->data; + d->dev_id=wc->out_devid; + memcpy(&d->in_guid, &wc->in_guid, sizeof(GUID)); + memcpy(&d->out_guid, &wc->out_guid, sizeof(GUID)); + return f; +} + +MS_FILTER_DESC_EXPORT(winsndds_read_desc) +MS_FILTER_DESC_EXPORT(winsndds_write_desc) + +#endif diff --git a/linphone/mediastreamer2/src/winvideo.c b/linphone/mediastreamer2/src/winvideo.c new file mode 100644 index 000000000..5cae8591a --- /dev/null +++ b/linphone/mediastreamer2/src/winvideo.c @@ -0,0 +1,637 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msv4l.h" +#include "Vfw.h" +#include +#include + +#include "nowebcam.h" +#include "mediastreamer2/mswebcam.h" + +#ifndef _MSC_VER +#include "vfw-missing.h" +#endif + +#define AMD_HACK2 + +typedef struct V4wState{ +#ifdef AMD_HACK2 + ms_thread_t thread; + ms_mutex_t thread_lock; + ms_cond_t thread_cond; + bool_t thread_running; +#endif + + char dev[512]; + int devidx; + HWND capvideo; + MSVideoSize vsize; + int pix_fmt; + mblk_t *mire[10]; + queue_t rq; + ms_mutex_t mutex; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + bool_t running; + bool_t startwith_yuv_bug; /* avoid bug with USB vimicro cards. */ + bool_t started; + bool_t autostarted; +}V4wState; + +static void dummy(void*p){ +} + +LRESULT CALLBACK VideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr) +{ + V4wState *s; + mblk_t *buf; + int size; + + s = (V4wState *)capGetUserData(hWnd); + if (s==NULL) + return FALSE; + + size = lpVHdr->dwBufferLength; + if (size>0 && s->running){ + buf = esballoc(lpVHdr->lpData,size,0,dummy); + buf->b_wptr+=size; + + ms_mutex_lock(&s->mutex); + putq(&s->rq, buf); + ms_mutex_unlock(&s->mutex); + } + return TRUE ; +} + +static bool_t try_format(V4wState *s, BITMAPINFO *videoformat, MSPixFmt pixfmt){ + switch(pixfmt){ + case MS_YUV420P: + videoformat->bmiHeader.biBitCount = 12; + videoformat->bmiHeader.biCompression=MAKEFOURCC('I','4','2','0'); + break; + case MS_RGB24: + videoformat->bmiHeader.biBitCount = 24; + videoformat->bmiHeader.biCompression=BI_RGB; + break; + default: + return FALSE; + } + return capSetVideoFormat(s->capvideo, videoformat, sizeof(BITMAPINFO)); +} + +static int v4w_open_videodevice(V4wState *s) +{ + CAPTUREPARMS capparam ; + BITMAPINFO videoformat; + char compname[5]; + int i; + char dev[80]; + char ver[80]; + compname[4]='\0'; + + for (i = 0; i < 9; i++){ + if (capGetDriverDescription(i, dev, sizeof (dev), + ver, sizeof (ver))) + { + snprintf(s->dev, sizeof(s->dev), "%s/%s",dev,ver); + ms_message("v4w: detected %s",s->dev); + s->devidx=i; + break; + } + } + if (s->capvideo==NULL) + { + s->capvideo = capCreateCaptureWindow("Capture Window",WS_CHILD /* WS_OVERLAPPED */ + ,0,0,s->vsize.width,s->vsize.height,HWND_MESSAGE, 0) ; + if (s->capvideo==NULL) + { + ms_warning("v4w: could not create capture windows"); + return -1; + } + } + + if(!capDriverConnect(s->capvideo,s->devidx )) + { + ms_warning("v4w: could not connect to capture driver"); + DestroyWindow(s->capvideo); + s->capvideo=NULL; + s->pix_fmt=MS_YUV420P; /* no webcam stuff */ + return -1; + } + /* + capPreviewRate(s->capvideo,s->fps) ; + if(!capPreview (s->capvideo, 1)) + { + ms_warning("v4w: cannot start video preview"); + capDriverDisconnect(s->capvideo); + DestroyWindow(s->capvideo); + s->capvideo=NULL; + return -1; + } + */ + capCaptureGetSetup(s->capvideo,&capparam,sizeof(capparam)) ; + capparam.dwRequestMicroSecPerFrame = 100000 ; + // detach capture from application + capparam.fYield = TRUE ; + capparam.fMakeUserHitOKToCapture = FALSE; + capparam.fAbortLeftMouse = FALSE; + capparam.fAbortRightMouse = FALSE; + capparam.wPercentDropForError = 90 ; + capparam.fCaptureAudio = FALSE ; + capparam.fAbortRightMouse = FALSE; + capparam.fAbortLeftMouse = FALSE; + capparam.AVStreamMaster = AVSTREAMMASTER_NONE ; + + if (!capCaptureSetSetup(s->capvideo,&capparam,sizeof(capparam))){ + ms_error("capCaptureSetSetup failed."); + } + capSetUserData(s->capvideo, s); + capGetVideoFormat(s->capvideo, &videoformat, sizeof(BITMAPINFO)); + + videoformat.bmiHeader.biSizeImage = 0; + videoformat.bmiHeader.biWidth = s->vsize.width; + videoformat.bmiHeader.biHeight = s->vsize.height; + /* "orig planes = " disp->videoformat.bmiHeader.biPlanes */ + /* "orig bitcount = " disp->videoformat.bmiHeader.biBitCount */ + /* "orig compression = " disp->videoformat.bmiHeader.biCompression */ + memcpy(compname,&videoformat.bmiHeader.biCompression,4); + ms_message("v4w: camera's current format is %s", compname); + + if (s->startwith_yuv_bug==TRUE && try_format(s,&videoformat,MS_RGB24)){ + s->pix_fmt=MS_RGB24; + ms_message("Using RGB24"); + }else if (try_format(s,&videoformat,MS_YUV420P)){ + s->pix_fmt=MS_YUV420P; + ms_message("Using YUV420P"); + }else if (try_format(s,&videoformat,MS_RGB24)){ + s->pix_fmt=MS_RGB24; + ms_message("Using RGB24"); + s->startwith_yuv_bug=TRUE; + }else{ + ms_error("v4w: Failed to set any video format."); + capDriverDisconnect (s->capvideo); + DestroyWindow(s->capvideo); + s->capvideo=NULL; + return -1; + } + if (!capSetCallbackOnVideoStream(s->capvideo, VideoStreamCallback)) + { + ms_error("v4w: fail to set capture callback"); + capDriverDisconnect (s->capvideo); + DestroyWindow(s->capvideo); + s->capvideo=NULL; + return -1; + } + if (!capCaptureSequenceNoFile(s->capvideo)){ + ms_error("v4w: fail to start capture"); + capDriverDisconnect (s->capvideo); + capSetCallbackOnVideoStream(s->capvideo, NULL); + DestroyWindow(s->capvideo); + s->capvideo=NULL; + } + return 0; +} + +static void v4w_init(MSFilter *f){ + V4wState *s=(V4wState *)ms_new0(V4wState,1); + int idx; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + s->pix_fmt=MS_RGB24; + + s->capvideo=NULL; + qinit(&s->rq); + for (idx=0;idx<10;idx++) + { + s->mire[idx]=NULL; + } + ms_mutex_init(&s->mutex,NULL); + s->start_time=0; + s->frame_count=-1; + s->fps=15; + s->started=FALSE; + s->autostarted=FALSE; + +#ifdef AMD_HACK2 + /* avoid bug with USB vimicro cards: + How can I detect that this problem exist? + */ + s->startwith_yuv_bug=FALSE; +#endif + +#ifdef AMD_HACK2 + s->thread = NULL; + ms_mutex_init(&s->thread_lock,NULL); + ms_cond_init(&s->thread_cond,NULL); + s->thread_running = FALSE; +#endif + + f->data=s; +} + +static int _v4w_start(V4wState *s, void *arg) +{ + int i; + s->frame_count=-1; + i = v4w_open_videodevice(s); + if (i==0 && s->startwith_yuv_bug==TRUE) + { + /* reopen device directly with MS_RGB24 */ + if (s->capvideo){ + capSetUserData(s->capvideo, (long) 0); + capCaptureStop(s->capvideo); + capCaptureAbort(s->capvideo); + capDriverDisconnect(s->capvideo); + capSetCallbackOnVideoStream(s->capvideo, NULL); + flushq(&s->rq,0); + ms_message("v4w: destroying capture window"); + DestroyWindow(s->capvideo); + ms_message("v4w: capture window destroyed"); + s->capvideo=NULL; + } + i = v4w_open_videodevice(s); + } + return i; +} + +static int _v4w_stop(V4wState *s, void *arg){ + s->frame_count=-1; + if (s->capvideo){ + capCaptureStop(s->capvideo); + Sleep(1000); + //capCaptureAbort(s->capvideo); + capSetCallbackOnVideoStream(s->capvideo, NULL); + //SendMessage(s->capvideo, WM_CLOSE, 0, 0); + capDriverDisconnect(s->capvideo); + capSetUserData(s->capvideo, (long) 0); + flushq(&s->rq,0); + ms_message("v4w: destroying capture window"); + DestroyWindow(s->capvideo); + ms_message("v4w: capture window destroyed"); + s->capvideo=NULL; + } +#if 0 + if (s->capvideo){ + CAPSTATUS status; + capCaptureStop(s->capvideo); + capDriverDisconnect(s->capvideo); + capCaptureAbort(s->capvideo); + + capSetCallbackOnVideoStream(s->capvideo, NULL); + while (1) + { + if (capGetStatus(s->capvideo, &status, sizeof(status))) + { + if (status.fCapturingNow==FALSE) + break; + Sleep(10); + ms_message("still capturing"); + } + } + DestroyWindow(s->capvideo); + s->capvideo=NULL; + } +#endif + return 0; +} + +#ifdef AMD_HACK2 + +void * +v4w_thread(void *arg) +{ + V4wState *s=(V4wState*)arg; + MSG msg; + + ms_mutex_lock(&s->thread_lock); + _v4w_start(s, NULL); + ms_cond_signal(&s->thread_cond); + ms_mutex_unlock(&s->thread_lock); + + while(s->thread_running) + { + BOOL fGotMessage; + if((fGotMessage = PeekMessage(&msg, (HWND) s->capvideo, 0, 0, PM_REMOVE)) != 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + Sleep(10); + } + + ms_mutex_lock(&s->thread_lock); + _v4w_stop(s, NULL); + ms_cond_signal(&s->thread_cond); + ms_mutex_unlock(&s->thread_lock); + ms_thread_exit(NULL); + return NULL; +} + + +static int v4w_start(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->thread_running=TRUE; + ms_thread_create(&s->thread,NULL,v4w_thread,s); + ms_mutex_lock(&s->thread_lock); + ms_cond_wait(&s->thread_cond,&s->thread_lock); + ms_mutex_unlock(&s->thread_lock); + s->started=TRUE; + return 0; +} + +static int v4w_stop(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + ms_mutex_lock(&s->thread_lock); + s->thread_running=FALSE; + //SendMessage(s->capvideo, WM_CLOSE, 0, 0); + ms_cond_wait(&s->thread_cond,&s->thread_lock); + ms_mutex_unlock(&s->thread_lock); + ms_thread_join(s->thread,NULL); + s->started=FALSE; + return 0; +} + +#else + +static int v4w_start(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + _v4w_start(s, NULL); + s->started=TRUE; + return 0; +} + +static int v4w_stop(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + _v4w_stop(s, NULL); + s->started=FALSE; + return 0; +} + +#endif + +static void v4w_uninit(MSFilter *f){ + V4wState *s=(V4wState*)f->data; + int idx; + flushq(&s->rq,0); + ms_mutex_destroy(&s->mutex); + for (idx=0;idx<10;idx++) + { + if (s->mire[idx]==NULL) + break; + freemsg(s->mire[idx]); + } + if (s->capvideo!=NULL) + { + ms_message("v4w: destroying capture window"); + DestroyWindow(s->capvideo); + ms_message("v4w: capture window destroyed"); + s->capvideo=NULL; + } +#ifdef AMD_HACK2 + ms_cond_destroy(&s->thread_cond); + ms_mutex_destroy(&s->thread_lock); +#endif + ms_free(s); +} + +static mblk_t * v4w_make_nowebcam(V4wState *s){ + int idx; + int count; + if (s->mire[0]==NULL && s->frame_ind==0){ + /* load several images to fake a movie */ + for (idx=0;idx<10;idx++) + { + s->mire[idx]=ms_load_nowebcam(&s->vsize, idx); + if (s->mire[idx]==NULL) + break; + } + if (idx==0) + s->mire[0]=ms_load_nowebcam(&s->vsize, -1); + } + for (count=0;count<10;count++) + { + if (s->mire[count]==NULL) + break; + } + + s->frame_ind++; + if (count==0) + return NULL; + + idx = s->frame_ind%count; + if (s->mire[idx]!=NULL) + return s->mire[idx]; + return s->mire[0]; +} + +static void v4w_preprocess(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + if (!s->started) { + ms_message("V4W auto-started."); + v4w_start(obj,NULL); + s->autostarted=TRUE; + } + s->running=TRUE; + if (s->capvideo==NULL) + s->fps=1; +} + +static void v4w_postprocess(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + s->running=FALSE; + if (s->autostarted){ + v4w_stop(obj,NULL); + } +} + +static void v4w_process(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + mblk_t *m; + uint32_t timestamp; + int cur_frame; + + if (s->frame_count==-1){ + s->start_time=obj->ticker->time; + s->frame_count=0; + } + + + cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame>s->frame_count){ + mblk_t *om=NULL; + ms_mutex_lock(&s->mutex); + /*keep the most recent frame if several frames have been captured */ + if (s->capvideo!=NULL){ + while((m=getq(&s->rq))!=NULL){ + if (om!=NULL) freemsg(om); + om=m; + } + }else { + mblk_t *nowebcam = v4w_make_nowebcam(s); + if (nowebcam!=NULL) + om=dupmsg(nowebcam); + } + ms_mutex_unlock(&s->mutex); + if (om!=NULL){ + timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/ + mblk_set_timestamp_info(om,timestamp); + ms_queue_put(obj->outputs[0],om); + /*ms_message("picture sent");*/ + } + s->frame_count++; + } +} + +static int v4w_set_fps(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->fps=*((float*)arg); + return 0; +} + +static int v4w_get_pix_fmt(MSFilter *f,void *arg){ + V4wState *s=(V4wState*)f->data; + if (!s->started) { + ms_message("V4W auto-started in v4w_get_pix_fmt()"); + v4w_start(f,NULL); + s->autostarted=TRUE; + } + *((MSPixFmt*)arg) = (MSPixFmt)s->pix_fmt; + return 0; +} + +static int v4w_set_vsize(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->vsize=*((MSVideoSize*)arg); + return 0; +} + +static int v4w_get_vsize(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + MSVideoSize *vs=(MSVideoSize*)arg; + vs->width=s->vsize.width; + vs->height=s->vsize.height; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , v4w_set_fps }, + { MS_FILTER_GET_PIX_FMT , v4w_get_pix_fmt }, + { MS_FILTER_SET_VIDEO_SIZE, v4w_set_vsize }, + { MS_FILTER_GET_VIDEO_SIZE, v4w_get_vsize }, + { MS_V4L_START , v4w_start }, + { MS_V4L_STOP , v4w_stop }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_v4w_desc={ + MS_V4L_ID, + "MSV4w", + "A video4windows compatible source filter to stream pictures.", + MS_FILTER_OTHER, + NULL, + 0, + 1, + v4w_init, + v4w_preprocess, + v4w_process, + v4w_postprocess, + v4w_uninit, + methods +}; + +#else + +MSFilterDesc ms_v4w_desc={ + .id=MS_V4L_ID, + .name="MSV4w", + .text="A video4windows compatible source filter to stream pictures.", + .ninputs=0, + .noutputs=1, + .category=MS_FILTER_OTHER, + .init=v4w_init, + .preprocess=v4w_preprocess, + .process=v4w_process, + .postprocess=v4w_postprocess, + .uninit=v4w_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_v4w_desc) + +static void ms_v4w_detect(MSWebCamManager *obj); + +static void ms_v4w_cam_init(MSWebCam *cam){ +} + + +static MSFilter *ms_v4w_create_reader(MSWebCam *obj){ + MSFilter *f= ms_filter_new_from_desc(&ms_v4w_desc); + V4wState *s=(V4wState*)f->data; + s->devidx=(int)obj->data; + return f; +} + +MSWebCamDesc ms_v4w_cam_desc={ + "VideoForWindows grabber", + &ms_v4w_detect, + &ms_v4w_cam_init, + &ms_v4w_create_reader, + NULL +}; + +static void ms_v4w_detect(MSWebCamManager *obj){ + int i; + char dev[80]; + char ver[80]; + char name[160]; + MSWebCam *cam; + for (i = 0; i < 9; i++){ + if (capGetDriverDescription(i, dev, sizeof (dev), + ver, sizeof (ver))){ + HWND hwnd=capCreateCaptureWindow("Capture Window",WS_CHILD /* WS_OVERLAPPED */ + ,0,0,352,288,HWND_MESSAGE, 0) ; + if (hwnd==NULL) break; + if(!capDriverConnect(hwnd,i )){ + ms_warning("v4w: could not connect to capture driver, no webcam connected."); + DestroyWindow(hwnd); + break; + }else{ + capDriverDisconnect(hwnd); + DestroyWindow(hwnd); + } + snprintf(name, sizeof(name), "%s/%s",dev,ver); + cam=ms_web_cam_new(&ms_v4w_cam_desc); + cam->data=(void*)i;/*store the device index */ + cam->name=ms_strdup(name); + ms_web_cam_manager_add_cam(obj,cam); + } + } +} + diff --git a/linphone/mediastreamer2/src/winvideods.c b/linphone/mediastreamer2/src/winvideods.c new file mode 100644 index 000000000..722fdbc78 --- /dev/null +++ b/linphone/mediastreamer2/src/winvideods.c @@ -0,0 +1,1048 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#define UNICODE +#define AYMERIC_TEST +#define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA + +#include "mediastreamer2/msvideo.h" +#include "mediastreamer2/msticker.h" +#include "mediastreamer2/msv4l.h" +#include "mediastreamer2/mswebcam.h" + +#include "nowebcam.h" +#include + +#include +#include +#include + +#include +#include +#include "dxfilter.h" +#include +#include +#include + +HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister); +void RemoveGraphFromRot(DWORD pdwRegister); + +typedef struct V4wState{ + + char dev[512]; + int devidx; + + CComPtr m_pGraph; + CComPtr m_pBuilder; + CComPtr m_pControl; + CDXFilter *m_pDXFilter; + CComPtr m_pIDXFilter; + CComPtr m_pNullRenderer; + CComPtr m_pDeviceFilter; + DWORD rotregvalue; + + MSVideoSize vsize; + int pix_fmt; + mblk_t *mire[10]; + char nowebcamimage[256]; + queue_t rq; + ms_mutex_t mutex; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + bool_t running; +}V4wState; + +static V4wState *s_callback=NULL; + +static void dummy(void*p){ +} + +HRESULT ( Callback)(IMediaSample* pSample, REFERENCE_TIME* sTime, REFERENCE_TIME* eTime, BOOL changed) +{ + BYTE *byte_buf=NULL; + mblk_t *buf; + + V4wState *s = s_callback; + if (s==NULL) + return S_OK; + + HRESULT hr = pSample->GetPointer(&byte_buf); + if (FAILED(hr)) + { + return S_OK; + } + + int size = pSample->GetActualDataLength(); + if (size>+1000) + { + buf=allocb(size,0); + memcpy(buf->b_wptr, byte_buf, size); + if (s->pix_fmt==MS_RGB24) + { + /* Conversion from top down bottom up (BGR to RGB and flip) */ + unsigned long Index,nPixels; + unsigned char *blue; + unsigned char tmp; + short iPixelSize; + + blue=buf->b_wptr; + + nPixels=s->vsize.width*s->vsize.height; + iPixelSize=24/8; + + for(Index=0;Index!=nPixels;Index++) // For each pixel + { + tmp=*blue; + *blue=*(blue+2); + *(blue+2)=tmp; + blue+=iPixelSize; + } + + unsigned char *pLine1, *pLine2; + int iLineLen,iIndex; + + iLineLen=s->vsize.width*iPixelSize; + pLine1=buf->b_wptr; + pLine2=&(buf->b_wptr)[iLineLen * (s->vsize.height - 1)]; + + for( ;pLine1b_wptr+=size; + + ms_mutex_lock(&s->mutex); + putq(&s->rq, buf); + ms_mutex_unlock(&s->mutex); + + } + return S_OK; +} + +int try_format(V4wState *s, int format) +{ + HRESULT hr=S_OK; + IEnumPins *pEnum=0; + ULONG ulFound; + IPin *pPin; + + GUID guid_format; + DWORD biCompression; + DWORD biBitCount; + + // Verify input + if (!s->m_pDeviceFilter) + return -1; + + if (format == MS_YUV420P) + guid_format = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0')); + else if (format == MS_YUYV) + guid_format = MEDIASUBTYPE_YUYV; + else if (format == MS_UYVY) + guid_format = MEDIASUBTYPE_UYVY; + else if (format == MS_RGB24) + guid_format = MEDIASUBTYPE_RGB24; + else if (format == MS_YUY2) + guid_format = MEDIASUBTYPE_YUY2; + + if (format == MS_YUV420P) + biCompression = MAKEFOURCC('I','4','2','0'); + else if (format == MS_YUYV) + biCompression = MAKEFOURCC('Y','U','Y','V'); + else if (format == MS_UYVY) + biCompression = MAKEFOURCC('U','Y','V','Y'); + else if (format == MS_RGB24) + biCompression = BI_RGB; + else if (format == MS_YUY2) + biCompression = MAKEFOURCC('Y','U','Y','2'); + + if (format == MS_YUV420P) + biBitCount = 12; + else if (format == MS_YUYV) + biBitCount = 16; + else if (format == MS_UYVY) + biBitCount = 16; + else if (format == MS_RGB24) + biBitCount = 24; + else if (format == MS_YUY2) + biBitCount = 16; + + // Get pin enumerator + hr = s->m_pDeviceFilter->EnumPins(&pEnum); + if(FAILED(hr)) + return -1; + + pEnum->Reset(); + + // Count every pin on the filter + while(S_OK == pEnum->Next(1, &pPin, &ulFound)) + { + PIN_DIRECTION pindir = (PIN_DIRECTION) 3; + + hr = pPin->QueryDirection(&pindir); + + if(pindir != PINDIR_INPUT) + { + IEnumMediaTypes *ppEnum; + ULONG ulFound2; + hr = pPin->EnumMediaTypes(&ppEnum); + if(FAILED(hr)) + continue; + + AM_MEDIA_TYPE *ppMediaTypes; + while(S_OK == ppEnum->Next(1, &ppMediaTypes, &ulFound2)) + { + if (ppMediaTypes->formattype != FORMAT_VideoInfo) + continue; + if (ppMediaTypes->majortype != MEDIATYPE_Video) + continue; + if (ppMediaTypes->subtype != guid_format) + continue; + VIDEOINFO *pvi = (VIDEOINFO *)ppMediaTypes->pbFormat; + if (pvi->bmiHeader.biCompression!=biCompression) + continue; + if (pvi->bmiHeader.biBitCount!=biBitCount) + continue; + + pPin->Release(); + pEnum->Release(); + return 0; + } + } + + pPin->Release(); + } + + pEnum->Release(); + return -1; +} + +int try_format_size(V4wState *s, int format, int width, int height) +{ + HRESULT hr=S_OK; + IEnumPins *pEnum=0; + ULONG ulFound; + IPin *pPin; + + GUID guid_format; + DWORD biCompression; + DWORD biBitCount; + + // Verify input + if (!s->m_pDeviceFilter) + return -1; + + if (format == MS_YUV420P) + guid_format = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0')); + else if (format == MS_YUYV) + guid_format = MEDIASUBTYPE_YUYV; + else if (format == MS_UYVY) + guid_format = MEDIASUBTYPE_UYVY; + else if (format == MS_RGB24) + guid_format = MEDIASUBTYPE_RGB24; + else if (format == MS_YUY2) + guid_format = MEDIASUBTYPE_YUY2; + + if (format == MS_YUV420P) + biCompression = MAKEFOURCC('I','4','2','0'); + else if (format == MS_YUYV) + biCompression = MAKEFOURCC('Y','U','Y','V'); + else if (format == MS_UYVY) + biCompression = MAKEFOURCC('U','Y','V','Y'); + else if (format == MS_RGB24) + biCompression = BI_RGB; + else if (format == MS_YUY2) + biCompression = MAKEFOURCC('Y','U','Y','2'); + + if (format == MS_YUV420P) + biBitCount = 12; + else if (format == MS_YUYV) + biBitCount = 16; + else if (format == MS_UYVY) + biBitCount = 16; + else if (format == MS_RGB24) + biBitCount = 24; + else if (format == MS_YUY2) + biBitCount = 16; + + // Get pin enumerator + hr = s->m_pDeviceFilter->EnumPins(&pEnum); + if(FAILED(hr)) + return -1; + + pEnum->Reset(); + + // Count every pin on the filter + while(S_OK == pEnum->Next(1, &pPin, &ulFound)) + { + PIN_DIRECTION pindir = (PIN_DIRECTION) 3; + + hr = pPin->QueryDirection(&pindir); + + if(pindir != PINDIR_INPUT) + { + IEnumMediaTypes *ppEnum; + ULONG ulFound2; + hr = pPin->EnumMediaTypes(&ppEnum); + if(FAILED(hr)) + continue; + + AM_MEDIA_TYPE *ppMediaTypes; + while(S_OK == ppEnum->Next(1, &ppMediaTypes, &ulFound2)) + { + if (ppMediaTypes->formattype != FORMAT_VideoInfo) + continue; + if (ppMediaTypes->majortype != MEDIATYPE_Video) + continue; + if (ppMediaTypes->subtype != guid_format) + continue; + VIDEOINFO *pvi = (VIDEOINFO *)ppMediaTypes->pbFormat; + if (pvi->bmiHeader.biCompression!=biCompression) + continue; + if (pvi->bmiHeader.biBitCount!=biBitCount) + continue; + if (pvi->bmiHeader.biHeight!=height) + continue; + if (pvi->bmiHeader.biWidth!=width) + continue; + + s->vsize.width = width; + s->vsize.height = height; + + pPin->Release(); + pEnum->Release(); + return 0; + } + } + + pPin->Release(); + } + + pEnum->Release(); + return -1; +} + +static int v4w_open_videodevice(V4wState *s) +{ + // Initialize COM + CoInitialize(NULL); + + // get a Graph + HRESULT hr=s->m_pGraph.CoCreateInstance(CLSID_FilterGraph); + if(FAILED(hr)) + { + return -1; + } + + // get a CaptureGraphBuilder2 + hr=s->m_pBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder2); + if(FAILED(hr)) + { + return -2; + } + + // connect capture graph builder with the graph + s->m_pBuilder->SetFiltergraph(s->m_pGraph); + + // get mediacontrol so we can start and stop the filter graph + hr=s->m_pGraph.QueryInterface(&(s->m_pControl)); + if(FAILED(hr)) + { + return -3; + } + + +#ifdef _DEBUG + HANDLE m_hLogFile=CreateFile(L"DShowGraphLog.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if(m_hLogFile!=INVALID_HANDLE_VALUE) + { + hr=s->m_pGraph->SetLogFile((DWORD_PTR)m_hLogFile); + /* ASSERT(SUCCEEDED(hr)); */ + } + + //AddGraphToRot(s->m_pGraph, &s->rotregvalue); +#endif + + ICreateDevEnum *pCreateDevEnum = NULL; + IEnumMoniker *pEnumMoniker = NULL; + IMoniker *pMoniker = NULL; + + ULONG nFetched = 0; + + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + IID_ICreateDevEnum, (PVOID *)&pCreateDevEnum); + if(FAILED(hr)) + { + return -4; + } + + hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, + &pEnumMoniker, 0); + if (FAILED(hr) || pEnumMoniker == NULL) { + //printf("no device\n"); + return -5; + } + + pEnumMoniker->Reset(); + + int pos=0; + while(S_OK == pEnumMoniker->Next(1, &pMoniker, &nFetched) ) + { + if (pos>=s->devidx) + break; + pos++; + pMoniker->Release(); + pMoniker=NULL; + } + if(pMoniker==NULL) + { + return -6; + } + + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&s->m_pDeviceFilter ); + if(FAILED(hr)) + { + return -7; + } + + s->m_pGraph->AddFilter(s->m_pDeviceFilter, L"Device Filter"); + + pMoniker->Release(); + pEnumMoniker->Release(); + pCreateDevEnum->Release(); + + if (try_format(s, s->pix_fmt)==0) + s->pix_fmt = s->pix_fmt; + else if (try_format(s,MS_YUV420P)==0) + s->pix_fmt = MS_YUV420P; + else if (try_format(s,MS_YUY2)==0) + s->pix_fmt = MS_YUY2; + else if (try_format(s,MS_YUYV)==0) + s->pix_fmt = MS_YUYV; + else if (try_format(s,MS_UYVY)==0) + s->pix_fmt = MS_UYVY; + else if (try_format(s,MS_RGB24)==0) + s->pix_fmt = MS_RGB24; + else + { + ms_error("Unsupported video pixel format."); + return -8; + } + + if (s->pix_fmt == MS_YUV420P) + ms_message("Driver supports YUV420P, using that format."); + else if (s->pix_fmt == MS_YUY2) + ms_message("Driver supports YUY2 (UYVY), using that format."); + else if (s->pix_fmt == MS_YUYV) + ms_message("Driver supports YUV422, using that format."); + else if (s->pix_fmt == MS_UYVY) + ms_message("Driver supports UYVY, using that format."); + else if (s->pix_fmt == MS_RGB24) + ms_message("Driver supports RGB24, using that format."); + + if (try_format_size(s, s->pix_fmt, s->vsize.width, s->vsize.height)==0) + ms_message("Selected Size: %ix%i.", s->vsize.width, s->vsize.height); + else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H)==0) + ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H); + else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H)==0) + ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H); + else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H)==0) + ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H); + else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H)==0) + ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H); + else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H)==0) + ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H); + else + { + ms_error("No supported size found for format."); + /* size not supported? */ + return -9; + } + + // get DXFilter + s->m_pDXFilter = new CDXFilter(NULL, &hr, FALSE); + if(s->m_pDXFilter==NULL) + { + return -10; + } + s->m_pDXFilter->AddRef(); + + CMediaType mt; + mt.SetType(&MEDIATYPE_Video); + + GUID m = MEDIASUBTYPE_RGB24; + if (s->pix_fmt == MS_YUV420P) + m = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0')); + else if (s->pix_fmt == MS_YUY2) + m = MEDIASUBTYPE_YUY2; + else if (s->pix_fmt == MS_YUYV) + m = MEDIASUBTYPE_YUYV; + else if (s->pix_fmt == MS_UYVY) + m = MEDIASUBTYPE_UYVY; + else if (s->pix_fmt == MS_RGB24) + m = MEDIASUBTYPE_RGB24; + mt.SetSubtype(&m); + + mt.formattype = FORMAT_VideoInfo; + mt.SetTemporalCompression(FALSE); + + VIDEOINFO *pvi = (VIDEOINFO *) + mt.AllocFormatBuffer(sizeof(VIDEOINFO)); + if (NULL == pvi) + return -11; + ZeroMemory(pvi, sizeof(VIDEOINFO)); + + if (s->pix_fmt == MS_YUV420P) + pvi->bmiHeader.biCompression = MAKEFOURCC('I','4','2','0'); + else if (s->pix_fmt == MS_YUY2) + pvi->bmiHeader.biCompression = MAKEFOURCC('Y','U','Y','2'); + else if (s->pix_fmt == MS_YUYV) + pvi->bmiHeader.biCompression = MAKEFOURCC('Y','U','Y','V'); + else if (s->pix_fmt == MS_UYVY) + pvi->bmiHeader.biCompression = MAKEFOURCC('U','Y','V','Y'); + else if (s->pix_fmt == MS_RGB24) + pvi->bmiHeader.biCompression = BI_RGB; + + if (s->pix_fmt == MS_YUV420P) + pvi->bmiHeader.biBitCount = 12; + else if (s->pix_fmt == MS_YUY2) + pvi->bmiHeader.biBitCount = 16; + else if (s->pix_fmt == MS_YUYV) + pvi->bmiHeader.biBitCount = 16; + else if (s->pix_fmt == MS_UYVY) + pvi->bmiHeader.biBitCount = 16; + else if (s->pix_fmt == MS_RGB24) + pvi->bmiHeader.biBitCount = 24; + + pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pvi->bmiHeader.biWidth = s->vsize.width; + pvi->bmiHeader.biHeight = s->vsize.height; + pvi->bmiHeader.biPlanes = 1; + pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader); + pvi->bmiHeader.biClrImportant = 0; + mt.SetSampleSize(pvi->bmiHeader.biSizeImage); + mt.SetFormat((BYTE*)pvi, sizeof(VIDEOINFO)); + + hr = s->m_pDXFilter->SetAcceptedMediaType(&mt); + if(FAILED(hr)) + { + return -12; + } + + hr = s->m_pDXFilter->SetCallback(Callback); + if(FAILED(hr)) + { + return -13; + } + + hr = s->m_pDXFilter->QueryInterface(IID_IBaseFilter, + (LPVOID *)&s->m_pIDXFilter); + if(FAILED(hr)) + { + return -14; + } + + hr = s->m_pGraph->AddFilter(s->m_pIDXFilter, L"DXFilter Filter"); + if(FAILED(hr)) + { + return -15; + } + + + // get null renderer + hr=s->m_pNullRenderer.CoCreateInstance(CLSID_NullRenderer); + if(FAILED(hr)) + { + return -16; + } + if (s->m_pNullRenderer!=NULL) + { + s->m_pGraph->AddFilter(s->m_pNullRenderer, L"Null Renderer"); + } + + hr = s->m_pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, + &MEDIATYPE_Video, s->m_pDeviceFilter, s->m_pIDXFilter, s->m_pNullRenderer); + if (FAILED(hr)) + { + //hr = s->m_pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, + // &MEDIATYPE_Video, s->m_pDeviceFilter, s->m_pIDXFilter, s->m_pNullRenderer); + if (FAILED(hr)) + { + return -17; + } + } + + //m_pDXFilter->SetBufferSamples(TRUE); + + s_callback = s; + hr = s->m_pControl->Run(); + if(FAILED(hr)) + { + return -18; + } + + s->rotregvalue=1; + return 0; +} + +/**************************************************************************** + +FUNCTION: AddGraphToRot. + +DESCRIPTION: + Adds a DirectShow filter graph to the Running Object Table, + allowing GraphEdit to "spy" on a remote filter graph. + +PARAMETERS: + +RETURNS: + . 0 for success, otherwise an error #. + . Standard COM/HRESULT error numbers are returned if a COM/HRESULT error + was encountered. + +****************************************************************************/ +HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) +{ + IMoniker * pMoniker; + IRunningObjectTable *pROT; + WCHAR wsz[128]; + HRESULT hr; + + if (FAILED(GetRunningObjectTable(0, &pROT))) + return E_FAIL; + + wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId()); + wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId()); + + hr = CreateItemMoniker(L"!", wsz, &pMoniker); + if (SUCCEEDED(hr)) + { + hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister); + pMoniker->Release(); + } + + pROT->Release(); + return hr; +} + + +/**************************************************************************** + +FUNCTION: RemoveGraphFromRot. + +DESCRIPTION: + Removes a filter graph from the Running Object Table. + +PARAMETERS: + +****************************************************************************/ +void RemoveGraphFromRot(DWORD pdwRegister) +{ + IRunningObjectTable *pROT; + + if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) + { + pROT->Revoke(pdwRegister); + pROT->Release(); + } +} + +static void v4w_init(MSFilter *f){ + V4wState *s=(V4wState *)ms_new0(V4wState,1); + int idx; + s->devidx=0; + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + //s->pix_fmt=MS_RGB24; + s->pix_fmt=MS_YUV420P; + + s->rotregvalue = 0; + s->m_pGraph=NULL; + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pDXFilter=NULL; + s->m_pIDXFilter=NULL; + s->m_pDeviceFilter=NULL; + + qinit(&s->rq); + for (idx=0;idx<10;idx++) + { + s->mire[idx]=NULL; + } + memset(s->nowebcamimage, 0, sizeof(s->nowebcamimage)); + ms_mutex_init(&s->mutex,NULL); + s->start_time=0; + s->frame_count=-1; + s->fps=15; + + f->data=s; +} + + +static int _v4w_start(V4wState *s, void *arg) +{ + int i; + s->frame_count=-1; + + i = v4w_open_videodevice(s); + + if (s->rotregvalue==0){ + //RemoveGraphFromRot(s->rotregvalue); + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + s_callback = NULL; + flushq(&s->rq,0); + ms_message("v4w: graph not started (err=%i)", i); + s->rotregvalue=0; + s->pix_fmt = MS_YUV420P; + } + return i; +} + +static int _v4w_stop(V4wState *s, void *arg){ + s->frame_count=-1; + if (s->rotregvalue>0){ + HRESULT hr = s->m_pControl->Stop(); + if(FAILED(hr)) + { + ms_message("v4w: could not stop graph"); + } + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + //RemoveGraphFromRot(s->rotregvalue); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + s_callback = NULL; + flushq(&s->rq,0); + ms_message("v4w: graph destroyed"); + s->rotregvalue=0; + } + return 0; +} + + +static int v4w_start(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + _v4w_start(s, NULL); + return 0; +} + +static int v4w_stop(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + _v4w_stop(s, NULL); + return 0; +} + + +static void v4w_uninit(MSFilter *f){ + V4wState *s=(V4wState*)f->data; + int idx; + flushq(&s->rq,0); + ms_mutex_destroy(&s->mutex); + for (idx=0;idx<10;idx++) + { + if (s->mire[idx]==NULL) + break; + freemsg(s->mire[idx]); + } + if (s->rotregvalue>0){ + HRESULT hr = s->m_pControl->Stop(); + if(FAILED(hr)) + { + ms_message("v4w: could not stop graph"); + } + if (s->m_pNullRenderer!=NULL) + s->m_pGraph->RemoveFilter(s->m_pNullRenderer); + if (s->m_pIDXFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pIDXFilter); + if (s->m_pDeviceFilter!=NULL) + s->m_pGraph->RemoveFilter(s->m_pDeviceFilter); + //RemoveGraphFromRot(s->rotregvalue); + s->m_pBuilder=NULL; + s->m_pControl=NULL; + s->m_pIDXFilter=NULL; + if (s->m_pDXFilter!=NULL) + s->m_pDXFilter->Release(); + s->m_pDXFilter=NULL; + s->m_pGraph=NULL; + s->m_pNullRenderer=NULL; + s->m_pDeviceFilter=NULL; + CoUninitialize(); + s_callback = NULL; + flushq(&s->rq,0); + ms_message("v4w: graph destroyed"); + s->rotregvalue=0; + } + ms_free(s); +} + +static mblk_t * v4w_make_nowebcam(V4wState *s){ +#if defined(_WIN32_WCE) + return NULL; +#else + int idx; + int count; + if(s->mire[0]==NULL && s->frame_ind==0 && s->nowebcamimage[0] != '\0') + { + s->mire[0] = ms_load_jpeg_as_yuv(s->nowebcamimage,&s->vsize); + } + if (s->mire[0]==NULL && s->frame_ind==0){ + /* load several images to fake a movie */ + for (idx=0;idx<10;idx++) + { + s->mire[idx]=ms_load_nowebcam(&s->vsize, idx); + if (s->mire[idx]==NULL) + break; + } + if (idx==0) + s->mire[0]=ms_load_nowebcam(&s->vsize, -1); + } + for (count=0;count<10;count++) + { + if (s->mire[count]==NULL) + break; + } + + s->frame_ind++; + if (count==0) + return NULL; + + idx = s->frame_ind%count; + if (s->mire[idx]!=NULL) + return s->mire[idx]; + return s->mire[0]; +#endif +} + +static void v4w_preprocess(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + s->running=TRUE; + if (s->rotregvalue==0) + s->fps=1; +} + +static void v4w_postprocess(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + s->running=FALSE; + s->start_time=0; + s->frame_count=-1; + flushq(&s->rq,0); +} + +static void v4w_process(MSFilter * obj){ + V4wState *s=(V4wState*)obj->data; + mblk_t *m; + uint32_t timestamp; + int cur_frame; + + if (s->frame_count==-1){ + s->start_time=obj->ticker->time; + s->frame_count=0; + } + + cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame>s->frame_count){ + mblk_t *om=NULL; + ms_mutex_lock(&s->mutex); + /*keep the most recent frame if several frames have been captured */ + if (s->rotregvalue!=0){ + while((m=getq(&s->rq))!=NULL){ + if (om!=NULL) freemsg(om); + om=m; + } + }else { + mblk_t *nowebcam = v4w_make_nowebcam(s); + if (nowebcam!=NULL) + om=dupmsg(nowebcam); + } + ms_mutex_unlock(&s->mutex); + if (om!=NULL){ + timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/ + mblk_set_timestamp_info(om,timestamp); + ms_queue_put(obj->outputs[0],om); + /*ms_message("picture sent");*/ + } + s->frame_count++; + } +} + + + +static int v4w_set_fps(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->fps=*((float*)arg); + s->frame_count=-1; /* reset counter used for fps */ + return 0; +} + +static int v4w_get_pix_fmt(MSFilter *f,void *arg){ + V4wState *s=(V4wState*)f->data; + *((MSPixFmt*)arg) = (MSPixFmt)s->pix_fmt; + return 0; +} + +static int v4w_set_vsize(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->vsize=*((MSVideoSize*)arg); + return 0; +} + +static int v4w_get_vsize(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + MSVideoSize *vs=(MSVideoSize*)arg; + vs->width=s->vsize.width; + vs->height=s->vsize.height; + return 0; +} + +static int v4w_set_device(MSFilter *f, void *arg){ + V4wState *s=(V4wState*)f->data; + s->devidx=*((int*)arg); + return 0; +} + +static int v4w_set_image(MSFilter *f, void *arg){ + int idx; + V4wState *s=(V4wState*)f->data; + char *image = (char *)arg; + ms_mutex_lock(&s->mutex); + if (image!=NULL && image[0]!='\0') + snprintf(s->nowebcamimage, sizeof(s->nowebcamimage), "%s", image); + else + s->nowebcamimage[0] = '\0'; + for (idx=0;idx<10;idx++) + { + if (s->mire[idx]==NULL) + break; + freemsg(s->mire[idx]); + s->mire[idx]=NULL; + } + s->frame_ind=0; + ms_mutex_unlock(&s->mutex); + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , v4w_set_fps }, + { MS_FILTER_GET_PIX_FMT , v4w_get_pix_fmt }, + { MS_FILTER_SET_VIDEO_SIZE, v4w_set_vsize }, + { MS_FILTER_GET_VIDEO_SIZE, v4w_get_vsize }, + { MS_V4L_START , v4w_start }, + { MS_V4L_STOP , v4w_stop }, + { MS_V4L_SET_DEVICE , v4w_set_device }, + { MS_V4L_SET_IMAGE , v4w_set_image }, + { 0 , NULL } +}; + +#ifdef _MSC_VER + +MSFilterDesc ms_v4w_desc={ + MS_V4L_ID, + "MSV4w", + "A video4windows compatible source filter to stream pictures.", + MS_FILTER_OTHER, + NULL, + 0, + 1, + v4w_init, + v4w_preprocess, + v4w_process, + v4w_postprocess, + v4w_uninit, + methods +}; + +#else + +MSFilterDesc ms_v4w_desc={ + .id=MS_V4L_ID, + .name="MSV4w", + .text="A video4windows compatible source filter to stream pictures.", + .ninputs=0, + .noutputs=1, + .category=MS_FILTER_OTHER, + .init=v4w_init, + .preprocess=v4w_preprocess, + .process=v4w_process, + .postprocess=v4w_postprocess, + .uninit=v4w_uninit, + .methods=methods +}; + +#endif + +MS_FILTER_DESC_EXPORT(ms_v4w_desc) + +static MSFilter *vfw_create_reader(MSWebCam *obj){ + return ms_filter_new_from_desc(&ms_v4w_desc); +} + +static void vfw_detect(MSWebCamManager *obj); + +static void vfw_cam_init(MSWebCam *cam){ + cam->name=ms_strdup("dx0"); +} + +MSWebCamDesc ms_v4w_cam_desc={ + "DirectX Video Grabber", + &vfw_detect, + &vfw_cam_init, + &vfw_create_reader, + NULL +}; + +static void vfw_detect(MSWebCamManager *obj){ + MSWebCam *cam=ms_web_cam_new(&ms_v4w_cam_desc); + ms_web_cam_manager_add_cam(obj,cam); +} diff --git a/linphone/mediastreamer2/tests/.cvsignore b/linphone/mediastreamer2/tests/.cvsignore new file mode 100644 index 000000000..9a8edd6cc --- /dev/null +++ b/linphone/mediastreamer2/tests/.cvsignore @@ -0,0 +1,8 @@ +Makefile.in +Makefile +.deps +.libs +echo +mediastream +ring +videodisplay diff --git a/linphone/mediastreamer2/tests/Makefile.am b/linphone/mediastreamer2/tests/Makefile.am new file mode 100644 index 000000000..ee8638e46 --- /dev/null +++ b/linphone/mediastreamer2/tests/Makefile.am @@ -0,0 +1,32 @@ +noinst_PROGRAMS=echo ring mtudiscover + +if BUILD_VIDEO +noinst_PROGRAMS+=videodisplay +endif + +echo_SOURCES=echo.c +ring_SOURCES=ring.c +videodisplay_SOURCES=videodisplay.c +mtudiscover_SOURCES=mtudiscover.c + +libexec_PROGRAMS=mediastream + +mediastream_SOURCES=mediastream.c + +#libquickstream.la would be enough, but to workaround a bug of libtool when +#cross compiling we need to add all the dependencies. +LDADD= $(top_builddir)/src/libmediastreamer.la \ + $(ORTP_LIBS) \ + $(ALSA_LIBS) \ + $(ARTS_LIBS) \ + $(SPEEX_LIBS) \ + $(GSM_LIBS) \ + $(THEORA_LIBS) \ + $(FFMPEG_LIBS) + + + +INCLUDES=-I$(top_srcdir)/include/ + +AM_CFLAGS=-I$(top_srcdir) $(ORTP_CFLAGS) $(STRICT_OPTIONS) $(VIDEO_CFLAGS) +AM_LDFLAGS=-rdynamic diff --git a/linphone/mediastreamer2/tests/echo.c b/linphone/mediastreamer2/tests/echo.c new file mode 100644 index 000000000..b6cf6411b --- /dev/null +++ b/linphone/mediastreamer2/tests/echo.c @@ -0,0 +1,74 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msticker.h" + +#include + +static int run=1; + +static void stop(int signum){ + run=0; +} + +int main(int argc, char *argv[]){ + MSFilter *f1,*f2; + MSSndCard *card; + MSTicker *ticker; + char *card_id=NULL; + ortp_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + ms_init(); + + signal(SIGINT,stop); + + if (argc>1) + card_id=argv[1]; + + if (card_id!=NULL) + { + card=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),card_id); +#ifdef __linux + if (card==NULL) + card = ms_alsa_card_new_custom(card_id, card_id); +#endif + } + else card=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); + + if (card==NULL){ + ms_error("No card."); + return -1; + } + f1=ms_snd_card_create_reader(card); + f2=ms_snd_card_create_writer(card); + ticker=ms_ticker_new(); + ms_filter_link(f1,0,f2,0); + ms_ticker_attach(ticker,f1); + while(run) + sleep(1); + ms_ticker_detach(ticker,f1); + ms_ticker_destroy(ticker); + ms_filter_unlink(f1,0,f2,0); + ms_filter_destroy(f1); + ms_filter_destroy(f2); + return 0; +} diff --git a/linphone/mediastreamer2/tests/mediastream.c b/linphone/mediastreamer2/tests/mediastream.c new file mode 100644 index 000000000..17ebef068 --- /dev/null +++ b/linphone/mediastreamer2/tests/mediastream.c @@ -0,0 +1,266 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mediastream.h" +#ifdef VIDEO_ENABLED +#include "mediastreamer2/msv4l.h" +#endif + +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include +#include + +static int cond=1; + +static void stop_handler(int signum) +{ + cond--; + if (cond<0) exit(-1); +} + +static bool_t parse_addr(const char *addr, char *ip, int len, int *port) +{ + char *semicolon=NULL; + int iplen; + int slen; + char *p; + + *port=0; + semicolon=strchr(addr,':'); + for (p=addr+strlen(addr)-1;p>addr;p--){ + if (*p==':') { + semicolon=p; + break; + } + } + if (semicolon==NULL) return FALSE; + iplen=semicolon-addr; + slen=MIN(iplen,len-1); + strncpy(ip,addr,slen); + ip[slen]='\0'; + *port=atoi(semicolon+1); + return TRUE; +} + +static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len){ + char str[256]; + int len=MIN(sizeof(str)-1,content_len); + strncpy(str,content,len); + str[len]='\0'; + switch(t){ + case RTCP_SDES_CNAME: + ms_message("Found CNAME=%s",str); + break; + case RTCP_SDES_TOOL: + ms_message("Found TOOL=%s",str); + break; + case RTCP_SDES_NOTE: + ms_message("Found NOTE=%s",str); + break; + default: + ms_message("Unhandled SDES item (%s)",str); + } +} + +static void parse_rtcp(mblk_t *m){ + do{ + if (rtcp_is_RR(m)){ + ms_message("Receiving RTCP RR"); + }else if (rtcp_is_SR(m)){ + ms_message("Receiving RTCP SR"); + }else if (rtcp_is_SDES(m)){ + ms_message("Receiving RTCP SDES"); + rtcp_sdes_parse(m,display_items,NULL); + }else { + ms_message("Receiving unhandled RTCP message"); + } + }while(rtcp_next_packet(m)); +} + +static void parse_events(OrtpEvQueue *q){ + OrtpEvent *ev; + while((ev=ortp_ev_queue_get(q))!=NULL){ + OrtpEventData *d=ortp_event_get_data(ev); + switch(ortp_event_get_type(ev)){ + case ORTP_EVENT_RTCP_PACKET_RECEIVED: + parse_rtcp(d->packet); + break; + default: + ms_warning("Unhandled ortp event."); + } + ortp_event_destroy(ev); + } +} + +const char *usage="mediastream --local --remote --payload \n" + "[ --fmtp ]\n" + "[ --jitter ]\n"; +static void run_media_streams(int localport, const char *remote_ip, int remoteport, int payload, const char *fmtp, int jitter, bool_t ec, int bitrate); + + +int main(int argc, char * argv[]) +{ + int i; + int localport=0,remoteport=0,payload=0; + char ip[50]; + const char *fmtp=NULL; + int jitter=50; + int bitrate=0; + bool_t ec=FALSE; + /*create the rtp session */ + ortp_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015); + rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb); + rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb); + rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc); +#ifdef VIDEO_ENABLED + rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998); + rtp_profile_set_payload(&av_profile,97,&payload_type_theora); + rtp_profile_set_payload(&av_profile,99,&payload_type_mp4v); + rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow); + rtp_profile_set_payload(&av_profile,102,&payload_type_h264); +#endif + if (argc<4) { + printf(usage); + return -1; + } + for (i=1;i0) pt->normal_bitrate=bitrate; + + if (pt->type!=PAYLOAD_VIDEO){ + printf("Starting audio stream.\n"); + audio=audio_stream_start(profile,localport,remote_ip,remoteport,payload,jitter, ec); + if (audio) session=audio->session; + }else{ +#ifdef VIDEO_ENABLED + printf("Starting video stream.\n"); + video=video_stream_new(localport, ms_is_ipv6(remote_ip)); + + video_stream_start(video,profile, + remote_ip, + remoteport,remoteport+1, + payload, + jitter, + ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get())); + session=video->session; +#else + printf("Error: video support not compiled.\n"); +#endif + } + rtp_session_register_event_queue(session,q); + while(cond) + { + int n; + for(n=0;n<100;++n){ +#ifdef WIN32 + MSG msg; + Sleep(10); + while (PeekMessage(&msg, NULL, 0, 0,1)){ + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#else + struct timespec ts; + ts.tv_sec=0; + ts.tv_nsec=10000000; + nanosleep(&ts,NULL); +#endif +#if defined(VIDEO_ENABLED) + if (video) video_stream_iterate(video); +#endif + } + ortp_global_stats_display(); + if (session){ + printf("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n", + rtp_session_compute_recv_bandwidth(session)*1e-3, + rtp_session_compute_send_bandwidth(session)*1e-3); + parse_events(q); + } + } + + printf("stoping all...\n"); + + if (audio) audio_stream_stop(audio); +#ifdef VIDEO_ENABLED + if (video) video_stream_stop(video); +#endif + ortp_ev_queue_destroy(q); + rtp_profile_destroy(profile); +} diff --git a/linphone/mediastreamer2/tests/mtudiscover.c b/linphone/mediastreamer2/tests/mtudiscover.c new file mode 100644 index 000000000..92f2285ea --- /dev/null +++ b/linphone/mediastreamer2/tests/mtudiscover.c @@ -0,0 +1,33 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "mediastreamer2/mscommon.h" + +int main(int argc, char *argv[]){ + + ms_init(); + if (argc<2){ + ms_error("Usage: mtudiscover [host]"); + return -1; + } + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + printf("result: %i \n",ms_discover_mtu(argv[1])); + return 0; +} diff --git a/linphone/mediastreamer2/tests/ring.c b/linphone/mediastreamer2/tests/ring.c new file mode 100644 index 000000000..4cbcd27d8 --- /dev/null +++ b/linphone/mediastreamer2/tests/ring.c @@ -0,0 +1,52 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "mediastreamer-config.h" +#endif + +#include "mediastreamer2/mediastream.h" + +int main(int argc, char *argv[]){ + RingStream *r; + const char *file; + MSSndCard *sc; + const char * card_id=NULL; + + ortp_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + ms_init(); + if (argc>1){ + file=argv[1]; + }else file="/usr/share/sounds/linphone/rings/oldphone.wav"; + if (argc>2){ + card_id=argv[2]; + } + + sc=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),card_id); +#ifdef __linux + if (sc==NULL) + sc = ms_alsa_card_new_custom(card_id, card_id); +#endif + + r=ring_start(file,2000,sc); + sleep(10); + ring_stop(r); + return 0; +} diff --git a/linphone/mediastreamer2/tests/videodisplay.c b/linphone/mediastreamer2/tests/videodisplay.c new file mode 100644 index 000000000..9d187ac92 --- /dev/null +++ b/linphone/mediastreamer2/tests/videodisplay.c @@ -0,0 +1,116 @@ +/* +mediastreamer2 library - modular sound and video processing and streaming +Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/msvideoout.h" +#include "mediastreamer2/msv4l.h" + +int main(int argc, char *argv[]){ + VideoStream *vs; + MSWebCam *cam; + int i; + ortp_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + ms_init(); + cam=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get()); + /* this is to test the sequence start/stop */ + for(i=0;i<1;++i){ + int n; + vs=video_preview_start(cam); + + for(n=0;n<1000;++n){ +#ifdef WIN32 + MSG msg; + Sleep(100); + while (PeekMessage(&msg, NULL, 0, 0,1)){ + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#else + struct timespec ts; + ts.tv_sec=0; + ts.tv_nsec=10000000; + nanosleep(&ts,NULL); + + if (vs) video_stream_iterate(vs); +#endif + +#if 0 /* test code */ + if (n==300) + { + ms_filter_call_method_noarg (vs->source, MS_V4L_STOP); + } + if (n==400) + { + ms_ticker_detach (vs->ticker, vs->source); + + vs->tee = ms_filter_new(MS_TEE_ID); + + ms_filter_unlink(vs->pixconv,0, vs->output,0); + + ms_filter_link(vs->pixconv,0,vs->tee,0); + ms_filter_link(vs->tee,0,vs->output,0); + ms_filter_link(vs->tee,1,vs->output,1); + + //ms_filter_unlink(vs->tee,0,vs->output,0); + ms_ticker_attach (vs->ticker, vs->source); + + } + if (n==500) + { + int corner=1; + ms_filter_call_method(vs->output,MS_VIDEO_OUT_SET_CORNER,&corner); + } + if (n==600) + { + int corner=2; + ms_filter_call_method(vs->output,MS_VIDEO_OUT_SET_CORNER,&corner); + } + if (n==700) + { + int corner=3; + ms_filter_call_method(vs->output,MS_VIDEO_OUT_SET_CORNER,&corner); + } + if (n==800) + { + int corner=-1; + ms_filter_call_method(vs->output,MS_VIDEO_OUT_SET_CORNER,&corner); + } + if (n==900) + { + ms_ticker_detach (vs->ticker, vs->source); + + ms_filter_unlink(vs->pixconv,0,vs->tee,0); + ms_filter_unlink(vs->tee,0,vs->output,0); + ms_filter_unlink(vs->tee,1,vs->output,1); + ms_filter_destroy(vs->tee); + vs->tee=NULL; + + ms_filter_link(vs->pixconv,0, vs->output,0); + + + //ms_filter_unlink(vs->tee,0,vs->output,0); + ms_ticker_attach (vs->ticker, vs->source); + } +#endif + } + video_preview_stop(vs); + } + return 0; +} diff --git a/linphone/oRTP/.cvsignore b/linphone/oRTP/.cvsignore new file mode 100644 index 000000000..8babbdc96 --- /dev/null +++ b/linphone/oRTP/.cvsignore @@ -0,0 +1,23 @@ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.guess +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +ortp-config.h +ortp-config.h.in +ortp.defs +ortp.pc +ortp.spec +stamp-h1 +doc +ortp.doxygen +.settings diff --git a/linphone/oRTP/AUTHORS b/linphone/oRTP/AUTHORS new file mode 100644 index 000000000..6e305d120 --- /dev/null +++ b/linphone/oRTP/AUTHORS @@ -0,0 +1,4 @@ +Simon MORLAT (simon dot morlat at linphone dot org) is the author the oRTP library. + + +Lovadina Nicola < lovadina dot nicola dot 10272 at unimo dot it > worked on RTCP support. diff --git a/linphone/oRTP/COPYING b/linphone/oRTP/COPYING new file mode 100644 index 000000000..b1e3f5a26 --- /dev/null +++ b/linphone/oRTP/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/linphone/oRTP/ChangeLog b/linphone/oRTP/ChangeLog new file mode 100644 index 000000000..8276cdffa --- /dev/null +++ b/linphone/oRTP/ChangeLog @@ -0,0 +1,153 @@ +2007-07-26 Francois-Xavier Kowalski + + * pkg.list: 1.3 + Do not run makewhatis when installing EPM-generated package. + +2007-04-19 Francois-Xavier Kowalski + + * ortp.spec.in (Requires): 1.4 + Adapt to new documentation generation change from gtk-doc to + Doxygen. + + * Makefile.am (docdir): 1.27 + automake's docdir is not always defined & is generally not + package specific, so we manually define docdir & pkgdocdir. + +2007-03-01 Francois-Xavier Kowalski + + * include/ortp/payloadtype.h: 1.28 + Encompass every declaration (whether lvalue or not) under extern + "C". + +2007-01-18 Francois-Xavier Kowalski + + * oRTP/Makefile.am: 1.24 + Fix RPM package generattion to cope with + + +2006-10-24 Francois-Xavier 'FiX' KOWALSKI + + * include/ortp/port.h: 1.21 + * src/scheduler.h (ortp_get_scheduler): 1.13 + Disable some Intel C/C++ warnings to build with icc. + + * include/ortp/stun_udp.h (__STUN_UDP_H__): 1.6 + * include/ortp/stun.h: 1.6 + Use + +2006-07-10 Francois-Xavier 'FiX' KOWALSKI + + * configure.ac: 1.89 + * gtk-doc.make (dist-check-gtkdoc): 1.1 + Non-fatal but incomplete "make dist" when gtk-doc is not + installed. + +2006-07-07 Francois-Xavier 'FiX' KOWALSKI + + * src/avprofile.c (NORMAL_BITRATE): 1.27 + Use ISO C/99 tagged struct syntax rather than GCC's legacy one. + +2006-07-07 Francois-Xavier Kowalski + + * src/rtpsession.c (RTP_SEQ_IS_GREATER): 1.132 + Fix comment content (using <>) that breaks gtkdoc SGML + generation. + + * include/ortp/event.h: 1.3 + OrtpEventData cannot be a type a s struct at the same time. + + * ortp.spec.in (Requires): 1.2 + Drop glib option + + * gtk-doc.make: + * docs/Makefile.am (#DOC_MAIN_SGML_FILE): 1.7 + * Makefile.am + Use slightly modified gtkdocize. + + * ortp.spec.in (Requires): 1.2 + Force build of gtk-doc, as the default choice that comes with + GTK_DOC_CHECK m4 macro is "no". + +2006-07-06 Francois-Xavier Kowalski + + * src/payloadtype.c (rtp_profile_destroy): 1.20 + avoid double-free + + * configure.ac: 1.88 + ortp-0.10.1.1 + +Friday March 10 2006 : ortp-0.9.1 + - fix package name (was 0.9.0.) + +Wednesday March 8 2006 : ortp-0.9.0 + - a lot of cleanups, glib dropped, win32 port reactivated + +Tuesday December 20 2005 : ortp-0.8.1 + - change session's clockrate dependant parameters upon payload type changed events at socket level + - rtp_session_set_recv_buf_size() added. + - bugfix in rtp_session_set_remote_addr() + - memory leak fixed in rtp_profile_destroy() + +Wednesday December 07 2005: ortp-0.8.0 + - make package modifications + - make rpm added + - add support for different payload types for incoming and outgoing stream (which breaks api compatibility) + - prefix all PayloadType with payload_type_* to avoid naming conflicts + +Wednesday August 24 2005: ortp-0.7.1 + - added patch for pkgconfig support from Jean-Philippe Barrette-LaPierre + +Monday August 8 2005: ortp-0.7.1pre5 + - adaptive jitter buffer improvements + - timestamp compensated packets returned by rtp_session_recvm_with_ts + - new payload definitions. + +Tuesday August 2 2005: ortp-0.7.1pre4 + - adaptive jitter buffer cleanups. + - hton24 utility function added for RTCP + +Tuesday July 4 2005: ortp-0.7.1pre3 + - improve automatic jitter buffer: no more closed-loop; just estimation. + - merge patch for multicast from Samuel Thibault + - merge patch for parsing of rtcp packets from Nicola Baldo + - add static payload definitions for g723.1 and g729. + +Wednesday November 17 2004: ortp-0.7.0 series starts + - add automatic jitter buffer: + * compensate clock slides + * estimate the jitter and sets the minimum jitter compensation delay accordingly + - posix timer simplified + - less system calls: use non blocking recv() and don't use select() or poll() + - add new functions for optimized packet sending + - recv() and send() are always made within the rtp_session_recv..() and rtp_session_send..() + functions. That means that scheduled non blocking mode does no more work as it worked before, ie + that packet will be sent immediately rather than being sent on time by the scheduler as it was before. + - HPUX kernel target removed. + - scheduler always built. + +Tuesday August 12 2003 : ortp-0.6.3 + - some improvements by Aymeric Moizard for Win32 build + - some bug fixes concerning ipv6 support. + +Thursday August 7 2003 : ortp-0.6.2 + - just some minor improvements for using oRTP in a C++ environment. + +Wednesday January 8 2003: ortp-0.6.0 + - many bug fixes by Telisma: the most important bug concerned the windows port. + - some new functionnalities concerning the RTP profiles and payload management. + - ported to glib-2.0 . + +Monday September 23 2002: ortp-0.5.0 + - ortp has been ported to the Microsoft Windows OS (version 2000 and later) by Eloquant + (http://www.eloquant.com) + - some bug fixes and improvements of the windows port have been made by Telisma + (http://www.telisma.com) + +Wednesday June 5 2002: ortp-0.4.4 + - Some crashing bugs fixed. + +Wednesday May 15 2002: ortp-0.4.3 + - Install include files properly. + +Tuesday May 7 2002: ortp-0.4.2 + - First official and public release of oRTP. diff --git a/linphone/oRTP/INSTALL b/linphone/oRTP/INSTALL new file mode 100644 index 000000000..54caf7c19 --- /dev/null +++ b/linphone/oRTP/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/linphone/oRTP/Makefile.am b/linphone/oRTP/Makefile.am new file mode 100644 index 000000000..498efe1ab --- /dev/null +++ b/linphone/oRTP/Makefile.am @@ -0,0 +1,88 @@ +# linphone/oRTP/Makefile.am -- + +EXTRA_DIST = oRTP.prj ortp-config.h.in TODO pkg.list autogen.sh ortp.pc.in ortp.spec.in ortp.spec ortp.doxygen + +SUBDIRS=src build include + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = ortp.pc + + +#html doc +if HAVE_DOXYGEN + +# doxdir & pkgdocdir are not always defined by automake +docdir=$(datadir)/doc +pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION) +doc_htmldir=$(pkgdocdir)/html + +doc_html_DATA = $(top_builddir)/doc/html/html.tar + +$(doc_html_DATA): $(top_builddir)/doc/html/index.html + cd $( + TAR_OPTIONS=--wildcards rpmbuild -ta --clean --rmsource --rmspec $(PACKAGE)-$(VERSION).tar.gz + +# `make package' + +if WITH_EPM + +.PHONY: package + +PKG_NAME = $(PACKAGE)-$(VERSION)-$(RELEASE) +BUILDROOT = $(shell pwd)/epm-install + +package: $(srcdir)/pkg.list $(srcdir)/configure + -rm -rf pkg $(BUILDROOT) $(PKG_NAME).* + $(MAKE) install DESTDIR=$(BUILDROOT) + $(MKEPMLIST) -u $(SYS_USER) -g $(SYS_GROUP) --prefix $(prefix) \ + $(BUILDROOT)/$(prefix) > files.list + $(EPM) -vv -f native -g -n -a $(ARCH) --keep-files --output-dir pkg \ + srcdir=$(srcdir) \ + top_srcdir=$(top_srcdir) \ + top_builddir=$(top_builddir) \ + PACKAGE=$(PACKAGE) \ + SUMMARY="$(SUMMARY)" \ + VERSION=$(ORTP_PKGCONFIG_VERSION) \ + RELEASE=$(RELEASE) \ + LICENSE="$(LICENSE)" \ + VENDOR="$(VENDOR)" \ + PACKAGER="$(PACKAGER)" \ + $(PACKAGE) $(srcdir)/pkg.list + mv -f pkg/$(PACKAGE)-$(ORTP_PKGCONFIG_VERSION)-$(RELEASE).$(EPM_PKG_EXT) $(PKG_NAME).$(ARCH).$(EPM_PKG_EXT) + +clean-local: + rm -rf pkg $(BUILDROOT) + rm -f files.list + rm -rf doc + +endif WITH_EPM + +distclean-local: + -rm -f ortp.defs + +all-local: ortp.spec + +ortp.spec: ortp.spec.in + diff --git a/linphone/oRTP/NEWS b/linphone/oRTP/NEWS new file mode 100644 index 000000000..4d1f4c413 --- /dev/null +++ b/linphone/oRTP/NEWS @@ -0,0 +1,43 @@ +DATE ortp-0.15.0 + - telephone event detection bugfix + - reduce number of memory allocation: !! attention here ABI/API change !! + If you are using mp=rtp_session_recvm_with_ts(), the payload data is no more pointed by mp->b_cont->b_rptr. + Instead you can use the following to skip the header: + rtp_get_payload(mp,mp->b_rptr); + +March 14, 2007: ortp-0.14.3 + - new ortp_set_memory_functions() method + - jitter buffer bugfixes, simplification and improvements + +July 27, 2007: ortp-0.14.0 + - a few optimisations + - support for number of channels in PayloadType (interface changed !) + - srtp optional support (using libsrtp from http://srtp.sf.net) + +April, 11 2007: ortp-0.13.1: + - do not recv rtcp packets from rtp_session_sendm_with_ts() when session is not send-only. + - removed gtk-doc, using doxygen instead. + - minor patches + +January, 23 2007: ortp-0.13.0 + - add support for a pluggable transport layer + - enables use of different RtpProfile for send and recv directions + - fix RTCP memleak + - new telephone-event types added. + +November, 9 2006: ortp-0.12.0 + - fix statistics + - jitter buffer accuracy improved + - enable 0 ms jitter buffer (implies permissive dequeuing of packets) + - enable optional connected mode: the udp socket is connect()ed so only + packets coming from the connected destination are received. + +August, 22 2006: ortp-0.11.0 + - added rtp_session_set_dscp, rtp_session_send_rtcp_APP + - fixed statistics little bugs. + +May, 30 2006: ortp-0.10.0 + - new RTCP parser + - new event api + - stun helper routines + - permissive algorithm for video packet enqueueing diff --git a/linphone/oRTP/README b/linphone/oRTP/README new file mode 100644 index 000000000..be6a82033 --- /dev/null +++ b/linphone/oRTP/README @@ -0,0 +1,58 @@ +What is it ? +************ + +oRTP is a LGPL licensed C library implementing the RTP protocol (rfc3550). It is available +for most unix clones (primilarly Linux and HP-UX), and Microsoft Windows. + +What are the build prequisites ? +******************************** +libc library and header files. + +How do you I test ? +******************* + +There are shorts and easy to understand programs given with the library. There are good example +to understand how to use oRTP api. +- rtpsend : sends a stream from a file on disk. +- rtprecv : receives a stream and writes it to disk. +- mrtpsend: sends multiple streams from a file on disk to a range of remote port. +- mrtprecv: receives mutiple streams on a range of local ports and writes them on disk. + + +Is there some documentation ? +***************************** + +See the doxygen generated API documentation in docs/html. Program examples are a very good +starting point. + + +What are the current features ? +****************************** + - works with ipv6 + - packet scheduler + - adaptive jitter compensation + - automatic sending of RTCP SR or RR coumpounded with a SDES + - RTCP parser API + + +What are the planned features ? +******************************* + - multi-endpoint rtp sessions. + + +In which application oRTP is being used ? +***************************************** + - linphone (http://www.linphone.org) was the first. + - the OCMP platform (a Hewlett Packard product). + +How to compile my program using ortp ? +************************************** +gcc -o myprogram `pkg-config --cflags ortp` myprogram.c \ + `pkg-config --libs ortp` + + +What about Windows port ? +************************* +There are instructions and Microsoft Visual C++ project files in build/win32native/oRTP. + + diff --git a/linphone/oRTP/TODO b/linphone/oRTP/TODO new file mode 100644 index 000000000..ade9114db --- /dev/null +++ b/linphone/oRTP/TODO @@ -0,0 +1,2 @@ +* make statistics thread-safe. +* add a rtp_stats_display() func to display rtp_stats_t properly. diff --git a/linphone/oRTP/autogen.sh b/linphone/oRTP/autogen.sh new file mode 100755 index 000000000..203deb262 --- /dev/null +++ b/linphone/oRTP/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh +AM_VERSION="1.9" +if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then + # automake-1.9 (recommended) is not available on Fedora 8 + AUTOMAKE=automake + ACLOCAL=aclocal +else + ACLOCAL=aclocal-${AM_VERSION} + AUTOMAKE=automake-${AM_VERSION} +fi + +set -x +rm -rf config.cache autom4te.cache +$ACLOCAL +autoheader +$AUTOMAKE --add-missing --copy +libtoolize --copy --force +autoconf diff --git a/linphone/oRTP/build/.cvsignore b/linphone/oRTP/build/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/oRTP/build/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/oRTP/build/Makefile.am b/linphone/oRTP/build/Makefile.am new file mode 100644 index 000000000..2a2af13b6 --- /dev/null +++ b/linphone/oRTP/build/Makefile.am @@ -0,0 +1 @@ +SUBDIRS= win32native wince diff --git a/linphone/oRTP/build/win32/.cvsignore b/linphone/oRTP/build/win32/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/oRTP/build/win32/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/oRTP/build/win32native/.cvsignore b/linphone/oRTP/build/win32native/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/oRTP/build/win32native/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/oRTP/build/win32native/Makefile.am b/linphone/oRTP/build/win32native/Makefile.am new file mode 100644 index 000000000..dc2e14b05 --- /dev/null +++ b/linphone/oRTP/build/win32native/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=oRTP.vcproj ortp.def ortp.dev + diff --git a/linphone/oRTP/build/win32native/oRTP.vcproj b/linphone/oRTP/build/win32native/oRTP.vcproj new file mode 100644 index 000000000..f5da64506 --- /dev/null +++ b/linphone/oRTP/build/win32native/oRTP.vcproj @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/oRTP/build/win32native/ortp-dll.dev b/linphone/oRTP/build/win32native/ortp-dll.dev new file mode 100755 index 000000000..336b4e44f --- /dev/null +++ b/linphone/oRTP/build/win32native/ortp-dll.dev @@ -0,0 +1,473 @@ +[Project] +FileName=ortp-dll.dev +Name=ortp +UnitCount=41 +Type=2 +Ver=3 +IsCpp=1 +Folders= +CommandLine= +CompilerSettings=00000000000100000000b0 +PchHead=-1 +PchSource=-1 +ProfilesCount=1 +ProfileIndex=0 + +[Unit1] +FileName=..\..\include\ortp\telephonyevents.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\..\include\ortp\ortp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\..\include\ortp\payloadtype.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\..\include\ortp\port.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\..\include\ortp\rtcp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\include\ortp\rtp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\..\include\ortp\rtpsignaltable.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\include\ortp\sessionset.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\include\ortp\str_utils.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\..\src\avprofile.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\..\src\jitterctl.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\..\src\jitterctl.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\..\src\ortp.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\..\src\payloadtype.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\..\src\port.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\..\src\posixtimer.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\..\src\rtcp.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\..\src\rtcpparse.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\..\src\rtpparse.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\..\src\rtpsession.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\..\src\rtpsignaltable.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\..\src\rtptimer.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\..\src\rtptimer.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\..\src\scheduler.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\..\src\scheduler.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\..\src\sessionset.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\..\src\str_utils.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\..\src\telephonyevents.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\..\src\utils.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\..\src\utils.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\..\src\dll_entry.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\..\src\ortp-config-win32.h +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\..\src\event.c +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\..\include\ortp\event.h +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\..\src\stun.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 +UnitCount=40 + +[Unit37] +FileName=..\..\src\stun_udp.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\..\src\rtpsession_inet.c +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= +CompileCpp=0 + +[Unit7] +FileName=..\..\include\ortp\rtpsession.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\..\src\rtpsession_priv.h +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\..\include\ortp\stun.h +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Profile1] +ProfileName=Default Profile +Type=3 +ObjFiles= +Includes=../../include;. +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DORTP_INET6_@@_-D_WORKAROUND_MINGW32_BUGS _@@_-Wall -Werror _@@_-D_WIN32_WINNT=0x0501_@@_-DORTP_STATIC_@@_ +CppCompiler=_@@_ +Linker=-lws2_32_@@_-liphlpapi_@@_-lwinmm_@@_ +PreprocDefines= +CompilerSettings=00000000000100000000b0 +Icon= +ExeOutput=..\WIN32N~1 +ObjectOutput=Default Profile +OverrideOutput=1 +OverrideOutputName=ortp.dll +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + +[Unit41] +FileName=..\..\src\b64.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= $(CC) -c b64.c -o "Default Profile/b64.o" $(CFLAGS) + diff --git a/linphone/oRTP/build/win32native/ortp-static.dev b/linphone/oRTP/build/win32native/ortp-static.dev new file mode 100755 index 000000000..3a8b15901 --- /dev/null +++ b/linphone/oRTP/build/win32native/ortp-static.dev @@ -0,0 +1,462 @@ +[Project] +FileName=ortp-static.dev +Name=ortp +UnitCount=40 +Type=2 +Ver=3 +IsCpp=1 +Folders= +CommandLine= +CompilerSettings=00000000000100000000b0 +PchHead=-1 +PchSource=-1 +ProfilesCount=1 +ProfileIndex=0 + +[Unit1] +FileName=..\..\include\ortp\telephonyevents.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\..\include\ortp\ortp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\..\include\ortp\payloadtype.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\..\include\ortp\port.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\..\include\ortp\rtcp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\include\ortp\rtp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\..\include\ortp\rtpsignaltable.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\include\ortp\sessionset.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\include\ortp\str_utils.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\..\src\avprofile.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\..\src\jitterctl.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\..\src\jitterctl.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\..\src\ortp.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\..\src\payloadtype.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\..\src\port.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\..\src\posixtimer.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\..\src\rtcp.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\..\src\rtcpparse.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\..\src\rtpparse.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\..\src\rtpsession.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\..\src\rtpsignaltable.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\..\src\rtptimer.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\..\src\rtptimer.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\..\src\scheduler.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\..\src\scheduler.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\..\src\sessionset.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\..\src\str_utils.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\..\src\telephonyevents.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\..\src\utils.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\..\src\utils.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\..\src\dll_entry.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\..\src\ortp-config-win32.h +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\..\src\event.c +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\..\include\ortp\event.h +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\..\src\stun.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 + +[Unit37] +FileName=..\..\src\stun_udp.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\..\src\rtpsession_inet.c +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= +CompileCpp=0 + +[Unit7] +FileName=..\..\include\ortp\rtpsession.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\..\src\rtpsession_priv.h +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\..\include\ortp\stun.h +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Profile1] +ProfileName=Default Profile +Type=2 +ObjFiles= +Includes=../../include;. +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DORTP_INET6_@@_-D_WORKAROUND_MINGW32_BUGS _@@_-Wall -Werror _@@_-D_WIN32_WINNT=0x0501_@@_-DORTP_STATIC_@@_ +CppCompiler=_@@_ +Linker=_@@_ +PreprocDefines= +CompilerSettings=00000000000100000000b0 +Icon= +ExeOutput=..\WIN32N~1 +ObjectOutput=Default Profile +OverrideOutput=1 +OverrideOutputName=libortp.a +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + diff --git a/linphone/oRTP/build/win32native/ortp.def b/linphone/oRTP/build/win32native/ortp.def new file mode 100755 index 000000000..be8988976 --- /dev/null +++ b/linphone/oRTP/build/win32native/ortp.def @@ -0,0 +1,174 @@ +LIBRARY ortp + +EXPORTS + + ortp_init + ortp_scheduler_init + ortp_exit + + ortp_get_scheduler + ortp_set_log_file + ortp_set_log_level_mask + ortp_logv_out + ortp_set_log_handler + ortp_strdup_printf + ortp_logv + + ortp_get_global_stats + ortp_global_stats_display + + session_set_new + session_set_select + session_set_destroy + + rtp_stats_display + rtp_session_get_stats + + rtp_session_init + rtp_session_new + + rtp_session_set_scheduling_mode + rtp_session_set_blocking_mode + rtp_session_set_profile + rtp_session_get_profile + rtp_session_set_data + + rtp_session_signal_connect + rtp_session_signal_disconnect_by_callback + rtp_session_set_ssrc + rtp_session_set_seq_number + rtp_session_get_seq_number + rtp_session_set_jitter_compensation + rtp_session_set_local_addr + rtp_session_set_remote_addr + rtp_session_enable_adaptive_jitter_compensation + rtp_session_set_recv_buf_size + + rtp_session_send_with_ts + rtp_session_sendm_with_ts + + rtp_session_set_sockets + rtp_session_get_rtp_socket + rtp_session_get_rtcp_socket + + rtp_session_set_payload_type + rtp_session_set_send_payload_type + rtp_session_get_send_payload_type + rtp_session_set_recv_payload_type + rtp_session_get_recv_payload_type + + rtp_session_recv_with_ts + rtp_session_recvm_with_ts + rtp_session_create_packet + + rtp_session_get_current_send_ts + rtp_session_get_current_recv_ts + rtp_session_reset + rtp_session_uninit + rtp_session_destroy + + rtp_add_csrc + + rtp_session_send_dtmf + + rtp_session_set_source_description + rtp_session_set_symmetric_rtp + + rtp_profile_new + rtp_profile_set_payload + rtp_profile_clone_full + rtp_profile_destroy + rtp_profile_get_payload_from_rtpmap + + payload_type_set_send_fmtp + payload_type_clone + fmtp_get_value + + ortp_free + ortp_malloc + ortp_strdup + ortp_realloc + ortp_malloc0 + freemsg + dupmsg + + allocb + getq + putq + msgpullup + qinit + flushq + msgdsize + peekq + freeb + dupb + concatb + esballoc + + WIN_thread_create + WIN_thread_join + WIN_cond_init + WIN_mutex_init + WIN_mutex_unlock + WIN_cond_wait + WIN_mutex_lock + WIN_cond_destroy + WIN_mutex_destroy + WIN_cond_signal + + __ortp_log_mask + + rtp_session_register_event_queue + rtp_session_unregister_event_queue + ortp_ev_queue_new + ortp_ev_queue_flush + ortp_ev_queue_get + ortp_ev_queue_destroy + ortp_event_get_type + ortp_event_get_data + ortp_event_destroy + + stunParseHostName + stunParseServerName + sendMessage + stunEncodeMessage + stunBuildReqSimple + stunParseMessage + stunServerProcessMsg + stunNatType + stunTest + stunOpenSocket + stunOpenSocketPair + + getWinSocketError + + rtp_session_set_transports + srtp_transport_new + + ortp_srtp_init + ortp_srtp_create + ortp_srtp_dealloc + ortp_srtp_add_stream + + rtp_session_set_dscp + rtp_session_compute_recv_bandwidth + rtp_session_compute_send_bandwidth + rtcp_next_packet + rtcp_sdes_parse + rtcp_is_SDES + rtcp_SR_get_report_block + rtcp_is_SR + rtcp_is_RR + rtp_session_flush_sockets + rtp_session_resync + rtp_session_set_remote_addr_and_port + rtp_session_set_time_jump_limit + + copymsg + rtp_session_enable_jitter_buffer + + rtp_session_set_rtp_socket_recv_buffer_size + rtp_session_set_rtp_socket_send_buffer_size + rtp_session_set_jitter_buffer_params + + rtp_get_payload diff --git a/linphone/oRTP/build/win32native/ortp.dev b/linphone/oRTP/build/win32native/ortp.dev new file mode 100755 index 000000000..8b0165162 --- /dev/null +++ b/linphone/oRTP/build/win32native/ortp.dev @@ -0,0 +1,449 @@ +[Project] +FileName=ortp.dev +Name=ortp +UnitCount=40 +Type=3 +Ver=1 +ObjFiles= +Includes=../../include;. +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DORTP_EXPORTS _@@_-DBUILDING_DLL=1 _@@_-DORTP_DLL_@@_-DORTP_INET6_@@_-D_WORKAROUND_MINGW32_BUGS -Wall -Werror _@@_-D_WIN32_WINNT=0x0501_@@_ +CppCompiler=-DBUILDING_DLL=1_@@_ +Linker=--no-export-all-symbols --add-stdcall-alias_@@_--def ortp.def_@@_-lws2_32 -lwinmm_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=1 +OverrideOutputName=ortp.dll +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=00000000000100000000b0 + +[Unit1] +FileName=..\..\include\ortp\telephonyevents.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\..\include\ortp\ortp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\..\include\ortp\payloadtype.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\..\include\ortp\port.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\..\include\ortp\rtcp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\include\ortp\rtp.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\..\include\ortp\rtpsignaltable.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\include\ortp\sessionset.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\include\ortp\str_utils.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\..\src\avprofile.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\..\src\jitterctl.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\..\src\jitterctl.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\..\src\ortp.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\..\src\payloadtype.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\..\src\port.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\..\src\posixtimer.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\..\src\rtcp.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\..\src\rtcpparse.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\..\src\rtpparse.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\..\src\rtpsession.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\..\src\rtpsignaltable.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\..\src\rtptimer.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\..\src\rtptimer.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\..\src\scheduler.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\..\src\scheduler.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\..\src\sessionset.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\..\src\str_utils.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\..\src\telephonyevents.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\..\src\utils.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\..\src\utils.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\..\src\dll_entry.c +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\..\src\ortp-config-win32.h +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\..\src\event.c +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\..\include\ortp\event.h +CompileCpp=0 +Folder=ortp/telephonyevents.h +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\..\src\stun.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit37] +FileName=..\..\src\stun_udp.c +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\..\src\rtpsession_inet.c +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= +CompileCpp=0 + +[Unit7] +FileName=..\..\include\ortp\rtpsession.h +CompileCpp=0 +Folder=ortpdll +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\..\src\rtpsession_priv.h +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\..\include\ortp\stun.h +CompileCpp=0 +Folder=ortp +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/linphone/oRTP/build/wince/.cvsignore b/linphone/oRTP/build/wince/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/oRTP/build/wince/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/oRTP/build/wince/Makefile.am b/linphone/oRTP/build/wince/Makefile.am new file mode 100644 index 000000000..3a96a0bac --- /dev/null +++ b/linphone/oRTP/build/wince/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=oRTP.vcproj ortp.def + diff --git a/linphone/oRTP/build/wince/oRTP.vcproj b/linphone/oRTP/build/wince/oRTP.vcproj new file mode 100644 index 000000000..81e457dc4 --- /dev/null +++ b/linphone/oRTP/build/wince/oRTP.vcproj @@ -0,0 +1,1019 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/oRTP/build/wince/ortp.def b/linphone/oRTP/build/wince/ortp.def new file mode 100644 index 000000000..f51512c82 --- /dev/null +++ b/linphone/oRTP/build/wince/ortp.def @@ -0,0 +1,163 @@ +LIBRARY ortp + +EXPORTS + + ortp_init + ortp_scheduler_init + ortp_exit + + ortp_get_scheduler + ortp_set_log_file + ortp_set_log_level_mask + ortp_logv_out + ortp_set_log_handler + ortp_strdup_printf + ortp_logv + + ortp_get_global_stats + ortp_global_stats_display + + session_set_new + session_set_select + session_set_destroy + + rtp_stats_display + rtp_session_get_stats + + rtp_session_init + rtp_session_new + + rtp_session_set_scheduling_mode + rtp_session_set_blocking_mode + rtp_session_set_profile + rtp_session_get_profile + rtp_session_set_data + + rtp_session_signal_connect + rtp_session_signal_disconnect_by_callback + rtp_session_set_ssrc + rtp_session_set_seq_number + rtp_session_get_seq_number + rtp_session_set_jitter_compensation + rtp_session_set_local_addr + rtp_session_set_remote_addr + rtp_session_enable_adaptive_jitter_compensation + rtp_session_set_recv_buf_size + + rtp_session_send_with_ts + rtp_session_sendm_with_ts + + rtp_session_set_sockets + rtp_session_get_rtp_socket + rtp_session_get_rtcp_socket + + rtp_session_set_payload_type + rtp_session_set_send_payload_type + rtp_session_get_send_payload_type + rtp_session_set_recv_payload_type + rtp_session_get_recv_payload_type + + rtp_session_recv_with_ts + rtp_session_recvm_with_ts + rtp_session_create_packet + + rtp_session_get_current_send_ts + rtp_session_get_current_recv_ts + rtp_session_reset + rtp_session_uninit + rtp_session_destroy + + rtp_add_csrc + + rtp_session_send_dtmf + + rtp_session_set_source_description + rtp_session_set_symmetric_rtp + + rtp_profile_new + rtp_profile_set_payload + rtp_profile_clone_full + rtp_profile_destroy + rtp_profile_get_payload_from_rtpmap + + payload_type_set_send_fmtp + payload_type_clone + fmtp_get_value + + ortp_free + ortp_malloc + ortp_strdup + ortp_realloc + ortp_malloc0 + freemsg + dupmsg + + allocb + getq + putq + msgpullup + qinit + flushq + msgdsize + peekq + freeb + dupb + concatb + + WIN_thread_create + WIN_thread_join + WIN_cond_init + WIN_mutex_init + WIN_mutex_unlock + WIN_cond_wait + WIN_mutex_lock + WIN_cond_destroy + WIN_mutex_destroy + WIN_cond_signal + + __ortp_log_mask + + rtp_session_register_event_queue + rtp_session_unregister_event_queue + ortp_ev_queue_new + ortp_ev_queue_flush + ortp_ev_queue_get + ortp_ev_queue_destroy + ortp_event_get_type + ortp_event_get_data + ortp_event_destroy + + stunParseHostName + stunParseServerName + sendMessage + stunEncodeMessage + stunBuildReqSimple + stunParseMessage + stunServerProcessMsg + stunNatType + stunTest + stunOpenSocket + stunOpenSocketPair + + getWinSocketError + + rtp_session_set_dscp + esballoc + + rtp_session_flush_sockets + rtp_session_resync + rtp_session_set_remote_addr_and_port + rtp_session_resync + rtp_session_set_time_jump_limit + + copymsg + rtp_session_enable_jitter_buffer + + rtp_session_compute_recv_bandwidth + rtp_session_compute_send_bandwidth + + rtp_session_set_rtp_socket_recv_buffer_size + rtp_session_set_rtp_socket_send_buffer_size + rtp_session_set_jitter_buffer_params + + rtp_get_payload diff --git a/linphone/oRTP/configure.ac b/linphone/oRTP/configure.ac new file mode 100644 index 000000000..6feb26f64 --- /dev/null +++ b/linphone/oRTP/configure.ac @@ -0,0 +1,331 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([ortp],[0.15.0]) +AC_CANONICAL_SYSTEM + +dnl Source packaging numbers +ORTP_MAJOR_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f1) +ORTP_MINOR_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f2) +ORTP_MICRO_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f3) +ORTP_EXTRA_VERSION=$(echo $PACKAGE_VERSION | cut -d. -f4) + +LIBORTP_SO_CURRENT=8 dnl increment this number when you add/change/remove an interface +LIBORTP_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT +LIBORTP_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface + +LIBORTP_SO_VERSION=$LIBORTP_SO_CURRENT:$LIBORTP_SO_REVISION:$LIBORTP_SO_AGE +ORTP_VERSION=${ORTP_MAJOR_VERSION}.${ORTP_MINOR_VERSION}.${ORTP_MICRO_VERSION} + +if test -n "$ORTP_EXTRA_VERSION" ; then + ORTP_VERSION="${ORTP_VERSION}.${ORTP_EXTRA_VERSION}" +fi + +ORTP_PKGCONFIG_VERSION=${ORTP_VERSION} + +AC_SUBST(LIBORTP_SO_VERSION) +AC_SUBST(ORTP_VERSION) +AC_SUBST(ORTP_PKGCONFIG_VERSION) + + +PACKAGE=ortp + +AM_INIT_AUTOMAKE([tar-ustar]) +AC_CONFIG_HEADERS(ortp-config.h) +AC_DEFINE_UNQUOTED(ORTP_MAJOR_VERSION,$ORTP_MAJOR_VERSION, [major version]) +AC_DEFINE_UNQUOTED(ORTP_MINOR_VERSION,$ORTP_MINOR_VERSION, [minor version]) +AC_DEFINE_UNQUOTED(ORTP_MICRO_VERSION,$ORTP_MICRO_VERSION, [micro version]) +AC_DEFINE_UNQUOTED(ORTP_VERSION,"$ORTP_VERSION",[ortp version number]) + +AC_SUBST([mkdir_p]) + +AC_MSG_CHECKING([warning make an error on compilation]) +AC_ARG_ENABLE(strict, +[ --enable-strict Enable error on compilation warning [default=yes]], +[wall_werror=$enableval], +[wall_werror=yes] +) + +AC_ARG_ENABLE(perf, +[ --enable-perf Disable costly features to reduce cpu consumtion [default=no]], +[perf=$enableval], +[perf=no] +) + +ORTP_DEFS= + +dnl enable ipv6 support +AC_ARG_ENABLE(ipv6, + [ --enable-ipv6 Turn on ipv6 support], + [case "${enableval}" in + yes) ipv6=true;; + no) ipv6=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ipv6) ;; + esac],[ipv6=true]) +if test x$ipv6 = xtrue ; then + ORTP_DEFS="$ORTP_DEFS -DORTP_INET6" +fi + +AC_ARG_ENABLE(mode64bit, + [ --enable-mode64bit=[yes/no] produce a 64-bit library. [default=no]], + [case "${enableval}" in + yes) mode64bit_enabled=yes;; + no) mode64bit_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-mode64bit");; + esac], + [mode64bit_enabled=no]) + +AC_ARG_ENABLE(debug, + [ --enable-debug=[yes/no] enables the display of traces showing the execution of the library. [default=yes]], + [case "${enableval}" in + yes) debug_enabled=yes;; + no) debug_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-debug");; + esac], + [debug_enabled=no]) + + +hpux_host=no +posixtimer_interval=10000 +PTHREAD_LDFLAGS= + +case "$target_os" in + *hpux*) + hpux_host=yes + AC_DEFINE(NOCONNECT,1,[Defined if we should not use connect() on udp sockets]) + CFLAGS="$CFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=199506L" + LIBS="$LIBS -lxnet" + ;; + *freebsd*) + AC_DEFINE(NOCONNECT,1,[Defined if we should not use connect() on udp sockets]) + PTHREAD_LDFLAGS="-pthread" + ;; +esac + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) + +if test "$GCC" != "yes" ; then + if test "$hpux_host" = "yes" ; then + dnl we are probably using HPUX cc compiler, so add a +O2 to CFLAGS + CFLAGS="$CFLAGS +O2 -g " + if test x$mode64bit_enabled = xyes ; then + CFLAGS="$CFLAGS +DA2.0W +DS2.0" + fi + fi +else + CFLAGS="$CFLAGS -Wall" +fi + +build_scheduler=yes + +dnl Check if we have seteuid system call +AC_CHECK_FUNCS(seteuid) + + +dnl check if we can use the pthread_library +AC_CHECK_LIB(pthread, pthread_mutex_init, [pthread_enabled=yes], [pthread_enabled=no]) +if test $pthread_enabled = "no" ; then + build_scheduler=no +else + PTHREAD_LIBS="-lpthread" + PTHREAD_CFLAGS="-D_REENTRANT" + AC_SUBST(PTHREAD_CFLAGS) + AC_SUBST(PTHREAD_LIBS) + AC_SUBST(PTHREAD_LDFLAGS) +fi +AC_ARG_WITH(thread-stack-size, + AC_HELP_STRING([--with-thread-stack-size=SIZE-IN-BYTES],[Set thread stack size [[default=os-default]]]), + [thread_stack_size=$withval], [thread_stack_size=0]) +AC_DEFINE_UNQUOTED(ORTP_DEFAULT_THREAD_STACK_SIZE, $thread_stack_size, [Default thread stack size (0 = let operating system decide)]) + + +dnl check for libsrtp support (secure rtp) +AC_ARG_WITH( srtp, + [ --with-srtp Set prefix where libsrtp can be found (ex:/usr or /usr/local)[default=/usr] ], + [ srtp_prefix=${withval}],[ srtp_prefix=/usr ]) + + +if test "${srtp_prefix}" != "/usr" ; then + SRTP_CFLAGS="-I${srtp_prefix}/include" + SRTP_LIBS="-L${srtp_prefix}/lib" +fi +SRTP_LIBS="$SRTP_LIBS -lsrtp" + +dnl check srtp headers +have_srtp=no +CPPFLAGS_save=$CPPFLAGS +CPPFLAGS=$SRTP_CFLAGS +AC_CHECK_HEADER([srtp/srtp.h],have_srtp_headers=yes) +CPPFLAGS=$CPPFLAGS_save + +dnl check for srtp lib +LDFLAGS_save=$LDFLAGS +LDFLAGS=$SRTP_LIBS +LIBS_save=$LIBS +AC_CHECK_LIB(srtp,srtp_init,have_srtp_lib=yes) +LDFLAGS=$LDFLAGS_save +LIBS=$LIBS_save + +if test "$have_srtp_headers$have_srtp_lib" = "yesyes" ; then + have_srtp=yes + AC_DEFINE(HAVE_SRTP, 1, [Defined when srtp support is compiled]) +else + AC_MSG_NOTICE([Could not find libsrtp headers or lib, cryto transport disabled.]) + SRTP_CFLAGS= + SRTP_LIBS= +fi + +AC_SUBST(SRTP_CFLAGS) +AC_SUBST(SRTP_LIBS) + +if test $debug_enabled = "yes"; then + ORTP_DEFS="$ORTP_DEFS -DORTP_DEBUG_MODE -g" + CFLAGS=`echo $CFLAGS | sed 's/-O.//'` +fi + +AC_ARG_ENABLE(memcheck, + [ --enable-memcheck=[yes/no] enables memory leak detection (HPUX only).], + [case "${enableval}" in + yes) memcheck_enabled=yes;; + no) memcheck_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-memcheck");; + esac], + [memcheck_enabled=no]) + +if test "$memcheck_enabled" = "yes" ; then + if test "$hpux_host" = "yes" ; then + AC_DEFINE(ENABLE_MEMCHECK,1,[Defined when memory leak checking if enabled]) + else + echo "WARNING ************ : the memory check option is only available for HPUX." + fi +fi + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(poll.h sys/poll.h sys/uio.h fcntl.h sys/time.h unistd.h sys/audio.h linux/soundcard.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_HEADER_TIME +AC_WORDS_BIGENDIAN +if test x$ac_cv_c_bigendian = xyes ; then + ORTP_DEFS="$ORTP_DEFS -DORTP_BIGENDIAN" +fi + +dnl Checks for library functions. +AC_CHECK_FUNCS(select socket strerror) + +if test $hpux_host = "yes" ; then +dnl it seems 10 ms is too fast on hpux and it causes trouble + posixtimer_interval=20000 +fi + +AC_DEFINE_UNQUOTED(POSIXTIMER_INTERVAL,$posixtimer_interval,[Defines the periodicity of the rtp scheduler in microseconds]) + +if test "$perf" = "yes" ; then + CFLAGS="$CFLAGS -DPERF" +fi + +if test $GCC = yes && test $wall_werror = yes; then + CFLAGS="$CFLAGS -Werror " +fi + +ORTPDEPS_LIBS="$ORTPDEPS_LIBS $PTHREAD_LIBS $PTHREAD_LDFLAGS $SRTP_LIBS" +ORTPDEPS_CFLAGS="$ORTPDEPS_CFLAGS $PTHREAD_CFLAGS $ORTP_DEFS $SRTP_CFLAGS" +CFLAGS="$CFLAGS $ORTP_DEFS" +echo "$ORTPDEPS_CFLAGS" > ortp.defs + + +dnl ################################################## +dnl # Check for gtk-doc. +dnl ################################################## + +AC_PATH_PROG(DOXYGEN,doxygen,false) +AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false) + + +dnl ################################################## +dnl # Check for ESP Packager +dnl ################################################## + +AC_PATH_PROG(EPM,epm,false) +AC_PATH_PROG(MKEPMLIST,mkepmlist,false) +AC_PATH_PROG(EPMINSTALL,epminstall,false) +AM_CONDITIONAL(WITH_EPM,test $EPM != false && test $MKEPMLIST != false && test $EPMINSTALL != false) + + +# Preferred packaging system, as per EPM terminology +case $target in +*-*-linux*) + if test -f /etc/debian_version ; then + EPM_PKG_EXT=deb + else + EPM_PKG_EXT=rpm + fi + ;; +*-hp-hpux*) + EPM_PKG_EXT=depot.gz;; +*-dec-osf*) + EPM_PKG_EXT=setld;; +esac +AC_SUBST(EPM_PKG_EXT) + +# System software User & Group names +case $target in +*-*-linux*) + SYS_USER=root + SYS_GROUP=root + ;; +*-*-hpux*|*-dec-osf*) + SYS_USER=bin + SYS_GROUP=bin + ;; +esac +AC_SUBST(SYS_USER) +AC_SUBST(SYS_GROUP) + +# CPU Architecture +case $target_cpu in +i?86) ARCH=i386;; +*) ARCH=$target_cpu;; +esac +AC_SUBST(ARCH) + +# Various other packaging variables, that can be over-ridden ad `make +# package' time +SUMMARY="An LGPL implementation of RTP - RFC3550" +AC_SUBST(SUMMARY) +PACKAGER=anonymous +AC_SUBST(PACKAGER) +LICENSE=LGPL +AC_SUBST(LICENSE) +VENDOR=Linphone +AC_SUBST(VENDOR) +RELEASE=1 +AC_SUBST(RELEASE) + +AC_SUBST(ORTPDEPS_CFLAGS) +AC_SUBST(ORTPDEPS_LIBS) +AC_SUBST(ORTPDEPS_LDFLAGS) + +AC_OUTPUT( +Makefile +include/Makefile +include/ortp/Makefile +src/Makefile +src/tests/Makefile +src/tests/win_receiver/Makefile +src/tests/win_sender/Makefile +build/Makefile +build/win32native/Makefile +build/wince/Makefile +ortp.pc +ortp.spec +ortp.doxygen +) + +AC_MSG_WARN([ortp-0.15.0 breaks compatibility with older releases, because value returned by rtp_session_recvm_with_ts() has + changed. See the API documentation in doc/ for further readings.]) diff --git a/linphone/oRTP/docs/.cvsignore b/linphone/oRTP/docs/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/oRTP/docs/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/oRTP/include/.cvsignore b/linphone/oRTP/include/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/oRTP/include/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/oRTP/include/Makefile.am b/linphone/oRTP/include/Makefile.am new file mode 100644 index 000000000..ca785d102 --- /dev/null +++ b/linphone/oRTP/include/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=ortp diff --git a/linphone/oRTP/include/ortp/.cvsignore b/linphone/oRTP/include/ortp/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/oRTP/include/ortp/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/oRTP/include/ortp/Makefile.am b/linphone/oRTP/include/ortp/Makefile.am new file mode 100644 index 000000000..c8f0133f1 --- /dev/null +++ b/linphone/oRTP/include/ortp/Makefile.am @@ -0,0 +1,11 @@ + + +ortp_includedir=$(includedir)/ortp + +ortp_include_HEADERS=str_utils.h rtpsession.h rtp.h port.h \ + ortp.h telephonyevents.h sessionset.h payloadtype.h rtpsignaltable.h \ + rtcp.h \ + event.h stun.h stun_udp.h srtp.h \ + b64.h + +EXTRA_DIST=$(ortp_include_HEADERS) diff --git a/linphone/oRTP/include/ortp/b64.h b/linphone/oRTP/include/ortp/b64.h new file mode 100644 index 000000000..f2ce4578a --- /dev/null +++ b/linphone/oRTP/include/ortp/b64.h @@ -0,0 +1,420 @@ +/* ///////////////////////////////////////////////////////////////////////////// + * File: b64/b64.h + * + * Purpose: Header file for the b64 library + * + * Created: 18th October 2004 + * Updated: 24th August 2008 + * + * Thanks: To Adam McLaurin, for ideas regarding the b64_decode2() and + * b64_encode2(). + * + * Home: http://synesis.com.au/software/ + * + * Copyright (c) 2004-2008, Matthew Wilson and Synesis Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of + * any contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////////// */ + + +/** \file b64/b64.h + * + * \brief [C/C++] Header file for the b64 library. + */ + +#ifndef B64_INCL_B64_H_B64 +#define B64_INCL_B64_H_B64 + +/* ///////////////////////////////////////////////////////////////////////////// + * Version information + */ + +#ifndef B64_DOCUMENTATION_SKIP_SECTION +# define B64_VER_B64_H_B64_MAJOR 1 +# define B64_VER_B64_H_B64_MINOR 5 +# define B64_VER_B64_H_B64_REVISION 4 +# define B64_VER_B64_H_B64_EDIT 28 +#endif /* !B64_DOCUMENTATION_SKIP_SECTION */ + +/** \def B64_VER_MAJOR + * The major version number of b64 + */ + +/** \def B64_VER_MINOR + * The minor version number of b64 + */ + +/** \def B64_VER_REVISION + * The revision version number of b64 + */ + +/** \def B64_VER + * The current composite version number of b64 + */ + +#ifndef B64_DOCUMENTATION_SKIP_SECTION +# define B64_VER_1_0_1 0x01000100 +# define B64_VER_1_0_2 0x01000200 +# define B64_VER_1_0_3 0x01000300 +# define B64_VER_1_1_1 0x01010100 +# define B64_VER_1_1_2 0x01010200 +# define B64_VER_1_1_3 0x01010300 +# define B64_VER_1_2_1 0x01020100 +# define B64_VER_1_2_2 0x01020200 +# define B64_VER_1_2_3 0x01020300 +# define B64_VER_1_2_4 0x01020400 +# define B64_VER_1_2_5 0x01020500 +# define B64_VER_1_2_6 0x01020600 +# define B64_VER_1_2_7 0x01020700 +# define B64_VER_1_3_1 0x010301ff +# define B64_VER_1_3_2 0x010302ff +# define B64_VER_1_3_3 0x010303ff +# define B64_VER_1_3_4 0x010304ff + +# define B64_VER B64_VER_1_3_4 +#else /* ? B64_DOCUMENTATION_SKIP_SECTION */ +# define B64_VER 0x010304ff +#endif /* !B64_DOCUMENTATION_SKIP_SECTION */ + +#define B64_VER_MAJOR 1 +#define B64_VER_MINOR 3 +#define B64_VER_REVISION 4 + +/* ///////////////////////////////////////////////////////////////////////////// + * Includes + */ + +#include + +/* ///////////////////////////////////////////////////////////////////////////// + * Namespace + */ + +#if !defined(B64_NO_NAMESPACE) && \ + !defined(__cplusplus) +# define B64_NO_NAMESPACE +#endif /* !B64_NO_NAMESPACE && !__cplusplus */ + +#ifdef B64_NAMESPACE +# undef B64_NAMESPACE +#endif /* B64_NAMESPACE */ + +#ifdef B64_NAMESPACE_QUALIFIER +# undef B64_NAMESPACE_QUALIFIER +#endif /* B64_NAMESPACE_QUALIFIER */ + + +#ifndef B64_NO_NAMESPACE + +# ifdef B64_CUSTOM_NAMESPACE +# define B64_NAMESPACE B64_CUSTOM_NAMESPACE +# else /* ? B64_CUSTOM_NAMESPACE */ +# define B64_NAMESPACE b64 +# endif /* B64_CUSTOM_NAMESPACE */ + +# if defined(B64_CUSTOM_NAMESPACE) && \ + defined(B64_CUSTOM_NAMESPACE_QUALIFIER) +# define B64_NAMESPACE_QUALIFIER B64_CUSTOM_NAMESPACE_QUALIFIER +# else /* B64_CUSTOM_NAMESPACE && B64_CUSTOM_NAMESPACE_QUALIFIER */ +# define B64_NAMESPACE_QUALIFIER ::B64_NAMESPACE +# endif /* B64_CUSTOM_NAMESPACE && B64_CUSTOM_NAMESPACE_QUALIFIER */ + + +/** \brief [C/C++] The b64 namespace, within which the core library types and functions + * reside in C++ compilation. In C compilation, they all reside in the global + * namespace. + * + * \htmlonly + *
+ * \endhtmlonly + */ +namespace B64_NAMESPACE +{ +#endif /* !B64_NO_NAMESPACE */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Enumerations + */ + +/** \brief Return codes (from b64_encode2() / b64_decode2()) + */ +enum B64_RC +{ + B64_RC_OK = 0 /*!< Operation was successful. */ + , B64_RC_INSUFFICIENT_BUFFER = 1 /*!< The given translation buffer was not of sufficient size. */ + , B64_RC_TRUNCATED_INPUT = 2 /*!< The input did not represent a fully formed stream of octet couplings. */ + , B64_RC_DATA_ERROR = 3 /*!< Invalid data. */ +#ifndef B64_DOCUMENTATION_SKIP_SECTION + , B64_max_RC_value +#endif /* !B64_DOCUMENTATION_SKIP_SECTION */ +}; + +#ifndef __cplusplus +typedef enum B64_RC B64_RC; +#endif /* !__cplusplus */ + +/** \brief Coding behaviour modification flags (for b64_encode2() / b64_decode2()) + */ +enum B64_FLAGS +{ + B64_F_LINE_LEN_USE_PARAM = 0x0000 /*!< Uses the lineLen parameter to b64_encode2(). Ignored by b64_decode2(). */ + , B64_F_LINE_LEN_INFINITE = 0x0001 /*!< Ignores the lineLen parameter to b64_encode2(). Line length is infinite. Ignored by b64_decode2(). */ + , B64_F_LINE_LEN_64 = 0x0002 /*!< Ignores the lineLen parameter to b64_encode2(). Line length is 64. Ignored by b64_decode2(). */ + , B64_F_LINE_LEN_76 = 0x0003 /*!< Ignores the lineLen parameter to b64_encode2(). Line length is 76. Ignored by b64_decode2(). */ + , B64_F_LINE_LEN_MASK = 0x000f /*!< Mask for testing line length flags to b64_encode2(). Ignored by b64_encode2(). */ + , B64_F_STOP_ON_NOTHING = 0x0000 /*!< Decoding ignores all invalid characters in the input data. Ignored by b64_encode2(). */ + , B64_F_STOP_ON_UNKNOWN_CHAR = 0x0100 /*!< Causes decoding to break if any non-Base-64 [a-zA-Z0-9=+/], non-whitespace character is encountered. Ignored by b64_encode2(). */ + , B64_F_STOP_ON_UNEXPECTED_WS = 0x0200 /*!< Causes decoding to break if any unexpected whitespace is encountered. Ignored by b64_encode2(). */ + , B64_F_STOP_ON_BAD_CHAR = 0x0300 /*!< Causes decoding to break if any non-Base-64 [a-zA-Z0-9=+/] character is encountered. Ignored by b64_encode2(). */ +}; + +#ifndef __cplusplus +typedef enum B64_FLAGS B64_FLAGS; +#endif /* !__cplusplus */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Functions + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** \brief Encodes a block of binary data into Base-64 + * + * \param src Pointer to the block to be encoded. May not be NULL, except when + * \c dest is NULL, in which case it is ignored. + * \param srcSize Length of block to be encoded + * \param dest Pointer to the buffer into which the result is to be written. May + * be NULL, in which case the function returns the required length + * \param destLen Length of the buffer into which the result is to be written. Must + * be at least as large as that indicated by the return value from + * \link b64::b64_encode b64_encode(NULL, srcSize, NULL, 0)\endlink. + * + * \return 0 if the size of the buffer was insufficient, or the length of the + * converted buffer was longer than \c destLen + * + * \note The function returns the required length if \c dest is NULL + * + * \note The function returns the required length if \c dest is NULL. The returned size + * might be larger than the actual required size, but will never be smaller. + * + * \note Threading: The function is fully re-entrant. + * + * \see b64::encode() + */ +size_t b64_encode(void const *src, size_t srcSize, char *dest, size_t destLen); + +/** \brief Encodes a block of binary data into Base-64 + * + * \param src Pointer to the block to be encoded. May not be NULL, except when + * \c dest is NULL, in which case it is ignored. + * \param srcSize Length of block to be encoded + * \param dest Pointer to the buffer into which the result is to be written. May + * be NULL, in which case the function returns the required length + * \param destLen Length of the buffer into which the result is to be written. Must + * be at least as large as that indicated by the return value from + * \link b64::b64_encode2 b64_encode2(NULL, srcSize, NULL, 0, flags, lineLen, rc)\endlink. + * \param flags A combination of the B64_FLAGS enumeration, that moderate the + * behaviour of the function + * \param lineLen If the flags parameter contains B64_F_LINE_LEN_USE_PARAM, then + * this parameter represents the length of the lines into which the encoded form is split, + * with a hard line break ('\\r\\n'). If this value is 0, then the line is not + * split. If it is <0, then the RFC-1113 recommended line length of 64 is used + * \param rc The return code representing the status of the operation. May be NULL. + * + * \return 0 if the size of the buffer was insufficient, or the length of the + * converted buffer was longer than \c destLen + * + * \note The function returns the required length if \c dest is NULL. The returned size + * might be larger than the actual required size, but will never be smaller. + * + * \note Threading: The function is fully re-entrant. + * + * \see b64::encode() + */ +size_t b64_encode2( void const *src + , size_t srcSize + , char *dest + , size_t destLen + , unsigned flags + , int lineLen /* = 0 */ + , B64_RC *rc /* = NULL */); + +/** \brief Decodes a sequence of Base-64 into a block of binary data + * + * \param src Pointer to the Base-64 block to be decoded. May not be NULL, except when + * \c dest is NULL, in which case it is ignored. If \c dest is NULL, and \c src is + * not NULL, then the returned value is calculated exactly, otherwise a value + * is returned that is guaranteed to be large enough to hold the decoded block. + * + * \param srcLen Length of block to be encoded. Must be an integral of 4, the Base-64 + * encoding quantum, otherwise the Base-64 block is assumed to be invalid + * \param dest Pointer to the buffer into which the result is to be written. May + * be NULL, in which case the function returns the required length + * \param destSize Length of the buffer into which the result is to be written. Must + * be at least as large as that indicated by the return value from + * \c b64_decode(src, srcSize, NULL, 0), even in the case where the encoded form + * contains a number of characters that will be ignored, resulting in a lower total + * length of converted form. + * + * \return 0 if the size of the buffer was insufficient, or the length of the + * converted buffer was longer than \c destSize + * + * \note The function returns the required length if \c dest is NULL. The returned size + * might be larger than the actual required size, but will never be smaller. + * + * \note \anchor anchor__4_characters The behaviour of both + * \link b64::b64_encode2 b64_encode2()\endlink + * and + * \link b64::b64_decode2 b64_decode2()\endlink + * are undefined if the line length is not a multiple of 4. + * + * \note Threading: The function is fully re-entrant. + * + * \see b64::decode() + */ +size_t b64_decode(char const *src, size_t srcLen, void *dest, size_t destSize); + +/** \brief Decodes a sequence of Base-64 into a block of binary data + * + * \param src Pointer to the Base-64 block to be decoded. May not be NULL, except when + * \c dest is NULL, in which case it is ignored. If \c dest is NULL, and \c src is + * not NULL, then the returned value is calculated exactly, otherwise a value + * is returned that is guaranteed to be large enough to hold the decoded block. + * + * \param srcLen Length of block to be encoded. Must be an integral of 4, the Base-64 + * encoding quantum, otherwise the Base-64 block is assumed to be invalid + * \param dest Pointer to the buffer into which the result is to be written. May + * be NULL, in which case the function returns the required length + * \param destSize Length of the buffer into which the result is to be written. Must + * be at least as large as that indicated by the return value from + * \c b64_decode(src, srcSize, NULL, 0), even in the case where the encoded form + * contains a number of characters that will be ignored, resulting in a lower total + * length of converted form. + * \param flags A combination of the B64_FLAGS enumeration, that moderate the + * behaviour of the function. + * \param rc The return code representing the status of the operation. May be NULL. + * \param badChar If the flags parameter does not contain B64_F_STOP_ON_NOTHING, this + * parameter specifies the address of a pointer that will be set to point to any + * character in the sequence that stops the parsing, as dictated by the flags + * parameter. May be NULL. + * + * \return 0 if the size of the buffer was insufficient, or the length of the + * converted buffer was longer than \c destSize, or a bad character stopped parsing. + * + * \note The function returns the required length if \c dest is NULL. The returned size + * might be larger than the actual required size, but will never be smaller. + * + * \note The behaviour of both + * \link b64::b64_encode2 b64_encode2()\endlink + * and + * \link b64::b64_decode2 b64_decode2()\endlink + * are undefined if the line length is not a multiple of 4. + * + * \note Threading: The function is fully re-entrant. + * + * \see b64::decode() + */ +size_t b64_decode2( char const *src + , size_t srcLen + , void *dest + , size_t destSize + , unsigned flags + , char const **badChar /* = NULL */ + , B64_RC *rc /* = NULL */); + + +/** \brief Returns the textual description of the error + * + * \param code The \link b64::B64_RC error code\endlink + */ +char const *b64_getErrorString(B64_RC code); + +/** \brief Returns the length of the textual description of the error + * + * \see b64_getErrorString() + * + * \param code The \link b64::B64_RC error code\endlink + */ +size_t b64_getErrorStringLength(B64_RC code); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Namespace + */ + +#ifndef B64_NO_NAMESPACE +} /* namespace B64_NAMESPACE */ + +# ifndef B64_DOCUMENTATION_SKIP_SECTION + +namespace stlsoft +{ + + inline char const *c_str_data_a( B64_NAMESPACE_QUALIFIER::B64_RC code) + { + return B64_NAMESPACE_QUALIFIER::b64_getErrorString(code); + } + inline char const *c_str_data( B64_NAMESPACE_QUALIFIER::B64_RC code) + { + return B64_NAMESPACE_QUALIFIER::b64_getErrorString(code); + } + + inline size_t c_str_len_a( B64_NAMESPACE_QUALIFIER::B64_RC code) + { + return B64_NAMESPACE_QUALIFIER::b64_getErrorStringLength(code); + } + inline size_t c_str_len( B64_NAMESPACE_QUALIFIER::B64_RC code) + { + return B64_NAMESPACE_QUALIFIER::b64_getErrorStringLength(code); + } + + inline char const *c_str_ptr_a( B64_NAMESPACE_QUALIFIER::B64_RC code) + { + return B64_NAMESPACE_QUALIFIER::b64_getErrorString(code); + } + inline char const *c_str_ptr( B64_NAMESPACE_QUALIFIER::B64_RC code) + { + return B64_NAMESPACE_QUALIFIER::b64_getErrorString(code); + } + +} /* namespace stlsoft */ + +# endif /* !B64_DOCUMENTATION_SKIP_SECTION */ + +#endif /* !B64_NO_NAMESPACE */ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#endif /* B64_INCL_B64_H_B64 */ + +/* ////////////////////////////////////////////////////////////////////////// */ diff --git a/linphone/oRTP/include/ortp/event.h b/linphone/oRTP/include/ortp/event.h new file mode 100644 index 000000000..071d417d6 --- /dev/null +++ b/linphone/oRTP/include/ortp/event.h @@ -0,0 +1,85 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef ortp_events_h +#define ortp_events_h + +#include + +typedef mblk_t OrtpEvent; + +typedef unsigned long OrtpEventType; + +typedef struct RtpEndpoint{ +#ifdef ORTP_INET6 + struct sockaddr_storage addr; +#else + struct sockaddr addr; +#endif + socklen_t addrlen; +}RtpEndpoint; + + +struct _OrtpEventData{ + mblk_t *packet; /* most events are associated to a received packet */ + RtpEndpoint *ep; + union { + int telephone_event; + int payload_type; + } info; +}; + +typedef struct _OrtpEventData OrtpEventData; + + + +#ifdef __cplusplus +extern "C"{ +#endif + +RtpEndpoint *rtp_endpoint_new(struct sockaddr *addr, socklen_t addrlen); +RtpEndpoint *rtp_endpoint_dup(const RtpEndpoint *ep); + +OrtpEvent * ortp_event_new(OrtpEventType tp); +OrtpEventType ortp_event_get_type(const OrtpEvent *ev); +/* type is one of the following*/ +#define ORTP_EVENT_STUN_PACKET_RECEIVED 1 +#define ORTP_EVENT_PAYLOAD_TYPE_CHANGED 2 +#define ORTP_EVENT_TELEPHONE_EVENT 3 +#define ORTP_EVENT_RTCP_PACKET_RECEIVED 4 +OrtpEventData * ortp_event_get_data(OrtpEvent *ev); +void ortp_event_destroy(OrtpEvent *ev); +OrtpEvent *ortp_event_dup(OrtpEvent *ev); + +typedef struct OrtpEvQueue{ + queue_t q; + ortp_mutex_t mutex; +} OrtpEvQueue; + +OrtpEvQueue * ortp_ev_queue_new(void); +void ortp_ev_queue_destroy(OrtpEvQueue *q); +OrtpEvent * ortp_ev_queue_get(OrtpEvQueue *q); +void ortp_ev_queue_flush(OrtpEvQueue * qp); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/linphone/oRTP/include/ortp/ortp.h b/linphone/oRTP/include/ortp/ortp.h new file mode 100644 index 000000000..8176af523 --- /dev/null +++ b/linphone/oRTP/include/ortp/ortp.h @@ -0,0 +1,199 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** \mainpage oRTP API documentation + * + * \section init Initializing oRTP + * + * see ortp.h documentation. + * + * \section rtpsession the RtpSession object + * + * see the rtpsession.h documentation. + * + * \section payloadtypes Managing PayloadType(s) and RtpProfile(s) + * + * see the payloadtype.h documentation. + * + * \section telephonevents Sending and receiving telephone-event (RFC2833) + * + * see the telephonyevents.h documentation. + * To get informed about incoming telephone-event you can register a callback + * using rtp_session_signal_connect() or by registering an event queue using + * rtp_session_register_event_queue(). + * + * \section sessionset Managing several RtpSession simultaneously + * + * see the sessionset.h documentation. + * + * \section rtcp Parsing incoming rtcp packets. + * + * The parsing api is defined in rtcp.h (not yet documented). + * + * \section examples Examples + * + * oRTP comes with a set of examples in src/tests. + * - rtprecv.c rtpsend.c show how to receive and send a single RTP stream. + * - mrtprecv.c mrtpsend.c show how to receive and send multiple RTP streams + * simultaneously + * + */ + +/** + * \file ortp.h + * \brief General purpose library functions. + * +**/ + +#ifndef ORTP_H +#define ORTP_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +bool_t ortp_min_version_required(int major, int minor, int micro); +void ortp_init(void); +void ortp_scheduler_init(void); +void ortp_exit(void); + +/***************/ +/* logging api */ +/***************/ + +typedef enum { + ORTP_DEBUG=1, + ORTP_MESSAGE=1<<1, + ORTP_WARNING=1<<2, + ORTP_ERROR=1<<3, + ORTP_FATAL=1<<4, + ORTP_LOGLEV_END=1<<5 +} OrtpLogLevel; + + +typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args); + +void ortp_set_log_file(FILE *file); +void ortp_set_log_handler(OrtpLogFunc func); + +VAR_DECLSPEC OrtpLogFunc ortp_logv_out; + +extern unsigned int __ortp_log_mask; + +#define ortp_log_level_enabled(level) (__ortp_log_mask & (level)) + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#define ortp_logv(level,fmt,args) \ +{\ + if (ortp_logv_out!=NULL && ortp_log_level_enabled(level)) \ + ortp_logv_out(level,fmt,args);\ + if ((level)==ORTP_FATAL) abort();\ +}while(0) +#else +void ortp_logv(int level, const char *fmt, va_list args); +#endif + +void ortp_set_log_level_mask(int levelmask); + +#ifdef ORTP_DEBUG_MODE +static inline void ortp_debug(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_DEBUG, fmt, args); + va_end (args); +} +#else + +#define ortp_debug(...) + +#endif + +#ifdef ORTP_NOMESSAGE_MODE + +#define ortp_log(...) +#define ortp_message(...) +#define ortp_warning(...) + +#else + +static inline void ortp_log(OrtpLogLevel lev, const char *fmt,...){ + va_list args; + va_start (args, fmt); + ortp_logv(lev, fmt, args); + va_end (args); +} + +static inline void ortp_message(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_MESSAGE, fmt, args); + va_end (args); +} + +static inline void ortp_warning(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_WARNING, fmt, args); + va_end (args); +} + +#endif + +static inline void ortp_error(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_ERROR, fmt, args); + va_end (args); +} + +static inline void ortp_fatal(const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + ortp_logv(ORTP_FATAL, fmt, args); + va_end (args); +} + + +/****************/ +/*statistics api*/ +/****************/ + +extern rtp_stats_t ortp_global_stats; + +void ortp_global_stats_reset(void); +rtp_stats_t *ortp_get_global_stats(void); + +void ortp_global_stats_display(void); +void rtp_stats_display(const rtp_stats_t *stats, const char *header); +void rtp_stats_reset(rtp_stats_t *stats); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/payloadtype.h b/linphone/oRTP/include/ortp/payloadtype.h new file mode 100644 index 000000000..79081ece4 --- /dev/null +++ b/linphone/oRTP/include/ortp/payloadtype.h @@ -0,0 +1,208 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + * \file payloadtype.h + * \brief Using and creating standart and custom RTP profiles + * +**/ + +#ifndef PAYLOADTYPE_H +#define PAYLOADTYPE_H +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +/* flags for PayloadType::flags */ + +#define PAYLOAD_TYPE_ALLOCATED (1) + /* private flags for future use by ortp */ +#define PAYLOAD_TYPE_PRIV1 (1<<1) +#define PAYLOAD_TYPE_PRIV2 (1<<2) +#define PAYLOAD_TYPE_PRIV3 (1<<3) + /* user flags, can be used by the application on top of oRTP */ +#define PAYLOAD_TYPE_USER_FLAG_0 (1<<4) +#define PAYLOAD_TYPE_USER_FLAG_1 (1<<5) +#define PAYLOAD_TYPE_USER_FLAG_2 (1<<6) + /* ask for more if you need*/ + +#define PAYLOAD_AUDIO_CONTINUOUS 0 +#define PAYLOAD_AUDIO_PACKETIZED 1 +#define PAYLOAD_VIDEO 2 +#define PAYLOAD_OTHER 3 /* ?? */ + +struct _PayloadType +{ + int type; /**< one of PAYLOAD_* macros*/ + int clock_rate; /**< rtp clock rate*/ + char bits_per_sample; /* in case of continuous audio data */ + char *zero_pattern; + int pattern_length; + /* other useful information for the application*/ + int normal_bitrate; /*in bit/s */ + char *mime_type; /**flags|=((int)flag) +#define payload_type_unset_flag(pt,flag) (pt)->flags&=(~(int)flag) +#define payload_type_get_flags(pt) (pt)->flags + +#define RTP_PROFILE_MAX_PAYLOADS 128 + +/** + * The RTP profile is a table RTP_PROFILE_MAX_PAYLOADS entries to make the matching + * between RTP payload type number and the PayloadType that defines the type of + * media. +**/ +struct _RtpProfile +{ + char *name; + PayloadType *payload[RTP_PROFILE_MAX_PAYLOADS]; +}; + + +typedef struct _RtpProfile RtpProfile; + +PayloadType *payload_type_new(void); +PayloadType *payload_type_clone(PayloadType *payload); +char *payload_type_get_rtpmap(PayloadType *pt); +void payload_type_destroy(PayloadType *pt); +void payload_type_set_recv_fmtp(PayloadType *pt, const char *fmtp); +void payload_type_set_send_fmtp(PayloadType *pt, const char *fmtp); +void payload_type_append_recv_fmtp(PayloadType *pt, const char *fmtp); +void payload_type_append_send_fmtp(PayloadType *pt, const char *fmtp); + + +bool_t fmtp_get_value(const char *fmtp, const char *param_name, char *result, size_t result_len); + +VAR_DECLSPEC RtpProfile av_profile; + +#define payload_type_set_user_data(pt,p) (pt)->user_data=(p) +#define payload_type_get_user_data(pt) ((pt)->user_data) + +#define rtp_profile_get_name(profile) (const char*)((profile)->name) + +void rtp_profile_set_payload(RtpProfile *prof, int idx, PayloadType *pt); + +/** + * Set payload type number @index unassigned in the profile. + * + *@param profile an RTP profile + *@param index the payload type number +**/ +#define rtp_profile_clear_payload(profile,index) \ + rtp_profile_set_payload(profile,index,NULL) + +/* I prefer have this function inlined because it is very often called in the code */ +/** + * + * Gets the payload description of the payload type @index in the profile. + * + *@param profile an RTP profile (a #RtpProfile object) + *@param index the payload type number + *@return the payload description (a PayloadType object) +**/ +static inline PayloadType * rtp_profile_get_payload(RtpProfile *prof, int idx){ + if (idx<0 || idx>=RTP_PROFILE_MAX_PAYLOADS) { + return NULL; + } + return prof->payload[idx]; +} +void rtp_profile_clear_all(RtpProfile *prof); +void rtp_profile_set_name(RtpProfile *prof, const char *name); +PayloadType * rtp_profile_get_payload_from_mime(RtpProfile *profile,const char *mime); +PayloadType * rtp_profile_get_payload_from_rtpmap(RtpProfile *profile, const char *rtpmap); +int rtp_profile_get_payload_number_from_mime(RtpProfile *profile,const char *mime); +int rtp_profile_get_payload_number_from_rtpmap(RtpProfile *profile, const char *rtpmap); +int rtp_profile_find_payload_number(RtpProfile *prof,const char *mime,int rate, int channels); +PayloadType * rtp_profile_find_payload(RtpProfile *prof,const char *mime,int rate, int channels); +int rtp_profile_move_payload(RtpProfile *prof,int oldpos,int newpos); + +RtpProfile * rtp_profile_new(const char *name); +/* clone a profile, payload are not cloned */ +RtpProfile * rtp_profile_clone(RtpProfile *prof); + + +/*clone a profile and its payloads (ie payload type are newly allocated, not reusing payload types of the reference profile) */ +RtpProfile * rtp_profile_clone_full(RtpProfile *prof); +/* frees the profile and all its PayloadTypes*/ +void rtp_profile_destroy(RtpProfile *prof); + + +/* some payload types */ +/* audio */ +VAR_DECLSPEC PayloadType payload_type_pcmu8000; +VAR_DECLSPEC PayloadType payload_type_pcma8000; +VAR_DECLSPEC PayloadType payload_type_pcm8000; +VAR_DECLSPEC PayloadType payload_type_l16_mono; +VAR_DECLSPEC PayloadType payload_type_l16_stereo; +VAR_DECLSPEC PayloadType payload_type_lpc1016; +VAR_DECLSPEC PayloadType payload_type_g729; +VAR_DECLSPEC PayloadType payload_type_g7231; +VAR_DECLSPEC PayloadType payload_type_g726_40; +VAR_DECLSPEC PayloadType payload_type_g726_32; +VAR_DECLSPEC PayloadType payload_type_g726_24; +VAR_DECLSPEC PayloadType payload_type_g726_16; +VAR_DECLSPEC PayloadType payload_type_gsm; +VAR_DECLSPEC PayloadType payload_type_lpc; +VAR_DECLSPEC PayloadType payload_type_lpc1015; +VAR_DECLSPEC PayloadType payload_type_speex_nb; +VAR_DECLSPEC PayloadType payload_type_speex_wb; +VAR_DECLSPEC PayloadType payload_type_speex_uwb; +VAR_DECLSPEC PayloadType payload_type_ilbc; +VAR_DECLSPEC PayloadType payload_type_amr; +VAR_DECLSPEC PayloadType payload_type_amrwb; +VAR_DECLSPEC PayloadType payload_type_truespeech; +VAR_DECLSPEC PayloadType payload_type_evrc0; + +/* video */ +VAR_DECLSPEC PayloadType payload_type_mpv; +VAR_DECLSPEC PayloadType payload_type_h261; +VAR_DECLSPEC PayloadType payload_type_h263; +VAR_DECLSPEC PayloadType payload_type_h263_1998; +VAR_DECLSPEC PayloadType payload_type_h263_2000; +VAR_DECLSPEC PayloadType payload_type_mp4v; +VAR_DECLSPEC PayloadType payload_type_theora; +VAR_DECLSPEC PayloadType payload_type_h264; +VAR_DECLSPEC PayloadType payload_type_x_snow; +VAR_DECLSPEC PayloadType payload_type_t140; + +/* non standard file transfer over UDP */ +VAR_DECLSPEC PayloadType payload_type_x_udpftp; + +/* telephone-event */ +VAR_DECLSPEC PayloadType payload_type_telephone_event; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/port.h b/linphone/oRTP/include/ortp/port.h new file mode 100644 index 000000000..c50fb2de0 --- /dev/null +++ b/linphone/oRTP/include/ortp/port.h @@ -0,0 +1,250 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* this file is responsible of the portability of the stack */ + +#ifndef ORTP_PORT_H +#define ORTP_PORT_H + + +#if !defined(WIN32) && !defined(_WIN32_WCE) +/********************************/ +/* definitions for UNIX flavour */ +/********************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux +#include +#endif + + +#include +#include +#include +#if defined(_XOPEN_SOURCE_EXTENDED) || !defined(__hpux) +#include +#endif + + + +#include + +#ifdef ORTP_INET6 +#include +#endif + +typedef int ortp_socket_t; +typedef pthread_t ortp_thread_t; +typedef pthread_mutex_t ortp_mutex_t; +typedef pthread_cond_t ortp_cond_t; + +#ifdef __INTEL_COMPILER +#pragma warning(disable : 111) // statement is unreachable +#pragma warning(disable : 181) // argument is incompatible with corresponding format string conversion +#pragma warning(disable : 188) // enumerated type mixed with another type +#pragma warning(disable : 593) // variable "xxx" was set but never used +#pragma warning(disable : 810) // conversion from "int" to "unsigned short" may lose significant bits +#pragma warning(disable : 869) // parameter "xxx" was never referenced +#pragma warning(disable : 981) // operands are evaluated in unspecified order +#pragma warning(disable : 1418) // external function definition with no prior declaration +#pragma warning(disable : 1419) // external declaration in primary source file +#pragma warning(disable : 1469) // "cc" clobber ignored +#endif + +int __ortp_thread_join(ortp_thread_t thread, void **ptr); +int __ortp_thread_create(pthread_t *thread, pthread_attr_t *attr, void * (*routine)(void*), void *arg); +#define ortp_thread_create __ortp_thread_create +#define ortp_thread_join __ortp_thread_join +#define ortp_thread_exit pthread_exit +#define ortp_mutex_init pthread_mutex_init +#define ortp_mutex_lock pthread_mutex_lock +#define ortp_mutex_unlock pthread_mutex_unlock +#define ortp_mutex_destroy pthread_mutex_destroy +#define ortp_cond_init pthread_cond_init +#define ortp_cond_signal pthread_cond_signal +#define ortp_cond_broadcast pthread_cond_broadcast +#define ortp_cond_wait pthread_cond_wait +#define ortp_cond_destroy pthread_cond_destroy + +#define SOCKET_OPTION_VALUE void * +#define SOCKET_BUFFER void * + +#define getSocketError() strerror(errno) +#define getSocketErrorCode() (errno) + +#else +/*********************************/ +/* definitions for WIN32 flavour */ +/*********************************/ + +#include +#include +#include +#include +#include + + +#ifdef _MSC_VER +#pragma push_macro("_WINSOCKAPI_") +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ +#endif + +typedef unsigned __int64 uint64_t; +typedef __int64 int64_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned char uint8_t; +typedef __int16 int16_t; +#else +#include /*provided by mingw32*/ +#endif + +#define vsnprintf _vsnprintf +#define srandom srand +#define random rand + + +typedef SOCKET ortp_socket_t; +typedef HANDLE ortp_cond_t; +typedef HANDLE ortp_mutex_t; +typedef HANDLE ortp_thread_t; + +#define ortp_thread_create WIN_thread_create +#define ortp_thread_join WIN_thread_join +#define ortp_thread_exit(arg) +#define ortp_mutex_init WIN_mutex_init +#define ortp_mutex_lock WIN_mutex_lock +#define ortp_mutex_unlock WIN_mutex_unlock +#define ortp_mutex_destroy WIN_mutex_destroy +#define ortp_cond_init WIN_cond_init +#define ortp_cond_signal WIN_cond_signal +#define ortp_cond_broadcast WIN_cond_broadcast +#define ortp_cond_wait WIN_cond_wait +#define ortp_cond_destroy WIN_cond_destroy + + +#ifdef __cplusplus +extern "C" +{ +#endif + +int WIN_mutex_init(ortp_mutex_t *m, void *attr_unused); +int WIN_mutex_lock(ortp_mutex_t *mutex); +int WIN_mutex_unlock(ortp_mutex_t *mutex); +int WIN_mutex_destroy(ortp_mutex_t *mutex); +int WIN_thread_create(ortp_thread_t *t, void *attr_unused, void *(*func)(void*), void *arg); +int WIN_thread_join(ortp_thread_t thread, void **unused); +int WIN_cond_init(ortp_cond_t *cond, void *attr_unused); +int WIN_cond_wait(ortp_cond_t * cond, ortp_mutex_t * mutex); +int WIN_cond_signal(ortp_cond_t * cond); +int WIN_cond_broadcast(ortp_cond_t * cond); +int WIN_cond_destroy(ortp_cond_t * cond); + +#ifdef __cplusplus +} +#endif + +#define SOCKET_OPTION_VALUE char * +#define inline __inline + +const char *getWinSocketError(int error); +#define getSocketErrorCode() WSAGetLastError() +#define getSocketError() getWinSocketError(WSAGetLastError()) + +#define snprintf _snprintf +#define strcasecmp _stricmp + +#if 0 +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif + +int gettimeofday (struct timeval *tv, void* tz); +#ifdef _WORKAROUND_MINGW32_BUGS +char * WSAAPI gai_strerror(int errnum); +#endif + + +#endif + +typedef unsigned char bool_t; +#undef TRUE +#undef FALSE +#define TRUE 1 +#define FALSE 0 + +#ifdef __cplusplus +extern "C"{ +#endif + +void* ortp_malloc(size_t sz); +void ortp_free(void *ptr); +void* ortp_realloc(void *ptr, size_t sz); +void* ortp_malloc0(size_t sz); +char * ortp_strdup(const char *tmp); + +/*override the allocator with this method, to be called BEFORE ortp_init()*/ +typedef struct _OrtpMemoryFunctions{ + void *(*malloc_fun)(size_t sz); + void *(*realloc_fun)(void *ptr, size_t sz); + void (*free_fun)(void *ptr); +}OrtpMemoryFunctions; + +void ortp_set_memory_functions(OrtpMemoryFunctions *functions); + +#define ortp_new(type,count) ortp_malloc(sizeof(type)*(count)) +#define ortp_new0(type,count) ortp_malloc0(sizeof(type)*(count)) + +int close_socket(ortp_socket_t sock); +int set_non_blocking_socket(ortp_socket_t sock); + +char *ortp_strndup(const char *str,int n); +char *ortp_strdup_printf(const char *fmt,...); + +#ifdef __cplusplus +} +#endif + + +#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(ORTP_STATIC) +#ifdef ORTP_EXPORTS + #define VAR_DECLSPEC __declspec(dllexport) +#else + #define VAR_DECLSPEC __declspec(dllimport) +#endif +#else + #define VAR_DECLSPEC extern +#endif + + +#endif + + diff --git a/linphone/oRTP/include/ortp/rtcp.h b/linphone/oRTP/include/ortp/rtcp.h new file mode 100644 index 000000000..950179764 --- /dev/null +++ b/linphone/oRTP/include/ortp/rtcp.h @@ -0,0 +1,252 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef RTCP_H +#define RTCP_H + +#include + +#define RTCP_MAX_RECV_BUFSIZE 1024 + +#define RTCP_SENDER_INFO_SIZE 20 +#define RTCP_REPORT_BLOCK_SIZE 24 +#define RTCP_COMMON_HEADER_SIZE 4 +#define RTCP_SSRC_FIELD_SIZE 4 + +#ifdef __cplusplus +extern "C"{ +#endif + +/* RTCP common header */ + +typedef enum { + RTCP_SR = 200, + RTCP_RR = 201, + RTCP_SDES = 202, + RTCP_BYE = 203, + RTCP_APP = 204 +} rtcp_type_t; + + +typedef struct rtcp_common_header +{ +#ifdef ORTP_BIGENDIAN + uint16_t version:2; + uint16_t padbit:1; + uint16_t rc:5; + uint16_t packet_type:8; +#else + uint16_t rc:5; + uint16_t padbit:1; + uint16_t version:2; + uint16_t packet_type:8; +#endif + uint16_t length:16; +} rtcp_common_header_t; + +#define rtcp_common_header_set_version(ch,v) (ch)->version=v +#define rtcp_common_header_set_padbit(ch,p) (ch)->padbit=p +#define rtcp_common_header_set_rc(ch,rc) (ch)->rc=rc +#define rtcp_common_header_set_packet_type(ch,pt) (ch)->packet_type=pt +#define rtcp_common_header_set_length(ch,l) (ch)->length=htons(l) + +#define rtcp_common_header_get_version(ch) ((ch)->version) +#define rtcp_common_header_get padbit(ch) ((ch)->padbit) +#define rtcp_common_header_get_rc(ch) ((ch)->rc) +#define rtcp_common_header_get_packet_type(ch) ((ch)->packet_type) +#define rtcp_common_header_get_length(ch) ntohs((ch)->length) + + +/* SR or RR packets */ + +typedef struct sender_info +{ + uint32_t ntp_timestamp_msw; + uint32_t ntp_timestamp_lsw; + uint32_t rtp_timestamp; + uint32_t senders_packet_count; + uint32_t senders_octet_count; +} sender_info_t; + +uint64_t sender_info_get_ntp_timestamp(const sender_info_t *si); +#define sender_info_get_rtp_timestamp(si) ((si)->rtp_timestamp) +#define sender_info_get_packet_count(si) \ + ntohl((si)->senders_packet_count) +#define sender_info_get_octet_count(si) \ + ntohl((si)->senders_octet_count) + + +typedef struct report_block +{ + uint32_t ssrc; + uint32_t fl_cnpl;/*fraction lost + cumulative number of packet lost*/ + uint32_t ext_high_seq_num_rec; /*extended highest sequence number received */ + uint32_t interarrival_jitter; + uint32_t lsr; /*last SR */ + uint32_t delay_snc_last_sr; /*delay since last sr*/ +} report_block_t; + +#define report_block_get_ssrc(rb) \ + ntohl((rb)->ssrc) +#define report_block_get_fraction_lost(rb) \ + (((uint32_t)ntohl((rb)->fl_cnpl))>>24) +#define report_block_get_cum_packet_loss(rb) \ + (((uint32_t)ntohl((rb)->fl_cnpl)) & 0xFFFFFF) +#define report_block_get_high_ext_seq(rb) \ + ntohl(((report_block_t*)(rb))->ext_high_seq_num_rec) +#define report_block_get_interarrival_jitter(rb) \ + ntohl(((report_block_t*)(rb))->interarrival_jitter) +#define report_block_get_last_SR_time(rb) \ + ntohl(((report_block_t*)(rb))->lsr) +#define report_block_get_last_SR_delay(rb) \ + ntohl(((report_block_t*)(rb))->delay_snc_last_sr) + +#define report_block_set_fraction_lost(rb,fl)\ + ((rb)->fl_cnpl)=htonl( (ntohl((rb)->fl_cnpl) & 0xFFFFFF) | (((fl) & 0xFF)<<24)) + +#define report_block_set_cum_packet_lost(rb,cpl)\ + ((rb)->fl_cnpl)=htonl( (ntohl((rb)->fl_cnpl) & 0xFF000000) | (((cpl) & 0xFFFFFF))) + +/* SDES packets */ + +typedef enum { + RTCP_SDES_END = 0, + RTCP_SDES_CNAME = 1, + RTCP_SDES_NAME = 2, + RTCP_SDES_EMAIL = 3, + RTCP_SDES_PHONE = 4, + RTCP_SDES_LOC = 5, + RTCP_SDES_TOOL = 6, + RTCP_SDES_NOTE = 7, + RTCP_SDES_PRIV = 8, + RTCP_SDES_MAX = 9 +} rtcp_sdes_type_t; + +typedef struct sdes_chunk +{ + uint32_t csrc; +} sdes_chunk_t; + + +#define sdes_chunk_get_csrc(c) ntohl((c)->csrc) + +typedef struct sdes_item +{ + uint8_t item_type; + uint8_t len; + char content[1]; +} sdes_item_t; + +#define RTCP_SDES_MAX_STRING_SIZE 255 +#define RTCP_SDES_ITEM_HEADER_SIZE 2 +#define RTCP_SDES_CHUNK_DEFAULT_SIZE 1024 +#define RTCP_SDES_CHUNK_HEADER_SIZE (sizeof(sdes_chunk_t)) + +/* RTCP bye packet */ + +typedef struct rtcp_bye_reason +{ + uint8_t len; + char content[1]; +} rtcp_bye_reason_t; + +typedef struct rtcp_bye +{ + rtcp_common_header_t ch; + uint32_t ssrc[1]; /* the bye may contain several ssrc/csrc */ +} rtcp_bye_t; +#define RTCP_BYE_HEADER_SIZE sizeof(rtcp_bye_t) +#define RTCP_BYE_REASON_MAX_STRING_SIZE 255 + + + +typedef struct rtcp_sr{ + rtcp_common_header_t ch; + uint32_t ssrc; + sender_info_t si; + report_block_t rb[1]; +} rtcp_sr_t; + +typedef struct rtcp_rr{ + rtcp_common_header_t ch; + uint32_t ssrc; + report_block_t rb[1]; +} rtcp_rr_t; + +typedef struct rtcp_app{ + rtcp_common_header_t ch; + uint32_t ssrc; + char name[4]; +} rtcp_app_t; + +struct _RtpSession; +void rtp_session_rtcp_process_send(struct _RtpSession *s); +void rtp_session_rtcp_process_recv(struct _RtpSession *s); + +#define RTCP_DEFAULT_REPORT_INTERVAL 5 + + +/* packet parsing api */ + +/*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP +packet */ +bool_t rtcp_next_packet(mblk_t *m); +/* put the read pointer at the first RTCP packet of the compound packet (as before any previous calls ot rtcp_next_packet() */ +void rtcp_rewind(mblk_t *m); +/* get common header*/ +const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m); + +/*Sender Report accessors */ +/* check if this packet is a SR and if it is correct */ +bool_t rtcp_is_SR(const mblk_t *m); +uint32_t rtcp_SR_get_ssrc(const mblk_t *m); +const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m); +const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx); + +/*Receiver report accessors*/ +bool_t rtcp_is_RR(const mblk_t *m); +uint32_t rtcp_RR_get_ssrc(const mblk_t *m); +const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx); + +/*SDES accessors */ +bool_t rtcp_is_SDES(const mblk_t *m); +typedef void (*SdesItemFoundCallback)(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len); +void rtcp_sdes_parse(const mblk_t *m, SdesItemFoundCallback cb, void *user_data); + +/*BYE accessors */ +bool_t rtcp_is_BYE(const mblk_t *m); +bool_t rtcp_BYE_get_ssrc(const mblk_t *m, int idx, uint32_t *ssrc); +bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len); + +/*APP accessors */ +bool_t rtcp_is_APP(const mblk_t *m); +int rtcp_APP_get_subtype(const mblk_t *m); +uint32_t rtcp_APP_get_ssrc(const mblk_t *m); +/* name argument is supposed to be at least 4 characters (note: no '\0' written)*/ +void rtcp_APP_get_name(const mblk_t *m, char *name); +/* retrieve the data. when returning, data points directly into the mblk_t */ +void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/rtp.h b/linphone/oRTP/include/ortp/rtp.h new file mode 100644 index 000000000..5ecd95def --- /dev/null +++ b/linphone/oRTP/include/ortp/rtp.h @@ -0,0 +1,115 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef RTP_H +#define RTP_H + +#include +#include + +#define IPMAXLEN 20 +#define UDP_MAX_SIZE 1500 +#define RTP_FIXED_HEADER_SIZE 12 +#define RTP_DEFAULT_JITTER_TIME 80 /*miliseconds*/ +#define RTP_DEFAULT_MULTICAST_TTL 5 /*hops*/ +#define RTP_DEFAULT_MULTICAST_LOOPBACK 0 /*false*/ +#define RTP_DEFAULT_DSCP 0x00 /*best effort*/ + + + +typedef struct rtp_header +{ +#ifdef ORTP_BIGENDIAN + uint16_t version:2; + uint16_t padbit:1; + uint16_t extbit:1; + uint16_t cc:4; + uint16_t markbit:1; + uint16_t paytype:7; +#else + uint16_t cc:4; + uint16_t extbit:1; + uint16_t padbit:1; + uint16_t version:2; + uint16_t paytype:7; + uint16_t markbit:1; +#endif + uint16_t seq_number; + uint32_t timestamp; + uint32_t ssrc; + uint32_t csrc[16]; +} rtp_header_t; + + + + +typedef struct rtp_stats +{ + uint64_t packet_sent; + uint64_t sent; /* bytes sent */ + uint64_t recv; /* bytes of payload received and delivered in time to the application */ + uint64_t hw_recv; /* bytes of payload received */ + uint64_t packet_recv; /* number of packets received */ + uint64_t unavaillable; /* packets not availlable when they were queried */ + uint64_t outoftime; /* number of packets that were received too late */ + uint64_t cum_packet_loss; /* cumulative number of packet lost */ + uint64_t bad; /* packets that did not appear to be RTP */ + uint64_t discarded; /* incoming packets discarded because the queue exceeds its max size */ +} rtp_stats_t; + +#define RTP_TIMESTAMP_IS_NEWER_THAN(ts1,ts2) \ + ((uint32_t)((uint32_t)(ts1) - (uint32_t)(ts2))< (uint32_t)(1<<31)) + +#define RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(ts1,ts2) \ + ( ((uint32_t)((uint32_t)(ts1) - (uint32_t)(ts2))< (uint32_t)(1<<31)) && (ts1)!=(ts2) ) + +#define TIME_IS_NEWER_THAN(t1,t2) RTP_TIMESTAMP_IS_NEWER_THAN(t1,t2) + +#define TIME_IS_STRICTLY_NEWER_THAN(t1,t2) RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(t1,t2) + + +#ifdef __cplusplus +extern "C"{ +#endif + +/* packet api */ +/* the first argument is a mblk_t. The header is supposed to be not splitted */ +#define rtp_set_markbit(mp,value) ((rtp_header_t*)((mp)->b_rptr))->markbit=(value) +#define rtp_set_seqnumber(mp,seq) ((rtp_header_t*)((mp)->b_rptr))->seq_number=(seq) +#define rtp_set_timestamp(mp,ts) ((rtp_header_t*)((mp)->b_rptr))->timestamp=(ts) +#define rtp_set_ssrc(mp,_ssrc) ((rtp_header_t*)((mp)->b_rptr))->ssrc=(_ssrc) +void rtp_add_csrc(mblk_t *mp ,uint32_t csrc); +#define rtp_set_payload_type(mp,pt) ((rtp_header_t*)((mp)->b_rptr))->paytype=(pt) + +#define rtp_get_markbit(mp) (((rtp_header_t*)((mp)->b_rptr))->markbit) +#define rtp_get_timestamp(mp) (((rtp_header_t*)((mp)->b_rptr))->timestamp) +#define rtp_get_seqnumber(mp) (((rtp_header_t*)((mp)->b_rptr))->seq_number) +#define rtp_get_payload_type(mp) (((rtp_header_t*)((mp)->b_rptr))->paytype) +#define rtp_get_ssrc(mp) (((rtp_header_t*)((mp)->b_rptr))->ssrc) +#define rtp_get_cc(mp) (((rtp_header_t*)((mp)->b_rptr))->cc) +#define rtp_get_csrc(mp, idx) (((rtp_header_t*)((mp)->b_rptr))->csrc[idx]) + +int rtp_get_payload(mblk_t *packet, unsigned char **start); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/rtpsession.h b/linphone/oRTP/include/ortp/rtpsession.h new file mode 100644 index 000000000..5b127d9ca --- /dev/null +++ b/linphone/oRTP/include/ortp/rtpsession.h @@ -0,0 +1,380 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + * \file rtpsession.h + * \brief The RtpSession api + * + * The RtpSession objects represent a RTP session: once it is configured with + * local and remote network addresses and a payload type is given, it let you send + * and recv a media stream. +**/ + + +#ifndef RTPSESSION_H +#define RTPSESSION_H + + +#include +#include +#include +#include +#include +#include +#include +#include + + + +typedef enum { + RTP_SESSION_RECVONLY, + RTP_SESSION_SENDONLY, + RTP_SESSION_SENDRECV +} RtpSessionMode; + + +/*! Jitter buffer parameters +*/ +typedef struct _JBParameters{ + int min_size; /**< in milliseconds*/ + int nom_size; /**< idem */ + int max_size; /**< idem */ + bool_t adaptive; + bool_t pad[3]; + int max_packets; /**< max number of packets allowed to be queued in the jitter buffer */ +} JBParameters; + +typedef struct _JitterControl +{ + int count; + int jitt_comp; /* the user jitt_comp in miliseconds*/ + int jitt_comp_ts; /* the jitt_comp converted in rtp time (same unit as timestamp) */ + int adapt_jitt_comp_ts; + int64_t slide; + int64_t prev_slide; + float jitter; + int olddiff; + float inter_jitter; /* interarrival jitter as defined in the RFC */ + int corrective_step; + int corrective_slide; + bool_t adaptive; + bool_t enabled; +} JitterControl; + +typedef struct _WaitPoint +{ + ortp_mutex_t lock; + ortp_cond_t cond; + uint32_t time; + bool_t wakeup; +} WaitPoint; + +typedef struct _RtpTransport +{ + void *data; + ortp_socket_t (*t_getsocket)(struct _RtpTransport *t); + int (*t_sendto)(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen); + int (*t_recvfrom)(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen); + struct _RtpSession *session;//flags|=(flag) +#define rtp_session_unset_flag(session,flag) (session)->flags&=~(flag) +void rtp_session_uninit(RtpSession *session); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/rtpsignaltable.h b/linphone/oRTP/include/ortp/rtpsignaltable.h new file mode 100644 index 000000000..fb74e8ddc --- /dev/null +++ b/linphone/oRTP/include/ortp/rtpsignaltable.h @@ -0,0 +1,53 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef rtpsignaltable_h +#define rtpsignaltable_h + +#define RTP_CALLBACK_TABLE_MAX_ENTRIES 5 + +typedef void (*RtpCallback)(struct _RtpSession *, ...); + +struct _RtpSignalTable +{ + RtpCallback callback[RTP_CALLBACK_TABLE_MAX_ENTRIES]; + unsigned long user_data[RTP_CALLBACK_TABLE_MAX_ENTRIES]; + struct _RtpSession *session; + const char *signal_name; + int count; +}; + +typedef struct _RtpSignalTable RtpSignalTable; + +void rtp_signal_table_init(RtpSignalTable *table,struct _RtpSession *session, const char *signal_name); + +int rtp_signal_table_add(RtpSignalTable *table,RtpCallback cb, unsigned long user_data); + +void rtp_signal_table_emit(RtpSignalTable *table); + +/* emit but with a second arg */ +void rtp_signal_table_emit2(RtpSignalTable *table, unsigned long arg); + +/* emit but with a third arg */ +void rtp_signal_table_emit3(RtpSignalTable *table, unsigned long arg1, unsigned long arg2); + +int rtp_signal_table_remove_by_callback(RtpSignalTable *table,RtpCallback cb); + +#endif + diff --git a/linphone/oRTP/include/ortp/sessionset.h b/linphone/oRTP/include/ortp/sessionset.h new file mode 100644 index 000000000..1eadc759e --- /dev/null +++ b/linphone/oRTP/include/ortp/sessionset.h @@ -0,0 +1,139 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/** + * \file sessionset.h + * \brief Sending and receiving multiple streams together with only one thread. + * +**/ +#ifndef SESSIONSET_H +#define SESSIONSET_H + + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + + +#if !defined(_WIN32) && !defined(_WIN32_WCE) +/* UNIX */ +#include +#include +#include + +#define ORTP_FD_SET(d, s) FD_SET(d, s) +#define ORTP_FD_CLR(d, s) FD_CLR(d, s) +#define ORTP_FD_ISSET(d, s) FD_ISSET(d, s) +#define ORTP_FD_ZERO(s) FD_ZERO(s) + +typedef fd_set ortp_fd_set; + + +#else +/* WIN32 */ + +#define ORTP_FD_ZERO(s) \ + do { \ + unsigned int __i; \ + ortp_fd_set *__arr = (s); \ + for (__i = 0; __i < sizeof (ortp_fd_set) / sizeof (ortp__fd_mask); ++__i) \ + ORTP__FDS_BITS (__arr)[__i] = 0; \ + } while (0) +#define ORTP_FD_SET(d, s) (ORTP__FDS_BITS (s)[ORTP__FDELT(d)] |= ORTP__FDMASK(d)) +#define ORTP_FD_CLR(d, s) (ORTP__FDS_BITS (s)[ORTP__FDELT(d)] &= ~ORTP__FDMASK(d)) +#define ORTP_FD_ISSET(d, s) ((ORTP__FDS_BITS (s)[ORTP__FDELT(d)] & ORTP__FDMASK(d)) != 0) + + + +/* The fd_set member is required to be an array of longs. */ +typedef long int ortp__fd_mask; + + +/* Number of bits per word of `fd_set' (some code assumes this is 32). */ +#define ORTP__FD_SETSIZE 1024 + +/* It's easier to assume 8-bit bytes than to get CHAR_BIT. */ +#define ORTP__NFDBITS (8 * sizeof (ortp__fd_mask)) +#define ORTP__FDELT(d) ((d) / ORTP__NFDBITS) +#define ORTP__FDMASK(d) ((ortp__fd_mask) 1 << ((d) % ORTP__NFDBITS)) + + +/* fd_set for select and pselect. */ +typedef struct + { + ortp__fd_mask fds_bits[ORTP__FD_SETSIZE / ORTP__NFDBITS]; +# define ORTP__FDS_BITS(set) ((set)->fds_bits) + } ortp_fd_set; + + +#endif /*end WIN32*/ + +struct _SessionSet +{ + ortp_fd_set rtpset; +}; + + +typedef struct _SessionSet SessionSet; + +#define session_set_init(ss) ORTP_FD_ZERO(&(ss)->rtpset) + +SessionSet * session_set_new(void); +/** + * This macro adds the rtp session to the set. + * @param ss a set (SessionSet object) + * @param rtpsession a RtpSession +**/ +#define session_set_set(ss,rtpsession) ORTP_FD_SET((rtpsession)->mask_pos,&(ss)->rtpset) + +/** + * This macro tests if the session is part of the set. 1 is returned if true, 0 else. + *@param ss a set (#SessionSet object) + *@param rtpsession a rtp session + * +**/ +#define session_set_is_set(ss,rtpsession) ORTP_FD_ISSET((rtpsession)->mask_pos,&(ss)->rtpset) + +/** + * Removes the session from the set. + *@param ss a set of sessions. + *@param rtpsession a rtp session. + * + * +**/ +#define session_set_clr(ss,rtpsession) ORTP_FD_CLR((rtpsession)->mask_pos,&(ss)->rtpset) + +#define session_set_copy(dest,src) memcpy(&(dest)->rtpset,&(src)->rtpset,sizeof(ortp_fd_set)) + + +/** + * Frees a SessionSet. +**/ +void session_set_destroy(SessionSet *set); + + +int session_set_select(SessionSet *recvs, SessionSet *sends, SessionSet *errors); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/srtp.h b/linphone/oRTP/include/ortp/srtp.h new file mode 100644 index 000000000..f6dae3874 --- /dev/null +++ b/linphone/oRTP/include/ortp/srtp.h @@ -0,0 +1,44 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef ortp_srtp_h +#define ortp_srtp_h + +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + + +err_status_t ortp_srtp_init(void); +err_status_t ortp_srtp_create(srtp_t *session, const srtp_policy_t *policy); +err_status_t ortp_srtp_dealloc(srtp_t session); +err_status_t ortp_srtp_add_stream(srtp_t session, const srtp_policy_t *policy); + +bool_t ortp_srtp_supported(void); + +int srtp_transport_new(srtp_t srtp, RtpTransport **rtpt, RtpTransport **rtcpt ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/str_utils.h b/linphone/oRTP/include/ortp/str_utils.h new file mode 100644 index 000000000..ae073dd5b --- /dev/null +++ b/linphone/oRTP/include/ortp/str_utils.h @@ -0,0 +1,131 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef STR_UTILS_H +#define STR_UTILS_H + + +#include + + +typedef struct msgb +{ + struct msgb *b_prev; + struct msgb *b_next; + struct msgb *b_cont; + struct datab *b_datap; + unsigned char *b_rptr; + unsigned char *b_wptr; + uint32_t reserved1; + uint32_t reserved2; +} mblk_t; + +typedef struct datab +{ + unsigned char *db_base; + unsigned char *db_lim; + void (*db_freefn)(void*); + int db_ref; +} dblk_t; + +typedef struct _queue +{ + mblk_t _q_stopper; + int q_mcount; /*number of packet in the q */ +} queue_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void qinit(queue_t *q); + +void putq(queue_t *q, mblk_t *m); + +mblk_t * getq(queue_t *q); + +void insq(queue_t *q,mblk_t *emp, mblk_t *mp); + +void remq(queue_t *q, mblk_t *mp); + +mblk_t * peekq(queue_t *q); + +/* remove and free all messages in the q */ +#define FLUSHALL 0 +void flushq(queue_t *q, int how); + +void mblk_init(mblk_t *mp); + +/* allocates a mblk_t, that points to a datab_t, that points to a buffer of size size. */ +mblk_t *allocb(int size, int unused); +#define BPRI_MED 0 + +/* allocates a mblk_t, that points to a datab_t, that points to buf; buf will be freed using freefn */ +mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*) ); + +/* frees a mblk_t, and if the datab ref_count is 0, frees it and the buffer too */ +void freeb(mblk_t *m); + +/* frees recursively (follow b_cont) a mblk_t, and if the datab +ref_count is 0, frees it and the buffer too */ +void freemsg(mblk_t *mp); + +/* duplicates a mblk_t , buffer is not duplicated*/ +mblk_t *dupb(mblk_t *m); + +/* duplicates a complex mblk_t, buffer is not duplicated */ +mblk_t *dupmsg(mblk_t* m); + +/* returns the size of data of a message */ +int msgdsize(const mblk_t *mp); + +/* concatenates all fragment of a complex message*/ +void msgpullup(mblk_t *mp,int len); + +/* duplicates a single message, but with buffer included */ +mblk_t *copyb(mblk_t *mp); + +/* duplicates a complex message with buffer included */ +mblk_t *copymsg(mblk_t *mp); + +mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad); +void msgappend(mblk_t *mp, const char *data, int size, bool_t pad); + +mblk_t *concatb(mblk_t *mp, mblk_t *newm); + +#define qempty(q) (&(q)->_q_stopper==(q)->_q_stopper.b_next) +#define qfirst(q) ((q)->_q_stopper.b_next!=&(q)->_q_stopper ? (q)->_q_stopper.b_next : NULL) +#define qbegin(q) ((q)->_q_stopper.b_next) +#define qlast(q) ((q)->_q_stopper.b_prev!=&(q)->_q_stopper ? (q)->_q_stopper.b_prev : NULL) +#define qend(q,mp) ((mp)==&(q)->_q_stopper) +#define qnext(q,mp) ((mp)->b_next) + +typedef struct _msgb_allocator{ + queue_t q; +}msgb_allocator_t; + +void msgb_allocator_init(msgb_allocator_t *pa); +mblk_t *msgb_allocator_alloc(msgb_allocator_t *pa, int size); +void msgb_allocator_uninit(msgb_allocator_t *pa); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/stun.h b/linphone/oRTP/include/ortp/stun.h new file mode 100644 index 000000000..b7be9a4b3 --- /dev/null +++ b/linphone/oRTP/include/ortp/stun.h @@ -0,0 +1,406 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ==================================================================== + * The Vovida Software License, Version 1.0 + * + * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The names "VOCAL", "Vovida Open Communication Application Library", + * and "Vovida Open Communication Application Library (VOCAL)" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact vocal@vovida.org. + * + * 4. Products derived from this software may not be called "VOCAL", nor + * may "VOCAL" appear in their name, without prior written + * permission of Vovida Networks, Inc. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA + * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES + * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by Vovida + * Networks, Inc. and many individuals on behalf of Vovida Networks, + * Inc. For more information on Vovida Networks, Inc., please see + * . + * + */ + + +#ifndef __STUN_H__ +#define __STUN_H__ + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* if you change this version, change in makefile too */ +#define STUN_VERSION "0.94" + +#define STUN_MAX_STRING 256 +#define STUN_MAX_UNKNOWN_ATTRIBUTES 8 +#define STUN_MAX_MESSAGE_SIZE 2048 + +#define STUN_PORT 3478 + +/* define some basic types */ +typedef unsigned char UInt8; +typedef unsigned short UInt16; +typedef unsigned int UInt32; +#if defined(WIN32) || defined(_WIN32_WCE) +typedef unsigned __int64 UInt64; +#else +typedef unsigned long long UInt64; +#endif +typedef struct { unsigned char octet[16]; } UInt128; + +/* define a structure to hold a stun address */ +#define IPv4Family 0x01 +#define IPv6Family 0x02 + +/* define flags */ +#define ChangeIpFlag 0x04 +#define ChangePortFlag 0x02 + +/* define stun attribute */ +#define MappedAddress 0x0001 +#define ResponseAddress 0x0002 +#define ChangeRequest 0x0003 +#define SourceAddress 0x0004 +#define ChangedAddress 0x0005 +#define Username 0x0006 +#define Password 0x0007 +#define MessageIntegrity 0x0008 +#define ErrorCode 0x0009 +#define UnknownAttribute 0x000A +#define ReflectedFrom 0x000B +#define XorMappedAddress 0x0020 +#define XorOnly 0x0021 +#define ServerName 0x0022 +#define SecondaryAddress 0x0050 /* Non standard extention */ + +/* define types for a stun message */ +#define BindRequestMsg 0x0001 +#define BindResponseMsg 0x0101 +#define BindErrorResponseMsg 0x0111 +#define SharedSecretRequestMsg 0x0002 +#define SharedSecretResponseMsg 0x0102 +#define SharedSecretErrorResponseMsg 0x0112 + +typedef struct +{ + UInt16 msgType; + UInt16 msgLength; + UInt128 id; +} StunMsgHdr; + + +typedef struct +{ + UInt16 type; + UInt16 length; +} StunAtrHdr; + +typedef struct +{ + UInt16 port; + UInt32 addr; +} StunAddress4; + +typedef struct +{ + UInt8 pad; + UInt8 family; + StunAddress4 ipv4; +} StunAtrAddress4; + +typedef struct +{ + UInt32 value; +} StunAtrChangeRequest; + +typedef struct +{ + UInt16 pad; /* all 0 */ + UInt8 errorClass; + UInt8 number; + char reason[STUN_MAX_STRING]; + UInt16 sizeReason; +} StunAtrError; + +typedef struct +{ + UInt16 attrType[STUN_MAX_UNKNOWN_ATTRIBUTES]; + UInt16 numAttributes; +} StunAtrUnknown; + +typedef struct +{ + char value[STUN_MAX_STRING]; + UInt16 sizeValue; +} StunAtrString; + +typedef struct +{ + char hash[20]; +} StunAtrIntegrity; + +typedef enum +{ + HmacUnkown=0, + HmacOK, + HmacBadUserName, + HmacUnkownUserName, + HmacFailed +} StunHmacStatus; + +typedef struct +{ + StunMsgHdr msgHdr; + + bool_t hasMappedAddress; + StunAtrAddress4 mappedAddress; + + bool_t hasResponseAddress; + StunAtrAddress4 responseAddress; + + bool_t hasChangeRequest; + StunAtrChangeRequest changeRequest; + + bool_t hasSourceAddress; + StunAtrAddress4 sourceAddress; + + bool_t hasChangedAddress; + StunAtrAddress4 changedAddress; + + bool_t hasUsername; + StunAtrString username; + + bool_t hasPassword; + StunAtrString password; + + bool_t hasMessageIntegrity; + StunAtrIntegrity messageIntegrity; + + bool_t hasErrorCode; + StunAtrError errorCode; + + bool_t hasUnknownAttributes; + StunAtrUnknown unknownAttributes; + + bool_t hasReflectedFrom; + StunAtrAddress4 reflectedFrom; + + bool_t hasXorMappedAddress; + StunAtrAddress4 xorMappedAddress; + + bool_t xorOnly; + + bool_t hasServerName; + StunAtrString serverName; + + bool_t hasSecondaryAddress; + StunAtrAddress4 secondaryAddress; +} StunMessage; + + +/* Define enum with different types of NAT */ +typedef enum +{ + StunTypeUnknown=0, + StunTypeOpen, + StunTypeConeNat, + StunTypeRestrictedNat, + StunTypePortRestrictedNat, + StunTypeSymNat, + StunTypeSymFirewall, + StunTypeBlocked, + StunTypeFailure +} NatType; + + +#define MAX_MEDIA_RELAYS 500 +#define MAX_RTP_MSG_SIZE 1500 +#define MEDIA_RELAY_TIMEOUT 3*60 + +typedef struct +{ + int relayPort; /* media relay port */ + int fd; /* media relay file descriptor */ + StunAddress4 destination; /* NAT IP:port */ + time_t expireTime; /* if no activity after time, close the socket */ +} StunMediaRelay; + +typedef struct +{ + StunAddress4 myAddr; + StunAddress4 altAddr; + Socket myFd; + Socket altPortFd; + Socket altIpFd; + Socket altIpPortFd; + bool_t relay; /* true if media relaying is to be done */ + StunMediaRelay relays[MAX_MEDIA_RELAYS]; +} StunServerInfo; + +bool_t +stunParseMessage( char* buf, + unsigned int bufLen, + StunMessage *message, + bool_t verbose ); + +void +stunBuildReqSimple( StunMessage* msg, + const StunAtrString *username, + bool_t changePort, bool_t changeIp, unsigned int id ); + +unsigned int +stunEncodeMessage( const StunMessage *message, + char* buf, + unsigned int bufLen, + const StunAtrString *password, + bool_t verbose); + +void +stunCreateUserName(const StunAddress4 *addr, StunAtrString* username); + +void +stunGetUserNameAndPassword( const StunAddress4 *dest, + StunAtrString* username, + StunAtrString* password); + +void +stunCreatePassword(const StunAtrString *username, StunAtrString* password); + +int +stunRand(void); + +UInt64 +stunGetSystemTimeSecs(void); + +/* find the IP address of a the specified stun server - return false is fails parse */ +bool_t +stunParseServerName( char* serverName, StunAddress4 *stunServerAddr); + +bool_t +stunParseHostName( char* peerName, + UInt32 *ip, + UInt16 *portVal, + UInt16 defaultPort ); + +/* return true if all is OK + Create a media relay and do the STERN thing if startMediaPort is non-zero */ +bool_t +stunInitServer(StunServerInfo *info, + const StunAddress4 *myAddr, + const StunAddress4 *altAddr, + int startMediaPort, + bool_t verbose); + +void +stunStopServer(StunServerInfo *info); + +#if 0 /* no usefull here */ +/* return true if all is OK */ +bool_t +stunServerProcess(StunServerInfo *info, bool_t verbose); +#endif + +/* returns number of address found - take array or addres */ +int +stunFindLocalInterfaces(UInt32* addresses, int maxSize ); + +int +stunTest( StunAddress4 *dest, int testNum, bool_t verbose, StunAddress4* srcAddr, StunAddress4 *sMappedAddr, StunAddress4* sChangedAddr); + +NatType +stunNatType( StunAddress4 *dest, bool_t verbose, + bool_t* preservePort, /* if set, is return for if NAT preservers ports or not */ + bool_t* hairpin , /* if set, is the return for if NAT will hairpin packets */ + int port, /* port to use for the test, 0 to choose random port */ + StunAddress4* sAddr /* NIC to use */ + ); + +bool_t +stunServerProcessMsg( char* buf, + unsigned int bufLen, + StunAddress4 *from, + StunAddress4 *secondary, + StunAddress4 *myAddr, + StunAddress4 *altAddr, + StunMessage *resp, + StunAddress4 *destination, + StunAtrString *hmacPassword, + bool_t* changePort, + bool_t* changeIp, + bool_t verbose); + +int +stunOpenSocket( StunAddress4 *dest, + StunAddress4* mappedAddr, + int port, + StunAddress4* srcAddr, + bool_t verbose ); + +bool_t +stunOpenSocketPair(StunAddress4 *dest, + StunAddress4* mapAddr_rtp, + StunAddress4* mapAddr_rtcp, + int* fd1, int* fd2, + int srcPort, StunAddress4* srcAddr, + bool_t verbose); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/linphone/oRTP/include/ortp/stun_udp.h b/linphone/oRTP/include/ortp/stun_udp.h new file mode 100644 index 000000000..d4a607946 --- /dev/null +++ b/linphone/oRTP/include/ortp/stun_udp.h @@ -0,0 +1,142 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ==================================================================== + * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * . + * + */ + +#ifndef __STUN_UDP_H__ +#define __STUN_UDP_H__ + +#ifndef __cplusplus +//#define bool int +//#define false 0 +//#define true 1 +#endif + +#ifdef __MACH__ +#include +#ifndef _SOCKLEN_T +typedef int socklen_t; +#endif +#endif + +#include + +#if !defined(_WIN32_WCE) +#include +#endif + +#if defined(WIN32) || defined(_WIN32_WCE) +#define snprintf _snprintf + +#include +/* #include */ + +typedef int socklen_t; +typedef SOCKET Socket; + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE + +typedef LONGLONG Int64; + +#else + +typedef int Socket; +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 + +#define closesocket(fd) close(fd) + +#define WSANOTINITIALISED EPROTONOSUPPORT + +#endif + +#ifdef __cplusplus +extern "C"{ +#endif + +int getErrno(void); + +/* Open a UDP socket to receive on the given port - if port is 0, pick a a + port, if interfaceIp!=0 then use ONLY the interface specified instead of + all of them */ +Socket +openPort( unsigned short port, unsigned int interfaceIp, + bool_t verbose); + + +/* recive a UDP message */ +bool_t +getMessage( Socket fd, char* buf, int* len, + unsigned int* srcIp, unsigned short* srcPort, + bool_t verbose); + + +/* send a UDP message */ +bool_t +sendMessage( Socket fd, char* msg, int len, + unsigned int dstIp, unsigned short dstPort, + bool_t verbose); + + +/* set up network - does nothing in unix but needed for windows */ +void +initNetwork(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/oRTP/include/ortp/telephonyevents.h b/linphone/oRTP/include/ortp/telephonyevents.h new file mode 100644 index 000000000..284e097ee --- /dev/null +++ b/linphone/oRTP/include/ortp/telephonyevents.h @@ -0,0 +1,105 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + * \file telephonyevents.h + * \brief Receiving and sending telephone events (RFC2833) + * +**/ + + +#ifndef TELEPHONYEVENTS_H +#define TELEPHONYEVENTS_H + +#include + + +struct _telephone_event +{ +#ifdef ORTP_BIGENDIAN + uint32_t event:8; + uint32_t E:1; + uint32_t R:1; + uint32_t volume:6; + uint32_t duration:16; +#else + uint32_t event:8; + uint32_t volume:6; + uint32_t R:1; + uint32_t E:1; + uint32_t duration:16; +#endif +}; + +typedef struct _telephone_event telephone_event_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* tell if the session supports telephony events. For this the telephony events payload_type + must be present in the rtp profile used by the session */ + +/* low level functions */ +int rtp_session_telephone_events_supported(RtpSession *session); +int rtp_session_send_telephone_events_supported(RtpSession *session); +int rtp_session_recv_telephone_events_supported(RtpSession *session); + +mblk_t *rtp_session_create_telephone_event_packet(RtpSession *session, int start); + +int rtp_session_add_telephone_event(RtpSession *session, + mblk_t *packet, uint8_t event, int end, uint8_t volume, uint16_t duration); + +int rtp_session_read_telephone_event(RtpSession *session, + mblk_t *packet,telephone_event_t **tab); + +/* high level functions*/ +int rtp_session_send_dtmf(RtpSession *session, char dtmf, uint32_t userts); +int rtp_session_send_dtmf2(RtpSession *session, char dtmf, uint32_t userts, int duration); +/* for high level telephony event callback */ +void rtp_session_check_telephone_events(RtpSession *session, mblk_t *m0); + +#ifdef __cplusplus +} +#endif + +/* the size allocated for telephony events packets */ +#define TELEPHONY_EVENTS_ALLOCATED_SIZE (4*sizeof(telephone_event_t)) + +/* list of named events */ +#define TEV_DTMF_0 (0) +#define TEV_DTMF_1 (1) +#define TEV_DTMF_2 (2) +#define TEV_DTMF_3 (3) +#define TEV_DTMF_4 (4) +#define TEV_DTMF_5 (5) +#define TEV_DTMF_6 (6) +#define TEV_DTMF_7 (7) +#define TEV_DTMF_8 (8) +#define TEV_DTMF_9 (9) +#define TEV_DTMF_STAR (10) +#define TEV_DTMF_POUND (11) +#define TEV_DTMF_A (12) +#define TEV_DTMF_B (13) +#define TEV_DTMF_C (14) +#define TEV_DTMF_D (15) +#define TEV_FLASH (16) + + +#endif diff --git a/linphone/oRTP/oRTP.prj b/linphone/oRTP/oRTP.prj new file mode 100644 index 000000000..1c406516d --- /dev/null +++ b/linphone/oRTP/oRTP.prj @@ -0,0 +1,193 @@ +# Anjuta Version 1.1.97 +Compatibility Level: 1 + + +Some description + + + + + + + + + + + + + + + + + +props.file.type=project + +anjuta.version=1.1.97 +anjuta.compatibility.level=1 + +project.name=oRTP +project.type=GENERIC +project.target.type=EXECUTABLE +project.version=0.99 +project.author=Simon Morlat +project.source.target=Rtp stack +project.has.gettext=0 +project.gui.command= +project.programming.language=C +project.excluded.modules=intl + +project.config.extra.modules.before= +project.config.extra.modules.after= +project.config.blocked=1 +project.config.disable.overwriting=1 1 1 1 1 1 1 1 1 + +project.menu.entry=oRTP Version 0.99 +project.menu.group=Application +project.menu.comment=oRTP Version 0.99 +project.menu.icon= +project.menu.need.terminal=0 + +project.configure.options= +anjuta.program.arguments= +preferences.build.option.jobs=0 +preferences.build.option.silent=0 +preferences.build.option.autosave=1 +preferences.anjuta.make.options=-k +preferences.make=make +preferences.build.option.keep.going=1 +preferences.build.option.warn.undef=0 +preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss +preferences.autoformat.style=Style of Kangleipak +preferences.indent.opening=0 +preferences.autoformat.disable=0 +preferences.indent.automatic=1 +preferences.use.tabs=1 +preferences.indent.size=4 +preferences.tabsize=4 +preferences.indent.closing=0 + +module.include.name=. +module.include.type= +module.include.files=\ + src/errno-win32.h\ + src/export.h\ + src/ortp-config-win32.h\ + src/ortp.h\ + src/payloadtype.h\ + src/port_fct.h\ + src/rtp.h\ + src/rtpmod.h\ + src/rtpport.h\ + src/rtpsession.h\ + src/rtpsignaltable.h\ + src/rtptimer.h\ + src/scheduler.h\ + src/sessionset.h\ + src/str_utils.h\ + src/telephonyevents.h\ + src/rtcp.h\ + ortp-config.h + +module.source.name=. +module.source.type= +module.source.files=\ + src/avprofile.c\ + src/export.c\ + src/mrtprecv.c\ + src/mrtpsend.c\ + src/ortp.c\ + src/ortpdlkm.c\ + src/payloadtype.c\ + src/port_fct.c\ + src/posixtimer.c\ + src/rtpmemtest.c\ + src/rtpmod.c\ + src/rtpparse.c\ + src/rtprecv.c\ + src/rtpsend.c\ + src/rtpsession.c\ + src/rtpsignaltable.c\ + src/rtptimer.c\ + src/scheduler.c\ + src/sessionset.c\ + src/str_utils.c\ + src/telephonyevents.c\ + src/test_tevrecv.c\ + src/test_tevsend.c\ + src/test_timer.c\ + src/tevmrtprecv.c\ + src/tevrtprecv.c\ + src/tevrtpsend.c + +module.pixmap.name=. +module.pixmap.type= +module.pixmap.files=\ + docs/html/home.png\ + docs/html/left.png\ + docs/html/right.png\ + docs/html/up.png + +module.data.name=. +module.data.type= +module.data.files= + +module.help.name=. +module.help.type= +module.help.files= + +module.doc.name=. +module.doc.type= +module.doc.files=\ + build/win32/oRTP/README\ + AUTHORS\ + COPYING\ + ChangeLog\ + INSTALL\ + NEWS\ + README\ + TODO\ + docs/tmpl/multiplexing.sgml\ + docs/tmpl/ortp-unused.sgml\ + docs/tmpl/payloads.sgml\ + docs/tmpl/rtpsessionapi.sgml\ + docs/tmpl/stackinit.sgml\ + docs/tmpl/stackmanagement.sgml\ + docs/tmpl/telephoneevents.sgml\ + docs/sgml/payloads.sgml\ + docs/sgml/tree_index.sgml\ + docs/sgml/object_index.sgml\ + docs/sgml/rtpsessionapi.sgml\ + docs/sgml/stackmanagement.sgml\ + docs/sgml/multiplexing.sgml\ + docs/sgml/telephoneevents.sgml\ + docs/ortp-docs.sgml\ + docs/html/book1.html\ + docs/html/ortpapi.html\ + docs/html/ortp-stack-management-functions.html\ + docs/html/ortp-rtpsession-api.html\ + docs/html/ortp-rtp-payloads-and-profiles.html\ + docs/html/ortp-multiplexing-sessions-(in-a-one-thread-design).html\ + docs/html/ortp-telephone-events-(rfc2833)-.html\ + docs/html/index.sgml\ + docs/html/ortp-library-management-functions.html + +module.po.files= + +compiler.options.supports= +compiler.options.include.paths=\ + .\ + .. +compiler.options.library.paths= +compiler.options.libraries= +compiler.options.libraries.selected= +compiler.options.defines=\ + HAVE_CONFIG_H +compiler.options.defines.selected= +compiler.options.warning.buttons=0 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0 +compiler.options.optimize.buttons=0 0 1 0 +compiler.options.other.buttons=1 0 +compiler.options.other.c.flags= +compiler.options.other.l.flags= +compiler.options.other.l.libs= + +project.src.paths= diff --git a/linphone/oRTP/oRTP.pws b/linphone/oRTP/oRTP.pws new file mode 100644 index 000000000..342999ad9 --- /dev/null +++ b/linphone/oRTP/oRTP.pws @@ -0,0 +1,67 @@ + +[executer] +RunInTerminal=true + +[Project DBase] +ShowLocals=true + +[filenumbers] +0=1846 +1=270 +2=1 +3=34 +4=43 +5=1 +6=4 +7=27 +8=9 + +[filemarkers] +0= +1= +2= +3= +4= +5= +6= +7= +8= + +[File View] +filter.file.unmatch=*.so *.o *.a *.la +filter.file.ignore.hidden=0 +filter.dir.ignore.hidden=0 + +[filelist] +0=/home/sangamon/src/devel/linphone/oRTP/src/rtpsession.c +1=/home/sangamon/src/devel/linphone/oRTP/src/rtpsession.h +2=/home/sangamon/src/devel/linphone/oRTP/src/rtcp.h +3=/home/sangamon/src/devel/linphone/oRTP/src/scheduler.c + +[Project Tree] +0=0 +1=0:1 + +[File Tree] +0=0 + +[replace_text] +0=telephone_event +1=session->rtp +2=PAYLOAD_AUDIO_CONTINUOUS +3=ortp_global_stats +4=session->rtp.rq +5=session->rtp.wq + +[find_text] +0=rtp_session_create +1=chunk_item_new +2=rtcp_calculate_sdes_padding +3=rtp_session_process +4=scheduler +5=rtp +6=rtp_send +7=RtpSession + +[find_in_files] +0=exit diff --git a/linphone/oRTP/ortp.doxygen.in b/linphone/oRTP/ortp.doxygen.in new file mode 100644 index 000000000..69ba62da2 --- /dev/null +++ b/linphone/oRTP/ortp.doxygen.in @@ -0,0 +1,225 @@ +# Doxyfile 1.5.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = oRTP +PROJECT_NUMBER = @ORTP_VERSION@ +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = @srcdir@/src @srcdir@/include/ortp +FILE_PATTERNS = *.c *.h +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = @srcdir@/src/tests +EXAMPLE_PATTERNS = *.c +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/linphone/oRTP/ortp.pc.in b/linphone/oRTP/ortp.pc.in new file mode 100644 index 000000000..8084faecd --- /dev/null +++ b/linphone/oRTP/ortp.pc.in @@ -0,0 +1,10 @@ +# This is a comment +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ + +Name: oRTP +Description: Implement the RFC3550 (RTP) with a easy to use API with high and low level access. +Version: @ORTP_PKGCONFIG_VERSION@ +Libs: -L@libdir@ -lortp @ORTPDEPS_LIBS@ +Cflags: -I@includedir@ @ORTPDEPS_CFLAGS@ diff --git a/linphone/oRTP/ortp.spec.in b/linphone/oRTP/ortp.spec.in new file mode 100644 index 000000000..f73cdfcdf --- /dev/null +++ b/linphone/oRTP/ortp.spec.in @@ -0,0 +1,83 @@ +# -*- rpm-spec -*- +# +# ortp -- Real-time Transport Protocol Stack +# +# Default is optimized for Pentium IV but will execute on Pentium II & +# later (i686). + +%ifarch %ix86 +%define ortp_cpu pentium4 +%endif + +Summary: Real-time Transport Protocol Stack +Name: ortp +Version: @ORTP_PKGCONFIG_VERSION@ +Release: 1 +License: LGPL +Group: Applications/Communications +URL: http://linphone.org/ortp/ +Source0: %{name}-@ORTP_PKGCONFIG_VERSION@.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot +%ifarch %ix86 +BuildArch: i686 +%endif + +%description +oRTP is a LGPL licensed C library implementing the RTP protocol +(rfc1889). It is available for most unix clones (primilarly Linux and +HP-UX), and Microsoft Windows. + +%package devel +Summary: Headers, libraries and docs for the oRTP library +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +oRTP is a LGPL licensed C library implementing the RTP protocol +(rfc1889). It is available for most unix clones (primilarly Linux and +HP-UX), and Microsoft Windows. + +This package contains header files and development libraries needed to +develop programs using the oRTP library. + +%ifarch %ix86 +%define ortp_arch_cflags -malign-double -march=i686 -mcpu=%{ortp_cpu} +%else +# Must be non-empty +%define ortp_arch_cflags -Wall +%endif +%define ortp_cflags %ortp_arch_cflags -Wall -g -pipe -pthread -O3 -fomit-frame-pointer -fno-schedule-insns -fschedule-insns2 -fstrict-aliasing + +%prep +%setup -q + +%build +%configure \ + --enable-shared \ + --enable-static +%{__make} -j$RPM_BUILD_NCPUS CFLAGS="%ortp_cflags" CXXFLAGS="%ortp_cflags" + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%doc AUTHORS COPYING ChangeLog INSTALL NEWS README TODO +%{_libdir}/*.so.* + +%files devel +%defattr(-,root,root,-) +%doc doc/html +%{_libdir}/*.la +%{_libdir}/*.a +%{_libdir}/*.so +%{_libdir}/pkgconfig/*.pc +%{_includedir} + +%changelog +* Tue Oct 25 2005 Francois-Xavier Kowalski +- Add to oRTP distribution with "make rpm" target diff --git a/linphone/oRTP/pkg.list b/linphone/oRTP/pkg.list new file mode 100644 index 000000000..e02f91683 --- /dev/null +++ b/linphone/oRTP/pkg.list @@ -0,0 +1,38 @@ +# -*- rpm-spec -*- ############################################################ +# +# EPM list file. See epm(1) and epm.list(5) for details +# +############################################################################### + +%product ${SUMMARY} +%version ${VERSION} +%release ${RELEASE} +%description ${SUMMARY} +%vendor ${VENDOR} +%copyright ${LICENSE} +%license ${LICENSE} +%readme ${srcdir}/README +%packager ${PACKAGER} + +%system linux + +# Package all-in one: should be split later on... +%provides ortp-devel + +%postinstall << EOF +ldconfig 2>&1 | logger -i -s -t ${PACKAGE} +EOF + +%postremove << EOF +ldconfig 2>&1 | logger -i -s -t ${PACKAGE} +EOF + +%system hpux + +%system all + +%include files.list + +%provides ortp +%replaces ortp + diff --git a/linphone/oRTP/src/.cvsignore b/linphone/oRTP/src/.cvsignore new file mode 100644 index 000000000..fec93a5ec --- /dev/null +++ b/linphone/oRTP/src/.cvsignore @@ -0,0 +1,15 @@ +*.lo +.deps +.libs +Makefile +Makefile.in +libortp.la +mrtprecv +mrtpsend +rtpmemtest +rtprecv +rtpsend +test_timer +tevmrtprecv +tevrtprecv +tevrtpsend diff --git a/linphone/oRTP/src/Makefile.am b/linphone/oRTP/src/Makefile.am new file mode 100644 index 000000000..3a6ca3780 --- /dev/null +++ b/linphone/oRTP/src/Makefile.am @@ -0,0 +1,41 @@ + +EXTRA_DIST=ortp-config-win32.h dll_entry.c + +AM_CFLAGS= $(PTHREAD_CFLAGS) -I$(top_srcdir) $(TRUESPEECH_CFLAGS) $(SRTP_CFLAGS) +AM_LDFLAGS= $(PTHREAD_LDFLAGS) + +INCLUDES=-I$(top_srcdir)/include/ + +lib_LTLIBRARIES = libortp.la + +libortp_la_SOURCES= str_utils.c \ + port.c \ + rtpparse.c \ + rtpsession.c \ + rtpsession_inet.c \ + rtpsession_priv.h \ + jitterctl.c jitterctl.h \ + rtpsignaltable.c \ + rtptimer.c rtptimer.h \ + posixtimer.c \ + ortp.c \ + scheduler.c scheduler.h \ + avprofile.c \ + sessionset.c \ + telephonyevents.c \ + payloadtype.c \ + rtcp.c \ + utils.c utils.h \ + rtcpparse.c \ + event.c \ + stun.c stun_udp.c \ + srtp.c \ + b64.c + + +libortp_la_LIBADD= $(PTHREAD_LIBS) -lm $(SRTP_LIBS) + +libortp_la_LDFLAGS= -version-info $(LIBORTP_SO_VERSION) + + +SUBDIRS= . tests diff --git a/linphone/oRTP/src/avprofile.c b/linphone/oRTP/src/avprofile.c new file mode 100644 index 000000000..8939abf35 --- /dev/null +++ b/linphone/oRTP/src/avprofile.c @@ -0,0 +1,483 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include + +char offset127=127; +char offset0xD5=(char)0xD5; +char offset0[4] = {0x00, 0x00, 0x00, 0x00}; + +/* + * IMPORTANT : some compiler don't support the tagged-field syntax. Those + * macros are there to trap the problem This means that if you want to keep + * portability, payload types must be defined with their fields in the right + * order. + */ +#if defined(_ISOC99_SOURCE) +// ISO C99's tagged syntax +#define TYPE(val) .type=(val) +#define CLOCK_RATE(val) .clock_rate=(val) +#define BITS_PER_SAMPLE(val) .bits_per_sample=(val) +#define ZERO_PATTERN(val) .zero_pattern=(val) +#define PATTERN_LENGTH(val) .pattern_length=(val) +#define NORMAL_BITRATE(val) .normal_bitrate=(val) +#define MIME_TYPE(val) .mime_type=(val) +#define CHANNELS(val) .channels=(val) +#define FMTP(val) .FMTP=(val) +#elif defined(__GNUC__) +// GCC's legacy tagged syntax (even old versions have it) +#define TYPE(val) type: (val) +#define CLOCK_RATE(val) clock_rate: (val) +#define BITS_PER_SAMPLE(val) bits_per_sample: (val) +#define ZERO_PATTERN(val) zero_pattern: (val) +#define PATTERN_LENGTH(val) pattern_length: (val) +#define NORMAL_BITRATE(val) normal_bitrate: (val) +#define MIME_TYPE(val) mime_type: (val) +#define CHANNELS(val) channels: (val) +#define FMTP(val) FMTP: (val) +#else +// No tagged syntax supported +#define TYPE(val) (val) +#define CLOCK_RATE(val) (val) +#define BITS_PER_SAMPLE(val) (val) +#define ZERO_PATTERN(val) (val) +#define PATTERN_LENGTH(val) (val) +#define NORMAL_BITRATE(val) (val) +#define MIME_TYPE(val) (val) +#define CHANNELS(val) (val) +#define FMTP(val) (val) + +#endif + +PayloadType payload_type_pcmu8000={ + TYPE( PAYLOAD_AUDIO_CONTINUOUS), + CLOCK_RATE( 8000), + BITS_PER_SAMPLE(8), + ZERO_PATTERN( &offset127), + PATTERN_LENGTH( 1), + NORMAL_BITRATE( 64000), + MIME_TYPE ("PCMU"), + CHANNELS(1) +}; + +PayloadType payload_type_pcma8000={ + TYPE( PAYLOAD_AUDIO_CONTINUOUS), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(8), + ZERO_PATTERN( &offset0xD5), + PATTERN_LENGTH( 1), + NORMAL_BITRATE( 64000), + MIME_TYPE ("PCMA"), + CHANNELS(1) +}; + +PayloadType payload_type_pcm8000={ + TYPE( PAYLOAD_AUDIO_CONTINUOUS), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(16), + ZERO_PATTERN( offset0), + PATTERN_LENGTH(1), + NORMAL_BITRATE( 128000), + MIME_TYPE ("PCM"), + CHANNELS(1) +}; + +PayloadType payload_type_l16_mono={ + TYPE( PAYLOAD_AUDIO_CONTINUOUS), + CLOCK_RATE(44100), + BITS_PER_SAMPLE(16), + ZERO_PATTERN( offset0 ), + PATTERN_LENGTH(2), + NORMAL_BITRATE(705600), /* (44100 x 16bits per frame x 1 channel) */ + MIME_TYPE ("L16"), + CHANNELS(1) +}; + +PayloadType payload_type_l16_stereo={ + TYPE( PAYLOAD_AUDIO_CONTINUOUS), + CLOCK_RATE(44100), + BITS_PER_SAMPLE(32), /* 16bits x 2 channels */ + ZERO_PATTERN( offset0 ), + PATTERN_LENGTH(4), + NORMAL_BITRATE(1411200), /* (44100 x 16bits per frame x 2 channels) */ + MIME_TYPE ("L16"), + CHANNELS(2) +}; + +PayloadType payload_type_lpc1016={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN( NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 2400), + MIME_TYPE ("1016"), + CHANNELS(1) +}; + + +PayloadType payload_type_gsm= +{ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 13500), + MIME_TYPE ("GSM"), + CHANNELS(1) +}; + +PayloadType payload_type_lpc= +{ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 5600), /* 20ms / 14 octets per frame */ + MIME_TYPE ("LPC"), + CHANNELS(1) +}; + +PayloadType payload_type_g7231= +{ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 6300), + MIME_TYPE ("G723"), + CHANNELS(1) +}; + +PayloadType payload_type_g729={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 8000), + MIME_TYPE ("G729"), + CHANNELS(1) +}; + +PayloadType payload_type_g726_40={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 8000), + MIME_TYPE ("G726-40"), + CHANNELS(1) +}; + +PayloadType payload_type_g726_32={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 8000), + MIME_TYPE ("G726-32"), + CHANNELS(1) +}; + +PayloadType payload_type_g726_24={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 8000), + MIME_TYPE ("G726-24"), + CHANNELS(1) +}; + +PayloadType payload_type_g726_16={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE( 8000), + MIME_TYPE ("G726-16"), + CHANNELS(1) +}; + +PayloadType payload_type_mpv= +{ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE( 256000), + MIME_TYPE ("MPV"), + CHANNELS(0) +}; + + +PayloadType payload_type_h261={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(0), + MIME_TYPE ("H261"), + CHANNELS(0) +}; + +PayloadType payload_type_h263={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(256000), + MIME_TYPE ("H263"), + CHANNELS(0) +}; + +PayloadType payload_type_truespeech= +{ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE( 0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH( 0), + NORMAL_BITRATE(8536), + MIME_TYPE ("TSP0"), + CHANNELS(0) +}; + + +#ifdef __cplusplus +extern "C" +{ +#endif +RtpProfile av_profile; +#ifdef __cplusplus +} +#endif + + +void av_profile_init(RtpProfile *profile) +{ + rtp_profile_clear_all(profile); + profile->name="AV profile"; + rtp_profile_set_payload(profile,0,&payload_type_pcmu8000); + rtp_profile_set_payload(profile,1,&payload_type_lpc1016); + rtp_profile_set_payload(profile,3,&payload_type_gsm); + rtp_profile_set_payload(profile,7,&payload_type_lpc); + rtp_profile_set_payload(profile,4,&payload_type_g7231); + rtp_profile_set_payload(profile,8,&payload_type_pcma8000); + rtp_profile_set_payload(profile,10,&payload_type_l16_stereo); + rtp_profile_set_payload(profile,11,&payload_type_l16_mono); + rtp_profile_set_payload(profile,18,&payload_type_g729); + rtp_profile_set_payload(profile,31,&payload_type_h261); + rtp_profile_set_payload(profile,32,&payload_type_mpv); + rtp_profile_set_payload(profile,34,&payload_type_h263); +} + +/* these are extra payload types that can be used dynamically */ +PayloadType payload_type_lpc1015={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(2400), + MIME_TYPE ("1015"), + CHANNELS(1) +}; + +PayloadType payload_type_speex_nb={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(8000), /*not true: 8000 is the minimum*/ + MIME_TYPE ("speex"), + CHANNELS(1) +}; + +PayloadType payload_type_speex_wb={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(16000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(28000), + MIME_TYPE ("speex"), + CHANNELS(1) +}; + +PayloadType payload_type_speex_uwb={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(32000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(28000), + MIME_TYPE ("speex"), + CHANNELS(1) +}; + +PayloadType payload_type_ilbc={ + TYPE( PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(13300), /* the minimum, with 30ms frames */ + MIME_TYPE ("iLBC"), + CHANNELS(1), +}; + +PayloadType payload_type_amr={ + TYPE(PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(0), + MIME_TYPE ("AMR"), + CHANNELS(1) +}; + +PayloadType payload_type_amrwb={ + TYPE(PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(16000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(0), + MIME_TYPE ("AMR-WB"), + CHANNELS(1) +}; + +PayloadType payload_type_mp4v={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(0), + MIME_TYPE ("MP4V-ES"), + CHANNELS(0) +}; + + +PayloadType payload_type_evrc0={ + TYPE(PAYLOAD_AUDIO_PACKETIZED), + CLOCK_RATE(8000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(0), + MIME_TYPE ("EVRC0"), + CHANNELS(1) +}; + + +PayloadType payload_type_h263_1998={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(256000), + MIME_TYPE ("H263-1998"), + CHANNELS(0) +}; + +PayloadType payload_type_h263_2000={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(0), + MIME_TYPE ("H263-2000"), + CHANNELS(0) +}; + +PayloadType payload_type_theora={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(256000), + MIME_TYPE ("theora"), + CHANNELS(0) +}; + +PayloadType payload_type_h264={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(256000), + MIME_TYPE ("H264"), + CHANNELS(0) +}; + +PayloadType payload_type_x_snow={ + TYPE( PAYLOAD_VIDEO), + CLOCK_RATE(90000), + BITS_PER_SAMPLE(0), + ZERO_PATTERN(NULL), + PATTERN_LENGTH(0), + NORMAL_BITRATE(256000), + MIME_TYPE ("x-snow"), + CHANNELS(0) +}; + +PayloadType payload_type_t140={ + PAYLOAD_AUDIO_PACKETIZED, /*type */ + 1000, + 0, + NULL, + 0, + 0, + "t140", + 0, + 0 +}; + +PayloadType payload_type_x_udpftp={ + PAYLOAD_AUDIO_PACKETIZED, /*type */ + 1000, + 0, + NULL, + 0, + 0, + "x-udpftp", + 0, + 0 +}; + diff --git a/linphone/oRTP/src/b64.c b/linphone/oRTP/src/b64.c new file mode 100644 index 000000000..352367198 --- /dev/null +++ b/linphone/oRTP/src/b64.c @@ -0,0 +1,606 @@ +/* ///////////////////////////////////////////////////////////////////////////// + * File: b64.c + * + * Purpose: Implementation file for the b64 library + * + * Created: 18th October 2004 + * Updated: 3rd May 2008 + * + * Home: http://synesis.com.au/software/ + * + * Copyright (c) 2004-2008, Matthew Wilson and Synesis Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of + * any contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////////// */ + + +/** \file b64.c Implementation file for the b64 library + */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Version information + */ + +#ifndef B64_DOCUMENTATION_SKIP_SECTION +# define B64_VER_C_B64_MAJOR 1 +# define B64_VER_C_B64_MINOR 2 +# define B64_VER_C_B64_REVISION 3 +# define B64_VER_C_B64_EDIT 17 +#endif /* !B64_DOCUMENTATION_SKIP_SECTION */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Includes + */ + +#include "ortp/b64.h" + +#include +#include + +/* ///////////////////////////////////////////////////////////////////////////// + * Constants and definitions + */ + +#ifndef B64_DOCUMENTATION_SKIP_SECTION +# define NUM_PLAIN_DATA_BYTES (3) +# define NUM_ENCODED_DATA_BYTES (4) +#endif /* !B64_DOCUMENTATION_SKIP_SECTION */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Macros + */ + +#ifndef NUM_ELEMENTS +# define NUM_ELEMENTS(x) (sizeof(x) / sizeof(x[0])) +#endif /* !NUM_ELEMENTS */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Warnings + */ + +#if defined(_MSC_VER) && \ + _MSC_VER < 1000 +# pragma warning(disable : 4705) +#endif /* _MSC_VER < 1000 */ + +/* ///////////////////////////////////////////////////////////////////////////// + * Data + */ + +static const char b64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const signed char b64_indexes[] = +{ + /* 0 - 31 / 0x00 - 0x1f */ + -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + /* 32 - 63 / 0x20 - 0x3f */ + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, 62, -1, -1, -1, 63 /* ... , '+', ... '/' */ + , 52, 53, 54, 55, 56, 57, 58, 59 /* '0' - '7' */ + , 60, 61, -1, -1, -1, -1, -1, -1 /* '8', '9', ... */ + /* 64 - 95 / 0x40 - 0x5f */ + , -1, 0, 1, 2, 3, 4, 5, 6 /* ..., 'A' - 'G' */ + , 7, 8, 9, 10, 11, 12, 13, 14 /* 'H' - 'O' */ + , 15, 16, 17, 18, 19, 20, 21, 22 /* 'P' - 'W' */ + , 23, 24, 25, -1, -1, -1, -1, -1 /* 'X', 'Y', 'Z', ... */ + /* 96 - 127 / 0x60 - 0x7f */ + , -1, 26, 27, 28, 29, 30, 31, 32 /* ..., 'a' - 'g' */ + , 33, 34, 35, 36, 37, 38, 39, 40 /* 'h' - 'o' */ + , 41, 42, 43, 44, 45, 46, 47, 48 /* 'p' - 'w' */ + , 49, 50, 51, -1, -1, -1, -1, -1 /* 'x', 'y', 'z', ... */ + + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 + , -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/* ///////////////////////////////////////////////////////////////////////////// + * Helper functions + */ + +/** This function reads in 3 bytes at a time, and translates them into 4 + * characters. + */ +static size_t b64_encode_( unsigned char const *src + , size_t srcSize + , char *const dest + , size_t destLen + , unsigned lineLen + , B64_RC *rc) +{ + size_t total = ((srcSize + (NUM_PLAIN_DATA_BYTES - 1)) / NUM_PLAIN_DATA_BYTES) * NUM_ENCODED_DATA_BYTES; + + assert(NULL != rc); + *rc = B64_RC_OK; + + if(lineLen > 0) + { + size_t numLines = (total + (lineLen - 1)) / lineLen; + + total += 2 * (numLines - 1); + } + + if(NULL == dest) + { + return total; + } + else if(destLen < total) + { + *rc = B64_RC_INSUFFICIENT_BUFFER; + + return 0; + } + else + { + char *p = dest; + char *end = dest + destLen; + size_t len = 0; + + for(; NUM_PLAIN_DATA_BYTES <= srcSize; srcSize -= NUM_PLAIN_DATA_BYTES) + { + char characters[NUM_ENCODED_DATA_BYTES]; + + /* + * + * | 0 | 1 | 2 | + * + * | | | | + * | | | | | | | + * | | | | | | | | | | | | | + * | | | | | | | | | | | | | | | | | | | | | | | | | + * + * | 0 | 1 | 2 | 3 | + * + */ + + /* characters[0] is the 6 left-most bits of src[0] */ + characters[0] = (char)((src[0] & 0xfc) >> 2); + /* characters[0] is the right-most 2 bits of src[0] and the left-most 4 bits of src[1] */ + characters[1] = (char)(((src[0] & 0x03) << 4) + ((src[1] & 0xf0) >> 4)); + /* characters[0] is the right-most 4 bits of src[1] and the 2 left-most bits of src[2] */ + characters[2] = (char)(((src[1] & 0x0f) << 2) + ((src[2] & 0xc0) >> 6)); + /* characters[3] is the right-most 6 bits of src[2] */ + characters[3] = (char)(src[2] & 0x3f); + +#ifndef __WATCOMC__ + assert(characters[0] >= 0 && characters[0] < 64); + assert(characters[1] >= 0 && characters[1] < 64); + assert(characters[2] >= 0 && characters[2] < 64); + assert(characters[3] >= 0 && characters[3] < 64); +#endif /* __WATCOMC__ */ + + src += NUM_PLAIN_DATA_BYTES; + *p++ = b64_chars[(unsigned char)characters[0]]; + assert(NULL != strchr(b64_chars, *(p-1))); + ++len; + assert(len != lineLen); + + *p++ = b64_chars[(unsigned char)characters[1]]; + assert(NULL != strchr(b64_chars, *(p-1))); + ++len; + assert(len != lineLen); + + *p++ = b64_chars[(unsigned char)characters[2]]; + assert(NULL != strchr(b64_chars, *(p-1))); + ++len; + assert(len != lineLen); + + *p++ = b64_chars[(unsigned char)characters[3]]; + assert(NULL != strchr(b64_chars, *(p-1))); + + if( ++len == lineLen && + p != end) + { + *p++ = '\r'; + *p++ = '\n'; + len = 0; + } + } + + if(0 != srcSize) + { + /* Deal with the overspill, by boosting it up to three bytes (using 0s) + * and then appending '=' for any missing characters. + * + * This is done into a temporary buffer, so we can call ourselves and + * have the output continue to be written direct to the destination. + */ + + unsigned char dummy[NUM_PLAIN_DATA_BYTES]; + size_t i; + + for(i = 0; i < srcSize; ++i) + { + dummy[i] = *src++; + } + + for(; i < NUM_PLAIN_DATA_BYTES; ++i) + { + dummy[i] = '\0'; + } + + b64_encode_(&dummy[0], NUM_PLAIN_DATA_BYTES, p, NUM_ENCODED_DATA_BYTES * (1 + 2), 0, rc); + + for(p += 1 + srcSize; srcSize++ < NUM_PLAIN_DATA_BYTES; ) + { + *p++ = '='; + } + } + + return total; + } +} + +/** This function reads in a character string in 4-character chunks, and writes + * out the converted form in 3-byte chunks to the destination. + */ +static size_t b64_decode_( char const *src + , size_t srcLen + , unsigned char *dest + , size_t destSize + , unsigned flags + , char const **badChar + , B64_RC *rc) +{ + const size_t wholeChunks = (srcLen / NUM_ENCODED_DATA_BYTES); + const size_t remainderBytes = (srcLen % NUM_ENCODED_DATA_BYTES); + size_t maxTotal = (wholeChunks + (0 != remainderBytes)) * NUM_PLAIN_DATA_BYTES; + unsigned char *dest_ = dest; + + ((void)remainderBytes); + + assert(NULL != badChar); + assert(NULL != rc); + + *badChar = NULL; + *rc = B64_RC_OK; + + if(NULL == dest) + { + return maxTotal; + } + else if(destSize < maxTotal) + { + *rc = B64_RC_INSUFFICIENT_BUFFER; + + return 0; + } + else + { + /* Now we iterate through the src, collecting together four characters + * at a time from the Base-64 alphabet, until the end-point is reached. + * + * + */ + + char const *begin = src; + char const *const end = begin + srcLen; + size_t currIndex = 0; + size_t numPads = 0; + signed char indexes[NUM_ENCODED_DATA_BYTES]; /* 4 */ + + for(; begin != end; ++begin) + { + const char ch = *begin; + + if('=' == ch) + { + assert(currIndex < NUM_ENCODED_DATA_BYTES); + + indexes[currIndex++] = '\0'; + + ++numPads; + } + else + { + /* NOTE: Had to rename 'index' to 'ix', due to name clash with GCC on 64-bit Linux. */ + signed char ix = b64_indexes[(unsigned char)ch]; + + if(-1 == ix) + { + switch(ch) + { + case ' ': + case '\t': + case '\b': + case '\v': + if(B64_F_STOP_ON_UNEXPECTED_WS & flags) + { + *rc = B64_RC_DATA_ERROR; + *badChar = begin; + return 0; + } + else + { + /* Fall through */ + } + case '\r': + case '\n': + continue; + default: + if(B64_F_STOP_ON_UNKNOWN_CHAR & flags) + { + *rc = B64_RC_DATA_ERROR; + *badChar = begin; + return 0; + } + else + { + continue; + } + } + } + else + { + numPads = 0; + + assert(currIndex < NUM_ENCODED_DATA_BYTES); + + indexes[currIndex++] = ix; + } + } + + if(NUM_ENCODED_DATA_BYTES == currIndex) + { + unsigned char bytes[NUM_PLAIN_DATA_BYTES]; /* 3 */ + + bytes[0] = (unsigned char)((indexes[0] << 2) + ((indexes[1] & 0x30) >> 4)); + + currIndex = 0; + + *dest++ = bytes[0]; + if(2 != numPads) + { + bytes[1] = (unsigned char)(((indexes[1] & 0xf) << 4) + ((indexes[2] & 0x3c) >> 2)); + + *dest++ = bytes[1]; + + if(1 != numPads) + { + bytes[2] = (unsigned char)(((indexes[2] & 0x3) << 6) + indexes[3]); + + *dest++ = bytes[2]; + } + } + if(0 != numPads) + { + break; + } + } + } + + return (size_t)(dest - dest_); + } +} + +/* ///////////////////////////////////////////////////////////////////////////// + * API functions + */ + +size_t b64_encode(void const *src, size_t srcSize, char *dest, size_t destLen) +{ + /* Use Null Object (Variable) here for rc, so do not need to check + * elsewhere. + */ + B64_RC rc_; + + return b64_encode_((unsigned char const*)src, srcSize, dest, destLen, 0, &rc_); +} + +size_t b64_encode2( void const *src + , size_t srcSize + , char *dest + , size_t destLen + , unsigned flags + , int lineLen /* = -1 */ + , B64_RC *rc /* = NULL */) +{ + /* Use Null Object (Variable) here for rc, so do not need to check + * elsewhere + */ + B64_RC rc_; + if(NULL == rc) + { + rc = &rc_; + } + + switch(B64_F_LINE_LEN_MASK & flags) + { + case B64_F_LINE_LEN_USE_PARAM: + if(lineLen >= 0) + { + break; + } + /* Fall through to 64 */ + case B64_F_LINE_LEN_64: + lineLen = 64; + break; + case B64_F_LINE_LEN_76: + lineLen = 76; + break; + default: + assert(!"Bad line length flag specified to b64_encode2()"); + case B64_F_LINE_LEN_INFINITE: + lineLen = 0; + break; + } + + assert(0 == (lineLen % 4)); + + return b64_encode_((unsigned char const*)src, srcSize, dest, destLen, (unsigned)lineLen, rc); +} + +size_t b64_decode(char const *src, size_t srcLen, void *dest, size_t destSize) +{ + /* Use Null Object (Variable) here for rc and badChar, so do not need to + * check elsewhere. + */ + char const *badChar_; + B64_RC rc_; + + return b64_decode_(src, srcLen, (unsigned char*)dest, destSize, B64_F_STOP_ON_NOTHING, &badChar_, &rc_); +} + +size_t b64_decode2( char const *src + , size_t srcLen + , void *dest + , size_t destSize + , unsigned flags + , char const **badChar /* = NULL */ + , B64_RC *rc /* = NULL */) +{ + char const *badChar_; + B64_RC rc_; + + /* Use Null Object (Variable) here for rc and badChar, so do not need to + * check elsewhere. + */ + if(NULL == badChar) + { + badChar = &badChar_; + } + if(NULL == rc) + { + rc = &rc_; + } + + return b64_decode_(src, srcLen, (unsigned char*)dest, destSize, flags, badChar, rc); +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef B64_DOCUMENTATION_SKIP_SECTION +struct b64ErrorString_t_ +#else /* !B64_DOCUMENTATION_SKIP_SECTION */ +typedef struct b64ErrorString_t_ b64ErrorString_t_; +struct b64ErrorString_t_ +#endif /* !B64_DOCUMENTATION_SKIP_SECTION */ +{ + int code; /*!< The error code. */ + char const *str; /*!< The string. */ + size_t len; /*!< The string length. */ +}; + + + +#define SEVERITY_STR_DECL(rc, desc) \ + \ + static const char s_str##rc[] = desc; \ + static const b64ErrorString_t_ s_rct##rc = { rc, s_str##rc, NUM_ELEMENTS(s_str##rc) - 1 } + + +#define SEVERITY_STR_ENTRY(rc) \ + \ + &s_rct##rc + + +static char const *b64_LookupCodeA_(int code, b64ErrorString_t_ const **mappings, size_t cMappings, size_t *len) +{ + /* Use Null Object (Variable) here for len, so do not need to check + * elsewhere. + */ + size_t len_; + + if(NULL == len) + { + len = &len_; + } + + /* Checked, indexed search. */ + if( code >= 0 && + code < B64_max_RC_value) + { + if(code == mappings[code]->code) + { + return (*len = mappings[code]->len, mappings[code]->str); + } + } + + /* Linear search. Should only be needed if order in + * b64_LookupErrorStringA_() messed up. + */ + { size_t i; for(i = 0; i < cMappings; ++i) + { + if(code == mappings[i]->code) + { + return (*len = mappings[i]->len, mappings[i]->str); + } + }} + + return (*len = 0, ""); +} + +static char const *b64_LookupErrorStringA_(int error, size_t *len) +{ + SEVERITY_STR_DECL(B64_RC_OK , "Operation was successful" ); + SEVERITY_STR_DECL(B64_RC_INSUFFICIENT_BUFFER , "The given translation buffer was not of sufficient size" ); + SEVERITY_STR_DECL(B64_RC_TRUNCATED_INPUT , "The input did not represent a fully formed stream of octet couplings" ); + SEVERITY_STR_DECL(B64_RC_DATA_ERROR , "Invalid data" ); + + static const b64ErrorString_t_ *s_strings[] = + { + SEVERITY_STR_ENTRY(B64_RC_OK), + SEVERITY_STR_ENTRY(B64_RC_INSUFFICIENT_BUFFER), + SEVERITY_STR_ENTRY(B64_RC_TRUNCATED_INPUT), + SEVERITY_STR_ENTRY(B64_RC_DATA_ERROR), + }; + + return b64_LookupCodeA_(error, s_strings, NUM_ELEMENTS(s_strings), len); +} + +char const *b64_getErrorString(B64_RC code) +{ + return b64_LookupErrorStringA_((int)code, NULL); +} + +size_t b64_getErrorStringLength(B64_RC code) +{ + size_t len; + + return (b64_LookupErrorStringA_((int)code, &len), len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ diff --git a/linphone/oRTP/src/dll_entry.c b/linphone/oRTP/src/dll_entry.c new file mode 100644 index 000000000..37ac6cf12 --- /dev/null +++ b/linphone/oRTP/src/dll_entry.c @@ -0,0 +1,147 @@ + +#ifdef WIN32 +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" +#endif +#include "ortp/ortp.h" + +typedef struct __STRUCT_SHARED_DATA__ +{ + DWORD m_nReference; + DWORD m_dwStartTime; + BOOL m_bInitialize; + +} SHARED_DATA, * LPSHARED_DATA; + +#ifdef EXTERNAL_LOGGER +#include "logger.h" +#else +#define RegisterLog(logVar, logString); +#define UnregisterLog(logVar, logString); +#endif + +extern DWORD dwoRTPLogLevel; + +#define SHMEMSIZE sizeof(SHARED_DATA) + +static LPSHARED_DATA lpSharedData; +static HANDLE hMapObject = NULL; // handle to file mapping + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, // handle to DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpReserved // reserved + ) +{ + BOOL fInit = FALSE; + WORD wVersionRequested; + WSADATA wsaData; + + // Perform actions based on the reason for calling. + switch( fdwReason ) + { + case DLL_PROCESS_ATTACH: + + OutputDebugString("--> dll_entry.c - oRTP.dll - DLL_PROCESS_ATTACH()\n"); + + wVersionRequested = MAKEWORD( 1, 0 ); + + if (WSAStartup(wVersionRequested,&wsaData)!=0) + { + return FALSE; + } + + // Create a named file mapping object. + hMapObject = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file + NULL, // default security attributes + PAGE_READWRITE, // read/write access + 0, // size: high 32-bits + SHMEMSIZE, // size: low 32-bits + "oRTPSharedMemory"); // name of map object + + if (hMapObject == NULL) + return FALSE; + + // The first process to attach initializes memory. + fInit = (GetLastError() != ERROR_ALREADY_EXISTS); + + // Get a pointer to the file-mapped shared memory. + + lpSharedData = (LPSHARED_DATA) MapViewOfFile( hMapObject, // object to map view of + FILE_MAP_WRITE, // read/write access + 0, // high offset: map from + 0, // low offset: beginning + 0); // default: map entire file + if (lpSharedData == NULL) + return FALSE; + + // Initialize memory if this is the first process. + + if (fInit) + { + OutputDebugString("--> dll_entry.c - oRTP.dll - Initializing module\n"); + + lpSharedData->m_dwStartTime = GetTickCount(); + lpSharedData->m_nReference = 1; + lpSharedData->m_bInitialize = FALSE; + + // Register the log + RegisterLog(&dwoRTPLogLevel, "LOG_ORTP"); + } + else + { + OutputDebugString("--> dll_entry.c - oRTP.dll - Binding\n"); + lpSharedData->m_nReference++; + } + break; + + case DLL_THREAD_ATTACH: + + if (lpSharedData != NULL) + { + if (lpSharedData->m_bInitialize == FALSE) + { + // Initialize oRTP + ortp_init(); + + // Start the scheduler + //ortp_scheduler_init(); + + lpSharedData->m_bInitialize = TRUE; + } + } + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + + if (lpSharedData != NULL) + { + OutputDebugString("--> dll_entry.c - oRTP.dll - Binding\n"); + lpSharedData->m_nReference--; + + if (lpSharedData->m_nReference == 0) + { + OutputDebugString("--> dll_entry.c - oRTP.dll - Detaching\n"); + + ortp_exit(); + UnregisterLog(&dwoRTPLogLevel, "LOG_ORTP"); + + + // Unmap shared memory from the process's address space. + UnmapViewOfFile(lpSharedData); + lpSharedData = NULL; + + // Close the process's handle to the file-mapping object. + CloseHandle(hMapObject); + hMapObject = INVALID_HANDLE_VALUE; + } + } + break; + } + + return TRUE; // Successful DLL_PROCESS_ATTACH. +} diff --git a/linphone/oRTP/src/event.c b/linphone/oRTP/src/event.c new file mode 100644 index 000000000..00718e2e7 --- /dev/null +++ b/linphone/oRTP/src/event.c @@ -0,0 +1,116 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ortp/event.h" +#include "ortp/ortp.h" + +RtpEndpoint *rtp_endpoint_new(struct sockaddr *addr, socklen_t addrlen){ + RtpEndpoint *ep=ortp_new(RtpEndpoint,1); + if (sizeof(ep->addr)addr,addr,addrlen); + ep->addrlen=addrlen; + return ep; +} + +void rtp_endpoint_destroy(RtpEndpoint *ep){ + ortp_free(ep); +} + +RtpEndpoint *rtp_endpoint_dup(const RtpEndpoint *ep){ + return rtp_endpoint_new((struct sockaddr*)&ep->addr,ep->addrlen); +} + +OrtpEvent * ortp_event_new(unsigned long type){ + const int size=sizeof(OrtpEventType)+sizeof(OrtpEventData); + mblk_t *m=allocb(size,0); + memset(m->b_wptr,0,size); + *((OrtpEventType*)m->b_wptr)=type; + return m; +} + +OrtpEvent *ortp_event_dup(OrtpEvent *ev){ +#if 0 + OrtpEvent *nev=dupb(ev); +#else + OrtpEvent *nev = ortp_event_new(ortp_event_get_type(ev)); + OrtpEventData * ed = ortp_event_get_data(ev); + OrtpEventData * edv = ortp_event_get_data(nev); + + if (ed->ep) edv->ep = rtp_endpoint_dup(ed->ep); + if (ed->packet) edv->packet = copymsg(ed->packet); + edv->info.telephone_event = ed->info.telephone_event; +#endif + return nev; +} + +OrtpEventType ortp_event_get_type(const OrtpEvent *ev){ + return ((OrtpEventType*)ev->b_rptr)[0]; +} + +OrtpEventData * ortp_event_get_data(OrtpEvent *ev){ + return (OrtpEventData*)(ev->b_rptr+sizeof(OrtpEventType)); +} + +void ortp_event_destroy(OrtpEvent *ev){ + OrtpEventData *d=ortp_event_get_data(ev); + if (ev->b_datap->db_ref==1){ + if (d->packet) freemsg(d->packet); + if (d->ep) rtp_endpoint_destroy(d->ep); + } + freemsg(ev); +} + +OrtpEvQueue * ortp_ev_queue_new(){ + OrtpEvQueue *q=ortp_new(OrtpEvQueue,1); + qinit(&q->q); + ortp_mutex_init(&q->mutex,NULL); + return q; +} + +void ortp_ev_queue_flush(OrtpEvQueue * qp){ + OrtpEvent *ev; + while((ev=ortp_ev_queue_get(qp))!=NULL){ + ortp_event_destroy(ev); + } +} + +OrtpEvent * ortp_ev_queue_get(OrtpEvQueue *q){ + OrtpEvent *ev; + ortp_mutex_lock(&q->mutex); + ev=getq(&q->q); + ortp_mutex_unlock(&q->mutex); + return ev; +} + +void ortp_ev_queue_destroy(OrtpEvQueue * qp){ + ortp_ev_queue_flush(qp); + ortp_mutex_destroy(&qp->mutex); + ortp_free(qp); +} + +void ortp_ev_queue_put(OrtpEvQueue *q, OrtpEvent *ev){ + ortp_mutex_lock(&q->mutex); + putq(&q->q,ev); + ortp_mutex_unlock(&q->mutex); +} + diff --git a/linphone/oRTP/src/jitterctl.c b/linphone/oRTP/src/jitterctl.c new file mode 100644 index 000000000..0ee9dd4ca --- /dev/null +++ b/linphone/oRTP/src/jitterctl.c @@ -0,0 +1,182 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*************************************************************************** + * jitterctl.c + * + * Mon Nov 8 11:53:21 2004 + * Copyright 2004 Simon MORLAT + * Email simon.morlat@linphone.org + ****************************************************************************/ + +#include "ortp/rtpsession.h" +#include "ortp/payloadtype.h" +#include "ortp/ortp.h" +#include "utils.h" +#include "rtpsession_priv.h" +#include + +#define JC_BETA 0.01 +#define JC_GAMMA (JC_BETA) + +#include "jitterctl.h" + +void jitter_control_init(JitterControl *ctl, int base_jiitt_time, PayloadType *payload){ + ctl->count=0; + ctl->slide=0; + ctl->prev_slide=0; + ctl->jitter=0; + ctl->inter_jitter=0; + ctl->slide=0; + if (base_jiitt_time!=-1) ctl->jitt_comp = base_jiitt_time; + /* convert in timestamp unit: */ + if (payload!=NULL){ + jitter_control_set_payload(ctl,payload); + } + ctl->adapt_jitt_comp_ts=ctl->jitt_comp_ts; + ctl->corrective_slide=0; +} + +void jitter_control_enable_adaptive(JitterControl *ctl, bool_t val){ + ctl->adaptive=val; +} + +void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt){ + ctl->jitt_comp_ts = + (int) (((double) ctl->jitt_comp / 1000.0) * (pt->clock_rate)); + ctl->corrective_step=(160 * 8000 )/pt->clock_rate; /* This formula got to me after some beers */ + ctl->adapt_jitt_comp_ts=ctl->jitt_comp_ts; +} + + +void jitter_control_dump_stats(JitterControl *ctl){ + ortp_message("JitterControl:\n\tslide=%g,jitter=%g,count=%i", + (double)ctl->slide,ctl->jitter, ctl->count); +} + +/*the goal of this method is to compute "corrective_slide": a timestamp unit'd value to be added + to recv timestamp to make them reflect the instant they are delivered by the jitter buffer. */ +void jitter_control_update_corrective_slide(JitterControl *ctl){ + int tmp; + tmp=(int)(ctl->slide)-ctl->prev_slide; + if (tmp>ctl->corrective_step) { + ctl->corrective_slide+=ctl->corrective_step; + ctl->prev_slide=ctl->slide+ctl->corrective_step; + } + else if (tmp<-ctl->corrective_step) { + ctl->corrective_slide-=ctl->corrective_step; + ctl->prev_slide=ctl->slide-ctl->corrective_step; + } +} + +/* + The algorithm computes two values: + slide: an average of difference between the expected and the socket-received timestamp + jitter: an average of the absolute value of the difference between socket-received timestamp and slide. + slide is used to make clock-slide detection and correction. + jitter is added to the initial jitt_comp_time value. It compensates bursty packets arrival (packets + not arriving at regular interval ). +*/ +void jitter_control_new_packet(JitterControl *ctl, uint32_t packet_ts, uint32_t cur_str_ts){ + int64_t diff=(int64_t)packet_ts - (int64_t)cur_str_ts; + double gap,slide; + int d; + //printf("diff=%g\n",diff); + if (ctl->count==0){ + slide=ctl->slide=ctl->prev_slide=diff; + ctl->olddiff=diff; + ctl->jitter=0; + }else{ + slide=((double)ctl->slide*(1-JC_BETA)) + ((double)diff*JC_BETA); + } + gap=(double)diff - slide; + gap=gap<0 ? -gap : 0; /*compute only for late packets*/ + ctl->jitter=(float) ((ctl->jitter*(1-JC_GAMMA)) + (gap*JC_GAMMA)); + d=diff-ctl->olddiff; + ctl->inter_jitter=(float) (ctl->inter_jitter+ (( (float)abs(d) - ctl->inter_jitter)*(1/16.0))); + ctl->olddiff=diff; + ctl->count++; + if (ctl->adaptive){ + + if (ctl->count%50==0) { + ctl->adapt_jitt_comp_ts=(int) MAX(ctl->jitt_comp_ts,2*ctl->jitter); + /*jitter_control_dump_stats(ctl);*/ + } + + ctl->slide=slide; + }else { + /*ctl->slide and jitter size are not updated*/ + } + return ; +} + + + + + +/** + *rtp_session_set_jitter_compensation: + *@session: a RtpSession + *@milisec: the time interval in milisec to be jitter compensed. + * + * Sets the time interval for which packet are buffered instead of being delivered to the + * application. + **/ +void +rtp_session_set_jitter_compensation (RtpSession * session, int milisec) +{ + PayloadType *payload=NULL; + if (session->rcv.pt!=-1) { + payload = rtp_profile_get_payload (session->rcv.profile,session->rcv.pt); + }/*else not set yet */ + jitter_control_init(&session->rtp.jittctl,milisec,payload); +} + +void rtp_session_enable_adaptive_jitter_compensation(RtpSession *session, bool_t val){ + jitter_control_enable_adaptive(&session->rtp.jittctl,val); +} + +bool_t rtp_session_adaptive_jitter_compensation_enabled(RtpSession *session){ + return session->rtp.jittctl.adaptive; +} + +void rtp_session_enable_jitter_buffer(RtpSession *session, bool_t enabled){ + session->rtp.jittctl.enabled=enabled; + session->flags|=RTP_SESSION_RECV_SYNC; +} + +bool_t rtp_session_jitter_buffer_enabled(const RtpSession *session){ + return session->rtp.jittctl.enabled; +} + +void rtp_session_set_jitter_buffer_params(RtpSession *session, const JBParameters *par){ + /* FIXME min_size and max_size to be implemented */ + rtp_session_set_jitter_compensation(session,par->nom_size); + jitter_control_enable_adaptive(&session->rtp.jittctl,par->adaptive); + session->rtp.max_rq_size=par->max_packets; +} + +void rtp_session_get_jitter_buffer_params(RtpSession *session, JBParameters *par){ + int nom_size=session->rtp.jittctl.jitt_comp; + par->min_size=nom_size; + par->nom_size=nom_size; + par->max_size=-1; + par->adaptive=session->rtp.jittctl.adaptive; + par->max_packets=session->rtp.max_rq_size; +} + diff --git a/linphone/oRTP/src/jitterctl.h b/linphone/oRTP/src/jitterctl.h new file mode 100644 index 000000000..713756118 --- /dev/null +++ b/linphone/oRTP/src/jitterctl.h @@ -0,0 +1,41 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*************************************************************************** + * jitterctl.c + * + * Mon Nov 8 11:53:21 2004 + * Copyright 2004 Simon MORLAT + * Email simon.morlat@linphone.org + ****************************************************************************/ + +#ifndef JITTERCTL_H +#define JITTERCTL_H + + +void jitter_control_init(JitterControl *ctl, int base_jiitt_time, PayloadType *pt); +void jitter_control_enable_adaptive(JitterControl *ctl, bool_t val); +void jitter_control_new_packet(JitterControl *ctl, uint32_t packet_ts, uint32_t cur_str_ts); +#define jitter_control_adaptive_enabled(ctl) ((ctl)->adaptive) +void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt); +void jitter_control_update_corrective_slide(JitterControl *ctl); +static inline uint32_t jitter_control_get_compensated_timestamp(JitterControl *obj , uint32_t user_ts){ + return user_ts+obj->slide-obj->adapt_jitt_comp_ts; +} + +#endif diff --git a/linphone/oRTP/src/master b/linphone/oRTP/src/master new file mode 100644 index 000000000..ded8bca41 --- /dev/null +++ b/linphone/oRTP/src/master @@ -0,0 +1,33 @@ +*############################################################ +*# +*# $Header: /sources/linphone/linphone/oRTP/src/master,v 1.1 2002/02/25 08:41:53 smorlat Exp $ +*# +*# $Source: /sources/linphone/linphone/oRTP/src/master,v $ +*# $Revision: 1.1 $ +*# $Locker: $ +*# +*############################################################ +$VERSION +1 +$$$ + +$DRIVER_INSTALL +oRTP -1 -1 +$$$ + +$LOADABLE +$$$ + +$INTERFACE +base +$$$ + +$DRIVER_DEPENDENCY +$$$ + +$TYPE +oRTP wsio_class pseudo pmi -1 -1 +$$$ + +$TUNABLE +$$$ diff --git a/linphone/oRTP/src/ortp-config-win32.h b/linphone/oRTP/src/ortp-config-win32.h new file mode 100644 index 000000000..6227ef64b --- /dev/null +++ b/linphone/oRTP/src/ortp-config-win32.h @@ -0,0 +1,31 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/* ortp-config-win32.h. Generated manually... */ +#define ORTP_VERSION "0.8.2" +#define ORTP_MAJOR_VERSION 0 +#define ORTP_MINOR_VERSION 8 +#define ORTP_MICRO_VERSION 2 +#define ORTP_EXTRA_VERSION + +/* define the debug mode */ +#define RTP_DEBUG 1 + +#define HAVE_SRTP 1 diff --git a/linphone/oRTP/src/ortp.c b/linphone/oRTP/src/ortp.c new file mode 100644 index 000000000..2c11abf56 --- /dev/null +++ b/linphone/oRTP/src/ortp.c @@ -0,0 +1,372 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#if defined(WIN32) || defined(_WIN32_WCE) +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" +#endif +#include "ortp/ortp.h" +#include "scheduler.h" + +rtp_stats_t ortp_global_stats; + +#ifdef ENABLE_MEMCHECK +int ortp_allocations=0; +#endif + + +RtpScheduler *__ortp_scheduler; + + + +extern void av_profile_init(RtpProfile *profile); + +static void init_random_number_generator(){ + struct timeval t; + gettimeofday(&t,NULL); + srandom(t.tv_usec+t.tv_sec); +} + + +#ifdef WIN32 +static bool_t win32_init_sockets(void){ + WORD wVersionRequested; + WSADATA wsaData; + int i; + + wVersionRequested = MAKEWORD(1,1); + if( (i = WSAStartup(wVersionRequested, &wsaData))!=0) + { + ortp_error("Unable to initialize windows socket api, reason: %d",i); + return FALSE; + } + return TRUE; +} +#endif + +/** + * Initialize the oRTP library. You should call this function first before using + * oRTP API. +**/ +void ortp_init() +{ + static bool_t initialized=FALSE; + if (initialized) return; + initialized=TRUE; + +#ifdef WIN32 + win32_init_sockets(); +#endif + + av_profile_init(&av_profile); + ortp_global_stats_reset(); + init_random_number_generator(); + ortp_message("oRTP-" ORTP_VERSION " initialized."); +} + + +/** + * Initialize the oRTP scheduler. You only have to do that if you intend to use the + * scheduled mode of the #RtpSession in your application. + * +**/ +void ortp_scheduler_init() +{ + static bool_t initialized=FALSE; + if (initialized) return; + initialized=TRUE; +#ifdef __hpux + /* on hpux, we must block sigalrm on the main process, because signal delivery + is ?random?, well, sometimes the SIGALRM goes to both the main thread and the + scheduler thread */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set,SIGALRM); + sigprocmask(SIG_BLOCK,&set,NULL); +#endif /* __hpux */ + + __ortp_scheduler=rtp_scheduler_new(); + rtp_scheduler_start(__ortp_scheduler); + //sleep(1); +} + + +/** + * Gracefully uninitialize the library, including shutdowning the scheduler if it was started. + * +**/ +void ortp_exit() +{ + if (__ortp_scheduler!=NULL) + { + rtp_scheduler_destroy(__ortp_scheduler); + __ortp_scheduler=NULL; + } +} + +RtpScheduler * ortp_get_scheduler() +{ + if (__ortp_scheduler==NULL) ortp_error("Cannot use the scheduled mode: the scheduler is not " + "started. Call ortp_scheduler_init() at the begginning of the application."); + return __ortp_scheduler; +} + + +static FILE *__log_file=0; + +/** + *@param file a FILE pointer where to output the ortp logs. + * +**/ +void ortp_set_log_file(FILE *file) +{ + __log_file=file; +} + +static void __ortp_logv_out(OrtpLogLevel lev, const char *fmt, va_list args); + +OrtpLogFunc ortp_logv_out=__ortp_logv_out; + +/** + *@param func: your logging function, compatible with the OrtpLogFunc prototype. + * +**/ +void ortp_set_log_handler(OrtpLogFunc func){ + ortp_logv_out=func; +} + + +unsigned int __ortp_log_mask=ORTP_WARNING|ORTP_ERROR|ORTP_FATAL; + +/** + * @ param levelmask a mask of ORTP_DEBUG, ORTP_MESSAGE, ORTP_WARNING, ORTP_ERROR + * ORTP_FATAL . +**/ +void ortp_set_log_level_mask(int levelmask){ + __ortp_log_mask=levelmask; +} + +static char * _strdup_vprintf(const char *fmt, va_list ap) +{ + /* Guess we need no more than 100 bytes. */ + int n, size = 200; + char *p,*np; +#ifdef __linux + va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ +#endif + if ((p = (char *) ortp_malloc (size)) == NULL) + return NULL; + while (1) + { + /* Try to print in the allocated space. */ +#ifdef __linux + va_copy(cap,ap); + n = vsnprintf (p, size, fmt, cap); + va_end(cap); +#else + /*this works on 32 bits, luckily*/ + n = vsnprintf (p, size, fmt, ap); +#endif + /* If that worked, return the string. */ + if (n > -1 && n < size) + return p; + //printf("Reallocing space.\n"); + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + if ((np = (char *) ortp_realloc (p, size)) == NULL) + { + free(p); + return NULL; + } + else + { + p = np; + } + } +} + +char *ortp_strdup_printf(const char *fmt,...){ + char *ret; + va_list args; + va_start (args, fmt); + ret=_strdup_vprintf(fmt, args); + va_end (args); + return ret; +} + +#if defined(WIN32) || defined(_WIN32_WCE) +#define ENDLINE "\r\n" +#else +#define ENDLINE "\n" +#endif + +#if defined(WIN32) || defined(_WIN32_WCE) +void ortp_logv(int level, const char *fmt, va_list args) +{ + if (ortp_logv_out!=NULL && ortp_log_level_enabled(level)) + ortp_logv_out(level,fmt,args); +#if !defined(_WIN32_WCE) + if ((level)==ORTP_FATAL) abort(); +#endif +} +#endif + +static void __ortp_logv_out(OrtpLogLevel lev, const char *fmt, va_list args){ + const char *lname="undef"; + char *msg; + if (__log_file==NULL) __log_file=stderr; + switch(lev){ + case ORTP_DEBUG: + lname="debug"; + break; + case ORTP_MESSAGE: + lname="message"; + break; + case ORTP_WARNING: + lname="warning"; + break; + case ORTP_ERROR: + lname="error"; + break; + case ORTP_FATAL: + lname="fatal"; + break; + default: + ortp_fatal("Bad level !"); + } + msg=_strdup_vprintf(fmt,args); + fprintf(__log_file,"ortp-%s-%s" ENDLINE,lname,msg); + ortp_free(msg); +} + +/** + * Display global statistics (cumulative for all RtpSession) +**/ +void ortp_global_stats_display() +{ + rtp_stats_display(&ortp_global_stats,"Global statistics"); +#ifdef ENABLE_MEMCHECK + printf("Unfreed allocations: %i\n",ortp_allocations); +#endif +} + +/** + * Print RTP statistics. +**/ +void rtp_stats_display(const rtp_stats_t *stats, const char *header) +{ +#ifndef WIN32 + ortp_log(ORTP_MESSAGE, + "oRTP-stats:\n %s :", + header); + ortp_log(ORTP_MESSAGE, + " number of rtp packet sent=%lld", + (long long)stats->packet_sent); + ortp_log(ORTP_MESSAGE, + " number of rtp bytes sent=%lld bytes", + (long long)stats->sent); + ortp_log(ORTP_MESSAGE, + " number of rtp packet received=%lld", + (long long)stats->packet_recv); + ortp_log(ORTP_MESSAGE, + " number of rtp bytes received=%lld bytes", + (long long)stats->hw_recv); + ortp_log(ORTP_MESSAGE, + " number of incoming rtp bytes successfully delivered to the application=%lld ", + (long long)stats->recv); + ortp_log(ORTP_MESSAGE, + " number of times the application queried a packet that didn't exist=%lld ", + (long long)stats->unavaillable); + ortp_log(ORTP_MESSAGE, + " number of rtp packet lost=%lld", + (long long) stats->cum_packet_loss); + ortp_log(ORTP_MESSAGE, + " number of rtp packets received too late=%lld", + (long long)stats->outoftime); + ortp_log(ORTP_MESSAGE, + " number of bad formatted rtp packets=%lld", + (long long)stats->bad); + ortp_log(ORTP_MESSAGE, + " number of packet discarded because of queue overflow=%lld", + (long long)stats->discarded); +#else + ortp_log(ORTP_MESSAGE, + "oRTP-stats:\n %s :", + header); + ortp_log(ORTP_MESSAGE, + " number of rtp packet sent=%I64d", + (uint64_t)stats->packet_sent); + ortp_log(ORTP_MESSAGE, + " number of rtp bytes sent=%I64d bytes", + (uint64_t)stats->sent); + ortp_log(ORTP_MESSAGE, + " number of rtp packet received=%I64d", + (uint64_t)stats->packet_recv); + ortp_log(ORTP_MESSAGE, + " number of rtp bytes received=%I64d bytes", + (uint64_t)stats->hw_recv); + ortp_log(ORTP_MESSAGE, + " number of incoming rtp bytes successfully delivered to the application=%I64d ", + (uint64_t)stats->recv); + ortp_log(ORTP_MESSAGE, + " number of times the application queried a packet that didn't exist=%I64d ", + (uint64_t)stats->unavaillable); + ortp_log(ORTP_MESSAGE, + " number of rtp packet lost=%I64d", + (uint64_t) stats->cum_packet_loss); + ortp_log(ORTP_MESSAGE, + " number of rtp packets received too late=%I64d", + (uint64_t)stats->outoftime); + ortp_log(ORTP_MESSAGE, + " number of bad formatted rtp packets=%I64d", + (uint64_t)stats->bad); + ortp_log(ORTP_MESSAGE, + " number of packet discarded because of queue overflow=%I64d", + (uint64_t)stats->discarded); +#endif +} + +void ortp_global_stats_reset(){ + memset(&ortp_global_stats,0,sizeof(rtp_stats_t)); +} + +rtp_stats_t *ortp_get_global_stats(){ + return &ortp_global_stats; +} + +void rtp_stats_reset(rtp_stats_t *stats){ + memset((void*)stats,0,sizeof(rtp_stats_t)); +} + + +/** + * This function give the opportunity to programs to check if the libortp they link to + * has the minimum version number they need. + * + * Returns: true if ortp has a version number greater or equal than the required one. +**/ +bool_t ortp_min_version_required(int major, int minor, int micro){ + return ((major*1000000) + (minor*1000) + micro) <= + ((ORTP_MAJOR_VERSION*1000000) + (ORTP_MINOR_VERSION*1000) + ORTP_MICRO_VERSION); +} diff --git a/linphone/oRTP/src/payloadtype.c b/linphone/oRTP/src/payloadtype.c new file mode 100644 index 000000000..53335736f --- /dev/null +++ b/linphone/oRTP/src/payloadtype.c @@ -0,0 +1,362 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ortp/ortp.h" +#include "ortp/payloadtype.h" +#include "utils.h" + +char *payload_type_get_rtpmap(PayloadType *pt) +{ + int len=(int)strlen(pt->mime_type)+15; + char *rtpmap=(char *) ortp_malloc(len); + if (pt->channels>0) + snprintf(rtpmap,len,"%s/%i/%i",pt->mime_type,pt->clock_rate,pt->channels); + else + snprintf(rtpmap,len,"%s/%i",pt->mime_type,pt->clock_rate); + return rtpmap; +} + +PayloadType *payload_type_new() +{ + PayloadType *newpayload=(PayloadType *)ortp_new0(PayloadType,1); + newpayload->flags|=PAYLOAD_TYPE_ALLOCATED; + return newpayload; +} + + +PayloadType *payload_type_clone(PayloadType *payload) +{ + PayloadType *newpayload=(PayloadType *)ortp_new0(PayloadType,1); + memcpy(newpayload,payload,sizeof(PayloadType)); + newpayload->mime_type=ortp_strdup(payload->mime_type); + if (payload->recv_fmtp!=NULL) { + newpayload->recv_fmtp=ortp_strdup(payload->recv_fmtp); + } + if (payload->send_fmtp!=NULL){ + newpayload->send_fmtp=ortp_strdup(payload->send_fmtp); + } + newpayload->flags|=PAYLOAD_TYPE_ALLOCATED; + return newpayload; +} + +static bool_t canWrite(PayloadType *pt){ + if (!(pt->flags & PAYLOAD_TYPE_ALLOCATED)) { + ortp_error("Cannot change parameters of statically defined payload types: make your" + " own copy using payload_type_clone() first."); + return FALSE; + } + return TRUE; +} + +/** + * Sets a recv parameters (fmtp) for the PayloadType. + * This method is provided for applications using RTP with SDP, but + * actually the ftmp information is not used for RTP processing. +**/ +void payload_type_set_recv_fmtp(PayloadType *pt, const char *fmtp){ + if (canWrite(pt)){ + if (pt->recv_fmtp!=NULL) ortp_free(pt->recv_fmtp); + if (fmtp!=NULL) pt->recv_fmtp=ortp_strdup(fmtp); + else pt->recv_fmtp=NULL; + } +} + +/** + * Sets a send parameters (fmtp) for the PayloadType. + * This method is provided for applications using RTP with SDP, but + * actually the ftmp information is not used for RTP processing. +**/ +void payload_type_set_send_fmtp(PayloadType *pt, const char *fmtp){ + if (canWrite(pt)){ + if (pt->send_fmtp!=NULL) ortp_free(pt->send_fmtp); + if (fmtp!=NULL) pt->send_fmtp=ortp_strdup(fmtp); + else pt->send_fmtp=NULL; + } +} + + + +void payload_type_append_recv_fmtp(PayloadType *pt, const char *fmtp){ + if (canWrite(pt)){ + if (pt->recv_fmtp==NULL) + pt->recv_fmtp=ortp_strdup(fmtp); + else{ + char *tmp=ortp_strdup_printf("%s;%s",pt->recv_fmtp,fmtp); + ortp_free(pt->recv_fmtp); + pt->recv_fmtp=tmp; + } + } +} + +void payload_type_append_send_fmtp(PayloadType *pt, const char *fmtp){ + if (canWrite(pt)){ + if (pt->send_fmtp==NULL) + pt->send_fmtp=ortp_strdup(fmtp); + else{ + char *tmp=ortp_strdup_printf("%s;%s",pt->send_fmtp,fmtp); + ortp_free(pt->send_fmtp); + pt->send_fmtp=tmp; + } + } +} + + +/** + * Frees a PayloadType. +**/ +void payload_type_destroy(PayloadType *pt) +{ + if (pt->mime_type) ortp_free(pt->mime_type); + if (pt->recv_fmtp) ortp_free(pt->recv_fmtp); + if (pt->send_fmtp) ortp_free(pt->send_fmtp); + ortp_free(pt); +} + +/** + * Parses a fmtp string such as "profile=0;level=10", finds the value matching + * parameter param_name, and writes it into result. + * Despite fmtp strings are not used anywhere within oRTP, this function can + * be useful for people using RTP streams described from SDP. + * @param fmtp the fmtp line (format parameters) + * @param param_name the parameter to search for + * @param result the value given for the parameter (if found) + * @param result_len the size allocated to hold the result string + * @return TRUE if the parameter was found, else FALSE. +**/ +bool_t fmtp_get_value(const char *fmtp, const char *param_name, char *result, size_t result_len){ + const char *pos=strstr(fmtp,param_name); + if (pos){ + const char *equal=strchr(pos,'='); + if (equal){ + int copied; + const char *end=strchr(equal+1,';'); + if (end==NULL) end=fmtp+strlen(fmtp); /*assuming this is the last param */ + copied=MIN(result_len-1,end-(equal+1)); + strncpy(result,equal+1,copied); + result[copied]='\0'; + return TRUE; + } + } + return FALSE; +} + + +int rtp_profile_get_payload_number_from_mime(RtpProfile *profile,const char *mime) +{ + PayloadType *pt; + int i; + for (i=0;imime_type,mime)==0){ + return i; + } + } + } + return -1; +} + +int rtp_profile_find_payload_number(RtpProfile*profile,const char *mime,int rate,int channels) +{ + int i; + PayloadType *pt; + for (i=0;imime_type,mime)==0 && + pt->clock_rate==rate && + (pt->channels==channels || channels<=0 || pt->channels<=0)) { + /*we don't look at channels if it is undefined + ie a negative or zero value*/ + + return i; + } + } + } + return -1; +} + +int rtp_profile_get_payload_number_from_rtpmap(RtpProfile *profile,const char *rtpmap) +{ + int clock_rate, channels, ret; + char* subtype = ortp_strdup( rtpmap ); + char* rate_str = NULL; + char* chan_str = NULL; + + + /* find the slash after the subtype */ + rate_str = strchr(subtype, '/'); + if (rate_str && strlen(rate_str)>1) { + *rate_str = 0; + rate_str++; + + /* Look for another slash */ + chan_str = strchr(rate_str, '/'); + if (chan_str && strlen(chan_str)>1) { + *chan_str = 0; + chan_str++; + } else { + chan_str = NULL; + } + } else { + rate_str = NULL; + } + + // Use default clock rate if none given + if (rate_str) clock_rate = atoi(rate_str); + else clock_rate = 8000; + + // Use default number of channels if none given + if (chan_str) channels = atoi(chan_str); + else channels = -1; + + //printf("Searching for payload %s at freq %i with %i channels\n",subtype,clock_rate,ch1annels); + ret=rtp_profile_find_payload_number(profile,subtype,clock_rate,channels); + ortp_free(subtype); + return ret; +} + +PayloadType * rtp_profile_find_payload(RtpProfile *prof,const char *mime,int rate,int channels) +{ + int i; + i=rtp_profile_find_payload_number(prof,mime,rate,channels); + if (i>=0) return rtp_profile_get_payload(prof,i); + return NULL; +} + + +PayloadType * rtp_profile_get_payload_from_mime(RtpProfile *profile,const char *mime) +{ + int pt; + pt=rtp_profile_get_payload_number_from_mime(profile,mime); + if (pt==-1) return NULL; + else return rtp_profile_get_payload(profile,pt); +} + + +PayloadType * rtp_profile_get_payload_from_rtpmap(RtpProfile *profile, const char *rtpmap) +{ + int pt = rtp_profile_get_payload_number_from_rtpmap(profile,rtpmap); + if (pt==-1) return NULL; + else return rtp_profile_get_payload(profile,pt); +} + +int rtp_profile_move_payload(RtpProfile *prof,int oldpos,int newpos){ + prof->payload[newpos]=prof->payload[oldpos]; + prof->payload[oldpos]=NULL; + return 0; +} + +RtpProfile * rtp_profile_new(const char *name) +{ + RtpProfile *prof=(RtpProfile*)ortp_new0(RtpProfile,1); + rtp_profile_set_name(prof,name); + return prof; +} + +/** + * Assign payload type number index to payload type desribed in pt for the RTP profile profile. + * @param profile a RTP profile + * @param idx the payload type number + * @param pt the payload type description + * +**/ +void rtp_profile_set_payload(RtpProfile *prof, int idx, PayloadType *pt){ + if (idx<0 || idx>=RTP_PROFILE_MAX_PAYLOADS) { + ortp_error("Bad index %i",idx); + return; + } + prof->payload[idx]=pt; +} + +/** + * Initialize the profile to the empty profile (all payload type are unassigned). + *@param profile a RTP profile + * +**/ +void rtp_profile_clear_all(RtpProfile *obj){ + int i; + for (i=0;ipayload[i]=0; + } +} + + +/** + * Set a name to the rtp profile. (This is not required) + * @param profile a rtp profile object + * @param nm a string + * +**/ +void rtp_profile_set_name(RtpProfile *obj, const char *name){ + if (obj->name!=NULL) ortp_free(obj->name); + obj->name=ortp_strdup(name); +} + +/* ! payload are not cloned*/ +RtpProfile * rtp_profile_clone(RtpProfile *prof) +{ + int i; + PayloadType *pt; + RtpProfile *newprof=rtp_profile_new(prof->name); + for (i=0;iname); + for (i=0;iname) { + ortp_free(prof->name); + prof->name = NULL; + } + for (i=0;iflags & PAYLOAD_TYPE_ALLOCATED)) + payload_type_destroy(payload); + } + ortp_free(prof); +} diff --git a/linphone/oRTP/src/port.c b/linphone/oRTP/src/port.c new file mode 100644 index 000000000..4b42b1c69 --- /dev/null +++ b/linphone/oRTP/src/port.c @@ -0,0 +1,336 @@ + +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#if defined(WIN32) || defined(_WIN32_WCE) +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" +#endif +#include "ortp/port.h" +#include "ortp/ortp.h" +#include "utils.h" + +#if defined(_WIN32) && !defined(_WIN32_WCE) +#include +#endif + +static void *ortp_libc_malloc(size_t sz){ + return malloc(sz); +} + +static void *ortp_libc_realloc(void *ptr, size_t sz){ + return realloc(ptr,sz); +} + +static void ortp_libc_free(void*ptr){ + free(ptr); +} + +static bool_t allocator_used=FALSE; + +static OrtpMemoryFunctions ortp_allocator={ + ortp_libc_malloc, + ortp_libc_realloc, + ortp_libc_free +}; + +void ortp_set_memory_functions(OrtpMemoryFunctions *functions){ + if (allocator_used){ + ortp_fatal("ortp_set_memory_functions() must be called before " + "first use of ortp_malloc or ortp_realloc"); + return; + } + ortp_allocator=*functions; +} + +void* ortp_malloc(size_t sz){ + allocator_used=TRUE; + return ortp_allocator.malloc_fun(sz); +} + +void* ortp_realloc(void *ptr, size_t sz){ + allocator_used=TRUE; + return ortp_allocator.realloc_fun(ptr,sz); +} + +void ortp_free(void* ptr){ + ortp_allocator.free_fun(ptr); +} + +void * ortp_malloc0(size_t size){ + void *ptr=ortp_malloc(size); + memset(ptr,0,size); + return ptr; +} + +char * ortp_strdup(const char *tmp){ + size_t sz; + char *ret; + if (tmp==NULL) + return NULL; + sz=strlen(tmp)+1; + ret=(char*)ortp_malloc(sz); + strcpy(ret,tmp); + ret[sz-1]='\0'; + return ret; +} + +/* + * this method is an utility method that calls fnctl() on UNIX or + * ioctlsocket on Win32. + * int retrun the result of the system method + */ +int set_non_blocking_socket (ortp_socket_t sock) +{ + + +#if !defined(_WIN32) && !defined(_WIN32_WCE) + return fcntl (sock, F_SETFL, O_NONBLOCK); +#else + unsigned long nonBlock = 1; + return ioctlsocket(sock, FIONBIO , &nonBlock); +#endif +} + + +/* + * this method is an utility method that calls close() on UNIX or + * closesocket on Win32. + * int retrun the result of the system method + */ +int close_socket(ortp_socket_t sock){ +#if !defined(_WIN32) && !defined(_WIN32_WCE) + return close (sock); +#else + return closesocket(sock); +#endif +} + + + +#if !defined(_WIN32) && !defined(_WIN32_WCE) + /* Use UNIX inet_aton method */ +#else + int inet_aton (const char * cp, struct in_addr * addr) + { + unsigned long retval; + + retval = inet_addr (cp); + + if (retval == INADDR_NONE) + { + return -1; + } + else + { + addr->S_un.S_addr = retval; + return 1; + } + } +#endif + +char *ortp_strndup(const char *str,int n){ + int min=MIN((int)strlen(str),n)+1; + char *ret=(char*)ortp_malloc(min); + strncpy(ret,str,n); + ret[min-1]='\0'; + return ret; +} + +#if !defined(_WIN32) && !defined(_WIN32_WCE) +int __ortp_thread_join(ortp_thread_t thread, void **ptr){ + int err=pthread_join(thread,ptr); + if (err!=0) { + ortp_error("pthread_join error: %s",strerror(err)); + } + return err; +} + +int __ortp_thread_create(pthread_t *thread, pthread_attr_t *attr, void * (*routine)(void*), void *arg){ + pthread_attr_t my_attr; + pthread_attr_init(&my_attr); + if (attr) + my_attr = *attr; +#ifdef ORTP_DEFAULT_THREAD_STACK_SIZE + if (ORTP_DEFAULT_THREAD_STACK_SIZE!=0) + pthread_attr_setstacksize(&my_attr, ORTP_DEFAULT_THREAD_STACK_SIZE); +#endif + return pthread_create(thread, &my_attr, routine, arg); +} + +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) + +int WIN_mutex_init(ortp_mutex_t *mutex, void *attr) +{ + *mutex=CreateMutex(NULL, FALSE, NULL); + return 0; +} + +int WIN_mutex_lock(ortp_mutex_t * hMutex) +{ + WaitForSingleObject(*hMutex, INFINITE); /* == WAIT_TIMEOUT; */ + return 0; +} + +int WIN_mutex_unlock(ortp_mutex_t * hMutex) +{ + ReleaseMutex(*hMutex); + return 0; +} + +int WIN_mutex_destroy(ortp_mutex_t * hMutex) +{ + CloseHandle(*hMutex); + return 0; +} + +typedef struct thread_param{ + void * (*func)(void *); + void * arg; +}thread_param_t; + +static unsigned WINAPI thread_starter(void *data){ + thread_param_t *params=(thread_param_t*)data; + void *ret=params->func(params->arg); + ortp_free(data); + return (DWORD)ret; +} + +#if defined _WIN32_WCE +# define _beginthreadex CreateThread +# define _endthreadex ExitThread +#endif + +int WIN_thread_create(ortp_thread_t *th, void *attr, void * (*func)(void *), void *data) +{ + thread_param_t *params=ortp_new(thread_param_t,1); + params->func=func; + params->arg=data; + *th=(HANDLE)_beginthreadex( NULL, 0, thread_starter, params, 0, NULL); + return 0; +} + +int WIN_thread_join(ortp_thread_t thread_h, void **unused) +{ + if (thread_h!=NULL) + { + WaitForSingleObject(thread_h, INFINITE); + CloseHandle(thread_h); + } + return 0; +} + +int WIN_cond_init(ortp_cond_t *cond, void *attr) +{ + *cond=CreateEvent(NULL, FALSE, FALSE, NULL); + return 0; +} + +int WIN_cond_wait(ortp_cond_t* hCond, ortp_mutex_t * hMutex) +{ + //gulp: this is not very atomic ! bug here ? + WIN_mutex_unlock(hMutex); + WaitForSingleObject(*hCond, INFINITE); + WIN_mutex_lock(hMutex); + return 0; +} + +int WIN_cond_signal(ortp_cond_t * hCond) +{ + SetEvent(*hCond); + return 0; +} + +int WIN_cond_broadcast(ortp_cond_t * hCond) +{ + WIN_cond_signal(hCond); + return 0; +} + +int WIN_cond_destroy(ortp_cond_t * hCond) +{ + CloseHandle(*hCond); + return 0; +} + + +#if defined(_WIN32_WCE) +#include + +int +gettimeofday (struct timeval *tv, void *tz) +{ + DWORD timemillis = GetTickCount(); + tv->tv_sec = timemillis/1000; + tv->tv_usec = (timemillis - (tv->tv_sec*1000)) * 1000; + return 0; +} + +#else + +int gettimeofday (struct timeval *tv, void* tz) +{ + union + { + __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME fileTime; + } now; + + GetSystemTimeAsFileTime (&now.fileTime); + tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); + tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); + return (0); +} + +#endif + +const char *getWinSocketError(int error) +{ + static char buf[80]; + + switch (error) + { + case WSANOTINITIALISED: return "Windows sockets not initialized : call WSAStartup"; + case WSAEADDRINUSE: return "Local Address already in use"; + case WSAEADDRNOTAVAIL: return "The specified address is not a valid address for this machine"; + case WSAEINVAL: return "The socket is already bound to an address."; + case WSAENOBUFS: return "Not enough buffers available, too many connections."; + case WSAENOTSOCK: return "The descriptor is not a socket."; + case WSAECONNRESET: return "Connection reset by peer"; + + default : + sprintf(buf, "Error code : %d", error); + return buf; + break; + } + + return buf; +} + +#ifdef _WORKAROUND_MINGW32_BUGS +char * WSAAPI gai_strerror(int errnum){ + return (char*)getWinSocketError(errnum); +} +#endif + +#endif + diff --git a/linphone/oRTP/src/posixtimer.c b/linphone/oRTP/src/posixtimer.c new file mode 100644 index 000000000..6330da00b --- /dev/null +++ b/linphone/oRTP/src/posixtimer.c @@ -0,0 +1,177 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if defined(WIN32) || defined(_WIN32_WCE) +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" +#endif + +#include "ortp/ortp.h" +#include "rtptimer.h" + +#if !defined(_WIN32) && !defined(_WIN32_WCE) + +#ifdef __linux__ +#include +#endif + +#include +#include +#include + + +static struct timeval orig,cur; +static uint32_t posix_timer_time=0; /*in milisecond */ + +void posix_timer_init() +{ + posix_timer.state=RTP_TIMER_RUNNING; + gettimeofday(&orig,NULL); + posix_timer_time=0; +} + + + + +void posix_timer_do() +{ + int diff,time; + struct timeval tv; + gettimeofday(&cur,NULL); + time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 ); + if ( (diff=time-posix_timer_time)>50){ + ortp_warning("Must catchup %i miliseconds.",diff); + } + while((diff = posix_timer_time-time) > 0) + { + tv.tv_sec = diff/1000; + tv.tv_usec = (diff%1000)*1000; +#if defined(_WIN32) || defined(_WIN32_WCE) + /* this kind of select is not supported on windows */ + Sleep(tv.tv_usec/1000 + tv.tv_sec * 1000); +#else + select(0,NULL,NULL,NULL,&tv); +#endif + gettimeofday(&cur,NULL); + time=((cur.tv_usec-orig.tv_usec)/1000 ) + ((cur.tv_sec-orig.tv_sec)*1000 ); + } + posix_timer_time+=POSIXTIMER_INTERVAL/1000; + +} + +void posix_timer_uninit() +{ + posix_timer.state=RTP_TIMER_STOPPED; +} + +RtpTimer posix_timer={ 0, + posix_timer_init, + posix_timer_do, + posix_timer_uninit, + {0,POSIXTIMER_INTERVAL}}; + + +#else //WIN32 + + +#include +#include + + +MMRESULT timerId; +HANDLE TimeEvent; +int late_ticks; + + +static DWORD posix_timer_time; +static DWORD offset_time; + + +#define TIME_INTERVAL 50 +#define TIME_RESOLUTION 10 +#define TIME_TIMEOUT 100 + + + +void CALLBACK timerCb(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + // Check timerId + if (timerId == uID) + { + SetEvent(TimeEvent); + posix_timer_time += TIME_INTERVAL; + } +} + + +void win_timer_init(void) +{ + timerId = timeSetEvent(TIME_INTERVAL,10,timerCb,0,TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + TimeEvent = CreateEvent(NULL,FALSE,FALSE,NULL); + + late_ticks = 0; + + offset_time = GetTickCount(); + posix_timer_time=0; +} + + +void win_timer_do(void) +{ + DWORD diff; + + // If timer have expired while we where out of this method + // Try to run after lost time. + if (late_ticks > 0) + { + late_ticks--; + posix_timer_time+=TIME_INTERVAL; + return; + } + + + diff = GetTickCount() - posix_timer_time - offset_time; + if( diff>TIME_INTERVAL && (diff<(1<<31))) + { + late_ticks = diff/TIME_INTERVAL; + ortp_warning("we must catchup %i ticks.",late_ticks); + return; + } + + WaitForSingleObject(TimeEvent,TIME_TIMEOUT); + return; +} + + +void win_timer_close(void) +{ + timeKillEvent(timerId); +} + +RtpTimer toto; + +RtpTimer posix_timer={ 0, + win_timer_init, + win_timer_do, + win_timer_close, + {0,TIME_INTERVAL * 1000}}; + + +#endif // _WIN32 diff --git a/linphone/oRTP/src/rtcp.c b/linphone/oRTP/src/rtcp.c new file mode 100644 index 000000000..2d14813d5 --- /dev/null +++ b/linphone/oRTP/src/rtcp.c @@ -0,0 +1,412 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/*************************************************************************** + * rtcp.c + * + * Wed Dec 1 11:45:30 2004 + * Copyright 2004 Simon Morlat + * Email simon dot morlat at linphone dot org + ****************************************************************************/ +#include "ortp/ortp.h" +#include "ortp/rtpsession.h" +#include "ortp/rtcp.h" +#include "utils.h" +#include "rtpsession_priv.h" + +#define rtcp_bye_set_ssrc(b,pos,ssrc) (b)->ssrc[pos]=htonl(ssrc) +#define rtcp_bye_get_ssrc(b,pos) ntohl((b)->ssrc[pos]) + + +void rtcp_common_header_init(rtcp_common_header_t *ch, RtpSession *s,int type, int rc, int bytes_len){ + rtcp_common_header_set_version(ch,2); + rtcp_common_header_set_padbit(ch,0); + rtcp_common_header_set_packet_type(ch,type); + rtcp_common_header_set_rc(ch,rc); /* as we don't yet support multi source receiving */ + rtcp_common_header_set_length(ch,(bytes_len/4)-1); +} + +static mblk_t *sdes_chunk_new(uint32_t ssrc){ + mblk_t *m=allocb(RTCP_SDES_CHUNK_DEFAULT_SIZE,0); + sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr; + sc->csrc=htonl(ssrc); + m->b_wptr+=sizeof(sc->csrc); + return m; +} + + +static mblk_t * sdes_chunk_append_item(mblk_t *m, rtcp_sdes_type_t sdes_type, const char *content) +{ + if ( content ) + { + sdes_item_t si; + si.item_type=sdes_type; + si.len=(uint8_t) MIN(strlen(content),RTCP_SDES_MAX_STRING_SIZE); + m=appendb(m,(char*)&si,RTCP_SDES_ITEM_HEADER_SIZE,FALSE); + m=appendb(m,content,si.len,FALSE); + } + return m; +} + +static void sdes_chunk_set_ssrc(mblk_t *m, uint32_t ssrc){ + sdes_chunk_t *sc=(sdes_chunk_t*)m->b_rptr; + sc->csrc=htonl(ssrc); +} + +#define sdes_chunk_get_ssrc(m) ntohl(((sdes_chunk_t*)((m)->b_rptr))->csrc) + +static mblk_t * sdes_chunk_pad(mblk_t *m){ + return appendb(m,"",1,TRUE); +} + +/** + * Set session's SDES item for automatic sending of RTCP compound packets. + * If some items are not specified, use NULL. +**/ +void rtp_session_set_source_description(RtpSession *session, + const char *cname, const char *name, const char *email, const char *phone, + const char *loc, const char *tool, const char *note){ + mblk_t *chunk = sdes_chunk_new(session->snd.ssrc); + mblk_t *m=chunk; + const char *_cname=cname; + if (_cname==NULL) + { + _cname="Unknown"; + } + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, _cname); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note); + chunk=sdes_chunk_pad(chunk); + if (session->sd!=NULL) freemsg(session->sd); + session->sd=m; +} + +void +rtp_session_add_contributing_source(RtpSession *session, uint32_t csrc, + const char *cname, const char *name, const char *email, const char *phone, + const char *loc, const char *tool, const char *note) +{ + mblk_t *chunk = sdes_chunk_new(csrc); + mblk_t *m=chunk; + char *_cname=(char*)cname; + if (_cname==NULL) + { + _cname="toto"; + } + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_CNAME, cname); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NAME, name); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_EMAIL, email); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_PHONE, phone); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_LOC, loc); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_TOOL, tool); + chunk=sdes_chunk_append_item(chunk, RTCP_SDES_NOTE, note); + chunk=sdes_chunk_pad(chunk); + putq(&session->contributing_sources,m); +} + + + +mblk_t* rtp_session_create_rtcp_sdes_packet(RtpSession *session) +{ + mblk_t *mp=allocb(sizeof(rtcp_common_header_t),0); + rtcp_common_header_t *rtcp; + mblk_t *tmp,*m=mp; + queue_t *q; + int rc=0; + rtcp = (rtcp_common_header_t*)mp->b_wptr; + mp->b_wptr+=sizeof(rtcp_common_header_t); + + /* concatenate all sdes chunks */ + sdes_chunk_set_ssrc(session->sd,session->snd.ssrc); + m=concatb(m,dupmsg(session->sd)); + rc++; + + q=&session->contributing_sources; + for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,mp)){ + m=concatb(m,dupmsg(tmp)); + rc++; + } + rtcp_common_header_init(rtcp,session,RTCP_SDES,rc,msgdsize(mp)); + return mp; +} + + +mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason) +{ + int packet_size; + int strsize = 0; + int strpadding = 0; + mblk_t *mp; + rtcp_bye_t *rtcp; + + packet_size = RTCP_BYE_HEADER_SIZE; + if (reason!=NULL) { + strsize=(int)MIN(strlen(reason),RTCP_BYE_REASON_MAX_STRING_SIZE); + if (strsize > 0) { + strpadding = 3 - (strsize % 4); + packet_size += 1 + strsize + strpadding; + } + } + mp = allocb(packet_size, 0); + + rtcp = (rtcp_bye_t*)mp->b_rptr; + rtcp_common_header_init(&rtcp->ch,NULL,RTCP_BYE,1,packet_size); + rtcp->ssrc[0] = htonl(ssrc); + mp->b_wptr += RTCP_BYE_HEADER_SIZE; + /* append the reason if any*/ + if (reason!=NULL) { + const char pad[] = {0, 0, 0}; + unsigned char strsize_octet = (unsigned char)strsize; + + appendb(mp, (const char*)&strsize_octet, 1, FALSE); + appendb(mp, reason,strsize, FALSE); + appendb(mp, pad,strpadding, FALSE); + } + return mp; +} + +void rtp_session_remove_contributing_sources(RtpSession *session, uint32_t ssrc) +{ + queue_t *q=&session->contributing_sources; + mblk_t *tmp; + for (tmp=qbegin(q); !qend(q,tmp); tmp=qnext(q,tmp)){ + uint32_t csrc=sdes_chunk_get_ssrc(tmp); + if (csrc==ssrc) { + remq(q,tmp); + break; + } + } + tmp=rtcp_create_simple_bye_packet(ssrc, NULL); + rtp_session_rtcp_send(session,tmp); +} + +static void sender_info_init(sender_info_t *info, RtpSession *session){ + struct timeval tv; + uint32_t tmp; + gettimeofday(&tv,NULL); + info->ntp_timestamp_msw=htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */ +#if defined(_WIN32_WCE) + tmp=(uint32_t)((double)tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6); +#else + tmp=(uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6); +#endif + info->ntp_timestamp_lsw=htonl(tmp); + info->rtp_timestamp=htonl(session->rtp.snd_last_ts); + info->senders_packet_count=(uint32_t) htonl((u_long) session->rtp.stats.packet_sent); + info->senders_octet_count=(uint32_t) htonl((u_long) session->rtp.sent_payload_bytes); + session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent; +} + + + +static void report_block_init(report_block_t *b, RtpSession *session){ + int packet_loss=0; + uint8_t loss_fraction=0; + RtpStream *stream=&session->rtp; + uint32_t delay_snc_last_sr=0; + uint32_t fl_cnpl; + + /* compute the statistics */ + /*printf("hwrcv_extseq.one=%u, hwrcv_seq_at_last_SR=%u hwrcv_since_last_SR=%u\n", + stream->hwrcv_extseq.one, + stream->hwrcv_seq_at_last_SR, + stream->hwrcv_since_last_SR + );*/ + if (stream->hwrcv_seq_at_last_SR!=0){ + packet_loss=(stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR) - stream->hwrcv_since_last_SR; + if (packet_loss<0) + packet_loss=0; + stream->stats.cum_packet_loss+=packet_loss; + loss_fraction=(int)(256.0*(float)packet_loss/(float)stream->hwrcv_since_last_SR); + } + /* reset them */ + stream->hwrcv_since_last_SR=0; + stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq; + + if (stream->last_rcv_SR_time.tv_sec!=0){ + struct timeval now; + float delay; + gettimeofday(&now,NULL); + delay=(float) ((now.tv_sec-stream->last_rcv_SR_time.tv_sec)*1e6 ) + (now.tv_usec-stream->last_rcv_SR_time.tv_usec); + delay=(float) (delay*65536*1e-6); + delay_snc_last_sr=(uint32_t) delay; + } + + b->ssrc=htonl(session->rcv.ssrc); + fl_cnpl=((loss_fraction&0xFF)<<24) | (stream->stats.cum_packet_loss & 0xFFFFFF); + b->fl_cnpl=htonl(fl_cnpl); + b->interarrival_jitter=htonl((uint32_t) stream->jittctl.inter_jitter); + b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq); + b->lsr=htonl(stream->last_rcv_SR_ts); + b->delay_snc_last_sr=htonl(delay_snc_last_sr); +} + + + +static int rtcp_sr_init(RtpSession *session, uint8_t *buf, int size){ + rtcp_sr_t *sr=(rtcp_sr_t*)buf; + int rr=(session->rtp.stats.packet_recv>0); + int sr_size=sizeof(rtcp_sr_t)-sizeof(report_block_t)+(rr*sizeof(report_block_t)); + if (sizech,session,RTCP_SR,rr,sr_size); + sr->ssrc=htonl(session->snd.ssrc); + sender_info_init(&sr->si,session); + /*only include a report block if packets were received*/ + if (rr) + report_block_init(&sr->rb[0],session); + return sr_size; +} + +static int rtcp_rr_init(RtpSession *session, uint8_t *buf, int size){ + rtcp_rr_t *rr=(rtcp_rr_t*)buf; + if (sizech,session,RTCP_RR,1,sizeof(rtcp_rr_t)); + rr->ssrc=htonl(session->snd.ssrc); + report_block_init(&rr->rb[0],session); + return sizeof(rtcp_rr_t); +} + +static int rtcp_app_init(RtpSession *session, uint8_t *buf, uint8_t subtype, const char *name, int size){ + rtcp_app_t *app=(rtcp_app_t*)buf; + if (sizech,session,RTCP_APP,subtype,size); + app->ssrc=htonl(session->snd.ssrc); + memset(app->name,0,4); + strncpy(app->name,name,4); + return sizeof(rtcp_app_t); +} + +static mblk_t * make_rr(RtpSession *session){ + mblk_t *cm=NULL; + mblk_t *sdes=NULL; + + cm=allocb(sizeof(rtcp_sr_t),0); + cm->b_wptr+=rtcp_rr_init(session,cm->b_wptr,sizeof(rtcp_rr_t)); + /* make a SDES packet */ + if (session->sd!=NULL) + sdes=rtp_session_create_rtcp_sdes_packet(session); + /* link them */ + cm->b_cont=sdes; + return cm; +} + + +static mblk_t * make_sr(RtpSession *session){ + mblk_t *cm=NULL; + mblk_t *sdes=NULL; + + cm=allocb(sizeof(rtcp_sr_t),0); + cm->b_wptr+=rtcp_sr_init(session,cm->b_wptr,sizeof(rtcp_sr_t)); + /* make a SDES packet */ + if (session->sd!=NULL) + sdes=rtp_session_create_rtcp_sdes_packet(session); + /* link them */ + cm->b_cont=sdes; + return cm; +} + +void rtp_session_rtcp_process_send(RtpSession *session){ + RtpStream *st=&session->rtp; + mblk_t *m; + if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval + || st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){ + st->last_rtcp_report_snt_r=st->rcv_last_app_ts; + st->last_rtcp_report_snt_s=st->snd_last_ts; + m=make_sr(session); + /* send the compound packet */ + rtp_session_rtcp_send(session,m); + ortp_debug("Rtcp compound message sent."); + } +} + +void rtp_session_rtcp_process_recv(RtpSession *session){ + RtpStream *st=&session->rtp; + mblk_t *m=NULL; + if (st->rcv_last_app_ts - st->last_rtcp_report_snt_r > st->rtcp_report_snt_interval + || st->snd_last_ts - st->last_rtcp_report_snt_s > st->rtcp_report_snt_interval){ + st->last_rtcp_report_snt_r=st->rcv_last_app_ts; + st->last_rtcp_report_snt_s=st->snd_last_ts; + + if (session->rtp.last_rtcp_packet_countrtp.stats.packet_sent){ + m=make_sr(session); + session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent; + }else if (session->rtp.stats.packet_recv>0){ + /*don't send RR when no packet are received yet*/ + m=make_rr(session); + } + if (m!=NULL){ + /* send the compound packet */ + rtp_session_rtcp_send(session,m); + ortp_debug("Rtcp compound message sent."); + } + } +} + +void rtp_session_send_rtcp_APP(RtpSession *session, uint8_t subtype, const char *name, const uint8_t *data, int datalen){ + mblk_t *h=allocb(sizeof(rtcp_app_t),0); + mblk_t *d; + h->b_wptr+=rtcp_app_init(session,h->b_wptr,subtype,name,datalen+sizeof(rtcp_app_t)); + d=esballoc((uint8_t*)data,datalen,0,NULL); + h->b_cont=d; + rtp_session_rtcp_send(session,h); +} + +/** + * Sends a RTCP bye packet. + *@param session RtpSession + *@param reason the reason phrase. +**/ +int +rtp_session_bye(RtpSession *session, const char *reason) +{ + mblk_t *cm; + mblk_t *sdes = NULL; + mblk_t *bye = NULL; + int ret; + + /* Make a BYE packet (will be on the end of the compund packet). */ + bye = rtcp_create_simple_bye_packet(session->snd.ssrc, reason); + + /* SR or RR is determined by the fact whether stream was sent*/ + if (session->rtp.stats.packet_sent>0) + { + cm = allocb(sizeof(rtcp_sr_t), 0); + cm->b_wptr += rtcp_sr_init(session,cm->b_wptr, sizeof(rtcp_sr_t)); + /* make a SDES packet */ + sdes = rtp_session_create_rtcp_sdes_packet(session); + /* link them */ + concatb(concatb(cm, sdes), bye); + } else if (session->rtp.stats.packet_recv>0){ + /* make a RR packet */ + cm = allocb(sizeof(rtcp_rr_t), 0); + cm->b_wptr += rtcp_rr_init(session, cm->b_wptr, sizeof(rtcp_rr_t)); + /* link them */ + cm->b_cont = bye; + }else cm=bye; + + /* Send compound packet. */ + ret = rtp_session_rtcp_send(session, cm); + + return ret; +} + diff --git a/linphone/oRTP/src/rtcpparse.c b/linphone/oRTP/src/rtcpparse.c new file mode 100644 index 000000000..64df2c776 --- /dev/null +++ b/linphone/oRTP/src/rtcpparse.c @@ -0,0 +1,541 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "ortp/ortp.h" +#include "utils.h" + + +/*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP +packet */ +bool_t rtcp_next_packet(mblk_t *m){ + const rtcp_common_header_t *ch=rtcp_get_common_header(m); + if (ch){ + int nextlen=sizeof(rtcp_common_header_t)+ + (rtcp_common_header_get_length(ch)*4); + if (m->b_rptr+nextlenb_wptr){ + m->b_rptr+=nextlen; + return TRUE; + } + } + return FALSE; +} + +void rtcp_rewind(mblk_t *m){ + m->b_rptr=m->b_datap->db_base; +} + +/* get common header; this function will also check the sanity of the packet*/ +const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m){ + int size=msgdsize(m); + rtcp_common_header_t *ch; + if (m->b_cont!=NULL){ + ortp_fatal("RTCP parser does not work on fragmented mblk_t. Use msgpullup() before to re-assemble the packet."); + return NULL; + } + if (sizeb_rptr; + return ch; +} + +bool_t rtcp_is_SR(const mblk_t *m){ + const rtcp_common_header_t *ch=rtcp_get_common_header(m); + if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_SR){ + if (msgdsize(m)b_rptr; + return ntohl(sr->ssrc); +} + +const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m){ + rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr; + return &sr->si; +} + +const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx){ + rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr; + report_block_t *rb=&sr->rb[idx]; + int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&sr->ch)); + if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= m->b_rptr + size ) { + return rb; + }else{ + if (idxch)){ + ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx); + } + } + return NULL; +} + +/*Receiver report accessors*/ +bool_t rtcp_is_RR(const mblk_t *m){ + const rtcp_common_header_t *ch=rtcp_get_common_header(m); + if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_RR){ + if (msgdsize(m)b_rptr; + return ntohl(rr->ssrc); +} + +const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx){ + rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr; + report_block_t *rb=&rr->rb[idx]; + int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&rr->ch)); + if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= (m->b_rptr + size ) ){ + return rb; + }else{ + if (idxch)){ + ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx); + } + } + return NULL; +} + +/*SDES accessors */ +bool_t rtcp_is_SDES(const mblk_t *m){ + const rtcp_common_header_t *ch=rtcp_get_common_header(m); + if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_SDES){ + if (msgdsize(m)b_rptr+sizeof(rtcp_common_header_t); + const rtcp_common_header_t *ch=(rtcp_common_header_t*)m->b_rptr; + uint8_t *end=rptr+sizeof(rtcp_common_header_t)+ + (4*rtcp_common_header_get_length(ch)); + uint32_t ssrc=0; + int nchunk=0; + bool_t chunk_start=TRUE; + + if (end>(uint8_t*)m->b_wptr) end=(uint8_t*)m->b_wptr; + + while(rptrb_rptr; + int rc=rtcp_common_header_get_rc(&bye->ch); + int len=rtcp_common_header_get_length(&bye->ch); + if (idxssrc[idx]<=(m->b_rptr + +sizeof(rtcp_common_header_t)+len-4)) { + *ssrc=ntohl(bye->ssrc[idx]); + return TRUE; + }else{ + ortp_warning("RTCP BYE should contain %i ssrc, but there is not enough room for it."); + } + } + return FALSE; +} + +bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len){ + rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr; + int rc=rtcp_common_header_get_rc(&bye->ch); + int len=rtcp_common_header_get_length(&bye->ch); + uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t)+rc*4; + uint8_t *end=(uint8_t*)(m->b_rptr+sizeof(rtcp_common_header_t)+len); + if (rptrb_rptr; + return rtcp_common_header_get_rc(&app->ch); +} + +uint32_t rtcp_APP_get_ssrc(const mblk_t *m){ + rtcp_app_t *app=(rtcp_app_t*)m->b_rptr; + return ntohl(app->ssrc); +} +/* name argument is supposed to be at least 4 characters (note: no '\0' written)*/ +void rtcp_APP_get_name(const mblk_t *m, char *name){ + rtcp_app_t *app=(rtcp_app_t*)m->b_rptr; + memcpy(name,app->name,4); +} +/* retrieve the data. when returning, data points directly into the mblk_t */ +void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len){ + rtcp_app_t *app=(rtcp_app_t*)m->b_rptr; + int datalen=sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(&app->ch)-8; + if (datalen>0){ + *data=(uint8_t*)m->b_rptr+sizeof(rtcp_app_t); + *len=datalen; + }else{ + *len=0; + *data=NULL; + } +} + +/*old functions: deprecated, but some useful code parts can be reused */ +/* Start from now this source code file was written by Nicola Baldo as an extension of + the oRTP library. Copyright (C) 2005 Nicola Baldo nicola@baldo.biz*/ + +void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval rcv_time_tv) +{ + rb->ssrc = ntohl(rb->ssrc); + + if ( rb->ssrc != session->snd.ssrc ) + + { + ortp_debug("Received rtcp report block related to unknown ssrc (not from us)... discarded"); + return; + } + + else + + { + uint32_t rcv_time_msw; + uint32_t rcv_time_lsw; + uint32_t rcv_time; + double rtt; + + rcv_time_msw = rcv_time_tv.tv_sec; +#if defined(_WIN32_WCE) + rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6); +#else + rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(1LL<<32)*1.0e-6); +#endif + rcv_time = (rcv_time_msw<<16) | (rcv_time_lsw >> 16); + +/* + rb->cum_num_packet_lost = ntoh24(rb->cum_num_packet_lost); + rb->ext_high_seq_num_rec = ntohl(rb->ext_high_seq_num_rec); + rb->interarrival_jitter = ntohl(rb->interarrival_jitter); + rb->lsr = ntohl(rb->lsr); + rb->delay_snc_last_sr = ntohl(rb->delay_snc_last_sr); +*/ + + /* calculating Round Trip Time*/ + if (rb->lsr != 0) + { + rtt = (double) (rcv_time - rb->delay_snc_last_sr - rb->lsr); + rtt = rtt/65536; + //printf("RTT = %f s\n",rtt); + } + + } + +} + +void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp) +{ + rtcp_common_header_t *rtcp; + int msgsize; + int rtcp_pk_size; + RtpStream *rtpstream=&session->rtp; + struct timeval rcv_time_tv; + + + gettimeofday(&rcv_time_tv,NULL); + + return_if_fail(mp!=NULL); + + msgsize=(int) (mp->b_wptr-mp->b_rptr); + + if (msgsize < RTCP_COMMON_HEADER_SIZE) + { + ortp_debug("Receiving too short rtcp packet... discarded"); + return; + } + + rtcp=(rtcp_common_header_t *)mp->b_rptr; + + /* compound rtcp packet can be composed by more than one rtcp message */ + while (msgsize >= RTCP_COMMON_HEADER_SIZE) + { + + if (rtcp->version!=2) + { + ortp_debug("Receiving rtcp packet with version number !=2...discarded"); + return; + } + + /* convert header data from network order to host order */ + rtcp->length = ntohs(rtcp->length); + + /* compute length */ + rtcp_pk_size = (rtcp->length + 1) * 4; + /* Sanity check of simple RTCP packet length. */ + if (rtcp_pk_size > msgsize) + { + ortp_debug("Receiving rtcp packet shorter than the specified length.. discared"); + return; + } + + switch (rtcp->packet_type) + + { + + case RTCP_SR: + + { + rtcp_sr_t *sr = (rtcp_sr_t *) rtcp; + report_block_t *rb; + int i; + + if ( ntohl(sr->ssrc) != session->rcv.ssrc ) + { + ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded"); + return; + } + + if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc)) + { + ortp_debug("Receiving too short rtcp sr packet... discarded"); + return; + } + + /* parsing RTCP Sender Info */ + sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw); + sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw); + sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp); + sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count); + sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count); + + /* saving data to fill LSR and DLSR field in next RTCP report to be transmitted */ + rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16); + rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec; + rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec; + + + /* parsing all RTCP report blocks */ + for (i=0; ich.rc; i++) + { + rb = &(sr->rb[i]); + report_block_parse(session, rb, rcv_time_tv); + } + + } + break; + + + + case RTCP_RR: + + { + rtcp_rr_t *rr = (rtcp_rr_t *) rtcp; + report_block_t *rb; + int i; + + if (session->rcv.ssrc == 0) + { + /* rcv.ssrc is not set, so we adopt the incoming one */ + session->rcv.ssrc = ntohl(rr->ssrc); + } + else if ( ntohl(rr->ssrc) != session->rcv.ssrc ) + { + ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded"); + return; + } + + if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc)) + { + ortp_debug("Receiving too short rtcp sr packet... discarded"); + return; + } + + /* parsing all RTCP report blocks */ + for (i=0; ich.rc; i++) + { + rb = &(rr->rb[i]); + report_block_parse(session, rb, rcv_time_tv); + } + + } + break; + + + case RTCP_SDES: + /* to be implemented */ + break; + + + case RTCP_BYE: + { + rtcp_bye_t *bye = (rtcp_bye_t *) rtcp; + unsigned sclen = bye->ch.rc * 4; + int reason_space_len = rtcp_pk_size + - sizeof (rtcp_common_header_t) + - sclen; + int i; + char *reason = NULL; + bool_t rcv_ssrc_match = FALSE; + + if (reason_space_len < 0) { + ortp_debug("Receiving too short RTCP BYE packet... discarded"); + return; + } + for (i = 0; i < bye->ch.rc; i++) { + if (ntohl(bye->ssrc[i]) == session->rcv.ssrc) { + rcv_ssrc_match = TRUE; + break; + } + } + if (rcv_ssrc_match) { + if (session->on_rtcp_bye.count > 0) { + /* Get reason. */ + if (reason_space_len > 1) { + uint8_t *reasonbuf = (uint8_t *) rtcp + + sizeof (rtcp_common_header_t) + + sclen; + if (reasonbuf[0] <= reason_space_len-1) + reason = ortp_strndup((char *)(reasonbuf+1), reasonbuf[0]); + else + ortp_debug("Incorrect RTCP BYE reason length"); + } + rtp_signal_table_emit2(&session->on_rtcp_bye, + (long)reason); + if (reason) + ortp_free(reason); + } else { + ortp_debug("Got RTCP BYE without RTCP BYE handler"); + } + } else { + ortp_debug("No SSRC in the BYE packet matched our rcv.ssrc."); + } + break; + } + + case RTCP_APP: + /* to be implemented */ + break; + + + default: + + ortp_debug("Receiving unknown rtcp packet type... discarded"); + return; + + } + + + msgsize -= rtcp_pk_size; /* size of unparsed portion of UDP packet, in octets */ + rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp); /* pointer to next RTCP packet in current UDP packet */ + + } + + /* The function did not failed sanity checks, write down the RTPC/RTCP + reception time. */ + session->last_recv_time = rcv_time_tv; +} diff --git a/linphone/oRTP/src/rtpparse.c b/linphone/oRTP/src/rtpparse.c new file mode 100644 index 000000000..93c15cbbe --- /dev/null +++ b/linphone/oRTP/src/rtpparse.c @@ -0,0 +1,213 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include +#include "jitterctl.h" +#include "utils.h" +#include "rtpsession_priv.h" + +#define SSRC_CHANGED_THRESHOLD 50 + +static void queue_packet(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded) +{ + mblk_t *tmp; + int header_size; + *discarded=0; + header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc); + if ((mp->b_wptr - mp->b_rptr)==header_size){ + ortp_debug("Rtp packet contains no data."); + (*discarded)++; + freemsg(mp); + return; + } + /* and then add the packet to the queue */ + + rtp_putq(q,mp); + /* make some checks: q size must not exceed RtpStream::max_rq_size */ + while (q->q_mcount > maxrqsz) + { + /* remove the oldest mblk_t */ + tmp=getq(q); + if (mp!=NULL) + { + ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp); + freemsg(tmp); + (*discarded)++; + } + } +} + +void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen) +{ + int i; + rtp_header_t *rtp; + int msgsize; + RtpStream *rtpstream=&session->rtp; + rtp_stats_t *stats=&rtpstream->stats; + + msgsize=mp->b_wptr-mp->b_rptr; + + if (msgsizestats.bad++; + ortp_global_stats.bad++; + freemsg(mp); + return; + } + rtp=(rtp_header_t*)mp->b_rptr; + if (rtp->version!=2) + { + /* try to see if it is a STUN packet */ + uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t))); + stunlen = ntohs(stunlen); + if (stunlen+20==mp->b_wptr-mp->b_rptr){ + /* this looks like a stun packet */ + if (session->eventqs!=NULL){ + OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED); + OrtpEventData *ed=ortp_event_get_data(ev); + ed->packet=mp; + ed->ep=rtp_endpoint_new(addr,addrlen); + rtp_session_dispatch_event(session,ev); + return; + } + }else{ + /* discard*/ + ortp_debug("Receiving rtp packet with version number !=2...discarded"); + stats->bad++; + ortp_global_stats.bad++; + freemsg(mp); + return; + } + } + + /* only count non-stun packets. */ + ortp_global_stats.packet_recv++; + stats->packet_recv++; + ortp_global_stats.hw_recv+=msgsize; + stats->hw_recv+=msgsize; + session->rtp.hwrcv_since_last_SR++; + + + /* convert all header data from network order to host order */ + rtp->seq_number=ntohs(rtp->seq_number); + rtp->timestamp=ntohl(rtp->timestamp); + rtp->ssrc=ntohl(rtp->ssrc); + /* convert csrc if necessary */ + if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){ + ortp_debug("Receiving too short rtp packet."); + stats->bad++; + ortp_global_stats.bad++; + freemsg(mp); + return; + } + +#ifndef PERF + /* Write down the last RTP/RTCP packet reception time. */ + gettimeofday(&session->last_recv_time, NULL); +#endif + + for (i=0;icc;i++) + rtp->csrc[i]=ntohl(rtp->csrc[i]); + /*the goal of the following code is to lock on an incoming SSRC to avoid + receiving "mixed streams"*/ + if (session->ssrc_set){ + /*the ssrc is set, so we must check it */ + if (session->rcv.ssrc!=rtp->ssrc){ + if (session->inc_ssrc_candidate==rtp->ssrc){ + session->inc_same_ssrc_count++; + }else{ + session->inc_same_ssrc_count=0; + session->inc_ssrc_candidate=rtp->ssrc; + } + if (session->inc_same_ssrc_count>SSRC_CHANGED_THRESHOLD){ + session->rcv.ssrc=rtp->ssrc; + rtp_signal_table_emit(&session->on_ssrc_changed); + }else{ + /*discard the packet*/ + ortp_debug("Receiving packet with unknown ssrc."); + stats->bad++; + ortp_global_stats.bad++; + freemsg(mp); + return; + } + } + }else{ + session->ssrc_set=TRUE; + session->rcv.ssrc=rtp->ssrc; + } + + /* update some statistics */ + { + poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq; + if (rtp->seq_number>extseq->split.lo){ + extseq->split.lo=rtp->seq_number; + }else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){ + /* this is a check for sequence number looping */ + extseq->split.lo=rtp->seq_number; + extseq->split.hi++; + } + } + + /* check for possible telephone events */ + if (rtp->paytype==session->rcv.telephone_events_pt){ + queue_packet(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i); + stats->discarded+=i; + ortp_global_stats.discarded+=i; + return; + } + + /* check for possible payload type change, in order to update accordingly our clock-rate dependant + parameters */ + if (session->hw_recv_pt!=rtp->paytype){ + rtp_session_update_payload_type(session,rtp->paytype); + } + + jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts); + + if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) { + /* detect timestamp important jumps in the future, to workaround stupid rtp senders */ + if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){ + ortp_debug("rtp_parse: timestamp jump ?"); + rtp_signal_table_emit2(&session->on_timestamp_jump,(long)&rtp->timestamp); + } + else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){ + /* don't queue packets older than the last returned packet to the application*/ + /* Call timstamp jumb in case of + * large negative Ts jump or if ts is set to 0 + */ + + if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){ + ortp_warning("rtp_parse: negative timestamp jump"); + rtp_signal_table_emit2(&session->on_timestamp_jump, + (long)&rtp->timestamp); + } + ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp); + freemsg(mp); + stats->outoftime++; + ortp_global_stats.outoftime++; + return; + } + } + + queue_packet(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i); + stats->discarded+=i; + ortp_global_stats.discarded+=i; +} + diff --git a/linphone/oRTP/src/rtpsession.c b/linphone/oRTP/src/rtpsession.c new file mode 100644 index 000000000..f773dcb86 --- /dev/null +++ b/linphone/oRTP/src/rtpsession.c @@ -0,0 +1,1596 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#if defined(WIN32) || defined(_WIN32_WCE) +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" +#endif + +#include "ortp/ortp.h" +#include "ortp/telephonyevents.h" +#include "ortp/rtcp.h" +#include "jitterctl.h" +#include "scheduler.h" +#include "utils.h" +#include "rtpsession_priv.h" + +extern mblk_t *rtcp_create_simple_bye_packet(uint32_t ssrc, const char *reason); +extern int rtcp_sr_init(RtpSession *session, char *buf, int size); +extern int rtcp_rr_init(RtpSession *session, char *buf, int size); + + + +/* this function initialize all session parameter's that depend on the payload type */ +static void payload_type_changed(RtpSession *session, PayloadType *pt){ + jitter_control_set_payload(&session->rtp.jittctl,pt); + session->rtp.rtcp_report_snt_interval=RTCP_DEFAULT_REPORT_INTERVAL*pt->clock_rate; + rtp_session_set_time_jump_limit(session,session->rtp.time_jump); + if (pt->type==PAYLOAD_VIDEO){ + session->permissive=TRUE; + ortp_message("Using permissive algorithm"); + } + else session->permissive=FALSE; +} + +void wait_point_init(WaitPoint *wp){ + ortp_mutex_init(&wp->lock,NULL); + ortp_cond_init(&wp->cond,NULL); + wp->time=0; + wp->wakeup=FALSE; +} +void wait_point_uninit(WaitPoint *wp){ + ortp_cond_destroy(&wp->cond); + ortp_mutex_destroy(&wp->lock); +} + +#define wait_point_lock(wp) ortp_mutex_lock(&(wp)->lock) +#define wait_point_unlock(wp) ortp_mutex_unlock(&(wp)->lock) + +void wait_point_wakeup_at(WaitPoint *wp, uint32_t t, bool_t dosleep){ + wp->time=t; + wp->wakeup=TRUE; + if (dosleep) ortp_cond_wait(&wp->cond,&wp->lock); +} + + +bool_t wait_point_check(WaitPoint *wp, uint32_t t){ + bool_t ok=FALSE; + + if (wp->wakeup){ + if (TIME_IS_NEWER_THAN(t,wp->time)){ + wp->wakeup=FALSE; + ok=TRUE; + + } + } + return ok; +} +#define wait_point_wakeup(wp) ortp_cond_signal(&(wp)->cond); + +extern void rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, + struct sockaddr *addr, socklen_t addrlen); + + +static uint32_t uint32_t_random(){ + return random(); +} + + +#define RTP_SEQ_IS_GREATER(seq1,seq2)\ + ((uint16_t)((uint16_t)(seq1) - (uint16_t)(seq2))< (uint16_t)(1<<15)) + +/* put an rtp packet in queue. It is called by rtp_parse()*/ +void rtp_putq(queue_t *q, mblk_t *mp) +{ + mblk_t *tmp; + rtp_header_t *rtp=(rtp_header_t*)mp->b_rptr,*tmprtp; + /* insert message block by increasing time stamp order : the last (at the bottom) + message of the queue is the newest*/ + ortp_debug("rtp_putq(): Enqueuing packet with ts=%i and seq=%i",rtp->timestamp,rtp->seq_number); + + if (qempty(q)) { + putq(q,mp); + return; + } + tmp=qlast(q); + /* we look at the queue from bottom to top, because enqueued packets have a better chance + to be enqueued at the bottom, since there are surely newer */ + while (!qend(q,tmp)) + { + tmprtp=(rtp_header_t*)tmp->b_rptr; + ortp_debug("rtp_putq(): Seeing packet with seq=%i",tmprtp->seq_number); + + if (rtp->seq_number == tmprtp->seq_number) + { + /* this is a duplicated packet. Don't queue it */ + ortp_debug("rtp_putq: duplicated message."); + freemsg(mp); + return; + }else if (RTP_SEQ_IS_GREATER(rtp->seq_number,tmprtp->seq_number)){ + + insq(q,tmp->b_next,mp); + return; + } + tmp=tmp->b_prev; + } + /* this packet is the oldest, it has to be + placed on top of the queue */ + insq(q,qfirst(q),mp); + +} + + + +mblk_t *rtp_getq(queue_t *q,uint32_t timestamp, int *rejected) +{ + mblk_t *tmp,*ret=NULL,*old=NULL; + rtp_header_t *tmprtp; + uint32_t ts_found=0; + + *rejected=0; + ortp_debug("rtp_getq(): Timestamp %i wanted.",timestamp); + + if (qempty(q)) + { + /*ortp_debug("rtp_getq: q is empty.");*/ + return NULL; + } + /* return the packet with ts just equal or older than the asked timestamp */ + /* packets with older timestamps are discarded */ + while ((tmp=qfirst(q))!=NULL) + { + tmprtp=(rtp_header_t*)tmp->b_rptr; + ortp_debug("rtp_getq: Seeing packet with ts=%i",tmprtp->timestamp); + if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) ) + { + if (ret!=NULL && tmprtp->timestamp==ts_found) { + /* we've found two packets with same timestamp. return the first one */ + break; + } + if (old!=NULL) { + ortp_debug("rtp_getq: discarding too old packet with ts=%i",ts_found); + (*rejected)++; + freemsg(old); + } + ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/ + ts_found=tmprtp->timestamp; + ortp_debug("rtp_getq: Found packet with ts=%i",tmprtp->timestamp); + old=ret; + } + else + { + break; + } + } + return ret; +} + +mblk_t *rtp_getq_permissive(queue_t *q,uint32_t timestamp, int *rejected) +{ + mblk_t *tmp,*ret=NULL; + rtp_header_t *tmprtp; + + *rejected=0; + ortp_debug("rtp_getq_permissive(): Timestamp %i wanted.",timestamp); + + if (qempty(q)) + { + /*ortp_debug("rtp_getq: q is empty.");*/ + return NULL; + } + /* return the packet with the older timestamp (provided that it is older than + the asked timestamp) */ + tmp=qfirst(q); + tmprtp=(rtp_header_t*)tmp->b_rptr; + ortp_debug("rtp_getq_permissive: Seeing packet with ts=%i",tmprtp->timestamp); + if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) ) + { + ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/ + ortp_debug("rtp_getq_permissive: Found packet with ts=%i",tmprtp->timestamp); + } + return ret; +} + + +void +rtp_session_init (RtpSession * session, int mode) +{ + JBParameters jbp; + memset (session, 0, sizeof (RtpSession)); + session->mode = (RtpSessionMode) mode; + if ((mode == RTP_SESSION_RECVONLY) || (mode == RTP_SESSION_SENDRECV)) + { + rtp_session_set_flag (session, RTP_SESSION_RECV_SYNC); + rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED); + + } + if ((mode == RTP_SESSION_SENDONLY) || (mode == RTP_SESSION_SENDRECV)) + { + rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED); + session->snd.ssrc=uint32_t_random(); + /* set default source description */ + rtp_session_set_source_description(session,"unknown@unknown",NULL,NULL, + NULL,NULL,"oRTP-" ORTP_VERSION,"This is free sofware (LGPL) !"); + } + session->snd.telephone_events_pt=-1; /* not defined a priori */ + session->rcv.telephone_events_pt=-1; /* not defined a priori */ + rtp_session_set_profile (session, &av_profile); /*the default profile to work with */ + session->rtp.socket=-1; + session->rtcp.socket=-1; +#ifndef WIN32 + session->rtp.snd_socket_size=0; /*use OS default value unless on windows where they are definitely too short*/ + session->rtp.rcv_socket_size=0; +#else + session->rtp.snd_socket_size=session->rtp.rcv_socket_size=65536; +#endif + session->dscp=RTP_DEFAULT_DSCP; + session->multicast_ttl=RTP_DEFAULT_MULTICAST_TTL; + session->multicast_loopback=RTP_DEFAULT_MULTICAST_LOOPBACK; + qinit(&session->rtp.rq); + qinit(&session->rtp.tev_rq); + qinit(&session->contributing_sources); + session->eventqs=NULL; + /* init signal tables */ + rtp_signal_table_init (&session->on_ssrc_changed, session,"ssrc_changed"); + rtp_signal_table_init (&session->on_payload_type_changed, session,"payload_type_changed"); + rtp_signal_table_init (&session->on_telephone_event, session,"telephone-event"); + rtp_signal_table_init (&session->on_telephone_event_packet, session,"telephone-event_packet"); + rtp_signal_table_init (&session->on_timestamp_jump,session,"timestamp_jump"); + rtp_signal_table_init (&session->on_network_error,session,"network_error"); + rtp_signal_table_init (&session->on_rtcp_bye,session,"rtcp_bye"); + wait_point_init(&session->snd.wp); + wait_point_init(&session->rcv.wp); + /*defaults send payload type to 0 (pcmu)*/ + rtp_session_set_send_payload_type(session,0); + /*sets supposed recv payload type to undefined */ + rtp_session_set_recv_payload_type(session,-1); + /* configure jitter buffer with working default parameters */ + jbp.min_size=RTP_DEFAULT_JITTER_TIME; + jbp.nom_size=RTP_DEFAULT_JITTER_TIME; + jbp.max_size=-1; + jbp.max_packets= 100;/* maximum number of packet allowed to be queued */ + jbp.adaptive=TRUE; + rtp_session_enable_jitter_buffer(session,TRUE); + rtp_session_set_jitter_buffer_params(session,&jbp); + rtp_session_set_time_jump_limit(session,5000); + rtp_session_enable_rtcp(session,TRUE); + session->recv_buf_size = UDP_MAX_SIZE; + session->symmetric_rtp = FALSE; + session->permissive=FALSE; + msgb_allocator_init(&session->allocator); +} + + +/** + * Creates a new rtp session. + * If the session is able to send data (RTP_SESSION_SENDONLY or + * RTP_SESSION_SENDRECV), then a random SSRC number is choosed for + * the outgoing stream. + * @param mode One of the RtpSessionMode flags. + * + * @return the newly created rtp session. +**/ +RtpSession * +rtp_session_new (int mode) +{ + RtpSession *session; + session = (RtpSession *) ortp_malloc (sizeof (RtpSession)); + rtp_session_init (session, mode); + return session; +} + +/** + * Sets the scheduling mode of the rtp session. If @yesno is TRUE, the rtp session is in + * the scheduled mode, that means that you can use session_set_select() to block until it's time + * to receive or send on this session according to the timestamp passed to the respective functions. + * You can also use blocking mode (see rtp_session_set_blocking_mode() ), to simply block within + * the receive and send functions. + * If @yesno is FALSE, the ortp scheduler will not manage those sessions, meaning that blocking mode + * and the use of session_set_select() for this session are disabled. + *@param session a rtp session. + *@param yesno a boolean to indicate the scheduling mode. + * + * +**/ +void +rtp_session_set_scheduling_mode (RtpSession * session, int yesno) +{ + if (yesno) + { + RtpScheduler *sched; + sched = ortp_get_scheduler (); + if (sched != NULL) + { + rtp_session_set_flag (session, RTP_SESSION_SCHEDULED); + session->sched = sched; + rtp_scheduler_add_session (sched, session); + } + else + ortp_warning + ("rtp_session_set_scheduling_mode: Cannot use scheduled mode because the " + "scheduler is not started. Use ortp_scheduler_init() before."); + } + else + rtp_session_unset_flag (session, RTP_SESSION_SCHEDULED); +} + + +/** + * This function implicitely enables the scheduling mode if yesno is TRUE. + * rtp_session_set_blocking_mode() defines the behaviour of the rtp_session_recv_with_ts() and + * rtp_session_send_with_ts() functions. If @yesno is TRUE, rtp_session_recv_with_ts() + * will block until it is time for the packet to be received, according to the timestamp + * passed to the function. After this time, the function returns. + * For rtp_session_send_with_ts(), it will block until it is time for the packet to be sent. + * If @yesno is FALSE, then the two functions will return immediately. + * + * @param session a rtp session + * @param yesno a boolean +**/ +void +rtp_session_set_blocking_mode (RtpSession * session, int yesno) +{ + if (yesno){ + rtp_session_set_scheduling_mode(session,TRUE); + rtp_session_set_flag (session, RTP_SESSION_BLOCKING_MODE); + }else + rtp_session_unset_flag (session, RTP_SESSION_BLOCKING_MODE); +} + +/** + * Set the RTP profile to be used for the session. By default, all session are created by + * rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application + * can set any other profile instead using that function. + * + * @param session a rtp session + * @param profile a rtp profile +**/ + +void +rtp_session_set_profile (RtpSession * session, RtpProfile * profile) +{ + session->snd.profile = profile; + session->rcv.profile = profile; + rtp_session_telephone_events_supported(session); +} + +/** + * By default oRTP automatically sends RTCP SR or RR packets. If + * yesno is set to FALSE, the RTCP sending of packet is disabled. + * This functionnality might be needed for some equipments that do not + * support RTCP, leading to a traffic of ICMP errors on the network. + * It can also be used to save bandwidth despite the RTCP bandwidth is + * actually and usually very very low. +**/ +void rtp_session_enable_rtcp(RtpSession *session, bool_t yesno){ + session->rtcp.enabled=yesno; +} + +/** + * Set the RTP profile to be used for the sending by this session. By default, all session are created by + * rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application + * can set any other profile instead using that function. + * @param session a rtp session + * @param profile a rtp profile + * +**/ + +void +rtp_session_set_send_profile (RtpSession * session, RtpProfile * profile) +{ + session->snd.profile = profile; + rtp_session_send_telephone_events_supported(session); +} + + + +/** + * Set the RTP profile to be used for the receiveing by this session. By default, all session are created by + * rtp_session_new() are initialized with the AV profile, as defined in RFC 3551. The application + * can set any other profile instead using that function. + * + * @param session a rtp session + * @param profile a rtp profile +**/ + +void +rtp_session_set_recv_profile (RtpSession * session, RtpProfile * profile) +{ + session->rcv.profile = profile; + rtp_session_recv_telephone_events_supported(session); +} + +/** + *@param session a rtp session + * + * DEPRECATED! Returns current send profile. + * Use rtp_session_get_send_profile() or rtp_session_get_recv_profile() + * +**/ +RtpProfile *rtp_session_get_profile(RtpSession *session){ + return session->snd.profile; +} + + +/** + *@param session a rtp session + * + * Returns current send profile. + * +**/ +RtpProfile *rtp_session_get_send_profile(RtpSession *session){ + return session->snd.profile; +} + +/** + *@param session a rtp session + * + * Returns current receive profile. + * +**/ +RtpProfile *rtp_session_get_recv_profile(RtpSession *session){ + return session->rcv.profile; +} + +/** + * The default value is UDP_MAX_SIZE bytes, a value which is working for mostly everyone. + * However if your application can make assumption on the sizes of received packet, + * it can be interesting to set it to a lower value in order to save memory. + * + * @param session a rtp session + * @param bufsize max size in bytes for receiving packets +**/ +void rtp_session_set_recv_buf_size(RtpSession *session, int bufsize){ + session->recv_buf_size=bufsize; +} + +/** + * Set kernel send maximum buffer size for the rtp socket. + * A value of zero defaults to the operating system default. +**/ +void rtp_session_set_rtp_socket_send_buffer_size(RtpSession * session, unsigned int size){ + session->rtp.snd_socket_size=size; +} + +/** + * Set kernel recv maximum buffer size for the rtp socket. + * A value of zero defaults to the operating system default. +**/ +void rtp_session_set_rtp_socket_recv_buffer_size(RtpSession * session, unsigned int size){ + session->rtp.rcv_socket_size=size; +} + +/** + * This function provides the way for an application to be informed of various events that + * may occur during a rtp session. @signal is a string identifying the event, and @cb is + * a user supplied function in charge of processing it. The application can register + * several callbacks for the same signal, in the limit of #RTP_CALLBACK_TABLE_MAX_ENTRIES. + * Here are name and meaning of supported signals types: + * + * "ssrc_changed" : the SSRC of the incoming stream has changed. + * + * "payload_type_changed" : the payload type of the incoming stream has changed. + * + * "telephone-event_packet" : a telephone-event rtp packet (RFC2833) is received. + * + * "telephone-event" : a telephone event has occured. This is a high-level shortcut for "telephone-event_packet". + * + * "network_error" : a network error happened on a socket. Arguments of the callback functions are + * a const char * explaining the error, an int errno error code and the user_data as usual. + * + * "timestamp_jump" : we have received a packet with timestamp in far future compared to last timestamp received. + * The farness of far future is set by rtp_sesssion_set_time_jump_limit() + * "rtcp_bye": we have received a RTCP bye packet. Arguments of the callback + * functions are a const char * containing the leaving reason and + * the user_data. + * + * Returns: 0 on success, -EOPNOTSUPP if the signal does not exists, -1 if no more callbacks + * can be assigned to the signal type. + * + * @param session a rtp session + * @param signal_name the name of a signal + * @param cb a RtpCallback + * @param user_data a pointer to any data to be passed when invoking the callback. + * +**/ +int +rtp_session_signal_connect (RtpSession * session, const char *signal_name, + RtpCallback cb, unsigned long user_data) +{ + OList *elem; + for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){ + RtpSignalTable *s=(RtpSignalTable*) elem->data; + if (strcmp(signal_name,s->signal_name)==0){ + return rtp_signal_table_add(s,cb,user_data); + } + } + ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal_name); + return -1; +} + + +/** + * Removes callback function @cb to the list of callbacks for signal @signal. + * + * @param session a rtp session + * @param signal_name a signal name + * @param cb a callback function. + * @return: 0 on success, a negative value if the callback was not found. +**/ +int +rtp_session_signal_disconnect_by_callback (RtpSession * session, const char *signal_name, + RtpCallback cb) +{ + OList *elem; + for (elem=session->signal_tables;elem!=NULL;elem=o_list_next(elem)){ + RtpSignalTable *s=(RtpSignalTable*) elem->data; + if (strcmp(signal_name,s->signal_name)==0){ + return rtp_signal_table_remove_by_callback(s,cb); + } + } + ortp_warning ("rtp_session_signal_connect: inexistant signal %s",signal_name); + return -1; +} + + +/** + * sets the initial sequence number of a sending session. + * @param session a rtp session freshly created. + * @param addr a 16 bit unsigned number. + * +**/ +void rtp_session_set_seq_number(RtpSession *session, uint16_t seq){ + session->rtp.snd_seq=seq; +} + + +uint16_t rtp_session_get_seq_number(RtpSession *session){ + return session->rtp.snd_seq; +} + + +/** + * Sets the SSRC for the outgoing stream. + * If not done, a random ssrc is used. + * + * @param session a rtp session. + * @param ssrc an unsigned 32bit integer representing the synchronisation source identifier (SSRC). +**/ +void +rtp_session_set_ssrc (RtpSession * session, uint32_t ssrc) +{ + session->snd.ssrc = ssrc; +} + + +void rtp_session_update_payload_type(RtpSession *session, int paytype){ + /* check if we support this payload type */ + PayloadType *pt=rtp_profile_get_payload(session->rcv.profile,paytype); + session->hw_recv_pt=paytype; + if (pt!=0){ + ortp_message ("payload type changed to %i(%s) !", + paytype,pt->mime_type); + payload_type_changed(session,pt); + }else{ + ortp_warning("Receiving packet with unknown payload type %i.",paytype); + } +} +/** + * Sets the payload type of the rtp session. It decides of the payload types written in the + * of the rtp header for the outgoing stream, if the session is SENDRECV or SENDONLY. + * For payload type in incoming packets, the application can be informed by registering + * for the "payload_type_changed" signal, so that it can make the necessary changes + * on the downstream decoder that deals with the payload of the packets. + * + * @param session a rtp session + * @param paytype the payload type number + * @return 0 on success, -1 if the payload is not defined. +**/ + +int +rtp_session_set_send_payload_type (RtpSession * session, int paytype) +{ + session->snd.pt=paytype; + return 0; +} + +/** + *@param session a rtp session + * + *@return the payload type currently used in outgoing rtp packets +**/ +int rtp_session_get_send_payload_type(const RtpSession *session){ + return session->snd.pt; +} + +/** + * + * Sets the expected payload type for incoming packets. + * If the actual payload type in incoming packets is different that this expected payload type, thus + * the "payload_type_changed" signal is emitted. + * + *@param session a rtp session + *@param paytype the payload type number + *@return 0 on success, -1 if the payload is not defined. +**/ + +int +rtp_session_set_recv_payload_type (RtpSession * session, int paytype) +{ + PayloadType *pt; + session->rcv.pt=paytype; + session->hw_recv_pt=paytype; + pt=rtp_profile_get_payload(session->rcv.profile,paytype); + if (pt!=NULL){ + payload_type_changed(session,pt); + } + return 0; +} + +/** + *@param session a rtp session + * + * @return the payload type currently used in incoming rtp packets +**/ +int rtp_session_get_recv_payload_type(const RtpSession *session){ + return session->rcv.pt; +} + +/** + * Sets the expected payload type for incoming packets and payload type to be used for outgoing packets. + * If the actual payload type in incoming packets is different that this expected payload type, thus + * the "payload_type_changed" signal is emitted. + * + * @param session a rtp session + * @param paytype the payload type number + * @return 0 on success, -1 if the payload is not defined. +**/ +int rtp_session_set_payload_type(RtpSession *session, int pt){ + if (rtp_session_set_send_payload_type(session,pt)<0) return -1; + if (rtp_session_set_recv_payload_type(session,pt)<0) return -1; + return 0; +} + + +static void rtp_header_init_from_session(rtp_header_t *rtp, RtpSession *session){ + rtp->version = 2; + rtp->padbit = 0; + rtp->extbit = 0; + rtp->markbit= 0; + rtp->cc = 0; + rtp->paytype = session->snd.pt; + rtp->ssrc = session->snd.ssrc; + rtp->timestamp = 0; /* set later, when packet is sended */ + /* set a seq number */ + rtp->seq_number=session->rtp.snd_seq; +} + +/** + * Allocates a new rtp packet. In the header, ssrc and payload_type according to the session's + * context. Timestamp and seq number are not set, there will be set when the packet is going to be + * sent with rtp_session_sendm_with_ts(). + * If payload_size is zero, thus an empty packet (just a RTP header) is returned. + * + *@param session a rtp session. + *@param header_size the rtp header size. For standart size (without extensions), it is RTP_FIXED_HEADER_SIZE + *@param payload data to be copied into the rtp packet. + *@param payload_size size of data carried by the rtp packet. + *@return a rtp packet in a mblk_t (message block) structure. +**/ +mblk_t * rtp_session_create_packet(RtpSession *session,int header_size, const uint8_t *payload, int payload_size) +{ + mblk_t *mp; + int msglen=header_size+payload_size; + rtp_header_t *rtp; + + mp=allocb(msglen,BPRI_MED); + rtp=(rtp_header_t*)mp->b_rptr; + rtp_header_init_from_session(rtp,session); + /*copy the payload, if any */ + mp->b_wptr+=header_size; + if (payload_size){ + memcpy(mp->b_wptr,payload,payload_size); + mp->b_wptr+=payload_size; + } + return mp; +} + +/** + * Creates a new rtp packet using the given payload buffer (no copy). The header will be allocated separetely. + * In the header, ssrc and payload_type according to the session's + * context. Timestamp and seq number are not set, there will be set when the packet is going to be + * sent with rtp_session_sendm_with_ts(). + * oRTP will send this packet using libc's sendmsg() (if this function is availlable!) so that there will be no + * packet concatenation involving copies to be done in user-space. + * @freefn can be NULL, in that case payload will be kept untouched. + * + * @param session a rtp session. + * @param payload the data to be sent with this packet + * @param payload_size size of data + * @param freefn a function that will be called when the payload buffer is no more needed. + * @return: a rtp packet in a mblk_t (message block) structure. +**/ + +mblk_t * rtp_session_create_packet_with_data(RtpSession *session, uint8_t *payload, int payload_size, void (*freefn)(void*)) +{ + mblk_t *mp,*mpayload; + int header_size=RTP_FIXED_HEADER_SIZE; /* revisit when support for csrc is done */ + rtp_header_t *rtp; + + mp=allocb(header_size,BPRI_MED); + rtp=(rtp_header_t*)mp->b_rptr; + rtp_header_init_from_session(rtp,session); + mp->b_wptr+=header_size; + /* create a mblk_t around the user supplied payload buffer */ + mpayload=esballoc(payload,payload_size,BPRI_MED,freefn); + mpayload->b_wptr+=payload_size; + /* link it with the header */ + mp->b_cont=mpayload; + return mp; +} + + +/** + * Creates a new rtp packet using the buffer given in arguments (no copy). + * In the header, ssrc and payload_type according to the session's + *context. Timestamp and seq number are not set, there will be set when the packet is going to be + * sent with rtp_session_sendm_with_ts(). + * @freefn can be NULL, in that case payload will be kept untouched. + * + * @param session a rtp session. + * @param buffer a buffer that contains first just enough place to write a RTP header, then the data to send. + * @param size the size of the buffer + * @param freefn a function that will be called once the buffer is no more needed (the data has been sent). + * @return a rtp packet in a mblk_t (message block) structure. +**/ +mblk_t * rtp_session_create_packet_in_place(RtpSession *session,uint8_t *buffer, int size, void (*freefn)(void*) ) +{ + mblk_t *mp; + rtp_header_t *rtp; + + mp=esballoc(buffer,size,BPRI_MED,freefn); + + rtp=(rtp_header_t*)mp->b_rptr; + rtp_header_init_from_session(rtp,session); + return mp; +} + + +int +__rtp_session_sendm_with_ts (RtpSession * session, mblk_t *mp, uint32_t packet_ts, uint32_t send_ts) +{ + rtp_header_t *rtp; + uint32_t packet_time; + int error = 0; + int packsize; + RtpScheduler *sched=session->sched; + RtpStream *stream=&session->rtp; + + if (session->flags & RTP_SESSION_SEND_NOT_STARTED) + { + session->rtp.snd_ts_offset = send_ts; + /* Set initial last_rcv_time to first send time. */ + if ((session->flags & RTP_SESSION_RECV_NOT_STARTED) + || session->mode == RTP_SESSION_SENDONLY) + { + gettimeofday(&session->last_recv_time, NULL); + } + if (session->flags & RTP_SESSION_SCHEDULED) + { + session->rtp.snd_time_offset = sched->time_; + } + rtp_session_unset_flag (session,RTP_SESSION_SEND_NOT_STARTED); + } + /* if we are in blocking mode, then suspend the process until the scheduler it's time to send the + * next packet */ + /* if the timestamp of the packet queued is older than current time, then you we must + * not block */ + if (session->flags & RTP_SESSION_SCHEDULED) + { + packet_time = + rtp_session_ts_to_time (session, + send_ts - + session->rtp.snd_ts_offset) + + session->rtp.snd_time_offset; + /*ortp_message("rtp_session_send_with_ts: packet_time=%i time=%i",packet_time,sched->time_);*/ + wait_point_lock(&session->snd.wp); + if (TIME_IS_STRICTLY_NEWER_THAN (packet_time, sched->time_)) + { + wait_point_wakeup_at(&session->snd.wp,packet_time,(session->flags & RTP_SESSION_BLOCKING_MODE)!=0); + session_set_clr(&sched->w_sessions,session); /* the session has written */ + } + else session_set_set(&sched->w_sessions,session); /*to indicate select to return immediately */ + wait_point_unlock(&session->snd.wp); + } + + if(mp==NULL) {/*for people who just want to be blocked but + do not want to send anything.*/ + session->rtp.snd_last_ts = packet_ts; + return 0; + } + + rtp=(rtp_header_t*)mp->b_rptr; + + packsize = msgdsize(mp) ; + + rtp->timestamp=packet_ts; + if (session->snd.telephone_events_pt==rtp->paytype) + { + session->rtp.snd_seq++; + rtp->seq_number = session->rtp.snd_seq; + } + else + session->rtp.snd_seq=rtp->seq_number+1; + session->rtp.snd_last_ts = packet_ts; + + + ortp_global_stats.sent += packsize; + stream->sent_payload_bytes+=packsize-RTP_FIXED_HEADER_SIZE; + stream->stats.sent += packsize; + ortp_global_stats.packet_sent++; + stream->stats.packet_sent++; + + error = rtp_session_rtp_send (session, mp); + /*send RTCP packet if needed */ + rtp_session_rtcp_process_send(session); + /* receives rtcp packet if session is send-only*/ + /*otherwise it is done in rtp_session_recvm_with_ts */ + if (session->mode==RTP_SESSION_SENDONLY) rtp_session_rtcp_recv(session); + return error; +} + +/** + * Send the rtp datagram @mp to the destination set by rtp_session_set_remote_addr() + * with timestamp @timestamp. For audio data, the timestamp is the number + * of the first sample resulting of the data transmitted. See rfc1889 for details. + * The packet (@mp) is freed once it is sended. + * + *@param session a rtp session. + *@param mp a rtp packet presented as a mblk_t. + *@param timestamp the timestamp of the data to be sent. + * @return the number of bytes sent over the network. +**/ + +int rtp_session_sendm_with_ts(RtpSession *session, mblk_t *packet, uint32_t timestamp){ + return __rtp_session_sendm_with_ts(session,packet,timestamp,timestamp); +} + + + + +/** + * Send a rtp datagram to the destination set by rtp_session_set_remote_addr() containing + * the data from @buffer with timestamp @userts. This is a high level function that uses + * rtp_session_create_packet() and rtp_session_sendm_with_ts() to send the data. + * + *@param session a rtp session. + *@param buffer a buffer containing the data to be sent in a rtp packet. + *@param len the length of the data buffer, in bytes. + *@param userts the timestamp of the data to be sent. Refer to the rfc to know what it is. + * + *@param return the number of bytes sent over the network. +**/ +int +rtp_session_send_with_ts (RtpSession * session, const uint8_t * buffer, int len, + uint32_t userts) +{ + mblk_t *m; + int err; +#ifdef USE_SENDMSG + m=rtp_session_create_packet_with_data(session,(uint8_t*)buffer,len,NULL); +#else + m = rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,(uint8_t*)buffer,len); +#endif + err=rtp_session_sendm_with_ts(session,m,userts); + return err; +} + + + +extern void rtcp_parse(RtpSession *session, mblk_t *mp); + + + +static void payload_type_changed_notify(RtpSession *session, int paytype){ + session->rcv.pt = paytype; + rtp_signal_table_emit (&session->on_payload_type_changed); +} + + +/** + * Try to get a rtp packet presented as a mblk_t structure from the rtp session. + * The @user_ts parameter is relative to the first timestamp of the incoming stream. In other + * words, the application does not have to know the first timestamp of the stream, it can + * simply call for the first time this function with @user_ts=0, and then incrementing it + * as it want. The RtpSession takes care of synchronisation between the stream timestamp + * and the user timestamp given here. + * + * This function returns the entire packet (with header). + * + * The behaviour of this function has changed since version 0.15.0. Previously the payload data could be + * accessed using mblk_t::b_cont::b_rptr field of the returned mblk_t. + * This is no more the case. + * The convenient way of accessing the payload data is to use rtp_get_payload() : + * @code + * unsigned char *payload; + * int payload_size; + * payload_size=rtp_get_payload(mp,&payload); + * @endcode + * OR simply skip the header this way, the data is then comprised between mp->b_rptr and mp->b_wptr: + * @code + * rtp_get_payload(mp,&mp->b_rptr); + * @endcode + * + * + * @param session a rtp session. + * @param user_ts a timestamp. + * + * @return a rtp packet presented as a mblk_t. +**/ + +mblk_t * +rtp_session_recvm_with_ts (RtpSession * session, uint32_t user_ts) +{ + mblk_t *mp = NULL; + rtp_header_t *rtp; + uint32_t ts; + uint32_t packet_time; + RtpScheduler *sched=session->sched; + RtpStream *stream=&session->rtp; + int rejected=0; + bool_t read_socket=TRUE; + + /* if we are scheduled, remember the scheduler time at which the application has + * asked for its first timestamp */ + + if (session->flags & RTP_SESSION_RECV_NOT_STARTED) + { + session->rtp.rcv_query_ts_offset = user_ts; + /* Set initial last_rcv_time to first recv time. */ + if ((session->flags & RTP_SESSION_SEND_NOT_STARTED) + || session->mode == RTP_SESSION_RECVONLY){ + gettimeofday(&session->last_recv_time, NULL); + } + if (session->flags & RTP_SESSION_SCHEDULED) + { + session->rtp.rcv_time_offset = sched->time_; + //ortp_message("setting snd_time_offset=%i",session->rtp.snd_time_offset); + } + rtp_session_unset_flag (session,RTP_SESSION_RECV_NOT_STARTED); + }else{ + /*prevent reading from the sockets when two + consecutives calls for a same timestamp*/ + if (user_ts==session->rtp.rcv_last_app_ts) + read_socket=FALSE; + } + session->rtp.rcv_last_app_ts = user_ts; + if (read_socket){ + rtp_session_rtp_recv (session, user_ts); + rtp_session_rtcp_recv(session); + } + /* check for telephone event first */ + mp=getq(&session->rtp.tev_rq); + if (mp!=NULL){ + int msgsize=msgdsize(mp); + ortp_global_stats.recv += msgsize; + stream->stats.recv += msgsize; + rtp_signal_table_emit2(&session->on_telephone_event_packet,(long)mp); + rtp_session_check_telephone_events(session,mp); + freemsg(mp); + mp=NULL; + } + + /* then now try to return a media packet, if possible */ + /* first condition: if the session is starting, don't return anything + * until the queue size reaches jitt_comp */ + + if (session->flags & RTP_SESSION_RECV_SYNC) + { + queue_t *q = &session->rtp.rq; + if (qempty(q)) + { + ortp_debug ("Queue is empty."); + goto end; + } + rtp = (rtp_header_t *) qfirst(q)->b_rptr; + session->rtp.rcv_ts_offset = rtp->timestamp; + session->rtp.rcv_last_ret_ts = user_ts; /* just to have an init value */ + session->rcv.ssrc = rtp->ssrc; + /* delete the recv synchronisation flag */ + rtp_session_unset_flag (session, RTP_SESSION_RECV_SYNC); + } + + /*calculate the stream timestamp from the user timestamp */ + ts = jitter_control_get_compensated_timestamp(&session->rtp.jittctl,user_ts); + if (session->rtp.jittctl.enabled==TRUE){ + if (session->permissive) + mp = rtp_getq_permissive(&session->rtp.rq, ts,&rejected); + else{ + mp = rtp_getq(&session->rtp.rq, ts,&rejected); + } + }else mp=getq(&session->rtp.rq);/*no jitter buffer at all*/ + + stream->stats.outoftime+=rejected; + ortp_global_stats.outoftime+=rejected; + + goto end; + + end: + if (mp != NULL) + { + int msgsize = msgdsize (mp); /* evaluate how much bytes (including header) is received by app */ + uint32_t packet_ts; + ortp_global_stats.recv += msgsize; + stream->stats.recv += msgsize; + rtp = (rtp_header_t *) mp->b_rptr; + packet_ts=rtp->timestamp; + ortp_debug("Returning mp with ts=%i", packet_ts); + /* check for payload type changes */ + if (session->rcv.pt != rtp->paytype) + { + payload_type_changed_notify(session, rtp->paytype); + } + /* update the packet's timestamp so that it corrected by the + adaptive jitter buffer mechanism */ + if (session->rtp.jittctl.adaptive){ + uint32_t changed_ts; + /* only update correction offset between packets of different + timestamps*/ + if (packet_ts!=session->rtp.rcv_last_ts) + jitter_control_update_corrective_slide(&session->rtp.jittctl); + changed_ts=packet_ts+session->rtp.jittctl.corrective_slide; + rtp->timestamp=changed_ts; + /*ortp_debug("Returned packet has timestamp %u, with clock slide compensated it is %u",packet_ts,rtp->timestamp);*/ + } + session->rtp.rcv_last_ts = packet_ts; + if (!(session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED)){ + rtp_session_set_flag(session,RTP_SESSION_FIRST_PACKET_DELIVERED); + } + } + else + { + ortp_debug ("No mp for timestamp queried"); + stream->stats.unavaillable++; + ortp_global_stats.unavaillable++; + } + rtp_session_rtcp_process_recv(session); + + if (session->flags & RTP_SESSION_SCHEDULED) + { + /* if we are in blocking mode, then suspend the calling process until timestamp + * wanted expires */ + /* but we must not block the process if the timestamp wanted by the application is older + * than current time */ + packet_time = + rtp_session_ts_to_time (session, + user_ts - + session->rtp.rcv_query_ts_offset) + + session->rtp.rcv_time_offset; + ortp_debug ("rtp_session_recvm_with_ts: packet_time=%i, time=%i",packet_time, sched->time_); + wait_point_lock(&session->rcv.wp); + if (TIME_IS_STRICTLY_NEWER_THAN (packet_time, sched->time_)) + { + wait_point_wakeup_at(&session->rcv.wp,packet_time, (session->flags & RTP_SESSION_BLOCKING_MODE)!=0); + session_set_clr(&sched->r_sessions,session); + } + else session_set_set(&sched->r_sessions,session); /*to unblock _select() immediately */ + wait_point_unlock(&session->rcv.wp); + } + return mp; +} + + +/** + * NOTE: use of this function is discouraged when sending payloads other than + * pcm/pcmu/pcma/adpcm types. + * rtp_session_recvm_with_ts() does better job. + * + * Tries to read the bytes of the incoming rtp stream related to timestamp ts. In case + * where the user supplied buffer @buffer is not large enough to get all the data + * related to timestamp ts, then *( have_more) is set to 1 to indicate that the application + * should recall the function with the same timestamp to get more data. + * + * When the rtp session is scheduled (see rtp_session_set_scheduling_mode() ), and the + * blocking mode is on (see rtp_session_set_blocking_mode() ), then the calling thread + * is suspended until the timestamp given as argument expires, whatever a received packet + * fits the query or not. + * + * Important note: it is clear that the application cannot know the timestamp of the first + * packet of the incoming stream, because it can be random. The @ts timestamp given to the + * function is used relatively to first timestamp of the stream. In simple words, 0 is a good + * value to start calling this function. + * + * This function internally calls rtp_session_recvm_with_ts() to get a rtp packet. The content + * of this packet is then copied into the user supplied buffer in an intelligent manner: + * the function takes care of the size of the supplied buffer and the timestamp given in + * argument. Using this function it is possible to read continous audio data (e.g. pcma,pcmu...) + * with for example a standart buffer of size of 160 with timestamp incrementing by 160 while the incoming + * stream has a different packet size. + * + *Returns: if a packet was availlable with the corresponding timestamp supplied in argument + * then the number of bytes written in the user supplied buffer is returned. If no packets + * are availlable, either because the sender has not started to send the stream, or either + * because silence packet are not transmitted, or either because the packet was lost during + * network transport, then the function returns zero. + *@param session a rtp session. + *@param buffer a user supplied buffer to write the data. + *@param len the length in bytes of the user supplied buffer. + *@param ts the timestamp wanted. + *@param have_more the address of an integer to indicate if more data is availlable for the given timestamp. + * +**/ +int rtp_session_recv_with_ts (RtpSession * session, uint8_t * buffer, + int len, uint32_t ts, int * have_more){ + mblk_t *mp=NULL; + int plen,blen=0; + *have_more=0; + while(1){ + if (session->pending){ + mp=session->pending; + session->pending=NULL; + }else { + mp=rtp_session_recvm_with_ts(session,ts); + if (mp!=NULL) rtp_get_payload(mp,&mp->b_rptr); + } + if (mp){ + plen=mp->b_wptr-mp->b_rptr; + if (plen<=len){ + memcpy(buffer,mp->b_rptr,plen); + buffer+=plen; + blen+=plen; + len-=plen; + freemsg(mp); + mp=NULL; + }else{ + memcpy(buffer,mp->b_rptr,len); + mp->b_rptr+=len; + buffer+=len; + blen+=len; + len=0; + session->pending=mp; + *have_more=1; + break; + } + }else break; + } + return blen; +} +/** + * When the rtp session is scheduled and has started to send packets, this function + * computes the timestamp that matches to the present time. Using this function can be + * usefull when sending discontinuous streams. Some time can be elapsed between the end + * of a stream burst and the begin of a new stream burst, and the application may be not + * not aware of this elapsed time. In order to get a valid (current) timestamp to pass to + * #rtp_session_send_with_ts() or #rtp_session_sendm_with_ts(), the application may + * use rtp_session_get_current_send_ts(). + * + * @param session a rtp session. + * @return the current send timestamp for the rtp session. +**/ +uint32_t rtp_session_get_current_send_ts(RtpSession *session) +{ + uint32_t userts; + uint32_t session_time; + RtpScheduler *sched=session->sched; + PayloadType *payload; + payload=rtp_profile_get_payload(session->snd.profile,session->snd.pt); + return_val_if_fail(payload!=NULL, 0); + if ( (session->flags & RTP_SESSION_SCHEDULED)==0 ){ + ortp_warning("can't guess current timestamp because session is not scheduled."); + return 0; + } + session_time=sched->time_-session->rtp.snd_time_offset; + userts= (uint32_t)( ( (double)(session_time) * (double) payload->clock_rate )/ 1000.0) + + session->rtp.snd_ts_offset; + return userts; +} + +/** + * Same thing as rtp_session_get_current_send_ts() except that it's for an incoming stream. + * Works only on scheduled mode. + * + * @param session a rtp session. + * @return the theoritical that would have to be receive now. + * +**/ +uint32_t rtp_session_get_current_recv_ts(RtpSession *session){ + uint32_t userts; + uint32_t session_time; + RtpScheduler *sched=ortp_get_scheduler(); + PayloadType *payload; + payload=rtp_profile_get_payload(session->rcv.profile,session->rcv.pt); + return_val_if_fail(payload!=NULL, 0); + if ( (session->flags & RTP_SESSION_SCHEDULED)==0 ){ + ortp_warning("can't guess current timestamp because session is not scheduled."); + return 0; + } + session_time=sched->time_-session->rtp.rcv_time_offset; + userts= (uint32_t)( ( (double)(session_time) * (double) payload->clock_rate )/ 1000.0) + + session->rtp.rcv_ts_offset; + return userts; +} + +/** + * oRTP has the possibility to inform the application through a callback registered + * with rtp_session_signal_connect about crazy incoming RTP stream that jumps from + * a timestamp N to N+some_crazy_value. This lets the opportunity for the application + * to reset the session in order to resynchronize, or any other action like stopping the call + * and reporting an error. + * @param session the rtp session + * @param ts_step a time interval in miliseconds + * +**/ +void rtp_session_set_time_jump_limit(RtpSession *session, int milisecs){ + uint32_t ts; + session->rtp.time_jump=milisecs; + ts=rtp_session_time_to_ts(session,milisecs); + if (ts==0) session->rtp.ts_jump=1<<31; /* do not detect ts jump */ + else session->rtp.ts_jump=ts; +} + +/** + * Closes the rtp and rtcp sockets. +**/ +void rtp_session_release_sockets(RtpSession *session){ + if (session->rtp.socket>=0) close_socket (session->rtp.socket); + if (session->rtcp.socket>=0) close_socket (session->rtcp.socket); + session->rtp.socket=-1; + session->rtcp.socket=-1; + if (session->rtp.tr!=NULL) + ortp_free(session->rtp.tr); + if (session->rtcp.tr!=NULL) + ortp_free(session->rtcp.tr); + session->rtp.tr = 0; + session->rtcp.tr = 0; + + /* don't discard remote addresses, then can be preserved for next use. + session->rtp.rem_addrlen=0; + session->rtcp.rem_addrlen=0; + */ +} + +ortp_socket_t rtp_session_get_rtp_socket(const RtpSession *session){ + return rtp_session_using_transport(session, rtp) ? (session->rtp.tr->t_getsocket)(session->rtp.tr) : session->rtp.socket; +} + +ortp_socket_t rtp_session_get_rtcp_socket(const RtpSession *session){ + return rtp_session_using_transport(session, rtcp) ? (session->rtcp.tr->t_getsocket)(session->rtcp.tr) : session->rtcp.socket; +} + +/** + * Register an event queue. + * An application can use an event queue to get informed about various RTP events. +**/ +void rtp_session_register_event_queue(RtpSession *session, OrtpEvQueue *q){ + session->eventqs=o_list_append(session->eventqs,q); +} + +void rtp_session_unregister_event_queue(RtpSession *session, OrtpEvQueue *q){ + session->eventqs=o_list_remove(session->eventqs,q); +} + +void rtp_session_dispatch_event(RtpSession *session, OrtpEvent *ev){ + OList *it; + int i; + for(i=0,it=session->eventqs;it!=NULL;it=it->next,++i){ + ortp_ev_queue_put((OrtpEvQueue*)it->data,ortp_event_dup(ev)); + } + ortp_event_destroy(ev); +} + + +void rtp_session_uninit (RtpSession * session) +{ + /* first of all remove the session from the scheduler */ + if (session->flags & RTP_SESSION_SCHEDULED) + { + rtp_scheduler_remove_session (session->sched,session); + } + /*flush all queues */ + flushq(&session->rtp.rq, FLUSHALL); + flushq(&session->rtp.tev_rq, FLUSHALL); + + if (session->eventqs!=NULL) o_list_free(session->eventqs); + /* close sockets */ + rtp_session_release_sockets(session); + + wait_point_uninit(&session->snd.wp); + wait_point_uninit(&session->rcv.wp); + if (session->current_tev!=NULL) freemsg(session->current_tev); + if (session->rtp.cached_mp!=NULL) freemsg(session->rtp.cached_mp); + if (session->rtcp.cached_mp!=NULL) freemsg(session->rtcp.cached_mp); + if (session->sd!=NULL) freemsg(session->sd); + + session->signal_tables = o_list_free(session->signal_tables); + msgb_allocator_uninit(&session->allocator); +} + +/** + * Resynchronize to the incoming RTP streams. + * This can be useful to handle discoutinuous timestamps. + * For example, call this function from the timestamp_jump signal handler. + * @param session the rtp session +**/ +void rtp_session_resync(RtpSession *session){ + flushq (&session->rtp.rq, FLUSHALL); + rtp_session_set_flag(session, RTP_SESSION_RECV_SYNC); + rtp_session_unset_flag(session,RTP_SESSION_FIRST_PACKET_DELIVERED); + jitter_control_init(&session->rtp.jittctl,-1,NULL); +} + +/** + * Reset the session: local and remote addresses are kept. It resets timestamp, sequence + * number, and calls rtp_session_resync(). + * + * @param session a rtp session. +**/ +void rtp_session_reset (RtpSession * session) +{ + rtp_session_set_flag (session, RTP_SESSION_RECV_NOT_STARTED); + rtp_session_set_flag (session, RTP_SESSION_SEND_NOT_STARTED); + //session->ssrc=0; + session->rtp.snd_time_offset = 0; + session->rtp.snd_ts_offset = 0; + session->rtp.snd_rand_offset = 0; + session->rtp.snd_last_ts = 0; + session->rtp.rcv_time_offset = 0; + session->rtp.rcv_ts_offset = 0; + session->rtp.rcv_query_ts_offset = 0; + session->rtp.rcv_last_ts = 0; + session->rtp.rcv_last_app_ts = 0; + session->rtp.hwrcv_extseq = 0; + session->rtp.hwrcv_since_last_SR=0; + session->rtp.snd_seq = 0; + session->rtp.sent_payload_bytes=0; + rtp_session_clear_send_error_code(session); + rtp_session_clear_recv_error_code(session); + rtp_stats_reset(&session->rtp.stats); + rtp_session_resync(session); +} + +/** + * Retrieve the session's statistics. +**/ +const rtp_stats_t * rtp_session_get_stats(const RtpSession *session){ + return &session->rtp.stats; +} + +void rtp_session_reset_stats(RtpSession *session){ + memset(&session->rtp.stats,0,sizeof(rtp_stats_t)); +} + +/** + * Stores some application specific data into the session, so that it is easy to retrieve it from the signal callbacks using rtp_session_get_data(). + * @param session a rtp session + * @param data an opaque pointer to be stored in the session +**/ + +void rtp_session_set_data(RtpSession *session, void *data){ + session->user_data=data; +} + +/** + * @param session a rtp session + * @return the void pointer previously set using rtp_session_set_data() +**/ +void *rtp_session_get_data(const RtpSession *session){ + return session->user_data; +} + +/** + * Enable or disable the "rtp symmetric" hack which consists of the following: + * after the first packet is received, the source address of the packet + * is set to be the destination address for all next packets. + * This is useful to pass-through firewalls. + * @param session a rtp session + * @param yesno a boolean to enable or disable the feature + * +**/ +void +rtp_session_set_symmetric_rtp (RtpSession * session, bool_t yesno) +{ + session->symmetric_rtp =yesno; +} + +/** + * If yesno is TRUE, thus a connect() syscall is done on the socket to + * the destination address set by rtp_session_set_remote_addr(), or + * if the session does symmetric rtp (see rtp_session_set_symmetric_rtp()) + * a the connect() is done to the source address of the first packet received. + * Connecting a socket has effect of rejecting all incoming packets that + * don't come from the address specified in connect(). + * It also makes ICMP errors (such as connection refused) available to the + * application. + * @param session a rtp session + * @param yesno a boolean to enable or disable the feature + * +**/ +void rtp_session_set_connected_mode(RtpSession *session, bool_t yesno){ + session->use_connect=yesno; +} + +static float compute_bw(struct timeval *orig, unsigned int bytes){ + struct timeval current; + float bw; + float time; + if (bytes==0) return 0; + gettimeofday(¤t,NULL); + time=(float)(current.tv_sec - orig->tv_sec) + + ((float)(current.tv_usec - orig->tv_usec)*1e-6); + bw=((float)bytes)*8/(time+0.001); + /*+0.0001 avoids a division by zero without changing the results significatively*/ + return bw; +} + +float rtp_session_compute_recv_bandwidth(RtpSession *session){ + float bw; + bw=compute_bw(&session->rtp.recv_bw_start,session->rtp.recv_bytes); + session->rtp.recv_bytes=0; + return bw; +} + +float rtp_session_compute_send_bandwidth(RtpSession *session){ + float bw; + bw=compute_bw(&session->rtp.send_bw_start,session->rtp.sent_bytes); + session->rtp.sent_bytes=0; + return bw; +} + +int rtp_session_get_last_send_error_code(RtpSession *session){ + return session->rtp.send_errno; +} + +void rtp_session_clear_send_error_code(RtpSession *session){ + session->rtp.send_errno=0; +} + +int rtp_session_get_last_recv_error_code(RtpSession *session){ + return session->rtp.recv_errno; +} + +void rtp_session_clear_recv_error_code(RtpSession *session){ + session->rtp.send_errno=0; +} + +/** + * Destroys a rtp session. + * All memory allocated for the RtpSession is freed. + * + * @param session a rtp session. +**/ +void rtp_session_destroy (RtpSession * session) +{ + rtp_session_uninit (session); + ortp_free (session); +} + +void rtp_session_make_time_distorsion(RtpSession *session, int milisec) +{ + session->rtp.snd_time_offset+=milisec; +} + + +/* packet api */ + +void rtp_add_csrc(mblk_t *mp, uint32_t csrc) +{ + rtp_header_t *hdr=(rtp_header_t*)mp->b_rptr; + hdr->csrc[hdr->cc]=csrc; + hdr->cc++; +} + +/** + * Get a pointer to the beginning of the payload data of the RTP packet. + * @param packet a RTP packet represented as a mblk_t + * @param start a pointer to the beginning of the payload data, pointing inside the packet. + * @return the length of the payload data. +**/ +int rtp_get_payload(mblk_t *packet, unsigned char **start){ + unsigned char *tmp; + int header_len=RTP_FIXED_HEADER_SIZE+(rtp_get_cc(packet)*4); + tmp=packet->b_rptr+header_len; + if (tmp>packet->b_wptr){ + if (packet->b_cont!=NULL){ + tmp=packet->b_cont->b_rptr+(header_len- (packet->b_wptr-packet->b_rptr)); + if (tmp<=packet->b_cont->b_wptr){ + *start=tmp; + return packet->b_cont->b_wptr-tmp; + } + } + ortp_warning("Invalid RTP packet"); + return -1; + } + *start=tmp; + return packet->b_wptr-tmp; +} + + +/** + * Gets last time a valid RTP or RTCP packet was received. + * @param session RtpSession to get last receive time from. + * @param tv Pointer to struct timeval to fill. + * +**/ +void +rtp_session_get_last_recv_time(RtpSession *session, struct timeval *tv) +{ +#ifdef PERF + ortp_error("rtp_session_get_last_recv_time() feature disabled."); +#else + *tv = session->last_recv_time; +#endif +} + + + +uint32_t rtp_session_time_to_ts(RtpSession *session, int millisecs){ + PayloadType *payload; + payload = + rtp_profile_get_payload (session->snd.profile, + session->snd.pt); + if (payload == NULL) + { + ortp_warning + ("rtp_session_ts_to_t: use of unsupported payload type %d.", session->snd.pt); + return 0; + } + /* the return value is in milisecond */ + return (uint32_t) (payload->clock_rate*(double) (millisecs/1000.0f)); +} + +/* function used by the scheduler only:*/ +uint32_t rtp_session_ts_to_time (RtpSession * session, uint32_t timestamp) +{ + PayloadType *payload; + payload = + rtp_profile_get_payload (session->snd.profile, + session->snd.pt); + if (payload == NULL) + { + ortp_warning + ("rtp_session_ts_to_t: use of unsupported payload type %d.", session->snd.pt); + return 0; + } + /* the return value is in milisecond */ + return (uint32_t) (1000.0 * + ((double) timestamp / + (double) payload->clock_rate)); +} + + +/* time is the number of miliseconds elapsed since the start of the scheduler */ +void rtp_session_process (RtpSession * session, uint32_t time, RtpScheduler *sched) +{ + wait_point_lock(&session->snd.wp); + if (wait_point_check(&session->snd.wp,time)){ + session_set_set(&sched->w_sessions,session); + wait_point_wakeup(&session->snd.wp); + } + wait_point_unlock(&session->snd.wp); + + wait_point_lock(&session->rcv.wp); + if (wait_point_check(&session->rcv.wp,time)){ + session_set_set(&sched->r_sessions,session); + wait_point_wakeup(&session->rcv.wp); + } + wait_point_unlock(&session->rcv.wp); +} + diff --git a/linphone/oRTP/src/rtpsession_inet.c b/linphone/oRTP/src/rtpsession_inet.c new file mode 100644 index 000000000..e8e95f4b8 --- /dev/null +++ b/linphone/oRTP/src/rtpsession_inet.c @@ -0,0 +1,1028 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ortp/ortp.h" +#include "utils.h" +#include "ortp/rtpsession.h" +#include "rtpsession_priv.h" + + +#if defined(WIN32) || defined(_WIN32_WCE) +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" /*needed for HAVE_SYS_UIO_H */ +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#define USE_SENDMSG 1 +#endif + +#define can_connect(s) ( (s)->use_connect && !(s)->symmetric_rtp) + +static bool_t try_connect(int fd, const struct sockaddr *dest, socklen_t addrlen){ + if (connect(fd,dest,addrlen)<0){ + ortp_warning("Could not connect() socket: %s",getSocketError()); + return FALSE; + } + return TRUE; +} + +static ortp_socket_t create_and_bind(const char *addr, int port, int *sock_family, bool_t reuse_addr){ + int err; + int optval = 1; + ortp_socket_t sock=-1; +#ifdef ORTP_INET6 + char num[8]; + struct addrinfo hints, *res0, *res; +#else + struct sockaddr_in saddr; +#endif + +#ifdef ORTP_INET6 + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + snprintf(num, sizeof(num), "%d",port); + err = getaddrinfo(addr,num, &hints, &res0); + if (err!=0) { + ortp_warning ("Error in getaddrinfo on (addr=%s port=%i): %s", addr, port, gai_strerror(err)); + return -1; + } + + for (res = res0; res; res = res->ai_next) { + sock = socket(res->ai_family, res->ai_socktype, 0); + if (sock < 0) + continue; + if (reuse_addr){ + err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (SOCKET_OPTION_VALUE)&optval, sizeof (optval)); + if (err < 0) + { + ortp_warning ("Fail to set rtp address reusable: %s.", getSocketError()); + } + } + + *sock_family=res->ai_family; + err = bind (sock, res->ai_addr, res->ai_addrlen); + if (err != 0) + { + ortp_warning ("Fail to bind rtp socket to (addr=%s port=%i) : %s.", addr,port, getSocketError()); + close_socket (sock); + sock=-1; + continue; + } +#ifndef __hpux + switch (res->ai_family) + { + case AF_INET: + if (IN_MULTICAST(ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr))) + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr; + mreq.imr_interface.s_addr = INADDR_ANY; + err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (SOCKET_OPTION_VALUE) &mreq, sizeof(mreq)); + if (err < 0) + { + ortp_warning ("Fail to join address group: %s.", getSocketError()); + close_socket (sock); + sock=-1; + continue; + } + } + break; + case AF_INET6: + if (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr))) + { + struct ipv6_mreq mreq; + mreq.ipv6mr_multiaddr = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; + mreq.ipv6mr_interface = 0; + err = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (SOCKET_OPTION_VALUE)&mreq, sizeof(mreq)); + if (err < 0) + { + ortp_warning ("Fail to join address group: %s.", getSocketError()); + close_socket (sock); + sock=-1; + continue; + } + } + break; + } +#endif /*hpux*/ + break; + } + freeaddrinfo(res0); +#else + saddr.sin_family = AF_INET; + *sock_family=AF_INET; + err = inet_aton (addr, &saddr.sin_addr); + if (err < 0) + { + ortp_warning ("Error in socket address:%s.", getSocketError()); + return err; + } + saddr.sin_port = htons (port); + + sock = socket (PF_INET, SOCK_DGRAM, 0); + + if (sock<0) return -1; + if (reuse_addr){ + err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (SOCKET_OPTION_VALUE)&optval, sizeof (optval)); + if (err < 0) + { + ortp_warning ("Fail to set rtp address reusable: %s.",getSocketError()); + } + } + + err = bind (sock, + (struct sockaddr *) &saddr, + sizeof (saddr)); + + if (err != 0) + { + ortp_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError()); + close_socket (sock); + return -1; + } +#endif + if (sock>=0){ + set_non_blocking_socket (sock); + } + return sock; +} + +static void set_socket_sizes(int sock, unsigned int sndbufsz, unsigned int rcvbufsz){ + int err; + bool_t done=FALSE; + if (sndbufsz>0){ +#ifdef SO_SNDBUFFORCE + err = setsockopt(sock, SOL_SOCKET, SO_SNDBUFFORCE, (void *)&sndbufsz, sizeof(sndbufsz)); + if (err == -1) { + ortp_error("Fail to increase socket's send buffer size with SO_SNDBUFFORCE: %s.", getSocketError()); + }else done=TRUE; +#endif + if (!done){ + err = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&sndbufsz, sizeof(sndbufsz)); + if (err == -1) { + ortp_error("Fail to increase socket's send buffer size with SO_SNDBUF: %s.", getSocketError()); + } + } + } + done=FALSE; + if (rcvbufsz>0){ +#ifdef SO_RCVBUFFORCE + err = setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&rcvbufsz, sizeof(rcvbufsz)); + if (err == -1) { + ortp_error("Fail to increase socket's recv buffer size with SO_RCVBUFFORCE: %s.", getSocketError()); + } +#endif + if (!done){ + err = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbufsz, sizeof(rcvbufsz)); + if (err == -1) { + ortp_error("Fail to increase socket's recv buffer size with SO_RCVBUF: %s.", getSocketError()); + } + } + + } +} + +static ortp_socket_t create_and_bind_random(const char *localip, int *sock_family, int *port){ + int retry; + ortp_socket_t sock = -1; + for (retry=0;retry<100;retry++) + { + int localport; + do + { + localport = (rand () + 5000) & 0xfffe; + } + while ((localport < 5000) || (localport > 0xffff)); + /*do not set REUSEADDR in case of random allocation */ + sock = create_and_bind(localip, localport, sock_family,FALSE); + if (sock>=0) { + *port=localport; + return sock; + } + } + ortp_warning("create_and_bind_random: Could not find a random port for %s !",localip); + return -1; +} + +/** + *rtp_session_set_local_addr: + *@session: a rtp session freshly created. + *@addr: a local IP address in the xxx.xxx.xxx.xxx form. + *@port: a local port or -1 to let oRTP choose the port randomly + * + * Specify the local addr to be use to listen for rtp packets or to send rtp packet from. + * In case where the rtp session is send-only, then it is not required to call this function: + * when calling rtp_session_set_remote_addr(), if no local address has been set, then the + * default INADRR_ANY (0.0.0.0) IP address with a random port will be used. Calling + * rtp_sesession_set_local_addr() is mandatory when the session is recv-only or duplex. + * + * Returns: 0 on success. +**/ + +int +rtp_session_set_local_addr (RtpSession * session, const char * addr, int port) +{ + ortp_socket_t sock; + int sockfamily; + if (session->rtp.socket>=0){ + /* don't rebind, but close before*/ + rtp_session_release_sockets(session); + } + /* try to bind the rtp port */ + if (port>0) + sock=create_and_bind(addr,port,&sockfamily,TRUE); + else + sock=create_and_bind_random(addr,&sockfamily,&port); + if (sock>=0){ + set_socket_sizes(sock,session->rtp.snd_socket_size,session->rtp.rcv_socket_size); + session->rtp.sockfamily=sockfamily; + session->rtp.socket=sock; + session->rtp.loc_port=port; + /*try to bind rtcp port */ + sock=create_and_bind(addr,port+1,&sockfamily,TRUE); + if (sock>=0){ + session->rtcp.sockfamily=sockfamily; + session->rtcp.socket=sock; + }else{ + ortp_warning("Could not create and bind rtcp socket."); + } + + /* set socket options (but don't change chosen states) */ + rtp_session_set_dscp( session, -1 ); + rtp_session_set_multicast_ttl( session, -1 ); + rtp_session_set_multicast_loopback( session, -1 ); + + return 0; + } + return -1; +} + + +/** + *rtp_session_set_multicast_ttl: + *@session: a rtp session + *@ttl: desired Multicast Time-To-Live + * + * Sets the TTL (Time-To-Live) for outgoing multicast packets. + * + * Returns: 0 on success. + * +**/ +int rtp_session_set_multicast_ttl(RtpSession *session, int ttl) +{ + int retval; + + // Store new TTL if one is specified + if (ttl>0) session->multicast_ttl = ttl; + + // Don't do anything if socket hasn't been created yet + if (session->rtp.socket < 0) return 0; + + switch (session->rtp.sockfamily) { + case AF_INET: { + + retval= setsockopt(session->rtp.socket, IPPROTO_IP, IP_MULTICAST_TTL, + (SOCKET_OPTION_VALUE) &session->multicast_ttl, sizeof(session->multicast_ttl)); + + if (retval<0) break; + + retval= setsockopt(session->rtcp.socket, IPPROTO_IP, IP_MULTICAST_TTL, + (SOCKET_OPTION_VALUE) &session->multicast_ttl, sizeof(session->multicast_ttl)); + + } break; + + case AF_INET6: { + + retval= setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + (SOCKET_OPTION_VALUE)&session->multicast_ttl, sizeof(session->multicast_ttl)); + + if (retval<0) break; + + retval= setsockopt(session->rtcp.socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + (SOCKET_OPTION_VALUE) &session->multicast_ttl, sizeof(session->multicast_ttl)); + + } break; + + default: + retval=-1; + } + + if (retval<0) + ortp_warning("Failed to set multicast TTL on socket."); + + + return retval; +} + + +/** + *rtp_session_get_multicast_ttl: + *@session: a rtp session + * + * Returns the TTL (Time-To-Live) for outgoing multicast packets. + * +**/ +int rtp_session_get_multicast_ttl(RtpSession *session) +{ + return session->multicast_ttl; +} + + +/** + *rtp_session_set_multicast_loopback: + *@session: a rtp session + *@ttl: desired Multicast Time-To-Live + * + * Sets the TTL (Time-To-Live) for outgoing multicast packets. + * + * Returns: 0 on success. + * +**/ +int rtp_session_set_multicast_loopback(RtpSession *session, int yesno) +{ + int retval; + + // Store new loopback state if one is specified + if (yesno==0) { + // Don't loop back + session->multicast_loopback = 0; + } else if (yesno>0) { + // Do loop back + session->multicast_loopback = 1; + } + + // Don't do anything if socket hasn't been created yet + if (session->rtp.socket < 0) return 0; + + switch (session->rtp.sockfamily) { + case AF_INET: { + + retval= setsockopt(session->rtp.socket, IPPROTO_IP, IP_MULTICAST_LOOP, + (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); + + if (retval<0) break; + + retval= setsockopt(session->rtcp.socket, IPPROTO_IP, IP_MULTICAST_LOOP, + (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); + + } break; + + case AF_INET6: { + + retval= setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); + + if (retval<0) break; + + retval= setsockopt(session->rtcp.socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); + + } break; + + default: + retval=-1; + } + + if (retval<0) + ortp_warning("Failed to set multicast loopback on socket."); + + + return retval; +} + + +/** + *rtp_session_get_multicast_loopback: + *@session: a rtp session + * + * Returns the multicast loopback state of rtp session (true or false). + * +**/ +int rtp_session_get_multicast_loopback(RtpSession *session) +{ + return session->multicast_loopback; +} + +/** + *rtp_session_set_dscp: + *@session: a rtp session + *@dscp: desired DSCP PHB value + * + * Sets the DSCP (Differentiated Services Code Point) for outgoing RTP packets. + * + * Returns: 0 on success. + * +**/ +int rtp_session_set_dscp(RtpSession *session, int dscp){ + int retval=0; + int tos; + + // Store new DSCP value if one is specified + if (dscp>=0) session->dscp = dscp; + + // Don't do anything if socket hasn't been created yet + if (session->rtp.socket < 0) return 0; + + // DSCP value is in the upper six bits of the TOS field + tos = (session->dscp << 2) & 0xFC; + switch (session->rtp.sockfamily) { + case AF_INET: + retval = setsockopt(session->rtp.socket, IPPROTO_IP, IP_TOS, (SOCKET_OPTION_VALUE)&tos, sizeof(tos)); + break; +#ifdef ORTP_INET6 + case AF_INET6: +# ifdef IPV6_TCLASS /*seems not defined by my libc*/ + retval = setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_TCLASS, + (SOCKET_OPTION_VALUE)&tos, sizeof(tos)); +# else + /*in case that works:*/ + retval = setsockopt(session->rtp.socket, IPPROTO_IPV6, IP_TOS, + (SOCKET_OPTION_VALUE)&tos, sizeof(tos)); +#endif + break; +#endif + default: + retval=-1; + } + if (retval<0) + ortp_warning("Failed to set DSCP value on socket."); + + return retval; +} + + +/** + *rtp_session_get_dscp: + *@session: a rtp session + * + * Returns the DSCP (Differentiated Services Code Point) for outgoing RTP packets. + * +**/ +int rtp_session_get_dscp(const RtpSession *session) +{ + return session->dscp; +} + + +/** + *rtp_session_get_local_port: + *@session: a rtp session for which rtp_session_set_local_addr() or rtp_session_set_remote_addr() has been called + * + * This function can be useful to retrieve the local port that was randomly choosen by + * rtp_session_set_remote_addr() when rtp_session_set_local_addr() was not called. + * + * Returns: the local port used to listen for rtp packets, -1 if not set. +**/ + +int rtp_session_get_local_port(const RtpSession *session){ + return (session->rtp.loc_port>0) ? session->rtp.loc_port : -1; +} + + +static char * ortp_inet_ntoa(struct sockaddr *addr, int addrlen, char *dest, int destlen){ +#ifdef ORTP_INET6 + int err; + dest[0]=0; + err=getnameinfo(addr,addrlen,dest,destlen,NULL,0,NI_NUMERICHOST); + if (err!=0){ + ortp_warning("getnameinfo error: %s",gai_strerror(err)); + } +#else + char *tmp=inet_ntoa(((struct sockaddr_in*)addr)->sin_addr); + strncpy(dest,tmp,destlen); + dest[destlen-1]='\0'; +#endif + return dest; +} + +/** + *rtp_session_set_remote_addr: + *@session: a rtp session freshly created. + *@addr: a local IP address in the xxx.xxx.xxx.xxx form. + *@port: a local port. + * + * Sets the remote address of the rtp session, ie the destination address where rtp packet + * are sent. If the session is recv-only or duplex, it also sets the origin of incoming RTP + * packets. Rtp packets that don't come from addr:port are discarded. + * + * Returns: 0 on success. +**/ +int +rtp_session_set_remote_addr (RtpSession * session, const char * addr, int port){ + return rtp_session_set_remote_addr_full (session, addr, port, port+1); +} + +/** + *rtp_session_set_remote_addr_full: + *@session: a rtp session freshly created. + *@addr: a local IP address in the xxx.xxx.xxx.xxx form. + *@rtp_port: a local rtp port. + *@rtcp_port: a local rtcp port. + * + * Sets the remote address of the rtp session, ie the destination address where rtp packet + * are sent. If the session is recv-only or duplex, it also sets the origin of incoming RTP + * packets. Rtp packets that don't come from addr:port are discarded. + * + * Returns: 0 on success. +**/ + +int +rtp_session_set_remote_addr_full (RtpSession * session, const char * addr, int rtp_port, int rtcp_port) +{ + int err; +#ifdef ORTP_INET6 + struct addrinfo hints, *res0, *res; + char num[8]; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + snprintf(num, sizeof(num), "%d", rtp_port); + err = getaddrinfo(addr, num, &hints, &res0); + if (err) { + ortp_warning ("Error in socket address: %s", gai_strerror(err)); + return -1; + } +#endif + if (session->rtp.socket == -1){ + /* the session has not its socket bound, do it */ + ortp_message ("Setting random local addresses."); +#ifdef ORTP_INET6 + /* bind to an address type that matches the destination address */ + if (res0->ai_addr->sa_family==AF_INET6) + err = rtp_session_set_local_addr (session, "::", -1); + else err=rtp_session_set_local_addr (session, "0.0.0.0", -1); +#else + err = rtp_session_set_local_addr (session, "0.0.0.0", -1); +#endif + if (err<0) return -1; + } + +#ifdef ORTP_INET6 + err=1; + for (res = res0; res; res = res->ai_next) { + /* set a destination address that has the same type as the local address */ + if (res->ai_family==session->rtp.sockfamily ) { + memcpy( &session->rtp.rem_addr, res->ai_addr, res->ai_addrlen); + session->rtp.rem_addrlen=res->ai_addrlen; + err=0; + break; + } + } + freeaddrinfo(res0); + if (err) { + ortp_warning("Could not set destination for RTP socket to %s:%i.",addr,rtp_port); + return -1; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + snprintf(num, sizeof(num), "%d", rtcp_port); + err = getaddrinfo(addr, num, &hints, &res0); + if (err) { + ortp_warning ("Error: %s", gai_strerror(err)); + return err; + } + err=1; + for (res = res0; res; res = res->ai_next) { + /* set a destination address that has the same type as the local address */ + if (res->ai_family==session->rtp.sockfamily ) { + err=0; + memcpy( &session->rtcp.rem_addr, res->ai_addr, res->ai_addrlen); + session->rtcp.rem_addrlen=res->ai_addrlen; + break; + } + } + freeaddrinfo(res0); + if (err) { + ortp_warning("Could not set destination for RCTP socket to %s:%i.",addr,rtcp_port); + return -1; + } +#else + session->rtp.rem_addrlen=sizeof(session->rtp.rem_addr); + session->rtp.rem_addr.sin_family = AF_INET; + + err = inet_aton (addr, &session->rtp.rem_addr.sin_addr); + if (err < 0) + { + ortp_warning ("Error in socket address:%s.", getSocketError()); + return err; + } + session->rtp.rem_addr.sin_port = htons (rtp_port); + + memcpy (&session->rtcp.rem_addr, &session->rtp.rem_addr, + sizeof (struct sockaddr_in)); + session->rtcp.rem_addr.sin_port = htons (rtcp_port); + session->rtcp.rem_addrlen=sizeof(session->rtcp.rem_addr); +#endif + if (can_connect(session)){ + if (try_connect(session->rtp.socket,(struct sockaddr*)&session->rtp.rem_addr,session->rtp.rem_addrlen)) + session->flags|=RTP_SOCKET_CONNECTED; + if (session->rtcp.socket>=0){ + if (try_connect(session->rtcp.socket,(struct sockaddr*)&session->rtcp.rem_addr,session->rtcp.rem_addrlen)) + session->flags|=RTCP_SOCKET_CONNECTED; + } + }else if (session->flags & RTP_SOCKET_CONNECTED){ + /*must dissolve association done by connect(). + See connect(2) manpage*/ + struct sockaddr sa; + sa.sa_family=AF_UNSPEC; + if (connect(session->rtp.socket,&sa,sizeof(sa))<0){ + ortp_error("Cannot dissolve connect() association for rtp socket: %s", getSocketError()); + } + if (connect(session->rtcp.socket,&sa,sizeof(sa))<0){ + ortp_error("Cannot dissolve connect() association for rtcp socket: %s", getSocketError()); + } + session->flags&=~RTP_SOCKET_CONNECTED; + session->flags&=~RTCP_SOCKET_CONNECTED; + } + return 0; +} + +int +rtp_session_set_remote_addr_and_port(RtpSession * session, const char * addr, int rtp_port, int rtcp_port){ + return rtp_session_set_remote_addr_full(session,addr,rtp_port,rtcp_port); +} + +void rtp_session_set_sockets(RtpSession *session, int rtpfd, int rtcpfd) +{ + if (rtpfd>=0) set_non_blocking_socket(rtpfd); + if (rtcpfd>=0) set_non_blocking_socket(rtcpfd); + session->rtp.socket=rtpfd; + session->rtcp.socket=rtcpfd; + if (rtpfd>=0 || rtcpfd>=0 ) + session->flags|=(RTP_SESSION_USING_EXT_SOCKETS|RTP_SOCKET_CONNECTED|RTCP_SOCKET_CONNECTED); + else session->flags&=~(RTP_SESSION_USING_EXT_SOCKETS|RTP_SOCKET_CONNECTED|RTCP_SOCKET_CONNECTED); +} + +void rtp_session_set_transports(RtpSession *session, struct _RtpTransport *rtptr, struct _RtpTransport *rtcptr) +{ + session->rtp.tr = rtptr; + session->rtcp.tr = rtcptr; + if (rtptr) + rtptr->session=session; + if (rtcptr) + rtcptr->session=session; + + if (rtptr || rtcptr ) + session->flags|=(RTP_SESSION_USING_TRANSPORT); + else session->flags&=~(RTP_SESSION_USING_TRANSPORT); +} + + + +/** + *rtp_session_flush_sockets: + *@session: a rtp session + * + * Flushes the sockets for all pending incoming packets. + * This can be usefull if you did not listen to the stream for a while + * and wishes to start to receive again. During the time no receive is made + * packets get bufferised into the internal kernel socket structure. + * +**/ +void rtp_session_flush_sockets(RtpSession *session){ + unsigned char trash[4096]; +#ifdef ORTP_INET6 + struct sockaddr_storage from; +#else + struct sockaddr from; +#endif + socklen_t fromlen=sizeof(from); + if (rtp_session_using_transport(session, rtp)) + { + mblk_t *trashmp=esballoc(trash,sizeof(trash),0,NULL); + + while (session->rtp.tr->t_recvfrom(session->rtp.tr,trashmp,0,(struct sockaddr *)&from,&fromlen)>0){}; + + if (session->rtcp.tr) + while (session->rtcp.tr->t_recvfrom(session->rtcp.tr,trashmp,0,(struct sockaddr *)&from,&fromlen)>0){}; + freemsg(trashmp); + return; + } + + if (session->rtp.socket>=0){ + while (recvfrom(session->rtp.socket,trash,sizeof(trash),0,(struct sockaddr *)&from,&fromlen)>0){}; + } + if (session->rtcp.socket>=0){ + while (recvfrom(session->rtcp.socket,trash,sizeof(trash),0,(struct sockaddr*)&from,&fromlen)>0){}; + } +} + + +#ifdef USE_SENDMSG +#define MAX_IOV 30 +static int rtp_sendmsg(int sock,mblk_t *m, struct sockaddr *rem_addr, int addr_len){ + int error; + struct msghdr msg; + struct iovec iov[MAX_IOV]; + int iovlen; + for(iovlen=0; iovlenb_cont,iovlen++){ + iov[iovlen].iov_base=m->b_rptr; + iov[iovlen].iov_len=m->b_wptr-m->b_rptr; + } + if (iovlen==MAX_IOV){ + ortp_error("Too long msgb, didn't fit into iov, end discarded."); + } + msg.msg_name=(void*)rem_addr; + msg.msg_namelen=addr_len; + msg.msg_iov=&iov[0]; + msg.msg_iovlen=iovlen; + msg.msg_control=NULL; + msg.msg_controllen=0; + msg.msg_flags=0; + error=sendmsg(sock,&msg,0); + return error; +} +#endif + +#define IP_UDP_OVERHEAD (20+8) + +static void update_sent_bytes(RtpSession*s, int nbytes){ + if (s->rtp.sent_bytes==0){ + gettimeofday(&s->rtp.send_bw_start,NULL); + } + s->rtp.sent_bytes+=nbytes+IP_UDP_OVERHEAD; +} + +static void update_recv_bytes(RtpSession*s, int nbytes){ + if (s->rtp.recv_bytes==0){ + gettimeofday(&s->rtp.recv_bw_start,NULL); + } + s->rtp.recv_bytes+=nbytes+IP_UDP_OVERHEAD; +} + +int +rtp_session_rtp_send (RtpSession * session, mblk_t * m) +{ + int error; + int i; + rtp_header_t *hdr; + struct sockaddr *destaddr=(struct sockaddr*)&session->rtp.rem_addr; + socklen_t destlen=session->rtp.rem_addrlen; + ortp_socket_t sockfd=session->rtp.socket; + + hdr = (rtp_header_t *) m->b_rptr; + /* perform host to network conversions */ + hdr->ssrc = htonl (hdr->ssrc); + hdr->timestamp = htonl (hdr->timestamp); + hdr->seq_number = htons (hdr->seq_number); + for (i = 0; i < hdr->cc; i++) + hdr->csrc[i] = htonl (hdr->csrc[i]); + + if (session->flags & RTP_SOCKET_CONNECTED) { + destaddr=NULL; + destlen=0; + } + + if (rtp_session_using_transport(session, rtp)){ + error = (session->rtp.tr->t_sendto) (session->rtp.tr,m,0,destaddr,destlen); + }else{ +#ifdef USE_SENDMSG + error=rtp_sendmsg(sockfd,m,destaddr,destlen); +#else + if (m->b_cont!=NULL) + msgpullup(m,-1); + error = sendto (sockfd, m->b_rptr, (int) (m->b_wptr - m->b_rptr), + 0,destaddr,destlen); +#endif + } + if (error < 0){ + if (session->on_network_error.count>0){ + rtp_signal_table_emit3(&session->on_network_error,(long)"Error sending RTP packet",INT_TO_POINTER(getSocketErrorCode())); + }else ortp_warning ("Error sending rtp packet: %s ; socket=%i", getSocketError(), sockfd); + session->rtp.send_errno=getSocketErrorCode(); + }else{ + update_sent_bytes(session,error); + } + freemsg (m); + return error; +} + +int +rtp_session_rtcp_send (RtpSession * session, mblk_t * m) +{ + int error=0; + ortp_socket_t sockfd=session->rtcp.socket; + struct sockaddr *destaddr=(struct sockaddr*)&session->rtcp.rem_addr; + socklen_t destlen=session->rtcp.rem_addrlen; + bool_t using_connected_socket=(session->flags & RTCP_SOCKET_CONNECTED)!=0; + + if (using_connected_socket) { + destaddr=NULL; + destlen=0; + } + + if (session->rtcp.enabled && + ( (sockfd>=0 && (session->rtcp.rem_addrlen>0 ||using_connected_socket)) + || rtp_session_using_transport(session, rtcp) ) ){ + if (rtp_session_using_transport(session, rtcp)){ + error = (session->rtcp.tr->t_sendto) (session->rtcp.tr, m, 0, + destaddr, destlen); + } + else{ +#ifdef USE_SENDMSG + error=rtp_sendmsg(sockfd,m,destaddr, destlen); +#else + if (m->b_cont!=NULL){ + msgpullup(m,-1); + } + error = sendto (sockfd, m->b_rptr, + (int) (m->b_wptr - m->b_rptr), 0, + destaddr, destlen); +#endif + } + if (error < 0){ + char host[65]; + if (session->on_network_error.count>0){ + rtp_signal_table_emit3(&session->on_network_error,(long)"Error sending RTCP packet",INT_TO_POINTER(getSocketErrorCode())); + }else ortp_warning ("Error sending rtcp packet: %s ; socket=%i; addr=%s", getSocketError(), session->rtcp.socket, ortp_inet_ntoa((struct sockaddr*)&session->rtcp.rem_addr,session->rtcp.rem_addrlen,host,sizeof(host)) ); + } + }else ortp_message("Not sending rtcp report: sockfd=%i, rem_addrlen=%i, connected=%i",sockfd,session->rtcp.rem_addrlen,using_connected_socket); + freemsg (m); + return error; +} + +int +rtp_session_rtp_recv (RtpSession * session, uint32_t user_ts) +{ + int error; + ortp_socket_t sockfd=session->rtp.socket; +#ifdef ORTP_INET6 + struct sockaddr_storage remaddr; +#else + struct sockaddr remaddr; +#endif + socklen_t addrlen = sizeof (remaddr); + mblk_t *mp; + + if ((sockfd<0) && !rtp_session_using_transport(session, rtp)) return -1; /*session has no sockets for the moment*/ + + while (1) + { + int bufsz; + bool_t sock_connected=!!(session->flags & RTP_SOCKET_CONNECTED); + + if (session->rtp.cached_mp==NULL) + session->rtp.cached_mp = msgb_allocator_alloc(&session->allocator,session->recv_buf_size); + mp=session->rtp.cached_mp; + bufsz=(int) (mp->b_datap->db_lim - mp->b_datap->db_base); + if (sock_connected){ + error=recv(sockfd,mp->b_wptr,bufsz,0); + }else if (rtp_session_using_transport(session, rtp)) + error = (session->rtp.tr->t_recvfrom)(session->rtp.tr, mp, 0, + (struct sockaddr *) &remaddr, + &addrlen); + else error = recvfrom(sockfd, mp->b_wptr, + bufsz, 0, + (struct sockaddr *) &remaddr, + &addrlen); + if (error > 0){ + if (session->symmetric_rtp && !sock_connected){ + /* store the sender rtp address to do symmetric RTP */ + memcpy(&session->rtp.rem_addr,&remaddr,addrlen); + session->rtp.rem_addrlen=addrlen; + if (session->use_connect){ + if (try_connect(sockfd,(struct sockaddr*)&remaddr,addrlen)) + session->flags|=RTP_SOCKET_CONNECTED; + } + } + /* then parse the message and put on queue */ + mp->b_wptr+=error; + rtp_session_rtp_parse (session, mp, user_ts, (struct sockaddr*)&remaddr,addrlen); + session->rtp.cached_mp=NULL; + /*for bandwidth measurements:*/ + update_recv_bytes(session,error); + } + else + { + int errnum=getSocketErrorCode(); + + if (error == 0) + { + ortp_warning + ("rtp_recv: strange... recv() returned zero."); + } + else if (!is_would_block_error(errnum)) + { + if (session->on_network_error.count>0){ + rtp_signal_table_emit3(&session->on_network_error,(long)"Error receiving RTP packet",INT_TO_POINTER(getSocketErrorCode())); + }else ortp_warning("Error receiving RTP packet: %s.",getSocketError()); + } + /* don't free the cached_mp, it will be reused next time */ + return -1; /* avoids an infinite loop ! */ + } + } + return error; +} + +void rtp_session_notify_inc_rtcp(RtpSession *session, mblk_t *m){ + if (session->eventqs!=NULL){ + OrtpEvent *ev=ortp_event_new(ORTP_EVENT_RTCP_PACKET_RECEIVED); + OrtpEventData *d=ortp_event_get_data(ev); + d->packet=m; + rtp_session_dispatch_event(session,ev); + } + else freemsg(m); /* avoid memory leak */ +} + +int +rtp_session_rtcp_recv (RtpSession * session) +{ + int error; +#ifdef ORTP_INET6 + struct sockaddr_storage remaddr; +#else + struct sockaddr remaddr; +#endif + socklen_t addrlen=0; + mblk_t *mp; + + if (session->rtcp.socket<0 && !rtp_session_using_transport(session, rtcp)) return -1; /*session has no rtcp sockets for the moment*/ + + + while (1) + { + bool_t sock_connected=!!(session->flags & RTCP_SOCKET_CONNECTED); + if (session->rtcp.cached_mp==NULL) + session->rtcp.cached_mp = allocb (RTCP_MAX_RECV_BUFSIZE, 0); + + mp=session->rtcp.cached_mp; + if (sock_connected){ + error=recv(session->rtcp.socket,mp->b_wptr,RTCP_MAX_RECV_BUFSIZE,0); + }else { + addrlen=sizeof (remaddr); + + if (rtp_session_using_transport(session, rtcp)) + error=(session->rtcp.tr->t_recvfrom)(session->rtcp.tr, mp, 0, + (struct sockaddr *) &remaddr, + &addrlen); + else + error=recvfrom (session->rtcp.socket, mp->b_wptr, + RTCP_MAX_RECV_BUFSIZE, 0, + (struct sockaddr *) &remaddr, + &addrlen); + } + if (error > 0) + { + mp->b_wptr += error; + /* post an event to notify the application*/ + { + rtp_session_notify_inc_rtcp(session,mp); + } + session->rtcp.cached_mp=NULL; + if (session->symmetric_rtp && !sock_connected){ + /* store the sender rtp address to do symmetric RTP */ + memcpy(&session->rtcp.rem_addr,&remaddr,addrlen); + session->rtcp.rem_addrlen=addrlen; + if (session->use_connect){ + if (try_connect(session->rtcp.socket,(struct sockaddr*)&remaddr,addrlen)) + session->flags|=RTCP_SOCKET_CONNECTED; + } + } + } + else + { + int errnum=getSocketErrorCode(); + + if (error == 0) + { + ortp_warning + ("rtcp_recv: strange... recv() returned zero."); + } + else if (!is_would_block_error(errnum)) + { + if (session->on_network_error.count>0){ + rtp_signal_table_emit3(&session->on_network_error,(long)"Error receiving RTCP packet",INT_TO_POINTER(errnum)); + }else ortp_warning("Error receiving RTCP packet: %s.",getSocketError()); + session->rtp.recv_errno=errnum; + } + /* don't free the cached_mp, it will be reused next time */ + return -1; /* avoids an infinite loop ! */ + } + } + return error; +} + diff --git a/linphone/oRTP/src/rtpsession_priv.h b/linphone/oRTP/src/rtpsession_priv.h new file mode 100644 index 000000000..24e955669 --- /dev/null +++ b/linphone/oRTP/src/rtpsession_priv.h @@ -0,0 +1,54 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef rtpsession_priv_h +#define rtpsession_priv_h + +#include "ortp/rtpsession.h" + +typedef enum { + RTP_SESSION_RECV_SYNC=1, /* the rtp session is synchronising in the incoming stream */ + RTP_SESSION_FIRST_PACKET_DELIVERED=1<<1, + RTP_SESSION_SCHEDULED=1<<2,/* the scheduler controls this session*/ + RTP_SESSION_BLOCKING_MODE=1<<3, /* in blocking mode */ + RTP_SESSION_RECV_NOT_STARTED=1<<4, /* the application has not started to try to recv */ + RTP_SESSION_SEND_NOT_STARTED=1<<5, /* the application has not started to send something */ + RTP_SESSION_IN_SCHEDULER=1<<6, /* the rtp session is in the scheduler list */ + RTP_SESSION_USING_EXT_SOCKETS=1<<7, /* the session is using externaly supplied sockets */ + RTP_SOCKET_CONNECTED=1<<8, + RTCP_SOCKET_CONNECTED=1<<9, + RTP_SESSION_USING_TRANSPORT=1<<10 +}RtpSessionFlags; + +#define rtp_session_using_transport(s, stream) (((s)->flags & RTP_SESSION_USING_TRANSPORT) && (s->stream.tr != 0)) + +void rtp_session_update_payload_type(RtpSession * session, int pt); +void rtp_putq(queue_t *q, mblk_t *mp); +mblk_t * rtp_getq(queue_t *q, uint32_t ts, int *rejected); +int rtp_session_rtp_recv(RtpSession * session, uint32_t ts); +int rtp_session_rtcp_recv(RtpSession * session); +int rtp_session_rtp_send (RtpSession * session, mblk_t * m); +int rtp_session_rtcp_send (RtpSession * session, mblk_t * m); + +void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen); +void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp); + +void rtp_session_dispatch_event(RtpSession *session, OrtpEvent *ev); + +#endif diff --git a/linphone/oRTP/src/rtpsignaltable.c b/linphone/oRTP/src/rtpsignaltable.c new file mode 100644 index 000000000..14d8587b9 --- /dev/null +++ b/linphone/oRTP/src/rtpsignaltable.c @@ -0,0 +1,98 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#include +#include "utils.h" + + +void rtp_signal_table_init(RtpSignalTable *table,RtpSession *session, const char *signal_name) +{ + memset(table,0,sizeof(RtpSignalTable)); + table->session=session; + table->signal_name=signal_name; + session->signal_tables=o_list_append(session->signal_tables,(void*)table); +} + +int rtp_signal_table_add(RtpSignalTable *table,RtpCallback cb, unsigned long user_data) +{ + int i; + + for (i=0;icallback[i]==NULL){ + table->callback[i]=cb; + table->user_data[i]=user_data; + table->count++; + return 0; + } + } + return -1; +} + +void rtp_signal_table_emit(RtpSignalTable *table) +{ + int i,c; + + for (i=0,c=0;ccount;i++){ + if (table->callback[i]!=NULL){ + c++; /*I like it*/ + table->callback[i](table->session,table->user_data[i]); + } + } +} + +void rtp_signal_table_emit2(RtpSignalTable *table,unsigned long arg) +{ + int i,c; + + for (i=0,c=0;ccount;i++){ + if (table->callback[i]!=NULL){ + c++; /*I like it*/ + table->callback[i](table->session,arg,table->user_data[i]); + } + } +} + +void rtp_signal_table_emit3(RtpSignalTable *table, unsigned long arg1, unsigned long arg2) +{ + int i,c; + + for (i=0,c=0;ccount;i++){ + if (table->callback[i]!=NULL){ + c++; /*I like it*/ + table->callback[i](table->session,arg1,arg2,table->user_data[i]); + } + } +} + +int rtp_signal_table_remove_by_callback(RtpSignalTable *table,RtpCallback cb) +{ + int i; + + for (i=0;icallback[i]==cb){ + table->callback[i]=NULL; + table->user_data[i]=0; + table->count--; + return 0; + } + } + return -1; +} diff --git a/linphone/oRTP/src/rtptimer.c b/linphone/oRTP/src/rtptimer.c new file mode 100644 index 000000000..261be48ff --- /dev/null +++ b/linphone/oRTP/src/rtptimer.c @@ -0,0 +1,33 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ortp/ortp.h" +#include "rtptimer.h" + +void rtp_timer_set_interval(RtpTimer *timer, struct timeval *interval) +{ + if (timer->state==RTP_TIMER_RUNNING){ + ortp_warning("Cannot change timer interval while it is running.\n"); + return; + } + timer->interval.tv_sec=interval->tv_sec; + timer->interval.tv_usec=interval->tv_usec; +} + + diff --git a/linphone/oRTP/src/rtptimer.h b/linphone/oRTP/src/rtptimer.h new file mode 100644 index 000000000..c4a01a456 --- /dev/null +++ b/linphone/oRTP/src/rtptimer.h @@ -0,0 +1,52 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef RTPTIMER_H +#define RTPTIMER_H + +#if !defined(_WIN32) && !defined(_WIN32_WCE) +#include +#else +#include +#include "winsock2.h" +#endif + +#include + + +typedef void (*RtpTimerFunc)(void); + +struct _RtpTimer +{ + int state; +#define RTP_TIMER_RUNNING 1 +#define RTP_TIMER_STOPPED 0 + RtpTimerFunc timer_init; + RtpTimerFunc timer_do; + RtpTimerFunc timer_uninit; + struct timeval interval; +}; + +typedef struct _RtpTimer RtpTimer; + +void rtp_timer_set_interval(RtpTimer *timer, struct timeval *interval); + +extern RtpTimer posix_timer; + +#endif diff --git a/linphone/oRTP/src/scheduler.c b/linphone/oRTP/src/scheduler.c new file mode 100644 index 000000000..0e53c7bfb --- /dev/null +++ b/linphone/oRTP/src/scheduler.c @@ -0,0 +1,212 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "utils.h" +#include "scheduler.h" +#include "rtpsession_priv.h" + +// To avoid warning during compile +extern void rtp_session_process (RtpSession * session, uint32_t time, RtpScheduler *sched); + + +void rtp_scheduler_init(RtpScheduler *sched) +{ + sched->list=0; + sched->time_=0; + /* default to the posix timer */ + rtp_scheduler_set_timer(sched,&posix_timer); + ortp_mutex_init(&sched->lock,NULL); + ortp_cond_init(&sched->unblock_select_cond,NULL); + sched->max_sessions=sizeof(SessionSet)*8; + session_set_init(&sched->all_sessions); + sched->all_max=0; + session_set_init(&sched->r_sessions); + sched->r_max=0; + session_set_init(&sched->w_sessions); + sched->w_max=0; + session_set_init(&sched->e_sessions); + sched->e_max=0; +} + +RtpScheduler * rtp_scheduler_new() +{ + RtpScheduler *sched=(RtpScheduler *) ortp_malloc(sizeof(RtpScheduler)); + memset(sched,0,sizeof(RtpScheduler)); + rtp_scheduler_init(sched); + return sched; +} + +void rtp_scheduler_set_timer(RtpScheduler *sched,RtpTimer *timer) +{ + if (sched->thread_running){ + ortp_warning("Cannot change timer while the scheduler is running !!"); + return; + } + sched->timer=timer; + /* report the timer increment */ + sched->timer_inc=(timer->interval.tv_usec/1000) + (timer->interval.tv_sec*1000); +} + +void rtp_scheduler_start(RtpScheduler *sched) +{ + if (sched->thread_running==0){ + sched->thread_running=1; + ortp_mutex_lock(&sched->lock); + ortp_thread_create(&sched->thread, NULL, rtp_scheduler_schedule,(void*)sched); + ortp_cond_wait(&sched->unblock_select_cond,&sched->lock); + ortp_mutex_unlock(&sched->lock); + } + else ortp_warning("Scheduler thread already running."); + +} +void rtp_scheduler_stop(RtpScheduler *sched) +{ + if (sched->thread_running==1) + { + sched->thread_running=0; + ortp_thread_join(sched->thread, NULL); + } + else ortp_warning("Scheduler thread is not running."); +} + +void rtp_scheduler_destroy(RtpScheduler *sched) +{ + if (sched->thread_running) rtp_scheduler_stop(sched); + ortp_mutex_destroy(&sched->lock); + //g_mutex_free(sched->unblock_select_mutex); + ortp_cond_destroy(&sched->unblock_select_cond); + ortp_free(sched); +} + +void * rtp_scheduler_schedule(void * psched) +{ + RtpScheduler *sched=(RtpScheduler*) psched; + RtpTimer *timer=sched->timer; + RtpSession *current; + + /* take this lock to prevent the thread to start until g_thread_create() returns + because we need sched->thread to be initialized */ + ortp_mutex_lock(&sched->lock); + ortp_cond_signal(&sched->unblock_select_cond); /* unblock the starting thread */ + ortp_mutex_unlock(&sched->lock); + timer->timer_init(); + while(sched->thread_running) + { + /* do the processing here: */ + ortp_mutex_lock(&sched->lock); + + current=sched->list; + /* processing all scheduled rtp sessions */ + while (current!=NULL) + { + ortp_debug("scheduler: processing session=0x%x.\n",current); + rtp_session_process(current,sched->time_,sched); + current=current->next; + } + /* wake up all the threads that are sleeping in _select() */ + ortp_cond_broadcast(&sched->unblock_select_cond); + ortp_mutex_unlock(&sched->lock); + + /* now while the scheduler is going to sleep, the other threads can compute their + result mask and see if they have to leave, or to wait for next tick*/ + //ortp_message("scheduler: sleeping."); + timer->timer_do(); + sched->time_+=sched->timer_inc; + } + /* when leaving the thread, stop the timer */ + timer->timer_uninit(); + return NULL; +} + +void rtp_scheduler_add_session(RtpScheduler *sched, RtpSession *session) +{ + RtpSession *oldfirst; + int i; + if (session->flags & RTP_SESSION_IN_SCHEDULER){ + /* the rtp session is already scheduled, so return silently */ + return; + } + rtp_scheduler_lock(sched); + /* enqueue the session to the list of scheduled sessions */ + oldfirst=sched->list; + sched->list=session; + session->next=oldfirst; + if (sched->max_sessions==0){ + ortp_error("rtp_scheduler_add_session: max_session=0 !"); + } + /* find a free pos in the session mask*/ + for (i=0;imax_sessions;i++){ + if (!ORTP_FD_ISSET(i,&sched->all_sessions.rtpset)){ + session->mask_pos=i; + session_set_set(&sched->all_sessions,session); + /* make a new session scheduled not blockable if it has not started*/ + if (session->flags & RTP_SESSION_RECV_NOT_STARTED) + session_set_set(&sched->r_sessions,session); + if (session->flags & RTP_SESSION_SEND_NOT_STARTED) + session_set_set(&sched->w_sessions,session); + if (i>sched->all_max){ + sched->all_max=i; + } + break; + } + } + + rtp_session_set_flag(session,RTP_SESSION_IN_SCHEDULER); + rtp_scheduler_unlock(sched); +} + +void rtp_scheduler_remove_session(RtpScheduler *sched, RtpSession *session) +{ + RtpSession *tmp; + int cond=1; + return_if_fail(session!=NULL); + if (!(session->flags & RTP_SESSION_IN_SCHEDULER)){ + /* the rtp session is not scheduled, so return silently */ + return; + } + + rtp_scheduler_lock(sched); + tmp=sched->list; + if (tmp==session){ + sched->list=tmp->next; + rtp_session_unset_flag(session,RTP_SESSION_IN_SCHEDULER); + session_set_clr(&sched->all_sessions,session); + rtp_scheduler_unlock(sched); + return; + } + /* go the position of session in the list */ + while(cond){ + if (tmp!=NULL){ + if (tmp->next==session){ + tmp->next=tmp->next->next; + cond=0; + } + else tmp=tmp->next; + }else { + /* the session was not found ! */ + ortp_warning("rtp_scheduler_remove_session: the session was not found in the scheduler list!"); + cond=0; + } + } + rtp_session_unset_flag(session,RTP_SESSION_IN_SCHEDULER); + /* delete the bit in the mask */ + session_set_clr(&sched->all_sessions,session); + rtp_scheduler_unlock(sched); +} diff --git a/linphone/oRTP/src/scheduler.h b/linphone/oRTP/src/scheduler.h new file mode 100644 index 000000000..5e15751a2 --- /dev/null +++ b/linphone/oRTP/src/scheduler.h @@ -0,0 +1,69 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SCHEDULER_H +#define SCHEDULER_H + +#include "ortp/rtpsession.h" +#include "ortp/sessionset.h" +#include "rtptimer.h" + + +struct _RtpScheduler { + + RtpSession *list; /* list of scheduled sessions*/ + SessionSet all_sessions; /* mask of scheduled sessions */ + int all_max; /* the highest pos in the all mask */ + SessionSet r_sessions; /* mask of sessions that have a recv event */ + int r_max; + SessionSet w_sessions; /* mask of sessions that have a send event */ + int w_max; + SessionSet e_sessions; /* mask of session that have error event */ + int e_max; + int max_sessions; /* the number of position in the masks */ + /* GMutex *unblock_select_mutex; */ + ortp_cond_t unblock_select_cond; + ortp_mutex_t lock; + ortp_thread_t thread; + int thread_running; + struct _RtpTimer *timer; + uint32_t time_; /*number of miliseconds elapsed since the start of the thread */ + uint32_t timer_inc; /* the timer increment in milisec */ +}; + +typedef struct _RtpScheduler RtpScheduler; + +RtpScheduler * rtp_scheduler_new(void); +void rtp_scheduler_set_timer(RtpScheduler *sched,RtpTimer *timer); +void rtp_scheduler_start(RtpScheduler *sched); +void rtp_scheduler_stop(RtpScheduler *sched); +void rtp_scheduler_destroy(RtpScheduler *sched); + +void rtp_scheduler_add_session(RtpScheduler *sched, RtpSession *session); +void rtp_scheduler_remove_session(RtpScheduler *sched, RtpSession *session); + +void * rtp_scheduler_schedule(void * sched); + +#define rtp_scheduler_lock(sched) ortp_mutex_lock(&(sched)->lock) +#define rtp_scheduler_unlock(sched) ortp_mutex_unlock(&(sched)->lock) + +/* void rtp_scheduler_add_set(RtpScheduler *sched, SessionSet *set); */ + +RtpScheduler * ortp_get_scheduler(void); +#endif diff --git a/linphone/oRTP/src/sessionset.c b/linphone/oRTP/src/sessionset.c new file mode 100644 index 000000000..3a7ad1cfd --- /dev/null +++ b/linphone/oRTP/src/sessionset.c @@ -0,0 +1,148 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "scheduler.h" + + +/** + * Allocates and initialize a new empty session set. + * + * @return the empty session set. +**/ +SessionSet * session_set_new() +{ + SessionSet *set=(SessionSet *) ortp_malloc(sizeof(SessionSet)); + session_set_init(set); + return set; +} + + +/** + * Destroys a session set. + * +**/ + +void session_set_destroy(SessionSet *set) +{ + ortp_free(set); +} + +int session_set_and(SessionSet *sched_set, int maxs, SessionSet *user_set, SessionSet *result_set) +{ + uint32_t *mask1,*mask2,*mask3; + int i=0; + int j,ret=0; + mask1=(uint32_t*)(void*)&sched_set->rtpset; + mask2=(uint32_t*)(void*)&user_set->rtpset; + mask3=(uint32_t*)(void*)&result_set->rtpset; + while(i>j) & 1){ + ret++; + } + } + } + i+=32; + mask1++; + mask2++; + mask3++; + } + //printf("session_set_and: ret=%i\n",ret); + return ret; +} + +/** + * This function performs similarly as libc select() function, but performs on #RtpSession + * instead of file descriptors. + * session_set_select() suspends the calling process until some events arrive on one of the + * three sets passed in argument. Two of the sets can be NULL. + * The first set @recvs is interpreted as a set of RtpSession waiting for receive events: + * a new buffer (perhaps empty) is availlable on one or more sessions of the set, or the last + * receive operation with rtp_session_recv_with_ts() would have finished if it were in + * blocking mode. + * The second set is interpreted as a set of RtpSession waiting for send events, i.e. the last + * rtp_session_send_with_ts() call on a session would have finished if it were in blocking mode. + * + * When some events arrived on some of sets, then the function returns and sets are changed + * to indicate the sessions where events happened. + * Sessions can be added to sets using session_set_set(), a session has to be tested to be + * part of a set using session_set_is_set(). + * + * @param recvs a set of rtp sessions to be watched for read events + * @param sends a set of rtp sessions to be watched for write events + * @param errors a set of rtp sessions to be watched for errors + * @return: the number of sessions on which the selected events happened. +**/ +int session_set_select(SessionSet *recvs, SessionSet *sends, SessionSet *errors) +{ + int ret=0,bits; + SessionSet temp; + RtpScheduler *sched=ortp_get_scheduler(); + + /*lock the scheduler to not read the masks while they are being modified by the scheduler*/ + rtp_scheduler_lock(sched); + + while(1){ + /* computes the SessionSet intersection (in the other words mask intersection) between + the mask given by the user and scheduler masks */ + if (recvs!=NULL){ + session_set_init(&temp); + bits=session_set_and(&sched->r_sessions,sched->all_max,recvs,&temp); + ret+=bits; + /* copy the result set in the given user set (might be empty) */ + if (ret>0) session_set_copy(recvs,&temp); + } + if (sends!=NULL){ + session_set_init(&temp); + bits=session_set_and(&sched->w_sessions,sched->all_max,sends,&temp); + ret+=bits; + if (ret>0){ + /* copy the result set in the given user set (might be empty)*/ + session_set_copy(sends,&temp); + } + } + if (errors!=NULL){ + session_set_init(&temp); + bits=session_set_and(&sched->e_sessions,sched->all_max,errors,&temp); + ret+=bits; + if (ret>0){ + /* copy the result set in the given user set */ + session_set_copy(errors,&temp); + } + } + if (ret>0){ + /* there are set file descriptors, return immediately */ + //printf("There are %i sessions set, returning.\n",ret); + rtp_scheduler_unlock(sched); + return ret; + } + //printf("There are %i sessions set.\n",ret); + /* else we wait until the next loop of the scheduler*/ + ortp_cond_wait(&sched->unblock_select_cond,&sched->lock); + } + + return -1; +} + diff --git a/linphone/oRTP/src/srtp.c b/linphone/oRTP/src/srtp.c new file mode 100644 index 000000000..f1dfd24b6 --- /dev/null +++ b/linphone/oRTP/src/srtp.c @@ -0,0 +1,203 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if defined(WIN32) || defined(_WIN32_WCE) +#include "ortp-config-win32.h" +#else +#include "ortp-config.h" +#endif +#include "ortp/ortp.h" + +#ifdef HAVE_SRTP + +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include "ortp/srtp.h" + +#define SRTP_PAD_BYTES 64 /*?? */ + +static int srtp_sendto(RtpTransport *t, mblk_t *m, int flags, const struct sockaddr *to, socklen_t tolen){ + srtp_t srtp=(srtp_t)t->data; + int slen; + err_status_t err; + /* enlarge the buffer for srtp to write its data */ + msgpullup(m,msgdsize(m)+SRTP_PAD_BYTES); + slen=m->b_wptr-m->b_rptr; + err=srtp_protect(srtp,m->b_rptr,&slen); + if (err==err_status_ok){ + return sendto(t->session->rtp.socket,m->b_rptr,slen,flags,to,tolen); + } + ortp_error("srtp_protect() failed"); + return -1; +} + +static int srtp_recvfrom(RtpTransport *t, mblk_t *m, int flags, struct sockaddr *from, socklen_t *fromlen){ + srtp_t srtp=(srtp_t)t->data; + int err; + int slen; + err=recvfrom(t->session->rtp.socket,m->b_wptr,m->b_datap->db_lim-m->b_datap->db_base,flags,from,fromlen); + if (err>0){ + + /* keep NON-RTP data unencrypted */ + rtp_header_t *rtp; + if (err>=RTP_FIXED_HEADER_SIZE) + { + rtp = (rtp_header_t*)m->b_wptr; + if (rtp->version!=2) + { + return err; + } + } + + slen=err; + if (srtp_unprotect(srtp,m->b_wptr,&slen)==err_status_ok) + return slen; + else { + ortp_error("srtp_unprotect() failed"); + return -1; + } + } + return err; +} + +static int srtcp_sendto(RtpTransport *t, mblk_t *m, int flags, const struct sockaddr *to, socklen_t tolen){ + srtp_t srtp=(srtp_t)t->data; + int slen; + /* enlarge the buffer for srtp to write its data */ + msgpullup(m,msgdsize(m)+SRTP_PAD_BYTES); + slen=m->b_wptr-m->b_rptr; + if (srtp_protect_rtcp(srtp,m->b_rptr,&slen)==err_status_ok){ + return sendto(t->session->rtcp.socket,m->b_rptr,slen,flags,to,tolen); + } + ortp_error("srtp_protect_rtcp() failed"); + return -1; +} + +static int srtcp_recvfrom(RtpTransport *t, mblk_t *m, int flags, struct sockaddr *from, socklen_t *fromlen){ + srtp_t srtp=(srtp_t)t->data; + int err; + int slen; + err=recvfrom(t->session->rtcp.socket,m->b_wptr,m->b_datap->db_lim-m->b_datap->db_base,flags,from,fromlen); + if (err>0){ + slen=err; + if (srtp_unprotect_rtcp(srtp,m->b_wptr,&slen)==err_status_ok) + return slen; + else { + ortp_error("srtp_unprotect_rtcp() failed"); + return -1; + } + } + return err; +} + +ortp_socket_t +srtp_getsocket(RtpTransport *t) +{ + return t->session->rtp.socket; +} + +ortp_socket_t +srtcp_getsocket(RtpTransport *t) +{ + return t->session->rtcp.socket; +} + +/** + * Creates a pair of Secure-RTP/Secure-RTCP RtpTransport's. + * oRTP relies on libsrtp (see http://srtp.sf.net ) for secure RTP encryption. + * This function creates a RtpTransport object to be used to the RtpSession using + * rtp_session_set_transport(). + * @srtp: the srtp_t session to be used + * +**/ +int srtp_transport_new(srtp_t srtp, RtpTransport **rtpt, RtpTransport **rtcpt ){ + if (rtpt) { + (*rtpt)=ortp_new(RtpTransport,1); + (*rtpt)->data=srtp; + (*rtpt)->t_getsocket=srtp_getsocket; + (*rtpt)->t_sendto=srtp_sendto; + (*rtpt)->t_recvfrom=srtp_recvfrom; + } + if (rtcpt) { + (*rtcpt)=ortp_new(RtpTransport,1); + (*rtcpt)->data=srtp; + (*rtcpt)->t_getsocket=srtcp_getsocket; + (*rtcpt)->t_sendto=srtcp_sendto; + (*rtcpt)->t_recvfrom=srtcp_recvfrom; + } + return 0; +} + +err_status_t ortp_srtp_init(void) +{ + return srtp_init(); +} + +err_status_t ortp_srtp_create(srtp_t *session, const srtp_policy_t *policy) +{ + int i; + i = srtp_create(session, policy); + return i; +} + +err_status_t ortp_srtp_dealloc(srtp_t session) +{ + return srtp_dealloc(session); +} + +err_status_t ortp_srtp_add_stream(srtp_t session, const srtp_policy_t *policy) +{ + return srtp_add_stream(session, policy); +} + +bool_t ortp_srtp_supported(void){ + return TRUE; +} + +#else + +int srtp_transport_new(void *i, RtpTransport **rtpt, RtpTransport **rtcpt ){ + ortp_error("srtp_transport_new: oRTP has not been compiled with SRTP support."); + return -1; +} + +bool_t ortp_srtp_supported(void){ + return FALSE; +} + +int ortp_srtp_create(void *i, const void *policy) +{ + return -1; +} + +int ortp_srtp_dealloc(void *session) +{ + return -1; +} + +int ortp_srtp_add_stream(void *session, const void *policy) +{ + return -1; +} + +#endif + diff --git a/linphone/oRTP/src/str_utils.c b/linphone/oRTP/src/str_utils.c new file mode 100644 index 000000000..09ebad9a6 --- /dev/null +++ b/linphone/oRTP/src/str_utils.c @@ -0,0 +1,337 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ortp/ortp.h" +#include "ortp/rtp.h" +#include "ortp/str_utils.h" +#include "utils.h" + +void qinit(queue_t *q){ + mblk_init(&q->_q_stopper); + q->_q_stopper.b_next=&q->_q_stopper; + q->_q_stopper.b_prev=&q->_q_stopper; + q->q_mcount=0; +} + +void mblk_init(mblk_t *mp) +{ + mp->b_cont=mp->b_prev=mp->b_next=NULL; + mp->b_rptr=mp->b_wptr=NULL; + mp->reserved1=0; + mp->reserved2=0; +} + +dblk_t *datab_alloc(int size){ + dblk_t *db; + int total_size=sizeof(dblk_t)+size; + db=(dblk_t *) ortp_malloc(total_size); + db->db_base=(uint8_t*)db+sizeof(dblk_t); + db->db_lim=db->db_base+size; + db->db_ref=1; + db->db_freefn=NULL; /* the buffer pointed by db_base must never be freed !*/ + return db; +} + +static inline void datab_ref(dblk_t *d){ + d->db_ref++; +} + +static inline void datab_unref(dblk_t *d){ + d->db_ref--; + if (d->db_ref==0){ + if (d->db_freefn!=NULL) + d->db_freefn(d->db_base); + ortp_free(d); + } +} + + +mblk_t *allocb(int size, int pri) +{ + mblk_t *mp; + dblk_t *datab; + + mp=(mblk_t *) ortp_malloc(sizeof(mblk_t)); + mblk_init(mp); + datab=datab_alloc(size); + + mp->b_datap=datab; + mp->b_rptr=mp->b_wptr=datab->db_base; + mp->b_next=mp->b_prev=mp->b_cont=NULL; + return mp; +} + +mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*) ) +{ + mblk_t *mp; + dblk_t *datab; + + mp=(mblk_t *) ortp_malloc(sizeof(mblk_t)); + mblk_init(mp); + datab=(dblk_t *) ortp_malloc(sizeof(dblk_t)); + + + datab->db_base=buf; + datab->db_lim=buf+size; + datab->db_ref=1; + datab->db_freefn=freefn; + + mp->b_datap=datab; + mp->b_rptr=mp->b_wptr=buf; + mp->b_next=mp->b_prev=mp->b_cont=NULL; + return mp; +} + + +void freeb(mblk_t *mp) +{ + return_if_fail(mp->b_datap!=NULL); + return_if_fail(mp->b_datap->db_base!=NULL); + + datab_unref(mp->b_datap); + ortp_free(mp); +} + +void freemsg(mblk_t *mp) +{ + mblk_t *tmp1,*tmp2; + tmp1=mp; + while(tmp1!=NULL) + { + tmp2=tmp1->b_cont; + freeb(tmp1); + tmp1=tmp2; + } +} + +mblk_t *dupb(mblk_t *mp) +{ + mblk_t *newm; + return_val_if_fail(mp->b_datap!=NULL,NULL); + return_val_if_fail(mp->b_datap->db_base!=NULL,NULL); + + datab_ref(mp->b_datap); + newm=(mblk_t *) ortp_malloc(sizeof(mblk_t)); + mblk_init(newm); + newm->b_datap=mp->b_datap; + newm->b_rptr=mp->b_rptr; + newm->b_wptr=mp->b_wptr; + return newm; +} + +/* duplicates a complex mblk_t */ +mblk_t *dupmsg(mblk_t* m) +{ + mblk_t *newm=NULL,*mp,*prev; + prev=newm=dupb(m); + m=m->b_cont; + while (m!=NULL){ + mp=dupb(m); + prev->b_cont=mp; + prev=mp; + m=m->b_cont; + } + return newm; +} + +void putq(queue_t *q,mblk_t *mp) +{ + q->_q_stopper.b_prev->b_next=mp; + mp->b_prev=q->_q_stopper.b_prev; + mp->b_next=&q->_q_stopper; + q->_q_stopper.b_prev=mp; + q->q_mcount++; +} + +mblk_t *getq(queue_t *q) +{ + mblk_t *tmp; + tmp=q->_q_stopper.b_next; + if (tmp==&q->_q_stopper) return NULL; + q->_q_stopper.b_next=tmp->b_next; + tmp->b_next->b_prev=&q->_q_stopper; + tmp->b_prev=NULL; + tmp->b_next=NULL; + q->q_mcount--; + return tmp; +} + +mblk_t * peekq(queue_t *q){ + mblk_t *tmp; + tmp=q->_q_stopper.b_next; + if (tmp==&q->_q_stopper) return NULL; + return tmp; +} + +/* insert mp in q just before emp */ +void insq(queue_t *q,mblk_t *emp, mblk_t *mp) +{ + if (emp==NULL){ + putq(q,mp); + return; + } + q->q_mcount++; + emp->b_prev->b_next=mp; + mp->b_prev=emp->b_prev; + emp->b_prev=mp; + mp->b_next=emp; +} + +void remq(queue_t *q, mblk_t *mp){ + q->q_mcount--; + mp->b_prev->b_next=mp->b_next; + mp->b_next->b_prev=mp->b_prev; + mp->b_next=NULL; + mp->b_prev=NULL; +} + +/* remove and free all messages in the q */ +void flushq(queue_t *q, int how) +{ + mblk_t *mp; + + while ((mp=getq(q))!=NULL) + { + freemsg(mp); + } +} + +int msgdsize(const mblk_t *mp) +{ + int msgsize=0; + while(mp!=NULL){ + msgsize+=(int) (mp->b_wptr-mp->b_rptr); + mp=mp->b_cont; + } + return msgsize; +} + +void msgpullup(mblk_t *mp,int len) +{ + mblk_t *firstm=mp; + dblk_t *db; + int wlen=0; + + if (mp->b_cont==NULL && len==-1) return; /*nothing to do, message is not fragmented */ + + if (len==-1) len=msgdsize(mp); + db=datab_alloc(len); + while(wlenb_wptr-mp->b_rptr; + if (mlen<=remain){ + memcpy(&db->db_base[wlen],mp->b_rptr,mlen); + wlen+=mlen; + mp=mp->b_cont; + }else{ + memcpy(&db->db_base[wlen],mp->b_rptr,remain); + wlen+=remain; + } + } + /*set firstm to point to the new datab */ + freemsg(firstm->b_cont); + firstm->b_cont=NULL; + datab_unref(firstm->b_datap); + firstm->b_datap=db; + firstm->b_rptr=db->db_base; + firstm->b_wptr=firstm->b_rptr+wlen; +} + + +mblk_t *copyb(mblk_t *mp) +{ + mblk_t *newm; + int len=(int) (mp->b_wptr-mp->b_rptr); + newm=allocb(len,BPRI_MED); + memcpy(newm->b_wptr,mp->b_rptr,len); + newm->b_wptr+=len; + return newm; +} + +mblk_t *copymsg(mblk_t *mp) +{ + mblk_t *newm=0,*m; + m=newm=copyb(mp); + mp=mp->b_cont; + while(mp!=NULL){ + m->b_cont=copyb(mp); + m=m->b_cont; + mp=mp->b_cont; + } + return newm; +} + +mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad){ + int padcnt=0; + int i; + if (pad){ + padcnt= (int)(4L-( (long)(((long)mp->b_wptr)+size) % 4L)) % 4L; + } + if ((mp->b_wptr + size +padcnt) > mp->b_datap->db_lim){ + /* buffer is not large enough: append a new block (with the same size ?)*/ + int plen=(int)((char*)mp->b_datap->db_lim - (char*) mp->b_datap->db_base); + mp->b_cont=allocb(MAX(plen,size),0); + mp=mp->b_cont; + } + if (size) memcpy(mp->b_wptr,data,size); + mp->b_wptr+=size; + for (i=0;ib_wptr[0]=0; + mp->b_wptr++; + } + return mp; +} + +void msgappend(mblk_t *mp, const char *data, int size, bool_t pad){ + while(mp->b_cont!=NULL) mp=mp->b_cont; + appendb(mp,data,size,pad); +} + +mblk_t *concatb(mblk_t *mp, mblk_t *newm){ + while (mp->b_cont!=NULL) mp=mp->b_cont; + mp->b_cont=newm; + while(newm->b_cont!=NULL) newm=newm->b_cont; + return newm; +} + +void msgb_allocator_init(msgb_allocator_t *a){ + qinit(&a->q); +} + +mblk_t *msgb_allocator_alloc(msgb_allocator_t *a, int size){ + queue_t *q=&a->q; + mblk_t *m,*found=NULL; + + /*lookup for an unused msgb (data block with ref count ==1)*/ + for(m=qbegin(q);!qend(q,m);m=qnext(q,m)){ + if (m->b_datap->db_ref==1 && m->b_datap->db_lim-m->b_datap->db_base>=size){ + found=m; + break; + } + } + if (found==NULL){ + found=allocb(size,0); + putq(q,found); + } + return dupb(found); +} + +void msgb_allocator_uninit(msgb_allocator_t *a){ + flushq(&a->q,-1); +} diff --git a/linphone/oRTP/src/stun.c b/linphone/oRTP/src/stun.c new file mode 100644 index 000000000..a0e34a471 --- /dev/null +++ b/linphone/oRTP/src/stun.c @@ -0,0 +1,2641 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* ==================================================================== + * The Vovida Software License, Version 1.0 + * + * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The names "VOCAL", "Vovida Open Communication Application Library", + * and "Vovida Open Communication Application Library (VOCAL)" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact vocal@vovida.org. + * + * 4. Products derived from this software may not be called "VOCAL", nor + * may "VOCAL" appear in their name, without prior written + * permission of Vovida Networks, Inc. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA + * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES + * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by Vovida + * Networks, Inc. and many individuals on behalf of Vovida Networks, + * Inc. For more information on Vovida Networks, Inc., please see + * . + * + */ + +#ifndef _WIN32_WCE +#include +#endif + +#include + +#if defined(WIN32) || defined(_WIN32_WCE) +#include +#include +/* #include */ +#include +#include /*for isdigit() */ +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + + +#define NOSSL +/* + #if defined(__sparc__) || defined(WIN32) + #define NOSSL + #endif + #define NOSSL +*/ + +#include "ortp/stun_udp.h" +#include "ortp/stun.h" +#include "ortp/ortp.h" + +static char *ipaddr(const StunAddress4 *addr) +{ + static char tmp[512]; + struct in_addr inaddr; + char *atmp; + inaddr.s_addr = htonl(addr->addr); + atmp = (char *)inet_ntoa(inaddr); + + snprintf(tmp, 512, "%s:%i", atmp, addr->port); + return tmp; +} + +static void +computeHmac(char* hmac, const char* input, int length, const char* key, int keySize); + +static bool_t +stunParseAtrAddress( char* body, unsigned int hdrLen, StunAtrAddress4 *result ) +{ + if ( hdrLen != 8 ) + { + ortp_error("stun: hdrLen wrong for Address\n"); + return FALSE; + } + result->pad = *body++; + result->family = *body++; + if (result->family == IPv4Family) + { + UInt16 nport; + UInt32 naddr; + memcpy(&nport, body, 2); body+=2; + result->ipv4.port = ntohs(nport); + + memcpy(&naddr, body, 4); body+=4; + result->ipv4.addr = ntohl(naddr); + return TRUE; + } + else if (result->family == IPv6Family) + { + ortp_error("stun: ipv6 not supported\n"); + } + else + { + ortp_error("stun: bad address family: %i\n", result->family); + } + + return FALSE; +} + +static bool_t +stunParseAtrChangeRequest( char* body, unsigned int hdrLen, StunAtrChangeRequest *result ) +{ + if ( hdrLen != 4 ) + { + /* ortp_error("stun: hdr length = %i expecting %i\n",hdrLen, sizeof(result)); */ + + ortp_error("stun: Incorrect size for ChangeRequest"); + return FALSE; + } + else + { + memcpy(&result->value, body, 4); + result->value = ntohl(result->value); + return TRUE; + } +} + +static bool_t +stunParseAtrError( char* body, unsigned int hdrLen, StunAtrError *result ) +{ + if ( hdrLen >= sizeof(result) ) + { + ortp_error("stun: head on Error too large"); + return FALSE; + } + else + { + memcpy(&result->pad, body, 2); body+=2; + result->pad = ntohs(result->pad); + result->errorClass = *body++; + result->number = *body++; + + result->sizeReason = hdrLen - 4; + memcpy(&result->reason, body, result->sizeReason); + result->reason[result->sizeReason] = 0; + return TRUE; + } +} + +static bool_t +stunParseAtrUnknown( char* body, unsigned int hdrLen, StunAtrUnknown *result ) +{ + if ( hdrLen >= sizeof(result) ) + { + return FALSE; + } + else + { + int i; + if (hdrLen % 4 != 0) return FALSE; + result->numAttributes = hdrLen / 4; + for (i=0; inumAttributes; i++) + { + memcpy(&result->attrType[i], body, 2); body+=2; + result->attrType[i] = ntohs(result->attrType[i]); + } + return TRUE; + } +} + + +static bool_t +stunParseAtrString( char* body, unsigned int hdrLen, StunAtrString *result ) +{ + if ( hdrLen >= STUN_MAX_STRING ) + { + ortp_error("stun: String is too large"); + return FALSE; + } + else + { + if (hdrLen % 4 != 0) + { + ortp_error("stun: Bad length string %i\n", hdrLen); + return FALSE; + } + + result->sizeValue = hdrLen; + memcpy(&result->value, body, hdrLen); + result->value[hdrLen] = 0; + return TRUE; + } +} + + +static bool_t +stunParseAtrIntegrity( char* body, unsigned int hdrLen, StunAtrIntegrity *result ) +{ + if ( hdrLen != 20) + { + ortp_error("stun: MessageIntegrity must be 20 bytes"); + return FALSE; + } + else + { + memcpy(&result->hash, body, hdrLen); + return TRUE; + } +} + + +bool_t +stunParseMessage( char* buf, unsigned int bufLen, StunMessage *msg, bool_t verbose) +{ + char* body; + unsigned int size; + if (verbose) + ortp_message("stun: Received stun message: %i bytes\n", bufLen); + memset(msg, 0, sizeof(msg)); + + if (sizeof(StunMsgHdr) > bufLen) + { + ortp_warning("stun: Bad message\n"); + return FALSE; + } + + memcpy(&msg->msgHdr, buf, sizeof(StunMsgHdr)); + msg->msgHdr.msgType = ntohs(msg->msgHdr.msgType); + msg->msgHdr.msgLength = ntohs(msg->msgHdr.msgLength); + + if (msg->msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen) + { + ortp_warning("stun: Message header length doesn't match message size: %i - %i\n", msg->msgHdr.msgLength, bufLen); + return FALSE; + } + + body = buf + sizeof(StunMsgHdr); + size = msg->msgHdr.msgLength; + + /*ortp_message("stun: bytes after header = %i\n", size); */ + + while ( size > 0 ) + { + /* !jf! should check that there are enough bytes left in the buffer */ + + StunAtrHdr* attr = (StunAtrHdr*)body; /*reinterpret_cast(body);*/ + + unsigned int attrLen = ntohs(attr->length); + int atrType = ntohs(attr->type); + + /*if (verbose) ortp_message("stun: Found attribute type=" << AttrNames[atrType] << " length=" << attrLen << endl;*/ + if ( attrLen+4 > size ) + { + ortp_error("stun: claims attribute is larger than size of message (attribute type=%i)\n", atrType); + return FALSE; + } + + body += 4; /* skip the length and type in attribute header */ + size -= 4; + + if (atrType == MappedAddress) + { + msg->hasMappedAddress = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->mappedAddress )== FALSE ) + { + ortp_error("stun: problem parsing MappedAddress\n"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: MappedAddress = %s\n", ipaddr(&msg->mappedAddress.ipv4)); + } + + } + else if (atrType == ResponseAddress) + { + msg->hasResponseAddress = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->responseAddress )== FALSE ) + { + ortp_error("stun: problem parsing ResponseAddress"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: ResponseAddress = %s\n", ipaddr(&msg->responseAddress.ipv4)); + } + } + else if (atrType == ChangeRequest) + { + msg->hasChangeRequest = TRUE; + if (stunParseAtrChangeRequest( body, attrLen, &msg->changeRequest) == FALSE) + { + ortp_error("stun: problem parsing ChangeRequest\n"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: ChangeRequest = %i\n", msg->changeRequest.value); + } + } + else if (atrType == SourceAddress) + { + msg->hasSourceAddress = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->sourceAddress )== FALSE ) + { + ortp_error("stun: problem parsing SourceAddress\n"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: SourceAddress = %s\n", ipaddr(&msg->sourceAddress.ipv4) ); + } + } + else if (atrType == ChangedAddress) + { + msg->hasChangedAddress = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->changedAddress )== FALSE ) + { + ortp_error("stun: problem parsing ChangedAddress\n"); + return FALSE; + } + else + { + if (verbose) ortp_message("stun: ChangedAddress = %s\n", ipaddr(&msg->changedAddress.ipv4)); + } + } + else if (atrType == Username) + { + msg->hasUsername = TRUE; + if (stunParseAtrString( body, attrLen, &msg->username) == FALSE) + { + ortp_error("stun: problem parsing Username"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: Username = %s\n", msg->username.value ); + } + } + else if (atrType == Password) + { + msg->hasPassword = TRUE; + if (stunParseAtrString( body, attrLen, &msg->password) == FALSE) + { + ortp_error("stun: problem parsing Password"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: Password = %s\n", msg->password.value ); + } + } + else if (atrType == MessageIntegrity) + { + msg->hasMessageIntegrity = TRUE; + if (stunParseAtrIntegrity( body, attrLen, &msg->messageIntegrity) == FALSE) + { + ortp_error("stun: problem parsing MessageIntegrity"); + return FALSE; + } + else + { + /*if (verbose) ortp_message("stun: MessageIntegrity = " << msg->messageIntegrity.hash ); */ + } + + /* read the current HMAC + look up the password given the user of given the transaction id + compute the HMAC on the buffer + decide if they match or not */ + } + else if (atrType == ErrorCode) + { + msg->hasErrorCode = TRUE; + if (stunParseAtrError(body, attrLen, &msg->errorCode) == FALSE) + { + ortp_error("stun: problem parsing ErrorCode"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: ErrorCode = %i %i %s\n", + msg->errorCode.errorClass , + msg->errorCode.number , + msg->errorCode.reason ); + } + + } + else if (atrType == UnknownAttribute) + { + msg->hasUnknownAttributes = TRUE; + if (stunParseAtrUnknown(body, attrLen, &msg->unknownAttributes) == FALSE) + { + ortp_error("stun: problem parsing UnknownAttribute"); + return FALSE; + } + } + else if (atrType == ReflectedFrom) + { + msg->hasReflectedFrom = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->reflectedFrom ) == FALSE ) + { + ortp_error("stun: problem parsing ReflectedFrom"); + return FALSE; + } + } + else if (atrType == XorMappedAddress) + { + msg->hasXorMappedAddress = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->xorMappedAddress ) == FALSE ) + { + ortp_error("stun: problem parsing XorMappedAddress"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: XorMappedAddress = %s\n", ipaddr(&msg->mappedAddress.ipv4) ); + } + } + else if (atrType == XorOnly) + { + msg->xorOnly = TRUE; + } + else if (atrType == ServerName) + { + msg->hasServerName = TRUE; + if (stunParseAtrString( body, attrLen, &msg->serverName) == FALSE) + { + ortp_error("stun: problem parsing ServerName"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: ServerName = %s\n", msg->serverName.value ); + } + } + else if (atrType == SecondaryAddress) + { + msg->hasSecondaryAddress = TRUE; + if ( stunParseAtrAddress( body, attrLen, &msg->secondaryAddress ) == FALSE ) + { + ortp_error("stun: problem parsing secondaryAddress"); + return FALSE; + } + else + { + if (verbose) + ortp_message("stun: SecondaryAddress = %s\n", ipaddr(&msg->secondaryAddress.ipv4) ); + } + } + else + { + if (verbose) + ortp_message("stun: Unknown attribute: %i\n", atrType ); + if ( atrType <= 0x7FFF ) + { + return FALSE; + } + } + + body += attrLen; + size -= attrLen; + } + + return TRUE; +} + + +static char* +encode16(char* buf, UInt16 data) +{ + UInt16 ndata = htons(data); + /*memcpy(buf, reinterpret_cast(&ndata), sizeof(UInt16)); */ + memcpy(buf, &ndata, sizeof(UInt16)); + return buf + sizeof(UInt16); +} + +static char* +encode32(char* buf, UInt32 data) +{ + UInt32 ndata = htonl(data); + /*memcpy(buf, reinterpret_cast(&ndata), sizeof(UInt32));*/ + memcpy(buf, &ndata, sizeof(UInt32)); + return buf + sizeof(UInt32); +} + + +static char* +encode(char* buf, const char* data, unsigned int length) +{ + memcpy(buf, data, length); + return buf + length; +} + + +static char* +encodeAtrAddress4(char* ptr, UInt16 type, const StunAtrAddress4 *atr) +{ + ptr = encode16(ptr, type); + ptr = encode16(ptr, 8); + *ptr++ = atr->pad; + *ptr++ = IPv4Family; + ptr = encode16(ptr, atr->ipv4.port); + ptr = encode32(ptr, atr->ipv4.addr); + + return ptr; +} + +static char* +encodeAtrChangeRequest(char* ptr, const StunAtrChangeRequest *atr) +{ + ptr = encode16(ptr, ChangeRequest); + ptr = encode16(ptr, 4); + ptr = encode32(ptr, atr->value); + return ptr; +} + +static char* +encodeAtrError(char* ptr, const StunAtrError *atr) +{ + ptr = encode16(ptr, ErrorCode); + ptr = encode16(ptr, 6 + atr->sizeReason); + ptr = encode16(ptr, atr->pad); + *ptr++ = atr->errorClass; + *ptr++ = atr->number; + ptr = encode(ptr, atr->reason, atr->sizeReason); + return ptr; +} + + +static char* +encodeAtrUnknown(char* ptr, const StunAtrUnknown *atr) +{ + int i; + ptr = encode16(ptr, UnknownAttribute); + ptr = encode16(ptr, 2+2*atr->numAttributes); + for (i=0; inumAttributes; i++) + { + ptr = encode16(ptr, atr->attrType[i]); + } + return ptr; +} + + +static char* +encodeXorOnly(char* ptr) +{ + ptr = encode16(ptr, XorOnly ); + return ptr; +} + + +static char* +encodeAtrString(char* ptr, UInt16 type, const StunAtrString *atr) +{ + /*assert(atr->sizeValue % 4 == 0);*/ + + ptr = encode16(ptr, type); + ptr = encode16(ptr, atr->sizeValue); + ptr = encode(ptr, atr->value, atr->sizeValue); + return ptr; +} + + +static char* +encodeAtrIntegrity(char* ptr, const StunAtrIntegrity *atr) +{ + ptr = encode16(ptr, MessageIntegrity); + ptr = encode16(ptr, 20); + ptr = encode(ptr, atr->hash, sizeof(atr->hash)); + return ptr; +} + + +unsigned int +stunEncodeMessage( const StunMessage *msg, + char* buf, + unsigned int bufLen, + const StunAtrString *password, + bool_t verbose) +{ + /*assert(bufLen >= sizeof(StunMsgHdr));*/ + char* ptr = buf; + char* lengthp; + ptr = encode16(ptr, msg->msgHdr.msgType); + lengthp = ptr; + ptr = encode16(ptr, 0); + /*ptr = encode(ptr, reinterpret_cast(msg->msgHdr.id.octet), sizeof(msg->msgHdr.id));*/ + ptr = encode(ptr, (const char*)msg->msgHdr.id.octet, sizeof(msg->msgHdr.id)); + + if (verbose) ortp_message("stun: Encoding stun message: "); + if (msg->hasMappedAddress) + { + if (verbose) ortp_message("stun: Encoding MappedAddress: %s\n", ipaddr(&msg->mappedAddress.ipv4) ); + ptr = encodeAtrAddress4 (ptr, MappedAddress, &msg->mappedAddress); + } + if (msg->hasResponseAddress) + { + if (verbose) ortp_message("stun: Encoding ResponseAddress: %s\n", ipaddr(&msg->responseAddress.ipv4) ); + ptr = encodeAtrAddress4(ptr, ResponseAddress, &msg->responseAddress); + } + if (msg->hasChangeRequest) + { + if (verbose) ortp_message("stun: Encoding ChangeRequest: %i\n", msg->changeRequest.value ); + ptr = encodeAtrChangeRequest(ptr, &msg->changeRequest); + } + if (msg->hasSourceAddress) + { + if (verbose) ortp_message("stun: Encoding SourceAddress: %s\n", ipaddr(&msg->sourceAddress.ipv4) ); + ptr = encodeAtrAddress4(ptr, SourceAddress, &msg->sourceAddress); + } + if (msg->hasChangedAddress) + { + if (verbose) ortp_message("stun: Encoding ChangedAddress: %s\n", ipaddr(&msg->changedAddress.ipv4) ); + ptr = encodeAtrAddress4(ptr, ChangedAddress, &msg->changedAddress); + } + if (msg->hasUsername) + { + if (verbose) ortp_message("stun: Encoding Username: %s\n", msg->username.value ); + ptr = encodeAtrString(ptr, Username, &msg->username); + } + if (msg->hasPassword) + { + if (verbose) ortp_message("stun: Encoding Password: %s\n", msg->password.value ); + ptr = encodeAtrString(ptr, Password, &msg->password); + } + if (msg->hasErrorCode) + { + if (verbose) ortp_message("stun: Encoding ErrorCode: class=%i number=%i reason=%s\n" + , msg->errorCode.errorClass + , msg->errorCode.number + , msg->errorCode.reason ); + + ptr = encodeAtrError(ptr, &msg->errorCode); + } + if (msg->hasUnknownAttributes) + { + if (verbose) ortp_message("stun: Encoding UnknownAttribute: ???"); + ptr = encodeAtrUnknown(ptr, &msg->unknownAttributes); + } + if (msg->hasReflectedFrom) + { + if (verbose) ortp_message("stun: Encoding ReflectedFrom: %s\n", ipaddr(&msg->reflectedFrom.ipv4) ); + ptr = encodeAtrAddress4(ptr, ReflectedFrom, &msg->reflectedFrom); + } + if (msg->hasXorMappedAddress) + { + if (verbose) ortp_message("stun: Encoding XorMappedAddress: %s\n", ipaddr(&msg->xorMappedAddress.ipv4) ); + ptr = encodeAtrAddress4 (ptr, XorMappedAddress, &msg->xorMappedAddress); + } + if (msg->xorOnly) + { + if (verbose) ortp_message("stun: Encoding xorOnly: "); + ptr = encodeXorOnly( ptr ); + } + if (msg->hasServerName) + { + if (verbose) ortp_message("stun: Encoding ServerName: %s\n", msg->serverName.value ); + ptr = encodeAtrString(ptr, ServerName, &msg->serverName); + } + if (msg->hasSecondaryAddress) + { + if (verbose) ortp_message("stun: Encoding SecondaryAddress: %s\n", ipaddr(&msg->secondaryAddress.ipv4) ); + ptr = encodeAtrAddress4 (ptr, SecondaryAddress, &msg->secondaryAddress); + } + + if (password->sizeValue > 0) + { + StunAtrIntegrity integrity; + if (verbose) ortp_message("stun: HMAC with password: %s\n", password->value ); + + computeHmac(integrity.hash, buf, (int)(ptr-buf) , password->value, password->sizeValue); + ptr = encodeAtrIntegrity(ptr, &integrity); + } + + encode16(lengthp, (UInt16)(ptr - buf - sizeof(StunMsgHdr))); + return (int)(ptr - buf); +} + +int +stunRand(void) +{ + /* return 32 bits of random stuff */ + /* assert( sizeof(int) == 4 ); */ + static bool_t init=FALSE; + if ( !init ) + { + UInt64 tick; + int seed; + init = TRUE; + +#if defined(_WIN32_WCE) + tick = GetTickCount (); +#elif defined(_MSC_VER) + { + volatile unsigned int lowtick=0,hightick=0; + __asm + { + rdtsc + mov lowtick, eax + mov hightick, edx + } + tick = hightick; + tick <<= 32; + tick |= lowtick; + } +#elif defined(__GNUC__) && ( defined(__i686__) || defined(__i386__) ) + asm("rdtsc" : "=A" (tick)); +#elif defined(__GNUC__) && defined(__amd64__) + asm("rdtsc" : "=A" (tick)); +#elif defined (__SUNPRO_CC) && defined( __sparc__ ) + tick = gethrtime(); +#elif defined(__MACH__) + { + int fd=open("/dev/random",O_RDONLY); + read(fd,&tick,sizeof(tick)); + closesocket(fd); + } +#elif defined(__linux) + { + fd_set fdSet; + int maxFd=0; + struct timeval tv; + int e; + + int fd=open("/dev/random",O_RDONLY); + + if (fd<0) + { + ortp_message("stun: Failed to open random device\n"); + return random(); + } + FD_ZERO(&fdSet); + FD_SET(fd,&fdSet); + maxFd=fd+1; + + tv.tv_sec = 0; + tv.tv_usec = 500; + + e = select( maxFd, &fdSet, NULL,NULL, &tv ); + if (e <= 0) + { + ortp_error("stun: Failed to get data from random device\n"); + closesocket(fd); + return random(); + } + read(fd,&tick,sizeof(tick)); + closesocket(fd); + } +#else +# error Need some way to seed the random number generator +#endif + seed = (int)(tick); +#if defined(_WIN32) || defined(_WIN32_WCE) + srand(seed); +#else + srandom(seed); +#endif + } + +#if defined(_WIN32) || defined(_WIN32_WCE) + /* assert( RAND_MAX == 0x7fff ); */ + { + int r1 = rand(); + int r2 = rand(); + int ret = (r1<<16) + r2; + + return ret; + } +#else + return random(); +#endif +} + + +/* return a random number to use as a port */ +static int +randomPort() +{ + int min=0x4000; + int max=0x7FFF; + + int ret = stunRand(); + ret = ret|min; + ret = ret&max; + + return ret; +} + + +#ifdef NOSSL +static void +computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey) +{ + strncpy(hmac,"hmac-not-implemented",20); +} +#else +#include + +static void +computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey) +{ + unsigned int resultSize=0; + HMAC(EVP_sha1(), + key, sizeKey, + (const unsigned char*) input, length, + (unsigned char*)hmac, &resultSize); + /* + HMAC(EVP_sha1(), + key, sizeKey, + reinterpret_cast(input), length, + reinterpret_cast(hmac), &resultSize); + //assert(resultSize == 20); + */ +} +#endif + + +static void +toHex(const char* buffer, int bufferSize, char* output) +{ + int i; + static char hexmap[] = "0123456789abcdef"; + + const char* p = buffer; + char* r = output; + for (i=0; i < bufferSize; i++) + { + unsigned char temp = *p++; + + int hi = (temp & 0xf0)>>4; + int low = (temp & 0xf); + + *r++ = hexmap[hi]; + *r++ = hexmap[low]; + } + *r = 0; +} + +void +stunCreateUserName(const StunAddress4* source, StunAtrString* username) +{ + UInt64 time = stunGetSystemTimeSecs(); + UInt64 lotime; + char buffer[1024]; + char hmac[20]; + char key[] = "Jason"; + char hmacHex[41]; + int l; + + time -= (time % 20*60); + /* UInt64 hitime = time >> 32; */ + lotime = time & 0xFFFFFFFF; + + sprintf(buffer, + "%08x:%08x:%08x:", + (UInt32)(source->addr), + (UInt32)(stunRand()), + (UInt32)(lotime)); + /*assert( strlen(buffer) < 1024 ); */ + + /*assert(strlen(buffer) + 41 < STUN_MAX_STRING); */ + + computeHmac(hmac, buffer, strlen(buffer), key, strlen(key) ); + toHex(hmac, 20, hmacHex ); + hmacHex[40] =0; + + strcat(buffer,hmacHex); + + l = strlen(buffer); + /* assert( l+1 < STUN_MAX_STRING );*/ + /* assert( l%4 == 0 ); */ + + username->sizeValue = l; + memcpy(username->value,buffer,l); + username->value[l]=0; + + /* if (verbose) ortp_message("stun: computed username=%s\n", username.value ); */ +} + +void +stunCreatePassword(const StunAtrString *username, StunAtrString* password) +{ + char hmac[20]; + char key[] = "Fluffy"; + /* char buffer[STUN_MAX_STRING]; */ + computeHmac(hmac, username->value, strlen(username->value), key, strlen(key)); + toHex(hmac, 20, password->value); + password->sizeValue = 40; + password->value[40]=0; + + /* ortp_message("stun: password=%s\n", password->value ); */ +} + + +UInt64 +stunGetSystemTimeSecs(void) +{ + UInt64 time=0; +#if defined(_WIN32) || defined(_WIN32_WCE) + SYSTEMTIME t; + /* CJ TODO - this probably has bug on wrap around every 24 hours */ + GetSystemTime( &t ); + time = (t.wHour*60+t.wMinute)*60+t.wSecond; +#else + struct timeval now; + gettimeofday( &now , NULL ); + /* assert( now ); */ + time = now.tv_sec; +#endif + return time; +} + + +/* returns TRUE if it scucceeded */ +bool_t +stunParseHostName( char* peerName, + UInt32* ip, + UInt16* portVal, + UInt16 defaultPort ) +{ + struct in_addr sin_addr; + + char host[512]; + char* port = NULL; + int portNum = defaultPort; + char* sep; + struct hostent* h; + + strncpy(host,peerName,512); + host[512-1]='\0'; + + /* pull out the port part if present. */ + sep = strchr(host,':'); + + if ( sep == NULL ) + { + portNum = defaultPort; + } + else + { + char* endPtr=NULL; + *sep = '\0'; + port = sep + 1; + /* set port part */ + + + portNum = strtol(port,&endPtr,10); + + if ( endPtr != NULL ) + { + if ( *endPtr != '\0' ) + { + portNum = defaultPort; + } + } + } + + if ( portNum < 1024 ) return FALSE; + if ( portNum >= 0xFFFF ) return FALSE; + + /* figure out the host part */ + +#if defined(_WIN32) || defined(_WIN32_WCE) + /* assert( strlen(host) >= 1 ); */ + if ( isdigit( host[0] ) ) + { + /* assume it is a ip address */ + unsigned long a = inet_addr(host); + /* cerr << "a=0x" << hex << a << dec ); */ + + *ip = ntohl( a ); + } + else + { + /* assume it is a host name */ + h = gethostbyname( host ); + + if ( h == NULL ) + { + /*int err = getErrno();*/ + + /* ortp_message("stun: error was %i\n", err); */ + /* std::cerr << "error was " << err << std::endl; */ + /* assert( err != WSANOTINITIALISED ); */ + + *ip = ntohl( 0x7F000001L ); + + return FALSE; + } + else + { + sin_addr = *(struct in_addr*)h->h_addr; + *ip = ntohl( sin_addr.s_addr ); + } + } + +#else + h = gethostbyname( host ); + if ( h == NULL ) + { + /* + int err = getErrno(); + ortp_message("stun: error was %i\n", err); + */ + *ip = ntohl( 0x7F000001L ); + return FALSE; + } + else + { + sin_addr = *(struct in_addr*)h->h_addr; + *ip = ntohl( sin_addr.s_addr ); + } +#endif + + *portVal = portNum; + + return TRUE; +} + + +bool_t +stunParseServerName( char* name, StunAddress4 *addr) +{ + /* assert(name); */ + + /* TODO - put in DNS SRV stuff. */ + + bool_t ret = stunParseHostName( name, &addr->addr, &addr->port, 3478); + if ( ret != TRUE ) + { + addr->port=0xFFFF; + } + return ret; +} + + +static void +stunCreateErrorResponse(StunMessage *response, int cl, int number, const char* msg) +{ + response->msgHdr.msgType = BindErrorResponseMsg; + response->hasErrorCode = TRUE; + response->errorCode.errorClass = cl; + response->errorCode.number = number; + strcpy(response->errorCode.reason, msg); +} + +#if 0 +static void +stunCreateSharedSecretErrorResponse(StunMessage& response, int cl, int number, const char* msg) +{ + response.msgHdr.msgType = SharedSecretErrorResponseMsg; + response.hasErrorCode = TRUE; + response.errorCode.errorClass = cl; + response.errorCode.number = number; + strcpy(response.errorCode.reason, msg); +} +#endif + +static void +stunCreateSharedSecretResponse(const StunMessage *request, const StunAddress4 *source, StunMessage *response) +{ + response->msgHdr.msgType = SharedSecretResponseMsg; + response->msgHdr.id = request->msgHdr.id; + + response->hasUsername = TRUE; + stunCreateUserName( source, &response->username); + + response->hasPassword = TRUE; + stunCreatePassword( &response->username, &response->password); +} + + +/* This funtion takes a single message sent to a stun server, parses + and constructs an apropriate repsonse - returns TRUE if message is + valid */ +bool_t +stunServerProcessMsg( char* buf, + unsigned int bufLen, + StunAddress4 *from, + StunAddress4 *secondary, + StunAddress4 *myAddr, + StunAddress4 *altAddr, + StunMessage *resp, + StunAddress4 *destination, + StunAtrString *hmacPassword, + bool_t* changePort, + bool_t* changeIp, + bool_t verbose) +{ + int i; + StunMessage req; + StunAddress4 mapped; + StunAddress4 respondTo; + UInt32 flags; + bool_t ok; + /* set up information for default response */ + + memset( &req, 0 , sizeof(req) ); + memset( resp, 0 , sizeof(*resp) ); + + *changeIp = FALSE; + *changePort = FALSE; + + ok = stunParseMessage( buf,bufLen, &req, verbose); + + if (!ok) /* Complete garbage, drop it on the floor */ + { + if (verbose) ortp_error("stun: Request did not parse"); + return FALSE; + } + if (verbose) ortp_message("stun: Request parsed ok"); + + mapped = req.mappedAddress.ipv4; + respondTo = req.responseAddress.ipv4; + flags = req.changeRequest.value; + + if (req.msgHdr.msgType==SharedSecretRequestMsg) + { + if(verbose) ortp_message("stun: Received SharedSecretRequestMsg on udp. send error 433."); + /* !cj! - should fix so you know if this came over TLS or UDP */ + stunCreateSharedSecretResponse(&req, from, resp); + /* stunCreateSharedSecretErrorResponse(*resp, 4, 33, "this request must be over TLS"); */ + return TRUE; + + } + else if (req.msgHdr.msgType==BindRequestMsg) + { + if (!req.hasMessageIntegrity) + { + if (verbose) ortp_message("stun: BindRequest does not contain MessageIntegrity"); + + if (0) /* !jf! mustAuthenticate */ + { + if(verbose) ortp_message("stun: Received BindRequest with no MessageIntegrity. Sending 401."); + stunCreateErrorResponse(resp, 4, 1, "Missing MessageIntegrity"); + return TRUE; + } + } + else + { + if (!req.hasUsername) + { + if (verbose) ortp_message("stun: No UserName. Send 432."); + stunCreateErrorResponse(resp, 4, 32, "No UserName and contains MessageIntegrity"); + return TRUE; + } + else + { + if (verbose) ortp_message("stun: Validating username: %s", req.username.value ); + /* !jf! could retrieve associated password from provisioning here */ + if (strcmp(req.username.value, "test") == 0) + { + if (0) + { + /* !jf! if the credentials are stale */ + stunCreateErrorResponse(resp, 4, 30, "Stale credentials on BindRequest"); + return TRUE; + } + else + { + unsigned char hmac[20]; + if (verbose) ortp_message("stun: Validating MessageIntegrity"); + /* need access to shared secret */ + +#ifndef NOSSL + { + unsigned int hmacSize=20; + + HMAC(EVP_sha1(), + "1234", 4, + (const unsigned char*) buf, bufLen-20-4, + hmac, &hmacSize); + /*HMAC(EVP_sha1(), + "1234", 4, + reinterpret_cast(buf), bufLen-20-4, + hmac, &hmacSize); + //assert(hmacSize == 20); + */ + } +#endif + + if (memcmp(buf, hmac, 20) != 0) + { + if (verbose) ortp_warning("stun: MessageIntegrity is bad. Sending "); + stunCreateErrorResponse(resp, 4, 3, "Unknown username. Try test with password 1234"); + return TRUE; + } + + /* need to compute this later after message is filled in */ + resp->hasMessageIntegrity = TRUE; + /* assert(req.hasUsername); */ + resp->hasUsername = TRUE; + resp->username = req.username; /* copy username in */ + } + } + else + { + if (verbose) ortp_message("stun: Invalid username: %s Send 430", req.username.value); + } + } + } + + /* TODO !jf! should check for unknown attributes here and send 420 listing the + unknown attributes. */ + + if ( respondTo.port == 0 ) + { + /* respondTo = from; */ + memcpy(&respondTo, from, sizeof(StunAddress4)); + } + if ( mapped.port == 0 ) + { + /* mapped = from; */ + memcpy(&mapped, from, sizeof(StunAddress4)); + } + + *changeIp = ( flags & ChangeIpFlag )?TRUE:FALSE; + *changePort = ( flags & ChangePortFlag )?TRUE:FALSE; + + if (verbose) + { + ortp_message("stun: Request is valid:\n"); + ortp_message("stun: \t flags= %i\n", flags ); + ortp_message("stun: \t changeIp= %i\n", *changeIp ); + ortp_message("stun: \t changePort=%i\n", *changePort ); + ortp_message("stun: \t from= %i\n", from->addr ); + ortp_message("stun: \t respond to= %i\n", respondTo.addr ); + ortp_message("stun: \t mapped= %i\n", mapped.addr ); + } + + /* form the outgoing message */ + resp->msgHdr.msgType = BindResponseMsg; + for (i=0; i<16; i++ ) + { + resp->msgHdr.id.octet[i] = req.msgHdr.id.octet[i]; + } + + if ( req.xorOnly == FALSE ) + { + resp->hasMappedAddress = TRUE; + resp->mappedAddress.ipv4.port = mapped.port; + resp->mappedAddress.ipv4.addr = mapped.addr; + } + + if (1) /* do xorMapped address or not */ + { + UInt16 id16; + UInt32 id32; + resp->hasXorMappedAddress = TRUE; + id16 = req.msgHdr.id.octet[7]<<8 + | req.msgHdr.id.octet[6]; + id32 = req.msgHdr.id.octet[7]<<24 + | req.msgHdr.id.octet[6]<<16 + | req.msgHdr.id.octet[5]<<8 + | req.msgHdr.id.octet[4]; + resp->xorMappedAddress.ipv4.port = mapped.port^id16; + resp->xorMappedAddress.ipv4.addr = mapped.addr^id32; + } + + resp->hasSourceAddress = TRUE; + resp->sourceAddress.ipv4.port = (*changePort) ? altAddr->port : myAddr->port; + resp->sourceAddress.ipv4.addr = (*changeIp) ? altAddr->addr : myAddr->addr; + + resp->hasChangedAddress = TRUE; + resp->changedAddress.ipv4.port = altAddr->port; + resp->changedAddress.ipv4.addr = altAddr->addr; + + if ( secondary->port != 0 ) + { + resp->hasSecondaryAddress = TRUE; + resp->secondaryAddress.ipv4.port = secondary->port; + resp->secondaryAddress.ipv4.addr = secondary->addr; + } + + if ( req.hasUsername && req.username.sizeValue > 0 ) + { + /* copy username in */ + resp->hasUsername = TRUE; + /* assert( req.username.sizeValue % 4 == 0 ); */ + /* assert( req.username.sizeValue < STUN_MAX_STRING ); */ + memcpy( resp->username.value, req.username.value, req.username.sizeValue ); + resp->username.sizeValue = req.username.sizeValue; + } + + if (1) /* add ServerName */ + { + const char serverName[] = "Vovida.org " STUN_VERSION; /* must pad to mult of 4 */ + resp->hasServerName = TRUE; + + /* assert( sizeof(serverName) < STUN_MAX_STRING ); */ + /* cerr << "sizeof serverName is " << sizeof(serverName) ); */ + /* assert( sizeof(serverName)%4 == 0 ); */ + memcpy( resp->serverName.value, serverName, sizeof(serverName)); + resp->serverName.sizeValue = sizeof(serverName); + } + + if ( req.hasMessageIntegrity & req.hasUsername ) + { + /* this creates the password that will be used in the HMAC when then */ + /* messages is sent */ + stunCreatePassword( &req.username, hmacPassword ); + } + + if (req.hasUsername && (req.username.sizeValue > 64 ) ) + { + UInt32 source; + /* assert( sizeof(int) == sizeof(UInt32) ); */ + + sscanf(req.username.value, "%x", &source); + resp->hasReflectedFrom = TRUE; + resp->reflectedFrom.ipv4.port = 0; + resp->reflectedFrom.ipv4.addr = source; + } + + destination->port = respondTo.port; + destination->addr = respondTo.addr; + + return TRUE; + } + else + { + if (verbose) ortp_error("stun: Unknown or unsupported request "); + return FALSE; + } + + /* assert(0); */ + return FALSE; +} + +bool_t +stunInitServer(StunServerInfo *info, const StunAddress4 *myAddr, const StunAddress4 *altAddr, int startMediaPort, bool_t verbose ) +{ + /* assert( myAddr.port != 0 ); */ + /* assert( altAddr.port!= 0 ); */ + /* assert( myAddr.addr != 0 ); */ + /* assert( altAddr.addr != 0 ); */ + + /* info->myAddr = myAddr; */ + info->myAddr.port = myAddr->port; + info->myAddr.addr = myAddr->addr; + + /* info->altAddr = altAddr; */ + info->altAddr.port = altAddr->port; + info->altAddr.addr = altAddr->addr; + + info->myFd = INVALID_SOCKET; + info->altPortFd = INVALID_SOCKET; + info->altIpFd = INVALID_SOCKET; + info->altIpPortFd = INVALID_SOCKET; + + memset(info->relays, 0, sizeof(info->relays)); + if (startMediaPort > 0) + { + int i; + info->relay = TRUE; + + for (i=0; irelays[i]; + relay->relayPort = startMediaPort+i; + relay->fd = 0; + relay->expireTime = 0; + } + } + else + { + info->relay = FALSE; + } + + if ((info->myFd = openPort(myAddr->port, myAddr->addr,verbose)) == INVALID_SOCKET) + { + ortp_error("stun: Can't open %i\n", myAddr->addr ); + stunStopServer(info); + + return FALSE; + } + /*if (verbose) ortp_message("stun: Opened " << myAddr->addr << ":" << myAddr->port << " --> " << info->myFd ); */ + + if ((info->altPortFd = openPort(altAddr->port,myAddr->addr,verbose)) == INVALID_SOCKET) + { + ortp_error("stun: Can't open %i\n", myAddr->addr ); + stunStopServer(info); + return FALSE; + } + /* if (verbose) ortp_message("stun: Opened " << myAddr->addr << ":" << altAddr->port << " --> " << info->altPortFd ); */ + + + info->altIpFd = INVALID_SOCKET; + if ( altAddr->addr != 0 ) + { + if ((info->altIpFd = openPort( myAddr->port, altAddr->addr,verbose)) == INVALID_SOCKET) + { + ortp_error("stun: Can't open %i\n", altAddr->addr ); + stunStopServer(info); + return FALSE; + } + /* if (verbose) ortp_message("stun: Opened " << altAddr->addr << ":" << myAddr->port << " --> " << info->altIpFd ); */ + } + + info->altIpPortFd = INVALID_SOCKET; + if ( altAddr->addr != 0 ) + { if ((info->altIpPortFd = openPort(altAddr->port, altAddr->addr,verbose)) == INVALID_SOCKET) + { + ortp_error("stun: Can't open %i\n", altAddr->addr ); + stunStopServer(info); + return FALSE; + } + /* if (verbose) ortp_message("stun: Opened " << altAddr->addr << ":" << altAddr->port << " --> " << info->altIpPortFd ); */ + } + + return TRUE; +} + +void +stunStopServer(StunServerInfo *info) +{ + if (info->myFd > 0) closesocket(info->myFd); + if (info->altPortFd > 0) closesocket(info->altPortFd); + if (info->altIpFd > 0) closesocket(info->altIpFd); + if (info->altIpPortFd > 0) closesocket(info->altIpPortFd); + + if (info->relay) + { + int i; + for (i=0; irelays[i]; + if (relay->fd) + { + closesocket(relay->fd); + relay->fd = 0; + } + } + } +} + +#if 0 /* no usefull here */ + +bool_t +stunServerProcess(StunServerInfo *info, bool_t verbose) +{ + char msg[STUN_MAX_MESSAGE_SIZE]; + int msgLen = sizeof(msg); + + bool_t ok = FALSE; + bool_t recvAltIp =FALSE; + bool_t recvAltPort = FALSE; + + fd_set fdSet; +#if defined(_WIN32) || defined(_WIN32_WCE) + unsigned int maxFd=0; +#else + int maxFd=0; +#endif + struct timeval tv; + int e; + + FD_ZERO(&fdSet); + FD_SET(info->myFd,&fdSet); + if ( info->myFd >= maxFd ) maxFd=info->myFd+1; + FD_SET(info->altPortFd,&fdSet); + if ( info->altPortFd >= maxFd ) maxFd=info->altPortFd+1; + + if ( info->altIpFd != INVALID_SOCKET ) + { + FD_SET(info->altIpFd,&fdSet); + if (info->altIpFd>=maxFd) maxFd=info->altIpFd+1; + } + if ( info->altIpPortFd != INVALID_SOCKET ) + { + FD_SET(info->altIpPortFd,&fdSet); + if (info->altIpPortFd>=maxFd) maxFd=info->altIpPortFd+1; + } + + if (info->relay) + { + int i; + for (i=0; irelays[i]; + if (relay->fd) + { + FD_SET(relay->fd, &fdSet); + if (relay->fd >= maxFd) maxFd=relay->fd+1; + } + } + } + + if ( info->altIpFd != INVALID_SOCKET ) + { + FD_SET(info->altIpFd,&fdSet); + if (info->altIpFd>=maxFd) maxFd=info->altIpFd+1; + } + if ( info->altIpPortFd != INVALID_SOCKET ) + { + FD_SET(info->altIpPortFd,&fdSet); + if (info->altIpPortFd>=maxFd) maxFd=info->altIpPortFd+1; + } + + tv.tv_sec = 0; + tv.tv_usec = 1000; + + e = select( maxFd, &fdSet, NULL,NULL, &tv ); + if (e < 0) + { + int err = getErrno(); +#if !defined(_WIN32_WCE) + ortp_error("stun: Error on select: %s\n", strerror(err) ); +#else + ortp_error("stun: Error on select: %i\n", err ); +#endif + } + else if (e >= 0) + { + StunAddress4 from; + int relayPort = 0; + + bool_t changePort = FALSE; + bool_t changeIp = FALSE; + + StunMessage resp; + StunAddress4 dest; + StunAtrString hmacPassword; + + StunAddress4 secondary; + + char buf[STUN_MAX_MESSAGE_SIZE]; + int len = sizeof(buf); + + hmacPassword.sizeValue = 0; + secondary.port = 0; + secondary.addr = 0; + + /* do the media relaying */ + if (info->relay) + { + time_t now; + int i; +#if !defined(_WIN32_WCE) + now = time(0); +#else + DWORD timemillis = GetTickCount(); + now = timemillis/1000; +#endif + for (i=0; irelays[i]; + if (relay->fd) + { + if (FD_ISSET(relay->fd, &fdSet)) + { + char msg[MAX_RTP_MSG_SIZE]; + int msgLen = sizeof(msg); + + StunAddress4 rtpFrom; + ok = getMessage( relay->fd, msg, &msgLen, &rtpFrom.addr, &rtpFrom.port ,verbose); + if (ok) + { + sendMessage(info->myFd, msg, msgLen, relay->destination.addr, relay->destination.port, verbose); + relay->expireTime = now + MEDIA_RELAY_TIMEOUT; + if ( verbose ) ortp_message("stun: Relay packet on %i from %i -> %i", + relay->fd, + rtpFrom.addr, + relay->destination.addr + ); + } + } + else if (now > relay->expireTime) + { + closesocket(relay->fd); + relay->fd = 0; + } + } + } + } + + + if (FD_ISSET(info->myFd,&fdSet)) + { + if (verbose) ortp_message("stun: received on A1:P1"); + recvAltIp = FALSE; + recvAltPort = FALSE; + ok = getMessage( info->myFd, msg, &msgLen, &from.addr, &from.port,verbose ); + } + else if (FD_ISSET(info->altPortFd, &fdSet)) + { + if (verbose) ortp_message("stun: received on A1:P2"); + recvAltIp = FALSE; + recvAltPort = TRUE; + ok = getMessage( info->altPortFd, msg, &msgLen, &from.addr, &from.port,verbose ); + } + else if ( (info->altIpFd!=INVALID_SOCKET) && FD_ISSET(info->altIpFd,&fdSet)) + { + if (verbose) ortp_message("stun: received on A2:P1"); + recvAltIp = TRUE; + recvAltPort = FALSE; + ok = getMessage( info->altIpFd, msg, &msgLen, &from.addr, &from.port ,verbose); + } + else if ( (info->altIpPortFd!=INVALID_SOCKET) && FD_ISSET(info->altIpPortFd, &fdSet)) + { + if (verbose) ortp_message("stun: received on A2:P2"); + recvAltIp = TRUE; + recvAltPort = TRUE; + ok = getMessage( info->altIpPortFd, msg, &msgLen, &from.addr, &from.port,verbose ); + } + else + { + return TRUE; + } + + if (info->relay) + { + int i; + for (i=0; irelays[i]; + if (relay->destination.addr == from.addr && + relay->destination.port == from.port) + { + relayPort = relay->relayPort; + relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT; + break; + } + } + + if (relayPort == 0) + { + int i; + for (i=0; irelays[i]; + if (relay->fd == 0) + { + if ( verbose ) ortp_message("stun: Open relay port %i\n", relay->relayPort ); + relay->fd = openPort(relay->relayPort, info->myAddr.addr, verbose); + relay->destination.addr = from.addr; + relay->destination.port = from.port; + relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT; + relayPort = relay->relayPort; + break; + } + } + } + } + + if ( !ok ) + { + if ( verbose ) ortp_message("stun: Get message did not return a valid message\n"); + return TRUE; + } + + if ( verbose ) ortp_message("stun: Got a request (len=%i) from %i", msgLen, from.addr); + + if ( msgLen <= 0 ) + { + return TRUE; + } + + if (info->relay && relayPort) + { + secondary = from; + + from.addr = info->myAddr.addr; + from.port = relayPort; + } + + ok = stunServerProcessMsg( msg, msgLen, &from, &secondary, + recvAltIp ? &info->altAddr : &info->myAddr, + recvAltIp ? &info->myAddr : &info->altAddr, + &resp, + &dest, + &hmacPassword, + &changePort, + &changeIp, + verbose ); + + if ( !ok ) + { + if ( verbose ) ortp_error("stun: Failed to parse message"); + return TRUE; + } + + len = stunEncodeMessage( &resp, buf, len, &hmacPassword,verbose ); + + if ( dest.addr == 0 ) ok=FALSE; + if ( dest.port == 0 ) ok=FALSE; + + if ( ok ) + { + /* assert( dest.addr != 0 ); */ + /* assert( dest.port != 0 ); */ + + Socket sendFd; + + bool_t sendAltIp = recvAltIp; /* send on the received IP address */ + bool_t sendAltPort = recvAltPort; /* send on the received port */ + + if ( changeIp ) sendAltIp = !sendAltIp; /* if need to change IP, then flip logic */ + if ( changePort ) sendAltPort = !sendAltPort; /* if need to change port, then flip logic */ + + if ( !sendAltPort ) + { + if ( !sendAltIp ) + { + sendFd = info->myFd; + } + else + { + sendFd = info->altIpFd; + } + } + else + { + if ( !sendAltIp ) + { + sendFd = info->altPortFd; + } + else + { + sendFd = info->altIpPortFd; + } + } + + if ( sendFd != INVALID_SOCKET ) + { + sendMessage( sendFd, buf, len, dest.addr, dest.port, verbose ); + } + } + } + + return TRUE; +} +#endif + +int +stunFindLocalInterfaces(UInt32* addresses,int maxRet) +{ +#if defined(WIN32) || defined(_WIN32_WCE) || defined(__sparc__) + return 0; +#else + struct ifconf ifc; + int e; + + int s = socket( AF_INET, SOCK_DGRAM, 0 ); + int len = 100 * sizeof(struct ifreq); + + char buf[ 100 * sizeof(struct ifreq) ]; + char *ptr; + int tl; + int count=0; + + ifc.ifc_len = len; + ifc.ifc_buf = buf; + + e = ioctl(s,SIOCGIFCONF,&ifc); + ptr = buf; + tl = ifc.ifc_len; + + while ( (tl > 0) && ( count < maxRet) ) + { + struct ifreq* ifr = (struct ifreq *)ptr; + struct ifreq ifr2; + struct sockaddr a; + struct sockaddr_in* addr; + + UInt32 ai; + int si = sizeof(ifr->ifr_name) + sizeof(struct sockaddr); + tl -= si; + ptr += si; + /* char* name = ifr->ifr_ifrn.ifrn_name; */ + /* cerr << "name = " << name ); */ + + ifr2 = *ifr; + + e = ioctl(s,SIOCGIFADDR,&ifr2); + if ( e == -1 ) + { + break; + } + + /* cerr << "ioctl addr e = " << e ; */ + + a = ifr2.ifr_addr; + addr = (struct sockaddr_in*) &a; + + ai = ntohl( addr->sin_addr.s_addr ); + if ((int)((ai>>24)&0xFF) != 127) + { + addresses[count++] = ai; + } + + } + + closesocket(s); + + return count; +#endif +} + + +void +stunBuildReqSimple( StunMessage* msg, + const StunAtrString *username, + bool_t changePort, bool_t changeIp, unsigned int id ) +{ + int i; + /* assert( msg ); */ + memset( msg , 0 , sizeof(*msg) ); + + msg->msgHdr.msgType = BindRequestMsg; + + for ( i=0; i<16; i=i+4 ) + { + /* assert(i+3<16); */ + int r = stunRand(); + msg->msgHdr.id.octet[i+0]= r>>0; + msg->msgHdr.id.octet[i+1]= r>>8; + msg->msgHdr.id.octet[i+2]= r>>16; + msg->msgHdr.id.octet[i+3]= r>>24; + } + + if ( id != 0 ) + { + msg->msgHdr.id.octet[0] = id; + } + + msg->hasChangeRequest = TRUE; + msg->changeRequest.value =(changeIp?ChangeIpFlag:0) | + (changePort?ChangePortFlag:0); + + if ( username->sizeValue > 0 ) + { + msg->hasUsername = TRUE; + /* msg->username = username; */ + memcpy(&msg->username, username, sizeof(StunAtrString)); + } +} + + +static void +stunSendTest( Socket myFd, StunAddress4 *dest, + const StunAtrString *username, const StunAtrString *password, + int testNum, bool_t verbose ) +{ + /* assert( dest.addr != 0 ); */ + /* assert( dest.port != 0 ); */ + + bool_t changePort=FALSE; + bool_t changeIP=FALSE; + bool_t discard=FALSE; + + StunMessage req; + char buf[STUN_MAX_MESSAGE_SIZE]; + int len = STUN_MAX_MESSAGE_SIZE; + + switch (testNum) + { + case 1: + case 10: + case 11: + break; + case 2: + /* changePort=TRUE; */ + changeIP=TRUE; + break; + case 3: + changePort=TRUE; + break; + case 4: + changeIP=TRUE; + break; + case 5: + discard=TRUE; + break; + default: + ortp_error("stun: Test %i is unkown\n", testNum); + return ; /* error */ + } + + memset(&req, 0, sizeof(StunMessage)); + + stunBuildReqSimple( &req, username, + changePort , changeIP , + testNum ); + + len = stunEncodeMessage( &req, buf, len, password,verbose ); + + if ( verbose ) + { + ortp_message("stun: About to send msg of len %i to %s\n", len, ipaddr(dest) ); + } + + sendMessage( myFd, buf, len, dest->addr, dest->port, verbose ); + + /* add some delay so the packets don't get sent too quickly */ +#if defined(_WIN32_WCE) + Sleep (10); +#elif defined(WIN32)/* !cj! TODO - should fix this up in windows */ + { + clock_t now = clock(); + /* assert( CLOCKS_PER_SEC == 1000 ); */ + while ( clock() <= now+10 ) { }; + } +#else + usleep(10*1000); +#endif + +} + + +void +stunGetUserNameAndPassword( const StunAddress4 *dest, + StunAtrString* username, + StunAtrString* password) +{ + /* !cj! This is totally bogus - need to make TLS connection to dest and get a */ + /* username and password to use */ + stunCreateUserName(dest, username); + stunCreatePassword(username, password); +} + + +int +stunTest( StunAddress4 *dest, int testNum, bool_t verbose, StunAddress4* sAddr , StunAddress4 *sMappedAddr, StunAddress4* sChangedAddr) +{ + /* assert( dest.addr != 0 ); */ + /* assert( dest.port != 0 ); */ + + int port = randomPort(); + UInt32 interfaceIp=0; + Socket myFd; + StunAtrString username; + StunAtrString password; + char msg[STUN_MAX_MESSAGE_SIZE]; + int msgLen = STUN_MAX_MESSAGE_SIZE; + StunAddress4 from; + StunMessage resp; + bool_t ok; + + if (sAddr) + { + interfaceIp = sAddr->addr; + if ( sAddr->port != 0 ) + { + port = sAddr->port; + } + } + myFd = openPort(port,interfaceIp,verbose); + if ( myFd == INVALID_SOCKET) + return -1; + + username.sizeValue = 0; + password.sizeValue = 0; + +#ifdef USE_TLS + stunGetUserNameAndPassword( dest, &username, &password ); +#endif + + stunSendTest( myFd, dest, &username, &password, testNum, verbose ); + + ok = getMessage( myFd, + msg, + &msgLen, + &from.addr, + &from.port,verbose ); + closesocket(myFd); + if (!ok) + return -1; + + memset(&resp, 0, sizeof(StunMessage)); + + if ( verbose ) ortp_message("stun: Got a response"); + ok = stunParseMessage( msg,msgLen, &resp,verbose ); + + if ( verbose ) + { + ortp_message("stun: \t ok=%i\n", ok ); +#if defined(WIN32) || defined(_WIN32_WCE) + ortp_message("stun: \t id=%u\n", *(unsigned int*)&resp.msgHdr.id ); +#endif + ortp_message("stun: \t mappedAddr=%i\n", resp.mappedAddress.ipv4.addr ); + ortp_message("stun: \t changedAddr=%i\n", resp.changedAddress.ipv4.addr ); + } + + if (sAddr) + { + sAddr->port = port; + } + + if (sMappedAddr) + { + sMappedAddr->port = resp.mappedAddress.ipv4.port; + sMappedAddr->addr = resp.mappedAddress.ipv4.addr; + } + + if (sChangedAddr) + { + sChangedAddr->port = resp.changedAddress.ipv4.port; + sChangedAddr->addr = resp.changedAddress.ipv4.addr; + } + + if (ok) + return 0; + else + return -1; +} + + +NatType +stunNatType( StunAddress4 *dest, + bool_t verbose, + bool_t* preservePort, /* if set, is return for if NAT preservers ports or not */ + bool_t* hairpin, /* if set, is the return for if NAT will hairpin packets */ + int port, /* port to use for the test, 0 to choose random port */ + StunAddress4* sAddr /* NIC to use */ + ) +{ + /* assert( dest.addr != 0 ); */ + /* assert( dest.port != 0 ); */ + UInt32 interfaceIp=0; + Socket myFd1; + Socket myFd2; + + bool_t respTestI=FALSE; + bool_t isNat=TRUE; + StunAddress4 testIchangedAddr; + StunAddress4 testImappedAddr; + bool_t respTestI2=FALSE; + bool_t mappedIpSame = TRUE; + StunAddress4 testI2mappedAddr; + /* StunAddress4 testI2dest=dest; */ + StunAddress4 testI2dest; + bool_t respTestII=FALSE; + bool_t respTestIII=FALSE; + bool_t respTestHairpin=FALSE; + StunAtrString username; + StunAtrString password; + int count=0; + UInt64 second_started; + UInt64 second_elapsed; + Socket s; + + if ( hairpin ) + { + *hairpin = FALSE; + } + + if ( port == 0 ) + { + port = randomPort(); + } + + if (sAddr) + { + interfaceIp = sAddr->addr; + } + myFd1 = openPort(port,interfaceIp,verbose); + myFd2 = openPort(port+1,interfaceIp,verbose); + + if ( ( myFd1 == INVALID_SOCKET) || ( myFd2 == INVALID_SOCKET) ) + { + ortp_error("stun: Some problem opening port/interface to send on\n"); + return StunTypeFailure; + } + + /* assert( myFd1 != INVALID_SOCKET ); */ + /* assert( myFd2 != INVALID_SOCKET ); */ + + memcpy(&testI2dest, dest, sizeof(StunAddress4)); + + memset(&testImappedAddr,0,sizeof(testImappedAddr)); + + username.sizeValue = 0; + password.sizeValue = 0; + +#ifdef USE_TLS + stunGetUserNameAndPassword( dest, username, password ); +#endif + + /* stunSendTest( myFd1, dest, username, password, 1, verbose ); */ + + + second_started = stunGetSystemTimeSecs(); + second_elapsed = 1; + + while ( count < 7 && second_elapsed < 5) + { + struct timeval tv; + fd_set fdSet; + int err; + int e; + +#if defined(WIN32) || defined(_WIN32_WCE) + unsigned int fdSetSize; +#else + int fdSetSize; +#endif + + second_elapsed = stunGetSystemTimeSecs() - second_started ; + + FD_ZERO(&fdSet); fdSetSize=0; + FD_SET(myFd1,&fdSet); fdSetSize = (myFd1+1>fdSetSize) ? myFd1+1 : fdSetSize; + FD_SET(myFd2,&fdSet); fdSetSize = (myFd2+1>fdSetSize) ? myFd2+1 : fdSetSize; + tv.tv_sec=0; + tv.tv_usec=500*1000; /* 150 ms */ + if ( count == 0 ) tv.tv_usec=0; + + err = select(fdSetSize, &fdSet, NULL, NULL, &tv); + e = getErrno(); + if ( err == SOCKET_ERROR ) + { + /* error occured */ +#if !defined(_WIN32_WCE) + ortp_error("stun: Error %i %s in select\n", e, strerror(e)); +#else + ortp_error("stun: Error %i in select\n", e); +#endif + closesocket(myFd1); /* AMD */ + closesocket(myFd2); /* AMD */ + return StunTypeFailure; + } + else if ( err == 0 ) + { + /* timeout occured */ + count++; + + if ( !respTestI ) + { + stunSendTest( myFd1, dest, &username, &password, 1 ,verbose ); + } + + if ( (!respTestI2) && respTestI ) + { + /* check the address to send to if valid */ + if ( ( testI2dest.addr != 0 ) && + ( testI2dest.port != 0 ) ) + { + stunSendTest( myFd1, &testI2dest, &username, &password, 10 ,verbose); + } + } + + if ( !respTestII ) + { + stunSendTest( myFd2, dest, &username, &password, 2 ,verbose ); + } + + if ( !respTestIII ) + { + stunSendTest( myFd2, dest, &username, &password, 3 ,verbose ); + } + + if ( respTestI && (!respTestHairpin) ) + { + if ( ( testImappedAddr.addr != 0 ) && + ( testImappedAddr.port != 0 ) ) + { + stunSendTest( myFd1, &testImappedAddr, &username, &password, 11 ,verbose ); + } + } + } + else + { + int i; + /* if (verbose) ortp_message("stun: -----------------------------------------"); */ + /* assert( err>0 ); */ + /* data is avialbe on some fd */ + + for ( i=0; i<2; i++) + { + Socket myFd; + if ( i==0 ) + { + myFd=myFd1; + } + else + { + myFd=myFd2; + } + + if ( myFd!=INVALID_SOCKET ) + { + if ( FD_ISSET(myFd,&fdSet) ) + { + char msg[STUN_MAX_MESSAGE_SIZE]; + int msgLen = sizeof(msg); + + StunAddress4 from; + StunMessage resp; + + getMessage( myFd, + msg, + &msgLen, + &from.addr, + &from.port,verbose ); + + memset(&resp, 0, sizeof(StunMessage)); + + stunParseMessage( msg,msgLen, &resp,verbose ); + + if ( verbose ) + { + ortp_message("stun: Received message of type %i id=%i\n", + resp.msgHdr.msgType, + (int)(resp.msgHdr.id.octet[0]) ); + } + + switch( resp.msgHdr.id.octet[0] ) + { + case 1: + { + if ( !respTestI ) + { + + testIchangedAddr.addr = resp.changedAddress.ipv4.addr; + testIchangedAddr.port = resp.changedAddress.ipv4.port; + testImappedAddr.addr = resp.mappedAddress.ipv4.addr; + testImappedAddr.port = resp.mappedAddress.ipv4.port; + + if ( preservePort ) + { + *preservePort = ( testImappedAddr.port == port ); + } + + testI2dest.addr = resp.changedAddress.ipv4.addr; + + if (sAddr) + { + sAddr->port = testImappedAddr.port; + sAddr->addr = testImappedAddr.addr; + } + + count = 0; + } + respTestI=TRUE; + } + break; + case 2: + { + respTestII=TRUE; + } + break; + case 3: + { + respTestIII=TRUE; + } + break; + case 10: + { + if ( !respTestI2 ) + { + testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr; + testI2mappedAddr.port = resp.mappedAddress.ipv4.port; + + mappedIpSame = FALSE; + if ( (testI2mappedAddr.addr == testImappedAddr.addr ) && + (testI2mappedAddr.port == testImappedAddr.port )) + { + mappedIpSame = TRUE; + } + + + } + respTestI2=TRUE; + } + break; + case 11: + { + + if ( hairpin ) + { + *hairpin = TRUE; + } + respTestHairpin = TRUE; + } + break; + } + } + } + } + } + } + + closesocket(myFd1); /* AMD */ + closesocket(myFd2); /* AMD */ + + /* see if we can bind to this address */ + /* cerr << "try binding to " << testImappedAddr ); */ + s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, FALSE ); + if ( s != INVALID_SOCKET ) + { + isNat = FALSE; + /* cerr << "binding worked"); */ + } + else + { + isNat = TRUE; + /* cerr << "binding failed"); */ + } + + closesocket(s); /* AMD */ + + if (verbose) + { + ortp_message("stun: test I = %i\n", respTestI ); + ortp_message("stun: test II = %i\n", respTestII ); + ortp_message("stun: test III = %i\n", respTestIII ); + ortp_message("stun: test I(2) = %i\n", respTestI2 ); + ortp_message("stun: is nat = %i\n", isNat); + ortp_message("stun: mapped IP same = %i\n", mappedIpSame ); + } + + /* implement logic flow chart from draft RFC */ + if ( respTestI ) + { + if ( isNat ) + { + if (respTestII) + { + return StunTypeConeNat; + } + else + { + if ( mappedIpSame ) + { + if ( respTestIII ) + { + return StunTypeRestrictedNat; + } + else + { + return StunTypePortRestrictedNat; + } + } + else + { + return StunTypeSymNat; + } + } + } + else + { + if (respTestII) + { + return StunTypeOpen; + } + else + { + return StunTypeSymFirewall; + } + } + } + else + { + return StunTypeBlocked; + } + + return StunTypeUnknown; +} + +int +stunOpenSocket( StunAddress4 *dest, StunAddress4* mapAddr, + int port, StunAddress4* srcAddr, + bool_t verbose ) +{ + /* assert( dest.addr != 0 ); */ + /* assert( dest.port != 0 ); */ + /* assert( mapAddr );*/ + unsigned int interfaceIp = 0; + Socket myFd; + char msg[STUN_MAX_MESSAGE_SIZE]; + int msgLen = sizeof(msg); + + StunAtrString username; + StunAtrString password; + + StunAddress4 from; + StunMessage resp; + bool_t ok; + StunAddress4 mappedAddr; + + if ( port == 0 ) + { + port = randomPort(); + } + + if ( srcAddr ) + { + interfaceIp = srcAddr->addr; + } + + myFd = openPort(port,interfaceIp,verbose); + if (myFd == INVALID_SOCKET) + { + return myFd; + } + + username.sizeValue = 0; + password.sizeValue = 0; + +#ifdef USE_TLS + stunGetUserNameAndPassword( dest, username, password ); +#endif + + stunSendTest(myFd, dest, &username, &password, 1, 0/*FALSE*/ ); + + getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); + + memset(&resp, 0, sizeof(StunMessage)); + + ok = stunParseMessage( msg, msgLen, &resp,verbose ); + if (!ok) + { + closesocket(myFd); + return -1; + } + + mappedAddr = resp.mappedAddress.ipv4; + + /* + ortp_message("stun: --- stunOpenSocket --- "); + ortp_message("stun: \treq id=" << req.id ); + ortp_message("stun: \tresp id=" << id ); + ortp_message("stun: \tmappedAddr=" << mappedAddr ); + */ + + *mapAddr = mappedAddr; + + return myFd; +} + + +bool_t +stunOpenSocketPair(StunAddress4 *dest, + StunAddress4* mapAddr_rtp, + StunAddress4* mapAddr_rtcp, + int* fd1, int* fd2, + int port, StunAddress4* srcAddr, + bool_t verbose ) +{ + /* assert( dest.addr!= 0 ); */ + /* assert( dest.port != 0 ); */ + /* assert( mapAddr ); */ + + const int NUM=2; + char msg[STUN_MAX_MESSAGE_SIZE]; + int msgLen =sizeof(msg); + + StunAddress4 from; + int fd[2/*NUM*/]; + int i; + + unsigned int interfaceIp = 0; + + StunAtrString username; + StunAtrString password; + + StunAddress4 mappedAddr[2/*NUM*/]; + + if ( port == 0 ) + { + port = randomPort(); + } + + *fd1=-1; + *fd2=-1; + + if ( srcAddr ) + { + interfaceIp = srcAddr->addr; + } + + for( i=0; i 0) + { + closesocket(fd[--i]); + } + return FALSE; + } + } + + username.sizeValue = 0; + password.sizeValue = 0; + +#ifdef USE_TLS + stunGetUserNameAndPassword( dest, username, password ); +#endif + + for( i=0; i. + * + */ + +#include +#include +#include +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include + +#include + +#if defined(WIN32) || defined(_WIN32_WCE) + +#include +#include +/* #include */ + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include + +#include "ortp/stun_udp.h" +#include "ortp/ortp.h" + +#if !defined(WIN32) && !defined(_WIN32_WCE) +int getErrno() { return errno; } +#else +int getErrno() { return WSAGetLastError(); } +#endif + +Socket +openPort( unsigned short port, unsigned int interfaceIp, bool_t verbose ) +{ + struct sockaddr_in addr; + Socket fd; + + fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if ( fd == INVALID_SOCKET ) + { + ortp_error("stun_udp: Could not create a UDP socket"); + return INVALID_SOCKET; + } + + memset((char*) &(addr),0, sizeof((addr))); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if ( (interfaceIp != 0) && + ( interfaceIp != 0x100007f ) ) + { + addr.sin_addr.s_addr = htonl(interfaceIp); + if (verbose ) + { + ortp_message("Binding to interface 0x%lu\n",(unsigned long) htonl(interfaceIp)); + } + } + + if ( bind( fd,(struct sockaddr*)&addr, sizeof(addr)) != 0 ) + { + int e = getErrno(); + + switch (e) + { + case 0: + { + ortp_error("stun_udp: Could not bind socket");; + return INVALID_SOCKET; + } + case EADDRINUSE: + { + ortp_error("stun_udp: Port %i for receiving UDP is in use", port); + return INVALID_SOCKET; + } + break; + case EADDRNOTAVAIL: + { + if ( verbose ) + { + ortp_error("stun_udp: Cannot assign requested address"); + } + return INVALID_SOCKET; + } + break; + default: + { +#if !defined(_WIN32_WCE) + ortp_error("stun_udp: Could not bind UDP receive port Error=%i %s", + e, strerror(e)); +#else + ortp_error("stun_udp: Could not bind UDP receive port Error=%i", + e); +#endif + return INVALID_SOCKET; + } + break; + } + } + if ( verbose ) + { + ortp_message("stun: opened port %i with fd %i\n", port, fd); + } + + /* assert( fd != INVALID_SOCKET ); */ + + return fd; +} + + +bool_t +getMessage( Socket fd, char* buf, int* len, + unsigned int* srcIp, unsigned short* srcPort, + bool_t verbose) +{ + /* assert( fd != INVALID_SOCKET ); */ + + int originalSize = *len; + struct sockaddr_in from; + int fromLen = sizeof(from); + + + int err; + struct timeval tv; + fd_set fdSet; +#if defined(WIN32) || defined(_WIN32_WCE) + unsigned int fdSetSize; +#else + int fdSetSize; +#endif + + if (originalSize <= 0) + { + return FALSE; + } + + tv.tv_sec=1; + tv.tv_usec=0; /* 150 ms */ + FD_ZERO(&fdSet); fdSetSize=0; + FD_SET(fd,&fdSet); fdSetSize = fd+1; + + err = select(fdSetSize, &fdSet, NULL, NULL, &tv); + if ( err == SOCKET_ERROR ) + { + int e = getErrno(); + switch (e) + { + case ENOTSOCK: + ortp_error("stun_udp: Error fd not a socket"); + break; + case ECONNRESET: + ortp_error("stun_udp: Error connection reset - host not reachable"); + break; + + default: + ortp_error("stun_udp: Socket Error=%i", e); + } + return FALSE; + } + + if (err==0) + { + ortp_error("stun_udp: Connection timeout with stun server!"); + *len = 0; + return FALSE; + } + + if (FD_ISSET (fd, &fdSet)) + { + *len = recvfrom(fd, + buf, + originalSize, + 0, + (struct sockaddr *)&from, + (socklen_t*)&fromLen); + + if ( *len == SOCKET_ERROR ) + { + int e = getErrno(); + + switch (e) + { + case ENOTSOCK: + ortp_error("stun_udp: Error fd not a socket"); + break; + case ECONNRESET: + ortp_error("stun_udp: Error connection reset - host not reachable"); + break; + + default: + ortp_error("stun_udp: Socket Error=%i", e); + } + + return FALSE; + } + + if ( *len < 0 ) + { + ortp_error("stun_udp: socket closed? negative len"); + return FALSE; + } + + if ( *len == 0 ) + { + ortp_error("stun_udp: socket closed? zero len"); + return FALSE; + } + + *srcPort = ntohs(from.sin_port); + *srcIp = ntohl(from.sin_addr.s_addr); + + if ( (*len)+1 >= originalSize ) + { + if (verbose) + { + ortp_error("stun_udp: Received a message that was too large"); + } + return FALSE; + } + buf[*len]=0; + + return TRUE; + } + return FALSE; +} + + +bool_t +sendMessage( Socket fd, char* buf, int l, + unsigned int dstIp, unsigned short dstPort, + bool_t verbose) +{ + int s; + + if (fd == INVALID_SOCKET) + return FALSE; + + if ( dstPort == 0 ) + { + /* sending on a connected port */ + s = send(fd,buf,l,0); + } + else + { + struct sockaddr_in to; + int toLen = sizeof(to); + if (dstIp == 0) + { + ortp_error("stun_udp: invalid IP provided (dstIP==0)"); + return FALSE; + } + + memset(&to,0,toLen); + + to.sin_family = AF_INET; + to.sin_port = htons(dstPort); + to.sin_addr.s_addr = htonl(dstIp); + + s = sendto(fd, buf, l, 0,(struct sockaddr*)&to, toLen); + } + + if ( s == SOCKET_ERROR ) + { + int e = getErrno(); + switch (e) + { + case ECONNREFUSED: + case EHOSTDOWN: + case EHOSTUNREACH: + { + /* quietly ignore this */ + } + break; + case EAFNOSUPPORT: + { + ortp_error("stun_udp: err EAFNOSUPPORT in send"); + } + break; + default: + { +#if !defined(_WIN32_WCE) + ortp_error("stun_udp: err %i %s in send", e, strerror(e)); +#else + ortp_error("stun_udp: err %i in send", e); +#endif + } + } + return FALSE; + } + + if ( s == 0 ) + { + ortp_error("stun_udp: no data sent in send"); + return FALSE; + } + + if ( s != l ) + { + if (verbose) + { + ortp_error("stun_udp: only %i out of %i bytes sent", s, l); + } + return FALSE; + } + + return TRUE; +} + + +void +initNetwork() +{ +#if defined(WIN32) || defined(_WIN32_WCE) + WORD wVersionRequested = MAKEWORD( 2, 2 ); + WSADATA wsaData; + int err; + + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) + { + /* could not find a usable WinSock DLL */ + ortp_error("stun_udp: Could not load winsock"); + } + + /* Confirm that the WinSock DLL supports 2.2.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.2 in addition to 2.2, it will still return */ + /* 2.2 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 2 ) + { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + WSACleanup( ); + ortp_error("stun_udp: Wrong winsock (!= 2.2) version"); + } +#endif +} + + +/* ==================================================================== + * The Vovida Software License, Version 1.0 + * + * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The names "VOCAL", "Vovida Open Communication Application Library", + * and "Vovida Open Communication Application Library (VOCAL)" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact vocal@vovida.org. + * + * 4. Products derived from this software may not be called "VOCAL", nor + * may "VOCAL" appear in their name, without prior written + * permission of Vovida Networks, Inc. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA + * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES + * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by Vovida + * Networks, Inc. and many individuals on behalf of Vovida Networks, + * Inc. For more information on Vovida Networks, Inc., please see + * . + * + */ + +/* Local Variables: + mode:c + c-file-style:"ellemtel" + c-file-offsets:((case-label . +)) + indent-tabs-mode:nil + End: +*/ diff --git a/linphone/oRTP/src/system b/linphone/oRTP/src/system new file mode 100644 index 000000000..50dcc4375 --- /dev/null +++ b/linphone/oRTP/src/system @@ -0,0 +1,15 @@ +*############################################################ +*# +*# $Header: /sources/linphone/linphone/oRTP/src/system,v 1.1 2002/02/25 08:41:53 smorlat Exp $ +*# +*# $Source: /sources/linphone/linphone/oRTP/src/system,v $ +*# $Revision: 1.1 $ +*# $Locker: $ +*# +*############################################################ +$VERSION 1 +$CONFIGURE Y +$LOADABLE Y +$TUNABLE +$$$ + diff --git a/linphone/oRTP/src/telephonyevents.c b/linphone/oRTP/src/telephonyevents.c new file mode 100644 index 000000000..538bdba4e --- /dev/null +++ b/linphone/oRTP/src/telephonyevents.c @@ -0,0 +1,421 @@ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc1889) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "utils.h" +#include "rtpsession_priv.h" +#include + +PayloadType payload_type_telephone_event={ + PAYLOAD_AUDIO_PACKETIZED, /*type */ + 8000, /*clock rate */ + 0, /* bytes per sample N/A */ + NULL, /* zero pattern N/A*/ + 0, /*pattern_length N/A */ + 0, /* normal_bitrate */ + "telephone-event", /* MIME subtype */ + 0, /* Audio Channels N/A */ + 0 /*flags */ +}; + +/** + * Tells whether telephony events payload type is supported within the + * context of the rtp session. + * @param session a rtp session + * + * @return the payload type number used for telephony events if found, -1 if not found. +**/ +int rtp_session_telephone_events_supported(RtpSession *session) +{ + /* search for a telephony event payload in the current profile */ + session->snd.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->snd.profile,"telephone-event"); + session->rcv.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->rcv.profile,"telephone-event"); + /*printf("Telephone event pt is %i\n",session->telephone_events_pt);*/ + return session->snd.telephone_events_pt; +} + + +/** + * Tells whether telephone event payload type is supported for send within the + * context of the rtp session. + * @param session a rtp session + * + * @return the payload type number used for telephony events if found, -1 if not found. +**/ +int rtp_session_send_telephone_events_supported(RtpSession *session) +{ + /* search for a telephony event payload in the current profile */ + session->snd.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->snd.profile,"telephone-event"); + /*printf("Telephone event pt is %i\n",session->telephone_events_pt);*/ + return session->snd.telephone_events_pt; +} + +/** + * Tells whether telephone event payload type is supported for receiving within the + * context of the rtp session. + * @param session a rtp session + * + * @return the payload type number used for telephony events if found, -1 if not found. +**/int rtp_session_recv_telephone_events_supported(RtpSession *session) +{ + /* search for a telephony event payload in the current profile */ + session->rcv.telephone_events_pt=rtp_profile_get_payload_number_from_mime(session->rcv.profile,"telephone-event"); + /*printf("Telephone event pt is %i\n",session->telephone_events_pt);*/ + return session->snd.telephone_events_pt; +} + + +/** + * Allocates a new rtp packet to be used to add named telephony events. The application can use + * then rtp_session_add_telephone_event() to add named events to the packet. + * Finally the packet has to be sent with rtp_session_sendm_with_ts(). + * + * @param session a rtp session. + * @param start boolean to indicate if the marker bit should be set. + * + * @return a message block containing the rtp packet if successfull, NULL if the rtp session + *cannot support telephony event (because the rtp profile it is bound to does not include + *a telephony event payload type). +**/ +mblk_t *rtp_session_create_telephone_event_packet(RtpSession *session, int start) +{ + mblk_t *mp; + rtp_header_t *rtp; + + return_val_if_fail(session->snd.telephone_events_pt!=-1,NULL); + + mp=allocb(RTP_FIXED_HEADER_SIZE+TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED); + if (mp==NULL) return NULL; + rtp=(rtp_header_t*)mp->b_rptr; + rtp->version = 2; + rtp->markbit=start; + rtp->padbit = 0; + rtp->extbit = 0; + rtp->cc = 0; + rtp->ssrc = session->snd.ssrc; + /* timestamp set later, when packet is sended */ + /*seq number set later, when packet is sended */ + + /*set the payload type */ + rtp->paytype=session->snd.telephone_events_pt; + + /*copy the payload */ + mp->b_wptr+=RTP_FIXED_HEADER_SIZE; + return mp; +} + + +/** + *@param session a rtp session. + *@param packet a rtp packet as a mblk_t + *@param event the event type as described in rfc2833, ie one of the TEV_* macros. + *@param end a boolean to indicate if the end bit should be set. (end of tone) + *@param volume the volume of the telephony tone, as described in rfc2833 + *@param duration the duration of the telephony tone, in timestamp unit. + * + * Adds a named telephony event to a rtp packet previously allocated using + * rtp_session_create_telephone_event_packet(). + * + *@return 0 on success. +**/ +int rtp_session_add_telephone_event(RtpSession *session, + mblk_t *packet, uint8_t event, int end, uint8_t volume, uint16_t duration) +{ + mblk_t *mp=packet; + telephone_event_t *event_hdr; + + + /* find the place where to add the new telephony event to the packet */ + while(mp->b_cont!=NULL) mp=mp->b_cont; + /* see if we need to allocate a new mblk_t */ + if ( ( mp->b_wptr) >= (mp->b_datap->db_lim)){ + mblk_t *newm=allocb(TELEPHONY_EVENTS_ALLOCATED_SIZE,BPRI_MED); + mp->b_cont=newm; + mp=mp->b_cont; + } + if (mp==NULL) return -1; + event_hdr=(telephone_event_t*)mp->b_wptr; + event_hdr->event=event; + event_hdr->R=0; + event_hdr->E=end; + event_hdr->volume=volume; + event_hdr->duration=htons(duration); + mp->b_wptr+=sizeof(telephone_event_t); + return 0; +} +/** + * This functions creates telephony events packets for dtmf and sends them. + * It uses rtp_session_create_telephone_event_packet() and + * rtp_session_add_telephone_event() to create them and finally + * rtp_session_sendm_with_ts() to send them. + * + * @param session a rtp session + * @param dtmf a character meaning the dtmf (ex: '1', '#' , '9' ...) + * @param userts the timestamp + * @return 0 if successfull, -1 if the session cannot support telephony events or if the dtmf given as argument is not valid. +**/ +int rtp_session_send_dtmf(RtpSession *session, char dtmf, uint32_t userts) +{ + return rtp_session_send_dtmf2(session, dtmf, userts, 480); +} + +/** + * A variation of rtp_session_send_dtmf() with duration specified. + * + * @param session a rtp session + * @param dtmf a character meaning the dtmf (ex: '1', '#' , '9' ...) + * @param userts the timestamp + * @param duration duration of the dtmf in timestamp units + * @return 0 if successfull, -1 if the session cannot support telephony events or if the dtmf given as argument is not valid. +**/ +int rtp_session_send_dtmf2(RtpSession *session, char dtmf, uint32_t userts, int duration) +{ + mblk_t *m1,*m2,*m3; + int tev_type; + int durationtier = duration/3; + + /* create the first telephony event packet */ + switch (dtmf){ + case '1': + tev_type=TEV_DTMF_1; + break; + case '2': + tev_type=TEV_DTMF_2; + break; + case '3': + tev_type=TEV_DTMF_3; + break; + case '4': + tev_type=TEV_DTMF_4; + break; + case '5': + tev_type=TEV_DTMF_5; + break; + case '6': + tev_type=TEV_DTMF_6; + break; + case '7': + tev_type=TEV_DTMF_7; + break; + case '8': + tev_type=TEV_DTMF_8; + break; + case '9': + tev_type=TEV_DTMF_9; + break; + case '*': + tev_type=TEV_DTMF_STAR; + break; + case '0': + tev_type=TEV_DTMF_0; + break; + case '#': + tev_type=TEV_DTMF_POUND; + break; + + case 'A': + case 'a': + tev_type=TEV_DTMF_A; + break; + + + case 'B': + case 'b': + tev_type=TEV_DTMF_B; + break; + + case 'C': + case 'c': + tev_type=TEV_DTMF_C; + break; + + case 'D': + case 'd': + tev_type=TEV_DTMF_D; + break; + + case '!': + tev_type=TEV_FLASH; + break; + + + default: + ortp_warning("Bad dtmf: %c.",dtmf); + return -1; + } + + m1=rtp_session_create_telephone_event_packet(session,1); + if (m1==NULL) return -1; + rtp_session_add_telephone_event(session,m1,tev_type,0,10,durationtier); + /* create a second packet */ + m2=rtp_session_create_telephone_event_packet(session,0); + if (m2==NULL) return -1; + rtp_session_add_telephone_event(session,m2,tev_type,0,10, durationtier+durationtier); + + /* create a third and final packet */ + m3=rtp_session_create_telephone_event_packet(session,0); + if (m3==NULL) return -1; + rtp_session_add_telephone_event(session,m3,tev_type,1,10,duration); + + /* and now sends them */ + rtp_session_sendm_with_ts(session,m1,userts); + rtp_session_sendm_with_ts(session,m2,userts); + /* the last packet is sent three times in order to improve reliability*/ + m1=copymsg(m3); + m2=copymsg(m3); + /* NOTE: */ + /* we need to copymsg() instead of dupmsg() because the buffers are modified when + the packet is sended because of the host-to-network conversion of timestamp,ssrc, csrc, and + seq number. + */ + rtp_session_sendm_with_ts(session,m3,userts); + session->rtp.snd_seq--; + rtp_session_sendm_with_ts(session,m1,userts); + session->rtp.snd_seq--; + rtp_session_sendm_with_ts(session,m2,userts); + return 0; +} + + +/** + * Reads telephony events from a rtp packet. *@tab points to the beginning of the event buffer. + * + * @param session a rtp session from which telephony events are received. + * @param packet a rtp packet as a mblk_t. + * @param tab the address of a pointer. + * @return the number of events in the packet if successfull, 0 if the packet did not contain telephony events. +**/ +int rtp_session_read_telephone_event(RtpSession *session, + mblk_t *packet,telephone_event_t **tab) +{ + int datasize; + int num; + int i; + telephone_event_t *tev; + rtp_header_t *hdr=(rtp_header_t*)packet->b_rptr; + unsigned char *payload; + if (hdr->paytype!=session->rcv.telephone_events_pt) return 0; /* this is not tel ev.*/ + datasize=rtp_get_payload(packet,&payload); + tev=*tab=(telephone_event_t*)payload; + /* convert from network to host order what should be */ + num=datasize/sizeof(telephone_event_t); + for (i=0;ion_telephone_event,(long)(long)event[0].event); + if (session->eventqs!=NULL){ + ev=ortp_event_new(ORTP_EVENT_TELEPHONE_EVENT); + evd=ortp_event_get_data(ev); + evd->packet=dupmsg(session->current_tev); + evd->info.telephone_event=event[0].event; + rtp_session_dispatch_event(session,ev); + } +} + +static void notify_events_ended(RtpSession *session, telephone_event_t *events, int num){ + int i; + for (i=0;ib_rptr; + + datasize=rtp_get_payload(m0,&payload); + + num=datasize/sizeof(telephone_event_t); + events=(telephone_event_t*)payload; + + + if (hdr->markbit==1) + { + /* this is a start of new events. Store the event buffer for later use*/ + if (session->current_tev!=NULL) { + freemsg(session->current_tev); + session->current_tev=NULL; + } + session->current_tev=copymsg(m0); + /* handle the case where the events are short enough to end within the packet that has the marker bit*/ + notify_events_ended(session,events,num); + } + /* whatever there is a markbit set or not, we parse the packet and compare it to previously received one */ + cur_tev=session->current_tev; + if (cur_tev!=NULL) + { + /* first compare timestamp, they must be identical */ + if (((rtp_header_t*)cur_tev->b_rptr)->timestamp== + ((rtp_header_t*)m0->b_rptr)->timestamp) + { + datasize=rtp_get_payload(cur_tev,&payload); + num2=datasize/sizeof(telephone_event_t); + evbuf=(telephone_event_t*)payload; + for (i=0;icurrent_tev!=NULL) { + freemsg(session->current_tev); + session->current_tev=NULL; + } + session->current_tev=copymsg(m0); + notify_events_ended(session,events,num); + } + } + else + { + /* there is no pending events, but we did not received marked bit packet + either the sending implementation is not compliant, either it has been lost, + we must deal with it anyway.*/ + session->current_tev=copymsg(m0); + /* inform the application if there are tone ends */ + notify_events_ended(session,events,num); + } +} diff --git a/linphone/oRTP/src/tests/.cvsignore b/linphone/oRTP/src/tests/.cvsignore new file mode 100644 index 000000000..cfffd5f7d --- /dev/null +++ b/linphone/oRTP/src/tests/.cvsignore @@ -0,0 +1,15 @@ +Makefile +Makefile.in +.deps +.libs +*.lo +*.la +mrtprecv +mrtpsend +rtpmemtest +rtprecv +rtpsend +test_timer +tevmrtprecv +tevrtprecv +tevrtpsend diff --git a/linphone/oRTP/src/tests/Makefile.am b/linphone/oRTP/src/tests/Makefile.am new file mode 100644 index 000000000..a0ca2e3e0 --- /dev/null +++ b/linphone/oRTP/src/tests/Makefile.am @@ -0,0 +1,28 @@ +SUBDIRS=win_receiver win_sender + +noinst_PROGRAMS= rtpsend rtprecv mrtpsend mrtprecv test_timer rtpmemtest tevrtpsend tevrtprecv tevmrtprecv rtpsend_stupid + +rtpsend_SOURCES= rtpsend.c + +rtprecv_SOURCES= rtprecv.c + +mrtpsend_SOURCES= mrtpsend.c + +mrtprecv_SOURCES= mrtprecv.c + +rtpmemtest_SOURCES= rtpmemtest.c + +test_timer_SOURCES= test_timer.c + +tevrtpsend_SOURCES= tevrtpsend.c + +tevrtprecv_SOURCES= tevrtprecv.c + +tevmrtprecv_SOURCES= tevmrtprecv.c + +rtpsend_stupid_SOURCES=rtpsend_stupid.c + +AM_CFLAGS= -D_ORTP_SOURCE $(PTHREAD_CFLAGS) +AM_LDFLAGS= $(PTHREAD_LDFLAGS) +LDADD=$(top_builddir)/src/libortp.la $(SRTP_LIBS) +INCLUDES=-I$(top_srcdir)/include/ diff --git a/linphone/oRTP/src/tests/mrtprecv.c b/linphone/oRTP/src/tests/mrtprecv.c new file mode 100644 index 000000000..a5b9de280 --- /dev/null +++ b/linphone/oRTP/src/tests/mrtprecv.c @@ -0,0 +1,159 @@ +/* + The oRTP LinPhone RTP library intends to provide basics for a RTP stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* this program shows how to receive streams in paralel using the SessionSet api + and two threads only. */ + +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include + +#include +#include +#include +#endif + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: mrtprecv file_prefix local_port number_of_streams \n" + "Receives multiples rtp streams on local_port+2*k, k={0..number_of_streams}\n"; + +#define STREAMS_COUNT 1000 + +/* malloc'd in order to detect buffer overflows with efence */ +static uint8_t* recvbuf=0; + +int rtp2disk(RtpSession *session,uint32_t ts, int fd) +{ + int err,havemore=1; + while (havemore){ + err=rtp_session_recv_with_ts(session,recvbuf,160,ts,&havemore); + if (havemore) printf("warning: havemore=%i!\n",havemore); + if (err>0){ + rtp_session_set_data(session,(void*)1); + /* to indicate that (for the application) the stream has started, so we can start + recording on disk */ + } + if (session->user_data != NULL) { + size_t ret = write(fd,recvbuf,err); + assert( ret == err ); + } + } + return 0; +} + + +int main(int argc, char *argv[]) +{ + RtpSession *session[STREAMS_COUNT]; + int i; + int filefd[STREAMS_COUNT]; + int port; + uint32_t user_ts=0; + int channels; + SessionSet *set; + char *filename; + + if (argc<4){ + printf(help); + return -1; + } + + channels=atoi(argv[3]); + if (channels==0){ + printf(help); + return -1; + } + + ortp_init(); + ortp_scheduler_init(); + + port=atoi(argv[2]); + recvbuf=ortp_malloc(160); + + for (i=0;i +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#endif + + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: mrtpsend filename ip port nstreams [--packet-size size] [--ts-inc value]\n"; + +#define STREAMS_COUNT 1000 + + + +int main(int argc, char *argv[]) +{ + RtpSession *session[STREAMS_COUNT]; + unsigned char *buffer; + int packet_size=160; + int ts_inc=160; + int i; + FILE *infile; + char *ssrc; + int port; + uint32_t user_ts=0; + int channels; + SessionSet *set; + + if (argc<5){ + printf(help); + return -1; + } + + channels=atoi(argv[4]); + if (channels==0){ + printf(help); + return -1; + } + + /* look at command line options */ + for (i=5;i0) && (runcond) ) + { + int k; + //ortp_message("Sending packet."); + for (k=0;k +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#else +//#include +#endif + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: mrtprecv file_prefix local_port number_of_streams \n" + "Receives multiples rtp streams on local_port+2*k, k={0..number_of_streams}\n"; + +#define STREAMS_COUNT 1000 + +int rtp2disk(RtpSession *session,uint32_t ts, int fd) +{ + unsigned char buffer[160]; + int err,havemore=1; + while (havemore){ + err=rtp_session_recv_with_ts(session,buffer,160,ts,&havemore); + if (err>0){ + rtp_session_set_data(session,(void*)1); + /* to indicate that (for the application) the stream has started, so we can start + recording on disk */ + } + if (session->user_data != NULL) { + size_t ret = write(fd,buffer,err); + assert( ret == err ); + } + } + return 0; +} + + +int main(int argc, char *argv[]) +{ + RtpSession *session[STREAMS_COUNT]; + int i; + int filefd[STREAMS_COUNT]; + int port; + uint32_t user_ts=0; + int channels; + SessionSet *set; + char *filename; + + argc=4; + argv[1]="/tmp/output"; + argv[2]="8000"; + argv[3]="100"; + + if (argc<4){ + printf(help); + return -1; + } + + channels=atoi(argv[3]); + if (channels==0){ + printf(help); + return -1; + } + + ortp_init(); + ortp_scheduler_init(); + + port=atoi(argv[2]); + for (i=0;isetflags=%i\n",session[k]->setflags); + } + /* and then suspend the process by selecting() */ + session_set_select(set,NULL,NULL); + for (k=0;k +#include +#include +#ifndef _WIN32 +#include +#include +#include +#endif + +int cond=1; + +void stop_handler(int signum) +{ + cond=0; +} + +void ssrc_cb(RtpSession *session) +{ + printf("hey, the ssrc has changed !\n"); +} + +static char *help="usage: rtprecv filename loc_port [--format format] [--soundcard] [--noadapt] [--with-jitter ]\n"; + +#define MULAW 0 +#define ALAW 1 + +#if defined(__hpux) && HAVE_SYS_AUDIO_H + +#include + +int sound_init(int format) +{ + int fd; + fd=open("/dev/audio",O_WRONLY); + if (fd<0){ + perror("Can't open /dev/audio"); + return -1; + } + ioctl(fd,AUDIO_RESET,0); + ioctl(fd,AUDIO_SET_SAMPLE_RATE,8000); + ioctl(fd,AUDIO_SET_CHANNELS,1); + if (format==MULAW) + ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ULAW); + else ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ALAW); + return fd; +} +#else +int sound_init(int format) +{ + return -1; +} +#endif + +int main(int argc, char*argv[]) +{ + RtpSession *session; + unsigned char buffer[160]; + int err; + uint32_t ts=0; + int stream_received=0; + FILE *outfile; + int local_port; + int have_more; + int i; + int format=0; + int soundcard=0; + int sound_fd=0; + int jittcomp=40; + bool_t adapt=TRUE; + + /* init the lib */ + if (argc<3){ + printf(help); + return -1; + } + local_port=atoi(argv[2]); + if (local_port<=0) { + printf(help); + return -1; + } + for (i=3;i0) stream_received=1; + /* this is to avoid to write to disk some silence before the first RTP packet is returned*/ + if ((stream_received) && (err>0)) { + size_t ret = fwrite(buffer,1,err,outfile); + if (sound_fd>0) + ret = write(sound_fd,buffer,err); + } + } + ts+=160; + //ortp_message("Receiving packet."); + } + + rtp_session_destroy(session); + ortp_exit(); + + ortp_global_stats_display(); + + return 0; +} diff --git a/linphone/oRTP/src/tests/rtpsend.c b/linphone/oRTP/src/tests/rtpsend.c new file mode 100644 index 000000000..19935bd01 --- /dev/null +++ b/linphone/oRTP/src/tests/rtpsend.c @@ -0,0 +1,128 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#endif + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: rtpsend filename dest_ip4addr dest_port [ --with-clockslide ] [ --with-jitter ]\n"; + +int main(int argc, char *argv[]) +{ + RtpSession *session; + unsigned char buffer[160]; + int i; + FILE *infile; + char *ssrc; + uint32_t user_ts=0; + int clockslide=0; + int jitter=0; + if (argc<4){ + printf(help); + return -1; + } + for(i=4;i=argc) { + printf(help); + return -1; + } + clockslide=atoi(argv[i]); + ortp_message("Using clockslide of %i milisecond every 50 packets.",clockslide); + }else if (strcmp(argv[i],"--with-jitter")==0){ + ortp_message("Jitter will be added to outgoing stream."); + i++; + if (i>=argc) { + printf(help); + return -1; + } + jitter=atoi(argv[i]); + } + } + + ortp_init(); + ortp_scheduler_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR); + session=rtp_session_new(RTP_SESSION_SENDONLY); + + rtp_session_set_scheduling_mode(session,1); + rtp_session_set_blocking_mode(session,1); + rtp_session_set_connected_mode(session,TRUE); + rtp_session_set_remote_addr(session,argv[2],atoi(argv[3])); + rtp_session_set_payload_type(session,0); + + ssrc=getenv("SSRC"); + if (ssrc!=NULL) { + printf("using SSRC=%i.\n",atoi(ssrc)); + rtp_session_set_ssrc(session,atoi(ssrc)); + } + + #ifndef _WIN32 + infile=fopen(argv[1],"r"); + #else + infile=fopen(argv[1],"rb"); + #endif + + if (infile==NULL) { + perror("Cannot open file"); + return -1; + } + + signal(SIGINT,stophandler); + while( ((i=fread(buffer,1,160,infile))>0) && (runcond) ) + { + rtp_session_send_with_ts(session,buffer,i,user_ts); + user_ts+=160; + if (clockslide!=0 && user_ts%(160*50)==0){ + ortp_message("Clock sliding of %i miliseconds now",clockslide); + rtp_session_make_time_distorsion(session,clockslide); + } + /*this will simulate a burst of late packets */ + if (jitter && (user_ts%(8000)==0)) { + struct timespec pausetime, remtime; + ortp_message("Simulating late packets now (%i milliseconds)",jitter); + pausetime.tv_sec=jitter/1000; + pausetime.tv_nsec=(jitter%1000)*1000000; + while(nanosleep(&pausetime,&remtime)==-1 && errno==EINTR){ + pausetime=remtime; + } + } + } + + fclose(infile); + rtp_session_destroy(session); + ortp_exit(); + ortp_global_stats_display(); + + return 0; +} diff --git a/linphone/oRTP/src/tests/rtpsend_stupid.c b/linphone/oRTP/src/tests/rtpsend_stupid.c new file mode 100644 index 000000000..0758ceaee --- /dev/null +++ b/linphone/oRTP/src/tests/rtpsend_stupid.c @@ -0,0 +1,126 @@ + /* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#endif +/*defined in library, but not declared in public headers (this method is only useful for tests)*/ +extern int __rtp_session_sendm_with_ts(RtpSession *session, mblk_t *packet, uint32_t packet_ts, uint32_t send_ts); + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: rtpsend filename dest_ip4addr dest_port [ --with-clockslide ] [ --with-ptime ]\n"; + +int main(int argc, char *argv[]) +{ + RtpSession *session; + unsigned char buffer[160]; + int i; + FILE *infile; + char *ssrc; + uint32_t packet_ts=0,send_ts=0; + uint32_t send_ts_inc=160; + int clockslide=0; + int jitter=0; + if (argc<4){ + printf(help); + return -1; + } + for(i=4;i=argc) { + printf(help); + return -1; + } + clockslide=atoi(argv[i]); + ortp_message("Using clockslide of %i milisecond every 50 packets.",clockslide); + }else if (strcmp(argv[i],"--with-ptime")==0){ + ortp_message("Ptime related jitter will be added to outgoing stream."); + i++; + if (i>=argc) { + printf(help); + return -1; + } + jitter=atoi(argv[i]); + send_ts_inc=jitter*8; + } + } + + ortp_init(); + ortp_scheduler_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR); + session=rtp_session_new(RTP_SESSION_SENDONLY); + + rtp_session_set_scheduling_mode(session,1); + rtp_session_set_blocking_mode(session,1); + rtp_session_set_connected_mode(session,TRUE); + rtp_session_set_remote_addr(session,argv[2],atoi(argv[3])); + rtp_session_set_payload_type(session,0); + + ssrc=getenv("SSRC"); + if (ssrc!=NULL) { + printf("using SSRC=%i.\n",atoi(ssrc)); + rtp_session_set_ssrc(session,atoi(ssrc)); + } + + #ifndef _WIN32 + infile=fopen(argv[1],"r"); + #else + infile=fopen(argv[1],"rb"); + #endif + + if (infile==NULL) { + perror("Cannot open file"); + return -1; + } + + signal(SIGINT,stophandler); + while( ((i=fread(buffer,1,160,infile))>0) && (runcond) ) + { + mblk_t *m=rtp_session_create_packet(session,RTP_FIXED_HEADER_SIZE,buffer,i); + __rtp_session_sendm_with_ts(session,m,packet_ts,send_ts); + packet_ts+=160; + if ((send_ts+send_ts_inc)<=packet_ts){ + send_ts+=send_ts_inc; + } + if (clockslide!=0 && send_ts%(160*50)==0){ + ortp_message("Clock sliding of %i miliseconds now",clockslide); + rtp_session_make_time_distorsion(session,clockslide); + } + } + + fclose(infile); + rtp_session_destroy(session); + ortp_exit(); + ortp_global_stats_display(); + + return 0; +} diff --git a/linphone/oRTP/src/tests/test_timer.c b/linphone/oRTP/src/tests/test_timer.c new file mode 100644 index 000000000..48f4d0da2 --- /dev/null +++ b/linphone/oRTP/src/tests/test_timer.c @@ -0,0 +1,43 @@ + /* + The oRTP LinPhone RTP library intends to provide basics for a RTP stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "../rtptimer.h" +#include + +int main(int argc, char *argv[]) +{ + RtpTimer *timer=&posix_timer; + int i; + struct timeval interval; + + interval.tv_sec=0; + interval.tv_usec=500000; + + rtp_timer_set_interval(timer,&interval); + + timer->timer_init(); + for (i=0;i<10;i++) + { + printf("doing something...\n"); + timer->timer_do(); + } + timer->timer_uninit(); + return 0; +} diff --git a/linphone/oRTP/src/tests/tevmrtprecv.c b/linphone/oRTP/src/tests/tevmrtprecv.c new file mode 100644 index 000000000..b306d2057 --- /dev/null +++ b/linphone/oRTP/src/tests/tevmrtprecv.c @@ -0,0 +1,175 @@ + /* + The oRTP LinPhone RTP library intends to provide basics for a RTP stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* this program shows how to receive streams in paralel using the SessionSet api + and two threads only. */ + +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include + +#else +//#include +#endif + +#include + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + +static int *p_channel_id; + +int dtmf_count=0; + +static char *help="usage: tevmrtprecv file_prefix local_port number_of_streams \n" + "Receives multiples rtp streams with telephone events on local_port+2*k, k={0..number_of_streams}\n"; + +#define STREAMS_COUNT 1000 + + +void recv_tev_cb(RtpSession *session,int type,long user_data) +{ + //printf("Receiving telephony event:%i\n",type); + if (type<16) printf("This is dtmf %c on channel %d\n",dtmf_tab[type],*(int *)user_data); + dtmf_count++; +} + +int rtp2disk(RtpSession *session,uint32_t ts, int fd) +{ + unsigned char buffer[160]; + int err,havemore=1; + while (havemore){ + err=rtp_session_recv_with_ts(session,buffer,160,ts,&havemore); + if (err>0){ + rtp_session_set_data(session,(void*)1); + /* to indicate that (for the application) the stream has started, so we can start + recording on disk */ + } + if (session->user_data != NULL) { + size_t ret = write(fd,buffer,err); + assert( ret == err ); + } + } + return 0; +} + + +int main(int argc, char *argv[]) +{ + RtpSession *session[STREAMS_COUNT]; + int i; + int filefd[STREAMS_COUNT]; + int port; + uint32_t user_ts=0; + int channels; + SessionSet *set; + char *filename; + + if (argc<4){ + printf(help); + return -1; + } + + channels=atoi(argv[3]); + if (channels==0){ + printf(help); + return -1; + } + + ortp_init(); + ortp_scheduler_init(); + + /* set the telephony event payload type to 96 in the av profile.*/ + rtp_profile_set_payload(&av_profile,96,&payload_type_telephone_event); + + port=atoi(argv[2]); + p_channel_id = (int *)ortp_malloc(channels*sizeof(int)); + for (i=0;i +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include +#endif +#include + +int runcond=1; + +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: test_tevrecv filename loc_port\n"; + +int dtmf_count=0; + +void recv_tev_cb(RtpSession *session,int type,long user_data) +{ + printf("Receiving telephony event:%i\n",type); + if (type<16) printf("This is dtmf %c\n",dtmf_tab[type]); + dtmf_count++; +} + +int main(int argc, char *argv[]) +{ + RtpSession *session; + unsigned char buffer[160]; + int err; + FILE *outfile; + uint32_t ts=0; + int have_more; + + if (argc<3){ + printf(help); + return -1; + } + + ortp_init(); + ortp_scheduler_init(); + + /* set the telephony event payload type to 96 in the av profile.*/ + rtp_profile_set_payload(&av_profile,96,&payload_type_telephone_event); + + session=rtp_session_new(RTP_SESSION_RECVONLY); + + rtp_session_set_scheduling_mode(session,1); + rtp_session_set_blocking_mode(session,1); + rtp_session_set_local_addr(session,"0.0.0.0",atoi(argv[2])); + rtp_session_set_payload_type(session,0); + + /* register for telephony events */ + rtp_session_signal_connect(session,"telephone-event",(RtpCallback)recv_tev_cb,0); + + outfile=fopen(argv[1],"wb"); + if (outfile==NULL) { + perror("Cannot open file"); + return -1; + } + signal(SIGINT,stophandler); + while(runcond) + { + have_more=1; + while (have_more){ + err=rtp_session_recv_with_ts(session,buffer,160,ts,&have_more); + if (err>0) { + size_t ret = fwrite(buffer,1,err,outfile); + assert( ret == err ); + } + } + ts+=160; + //ortp_message("Receiving packet."); + } + fclose(outfile); + rtp_session_destroy(session); + ortp_exit(); + ortp_global_stats_display(); + printf("Total dtmf events received: %i\n",dtmf_count); + return 0; +} diff --git a/linphone/oRTP/src/tests/tevrtpsend.c b/linphone/oRTP/src/tests/tevrtpsend.c new file mode 100644 index 000000000..c064f6c64 --- /dev/null +++ b/linphone/oRTP/src/tests/tevrtpsend.c @@ -0,0 +1,99 @@ +/* + The oRTP LinPhone RTP library intends to provide basics for a RTP stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include +#endif +#include + +int runcond=1; + +void stophandler(int signum) +{ + runcond=0; +} + +static char *help="usage: test_tevsend filename dest_ip4addr dest_port\n"; + +int main(int argc, char *argv[]) +{ + RtpSession *session; + unsigned char buffer[160]; + int i; + FILE *infile; + char *ssrc; + uint32_t user_ts=0; + int tel=0; + + if (argc<4){ + printf(help); + return -1; + } + + ortp_init(); + ortp_scheduler_init(); + + /* set the telephony event payload type to 96 in the av profile.*/ + rtp_profile_set_payload(&av_profile,96,&payload_type_telephone_event); + + session=rtp_session_new(RTP_SESSION_SENDONLY); + + rtp_session_set_scheduling_mode(session,1); + rtp_session_set_blocking_mode(session,1); + rtp_session_set_remote_addr(session,argv[2],atoi(argv[3])); + rtp_session_set_send_payload_type(session,0); + + ssrc=getenv("SSRC"); + if (ssrc!=NULL) { + printf("using SSRC=%i.\n",atoi(ssrc)); + rtp_session_set_ssrc(session,atoi(ssrc)); + } + + infile=fopen(argv[1],"rb"); + if (infile==NULL) { + perror("Cannot open file"); + return -1; + } + signal(SIGINT,stophandler); + while( ((i=fread(buffer,1,160,infile))>0) && (runcond) ) + { + //ortp_message("Sending packet."); + rtp_session_send_with_ts(session,buffer,i,user_ts); + user_ts+=160; + tel++; + if (tel==50){ + tel=0; + ortp_message("Sending telephony event packet."); + rtp_session_send_dtmf(session,'*',user_ts); + user_ts+=160+160+160; /* the duration of the dtmf */ + } + } + fclose(infile); + rtp_session_destroy(session); + ortp_exit(); + ortp_global_stats_display(); + return 0; +} diff --git a/linphone/oRTP/src/tests/win_receiver/.cvsignore b/linphone/oRTP/src/tests/win_receiver/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/oRTP/src/tests/win_receiver/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/oRTP/src/tests/win_receiver/Makefile.am b/linphone/oRTP/src/tests/win_receiver/Makefile.am new file mode 100644 index 000000000..e7e00556f --- /dev/null +++ b/linphone/oRTP/src/tests/win_receiver/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=RTPReceiver.cpp RTPReceiver.vcproj + diff --git a/linphone/oRTP/src/tests/win_receiver/RTPReceiver.cpp b/linphone/oRTP/src/tests/win_receiver/RTPReceiver.cpp new file mode 100644 index 000000000..8701508f8 --- /dev/null +++ b/linphone/oRTP/src/tests/win_receiver/RTPReceiver.cpp @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include + +#define STREAMS_COUNT 1000 + +BOOL m_bExit = FALSE; + +static char *help="usage: mrtprecv file_prefix local_port number_of_streams \n" + "Receives multiples rtp streams on local_port+2*k, k={0..number_of_streams}\n"; + + +void ProductVersion() +{ + char strBuffer[255]; + + printf("====================================\n"); + printf("Author : Simon Morlat =\n"); + printf("Porting : Yann STEPHAN =\n"); + printf("====================================\n"); + + memset(&strBuffer, 0x0, sizeof(strBuffer)); + + sprintf((char *) &strBuffer, "= RTPReceiver V1.0 - Date : %s - %s\n", __DATE__, __TIME__); + printf(strBuffer); + + printf("====================================\n"); +} + +BOOL ctrlHandlerFunction(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + // Handle the CTRL+C signal. + // CTRL+CLOSE: confirm that the user wants to exit. + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + m_bExit = TRUE; + return TRUE; + + default: + return FALSE; + } +} + +int rtp2disk(RtpSession *session,uint32_t ts, FILE * fd) +{ + char buffer[160]; + int err,havemore=1; + + while (havemore) + { + err=rtp_session_recv_with_ts(session,buffer,160,ts,&havemore); + + if (havemore) + printf("==> Warning: havemore=1!\n"); + + if (err>0) + { + rtp_session_set_data(session,(void*)1); + /* to indicate that (for the application) the stream has started, so we can start + recording on disk */ + } + + if (session->user_data != NULL) + { + fwrite(&buffer,1,160, fd); + } + } + return 0; +} + +int GetSystemInformation() +{ + SYSTEM_INFO SystemInfo; + + GetSystemInfo(&SystemInfo); + + return SystemInfo.dwNumberOfProcessors; +} + +int __cdecl main(int argc, char *argv[]) +{ + RtpSession * session[STREAMS_COUNT]; + FILE * filefd[STREAMS_COUNT]; + SessionSet * set; + + uint32_t user_ts = 0; + + int port = 0; + int channels = 0; + int i = 0; + int nCPUCount = 0; + int nSchedulerCPU = 2; + + char strFilename[MAX_PATH]; + + ProductVersion(); + + if (argc<4) + { + printf(help); + return -1; + } + + channels=atoi(argv[3]); + if (channels==0){ + printf(help); + return -1; + } + + // Now it's time to use the power of multiple CPUs + nCPUCount = GetSystemInformation(); + + printf("==> # of CPU detected : %d\n", nCPUCount); + + ortp_init(); + ortp_scheduler_init(); + + if (nCPUCount > 1) + { + if (nCPUCount > 2) + { + nSchedulerCPU = 3; + } + +/* if (ortp_bind_scheduler_to_cpu(nSchedulerCPU) != -1) + { + printf("==> Scheduler has been binded to CPU %d\n", nSchedulerCPU); + } + else + { + printf("==> Scheduler still binded to CPU 1\n"); + } +*/ + } + + port=atoi(argv[2]); + + for (i=0;i Cannot handle the CTRL-C...\n"); + } + + /* create a set */ + set=session_set_new(); + printf("==> RTP Receiver started\n"); + + while(m_bExit == FALSE) + { + int k; + + for (k=0;k Warning: session_set_select() is returning 0...\n"); + } + + for (k=0;k Session_set_is_set %d\n", k); + } + else + { + //printf("warning: session %i is not set !\n",k); + } + } + user_ts+=160; + } + + printf("==> Exiting\n"); + + for (i=0;i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/oRTP/src/tests/win_receiver/ortpreceiver.dev b/linphone/oRTP/src/tests/win_receiver/ortpreceiver.dev new file mode 100755 index 000000000..aa13ec819 --- /dev/null +++ b/linphone/oRTP/src/tests/win_receiver/ortpreceiver.dev @@ -0,0 +1,59 @@ +[Project] +FileName=ortpreceiver.dev +Name=ortpreceiver +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes=../../../include +Libs=../../../build/win32native/ +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DORTP_INET6_@@_ +CppCompiler= +Linker=-lortp_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=ortpreceiver.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=RTPReceiver.cpp +CompileCpp=0 +Folder=ortpreceiver +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/linphone/oRTP/src/tests/win_sender/.cvsignore b/linphone/oRTP/src/tests/win_sender/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/oRTP/src/tests/win_sender/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/oRTP/src/tests/win_sender/Makefile.am b/linphone/oRTP/src/tests/win_sender/Makefile.am new file mode 100644 index 000000000..3af05d969 --- /dev/null +++ b/linphone/oRTP/src/tests/win_sender/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST=RTPSender.cpp RTPSender.vcproj + diff --git a/linphone/oRTP/src/tests/win_sender/RTPSender.cpp b/linphone/oRTP/src/tests/win_sender/RTPSender.cpp new file mode 100644 index 000000000..95630b079 --- /dev/null +++ b/linphone/oRTP/src/tests/win_sender/RTPSender.cpp @@ -0,0 +1,265 @@ +#include +#include + +#define STREAMS_COUNT 1000 + +enum +{ + EVENT_STOP, + EVENT_RTP, + EVENT_COUNT // Always last +}; + + +RtpSession * m_Session[STREAMS_COUNT]; + +int m_nPacket_Size = 160; +int m_nTimestamp_Inc = 160; + +char * m_pBuffer = NULL; +char * m_SSRC = NULL; + +int m_nChannels = 0; +int m_nPort = 0; + +HANDLE m_hEvents[EVENT_COUNT]; + +BOOL m_bExit = FALSE; + +static char *help="usage: mrtpsend filename ip port nstreams [--packet-size size] [--ts-inc value]\n"; + +BOOL ctrlHandlerFunction(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + // Handle the CTRL+C signal. + // CTRL+CLOSE: confirm that the user wants to exit. + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + m_bExit = TRUE; + SetEvent(m_hEvents[EVENT_STOP]); + return TRUE; + + default: + return FALSE; + } +} + +int GetCommandArguments(int argc, char *argv[]) +{ + int nCounter; + + // Check the number of arguments + if (argc<5) + { + printf(help); + return -1; + } + + m_nChannels = atoi(argv[4]); + + // Get the number of channels + if (m_nChannels == 0) + { + printf(help); + return -1; + } + + /* look at command line options */ + for (nCounter=5; nCounter Sorry dude...\n"); + Sleep(1000); + return -1; + } + + printf("==> Starting the RTP Sender test\n"); + + + // =============== INSTALL THE CONTROL HANDLER =============== + if (SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ctrlHandlerFunction, TRUE) == 0) + { + printf("==> Cannot handle the CTRL-C...\n"); + } + + + printf("==> Timestamp increment will be %i\n" , m_nTimestamp_Inc); + printf("==> Packet size will be %i\n" , m_nPacket_Size); + + m_pBuffer = (char *) ortp_malloc(m_nPacket_Size); + + ortp_init(); + ortp_scheduler_init(); + printf("==> Scheduler initialized\n"); + + m_SSRC = getenv("SSRC"); + m_nPort = atoi(argv[3]); + + for (nCounter=0; nCounter < m_nChannels; nCounter++) + { + //printf("==> Channel [#%d]\n", nCounter); + + m_Session[nCounter] = rtp_session_new(RTP_SESSION_SENDONLY); + + rtp_session_set_scheduling_mode(m_Session[nCounter],1); + rtp_session_set_blocking_mode(m_Session[nCounter],0); + rtp_session_set_remote_addr(m_Session[nCounter],argv[2], m_nPort); + rtp_session_set_send_payload_type(m_Session[nCounter],0); + + if (m_SSRC != NULL) + { + rtp_session_set_ssrc(m_Session[nCounter],atoi(m_SSRC)); + } + + m_nPort+=2; + } + + infile=fopen(argv[1],"rb"); + + if (infile==NULL) + { + printf("==> Cannot open file !!!!"); + Sleep(1000); + return -1; + } + +// printf("==> Open file\n"); + + /* Create a set */ + pSessionSet = session_set_new(); +// printf("==> Session set\n"); + + while( ((nCounter= (int) fread(m_pBuffer,1,m_nPacket_Size,infile))>0) && (m_bExit == FALSE) ) + { + int k; + //g_message("Sending packet."); + for (k=0;k Session set set %d\n", k); + } + /* and then suspend the process by selecting() */ + session_set_select(NULL,pSessionSet,NULL); + //printf("==> Session set select\n"); + + for (k=0;k Session set is set %d\n", k); + rtp_session_send_with_ts(m_Session[k],m_pBuffer,nCounter,m_nUser_Timestamp); + //g_message("packet sended !"); + } + } + m_nUser_Timestamp+=m_nTimestamp_Inc; + } + + fclose(infile); + printf("==> Close file\n"); + + + + for(nCounter=0;nCounter Remove the CTRL-C handler...\n"); + SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ctrlHandlerFunction, FALSE); + + // Wait for an input key + printf("Waiting for exit : "); + + for (nCounter = 0; nCounter < 4*5; nCounter++) + { + printf("."); + Sleep(250); + } + + return 0; +} + diff --git a/linphone/oRTP/src/tests/win_sender/RTPSender.vcproj b/linphone/oRTP/src/tests/win_sender/RTPSender.vcproj new file mode 100644 index 000000000..32b054186 --- /dev/null +++ b/linphone/oRTP/src/tests/win_sender/RTPSender.vcproj @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphone/oRTP/src/tests/win_sender/ortpsender.dev b/linphone/oRTP/src/tests/win_sender/ortpsender.dev new file mode 100755 index 000000000..a7310659a --- /dev/null +++ b/linphone/oRTP/src/tests/win_sender/ortpsender.dev @@ -0,0 +1,59 @@ +[Project] +FileName=ortpsender.dev +Name=ortpsender +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes=../../../include +Libs=../../../build/win32native +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DORTP_INET6_@@_ +CppCompiler= +Linker=-lortp_@@_ +IsCpp=0 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=ortpsender.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=RTPSender.cpp +CompileCpp=0 +Folder=ortpsender +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/linphone/oRTP/src/utils.c b/linphone/oRTP/src/utils.c new file mode 100644 index 000000000..436e2a2c2 --- /dev/null +++ b/linphone/oRTP/src/utils.c @@ -0,0 +1,86 @@ +/*************************************************************************** + * utils.c + * + * Wed Feb 23 14:15:36 2005 + * Copyright 2005 Simon Morlat + * Email simon.morlat@linphone.org + ****************************************************************************/ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ortp/port.h" +#include "utils.h" + +OList *o_list_new(void *data){ + OList *new_elem=(OList*)ortp_new0(OList,1); + new_elem->data=data; + return new_elem; +} + +OList * o_list_append(OList *elem, void * data){ + OList *new_elem=o_list_new(data); + OList *it=elem; + if (elem==NULL) return new_elem; + while (it->next!=NULL) it=o_list_next(it); + it->next=new_elem; + new_elem->prev=it; + return elem; +} + +OList * o_list_free(OList *list){ + OList *elem = list; + OList *tmp; + return_val_if_fail(list, list); + while(elem->next!=NULL) { + tmp = elem; + elem = elem->next; + ortp_free(tmp); + } + ortp_free(elem); + return NULL; +} + +OList *o_list_remove_link(OList *list, OList *elem){ + OList *ret; + if (elem==list){ + ret=elem->next; + elem->prev=NULL; + elem->next=NULL; + if (ret!=NULL) ret->prev=NULL; + ortp_free(elem); + return ret; + } + elem->prev->next=elem->next; + if (elem->next!=NULL) elem->next->prev=elem->prev; + elem->next=NULL; + elem->prev=NULL; + ortp_free(elem); + return list; +} + +OList * o_list_remove(OList *list, void *data){ + OList *it; + for(it=list;it!=NULL;it=it->next){ + if (it->data==data){ + return o_list_remove_link(list,it); + } + } + return list; +} + diff --git a/linphone/oRTP/src/utils.h b/linphone/oRTP/src/utils.h new file mode 100644 index 000000000..0a50fcf0f --- /dev/null +++ b/linphone/oRTP/src/utils.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * utils.h + * + * Wed Feb 23 14:15:36 2005 + * Copyright 2005 Simon Morlat + * Email simon.morlat@linphone.org + ****************************************************************************/ +/* + The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. + Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef UTILS_H +#define UTILS_H + +#include "ortp/event.h" + +struct _OList { + struct _OList *next; + struct _OList *prev; + void *data; +}; + +typedef struct _OList OList; + + +#define o_list_next(elem) ((elem)->next) + +OList * o_list_append(OList *elem, void * data); +OList * o_list_remove(OList *list, void *data); +OList * o_list_free(OList *elem); + +#ifndef MIN +#define MIN(a,b) (((a)>(b)) ? (b) : (a)) +#endif +#ifndef MAX +#define MAX(a,b) (((a)>(b)) ? (a) : (b)) +#endif + +#define return_if_fail(expr) if (!(expr)) {printf("%s:%i- assertion"#expr "failed\n",__FILE__,__LINE__); return;} +#define return_val_if_fail(expr,ret) if (!(expr)) {printf("%s:%i- assertion" #expr "failed\n",__FILE__,__LINE__); return (ret);} + + +#define INT_TO_POINTER(truc) ((long)(long)(truc)) +#define POINTER_TO_INT(truc) ((int)(long)(truc)) + +typedef struct _dwsplit_t{ +#ifdef ORTP_BIGENDIAN + uint16_t hi; + uint16_t lo; +#else + uint16_t lo; + uint16_t hi; +#endif +} dwsplit_t; + +typedef union{ + dwsplit_t split; + uint32_t one; +} poly32_t; + +#ifdef ORTP_BIGENDIAN +#define hton24(x) (x) +#else +#define hton24(x) ((( (x) & 0x00ff0000) >>16) | (( (x) & 0x000000ff) <<16) | ( (x) & 0x0000ff00) ) +#endif +#define ntoh24(x) hton24(x) + +#if defined(WIN32) || defined(_WIN32_WCE) +#define is_would_block_error(errnum) (errnum==WSAEWOULDBLOCK) +#else +#define is_would_block_error(errnum) (errnum==EWOULDBLOCK || errnum==EAGAIN) +#endif + +void ortp_ev_queue_put(OrtpEvQueue *q, OrtpEvent *ev); + +#endif diff --git a/linphone/pixmaps/.cvsignore b/linphone/pixmaps/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/linphone/pixmaps/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/linphone/pixmaps/Makefile.am b/linphone/pixmaps/Makefile.am new file mode 100644 index 000000000..6968c4ee9 --- /dev/null +++ b/linphone/pixmaps/Makefile.am @@ -0,0 +1,11 @@ + + +pixmapdir=$(datadir)/pixmaps/linphone + +pixmap_DATA= linphone2.png linphone2.xpm linphone.png \ +sip-away.png sip-bifm.png \ +sip-busy.png sip-closed.png \ +sip-online.png sip-otl.png \ +sip-otp.png sip-wfa.png + +EXTRA_DIST=$(pixmap_DATA) diff --git a/linphone/pixmaps/linphone.png b/linphone/pixmaps/linphone.png new file mode 100644 index 000000000..06cf18315 Binary files /dev/null and b/linphone/pixmaps/linphone.png differ diff --git a/linphone/pixmaps/linphone2.png b/linphone/pixmaps/linphone2.png new file mode 100644 index 000000000..d1bf1ab63 Binary files /dev/null and b/linphone/pixmaps/linphone2.png differ diff --git a/linphone/pixmaps/linphone2.xpm b/linphone/pixmaps/linphone2.xpm new file mode 100644 index 000000000..717f8c42f --- /dev/null +++ b/linphone/pixmaps/linphone2.xpm @@ -0,0 +1,883 @@ +/* XPM */ +static char * linphone2_xpm[] = { +"50 45 835 2", +" c None", +". c #211F1D", +"+ c #53514E", +"@ c #5F5D59", +"# c #7D7C78", +"$ c #605F5C", +"% c #94928C", +"& c #95938D", +"* c #7B7A77", +"= c #605E5C", +"- c #353432", +"; c #585754", +"> c #84827D", +", c #B9B6B0", +"' c #D9D5CE", +") c #DFDBD3", +"! c #EAE6DE", +"~ c #EFEBE2", +"{ c #EEEAE1", +"] c #EFEBE3", +"^ c #EEEAE2", +"/ c #75726D", +"( c #5E5C58", +"_ c #7D7B77", +": c #BAB6AF", +"< c #E5E1D8", +"[ c #DAD7CF", +"} c #C8C4BD", +"| c #898782", +"1 c #949089", +"2 c #938F88", +"3 c #5B5854", +"4 c #45433F", +"5 c #4D4943", +"6 c #5F5C56", +"7 c #A5A199", +"8 c #DCD5C5", +"9 c #6F6B63", +"0 c #42413F", +"a c #A19E97", +"b c #DAD6CE", +"c c #EDE9E1", +"d c #D4D0C9", +"e c #96928C", +"f c #63605B", +"g c #827C73", +"h c #6F6961", +"i c #90877A", +"j c #8E8578", +"k c #B4A999", +"l c #B9AD9D", +"m c #C0B5A3", +"n c #BCB1A0", +"o c #858075", +"p c #C3BCAE", +"q c #EAE5DB", +"r c #E0D9C9", +"s c #C5BDAE", +"t c #20201E", +"u c #8D8B86", +"v c #CAC7C1", +"w c #D2CEC6", +"x c #918F89", +"y c #5D5A56", +"z c #A0998F", +"A c #827B6F", +"B c #C0B4A2", +"C c #C2B7A5", +"D c #C1B6A4", +"E c #8A8174", +"F c #94918B", +"G c #C7C3BB", +"H c #AFAAA1", +"I c #938B7E", +"J c #646058", +"K c #D8D1C3", +"L c #ECE7DE", +"M c #EBE7DD", +"N c #E4DED0", +"O c #DED6C5", +"P c #57544D", +"Q c #202020", +"R c #7E7C77", +"S c #DFDCD4", +"T c #F0ECE4", +"U c #EDE9E0", +"V c #ECE8E1", +"W c #B6B2AB", +"X c #77736E", +"Y c #767067", +"Z c #A3998B", +"` c #BCB09F", +" . c #C3B7A6", +".. c #BFB3A1", +"+. c #C3B8A7", +"@. c #BFB4A2", +"#. c #BDB2A1", +"$. c #3E3B35", +"%. c #BBB4A6", +"&. c #A7A39C", +"*. c #ECE9E1", +"=. c #77736A", +"-. c #E7E1D5", +";. c #E3DDCE", +">. c #8F897F", +",. c #22201E", +"'. c #91908C", +"). c #EFECE3", +"!. c #EBE7DE", +"~. c #878581", +"{. c #5B574F", +"]. c #7F786C", +"^. c #8D867A", +"/. c #9C9994", +"(. c #98958F", +"_. c #837B6E", +":. c #C4B9A7", +"<. c #958B7E", +"[. c #736D62", +"}. c #4E4942", +"|. c #4C4842", +"1. c #383632", +"2. c #99968F", +"3. c #ECE8DE", +"4. c #7C7972", +"5. c #CCC6BB", +"6. c #E9E4D9", +"7. c #EDE8DF", +"8. c #E1D9C9", +"9. c #BFB8A9", +"0. c #1A1A1A", +"a. c #C3BFB8", +"b. c #CFCCC4", +"c. c #85827C", +"d. c #56514A", +"e. c #A69C8D", +"f. c #BFB3A2", +"g. c #C2B7A6", +"h. c #B4AA9A", +"i. c #757168", +"j. c #706D68", +"k. c #918E88", +"l. c #464441", +"m. c #97948E", +"n. c #C9C6BF", +"o. c #8C8A85", +"p. c #8E897F", +"q. c #999488", +"r. c #817E77", +"s. c #C1BEB7", +"t. c #807D75", +"u. c #8A8377", +"v. c #6E6A63", +"w. c #A8A49C", +"x. c #EAE4D9", +"y. c #E4DDCF", +"z. c #D8D0C0", +"A. c #AFA99C", +"B. c #848076", +"C. c #BFBBB4", +"D. c #B1AEA8", +"E. c #47443F", +"F. c #5C5851", +"G. c #686259", +"H. c #B0A595", +"I. c #B7AC9B", +"J. c #817A6F", +"K. c #7E7A70", +"L. c #AEA99D", +"M. c #9A9791", +"N. c #EEE9E1", +"O. c #E6E2DA", +"P. c #CCC8BF", +"Q. c #E3DCCE", +"R. c #86827A", +"S. c #C6C3BC", +"T. c #7C7974", +"U. c #4A4642", +"V. c #6E685F", +"W. c #89837A", +"X. c #7B7873", +"Y. c #9A9892", +"Z. c #827D73", +"`. c #56534C", +" + c #6A675E", +".+ c #E2DBCC", +"++ c #EDE9DF", +"@+ c #DED8CC", +"#+ c #DDD5C4", +"$+ c #C4BDAE", +"%+ c #6F6B62", +"&+ c #312F2B", +"*+ c #6D6960", +"=+ c #A19B8F", +"-+ c #E5E1DA", +";+ c #7F7D79", +">+ c #CFCBC3", +",+ c #ACA9A2", +"'+ c #B6B1A8", +")+ c #B4B0AA", +"!+ c #827F7A", +"~+ c #444340", +"{+ c #262524", +"]+ c #C1BEB8", +"^+ c #9A968D", +"/+ c #242322", +"(+ c #CEC7B7", +"_+ c #DFD8C7", +":+ c #E6E0D3", +"<+ c #747067", +"[+ c #D3CCBC", +"}+ c #857F74", +"|+ c #595856", +"1+ c #CCC8C2", +"2+ c #D4D1C9", +"3+ c #ECE8DF", +"4+ c #CFCBC4", +"5+ c #93918C", +"6+ c #2F2E2C", +"7+ c #312F2C", +"8+ c #969185", +"9+ c #BAB3A5", +"0+ c #B1AB9D", +"a+ c #363532", +"b+ c #E2DED5", +"c+ c #676360", +"d+ c #4C4B4A", +"e+ c #767471", +"f+ c #75736D", +"g+ c #5B5956", +"h+ c #928D81", +"i+ c #E5DFD2", +"j+ c #EEE9E0", +"k+ c #EBE6DB", +"l+ c #C0B9AB", +"m+ c #A7A195", +"n+ c #8D887E", +"o+ c #C4BCAD", +"p+ c #BCB8B1", +"q+ c #D5D1C9", +"r+ c #7A746D", +"s+ c #AEABA4", +"t+ c #B2AFA8", +"u+ c #98948D", +"v+ c #7D7A76", +"w+ c #69655D", +"x+ c #9B9589", +"y+ c #A9A396", +"z+ c #A7A49F", +"A+ c #D8D2C9", +"B+ c #948F83", +"C+ c #454340", +"D+ c #D7D3CC", +"E+ c #63615E", +"F+ c #141414", +"G+ c #000000", +"H+ c #53504A", +"I+ c #EBE7DC", +"J+ c #E4DDD0", +"K+ c #898479", +"L+ c #ADA79A", +"M+ c #CBC3B4", +"N+ c #89847A", +"O+ c #CDC6B6", +"P+ c #AAA59C", +"Q+ c #9F9D98", +"R+ c #E6E2D9", +"S+ c #AFACA7", +"T+ c #615F5C", +"U+ c #201F1D", +"V+ c #66625B", +"W+ c #AEA89A", +"X+ c #AEA89B", +"Y+ c #B7B0A2", +"Z+ c #070707", +"`+ c #E0DED9", +" @ c #CFC7B8", +".@ c #6B6863", +"+@ c #63625E", +"@@ c #DBD3C3", +"#@ c #534D46", +"$@ c #807E7B", +"%@ c #DDD9D1", +"&@ c #36322E", +"*@ c #4B4A49", +"=@ c #6E6C67", +"-@ c #E5DED1", +";@ c #E9E4D8", +">@ c #EFEAE2", +",@ c #E2DCD0", +"'@ c #8F8A7F", +")@ c #999387", +"!@ c #4E4B45", +"~@ c #6B665E", +"{@ c #47433D", +"]@ c #D4CDC0", +"^@ c #E8E3DA", +"/@ c #1F1E1E", +"(@ c #65615A", +"_@ c #ADA699", +":@ c #949494", +"<@ c #BEBEBC", +"[@ c #DAD2C2", +"}@ c #7F7B74", +"|@ c #4D4D4D", +"1@ c #959084", +"2@ c #DAD5C9", +"3@ c #B9B1A2", +"4@ c #3C3934", +"5@ c #989693", +"6@ c #B1ADA5", +"7@ c #76746F", +"8@ c #4C4A44", +"9@ c #DCD4C3", +"0@ c #E9E3D8", +"a@ c #DCD8CE", +"b@ c #A6A49E", +"c@ c #9C9890", +"d@ c #7B776D", +"e@ c #55534E", +"f@ c #B5B3AD", +"g@ c #474440", +"h@ c #D0C9B9", +"i@ c #E7E2D7", +"j@ c #65635D", +"k@ c #4F4E4C", +"l@ c #B7B1A3", +"m@ c #B7B3A9", +"n@ c #96948E", +"o@ c #BCBBBB", +"p@ c #BCB6A9", +"q@ c #ABA6A1", +"r@ c #8E8C87", +"s@ c #161514", +"t@ c #545350", +"u@ c #B9B1A1", +"v@ c #958F84", +"w@ c #8C867B", +"x@ c #81796E", +"y@ c #BFB4A3", +"z@ c #C6BBAA", +"A@ c #5E5B53", +"B@ c #96938D", +"C@ c #696762", +"D@ c #DFD7C7", +"E@ c #C6C2B9", +"F@ c #817C72", +"G@ c #B3AC9F", +"H@ c #B5AFA4", +"I@ c #6C6964", +"J@ c #DFD8C9", +"K@ c #9C9C9B", +"L@ c #716E6A", +"M@ c #B8B1A3", +"N@ c #2A2926", +"O@ c #625F58", +"P@ c #E0D8C9", +"Q@ c #C1BAAB", +"R@ c #252321", +"S@ c #E1DDD5", +"T@ c #7B7977", +"U@ c #625E57", +"V@ c #322F2A", +"W@ c #C4B9A8", +"X@ c #D1C7B6", +"Y@ c #C1B5A4", +"Z@ c #C8BEAC", +"`@ c #9A9387", +" # c #2D2C28", +".# c #595752", +"+# c #A29D94", +"@# c #D5CEBD", +"## c #CBC4B4", +"$# c #DBD3C2", +"%# c #A09C94", +"&# c #C1C1C1", +"*# c #95938E", +"=# c #7F7A70", +"-# c #8B867C", +";# c #D6D0C4", +"># c #C9C2B3", +",# c #7C7B78", +"'# c #BEBBB5", +")# c #D1CABA", +"!# c #44423F", +"~# c #D6D2CA", +"{# c #3A3835", +"]# c #262421", +"^# c #33302C", +"/# c #69645B", +"(# c #8B8478", +"_# c #5F5951", +":# c #605C53", +"<# c #67635B", +"[# c #BFB8AA", +"}# c #928D82", +"|# c #B8B2A4", +"1# c #938F85", +"2# c #989287", +"3# c #89857C", +"4# c #706E6A", +"5# c #DED7C6", +"6# c #928F88", +"7# c #979797", +"8# c #B4AEA2", +"9# c #918C81", +"0# c #68645C", +"a# c #979286", +"b# c #4A4741", +"c# c #5E5D5A", +"d# c #B2AFAA", +"e# c #47453F", +"f# c #C2BBAC", +"g# c #B5AEA0", +"h# c #D4CDBC", +"i# c #CAC7C0", +"j# c #B5AEA1", +"k# c #CCC4B5", +"l# c #ACABA7", +"m# c #797979", +"n# c #757169", +"o# c #BDB6A7", +"p# c #68655D", +"q# c #A09B92", +"r# c #D1CABB", +"s# c #8D887D", +"t# c #80807F", +"u# c #C5BEAF", +"v# c #1E1D1B", +"w# c #A3A099", +"x# c #888681", +"y# c #6A6864", +"z# c #B3AEA3", +"A# c #4D4A44", +"B# c #D6CFBE", +"C# c #A29E95", +"D# c #C1BAAC", +"E# c #918C82", +"F# c #6D6961", +"G# c #B9B3A5", +"H# c #979084", +"I# c #3A3836", +"J# c #BDBBB7", +"K# c #C7C0B1", +"L# c #6C6860", +"M# c #D2CBBB", +"N# c #393836", +"O# c #66635D", +"P# c #A19D94", +"Q# c #656461", +"R# c #32302C", +"S# c #CCC5B5", +"T# c #DEDAD1", +"U# c #B1ACA3", +"V# c #7C7C7C", +"W# c #B5B4B1", +"X# c #5A5853", +"Y# c #4F4C46", +"Z# c #A09A8E", +"`# c #76726A", +" $ c #88857F", +".$ c #4B4843", +"+$ c #DAD2C1", +"@$ c #B4ADA0", +"#$ c #B7B4AF", +"$$ c #CCC9C2", +"%$ c #282623", +"&$ c #888378", +"*$ c #262522", +"=$ c #A8A194", +"-$ c #9A9388", +";$ c #BEB7A8", +">$ c #E3DCCD", +",$ c #D1CEC6", +"'$ c #ACA699", +")$ c #AFA99B", +"!$ c #B2ADA2", +"~$ c #A09D97", +"{$ c #C0BCB5", +"]$ c #B0A99C", +"^$ c #7A776F", +"/$ c #99958E", +"($ c #8A8681", +"_$ c #777068", +":$ c #B3AB9D", +"<$ c #131211", +"[$ c #5D5A53", +"}$ c #090908", +"|$ c #8C877C", +"1$ c #C7C1B4", +"2$ c #D3CEC5", +"3$ c #EAE5DA", +"4$ c #83817D", +"5$ c #C7C0B0", +"6$ c #484743", +"7$ c #C3BFB7", +"8$ c #C7C1B3", +"9$ c #9E998F", +"0$ c #CCC9C1", +"a$ c #C3C0B8", +"b$ c #817E78", +"c$ c #7F786E", +"d$ c #AFA494", +"e$ c #ABA396", +"f$ c #474645", +"g$ c #BCB9B3", +"h$ c #9B9893", +"i$ c #2B2926", +"j$ c #070706", +"k$ c #74716D", +"l$ c #B7B4AD", +"m$ c #484641", +"n$ c #504D47", +"o$ c #DBD6CC", +"p$ c #65615B", +"q$ c #DCD5C6", +"r$ c #B3ADA1", +"s$ c #A8A296", +"t$ c #949086", +"u$ c #999690", +"v$ c #AAA6A0", +"w$ c #6D675F", +"x$ c #A09789", +"y$ c #C2B6A5", +"z$ c #6C6259", +"A$ c #66645F", +"B$ c #2D2D2D", +"C$ c #64615B", +"D$ c #2F2D2A", +"E$ c #8B8781", +"F$ c #64625D", +"G$ c #0A0908", +"H$ c #393733", +"I$ c #C2BAAB", +"J$ c #D9D5CD", +"K$ c #9C978C", +"L$ c #CFC8B8", +"M$ c #9C968A", +"N$ c #928D83", +"O$ c #98958E", +"P$ c #CBC8C0", +"Q$ c #B1ADA7", +"R$ c #8D8A84", +"S$ c #878177", +"T$ c #B4AA9B", +"U$ c #B3A898", +"V$ c #7A7368", +"W$ c #706E6B", +"X$ c #292826", +"Y$ c #A9A499", +"Z$ c #3F3E3C", +"`$ c #1B1A18", +" % c #9F9C96", +".% c #2D2A27", +"+% c #C8C1B1", +"@% c #E6DFD2", +"#% c #C0BDB7", +"$% c #8C8982", +"%% c #C7C3BC", +"&% c #8E8B84", +"*% c #958E86", +"=% c #837B6F", +"-% c #AFA595", +";% c #80796E", +">% c #31302D", +",% c #8F8C87", +"'% c #74726E", +")% c #5E5C57", +"!% c #393430", +"~% c #413F3B", +"{% c #413C37", +"]% c #605E5A", +"^% c #22201D", +"/% c #0C0B0A", +"(% c #E9E4DA", +"_% c #D6CFC2", +":% c #7E766A", +"<% c #C0B4A3", +"[% c #C1B6A5", +"}% c #605B52", +"|% c #97938B", +"1% c #181817", +"2% c #0A0A0A", +"3% c #8D8981", +"4% c #787369", +"5% c #D4CFC6", +"6% c #DCD6C9", +"7% c #CAC6BC", +"8% c #A5A096", +"9% c #78756E", +"0% c #726E65", +"a% c #4A4742", +"b% c #605E59", +"c% c #363433", +"d% c #0B0A0A", +"e% c #BFB5A5", +"f% c #C3B8A6", +"g% c #6C6359", +"h% c #7C786E", +"i% c #46433D", +"j% c #55534F", +"k% c #BAB5AB", +"l% c #E1DACA", +"m% c #B1AA9C", +"n% c #928B80", +"o% c #ACA598", +"p% c #CCC5B8", +"q% c #E1DACB", +"r% c #CFC9BE", +"s% c #44413C", +"t% c #23221F", +"u% c #AFA89B", +"v% c #D5CCBB", +"w% c #BEB2A1", +"x% c #A59A8B", +"y% c #5C564D", +"z% c #0F0F0E", +"A% c #65625C", +"B% c #B8B4AE", +"C% c #AAA498", +"D% c #55514B", +"E% c #332F2A", +"F% c #47443E", +"G% c #252320", +"H% c #3A3833", +"I% c #6B665C", +"J% c #857D71", +"K% c #90887B", +"L% c #CBC1B0", +"M% c #CBC1AF", +"N% c #DED7CA", +"O% c #9B968A", +"P% c #59554E", +"Q% c #B5AB9C", +"R% c #7B7469", +"S% c #57524A", +"T% c #040303", +"U% c #2F2D29", +"V% c #BEBBB4", +"W% c #D2CEC3", +"X% c #1D1C1A", +"Y% c #292827", +"Z% c #1C1A18", +"`% c #090807", +" & c #181613", +".& c #807A6E", +"+& c #DCD5C7", +"@& c #B8B2A5", +"#& c #191815", +"$& c #B8B0A2", +"%& c #C9C1B2", +"&& c #6A6259", +"*& c #AEA393", +"=& c #625D54", +"-& c #010100", +";& c #353431", +">& c #76736C", +",& c #C8C5BD", +"'& c #979287", +")& c #3A3733", +"!& c #413E39", +"~& c #8A8680", +"{& c #BFB8AB", +"]& c #3A3631", +"^& c #494440", +"/& c #3C3731", +"(& c #28231F", +"_& c #181715", +":& c #040404", +"<& c #3D3933", +"[& c #B9B1A3", +"}& c #85827B", +"|& c #080807", +"1& c #645F57", +"2& c #8F897E", +"3& c #71675D", +"4& c #B5AB9A", +"5& c #766E63", +"6& c #38342F", +"7& c #0D0C0B", +"8& c #0D0B0A", +"9& c #33312D", +"0& c #D5CFC4", +"a& c #DBD4C5", +"b& c #534E48", +"c& c #030303", +"d& c #5E5D5E", +"e& c #535153", +"f& c #666460", +"g& c #3D3B39", +"h& c #79756B", +"i& c #43413B", +"j& c #B9B4A9", +"k& c #D5D0C6", +"l& c #CEC8BC", +"m& c #BDB6A9", +"n& c #97948F", +"o& c #D5CEC0", +"p& c #B2AC9E", +"q& c #ADA293", +"r& c #797166", +"s& c #151412", +"t& c #76736D", +"u& c #DBD4C8", +"v& c #D9D2C1", +"w& c #2E2B28", +"x& c #171615", +"y& c #454243", +"z& c #2C2B2A", +"A& c #68655E", +"B& c #807C75", +"C& c #BAB5AA", +"D& c #D0CABD", +"E& c #D9D1C0", +"F& c #E1DACD", +"G& c #DCD3C3", +"H& c #D0C7B7", +"I& c #D6CEBE", +"J& c #A8A299", +"K& c #54524D", +"L& c #0B0A09", +"M& c #5E5A53", +"N& c #9C9486", +"O& c #948C7E", +"P& c #544F47", +"Q& c #0D0C0A", +"R& c #DDD7CC", +"S& c #E4DFD3", +"T& c #AFAA9F", +"U& c #847F76", +"V& c #BFB7AB", +"W& c #E5DFD1", +"X& c #E8E3D7", +"Y& c #C6BBA9", +"Z& c #C8BDAC", +"`& c #B8AE9F", +" * c #756F65", +".* c #46413B", +"+* c #6A665D", +"@* c #B0AA9C", +"#* c #D7CFBF", +"$* c #E0D8C8", +"%* c #B8B2A7", +"&* c #5B5851", +"** c #272623", +"=* c #191513", +"-* c #413F3A", +";* c #4B4842", +">* c #87837B", +",* c #B7B2A9", +"'* c #A6A199", +")* c #E7E1D4", +"!* c #D7CEBD", +"~* c #D9D1C2", +"{* c #CDC4B3", +"]* c #B1A89A", +"^* c #837D73", +"/* c #534F48", +"(* c #373531", +"_* c #22211F", +":* c #C7BFB0", +"<* c #3F3D38", +"[* c #A8A295", +"}* c #BAB5A9", +"|* c #3B3935", +"1* c #706C63", +"2* c #91887C", +"3* c #C1B7A7", +"4* c #B7AD9D", +"5* c #69645C", +"6* c #74716B", +"7* c #A19D95", +"8* c #918B82", +"9* c #484640", +"0* c #636058", +"a* c #68635B", +"b* c #38332F", +"c* c #0E0C0B", +"d* c #837E73", +"e* c #34322E", +"f* c #050505", +"g* c #060606", +"h* c #060505", +"i* c #12100E", +"j* c #78746C", +"k* c #C5C0B5", +"l* c #AFABA1", +"m* c #44433F", +"n* c #100E0C", +"o* c #21201D", +"p* c #6C6963", +"q* c #D0CBBF", +"r* c #53504B", +"s* c #4E4B44", +"t* c #CCC5B6", +"u* c #72716C", +"v* c #6E6C66", +"w* c #43403B", +"x* c #B0AA9F", +"y* c #85817A", +"z* c #D5CFC3", +"A* c #8C887E", +"B* c #2D2C2A", +"C* c #2A2723", +"D* c #65635E", +"E* c #BCB7AC", +"F* c #66625A", +"G* c #7F796F", +"H* c #96928A", +"I* c #CCC7BE", +"J* c #B5B1A9", +"K* c #938F86", +"L* c #CCC8BE", +"M* c #1E1C1A", +"N* c #817D73", +"O* c #191715", +"P* c #726D64", +"Q* c #747069", +"R* c #E8E2D6", +"S* c #99958B", +"T* c #E5E0D3", +"U* c #7F7C73", +"V* c #666159", +"W* c #1A1917", +"X* c #131110", +"Y* c #726E66", +"Z* c #45433E", +"`* c #D9D1C1", +" = c #1E1B19", +".= c #CDC5B5", +"+= c #A7A194", +"@= c #242220", +"#= c #42403B", +"$= c #060605", +"%= c #484540", +" ", +" . + @ # $ % & % * = ", +" - ; > , ' ) ! ~ { ] { ] { ~ ^ / ", +" ( _ : < ~ ^ ~ ^ [ } | 1 2 3 4 5 6 7 8 9 ", +" 0 a b ^ ^ ~ c d e f g h i j k l m n o p q r s ", +" t u v { ] { w x y z A B C m D E F G H I J K L M N O P ", +" Q R S T U V W X Y Z ` ...+.@.C #.$.%.&.*.=.O -.{ ;.O O >. ", +" ,.'.^ { ).!.~.{.].#.^./.(._.:.<.[.}.|.1.O 2.3.4.5.6.] 7.-.8.9. ", +" 0.a.{ ^ b.c.d.e.f.g.h.i.j.c k.l.m.n.o.p.q.O r.s.t.u.v.w.x.y.O z. ", +" A.B.C.D.9 E.F.G.H.I.J.K.L.] M.).N.] { O.P.Q.R.S.T.U.V.W.X.Y.R.Z.`. ", +" +O .+++@+O O #+$+%+&+*+=+p.-+;+{ ] ^ ~ ^ ^ ^ U >+,+'+)+!+~+{+]+^+ ", +" /+(+_+U N.:+O O O O <+[+O }+|+1+^ ~ [ 2+^ ^ 3+4+5+@ 6+7+8+9+0+a+b+c+ ", +" d+e+f+g+h+i+j+k+j+:+O O l+m+n+O o+p+q+M.r+s+t+u+v+y w+x+y+8+z+A+O O B+C+D+E+ ", +" d+u F+G+H+#+;.I+^ ] J+O K+L+M+N+O O+P+Q+R+S+T+U+V+W+X+Y+Z+`+ @.@+@O O @@#@$@%@&@ ", +" *@=@G+ B+-@;@] >@{ ,@'@)@O M+!@~@{@]@^@/@(@_@O y.:@<@[@}@|@[@Y+1@2@O O 3@4@5@6@ ", +" 7@ 8@9@0@a@b@c@d@O O O e@f@g@h@O i@j@O O O h@_ k@l@O m@n@Q.H o@p@O O O &+q@r@ ", +" s@t@ G+u@v@w@x@y@z@O O A@B@C@(+O O D@E@F@O O O G@H@I@r J@K@L@M@N@O@P@O O Q@R@S@T@ ", +" U@<+ V@W@X@Y@Z@:.`@ #.#+#@#O O O O Q.1 ##O O $#%#&#*#$+=#-#;#>#,#'#)#O O K+!#~#{# ", +" w+i.]# ^#/#(#_#:#<#[#}#|#O O O O O O q 1#O O O $#2#3#4#5#6#7#8#9#0#a#O O O b#c#d# ", +" e#f# e#>#g#h#O O O O O O O O O O y.i#j#O O O k#l#m#n#o#p#q#r#s#t#5.O O u#v#w#x# ", +" y#z# A#B#O O O O O O O O O O O O O y.C#O+O O O D#E#F#G#H#I#J#K#T+L#M#O O Y+N#4+O# ", +" P#Q# R#S#O O O O O O O O O O O O O T#/ #+O O O U#V#W#9+X#Y#Z#`# $.$+$#+@$.@#$$$ ", +" %$&$ *$=$O O -$8+;$O O O O O O O >$,$'$O O O O 8@i.)$!$~${$L i+]$^$/$: ($_$:$G+", +" <$[$U@ }$|$1$s+2$=.O O O O O O O O 3$4$Q@O O O 5$6$7${ 3$8$9$u+0$a$b$c$d$@.e$G+", +" f$g$h$i$ j$k$l$m$n$9#O O O O O O O O 5#o$p$)#O O O q$r$s$t$u$b+v$w$x$n Y@Y@y$z$A$", +" B$C$D$ E$F$G$H$I$9#O O O O O O O O O N J$K$L$M$N$O$P$Q$R$S$T$U$m D Y@D D Y@V$W$", +" X$Y$Z$ `$ % .%+%w+O O O O O O O O O O @%#%$%%%0$&%*%=%-%D Y@D Y@D Y@D D Y@;%4#", +" >%,%'%)% !%~%{% R@]% ^%/%S$[@O O O O O O O O D@(%_%&$:%d$Y@D D m y$<%C m D Y@Y@[%}%F$", +" |%1% 2%`$3%4%5%;@N 6%7%8%9%0%a%b%c%d%H+K#O O O O O O O O e% .f. .<%y$D m C @.f%@.C m D D U$g% ", +" [$h%i%j%k%l%O m%k#n%o%p%-@++q%0@:+r%h%s%t%u%O O O O O O O v%..:.f.g.m D y$B f%w%+.@.C x%y%z% ", +" A%B%C%l%$+D%E%F%G%H%H%I%J%K%L%M%N%;.y.O%<$P%5$O O O O +$Q%+.w%f%B y$D m g.f.:...R%S%T%G+ ", +" U%V%W%z.s#X%Y%Z%G+G+G+G+G+G+j$`% &.&+&3$N @&#&v#$&O O O %&&&@.f%@.C m D y$<%*&=&}$-& ", +" ;&>&,&'&)&!&Q ~&{&]&G+ ^&/&(&_&:&<&[&:+D@}&G+|&1&z.O 2&3&C <%y$m D 4&5&6&7&8& ", +" 9&0&a&b&c&d&e&f&g&h&Z%i&a+j&k&l&>+m&n&>%P%L%O o&G+ G+^#p&h%{.Y@D q&r&6&s&G+ ", +" t&u&v&w&x&y&z&A&B&C&D&E&8 F&G&H&I&y.-.3$J&b#O K&G+ L&M&N&O&P&Q&G+ ", +"n$R&S&T&U&u#V&]@W&X&;.+$Y&Z&`& *.*+*@*#*$*%*&*=#**G+ =*G+G+ ", +"-*;*>*,*'*)*!*-@~*{*]*^*/*(*_*H%M$:*<*U@[*#+}***G+ ", +" |*1*=$2*3*4*5*.$G+6*7*8*8&v#9*0*a*H+b*c*M@+$d*e* ", +" f*g*h*i* U+-#E#N j*G+G+ k*l*m*n* ", +" o*u%p*q*r*G+ s*t*u*v*G+ ", +" w*x*y*z*A*B*C* D*E*[*}$G+ ", +" L#F*G*H*I*J*p@K*L*M#M*N*O* ", +" b#P*(+Q*R*S*T*U*l+1.V*W* ", +" X*Y*Z*`* =.=X%+=@=G+ ", +" #=$=%=G+ "}; diff --git a/linphone/pixmaps/sip-away.png b/linphone/pixmaps/sip-away.png new file mode 100644 index 000000000..ba7580faa Binary files /dev/null and b/linphone/pixmaps/sip-away.png differ diff --git a/linphone/pixmaps/sip-bifm.png b/linphone/pixmaps/sip-bifm.png new file mode 100644 index 000000000..898a18a7e Binary files /dev/null and b/linphone/pixmaps/sip-bifm.png differ diff --git a/linphone/pixmaps/sip-busy.png b/linphone/pixmaps/sip-busy.png new file mode 100644 index 000000000..550e10a13 Binary files /dev/null and b/linphone/pixmaps/sip-busy.png differ diff --git a/linphone/pixmaps/sip-closed.png b/linphone/pixmaps/sip-closed.png new file mode 100644 index 000000000..6bbe08352 Binary files /dev/null and b/linphone/pixmaps/sip-closed.png differ diff --git a/linphone/pixmaps/sip-online.png b/linphone/pixmaps/sip-online.png new file mode 100644 index 000000000..a6656ec57 Binary files /dev/null and b/linphone/pixmaps/sip-online.png differ diff --git a/linphone/pixmaps/sip-otl.png b/linphone/pixmaps/sip-otl.png new file mode 100644 index 000000000..cc9023b81 Binary files /dev/null and b/linphone/pixmaps/sip-otl.png differ diff --git a/linphone/pixmaps/sip-otp.png b/linphone/pixmaps/sip-otp.png new file mode 100644 index 000000000..0df6f91a0 Binary files /dev/null and b/linphone/pixmaps/sip-otp.png differ diff --git a/linphone/pixmaps/sip-wfa.png b/linphone/pixmaps/sip-wfa.png new file mode 100644 index 000000000..d6fe73b4f Binary files /dev/null and b/linphone/pixmaps/sip-wfa.png differ diff --git a/linphone/po/.cvsignore b/linphone/po/.cvsignore new file mode 100644 index 000000000..56888d9d5 --- /dev/null +++ b/linphone/po/.cvsignore @@ -0,0 +1,6 @@ +.intltool-merge-cache +Makefile +Makefile.in +POTFILES +*.gmo +stamp-* diff --git a/linphone/po/ChangeLog b/linphone/po/ChangeLog new file mode 100644 index 000000000..63269d9a1 --- /dev/null +++ b/linphone/po/ChangeLog @@ -0,0 +1,97 @@ +2007-01-17 gettextize + + * Makefile.in.in: Upgrade to gettext-0.16.1. + * cat-id-tbl.c: Remove file. + +2006-07-20 gettextize + + * Makefile.in.in: Upgrade to gettext-0.14.6. + * boldquot.sed: New file, from gettext-0.14.6. + * en@boldquot.header: New file, from gettext-0.14.6. + * en@quot.header: New file, from gettext-0.14.6. + * insert-header.sin: New file, from gettext-0.14.6. + * quot.sed: New file, from gettext-0.14.6. + * remove-potcdate.sin: New file, from gettext-0.14.6. + * Rules-quot: New file, from gettext-0.14.6. + * cat-id-tbl.c: Remove file. + +2002-10-15 gettextize + + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-10-08 gettextize + + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-10-08 gettextize + + * boldquot.sed: New file, from gettext-0.11.5. + * en@boldquot.header: New file, from gettext-0.11.5. + * en@quot.header: New file, from gettext-0.11.5. + * insert-header.sin: New file, from gettext-0.11.5. + * quot.sed: New file, from gettext-0.11.5. + * remove-potcdate.sin: New file, from gettext-0.11.5. + * Rules-quot: New file, from gettext-0.11.5. + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-10-04 gettextize + + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-10-04 gettextize + + * Makefile.in.in: Upgrade to gettext-0.11.5. + +2002-10-04 gettextize + + * Makefile.in.in: New file, from gettext-0.11.5. + +2002-10-01 gettextize + + * Makefile.in.in: Upgrade to gettext-0.11.5. + * boldquot.sed: New file, from gettext-0.11.5. + * en@boldquot.header: New file, from gettext-0.11.5. + * en@quot.header: New file, from gettext-0.11.5. + * insert-header.sin: New file, from gettext-0.11.5. + * quot.sed: New file, from gettext-0.11.5. + * remove-potcdate.sin: New file, from gettext-0.11.5. + * Rules-quot: New file, from gettext-0.11.5. + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-08-04 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.40. + +2002-08-04 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.40. + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-07-16 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.40. + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-02-16 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.40. + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + +2002-02-10 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.40. + +2002-02-10 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.40. + * cat-id-tbl.c: Remove file. + * stamp-cat-id: Remove file. + diff --git a/linphone/po/Makefile.in.in b/linphone/po/Makefile.in.in new file mode 100644 index 000000000..5022b8b18 --- /dev/null +++ b/linphone/po/Makefile.in.in @@ -0,0 +1,403 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. +# +# Origin: gettext-0.16 + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +localedir = @localedir@ +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# We use $(mkdir_p). +# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as +# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, +# @install_sh@ does not start with $(SHELL), so we add it. +# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined +# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake +# versions, $(mkinstalldirs) and $(install_sh) are unused. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +mkdir_p = @mkdir_p@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in remove-potcdate.sin \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: all-@USE_NLS@ + +all-yes: stamp-po +all-no: + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test ! -f $(srcdir)/$(DOMAIN).pot || \ + test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) + @test ! -f $(srcdir)/$(DOMAIN).pot || { \ + echo "touch stamp-po" && \ + echo timestamp > stamp-poT && \ + mv stamp-poT stamp-po; \ + } + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +# This target rebuilds $(DOMAIN).pot; it is an expensive operation. +# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed + if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ + msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ + else \ + msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ + fi; \ + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + --msgid-bugs-address="$$msgid_bugs_address" + test ! -f $(DOMAIN).po || { \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ + sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ + if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ + else \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + else \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + } + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + if test -f "$(srcdir)/$${lang}.po"; then \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ + else \ + $(MAKE) $${lang}.po-create; \ + fi + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkdir_p) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkdir_p) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: stamp-po $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + dists="$$dists $(DOMAIN).pot stamp-po"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir) || exit 1; \ + else \ + cp -p $(srcdir)/$$file $(distdir) || exit 1; \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for creating PO files. + +.nop.po-create: + @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ + echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ + exit 1 + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ + cd $(top_builddir) \ + && $(SHELL) ./config.status $(subdir)/$@.in po-directories + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/linphone/po/Makevars b/linphone/po/Makevars new file mode 100644 index 000000000..32692ab4b --- /dev/null +++ b/linphone/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Free Software Foundation, Inc. + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/linphone/po/Makevars.template b/linphone/po/Makevars.template new file mode 100644 index 000000000..32692ab4b --- /dev/null +++ b/linphone/po/Makevars.template @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Free Software Foundation, Inc. + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/linphone/po/POTFILES.in b/linphone/po/POTFILES.in new file mode 100644 index 000000000..1cbaf3490 --- /dev/null +++ b/linphone/po/POTFILES.in @@ -0,0 +1,18 @@ +# List of source files containing translatable strings. + +gtk/main.c +gtk/interface.c +gtk/callbacks.c +gtk/support.c +gtk/propertybox.c +gtk/gui_utils.c +gtk/linphone.c +gtk/presence.c +gtk/friends.c +gtk/addressbook.c + +coreapi/linphonecore.c +coreapi/misc.c +coreapi/exevents.c +coreapi/presence.c + diff --git a/linphone/po/Rules-quot b/linphone/po/Rules-quot new file mode 100644 index 000000000..9c2a995e3 --- /dev/null +++ b/linphone/po/Rules-quot @@ -0,0 +1,47 @@ +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-create: + $(MAKE) en@quot.po-update +en@boldquot.po-create: + $(MAKE) en@boldquot.po-update + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/linphone/po/boldquot.sed b/linphone/po/boldquot.sed new file mode 100644 index 000000000..4b937aa51 --- /dev/null +++ b/linphone/po/boldquot.sed @@ -0,0 +1,10 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g +s/“/“/g +s/â€/â€/g +s/‘/‘/g +s/’/’/g diff --git a/linphone/po/cat-id-tbl.c b/linphone/po/cat-id-tbl.c new file mode 100644 index 000000000..e69de29bb diff --git a/linphone/po/cs.po b/linphone/po/cs.po new file mode 100644 index 000000000..a389ae6cb --- /dev/null +++ b/linphone/po/cs.po @@ -0,0 +1,1049 @@ +# translation of linphone.po to cs_CZ +# This file is distributed under the same license as the PACKAGE package. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER. +# Klara Cihlarova , 2005. +# Petr Pisar , 2006, 2007. +# +msgid "" +msgstr "" +"Project-Id-Version: linphone-2.0.0\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2007-11-21 17:50+0100\n" +"Last-Translator: Petr Pisar \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "Volný SIP videofon" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Soubor" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Adresář" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Historie volání" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Zobrazit volání" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "UkonÄit" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "NápovÄ›da" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "Zde zadejte SIP adresu nebo telefonní Äíslo" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "SIP adresa:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Zobrazit adresář" + +#: gtk/interface.c:261 +msgid "..." +msgstr "…" + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Proxy:" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Volat nebo\n" +"pÅ™ijmout" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +"ZavÄ›sit nebo\n" +"odmítnout" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Nebo poslat zprávu!" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Zobrazit více…" + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Úroveň pÅ™ehrávání:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Úroveň nahrávání:" + +#: gtk/interface.c:354 +msgid "Ring level:" +msgstr "Úroveň vyzvánÄ›ní:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Zvuk" + +#: gtk/interface.c:382 +msgid "Enable video" +msgstr "Povolit obraz" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "Obraz" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "Ovládání" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Dosažitelný" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Mám práci, jsem zpÄ›t za " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "Druhá strana bude informována, že se vrátíte za X minut" + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "min" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "PryÄ" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "NeruÅ¡it" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "DoÄasnÄ› mimo" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Alternativní služba" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Přítomnost" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Zadejte Äísla pro zaslání DTMF." + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" +" 3\n" +"def" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" +" 2\n" +"abc" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" +" 4\n" +"ghi" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" +" 5\n" +"jkl" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" +" 6\n" +"mno" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" +" 7\n" +"pqrs" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" +" 8\n" +"tuv" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" +" 9\n" +"wxyz" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "Přátelé online" + +#: gtk/interface.c:849 gtk/interface.c:3029 +msgid "Linphone" +msgstr "Linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" +"© 2001\n" +"Vyrobeno ve Staré Dobré EvropÄ›" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone je program pro IP telefonii.\n" +"Je kompatibilní s protokoly SIP a RTP." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "http://www.linphone.org/" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parametry" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "Použít IPv6 síť (je-li dostupná)" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" +"Jestliže jste v síti podporující IPv6 protokol a chcete-li, aby jej linphone " +"používal, zapnÄ›te tuto volbu." + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "Obecné" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Tato volba je urÄena pouze pro uživatele v intranetu za firewallem. Pokud to " +"není váš případ, nevyplňujte." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "Bez firewallu" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "Pro odhad veÅ™ejné adresy použít tento STUN server:" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "VeÅ™ejná adresa firewallu:" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "Volby průchodu NATem (experimentální)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Velikosti vyrovnávací fronty v milisekundách (potlaÄení rozptylu):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "RTP port pro zvuk:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "RTP vlastnosti" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "Místo RTP rfc2833 použít pro DTMF pÅ™enos SIP INFO zprávu" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "DoporuÄeno je RTP-RFC2833." + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Ostatní" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Síť" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "Zvukové zařízení pro pÅ™ehrávání:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "mikrofon" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "line" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "Zvukové zařízení pro nahrávání:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Zdroj nahrávání:" + +#: gtk/interface.c:1277 +msgid "Ring sound device" +msgstr "Zvukové zařízení pro vyzvánÄ›ní:" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "ZvonÄ›ní:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "PotlaÄit ozvÄ›nu (projeví se na druhém konci)" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "Vyberte soubor" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Test" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Vlastnosti zvuku" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Zvukové zařízení" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Spustit uživatelského agenta SIP na portu:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Je doporuÄeno používat port 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "SIP port" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "VaÅ¡e SIP adresa:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Automaticky uhodnout platné jméno" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identita" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "PÅ™idat proxy/registraci" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Upravit" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Odstranit" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Vzdálené služby" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "Vyprázdnit vÅ¡echny ověřovací informace (uživatelské jméno, heslo…)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Ověřovací informace" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Seznam audio kodeků podle preference:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Kodeky zvuku" + +#: gtk/interface.c:1608 +msgid "Video Codecs" +msgstr "Kodeky obrazu" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Povolit" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Zakázat" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "Odchozí šířka pásma (kb/s):" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "Příchozí šířka pásma (kb/s):" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Poznámka: Kodeky oznaÄené ÄervenÄ› nelze u vaÅ¡eho typu pÅ™ipojení použít." + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "Nejsou dostupné žádné informace" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Informace o kodeku" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "Kodeky zvuku a obrazu" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Kodeky" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Adresář" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Vybrat" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Informace" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"Uživatel je momentálnÄ› nedostupný, ale navrhuje tyto alternativní formy " +"kontaktu:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Žádné." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Konfigurace proxy a registrace" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "SmÄ›rování (volitelné):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "SIP proxy:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "SIP identita:" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "RegistraÄní období:" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Odeslat registraci:" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "ZveÅ™ejnit svůj stav:" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Upravit kontaktní informace" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Jméno:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "Pravidlo pÅ™ihlášení:" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "Odeslat pÅ™ihlášení (podle online stavu osoby)" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Informace o kontaktu" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "Nové příchozí pÅ™ihlášení" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "Obdrželi jste nové pÅ™ihlášení…" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Odmítnout" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "PÅ™ijmout" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Žádost o ověření" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "pro doménu je vyžadováno ověření" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "ID uživatele:" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "heslo:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "uživatelské jméno:" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "doména:" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone – historie volání" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "Diskuzní skupina" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Text:" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Diskuze s %s" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Nelze najít soubor s obrázkem: %s" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "ÚÄet" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Povoleno" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Zakázáno" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Jméno" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Rychlost (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Stav" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Min. rychlost (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "Neomezená" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "Volající žádá o rezervaci zdrojů. Souhlasíte?" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" +"Volající nepoužívá rezervaci zdrojů. \t\t\t\t\tChcete pÅ™esto pokraÄovat?" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "linphone – příchozí hovor z %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" +"Obdrželi jste pÅ™ihlášení od %s. Znamená to, že si tato osoba pÅ™eje být " +"informována o vaÅ¡em stavu přítomnosti (online, zaneprázdnÄ›n, pryÄ…).\n" +"Souhlasíte?" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "Pro doménu %s je vyžadováno ověření" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Žádná" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Stav" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "Zdržet" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "Odmítnout" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "Å patnÄ› zadaná SIP adresa: SIP adresa má tvar sip:uživatel@doména" + +#: gtk/addressbook.c:226 +msgid "Contact list" +msgstr "Seznam kontaktů" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "ZameÅ¡kané hovory: %i" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "pÅ™eruÅ¡en" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "dokonÄen" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "promeÅ¡kán" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s v %s\n" +"Od: %s\n" +"Pro: %s\n" +"Stav: %s\n" +"Trvání: %i min %i s\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "Příchozí hovor" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "Odchozí hovor" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"Zdá se, že váš poÄítaÄ je pÅ™ipojen do IPv6 sítÄ›. StandardnÄ› linphone používá " +"pouze IPv4. Prosím, povedtÄ› zmÄ›ny v konfiguraci programu, pokud chcete " +"používat IPv6." + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "PÅ™ipraven." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "Hledá se adresa pomocí STUN…" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "STUN vyhledávání dokonÄeno…" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Vyhledává se umístÄ›ní Äísla…" + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "Toto Äíslo nelze vyhledat." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Å patnÄ› zadaná SIP adresa. Adresa má mít tento formát " + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "Promiňte, vedení více souÄasných hovorů není podporováno!" + +#: coreapi/linphonecore.c:1198 +msgid "Contacting" +msgstr "Kontaktuji" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "Nelze volat." + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "PÅ™ipojeno." + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "Hovor skonÄil." + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "Žádná adresa NATu/firewallu nebyla zadána!" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "Neplatná adresa NATu '%s': '%s" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Váš poÄítaÄ používá zvukový ovladaÄ ALSA. Jde o nejlepší\n" +"volbu. Linphone vÅ¡ak potÅ™ebuje ke své práci modul emulace\n" +"oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" +"'modprobe snd-pcm-oss', kterým modul zavede." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Váš poÄítaÄ používá zvukový ovladaÄ ALSA. Jde o nejlepší\n" +"volbu. Linphone vÅ¡ak potÅ™ebuje ke své práci modul mixer emulace\n" +"oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" +"'modprobe snd-mixer-oss', kterým modul zavede." + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "Hovor ukonÄen." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "Cíl je nedostupný." + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Uživatel je zaneprázdnÄ›n." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "Uživatel je doÄasnÄ› nedostupný." + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Dotaz pÅ™eruÅ¡en." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "Uživatel si nepÅ™eje být ruÅ¡en." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Volání odmítnuto." + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "Chybný dotaz" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Uživatele nelze na dané adrese zastihnout." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "Vzdálený uživatel nemá podporu pro žádný z navržených kodeků." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "VyprÅ¡ení Äasového limitu." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Vzdálený poÄítaÄ byl nalezen, ale odmítl pÅ™ipojení." + +#: coreapi/exevents.c:312 +msgid "is contacting you." +msgstr "vás volá." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "PÅ™esmÄ›rováno na %s…" + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"Uživatel je nedostupný, ale navrhuje tyto alternativní\n" +"setkání:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "ÄŒasná média." + +#: coreapi/exevents.c:837 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "Registrace na %s selhala: %s" + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "odpovÄ›Ä nedorazila vÄas" + +#: coreapi/exevents.c:851 +#, c-format +msgid "Registration on %s successful." +msgstr "Registrace na %s byla úspěšná." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "PryÄ" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "ÄŒekám na schválení" + +#: coreapi/presence.c:133 +msgid "Online" +msgstr "Online" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "ZaneprázdnÄ›n" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "Na chvíli pryÄ" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "Na příjmu" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "Na obÄ›dÄ›" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "ZavÅ™eno" + +#~ msgid "enter sip uri here" +#~ msgstr "Sem zadejte SIP URI" + +#~ msgid "User manual" +#~ msgstr "Uživatelská příruÄka" + +#~ msgid "Ring sound selection" +#~ msgstr "VýbÄ›r zvonÄ›ní" + +#~ msgid "Communication ended." +#~ msgstr "Komunikace ukonÄena." + +#~ msgid "Call cancelled." +#~ msgstr "Volání pÅ™eruÅ¡eno." + +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "VnÄ›jší IP adresa firewallu (v teÄkové notaci):" + +#~ msgid "Index" +#~ msgstr "Rejstřík" + +#~ msgid "Address" +#~ msgstr "Adresa" + +#~ msgid "28k modem" +#~ msgstr "28k modem" + +#~ msgid "56k modem" +#~ msgstr "56k modem" + +#~ msgid "64k modem (numeris)" +#~ msgstr "64k modem" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL nebo kabelový modem" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet nebo podobný" + +#~ msgid "Connection type:" +#~ msgstr "Typ pÅ™ipojení:" + +#~ msgid "Server address" +#~ msgstr "Adresa serveru:" + +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone nemůže otevřít zvukové zařízení %s. PÅ™ekontrolujte nastavení a " +#~ "funkÄnost zvukové karty." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Zde zadejte SIP adresu osoby, které si pÅ™ejete volat." + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "PÅ™ijmout nebo\n" +#~ "odmítnout" + +#~ msgid "%s. Retry after %i minute(s)." +#~ msgstr "%s. Zkusit znovu po %i min." diff --git a/linphone/po/de.po b/linphone/po/de.po new file mode 100644 index 000000000..ddb4cd508 --- /dev/null +++ b/linphone/po/de.po @@ -0,0 +1,1245 @@ +# SIP Telephony Application. +# Copyright (C) 2001, 2002 Free Software Foundation, Inc. +# Simon Morlat , 2001. +# +msgid "" +msgstr "" +"Project-Id-Version: linphone 0.7.1\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2003-05-23 17:51-0400\n" +"Last-Translator: Jean-Jacques Sarton , Ursula Herles-" +"Hartz \n" +"Language-Team: Deutsch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8-bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "Ein freies SIP Video-Fone" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Start" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Adressbuch" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Gesprächsverlauf" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Zeigt Gespräche" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "Beenden" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "Hilfe" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "Sip-Adresse oder Telefonnummer eingeben." + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Sip-Adresse:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Adressbuch" + +#: gtk/interface.c:261 +msgid "..." +msgstr "..." + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Benutze Proxy-Server:" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Anrufen oder\n" +"Entgegennehmen" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +"Auflegen\n" +"oder Abweisen" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Oder Chat" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Mehr anzeigen" + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Abhörpegel" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Aufnamepegel" + +#: gtk/interface.c:354 +msgid "Ring level:" +msgstr "Klingelpegel" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Ton" + +#: gtk/interface.c:382 +msgid "Enable video" +msgstr "Video einschalten" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "Video" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "Kontrolle" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Erreichbar" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Beschäftigt, wieder erreichbar in " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "" +"Der Teilnehmer wird informiert, dass Sie in X Minuten wieder anwesend sind." + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "mn" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Abwesend" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Nicht stören" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Unterwegs" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Andere Dienste" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Anwesenheit" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Zifferntasten drücken, um DTMF zu senden" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "" + +#: gtk/interface.c:561 +msgid "0" +msgstr "" + +#: gtk/interface.c:567 +msgid "#" +msgstr "" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "Meine online Freunde" + +#: gtk/interface.c:849 gtk/interface.c:3029 +msgid "Linphone" +msgstr "Linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" +"C: 2001\n" +"In Alt Europa erzeugt" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone ist ein web-phone.\n" +"Es ist mit den SIP- und RTP-Protokollen kompatibel." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parameter" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "IPv6 Netzwerk (falls vorhanden) verwenden" + +# msgstr "Teilnehmer zur Zeit nicht ansprechbar." +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" +"Ankreuzen wenn Sie ein ipv6 Netz haben und wenn Sie es wünschen dass " +"linphone es verwendet" + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Diese Option gilt nur für Anwender in einem privaten Netzwerk oder wenn der " +"Rechner durch einen Firewall geschützt ist. Andernfalls wird das Feld nicht " +"ausgefüllt" + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "Kein Firewall" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "Dieses STUN Server verwenden um die Firewalladresse zu Ermitteln" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "Firewall Adresse von Hand angeben" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "NAT-Transversaloptionen (experimentell)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Anzahl der gepufferten Pakete (Jitterausgleich):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "Sound RTP Port:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "RTP-Eigenschaften" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "Benutze SIP INFO Nachricht statt RTP rfc2833 für DTMF Übertragung" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "RTP-RFC2833 wird empfohlen" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Andere" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Netzwerk" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "Ton Wiedergabegerät:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "Mikrofon" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "Leitung" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "Audio Aufnahmegerät:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Aufnahmequelle:" + +#: gtk/interface.c:1277 +msgid "Ring sound device" +msgstr "Klingel Wiedergabegerät:" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "Klingelton:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" +"Echounterdrückung einschalten (eliminiert das von Gesprächspartnet gehörter " +"Echo)" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Anhören" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Audio Eigenschaften" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Audiogerät" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Sip \"user agent\" an Port:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Wir empfehlen, Port 5060 zu verwenden" + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "SIP-Port" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Ihre Sip-Adresse:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Automatisch einen gültigen Hostnamen erraten" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identität" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "Proxy/Registrator hinzufügen" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Bearbeiten" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Entfernen" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Dienste auf entferntem Server" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" +"Alle gespeicherten Authentifikationsinformationen löschen (Benutzername, " +"Passwort,...)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Authentifikationsinformation" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Liste von Audio-CoDecs in der Reihenfolge ihrer Präferenz" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Eigenschaften des Audiocodecs" + +#: gtk/interface.c:1608 +msgid "Video Codecs" +msgstr "Videocodecs" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Freigeben" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Sperren" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "Upload-Bandbreite (kbit/sec):" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "Download-Bandbreite (kbit/sec):" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Notiz: Rot markierten Codecs können bei Ihrer Internetverbindungsart nicht " +"verwendet werden." + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "Informationen nicht verfügbar" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Codec Information" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "Audio und Video Codecs" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Codecs" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Adressbuch" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Auswählen" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Information" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"Teilnehmer nicht erreichbar. Bitte stattdessen nachstehende Ressource " +"verwenden:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Nichts." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Proxy/Registrator Konfigurationsbox" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "Route (optional):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "SIP Proxy:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "SIP Identität" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "Registrierungsdauer." + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Sende Registrierung:" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "Anwesenheit Information publzieren" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Bearbeite Kontaktinformationen" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Name:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "Subskription Police" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "Sende Subskription (zeige Onlinestatus der Person an)" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Kontaktinformationen" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "Neu ankommende Subskription" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "Sie haben eine neue Subskription empfangen" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Ablehnen" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "Annehmen" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Authentifikation erfordert" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "Authentifikation erforderlich für Bereich" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "Benutzer ID:" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "Passwort" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "Benutzername:" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "Bereich:" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone - Gesprächsverlauf" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "Chat Raum" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Text" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Chat mit %s" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Pixmapdatei %s nicht gefunden" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "Konto" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Freigegeben" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Gesperrt" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Name" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Rate (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Status" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Min Bitrate (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "Unbegrenzt" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "Der Anrufer erbittet Resourcenreservierung. Sind Sie einverstanden?" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" +"Der Anrufer benutzt keine Resourcenreservierung. \t\t\t\t\tWollen Sie " +"dennoch fortfahren?" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "Linphone- empfängt ein Anruf von %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" +"Sie haben eine Subskription von %s empfangen. Das heißt, dass diese Person " +"ber Ihre Anwesenheitsinformation benachrichtigt werden will (erreichbar, " +"beschäftig, abwesend...).\n" +"Sind Sie einverstanden ?" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "Authentifikation erforderlich für Bereich %s" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Keinen" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Anwesenheitsstatus" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "Warten" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "Abweisen" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" +"Fehlerhafte Sip-Adresse. Eine Sip-Adresse hat folgenden Aufbau " + +#: gtk/addressbook.c:226 +msgid "Contact list" +msgstr "Kontaktliste" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "Sie haben %i Anruf(e) in Abwesenheit." + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "abgebrochen" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "beendet" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "verpasst" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s am %sVon: %s\n" +"An: %s\n" +"Status: %s\n" +"Dauer: %i mn %i sec\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "Eingehendes Gespr�h" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "Abgehendes Gespräch" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"Ihr Rechner scheint an einen IPv6 Netz angeschlossen zu sein. " +"Linphoneverwendet normalerweise IPv4. Bitte Konfiguration anpassen wenn sie " +"IPv6 verwenden wollen" + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "Bereit" + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "Stun Ermittlung läuft..." + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "Stun Ermittlung beendet..." + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Suche Telefonnummernziel.." + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "Konnte dies Nummer nicht auflösen." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Sip-Adresse kann nicht bestimmt werden. Eine Sip-Adresse hat folgenden " +"Aufbau " + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "Mehrfachen gleichzeitigen Anrufen nicht unterstützt !" + +#: coreapi/linphonecore.c:1198 +msgid "Contacting" +msgstr "Rufe an" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "Konnte kein Anruf vornehmen" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Verbunden." + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "Anruf beendet" + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "Keine Nat/Firewall Adresse vorgegeben !" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "Ungültige NAT Adresse '%s' : '%s'" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" +"Dies ist die beste Lösung; allerdings ist die von Linphone benötigte pcm OSS " +"Emulation\n" +"nicht vorhanden. Für die Einbindung des Moduls\n" +"bitte den Befehl 'modprobe snd-pcm-oss' als Anwender-Root verwenden." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" +"Dies ist die beste Lösung; allerdings ist die von Linphone benötigte pcm OSS " +"Emulation\n" +"nicht vorhanden. Fr die Einbindung des Moduls\n" +"bitte den Befehl 'modprobe snd-pcm-oss' als Anwender-Root verwenden." + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "Anruf beendet" + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "Konnte Ziel nicht erreichen" + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Besetzt." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "Teilnehmer zur Zeit nicht ansprechbar." + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Anruf annulliert." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "Teilnehmer möchte nicht gestört werden." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Anruf abgewiesen" + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "Fehlerhafte Anfrage" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Teilnehmer ist unter der angegebene Adresse nicht erreichbar." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "Die Gegenstelle untersttzt die angebotenen Codecs nicht." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "Zeitberschreitung." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Die Gegenstelle hat die Verbindung abgewiesen." + +#: coreapi/exevents.c:312 +msgid "is contacting you." +msgstr "ruft Sie an" + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "Nach %s umgeleitet..." + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"Teilnehmer nicht erreichbar. Bitte versuchen Sie es unter nachstehender " +"Ressource:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Registrierung auf %s schlug fehl (Zeitberschreitung)." + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, c-format +msgid "Registration on %s successful." +msgstr "Registrierung auf %s erfolgreich." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "Gegangen" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "Warte aud Bestätigung" + +#: coreapi/presence.c:133 +msgid "Online" +msgstr "Verbunden" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "Besetzt" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "Bald wieder da" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "Am Höhrer" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "Beim Essen" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "enter sip uri here" +#~ msgstr "Sip URI eingeben" + +#~ msgid "User manual" +#~ msgstr "Anwender-Handbuch" + +#~ msgid "Ring sound selection" +#~ msgstr "Klingelton ausw�len" + +#~ msgid "Communication ended." +#~ msgstr "Kommunikation beendet." + +#~ msgid "Call cancelled." +#~ msgstr "Anruf annulliert" + +#, fuzzy +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "IP-Adresse des Firewall (in Punktnotation)" + +#~ msgid "Address" +#~ msgstr "Adresse" + +#, fuzzy +#~ msgid "Server address" +#~ msgstr "Server-Adresse:" + +#~ msgid "28k modem" +#~ msgstr "28K Modem" + +#~ msgid "56k modem" +#~ msgstr "56K Modem" + +#~ msgid "64k modem (numeris)" +#~ msgstr "64K Modem (ISDN)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL oder Kabel-Modem" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet oder äquivalent" + +#~ msgid "Connection type:" +#~ msgstr "Verbindungstyp:" + +#, fuzzy +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone kann das Soundgerät nicht öffnen. Prfen Sie nach, ob die " +#~ "Soundkarte vollst�dig konfiguriert und funktionsfähig ist." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "" +#~ "Geben Sie die Sip-Adresse des Anwenders, den Sie anrufen möchten, hier " +#~ "ein." + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "Auflegen oder\n" +#~ "Abweisen" + +#~ msgid "%s. Retry after %i minute(s)." +#~ msgstr "%s. In %i Minuten wieder versuchen." + +#~ msgid "Timeout..." +#~ msgstr "Zeitüberschreitung..." + +#~ msgid "Connection" +#~ msgstr "Verbindung" + +#, fuzzy +#~ msgid "" +#~ "Add address\n" +#~ "book" +#~ msgstr "Adressbuch" + +#~ msgid "Toggle this if you want to be registered on a remote server." +#~ msgstr "" +#~ "Bitte ankreuzen, wenn Sie auf einem Sip-Server registriert werden wollen." + +#~ msgid "Address of record:" +#~ msgstr "Adresse des Eintrags:" + +#~ msgid "" +#~ "The password used for registration. On some servers it is not necessary" +#~ msgstr "" +#~ "Passwort für die Registrierung. Bei manchen Servern nicht erforderlich." + +#~ msgid "Use this registrar server as outbound proxy." +#~ msgstr "Verwenden Sie diesen Registrarserver als externen proxy." + +#~ msgid "sip address:" +#~ msgstr "SIP-Adresse:" + +#~ msgid "Display name:" +#~ msgstr "Angezeigter Name:" + +#~ msgid "Modify" +#~ msgstr "Ändern" + +#~ msgid "Registering..." +#~ msgstr "Registrierung" + +#~ msgid "" +#~ "You are currently using the i810_audio driver.\n" +#~ "This driver is buggy and so does not work with Linphone.\n" +#~ "We suggest that you replace it by its equivalent ALSA driver,\n" +#~ "either with packages from your distribution, or by downloading\n" +#~ "ALSA drivers at http://www.alsa-project.org." +#~ msgstr "" +#~ "Sie verwenden zur Zeit den i810_audio Treiber.\n" +#~ "Diese Treiber ist fehlerhaft und funktioniert nicht mit Linphone\n" +#~ "Wir empfehlen, den Treiber entweder durch das ALSA-Treiber-Paket von " +#~ "ihrer Distribution\n" +#~ "zu ersetzen oder die gewnschten ALSA-Treiber von http://www.alsa-project." +#~ "org\n" +#~ "zu beziehen und zu installieren" + +#~ msgid "Unregistration successfull." +#~ msgstr "Abmeldung erfolgreich." + +#~ msgid "Select network interface to use:" +#~ msgstr "Netzwerkschnittstelle wählen:" + +#~ msgid "Network interface properties" +#~ msgstr "Eigenschaften der Netzwerkschnittstelle" + +#~ msgid "RTP" +#~ msgstr "RTP" + +#~ msgid "Audio" +#~ msgstr "Audio" + +#~ msgid "C: 2001" +#~ msgstr "April 2001" + +#~ msgid "Add" +#~ msgstr "Hinzufgen" + +#~ msgid "Threads not supported by glib. Upgrade your glib.\n" +#~ msgstr "" +#~ "Threads werden von glib nicht unterstützt. Bitte aktualisieren Sie Ihre " +#~ "glib.\n" + +#~ msgid "Run linphone as a gnome-applet." +#~ msgstr "Linphone als gnome-Applet ausfhren." + +#~ msgid "Run linphone as a daemon (for use without gnome)." +#~ msgstr "Linphone als daemon ausführen (Verwendung ohne Gnome)." + +#~ msgid "" +#~ "Cannot find network previously used interface %s.\n" +#~ "If your computer is temporary connected to the internet, please connect " +#~ "and then run linphone.\n" +#~ "If you want to change your default network interface, go to the " +#~ "parameters 'box." +#~ msgstr "" +#~ "Linphone konnte die zuvor verwendete Netzwerkschnittstelle %s nicht " +#~ "finden.\n" +#~ "Wenn linphone nur temporär am Internet angeschlossen ist, stellen Sie " +#~ "eine Verbindung her und rufen Sie linphone erneut auf.\n" +#~ "Wenn Sie die vorgegebene Netzwerkschnittstelle ändern wollen, wählen Sie " +#~ "bitte \"Einstellungen\"." + +#~ msgid "" +#~ "Linphone cannot open the audio device.\n" +#~ "It may be caused by other programs using it.\n" +#~ "Do you want linphone to kill these programs (esd or artsd) ?" +#~ msgstr "" +#~ "Linphone kann die Soundschnittstelle nicht öffnen.\n" +#~ "Dies kann durch andere Applikationen verursacht sein.\n" +#~ "Möchten sie diese Programme (esd oder artsd) beenden?" + +#~ msgid "label37" +#~ msgstr "label37" + +#~ msgid "Use it as a:" +#~ msgstr "Verwenden als:" + +#~ msgid "Redirect server" +#~ msgstr "Umleitungs-Server" + +#~ msgid "Outbound proxy" +#~ msgstr "Ausgehender Proxy-Server" + +#~ msgid "" +#~ "Toggle this button if the registrar must be used to proxy calls through a " +#~ "firewall." +#~ msgstr "" +#~ "Verwenden Sie diesen Knopf, falls der Registrar zum Tunneln durch einen " +#~ "Firewall verwendet werden muß" + +#~ msgid "kbit/s" +#~ msgstr "Kbits/s" + +#~ msgid "OSS" +#~ msgstr "OSS" + +#~ msgid "ALSA" +#~ msgstr "ALSA" + +#~ msgid "Automatically kill applications using soundcard when needed" +#~ msgstr "Applikationen die die Soundkarte verwenden, automatisch beenden." + +#~ msgid "" +#~ "Your computer is connected to several networks. Check in the global " +#~ "parameters if Linphone uses the one that you want." +#~ msgstr "" +#~ "Ihr Rechner ist an mehere Netze angeschlossen. Stellen Sie sicher, daß in " +#~ "den Globalen Parametern die richtige Schnittstelle selektiert ist." + +#~ msgid "" +#~ "Linphone failed to open the sound device. See the README file included in " +#~ "the distribution for details." +#~ msgstr "" +#~ "Linphone konnte die Soundschnittstelle nicht öffnen. Weitere " +#~ "Informationen finden Sie in der README-Datei (enthalten in der " +#~ "Distribution)." + +#~ msgid "Interface not found." +#~ msgstr "Schnittstelle nicht gefunden." + +#~ msgid "Warning" +#~ msgstr "Warnung" + +#~ msgid "" +#~ "Linphone cannot open the sound device. It may be caused by other programs " +#~ "using it. Do you want linphone to kill these programs (esd or artsd) ?" +#~ msgstr "" +#~ "Linphone kann die Soundschnittstelle nicht öffnen. Dies kann durch andere " +#~ "Applikationen verursacht sein. Möchten sie diese Programme (esd oder " +#~ "artsd) beenden?" + +#~ msgid "Linphone shutdowns" +#~ msgstr "Linphone Ende" + +#~ msgid "Linphone shutdowns..." +#~ msgstr "Linphone Ende..." + +#~ msgid "" +#~ "Please, wait a few seconds untils linphone unregisters your sip addess " +#~ "from registrar server..." +#~ msgstr "Bitte einige Sekunden warten, bis Sip-Adresse ausgetragen ist." + +#~ msgid "Bad formuled sip address." +#~ msgstr "SIP-Adresse fehlerhaft." + +#~ msgid "Couldn't create pixmap from file: %s" +#~ msgstr "Konnte Pixmap nicht aus Datei %s erzeugen." + +#~ msgid "" +#~ "Linphone did not detect any valid network interface. If you use a " +#~ "temporary internet connection, please connect and then run linphone again." +#~ msgstr "" +#~ "Linphone konnte keine Netzwerkschnittstelle finden. Wenn Sie nur eine " +#~ "temporäre Internetverbindung haben, bitte erneut eine Internetverbindung " +#~ "herstellen und linphone nochmals starten." + +#~ msgid "List of network interfaces on your system." +#~ msgstr "Vorhandene Netzwerkschnittstellen ihres Systems" diff --git a/linphone/po/en@boldquot.header b/linphone/po/en@boldquot.header new file mode 100644 index 000000000..fedb6a06d --- /dev/null +++ b/linphone/po/en@boldquot.header @@ -0,0 +1,25 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# +# This catalog furthermore displays the text between the quotation marks in +# bold face, assuming the VT100/XTerm escape sequences. +# diff --git a/linphone/po/en@quot.header b/linphone/po/en@quot.header new file mode 100644 index 000000000..a9647fc35 --- /dev/null +++ b/linphone/po/en@quot.header @@ -0,0 +1,22 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# diff --git a/linphone/po/es.po b/linphone/po/es.po new file mode 100644 index 000000000..eefea265a --- /dev/null +++ b/linphone/po/es.po @@ -0,0 +1,1283 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Linphone 0.9.1\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" +"Last-Translator: Nelson Benitez \n" +"Language-Team: es \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Agenda" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +#, fuzzy +msgid "Enter sip address or phone number here" +msgstr "La direccion SIP del servidor de registro." + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "SIP:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Direccion SIP" + +#: gtk/interface.c:247 +#, fuzzy +msgid "Shows the address book" +msgstr "Muestra la Agenda" + +#: gtk/interface.c:261 +msgid "..." +msgstr "" + +#: gtk/interface.c:269 gtk/interface.c:2519 +#, fuzzy +msgid "Proxy to use:" +msgstr "Servidor Proxy" + +#: gtk/interface.c:278 +#, fuzzy +msgid "" +"Call or\n" +"answer" +msgstr "" +"Llamar o\n" +"Responder" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Mostrar mas..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Nivel de reproduccion:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Nivel de Grabacion:" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Nivel de Grabacion:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Sonido" + +#: gtk/interface.c:382 +#, fuzzy +msgid "Enable video" +msgstr "Activado" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Disponible" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Ocupado, estare de vuelta en " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "Se le comunicara a la otra persona que estaras de vuelta en X minutos" + +#: gtk/interface.c:431 +msgid "5" +msgstr "10" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "min" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Ausente" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "No molestar" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Vengo enseguida" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Servicio alternativo" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Estado" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Pulsa los digitos para mandar DTMFs." + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone es un telefono para Internet.\n" +"Es compatible con los protocolos SIP y RTP." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parametros" + +#: gtk/interface.c:1061 +#, fuzzy +msgid "Use IPv6 network (if available)" +msgstr "El usuario le dice que volvera enseguida." + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +#, fuzzy +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Esta opcion es solo para usuarios en una red privada, detras de un " +"cortafuegos. Siese no es tu caso, deja esto vacio." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +#, fuzzy +msgid "NAT traversal options (experimental)" +msgstr "Opciones para NAT transversal (experimental)" + +#: gtk/interface.c:1156 +#, fuzzy +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Numero de milisegundos en el buffer(compensacion jitter):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "Puerto RTP usado para audio:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "Propiedades de RTP" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Red" + +#: gtk/interface.c:1225 +#, fuzzy +msgid "Playback sound device:" +msgstr "Usar dispositivo de sonido:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "microfono" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "linea" + +#: gtk/interface.c:1250 +#, fuzzy +msgid "Capture sound device:" +msgstr "Usar dispositivo de sonido:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Fuente de grabacion:" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "Usar dispositivo de sonido:" + +#: gtk/interface.c:1285 +#, fuzzy +msgid "Ring sound:" +msgstr "Fuente de grabacion:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Propiedades de sonido" + +#: gtk/interface.c:1347 +#, fuzzy +msgid "Sound device" +msgstr "Usar dispositivo de sonido:" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Ejecutar SIP user agent en el puerto:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Se recomienda encarecidamente usar el puerto 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "Puerto SIP" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Tu direccion SIP:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identidad" + +#: gtk/interface.c:1467 +#, fuzzy +msgid "Add proxy/registrar" +msgstr "Usar el registro SIP" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Borrar" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Servicios Remotos:" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" + +#: gtk/interface.c:1547 +#, fuzzy +msgid "Authentication information" +msgstr "Informacion de codec" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Lista de codecs de audio, en orden de preferencia:" + +#: gtk/interface.c:1595 +#, fuzzy +msgid "Audio codecs" +msgstr "Propiedades del codec de Audio" + +#: gtk/interface.c:1608 +#, fuzzy +msgid "Video Codecs" +msgstr "Propiedades del codec de Audio" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Activado" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Desactivado" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "Nota: Los codecs en ROJO no son adecuados para tu conexion a internet." + +#: gtk/interface.c:1720 +#, fuzzy +msgid "No information availlable" +msgstr "Informacion no disponible" + +#: gtk/interface.c:1727 +#, fuzzy +msgid "Codec information" +msgstr "Informacion de codec" + +#: gtk/interface.c:1731 +#, fuzzy +msgid "Audio and video codecs" +msgstr "Propiedades del codec de Audio" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Codecs" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Agenda" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Seleccionar" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Informacion" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"Usuario no disponible en este momento pero le invita a contactarle usando el " +"siguiente recurso alternativo:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Ninguno." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "" + +#: gtk/interface.c:2344 +#, fuzzy +msgid "SIP Identity:" +msgstr "Identidad" + +#: gtk/interface.c:2359 +#, fuzzy +msgid "Registration Period:" +msgstr "Se ha registrado con exito." + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "" + +#: gtk/interface.c:2381 +#, fuzzy +msgid "Publish presence information:" +msgstr "Informacion de codec" + +#: gtk/interface.c:2466 +#, fuzzy +msgid "Edit contact information" +msgstr "(Ninguna informacion de contacto !)" + +#: gtk/interface.c:2505 +#, fuzzy +msgid "Name:" +msgstr "Nombre" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "" + +#: gtk/interface.c:2537 +#, fuzzy +msgid "Contact information" +msgstr "Informacion de codec" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "" + +#: gtk/interface.c:2799 +#, fuzzy +msgid "password:" +msgstr "Tu Contraseña:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "No se pudo encontrar el archivo pixmap: %s" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Activado" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Desactivado" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Nombre" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Estado" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "" + +#: gtk/linphone.c:410 +#, fuzzy +msgid "None" +msgstr "Ninguno." + +#: gtk/friends.c:117 +#, fuzzy +msgid "Presence status" +msgstr "Estado" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +#, fuzzy +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" +"Direccion SIP mal escrita. Una direccion SIP es " + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "Contactando " + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" + +#: coreapi/linphonecore.c:692 +#, fuzzy +msgid "Ready" +msgstr "Preparado." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "" + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "" + +#: coreapi/linphonecore.c:1138 +#, fuzzy +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Direccion SIP mal escrita. Una direccion SIP es " + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +#, fuzzy +msgid "Contacting" +msgstr "Contactando " + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Conectado." + +#: coreapi/linphonecore.c:1550 +#, fuzzy +msgid "Call ended" +msgstr "Llamada cancelada." + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Tu ordenador parece estar usando los controladores de ALSA.\n" +"Esa es la mejor eleccion. Sin embargo el modulo de emulacion pcm de OSS\n" +"no se encuentra y linphone lo necesita. Por favor ejecute\n" +"'modprobe snd-pcm-oss' como root para cargarlo." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Tu ordenador parece estar usando los controladores de ALSA.\n" +"Esa es la mejor eleccion. Sin embargo el modulo de emulacion mixer de OSS\n" +"no se encuentra y linphone lo necesita. Por favor ejecute\n" +" 'modprobe snd-mixer-oss' como root para cargarlo." + +#: coreapi/exevents.c:115 +#, fuzzy +msgid "Call terminated." +msgstr "Llamada cancelada." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "" + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "El usuario esta ocupado." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "El usuario le dice que volvera enseguida." + +#: coreapi/exevents.c:148 +#, fuzzy +msgid "Request Cancelled." +msgstr "Llamada cancelada." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "El usuario no quiere que lo molesten." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Llamada cancelada." + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "No se encontro ningun usuario en la direccion indicada." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "El usuario remoto no soporta ninguno de los codecs propuestos." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "Tiempo agotado." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Se encontro host remoto pero rechazo la conexion." + +#: coreapi/exevents.c:312 +#, fuzzy +msgid "is contacting you." +msgstr "le esta llamando." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "" + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"Usuario no disponible en este momento pero le invita\n" +"a contactarle usando el siguiente recurso alternativo:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Se ha registrado con exito." + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, fuzzy, c-format +msgid "Registration on %s successful." +msgstr "Se ha registrado con exito." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +#, fuzzy +msgid "Gone" +msgstr "Ninguno." + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +#, fuzzy +msgid "Online" +msgstr "linea" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "User manual" +#~ msgstr "Manual de Usuario" + +#~ msgid "Communication ended." +#~ msgstr "Comunicacion finalizada." + +#~ msgid "Call cancelled." +#~ msgstr "Llamada cancelada." + +#, fuzzy +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "Direccion IP del cortafuegos (en notacion con puntos):" + +#~ msgid "Index" +#~ msgstr "Indice" + +#~ msgid "Address" +#~ msgstr "Direccion" + +#, fuzzy +#~ msgid "Server address" +#~ msgstr "Direccion del Servidor:" + +#~ msgid "28k modem" +#~ msgstr "modem 28k" + +#~ msgid "56k modem" +#~ msgstr "modem 56k" + +#~ msgid "64k modem (numeris)" +#~ msgstr "modem 64k (numeris)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL o Cable" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet o equivalente" + +#~ msgid "Connection type:" +#~ msgstr "Tipo de conexion:" + +#, fuzzy +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone no pudo abrir el dispositivo de audio. Asegurese que su tarjeta " +#~ "de sonido esta completamente configurada y operativa." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Escribe aqui la direccion SIP de la persona que quieres llamar." + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "Descolgar o\n" +#~ "Rechazar" + +#~ msgid "%s. Retry after %i minute(s)." +#~ msgstr "%s. Reintentar tras %i minutos." + +#, fuzzy +#~ msgid "Timeout..." +#~ msgstr "Tiempo agotado." + +#~ msgid "Connection" +#~ msgstr "Conexion" + +#, fuzzy +#~ msgid "" +#~ "Add address\n" +#~ "book" +#~ msgstr "Agenda" + +#~ msgid "Toggle this if you want to be registered on a remote server." +#~ msgstr "Marcar opcion si desea registrarse en un servidor remoto." + +#~ msgid "Address of record:" +#~ msgstr "Nombre de registro:" + +#~ msgid "" +#~ "The password used for registration. On some servers it is not necessary" +#~ msgstr "" +#~ "La contraseña usada para registrarse. En algunos servidores no es " +#~ "necesaria" + +#~ msgid "Use this registrar server as outbound proxy." +#~ msgstr "Usar el servidor de registro como outbound proxy." + +#~ msgid "sip address:" +#~ msgstr "Direccion SIP:" + +#~ msgid "Display name:" +#~ msgstr "Nombre a mostrar:" + +#~ msgid "Modify" +#~ msgstr "Modificar" + +#~ msgid "Registering..." +#~ msgstr "Registrando..." + +#~ msgid "" +#~ "You are currently using the i810_audio driver.\n" +#~ "This driver is buggy and so does not work with Linphone.\n" +#~ "We suggest that you replace it by its equivalent ALSA driver,\n" +#~ "either with packages from your distribution, or by downloading\n" +#~ "ALSA drivers at http://www.alsa-project.org." +#~ msgstr "" +#~ "Estas usando actualmente el controlador i810_audio.\n" +#~ "Ese controlador tiene errores y por tanto no funciona con Linphone.\n" +#~ "Le recomendamos que lo sustituya por su controlador equivalente de ALSA,\n" +#~ "ya sea mediante paquetes de su distribucion, o descargando\n" +#~ "controladores ALSA de http://www.alsa-project.org." + +#~ msgid "Unregistration successfull." +#~ msgstr "Cancelacion del registro completada." + +#~ msgid "3" +#~ msgstr "3" + +#~ msgid "2" +#~ msgstr "2" + +#~ msgid "4" +#~ msgstr "4" + +#~ msgid "6" +#~ msgstr "6" + +#~ msgid "7" +#~ msgstr "7" + +#~ msgid "8" +#~ msgstr "8" + +#~ msgid "9" +#~ msgstr "9" + +#~ msgid "C: 2001" +#~ msgstr "Abril 2001" + +#~ msgid "Select network interface to use:" +#~ msgstr "Selecciona la interfaz de red para usar:" + +#~ msgid "Network interface properties" +#~ msgstr "Propiedades de Interfaz de Red:" + +#~ msgid "RTP" +#~ msgstr "RTP" + +#~ msgid "Add" +#~ msgstr "Añadir" + +#~ msgid "Threads not supported by glib. Upgrade your glib.\n" +#~ msgstr "Threads no soportados por glib. Actualize su glib.\n" + +#~ msgid "Run linphone as a gnome-applet." +#~ msgstr "Lanzar linphone como un gnome-applet." + +#~ msgid "Run linphone as a daemon (for use without gnome)." +#~ msgstr "Ejecutar linphone como demonio (para uso sin gnome)." + +#~ msgid "" +#~ "Cannot find network previously used interface %s.\n" +#~ "If your computer is temporary connected to the internet, please connect " +#~ "and then run linphone.\n" +#~ "If you want to change your default network interface, go to the " +#~ "parameters 'box." +#~ msgstr "" +#~ "No se puede encontrar la interfaz de red usada previamente %s.\n" +#~ "Si tu ordenador esta conectado temporalmente a Internet, por favor " +#~ "conecta y entonces ejecuta linphone.\n" +#~ "Si quieres cambiar tu interfaz de red predeterminada, ve a la opcion " +#~ "Parametros." + +#, fuzzy +#~ msgid "" +#~ "Linphone cannot open the audio device.\n" +#~ "It may be caused by other programs using it.\n" +#~ "Do you want linphone to kill these programs (esd or artsd) ?" +#~ msgstr "" +#~ "Linphone no puede abrir el dispositivo de audio.\n" +#~ " Puede deberse a que otros programas lo esten usando.\n" +#~ "¿ Quiere que Linphone cierre esos programas (esd o artsd) ?" + +#~ msgid "Use it as a:" +#~ msgstr "Usarlo como un:" + +#~ msgid "Redirect server" +#~ msgstr "Servidor de Redireccionamiento" + +#~ msgid "Outbound proxy" +#~ msgstr "Outbound proxy" + +#~ msgid "" +#~ "Togle this button if the registrar must be used to proxy calls through a " +#~ "firewall." +#~ msgstr "" +#~ "Marcar esta opcion si el servidor de registro debe ser usado para " +#~ "llamadas a proxy a traves de un cortafuegos." + +#~ msgid "OSS" +#~ msgstr "OSS" + +#~ msgid "ALSA" +#~ msgstr "ALSA" + +#~ msgid "Automatically kill applications using soundcard when needed" +#~ msgstr "" +#~ "Cerrar aplicaciones que usen la tarjeta de sonido cuando se necesite." + +#~ msgid "" +#~ "Your computer is connected to several networks. Check in the global " +#~ "parameters if Linphone uses the one that you want." +#~ msgstr "" +#~ "Tu ordenador esta conectado a varias redes. Revisa en los Parametros " +#~ "globales si Linphone usa la que necesitas." + +#~ msgid "" +#~ "Linphone failed to open the sound device. See the README file included in " +#~ "the distribution for details." +#~ msgstr "" +#~ "Linphone fallo al abrir el dispositivo de sonido. Vea el archivo README " +#~ "incluido en la distribucion para mas detalles." + +#~ msgid "Interface not found." +#~ msgstr "Interfaz no encontrada." + +#~ msgid "Warning" +#~ msgstr "Atencion" + +#~ msgid "" +#~ "Linphone cannot open the sound device. It may be caused by other programs " +#~ "using it. Do you want linphone to kill these programs (esd or artsd) ?" +#~ msgstr "" +#~ "Linphone no puede abrir el dispositivo de sonido. Puede deberse a que " +#~ "otros programaslo esten usando. ¿ Quiere que Linphone cierre esos " +#~ "programas (esd o artsd) ?" + +#~ msgid "Linphone shutdowns" +#~ msgstr "Linphone esta terminando..." + +#~ msgid "Linphone shutdowns..." +#~ msgstr "Linphone esta terminando..." + +#~ msgid "" +#~ "Please, wait a few seconds untils linphone unregisters your sip addess " +#~ "from registrar server..." +#~ msgstr "" +#~ "Por favor, espere unos segundos hasta que Linphone cancele el registro de " +#~ "su direccion SIP en el servidor de registros..." + +#~ msgid "Bad formuled sip address." +#~ msgstr "Direccion SIP mal escrita." + +#~ msgid "Couldn't create pixmap from file: %s" +#~ msgstr "No se pudo crear pixmap desde el archivo: %s" + +#~ msgid "" +#~ "Linphone did not detect any valid network interface. If you use a " +#~ "temporary internet connection, please connect and then run linphone again." +#~ msgstr "" +#~ "Linphone no detecto ninguna interfaz de red valida. Si usas una conexion " +#~ "temporal a Internet, por favor conecta y vuelve a ejecutar Linphone." + +#~ msgid "List of network interfaces on your system." +#~ msgstr "Lista de interfaces de red en tu sistema." + +#~ msgid "" +#~ "RTP est le mode de transport de la voix. Modifier ces paramètres pour " +#~ "tenter d'améliorer la qualité de la communication si celle-ci est " +#~ "dégradée." +#~ msgstr "" +#~ "RTP es el modelo de transporte de la voz. Modifica estos parametros para " +#~ "intentar mejorar la calidad de la comunicacion, si es que.es mala." + +#~ msgid "Use rtp port:" +#~ msgstr "Puerto RTP:" + +#~ msgid "" +#~ "Les codecs ou vocodeurs sont les algorithmes utilisés pour compresser la " +#~ "voix." +#~ msgstr "" +#~ "Los codecs o codificadores/decodificadores son los algoritmos usados para " +#~ "comprimir la voz." + +#~ msgid "" +#~ "Vous pouvez ajuster avec cet onglet des paramètre liés à votre carte son." +#~ msgstr "Puede modificar estos parametros a su gusto." diff --git a/linphone/po/fr.po b/linphone/po/fr.po new file mode 100644 index 000000000..0d05546fc --- /dev/null +++ b/linphone/po/fr.po @@ -0,0 +1,1031 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2001 Free Software Foundation, Inc. +# Simon Morlat , 2001. +# +msgid "" +msgstr "" +"Project-Id-Version: Linphone 0.9.1\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2002-12-06 17:33+0100\n" +"Last-Translator: Simon Morlat \n" +"Language-Team: french \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Aller à" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Carnet d'adresses" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Historique des appels" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Affichage des appels" + +#: gtk/interface.c:188 +#, fuzzy +msgid "Exit" +msgstr "Editer" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Adresse sip:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Affiche le carnet d'adresses" + +#: gtk/interface.c:261 +msgid "..." +msgstr "..." + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Serveur proxy" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Appeler ou\n" +"Répondre" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +"Raccrocher\n" +"ou refuser" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Ou chatter !" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Plus d'options..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Niveau d'écoute:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Niveau d'enregistrement:" + +#: gtk/interface.c:354 +msgid "Ring level:" +msgstr "Volume de la sonnerie :" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Son" + +#: gtk/interface.c:382 +msgid "Enable video" +msgstr "video active" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "Video" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "Controles" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Joignable" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Occupé, de retour dans " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "" +"Vos correspondants seront informés que vous serez de retour dans X minutes" + +#: gtk/interface.c:431 +msgid "5" +msgstr "" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Absent" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Ne pas déranger" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "En déplacement" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Autre service" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Présence" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Utiliser ce clavier pour envoyer des DTMFs." + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "" + +#: gtk/interface.c:561 +msgid "0" +msgstr "" + +#: gtk/interface.c:567 +msgid "#" +msgstr "" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "Mes amis en ligne" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" +"Avril 2001\n" +"Fabriqué en France" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone est un téléhone internet.\n" +"Il est compatible avec les protocoles SIP et RTP." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Paramètres" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "Utiliser un réseau IPv6 (si disponible)" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" +"Cocher cette case si vous êtes sur un réseau IPv6 et que vous voulez que " +"linphone l'utilise." + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Utiliser ceci si vous êtes dans un réseau privé derrière un pare-feu et que " +"vous souhaitez passer des appels vers l'internet public." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "Pas de pare-feu" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "Utiliser ce serveur STUN pour deviner l'adresse du pare feu:" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "Donner l'addresse du pare-feu manuellement:" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "Options d'utilisation avec un pare-feu (expérimental)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Temps de bufferisation (jitter compensation):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "Port RTP pour l'audio:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "Paramètres RTP" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" +"Utilise les messages SIP INFO à la place des RTP RFC2833 pour signaler les " +"DTMFs" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "RTP-RFC2833 est recommandé" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Autre" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Réseau" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "Carte son (pour l'écoute)" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "micro" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "line" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "Carte son (pour le micro) :" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Source d'enregistrement:" + +#: gtk/interface.c:1277 +msgid "Ring sound device" +msgstr "Carte son (pour la sonnerie) :" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "Son de sonnerie:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" +"Annulation d'écho active (annule l'écho entendu par votre correspondant)" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Ecouter" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Paramètres son" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Carte son" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "SIP user agent sur le port:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Il est FORTEMENT recommand�d'utiliser le port 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "Port SIP" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Votre adresse sip:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Choix automatique du nom d'hôte (recommandé)" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identité" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "Ajouter un proxy ou un registrar" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Editer" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Supprimer" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Services sur serveur distant" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" +"Effacer les informations d'authentification (utilisateur, mot de passe...)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Information d'authentification" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Liste des codecs audio, par ordre de préférence:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Codecs audio" + +#: gtk/interface.c:1608 +msgid "Video Codecs" +msgstr "Codecs video" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Active" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Désactive" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "Bande passante montante (kbit/sec)" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "Bande passante descendante (kbit/sec)" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Remarque: les codecs en rouge ne sont pas utilisables compte tenu de votre " +"type de connection internet." + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "Pas d'information disponible" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Information sur le codec" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "Codecs audio et video" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Carnet d'adresses" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Sélectionner" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"Votre correspondant n'est pas joignable actuellement mais il vous propose\n" +"de le contacter en utilisant le moyen alternatif suivant:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Aucun." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Paramétrage des proxy" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "Route (optionnel):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "Proxy SIP:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "Identité SIP:" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "Période d'enregistrement" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Enregistrement (REGISTER):" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "Envoyer les informations de presence" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Editer le contact" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Nom:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "Politique concernant les souscriptions:" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "Envoie une soucription (pour connaitre la disponibilit�de la personne)" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Information sur le contact" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "Nouvelle souscription entrante" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "Vous avez reçu une souscription..." + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Refuser" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "Accepter" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Vous devez vous authentifier" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "Authentification requise sur le realm" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "mot de passe:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "nom d'utilisateur:" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone - Historique des appels" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Texte:" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Chat avec %s" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Ne peut trouvé l'icone : %s" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "Compte" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Activé" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Désactivé" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Nom" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Fréquence (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Etat" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Débit min. (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "Pas de limite" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" +"Votre correspondant propose d'utiliser des m?anismes de r?ervation de " +"ressources. Souhaitez-vous accepter ?" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" +"Votre correspondant n'utilise pas de m?anisme de r?ervation de ressources. " +"Souhaitez-vous continuer tout de m?e ?" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "linphone - appel entrant de %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" +"Vous avez reçu une souscription de %s. Cela signifie que cette personne " +"souhaite être au courant de votre disponibilité au téléhone (en ligne, " +"occupé, parti...)\n" +"Etes vous d'accord ?" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "Authentification requise sur le realm %s" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Aucun" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Info de présence" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +#, fuzzy +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" +"Adresse SIP mal formulée. Une address sip ressemble à " + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "Appel de" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "Vous avez manqué %i appel(s)" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "abandonné" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "terminé" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "manqué" + +#: coreapi/linphonecore.c:223 +#, fuzzy, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s le %sDe: %s\n" +"A destination de: %s\n" +"Etat: %s\n" +"Durée: %i mn %i sec\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "Appel entrant" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "Appel sortant" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"Votre machine semble être connectée à un réseau IPv6. Par defaut linphone " +"utilise toujours de l'IPv4. Merci de mettre à jour votre configuration si " +"vous souhaitez utilisez un réseau IPv6." + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "Prêt." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "Découverte STUN en cours" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "Découverte STUN effectuée." + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Recherche de la destination du numéro de téléphone..." + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "La destination n'a pu être trouvée." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Adresse SIP mal formulée. Une address sip ressemble à " + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "Désolé, vous ne pouvez appeler plusieurs personnes simultanément !" + +#: coreapi/linphonecore.c:1198 +msgid "Contacting" +msgstr "Appel de" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "Echec" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "En ligne." + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "Appel terminé." + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "Adresse nat invalide '%s' : %s" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Votre ordinateur semble utiliser les pilotes sons ALSA.\n" +"C'est en g��al le meilleur choix, cependant un module\n" +"d'emulation oss est manquant et linphone en a besoin.\n" +"Veuillez s'il vous plait executer la commande\n" +"'modprobe snd-pcm-oss' en tant que root afin de le charger." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Votre ordinateur semble utiliser les pilotes sons ALSA. C'est en g��al le\n" +"meilleur choix, cependant un module d'emulation est manquant et linphone en\n" +"a besoin. Veuillez s'il vous plait executer la commande\n" +"'modprobe snd-mixer-oss' en tant que root afin de le charger." + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "Appel terminé." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "Impossible de joindre votre correspondant." + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Occupé..." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "L'usager est temporairement indisponible." + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Requête annulée." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "L'usager ne souhaite pas être dérangé" + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Appel décliné." + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "Requete erronée" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "L'utilisateur n'a pu être trouvé à l'addresse spécifiée" + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "Votre correspondant ne supporte aucun des codecs proposés." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "Temps d'attente dépassé..." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "La machine distante a été trouvée mais a refusé la connexion." + +#: coreapi/exevents.c:312 +msgid "is contacting you." +msgstr "vous appelle." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "Redirigé vers %s ..." + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"Votre correspondant n'est pas joignable actuellement mais il vous propose\n" +"de le contacter en utilisant le moyen alternatif suivant:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Echec de l'enregistrement sur %s (trop long)" + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, fuzzy, c-format +msgid "Registration on %s successful." +msgstr "Enregistrement sur %s effectué." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "Parti" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "En attente" + +#: coreapi/presence.c:133 +msgid "Online" +msgstr "Disponible" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "Occupé" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "De retour" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "Au téléphone" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "A table" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "Eteint" + +#~ msgid "enter sip uri here" +#~ msgstr "entrer une adresse sip ici" + +#~ msgid "User manual" +#~ msgstr "Manuel de l'utilisateur" + +#~ msgid "Ring sound selection" +#~ msgstr "Selection de la sonnerie" + +#~ msgid "Communication ended." +#~ msgstr "Communication termin�." + +#~ msgid "Call cancelled." +#~ msgstr "Appel annulé" + +#~ msgid "28k modem" +#~ msgstr "modem 28k" + +#~ msgid "56k modem" +#~ msgstr "modem 56k" + +#~ msgid "64k modem (numeris)" +#~ msgstr "modem 64k (numeris)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "modem ADSL ou cable" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet ou semblable" + +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "Adresse IP du pare-feu (de.ce.format.la) :" + +#~ msgid "Connection type:" +#~ msgstr "Type de connexion:" + +#~ msgid "Address" +#~ msgstr "Adresse" + +#~ msgid "Server address" +#~ msgstr "Adresse du serveur:" + +#, fuzzy +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone n'a pu utilis?votre carte son. Veuillez v?ifier qu'elle " +#~ "fonctionne correctement." diff --git a/linphone/po/hu.po b/linphone/po/hu.po new file mode 100644 index 000000000..ff0f2ee12 --- /dev/null +++ b/linphone/po/hu.po @@ -0,0 +1,986 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2007-12-14 11:12+0100\n" +"Last-Translator: \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "Egy ingyenes SIP video-telefon" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Ugrás" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Címjegyzék" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Hivás elÅ‘zmények" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Mutasd a hívásokat" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "Kilépés" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "Help" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "Gépeld ide a sip címet vagy a telefonszámot" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Sip cím:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Mutasd a címjegyzéket" + +#: gtk/interface.c:261 +msgid "..." +msgstr "..." + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Használt SIP Proxy:" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Hívás vagy\n" +"Válasz" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +"Lerak vagy\n" +"Nem válaszol" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Vagy chat-elj!" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "További beállítások..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Lejátszási hangerÅ‘:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Felvételi hangerÅ‘:" + +#: gtk/interface.c:354 +msgid "Ring level:" +msgstr "Csengetési hangerÅ‘:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Hang" + +#: gtk/interface.c:382 +msgid "Enable video" +msgstr "Video engedélyezés" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "Video" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "Vezérlés" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "ElérhetÅ‘" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Foglalt vagyok, jövök vissza" + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "A másik fél tájékoztatva lesz, hogy X perc alatt vissza fogsz jönni" + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "perc" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Nem elérhetÅ‘" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Ne zavarj" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Ideiglenesen nem elérhetÅ‘" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Ãtirányítás" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "ElérhetÅ‘" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Nyomja le a számokat a DTMF küldéshez" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" +" 3\n" +"def" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" +" 2\n" +"abc" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" +" 4\n" +"ghi" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" +" 5\n" +"jkl" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" +" 6\n" +"mno" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" +" 7\n" +"pqrs" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" +" 8\n" +"tuv" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" +" 9\n" +"wxyz" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "ElérhetÅ‘ partnerek" + +#: gtk/interface.c:849 gtk/interface.c:3029 +msgid "Linphone" +msgstr "Linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" +"C: 2001\n" +"Made in Old Europe" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"A Linphone egy web-telefon.\n" +"SIP és RTP kompatíbilis." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "http://www.linphone.org" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Paraméterek" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "IPv6 hálózat használata (ha elérhetÅ‘)" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "Ha egy IPv6 hálózat elérhetÅ‘, akkor a linphone használja azt." + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "Ãltalános" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Ez az opció azoknak a felhasználóknak kell, akik egy privát hálózaton tűzfal " +"mögül interneteznek. Egyébként üresen kell hagyni." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "Nincs tűzfal" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "STUN szerver használata a tűzfal címének meghatározásához." + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "Tűzfal külsÅ‘ címe:" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "NAT beállítások áttekintése (kísérleti)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "A pufferelt milisecondok száma (jitter compensation):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "RTP port, audió használatra:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "RTP beállítások" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "Használj SIP INFO üzenetet RTP rfc2833 helyett a DTMF átvitelnél" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "RTP-RFC2833 az ajánlott." + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Egyéb" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Hálózat" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "Lejátszó hang eszköz:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "mikrofon" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "line" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "FelvevÅ‘ hang eszköz:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Felvételi forrás:" + +#: gtk/interface.c:1277 +msgid "Ring sound device" +msgstr "CsengÅ‘hang forrás:" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "CsengÅ‘hang:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" +"Visszhang törlés engedélyezése (törli a visszhangot, amit hall a távoli " +"partner" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "Fájl kiválasztás" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Hallgatás" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Hang beállítások" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Hang eszköz" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "SIP felhasználó ügynök által használt port:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "ErÅ‘sen ajánlott az 5060-as port használata." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "SIP port" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Saját sip cím:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Automatikus valós hostnév megállapítása" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Azonosító" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "Proxy vagy regisztráció hozzáadás" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Szerkesztés" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Eltávolítás" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Távoli szolgáltatások" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" +"Az összes tárolt hitelesítési információ törlése (felhasználónév, jelszó...)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Hitelesítési információ" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Az audió kódoló-dekódolók listája, a preferencia rendjében:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Audio kodekek" + +#: gtk/interface.c:1608 +msgid "Video Codecs" +msgstr "Audio kodekek" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Engedélyezés" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Tiltás" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "Feltöltési sávszélesség (kbit/sec):" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "Letöltési sávszélesség (kbit/sec):" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Figyelem: A pirosban lévÅ‘ kodekek nem használhatók a jelenlegi " +"internetkapcsolattal." + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "Nem érhetÅ‘ el információ" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Kodekinformáció" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "Audio és video kodekek" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Kodekek" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Címjegyzék" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Kiválasztás" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Információk" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"A felhasználó jelenleg nem elérhetÅ‘, de kéri, hogy lépj vele kapcsolatba itt:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Nincs." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Proxy/Regisztráció konfigurációs doboz" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "Út (nem kötelezÅ‘):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "SIP Proxy:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "SIP azonosító:" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "Regisztrálási IdÅ‘köz:" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Regisztárció küldés:" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "Jelenléti információ közlése:" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Kapcsolatinformációk szerkesztése" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Név:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "Láthatósági szabály:" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "Láthatóság küldése (látszik a személy elérhetÅ‘ségi státusza)" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Kapcsolatiinformáció" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "Új beérkezÅ‘ elÅ‘fizetés" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "Megkaptál egy új elÅ‘fizetést." + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Hulladék" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "Elfogad" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Hitelesítést kértek" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "Hitelesítési kérelem a tartománynak" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "felhasználói azonosító:" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "jelszó:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "felhasználónév:" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "tartomány:" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone - HíváselÅ‘zmények" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "Chat szoba" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Szöveg:" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Chat-elés %s -el" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Nemtalálható a pixmap fájl: %s" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "Hozzáférés" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Engedélyezve" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Tiltva" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Név" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Érték (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Ãllapot" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Min bitrate (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "Korlátlan" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "A hívó forrásfoglalást kér. Egyetértesz?" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" +"A hívó nem használ forrásfoglalást. \t\t\t\t\tÃgy is szeretnéd folytatni?" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "linphone - hívást fogad innen %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" +"Kaptál egy elÅ‘fizetést tÅ‘le %s. Ez azt jelenti, hogy ez a személy szeretné, " +"hogy értesítsék a jelenlétinformációd (online, elfoglalt, away...).\n" +"Egyetértesz?" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "Hitelesítési kérelem ebbÅ‘l a tartományból %s" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Nincs" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Jelenlét státusz" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "Várakozás" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "Tiltás" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "Rossz sip cím: egy sip cím általában így néz ki: user@domain" + +#: gtk/addressbook.c:226 +msgid "Contact list" +msgstr "Kapcsolatilista" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "Van %i elhibázott hivás." + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "megszakítva" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "befejezve" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "elhibázva" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s nél %s\n" +"Tól: %s\n" +"Ig: %s\n" +"Ãllapot: %s\n" +"IdÅ‘tartam: %i perc %i másodperc\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "BeérkezÅ‘ hívás" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "KimenÅ‘ hívás" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"A géped úgy tűnik, hogy csatlakozik egy IPv6 hálózathoz. Alapból a linphone " +"mindig az IPv4-et használja. Frissítsd a konfigurációdat, ha használni " +"akarod az IPv6-ot" + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "Kész" + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "Stun keresés folyamatban..." + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "Stun keresés kész..." + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Telefonszám-cél keresése..." + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "Nem sikkerült értelmezni a számot." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Az adott szám nem értelmezhetÅ‘. Egy sip cím általában így néz ki: user@domain" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "Bocsánat, a többszörös egyidejű hívások még nem támogatottak!" + +#: coreapi/linphonecore.c:1198 +msgid "Contacting" +msgstr "Kapcsolódás" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "nem sikerült hívni" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Kapcsolódva." + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "Hívás vége" + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "Nincs nat/tűzfal cím megadva!" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "Hibás nat cím '%s' : %s" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" +"Ez a legjobb választás. Mindazonáltal a pcm* OSS emuláció modulra\n" +" a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" +"'modprobe snd-pcm-oss' parancsot rendszergazdaként." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" +"Ez a legjobb választás. Mindazonáltal a mixer OSS emuláció modulra\n" +" a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" +"'modprobe snd-pcm-oss' parancsot rendszergazdaként." + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "A hívás befejezve." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "A cél elérhetetlen." + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "A felhasználó foglalt." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "A felhasználó ideiglenesen nem elérhetÅ‘" + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Kérelem elutasítva." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "A felhasználó nem akarja, hogy zavarják." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Hívás elutasítva" + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "Rossz kérés" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Nem telálható felhasználó at adott címen." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "" +"A távoli felhasználó nem rendelkezik a javasolt kódoló-dekódolókkal (codecs)" + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "IdÅ‘túllépés." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "A távoli gép elérhetÅ‘, de a kapcsolatot visszautasította." + +#: coreapi/exevents.c:312 +msgid "is contacting you." +msgstr "kapcsolatba lép veled." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "Ãtirányítva idw %s..." + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"A felhasználó nem elérhetÅ‘ pillanatnyilag de meghívja Önt\n" +"thogy lépjen kapcsolatba vele miközben használja a következÅ‘ alternatív " +"erÅ‘forrást:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "Korai médiák." + +#: coreapi/exevents.c:837 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "A regisztáció a %s -n nem sikerült: %s" + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "idÅ‘túllépés után nincs válasz" + +#: coreapi/exevents.c:851 +#, c-format +msgid "Registration on %s successful." +msgstr "A regisztáció a %s -n sikerült." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "Elveszítve" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "Jóváhagyásra vár" + +#: coreapi/presence.c:133 +msgid "Online" +msgstr "ElérhetÅ‘" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "Foglalt" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "Legyen igazad" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "Telefonál" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "Ebédelni ment" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "Lezárva" diff --git a/linphone/po/insert-header.sin b/linphone/po/insert-header.sin new file mode 100644 index 000000000..b26de01f6 --- /dev/null +++ b/linphone/po/insert-header.sin @@ -0,0 +1,23 @@ +# Sed script that inserts the file called HEADER before the header entry. +# +# At each occurrence of a line starting with "msgid ", we execute the following +# commands. At the first occurrence, insert the file. At the following +# occurrences, do nothing. The distinction between the first and the following +# occurrences is achieved by looking at the hold space. +/^msgid /{ +x +# Test if the hold space is empty. +s/m/m/ +ta +# Yes it was empty. First occurrence. Read the file. +r HEADER +# Output the file's contents by reading the next line. But don't lose the +# current line while doing this. +g +N +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/linphone/po/it.po b/linphone/po/it.po new file mode 100644 index 000000000..680e6c73e --- /dev/null +++ b/linphone/po/it.po @@ -0,0 +1,1026 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Linphone 0.9.1\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" +"Last-Translator: Alberto Zanoni \n" +"Language-Team: it \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Rubrica" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +#, fuzzy +msgid "Enter sip address or phone number here" +msgstr "Indirizzo sip del server segretario." + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Indirizzo sip:" + +#: gtk/interface.c:247 +#, fuzzy +msgid "Shows the address book" +msgstr "Rubrica" + +#: gtk/interface.c:261 +msgid "..." +msgstr "" + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "" + +#: gtk/interface.c:278 +#, fuzzy +msgid "" +"Call or\n" +"answer" +msgstr "" +"Chiamare o\n" +"Rispondere" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Mostra altre opzioni..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Livello di riproduzione:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Livello di registrazione:" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Livello di registrazione:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Suono" + +#: gtk/interface.c:382 +#, fuzzy +msgid "Enable video" +msgstr "Attivato" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Raggiungibile" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Occupato, torno fra " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "L'altro utente sarà informato che sarai di ritorno in X minuti" + +#: gtk/interface.c:431 +msgid "5" +msgstr "" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "min" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Assente" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Non disturbare" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Temporaneamente non disponibile" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Servizio alternativo" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Presenza" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "" + +#: gtk/interface.c:561 +msgid "0" +msgstr "" + +#: gtk/interface.c:567 +msgid "#" +msgstr "" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone è un telefono su internet.\n" +"E' compatibile con i protocolli SIP et RTP." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parametri" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "" + +#: gtk/interface.c:1156 +#, fuzzy +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Numero dei pacchetti bufferizzati (compensazione jitter):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Rete" + +#: gtk/interface.c:1225 +#, fuzzy +msgid "Playback sound device:" +msgstr "Driver del suono:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "microfono" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "linea" + +#: gtk/interface.c:1250 +#, fuzzy +msgid "Capture sound device:" +msgstr "Driver del suono:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Sorgente di registrazione:" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "Driver del suono:" + +#: gtk/interface.c:1285 +#, fuzzy +msgid "Ring sound:" +msgstr "Sorgente di registrazione:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "" + +#: gtk/interface.c:1347 +#, fuzzy +msgid "Sound device" +msgstr "Driver del suono:" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Agente utente SIP sulla porta:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Si raccomanda FORTEMENTE di utilizzare la porta 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Il tuo indirizzo sip:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "" + +#: gtk/interface.c:1467 +#, fuzzy +msgid "Add proxy/registrar" +msgstr "Usa il segretario sip" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Servizi remoti:" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" + +#: gtk/interface.c:1547 +#, fuzzy +msgid "Authentication information" +msgstr "Informazioni" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Lista dei codec audio, in ordine di preferenza:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "" + +#: gtk/interface.c:1608 +#, fuzzy +msgid "Video Codecs" +msgstr "Codec" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Attivato" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Disattivato" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Nota: i codec in rosso non sono utilizzabili per il tuo tipo di connessione " +"internet." + +#: gtk/interface.c:1720 +#, fuzzy +msgid "No information availlable" +msgstr "Informazioni" + +#: gtk/interface.c:1727 +#, fuzzy +msgid "Codec information" +msgstr "Informazioni" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Codec" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Rubrica" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Seleziona" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Informazioni" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "" + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "" + +#: gtk/interface.c:2381 +#, fuzzy +msgid "Publish presence information:" +msgstr "Informazioni" + +#: gtk/interface.c:2466 +#, fuzzy +msgid "Edit contact information" +msgstr "Informazioni" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "" + +#: gtk/interface.c:2537 +#, fuzzy +msgid "Contact information" +msgstr "Informazioni" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "" + +#: gtk/interface.c:2799 +#, fuzzy +msgid "password:" +msgstr "Password:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +#, fuzzy +msgid "Enabled" +msgstr "Attivato" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +#, fuzzy +msgid "Disabled" +msgstr "Disattivato" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "" + +#: gtk/friends.c:117 +#, fuzzy +msgid "Presence status" +msgstr "Presenza" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "Connessione" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "" + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "" + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "" + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +#, fuzzy +msgid "Contacting" +msgstr "Connessione" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +#, fuzzy +msgid "Connected." +msgstr "Connessione" + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "" + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "" + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "" + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "" + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "" + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "" + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "" + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "" + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "" + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "" + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "" + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "" + +#: coreapi/exevents.c:312 +#, fuzzy +msgid "is contacting you." +msgstr "Connessione" + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "" + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "" + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, c-format +msgid "Registration on %s successful." +msgstr "" + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +#, fuzzy +msgid "Online" +msgstr "linea" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "User manual" +#~ msgstr "Manuale utente" + +#, fuzzy +#~ msgid "Address" +#~ msgstr "Rubrica" + +#, fuzzy +#~ msgid "Server address" +#~ msgstr "Indirizzo server:" + +#~ msgid "28k modem" +#~ msgstr "modem 28k" + +#~ msgid "56k modem" +#~ msgstr "modem 56k" + +#~ msgid "64k modem (numeris)" +#~ msgstr "modem 64k (numeris)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "modem ADSL o cavo" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet o equivalente" + +#~ msgid "Connection type:" +#~ msgstr "Tipo di connessione:" + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Inserire l'indirizzo sip dell'utente che si vuol chiamare." + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "Lasciare o\n" +#~ "Rifiutare" + +#~ msgid "Connection" +#~ msgstr "Connessione" + +#, fuzzy +#~ msgid "" +#~ "Add address\n" +#~ "book" +#~ msgstr "Rubrica" + +#~ msgid "Toggle this if you want to be registered on a remote server." +#~ msgstr "Clicare qui per la registrazione su un server remoto." + +#~ msgid "" +#~ "The password used for registration. On some servers it is not necessary" +#~ msgstr "" +#~ "Password usata per la registrazione. Su alcuni server non è necessaria" + +#~ msgid "sip address:" +#~ msgstr "Indirizzo sip:" + +#~ msgid "Display name:" +#~ msgstr "Mostra il nome:" diff --git a/linphone/po/ja.po b/linphone/po/ja.po new file mode 100644 index 000000000..3b8d13f50 --- /dev/null +++ b/linphone/po/ja.po @@ -0,0 +1,1156 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# »³¸ýÁ±Ìé , 2002. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: linphone 0.10\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2003-01-21 00:05+9000\n" +"Last-Translator: YAMAGUCHI YOSHIYA \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=EUC-JP\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "Linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "ÅÅÏÃÄ¢" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +#, fuzzy +msgid "Enter sip address or phone number here" +msgstr "¥ì¥¸¥¹¥È¥é¥µ¡¼¥Ð¡¼¤ÎSIP¥¢¥É¥ì¥¹" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Sip¥¢¥É¥ì¥¹:" + +#: gtk/interface.c:247 +#, fuzzy +msgid "Shows the address book" +msgstr "ÅÅÏÃÄ¢" + +#: gtk/interface.c:261 +msgid "..." +msgstr "" + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "" + +#: gtk/interface.c:278 +#, fuzzy +msgid "" +"Call or\n" +"answer" +msgstr "" +"ÅÅÏäò¤«¤±¤ë\n" +"ÅÅÏä˽Фë" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "¾ÜºÙ" + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "¼õÏò»ÎÌ" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Á÷Ïò»ÎÌ" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Á÷Ïò»ÎÌ" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "¥µ¥¦¥ó¥É" + +#: gtk/interface.c:382 +#, fuzzy +msgid "Enable video" +msgstr "»ÈÍѤ¹¤ë" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "ºßÀÊÃæ" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "º£Àʤò¤Ï¤º¤·¤Æ¤¤¤Þ¤¹¡£" + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "ȯ¿®¼Ô¤Ï¡¢¤¢¤Ê¤¿¤¬Xʬ¸å¤ËÌá¤Ã¤Æ¤¯¤ë¤³¤È¤¬Ê¬¤«¤ê¤Þ¤¹¡£" + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "ʬ" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "ÂàÀÊÃæ" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "¼ê¤¬Î¥¤»¤Þ¤»¤ó" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "¤¹¤°Ìá¤ê¤Þ¤¹" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "¾¤ÎÏ¢Íí¼êÃʤò»È¤Ã¤Æ²¼¤µ¤¤" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "¾õÂÖ" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "DTMF¤òÁ÷¿®¤¹¤ë¤¿¤á¤Î¿ô»ú¤ò²¡¤·¤Æ²¼¤µ¤¤¡£" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "Linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone¤Ï¥¤¥ó¥¿¡¼¥Í¥Ã¥ÈÅÅÏäǤ¹¡£\n" +"SIP¡¦RTP¥×¥í¥È¥³¥ë¤È¸ß´¹À­¤¬¤¢¤ê¤Þ¤¹¡£" + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "¥Ñ¥é¥á¡¼¥¿¡¼" + +#: gtk/interface.c:1061 +#, fuzzy +msgid "Use IPv6 network (if available)" +msgstr "¥æ¡¼¥¶¡¼¤Ï¡¢º£½Ð¤é¤ì¤Þ¤»¤ó¡£" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "" + +#: gtk/interface.c:1156 +#, fuzzy +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "" +"¥Ð¥Ã¥Õ¥¡¤¹¤ë¥ß¥êÉÃ\n" +"(²»À¼¤¬ÅÓÀÚ¤ì¤ë¤È¤­¤ÏÂ礭¤¯¤·¤Þ¤¹)" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "¥ª¡¼¥Ç¥£¥ª¤Ë»ÈÍѤ¹¤ëRTP¥Ý¡¼¥ÈÈÖ¹æ" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "RTP¤Î¥×¥í¥Ñ¥Æ¥£¡¼" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "¥Í¥Ã¥È¥ï¡¼¥¯" + +#: gtk/interface.c:1225 +#, fuzzy +msgid "Playback sound device:" +msgstr "»ÈÍѤ¹¤ë¥µ¥¦¥ó¥É¥Ç¥Ð¥¤¥¹" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "¥Þ¥¤¥¯ÆþÎÏ" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "¥é¥¤¥óÆþÎÏ" + +#: gtk/interface.c:1250 +#, fuzzy +msgid "Capture sound device:" +msgstr "»ÈÍѤ¹¤ë¥µ¥¦¥ó¥É¥Ç¥Ð¥¤¥¹" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Ï¿²»¤¹¤ë²»¸»" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "»ÈÍѤ¹¤ë¥µ¥¦¥ó¥É¥Ç¥Ð¥¤¥¹" + +#: gtk/interface.c:1285 +#, fuzzy +msgid "Ring sound:" +msgstr "Ï¿²»¤¹¤ë²»¸»" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "¥µ¥¦¥ó¥É¤Î¥×¥í¥Ñ¥Æ¥£¡¼" + +#: gtk/interface.c:1347 +#, fuzzy +msgid "Sound device" +msgstr "»ÈÍѤ¹¤ë¥µ¥¦¥ó¥É¥Ç¥Ð¥¤¥¹" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "SIP¥æ¡¼¥¶¡¼¥¨¡¼¥¸¥§¥ó¥È¤¬µ¯Æ°¤¹¤ë¥Ý¡¼¥È" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "5060È֥ݡ¼¥È¤ò»È¤¦¤³¤È¤ò¶¯¤¯¿ä¾©¤·¤Þ¤¹¡£" + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "SIP¤Î¥Ý¡¼¥È" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "¤¢¤Ê¤¿¤ÎSIP¥¢¥É¥ì¥¹" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "¸Ä¿Í¾ðÊó" + +#: gtk/interface.c:1467 +#, fuzzy +msgid "Add proxy/registrar" +msgstr "SIP¥ì¥¸¥¹¥È¥é¤ò»È¤¦" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "ºï½ü¤¹¤ë" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "¥ê¥â¡¼¥È¤Î¥µ¡¼¥Ó¥¹" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" + +#: gtk/interface.c:1547 +#, fuzzy +msgid "Authentication information" +msgstr "¥³¡¼¥Ç¥Ã¥¯¤Î¾ðÊó" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "¥³¡¼¥Ç¥Ã¥¯¤Î¥ê¥¹¥È¤Ç¤¹¡£»È¤¤¤¿¤¤½ç¤Ëʤ٤Ƥ¯¤À¤µ¤¤¡£" + +#: gtk/interface.c:1595 +#, fuzzy +msgid "Audio codecs" +msgstr "¥ª¡¼¥Ç¥£¥ª¥³¡¼¥Ç¥Ã¥¯¤Î¥×¥í¥Ñ¥Æ¥£¡¼" + +#: gtk/interface.c:1608 +#, fuzzy +msgid "Video Codecs" +msgstr "¥ª¡¼¥Ç¥£¥ª¥³¡¼¥Ç¥Ã¥¯¤Î¥×¥í¥Ñ¥Æ¥£¡¼" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "»ÈÍѤ¹¤ë" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "»ÈÍѤ·¤Ê¤¤" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "Ãí°Õ:ÀÖ¤¤¿§¤Î¥³¡¼¥Ç¥Ã¥¯¤Ï¡¢¸½ºß¤Î¥Í¥Ã¥È¥ï¡¼¥¯ÀܳÊýË¡¤Ç¤Ï»È¤¨¤Þ¤»¤ó¡£" + +#: gtk/interface.c:1720 +#, fuzzy +msgid "No information availlable" +msgstr "ÆÃ¤Ë¾ðÊó¤Ï¤¢¤ê¤Þ¤»¤ó" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "¥³¡¼¥Ç¥Ã¥¯¤Î¾ðÊó" + +#: gtk/interface.c:1731 +#, fuzzy +msgid "Audio and video codecs" +msgstr "¥ª¡¼¥Ç¥£¥ª¥³¡¼¥Ç¥Ã¥¯¤Î¥×¥í¥Ñ¥Æ¥£¡¼" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "¥³¡¼¥Ç¥Ã¥¯" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "ÅÅÏÃÄ¢" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "ÁªÂò¤¹¤ë" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "¾ðÊó" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"¥æ¡¼¥¶¡¼¤ËÀܳ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤¬¡¢¥æ¡¼¥¶¡¼¤ÏÂå¤ï¤ê¤Î¼êÃʤ˾·ÂÔ¤·¤Æ¤¤¤Þ" +"¤¹¡£Â¾¤Î¼êÃʤÇÏ¢Íí¤ò¤È¤Ã¤Æ¤¯¤À¤µ¤¤¡£" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "¤¢¤ê¤Þ¤»¤ó¡£" + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "" + +#: gtk/interface.c:2344 +#, fuzzy +msgid "SIP Identity:" +msgstr "¸Ä¿Í¾ðÊó" + +#: gtk/interface.c:2359 +#, fuzzy +msgid "Registration Period:" +msgstr "ÅÐÏ¿¤·¤Þ¤·¤¿¡£" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "" + +#: gtk/interface.c:2381 +#, fuzzy +msgid "Publish presence information:" +msgstr "¥³¡¼¥Ç¥Ã¥¯¤Î¾ðÊó" + +#: gtk/interface.c:2466 +#, fuzzy +msgid "Edit contact information" +msgstr "(Àܳ¤¹¤ë¤¿¤á¤Î¾ðÊ󤬤¢¤ê¤Þ¤»¤ó!)" + +#: gtk/interface.c:2505 +#, fuzzy +msgid "Name:" +msgstr "̾Á°" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "" + +#: gtk/interface.c:2537 +#, fuzzy +msgid "Contact information" +msgstr "¥³¡¼¥Ç¥Ã¥¯¤Î¾ðÊó" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "" + +#: gtk/interface.c:2799 +#, fuzzy +msgid "password:" +msgstr "¥Ñ¥¹¥ï¡¼¥É" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "pixmap¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó %s" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "»ÈÍѤ¹¤ë" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "»ÈÍѤ·¤Ê¤¤" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "̾Á°" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "¾õÂÖ" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "ºÇÄã¸Â¤Î¥Ó¥Ã¥È¥ì¡¼¥È (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "" + +#: gtk/linphone.c:410 +#, fuzzy +msgid "None" +msgstr "¤¢¤ê¤Þ¤»¤ó¡£" + +#: gtk/friends.c:117 +#, fuzzy +msgid "Presence status" +msgstr "¾õÂÖ" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +#, fuzzy +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" +"SIP¥¢¥É¥ì¥¹¤Î·Á¼°¥¨¥é¡¼¤Ç¤¹¡£SIP¥¢¥É¥ì¥¹¤Ï¡¢¤Î¤è¤¦¤Ê" +"·Á¼°¤Ç¤¹¡£" + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "ÀÜÂ³Ãæ" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" + +#: coreapi/linphonecore.c:692 +#, fuzzy +msgid "Ready" +msgstr "½àÈ÷´°Î»¡£" + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "" + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "" + +#: coreapi/linphonecore.c:1138 +#, fuzzy +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"SIP¥¢¥É¥ì¥¹¤Î·Á¼°¥¨¥é¡¼¤Ç¤¹¡£SIP¥¢¥É¥ì¥¹¤Ï¡¢¤Î¤è¤¦¤Ê" +"·Á¼°¤Ç¤¹¡£" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +#, fuzzy +msgid "Contacting" +msgstr "ÀÜÂ³Ãæ" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Àܳ¤·¤Þ¤·¤¿¡£" + +#: coreapi/linphonecore.c:1550 +#, fuzzy +msgid "Call ended" +msgstr "ÄÌÏäϵñÈݤµ¤ì¤Þ¤·¤¿¡£" + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"¤³¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤ÏALSA¥µ¥¦¥ó¥É¥É¥é¥¤¥Ð¡¼¤ò»ÈÍѤ·¤Æ¤¤¤ë¤è¤¦¤Ç¤¹¡£\n" +"¤½¤ì¤ÏºÇÎɤÎÁªÂò¤Ç¤¹¡£¤·¤«¤·¡¢Linphone¤¬É¬ÍפȤ¹¤ë\n" +"pcm oss¥¨¥ß¥å¥ì¡¼¥·¥ç¥ó¥â¥¸¥å¡¼¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n" +"¥í¡¼¥É¤¹¤ë¤¿¤á¤Ë¡¢¥ë¡¼¥È¸¢¸Â¤Ç'modprobe snd-pcm-oss'¤ò¼Â¹Ô¤·¤Æ¤¯¤À¤µ¤¤¡£" + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"¤³¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤ÏALSA¥µ¥¦¥ó¥É¥É¥é¥¤¥Ð¡¼¤ò»ÈÍѤ·¤Æ¤¤¤ë¤è¤¦¤Ç¤¹¡£\n" +"¤½¤ì¤ÏºÇÎɤÎÁªÂò¤Ç¤¹¡£¤·¤«¤·¡¢Linphone¤¬É¬ÍפȤ¹¤ë\n" +"mixer oss¥¨¥ß¥å¥ì¡¼¥·¥ç¥ó¥â¥¸¥å¡¼¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n" +"¥í¡¼¥É¤¹¤ë¤¿¤á¤Ë¡¢¥ë¡¼¥È¸¢¸Â¤Ç'modprobe snd-mixer-oss'¤ò¼Â¹Ô¤·¤Æ¤¯¤À¤µ¤¤¡£" + +#: coreapi/exevents.c:115 +#, fuzzy +msgid "Call terminated." +msgstr "ÄÌÏäϵñÈݤµ¤ì¤Þ¤·¤¿¡£" + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "" + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "¥æ¡¼¥¶¡¼¤Ï¥Ó¥¸¡¼¤Ç¤¹" + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "¥æ¡¼¥¶¡¼¤Ï¡¢º£½Ð¤é¤ì¤Þ¤»¤ó¡£" + +#: coreapi/exevents.c:148 +#, fuzzy +msgid "Request Cancelled." +msgstr "ÄÌÏäϥ­¥ã¥ó¥»¥ë¤µ¤ì¤Þ¤·¤¿¡£" + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "¥æ¡¼¥¶¡¼¤Ï¼ê¤¬Î¥¤»¤Ê¤¤¤è¤¦¤Ç¤¹¡£" + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "ÄÌÏäϵñÈݤµ¤ì¤Þ¤·¤¿¡£" + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "¥æ¡¼¥¶¡¼¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£" + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "Áê¼ê¦¤Ç¤Ï¡¢Ä󰯤·¤¿¥³¡¼¥Ç¥Ã¥¯¤ò°ì¤Ä¤â¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó¡£" + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "»þ´ÖÀÚ¤ì¤Ç¤¹¡£" + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "¥ê¥â¡¼¥È¥Û¥¹¥È¤¬¸«¤Ä¤«¤ê¤Þ¤·¤¿¤¬¡¢Àܳ¤òµñÈݤµ¤ì¤Þ¤·¤¿¡£" + +#: coreapi/exevents.c:312 +#, fuzzy +msgid "is contacting you." +msgstr "¤«¤éÅÅÏäǤ¹¡£" + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "" + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"¥æ¡¼¥¶¡¼¤ËÀܳ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤¬¡¢¥æ¡¼¥¶¡¼¤ÏÂå¤ï¤ê¤Î¼êÃʤ˾·ÂÔ¤·¤Æ¤¤¤Þ" +"¤¹¡£\n" +"¾¤Î¼êÃʤÇÏ¢Íí¤ò¤È¤Ã¤Æ¤¯¤À¤µ¤¤¡£" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "ÅÐÏ¿¤·¤Þ¤·¤¿¡£" + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, fuzzy, c-format +msgid "Registration on %s successful." +msgstr "ÅÐÏ¿¤·¤Þ¤·¤¿¡£" + +#: coreapi/presence.c:112 coreapi/presence.c:164 +#, fuzzy +msgid "Gone" +msgstr "¤¢¤ê¤Þ¤»¤ó¡£" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +#, fuzzy +msgid "Online" +msgstr "¥é¥¤¥óÆþÎÏ" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "User manual" +#~ msgstr "¥æ¡¼¥¶¡¼¥Þ¥Ë¥å¥¢¥ë" + +#~ msgid "Communication ended." +#~ msgstr "²ñÏäϽªÎ»¤·¤Þ¤·¤¿¡£" + +#~ msgid "Call cancelled." +#~ msgstr "ÄÌÏäϥ­¥ã¥ó¥»¥ë¤µ¤ì¤Þ¤·¤¿¡£" + +#~ msgid "Address" +#~ msgstr "¥¢¥É¥ì¥¹" + +#, fuzzy +#~ msgid "Server address" +#~ msgstr "¥µ¡¼¥Ð¡¼¤Î¥¢¥É¥ì¥¹" + +#~ msgid "28k modem" +#~ msgstr "28k¤Î¥â¥Ç¥à" + +#~ msgid "56k modem" +#~ msgstr "56k¤Î¥â¥Ç¥à" + +#~ msgid "64k modem (numeris)" +#~ msgstr "64K¤Î¥â¥Ç¥à(ISDN)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL¡¦CATV¥â¥Ç¥à" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "¥¤¡¼¥µ¥Í¥Ã¥È¤Ê¤É" + +#~ msgid "Connection type:" +#~ msgstr "Àܳ¤Î¥¿¥¤¥×" + +#, fuzzy +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone¤Ï¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò¥ª¡¼¥×¥ó¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£¥µ¥¦¥ó¥É¥«¡¼¥É¤ÎÀß" +#~ "Ä꤬´°Á´¤Ç¡¢Àµ¤·¤¯Æ°¤¤¤Æ¤¤¤ë¤«¤É¤¦¤«³Îǧ¤·¤Æ²¼¤µ¤¤¡£" + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "ÅÅÏäò¤«¤±¤¿¤¤Áê¼ê¤ÎSIP¥¢¥É¥ì¥¹¤òÆþÎϤ·¤Æ²¼¤µ¤¤¡£" + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "ÅÅÏäòÀÚ¤ë\n" +#~ "²ñÏäòµñÈÝ" + +#~ msgid "%s. Retry after %i minute(s)." +#~ msgstr "%s¡£%i ʬ¸å¤Ë¤«¤±Ä¾¤·¤Æ²¼¤µ¤¤¡£" + +#, fuzzy +#~ msgid "Timeout..." +#~ msgstr "»þ´ÖÀÚ¤ì¤Ç¤¹¡£" + +#~ msgid "Connection" +#~ msgstr "¥³¥Í¥¯¥·¥ç¥ó" + +#, fuzzy +#~ msgid "" +#~ "Add address\n" +#~ "book" +#~ msgstr "ÅÅÏÃÄ¢" + +#~ msgid "Toggle this if you want to be registered on a remote server." +#~ msgstr "¥ê¥â¡¼¥È¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤ë¤È¤­¤Ï¡¢¥Á¥§¥Ã¥¯¤·¤Æ²¼¤µ¤¤¡£" + +#~ msgid "Address of record:" +#~ msgstr "ÅÐÏ¿¤¹¤ë¥¢¥É¥ì¥¹" + +#~ msgid "" +#~ "The password used for registration. On some servers it is not necessary" +#~ msgstr "ÅÐÏ¿¤Ë¥Ñ¥¹¥ï¡¼¥É¤òÍѤ¤¤Þ¤¹¡£É¬¿Ü¤Ç¤Ê¤¤¥µ¡¼¥Ð¡¼¤â¤¢¤ê¤Þ¤¹¡£" + +#~ msgid "Use this registrar server as outbound proxy." +#~ msgstr "¥ì¥¸¥¹¥È¥é¥µ¡¼¥Ð¡¼¤ò¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤È¤·¤Æ»ÈÍѤ·¤Þ¤¹¡£" + +#~ msgid "sip address:" +#~ msgstr "SIP¥¢¥É¥ì¥¹" + +#~ msgid "Display name:" +#~ msgstr "ɽ¼¨¤µ¤ì¤ë̾Á°" + +#~ msgid "Modify" +#~ msgstr "½¤Àµ" + +#~ msgid "Registering..." +#~ msgstr "ÅÐÏ¿Ãæ¡Ä¡Ä" + +#, fuzzy +#~ msgid "" +#~ "You are currently using the i810_audio driver.\n" +#~ "This driver is buggy and so does not work with Linphone.\n" +#~ "We suggest that you replace it by its equivalent ALSA driver,\n" +#~ "either with packages from your distribution, or by downloading\n" +#~ "ALSA drivers at http://www.alsa-project.org." +#~ msgstr "" +#~ "¸½ºß¡¢i810¥ª¡¼¥Ç¥£¥ª¥É¥é¥¤¥Ð¡¼¤ò»È¤Ã¤Æ¤¤¤Þ¤¹¡£\n" +#~ "¤³¤Î¥É¥é¥¤¥Ð¡¼¤Ë¤Ï¥Ð¥°¤¬¤¢¤ê¡¢Linphone¤Ç¤Ï¤¦¤Þ¤¯Æ°ºî¤·¤Þ¤»¤ó¡£\n" +#~ "ALSA¥É¥é¥¤¥Ð¡¼¤ËÁêÅö¤¹¤ë\n" +#~ "¤¢¤Ê¤¿¤Î¥Ç¥£¥¹¥È¥ê¥Ó¥å¡¼¥¸¥ç¥ó¤Î¥Ñ¥Ã¥±¡¼¥¸¤«¡¢\n" +#~ "ALSA¥É¥é¥¤¥Ð¡¼(http://www.alsa-project.org)¤Ø¤Î¸ò´¹¤ò¿ä¾©¤·¤Þ¤¹¡£" + +#~ msgid "Unregistration successfull." +#~ msgstr "ÅÐÏ¿¤ò²ò½ü¤·¤Þ¤·¤¿¡£" + +#~ msgid "3" +#~ msgstr "3" + +#~ msgid "2" +#~ msgstr "2" + +#~ msgid "4" +#~ msgstr "4" + +#~ msgid "6" +#~ msgstr "6" + +#~ msgid "7" +#~ msgstr "7" + +#~ msgid "8" +#~ msgstr "8" + +#~ msgid "9" +#~ msgstr "9" + +#~ msgid "Select network interface to use:" +#~ msgstr "»ÈÍѤ¹¤ë¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ó¤Ç²¼¤µ¤¤" + +#~ msgid "Network interface properties" +#~ msgstr "¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Î¥×¥í¥Ñ¥Æ¥£¡¼" + +#~ msgid "RTP" +#~ msgstr "RTP" + +#~ msgid "Audio" +#~ msgstr "¥ª¡¼¥Ç¥£¥ª" + +#~ msgid "C: 2001" +#~ msgstr "C: 2001" + +#~ msgid "/dev/dsp" +#~ msgstr "/dev/dsp" + +#~ msgid "/dev/dsp1" +#~ msgstr "/dev/dsp1" + +#~ msgid "/dev/dsp2" +#~ msgstr "/dev/dsp2" + +#~ msgid "/dev/dsp3" +#~ msgstr "/dev/dsp3" + +#~ msgid "Add" +#~ msgstr "Äɲ乤ë" + +#~ msgid "Set the selected address in linphone'main window." +#~ msgstr "ÁªÂò¤·¤¿¥¢¥É¥ì¥¹¤¬Linphone¤Î¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤Ë¸½¤ì¤Þ¤¹¡£" diff --git a/linphone/po/linphone.pot b/linphone/po/linphone.pot new file mode 100644 index 000000000..3f01f8818 --- /dev/null +++ b/linphone/po/linphone.pot @@ -0,0 +1,930 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "" + +#: gtk/interface.c:261 +msgid "..." +msgstr "" + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "" + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "" + +#: gtk/interface.c:354 +msgid "Ring level:" +msgstr "" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "" + +#: gtk/interface.c:382 +msgid "Enable video" +msgstr "" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "" + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "" + +#: gtk/interface.c:431 +msgid "5" +msgstr "" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "" + +#: gtk/interface.c:561 +msgid "0" +msgstr "" + +#: gtk/interface.c:567 +msgid "#" +msgstr "" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "" + +#: gtk/interface.c:849 gtk/interface.c:3029 +msgid "Linphone" +msgstr "" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "" + +#: gtk/interface.c:1277 +msgid "Ring sound device" +msgstr "" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "" + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "" + +#: gtk/interface.c:1608 +msgid "Video Codecs" +msgstr "" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "" + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" + +#: gtk/addressbook.c:226 +msgid "Contact list" +msgstr "" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "" + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "" + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "" + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +msgid "Contacting" +msgstr "" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "" + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "" + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "" + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "" + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "" + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "" + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "" + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "" + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "" + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "" + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "" + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "" + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "" + +#: coreapi/exevents.c:312 +msgid "is contacting you." +msgstr "" + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "" + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "" + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, c-format +msgid "Registration on %s successful." +msgstr "" + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +msgid "Online" +msgstr "" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" diff --git a/linphone/po/nl.po b/linphone/po/nl.po new file mode 100644 index 000000000..e61ff87c9 --- /dev/null +++ b/linphone/po/nl.po @@ -0,0 +1,1062 @@ +# translation of nl.po to Nederlands +# Dutch translation of linphone. +# Copyright (C) 2005 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the linphone package. +# Taco Witte , 2005. +# Hendrik-Jan Heins , 2005. +# Hendrik-Jan Heins , 2007. +# +msgid "" +msgstr "" +"Project-Id-Version: nl\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2007-09-05 10:40+0200\n" +"Last-Translator: Hendrik-Jan Heins \n" +"Language-Team: Nederlands \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "Een Vrije SIP video-telefoon" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Ga" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Adresboek" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Oproepgeschiedenis" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Oproepen weergeven" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "Einde" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "Help" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "Geef het SIP adres of telefoonnummer in" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "SIP-adres:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Het adresboek weergeven" + +#: gtk/interface.c:261 +msgid "..." +msgstr "..." + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Te gebruiken proxy:" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Oproepen of\n" +"beantwoorden" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +"Ophangen\n" +"of weigeren" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Of chat!" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Meer weergeven..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Geluidssterkte afspelen:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Geluidssterkte opname:" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Geluidssterkte opname:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Geluid" + +#: gtk/interface.c:382 +msgid "Enable video" +msgstr "Video aan" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "Video" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "Functies" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Bereikbaar" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Bezig; ik ben terug over " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "" +"De andere partij zal worden geïnformeerd dat u over X minuten terug bent" + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "min" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Afwezig" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Niet storen" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Tijdelijk verplaatst" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Alternatieve dienst" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Aanwezigheid" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Druk op de cijfers om DTMF's te sturen" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" +" 3\n" +"def" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" +" 2\n" +"abc" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" +" 4\n" +"ghi" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" +" 5\n" +"jkl" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" +" 6\n" +"mno" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" +" 7\n" +"pqrs" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" +" 8\n" +"tuv" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" +" 9\n" +"wxyz" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "Mijn online vrienden" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" +"C: 2001\n" +"Gemaakt in antiek Europa" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone is een webtelefoon.\n" +"Het werkt met de SIP- en RTP-protocollen." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "http://www.linphone.org" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parameters" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "Gebruik IPv6 netwerk (wanneer het beschikbaar is)" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" +"Wijzig dit wanneer u op een IPv6 netwerk zit en linphone daarop wilt " +"gebruiken." + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "Globaal" + +#: gtk/interface.c:1081 +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Deze optie is alleen voor gebruikers in een lokaal netwerk, achter een " +"gateway: Wanneer u niet in deze situatie zit, laat dit dan leeg." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "Geen firewall" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "Gebruik deze STUN server om het firewall adres te achterhalen" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "Geef het firewall adres handmatig op" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "NAT-doorstuur opties (experimenteel)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Aantal gebufferde miliseconden (jitter compensatie):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "RTP-poort voor geluid:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "RTP-eigenschappen" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "Gebruik SIP INFO bericht in plaats van RTP rfc2833 voor DTMF berichten" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "RTP-RFC2833 is de aanbevolen manier." + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Overige" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Netwerk" + +#: gtk/interface.c:1225 +#, fuzzy +msgid "Playback sound device:" +msgstr "Geluidsapparaat gebruiken:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "microfoon" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "lijn" + +#: gtk/interface.c:1250 +#, fuzzy +msgid "Capture sound device:" +msgstr "Geluidsapparaat gebruiken:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Bron voor opname:" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "Geluidsapparaat gebruiken:" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "Belgeluid:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" +"Activeer de echo-onderdrukking (onderdrukt de echo die de andere partij " +"hoort)" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "Kies bestand" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Luisteren" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Geluidseigenschappen" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Geluidsapparaat" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Start SIP gebruikerssysteem op poort:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Het wordt sterk aangeraden om poort 5060 te gebruiken." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "SIP-poort" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Uw SIP-adres:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Automatisch een geldige hostnaam raden" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identiteit" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "Voeg proxy/registratieserver toe" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Bewerken" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Verwijderen" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Externe diensten" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" +"Schoon alle opgeslagen authorisatie gegevens op (gebruikersnaam, " +"wachtwoord...)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Authorisatie gegevens" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Lijst met audio codecs, in volgorde van voorkeur:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Audio codecs" + +#: gtk/interface.c:1608 +msgid "Video Codecs" +msgstr "Video codecs" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Aan" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Uit" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "Upload bandbreedte (kbit/sec):" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "Download bandbreedte (kbit/sec):" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Opmerking: Met rood weergegeven codecs zijn niet bruikbaar vanwege het soort " +"internetverbinding dat u heeft" + +#: gtk/interface.c:1720 +#, fuzzy +msgid "No information availlable" +msgstr "Geen informatie beschikbaar" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Codec informatie" + +#: gtk/interface.c:1731 +msgid "Audio and video codecs" +msgstr "Audio en video codecs" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Codecs" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Adresboek" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Kiezen" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Informatie" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"De gebruiker is op dit moment niet bereikbaar, maar hij nodigt u uit op de " +"volgende, alternatieve, manier contact met hem op te nemen:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Geen." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Proxy/registratieserver registratieveld" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "Route (optioneel):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "SIP-proxy:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "SIP-identiteit:" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "Registratieperiode:" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Verstruur registratie:" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "Toon informatie over aanwezigheid:" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Bewerk contactgegevens" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Naam:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "Aanmeldbeleid:" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "Verstruur aanmelding (bekijk de online status van een persoon)" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Contact informatie" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "Nieuwe inkomende aanmelding" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "U heeft een nieuwe aanmelding ontvangen..." + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Weigeren" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "Accepteren" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Authorisatie gevraagd" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "Authorisatie benodigd voor gebied" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "gebruikersID:" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "wachtwoord:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "gebruikersnaam:" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "gebied:" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone - Oproepgeschiedenis" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "Chat box" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Tekst:" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Chat met %s" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Kon pixmap bestand %s niet vinden" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "Account" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Aan" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Uit" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Naam" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Frequentie (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Status" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Minimale bitrate (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "Ongelimiteerd" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "De beller vraagt om reservering van bronnen. Gaat u accoord?" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" +"De beller gebruikt geen bron reservatie. \t\t\t\t\tWilt u toch doorgaan?" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "Linphone - binnenkomend gesprek van %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" +"U heeft een aanmelding ontvangen van %s. Dit betekent dat deze persoon een " +"melding wil ontvangen wat betreft uw status (online, bezig, weg...).\n" +"Gaat u accoord?" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "Authorisatie benodigd voor gebied %s" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Geen" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Aanwezigheidsstatus" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "Wachten" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "Weigeren" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" +"Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" +"gebruikersnaam@domeinnaam" + +#: gtk/addressbook.c:226 +msgid "Contact list" +msgstr "Contactlijst" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "U heeft %i oproep(en) gemist." + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "afgebroken" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "voltooid" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "gemist" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s op %s\n" +"Van: %s\n" +"Aan: %s\n" +"Status: %s\n" +"Tijdsduur: %i mins %i secs\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "Inkomende oproep" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "Uitgaande oproep" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"Uw machine lijkt verbonden te zijn met een IPv6 netwerk. Standaard gebruikt " +"linphone altijd IPv4. Wijzig uw configuratie wanneer u IPv6 wilt gebruiken." + +#: coreapi/linphonecore.c:692 +msgid "Ready" +msgstr "Gereed." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "STUN adres wordt opgezocht..." + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "STUN adres gevonden..." + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Zoekt de lokatie van het telefoonnummer..." + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "Kon dit nummer niet vinden." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" +"gebruikersnaam@domeinnaam" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "Helaas, meerdere gelijktijdige gesprekken wordt nog niet ondersteund!" + +#: coreapi/linphonecore.c:1198 +msgid "Contacting" +msgstr "Verbinden" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "Kon niet oproepen" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Verbonden." + +#: coreapi/linphonecore.c:1550 +msgid "Call ended" +msgstr "Oproep beeindigd" + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "Geen NAT/firewall adres opgegeven" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "Ongeldig NAT adres '%s' : %s" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" +"Dit is de beste keuze. Maar de pcm oss emulatie module mist\n" +"en linphone heeft deze nodig. Geeft u alstublieft het commando\n" +"'modprobe snd-pcm-oss' als root om de module te laden." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" +"Dit is de beste keuze. Maar de mixer oss emulatie module mist\n" +"en linphone heeft deze nodig. Geeft u alstublieft het commando\n" +"'modprobe snd-mixer-oss' als root om de module te laden." + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "Oproep beeindigd." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "Kon bestemming niet bereiken." + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Gebruiker is bezet." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "Gebruiker is tijdelijk niet beschikbaar." + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Verzoek geannuleerd." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "De gebruiker wenst niet gestoord te worden." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Oproep geweigerd." + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "Slecht geformuleerd verzoek" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Gebruiker kan niet worden gevonden bij opgegeven adres." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "De externe gebruiker ondersteunt geen van de voorgestelde codecs." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "Time-out." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Externe machine is gevonden, maar verbinding is geweigerd." + +#: coreapi/exevents.c:312 +msgid "is contacting you." +msgstr "belt u." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "Doorgeschakeld naar %s..." + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"De gebruiker is op dit moment niet bereikbaar, maar hij nodigt u uit om\n" +"op de volgende, alternatieve, manier contact met hem op te nemen:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Registratie op %s mislukt (time-out)." + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, c-format +msgid "Registration on %s successful." +msgstr "Registratie op %s gelukt." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +msgid "Gone" +msgstr "Weg" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "Wachten op accoord" + +#: coreapi/presence.c:133 +msgid "Online" +msgstr "Aanwezig" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "Bezet" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "Kom zo terug" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "Aan de telefoon" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "Aan het lunchen" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "Gesloten" + +#~ msgid "User manual" +#~ msgstr "Handleiding" + +#~ msgid "Ring sound selection" +#~ msgstr "Belgeluid keuze" + +#~ msgid "Communication ended." +#~ msgstr "Communicatie beëindigd." + +#~ msgid "Call cancelled." +#~ msgstr "Oproep geannuleerd." + +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "Extern IP adres van de firewall (in x.x.x.x notatie):" + +#~ msgid "Index" +#~ msgstr "Index" + +#~ msgid "Address" +#~ msgstr "Adres" + +#~ msgid "Server address" +#~ msgstr "Serveradres" + +#~ msgid "28k modem" +#~ msgstr "28k modem" + +#~ msgid "56k modem" +#~ msgstr "56k modem" + +#~ msgid "64k modem (numeris)" +#~ msgstr "64k modem (ISDN)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL- of kabelmodem" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet of vergelijkbaar" + +#~ msgid "Connection type:" +#~ msgstr "Soort verbinding:" + +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone kon het geluidsapparaat %s niet openen. Controleer of uw " +#~ "geluidskaart goed is ingesteld en werkt." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Geef hier het SIP-adres op van de persoon die u wilt bellen." + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "Ophangen\n" +#~ "of weigeren" + +#~ msgid "%s. Retry after %i minute(s)." +#~ msgstr "%s. Opnieuw proberen na %i minu(u)t(en)." diff --git a/linphone/po/pl.po b/linphone/po/pl.po new file mode 100644 index 000000000..7027ffc7f --- /dev/null +++ b/linphone/po/pl.po @@ -0,0 +1,1122 @@ +# SIP Telephony Application. +# Copyright (C) 2001, 2002 Free Software Foundation, Inc. +# Simon Morlat , 2001. +# +msgid "" +msgstr "" +"Project-Id-Version: linphone 0.7.1\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2003-08-22 12:50+0200\n" +"Last-Translator: Robert Nasiadek \n" +"Language-Team: Polski \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8-bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Książka adresowa" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "" + +#: gtk/interface.c:188 +msgid "Exit" +msgstr "" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +#, fuzzy +msgid "Enter sip address or phone number here" +msgstr "Adres serwera rejestracji sip" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Adres sip:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Pokazuje książkÄ™ adresowÄ…" + +#: gtk/interface.c:261 +msgid "..." +msgstr "..." + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "" + +#: gtk/interface.c:278 +#, fuzzy +msgid "" +"Call or\n" +"answer" +msgstr "" +"ZadzwoÅ„ lub\n" +"Odpowiedz" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Pokaż wiÄ™cej" + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Poziom odtwarzania:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Poziom nagrywania:" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Poziom nagrywania:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "DźwiÄ™k" + +#: gtk/interface.c:382 +#, fuzzy +msgid "Enable video" +msgstr "Włączone" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "DostÄ™pny" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "ZajÄ™ty, wrócÄ™ za " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "Osoba zostanie powiadomiona, że wrócisz za X minut." + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "mn" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "ZajÄ™ty" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Nie przeszkadzać" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Tymczasowo niedostÄ™pny" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Alternatywny adres" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Obecność" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Nacisnij cyfry, aby wysÅ‚ać DTMFy." + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone jest telefonem internetowym.\n" +"Jest kompatybilny z protokolami SIP i RTP." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parametr" + +#: gtk/interface.c:1061 +#, fuzzy +msgid "Use IPv6 network (if available)" +msgstr "Osoba jest tymczasowo niedostÄ™pna." + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +#, fuzzy +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Ta opcja jest tylko dla osób w sieci prywatnej, znajdujÄ…cych siÄ™ za " +"firewallem. Jeżeli nie jesteÅ› w takiej sytuacji, nie zmieniaj tej opcji." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "Opcje NAT traversal (eksperymentalne)" + +#: gtk/interface.c:1156 +#, fuzzy +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Czas bufora w milisekundach (kompensacja jitter):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "Port RTP dla dźwiÄ™ku:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "WÅ‚aÅ›ciwoÅ›ci RTP" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "" + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Sieć" + +#: gtk/interface.c:1225 +#, fuzzy +msgid "Playback sound device:" +msgstr "Użyj tego urzÄ…dzenia dźwiÄ™ku:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "mikrofon" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "linia" + +#: gtk/interface.c:1250 +#, fuzzy +msgid "Capture sound device:" +msgstr "Użyj tego urzÄ…dzenia dźwiÄ™ku:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "ŹródÅ‚o nagrywania:" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "Użyj tego urzÄ…dzenia dźwiÄ™ku:" + +#: gtk/interface.c:1285 +#, fuzzy +msgid "Ring sound:" +msgstr "ŹródÅ‚o nagrywania:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "WÅ‚aÅ›ciwoÅ›ci dźwiÄ™ku" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "DźwiÄ™k" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Uruchom agenta sip na porcie:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Rekomendowane jest użycie portu 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "Port SIP" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Twój adres sip:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Tożsamość" + +#: gtk/interface.c:1467 +#, fuzzy +msgid "Add proxy/registrar" +msgstr "Użyj rejestracji sip" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Zdalne usÅ‚ugi" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" + +#: gtk/interface.c:1547 +#, fuzzy +msgid "Authentication information" +msgstr "Informacje o kodeku" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Lista kodeków audio, w kolejnoÅ›ci preferencji:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Kodeki audio" + +#: gtk/interface.c:1608 +#, fuzzy +msgid "Video Codecs" +msgstr "Kodeki audio" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Włączony" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Wyłącz" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Uwaga: Czerwone kodeki nie mogÄ… być użyte, ze wzglÄ™du na typTwojego " +"połącznia z internetem." + +#: gtk/interface.c:1720 +#, fuzzy +msgid "No information availlable" +msgstr "Brak informacji" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Informacje o kodeku" + +#: gtk/interface.c:1731 +#, fuzzy +msgid "Audio and video codecs" +msgstr "Kodeki audio" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Kodeki" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Książka adresowa" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Wybierz" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Informacja" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"Użytkownik nie jest dostÄ™pny, ale proponuje kontakt poprzez alternatywny " +"adres:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Brak." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "" + +#: gtk/interface.c:2344 +#, fuzzy +msgid "SIP Identity:" +msgstr "Tożsamość" + +#: gtk/interface.c:2359 +#, fuzzy +msgid "Registration Period:" +msgstr "Rejestracja powiodÅ‚a siÄ™." + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "" + +#: gtk/interface.c:2381 +#, fuzzy +msgid "Publish presence information:" +msgstr "Informacje o kodeku" + +#: gtk/interface.c:2466 +#, fuzzy +msgid "Edit contact information" +msgstr "(Brak informacji kontaktowych !)" + +#: gtk/interface.c:2505 +#, fuzzy +msgid "Name:" +msgstr "Nazwa" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "" + +#: gtk/interface.c:2537 +#, fuzzy +msgid "Contact information" +msgstr "Informacje o kodeku" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "" + +#: gtk/interface.c:2799 +#, fuzzy +msgid "password:" +msgstr "Twoje hasÅ‚o:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Nie można znaleźć pixmapy: %s" + +#: gtk/propertybox.c:207 +msgid "Account" +msgstr "" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Włączone" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Wyłączone" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Nazwa" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Jakość (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Status" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Min przepustowość (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "" + +#: gtk/linphone.c:410 +#, fuzzy +msgid "None" +msgstr "Brak." + +#: gtk/friends.c:117 +#, fuzzy +msgid "Presence status" +msgstr "Obecność" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +#, fuzzy +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "Nie poprawny adres sip. Adres sip wyglÄ…da tak " + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "Dzwonie do " + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "" + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "" + +#: coreapi/linphonecore.c:223 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" + +#: coreapi/linphonecore.c:692 +#, fuzzy +msgid "Ready" +msgstr "Gotowy." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "" + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "" + +#: coreapi/linphonecore.c:1138 +#, fuzzy +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "Nie poprawny adres sip. Adres sip wyglÄ…da tak " + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +#, fuzzy +msgid "Contacting" +msgstr "Dzwonie do " + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Połączony" + +#: coreapi/linphonecore.c:1550 +#, fuzzy +msgid "Call ended" +msgstr "Rozmowa odrzucona." + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Używasz sterowników ALSA do dźwiÄ™ku.\n" +"To jest najlepszy wybór. Jednak brakuje moduÅ‚u emulacji pcm oss,\n" +"a Linphone go wymaga. Uruchom 'modprobe snd-pcm-oss' jako root,\n" +"aby go zaÅ‚adować" + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Używasz sterowników ALSA do dźwiÄ™ku.\n" +"To jest najlepszy wybór. Jednak brakuje moduÅ‚u emulacji mixera oss,\n" +"a Linphone go wymaga. Uruchom 'modprobe snd-mixer-oss' jako root,\n" +"aby go zaÅ‚adować" + +#: coreapi/exevents.c:115 +#, fuzzy +msgid "Call terminated." +msgstr "Rozmowa odrzucona." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "" + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Osoba jest zajÄ™ta." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "Osoba jest tymczasowo niedostÄ™pna." + +#: coreapi/exevents.c:148 +#, fuzzy +msgid "Request Cancelled." +msgstr "Połączenie odwoÅ‚ane." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "Osoba nie chce, aby jej przeszkadzać." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Rozmowa odrzucona." + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Osoba nie istnieje pod tym adresem." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "Osoba nie posiada żadnych zaproponowanych kodeków." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "UpÅ‚ynÄ…Å‚ limit czasu." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Serwer istnieje, ale odrzuciÅ‚ połączenie." + +#: coreapi/exevents.c:312 +#, fuzzy +msgid "is contacting you." +msgstr "dzwoni do Ciebie." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "" + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"Użytkownik nie jest dostÄ™pny, ale proponuje kontakt poprzez alternatywny " +"adres:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Rejestracja powiodÅ‚a siÄ™." + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, fuzzy, c-format +msgid "Registration on %s successful." +msgstr "Rejestracja powiodÅ‚a siÄ™." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +#, fuzzy +msgid "Gone" +msgstr "Brak." + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +#, fuzzy +msgid "Online" +msgstr "linia" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "User manual" +#~ msgstr "PodrÄ™cznik" + +#~ msgid "Communication ended." +#~ msgstr "Komunikacja zakoÅ„czona." + +#~ msgid "Call cancelled." +#~ msgstr "Połączenie odwoÅ‚ane." + +#, fuzzy +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "Adres IP firewall'u (w notacji kropkowej):" + +#~ msgid "Index" +#~ msgstr "Indeks" + +#~ msgid "Address" +#~ msgstr "Adres" + +#, fuzzy +#~ msgid "Server address" +#~ msgstr "Adres serwera:" + +#~ msgid "28k modem" +#~ msgstr "Modem 28K" + +#~ msgid "56k modem" +#~ msgstr "Modem 56K" + +#~ msgid "64k modem (numeris)" +#~ msgstr "Modem ISDN 64K" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL lub połączenie kablowe" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "LAN lub podobne" + +#~ msgid "Connection type:" +#~ msgstr "Typ połączenia:" + +#, fuzzy +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone nie mógÅ‚ otworzyć urzÄ…dzenia dźwiÄ™ku. Sprawdź czy Twoja karta " +#~ "jest dobrze skonfigurowana." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Tutaj wpisz adres sip osoby, do której chcesz zadzwonić" + +#~ msgid "" +#~ "Release or\n" +#~ "Refuse" +#~ msgstr "" +#~ "Rozłącz lub\n" +#~ "Odmów" + +#~ msgid "%s. Retry after %i minute(s)." +#~ msgstr "%s. Spróbuj za %i minut." + +#, fuzzy +#~ msgid "Timeout..." +#~ msgstr "UpÅ‚ynÄ…Å‚ limit czasu." + +#~ msgid "Connection" +#~ msgstr "LÄ…cze" + +#, fuzzy +#~ msgid "" +#~ "Add address\n" +#~ "book" +#~ msgstr "Książka adresowa" + +#~ msgid "Toggle this if you want to be registered on a remote server." +#~ msgstr "Włącz to, jeżeli chcesz siÄ™ zarejestrować na zdalnym serwerze." + +#~ msgid "Address of record:" +#~ msgstr "Adres do rejestracji:" + +#~ msgid "" +#~ "The password used for registration. On some servers it is not necessary" +#~ msgstr "HasÅ‚o do rejestracji. Na niektórych serwerach nie jest wymagane" + +#~ msgid "Use this registrar server as outbound proxy." +#~ msgstr "Użyj tego serwera rejestracji jako zewnÄ™trznego proxy" + +#~ msgid "sip address:" +#~ msgstr "Adres SIP:" + +#~ msgid "Display name:" +#~ msgstr "WyÅ›wietlana nazwa:" + +#~ msgid "Modify" +#~ msgstr "ZmieÅ„" + +#~ msgid "Registering..." +#~ msgstr "Rejestruje..." + +#~ msgid "" +#~ "You are currently using the i810_audio driver.\n" +#~ "This driver is buggy and so does not work with Linphone.\n" +#~ "We suggest that you replace it by its equivalent ALSA driver,\n" +#~ "either with packages from your distribution, or by downloading\n" +#~ "ALSA drivers at http://www.alsa-project.org." +#~ msgstr "" +#~ "Używasz sterownika i810_audio.\n" +#~ "Ten sterownik ma błędy i nie dziaÅ‚a z Linphone\n" +#~ "Sugerujemy zmiane sterowników na ich odpowiedniki ALSA z pakietów Twojej " +#~ "dystrybucji,\n" +#~ "lub ze strony http://www.alsa-project.org/." + +#~ msgid "Unregistration successfull." +#~ msgstr "Derejestracja powiodÅ‚a siÄ™." + +#~ msgid "3" +#~ msgstr "3" + +#~ msgid "2" +#~ msgstr "2" + +#~ msgid "4" +#~ msgstr "4" + +#~ msgid "6" +#~ msgstr "6" + +#~ msgid "7" +#~ msgstr "7" + +#~ msgid "8" +#~ msgstr "8" + +#~ msgid "9" +#~ msgstr "9" diff --git a/linphone/po/pt_BR.po b/linphone/po/pt_BR.po new file mode 100644 index 000000000..518f0fee0 --- /dev/null +++ b/linphone/po/pt_BR.po @@ -0,0 +1,1012 @@ +# Portuguese translations for gnomebaker package. +# Copyright (C) 2005 THE linphone COPYRIGHT HOLDER +# This file is distributed under the same license as the linphone package. +# Rafael Caesar Lenzi , 2005. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: linphone-1.1.0\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2006-07-11 23:30+0200\n" +"Last-Translator: Rafael Caesar Lenzi \n" +"Language-Team: pt_BR \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Ir" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Catálogo de endereços" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Histórico de chamadas" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Exibir chamadas" + +#: gtk/interface.c:188 +#, fuzzy +msgid "Exit" +msgstr "Editar" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "Endereço sip:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Exibe o catálogo de endereços" + +#: gtk/interface.c:261 +msgid "..." +msgstr "" + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Proxy à usar:" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Ligar ou\n" +"atender" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +"Desligar\n" +"ou recusar" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Ou bate-papo!" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Exibir mais..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Volume do auto-falante:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Volume do microfone:" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Volume do microfone:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Som" + +#: gtk/interface.c:382 +#, fuzzy +msgid "Enable video" +msgstr "Ativado" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Ocupado, volto em " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "" + +#: gtk/interface.c:431 +msgid "5" +msgstr "" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "min" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Ocupado" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Não perturbe" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Movido temporáriamente" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Serviço alternativo" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Presença" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" + +#: gtk/interface.c:513 +msgid "1" +msgstr "" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" + +#: gtk/interface.c:555 +msgid "*" +msgstr "" + +#: gtk/interface.c:561 +msgid "0" +msgstr "" + +#: gtk/interface.c:567 +msgid "#" +msgstr "" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "Meus amigos online" + +#: gtk/interface.c:849 gtk/interface.c:3029 +msgid "Linphone" +msgstr "" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone é um web-fone.\n" +"Ele é compatível com os protocolos SIP e RTP." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parâmetros" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "Usar rede IPv6 (se disponível)" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" +"Marque isto se você estiver em uma rede IPv6, e deseja que o linphone este " +"protocolo." + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "" + +#: gtk/interface.c:1081 +#, fuzzy +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Esta opção é somente para usuários de uma rede privada, atrás de um gateway. " +"Se você não está nesta situação, deixe isto em braco." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "Opções de NAT(Experimental)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Número de segundos em bueffer:" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "Porta RTP usada para audio:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "Propriedades RTP:" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "Usar mensagem SIP INFO em vez de RTP rfc2833 para transmissão de DTMF" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "RTP-RFC2833 é a maneira recomendada." + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Outro" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Rede" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "Dispositivo de som:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "microfone" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "linha" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "Dispositivo de captura de som:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Origem de gravação:" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "Dispositivo de som" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "Som do toque:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Escutar" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Propriedades de som" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Dispositivo de som" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Executar agente sip na porta:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "É altamente recomendavel usar a porta 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "Porta SIP" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Seu endereço SIP:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Adquirir automaticamente um nome de servidor válido." + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identificação" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "Adicionar proxy/registrador" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Editar" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Remover" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Serviços remotos" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "" +"Limpar todas as informações de autenticação (nomes de usuário, senha...)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Informações de autenticação" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Lista de codecs de audio, em ordem de preferência:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Codec's de áudio" + +#: gtk/interface.c:1608 +#, fuzzy +msgid "Video Codecs" +msgstr "Codec's de áudio" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Ativado" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Desativar" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "Informações não disponíveis" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Informações sobre o codec" + +#: gtk/interface.c:1731 +#, fuzzy +msgid "Audio and video codecs" +msgstr "Codec's de áudio" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Catálogo de endereços" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Selecionar" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Informações" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Nenhum" + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Configuração de proxy/registrador" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "Rota (opcional):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "Proxy SIP:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "Identificação SIP:" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "Período do registo:" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Enviar registro:" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "Informar informação de presença" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Edicar informação de contato" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Nome:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Informação de contato" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "" + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Recusar" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "Aceitar" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Autenticação requerida" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "Identificação:" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "Senha:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "Usuário" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone - Histórico de chamadas" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "Sala de bate-papo" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Texto:" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Bate-papo com %s" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Não é possível achar arquivo pixmap: %s" + +#: gtk/propertybox.c:207 +#, fuzzy +msgid "Account" +msgstr "Aceitar" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Ativado" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Desativado" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Nome" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Taxa (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Bitrate mínimo (kbits/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "Linphone - Recebendo chamada de %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Nenhum" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Status de presença" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "Contatando " + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "Você perdeu %i ligação(ões)." + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "Abortado" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "Competado" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "Perdido" + +#: coreapi/linphonecore.c:223 +#, fuzzy, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s em %sDe: %s\n" +"Para: %s\n" +"Status: %s\n" +"Duração: %i min %i seg\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "Camadas recebidas" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "Chamadas efetuadas" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"Sua máquina aparentemente está conectada em uma rede IPv6. Por padrão o " +"linphone sempre usa IPv4. Por favor atualize sua configuração se deseja usar " +"IPv6" + +#: coreapi/linphonecore.c:692 +#, fuzzy +msgid "Ready" +msgstr "Pronto." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Procurando por telefone de destino..." + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "Não foi possível encontrar este número." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +#, fuzzy +msgid "Contacting" +msgstr "Contatando " + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Conectado." + +#: coreapi/linphonecore.c:1550 +#, fuzzy +msgid "Call ended" +msgstr "Chamada cancelada." + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" + +#: coreapi/exevents.c:115 +msgid "Call terminated." +msgstr "" + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "Não foi possível alcançar o detino." + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Usuário está ocupado." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "Usuário está temporáriamente indisponível." + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Pedido cancelado." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "" + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "" + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Usuário não pode ser encontrado no endereço especificado." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "" + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "Tempo esgotado." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Servidor de destino encontrado, porém recusou a conexão." + +#: coreapi/exevents.c:312 +#, fuzzy +msgid "is contacting you." +msgstr "está chamado você." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "Redirecionado para %s..." + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Registro falhou (tempo esgotado)." + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, fuzzy, c-format +msgid "Registration on %s successful." +msgstr "Registro em %s efetuado." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +#, fuzzy +msgid "Gone" +msgstr "Nenhum" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +#, fuzzy +msgid "Online" +msgstr "linha" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "User manual" +#~ msgstr "Manual do usuário" + +#~ msgid "Ring sound selection" +#~ msgstr "Seleção de toque" + +#~ msgid "Communication ended." +#~ msgstr "Comunicação encerrada." + +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "Endereço externo do firewall:" + +#~ msgid "Index" +#~ msgstr "Ãndice" + +#~ msgid "Address" +#~ msgstr "Endereço" + +#~ msgid "Server address" +#~ msgstr "Endereço do servidor" + +#~ msgid "28k modem" +#~ msgstr "Modem 28k" + +#~ msgid "56k modem" +#~ msgstr "Modem 56l" + +#~ msgid "64k modem (numeris)" +#~ msgstr "Modem 64k" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL ou Cable modem" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet ou equivalente" + +#~ msgid "Connection type:" +#~ msgstr "Tipo de conexão:" + +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone não pode abrir dispositivo de áudio %s. Verifique se sua placa " +#~ "de som está configurada e funcionando." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Escreva aqui o endereço sip da pessoa que você quer ligar." diff --git a/linphone/po/quot.sed b/linphone/po/quot.sed new file mode 100644 index 000000000..0122c4631 --- /dev/null +++ b/linphone/po/quot.sed @@ -0,0 +1,6 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g diff --git a/linphone/po/remove-potcdate.sin b/linphone/po/remove-potcdate.sin new file mode 100644 index 000000000..2436c49e7 --- /dev/null +++ b/linphone/po/remove-potcdate.sin @@ -0,0 +1,19 @@ +# Sed script that remove the POT-Creation-Date line in the header entry +# from a POT file. +# +# The distinction between the first and the following occurrences of the +# pattern is achieved by looking at the hold space. +/^"POT-Creation-Date: .*"$/{ +x +# Test if the hold space is empty. +s/P/P/ +ta +# Yes it was empty. First occurrence. Remove the line. +g +d +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/linphone/po/sv.po b/linphone/po/sv.po new file mode 100644 index 000000000..a91d9be6b --- /dev/null +++ b/linphone/po/sv.po @@ -0,0 +1,1063 @@ +# Swedish translation of linphone. +# Copyright (C) 2005 THE linphone'S COPYRIGHT HOLDER +# This file is distributed under the same license as the linphone package. +# Daniel Nylander , 2005. +# , fuzzy +# +# +msgid "" +msgstr "" +"Project-Id-Version: linphone 1.1.0\n" +"Report-Msgid-Bugs-To: linphone-developers@nongnu.org\n" +"POT-Creation-Date: 2008-08-26 14:26+0200\n" +"PO-Revision-Date: 2005-11-23 13:51+0100\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gtk/main.c:58 +msgid "A free SIP video-phone" +msgstr "" + +#: gtk/interface.c:138 +msgid "linphone" +msgstr "linphone" + +#: gtk/interface.c:155 +msgid "Go" +msgstr "Allmänt" + +#: gtk/interface.c:162 +msgid "Address book" +msgstr "Addressbok" + +#: gtk/interface.c:174 +msgid "Call history" +msgstr "Samtalshistorik" + +#: gtk/interface.c:177 +msgid "Shows calls" +msgstr "Visa samtal" + +#: gtk/interface.c:188 +#, fuzzy +msgid "Exit" +msgstr "Redigera" + +#: gtk/interface.c:196 +msgid "Help" +msgstr "" + +#: gtk/interface.c:236 +msgid "Enter sip address or phone number here" +msgstr "" + +#: gtk/interface.c:237 gtk/interface.c:1398 gtk/interface.c:2335 +#: gtk/interface.c:2357 gtk/interface.c:2497 +msgid "sip:" +msgstr "sip:" + +#: gtk/interface.c:239 gtk/interface.c:2512 +msgid "Sip address:" +msgstr "SIP-address:" + +#: gtk/interface.c:247 +msgid "Shows the address book" +msgstr "Visar addressboken" + +#: gtk/interface.c:261 +msgid "..." +msgstr "..." + +#: gtk/interface.c:269 gtk/interface.c:2519 +msgid "Proxy to use:" +msgstr "Proxy att använda:" + +#: gtk/interface.c:278 +msgid "" +"Call or\n" +"answer" +msgstr "" +"Ring eller\n" +" svara" + +#: gtk/interface.c:283 +msgid "" +"Hangup\n" +"or refuse" +msgstr "" +" Lägg på\n" +"eller vägra" + +#: gtk/interface.c:288 +msgid "Or chat !" +msgstr "Eller chatta !" + +#: gtk/interface.c:310 +msgid "Show more..." +msgstr "Visa mer..." + +#: gtk/interface.c:332 +msgid "Playback level:" +msgstr "Uppspelningsnivå:" + +#: gtk/interface.c:343 +msgid "Recording level:" +msgstr "Inspelningsnivå:" + +#: gtk/interface.c:354 +#, fuzzy +msgid "Ring level:" +msgstr "Inspelningsnivå:" + +#: gtk/interface.c:365 +msgid "Sound" +msgstr "Ljud" + +#: gtk/interface.c:382 +#, fuzzy +msgid "Enable video" +msgstr "Aktiverad" + +#: gtk/interface.c:387 +msgid "Video" +msgstr "" + +#: gtk/interface.c:392 +msgid "Controls" +msgstr "" + +#: gtk/interface.c:410 +msgid "Reachable" +msgstr "Tillgänglig" + +#: gtk/interface.c:421 +msgid "Busy, I'll be back in " +msgstr "Borta, kommer tillbaka om " + +#: gtk/interface.c:430 +msgid "The other party will be informed that you'll be back in X minutes" +msgstr "" +"Den andra parten kommer att informeras om att du är tillbaka om X minuter" + +#: gtk/interface.c:431 +msgid "5" +msgstr "5" + +#: gtk/interface.c:433 +msgid "mn" +msgstr "min" + +#: gtk/interface.c:438 coreapi/presence.c:146 +msgid "Away" +msgstr "Borta" + +#: gtk/interface.c:444 +msgid "Do not disturb" +msgstr "Stör ej" + +#: gtk/interface.c:450 +msgid "Moved temporarily" +msgstr "Flyttad temporärt" + +#: gtk/interface.c:456 +msgid "Alternative service" +msgstr "Alternativ tjänst" + +#: gtk/interface.c:466 +msgid "URL:" +msgstr "URL:" + +#: gtk/interface.c:475 +msgid "Presence" +msgstr "Närvaro" + +#: gtk/interface.c:492 +msgid "Press digits to send DTMFs." +msgstr "Tryck siffror för att skicka som DTMF" + +#: gtk/interface.c:501 +msgid "" +" 3\n" +"def" +msgstr "" +" 3\n" +"def" + +#: gtk/interface.c:507 +msgid "" +" 2\n" +"abc" +msgstr "" +" 2\n" +"abc" + +#: gtk/interface.c:513 +msgid "1" +msgstr "1" + +#: gtk/interface.c:519 +msgid "" +" 4\n" +"ghi" +msgstr "" +" 4\n" +"ghi" + +#: gtk/interface.c:525 +msgid "" +" 5\n" +"jkl" +msgstr "" +" 5\n" +"jkl" + +#: gtk/interface.c:531 +msgid "" +" 6\n" +"mno" +msgstr "" +" 6\n" +"mno" + +#: gtk/interface.c:537 +msgid "" +" 7\n" +"pqrs" +msgstr "" +" 7\n" +"pqrs" + +#: gtk/interface.c:543 +msgid "" +" 8\n" +"tuv" +msgstr "" +" 8\n" +"tuv" + +#: gtk/interface.c:549 +msgid "" +" 9\n" +"wxyz" +msgstr "" +" 9\n" +"wxyz" + +#: gtk/interface.c:555 +msgid "*" +msgstr "*" + +#: gtk/interface.c:561 +msgid "0" +msgstr "0" + +#: gtk/interface.c:567 +msgid "#" +msgstr "#" + +#: gtk/interface.c:573 +msgid "DTMF" +msgstr "DTMF" + +#: gtk/interface.c:590 +msgid "My online friends" +msgstr "Mina vänner som är online" + +#: gtk/interface.c:849 gtk/interface.c:3029 +#, fuzzy +msgid "Linphone" +msgstr "linphone" + +#: gtk/interface.c:850 gtk/interface.c:3030 +msgid "" +"C: 2001\n" +"Made in Old Europe" +msgstr "" +"C: 2001\n" +"Tillverkad i Gamla Europa" + +#: gtk/interface.c:851 gtk/interface.c:3031 +msgid "" +"Linphone is a web-phone.\n" +"It is compatible with SIP and RTP protocols." +msgstr "" +"Linphone är en webbtelefon.\n" +"Den är kompatibel med SIP och RTP-protokollen." + +#: gtk/interface.c:854 +msgid "http://www.linphone.org" +msgstr "" + +#: gtk/interface.c:1028 +msgid "Parameters" +msgstr "Parametrar" + +#: gtk/interface.c:1061 +msgid "Use IPv6 network (if available)" +msgstr "Använd IPv6-nätverk (om tillgänglig)" + +#: gtk/interface.c:1064 +msgid "" +"Toggle this if you are on an ipv6 network and you wish linphone to use it." +msgstr "" +"Aktivera denna om du är ansluten till ett IPv6-nätverk och vill att linphone " +"ska använda det." + +#: gtk/interface.c:1066 +msgid "Global" +msgstr "Global" + +#: gtk/interface.c:1081 +#, fuzzy +msgid "" +"These options is only for users in a private network, behind a gateway. If " +"you are not in this situation, then leave this empty." +msgstr "" +"Denna funktion är bara för användare i ett privat nätverk bakom en " +"förmedlingsnod. Om du inte befinner dig i denna situation bör du lämna denna " +"blank." + +#: gtk/interface.c:1091 +msgid "No firewall" +msgstr "" + +#: gtk/interface.c:1099 +msgid "Use this STUN server to guess firewall address :" +msgstr "" + +#: gtk/interface.c:1107 +msgid "Specify firewall address manually:" +msgstr "" + +#: gtk/interface.c:1127 +msgid "NAT traversal options (experimental)" +msgstr "Inställning för NAT Traversal (experimentell)" + +#: gtk/interface.c:1156 +msgid "Number of buffered miliseconds (jitter compensation):" +msgstr "Antal millisekunder för buffert (jitterkompensation):" + +#: gtk/interface.c:1164 +msgid "RTP port used for audio:" +msgstr "RTP-port som används för ljud:" + +#: gtk/interface.c:1171 +msgid "RTP properties" +msgstr "RTP-egenskaper" + +#: gtk/interface.c:1189 +msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" +msgstr "" +"Använd SIP INFO-meddelande istället för RTP rfc2833 för sändning av DTMF" + +#: gtk/interface.c:1192 +msgid "RTP-RFC2833 is the recommended way." +msgstr "RTP-RFC2833 är rekommenderat." + +#: gtk/interface.c:1194 +msgid "Other" +msgstr "Annan" + +#: gtk/interface.c:1199 +msgid "Network" +msgstr "Nätverk" + +#: gtk/interface.c:1225 +msgid "Playback sound device:" +msgstr "Ljudenhet för uppspelning:" + +#: gtk/interface.c:1240 gtk/propertybox.c:629 gtk/propertybox.c:654 +msgid "micro" +msgstr "micro" + +#: gtk/interface.c:1241 gtk/propertybox.c:632 gtk/propertybox.c:655 +msgid "line" +msgstr "line" + +#: gtk/interface.c:1250 +msgid "Capture sound device:" +msgstr "Ljudenhet för inspelning:" + +#: gtk/interface.c:1270 +msgid "Recording source:" +msgstr "Inspelningskälla:" + +#: gtk/interface.c:1277 +#, fuzzy +msgid "Ring sound device" +msgstr "Ljudenhet" + +#: gtk/interface.c:1285 +msgid "Ring sound:" +msgstr "Ringsignal:" + +#: gtk/interface.c:1305 +msgid "Enable echo-canceler (cancels the echo heard by the remote party)" +msgstr "" + +#: gtk/interface.c:1319 +msgid "Choose file" +msgstr "" + +#: gtk/interface.c:1339 +msgid "Listen" +msgstr "Lyssna" + +#: gtk/interface.c:1343 +msgid "Sound properties" +msgstr "Ljudegenskaper" + +#: gtk/interface.c:1347 +msgid "Sound device" +msgstr "Ljudenhet" + +#: gtk/interface.c:1365 +msgid "Run sip user agent on port:" +msgstr "Kör SIP-agent på port:" + +#: gtk/interface.c:1374 +msgid "It is strongly recommended to use port 5060." +msgstr "Det rekommenderas starkt att använda port 5060." + +#: gtk/interface.c:1376 +msgid "SIP port" +msgstr "SIP-port" + +#: gtk/interface.c:1393 +msgid "Your sip address:" +msgstr "Din SIP-address:" + +#: gtk/interface.c:1407 +msgid "@" +msgstr "@" + +#: gtk/interface.c:1416 +msgid "Automatically guess a valid hostname" +msgstr "Gissa automatiskt ett giltigt värdnamn" + +#: gtk/interface.c:1420 +msgid "Identity" +msgstr "Identitet" + +#: gtk/interface.c:1467 +msgid "Add proxy/registrar" +msgstr "Lägg till proxy/registrar" + +#: gtk/interface.c:1488 gtk/interface.c:2114 +msgid "Edit" +msgstr "Redigera" + +#: gtk/interface.c:1509 +msgid "Remove" +msgstr "Ta bort" + +#: gtk/interface.c:1513 +msgid "Remote services" +msgstr "Fjärrtjänster" + +#: gtk/interface.c:1543 +msgid "Clear all stored authentication information (username,password...)" +msgstr "Rensa all lagra autentiseringsinformation (användarnamn,lösenord...)" + +#: gtk/interface.c:1547 +msgid "Authentication information" +msgstr "Autentiseringsinformation" + +#: gtk/interface.c:1551 +msgid "SIP" +msgstr "SIP" + +#: gtk/interface.c:1574 +msgid "List of audio codecs, in order of preference:" +msgstr "Lista av ljudkodare, sorterade efter önskemål:" + +#: gtk/interface.c:1595 +msgid "Audio codecs" +msgstr "Ljudkodare" + +#: gtk/interface.c:1608 +#, fuzzy +msgid "Video Codecs" +msgstr "Ljudkodare" + +#: gtk/interface.c:1644 +msgid "Enable" +msgstr "Aktivera" + +#: gtk/interface.c:1665 +msgid "Disable" +msgstr "Stäng av" + +#: gtk/interface.c:1673 +msgid "Upload bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1681 +msgid "Download bandwidth (kbit/sec):" +msgstr "" + +#: gtk/interface.c:1708 +msgid "" +"Note: Codecs in red are not usable regarding to your connection type to the " +"internet." +msgstr "" +"Notera: Kodare som är rödmarkerade är inte användbara enligt din " +"anslutningstyp mot Internet." + +#: gtk/interface.c:1720 +msgid "No information availlable" +msgstr "Ingen information tillgänglig" + +#: gtk/interface.c:1727 +msgid "Codec information" +msgstr "Information om kodare" + +#: gtk/interface.c:1731 +#, fuzzy +msgid "Audio and video codecs" +msgstr "Ljudkodare" + +#: gtk/interface.c:1736 +msgid "Codecs" +msgstr "Kodare" + +#: gtk/interface.c:2044 +msgid "Address Book" +msgstr "Addressbok" + +#: gtk/interface.c:2140 +msgid "Select" +msgstr "Välj" + +#: gtk/interface.c:2199 +msgid "Information" +msgstr "Information" + +#: gtk/interface.c:2217 +msgid "" +"User is not reachable at the moment but he invites you to contact him using " +"the following alternate ressource:" +msgstr "" +"Användare är inte tillgänglig för ögonblicket men han/hon inbjuder du att " +"kontakta honom/henne med följande alternativa resurser:" + +#: gtk/interface.c:2224 +msgid "None." +msgstr "Ingen." + +#: gtk/interface.c:2285 gtk/interface.c:2394 +msgid "Proxy/Registrar configuration box" +msgstr "Konfiguration av proxy/registrar" + +#: gtk/interface.c:2315 +msgid "Route (optional):" +msgstr "Rutt (valfri):" + +#: gtk/interface.c:2337 +msgid "SIP Proxy:" +msgstr "SIP-proxy:" + +#: gtk/interface.c:2344 +msgid "SIP Identity:" +msgstr "SIP-identitet:" + +#: gtk/interface.c:2359 +msgid "Registration Period:" +msgstr "Registreringsperiod:" + +#: gtk/interface.c:2374 +msgid "Send registration:" +msgstr "Skicka registrering:" + +#: gtk/interface.c:2381 +msgid "Publish presence information:" +msgstr "Publisera närvaroinformation:" + +#: gtk/interface.c:2466 +msgid "Edit contact information" +msgstr "Redigera kontaktinformation" + +#: gtk/interface.c:2505 +msgid "Name:" +msgstr "Namn:" + +#: gtk/interface.c:2526 +msgid "Subscribe policy:" +msgstr "Prenumerationspolicy:" + +#: gtk/interface.c:2533 +msgid "Send subscription (see person's online status)" +msgstr "Skicka prenumeration (se personens online-status)" + +#: gtk/interface.c:2537 +msgid "Contact information" +msgstr "Kontaktinformation" + +#: gtk/interface.c:2608 +msgid "New incoming subscription" +msgstr "Ny inkommande prenumeration" + +#: gtk/interface.c:2628 +msgid "You have received a new subscription..." +msgstr "Du har tagit emot en ny prenumeration..." + +#: gtk/interface.c:2655 +msgid "Refuse" +msgstr "Vägra" + +#: gtk/interface.c:2676 gtk/addressbook.c:57 +msgid "Accept" +msgstr "Acceptera" + +#: gtk/interface.c:2729 +msgid "Authentication requested" +msgstr "Autentiserings krävs" + +#: gtk/interface.c:2755 +msgid "Authentication required for realm" +msgstr "Autentisering krävs för domän" + +#: gtk/interface.c:2791 +msgid "userid:" +msgstr "användar-id:" + +#: gtk/interface.c:2799 +msgid "password:" +msgstr "lösenord:" + +#: gtk/interface.c:2807 +msgid "username:" +msgstr "användarnamn:" + +#: gtk/interface.c:2815 +msgid "realm:" +msgstr "domän:" + +#: gtk/interface.c:2876 +msgid "Linphone - Call history" +msgstr "Linphone - Samtalshistorik" + +#: gtk/interface.c:2943 +msgid "Chat Room" +msgstr "Chattrum" + +#: gtk/interface.c:2971 +msgid "Text:" +msgstr "Text:" + +#: gtk/callbacks.c:600 +#, c-format +msgid "Chat with %s" +msgstr "Chatta med %s" + +#: gtk/support.c:90 gtk/support.c:114 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Kunde inte hitta bildfil: %s" + +#: gtk/propertybox.c:207 +#, fuzzy +msgid "Account" +msgstr "Acceptera" + +#: gtk/propertybox.c:439 gtk/propertybox.c:524 gtk/propertybox.c:536 +#: gtk/propertybox.c:883 +msgid "Enabled" +msgstr "Aktiverad" + +#: gtk/propertybox.c:440 gtk/propertybox.c:884 +msgid "Disabled" +msgstr "Avstängd" + +#: gtk/propertybox.c:458 gtk/friends.c:110 +msgid "Name" +msgstr "Namn" + +#: gtk/propertybox.c:464 +msgid "Rate (Hz)" +msgstr "Takt (Hz)" + +#: gtk/propertybox.c:470 +msgid "Status" +msgstr "Status" + +#: gtk/propertybox.c:476 +msgid "Min bitrate (kbit/s)" +msgstr "Minimum bithastighet (kbit/s)" + +#: gtk/propertybox.c:504 gtk/propertybox.c:509 gtk/propertybox.c:1061 +#: gtk/propertybox.c:1072 +msgid "Unlimited" +msgstr "" + +#: gtk/linphone.c:215 +msgid "The caller asks for resource reservation. Do you agree ?" +msgstr "Inringaren frågar efter reservation av resurs. Godkänner du detta ?" + +#: gtk/linphone.c:218 +msgid "" +"The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " +"continue anyway ?" +msgstr "" +"Andra parten använder inte resursreservation. \t\t\t\t\tVill du fortsätta " +"ändå ?" + +#: gtk/linphone.c:245 +#, c-format +msgid "linphone - receiving call from %s" +msgstr "linphone - tar emot samtal från %s" + +#: gtk/linphone.c:272 +#, c-format +msgid "" +"You have received a subscription from %s.This means that this person wishes " +"to be notified of your presence information (online, busy, away...).\n" +"Do you agree ?" +msgstr "" +"Du har mottagit en prenumeration från %s. Detta betyder att denna person " +"önskar bli notifierad om din närvaroinformation (online, upptagen, " +"borta...)\n" +"Godkänner du detta ?" + +#: gtk/linphone.c:287 +#, c-format +msgid "Authentication required for realm %s" +msgstr "Autentisering krävs för domänen %s" + +#: gtk/linphone.c:410 +msgid "None" +msgstr "Ingen" + +#: gtk/friends.c:117 +msgid "Presence status" +msgstr "Närvarostatus" + +#: gtk/addressbook.c:55 +msgid "Wait" +msgstr "" + +#: gtk/addressbook.c:56 +msgid "Deny" +msgstr "" + +#: gtk/addressbook.c:124 +#, fuzzy +msgid "Bad sip address: a sip address looks like sip:user@domain" +msgstr "" +"Kunde inte tolka angiven SIP-address. En SIP URL ser normalt sett ut som sip:" +"användare@domän" + +#: gtk/addressbook.c:226 +#, fuzzy +msgid "Contact list" +msgstr "Kontaktar" + +#: coreapi/linphonecore.c:186 +#, c-format +msgid "You have missed %i call(s)." +msgstr "Du har %i missade samtal." + +#: coreapi/linphonecore.c:212 +msgid "aborted" +msgstr "avbruten" + +#: coreapi/linphonecore.c:215 +msgid "completed" +msgstr "genomförd" + +#: coreapi/linphonecore.c:218 +msgid "missed" +msgstr "missad" + +#: coreapi/linphonecore.c:223 +#, fuzzy, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s at %sFrån: %s\n" +"Till: %s\n" +"Status: %s\n" +"Längd: %i min %i sek\n" + +#: coreapi/linphonecore.c:224 +msgid "Incoming call" +msgstr "Inkommande samtal" + +#: coreapi/linphonecore.c:224 +msgid "Outgoing call" +msgstr "Utgående samtal" + +#: coreapi/linphonecore.c:410 +msgid "" +"Your machine appears to be connected to an IPv6 network. By default linphone " +"always uses IPv4. Please update your configuration if you want to use IPv6" +msgstr "" +"Din maskin verkar vara ansluten till ett IPv6-nätverk. Som standard använder " +"linphone alltid IPv4. Vänligen uppdatera din konfiguration om du vill " +"använda IPv6." + +#: coreapi/linphonecore.c:692 +#, fuzzy +msgid "Ready" +msgstr "Klar." + +#: coreapi/linphonecore.c:741 +msgid "Stun lookup in progress..." +msgstr "" + +#: coreapi/linphonecore.c:750 +msgid "Stun lookup done..." +msgstr "" + +#: coreapi/linphonecore.c:985 +msgid "Remote end seems to have disconnected, the call is going to be closed." +msgstr "" + +#: coreapi/linphonecore.c:1077 +msgid "Looking for telephone number destination..." +msgstr "Letar efter destination för telefonnummer..." + +#: coreapi/linphonecore.c:1079 +msgid "Could not resolve this number." +msgstr "Kunde inte slå upp detta nummer." + +#: coreapi/linphonecore.c:1138 +msgid "" +"Could not parse given sip address. A sip url usually looks like sip:" +"user@domain" +msgstr "" +"Kunde inte tolka angiven SIP-address. En SIP URL ser normalt sett ut som sip:" +"användare@domän" + +#: coreapi/linphonecore.c:1187 +msgid "Sorry, having multiple simultaneous calls is not supported yet !" +msgstr "" + +#: coreapi/linphonecore.c:1198 +#, fuzzy +msgid "Contacting" +msgstr "Kontaktar" + +#: coreapi/linphonecore.c:1235 +msgid "could not call" +msgstr "" + +#: coreapi/linphonecore.c:1524 coreapi/exevents.c:41 +msgid "Connected." +msgstr "Ansluten." + +#: coreapi/linphonecore.c:1550 +#, fuzzy +msgid "Call ended" +msgstr "Samtal vägrades." + +#: coreapi/linphonecore.c:1846 +msgid "No nat/firewall address supplied !" +msgstr "" + +#: coreapi/linphonecore.c:1858 coreapi/linphonecore.c:1870 +#, c-format +msgid "Invalid nat address '%s' : %s" +msgstr "" + +#: coreapi/misc.c:130 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the pcm oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +"'modprobe snd-pcm-oss' as root to load it." +msgstr "" +"Din dator verkar använda ljuddrivare för ALSA.\n" +"Detta är det bästa valet. Dock saknas emuleringsmodulen\n" +"för OSS-PCM och linphone behöver den. Vänligen\n" +"kör \"modprobe snd-pcm-oss\" som root för att läsa in den." + +#: coreapi/misc.c:133 +msgid "" +"Your computer appears to be using ALSA sound drivers.\n" +"This is the best choice. However the mixer oss emulation module\n" +"is missing and linphone needs it. Please execute\n" +" 'modprobe snd-mixer-oss' as root to load it." +msgstr "" +"Din dator verkar använda ljuddrivare för ALSA.\n" +"Detta är det bästa valet. Dock saknas emuleringsmodulen\n" +"för OSS-mixern och linphone behöver den. Vänligen\n" +"kör \"modprobe snd-mixer-oss\" som root för att läsa in den." + +#: coreapi/exevents.c:115 +#, fuzzy +msgid "Call terminated." +msgstr "Samtal vägrades." + +#: coreapi/exevents.c:137 +msgid "Could not reach destination." +msgstr "Kunde inte nå destination." + +#: coreapi/exevents.c:146 +msgid "User is busy." +msgstr "Användaren är upptagen." + +#: coreapi/exevents.c:147 +msgid "User is temporarily unavailable." +msgstr "Användaren är temporärt ej tillgänglig." + +#: coreapi/exevents.c:148 +msgid "Request Cancelled." +msgstr "Begäran avbruten." + +#: coreapi/exevents.c:150 +msgid "User does not want to be disturbed." +msgstr "Användaren vill inte bli störd." + +#: coreapi/exevents.c:151 +msgid "Call declined." +msgstr "Samtal vägrades." + +#: coreapi/exevents.c:170 +msgid "Bad request" +msgstr "Felaktig begäran" + +#: coreapi/exevents.c:173 +msgid "User cannot be found at given address." +msgstr "Användaren kunde inte hittas på den angivna addressen." + +#: coreapi/exevents.c:176 +msgid "Remote user cannot support any of proposed codecs." +msgstr "Fjärranvändaren har inte stöd för någon av de förslagna kodarna." + +#: coreapi/exevents.c:202 +msgid "Timeout." +msgstr "Timeout." + +#: coreapi/exevents.c:205 +msgid "Remote host was found but refused connection." +msgstr "Fjärrvärden hittades med vägrade ta emot anslutningen." + +#: coreapi/exevents.c:312 +#, fuzzy +msgid "is contacting you." +msgstr "ringer dig." + +#: coreapi/exevents.c:392 +#, c-format +msgid "Redirected to %s..." +msgstr "Omdirigerad till %s..." + +#: coreapi/exevents.c:408 +msgid "" +"User is not reachable at the moment but he invites you\n" +"to contact him using the following alternate resource:" +msgstr "" +"Användare är inte tillgänglig för tillfället men han/hon inbjuder\n" +"dig att kontakta honom/henne med följande alternativa resurs:" + +#: coreapi/exevents.c:775 +msgid "Early media." +msgstr "" + +#: coreapi/exevents.c:837 +#, fuzzy, c-format +msgid "Registration on %s failed: %s" +msgstr "Registrering misslyckades (timeout)." + +#: coreapi/exevents.c:837 +msgid "no response timeout" +msgstr "" + +#: coreapi/exevents.c:851 +#, fuzzy, c-format +msgid "Registration on %s successful." +msgstr "Registrering på %s lyckades." + +#: coreapi/presence.c:112 coreapi/presence.c:164 +#, fuzzy +msgid "Gone" +msgstr "Ingen" + +#: coreapi/presence.c:129 +msgid "Waiting for Approval" +msgstr "" + +#: coreapi/presence.c:133 +#, fuzzy +msgid "Online" +msgstr "line" + +#: coreapi/presence.c:137 +msgid "Busy" +msgstr "" + +#: coreapi/presence.c:142 +msgid "Be Right Back" +msgstr "" + +#: coreapi/presence.c:151 +msgid "On The Phone" +msgstr "" + +#: coreapi/presence.c:156 +msgid "Out To Lunch" +msgstr "" + +#: coreapi/presence.c:160 +msgid "Closed" +msgstr "" + +#~ msgid "User manual" +#~ msgstr "Användarmanual" + +#~ msgid "Ring sound selection" +#~ msgstr "Val av ringsignal" + +#~ msgid "Communication ended." +#~ msgstr "Anslutning avslutad." + +#~ msgid "Call cancelled." +#~ msgstr "Samtal avbrutet." + +#~ msgid "Firewall 's external ip address (in dot notations):" +#~ msgstr "Brandväggens externa IP-address (i punktnotation):" + +#~ msgid "Index" +#~ msgstr "Index" + +#~ msgid "Address" +#~ msgstr "Address" + +#~ msgid "Server address" +#~ msgstr "Serveraddress" + +#~ msgid "28k modem" +#~ msgstr "28k modem" + +#~ msgid "56k modem" +#~ msgstr "56k modem" + +#~ msgid "64k modem (numeris)" +#~ msgstr "64k modem (numerisk)" + +#~ msgid "ADSL or Cable modem" +#~ msgstr "ADSL eller kabelmodem" + +#~ msgid "Ethernet or equivalent" +#~ msgstr "Ethernet eller liknande" + +#~ msgid "Connection type:" +#~ msgstr "Anslutningstyp:" + +#~ msgid "" +#~ "Linphone could not open audio device %s. Check if your sound card is " +#~ "fully configured and working." +#~ msgstr "" +#~ "Linphone kunde inte öppna ljudenheten %s. Kontrollera om ditt ljudkort är " +#~ "konfigurerat och fungerar." + +#~ msgid "Type here the sip address of the person you want to call." +#~ msgstr "Ange SIP-addressen för personen du vill ringa." diff --git a/linphone/reconfig-SuSE b/linphone/reconfig-SuSE new file mode 100755 index 000000000..8a9aea659 --- /dev/null +++ b/linphone/reconfig-SuSE @@ -0,0 +1,23 @@ +#!/bin/sh +echo "Generating build scripts in linphone..." +libtoolize --copy --force +chmod 644 macros/* +cp /opt/gnome2/share/aclocal/gnome2-macros/* macros/. +aclocal-1.6 -I macros +autoheader +automake-1.6 --add-missing --copy +autoconf +rm -rf config.cache + +echo "Generating build scripts in osipua..." +cd osipua && ./reconfig + +echo "Generating build scripts in oRTP..." +cd .. +cd oRTP && ./reconfig + +echo "Generating build scripts in speex..." +cd .. +cd speex && libtoolize --copy --force && aclocal-1.6 && automake-1.6 --add-missing --copy && autoconf -f + + diff --git a/linphone/share/.cvsignore b/linphone/share/.cvsignore new file mode 100644 index 000000000..3d11e0206 --- /dev/null +++ b/linphone/share/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +*.raw +linphone.pc diff --git a/linphone/share/C/.cvsignore b/linphone/share/C/.cvsignore new file mode 100644 index 000000000..e1d20773b --- /dev/null +++ b/linphone/share/C/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +manual +manual.junk +manual.html diff --git a/linphone/share/C/Makefile.am b/linphone/share/C/Makefile.am new file mode 100644 index 000000000..0d6136465 --- /dev/null +++ b/linphone/share/C/Makefile.am @@ -0,0 +1,8 @@ + +HELPLANG=C + +include ../Makefile.inc + +man_MANS = linphone.1 linphonec.1 sipomatic.1 + +EXTRA_DIST+=$(man_MANS) diff --git a/linphone/share/C/linphone.1 b/linphone/share/C/linphone.1 new file mode 100644 index 000000000..8c87c64dc --- /dev/null +++ b/linphone/share/C/linphone.1 @@ -0,0 +1,42 @@ +.\" Linphone is an internet phone compatible with the Session Initiation Protocol (SIP: RFC3261 ) +.TH "linphone" "1" "1.0.0" "Simon Morlat" "linphone" +.SH "NAME" +.LP +linphone \- Gnome interface of linphone, a SIP compatible +internet phone. +.SH "SYNTAX" +.LP +linphone [\fI\-\-help\fP] [\fI\-\-verbose\fP] + +.SH "DESCRIPTION" +.LP +Linphone can be started without any extra argument. All parameters are accessible from the property box. + +.SH "OPTIONS" +.LP +.TP +\fB\-\-help\fR +Output help information and exit. +.TP +\fB\-\-version\fR +Output version information and exit. +\fB\-\-verbose\fR +Output internal messages on stdout, this is useful for debugging. +.SH "FILES" +.LP +\fI~/.gnome2/linphone\fP +.br +This is where linphone reads its config information. You do not have to modify or edit this file. +.br + +.SH "ENVIRONMENT VARIABLES" + +.SH "EXAMPLES" + +.SH "AUTHORS" +.LP +Simon MORLAT +See the AUTHORS file inside linphone's source for more details. +.SH "SEE ALSO" +.LP +linphonec(1) sipomatic(1) diff --git a/linphone/share/C/linphonec.1 b/linphone/share/C/linphonec.1 new file mode 100644 index 000000000..c19bf2108 --- /dev/null +++ b/linphone/share/C/linphonec.1 @@ -0,0 +1,69 @@ +.\" Linphone is an internet phone compatible with the Session Initiation Protocol (SIP: RFC3261 ) +.TH "linphonec" "1" "1.0.0" "Florian Winterstein & Simon MORLAT" "linphone, internet phone" +.SH "NAME" +.LP +linphonec \- Console interface of linphone, a SIP compatible +internet phone. +.SH "SYNTAX" +.LP +linphonec [\fI\-d\fP] <\fIdebug_level\fP> [\fI\-l\fP] <\fIdebug_file\fP> [\fI\-c\fP] <\fIconfig_file\fP> +.br +linphonec \fI\-v\fP +.SH "DESCRIPTION" +.LP +Linphonec is the console version of originally Gnome internet phone linphone (http://www.linphone.org) . +.br +Linphonec can be started without arguments. It doesn't need any config file to start correctly and will create a default one at the first startup if the file does not exist. +By default the path of the config file is ~/.linphonerc . +Most parameters (proxy, passwords) can be changed from the command line, for some of them (path of sound rings), you'll need +to edit the .linphonerc config file. +.br +Once linphonec has started, linphonec wait for some commands and is ready to receive calls. +.br +The most important commands are +.br +.TP +call : to call someone. A sip url is in the form sip:user@host +.TP +terminate : to terminate a call +.TP +answer : to accept an incoming call. +.TP +help : to display interactive help. +.TP + + + +.SH "OPTIONS" +.LP +.TP +\fB\-d\fR <\fIdebug_level\fP> +Use debug mode with given verbosity (debug_level). The debug_level is an integer in the range 0..5 . +.TP +\fB\-h\fR +Output help information and exit. +.TP +\fB\-l\fR <\fIlog_file\fP> +Specifies a file where debug information will be written. Default is stdout. +.TP +\fB\-c\fR <\fIconfig_file\fP> +Specifies the config file to read at startup. +.TP +.SH "FILES" +.LP +\fI~/.linphonec\fP +.br + +.SH "ENVIRONMENT VARIABLES" +.LP +.SH "EXAMPLES" +.LP + +.SH "AUTHORS" +.LP +Florian Winterstein +.br +Simon Morlat +.SH "SEE ALSO" +.LP +linphone(1) sipomatic(1) diff --git a/linphone/share/C/manual.lyx b/linphone/share/C/manual.lyx new file mode 100644 index 000000000..e11ca3bc7 --- /dev/null +++ b/linphone/share/C/manual.lyx @@ -0,0 +1,654 @@ +#LyX 1.4.4 created this file. For more info see http://www.lyx.org/ +\lyxformat 245 +\begin_document +\begin_header +\textclass docbook +\language english +\inputencoding default +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize default +\use_geometry false +\use_amsmath 1 +\cite_engine basic +\use_bibtopic false +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language french +\papercolumns 1 +\papersides 1 +\paperpagestyle default +\tracking_changes false +\output_changes true +\end_header + +\begin_body + +\begin_layout Title +Linphone's User Manual +\end_layout + +\begin_layout Date +July, 24th 2004 +\end_layout + +\begin_layout Section +Introduction +\end_layout + +\begin_layout Standard +Linphone is a simple web-phone. + It allows you to make two party-calls using an IP network like the internet. + What you need to run Linphone is : +\end_layout + +\begin_layout Itemize +a computer running the GNU/Linux operating system +\end_layout + +\begin_layout Itemize +gtk+>=2.4, in order to use the graphical interface (highly recommended!). + The console-only application (linphonec) does not need gtk but libreadline. +\end_layout + +\begin_layout Itemize +a sound card correctly configured to use the ALSA linux sound system +\end_layout + +\begin_layout Itemize +headphones or speakers +\end_layout + +\begin_layout Itemize +a microphone +\end_layout + +\begin_layout Itemize +a connection to a network (the Internet for example), using a modem, an + ethernet card, a Wifi adapter or anything else +\end_layout + +\begin_layout Standard +Since linphone needs to use the computer's sound system, before running + linphone, please make sure that no other application is using the audio + device. + +\end_layout + +\begin_layout Standard +Linphone is free, it is released under +\emph on +GNU Public License +\emph default +. +\end_layout + +\begin_layout Standard + +\emph on +WARNING: This software is provided with NO WARRANTY see file COPYING for + details. + This means you SHOULD NOT use linphone for confidential conversations: + there is NO encryption, so it is easy for any bad-intentioned person to + monitor the audio streams, and thus your conversation. + Note also that it is not recommended to run Linphone as root. +\end_layout + +\begin_layout Section +Running linphone +\end_layout + +\begin_layout Standard +Linphone can be run in three different ways: +\end_layout + +\begin_layout Itemize +as a normal application: in the gnome menu, linphone should appear in the + network sub-menu. + If you are not running gnome, you can execute linphone directly by typing + linphone in a terminal, for example. + Please note, that when linphone is not running, you cannot receive calls. +\end_layout + +\begin_layout Itemize +as a gnome applet: add the linphone applet by right-clicking on the gnome + panel, linphone appears in the network menu. + When linphone is running silently as a gnome panel, it is able to receive + calls even if its window is not shown. + If you want the main linphone window to appear, click on the applet. + When somebody calls you, the main window is shown and you will hear the + ring normally. +\end_layout + +\begin_layout Section +Making a call +\end_layout + +\begin_layout Subsection +Basic principles +\end_layout + +\begin_layout Standard +Linphone uses the Session Initiation Protocol (SIP) to establish a connection + with a remote host. + In this protocol each caller or callee is identified by a SIP url: sip:user_nam +e@host_name. + A SIP url's syntax like an email address, with a +\begin_inset Quotes sld +\end_inset + +sip: +\begin_inset Quotes sld +\end_inset + + prefix. +\end_layout + +\begin_layout Standard +User_name is probably your login account on a Unix machine, and host_name + is the machines fully qualified domain name (FQDN) or IP address. +\end_layout + +\begin_layout Standard +Note that SIP is a new telecommunication protocol designed to be simple, + and it is not compatible with H323 at all. +\end_layout + +\begin_layout Subsection +When IP address are not static, or not routable. +\end_layout + +\begin_layout Standard +For that purpose, you can register to a SIP provider or SIP proxy. + There exist several SIP proxies on the net, and some of them are free. + See, for example, http://iptel.org. + You'll have to get an account on the proxy and then tell linphone to use + it. + In this case, the user_name will assigned to you by the VoIP provider, + when you register, and host_name is the provider's host name (usually something + like sip.example.com). + +\end_layout + +\begin_layout Subsection +Test trial: If you have no friends to call at the moment (because it is + too late for example), but would like to know if linphone is really working. +\end_layout + +\begin_layout Standard +\begin_inset LatexCommand \label{sipomatic} + +\end_inset + +Since version 0.3.0, linphone comes with a test program called ' +\emph on +sipomatic +\emph default +'. + Sipomatic can answer automatically calls from linphone. + To do this: +\end_layout + +\begin_layout Itemize +run sipomatic from a terminal. + Sipomatic does not have a graphical interface, but you don't have to interact + with it, so it doesn't need one. + +\end_layout + +\begin_layout Itemize +Then type the following SIP url in the main window of linphone: sip:robot@127.0.0.1 +:5064 . + 127.0.0.1 is the local address for your computer, and robot is the name to + use for calling sipomatic. + 5064 is the port that sipomatic is listening to. + Normally you should always use 5060 (i.e the default port when no port is + specified) to call somebody, but sipomatic is the exception: it runs on + port 5064. + The reason for this is that linphone itself already runs on 5060, and you + cannot have two applications running on the same port, at the same time + and on the same machine. +\end_layout + +\begin_layout Itemize +Then press the call button. + After one second, sipomatic should answer to your call and you should hear + a short announcement. +\end_layout + +\begin_layout Section +\begin_inset LatexCommand \label{params} + +\end_inset + +Call parameters +\end_layout + +\begin_layout Subsection +\begin_inset LatexCommand \label{paramnetwork} + +\end_inset + +Network +\end_layout + +\begin_layout Standard +Linphone allows you to set your firewall address (see section 7) or a stun + server address that might help linphone calling and receiving calls. +\end_layout + +\begin_layout Standard +Linphone supports ipv6: you can enable it by toggling the +\begin_inset Quotes fld +\end_inset + +Enable ipv6 +\begin_inset Quotes frd +\end_inset + + checkbox. + However it can support Ipv6 and Ipv4 together. +\end_layout + +\begin_layout Subsection +\begin_inset LatexCommand \label{paramrtp} + +\end_inset + +RTP +\end_layout + +\begin_layout Standard +RTP (Real Time Protocol) is a protocol used to send media streams over networks. +\end_layout + +\begin_layout Itemize +RTP port: linphone uses default port 7078 to send and receive audio streams. + If you think port 7078 is used by another application, change it as you + wish. +\end_layout + +\begin_layout Itemize +Jitter compensation: This number represents the number of audio packets + linphone is waiting for before starting to play them. + If sometimes some audio packets are late, they have a greater chance to + be played. + Increase this parameter, if the other person's voice sounds 'chopped', + in order to improve the quality of the transmission. + This will however increase the delay (you will hear the remote user's talk + with a few seconds delay). + If, on the other hand, you are using a fast network, and you have good + audio drivers, you can set this parameters down to three packets, and you + will have a very small delay. +\end_layout + +\begin_layout Subsection +\begin_inset LatexCommand \label{paramsip} + +\end_inset + +SIP +\end_layout + +\begin_layout Standard +SIP (Session Initiation Protocol) is a protocol to establish and destroy + media sessions over a network. + In simple words, it's responsible for controlling calls. + It rings the remote user, initiates the call and terminates it when one + of the two parties hangs up. +\end_layout + +\begin_layout Itemize +SIP port: linphone uses default port 5060 to send and receive SIP packets. + It is highly recommended by SIP's RFC to use port 5060. + So, please don't change this unless you really know what you are doing. +\end_layout + +\begin_layout Itemize +Use registrar: toggle this button if you need the services of a remote SIP + server. + See section +\begin_inset Quotes eld +\end_inset + +Registering on a remote server +\begin_inset Quotes erd +\end_inset + + for details about this. +\end_layout + +\begin_layout Subsection +\begin_inset LatexCommand \label{paramcodec} + +\end_inset + +Codecs +\end_layout + +\begin_layout Standard +Codecs are algorithms especially designed to compress voice data. + For example, digitized voice in 16bit / 8000 Hz represents a data flow + of 128 kbits/second. + Using the GSM codec, this flow is reduced to 13 kbits/second, without significa +nt loss of quality. + Currently the best bitrate/quality compromise is achieved by using the + speex codec. +\end_layout + +\begin_layout Itemize +Codec choice: linphone can use several codecs. + Use buttons at the bottom of the codec list to put them in order of preference. + Note, that according to your network connection type, some codecs are not + usable. + They appear in red and they are not selectable. + You can decide to use or not a usable codec (in blue) by changing its status + with the enable/disable buttons at the bottom of the list. +\end_layout + +\begin_layout Itemize +Connection type: select how you are connected to the network you want to + use (in most cases that will be the internet). + This helps linphone configure itself according to the bandwidth of your + connection type. + For example some some high-bitrate codecs will be automatically disabled, + if you select connection with a 56k modem. +\end_layout + +\begin_layout Subsection +\begin_inset LatexCommand \label{paramaudio} + +\end_inset + +Audio parameters +\end_layout + +\begin_layout Standard +In this section you will find parameters related to your sound equipment. +\end_layout + +\begin_layout Itemize +Sound card choice: if you have several sound cards on your PC, you can select + the one to be used by linphone. +\end_layout + +\begin_layout Itemize +Source choice: in this combo box you can choose the recording source for + your voice. + In most cases it will be the microphone (mic). +\end_layout + +\begin_layout Section +Address book +\end_layout + +\begin_layout Standard +The address book lets you store and recall names and sip addresses of people. + +\end_layout + +\begin_layout Standard +When adding a new contact, a little contact box is displayed, where you + can fill in information about the person, mainly of course his SIP address. + Additionally you can toggle the +\begin_inset Quotes fld +\end_inset + +send subscription +\begin_inset Quotes frd +\end_inset + + button if you want the person to keep you informed of his online status + (ready, busy, gone...). + You can also choose to reject subscription from this person, meaning that + he will not be informed of your online status. +\end_layout + +\begin_layout Section +Using SIP proxies and registrar. +\end_layout + +\begin_layout Standard +Registering with a SIP server can be useful in two main cases: +\end_layout + +\begin_layout Itemize +Your machine does not have a public domain name, which prevents other users + to call you as they can't guess your IP address. + In this case, you can register with a proxy or redirect SIP server to get + a public SIP address. + For example, you are and let's suppose that there + exists a redirect or proxy SIP server at . + By registering as 'bob' with , your friends will be able + to call you at the address . + Of course, the user_name assigned to you by the SIP server may be different + from your login name on the local machine. + It can even be a number resembling a regular (PSTN) phone number, eg. + 5002000307. + The proxy or redirect server myserver.org will forward or redirect the calls + from your friends to your exact location. +\end_layout + +\begin_layout Standard +With linphone>=1.0.0 you can choose to use several proxies simultaneously. + Go to the property box, section sip, and click on add proxy. + You'll be prompted for a proxy address, route and your identity (also known + as address of record). + This information should be given to you by the SIP provider you registered + with. + Route can be omitted (ie. + is optional), so leave it empty in case you don't know what to put there. + The identity is the SIP address you are known by the proxy. + Other users on the network are supposed to always be able to find you at + this SIP address. +\end_layout + +\begin_layout Section +Behind a firewall +\end_layout + +\begin_layout Standard +In some cases the configuration of your network is such that linphone (or + any other SIP phone program) cannot tell with certainty, how other computers + on the network can talk to your computer. + This is usually the case, when your machine is behind a firewall/router + that uses the Network Address Translation (NAT) protocol (RFC 1631). + In order to find out linphone can use the services of a "Simple Traversal + of User datagram through Network address translators" (STUN) server (RFC + 3489). + If you are behind a NAT firewall/router put the name of your STUN server + in the respective field. + This information is usually provided to you by your SIP proxy/server and + most times, assuming that your SIP server is 'sip.example.com', it looks + like 'stun.example.com'. + You may also have to specify the port your STUN server listens to (default + 3478). +\end_layout + +\begin_layout Section +Problems +\end_layout + +\begin_layout Subsection +Connection problems +\end_layout + +\begin_layout Standard +Firewalls are the main cause of problems in call routing. + Check that udp ports are opened and masqueraded, and subscribe to a SIP + proxy outside: most proxies are able to handle firewalls issues themselves. + If not possible read section 7 (Behind a firewall). +\end_layout + +\begin_layout Subsection +Audio problems +\end_layout + +\begin_layout Quotation +Linphone seems to connect to the remote SIP url, it rings, but when the + callee answers, nothing happens and we can't hear each other. +\end_layout + +\begin_layout Itemize +Using your audio mixer program (eg. + 'alsamixer', 'kmix', or 'aumix') make make sure the audio output is not + muted and that the playback (master volume, PCM) and recording (mic) controls + are set to at least their medium values. +\end_layout + +\begin_layout Itemize +If the voice is sometimes interrupted, you can modify parameter RTP->jitter + compensation in the property box to greater values to avoid this. + But this will also increase the transmission delay. +\end_layout + +\begin_layout Itemize +If linphone cannot open the audio device, check if the user has the right + permissions to open /dev/dsp, and close all programs able to use audio + device (xmms, kaiman...), as at this point linphone cannot share the audio + device with other applications. +\end_layout + +\begin_layout Itemize +Use ALSA drivers (see +\begin_inset LatexCommand \url[http://www.alsa-project.org]{http://www.alsa-project.org} + +\end_inset + +). + Most distributions still use the old OSS kernel-official drivers, that + have big latency problems and are often buggy. + ALSA drivers are much better. + +\end_layout + +\begin_layout Section +Bugs reporting and suggestions +\end_layout + +\begin_layout Standard +First go to linphone's home page at +\begin_inset LatexCommand \url[http://www.linphone.org]{http://www.linphone.org} + +\end_inset + + to check if you have the latest version if linphone. +\end_layout + +\begin_layout Standard +If linphone crashes, send a report to the mailing list, linphone-users@nongnu.org. + If linphone does not work, but does not crash, please ensure you have read + this manual in its entirety before sending a bug report at the above address. + You can also send e-mail to the mailing list to request a specific feature, + that you think is missing from linphone. + Note that video support, and conferencing are planned features. + If someone is interested in helping with the translations of linphone to + other languages, s/he can send me a xx.po file based on the po/linphone.pot + file of the distribution. + You can also translate this user manual in other languages. + In any case, please contact me if you want more details. +\end_layout + +\begin_layout Section +Authors +\end_layout + +\begin_layout Standard +Simon MORLAT (simon.morlat@linphone.org) wrote: +\end_layout + +\begin_layout Itemize +main library (coreapi) +\end_layout + +\begin_layout Itemize +gnome interface (thanks to glade !) +\end_layout + +\begin_layout Itemize +RTP library (oRTP) +\end_layout + +\begin_layout Itemize +audio/video framework and wrappers (mediastreamer) +\end_layout + +\begin_layout Standard +Aymeric Moizard (jack@atosc.org) wrotes the osip and eXosip stacks that is + used by linphone. + +\end_layout + +\begin_layout Standard +The speex codec +\begin_inset LatexCommand \url[http://www.speex.org]{http://www.speex.org} + +\end_inset + + is a high quality low bitrate codec by Jean Marc Valin. +\end_layout + +\begin_layout Standard +The GSM library was written by : Jutta Degener and Carsten Bormann,Technische + Universitaet Berlin. +\end_layout + +\begin_layout Standard +The LPC10-1.5 library was written by: Andy Fingerhut Applied Research Laboratory + <-- this line is optional if Washington University, Campus Box 1045/Bryan + 509 you have limited space One Brookings Drive Saint Louis, MO 63130-4899 + jaf@arl.wustl.edu http://www.arl.wustl.edu/~jaf/ See text files in gsmlib and + lpc10-1.5 directories for further information. +\end_layout + +\begin_layout Standard +Icons by Pablo Marcelo Moia. +\end_layout + +\begin_layout Section +Thanks +\end_layout + +\begin_layout Standard +Thanks to Daemon Chaplin, for having done Glade, the gtk interface builder. +\end_layout + +\begin_layout Standard +Thanks to Aymeric Moizard, for his famous oSIP library. +\end_layout + +\begin_layout Standard +Thanks to Florian Winstertein, for the console interface of linphone. +\end_layout + +\begin_layout Standard +Thanks to Jean Marc Valin, for his great speex codec. +\end_layout + +\begin_layout Standard +Thanks to the authors of LPC10-1.5 and GSM code. +\end_layout + +\begin_layout Standard +Thanks to Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com ) for his RPMS. +\end_layout + +\begin_layout Standard +Thanks to Pablo Marcelo Moia for the great icons he has made for linphone. +\end_layout + +\begin_layout Standard +\begin_inset LatexCommand \tableofcontents{} + +\end_inset + + +\end_layout + +\end_body +\end_document diff --git a/linphone/share/C/manual.sgml b/linphone/share/C/manual.sgml new file mode 100644 index 000000000..4d4155e71 --- /dev/null +++ b/linphone/share/C/manual.sgml @@ -0,0 +1,85 @@ + + + + + ]> + + +
+ +Linphone's User Manual +July, 24th 2004 +Introduction +Linphone is a simple web-phone. It allows you to make two party-calls using an IP network like the internet. What you need to run Linphone is : +a computer running the GNU/Linux operating systemgtk+>=2.4, in order to use the graphical interface (highly recommended!). The console-only application (linphonec) does not need gtk but libreadline.a sound card correctly configured to use the ALSA linux sound systemheadphones or speakersa microphonea connection to a network (the Internet for example), using a modem, an ethernet card, a Wifi adapter or anything elseSince linphone needs to use the computer's sound system, before running linphone, please make sure that no other application is using the audio device. +Linphone is free, it is released under GNU Public License. +WARNING: This software is provided with NO WARRANTY see file COPYING for details. This means you SHOULD NOT use linphone for confidential conversations: there is NO encryption, so it is easy for any bad-intentioned person to monitor the audio streams, and thus your conversation. Note also that it is not recommended to run Linphone as root. +Running linphone +Linphone can be run in three different ways: +as a normal application: in the gnome menu, linphone should appear in the network sub-menu. If you are not running gnome, you can execute linphone directly by typing linphone in a terminal, for example. Please note, that when linphone is not running, you cannot receive calls.as a gnome applet: add the linphone applet by right-clicking on the gnome panel, linphone appears in the network menu. When linphone is running silently as a gnome panel, it is able to receive calls even if its window is not shown. If you want the main linphone window to appear, click on the applet. When somebody calls you, the main window is shown and you will hear the ring normally. +Making a call + +Basic principles +Linphone uses the Session Initiation Protocol (SIP) to establish a connection with a remote host. In this protocol each caller or callee is identified by a SIP url: sip:user_name@host_name. A SIP url's syntax like an email address, with a “sip:“ prefix. +User_name is probably your login account on a Unix machine, and host_name is the machines fully qualified domain name (FQDN) or IP address. +Note that SIP is a new telecommunication protocol designed to be simple, and it is not compatible with H323 at all. +When IP address are not static, or not routable. +For that purpose, you can register to a SIP provider or SIP proxy. There exist several SIP proxies on the net, and some of them are free. See, for example, http://iptel.org. You'll have to get an account on the proxy and then tell linphone to use it. In this case, the user_name will assigned to you by the VoIP provider, when you register, and host_name is the provider's host name (usually something like sip.example.com). +Test trial: If you have no friends to call at the moment (because it is too late for example), but would like to know if linphone is really working. +Since version 0.3.0, linphone comes with a test program called 'sipomatic'. Sipomatic can answer automatically calls from linphone. To do this: +run sipomatic from a terminal. Sipomatic does not have a graphical interface, but you don't have to interact with it, so it doesn't need one. Then type the following SIP url in the main window of linphone: sip:robot@127.0.0.1:5064 . 127.0.0.1 is the local address for your computer, and robot is the name to use for calling sipomatic. 5064 is the port that sipomatic is listening to. Normally you should always use 5060 (i.e the default port when no port is specified) to call somebody, but sipomatic is the exception: it runs on port 5064. The reason for this is that linphone itself already runs on 5060, and you cannot have two applications running on the same port, at the same time and on the same machine.Then press the call button. After one second, sipomatic should answer to your call and you should hear a short announcement. +<!-- anchor id="params" -->Call parameters + +<!-- anchor id="paramnetwork" -->Network +Linphone allows you to set your firewall address (see section 7) or a stun server address that might help linphone calling and receiving calls. +Linphone supports ipv6: you can enable it by toggling the “Enable ipv6” checkbox. However it can support Ipv6 and Ipv4 together. +<!-- anchor id="paramrtp" -->RTP +RTP (Real Time Protocol) is a protocol used to send media streams over networks. +RTP port: linphone uses default port 7078 to send and receive audio streams. If you think port 7078 is used by another application, change it as you wish.Jitter compensation: This number represents the number of audio packets linphone is waiting for before starting to play them. If sometimes some audio packets are late, they have a greater chance to be played. Increase this parameter, if the other person's voice sounds 'chopped', in order to improve the quality of the transmission. This will however increase the delay (you will hear the remote user's talk with a few seconds delay). If, on the other hand, you are using a fast network, and you have good audio drivers, you can set this parameters down to three packets, and you will have a very small delay. +<!-- anchor id="paramsip" -->SIP +SIP (Session Initiation Protocol) is a protocol to establish and destroy media sessions over a network. In simple words, it's responsible for controlling calls. It rings the remote user, initiates the call and terminates it when one of the two parties hangs up. +SIP port: linphone uses default port 5060 to send and receive SIP packets. It is highly recommended by SIP's RFC to use port 5060. So, please don't change this unless you really know what you are doing.Use registrar: toggle this button if you need the services of a remote SIP server. See section “Registering on a remote server” for details about this. +<!-- anchor id="paramcodec" -->Codecs +Codecs are algorithms especially designed to compress voice data. For example, digitized voice in 16bit / 8000 Hz represents a data flow of 128 kbits/second. Using the GSM codec, this flow is reduced to 13 kbits/second, without significant loss of quality. Currently the best bitrate/quality compromise is achieved by using the speex codec. +Codec choice: linphone can use several codecs. Use buttons at the bottom of the codec list to put them in order of preference. Note, that according to your network connection type, some codecs are not usable. They appear in red and they are not selectable. You can decide to use or not a usable codec (in blue) by changing its status with the enable/disable buttons at the bottom of the list.Connection type: select how you are connected to the network you want to use (in most cases that will be the internet). This helps linphone configure itself according to the bandwidth of your connection type. For example some some high-bitrate codecs will be automatically disabled, if you select connection with a 56k modem. +<!-- anchor id="paramaudio" -->Audio parameters +In this section you will find parameters related to your sound equipment. +Sound card choice: if you have several sound cards on your PC, you can select the one to be used by linphone.Source choice: in this combo box you can choose the recording source for your voice. In most cases it will be the microphone (mic). +Address book +The address book lets you store and recall names and sip addresses of people. +When adding a new contact, a little contact box is displayed, where you can fill in information about the person, mainly of course his SIP address. Additionally you can toggle the “send subscription” button if you want the person to keep you informed of his online status (ready, busy, gone...). You can also choose to reject subscription from this person, meaning that he will not be informed of your online status. +Using SIP proxies and registrar. +Registering with a SIP server can be useful in two main cases: +Your machine does not have a public domain name, which prevents other users to call you as they can't guess your IP address. In this case, you can register with a proxy or redirect SIP server to get a public SIP address. For example, you are <sip:bob@no-host-name> and let's suppose that there exists a redirect or proxy SIP server at <sip:myserver.org>. By registering as 'bob' with <sip:myserver.org>, your friends will be able to call you at the address <sip:bob@myserver.org> . Of course, the user_name assigned to you by the SIP server may be different from your login name on the local machine. It can even be a number resembling a regular (PSTN) phone number, eg. 5002000307. The proxy or redirect server myserver.org will forward or redirect the calls from your friends to your exact location.With linphone>=1.0.0 you can choose to use several proxies simultaneously. Go to the property box, section sip, and click on add proxy. You'll be prompted for a proxy address, route and your identity (also known as address of record). This information should be given to you by the SIP provider you registered with. Route can be omitted (ie. is optional), so leave it empty in case you don't know what to put there. The identity is the SIP address you are known by the proxy. Other users on the network are supposed to always be able to find you at this SIP address. +Behind a firewall +In some cases the configuration of your network is such that linphone (or any other SIP phone program) cannot tell with certainty, how other computers on the network can talk to your computer. This is usually the case, when your machine is behind a firewall/router that uses the Network Address Translation (NAT) protocol (RFC 1631). In order to find out linphone can use the services of a "Simple Traversal of User datagram through Network address translators" (STUN) server (RFC 3489). If you are behind a NAT firewall/router put the name of your STUN server in the respective field. This information is usually provided to you by your SIP proxy/server and most times, assuming that your SIP server is 'sip.example.com', it looks like 'stun.example.com'. You may also have to specify the port your STUN server listens to (default 3478). +Problems + +Connection problems +Firewalls are the main cause of problems in call routing. Check that udp ports are opened and masqueraded, and subscribe to a SIP proxy outside: most proxies are able to handle firewalls issues themselves. If not possible read section 7 (Behind a firewall). +Audio problems +
+Linphone seems to connect to the remote SIP url, it rings, but when the callee answers, nothing happens and we can't hear each other. +
+Using your audio mixer program (eg. 'alsamixer', 'kmix', or 'aumix') make make sure the audio output is not muted and that the playback (master volume, PCM) and recording (mic) controls are set to at least their medium values.If the voice is sometimes interrupted, you can modify parameter RTP->jitter compensation in the property box to greater values to avoid this. But this will also increase the transmission delay.If linphone cannot open the audio device, check if the user has the right permissions to open /dev/dsp, and close all programs able to use audio device (xmms, kaiman...), as at this point linphone cannot share the audio device with other applications.Use ALSA drivers (see http://www.alsa-project.org). Most distributions still use the old OSS kernel-official drivers, that have big latency problems and are often buggy. ALSA drivers are much better.
+Bugs reporting and suggestions +First go to linphone's home page at http://www.linphone.org to check if you have the latest version if linphone. +If linphone crashes, send a report to the mailing list, linphone-users@nongnu.org. If linphone does not work, but does not crash, please ensure you have read this manual in its entirety before sending a bug report at the above address. You can also send e-mail to the mailing list to request a specific feature, that you think is missing from linphone. Note that video support, and conferencing are planned features. If someone is interested in helping with the translations of linphone to other languages, s/he can send me a xx.po file based on the po/linphone.pot file of the distribution. You can also translate this user manual in other languages. In any case, please contact me if you want more details. +Authors +Simon MORLAT (simon.morlat@linphone.org) wrote: +main library (coreapi)gnome interface (thanks to glade !)RTP library (oRTP)audio/video framework and wrappers (mediastreamer)Aymeric Moizard (jack@atosc.org) wrotes the osip and eXosip stacks that is used by linphone. +The speex codec http://www.speex.org is a high quality low bitrate codec by Jean Marc Valin. +The GSM library was written by : Jutta Degener and Carsten Bormann,Technische Universitaet Berlin. +The LPC10-1.5 library was written by: Andy Fingerhut Applied Research Laboratory <-- this line is optional if Washington University, Campus Box 1045/Bryan 509 you have limited space One Brookings Drive Saint Louis, MO 63130-4899 jaf@arl.wustl.edu http://www.arl.wustl.edu/~jaf/ See text files in gsmlib and lpc10-1.5 directories for further information. +Icons by Pablo Marcelo Moia. +Thanks +Thanks to Daemon Chaplin, for having done Glade, the gtk interface builder. +Thanks to Aymeric Moizard, for his famous oSIP library. +Thanks to Florian Winstertein, for the console interface of linphone. +Thanks to Jean Marc Valin, for his great speex codec. +Thanks to the authors of LPC10-1.5 and GSM code. +Thanks to Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com ) for his RPMS. +Thanks to Pablo Marcelo Moia for the great icons he has made for linphone. +
\ No newline at end of file diff --git a/linphone/share/C/manual/.cvsignore b/linphone/share/C/manual/.cvsignore new file mode 100644 index 000000000..2d19fc766 --- /dev/null +++ b/linphone/share/C/manual/.cvsignore @@ -0,0 +1 @@ +*.html diff --git a/linphone/share/C/sipomatic.1 b/linphone/share/C/sipomatic.1 new file mode 100644 index 000000000..a1f21e8cf --- /dev/null +++ b/linphone/share/C/sipomatic.1 @@ -0,0 +1,70 @@ +.\" Sipomatic is a SIP phone server. It answers automatically to incoming calls by playing a short message. +.TH "sipomatic" "1" "1.0.0" "Simon Morlat" "linphone" +.SH "NAME" +.LP +sipomatic \- SIP auto\-responder from the linphone project. +.SH "SYNTAX" +.LP +sipomatic [\fI\-u\fP] <\fIsip\-url\fP> [\fI\-f\fP] <\fIannouce\-file\fP> [\fI\-s\fP] <\fIsend\-port\fP> +.LP +sipomatic \fI\-v\fP +.br +sipomatic \fI\-\-version\fP +.LP +sipomatic \fI\-h\fP +.br +sipomatic \fI\-\-help\fP +.SH "DESCRIPTION" +.LP +Sipomatic is primilarly a test tool for linphone. +It waits for incoming sip calls, and answer to them by playing a wav sound file on disk. The sended stream is encoded using the preferred codec of the calling sip\-phone. +.br +The default address of sipomatic is +It can be overriden with the \-u option. +.br +The default annouce file 'hello.wav' can be overriden with the \-f option. +.br +If you attempt to run several sipomatic on the same machine, then you will require the \-s option to specify explicitely the UDP port used by sipomatic to send its SIP messages. + +.SH "OPTIONS" +.LP +.TP +\fB\-u\fR <\fIurl\fP> +Set the sip url sipomatic listens to. The host part of address MUST always be a numerical ip address. The default url is sip:robot@127.0.0.1:5064 . +.TP +\fB\-f\fR <\fIannouce\-file\fP> +Specifies a 8000Hz 16 bits wav file to be played to the calling users. Default is usually /usr/share/sounds/linphone/hello.wav. +.TP +\fB\-s\fR <\fIsend\-port\fP> +Specifies explicitely the udp port number to be used to send SIP messages. +.TP +\fB\-v\fR +\fB\-\-version\fR +Output version information and exits. +.TP +\fB\-h\fR +\fB\-\-help\fR +Output help information and exits. +.TP +.SH "FILES" +.LP +\fI/usr/share/sounds/linphone/hello.raw\fP +.br +This is the file that sipomatic plays by default to the calling phones. +The format of this file is a 8000 Hz 16 bit wav file. +.br + +.SH "ENVIRONMENT VARIABLES" +.LP +.TP +\fBSIPOMATIC_URL\fP +Specifies the address sipomatic listens to. By default it is + . +.SH "EXAMPLES" + +.SH "AUTHORS" +.LP +Simon MORLAT +.SH "SEE ALSO" +.LP +linphone(1) linphonec(1) diff --git a/linphone/share/Makefile.am b/linphone/share/Makefile.am new file mode 100644 index 000000000..a15fe2ea7 --- /dev/null +++ b/linphone/share/Makefile.am @@ -0,0 +1,36 @@ + +SUBDIRS=C fr it ja cs + +LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav +LINPHONE_RINGS=rings/orig.wav \ + rings/oldphone.wav \ + rings/rock.wav \ + rings/bigben.wav \ + rings/toy.wav \ + rings/sweet.wav \ + rings/synth.wav \ + rings/tapping.wav + +sounddir=$(datadir)/sounds/linphone + +sound_DATA=$(LINPHONE_SOUNDS) + +ringdir=$(datadir)/sounds/linphone/rings + +ring_DATA=$(LINPHONE_RINGS) + +#to be compliant with freedesktop.org: +linphone_fddir= $(datadir)/applications +linphone_fd_DATA= linphone.desktop + + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA=linphone.pc + +EXTRA_DIST = $(LINPHONE_SOUNDS) \ + $(LINPHONE_RINGS) \ + linphone.gnorba \ + linphone.desktop \ + linphone_applet.desktop \ + linphone.pc.in \ + Makefile.inc diff --git a/linphone/share/Makefile.inc b/linphone/share/Makefile.inc new file mode 100644 index 000000000..7deb66aae --- /dev/null +++ b/linphone/share/Makefile.inc @@ -0,0 +1,25 @@ +linphone_manualdir = $(datadir)/gnome/help/linphone/$(HELPLANG)/ + +linphone_help = \ + $(top_builddir)/share/$(HELPLANG) + +if ENABLE_MANUAL +all-local: $(linphone_help)/manual.html +else +all-local: +endif + +$(linphone_help)/manual.html: + rm -f $(linphone_help)/manual.html + sgmltools $(srcdir)/manual.sgml + +install-data-local: + $(mkdir_p) $(DESTDIR)/$(linphone_manualdir) + -cp -f $(linphone_help)/*.html $(DESTDIR)/$(linphone_manualdir)/. + -cp -f $(linphone_help)/*.css $(DESTDIR)/$(linphone_manualdir)/. + +uninstall-local: + rm -rf $(linphone_manualdir) + + +EXTRA_DIST= manual.lyx manual.sgml diff --git a/linphone/share/cs/.cvsignore b/linphone/share/cs/.cvsignore new file mode 100644 index 000000000..3dda72986 --- /dev/null +++ b/linphone/share/cs/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/linphone/share/cs/Makefile.am b/linphone/share/cs/Makefile.am new file mode 100644 index 000000000..8bd5c4057 --- /dev/null +++ b/linphone/share/cs/Makefile.am @@ -0,0 +1,8 @@ + +HELPLANG=cs + +mandir=@mandir@/$(HELPLANG) + +man_MANS = linphone.1 linphonec.1 sipomatic.1 + +EXTRA_DIST=$(man_MANS) diff --git a/linphone/share/cs/linphone.1 b/linphone/share/cs/linphone.1 new file mode 100644 index 000000000..2e9967cc0 --- /dev/null +++ b/linphone/share/cs/linphone.1 @@ -0,0 +1,49 @@ +.\" Encoding: ISO-8859-2 +.\" Linphone is an internet phone compatible with the Session Initiation Protocol (SIP: RFC3261 ) +.\" Translation into Czech by Petr Písaø , 2006-02-26 +.TH "linphone" "1" "1.0.0" "Simon Morlat" "linphone" +.do hla cs +.do hpf hyphen.cs +.SH "JMÉNO" +.LP +linphone \- Gnome rozhraní pro linphone, internetový telefon podporující SIP. +.SH "SYNTAXE" +.LP +linphone [\fI\-\-help\fP] [\fI\-\-verbose\fP] + +.SH "POPIS" +.LP +Linphone mù¾e být spu¹tìn bez jakýchkoliv parametrù. V¹echny parametry jsou +mìnitelné v nabídce Nastavení. + +.SH "VOLBY" +.LP +.TP +\fB\-\-help\fR +Vypí¹e tuto nápovìdu a skonèí. +.TP +\fB\-\-version\fR +Vypí¹e verzi programu a skonèí. +.TP +\fB\-\-verbose\fR +Na standardní výstup vypisuje vnitøní hlá¹ení programu. Toto je vhodné pøi +ladìní. +.SH "SOUBORY" +.LP +\fI~/.gnome2/linphone\fP +.br +Odtud linphone naèítá svoji konfiguraci. Tento soubor nemusíte mìnit. +.br + +.SH "PROMÌNNÉ PROSTØEDÍ" + +.SH "PØÍKLADY" + +.SH "AUTOØI" +.LP +Simon MORLAT +Pro podrobnosti nahlédnìte do souboru AUTHORS, který je souèástí zdrojových +kódù linphone. +.SH "VIZ TAKÉ" +.LP +linphonec(1) sipomatic(1) diff --git a/linphone/share/cs/linphonec.1 b/linphone/share/cs/linphonec.1 new file mode 100644 index 000000000..3073c824f --- /dev/null +++ b/linphone/share/cs/linphonec.1 @@ -0,0 +1,76 @@ +.\" Encoding: ISO-8859-2 +.\" Linphone is an internet phone compatible with the Session Initiation Protocol (SIP: RFC3261 ) +.\" Translation into Czech by Petr Písaø , 2006-02-26 +.TH "linphonec" "1" "1.0.0" "Florian Winterstein & Simon MORLAT" "linphone, internetový telefon" +.do hla cs +.do hpf hyphen.cs +.SH "JMÉNO" +.LP +linphonec \- Øádkové rozhraní k linphone, internetový telefon podporující SIP. +.SH "SYNTAXE" +.LP +linphonec [\fI\-d\fP] <\fIúroveò_ladìní\fP> [\fI\-l\fP] <\fIlogovací_soubor\fP> +[\fI\-c\fP] <\fIkonfiguraèní_soubor\fP> +.br +linphonec \fI\-v\fP +.SH "POPIS" +.LP +Linphonec je konzolová verze internetového telefonu linphone urèeného pro +Gnome prostøedí (http://www.linphone.org). +.LP +Linphonec mù¾e být spu¹tìn bez jakýchkoliv parametrù. Pro správné spu¹tìní +nepotøebuje ¾ádný konfiguraèní soubor. Pokud ten neexistuje, pøi prvním spu¹tìní +bude vytvoøen vzorový. +Standardnì je konfiguraèní soubor ulo¾en v ~/.linphonerc. +Vìt¹ina parametrù (proxy, hesla) mù¾e být zmìnìna z pøíkazové øádky. Nìkteré +z nich (cesta k souboru s vyzvánìním) v¹ak lze zmìnit jen úpravou +konfiguraèního souboru .linponerc. +.LP +Jakmile je linphonec spu¹tìn, oèekává pøíkazy a je pøipraven pøijímat hovory. +.LP +Nejdùle¾itìj¹í pøíkazy jsou: +.br +.TP +call zavolat nìkomu. sip_url je ve tvaru sip:user@host +.TP +terminate ukonèit hovor +.TP +answer pøijmout pøíchozí hovor +.TP +help zobrazit interaktivní nápovìdu + +.SH "VOLBY" +.LP +.TP +\fB\-d\fR <\fIúroveò_ladìní\fP> +Pou¾ije ladící re¾im s danou mírou upovídanosti (úroveò_ladìní). úroveò_ladìní +je celé èíslo v rozsahu 0..5. +.TP +\fB\-h\fR +Vypí¹e nápovìdu a skonèí. +.TP +\fB\-l\fR <\fIlogovací_soubor\fP> +Urèuje soubor, kam budou zapisovány ladící informace. Jinak se pou¾ije +standardní výstup. +.TP +\fB\-c\fR <\fIkonfiguraèní_soubor\fP> +Urèuje konfiguraèní soubor, který bude naèten pøi spu¹tìní. + +.SH "SOUBORY" +.LP +\fI~/.linphonec\fP +.br + +.SH "PROMÌNNÉ PROSTØEDÍ" +.LP +.SH "PØÍKLADY" +.LP + +.SH "AUTOØI" +.LP +Florian Winterstein +.br +Simon Morlat +.SH "VIZ TAKÉ" +.LP +linphone(1) sipomatic(1) diff --git a/linphone/share/cs/sipomatic.1 b/linphone/share/cs/sipomatic.1 new file mode 100644 index 000000000..bf9d35ca0 --- /dev/null +++ b/linphone/share/cs/sipomatic.1 @@ -0,0 +1,82 @@ +.\" Encoding: ISO-8859-2 +.\" Sipomatic is a SIP phone server. It answers automatically to incoming calls by playing a short message. +.\" Translation into Czech by Petr Písaø , 2006-02-26 +.TH "sipomatic" "1" "1.0.0" "Simon Morlat" "linphone" +.do hla cs +.do hpf hyphen.cs +.SH "JMÉNO" +.LP +sipomatic \- SIP auto\-responder z projektu linphone. +.SH "SYNTAXE" +.LP +sipomatic [\fI\-u\fP] <\fIsip\-url\fP> [\fI\-f\fP] <\fInahrávka\fP> +[\fI\-s\fP] <\fIodchozí_port\fP> +.LP +sipomatic \fI\-v\fP +.br +sipomatic \fI\-\-version\fP +.LP +sipomatic \fI\-h\fP +.br +sipomatic \fI\-\-help\fP +.SH "POPIS" +.LP +Sipomatic je základní testovací nástroj pro linphone. +Èeká na pøíchozí sipový hovor a odpoví na nìj pøehráním zvukového souboru typu +WAV z disku. Odeslaný zvukový proud je kódován preferovaným kodekem volajícího +sipového telefonu. +.LP +Výchozí adresa sipomaticu je . Mù¾e být zmìnìna +volbou \-u. +.br +Namísto výchozího oznamovacího souboru "hello.wav" lze vybrat jiný volbou \-f. +.br +Jestli¾e se budete pokou¹et spustit více sipomatic klientù na jednom stroji, +pak budete potøebovat volbou \-s explicitnì urèit UDP port, který bude pou¾it +k odeslání vlastních SIP zpráv. + +.SH "VOLBY" +.LP +.TP +\fB\-u\fR <\fIurl\fP> +Nastaví SIP URL, na které bude sipomatic poslouchat. Èást adresy se jménem +poèítaèe MUSÍ být v¾dy èíselná IP adresa. Výchozí URL je sip:robot@127.0.0.1:5064 +.TP +\fB\-f\fR <\fInahrávka\fP> +Urèuje 8000Hz 16bitový WAV soubor, který bude pøehrán volajícímu u¾ivateli. +Výchozí cesta bývá /usr/share/sounds/linphone/hello.wav. +.TP +\fB\-s\fR <\fIodchozí_port\fP> +Explicitnì definuje èíslo UDP portu, který bude pou¾it pro odchozí SIP zprávy. +.TP +\fB\-v\fR +\fB\-\-version\fR +Vytiskne informace o verzi a skonèí. +.TP +\fB\-h\fR +\fB\-\-help\fR +Vypí¹e nápovìdu a skonèí. +.LP +.SH "SOUBORY" +.LP +\fI/usr/share/sounds/linphone/hello.raw\fP +.br +Toto je soubor, který sipomatic standardnì pøehraje volajícímu telefonu. +Formát tohoto souboru je WAV vzorkovaný 16bitovou hodnotou s frekvencí +8000 Hz. +.br + +.SH "PROMÌNNÉ PROSTØEDÍ" +.LP +.TP +\fBSIPOMATIC_URL\fP +Definuje adresu, na které sipomatic poslouchá. Jinak je pou¾ita + +.SH "PØÍKLADY" + +.SH "AUTOØI" +.LP +Simon MORLAT +.SH "VIZ TAKÉ" +.LP +linphone(1) linphonec(1) diff --git a/linphone/share/fr/.cvsignore b/linphone/share/fr/.cvsignore new file mode 100644 index 000000000..e1d20773b --- /dev/null +++ b/linphone/share/fr/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +manual +manual.junk +manual.html diff --git a/linphone/share/fr/Makefile.am b/linphone/share/fr/Makefile.am new file mode 100644 index 000000000..6da5a815c --- /dev/null +++ b/linphone/share/fr/Makefile.am @@ -0,0 +1,3 @@ +HELPLANG=fr + +include ../Makefile.inc diff --git a/linphone/share/fr/manual.lyx b/linphone/share/fr/manual.lyx new file mode 100644 index 000000000..793c7f4c6 --- /dev/null +++ b/linphone/share/fr/manual.lyx @@ -0,0 +1,745 @@ +#LyX 1.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 218 +\textclass docbook +\language french +\inputencoding latin1 +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize Default +\paperpackage a4 +\use_geometry 0 +\use_amsmath 0 +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language french +\quotes_times 2 +\papercolumns 1 +\papersides 1 +\paperpagestyle default + +\layout Title + + +\begin_inset LatexCommand \label{manual} + +\end_inset + +MANUEL DE L'UTILISATEUR DE LINPHONE +\layout Author + +Simon Morlat (simon.morlat@linphone.org) +\layout Date + +11-13-2001 +\layout Section + +Introduction +\layout Standard + +Linphone est un simple logiciel de téléphonie sur le web. + Il permet d'effectuer des conversations comprenants deux participants en + utilisant un réseau IP comme Internet. + Ainsi, voici l'équipement nécessaire pour utiliser Linphone : +\layout Itemize + +Linux ( Peut fonctionner dans d'autres environnements tels que BSD ou d'autres + UNIX, mais personne ne l'a encore testé.) +\layout Itemize + +Gnome 1.2 ou supérieur, installé mais pas nécessairement utilisé. +\layout Itemize + +Une carte son configuré correctement. +\layout Itemize + +Des écouteurs ou haut-parleurs. +\layout Itemize + +Un micro. +\layout Itemize + +Une connection réseau (Internet par exemple), par modem, carte réseau Ethernet + ... +\layout Standard + +Il est préférable de fermer toutes les applications utilisant la carte son + avant d'utiliser Linphone. + Linphone est un logiciel libre, il est distribué sous la license publique + GNU. +\layout Standard + + +\emph on +ATTENTION : Ce logiciel est distribué SANS GARANTIE. + Lisez le fichier COPYING pour plus de détails. + Ceci signifie entre autre que vous ne devez pas utiliser Linphone pour + des conversations confidentielles : il y a AUCUN CRYPTAGE, de ce fait, + il est peut-être facile pour quelqu'un de mal intentionné de pirater les + flux audios. + Notez toutefois, qu'il n'est pas recommandé d'utiliser Linphone en tant + qu'utilisateur root. +\layout Section + +Utilisation +\layout Standard + +Linphone peut être utilisé suivant 3 modes différents : +\layout Itemize + +En tant qu'application (normale) : Dans le menu de Gnome, Linphone devrait + apparaître dans la section Réseau ( "Network" ). + Si vous n'utilisez pas Gnome, vous pouvez démarrer Linphone dans une fenêtre + terminal par exemple. + Quand Linphone n'est pas en cours d'éxecution, vous ne pouvez pas recevoir + d'appel(s). +\layout Itemize + +En tant qu'applet Gnome : en cliquant sur le panneau Gnome du bouton droit, + ajoutez l'applet. + Linphone apparait dans la section Réseau. + En tournant en tâche de fond dans le panneau Gnome, Linphone est capable + de recevoir des appel(s) même si sa fenêtre n'est pas visible. + Si vous voulez voir la fenêtre principale, cliquez sur l'applet. + Quand un appel arrive, la fenêtre principale passe en premier plan,et vous + entendrez normalement la sonnerie retentir. +\layout Itemize + +En tant que démon : Ceci est intéressant pour les non-utilisateurs de Gnome. + Par exemple pour KDE, vous avez un repertoire /home/user/.kde2/AutoStart/ + où vous pouvez rajouter les applications que vous voulez voir démarrer + à votre début de session. + Ainsi, dans le repertoire cité, à l'aide du gestionnaire de fichiers, ajouter + un lien en cliquant du bouton droit. + La commande à rentrer est "linphone -daemon". + Vous ne verrez pas l'interface de Linphone, donc, pour la faire apparaitre, + démarrez Linphone normalement, par exemple à travers une fenêtre terminal. +\layout Section + +Comment appeler +\layout Subsection + +Principes de base +\layout Standard + +Linphone utilise le protocole SIP (Session Initiation Protocol) pour établir + les appels avec vos correspondants. + Le protocole spécifie que chaque personne doit être identifié par une URL + sip de la forme: sip:user_name@host_name. + Cette manière d'adresser les personnes est très proche de celle utilisée + pour le courrier électronique. +\layout Standard + +User_name est un nom d'utilisateurs sur une machine, comme un nom de login + sur une machine linux, par exemple. + Host_name est le nom d'une machine, soit sous forme d'adresse IP, ou plus + simplement sous forme de nom de domaine (ex: linphone.org) +\layout Standard + +Notez que SIP est un nouveau protocole de télécommunication fait pour être + simple et efficace sur l'internet, et qu'il est totalement différent et + incompatible avec H.323. + H.323 est le protocole actuellement utilisé par NetMeeting ou GnomeMeeting. +\layout Subsection + +Application: deux personnes (Bob et Tom) se connectent à internet par un + modem analogique classique. +\layout Standard + +Voici la manière la plus simple de procéder : +\layout Standard + +Pré-requis : +\layout Itemize + +Un modem 28.8 Baud ou plus. + +\layout Standard + +Déroulement : +\layout Itemize + +Il est convenu que Bob doit appeler Tom à 21h00. + A 21h00, Tom se connecte à Internet en utilisant kppp, gppp ou wvdial (ou + un autre). + Dès qu'il est connecté sur l'Internet, il peut lancer Linphone.En ouvrant + la fenêtre de statistiques de kppp ou gppp, il peut voir son adresse IP + (sinon, il peut taper /sbin/ifconfig pour l'obtenir). + Le nom de l'interface modem doit être ppp0. +\layout Itemize + +Ensuite, il envoit un email à Bob disant : "Mon adresse IP estxxx.xxx.xxx.xxx". +\layout Itemize + +Bob recoit l'email et tape dans la fenêtre de Linphone le nom est l'adresse + IP de la personne à contacter : Tom@xxx.xxx.xxx.xxx(L'adresse IP de Tom) et + pour finir, il appuit sur le bouton Appeler. + +\layout Itemize + +Linphone sonne à la maison de Tom ...Tom a juste à répondre à l'appel en cliquant + sur le bouton "répondre" et ainsi devrait pouvoir commencer la discussion. + +\layout Standard + +Si vous rencontrez des problèmes dans une de ces étapes, allez à la section + 4-Problèmes. +\layout Subsection + +Essai en local: vous n'avez personne à appeler pour l'instant, mais vous + souhaiteriez voir si linphone marche vraiment. +\layout Standard + + +\begin_inset LatexCommand \label{sipomatic} + +\end_inset + +Depuis la version 0.3.0, Linphone est livré avec un programme de test appelé + "sipomatic". + Sipomatic peut répondre automatiquement aux appels provenant de Linphone. + A vous d'essayer : +\layout Itemize + +Demarrez linphone. +\layout Itemize + +Démarrez sipomatic dans une fenêtre terminal. + Ne soyez pas supris, sipomatic ne possède aucune interface graphique, mais + vous n'avez pas besoin de modifier quoi-que-ce-soit. + +\layout Itemize + +Dans Linphone, allez dans les propriétés, section réseau, et choisissez + "lo" comme interface par défaut. + Appliquez les changements en cliquant sur OK. + Tapez l'adresse S.I.P suivante dans la fenêtre principale : sip:robot@127.0.0.1:5064. + 127.0.0.1 est l'adresse locale de votre ordinateur, et robot est le nom à + utiliser pour appeler sipomatic. + 5064 est le port par lequel sipomatic peut-être contacté. + Normalement, vous devez toujours utiliser 5060 pour appeler quelqu'un, + mais sipomatic est une exception : il fonctionne sur le port 5064. + La raison est que Linphone fonctionne déjà sur le port 5060, et il est + impossible d'avoir deux applications utilisant le même port au même instant, + sur la même machine. + +\layout Itemize + +Appuyez sur le bouton "Appeler". + Après quelques secondes, sipomatic devrait répondre à votre appel et vous + devez entendre une courte annonce. +\layout Section + + +\begin_inset LatexCommand \label{params} + +\end_inset + +Paramètres des appels +\layout Subsection + + +\begin_inset LatexCommand \label{paramnetwork} + +\end_inset + +Réseau +\layout Itemize + +Liste des interfaces réseau: vous devez choisir une interface réseau à utiliser + avec Linphone. + Si vous voulez contacter quelqu'un sur l'Internet, vous devez choisir l'interfa +ce réseau connectée à l'Internet. + Par exemple, si vous utilisez un modem, celle-ci devrait être ppp0. + Si vous n'êtes connecté à aucun réseau, seulement l'interface réseau locale + appelé lo apparaitra dans la liste. + La seule chose que vous pouvez faire dans ce cas la est d'appeler +\begin_inset LatexCommand \ref[sipomatic]{sipomatic} + +\end_inset + +. +\layout Itemize + +Type de connection: choisissez le type de connection que vous utilisez pour + vous connecter au réseau que vous désirez utiliser. + Ceci aidera Linphone à s'auto-configurer en fonction de la bande passante + de votre type de connection. +\layout Subsection + + +\begin_inset LatexCommand \label{paramrtp} + +\end_inset + +RTP +\layout Standard + +RTP signifie Real Time Protocol, il permet d'envoyer des flux de données + multimedia. +\layout Itemize + +port RTP: Linphone utilise le port 7072 par défaut pour envoyer et recevoir + des signaux audios. + Si vous pensez que le port 7072 est utilisé par une autre application, + changez le comme vous voulez. +\layout Itemize + +Jitter compensation: ce nombre représente le nombre de paquets audios que + Linphone attend avant de vous les faire entendre. + Augmentez ce nombre si vous entendez une voix hachée de manière à améliorer + la qualité de la transmission, mais attention, ceci augmente le delai (vous + entendrez la voix de l'utilisateur distant quelques millisecondes plus + tard).D'un autre côté, si vous utilisez un réseau parfait, et que vous disposez + de bon drivers audios, vous pouvez descendre ces paramètres très bas jusqu'à + 3 paquets, ainsi vous aurez un délai très faible. +\layout Subsection + + +\begin_inset LatexCommand \label{paramsip} + +\end_inset + +SIP +\layout Standard + +SIP (Session Initiation Protocol) est un protocole qui permet d'établir + des sessions de téléphonie par l'intermédiaire d'un réseau IP. + En simplifiant, c'est la chose qui permet de faire sonner chez l'autre + utilisateur, démarrer ou terminer l'appel quand l'un des deux correspondants + raccroche. +\layout Itemize + +port SIP: Linphone utilise par défaut le port 5060 pour envoyer / recevoir + des paquets SIP. + Il est hautement recommandé par la RFC du protocole SIP d'utiliser celui-ci. + Donc, ne le changez pas à moins que vous n'ayez vraiment pas le choix. +\layout Itemize + +Votre adresse SIP: modifiez ici votre nom d'utilisateur et votre nom de + machine à votre gré. + Bien entendu donner un nom de machine ici ne signifie pas que ce nom soit + connue des autres machines du réseau. + Néammoins linphone utilisera peu ce nom de machine et préfèrera utiliser + votre adresse IP pour communiquer avec d'autres machines. +\layout Itemize + +Utiliser un serveur sip registrar: Cochez ce choix, si vous voulez vous + enregistrer sur un serveur SIP (registrar) pour obtenir différents services. + Quand vous n'avez pas d'adresse IP fixe, cela peut-être très intéressant + pour permettre à vos amis de vous appeler. + Regardez la section intitulée " +\begin_inset LatexCommand \ref[enregistrement sur un serveur sip]{registering} + +\end_inset + +". +\layout Subsection + + +\begin_inset LatexCommand \label{paramcodec} + +\end_inset + +Codecs +\layout Standard + +Les codecs sont des algorithmes utilisés pour compresser la voix. + Par exemple, une voix digitalisée en 16bit/8000Hz représente un flux de + données de 128kbits/seconde. + En utilisant le vocodeur GSM, ce flux est réduit à 13kbits/seconde, sans + perte significative de qualité. +\layout Itemize + +Choix de codecs: Linphone peut utiliser plusieurs codecs. + Utilisez les boutons situés en dessous de la liste des codecs de manière + à les placer dans un order de préférence. + Notez bien, qu'en fonction de votre type de connection réseau, certains + codecs sont inutilisables.Ils apparaitront en rouge et ne seront pas sélectionna +ble. + Vous pouvez décider d'utiliser ou non un codec "utilisable" (en bleu) en + changeant son état à l'aide du bouton activer/désactiver en dessous de + la liste. +\layout Subsection + + +\begin_inset LatexCommand \label{paramaudio} + +\end_inset + +Audio parameters +\layout Itemize + +Mode de pilotage: si vous avez installé des drivers ALSA avec une librairie + ALSA <0.9, choisissez ALSA pour avoir de meilleires performances. + Sinon, ou si vous n'en savez rien, choisissez OSS, cela marche suffisemment + bien. +\layout Itemize + +Choix de la source d'enregistrement: vous pouvez choisir votre source d'enregist +rement pour la voix. + Dans la plupart des cas, celle-ci sera le microphone. +\layout Itemize + +Auto-kill option: en choissant cette option, Linphone essaiera de stopper + les processus sonores (esd & artsd) qui peuvent bloquer votre périphérique + sonore et ainsi provoquer des problèmes d'ouverture des périphériques par + Linphone quand il en a besoin. + Il est recommandé d'activer cette option. +\layout Section + +Carnet d'adresses +\layout Standard + +Depuis la version 0.4.1 linphone dispose d'un carnet d'adresses (menu connexion, + carnet d'addresses), avec lequel vous pouvez memoriser des adresses, et + les rappeler facilement lorsque vous souhaitez appeler. +\layout Section + + +\begin_inset LatexCommand \label{registering} + +\end_inset + +Enregistrement sur un serveur sip +\layout Standard + +Vous pouvez souscrire des services sur des serveurs sip distants appelés + registrar, proxy ou redirect server. + Ces services peuvent être: +\layout Standard + +You can suscribe for services on remote SIP servers. + These services can be: +\layout Itemize + +redirection: linphone va demander au serveur la création d' un compte . + Cette adresse pourra alors être utilisée par vos correspondants pour vous + joindre. + Un petit example concret pour bien comprendre: vous n'êtes qu'un pauvre + internaute connecté temporairement grace à un modem 56k. + Votre machine n'a pas de nom de domaine connu et votre adresse IP change + à chaque nouvelle connexion. + Il est impossible pour vos amis de vous joindre car il ne peuvent deviner + votre adresse IP, à moins que vous ne leur donniez en envoyant un courriel, + par exemple. + Pour palier à ce problème, vous pouvez demander à avoir un compte sur un + serveur sip connu de vos amis, qui lui est fixe et tout le temps connecté. + Pour cela, spécifiez l'adresse du serveur dans la boite de propriété, section + sip. + Cette adresse est par exemple et votre nom d'utilisate +ur est +\begin_inset Quotes fld +\end_inset + +Bob +\begin_inset Quotes frd +\end_inset + +. + Linphone va alors envoyer au serveur un message pour l'informer de la correspon +dance entre l'adresse et votre adresse IP actuelle. + Desormais vos amis peuvent vous appeler en utilisant cette nouvelle adresse, + leurs appels seront alors automatiquement redirigés vers votre machine. + Il n'ont plus besoin de connaitre votre adresse IP qui change tout le temps + pour vous joindre. + Bien sur, est supposée être bien connue de tout + vos amis. + +\layout Itemize + +proxy: c'est exactement le meme principe, excepté que la redirection se + fait de manière transparente et invisible le linphone de l'appelant. +\layout Standard + +Le registrar que vous avez spécifié peut aussi être utilisé comme proxy + sortant. + Dans ce cas tous les appels émanant de votre linphone seront dirigé vers + ce serveur, et il sera supposé les faire suivre vers les bonnes personnes. + Ceci est très utile et même indispensable lorsque vous utilisez linphone + dans un réseau privé abrité par un firewall, si bien sur un proxy sip est + actif sur le firewall. + +\layout Standard + +Pour utiliser solliciter un serveur sip, vous devez aller à la boîte de + propriété, rubrique SIP, et cocher le bouton qui se trouve en face de "use + registrar". + Tapez l'adresse du registrar, et choisissez un nom d'utilisateur qui n'est + pas trop fréquent de manière à éviter les conflits de noms. + Donnez une indication du service que le serveur doit effectuer pour vous + en cochant les boutons +\begin_inset Quotes fld +\end_inset + +redirection +\begin_inset Quotes frd +\end_inset + + ou +\begin_inset Quotes fld +\end_inset + +proxy +\begin_inset Quotes frd +\end_inset + +. + Sélectionnez aussi l'option +\begin_inset Quotes fld +\end_inset + +le serveur est un proxy sortant +\begin_inset Quotes frd +\end_inset + + si vous êtes derrière un pare-feu. +\layout Standard + +Enfin en fermant la boite de propriétés linphone communiquera immédiatement + avec le serveur SIP pour y obtenir les services demandés. + De même lorsque vous fermez linphone, celui ci prendra quelques secondes + pour se désenregistrer auprès du serveur. +\layout Standard + +Une liste de serveurs sip peut être trouvée à cette addresse: +\begin_inset LatexCommand \url[http://www.cs.columbia.edu/~hgs/sip/servers.html]{http://www.cs.columbia.edu/~hgs/sip/servers.html} + +\end_inset + +. + Malheureusement, beaucoup de ces serveurs ne fonctionnent plus, peut-être + à cause de la crise et de ses faillites. + Certains ne sont pas utilisables car ils requierent des méthodes d'autentificat +ion qui ne sont pas encore implémentées dans linphone. + Afin donc de ne pas vous faire perdre votre temps, une liste des serveurs + sip publiques fonctionnant avec linphone est disponible sur +\begin_inset LatexCommand \url[http://simon.morlat.free.fr/english/servers.html]{http://simon.morlat.free.fr/english/servers.html} + +\end_inset + +. +\layout Section + +Utilisation derrière les pares-feux +\layout Standard + +Linphone est capable de fonctionner derrière les firewalls grâce à un serveur + proxy SIP fonctionnant sur la machine firewall. + Un tel serveur est en cours de développement sur +\begin_inset LatexCommand \url[http://osipproxy.sourceforge.net]{http://osipproxy.sourceforge.net} + +\end_inset + +. + Bien sûr il sera libre et basé sur la librairie LGPL oSIP. +\layout Standard + +Une fois le proxy serveur mis en place, il vous faut configurer linphone + pour qu'il l'utilise. + Pour cela rendez vous dans la boite de propriétés, section SIP et cochez + la case +\begin_inset Quotes fld +\end_inset + +Utiliser un registrar SIP +\begin_inset Quotes frd +\end_inset + +, indiquez son adresse, et cocher l'option +\begin_inset Quotes fld +\end_inset + +le serveur est un proxy sortant +\begin_inset Quotes frd +\end_inset + +. +\layout Standard + +Il y a un cas pour lequel le proxy n'est pas indispensable: c'est le cas + où les machines du réseau privé possèdent une adresse publique, le firewall + étant là pour filtrer les paquets entrants ou sortants. + Vous devez pour permettre a linphone de fonctionner avec des machines exterieur +es, autoriser le traffic UDP sur le port SIP (par defaut 5060, il est deconseill +é de le changer), et sur le port RTP de chaque linphone du sous réseau. + Le port RTP est paramètrable comme bon vous semble dans la boite de proprietés. +\layout Section + +Problèmes divers +\layout Subsection + +Problèmes de connexion +\layout Quotation + +J'essaye d'appeler mon pote , mais rien ne se passe, + pas de sonnerie. +\layout Standard + +Vous devez vérifier que linphone utilise l'interface réseau qui vous connecte + sur le réseau ou se trouve votre ami. + La liste des interface disponibles est donnée dans la boite de propriété, + section réseau. + Sélectionnez la bonne. + +\layout Standard + +Si le problème persiste, il y a fort à parier que votre ami ne soit pas + joignable actuellement. +\layout Subsection + +Problèmes audio +\layout Quotation + +Linphone semble correctement établir l'appel, il sonne, mais une fois que + le correspondant a décrocher, plus rien ne se passe et on ne s'entend pas. +\layout Itemize + +La plupart des gens ont ce genre de symptome car ils n'ont pas choisi la + bonne interface réseau. + Si vous êtes connectés par modem, ce doit être ppp0. + En aucun cas l'interface +\begin_inset Quotes fld +\end_inset + +lo +\begin_inset Quotes frd +\end_inset + + ne peut permettre d'avoir une communication via le réseau. + Elle ne sert que pour le test local avec sipomatic (voir plus haut). +\layout Itemize + +Augmentez le niveau sonore d'acquisition et de restitution, à l'aide des + potentiomètres situés en bas de la fenêtre principale. +\layout Itemize + +Si la voix de votre correspondant vous semble coupée ou hachée, vous pouvez + essayer d'augmenter le paramètre jitter compensation de l'onglet RTP de + la boite de propriété. + Mais attention, cela augmente la latence en contrepartie. +\layout Itemize + +Si linphone ne peut se servir de la carte son, vérifiez que celle ci n'est + pas utilisée au meme moment par d'autres programmes audio. + +\layout Itemize + +Enfin utilisez les drivers sons alsa (voir +\begin_inset LatexCommand \url[http://www.alsa-project.org]{http://www.alsa-project.org} + +\end_inset + +) , plutôt que les oss fournit avec le kernel linux. + Malheureusement la plupart des distributions utilsent encore ces vieux + pilotes alors qu'ils presentent de nombreux bugs et problèmes de latence. + Les drivers ALSA sont beaucoup plus performants. + Notez que si vous changer vos drivers, vous n'avez nul besoin de recompiler + linphone ou de changer quoi que ce soit a sa configuration. + +\layout Section + +Rapports de bogues et suggestions +\layout Standard + +En premier lieu, allez sur le site de Linphone +\begin_inset LatexCommand \url[http://www.linphone.org]{http://www.linphone.org} + +\end_inset + + afin de vérifier que vous ayez bien la dernière version de Linphone. + +\layout Standard + +Si linphone plante, envoyez moi directement un message à bugs@linphone.org. + Si Linphone ne fonctionne pas, mais ne se plante pas, vérifiez bien que + vous avez bien lu ce manuel entièrement avant de m'envoyer un compte rendu + à l'adresse précédente. + Dans tous les cas veillez à m'envoyer le plus d'information possible relatifs + à votre problème, notamment la sortie de debug que linphone écrit lorsque + vous l'executez depuis un terminal. + Si vous désirez autre chose, n'hésitez pas à m'envoyer un email à l'adresse + help@linphone.org. + Prenez note que l'ajout de la vidéo et du mode conférence sont planifiés. + +\layout Standard + +Si quelqu'un est interessé pour faire des traductions de Linphone, envoyez + moi un fichier xx.po basé sur celui se trouvant dans po/linphone.pot de la + distribution. + Vous pouvez aussi traduire ce manuel utilisateur dans d'autres langues. + Dans tous les cas, contactez moi si vous voulez plus de détails. +\layout Section + +Auteurs +\layout Standard + +Simon MORLAT (simon.morlat@linphone.org) a ecrit: +\layout Itemize + +Programme principal (src) +\layout Itemize + +librairie RTP (lprtplib) +\layout Itemize + +osipua : la librarie sip User Agent au dessus d'osip. +\layout Itemize + +interface pour les drivers audio (audio) +\layout Itemize + +les wrappers pour les codecs lpc10-1.5, gsm et g711. + +\layout Standard + +Aymeric Moizard (jack@atosc.org) a ecrit la pile SIP oSIP utilisé par linphone. + +\layout Standard + +La librairie GSM a été écrite par: Jutta Degener and Carsten Bormann,Technische + Universitaet Berlin. +\layout Standard + +La librairie LPC10-1.5 par: Andy Fingerhut Applied Research Laboratory <-- + this line is optional if Washington University, Campus Box 1045/Bryan 509 + you have limited space One Brookings Drive Saint Louis, MO 63130-4899 jaf@arl.wu +stl.edu http://www.arl.wustl.edu/~jaf/ Lisez les fichiers textes README dans + les repertoire gsmlib et lpc10-1.5 pour plus d'informations. +\layout Standard + +Les icones sont de Pablo Marcelo Moia et le logo de Philippe Beau. +\layout Section + +Remerciements +\layout Standard + +Merci à Daemon Chaplin pour avoir fait Glade, le constructeur d'interface + graphique GTK+. +\layout Standard + +Merci aux auteurs du code des LPC10-1.5 et GSM. +\layout Standard + +Merci à Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com ) pour ses RPMS. +\layout Standard + +Merci à Pablo Marcelo Moia pour les icones. +\layout Standard + +Merci à Philippe Beau pour la traduction de ce manuel en Francais, pour + le logo, et pour le nouveau site web qu'il a fait pour linphone. +\layout Standard + + +\begin_inset LatexCommand \tableofcontents{} + +\end_inset + + +\the_end diff --git a/linphone/share/fr/manual.sgml b/linphone/share/fr/manual.sgml new file mode 100644 index 000000000..e800f0595 --- /dev/null +++ b/linphone/share/fr/manual.sgml @@ -0,0 +1,488 @@ + + +
+ + + + MANUEL DE L'UTILISATEUR DE LINPHONE + + + Simon Morlat (simon.morlat@linphone.org) + + + 11-13-2001 + + + + + Introduction + + + Linphone est un simple logiciel de téléphonie sur le web. Il permet d'effectuer des conversations comprenants deux participants en utilisant un réseau IP comme Internet. Ainsi, voici l'équipement nécessaire pour utiliser Linphone : + + + + + Linux ( Peut fonctionner dans d'autres environnements tels que BSD ou d'autres UNIX, mais personne ne l'a encore testé.) + + + + + Gnome 1.2 ou supérieur, installé mais pas nécessairement utilisé. + + + + + Une carte son configuré correctement. + + + + + Des écouteurs ou haut-parleurs. + + + + + Un micro. + + + + + Une connection réseau (Internet par exemple), par modem, carte réseau Ethernet ... + + + + + Il est préférable de fermer toutes les applications utilisant la carte son avant d'utiliser Linphone. Linphone est un logiciel libre, il est distribué sous la license publique GNU. + + + ATTENTION : Ce logiciel est distribué SANS GARANTIE. Lisez le fichier COPYING pour plus de détails. Ceci signifie entre autre que vous ne devez pas utiliser Linphone pour des conversations confidentielles : il y a AUCUN CRYPTAGE, de ce fait, il est peut-être facile pour quelqu'un de mal intentionné de pirater les flux audios. Notez toutefois, qu'il n'est pas recommandé d'utiliser Linphone en tant qu'utilisateur root. + + + + + Utilisation + + + Linphone peut être utilisé suivant 3 modes différents : + + + + + En tant qu'application (normale) : Dans le menu de Gnome, Linphone devrait apparaître dans la section Réseau ( "Network" ). Si vous n'utilisez pas Gnome, vous pouvez démarrer Linphone dans une fenêtre terminal par exemple. Quand Linphone n'est pas en cours d'éxecution, vous ne pouvez pas recevoir d'appel(s). + + + + + En tant qu'applet Gnome : en cliquant sur le panneau Gnome du bouton droit, ajoutez l'applet. Linphone apparait dans la section Réseau. En tournant en tâche de fond dans le panneau Gnome, Linphone est capable de recevoir des appel(s) même si sa fenêtre n'est pas visible. Si vous voulez voir la fenêtre principale, cliquez sur l'applet. Quand un appel arrive, la fenêtre principale passe en premier plan,et vous entendrez normalement la sonnerie retentir. + + + + + En tant que démon : Ceci est intéressant pour les non-utilisateurs de Gnome. Par exemple pour KDE, vous avez un repertoire /home/user/.kde2/AutoStart/ où vous pouvez rajouter les applications que vous voulez voir démarrer à votre début de session. Ainsi, dans le repertoire cité, à l'aide du gestionnaire de fichiers, ajouter un lien en cliquant du bouton droit. La commande à rentrer est "linphone -daemon". Vous ne verrez pas l'interface de Linphone, donc, pour la faire apparaitre, démarrez Linphone normalement, par exemple à travers une fenêtre terminal. + + + + + + + Comment appeler + + + + Principes de base + + + Linphone utilise le protocole SIP (Session Initiation Protocol) pour établir les appels avec vos correspondants. Le protocole spécifie que chaque personne doit être identifié par une URL sip de la forme: sip:user_name@host_name. Cette manière d'adresser les personnes est très proche de celle utilisée pour le courrier électronique. + + + User_name est un nom d'utilisateurs sur une machine, comme un nom de login sur une machine linux, par exemple. Host_name est le nom d'une machine, soit sous forme d'adresse IP, ou plus simplement sous forme de nom de domaine (ex: linphone.org) + + + Notez que SIP est un nouveau protocole de télécommunication fait pour être simple et efficace sur l'internet, et qu'il est totalement différent et incompatible avec H.323. H.323 est le protocole actuellement utilisé par NetMeeting ou GnomeMeeting. + + + + + Application: deux personnes (Bob et Tom) se connectent à internet par un modem analogique classique. + + + Voici la manière la plus simple de procéder : + + + Pré-requis : + + + + + Un modem 28.8 Baud ou plus. + + + + + Déroulement : + + + + + Il est convenu que Bob doit appeler Tom à 21h00. A 21h00, Tom se connecte à Internet en utilisant kppp, gppp ou wvdial (ou un autre). Dès qu'il est connecté sur l'Internet, il peut lancer Linphone.En ouvrant la fenêtre de statistiques de kppp ou gppp, il peut voir son adresse IP (sinon, il peut taper /sbin/ifconfig pour l'obtenir). Le nom de l'interface modem doit être ppp0. + + + + + Ensuite, il envoit un email à Bob disant : "Mon adresse IP estxxx.xxx.xxx.xxx". + + + + + Bob recoit l'email et tape dans la fenêtre de Linphone le nom est l'adresse IP de la personne à contacter : Tom@xxx.xxx.xxx.xxx(L'adresse IP de Tom) et pour finir, il appuit sur le bouton Appeler. + + + + + Linphone sonne à la maison de Tom ...Tom a juste à répondre à l'appel en cliquant sur le bouton "répondre" et ainsi devrait pouvoir commencer la discussion. + + + + + Si vous rencontrez des problèmes dans une de ces étapes, allez à la section 4-Problèmes. + + + + + Essai en local: vous n'avez personne à appeler pour l'instant, mais vous souhaiteriez voir si linphone marche vraiment. + + + Depuis la version 0.3.0, Linphone est livré avec un programme de test appelé "sipomatic". Sipomatic peut répondre automatiquement aux appels provenant de Linphone. A vous d'essayer : + + + + + Demarrez linphone. + + + + + Démarrez sipomatic dans une fenêtre terminal. Ne soyez pas supris, sipomatic ne possède aucune interface graphique, mais vous n'avez pas besoin de modifier quoi-que-ce-soit. + + + + + Dans Linphone, allez dans les propriétés, section réseau, et choisissez "lo" comme interface par défaut. Appliquez les changements en cliquant sur OK. Tapez l'adresse S.I.P suivante dans la fenêtre principale : sip:robot@127.0.0.1:5064. 127.0.0.1 est l'adresse locale de votre ordinateur, et robot est le nom à utiliser pour appeler sipomatic. 5064 est le port par lequel sipomatic peut-être contacté. Normalement, vous devez toujours utiliser 5060 pour appeler quelqu'un, mais sipomatic est une exception : il fonctionne sur le port 5064. La raison est que Linphone fonctionne déjà sur le port 5060, et il est impossible d'avoir deux applications utilisant le même port au même instant, sur la même machine. + + + + + Appuyez sur le bouton "Appeler". Après quelques secondes, sipomatic devrait répondre à votre appel et vous devez entendre une courte annonce. + + + + + + + + Paramètres des appels + + + + Réseau + + + + + Liste des interfaces réseau: vous devez choisir une interface réseau à utiliser avec Linphone. Si vous voulez contacter quelqu'un sur l'Internet, vous devez choisir l'interface réseau connectée à l'Internet. Par exemple, si vous utilisez un modem, celle-ci devrait être ppp0. Si vous n'êtes connecté à aucun réseau, seulement l'interface réseau locale appelé lo apparaitra dans la liste. La seule chose que vous pouvez faire dans ce cas la est d'appeler sipomatic. + + + + + Type de connection: choisissez le type de connection que vous utilisez pour vous connecter au réseau que vous désirez utiliser. Ceci aidera Linphone à s'auto-configurer en fonction de la bande passante de votre type de connection. + + + + + + + RTP + + + RTP signifie Real Time Protocol, il permet d'envoyer des flux de données multimedia. + + + + + port RTP: Linphone utilise le port 7072 par défaut pour envoyer et recevoir des signaux audios. Si vous pensez que le port 7072 est utilisé par une autre application, changez le comme vous voulez. + + + + + Jitter compensation: ce nombre représente le nombre de paquets audios que Linphone attend avant de vous les faire entendre. Augmentez ce nombre si vous entendez une voix hachée de manière à améliorer la qualité de la transmission, mais attention, ceci augmente le delai (vous entendrez la voix de l'utilisateur distant quelques millisecondes plus tard).D'un autre côté, si vous utilisez un réseau parfait, et que vous disposez de bon drivers audios, vous pouvez descendre ces paramètres très bas jusqu'à 3 paquets, ainsi vous aurez un délai très faible. + + + + + + + SIP + + + SIP (Session Initiation Protocol) est un protocole qui permet d'établir des sessions de téléphonie par l'intermédiaire d'un réseau IP. En simplifiant, c'est la chose qui permet de faire sonner chez l'autre utilisateur, démarrer ou terminer l'appel quand l'un des deux correspondants raccroche. + + + + + port SIP: Linphone utilise par défaut le port 5060 pour envoyer / recevoir des paquets SIP. Il est hautement recommandé par la RFC du protocole SIP d'utiliser celui-ci. Donc, ne le changez pas à moins que vous n'ayez vraiment pas le choix. + + + + + Votre adresse SIP: modifiez ici votre nom d'utilisateur et votre nom de machine à votre gré. Bien entendu donner un nom de machine ici ne signifie pas que ce nom soit connue des autres machines du réseau. Néammoins linphone utilisera peu ce nom de machine et préfèrera utiliser votre adresse IP pour communiquer avec d'autres machines. + + + + + Utiliser un serveur sip registrar: Cochez ce choix, si vous voulez vous enregistrer sur un serveur SIP (registrar) pour obtenir différents services. Quand vous n'avez pas d'adresse IP fixe, cela peut-être très intéressant pour permettre à vos amis de vous appeler. Regardez la section intitulée "enregistrement sur un serveur sip". + + + + + + + Codecs + + + Les codecs sont des algorithmes utilisés pour compresser la voix. Par exemple, une voix digitalisée en 16bit/8000Hz représente un flux de données de 128kbits/seconde. En utilisant le vocodeur GSM, ce flux est réduit à 13kbits/seconde, sans perte significative de qualité. + + + + + Choix de codecs: Linphone peut utiliser plusieurs codecs. Utilisez les boutons situés en dessous de la liste des codecs de manière à les placer dans un order de préférence. Notez bien, qu'en fonction de votre type de connection réseau, certains codecs sont inutilisables.Ils apparaitront en rouge et ne seront pas sélectionnable. Vous pouvez décider d'utiliser ou non un codec "utilisable" (en bleu) en changeant son état à l'aide du bouton activer/désactiver en dessous de la liste. + + + + + + + Audio parameters + + + + + Mode de pilotage: si vous avez installé des drivers ALSA avec une librairie ALSA <0.9, choisissez ALSA pour avoir de meilleires performances. Sinon, ou si vous n'en savez rien, choisissez OSS, cela marche suffisemment bien. + + + + + Choix de la source d'enregistrement: vous pouvez choisir votre source d'enregistrement pour la voix. Dans la plupart des cas, celle-ci sera le microphone. + + + + + Auto-kill option: en choissant cette option, Linphone essaiera de stopper les processus sonores (esd & artsd) qui peuvent bloquer votre périphérique sonore et ainsi provoquer des problèmes d'ouverture des périphériques par Linphone quand il en a besoin. Il est recommandé d'activer cette option. + + + + + + + + Carnet d'adresses + + + Depuis la version 0.4.1 linphone dispose d'un carnet d'adresses (menu connexion, carnet d'addresses), avec lequel vous pouvez memoriser des adresses, et les rappeler facilement lorsque vous souhaitez appeler. + + + + + Enregistrement sur un serveur sip + + + Vous pouvez souscrire des services sur des serveurs sip distants appelés registrar, proxy ou redirect server. Ces services peuvent être: + + + You can suscribe for services on remote SIP servers. These services can be: + + + + + redirection: linphone va demander au serveur la création d' un compte <sip:votre_nom@le_serveur_sip>. Cette adresse pourra alors être utilisée par vos correspondants pour vous joindre. Un petit example concret pour bien comprendre: vous n'êtes qu'un pauvre internaute connecté temporairement grace à un modem 56k. Votre machine n'a pas de nom de domaine connu et votre adresse IP change à chaque nouvelle connexion. Il est impossible pour vos amis de vous joindre car il ne peuvent deviner votre adresse IP, à moins que vous ne leur donniez en envoyant un courriel, par exemple. Pour palier à ce problème, vous pouvez demander à avoir un compte sur un serveur sip connu de vos amis, qui lui est fixe et tout le temps connecté. Pour cela, spécifiez l'adresse du serveur dans la boite de propriété, section sip. Cette adresse est par exemple <sip:serveur_exemple.com> et votre nom d'utilisateur est “Bob”. Linphone va alors envoyer au serveur un message pour l'informer de la correspondance entre l'adresse <sip:bob@serveur_exemple.com> et votre adresse IP actuelle. Desormais vos amis peuvent vous appeler en utilisant cette nouvelle adresse, leurs appels seront alors automatiquement redirigés vers votre machine. Il n'ont plus besoin de connaitre votre adresse IP qui change tout le temps pour vous joindre. Bien sur, <sip:serveur_exemple.com> est supposée être bien connue de tout vos amis. + + + + + proxy: c'est exactement le meme principe, excepté que la redirection se fait de manière transparente et invisible le linphone de l'appelant. + + + + + Le registrar que vous avez spécifié peut aussi être utilisé comme proxy sortant. Dans ce cas tous les appels émanant de votre linphone seront dirigé vers ce serveur, et il sera supposé les faire suivre vers les bonnes personnes. Ceci est très utile et même indispensable lorsque vous utilisez linphone dans un réseau privé abrité par un firewall, si bien sur un proxy sip est actif sur le firewall. + + + Pour utiliser solliciter un serveur sip, vous devez aller à la boîte de propriété, rubrique SIP, et cocher le bouton qui se trouve en face de "use registrar". Tapez l'adresse du registrar, et choisissez un nom d'utilisateur qui n'est pas trop fréquent de manière à éviter les conflits de noms. Donnez une indication du service que le serveur doit effectuer pour vous en cochant les boutons “redirection” ou “proxy”. Sélectionnez aussi l'option “le serveur est un proxy sortant” si vous êtes derrière un pare-feu. + + + Enfin en fermant la boite de propriétés linphone communiquera immédiatement avec le serveur SIP pour y obtenir les services demandés. De même lorsque vous fermez linphone, celui ci prendra quelques secondes pour se désenregistrer auprès du serveur. + + + Une liste de serveurs sip peut être trouvée à cette addresse: http://www.cs.columbia.edu/~hgs/sip/servers.html. Malheureusement, beaucoup de ces serveurs ne fonctionnent plus, peut-être à cause de la crise et de ses faillites. Certains ne sont pas utilisables car ils requierent des méthodes d'autentification qui ne sont pas encore implémentées dans linphone. Afin donc de ne pas vous faire perdre votre temps, une liste des serveurs sip publiques fonctionnant avec linphone est disponible sur http://simon.morlat.free.fr/english/servers.html. + + + + + Utilisation derrière les pares-feux + + + Linphone est capable de fonctionner derrière les firewalls grâce à un serveur proxy SIP fonctionnant sur la machine firewall. Un tel serveur est en cours de développement sur http://osipproxy.sourceforge.net. Bien sûr il sera libre et basé sur la librairie LGPL oSIP. + + + Une fois le proxy serveur mis en place, il vous faut configurer linphone pour qu'il l'utilise. Pour cela rendez vous dans la boite de propriétés, section SIP et cochez la case “Utiliser un registrar SIP”, indiquez son adresse, et cocher l'option “le serveur est un proxy sortant”. + + + Il y a un cas pour lequel le proxy n'est pas indispensable: c'est le cas où les machines du réseau privé possèdent une adresse publique, le firewall étant là pour filtrer les paquets entrants ou sortants. Vous devez pour permettre a linphone de fonctionner avec des machines exterieures, autoriser le traffic UDP sur le port SIP (par defaut 5060, il est deconseillé de le changer), et sur le port RTP de chaque linphone du sous réseau. Le port RTP est paramètrable comme bon vous semble dans la boite de proprietés. + + + + + Problèmes divers + + + + Problèmes de connexion + +
+ + J'essaye d'appeler mon pote <sip:toto@example.com>, mais rien ne se passe, pas de sonnerie. + +
+ + Vous devez vérifier que linphone utilise l'interface réseau qui vous connecte sur le réseau ou se trouve votre ami. La liste des interface disponibles est donnée dans la boite de propriété, section réseau. Sélectionnez la bonne. + + + Si le problème persiste, il y a fort à parier que votre ami ne soit pas joignable actuellement. + +
+ + + Problèmes audio + +
+ + Linphone semble correctement établir l'appel, il sonne, mais une fois que le correspondant a décrocher, plus rien ne se passe et on ne s'entend pas. + +
+ + + + La plupart des gens ont ce genre de symptome car ils n'ont pas choisi la bonne interface réseau. Si vous êtes connectés par modem, ce doit être ppp0. En aucun cas l'interface “lo” ne peut permettre d'avoir une communication via le réseau. Elle ne sert que pour le test local avec sipomatic (voir plus haut). + + + + + Augemtez le niveau sonore d'acquisition et de restitution, à l'aide des potentiomètres situés en bas de la fenêtre principale. + + + + + Si la voix de votre correspondant vous semble coupée ou hachée, vous pouvez essayer d'augmenter le paramètre jitter compensation de l'onglet RTP de la boite de propriété. Mais attention, cela augmente la latence en contrepartie. + + + + + Si linphone ne peut se servir de la carte son, vérifiez que celle ci n'est pas utilisée au meme moment par d'autres programmes audio. + + + + + Enfin utilisez les drivers sons alsa (voir http://www.alsa-project.org) , plutôt que les oss fournit avec le kernel linux. Malheureusement la plupart des distributions utilsent encore ces vieux pilotes alors qu'ils presentent de nombreux bugs et problèmes de latence. Les drviers ALSA sont beaucoup plus performants. Notez que si vous changer vos drivers, vous n'avez nul besoin de recompiler linphone ou de changer quoi que ce soit a sa configuration. + + + +
+
+ + + Rapports de bogues et suggestions + + + En premier lieu, allez sur le site de Linphone http://www.linphone.org afin de vérifier que vous ayez bien la dernière version de Linphone. + + + Si linphone plante, envoyez moi durectement un message à bugs@linphone.org. Si Linphone ne fonctionne pas, mais ne se plante pas, vérifiez bien que vous avez bien lu ce manuel entièrement avant de m'envoyer un compte rendu à l'adresse précédente. Dans tous les cas veillez à m'envoyer le plus d'information possible relatifs à votre problème, notamment la sortie de debug que linphone ecrit lorsque vous l'executez depuis un terminal. Si vous désirez autre chose, n'hésitez pas à m'envoyer un email à l'adresse help@linphone.org. Prenez note que l'ajout de la vidéo et du mode conférence sont planifiés. + + + Si quelqu'un est interessé pour faire des traductions de Linphone, envoyez moi un fichier xx.po basé sur celui se trouvant dans po/linphone.pot de la distribution. Vous pouvez aussi traduire ce manuel utiisateur dans d'autres langues. Dans tous les cas, contactez moi si vous voulez plus de détails. + + + + + Auteurs + + + Simon MORLAT (simon.morlat@linphone.org) a ecrit: + + + + + Programme principal (src) + + + + + librairie RTP (lprtplib) + + + + + osipua : la librarie sip User Agent au dessus d'osip. + + + + + interface pour les drivers audio (audio) + + + + + les wrappers pour les codecs lpc10-1.5, gsm et g711. + + + + + Aymeric Moizard (jack@atosc.org) a ecrit la pile SIP oSIP utilisé par linphone. + + + La librairie GSM a été écrite par: Jutta Degener and Carsten Bormann,Technische Universitaet Berlin. + + + La librairie LPC10-1.5 par: Andy Fingerhut Applied Research Laboratory <-- this line is optional if Washington University, Campus Box 1045/Bryan 509 you have limited space One Brookings Drive Saint Louis, MO 63130-4899 jaf@arl.wustl.edu http://www.arl.wustl.edu/˜jaf/ Lisez les fichiers textes README dans les repertoire gsmlib et lpc10-1.5 pour plus d'informations. + + + Les icones sont de Pablo Marcelo Moia et le logo de Philippe Beau. + + + + + Remerciements + + + Merci à Daemon Chaplin pour avoir fait Glade, le constructeur d'interface graphique GTK+. + + + Merci aux auteurs du code des LPC10-1.5 et GSM. + + + Merci à Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com ) pour ses RPMS. + + + Merci à Pablo Marcelo Moia pour les icones. + + + Merci à Philippe Beau pour la traduction de ce manuel en Francais, pour le logo, et pour le nouveau site web qu'il a fait pour linphone. + + + + + + + +
diff --git a/linphone/share/fr/manual/.cvsignore b/linphone/share/fr/manual/.cvsignore new file mode 100644 index 000000000..2d19fc766 --- /dev/null +++ b/linphone/share/fr/manual/.cvsignore @@ -0,0 +1 @@ +*.html diff --git a/linphone/share/hello16000.wav b/linphone/share/hello16000.wav new file mode 100644 index 000000000..92d44b175 Binary files /dev/null and b/linphone/share/hello16000.wav differ diff --git a/linphone/share/hello8000.wav b/linphone/share/hello8000.wav new file mode 100644 index 000000000..b787b202e Binary files /dev/null and b/linphone/share/hello8000.wav differ diff --git a/linphone/share/it/.cvsignore b/linphone/share/it/.cvsignore new file mode 100644 index 000000000..e1d20773b --- /dev/null +++ b/linphone/share/it/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +manual +manual.junk +manual.html diff --git a/linphone/share/it/Makefile.am b/linphone/share/it/Makefile.am new file mode 100644 index 000000000..e194637f5 --- /dev/null +++ b/linphone/share/it/Makefile.am @@ -0,0 +1,3 @@ +HELPLANG=it + +include ../Makefile.inc diff --git a/linphone/share/it/manual.lyx b/linphone/share/it/manual.lyx new file mode 100644 index 000000000..d0a0b06be --- /dev/null +++ b/linphone/share/it/manual.lyx @@ -0,0 +1,741 @@ +#LyX 1.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 218 +\textclass docbook +\language french +\inputencoding latin1 +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize Default +\paperpackage a4 +\use_geometry 0 +\use_amsmath 0 +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language french +\quotes_times 2 +\papercolumns 1 +\papersides 1 +\paperpagestyle default + +\layout Title + + +\begin_inset LatexCommand \label{manual} + +\end_inset + +MANUALE UTENTE LINPHONE +\layout Author + +Simon Morlat (simon.morlat@linphone.org) +\layout Date + +11-13-2001 +\layout Section + +Introduzione +\layout Standard + +Linphone è un semplice strumento di telefonia su rete. + Permette di effettuare conversazioni tra due utenti utilizzando una modalità + IP come Internet. + Ecco l'equipaggiamento necessario per usare Linphone : +\layout Itemize + +Linux ( Può funzionare anche in altri ambienti come BSD, o altri\SpecialChar ~ + UNIX, ma + non l'ho ancora testato personalmente.) +\layout Itemize + +Gnome 1.2 o superiore, installato ma non necessariamente usato. +\layout Itemize + +Una scheda sonora correttamente configurata. +\layout Itemize + +Cuffie o altoparlanti. +\layout Itemize + +Un microfono. +\layout Itemize + +Una connessione rete (Internet ad esempio), modem, scheda Ethernet ... +\layout Standard + +\SpecialChar ~ +E' consigliabile chiudere tutte le applicazioni che fanno uso della scheda + sonora prima di usare Linphone. + Linphone è un programma libero, distribuito sotto la licenza pubblica GNU. +\layout Standard + + +\emph on +ATTENZIONE : Questo strumento è distribuito SENZA GARANZIA. + Leggere il file COPYING per maggiori dettagli. + Questo significa tra l'altro che non dovete usare Linphone per chiamate + confidenziali: non ha ALCUNA CODIFICA DI PROTEZIONE, e quindi può essere + molto facile per qualche malintenzionato captare i flussi audio. + Si noti inoltre che si raccomanda di non usare Linphone come utente root. +\layout Section + +Uso +\layout Standard + +Linphone può essere usato in 3 modi diversi : +\layout Itemize + +Come applicazione (normale) : nel menu Gnome, Linphone dovrebbe apparire + nella sezione Rete. + Se non utilizzi Gnome, puoi lanciare Linphone da una finestra terminale, + per esempio. + Quando Linphone non è in esecuzione, non è possibile ricevere chiamate. +\layout Itemize + +Come applet Gnome : cliccando sul pannello Gnome col pulsante destro, aggiungere + l'applet. + Linphone apparirà nella sezione Rete. + Apparendo nel pannello Gnome, Linphone è capace di ricevere chiamate anche + se la sua finestra non è visibile. + Se si vuol vedere la finestra principale, cliccare sull'applet. + Quando c'è una chiamata, la finestra principale passa in primo piano, e + sentirai gli squilli della chiamata. +\layout Itemize + +Come demone : questo è interessante per coloro che non utilizzano Gnome. + Per esempio, per KDE, c'é una directory /home/user/.kde2/AutoStart/ dove + si possono inserire le applicazioni che si vogliono lanciare ad inizio + sessione. + Nella directory citata, con l'aiuto di un gestore di file, aggiungere un + collegamento cliccando col pulsante destro. + Il comando da inserire è "linphone -daemon". + L'interfaccia prinicipale di Linphone non sarà visibile, e dunque, per + farla apparire, si lanci Linphone normalmente, per esempio da una finestra + terminale. +\layout Section + +Come lanciarlo +\layout Subsection + +Principi di base +\layout Standard + +Linphone utilizza il protocollo SIP (Session Initiation Protocol) per effettuare + chiamate con altri interlocutori. + Il protocollo specifica che ciascuna persona dev'essere identificata da + un URL sip della forma: sip:nome_utente@nome_host. + Questo modo di chiamare le persone è molto simile a quello utilizzato per + la posta elettronica. +\layout Standard + +Nome_utente è il nome di un utente su una macchina, come il login su una + macchina linux, per esempio. + Nome_host è il nome di una macchina sotto forma di indirizzo IP, o più + semplicemente sotto forma di dominio (es: linphone.org). +\layout Standard + +Si noti che SIP è un nuovo protocollo di telecomunicazione fatto per essere + semplice ed efficace su internet, che è totalmente diverso ed incompatibile + con H.323. + H.323 è il protocollo attualmente usato da NetMeeting e GnomeMeeting. +\layout Subsection + +Applicazione: due persone (Bob e Tom) si connettono ad internet con un modem + analogico classico. +\layout Standard + +Ecco il modo più semplice di procedere : +\layout Standard + +Prerequisito : +\layout Itemize + +Un modem da 28.8 Baud o più. + +\layout Standard + +Procedimento: +\layout Itemize + +Si è convenuto che Bob debba chiamare Tom alle 21.00. + Alle 21.00, Tom si connette ad Internet utilizzando kppp, gppp o wvdial + (o un altro). + Una volta connesso ad internet, può lanciare Linphone. + Aprendo la finestra delle statistiche di kppp o gppp, può vedere il suo + indirizzo IP (altrimenti può digitare /sbin/ifconfig per vederlo). + Il nome dell'interfaccia modem dev'essere ppp0. +\layout Itemize + +Di seguito, manda un messaggio a Bob dicendo : "Il mio indirizzo IP è xxx.xxx.xxx.x +xx". +\layout Itemize + +Bob legge l'email e riporta nella finestra di Linphone il nome e l'indirizzo + IP della personne da contattare : Tom@xxx.xxx.xxx.xxx(L'indirizzo IP di Tom) + e per finire, clicca sul pulsante Chiamare. +\layout Itemize + +Linphone suona a casa di Tom ...Tom risponde alla chiamata cliccando sul pulsante + "Rispondere" ed a questo punto la conversazione può iniziare. + +\layout Standard + +Se si incontrassero problemi in uno di questi punti, si vada alla sezione + 4 - Problemi. +\layout Subsection + +Test in locale: non hai nessuno da chiamare per il momento, ma vuoi controllare + se Linphone funzioni davvero. +\layout Standard + + +\begin_inset LatexCommand \label{sipomatic} + +\end_inset + +A partire dalla versione 0.3.0, Linphone è dotato di un programma di test + chiamato "sipomatic". + Sipomatic può rispondere automaticamente alle chiamate provenienti da Linphone. + A voi la scelta : +\layout Itemize + +Lanciare linphone. +\layout Itemize + +Lanciare sipomatic in una finestra terminale. + Non siate sorpresi, sipomatic non possiede alcuna interfaccia grafica, + ma non c'è bisogno di modificare quello che sta sotto. + +\layout Itemize + +In Linphone, menu Parametri, sezione Rete, scegliere "lo" come interfaccia + di default. + Applicare il cambiamento cliccando su OK. + Digitare l'indirizzo S.I.P seguente nella finestra principale : sip:robot@127.0.0.1: +5064. + 127.0.0.1 è l'indirizzo locale del tuo computer, e robot è il nome da usare + per chiamare sipomatic. + 5064 è la porta con cui sipomatic può essere contattato. + Normalmente si deve utilizzare 5060 per chiamare qualcuno, ma sipomatic + fa eccezione : funziona con la porta 5064. + Il motivo è che Linphone funziona già sulla porta 5060, ed è impossibile + avere due applicazioni che utilizzino la stessa porta nello stesso momento, + sulla stessa macchina. + +\layout Itemize + +Cliccare sul pulsante "Chiamare". + Dopo qualche secondo, sipomatic dovrebbe rispondere alla chiamata e vi + dovrebbe dire un breve messaggio. +\layout Section + + +\begin_inset LatexCommand \label{params} + +\end_inset + +Parametri di chiamata +\layout Subsection + + +\begin_inset LatexCommand \label{paramnetwork} + +\end_inset + +Rete +\layout Itemize + +Lista delle interfacce di rete: bisogna scegliere un'interfaccia di rete + da usare con Linphone. + Se si vuole contattare qualcuno su Internet, bisogna scegliere l'interfaccia + di rete connessa ad Internet. + Per esempio, se si utilizza un modem, dovrà essere ppp0. + Se non si è connessi ad alcuna rete, solo l'interfaccia di rete locale, + chiamata lo, apparirà nella lista. + L'unica scelta che si può fare in questo caso è chiamare +\begin_inset LatexCommand \ref[sipomatic]{sipomatic} + +\end_inset + +. +\layout Itemize + +Tipo di connessione: scegliere il tipo di connessione utilizzata per connettervi + alla rete che si desidera utilizzare. + Questo aiuterà Linphone ad autoconfigurarsi in funzione della banda passante + del tipo di connessione. +\layout Subsection + + +\begin_inset LatexCommand \label{paramrtp} + +\end_inset + +RTP +\layout Standard + +RTP +\layout Itemize + +porta RTP: \SpecialChar ~ +Linphone utilizza la porta 7072 di default per inviare e ricevere + segnali audio. + Se la porta 7072 è usata da un'altra applicazione, la si cambi a piacere. +\layout Itemize + +Compensazione Jitter: questo numero rappresenta il numero di pacchetti audio + che Linphone aspetta prima di farli sentire. + Si aumenti questo numero se si sente male la voce, in modo da migliorare + la qualità di trasmissione, ma attenzione: questo aumenta il ritardo (Si + sentirà la voce dell'interlocutore qualche millisecondo più tardi). + D'altro canto, se si utilizza un server perfetto, e si dispone di buoni + driver audio, si può scegliere un valore basso fino a 3 pacchetti, sentendo + così un ritardo trascurabile. +\layout Subsection + + +\begin_inset LatexCommand \label{paramsip} + +\end_inset + +SIP +\layout Standard + +SIP (Session Initiation Protocol) è un protocollo che permette di stabilire + sessioni telefoniche grazie ad un server IP. + Semplificando, è ciò che permette di far suonare il telefono all'altro + interlocutore, sospendere o terminare una chiamata quando uno dei due riattacca. +\layout Itemize + +porta SIP: Linphone utilizza di default la porta 5060 per inviare / ricevere + pacchetti SIP. + Si raccomanda caldamente per la RFC del protocollo SIP di utilizzare questo + valore. + Non lo si cambi a meno che non si sappia davvero cosa si stia facendo. +\layout Itemize + +Indirizzo SIP: modifica nome utente e macchina a piacere. + Beninteso, dare un nome di macchina quinon significa che questo nome sia + conosciuto da altre macchine del server. + Nemmeno Linphone userà il nome della macchina e preferirà usare l'indirizzo + IP per comunicare con altre macchine. +\layout Itemize + +Usare un server segretario sip: si faccia questa scelta, se ci si vuole + registrare su un server SIP (segretario) per ottenere servizi vari. + Quando non si ha un indirizzo IP fisso, questo può essere interessante + per permettere agli amici di chiamare. + Vedere la sezione " +\begin_inset LatexCommand \ref[enregistrement sur un serveur sip]{registering} + +\end_inset + +". +\layout Subsection + + +\begin_inset LatexCommand \label{paramcodec} + +\end_inset + +Codec +\layout Standard + +I codecs sono algoritmi per comprimere la voce. + Per esempio, una voce digitalizzata a 16bit/8000Hz rappresenta un flusso + di dati di 128kbits/secondo. + Usando il codificatore vocale GSM, questo flusso è ridotto a 13kbits/secondo, + senza perdita significativa di qualità. +\layout Itemize + +Scelta dei codecs: Linphone può usare diversi codec. + Usare i pulsanti posti a lato della lista dei codec in modo da porli nell'ordin +e preferito. + Si badi bene, che in funzione del tipo di connessione alla rete, alcuni + codec sono inutilizzabili. + Questi appariranno in rosso e non saranno selezionabili. + Si può decidere di usare o no un codec "utilizzabile" (in blu) cambiando + il suo stato con l'aiuto del pulsante Attiva / Disattiva in fianco alla + lista. +\layout Subsection + + +\begin_inset LatexCommand \label{paramaudio} + +\end_inset + +Parametri audio +\layout Itemize + +Modo d'uso: se si ha installato il driver ALSA con una libreria ALSA <0.9, + si scelga ALSA per avere risultati migliori. + Altrimenti, o se non si sa, usare OSS, che funziona sufficientemente bene. +\layout Itemize + +\SpecialChar ~ +Scelta della fonte di registrazione: si può scegliere la fonte di registrazione + per la voce. + Nella maggior parte dei casi, sarà il microfono. +\layout Itemize + +Opzione auto-kill: scegliendo questa opzione, Linphone fermerà i server + sonori (esd & artsd) che possono bloccare la periferica sonora e provocare + così problemi problemi d'apertura delle periferiche da parte di Linphone + in caso di bisogno. + Si raccomanda di attivare questa opzione. +\layout Section + +Rubrica +\layout Standard + +A partire dalla versione 0.4.1 Linphone dispone di una rubrica (menu connessione, + rubrica), con la quale memorizzare indirizzi, e richiamarli facilmente + quando si vuol chiamare. +\layout Section + + +\begin_inset LatexCommand \label{registering} + +\end_inset + +Registrazione su un server sip +\layout Standard + +E' possibile sottoscrivere alcuni servizi sui server sip remoti chiamati + segretari, proxy o server ridiretti. + Questi servizi possono essere: +\layout Itemize + +ridirezione: Linphone chiede al server la creazione di un account . + Questo indirizzo potrà allora essere utilizzato dai tuoi interlocutori + per connetterti. + Un piccolo esempio concreto può essere utile: tu non sei altro che un internaut +a poverino, connesso temporaneamente grazie ad un modem 56k. + La tua macchina non ha un nome di dominio conosciuto ed il tuo indirizzo + IP cambia ad ogni connessione. + E' impossibile per gli amici chiamare in mancanza dell'indirizzo IP, a + meno che non lo si comunichi via posta elettronica, per esempio. + Per risolvere questo problema, si può chiedere di avere un indirizzo su + un server sip conosciuto dagli amici, fisso e sempre connesso. + Per far ciò, specificare l'indirizzo del server nel menu parametri, sezione + sip. + Questo indirizzo è, per esempio, ed il nome utente + è +\begin_inset Quotes fld +\end_inset + +Bob +\begin_inset Quotes frd +\end_inset + +. + Linphone invia allora al server un messaggio per informare della corrispondenza + tra l'indirizzo e l'indirizzo IP attuale. + D'ora in poi gli amici potranno chiamare usando questo nuovo indirizzo: + le chiamate saranno ridirette automaticamente verso la tua macchina. + Non ci sarà più bisogno di conoscere l'indirizzo IP, che cambia ogni volta, + per contattarti. + Ovviamente, si suppone che sia conosciuto da tutti + gli amici. +\layout Itemize + +Proxy: è esattamente lo stesso principio, tranne che la ridirezione viene + fatta in maniera trasparente ed invisibile dal Linphone del chiamante. +\layout Standard + +Il segretario specificato può essere utilizzato come proxy in uscita. + In questo caso tutte le chiamate in uscita dal tuo Linphone saranno dirette + verso tale server, che si suppone sia gestito da brave persone. + E' quindi molto utile, per non dire indispensabile, che si usi Linphone + su una rete privata, gestita da un firewall, anche se su un proxy sip è + sicuramente attivo un firewall. + +\layout Standard + +Per usare fin da subito un server sip, bisogna aprire il menu Parametri, + SIP, e cliccare sul pulsante in fianco a "Usa il segretario sip". + Digitare l'indirizzo del segretario, e scegliere un nome utente non troppo + comune, in modo da evitare conflitti di nomi. + Dare un'indicazione del servizio che il server deve effettuare per te e + cliccare sui pulsanti +\begin_inset Quotes fld +\end_inset + +ridirezione +\begin_inset Quotes frd +\end_inset + + o +\begin_inset Quotes fld +\end_inset + +proxy +\begin_inset Quotes frd +\end_inset + +. + Selezionare anche l'opzione +\begin_inset Quotes fld +\end_inset + +il server è un proxy in uscita +\begin_inset Quotes frd +\end_inset + + \SpecialChar ~ +se sei dietro ad un firewall. +\layout Standard + +Infine, confermando la scelta, Linphone comunicherà immediatamente con il\SpecialChar ~ + + server SIP per ottenere i servizi richiesti. + Allo stesso modo, in fase di uscita da Linphone, ci vorrà qualche secondo + per togliere la registrazione dal server. +\layout Standard + +Una lista di server sip può essere trovata a questo indirizzo: +\begin_inset LatexCommand \url[http://www.cs.columbia.edu/~hgs/sip/servers.html]{http://www.cs.columbia.edu/~hgs/sip/servers.html} + +\end_inset + +. +\layout Standard + +Sfortunatamente, poiché alcuni di questi server non funzionano più, forse + a causa della crisi e di fallimenti di società. + Alcuni non sono utilizzabili poiché richiedono metodi di autentificazione + non ancora implementati in Linphone. + Per non perdere tempo, una lista di server sip pubblici funzionanti con + Linphone è reperibile su +\begin_inset LatexCommand \url[http://simon.morlat.free.fr/english/servers.html]{http://simon.morlat.free.fr/english/servers.html} + +\end_inset + +. +\layout Section + +Uso dietro i firewall +\layout Standard + +Linphone è in grado di funzionare dietro i firewall grazie ad un server + proxy SIP in funzione sulla macchina firewall. + Un tale server è in corso di sviluppo su +\begin_inset LatexCommand \url[http://osipproxy.sourceforge.net]{http://osipproxy.sourceforge.net} + +\end_inset + +. + Ovviamente sarà libero e basato sulla libreria LGPL oSIP. +\layout Standard + +Una volta che il server proxy sarà attivo, si potrà configurare Linphone + per utilizzarlo. + Per far ciò, andare in Parametri, sezione SIP e attivare la casella +\begin_inset Quotes fld +\end_inset + +Usa il segretario SIP +\begin_inset Quotes frd +\end_inset + +, indicare il suo indirizzo, ed attivare l'opzione +\begin_inset Quotes fld +\end_inset + +il server è un proxy in uscita +\begin_inset Quotes frd +\end_inset + +. +\layout Standard + +C'è un caso in cui il\SpecialChar ~ + proxy non è indispensabile: quello in cui le macchine + di reti private possiedano un indirizzo pubblico: il firewall filtra i + pacchetti in entrata o uscita. + Bisogna permettere a Linphone di funzionare con le macchine esterne, autorizzar +e il traffico UDP sulla porta SIP (di default 5060, è possibile cambiarla), + e sulla porta RTP di ciascun Linphone nelle sottoreti. + La porta RTP è parametrizzabile, come si è visto, nel menu Parametri. +\layout Section + +Problemi vari +\layout Subsection + +Problemi di connessione +\layout Quotation + +Tento di chiamare il mio amico , ma niente da fare, + nessuno squillo. +\layout Standard + +Bisogna verificare che Linphone usi l'interfaccia di rete a cui sei connesso + con la rete su cui si trova il tuo amico. + La lista delle interfacce disponibili si trova in Parametri, sezione Rete. + Selezionarla. + +\layout Standard + +Se il problema persistesse, potrebbe essere che il tuo amico non sia al + momento raggiungibile. +\layout Subsection + +Problemi audio +\layout Quotation + +Linphone sembra connettersi correttamente, si sentono gli squilli, ma appena + l'interlocutore risponde, non si sente o si capisce più nulla. +\layout Itemize + +La maggior parte degli utenti ha di questi problemi poiché non è stata scelta + l'interfaccia di rete corretta. + Se si usa il modem, dev'essere ppp0. + In ogni caso, l'interfaccia +\begin_inset Quotes fld +\end_inset + +lo +\begin_inset Quotes frd +\end_inset + + non permette di avere una comunicazione via rete. + Serve solo per il test locale con sipomatic (vedere più avanti). +\layout Itemize + +Aumentare il livello sonoro di acquisizione ed emissione, usando i potenziometri + posti nella finestra principale. +\layout Itemize + +Se la voce dell'interlocutore sembra vibrare o echeggiare, si può tentaredi + aumentare il parametro comensazione jitter (Parametri, RTP). + Ma attenzione, questo aumenta il ritardo nella controparte. +\layout Itemize + +Se Linphone nonriesce ad usare la scheda sonora, verificare che non sia + utilizzata da qualche altro programma audio. + +\layout Itemize + +Infine, utilizzare il driver sonoro ALSA (vedere +\begin_inset LatexCommand \url[http://www.alsa-project.org]{http://www.alsa-project.org} + +\end_inset + +) , piuttosto che OSS, fornito con il kernel linux. + Sfortunatamente la maggior parte delle distribuzioni usano ancora vecchi + driver che hanno vari errori e problemi di ritardo. + I driver ALSA danno risultati migliori. + Si noti che se si cambiano driver, non c'è bisogno di ricompilare Linphone + o di cambiare una qualsiasi configurazione. + +\layout Section + +Errori e suggerimenti +\layout Standard + +In primo luogo, andare sul sito di Linphone +\begin_inset LatexCommand \url[http://www.linphone.org]{http://www.linphone.org} + +\end_inset + + e verificare di avere la versione più recente di Linphone. + +\layout Standard + +Se Linphone si bloccassse, inviami direttamente un messaggio a bugs@linphone.org. + Qualora Linphone non funzionasse, ma non si bloccasse, verificare bene + di aver letto tutto il manuale prima di mandare un resoconto all'indirizzo + indicato. + In ogni caso invia più informazioni possibili relativamente al problema, + in particolar modo i messaggi che compaiono quando lo si lancia da un terminale. + Se desideri qualche altra cosa, non esitare ad inviarmi un messaggio a + help@linphone.org.Tieni presente che l'aggiunta della modalità video e conferenza + sono in programma. + +\layout Standard + +Se qualcuno fosse interessato a fare traduzioni di Linphone, mi invii un + file xx.po basato su quello in po/linphone.pot della distribuzione. + Si può anche tradurre il manuale utente in altre lingue. + In ogni caso, contattami qualora volessi maggiori dettagli. +\layout Section + +Autori +\layout Standard + +Simon MORLAT (simon.morlat@linphone.org) ha scritto: +\layout Itemize + +Programma principale (src) +\layout Itemize + +Libreria RTP (lprtplib) +\layout Itemize + +osipua : la libreria Agente utente sip . +\layout Itemize + +Interfaccia per i driver audio (audio) +\layout Itemize + +Wrappers per i codecs lpc10-1.5, gsm e g711. + +\layout Standard + +Aymeric Moizard (jack@atosc.org) ha scritto la pila SIP oSIP usata da linphone. + +\layout Standard + +La libreria GSM è stata scritta da: Jutta Degener and Carsten Bormann,Technische + Universitaet Berlin. +\layout Standard + +La librairie LPC10-1.5 par: Andy Fingerhut Applied Research Laboratory Washington + University, Campus Box 1045/Bryan 509 One Brookings Drive Saint Louis, + MO 63130-4899 jaf@arl.wustl.edu http://www.arl.wustl.edu/~jaf/ +\layout Standard + +Leggere i file di testo README nella directory gsmlib e lpc10-1.5 per maggiori + informazioni. +\layout Standard + +Le icone sono di Pablo Marcelo Moia ed il logo di Philippe Beau. +\layout Section + +Ringraziamenti +\layout Standard + +Grazie a Daemon Chaplin per aver scritto Glade, il costruttore d'interfaccia + grafica GTK+. +\layout Standard + +Grazie agli autori del codice di LPC10-1.5 e GSM. +\layout Standard + +Grazie a Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com ) per i suoi + RPMS. +\layout Standard + +Grazie a Pablo Marcelo Moiaper le icone. +\layout Standard + +Grazie a Philippe Beau per la traduzione di questo manuale in francese, + per il logo, e per il nuovo sito web che ha creato per Linphone. +\layout Standard + +Grazie a Alberto Zanoni per + la traduzione di linphone e questo manuale in Italiano. +\layout Standard + + +\begin_inset LatexCommand \tableofcontents{} + +\end_inset + + +\the_end diff --git a/linphone/share/it/manual.sgml b/linphone/share/it/manual.sgml new file mode 100644 index 000000000..3465759e2 --- /dev/null +++ b/linphone/share/it/manual.sgml @@ -0,0 +1,494 @@ + + +
+ + + + MANUALE UTENTE LINPHONE + + + Simon Morlat (simon.morlat@linphone.org) + + + 11-13-2001 + + + + + Introduzione + + + Linphone è un semplice strumento di telefonia su rete. Permette di effettuare conversazioni tra due utenti utilizzando una modalità IP come Internet. Ecco l'equipaggiamento necessario per usare Linphone : + + + + + Linux ( Può funzionare anche in altri ambienti come BSD, o altri UNIX, ma non l'ho ancora testato personalmente.) + + + + + Gnome 1.2 o superiore, installato ma non necessariamente usato. + + + + + Una scheda sonora correttamente configurata. + + + + + Cuffie o altoparlanti. + + + + + Un microfono. + + + + + Una connessione rete (Internet ad esempio), modem, scheda Ethernet ... + + + + + E' consigliabile chiudere tutte le applicazioni che fanno uso della scheda sonora prima di usare Linphone. Linphone è un programma libero, distribuito sotto la licenza pubblica GNU. + + + ATTENZIONE : Questo strumento è distribuito SENZA GARANZIA. Leggere il file COPYING per maggiori dettagli. Questo significa tra l'altro che non dovete usare Linphone per chiamate confidenziali: non ha ALCUNA CODIFICA DI PROTEZIONE, e quindi può essere molto facile per qualche malintenzionato captare i flussi audio. Si noti inoltre che si raccomanda di non usare Linphone come utente root. + + + + + Uso + + + Linphone può essere usato in 3 modi diversi : + + + + + Come applicazione (normale) : nel menu Gnome, Linphone dovrebbe apparire nella sezione Rete. Se non utilizzi Gnome, puoi lanciare Linphone da una finestra terminale, per esempio. Quando Linphone non è in esecuzione, non è possibile ricevere chiamate. + + + + + Come applet Gnome : cliccando sul pannello Gnome col pulsante destro, aggiungere l'applet. Linphone apparirà nella sezione Rete. Apparendo nel pannello Gnome, Linphone è capace di ricevere chiamate anche se la sua finestra non è visibile. Se si vuol vedere la finestra principale, cliccare sull'applet. Quando c'è una chiamata, la finestra principale passa in primo piano, e sentirai gli squilli della chiamata. + + + + + Come demone : questo è interessante per coloro che non utilizzano Gnome. Per esempio, per KDE, c'é una directory /home/user/.kde2/AutoStart/ dove si possono inserire le applicazioni che si vogliono lanciare ad inizio sessione. Nella directory citata, con l'aiuto di un gestore di file, aggiungere un collegamento cliccando col pulsante destro. Il comando da inserire è "linphone -daemon". L'interfaccia prinicipale di Linphone non sarà visibile, e dunque, per farla apparire, si lanci Linphone normalmente, per esempio da una finestra terminale. + + + + + + + Come lanciarlo + + + + Principi di base + + + Linphone utilizza il protocollo SIP (Session Initiation Protocol) per effettuare chiamate con altri interlocutori. Il protocollo specifica che ciascuna persona dev'essere identificata da un URL sip della forma: sip:nome_utente@nome_host. Questo modo di chiamare le persone è molto simile a quello utilizzato per la posta elettronica. + + + Nome_utente è il nome di un utente su una macchina, come il login su una macchina linux, per esempio. Nome_host è il nome di una macchina sotto forma di indirizzo IP, o più semplicemente sotto forma di dominio (es: linphone.org). + + + Si noti che SIP è un nuovo protocollo di telecomunicazione fatto per essere semplice ed efficace su internet, che è totalmente diverso ed incompatibile con H.323. H.323 è il protocollo attualmente usato da NetMeeting e GnomeMeeting. + + + + + Applicazione: due persone (Bob e Tom) si connettono ad internet con un modem analogico classico. + + + Ecco il modo più semplice di procedere : + + + Prerequisito : + + + + + Un modem da 28.8 Baud o più. + + + + + Procedimento: + + + + + Si è convenuto che Bob debba chiamare Tom alle 21.00. Alle 21.00, Tom si connette ad Internet utilizzando kppp, gppp o wvdial (o un altro). Una volta connesso ad internet, può lanciare Linphone. Aprendo la finestra delle statistiche di kppp o gppp, può vedere il suo indirizzo IP (altrimenti può digitare /sbin/ifconfig per vederlo). Il nome dell'interfaccia modem dev'essere ppp0. + + + + + Di seguito, manda un messaggio a Bob dicendo : "Il mio indirizzo IP è xxx.xxx.xxx.xxx". + + + + + Bob legge l'email e riporta nella finestra di Linphone il nome e l'indirizzo IP della personne da contattare : Tom@xxx.xxx.xxx.xxx(L'indirizzo IP di Tom) e per finire, clicca sul pulsante Chiamare. + + + + + Linphone suona a casa di Tom ...Tom risponde alla chiamata cliccando sul pulsante "Rispondere" ed a questo punto la conversazione può iniziare. + + + + + Se si incontrassero problemi in uno di questi punti, si vada alla sezione 4 - Problemi. + + + + + Test in locale: non hai nessuno da chiamare per il momento, ma vuoi controllare se Linphone funzioni davvero. + + + A partire dalla versione 0.3.0, Linphone è dotato di un programma di test chiamato "sipomatic". Sipomatic può rispondere automaticamente alle chiamate provenienti da Linphone. A voi la scelta : + + + + + Lanciare linphone. + + + + + Lanciare sipomatic in una finestra terminale. Non siate sorpresi, sipomatic non possiede alcuna interfaccia grafica, ma non c'è bisogno di modificare quello che sta sotto. + + + + + In Linphone, menu Parametri, sezione Rete, scegliere "lo" come interfaccia di default. Applicare il cambiamento cliccando su OK. Digitare l'indirizzo S.I.P seguente nella finestra principale : sip:robot@127.0.0.1:5064. 127.0.0.1 è l'indirizzo locale del tuo computer, e robot è il nome da usare per chiamare sipomatic. 5064 è la porta con cui sipomatic può essere contattato. Normalmente si deve utilizzare 5060 per chiamare qualcuno, ma sipomatic fa eccezione : funziona con la porta 5064. Il motivo è che Linphone funziona già sulla porta 5060, ed è impossibile avere due applicazioni che utilizzino la stessa porta nello stesso momento, sulla stessa macchina. + + + + + Cliccare sul pulsante "Chiamare". Dopo qualche secondo, sipomatic dovrebbe rispondere alla chiamata e vi dovrebbe dire un breve messaggio. + + + + + + + + Parametri di chiamata + + + + Rete + + + + + Lista delle interfacce di rete: bisogna scegliere un'interfaccia di rete da usare con Linphone. Se si vuole contattare qualcuno su Internet, bisogna scegliere l'interfaccia di rete connessa ad Internet. Per esempio, se si utilizza un modem, dovrà essere ppp0. Se non si è connessi ad alcuna rete, solo l'interfaccia di rete locale, chiamata lo, apparirà nella lista. L'unica scelta che si può fare in questo caso è chiamare sipomatic. + + + + + Tipo di connessione: scegliere il tipo di connessione utilizzata per connettervi alla rete che si desidera utilizzare. Questo aiuterà Linphone ad autoconfigurarsi in funzione della banda passante del tipo di connessione. + + + + + + + RTP + + + RTP + + + + + porta RTP: Linphone utilizza la porta 7072 di default per inviare e ricevere segnali audio. Se la porta 7072 è usata da un'altra applicazione, la si cambi a piacere. + + + + + Compensazione Jitter: questo numero rappresenta il numero di pacchetti audio che Linphone aspetta prima di farli sentire. Si aumenti questo numero se si sente male la voce, in modo da migliorare la qualità di trasmissione, ma attenzione: questo aumenta il ritardo (Si sentirà la voce dell'interlocutore qualche millisecondo più tardi). D'altro canto, se si utilizza un server perfetto, e si dispone di buoni driver audio, si può scegliere un valore basso fino a 3 pacchetti, sentendo così un ritardo trascurabile. + + + + + + + SIP + + + SIP (Session Initiation Protocol) è un protocollo che permette di stabilire sessioni telefoniche grazie ad un server IP. Semplificando, è ciò che permette di far suonare il telefono all'altro interlocutore, sospendere o terminare una chiamata quando uno dei due riattacca. + + + + + porta SIP: Linphone utilizza di default la porta 5060 per inviare / ricevere pacchetti SIP. Si raccomanda caldamente per la RFC del protocollo SIP di utilizzare questo valore. Non lo si cambi a meno che non si sappia davvero cosa si stia facendo. + + + + + Indirizzo SIP: modifica nome utente e macchina a piacere. Beninteso, dare un nome di macchina quinon significa che questo nome sia conosciuto da altre macchine del server. Nemmeno Linphone userà il nome della macchina e preferirà usare l'indirizzo IP per comunicare con altre macchine. + + + + + Usare un server segretario sip: si faccia questa scelta, se ci si vuole registrare su un server SIP (segretario) per ottenere servizi vari. Quando non si ha un indirizzo IP fisso, questo può essere interessante per permettere agli amici di chiamare. Vedere la sezione "enregistrement sur un serveur sip". + + + + + + + Codec + + + I codecs sono algoritmi per comprimere la voce. Per esempio, una voce digitalizzata a 16bit/8000Hz rappresenta un flusso di dati di 128kbits/secondo. Usando il codificatore vocale GSM, questo flusso è ridotto a 13kbits/secondo, senza perdita significativa di qualità. + + + + + Scelta dei codecs: Linphone può usare diversi codec. Usare i pulsanti posti a lato della lista dei codec in modo da porli nell'ordine preferito. Si badi bene, che in funzione del tipo di connessione alla rete, alcuni codec sono inutilizzabili. Questi appariranno in rosso e non saranno selezionabili. Si può decidere di usare o no un codec "utilizzabile" (in blu) cambiando il suo stato con l'aiuto del pulsante Attiva / Disattiva in fianco alla lista. + + + + + + + Parametri audio + + + + + Modo d'uso: se si ha installato il driver ALSA con una libreria ALSA <0.9, si scelga ALSA per avere risultati migliori. Altrimenti, o se non si sa, usare OSS, che funziona sufficientemente bene. + + + + + Scelta della fonte di registrazione: si può scegliere la fonte di registrazione per la voce. Nella maggior parte dei casi, sarà il microfono. + + + + + Opzione auto-kill: scegliendo questa opzione, Linphone fermerà i server sonori (esd &#38; artsd) che possono bloccare la periferica sonora e provocare così problemi problemi d'apertura delle periferiche da parte di Linphone in caso di bisogno. Si raccomanda di attivare questa opzione. + + + + + + + + Rubrica + + + A partire dalla versione 0.4.1 Linphone dispone di una rubrica (menu connessione, rubrica), con la quale memorizzare indirizzi, e richiamarli facilmente quando si vuol chiamare. + + + + + Registrazione su un server sip + + + E' possibile sottoscrivere alcuni servizi sui server sip remoti chiamati segretari, proxy o server ridiretti. Questi servizi possono essere: + + + + + ridirezione: Linphone chiede al server la creazione di un account <sip:votre_nom@le_serveur_sip>. Questo indirizzo potrà allora essere utilizzato dai tuoi interlocutori per connetterti. Un piccolo esempio concreto può essere utile: tu non sei altro che un internauta poverino, connesso temporaneamente grazie ad un modem 56k. La tua macchina non ha un nome di dominio conosciuto ed il tuo indirizzo IP cambia ad ogni connessione. E' impossibile per gli amici chiamare in mancanza dell'indirizzo IP, a meno che non lo si comunichi via posta elettronica, per esempio. Per risolvere questo problema, si può chiedere di avere un indirizzo su un server sip conosciuto dagli amici, fisso e sempre connesso. Per far ciò, specificare l'indirizzo del server nel menu parametri, sezione sip. Questo indirizzo è, per esempio, <sip:server_esempio.com> ed il nome utente è “Bob”. Linphone invia allora al server un messaggio per informare della corrispondenza tra l'indirizzo <sip:bob@server_esempio.com> e l'indirizzo IP attuale. D'ora in poi gli amici potranno chiamare usando questo nuovo indirizzo: le chiamate saranno ridirette automaticamente verso la tua macchina. Non ci sarà più bisogno di conoscere l'indirizzo IP, che cambia ogni volta, per contattarti. Ovviamente, si suppone che <sip:server_esempio.com> sia conosciuto da tutti gli amici. + + + + + Proxy: è esattamente lo stesso principio, tranne che la ridirezione viene fatta in maniera trasparente ed invisibile dal Linphone del chiamante. + + + + + Il segretario specificato può essere utilizzato come proxy in uscita. In questo caso tutte le chiamate in uscita dal tuo Linphone saranno dirette verso tale server, che si suppone sia gestito da brave persone. E' quindi molto utile, per non dire indispensabile, che si usi Linphone su una rete privata, gestita da un firewall, anche se su un proxy sip è sicuramente attivo un firewall. + + + Per usare fin da subito un server sip, bisogna aprire il menu Parametri, SIP, e cliccare sul pulsante in fianco a "Usa il segretario sip". Digitare l'indirizzo del segretario, e scegliere un nome utente non troppo comune, in modo da evitare conflitti di nomi. Dare un'indicazione del servizio che il server deve effettuare per te e cliccare sui pulsanti “ridirezione” o “proxy”. Selezionare anche l'opzione “il server è un proxy in uscita” se sei dietro ad un firewall. + + + Infine, confermando la scelta, Linphone comunicherà immediatamente con il server SIP per ottenere i servizi richiesti. Allo stesso modo, in fase di uscita da Linphone, ci vorrà qualche secondo per togliere la registrazione dal server. + + + Una lista di server sip può essere trovata a questo indirizzo: http://www.cs.columbia.edu/~hgs/sip/servers.html. + + + Sfortunatamente, poiché alcuni di questi server non funzionano più, forse a causa della crisi e di fallimenti di società. Alcuni non sono utilizzabili poiché richiedono metodi di autentificazione non ancora implementati in Linphone. Per non perdere tempo, una lista di server sip pubblici funzionanti con Linphone è reperibile su http://simon.morlat.free.fr/english/servers.html. + + + + + Uso dietro i firewall + + + Linphone è in grado di funzionare dietro i firewall grazie ad un server proxy SIP in funzione sulla macchina firewall. Un tale server è in corso di sviluppo su http://osipproxy.sourceforge.net. Ovviamente sarà libero e basato sulla libreria LGPL oSIP. + + + Una volta che il server proxy sarà attivo, si potrà configurare Linphone per utilizzarlo. Per far ciò, andare in Parametri, sezione SIP e attivare la casella “Usa il segretario SIP”, indicare il suo indirizzo, ed attivare l'opzione “il server è un proxy in uscita”. + + + C'è un caso in cui il proxy non è indispensabile: quello in cui le macchine di reti private possiedano un indirizzo pubblico: il firewall filtra i pacchetti in entrata o uscita. Bisogna permettere a Linphone di funzionare con le macchine esterne, autorizzare il traffico UDP sulla porta SIP (di default 5060, è possibile cambiarla), e sulla porta RTP di ciascun Linphone nelle sottoreti. La porta RTP è parametrizzabile, come si è visto, nel menu Parametri. + + + + + Problemi vari + + + + Problemi di connessione + +
+ + Tento di chiamare il mio amico <sip:toto@esempio.com>, ma niente da fare, nessuno squillo. + +
+ + Bisogna verificare che Linphone usi l'interfaccia di rete a cui sei connesso con la rete su cui si trova il tuo amico. La lista delle interfacce disponibili si trova in Parametri, sezione Rete. Selezionarla. + + + Se il problema persistesse, potrebbe essere che il tuo amico non sia al momento raggiungibile. + +
+ + + Problemi audio + +
+ + Linphone sembra connettersi correttamente, si sentono gli squilli, ma appena l'interlocutore risponde, non si sente o si capisce più nulla. + +
+ + + + La maggior parte degli utenti ha di questi problemi poiché non è stata scelta l'interfaccia di rete corretta. Se si usa il modem, dev'essere ppp0. In ogni caso, l'interfaccia “lo” non permette di avere una comunicazione via rete. Serve solo per il test locale con sipomatic (vedere più avanti). + + + + + Aumentare il livello sonoro di acquisizione ed emissione, usando i potenziometri posti nella finestra principale. + + + + + Se la voce dell'interlocutore sembra vibrare o echeggiare, si può tentaredi aumentare il parametro comensazione jitter (Parametri, RTP). Ma attenzione, questo aumenta il ritardo nella controparte. + + + + + Se Linphone nonriesce ad usare la scheda sonora, verificare che non sia utilizzata da qualche altro programma audio. + + + + + Infine, utilizzare il driver sonoro ALSA (vedere http://www.alsa-project.org) , piuttosto che OSS, fornito con il kernel linux. Sfortunatamente la maggior parte delle distribuzioni usano ancora vecchi driver che hanno vari errori e problemi di ritardo. I driver ALSA danno risultati migliori. Si noti che se si cambiano driver, non c'è bisogno di ricompilare Linphone o di cambiare una qualsiasi configurazione. + + + +
+
+ + + Errori e suggerimenti + + + In primo luogo, andare sul sito di Linphone http://www.linphone.org e verificare di avere la versione più recente di Linphone. + + + Se Linphone si bloccassse, inviami direttamente un messaggio a bugs@linphone.org. Qualora Linphone non funzionasse, ma non si bloccasse, verificare bene di aver letto tutto il manuale prima di mandare un resoconto all'indirizzo indicato. In ogni caso invia più informazioni possibili relativamente al problema, in particolar modo i messaggi che compaiono quando lo si lancia da un terminale. Se desideri qualche altra cosa, non esitare ad inviarmi un messaggio a help@linphone.org.Tieni presente che l'aggiunta della modalità video e conferenza sono in programma. + + + Se qualcuno fosse interessato a fare traduzioni di Linphone, mi invii un file xx.po basato su quello in po/linphone.pot della distribuzione. Si può anche tradurre il manuale utente in altre lingue. In ogni caso, contattami qualora volessi maggiori dettagli. + + + + + Autori + + + Simon MORLAT (simon.morlat@linphone.org) ha scritto: + + + + + Programma principale (src) + + + + + Libreria RTP (lprtplib) + + + + + osipua : la libreria Agente utente sip . + + + + + Interfaccia per i driver audio (audio) + + + + + Wrappers per i codecs lpc10-1.5, gsm e g711. + + + + + Aymeric Moizard (jack@atosc.org) ha scritto la pila SIP oSIP usata da linphone. + + + La libreria GSM è stata scritta da: Jutta Degener and Carsten Bormann,Technische Universitaet Berlin. + + + La librairie LPC10-1.5 par: Andy Fingerhut Applied Research Laboratory Washington University, Campus Box 1045/Bryan 509 One Brookings Drive Saint Louis, MO 63130-4899 jaf@arl.wustl.edu http://www.arl.wustl.edu/˜jaf/ + + + Leggere i file di testo README nella directory gsmlib e lpc10-1.5 per maggiori informazioni. + + + Le icone sono di Pablo Marcelo Moia ed il logo di Philippe Beau. + + + + + Ringraziamenti + + + Grazie a Daemon Chaplin per aver scritto Glade, il costruttore d'interfaccia grafica GTK+. + + + Grazie agli autori del codice di LPC10-1.5 e GSM. + + + Grazie a Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com ) per i suoi RPMS. + + + Grazie a Pablo Marcelo Moiaper le icone. + + + Grazie a Philippe Beau per la traduzione di questo manuale in francese, per il logo, e per il nuovo sito web che ha creato per Linphone. + + + Grazie a Alberto Zanoni <alberto.zanoni@-NO-SPAM-PLEASE!-tiscalinet.it> per la traduzione di linphone e questo manuale in Italiano. + + + + + + + +
diff --git a/linphone/share/it/manual/.cvsignore b/linphone/share/it/manual/.cvsignore new file mode 100644 index 000000000..2d19fc766 --- /dev/null +++ b/linphone/share/it/manual/.cvsignore @@ -0,0 +1 @@ +*.html diff --git a/linphone/share/ja/.cvsignore b/linphone/share/ja/.cvsignore new file mode 100644 index 000000000..e1d20773b --- /dev/null +++ b/linphone/share/ja/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +manual +manual.junk +manual.html diff --git a/linphone/share/ja/Makefile.am b/linphone/share/ja/Makefile.am new file mode 100644 index 000000000..1d3028c6e --- /dev/null +++ b/linphone/share/ja/Makefile.am @@ -0,0 +1,3 @@ +HELPLANG=ja + +include ../Makefile.inc diff --git a/linphone/share/ja/manual.lyx b/linphone/share/ja/manual.lyx new file mode 100644 index 000000000..c1777bd96 --- /dev/null +++ b/linphone/share/ja/manual.lyx @@ -0,0 +1,505 @@ +#LyX 1.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 218 +\textclass docbook +\language english +\inputencoding default +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize Default +\paperpackage a4 +\use_geometry 0 +\use_amsmath 0 +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language english +\quotes_times 2 +\papercolumns 1 +\papersides 1 +\paperpagestyle default + +\layout Title + +LINPHONE¥æ¡¼¥¶¡¼¥Þ¥Ë¥å¥¢¥ë +\layout Author + +Simon Morlat (simon.morlat@linphone.org) +\layout Author + +Ìõ¡§»³¸ýÁ±Ìé(yushiya@anet.ne.jp) +\layout Date + +11-13-2001 +\layout Section + +¤Ï¤¸¤á¤Ë +\layout Standard + +Linphone¤Ï¡¢¥·¥ó¥×¥ë¤Ê¥¤¥ó¥¿¡¼¥Í¥Ã¥ÈÅÅÏäǤ¢¤ê¡¢Æó¼Ô´Ö¤ÎÄÌÏäò¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ê¤É¤ÎIPÌÖ¤òÄ̤¸¤Æ²Äǽ¤Ë¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£Linphone¤òµ¯Æ°¤¹¤ë¤Ë¤Ï°Ê²¼ +¤Î¤â¤Î¤¬É¬ÍפȤʤ롣 +\layout Itemize + +Linux(BSD¤Î¤è¤¦¤Ê¾¤ÎUNIX¤Ç¤âµ¯Æ°¤¹¤ë¤À¤í¤¦¤¬¡¢Linux´Ä¶­¤Û¤É¾¤Î´Ä¶­¤Ï¥Æ¥¹¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¡£) +\layout Itemize + +gnome1.2°Ê¾å¤¬¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë¤³¤È¡£É¬¤º¤·¤âµ¯Æ°¤·¤Æ¤¤¤ëɬÍפϤʤ¤¡£ +\layout Itemize + +¥Ø¥Ã¥É¥Û¥ó¤«¥¹¥Ô¡¼¥«¡¼¡£ +\layout Itemize + +¥µ¥¦¥ó¥É¥«¡¼¥É¤¬Àµ¤·¤¯ÀßÄꤵ¤ì¤Æ¤¤¤ë¤³¤È¡£ +\layout Itemize + +¥Þ¥¤¥¯¥í¥Õ¥©¥ó +\layout Itemize + +¥â¥Ç¥à¤ä¥¤¡¼¥µ¥Í¥Ã¥ÈÅù¤òÍѤ¤¤¿¡¢¥Í¥Ã¥È¥ï¡¼¥¯(¥¤¥ó¥¿¡¼¥Í¥Ã¥ÈÅù)¤Ø¤ÎÀܳ¡£ +\layout Standard + +¤Ê¤ª¡¢Linphone¤òµ¯Æ°¤¹¤ëÁ°¤Ë¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò»ÈÍѤ¹¤ë¤¹¤Ù¤Æ¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤ò½ªÎ»¤·¤Æ¤ª¤¯¤Î¤¬¤è¤¤¤À¤í¤¦¡£ +\layout Standard + +Linphone¤Ï¥Õ¥ê¡¼¥¦¥§¥¢¤Ç¤¢¤ê¡¢GNU Public Licence¤Ë½¾¤Ã¤ÆÇÛÉÛ¤µ¤ì¤ë¡£ +\layout Standard + +·Ù¹ð - Åö¥½¥Õ¥È¥¦¥§¥¢¤ÏÊݾڤʤ·¤ËÄ󶡤µ¤ì¤ë¤â¤Î¤Ç¤¢¤ë¡£¾Ü¤·¤¯¤ÏCOPYING¥Õ¥¡¥¤¥ë¤ò»²¾È¤µ¤ì¤¿¤¤¡£¤Ê¤ª¡¢Linphone¤Ï°Å¹æ²½¤òÍѤ¤¤Ê¤¤¤¿¤á¡¢°­°Õ¤¢¤ë¿Í +ʪ¤¬Íưפ˲»À¼¾ðÊó¤ò½¦¤¦¤³¤È¤¬¤Ç¤­¤ë¡£¤Ä¤Þ¤ê¡¢Linphone¤ÏÈëÌ©¤Î²ñÏäËÍѤ¤¤ë¤Ù¤­¤Ç¤Ï¤Ê¤¤¡£¤Þ¤¿¡¢Linphone¤Ï¥ë¡¼¥È¸¢¸Â¤Çµ¯Æ°¤·¤Ê¤¤¿ä¾©¤¹¤ë¡£ +\layout Section + +Linphone¤Îµ¯Æ° +\layout Standard + +Linphone¤Ï»°¤Ä¤ÎÊýË¡¤Çµ¯Æ°¤Ç¤­¤ë¡£ +\layout Itemize + +Ä̾ï¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤È¤·¤Æ - Linphone¤Ï¡¢gnome¥á¥Ë¥å¡¼¤ÎÃæ¤Î¥Í¥Ã¥È¥ï¡¼¥¯¥µ¥Ö¥á¥Ë¥å¡¼¤Ë¸½¤ì¤ë¡£¤â¤·¡¢gnome¤òµ¯Æ°¤·¤Æ¤Ê¤¤¤Î¤Ç¤¢¤ì¤Ð¡¢Î㤨¤Ð +¥¿¡¼¥ß¥Ê¥ë¤Ë +\begin_inset Quotes eld +\end_inset + +linphone +\begin_inset Quotes erd +\end_inset + +¤È¥¿¥¤¥×¤¹¤ë¤³¤È¤Ç¼Â¹Ô¤Ç¤­¤ë¡£Linphone¤¬µ¯Æ°¤·¤Æ¤¤¤Ê¤¤¤È¤­¤Ï¡¢ÅÅÏäò¼õ¤±¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£ +\layout Itemize + +gnome¥¢¥×¥ì¥Ã¥È¤È¤·¤Æ - gnome¥Ñ¥Í¥ë¤ò±¦¥¯¥ê¥Ã¥¯¤¹¤ë¤È¡¢¥Ñ¥Í¥ë¤ËLinphone¤òÄɲ乤뤳¤È¤¬¤Ç¤­¤ë¡£Linphone¤Ï¥Í¥Ã¥È¡¼¥ï¡¼¥¯¥á¥Ë¥å¡¼¤ÎÃæ +¤Ë¤¢¤ë¡£¤Ò¤Ã¤½¤ê¤È¥Ñ¥Í¥ë¤ÎÃæ¤Çµ¯Æ°¤¹¤ë¤³¤È¤Ç¡¢Linphone¤Ï¡¢¤¿¤È¤¨¥¦¥¤¥ó¥É¥¦¤¬¸½¤ì¤Æ¤¤¤Ê¤¯¤Æ¤âÅÅÏäò¼õ¤±¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤Ëɽ¼¨¤µ¤»¤¿¤¤¤È¤­ +¤Ë¤Ï¡¢¥¢¥×¥ì¥Ã¥È¤ò¥¯¥ê¥Ã¥¯¤¹¤ì¤Ð¤è¤¤¡£ÅÅÏ䬤«¤«¤Ã¤Æ¤­¤¿¤È¤­¤Ë¤Ï¡¢¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤¬É½¤ì¤Æ¡¢Ä̾ïÄ̤ê¤Ë¥Ù¥ë¤¬ÌĤäƤ¤¤ë¤Î¤¬Ê¹¤³¤¨¤ë¤À¤í¤¦¡£ +\layout Itemize + +¤Ò¤Ã¤½¤ê¤È¥Ç¡¼¥â¥ó¤È¤·¤Æ - ¤³¤ì¤Ï¡¢Èógnome¥æ¡¼¥¶¡¼¤Î¤¿¤á¤Î¤â¤Î¤Ç¤¢¤ë¡£Î㤨¤Ðkde¤Ç¤Ï¡¢/home/user/.kde2/AutoStart¥Ç¥£¥ì¥¯¥È¥ê¤Ë +¡¢¥í¥°¥¤¥ó»þ¤Ëµ¯Æ°¤·¤¿¤¤¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î¥ê¥ó¥¯¤òŽ¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢¾å½Ò¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥Õ¥¡¥¤¥ë¥Þ¥Í¡¼¥¸¥ã¡¼¤Ç°Üư¤·¡¢±¦¥¯¥ê¥Ã¥¯¤Ç¸½¤ì¤ë¥¢¥×¥ì¥Ã¥È¤«¤é¡¢¡Ö¥ê¥ó¥¯ +¤ÎÄɲáפò¼Â¹Ô¤¹¤ì¤Ð¤è¤¤¡£¤Ê¤ª¡¢µ¯Æ°¤¹¤ë¥³¥Þ¥ó¥É¤Ï¡¢ +\begin_inset Quotes eld +\end_inset + + linphone -deamon +\begin_inset Quotes erd +\end_inset + +¤Ç¤¢¤ë¡£¤³¤Î¾ì¹ç¡¢Linphone¤Î¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤ò¸«¤ë¤³¤È¤Ï¤Ê¤¤¤¬¡¢É½¼¨¤µ¤»¤¿¤¤¤È¤­¤Ë¤Ï¥¿¡¼¥ß¥Ê¥ëÅù¤«¤éLinphone¤òµ¯Æ°¤µ¤»¤ë¤Î¤ÈƱÍͤ˥¿¥¤¥×¤¹¤ì¤Ð¤è +¤¤¡£ +\layout Section + +ÅÅÏäò¤«¤±¤ë +\layout Subsection + +´ðËÜŪ¤Ê¸¶Â§ +\layout Standard + +¡Ösip:¥æ¡¼¥¶¡¼Ì¾@¥Û¥¹¥È̾¡×¤Î¤è¤¦¤ÊSIP URL¤Ë¤è¤Ã¤Æ¶èÊ̤µ¤ì¤ë¡£SIP URL¤Ï¡¢Æ¬¤Î¡Ösip:¡×¤ò½ü¤±¤ÐÈó¾ï¤Ëe-mail¥¢¥É¥ì¥¹¤È»÷¤Æ¤¤¤ë¡£ +\layout Standard + +¥æ¡¼¥¶¡¼Ì¾¤Ï¡¢UNIX¥Þ¥·¥ó¤Î¥í¥°¥¤¥ó¥Í¡¼¥à¤Î¤è¤¦¤Ê¤â¤Î¤Ç¡¢¥Û¥¹¥È̾¤Ï¥æ¡¼¥¶¡¼¤¬Àܳ¤¹¤ë¥Þ¥·¥ó¤Î̾Á°¤äIP¥¢¥É¥ì¥¹¤Ç¤¢¤ë¡£ +\layout Standard + +¤Ê¤ª¡¢SIP¤Ï¥·¥ó¥×¥ë¤ËÀ߷פµ¤ì¤¿¿·¤·¤¤ÄÌ¿®¤Î¥×¥í¥È¥³¥ë¤Ç¤¢¤ê¡¢H323¤È¤Ï¤Þ¤Ã¤¿¤¯¸ß´¹À­¤¬¤Ê¤¤¤³¤È¤ËÃí°Õ¤µ¤ì¤¿¤¤¡£ +\layout Subsection + +»ÈÍÑÎã:Æó¿Í¤Î¥æ¡¼¥¶¡¼¤¬¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ë¥â¥Ç¥à¤ÇÀܳ¤·¤Æ¤¤¤ë¤È¤­ +\layout Standard + +¤³¤ì¤Ï¡¢Ã±½ã¤Ê¼ê³¤­¤Ç¤¢¤ë¡£É¬ÍפȤµ¤ì¤ë¥Í¥Ã¥È¥ï¡¼¥¯¤Ï¡¢ +\layout Itemize + +28k°Ê¾å¤Î¥â¥Ç¥à +\layout Standard + +¤Ç¤¢¤ë¡£ +\layout Standard + +¥·¥Ê¥ê¥ª¤Ï¡¢°Ê²¼¤ÎÄ̤ê¤Ç¤¢¤ë¡£ +\layout Itemize + +¥Ü¥Ö¤Ï¥È¥à¤Ë21:00¤ËÅÅÏ乤뤳¤È¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡£¥È¥à¤Ï¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ëkppp¤ägppp¤äwmdial¤Ê¤É¤ÇÀܳ¤·¤Æ¤¤¤ë¡£ +\layout Itemize + +¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ËÀܳ¤·¤¿¤é¡¢¥Ü¥Ö¤ÏLinphone¤òµ¯Æ°¤Ç¤­¤ë¡£kppp¤ägppp¤Ê¤É¤ÎÅý·×¥Ü¥Ã¥¯¥¹¤ò³«¤¤¤Æ¡¢¥Ü¥Ö¤Ï¼«Ê¬¤ÎIP¥¢¥É¥ì¥¹¤òÃΤ뤳¤È¤¬¤Ç¤­¤ë¡£(/s +bin/ifconfig¤ò»È¤ï¤Ê¤¯¤Æ¤â³Îǧ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë)¡£ +\layout Itemize + +¼¡¤Ë¡¢¥È¥à¤Ï¥Ü¥Ö¤Ë¡ÖËͤÎIP¥¢¥É¥ì¥¹¤Ï¡¢xxx.xxx.xxx.xxx¤À¤è¡£¡×¤È¤¤¤¦ÆâÍÆ ¤Îe¥á¡¼¥ë¤òÁ÷¤ë¡£ +\layout Itemize + +¤½¤Î¤¹¤°¤¢¤È¤Ç¡¢¥È¥à¤Î²È¤ÎLinphone¤Î¥Ù¥ë¤¬ÌĤ롣¤½¤Î¤È¤­¡¢¥Ü¥Ö¤Ë¤â¸þ¤³¤¦¤Ç¥Ù¥ë¤¬ÌĤäƤ¤¤ë¤Î¤¬Ê¬¤«¤ë¤è¤¦¤Ë¥Ù¥ë¤Î²»¤¬Ê¹¤³¤¨¤ë¡£¤½¤³¤Ç¡¢¥È¥à¤¬ÅÅÏä˽Ф뤿 +¤á¤Ë¡ÖÅÅÏäò¤È¤ë¡×¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¤À¤±¤Ç¤è¤¤¡£¤½¤¦¤¹¤ì¤Ð¡¢¸ß¤¤¤Ë²ñÏ䬤Ǥ­¤ë¤Ï¤º¤Ç¤¢¤ë¡£ +\layout Standard + +ÌäÂ꤬¤¢¤Ã¤¿¤é¡¢Âè4Àá¤ÎÌäÂê¤ò»²¾È¤·¤ÆÍߤ·¤¤¡£ +\layout Subsection + +¥Æ¥¹¥È¤Î»î¹Ô - ¸½ºß(Î㤨¤Ð¿¼Ìë¤Ê¤É¤Ç)ÅÅÏäò¤«¤±¤ëͧ¿Í¤¬¤¤¤Ê¤¤¤¬¡¢Linphone¤¬ËÜÅö¤Ëư¤¤¤Æ¤¤¤ë¤«¤É¤¦¤«ÃΤꤿ¤¤¤È¤­ +\layout Standard + + +\begin_inset LatexCommand \label{sipomatic} + +\end_inset + +¥Ð¡¼¥¸¥ç¥ó3.0¤«¤é¤Ï¡¢Linphone¤Ë¤Ï¡Ösiptomatic¡×¤È¤¤¤¦¥×¥í¥°¥é¥à¤¬ÉÕ°¤·¤Æ¤¤¤ë¡£¤³¤ì¤Ï¡¢°Ê²¼¤Î¼ê½ç¤Ç»ÈÍѤǤ­¤ë¡£ +\layout Itemize + +siptomatic¤ò¥¿¡¼¥ß¥Ê¥ë¤«¤éµ¯Æ°¤¹¤ë¡£siptomatic¤Ï¥°¥é¥Õ¥£¥«¥ë¥¤¥ó¥¿¡¼¥Õ¥§¥¤¥¹¤òÈ÷¤¨¤Æ¤¤¤Ê¤¤¤¬¡¢¶Ã¤«¤Ê¤¤¤ÇÍߤ·¤¤¡£Áê¸ßŪ¤Ê¤ä¤ê¤È¤ê¤ò¤¹¤ëɬÍפ¬ +¤Ê¤¤¤«¤é¤Ç¤¢¤ë¡£ +\layout Itemize + +Linphone¤Î¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤Î¥¿¥Ö¤«¤é¡¢¡Ölo¡×¤ò¥Ç¥Õ¥©¥ë¥È¤Î¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ë·èÄꤷ¡¢Êѹ¹¤òOK¤ò¥¯¥ê¥Ã¥¯¤·¤ÆÅ¬ÍѤ¹¤ë¡£ + +\layout Itemize + +¡Ösip:robot@127.0.0.1:5064¡×¤È¤¤¤¦SIP URL¤ò¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤ËÆþÎϤ¹¤ë¡£127.0.0.1¤Ï¡¢¤¢¤Ê¤¿¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤Î ¥í¡¼¥«¥ë¥¢¥É¥ì¥¹¤Ç¡¢r +obot¤Ïsipomatic¤ËÅÅÏäò¤«¤±¤ëºÝ¤Î̾Á°¤Ç¤¢¤ë¡£5064¥Ý¡¼¥È¤¬¡¢sipomatic¤ËÀܳ²Äǽ¤Ê¥Ý¡¼¥È¤Ç¤¢¤ë¡£Ä̾ï¤ÏÅÅÏäò¤«¤±¤ë¤Î¤Ë5060È֥ݡ¼¥È¤ò +ÍѤ¤¤ë¤¬¡¢sipomatic¤ÏÎã³°¤Ç5064È֥ݡ¼¥È¤Çµ¯Æ°¤·¤Æ¤¤¤ë¡£¤³¤ì¤Ï¡¢Linphone¤¬¤¹¤Ç¤Ë5060È֥ݡ¼¥È(¤¹¤Ê¤ï¤Á¡¢¥Ý¡¼¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¥Ç¥Õ +¥©¥ë¥È¤Î¥Ý¡¼¥È¤È¤·¤Æ)¤Çµ¯Æ°¤·¤Æ¤¤¤ë¤«¤é¤Ç¤¢¤ê¡¢Æ±¤¸¥Ý¡¼¥È¤ò»È¤¦2¤Ä¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤òƱ»þ¤ËƱ¤¸¥³¥ó¥Ô¥å¡¼¥¿¡¼¤Çµ¯Æ°¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¤«¤é¤Ç¤¢¤ë¡£ +\layout Itemize + +¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¤È¡¢¿ôÉøå¤Ësiptomatic¤¬¤¢¤Ê¤¿¤ÎÅÅÏäËÊÖÅú¤·¡¢Ã»¤¤¥¢¥Ê¥¦¥ó¥¹¤¬Ê¹¤³¤¨¤ë¤À¤í¤¦¡£ +\layout Section + + +\begin_inset LatexCommand \label{params} + +\end_inset + +ÅÅÏäΥѥé¥á¡¼¥¿¡¼ +\layout Subsection + + +\begin_inset LatexCommand \label{paramnetwork} + +\end_inset + +¥Í¥Ã¥È¥ï¡¼¥¯ +\layout Itemize + +¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Î¥ê¥¹¥È - ¤¢¤Ê¤¿¤Ï¡¢Linphone¤Ë»È¤¦¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ÖɬÍפ¬¤¢¤ë¡£¤â¤·¡¢¥¤¥ó¥¿¡¼¥Í¥Ã¥È¾å¤Î狼¤ËÏ¢Íí¤ò¤·¤¿ +¤¤¤Î¤Ê¤é¡¢¤¢¤Ê¤¿¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤¬¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ËÀܳ¤·¤Æ¤¤¤ë¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤Ö¤Ù¤­¤Ç¤¢¤ë¡£²¿¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤Ë¤â¤Ä¤Ê¤¬¤Ã¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¡¢¡Ölo +¡×¤È¸Æ¤Ð¤ì¤ë¥í¡¼¥«¥ë¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤À¤±¤¬¥ê¥¹¥È¤Ë¸½¤ì¤ë¤À¤í¤¦¡£¤½¤ì¤Ï¡¢siptomatic¤ËÅÅÏäò¤¹¤ë¤³¤È¤À¤±¤¬¤Ç¤­¤ë¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ç¤¢¤ë¡£ + +\layout Itemize + +Àܳ¤Î¥¿¥¤¥× - »È¤¤¤¿¤¤¥Í¥Ã¥È¥ï¡¼¥¯¤Ø¤ÎÀܳ¤ÎÊýË¡¤òÁªÂò¤¹¤ë(ÂçÄñ¤Î¾ì¹ç¤Ï¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ç¤¢¤ë)¡£¤³¤ì¤Ï¡¢Linphone¤¬¤¢¤Ê¤¿¤ÎÂÓ°è¤òÀßÄꤹ¤ë¤Î¤òÊä½õ¤¹¤ë +¤¿¤á¤Ç¤¢¤ë¡£ +\layout Subsection + + +\begin_inset LatexCommand \label{paramrtp} + +\end_inset + +RTP +\layout Standard + +RTP(Real Time Protocol)¤Ï¡¢¥á¥Ç¥£¥¢¥¹¥È¥ê¡¼¥à¤ò¥Í¥Ã¥È¥ï¡¼¥¯±Û¤·¤ËÁ÷¿®¤¹¤ëºÝ¤ËÍѤ¤¤ë¥×¥í¥È¥³¥ë¤Ç¤¢¤ë¡£ +\layout Itemize + +RTP¥Ý¡¼¥È - Linphone¤Ï¡¢¥Ç¥Õ¥©¥ë¥È¤Ç²»À¼¥Ç¡¼¥¿¤ÎÁ÷¼õ¿®¤Ë7000È֥ݡ¼¥È¤òÍøÍѤ¹¤ë¡£7000È֥ݡ¼¥È¤¬Â¾¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Ë»È¤ï¤ì¤Æ¤¤¤ë¤È»×¤ï¤ì¤ë +¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥Ý¡¼¥È¤ËÊѹ¹¤¹¤ë¡£ +\layout Itemize + +¥Ð¥Ã¥Õ¥¡¤¹¤ë¥ß¥êÉà - ¤³¤Î¿ô»ú¤Ï¡¢Linphone¤¬ºÆÀ¸¤òÂÔµ¡¤¹¤ë²»À¼¥Ñ¥±¥Ã¥È¤Î¿ô¤òɽ¤·¤Æ¤¤¤ë¡£²»À¼¥Ñ¥±¥Ã¥È¤¬Á÷¤ì¤¬¤Á¤Ê¾ì¹ç¤Ë¡¢ºÆÀ¸¤µ¤ì¤º¤ËÇË´þ¤µ¤ì¤ë²»À¼¥Ñ¥± +¥Ã¥È¤ò¸º¤é¤¹¤³¤È¤¬¤Ç¤­¤ë¡£¡ÖÅÓÀÚ¤ìÅÓÀڤ첻¡×¤¬Ê¹¤³¤¨¤ë¾ì¹ç¡¢¤³¤ÎÃͤòÂ礭¤¯¤¹¤ë¤ÈÅÁÁ÷¤Î¸úΨ¤ò¾å¤²¤ë¤³¤È¤¬¤Ç¤­¤ë¤¬¡¢²»À¼¤ÎÃٱ䤬Â礭¤¯¤Ê¤ë(Áê¼ê¤ÎÀ¼¤¬¾¯¤·ÃÙ¤ì¤ÆÊ¹ +¤³¤¨¤ë)¡£¤æ¤¨¤Ë¡¢¥Í¥Ã¥È¥ï¡¼¥¯¤¬´°Á´¤Ç¹âÉʼÁ¤Î¥ª¡¼¥Ç¥£¥ª¥É¥é¥¤¥Ð¤ò»ÈÍѤ·¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢¤³¤ÎÃͤò3¥Ñ¥±¥Ã¥È¤Ë²¼¤²¤ì¤Ðû¤¤ÃÙ±ä»þ´Ö¤ÇÏ令ë¤è¤¦¤Ë¤Ê¤ë¡£ +\layout Subsection + + +\begin_inset LatexCommand \label{paramsip} + +\end_inset + +SIP +\layout Standard + +SIP(Session Initiation Protocol)¤Ï¡¢¥Í¥Ã¥È¥ï¡¼¥¯±Û¤·¤Ë¥á¥Ç¥£¥¢¤Î¥»¥Ã¥·¥ç¥ó¤ò³ÎΩ¤¹¤ë¥×¥í¥È¥³¥ë¤Ç¤¢¤ë¡£¤Ä¤Þ¤ê¤Ï¡¢¥ê¥â¡¼¥È¥æ¡¼¥¶¡¼ +´Ö¤Î²ñÏäò³«»Ï¤·¤¿¤ê¡¢ÊÒÊý¤¬ÅÅÏäòÀڤ俤Ȥ­¤Ë²ñÏäò½ªÎ»¤·¤¿¤ê¤¹¤ë¥×¥í¥È¥³¥ë¤Ç¤¢¤ë¡£ +\layout Itemize + +SIP¥Ý¡¼¥È - Linphone¤Ï¡¢¥Ç¥Õ¥©¥ë¥È¤ÇSIP¥Ñ¥±¥Ã¥È¤ÎÁ÷¼õ¿®¤Ë5060È֥ݡ¼¥È¤òÍѤ¤¤ë¡£SIP¤Î¥Ý¡¼¥È¤Ï¡¢RFC¤Ë5060ÈÖ¤òÍѤ¤¤ë¤³¤È¤¬¶¯¤¯¿ä¾©¤µ +¤ì¤Æ¤¤¤ë¡£¤è¤Ã¤Æ¡¢²¿¤ò¤·¤¿¤¤¤Î¤«¤òÌÀ³Î¤ËÍý²ò¤·¤Æ¤¤¤ë¤È¤­¤ò½ü¤¤¤Æ¤Ï¡¢¤³¤ì¤òÊѹ¹¤¹¤Ù¤­¤Ç¤Ï¤Ê¤¤¡£ +\layout Itemize + +SIP¤ÎÅÐÏ¿¤Ë¤¹¤ë - ¥ê¥â¡¼¥È¤ÎSIP¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤·¤¿¤¤¤È¤­¤Ë¤Ï¡¢¤³¤Î¥Ü¥¿¥ó¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£SIP¥µ¡¼¥Ð¡¼¤Î¥µ¡¼¥Ó¥¹¤Ë¤Ï¡¢Å¾Á÷¤ä¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤¬¤¢ +¤ë¡£¾Ü¤·¤¯¤Ï¡¢¡Ö¥ê¥â¡¼¥È¤Î¥µ¡¼¥Ð¡¼¤ËÀܳ¤¹¤ë¡×¤ÎÀá¤ò»²¾È¤µ¤ì¤¿¤¤¡£ +\layout Subsection + + +\begin_inset LatexCommand \label{paramcodec} + +\end_inset + +¥³¡¼¥Ç¥Ã¥¯ +\layout Standard + +¥³¡¼¥Ç¥Ã¥¯¤È¤Ï¡¢ÆÃ¤Ë²»À¼¥Ç¡¼¥¿¤Î°µ½Ì¤Î¤¿¤á¤ËÀ߷פµ¤ì¤¿¥¢¥ë¥´¥ê¥º¥à¤Î¤³¤È¤ò¸À¤¦¡£Î㤨¤Ð¡¢16bit/8000Hz¤Î¥Ç¥¸¥¿¥ë²½¤µ¤ì¤¿²»À¼¤È¸À¤¨¤Ð¡¢128kbit/ +ÉäΥǡ¼¥¿¤Îή¤ì¤òɽ¤·¤Æ¤¤¤ë¡£GSM¥Ü¥³¡¼¥À¡¼¤ò»ÈÍѤ¹¤ë¤È¡¢¤³¤ì¤Ï13bit kbit/Éä˽̾®¤µ¤ì¤ë¡£ +\layout Itemize + +¥³¡¼¥Ç¥Ã¥¯¤ÎÁªÂò - Linphone¤Ï¿ô¼ïÎà¤Î¥³¡¼¥Ç¥Ã¥¯¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¡£ ¥³¡¼¥Ç¥Ã¥¯¤Î¥ê¥¹¥È¤Î²¼Éô¤Ë¤¢¤ë¥Ü¥¿¥ó¤ò»È¤¦¤È¡¢»È¤¤¤¿¤¤½çÈÖ¤Ëʤ٤뤳¤È¤¬¤Ç¤­¤ë¡£ +¤À¤¬¡¢¥Í¥Ã¥È¥ï¡¼¥¯Àܳ¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ¤Ï(¥Í¥Ã¥È¥ï¡¼¥¯¤ÎÀá¤ò»²¾È)¡¢»È¤¨¤Ê¤¤¥³¡¼¥Ç¥Ã¥¯¤Î¼ïÎà¤â¡¢»ÈÍѤ¹¤ë¤«¤É¤¦¤«¤ò·èÄꤹ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£ +\layout Subsection + + +\begin_inset LatexCommand \label{paramaudio} + +\end_inset + +¥ª¡¼¥Ç¥£¥ª¥Ñ¥é¥á¡¼¥¿¡¼ +\layout Standard + +¤³¤ÎÀá¤Ç¤Ï¡¢²»À¼µ»½Ñ¤Ë´Ø¤¹¤ë¥Ñ¥é¥á¡¼¥¿¡¼¤ò²òÀ⤹¤ë¡£ +\layout Itemize + +¥É¥é¥¤¥Ð¤ÎÁªÂò - Linux¤Ç¤Ï¡¢OSS(¥«¡¼¥Í¥ë¥É¥é¥¤¥Ð¡¼¤È¤â¸Æ¤Ð¤ì¤ë)¤ÈALSA¤È¡¢°Û¤Ê¤ë2¼ïÎà¤Î¥µ¥¦¥ó¥É¥«¡¼¥É¥é¥¤¥Ð¤ò»ÈÍѤ¹¤ë¤³¤È¤¬¤Ç¤­¤ë¤¬¡¢ALSA¥É +¥é¥¤¥Ð¤ÏALSA¥é¥¤¥Ö¥é¥ê¤òÄ̤¹¤³¤È¤Ç¡¢¤µ¤é¤Ê ¤ë¥Ñ¥Õ¥©¡¼¥Þ¥ó¥¹¤òȯ´ø¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢ALSA¥É¥é¥¤¥Ð¡¼(snd_*¤Ç»Ï¤Þ¤ë̾Á°¤Ç¤¢¤ë)¤ò»ÈÍѤ·¤Æ +¤¤¤ë¾ì¹ç¤Ï¡¢ALSA¥â¡¼¥É¤òÁªÂò¤¹¤ë¤Î¤¬¤è¤¤¡£Ê¬¤«¤é¤Ê¤±¤ì¤Ð¡¢OSS¤òÁªÂò¤¹¤ë¡£ +\layout Itemize + +Auto-kill¥ª¥×¥·¥ç¥ó - ¤³¤Î¥ª¥×¥·¥ç¥ó¤ò»È¤¦¤È¡¢linphone¤Ï¥µ¥¦¥ó¥É¥Ç¡¼¥â¥ó(esd¤Èartsd)¤òÄä»ß¤·¤è¤¦¤È¤¹¤ë¡£¤³¤ì¤Ï¡¢¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹ +¤Ë¹±µ×Ū¤Ê¼è¤ê³°¤»¤Ê¤¤¥í¥Ã¥¯¤ò¤«¤±¤Æ¤·¤Þ¤¤¡¢Linphone¤¬É¬ÍפȤ·¤Æ¤¤¤ë¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò¥ª¡¼¥×¥ó¤µ¤»¤Ê¤¤¤è¤¦¤Ë¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡¢¤³¤Î¥ª¥×¥·¥ç¥ó¤Ï¡¢¥ª¥ó¤Ë¤· +¤Æ¤ª¤¯¤³¤È¤ò¿ä¾©¤¹¤ë¡£ +\layout Section + +ÅÅÏÃÄ¢ +\layout Standard + +ÅÅÏÃÄ¢(conection¤Î¥á¥Ë¥å¡¼¤ÎÃæ¤Ë¤¢¤ë)¤ò»È¤¦¤È¡¢SIP¥¢¥É¥ì¥¹¤òµ­²±¤È¸Æ½Ð¤·¤¬¤Ç¤­¤ë¡£SIP¥¢¥É¥ì¥¹¤Ï¡¢sip:¥æ¡¼¥¶¡¼Ì¾@¥É¥á¥¤¥ó̾¤Î·Á¼°¤Ç¤¢¤ë¡£¤Þ +¤¿¡¢¼«Ê¬¤¬Ê¬¤«¤ê¤ä¤¹¤¯¤¹¤ë¤¿¤á¤Ë¡¢É½¼¨¤µ¤ì¤ë̾Á°¤òÄɲ乤뤳¤È¤â¤Ç¤­¤ë¡£SIP¥¢¥É¥ì¥¹¤ò¸Æ¤Ó½Ð¤¹¤Ë¤Ï¡¢¥¢¥É¥ì¥¹¤Î¥ê¥¹¥È¤«¤éÁªÂò¤·¡¢¡ÖOK¡×¤Î¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë +¡£¤¹¤ë¤È¡¢ÁªÂò¤·¤¿¥¢¥É¥ì¥¹¤¬¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤Ë¸½¤ì¤ë¤Î¤¬³Îǧ¤Ç¤­¤ë¤À¤í¤¦¡£¸å¤Ï¡¢ÅÅÏäò¤«¤±¤ë¤¿¤á¤Ë¡ÖÅÅÏäò¤«¤±¤ë¡×¤Î¥Ü¥¿¥ó¤ò²¡¤»¤Ð¤è¤¤¤À¤±¤Ç¤¢¤ë¡£ +\layout Section + +SIP¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤ë +\layout Standard + +¥ê¥â¡¼¥È¤ÎSIP¥µ¡¼¥Ð¡¼¤Î¥µ¡¼¥Ó¥¹¤ËÅÐÏ¿¤¹¤ë¤³¤È¤â²Äǽ¤Ç¤¢¤ë¡£¤³¤Î¤è¤¦¤Ê¥µ¡¼¥Ó¥¹¤Ë¤Ï¡¢°Ê²¼¤Î¤è¤¦¤Ê¤â¤Î¤¬¤¢¤ë¡£ +\layout Itemize + +žÁ÷ - Linphon¤Ï¡¢¥µ¡¼¥Ð¡¼¤Ë¤Î¤è¤¦¤ÊSIP¥¢¥«¥¦¥ó¥È¤òºîÀ®¤¹¤ë¤è¤¦Í×ÀÁ¤¹¤ë¡£Î㤨¤Ð¡¢56k¤Î¥â¥Ç¥à +¤ò»È¤Ã¤ÆÃ±½ã¤Ë¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ËÀܳ¤·¤Æ¤¤¤ë¾ì¹ç¡¢¤¢¤Ê¤¿¤ÎIP¥¢¥É¥ì¥¹¤ÏÀÅŪ¤Ç¤Ï¤Ê¤¯¡¢¥Í¡¼¥à¥µ¡¼¥Ð¡¼¤ËÃΤé¤ì¤Æ¤¤¤ë¥Û¥¹¥È̾¤â»ý¤Ã¤Æ¤¤¤Ê¤¤¡£¤³¤ì¤Ç¤Ï¡¢Í§Ã£¤Ï¤¢¤Ê¤¿¤¬ +IP¥¢¥É¥ì¥¹¤òÄÌÃΤ¹¤ë¥á¡¼¥ë¤òÁ÷¤é¤Ê¤¤¸Â¤ê¡¢¤¢¤Ê¤¿¤ËÏ¢Íí¤ò¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£Îã¤È¤·¤Æ¡¢¤ËÅÐÏ¿¤ò¹Ô¤¦¤Î¤Ï´Êñ +¤Ç¤¢¤ë¡£¤¢¤Ê¤¿¤Î¥æ¡¼¥¶¡¼Ì¾¤Ï¡Öbob¡×¤À¤È¤¹¤ë¡£¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤ëºÝ¤Ë¡¢Linphone¤Ï¤¢¤Ê¤¿¤ÎIP¥¢¥É¥ì¥¹¤ò¥µ¡¼¥Ð¡¼¤ËÁ÷¿®¤·¡¢¥¢¥«¥¦¥ó¥È¡Ösip:bob@e +xample_registrar.com¡×¤¬ºîÀ®¤µ¤ì¤ë¡£¤½¤¦¤¹¤ë¤È¡¢¤¢¤Ê¤¿¤Îͧã¤Î¥¸¥à¤Ï¡¢¤È¤¤¤¦¥¢¥É¥ì +¥¹¤ËÅÅÏäò¤«¤±¤ë¤³¤È¤¬¤Ç¤­¤ë¡£ÅöÁ³¤Î¤³¤È¤Ê¤¬¤é¡¢ +\begin_inset Quotes eld +\end_inset + +example_registar.com +\begin_inset Quotes erd +\end_inset + +¤Ï¡¢¥¦¥§¥ë¥Î¥ó¡¦¥É¥á¥¤¥ó¥Í¡¼¥à¤Ç¤¢¤ë¡£¼¡¤Ë¡¢¥¸¥à¤ÎLinphone¤Ï¥Ü¥Ö¤Î³Î¼Â¤Ê¥í¥±¡¼¥·¥ç¥ó¤ò¼¨¤¹Å¾Á÷¥á¥Ã¥»¡¼¥¸¤ò¼õ¤±¼è¤ë¡£¤½¤¦¤·¤Æ¡¢¥Ü¥Ö¤Î²È¤Ç¥Ù¥ë¤¬ÌĤë¤Î¤Ç¤¢ +¤ë¡£ +\layout Itemize + +¥×¥í¥¯¥· - ¤³¤ì¤â¡¢Å¾Á÷¥á¥Ã¥»¡¼¥¸¤¬¥¸¥à¤ÎÅÅÏäËÁ÷¿®¤µ¤ì¤Ê¤¤¤³¤È¤ò¤Î¤¾¤±¤Ð¡¢Æ±Íͤθ¶Íý¤Ç¤¢¤ë¡£¤½¤ÎÂå¤ï¤ê¤Ë¡¢¥×¥í¥¯¥·¤Ï¥Ü¥Ö¤ÎLinphone¤Þ¤Ç¥À¥¤¥ì¥¯¥È¤Êž +Á÷¤ò¹Ô¤¦¡£ +\layout Standard + +¤³¤Î¤è¤¦¤ÊÅÐÏ¿¤Ï¡¢¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤Ë¤ª¤¤¤Æ¤âƱÍͤ˹Ԥï¤ì¤ë¡£¤³¤ì¤Ï¡¢Linphone¤ò¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤ÎÃæ¤Ç»È¤¦¤È¤­¤ËÍ­¸ú¤Ç¤¢¤ë¡£¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥· +¤Ï¡¢¥×¥é¥¤¥Ù¡¼¥È¥µ¥Ö¥Í¥Ã¥È¤Ë¤¢¤ëHTTP¥×¥í¥¯¥·¤ÈƱÍͤÎÌò³ä¤ò²Ì¤¿¤¹¡£³°Éô¤Ø¤Î²ñÏäϥ¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤¬°·¤¤¡¢¥Í¥Ã¥È¥ï¡¼¥¯³°¤Ë¤¤¤ë¤È»×¤ï¤ì¤ë¿Í¤Ø¤Î²ñÏäΞÁ÷ +¤ÎǤ¤òÉ餦¡£ +\layout Standard + +ÅÐÏ¿¥µ¡¼¥Ð¡¼¤òLinphone¤Ç»È¤¦¤Ë¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤«¤éSIP¤Î¥¿¥Ö¤òÁªÂò¤·¡¢¡ÖSIP¥¢¥É¥ì¥¹¤òÅÐÏ¿¤¹¤ë¡×¤Î¥Ü¥Ã¥¯¥¹¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ÅÐÏ¿¤¹¤ë¥¢¥É¥ì¥¹¤ò +ŬÀڤʥե£¡¼¥ë¥É¤ËÆþÎϤ·¤¿¤é¡¢¼¡¤Ë¡¢Å¾Á÷¤«¥×¥í¥¯¥·¤«¡¢Âбþ¤¹¤ë¥Ü¥Ã¥¯¥¹¤ò¥Á¥§¥Ã¥¯¤·¡¢ÅÐÏ¿¤òÍ׵᤹¤ë¥µ¡¼¥Ó¥¹¤Î¥¿¥¤¥×¤òÁªÂò¤¹¤ë¡£¤Þ¤¿¡¢³°Éô¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤Ø²ñÏäòÆ© +²á¤µ¤»¤ë¤¿¤á¤ÎÅÐÏ¿¥µ¡¼¥Ð¡¼¤¬É¬ÍפʤȤ­¤Ë¤Ï¡¢¡Ö¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤È¤·¤Æ»È¤¦¡×¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ +\layout Standard + +ºÇ¸å¤Ë¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÎOK¥Ü¥¿¥ó¤ò²¡¤¹¤È¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÏÊĤ¸¤é¤ì¡¢¤¿¤À¤Á¤ËÅÐÏ¿¥µ¡¼¥Ð¡¼¤Ë¤¢¤Ê¤¿¤ÎÀµ³Î¤Ê¾ì½ê¤òÃΤ餻¤ë¤¿¤á¤Î¸ò¾Ä¤¬»Ï¤Þ¤ë¡£Linph +one¤ò¥·¥ã¥Ã¥È¥À¥¦¥ó¤¹¤ë¤È¤­¤Ë¤Ï¡¢ÅÐÏ¿¥µ¡¼¥Ð¡¼¤«¤é¤¢¤Ê¤¿¤Î¾ì½ê¤ÎÅÐÏ¿¤ò²ò½ü¤¹¤ë¤¿¤á¡¢¿ôÉô֤«¤«¤ë¡£ +\layout Standard + +¥Ñ¥Ö¥ê¥Ã¥¯¤ÊÅÐÏ¿¥µ¡¼¥Ð¡¼¤Î¥ê¥¹¥È¤Ï¡¢°Ê²¼¤Ë·ÇºÜ¤µ¤ì¤Æ¤¤¤ë¡£ +\begin_inset LatexCommand \url[http://www.cs.columbia.edu/~hgs/sip/servers.html]{http://www.cs.columbia.edu/~hgs/sip/servers.html} + +\end_inset + + +\layout Standard + +¤À¤¬¡¢»Äǰ¤Ê¤³¤È¤Ë¡¢¤³¤ì¤é¤Î¥µ¡¼¥Ð¡¼¤Î¿¤¯¤Ï¤â¤¦Æ°¤¤¤Æ¤¤¤Ê¤¤¡£¤ª¤½¤é¤¯¡¢¶áº¢¤ÎÅŵ¤ÄÌ¿®¶È³¦¤Î´íµ¡¤Ë¤è¤ë¤â¤Î¤Ç¤¢¤í¤¦¡£Â¾¤ÎɬÍפȤµ¤ì¤ëǧ¾ÚÊýË¡¤Ï¡¢¸½ºßLinpho +ne¤Ç¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¡£ +\layout Standard + +̵ÍѤʼê´Ö¤òÈò¤±¤¿¤¤¤È¤­¤Ë¤Ï¡¢»ÈÍѲÄǽ¤Êưºî¤·¤Æ¤¤¤ë¥Ñ¥Ö¥ê¥Ã¥¯¤ÊSIP¥µ¡¼¥Ð¡¼¤Î¥ê¥¹¥È¤¬¡¢Linphoe¤Î°ÊÁ°¤ÎWEB¥µ¥¤¥È¤Î¥ê¥¹¥È¤¬ +\begin_inset LatexCommand \url[http://simon.morlat.free.fr/english/servers.html]{http://simon.morlat.free.fr/english/servers.html} + +\end_inset + +¤Ç»²¾È¤Ç¤­¤ë¡£ +\layout Section + +¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤ÎÆâ¦¤Ç +\layout Standard + +¸½ºß¤Ç¤Ï¡¢SIP¥×¥í¥¯¥·¤òÍѤ¤¤ë¤³¤È¤Ç¡¢Linphone¤Ï¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤ÎÆâ¦¤ÇÍøÍѲÄǽ¤Ç¤¢¤ë¡£SIP¥µ¡¼¥Ð¡¼¤Ï¡¢¥×¥é¥¤¥Ù¡¼¥È¥Í¥Ã¥È¥ï¡¼¥¯¤«¤é¤Î²ñÏäò³°Éô¤Î +¥Í¥Ã¥È¥ï¡¼¥¯¤ØÅ¾Á÷¤¹¤ëǤ¤òÉ餦¡£oSIP¥é¥¤¥Ö¥é¥ê¤òÍøÍѤ·¤¿SIP¥×¥í¥¯¥·¤Ï¡¢ +\begin_inset LatexCommand \url[http://osipproxy.sourceforge.net]{http://osipproxy.sourceforge.net} + +\end_inset + +¤Ç³«È¯¤µ¤ì¤Æ¤¤¤ë¡£ +\layout Standard + +SIP¤ÎÀá¤Î¡¢¡ÖSIP¤ËÅÐÏ¿¤¹¤ë¡×¤Î¹àÌܤò»²¹Í¤Ë¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÇÍѤ¤¤ëSIP¥×¥í¥¯¥·¤ò»ØÄꤷ¤ÆÍߤ·¤¤¡£ÀßÄꤹ¤ë¤Ë¤Ï¡¢SIP¥×¥í¥¯¥·¤Î¥¢¥É¥ì¥¹¤òÆþÎϤ·¡¢¡Ö +¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤È¤·¤ÆÅÐÏ¿¤¹¤ë¡×¤Î¥Ü¥¿¥ó¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ +\layout Standard + +¤Ê¤ª¡¢SIP¥×¥í¥¯¥·¤¬É¬Íפʤ¤¾ì¹ç¤â¤¢¤ë¡£¥Ñ¥Ö¥ê¥Ã¥¯¥¢¥É¥ì¥¹¤ò»ý¤Ã¤Æ¤¤¤ë¥Í¥Ã¥È¥ï¡¼¥¯²¼¤Ë¤¢¤Ê¤¿¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤¬¤¢¤ê¡¢¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤Ï³°Éô¥Í¥Ã¥È¥ï¡¼¥¯¤«¤é¤Î +¥Ñ¥±¥Ã¥È¤ÎÁ÷¼õ¿®¤ò¥Õ¥£¥ë¥¿¡¼¤¹¤ë¤À¤±¤Î¾ì¹ç¤Ç¤¢¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï¡¢¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤Î¥Þ¥·¥ó¤ÎSIP¤ÈRTP¤Î¥Ý¡¼¥È¤ò¥ª¡¼¥×¥ó¤¹¤ë¤À¤±¤Ç¤è¤¤¡£SIP¥Ý¡¼¥È¤Ï¥×¥í¥Ñ +¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÎSIP¤Î¥¿¥Ö¤Ë¡¢RTP¥Ý¡¼¥È¤Ï¡¢RTP¥Ý¡¼¥È¤ÏRTP¤Î¥¿¥Ö¤Ë¤¢¤ë¡£Î¾¼Ô¤È¤â¤ËÊѹ¹²Äǽ¤Ç¤¢¤ë¤¬¡¢SIP¥Ý¡¼¥È(5060ÈÖ)¤Ï¡¢Êѹ¹¤·¤Ê¤¤¤Ç¤ª¤¯¤³¤È +¤¬¶¯¤¯¿ä¾©¤µ¤ì¤ë¡£ +\layout Section + +º¤¤Ã¤¿¤È¤­¤Ë¤Ï +\layout Subsection + +Àܳ¾å¤Ë¤ª¤±¤ëÌäÂê +\layout Quotation + +»ä¤Ï¡¢Í§¿Í¤ËÅÅÏäò¤«¤±¤è¤¦¤È¤·¤¿¤À¤¬¡¢¤Ê¤Ë¤âµ¯¤­¤Ê¤¤¡£¥Ù¥ë¤âÌĤé¤Ê¤¤¡¢¤Þ¤Ã¤¿¤¯²¿¤âµ¯¤³¤é¤Ê¤¤¡£ +\layout Standard + +Linphone¤¬»ÈÍѤ·¤Æ¤¤¤ë¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ØÀܳ¤·¤Æ¤¤¤ë¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹(¤Þ¤¿¤Ï¡¢²ñÏ䬽ФƤ¤¤¯¤Ù¤­¥Í¥Ã¥È¥ï¡¼¥¯)¤ò¸¡¾Ú¤·¤Æ¤ß¤ë¤Ù¤­¤Ç¤¢¤í¤¦¡£¥×¥í +¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤Î¡¢¥Í¥Ã¥È¥ï¡¼¥¯¥¿¥Ö¤«¤é¡¢Àµ¤·¤¤¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ó¤Ç¤ß¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£ +\layout Standard + +¤¢¤ë¤¤¤Ï¡¢¤¢¤Ê¤¿¤¬Àܳ¤·¤è¤¦¤È¤·¤Æ¤¤¤ë¿Í¤¬¡¢¸½ºß·ÐÏ©¤¬Àܳ¤Ç¤­¤Ê¤¤¾õ¶·¤Ë¤¢¤ë¤Î¤«¤âÃΤì¤Ê¤¤¡Ä¡Ä¡£ +\layout Subsection + +²»À¼¤Ë¤ª¤±¤ëÌäÂê +\layout Quotation + +Linphone¤Ï¡¢¥ê¥â¡¼¥È¤ÎSIP URL¤ËÀܳ¤·¤Æ¤¤¤ë¤è¤¦¤Ç¡¢¥Ù¥ë¤ÏÌĤäƤ¤¤ë¤è¤¦¤À¡£¤±¤ì¤É¤â¡¢Áê¼ê¤¬ÅÅÏä˽Ф¿¤È¤­¤Ë¤Ï²¿¤âµ¯¤³¤é¤º¡¢¤ª¸ß¤¤¤ÎÀ¼¤¬Ê¹¤³¤¨¤Ê¤¤ +¡£ +\layout Itemize + +ÂçÄñ¤Î¿Í¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤«¤é¡¢Àµ¤·¤¤¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ó¤Ç¤¤¤Ê¤¤¤¿¤á¤Ë¡¢ÌäÂê¤òÀ¸¤¸¤µ¤»¤Æ¤·¤Þ¤¦¡£¥À¥¤¥ä¥ë¥¢¥Ã¥×Àܳ¤Ç¤Ï¡¢¡Öppp0¡×¤Ë¤Ê¤ë +¤Ï¤º¤Ç¤¢¤ë¡£¡Ö\i \"{} +lo¡×¤Ï¡¢¥Æ¥¹¥ÈÍѤˡ¢sipomatic¤À¤±¤Ë»ÈÍѤµ¤ì¤ë¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ç¤¢¤ë¤³¤È¤ËÃí°Õ¤µ¤ì¤¿¤¤¡£¤½¤Î¾¤Î¾ì¹ç¤Ç¤Ï µ¡Ç½¤·¤Ê¤¤¡£ +\layout Itemize + +¤Þ¤º¤Ï¡¢Á÷Ïò»Î̤ȼõÏò»Î̤ò¾å¤²¤Æ¤ß¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£ +\layout Itemize + +²»À¼¤¬¤È¤®¤ì¤È¤®¤ì¤Ë¤Ê¤ë¾ì¹ç¤Ï¡¢¤³¤ì¤ò²óÈò¤¹¤ë¤¿¤á¤Ë¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÎRTP¥¿¥Ö¤Î¡Ö¥Ð¥Ã¥Õ¥¡¤¹¤ë¥ß¥êÉáפÎÃͤòÂ礭¤¯¤·¤Æ¤ß¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£¤·¤«¤·¡¢¤³¤ì¤Ï +ÄÌ¿®¤ÎÃÙ±ä¤òÁýÂ礵¤»¤ë¡£ +\layout Itemize + +Linphone¤¬¡¢¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò¥ª¡¼¥×¥ó¤Ç¤­¤Ê¤¤¤È¤­¤Ë¤Ï¡¢/dev/dsp¤Î¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ò³Îǧ¤·¡¢¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò»ÈÍѤ¹¤ë¤¹¤Ù¤Æ¤Î¥×¥í¥°¥é¥à(xm +ms kaimanÅù)¤òÄä»ß¤¹¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£ +\layout Itemize + +ALSA¥É¥é¥¤¥Ð¡¼¤ò»ÈÍѤ¹¤ë( +\begin_inset LatexCommand \url[http://www.alsa-project.org]{http://www.alsa-project.org} + +\end_inset + +¤ò»²¾È¤µ¤ì¤¿¤¤)¡£ÂçÄñ¤Î¥Ç¥£¥¹¥È¥ê¥Ó¥å¡¼¥¸¥ç¥ó¤Ï¡¢¤Þ¤À¸Å¤¤¥«¡¼¥Í¥ë¸øÇ§¤Î¥É¥é¥¤¥Ð¡¼¤ò»ÈÍѤ·¤Æ¤¤¤ë¤¬¡¢¤³¤ì¤ÏÂ礭¤ÊÃÙ±ä¤È¿¤¯¤Î¥Ð¥°¤ò´Þ¤ó¤Ç¤¤¤ë¡£Linphone¤Ï +¡¢ALSA¥É¥é¥¤¥Ð¡¼¤ò¥¤¥ó¥¹¥È¡¼¥ë¤·¤¿¸å¤Î¥ê¥³¥ó¥Ñ¥¤¥ë¤òɬÍפȤ·¤Ê¤¤¤³¤È¡¢¤Þ¤¿¡¢¥ª¡¼¥Ç¥£¥ª¤ÎÀá¤Î¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤«¤é¤ÎALSA¥â¡¼¥É¤Ø¤ÎÊѹ¹¤Ïɬ¿Ü¤Ç¤Ï¤Ê¤¤¤³ +¤È¤â½Ò¤Ù¤Æ¤ª¤³¤¦¡£ +\layout Section + +¥Ð¥°Êó¹ð¤ÈÄó°Æ +\layout Standard + +¤Þ¤º¤Ï¡¢Linphone¤Î¥Û¡¼¥à¥Ú¡¼¥¸ +\begin_inset LatexCommand \url[http://www.linphone.org]{http://www.linphone.org} + +\end_inset + +¤«¤é¡¢ºÇ¿·¤ÎLinphone¤ò»ÈÍѤ·¤Æ¤¤¤ë¤«¤ò³Îǧ¤·¤ÆÍߤ·¤¤¡£ +\layout Standard + +¤â¤·¡¢Linphone¤¬¥¯¥é¥Ã¥·¥å¤·¤¿¤È¤­¤Ë¤Ï¡¢¥Ð¥°¥ì¥Ý¡¼¥È¤òľÀÜbugs@linphone.org¤Þ¤ÇÁ÷¤Ã¤ÆÍߤ·¤¤¡£¤â¤·¡¢¥¯¥é¥Ã¥·¥å¤Ï¤·¤Ê¤¤¤¬Linphone¤¬ +ưºî¤·¤Ê¤¤¤È¤­¤Ë¤Ï¡¢¾å¤Î¥¢¥É¥ì¥¹¤Ë¥Ð¥°¥ì¥Ý¡¼¥È¤òÁ÷¤ëÁ°¤Ë¡¢¥Þ¥Ë¥å¥¢¥ë¤ò ¤â¤¦°ìÅÙÆÉ¤ß¤«¤¨¤·¤ÆÍߤ·¤¤¡£¤â¤·¡¢²¿¤«¤òÄ󰯤·¤¿¤¤¤È¤­¤Ë¤Ï¡¢±ó褻¤º¤Ë¡¢help@lin +phone.org¤Þ¤Ç¥á¡¼¥ë¤òÁ÷¤Ã¤ÆÍߤ·¤¤¡£¤Ê¤ª¡¢¥Ó¥Ç¥ª¥µ¥Ý¡¼¥È¤È²ñµÄ¤Ï¡¢¾­Íè¤Î·×²è¤Ë¤¢¤ë¤³¤È¤ò½Ò¤Ù¤Æ¤ª¤³¤¦¡£¤Þ¤¿¡¢Linphonr¤ÎËÝÌõ¤Ë¶½Ì£¤ò»ý¤Ã¤¿¿Í¤Ï¡¢ÇÛÉÛ +¤µ¤ì¤Æ¤¤¤ëpo/linpyhone.pot¤Ë´ð¤Å¤¤¤¿xx.po¥Õ¥¡¥¤¥ë¤ò»ä¤ËÁ÷¤Ã¤ÆÍߤ·¤¤¡£¤Þ¤¿¡¢¤³¤Î¥Þ¥Ë¥å¥¢¥ë¤ò¾¤Î¸À¸ì¤ËËÝÌõ¤¹¤ë¤³¤È¤â²Äǽ¤Ç¤¢¤ë¡£¤¤¤º¤ì¤Ë¤·¤Æ¤â¡¢ +¾Ü¤·¤¤¤³¤È¤¬ÃΤꤿ¤¤¤È¤­¤Ï»ä¤ËÏ¢Íí¤·¤ÆÍߤ·¤¤¡£ +\layout Section + +ºî¼Ô +\layout Standard + +Simon MORLAT (simon.morlat@free.fr) ¤¬À½ºî¤·¤¿Éôʬ¤Ï°Ê²¼¤ÎÄ̤ê¤Ç¤¢¤ë¡£ +\layout Itemize + +¥á¥¤¥ó¥×¥í¥°¥é¥à(src) +\layout Itemize + +RTP ¥é¥¤¥Ö¥é¥ê (lprtplib) +\layout Itemize + +osipua -- osip¥¹¥¿¥Ã¥¯¤Ë´ð¤Å¤¤¤¿¥æ¡¼¥¶¡¼¥¨¡¼¥¸¥§¥ó¥È¤ÎAPI¡£oss¤ÈALSA¥É¥é¥¤¥Ð¡¼¤Î²»À¼¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¡£ +\layout Itemize + +(²»À¼) lpc10-1.5ÍѤÎwrappers, gsm and g711 ¥³¡¼¥Ç¥Ã¥¯ +\layout Standard + +Aymeric Moizard (jack@atosc.org)¤Ï¡¢ Linphone¤¬ÍøÍѤ·¤Æ¤¤¤ëosip¥¹¥¿¥Ã¥¯¤òÀ½ºî¤·¤¿¡£ +\layout Standard + +GSM¥é¥¤¥Ö¥é¥ê¤Ï¡¢Jutta Degener¤ÈCarsten Bormann(Technische Universitaet Berlin)¤Ë¤è¤Ã¤Æ½ñ¤«¤ì¤¿¡£ +\layout Standard + +The LPC10-1.5 ¥é¥¤¥Ö¥é¥ê¤Ï¡¢Andy Fingerhut(Applied Research Laboratory)¤Ë¤è¤Ã¤Æ½ñ¤«¤ì¤¿¡£ + <-- ¤³¤ÎÉôʬ¤Ï¥¹¥Ú¡¼¥¹¤ÎÅÔ¹ç¤Ë¤è¤ê¾Êά²Äǽ¤Ç¤¢¤ë¡£ Washington University, Campus Box 1045/Bryan + 509 ¥¹¥Ú¡¼¥¹¤Ë¸Â¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢¤³¤³¤«¤é¡£One Brookings Drive Saint Louis, MO 63130-4899 jaf@arl.wu +stl.edu http://www.arl.wustl.edu/~jaf/¤µ¤é¤Ê¤ë¾ðÊó¤Ï¡¢gsmlib¤Èlpc10-1.5¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Î¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤ò»²¾È¤µ¤ì¤¿¤¤ +¡£ +\layout Standard + +Pablo Marcelo Moia -- ¥¢¥¤¥³¥óÀ½ºî +\layout Section + +¼Õ¼­ +\layout Standard + +GTK¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¥Ó¥ë¥À¡¼¤ÎDaemon Chaplin¤Ë´¶¼Õ¤ò¡£ +\layout Standard + +ÃøÌÀ¤ÊoSIP¥é¥¤¥Ö¥é¥ê¡¼¤ÎAymeric Moizard¤Ë´¶¼Õ¤ò¡£ +\layout Standard + +LPC10-1.5¤ÈGSM¥³¡¼¥É¤Îºî¼Ô¤Ë´¶¼Õ¤ò¡£ +\layout Standard + +RPM¤òÄ󶡤·¤Æ¤¯¤ì¤¿¡¢Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com )¤Ë´¶¼Õ¤ò¡£ +\layout Standard + +Linphone¤ËÁÇŨ¤Ê¥¢¥¤¥³¥ó¤òÄ󶡤·¤Æ¤¯¤ì¤¿¡¢Pablo Marcelo Moia¤Ë´¶¼Õ¤ò¡£ +\layout Standard + + +\begin_inset LatexCommand \tableofcontents{} + +\end_inset + + +\the_end diff --git a/linphone/share/ja/manual.sgml b/linphone/share/ja/manual.sgml new file mode 100644 index 000000000..f36f0ebb6 --- /dev/null +++ b/linphone/share/ja/manual.sgml @@ -0,0 +1,480 @@ + + +
+ + + + LINPHONE¥æ¡¼¥¶¡¼¥Þ¥Ë¥å¥¢¥ë + + + Simon Morlat (simon.morlat@linphone.org) + Ìõ¡§»³¸ýÁ±Ìé(yushiya@anet.ne.jp) + + + 11-13-2001 + + + + + ¤Ï¤¸¤á¤Ë + + + Linphone¤Ï¡¢¥·¥ó¥×¥ë¤Ê¥¤¥ó¥¿¡¼¥Í¥Ã¥ÈÅÅÏäǤ¢¤ê¡¢Æó¼Ô´Ö¤ÎÄÌÏäò¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ê¤É¤ÎIPÌÖ¤òÄ̤¸¤Æ²Äǽ¤Ë¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£Linphone¤òµ¯Æ°¤¹¤ë¤Ë¤Ï°Ê²¼¤Î¤â¤Î¤¬É¬ÍפȤʤ롣 + + + + + Linux(BSD¤Î¤è¤¦¤Ê¾¤ÎUNIX¤Ç¤âµ¯Æ°¤¹¤ë¤À¤í¤¦¤¬¡¢Linux´Ä¶­¤Û¤É¾¤Î´Ä¶­¤Ï¥Æ¥¹¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¡£) + + + + + gnome1.2°Ê¾å¤¬¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë¤³¤È¡£É¬¤º¤·¤âµ¯Æ°¤·¤Æ¤¤¤ëɬÍפϤʤ¤¡£ + + + + + ¥Ø¥Ã¥É¥Û¥ó¤«¥¹¥Ô¡¼¥«¡¼¡£ + + + + + ¥µ¥¦¥ó¥É¥«¡¼¥É¤¬Àµ¤·¤¯ÀßÄꤵ¤ì¤Æ¤¤¤ë¤³¤È¡£ + + + + + ¥Þ¥¤¥¯¥í¥Õ¥©¥ó + + + + + ¥â¥Ç¥à¤ä¥¤¡¼¥µ¥Í¥Ã¥ÈÅù¤òÍѤ¤¤¿¡¢¥Í¥Ã¥È¥ï¡¼¥¯(¥¤¥ó¥¿¡¼¥Í¥Ã¥ÈÅù)¤Ø¤ÎÀܳ¡£ + + + + + ¤Ê¤ª¡¢Linphone¤òµ¯Æ°¤¹¤ëÁ°¤Ë¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò»ÈÍѤ¹¤ë¤¹¤Ù¤Æ¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤ò½ªÎ»¤·¤Æ¤ª¤¯¤Î¤¬¤è¤¤¤À¤í¤¦¡£ + + + Linphone¤Ï¥Õ¥ê¡¼¥¦¥§¥¢¤Ç¤¢¤ê¡¢GNU Public Licence¤Ë½¾¤Ã¤ÆÇÛÉÛ¤µ¤ì¤ë¡£ + + + ·Ù¹ð - Åö¥½¥Õ¥È¥¦¥§¥¢¤ÏÊݾڤʤ·¤ËÄ󶡤µ¤ì¤ë¤â¤Î¤Ç¤¢¤ë¡£¾Ü¤·¤¯¤ÏCOPYING¥Õ¥¡¥¤¥ë¤ò»²¾È¤µ¤ì¤¿¤¤¡£¤Ê¤ª¡¢Linphone¤Ï°Å¹æ²½¤òÍѤ¤¤Ê¤¤¤¿¤á¡¢°­°Õ¤¢¤ë¿Íʪ¤¬Íưפ˲»À¼¾ðÊó¤ò½¦¤¦¤³¤È¤¬¤Ç¤­¤ë¡£¤Ä¤Þ¤ê¡¢Linphone¤ÏÈëÌ©¤Î²ñÏäËÍѤ¤¤ë¤Ù¤­¤Ç¤Ï¤Ê¤¤¡£¤Þ¤¿¡¢Linphone¤Ï¥ë¡¼¥È¸¢¸Â¤Çµ¯Æ°¤·¤Ê¤¤¿ä¾©¤¹¤ë¡£ + + + + + Linphone¤Îµ¯Æ° + + + Linphone¤Ï»°¤Ä¤ÎÊýË¡¤Çµ¯Æ°¤Ç¤­¤ë¡£ + + + + + Ä̾ï¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤È¤·¤Æ - Linphone¤Ï¡¢gnome¥á¥Ë¥å¡¼¤ÎÃæ¤Î¥Í¥Ã¥È¥ï¡¼¥¯¥µ¥Ö¥á¥Ë¥å¡¼¤Ë¸½¤ì¤ë¡£¤â¤·¡¢gnome¤òµ¯Æ°¤·¤Æ¤Ê¤¤¤Î¤Ç¤¢¤ì¤Ð¡¢Î㤨¤Ð¥¿¡¼¥ß¥Ê¥ë¤Ë“linphone”¤È¥¿¥¤¥×¤¹¤ë¤³¤È¤Ç¼Â¹Ô¤Ç¤­¤ë¡£Linphone¤¬µ¯Æ°¤·¤Æ¤¤¤Ê¤¤¤È¤­¤Ï¡¢ÅÅÏäò¼õ¤±¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£ + + + + + gnome¥¢¥×¥ì¥Ã¥È¤È¤·¤Æ - gnome¥Ñ¥Í¥ë¤ò±¦¥¯¥ê¥Ã¥¯¤¹¤ë¤È¡¢¥Ñ¥Í¥ë¤ËLinphone¤òÄɲ乤뤳¤È¤¬¤Ç¤­¤ë¡£Linphone¤Ï¥Í¥Ã¥È¡¼¥ï¡¼¥¯¥á¥Ë¥å¡¼¤ÎÃæ¤Ë¤¢¤ë¡£¤Ò¤Ã¤½¤ê¤È¥Ñ¥Í¥ë¤ÎÃæ¤Çµ¯Æ°¤¹¤ë¤³¤È¤Ç¡¢Linphone¤Ï¡¢¤¿¤È¤¨¥¦¥¤¥ó¥É¥¦¤¬¸½¤ì¤Æ¤¤¤Ê¤¯¤Æ¤âÅÅÏäò¼õ¤±¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤Ëɽ¼¨¤µ¤»¤¿¤¤¤È¤­¤Ë¤Ï¡¢¥¢¥×¥ì¥Ã¥È¤ò¥¯¥ê¥Ã¥¯¤¹¤ì¤Ð¤è¤¤¡£ÅÅÏ䬤«¤«¤Ã¤Æ¤­¤¿¤È¤­¤Ë¤Ï¡¢¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤¬É½¤ì¤Æ¡¢Ä̾ïÄ̤ê¤Ë¥Ù¥ë¤¬ÌĤäƤ¤¤ë¤Î¤¬Ê¹¤³¤¨¤ë¤À¤í¤¦¡£ + + + + + ¤Ò¤Ã¤½¤ê¤È¥Ç¡¼¥â¥ó¤È¤·¤Æ - ¤³¤ì¤Ï¡¢Èógnome¥æ¡¼¥¶¡¼¤Î¤¿¤á¤Î¤â¤Î¤Ç¤¢¤ë¡£Î㤨¤Ðkde¤Ç¤Ï¡¢/home/user/.kde2/AutoStart¥Ç¥£¥ì¥¯¥È¥ê¤Ë¡¢¥í¥°¥¤¥ó»þ¤Ëµ¯Æ°¤·¤¿¤¤¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î¥ê¥ó¥¯¤òŽ¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢¾å½Ò¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥Õ¥¡¥¤¥ë¥Þ¥Í¡¼¥¸¥ã¡¼¤Ç°Üư¤·¡¢±¦¥¯¥ê¥Ã¥¯¤Ç¸½¤ì¤ë¥¢¥×¥ì¥Ã¥È¤«¤é¡¢¡Ö¥ê¥ó¥¯¤ÎÄɲáפò¼Â¹Ô¤¹¤ì¤Ð¤è¤¤¡£¤Ê¤ª¡¢µ¯Æ°¤¹¤ë¥³¥Þ¥ó¥É¤Ï¡¢“ linphone -deamon”¤Ç¤¢¤ë¡£¤³¤Î¾ì¹ç¡¢Linphone¤Î¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤ò¸«¤ë¤³¤È¤Ï¤Ê¤¤¤¬¡¢É½¼¨¤µ¤»¤¿¤¤¤È¤­¤Ë¤Ï¥¿¡¼¥ß¥Ê¥ëÅù¤«¤éLinphone¤òµ¯Æ°¤µ¤»¤ë¤Î¤ÈƱÍͤ˥¿¥¤¥×¤¹¤ì¤Ð¤è¤¤¡£ + + + + + + + ÅÅÏäò¤«¤±¤ë + + + + ´ðËÜŪ¤Ê¸¶Â§ + + + ¡Ösip:¥æ¡¼¥¶¡¼Ì¾@¥Û¥¹¥È̾¡×¤Î¤è¤¦¤ÊSIP URL¤Ë¤è¤Ã¤Æ¶èÊ̤µ¤ì¤ë¡£SIP URL¤Ï¡¢Æ¬¤Î¡Ösip:¡×¤ò½ü¤±¤ÐÈó¾ï¤Ëe-mail¥¢¥É¥ì¥¹¤È»÷¤Æ¤¤¤ë¡£ + + + ¥æ¡¼¥¶¡¼Ì¾¤Ï¡¢UNIX¥Þ¥·¥ó¤Î¥í¥°¥¤¥ó¥Í¡¼¥à¤Î¤è¤¦¤Ê¤â¤Î¤Ç¡¢¥Û¥¹¥È̾¤Ï¥æ¡¼¥¶¡¼¤¬Àܳ¤¹¤ë¥Þ¥·¥ó¤Î̾Á°¤äIP¥¢¥É¥ì¥¹¤Ç¤¢¤ë¡£ + + + ¤Ê¤ª¡¢SIP¤Ï¥·¥ó¥×¥ë¤ËÀ߷פµ¤ì¤¿¿·¤·¤¤ÄÌ¿®¤Î¥×¥í¥È¥³¥ë¤Ç¤¢¤ê¡¢H323¤È¤Ï¤Þ¤Ã¤¿¤¯¸ß´¹À­¤¬¤Ê¤¤¤³¤È¤ËÃí°Õ¤µ¤ì¤¿¤¤¡£ + + + + + »ÈÍÑÎã:Æó¿Í¤Î¥æ¡¼¥¶¡¼¤¬¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ë¥â¥Ç¥à¤ÇÀܳ¤·¤Æ¤¤¤ë¤È¤­ + + + ¤³¤ì¤Ï¡¢Ã±½ã¤Ê¼ê³¤­¤Ç¤¢¤ë¡£É¬ÍפȤµ¤ì¤ë¥Í¥Ã¥È¥ï¡¼¥¯¤Ï¡¢ + + + + + 28k°Ê¾å¤Î¥â¥Ç¥à + + + + + ¤Ç¤¢¤ë¡£ + + + ¥·¥Ê¥ê¥ª¤Ï¡¢°Ê²¼¤ÎÄ̤ê¤Ç¤¢¤ë¡£ + + + + + ¥Ü¥Ö¤Ï¥È¥à¤Ë21:00¤ËÅÅÏ乤뤳¤È¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡£¥È¥à¤Ï¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ëkppp¤ägppp¤äwmdial¤Ê¤É¤ÇÀܳ¤·¤Æ¤¤¤ë¡£ + + + + + ¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ËÀܳ¤·¤¿¤é¡¢¥Ü¥Ö¤ÏLinphone¤òµ¯Æ°¤Ç¤­¤ë¡£kppp¤ägppp¤Ê¤É¤ÎÅý·×¥Ü¥Ã¥¯¥¹¤ò³«¤¤¤Æ¡¢¥Ü¥Ö¤Ï¼«Ê¬¤ÎIP¥¢¥É¥ì¥¹¤òÃΤ뤳¤È¤¬¤Ç¤­¤ë¡£(/sbin/ifconfig¤ò»È¤ï¤Ê¤¯¤Æ¤â³Îǧ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë)¡£ + + + + + ¼¡¤Ë¡¢¥È¥à¤Ï¥Ü¥Ö¤Ë¡ÖËͤÎIP¥¢¥É¥ì¥¹¤Ï¡¢xxx.xxx.xxx.xxx¤À¤è¡£¡×¤È¤¤¤¦ÆâÍÆ ¤Îe¥á¡¼¥ë¤òÁ÷¤ë¡£ + + + + + ¤½¤Î¤¹¤°¤¢¤È¤Ç¡¢¥È¥à¤Î²È¤ÎLinphone¤Î¥Ù¥ë¤¬ÌĤ롣¤½¤Î¤È¤­¡¢¥Ü¥Ö¤Ë¤â¸þ¤³¤¦¤Ç¥Ù¥ë¤¬ÌĤäƤ¤¤ë¤Î¤¬Ê¬¤«¤ë¤è¤¦¤Ë¥Ù¥ë¤Î²»¤¬Ê¹¤³¤¨¤ë¡£¤½¤³¤Ç¡¢¥È¥à¤¬ÅÅÏä˽Ф뤿¤á¤Ë¡ÖÅÅÏäò¤È¤ë¡×¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¤À¤±¤Ç¤è¤¤¡£¤½¤¦¤¹¤ì¤Ð¡¢¸ß¤¤¤Ë²ñÏ䬤Ǥ­¤ë¤Ï¤º¤Ç¤¢¤ë¡£ + + + + + ÌäÂ꤬¤¢¤Ã¤¿¤é¡¢Âè4Àá¤ÎÌäÂê¤ò»²¾È¤·¤ÆÍߤ·¤¤¡£ + + + + + ¥Æ¥¹¥È¤Î»î¹Ô - ¸½ºß(Î㤨¤Ð¿¼Ìë¤Ê¤É¤Ç)ÅÅÏäò¤«¤±¤ëͧ¿Í¤¬¤¤¤Ê¤¤¤¬¡¢Linphone¤¬ËÜÅö¤Ëư¤¤¤Æ¤¤¤ë¤«¤É¤¦¤«ÃΤꤿ¤¤¤È¤­ + + + ¥Ð¡¼¥¸¥ç¥ó3.0¤«¤é¤Ï¡¢Linphone¤Ë¤Ï¡Ösiptomatic¡×¤È¤¤¤¦¥×¥í¥°¥é¥à¤¬ÉÕ°¤·¤Æ¤¤¤ë¡£¤³¤ì¤Ï¡¢°Ê²¼¤Î¼ê½ç¤Ç»ÈÍѤǤ­¤ë¡£ + + + + + siptomatic¤ò¥¿¡¼¥ß¥Ê¥ë¤«¤éµ¯Æ°¤¹¤ë¡£siptomatic¤Ï¥°¥é¥Õ¥£¥«¥ë¥¤¥ó¥¿¡¼¥Õ¥§¥¤¥¹¤òÈ÷¤¨¤Æ¤¤¤Ê¤¤¤¬¡¢¶Ã¤«¤Ê¤¤¤ÇÍߤ·¤¤¡£Áê¸ßŪ¤Ê¤ä¤ê¤È¤ê¤ò¤¹¤ëɬÍפ¬¤Ê¤¤¤«¤é¤Ç¤¢¤ë¡£ + + + + + Linphone¤Î¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤Î¥¿¥Ö¤«¤é¡¢¡Ölo¡×¤ò¥Ç¥Õ¥©¥ë¥È¤Î¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ë·èÄꤷ¡¢Êѹ¹¤òOK¤ò¥¯¥ê¥Ã¥¯¤·¤ÆÅ¬ÍѤ¹¤ë¡£ + + + + + ¡Ösip:robot@127.0.0.1:5064¡×¤È¤¤¤¦SIP URL¤ò¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤ËÆþÎϤ¹¤ë¡£127.0.0.1¤Ï¡¢¤¢¤Ê¤¿¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤Î ¥í¡¼¥«¥ë¥¢¥É¥ì¥¹¤Ç¡¢robot¤Ïsipomatic¤ËÅÅÏäò¤«¤±¤ëºÝ¤Î̾Á°¤Ç¤¢¤ë¡£5064¥Ý¡¼¥È¤¬¡¢sipomatic¤ËÀܳ²Äǽ¤Ê¥Ý¡¼¥È¤Ç¤¢¤ë¡£Ä̾ï¤ÏÅÅÏäò¤«¤±¤ë¤Î¤Ë5060È֥ݡ¼¥È¤òÍѤ¤¤ë¤¬¡¢sipomatic¤ÏÎã³°¤Ç5064È֥ݡ¼¥È¤Çµ¯Æ°¤·¤Æ¤¤¤ë¡£¤³¤ì¤Ï¡¢Linphone¤¬¤¹¤Ç¤Ë5060È֥ݡ¼¥È(¤¹¤Ê¤ï¤Á¡¢¥Ý¡¼¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¥Ç¥Õ¥©¥ë¥È¤Î¥Ý¡¼¥È¤È¤·¤Æ)¤Çµ¯Æ°¤·¤Æ¤¤¤ë¤«¤é¤Ç¤¢¤ê¡¢Æ±¤¸¥Ý¡¼¥È¤ò»È¤¦2¤Ä¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤òƱ»þ¤ËƱ¤¸¥³¥ó¥Ô¥å¡¼¥¿¡¼¤Çµ¯Æ°¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¤«¤é¤Ç¤¢¤ë¡£ + + + + + ¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¤È¡¢¿ôÉøå¤Ësiptomatic¤¬¤¢¤Ê¤¿¤ÎÅÅÏäËÊÖÅú¤·¡¢Ã»¤¤¥¢¥Ê¥¦¥ó¥¹¤¬Ê¹¤³¤¨¤ë¤À¤í¤¦¡£ + + + + + + + + ÅÅÏäΥѥé¥á¡¼¥¿¡¼ + + + + ¥Í¥Ã¥È¥ï¡¼¥¯ + + + + + ¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Î¥ê¥¹¥È - ¤¢¤Ê¤¿¤Ï¡¢Linphone¤Ë»È¤¦¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ÖɬÍפ¬¤¢¤ë¡£¤â¤·¡¢¥¤¥ó¥¿¡¼¥Í¥Ã¥È¾å¤Î狼¤ËÏ¢Íí¤ò¤·¤¿¤¤¤Î¤Ê¤é¡¢¤¢¤Ê¤¿¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤¬¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ËÀܳ¤·¤Æ¤¤¤ë¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤Ö¤Ù¤­¤Ç¤¢¤ë¡£²¿¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤Ë¤â¤Ä¤Ê¤¬¤Ã¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¡¢¡Ölo¡×¤È¸Æ¤Ð¤ì¤ë¥í¡¼¥«¥ë¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤À¤±¤¬¥ê¥¹¥È¤Ë¸½¤ì¤ë¤À¤í¤¦¡£¤½¤ì¤Ï¡¢siptomatic¤ËÅÅÏäò¤¹¤ë¤³¤È¤À¤±¤¬¤Ç¤­¤ë¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ç¤¢¤ë¡£ + + + + + Àܳ¤Î¥¿¥¤¥× - »È¤¤¤¿¤¤¥Í¥Ã¥È¥ï¡¼¥¯¤Ø¤ÎÀܳ¤ÎÊýË¡¤òÁªÂò¤¹¤ë(ÂçÄñ¤Î¾ì¹ç¤Ï¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤Ç¤¢¤ë)¡£¤³¤ì¤Ï¡¢Linphone¤¬¤¢¤Ê¤¿¤ÎÂÓ°è¤òÀßÄꤹ¤ë¤Î¤òÊä½õ¤¹¤ë¤¿¤á¤Ç¤¢¤ë¡£ + + + + + + + RTP + + + RTP(Real Time Protocol)¤Ï¡¢¥á¥Ç¥£¥¢¥¹¥È¥ê¡¼¥à¤ò¥Í¥Ã¥È¥ï¡¼¥¯±Û¤·¤ËÁ÷¿®¤¹¤ëºÝ¤ËÍѤ¤¤ë¥×¥í¥È¥³¥ë¤Ç¤¢¤ë¡£ + + + + + RTP¥Ý¡¼¥È - Linphone¤Ï¡¢¥Ç¥Õ¥©¥ë¥È¤Ç²»À¼¥Ç¡¼¥¿¤ÎÁ÷¼õ¿®¤Ë7000È֥ݡ¼¥È¤òÍøÍѤ¹¤ë¡£7000È֥ݡ¼¥È¤¬Â¾¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Ë»È¤ï¤ì¤Æ¤¤¤ë¤È»×¤ï¤ì¤ë¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥Ý¡¼¥È¤ËÊѹ¹¤¹¤ë¡£ + + + + + ¥Ð¥Ã¥Õ¥¡¤¹¤ë¥ß¥êÉà - ¤³¤Î¿ô»ú¤Ï¡¢Linphone¤¬ºÆÀ¸¤òÂÔµ¡¤¹¤ë²»À¼¥Ñ¥±¥Ã¥È¤Î¿ô¤òɽ¤·¤Æ¤¤¤ë¡£²»À¼¥Ñ¥±¥Ã¥È¤¬Á÷¤ì¤¬¤Á¤Ê¾ì¹ç¤Ë¡¢ºÆÀ¸¤µ¤ì¤º¤ËÇË´þ¤µ¤ì¤ë²»À¼¥Ñ¥±¥Ã¥È¤ò¸º¤é¤¹¤³¤È¤¬¤Ç¤­¤ë¡£¡ÖÅÓÀÚ¤ìÅÓÀڤ첻¡×¤¬Ê¹¤³¤¨¤ë¾ì¹ç¡¢¤³¤ÎÃͤòÂ礭¤¯¤¹¤ë¤ÈÅÁÁ÷¤Î¸úΨ¤ò¾å¤²¤ë¤³¤È¤¬¤Ç¤­¤ë¤¬¡¢²»À¼¤ÎÃٱ䤬Â礭¤¯¤Ê¤ë(Áê¼ê¤ÎÀ¼¤¬¾¯¤·ÃÙ¤ì¤ÆÊ¹¤³¤¨¤ë)¡£¤æ¤¨¤Ë¡¢¥Í¥Ã¥È¥ï¡¼¥¯¤¬´°Á´¤Ç¹âÉʼÁ¤Î¥ª¡¼¥Ç¥£¥ª¥É¥é¥¤¥Ð¤ò»ÈÍѤ·¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢¤³¤ÎÃͤò3¥Ñ¥±¥Ã¥È¤Ë²¼¤²¤ì¤Ðû¤¤ÃÙ±ä»þ´Ö¤ÇÏ令ë¤è¤¦¤Ë¤Ê¤ë¡£ + + + + + + + SIP + + + SIP(Session Initiation Protocol)¤Ï¡¢¥Í¥Ã¥È¥ï¡¼¥¯±Û¤·¤Ë¥á¥Ç¥£¥¢¤Î¥»¥Ã¥·¥ç¥ó¤ò³ÎΩ¤¹¤ë¥×¥í¥È¥³¥ë¤Ç¤¢¤ë¡£¤Ä¤Þ¤ê¤Ï¡¢¥ê¥â¡¼¥È¥æ¡¼¥¶¡¼´Ö¤Î²ñÏäò³«»Ï¤·¤¿¤ê¡¢ÊÒÊý¤¬ÅÅÏäòÀڤ俤Ȥ­¤Ë²ñÏäò½ªÎ»¤·¤¿¤ê¤¹¤ë¥×¥í¥È¥³¥ë¤Ç¤¢¤ë¡£ + + + + + SIP¥Ý¡¼¥È - Linphone¤Ï¡¢¥Ç¥Õ¥©¥ë¥È¤ÇSIP¥Ñ¥±¥Ã¥È¤ÎÁ÷¼õ¿®¤Ë5060È֥ݡ¼¥È¤òÍѤ¤¤ë¡£SIP¤Î¥Ý¡¼¥È¤Ï¡¢RFC¤Ë5060ÈÖ¤òÍѤ¤¤ë¤³¤È¤¬¶¯¤¯¿ä¾©¤µ¤ì¤Æ¤¤¤ë¡£¤è¤Ã¤Æ¡¢²¿¤ò¤·¤¿¤¤¤Î¤«¤òÌÀ³Î¤ËÍý²ò¤·¤Æ¤¤¤ë¤È¤­¤ò½ü¤¤¤Æ¤Ï¡¢¤³¤ì¤òÊѹ¹¤¹¤Ù¤­¤Ç¤Ï¤Ê¤¤¡£ + + + + + SIP¤ÎÅÐÏ¿¤Ë¤¹¤ë - ¥ê¥â¡¼¥È¤ÎSIP¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤·¤¿¤¤¤È¤­¤Ë¤Ï¡¢¤³¤Î¥Ü¥¿¥ó¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£SIP¥µ¡¼¥Ð¡¼¤Î¥µ¡¼¥Ó¥¹¤Ë¤Ï¡¢Å¾Á÷¤ä¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤¬¤¢¤ë¡£¾Ü¤·¤¯¤Ï¡¢¡Ö¥ê¥â¡¼¥È¤Î¥µ¡¼¥Ð¡¼¤ËÀܳ¤¹¤ë¡×¤ÎÀá¤ò»²¾È¤µ¤ì¤¿¤¤¡£ + + + + + + + ¥³¡¼¥Ç¥Ã¥¯ + + + ¥³¡¼¥Ç¥Ã¥¯¤È¤Ï¡¢ÆÃ¤Ë²»À¼¥Ç¡¼¥¿¤Î°µ½Ì¤Î¤¿¤á¤ËÀ߷פµ¤ì¤¿¥¢¥ë¥´¥ê¥º¥à¤Î¤³¤È¤ò¸À¤¦¡£Î㤨¤Ð¡¢16bit/8000Hz¤Î¥Ç¥¸¥¿¥ë²½¤µ¤ì¤¿²»À¼¤È¸À¤¨¤Ð¡¢128kbit/ÉäΥǡ¼¥¿¤Îή¤ì¤òɽ¤·¤Æ¤¤¤ë¡£GSM¥Ü¥³¡¼¥À¡¼¤ò»ÈÍѤ¹¤ë¤È¡¢¤³¤ì¤Ï13bit kbit/Éä˽̾®¤µ¤ì¤ë¡£ + + + + + ¥³¡¼¥Ç¥Ã¥¯¤ÎÁªÂò - Linphone¤Ï¿ô¼ïÎà¤Î¥³¡¼¥Ç¥Ã¥¯¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¡£ ¥³¡¼¥Ç¥Ã¥¯¤Î¥ê¥¹¥È¤Î²¼Éô¤Ë¤¢¤ë¥Ü¥¿¥ó¤ò»È¤¦¤È¡¢»È¤¤¤¿¤¤½çÈÖ¤Ëʤ٤뤳¤È¤¬¤Ç¤­¤ë¡£¤À¤¬¡¢¥Í¥Ã¥È¥ï¡¼¥¯Àܳ¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ¤Ï(¥Í¥Ã¥È¥ï¡¼¥¯¤ÎÀá¤ò»²¾È)¡¢»È¤¨¤Ê¤¤¥³¡¼¥Ç¥Ã¥¯¤Î¼ïÎà¤â¡¢»ÈÍѤ¹¤ë¤«¤É¤¦¤«¤ò·èÄꤹ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£ + + + + + + + ¥ª¡¼¥Ç¥£¥ª¥Ñ¥é¥á¡¼¥¿¡¼ + + + ¤³¤ÎÀá¤Ç¤Ï¡¢²»À¼µ»½Ñ¤Ë´Ø¤¹¤ë¥Ñ¥é¥á¡¼¥¿¡¼¤ò²òÀ⤹¤ë¡£ + + + + + ¥É¥é¥¤¥Ð¤ÎÁªÂò - Linux¤Ç¤Ï¡¢OSS(¥«¡¼¥Í¥ë¥É¥é¥¤¥Ð¡¼¤È¤â¸Æ¤Ð¤ì¤ë)¤ÈALSA¤È¡¢°Û¤Ê¤ë2¼ïÎà¤Î¥µ¥¦¥ó¥É¥«¡¼¥É¥é¥¤¥Ð¤ò»ÈÍѤ¹¤ë¤³¤È¤¬¤Ç¤­¤ë¤¬¡¢ALSA¥É¥é¥¤¥Ð¤ÏALSA¥é¥¤¥Ö¥é¥ê¤òÄ̤¹¤³¤È¤Ç¡¢¤µ¤é¤Ê ¤ë¥Ñ¥Õ¥©¡¼¥Þ¥ó¥¹¤òȯ´ø¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢ALSA¥É¥é¥¤¥Ð¡¼(snd_*¤Ç»Ï¤Þ¤ë̾Á°¤Ç¤¢¤ë)¤ò»ÈÍѤ·¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢ALSA¥â¡¼¥É¤òÁªÂò¤¹¤ë¤Î¤¬¤è¤¤¡£Ê¬¤«¤é¤Ê¤±¤ì¤Ð¡¢OSS¤òÁªÂò¤¹¤ë¡£ + + + + + Auto-kill¥ª¥×¥·¥ç¥ó - ¤³¤Î¥ª¥×¥·¥ç¥ó¤ò»È¤¦¤È¡¢linphone¤Ï¥µ¥¦¥ó¥É¥Ç¡¼¥â¥ó(esd¤Èartsd)¤òÄä»ß¤·¤è¤¦¤È¤¹¤ë¡£¤³¤ì¤Ï¡¢¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤Ë¹±µ×Ū¤Ê¼è¤ê³°¤»¤Ê¤¤¥í¥Ã¥¯¤ò¤«¤±¤Æ¤·¤Þ¤¤¡¢Linphone¤¬É¬ÍפȤ·¤Æ¤¤¤ë¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò¥ª¡¼¥×¥ó¤µ¤»¤Ê¤¤¤è¤¦¤Ë¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡¢¤³¤Î¥ª¥×¥·¥ç¥ó¤Ï¡¢¥ª¥ó¤Ë¤·¤Æ¤ª¤¯¤³¤È¤ò¿ä¾©¤¹¤ë¡£ + + + + + + + + ÅÅÏÃÄ¢ + + + ÅÅÏÃÄ¢(conection¤Î¥á¥Ë¥å¡¼¤ÎÃæ¤Ë¤¢¤ë)¤ò»È¤¦¤È¡¢SIP¥¢¥É¥ì¥¹¤òµ­²±¤È¸Æ½Ð¤·¤¬¤Ç¤­¤ë¡£SIP¥¢¥É¥ì¥¹¤Ï¡¢sip:¥æ¡¼¥¶¡¼Ì¾@¥É¥á¥¤¥ó̾¤Î·Á¼°¤Ç¤¢¤ë¡£¤Þ¤¿¡¢¼«Ê¬¤¬Ê¬¤«¤ê¤ä¤¹¤¯¤¹¤ë¤¿¤á¤Ë¡¢É½¼¨¤µ¤ì¤ë̾Á°¤òÄɲ乤뤳¤È¤â¤Ç¤­¤ë¡£SIP¥¢¥É¥ì¥¹¤ò¸Æ¤Ó½Ð¤¹¤Ë¤Ï¡¢¥¢¥É¥ì¥¹¤Î¥ê¥¹¥È¤«¤éÁªÂò¤·¡¢¡ÖOK¡×¤Î¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¡£¤¹¤ë¤È¡¢ÁªÂò¤·¤¿¥¢¥É¥ì¥¹¤¬¥á¥¤¥ó¥¦¥¤¥ó¥É¥¦¤Ë¸½¤ì¤ë¤Î¤¬³Îǧ¤Ç¤­¤ë¤À¤í¤¦¡£¸å¤Ï¡¢ÅÅÏäò¤«¤±¤ë¤¿¤á¤Ë¡ÖÅÅÏäò¤«¤±¤ë¡×¤Î¥Ü¥¿¥ó¤ò²¡¤»¤Ð¤è¤¤¤À¤±¤Ç¤¢¤ë¡£ + + + + + SIP¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤ë + + + ¥ê¥â¡¼¥È¤ÎSIP¥µ¡¼¥Ð¡¼¤Î¥µ¡¼¥Ó¥¹¤ËÅÐÏ¿¤¹¤ë¤³¤È¤â²Äǽ¤Ç¤¢¤ë¡£¤³¤Î¤è¤¦¤Ê¥µ¡¼¥Ó¥¹¤Ë¤Ï¡¢°Ê²¼¤Î¤è¤¦¤Ê¤â¤Î¤¬¤¢¤ë¡£ + + + + + žÁ÷ - Linphon¤Ï¡¢¥µ¡¼¥Ð¡¼¤Ë<sip:example_registrar.com>¤Î¤è¤¦¤ÊSIP¥¢¥«¥¦¥ó¥È¤òºîÀ®¤¹¤ë¤è¤¦Í×ÀÁ¤¹¤ë¡£Î㤨¤Ð¡¢56k¤Î¥â¥Ç¥à¤ò»È¤Ã¤ÆÃ±½ã¤Ë¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ËÀܳ¤·¤Æ¤¤¤ë¾ì¹ç¡¢¤¢¤Ê¤¿¤ÎIP¥¢¥É¥ì¥¹¤ÏÀÅŪ¤Ç¤Ï¤Ê¤¯¡¢¥Í¡¼¥à¥µ¡¼¥Ð¡¼¤ËÃΤé¤ì¤Æ¤¤¤ë¥Û¥¹¥È̾¤â»ý¤Ã¤Æ¤¤¤Ê¤¤¡£¤³¤ì¤Ç¤Ï¡¢Í§Ã£¤Ï¤¢¤Ê¤¿¤¬IP¥¢¥É¥ì¥¹¤òÄÌÃΤ¹¤ë¥á¡¼¥ë¤òÁ÷¤é¤Ê¤¤¸Â¤ê¡¢¤¢¤Ê¤¿¤ËÏ¢Íí¤ò¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£Îã¤È¤·¤Æ¡¢<sip:example_registrar.com>¤ËÅÐÏ¿¤ò¹Ô¤¦¤Î¤Ï´Êñ¤Ç¤¢¤ë¡£¤¢¤Ê¤¿¤Î¥æ¡¼¥¶¡¼Ì¾¤Ï¡Öbob¡×¤À¤È¤¹¤ë¡£¥µ¡¼¥Ð¡¼¤ËÅÐÏ¿¤¹¤ëºÝ¤Ë¡¢Linphone¤Ï¤¢¤Ê¤¿¤ÎIP¥¢¥É¥ì¥¹¤ò¥µ¡¼¥Ð¡¼¤ËÁ÷¿®¤·¡¢¥¢¥«¥¦¥ó¥È¡Ösip:bob@example_registrar.com¡×¤¬ºîÀ®¤µ¤ì¤ë¡£¤½¤¦¤¹¤ë¤È¡¢¤¢¤Ê¤¿¤Îͧã¤Î¥¸¥à¤Ï¡¢<sip:bob@example_registrar.com>¤È¤¤¤¦¥¢¥É¥ì¥¹¤ËÅÅÏäò¤«¤±¤ë¤³¤È¤¬¤Ç¤­¤ë¡£ÅöÁ³¤Î¤³¤È¤Ê¤¬¤é¡¢“example_registar.com”¤Ï¡¢¥¦¥§¥ë¥Î¥ó¡¦¥É¥á¥¤¥ó¥Í¡¼¥à¤Ç¤¢¤ë¡£¼¡¤Ë¡¢¥¸¥à¤ÎLinphone¤Ï¥Ü¥Ö¤Î³Î¼Â¤Ê¥í¥±¡¼¥·¥ç¥ó¤ò¼¨¤¹Å¾Á÷¥á¥Ã¥»¡¼¥¸¤ò¼õ¤±¼è¤ë¡£¤½¤¦¤·¤Æ¡¢¥Ü¥Ö¤Î²È¤Ç¥Ù¥ë¤¬ÌĤë¤Î¤Ç¤¢¤ë¡£ + + + + + ¥×¥í¥¯¥· - ¤³¤ì¤â¡¢Å¾Á÷¥á¥Ã¥»¡¼¥¸¤¬¥¸¥à¤ÎÅÅÏäËÁ÷¿®¤µ¤ì¤Ê¤¤¤³¤È¤ò¤Î¤¾¤±¤Ð¡¢Æ±Íͤθ¶Íý¤Ç¤¢¤ë¡£¤½¤ÎÂå¤ï¤ê¤Ë¡¢¥×¥í¥¯¥·¤Ï¥Ü¥Ö¤ÎLinphone¤Þ¤Ç¥À¥¤¥ì¥¯¥È¤ÊžÁ÷¤ò¹Ô¤¦¡£ + + + + + ¤³¤Î¤è¤¦¤ÊÅÐÏ¿¤Ï¡¢¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤Ë¤ª¤¤¤Æ¤âƱÍͤ˹Ԥï¤ì¤ë¡£¤³¤ì¤Ï¡¢Linphone¤ò¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤ÎÃæ¤Ç»È¤¦¤È¤­¤ËÍ­¸ú¤Ç¤¢¤ë¡£¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤Ï¡¢¥×¥é¥¤¥Ù¡¼¥È¥µ¥Ö¥Í¥Ã¥È¤Ë¤¢¤ëHTTP¥×¥í¥¯¥·¤ÈƱÍͤÎÌò³ä¤ò²Ì¤¿¤¹¡£³°Éô¤Ø¤Î²ñÏäϥ¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤¬°·¤¤¡¢¥Í¥Ã¥È¥ï¡¼¥¯³°¤Ë¤¤¤ë¤È»×¤ï¤ì¤ë¿Í¤Ø¤Î²ñÏäΞÁ÷¤ÎǤ¤òÉ餦¡£ + + + ÅÐÏ¿¥µ¡¼¥Ð¡¼¤òLinphone¤Ç»È¤¦¤Ë¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤«¤éSIP¤Î¥¿¥Ö¤òÁªÂò¤·¡¢¡ÖSIP¥¢¥É¥ì¥¹¤òÅÐÏ¿¤¹¤ë¡×¤Î¥Ü¥Ã¥¯¥¹¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ÅÐÏ¿¤¹¤ë¥¢¥É¥ì¥¹¤òŬÀڤʥե£¡¼¥ë¥É¤ËÆþÎϤ·¤¿¤é¡¢¼¡¤Ë¡¢Å¾Á÷¤«¥×¥í¥¯¥·¤«¡¢Âбþ¤¹¤ë¥Ü¥Ã¥¯¥¹¤ò¥Á¥§¥Ã¥¯¤·¡¢ÅÐÏ¿¤òÍ׵᤹¤ë¥µ¡¼¥Ó¥¹¤Î¥¿¥¤¥×¤òÁªÂò¤¹¤ë¡£¤Þ¤¿¡¢³°Éô¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤Ø²ñÏäòÆ©²á¤µ¤»¤ë¤¿¤á¤ÎÅÐÏ¿¥µ¡¼¥Ð¡¼¤¬É¬ÍפʤȤ­¤Ë¤Ï¡¢¡Ö¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤È¤·¤Æ»È¤¦¡×¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ + + + ºÇ¸å¤Ë¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÎOK¥Ü¥¿¥ó¤ò²¡¤¹¤È¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÏÊĤ¸¤é¤ì¡¢¤¿¤À¤Á¤ËÅÐÏ¿¥µ¡¼¥Ð¡¼¤Ë¤¢¤Ê¤¿¤ÎÀµ³Î¤Ê¾ì½ê¤òÃΤ餻¤ë¤¿¤á¤Î¸ò¾Ä¤¬»Ï¤Þ¤ë¡£Linphone¤ò¥·¥ã¥Ã¥È¥À¥¦¥ó¤¹¤ë¤È¤­¤Ë¤Ï¡¢ÅÐÏ¿¥µ¡¼¥Ð¡¼¤«¤é¤¢¤Ê¤¿¤Î¾ì½ê¤ÎÅÐÏ¿¤ò²ò½ü¤¹¤ë¤¿¤á¡¢¿ôÉô֤«¤«¤ë¡£ + + + ¥Ñ¥Ö¥ê¥Ã¥¯¤ÊÅÐÏ¿¥µ¡¼¥Ð¡¼¤Î¥ê¥¹¥È¤Ï¡¢°Ê²¼¤Ë·ÇºÜ¤µ¤ì¤Æ¤¤¤ë¡£http://www.cs.columbia.edu/~hgs/sip/servers.html + + + ¤À¤¬¡¢»Äǰ¤Ê¤³¤È¤Ë¡¢¤³¤ì¤é¤Î¥µ¡¼¥Ð¡¼¤Î¿¤¯¤Ï¤â¤¦Æ°¤¤¤Æ¤¤¤Ê¤¤¡£¤ª¤½¤é¤¯¡¢¶áº¢¤ÎÅŵ¤ÄÌ¿®¶È³¦¤Î´íµ¡¤Ë¤è¤ë¤â¤Î¤Ç¤¢¤í¤¦¡£Â¾¤ÎɬÍפȤµ¤ì¤ëǧ¾ÚÊýË¡¤Ï¡¢¸½ºßLinphone¤Ç¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¡£ + + + ̵ÍѤʼê´Ö¤òÈò¤±¤¿¤¤¤È¤­¤Ë¤Ï¡¢»ÈÍѲÄǽ¤Êưºî¤·¤Æ¤¤¤ë¥Ñ¥Ö¥ê¥Ã¥¯¤ÊSIP¥µ¡¼¥Ð¡¼¤Î¥ê¥¹¥È¤¬¡¢Linphoe¤Î°ÊÁ°¤ÎWEB¥µ¥¤¥È¤Î¥ê¥¹¥È¤¬http://simon.morlat.free.fr/english/servers.html¤Ç»²¾È¤Ç¤­¤ë¡£ + + + + + ¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤ÎÆâ¦¤Ç + + + ¸½ºß¤Ç¤Ï¡¢SIP¥×¥í¥¯¥·¤òÍѤ¤¤ë¤³¤È¤Ç¡¢Linphone¤Ï¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤ÎÆâ¦¤ÇÍøÍѲÄǽ¤Ç¤¢¤ë¡£SIP¥µ¡¼¥Ð¡¼¤Ï¡¢¥×¥é¥¤¥Ù¡¼¥È¥Í¥Ã¥È¥ï¡¼¥¯¤«¤é¤Î²ñÏäò³°Éô¤Î¥Í¥Ã¥È¥ï¡¼¥¯¤ØÅ¾Á÷¤¹¤ëǤ¤òÉ餦¡£oSIP¥é¥¤¥Ö¥é¥ê¤òÍøÍѤ·¤¿SIP¥×¥í¥¯¥·¤Ï¡¢http://osipproxy.sourceforge.net¤Ç³«È¯¤µ¤ì¤Æ¤¤¤ë¡£ + + + SIP¤ÎÀá¤Î¡¢¡ÖSIP¤ËÅÐÏ¿¤¹¤ë¡×¤Î¹àÌܤò»²¹Í¤Ë¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÇÍѤ¤¤ëSIP¥×¥í¥¯¥·¤ò»ØÄꤷ¤ÆÍߤ·¤¤¡£ÀßÄꤹ¤ë¤Ë¤Ï¡¢SIP¥×¥í¥¯¥·¤Î¥¢¥É¥ì¥¹¤òÆþÎϤ·¡¢¡Ö¥¢¥¦¥È¥Ð¥¦¥ó¥É¥×¥í¥¯¥·¤È¤·¤ÆÅÐÏ¿¤¹¤ë¡×¤Î¥Ü¥¿¥ó¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡£ + + + ¤Ê¤ª¡¢SIP¥×¥í¥¯¥·¤¬É¬Íפʤ¤¾ì¹ç¤â¤¢¤ë¡£¥Ñ¥Ö¥ê¥Ã¥¯¥¢¥É¥ì¥¹¤ò»ý¤Ã¤Æ¤¤¤ë¥Í¥Ã¥È¥ï¡¼¥¯²¼¤Ë¤¢¤Ê¤¿¤Î¥³¥ó¥Ô¥å¡¼¥¿¡¼¤¬¤¢¤ê¡¢¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤Ï³°Éô¥Í¥Ã¥È¥ï¡¼¥¯¤«¤é¤Î¥Ñ¥±¥Ã¥È¤ÎÁ÷¼õ¿®¤ò¥Õ¥£¥ë¥¿¡¼¤¹¤ë¤À¤±¤Î¾ì¹ç¤Ç¤¢¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï¡¢¥Õ¥¡¥¤¥ä¡¼¥¦¥©¡¼¥ë¤Î¥Þ¥·¥ó¤ÎSIP¤ÈRTP¤Î¥Ý¡¼¥È¤ò¥ª¡¼¥×¥ó¤¹¤ë¤À¤±¤Ç¤è¤¤¡£SIP¥Ý¡¼¥È¤Ï¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÎSIP¤Î¥¿¥Ö¤Ë¡¢RTP¥Ý¡¼¥È¤Ï¡¢RTP¥Ý¡¼¥È¤ÏRTP¤Î¥¿¥Ö¤Ë¤¢¤ë¡£Î¾¼Ô¤È¤â¤ËÊѹ¹²Äǽ¤Ç¤¢¤ë¤¬¡¢SIP¥Ý¡¼¥È(5060ÈÖ)¤Ï¡¢Êѹ¹¤·¤Ê¤¤¤Ç¤ª¤¯¤³¤È¤¬¶¯¤¯¿ä¾©¤µ¤ì¤ë¡£ + + + + + º¤¤Ã¤¿¤È¤­¤Ë¤Ï + + + + Àܳ¾å¤Ë¤ª¤±¤ëÌäÂê + +
+ + »ä¤Ï¡¢Í§¿Í<sip:toto@example.com>¤ËÅÅÏäò¤«¤±¤è¤¦¤È¤·¤¿¤À¤¬¡¢¤Ê¤Ë¤âµ¯¤­¤Ê¤¤¡£¥Ù¥ë¤âÌĤé¤Ê¤¤¡¢¤Þ¤Ã¤¿¤¯²¿¤âµ¯¤³¤é¤Ê¤¤¡£ + +
+ + Linphone¤¬»ÈÍѤ·¤Æ¤¤¤ë¥¤¥ó¥¿¡¼¥Í¥Ã¥È¤ØÀܳ¤·¤Æ¤¤¤ë¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹(¤Þ¤¿¤Ï¡¢²ñÏ䬽ФƤ¤¤¯¤Ù¤­¥Í¥Ã¥È¥ï¡¼¥¯)¤ò¸¡¾Ú¤·¤Æ¤ß¤ë¤Ù¤­¤Ç¤¢¤í¤¦¡£¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤Î¡¢¥Í¥Ã¥È¥ï¡¼¥¯¥¿¥Ö¤«¤é¡¢Àµ¤·¤¤¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ó¤Ç¤ß¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£ + + + ¤¢¤ë¤¤¤Ï¡¢¤¢¤Ê¤¿¤¬Àܳ¤·¤è¤¦¤È¤·¤Æ¤¤¤ë¿Í¤¬¡¢¸½ºß·ÐÏ©¤¬Àܳ¤Ç¤­¤Ê¤¤¾õ¶·¤Ë¤¢¤ë¤Î¤«¤âÃΤì¤Ê¤¤¡Ä¡Ä¡£ + +
+ + + ²»À¼¤Ë¤ª¤±¤ëÌäÂê + +
+ + Linphone¤Ï¡¢¥ê¥â¡¼¥È¤ÎSIP URL¤ËÀܳ¤·¤Æ¤¤¤ë¤è¤¦¤Ç¡¢¥Ù¥ë¤ÏÌĤäƤ¤¤ë¤è¤¦¤À¡£¤±¤ì¤É¤â¡¢Áê¼ê¤¬ÅÅÏä˽Ф¿¤È¤­¤Ë¤Ï²¿¤âµ¯¤³¤é¤º¡¢¤ª¸ß¤¤¤ÎÀ¼¤¬Ê¹¤³¤¨¤Ê¤¤¡£ + +
+ + + + ÂçÄñ¤Î¿Í¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤«¤é¡¢Àµ¤·¤¤¥Í¥Ã¥È¥ï¡¼¥¯¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÁª¤ó¤Ç¤¤¤Ê¤¤¤¿¤á¤Ë¡¢ÌäÂê¤òÀ¸¤¸¤µ¤»¤Æ¤·¤Þ¤¦¡£¥À¥¤¥ä¥ë¥¢¥Ã¥×Àܳ¤Ç¤Ï¡¢¡Öppp0¡×¤Ë¤Ê¤ë¤Ï¤º¤Ç¤¢¤ë¡£¡Ö\"{}lo¡×¤Ï¡¢¥Æ¥¹¥ÈÍѤˡ¢sipomatic¤À¤±¤Ë»ÈÍѤµ¤ì¤ë¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ç¤¢¤ë¤³¤È¤ËÃí°Õ¤µ¤ì¤¿¤¤¡£¤½¤Î¾¤Î¾ì¹ç¤Ç¤Ï µ¡Ç½¤·¤Ê¤¤¡£ + + + + + ¤Þ¤º¤Ï¡¢Á÷Ïò»Î̤ȼõÏò»Î̤ò¾å¤²¤Æ¤ß¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£ + + + + + ²»À¼¤¬¤È¤®¤ì¤È¤®¤ì¤Ë¤Ê¤ë¾ì¹ç¤Ï¡¢¤³¤ì¤ò²óÈò¤¹¤ë¤¿¤á¤Ë¡¢¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤ÎRTP¥¿¥Ö¤Î¡Ö¥Ð¥Ã¥Õ¥¡¤¹¤ë¥ß¥êÉáפÎÃͤòÂ礭¤¯¤·¤Æ¤ß¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£¤·¤«¤·¡¢¤³¤ì¤ÏÄÌ¿®¤ÎÃÙ±ä¤òÁýÂ礵¤»¤ë¡£ + + + + + Linphone¤¬¡¢¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò¥ª¡¼¥×¥ó¤Ç¤­¤Ê¤¤¤È¤­¤Ë¤Ï¡¢/dev/dsp¤Î¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ò³Îǧ¤·¡¢¥ª¡¼¥Ç¥£¥ª¥Ç¥Ð¥¤¥¹¤ò»ÈÍѤ¹¤ë¤¹¤Ù¤Æ¤Î¥×¥í¥°¥é¥à(xmms kaimanÅù)¤òÄä»ß¤¹¤ë¤Î¤¬¤è¤¤¤À¤í¤¦¡£ + + + + + ALSA¥É¥é¥¤¥Ð¡¼¤ò»ÈÍѤ¹¤ë(http://www.alsa-project.org¤ò»²¾È¤µ¤ì¤¿¤¤)¡£ÂçÄñ¤Î¥Ç¥£¥¹¥È¥ê¥Ó¥å¡¼¥¸¥ç¥ó¤Ï¡¢¤Þ¤À¸Å¤¤¥«¡¼¥Í¥ë¸øÇ§¤Î¥É¥é¥¤¥Ð¡¼¤ò»ÈÍѤ·¤Æ¤¤¤ë¤¬¡¢¤³¤ì¤ÏÂ礭¤ÊÃÙ±ä¤È¿¤¯¤Î¥Ð¥°¤ò´Þ¤ó¤Ç¤¤¤ë¡£Linphone¤Ï¡¢ALSA¥É¥é¥¤¥Ð¡¼¤ò¥¤¥ó¥¹¥È¡¼¥ë¤·¤¿¸å¤Î¥ê¥³¥ó¥Ñ¥¤¥ë¤òɬÍפȤ·¤Ê¤¤¤³¤È¡¢¤Þ¤¿¡¢¥ª¡¼¥Ç¥£¥ª¤ÎÀá¤Î¥×¥í¥Ñ¥Æ¥£¡¼¥Ü¥Ã¥¯¥¹¤«¤é¤ÎALSA¥â¡¼¥É¤Ø¤ÎÊѹ¹¤Ïɬ¿Ü¤Ç¤Ï¤Ê¤¤¤³¤È¤â½Ò¤Ù¤Æ¤ª¤³¤¦¡£ + + + +
+
+ + + ¥Ð¥°Êó¹ð¤ÈÄó°Æ + + + ¤Þ¤º¤Ï¡¢Linphone¤Î¥Û¡¼¥à¥Ú¡¼¥¸http://www.linphone.org¤«¤é¡¢ºÇ¿·¤ÎLinphone¤ò»ÈÍѤ·¤Æ¤¤¤ë¤«¤ò³Îǧ¤·¤ÆÍߤ·¤¤¡£ + + + ¤â¤·¡¢Linphone¤¬¥¯¥é¥Ã¥·¥å¤·¤¿¤È¤­¤Ë¤Ï¡¢¥Ð¥°¥ì¥Ý¡¼¥È¤òľÀÜbugs@linphone.org¤Þ¤ÇÁ÷¤Ã¤ÆÍߤ·¤¤¡£¤â¤·¡¢¥¯¥é¥Ã¥·¥å¤Ï¤·¤Ê¤¤¤¬Linphone¤¬Æ°ºî¤·¤Ê¤¤¤È¤­¤Ë¤Ï¡¢¾å¤Î¥¢¥É¥ì¥¹¤Ë¥Ð¥°¥ì¥Ý¡¼¥È¤òÁ÷¤ëÁ°¤Ë¡¢¥Þ¥Ë¥å¥¢¥ë¤ò ¤â¤¦°ìÅÙÆÉ¤ß¤«¤¨¤·¤ÆÍߤ·¤¤¡£¤â¤·¡¢²¿¤«¤òÄ󰯤·¤¿¤¤¤È¤­¤Ë¤Ï¡¢±ó褻¤º¤Ë¡¢help@linphone.org¤Þ¤Ç¥á¡¼¥ë¤òÁ÷¤Ã¤ÆÍߤ·¤¤¡£¤Ê¤ª¡¢¥Ó¥Ç¥ª¥µ¥Ý¡¼¥È¤È²ñµÄ¤Ï¡¢¾­Íè¤Î·×²è¤Ë¤¢¤ë¤³¤È¤ò½Ò¤Ù¤Æ¤ª¤³¤¦¡£¤Þ¤¿¡¢Linphonr¤ÎËÝÌõ¤Ë¶½Ì£¤ò»ý¤Ã¤¿¿Í¤Ï¡¢ÇÛÉÛ¤µ¤ì¤Æ¤¤¤ëpo/linpyhone.pot¤Ë´ð¤Å¤¤¤¿xx.po¥Õ¥¡¥¤¥ë¤ò»ä¤ËÁ÷¤Ã¤ÆÍߤ·¤¤¡£¤Þ¤¿¡¢¤³¤Î¥Þ¥Ë¥å¥¢¥ë¤ò¾¤Î¸À¸ì¤ËËÝÌõ¤¹¤ë¤³¤È¤â²Äǽ¤Ç¤¢¤ë¡£¤¤¤º¤ì¤Ë¤·¤Æ¤â¡¢¾Ü¤·¤¤¤³¤È¤¬ÃΤꤿ¤¤¤È¤­¤Ï»ä¤ËÏ¢Íí¤·¤ÆÍߤ·¤¤¡£ + + + + + ºî¼Ô + + + Simon MORLAT (simon.morlat@free.fr) ¤¬À½ºî¤·¤¿Éôʬ¤Ï°Ê²¼¤ÎÄ̤ê¤Ç¤¢¤ë¡£ + + + + + ¥á¥¤¥ó¥×¥í¥°¥é¥à(src) + + + + + RTP ¥é¥¤¥Ö¥é¥ê (lprtplib) + + + + + osipua -- osip¥¹¥¿¥Ã¥¯¤Ë´ð¤Å¤¤¤¿¥æ¡¼¥¶¡¼¥¨¡¼¥¸¥§¥ó¥È¤ÎAPI¡£oss¤ÈALSA¥É¥é¥¤¥Ð¡¼¤Î²»À¼¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¡£ + + + + + (²»À¼) lpc10-1.5ÍѤÎwrappers, gsm and g711 ¥³¡¼¥Ç¥Ã¥¯ + + + + + Aymeric Moizard (jack@atosc.org)¤Ï¡¢ Linphone¤¬ÍøÍѤ·¤Æ¤¤¤ëosip¥¹¥¿¥Ã¥¯¤òÀ½ºî¤·¤¿¡£ + + + GSM¥é¥¤¥Ö¥é¥ê¤Ï¡¢Jutta Degener¤ÈCarsten Bormann(Technische Universitaet Berlin)¤Ë¤è¤Ã¤Æ½ñ¤«¤ì¤¿¡£ + + + The LPC10-1.5 ¥é¥¤¥Ö¥é¥ê¤Ï¡¢Andy Fingerhut(Applied Research Laboratory)¤Ë¤è¤Ã¤Æ½ñ¤«¤ì¤¿¡£ <-- ¤³¤ÎÉôʬ¤Ï¥¹¥Ú¡¼¥¹¤ÎÅÔ¹ç¤Ë¤è¤ê¾Êά²Äǽ¤Ç¤¢¤ë¡£ Washington University, Campus Box 1045/Bryan 509 ¥¹¥Ú¡¼¥¹¤Ë¸Â¤ê¤¬¤¢¤ë¾ì¹ç¤Ï¡¢¤³¤³¤«¤é¡£One Brookings Drive Saint Louis, MO 63130-4899 jaf@arl.wustl.edu http://www.arl.wustl.edu/˜jaf/¤µ¤é¤Ê¤ë¾ðÊó¤Ï¡¢gsmlib¤Èlpc10-1.5¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Î¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤ò»²¾È¤µ¤ì¤¿¤¤¡£ + + + Pablo Marcelo Moia -- ¥¢¥¤¥³¥óÀ½ºî + + + + + ¼Õ¼­ + + + GTK¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¥Ó¥ë¥À¡¼¤ÎDaemon Chaplin¤Ë´¶¼Õ¤ò¡£ + + + ÃøÌÀ¤ÊoSIP¥é¥¤¥Ö¥é¥ê¡¼¤ÎAymeric Moizard¤Ë´¶¼Õ¤ò¡£ + + + LPC10-1.5¤ÈGSM¥³¡¼¥É¤Îºî¼Ô¤Ë´¶¼Õ¤ò¡£ + + + RPM¤òÄ󶡤·¤Æ¤¯¤ì¤¿¡¢Joel Barrios ( jbarrios@-NO-SPAM-linuxparatodos.com )¤Ë´¶¼Õ¤ò¡£ + + + Linphone¤ËÁÇŨ¤Ê¥¢¥¤¥³¥ó¤òÄ󶡤·¤Æ¤¯¤ì¤¿¡¢Pablo Marcelo Moia¤Ë´¶¼Õ¤ò¡£ + + + + + + + +
diff --git a/linphone/share/ja/manual/.cvsignore b/linphone/share/ja/manual/.cvsignore new file mode 100644 index 000000000..2d19fc766 --- /dev/null +++ b/linphone/share/ja/manual/.cvsignore @@ -0,0 +1 @@ +*.html diff --git a/linphone/share/linphone.desktop b/linphone/share/linphone.desktop new file mode 100644 index 000000000..09e110454 --- /dev/null +++ b/linphone/share/linphone.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Name=Linphone +Comment=Linphone is a web-phone +Comment[fr]=Linphone est un web-phone. +Comment[de]=Linphone ist ein web-phone. +Type=Application +Exec=linphone-3 +Icon=linphone/linphone2.png +Terminal=false +Categories=Application;Network; \ No newline at end of file diff --git a/linphone/share/linphone.gnorba b/linphone/share/linphone.gnorba new file mode 100644 index 000000000..b9e50592b --- /dev/null +++ b/linphone/share/linphone.gnorba @@ -0,0 +1,5 @@ +[linphone_applet] +type=exe +repo_id=IDL:GNOME/Applet:1.0 +description=Linphone is a web phone. +location_info=linphone --applet \ No newline at end of file diff --git a/linphone/share/linphone.pc.in b/linphone/share/linphone.pc.in new file mode 100644 index 000000000..abd76f414 --- /dev/null +++ b/linphone/share/linphone.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + + +Name: liblinphone +Description: All in one linphone libs. +Version: @VERSION@ +Libs: @LINPHONE_LIBS@ +Cflags: @LINPHONE_CFLAGS@ diff --git a/linphone/share/linphone_applet.desktop b/linphone/share/linphone_applet.desktop new file mode 100644 index 000000000..48403271d --- /dev/null +++ b/linphone/share/linphone_applet.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Linphone Applet +Comment=Linphone is a web-phone +Comment[fr]=Linphone est un web-phone. +Comment[de]=Linphone ist ein web-phone. +Type=Application +Exec=linphone --applet --activate-goad-server=linphone_applet +Icon=linphone/linphone2.png +Terminal=0 \ No newline at end of file diff --git a/linphone/share/ringback.wav b/linphone/share/ringback.wav new file mode 100644 index 000000000..21f4b5bfb Binary files /dev/null and b/linphone/share/ringback.wav differ diff --git a/linphone/share/rings/bigben.wav b/linphone/share/rings/bigben.wav new file mode 100644 index 000000000..f1ba850f6 Binary files /dev/null and b/linphone/share/rings/bigben.wav differ diff --git a/linphone/share/rings/oldphone.wav b/linphone/share/rings/oldphone.wav new file mode 100644 index 000000000..e3056cc5d Binary files /dev/null and b/linphone/share/rings/oldphone.wav differ diff --git a/linphone/share/rings/orig.wav b/linphone/share/rings/orig.wav new file mode 100644 index 000000000..af74b54af Binary files /dev/null and b/linphone/share/rings/orig.wav differ diff --git a/linphone/share/rings/rock.wav b/linphone/share/rings/rock.wav new file mode 100644 index 000000000..12374c067 Binary files /dev/null and b/linphone/share/rings/rock.wav differ diff --git a/linphone/share/rings/sweet.wav b/linphone/share/rings/sweet.wav new file mode 100644 index 000000000..e5145486d Binary files /dev/null and b/linphone/share/rings/sweet.wav differ diff --git a/linphone/share/rings/synth.wav b/linphone/share/rings/synth.wav new file mode 100644 index 000000000..7142f7a51 Binary files /dev/null and b/linphone/share/rings/synth.wav differ diff --git a/linphone/share/rings/tapping.wav b/linphone/share/rings/tapping.wav new file mode 100644 index 000000000..862fd79fb Binary files /dev/null and b/linphone/share/rings/tapping.wav differ diff --git a/linphone/share/rings/toy.wav b/linphone/share/rings/toy.wav new file mode 100644 index 000000000..7a5198492 Binary files /dev/null and b/linphone/share/rings/toy.wav differ diff --git a/linphone/stamp-h.in b/linphone/stamp-h.in new file mode 100644 index 000000000..9788f7023 --- /dev/null +++ b/linphone/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/linphone/support/.cvsignore b/linphone/support/.cvsignore new file mode 100644 index 000000000..6e5ca7ed4 --- /dev/null +++ b/linphone/support/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.deps +.libs +*.lo +*.la diff --git a/linphone/win32/config.h b/linphone/win32/config.h new file mode 100755 index 000000000..171a6b3a2 --- /dev/null +++ b/linphone/win32/config.h @@ -0,0 +1,7 @@ +#ifndef WIN32_CONFIG_H +#define WIN32_CONFIG_H + +#define LINPHONE_VERSION "1.3.0" +#define PACKAGE_PLUGINS_DIR "/" + +#endif diff --git a/linphone/win32/liblinphone.dev b/linphone/win32/liblinphone.dev new file mode 100755 index 000000000..743c965fc --- /dev/null +++ b/linphone/win32/liblinphone.dev @@ -0,0 +1,242 @@ +[Project] +FileName=liblinphone.dev +Name=liblinphone +UnitCount=18 +Type=2 +Ver=3 +IsCpp=1 +Folders= +CommandLine= +CompilerSettings=0000000000100000000000 +PchHead=-1 +PchSource=-1 +ProfilesCount=1 +ProfileIndex=0 + +[Unit1] +FileName=..\coreapi\sdphandler.h +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\coreapi\authentication.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\coreapi\chat.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\coreapi\enum.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\coreapi\enum.h +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\coreapi\exevents.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\coreapi\exevents.h +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\coreapi\friend.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\coreapi\linphonecore.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\coreapi\linphonecore.h +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\coreapi\lpconfig.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\coreapi\lpconfig.h +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\coreapi\misc.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\coreapi\presence.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\coreapi\private.h +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\coreapi\proxy.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\coreapi\sdphandler.c +CompileCpp=0 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\coreapi\general_state.c +CompileCpp=1 +Folder=liblinphone +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 + +[Profile1] +ProfileName=Default Profile +Type=2 +ObjFiles= +Includes=../oRTP/include;../mediastreamer2/include;../../linphone-deps/include +Libs=../oRTP/build/win32native;../mediastreamer2/build/win32native;../../linphone-deps/lib +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-Wall -Werror_@@_-D_WIN32_WINNT=0x501_@@_-D_WORKAROUND_MINGW32_BUGS_@@_-DINET6_@@_-DORTP_INET6_@@_-DORTP_STATIC_@@_-DVIDEO_ENABLED_@@_-ggdb_@@_-DOSIP_MT_@@_ +CppCompiler= +Linker= +PreprocDefines= +CompilerSettings=0000000000100000000000 +Icon= +ExeOutput=..\win32 +ObjectOutput=Default Profile +OverrideOutput=0 +OverrideOutputName=liblinphone.lib +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + diff --git a/linphone/win32acm/CODECS b/linphone/win32acm/CODECS new file mode 100644 index 000000000..87496f17e --- /dev/null +++ b/linphone/win32acm/CODECS @@ -0,0 +1,59 @@ +USING OTHER CODECS + +To use the library with other ACM-supported codecs besides +TrueSpeech, the following things are required: + + 1. DLL file supporting the codec + 2. correct format tag for the codec + 3. correct WAVEFORMATEX structure for the codec + +For codecs which are supported by mplayer, the easiest +way to get items 1 and 2 is by looking at the audio codec +section of mplayer's codec status table: + http://mplayerhq.hu/DOCS/codecs-status.html +If mplayer says it is using a .acm file to support the +audio codec, then most likely it can be used with this +library. If mplayer is using another method to support +that codec, you should probably consider using that +same method in your Linux program instead of this library, +because it is most likely a native way of supporting the +codec. Using a native codec should allow greater portability +of your code to other architectures besides x86 +and does not require your users to have Windows DLLs available. + +Determining item 3, the correct WAVEFORMATEX structure +for the codec, is the hardest part. If your code is +simply playing files encoded by the codec this is easy. +Your code must register the mapping between format tags +and DLL filenames (items 1 and 2 above) by making repeated +calls to MSACM_RegisterDriver(). Note that you will +often have to call MSACM_RegisterDriver() twice for each +codec, once to register it for the codec's format tag for +decoding, and once to register it with the PCM format tag +for encoding. Then to play a file you read the .wav header +from the beginning of the file and use that to create a +WAVEFORMATEX structure which you pass to the acmStreamOpen() +function. From there on out everything can be the same +as the example program. + +On the other hand, if your user is choosing the codec to +use for some encoding tasks, you do not have a .wav header +to read. The easiest thing to do in this case is probably +to create a .wav file in the desired format under Windows using +the Windows sound recorder. Then examine this file with +a hex editor and determine the appropriate values of the +fields to use in the WAVEFORMATEX structure. Note that +most codecs use extra fields beyond the basic WAVEFORMATEX +structure. test_truespeech.c shows how to create an extended +length WAVEFORMATEX and how to initialize the extra parts +for the TrueSpeech codec. A thorough writeup of the .wav +format headers is at + http://www.borg.com/~jglatt/tech/wave.htm + + +Most codecs will support 16-bit signed linear PCM, but probably +do not support a direct conversion to another proprietary +codec. To convert from one proprietary codec format to +another, typically a conversion to an intermediate 16-bit PCM +form is required. + diff --git a/linphone/win32acm/CREDITS b/linphone/win32acm/CREDITS new file mode 100644 index 000000000..0343fa20c --- /dev/null +++ b/linphone/win32acm/CREDITS @@ -0,0 +1,34 @@ + +This code was extracted from the mplayer +project (http://mplayerhq.hu) and slimmed down to support +only audio codecs. Apparently the mplayer project extracted +it from the Wine project (http://winehq.org). + + +The difficult work to load and use the Windows DLLs and emulate the +Windows ACM interface was done by (at a minimum) the following +individuals from the mplayer and Wine projects +as found in the current body of source code: + +Eugene Kuznetsov (divx@euro.ru) - WIN32 binary loader interface + shamelessly stolen from Wine +Bertho A. Stultiens - Elf-dll loader functions +Felix Buenemann - CPU detection +Alexandre Julliard - modules, pe_resource, lots of wine code +Eric Youndale - pe_image +Erik Bos - pe_image +Martin von Loewis - pe_image, pe_resource +Marcus Meissner - pe_image +Thomas Sandford - pe_resource +Robert J. Amstadt - pe_resource + + +The extraction from mplayer, slimming down, and use for encoding +TrueSpeech was done by the following individuals: + +Robert W. Brewer - test_truespeech.c, win32codec.c, + slimming, and documentation + +Piotr P. Karwasz - initial extraction from + mplayer code and example + loading of TrueSpeech dll diff --git a/linphone/win32acm/Makefile b/linphone/win32acm/Makefile new file mode 100644 index 000000000..5bbf7ee0c --- /dev/null +++ b/linphone/win32acm/Makefile @@ -0,0 +1,55 @@ + +# Generated automatically from Makefile.in by configure. +DEFINES=-DMPLAYER -D__WINE__ -Ddbg_printf=__vprintf \ + -DTRACE=__vprintf # -DDETAILED_OUT + +LIB = libwin32acm.a + +LIB_OBJECTS= ldt_keeper.o pe_image.o module.o \ +ext.o win32.o driver.o pe_resource.o \ +resource.o registry.o elfdll.o afl.o wrapper.o \ +cpudetect.o mp_msg.o win32codec.o + +# gcc-3.0 produces buggy code for acmStreamOpen() with +# "-O3 -fomit-frame-pointer" or "-O2 -fomit-frame-pointer +# -finline-functions -frename-registers" (code is OK with sole -O2), +# the bad code accesses parameters via %ebp without setting up a +# propper %ebp first! +# -fno-omit-frame-pointer works around this gcc-3.0 bug. gcc-2.95.2 is OK. +# Note: -D_FILE_OFFSET_BITS=32 is required to disable using mmap64(), +# as it's broken in glibc 2.1.2 (bad header) and 2.1.3 (bad code) +# put in $(OPT_FLAGS) for super speed +WARN_FLAGS = -Wall +CFLAGS=-I. -U_FILE_OFFSET_BITS -D_REENTRANT $(EXTRA_INC) $(WARN_FLAGS) -fno-omit-frame-pointer -g3 +#CFLAGS=-I. -I.. -O $(WARN_FLAGS) -g #-fno-omit-frame-pointer + +all: test_truespeech + +test_truespeech: test_truespeech.o $(LIB) + gcc -Wall -o test_truespeech test_truespeech.o $(LIB) \ + -lm -lpthread + +clean: + -rm -f test_truespeech *.o $(LIB) + +install: + +distdir: + +dist: + +distclean: clean +maintainer-clean: clean + +.c.o: $@ + $(CC) $(CFLAGS) $(DEFINES) -c $< + +$(LIB): $(LIB_OBJECTS) stubs.s + $(CC) -c ./stubs.s -o stubs.o +ifeq ($(TARGET_OS),OpenBSD) + ./loader_objfix.sh +endif + $(AR) -r $(LIB) $(LIB_OBJECTS) stubs.o + +dep: + echo "dependency not required/supported" diff --git a/linphone/win32acm/README b/linphone/win32acm/README new file mode 100644 index 000000000..268c2784f --- /dev/null +++ b/linphone/win32acm/README @@ -0,0 +1,128 @@ +Windows ACM (Audio Compression Manager) DLL library + + +PURPOSE + +This directory contains support for loading and using Windows ACM +(Audio Compression Manager) codecs from the native Windows DLL files. +Its purpose is to allow Linux programs running on the x86 architecture +to use proprietary Windows audio codecs. This enables Linux +users to interoperate with Windows users without +reverse engineering the codec completely from scratch. +For example, it should be straightforward to write a Linux +program based on this library to allow TrueSpeech encoded +.wav files to be exchanged with Windows users. Indeed, the provided +test program comes close to doing that, but for coding simplicity +it does not use .wav headers. + + +ACKNOWLEDGMENTS + +This code was extracted from the mplayer project (http://mplayerhq.hu), +which apparently extracted it from the Wine project (http://winehq.org). +It was slimmed down to support only the ACM audio codecs and not +video codecs. See the CREDITS file for details. + + +REQUIREMENTS + +To use the included TrueSpeech test program, the following Windows +DLLs are required: + + tsd32.dll + tssoft32.acm + +Other codecs may require other DLL files. A good source of +DLL files is the w32codecs archive, available at + http://mplayerhq.hu/MPlayer/releases/codecs/win32codecs.tar.bz2 +Debian users can install it using "apt-get install w32codecs". +Unfortunately, version 0.9 of w32codecs does not contain tsd32.dll. +You may need to obtain it via other means, such as copying it from +your Windows installation. + + +INSTALLATION + +The code is a library to be used in a larger program. To compile +it separately: + + vi config.h # edit as needed + vi Makefile # edit as needed + make + +This will build the output files libwin32acm.a and test_truespeech. + + +USAGE + +test_truespeech.c contains an example program to demonstrate use of +the ACM under Windows and to test the library with the TrueSpeech +codec. More documentation about using the ACM library functions +under Windows can be found at http://microsoft.com, specifically +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/audcomp_3kc2.asp +Or search for ACM on Microsoft's site. + +test_truespeech exercises the TrueSpeech +codec. It will read the file pcmin.raw in the current directory +and encode it via the TrueSpeech codec and write the result +to truespeechout.raw. It will then decode truespeechout.raw and +and produce the file pcmout.raw. Because TrueSpeech is a lossy +codec, the file pcmin.raw is not byte-for-byte identical to pcmout.raw, +however they should sound very similar. + +The files pcmin.raw and pcmout.raw can be played with the sox +utility "play" under Linux as follows. The options are +required because there is no header information in the file to inform +the player what format the file is in: + + play -f s -r 8000 -c 1 -s w pcmout.raw + +An example pcmin.raw file is included. +The format of the pcmin.raw file is PCM (pulse code modulation) +with 16-bit signed linear samples, mono (1 channel), at 8 KHz sampling rate. +It is basically a .wav file with the WAV headers removed, and can +be generated via the sox utility under Linux using options similar +to the "play" line above (specify a conversion +to .raw format). truespeechout.raw is a raw TrueSpeech file and +is approximately 1/15 the size of the input file. It is normally +not playable directly under Linux, although mplayer and some other +players which load the TrueSpeech DLL like this library does can +convert it to PCM on the fly for playing. + +If you would like to use the library with other ACM codecs besides +TrueSpeech, read the file CODECS for more information. + +win32codec.h and win32codec.c contain a simple wrapper around the +ACM codec functions to aid their use in Linphone. They can be +considered as another example. + + +TIPS FOR DEVELOPERS + +As shown in test_truespeech.c, the same input and output buffers +can be used for each block of data to convert without calling +acmStreamPrepareHeader() and acmStreamUnprepareHeader() over and +over. But if your application is using a different buffer for +each block of data, it is quite allowable to prepare and unprepare +the buffers each time a new block of data is converted. This is +what mplayer does, and it is also done in win32codec.c. Microsoft's +documentation about the ACM API is good, but the test_truespeech.c +example should be quite helpful. + +Microsoft's documentation does not clearly mention +that often a codec used in encoding mode requires +ACM_STREAMOPENF_NONREALTIME to be passed to +acmStreamOpen() or it will fail to open. This +parameter indicates that realtime operation is not required. +In the case of TrueSpeech, although the codec can operate perfectly +well in realtime on a modern PC, it appears the designers were conservative +and acmStreamOpen() will fail if realtime operation is requested. + +When converting from one proprietary codec format to another, +often 16-bit signed linear PCM must be used as an intermediate codec +step. Most codecs will support 16-bit signed linear PCM at a minimum +in addition to their own format. See CODECS for details on +using the library with ACM codecs besides TrueSpeech. + + Robert W. Brewer + 2003-05-31 \ No newline at end of file diff --git a/linphone/win32acm/TODO b/linphone/win32acm/TODO new file mode 100644 index 000000000..deb6f7598 --- /dev/null +++ b/linphone/win32acm/TODO @@ -0,0 +1,29 @@ + +use ./configure script to determine appropriate settings in config.h +and Makefile. + +fix segfault when closing acmStreams. Looks like it could +have something to do with using 2 streams at the same time +and then deallocating them. Appears that acmStreamClose() +attempting to close the driver when it is done is the wrong +thing. Maybe need reference counting of the driver so that +subsequent acmStreamOpen() calls just increment a refcount, +acmStreamClose() decrements it and when it reaches 0 it +closes the driver. Maybe make a simple test program to +open two acmStreams and then close them and see what happens. +Could run it under etrace for extra understanding. For +now the code in win32codec_destroy is commented out so +codecs are not properly destroyed. We can probably live with +a memory leak like that for a while. + +test with other audio codecs besides TrueSpeech. + + + +***** DONE ****** + +document the general procedure needed to get a new codec +working with the library. + +finish CREDITS file + diff --git a/linphone/win32acm/afl.c b/linphone/win32acm/afl.c new file mode 100644 index 000000000..d1024b1a5 --- /dev/null +++ b/linphone/win32acm/afl.c @@ -0,0 +1,753 @@ +/************************************************************************** + + + This file will contain an interface to ACM drivers. + Its content will be based mainly on wine/dlls/msacm32 + actually, for audio decompression only the following functions + are needed: + + acmStreamOpen ( takes formats of src and dest, returns stream handle ) + acmStreamPrepareHeader ( takes stream handler and info on data ) + acmStreamConvert ( the same as PrepareHeader ) + acmStreamUnprepareHeader + acmStreamClose + acmStreamSize + maybe acmStreamReset + + In future I'll also add functions for format enumeration, + but not right now. + + +***************************************************************************/ +#include "config.h" + +#include "wine/winbase.h" +#include "wine/windef.h" +#include "wine/winuser.h" +#include "wine/vfw.h" +#include "wine/winestring.h" +#include "wine/driver.h" +#include "wine/winerror.h" +#include "wine/msacm.h" +#include "wine/msacmdrv.h" +#include "wineacm.h" +#include "ext.h" +#include "driver.h" + +#include +#include +#include +#pragma pack(1) +#define OpenDriverA DrvOpen +#define CloseDriver DrvClose + +static inline PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has) +{ + return (PWINE_ACMSTREAM)has; +} + +/*********************************************************************** + * acmDriverAddA (MSACM32.2) + */ +MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule, + LPARAM lParam, DWORD dwPriority, DWORD fdwAdd) +{ + if (!phadid) + return MMSYSERR_INVALPARAM; + + /* Check if any unknown flags */ + if (fdwAdd & + ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND| + ACM_DRIVERADDF_GLOBAL)) + return MMSYSERR_INVALFLAG; + + /* Check if any incompatible flags */ + if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) && + (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND)) + return MMSYSERR_INVALFLAG; + + /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a + * LoadDriver on it, to be sure we can call SendDriverMessage on the + * hDrvr handle. + */ + *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, 0, hinstModule); + + /* FIXME: lParam, dwPriority and fdwAdd ignored */ + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * acmDriverClose (MSACM32.4) + */ +MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose) +{ + PWINE_ACMDRIVER p; + PWINE_ACMDRIVER* tp; + + if (fdwClose) + return MMSYSERR_INVALFLAG; + + p = MSACM_GetDriver(had); + if (!p) + return MMSYSERR_INVALHANDLE; + + for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) { + if (*tp == p) { + *tp = (*tp)->pNextACMDriver; + break; + } + } + + if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList) + CloseDriver(p->hDrvr); + + HeapFree(MSACM_hHeap, 0, p); + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * acmDriverEnum (MSACM32.7) + */ +MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum) +{ + PWINE_ACMDRIVERID p; + DWORD fdwSupport; + + if (!fnCallback) { + return MMSYSERR_INVALPARAM; + } + + if (fdwEnum && ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) { + return MMSYSERR_INVALFLAG; + } + + for (p = MSACM_pFirstACMDriverID; p; p = p->pNextACMDriverID) { + fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC; + if (!p->bEnabled) { + if (fdwEnum & ACM_DRIVERENUMF_DISABLED) + fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED; + else + continue; + } + (*fnCallback)((HACMDRIVERID) p, dwInstance, fdwSupport); + } + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * acmDriverID (MSACM32.8) + */ +MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID) +{ + PWINE_ACMOBJ pao; + + pao = MSACM_GetObj(hao); + if (!pao) + return MMSYSERR_INVALHANDLE; + + if (!phadid) + return MMSYSERR_INVALPARAM; + + if (fdwDriverID) + return MMSYSERR_INVALFLAG; + + *phadid = (HACMDRIVERID) pao->pACMDriverID; + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * acmDriverMessage (MSACM32.9) + * FIXME + * Not implemented + */ +LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2) +{ + PWINE_ACMDRIVER pad = MSACM_GetDriver(had); + if (!pad) + return MMSYSERR_INVALPARAM; + + /* FIXME: Check if uMsg legal */ + + if (!SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2)) + return MMSYSERR_NOTSUPPORTED; + + return MMSYSERR_NOERROR; +} + + +/*********************************************************************** + * acmDriverOpen (MSACM32.10) + */ +MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen) +{ + PWINE_ACMDRIVERID padid; + PWINE_ACMDRIVER pad; + ICOPEN icopen; + HDRVR hdrv; + + + TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen); + + if (!phad) + return MMSYSERR_INVALPARAM; + + padid = MSACM_GetDriverID(hadid); + if (!padid) + return MMSYSERR_INVALHANDLE; + + if (fdwOpen) + return MMSYSERR_INVALFLAG; + + pad = (PWINE_ACMDRIVER) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER)); + if (!pad) + return MMSYSERR_NOMEM; + + pad->obj.pACMDriverID = padid; + icopen.fccType = mmioFOURCC('a', 'u', 'd', 'c'); + icopen.fccHandler = (long)padid->pszFileName; + icopen.dwSize = sizeof(ICOPEN); + icopen.dwFlags = 0; + + icopen.pV1Reserved = padid->pszFileName; + if (!padid->hInstModule) + pad->hDrvr = OpenDriverA((long)&icopen); + else + pad->hDrvr = padid->hInstModule; + + if (!pad->hDrvr) { + HeapFree(MSACM_hHeap, 0, pad); + return MMSYSERR_ERROR; + } + + pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc"); + + /* insert new pad at beg of list */ + pad->pNextACMDriver = padid->pACMDriverList; + padid->pACMDriverList = pad; + + /* FIXME: Create a WINE_ACMDRIVER32 */ + *phad = (HACMDRIVER)pad; + + return MMSYSERR_NOERROR; +} + +/*********************************************************************** + * acmDriverRemove (MSACM32.12) + */ +MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove) +{ + PWINE_ACMDRIVERID padid; + + padid = MSACM_GetDriverID(hadid); + if (!padid) + return MMSYSERR_INVALHANDLE; + + if (fdwRemove) + return MMSYSERR_INVALFLAG; + + MSACM_UnregisterDriver(padid); + + return MMSYSERR_NOERROR; +} + + + +/**********************************************************************/ + +HANDLE MSACM_hHeap = (HANDLE) NULL; +PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL; +PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL; + +/*********************************************************************** + * MSACM_RegisterDriver32() + */ +PWINE_ACMDRIVERID MSACM_RegisterDriver(const char* pszFileName, + WORD wFormatTag, + HINSTANCE hinstModule) +{ + PWINE_ACMDRIVERID padid; + + TRACE("('%s', '%x', 0x%08x)\n", pszFileName, wFormatTag, hinstModule); + + padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID)); + padid->pszFileName = (char*)malloc(strlen(pszFileName)+1); + strcpy(padid->pszFileName, pszFileName); +// 1~strdup(pszDriverAlias); + padid->wFormatTag = wFormatTag; + padid->hInstModule = hinstModule; + padid->bEnabled = TRUE; + padid->pACMDriverList = NULL; + padid->pNextACMDriverID = NULL; + padid->pPrevACMDriverID = MSACM_pLastACMDriverID; + if (MSACM_pLastACMDriverID) + MSACM_pLastACMDriverID->pNextACMDriverID = padid; + MSACM_pLastACMDriverID = padid; + if (!MSACM_pFirstACMDriverID) + MSACM_pFirstACMDriverID = padid; + + return padid; +} + + +/*********************************************************************** + * MSACM_UnregisterDriver32() + */ +PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p) +{ + PWINE_ACMDRIVERID pNextACMDriverID; + + while (p->pACMDriverList) + acmDriverClose((HACMDRIVER) p->pACMDriverList, 0); + + if (p->pszFileName) + free(p->pszFileName); + + if (p == MSACM_pFirstACMDriverID) + MSACM_pFirstACMDriverID = p->pNextACMDriverID; + if (p == MSACM_pLastACMDriverID) + MSACM_pLastACMDriverID = p->pPrevACMDriverID; + + if (p->pPrevACMDriverID) + p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID; + if (p->pNextACMDriverID) + p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID; + + pNextACMDriverID = p->pNextACMDriverID; + + HeapFree(MSACM_hHeap, 0, p); + + return pNextACMDriverID; +} + +/*********************************************************************** + * MSACM_UnregisterAllDrivers32() + * FIXME + * Where should this function be called? + */ +void MSACM_UnregisterAllDrivers(void) +{ + PWINE_ACMDRIVERID p; + + for (p = MSACM_pFirstACMDriverID; p; p = MSACM_UnregisterDriver(p)); +} + +/*********************************************************************** + * MSACM_GetDriverID32() + */ +PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID) +{ + return (PWINE_ACMDRIVERID)hDriverID; +} + +/*********************************************************************** + * MSACM_GetDriver32() + */ +PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver) +{ + return (PWINE_ACMDRIVER)hDriver; +} + +/*********************************************************************** + * MSACM_GetObj32() + */ +PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj) +{ + return (PWINE_ACMOBJ)hObj; +} + + + +/*********************************************************************** + * acmStreamOpen (MSACM32.40) + */ +MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc, + PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + PWINE_ACMSTREAM was; + PWINE_ACMDRIVER wad; + MMRESULT ret; + int wfxSrcSize; + int wfxDstSize; + + TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n", + phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen); + + TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", + pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, + pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize); + + TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", + pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, + pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize); + +#define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize)) + wfxSrcSize = SIZEOF_WFX(pwfxSrc); + wfxDstSize = SIZEOF_WFX(pwfxDst); +#undef SIZEOF_WFX + + was = (PWINE_ACMSTREAM) HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0)); + if (was == NULL) + return MMSYSERR_NOMEM; + was->drvInst.cbStruct = sizeof(was->drvInst); + was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was)); + memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize); + // LHACM is checking for 0x1 + // but if this will not help + // was->drvInst.pwfxSrc->wFormatTag = 1; + was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize); + memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize); + if (pwfltr) { + was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize); + memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER)); + } else { + was->drvInst.pwfltr = NULL; + } + was->drvInst.dwCallback = dwCallback; + was->drvInst.dwInstance = dwInstance; + was->drvInst.fdwOpen = fdwOpen; + was->drvInst.fdwDriver = 0L; + was->drvInst.dwDriver = 0L; + was->drvInst.has = (HACMSTREAM)was; + + if (had) { + if (!(wad = MSACM_GetDriver(had))) { + ret = MMSYSERR_INVALPARAM; + goto errCleanUp; + } + + was->obj.pACMDriverID = wad->obj.pACMDriverID; + was->pDrv = wad; + was->hAcmDriver = 0; /* not to close it in acmStreamClose */ + + ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L); + if (ret != MMSYSERR_NOERROR) + goto errCleanUp; + } else { + PWINE_ACMDRIVERID wadi; + short drv_tag; + ret = ACMERR_NOTPOSSIBLE; +/* if(pwfxSrc->wFormatTag==1)//compression + drv_tag=pwfxDst->wFormatTag; + else + if(pwfxDst->wFormatTag==1)//decompression + drv_tag=pwfxSrc->wFormatTag; + else + goto errCleanUp; + + ret=acmDriverOpen2(drv_tag); + if (ret == MMSYSERR_NOERROR) { + if ((wad = MSACM_GetDriver(had)) != 0) { + was->obj.pACMDriverID = wad->obj.pACMDriverID; + was->pDrv = wad; + was->hAcmDriver = had; + + ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L); + if (ret == MMSYSERR_NOERROR) { + if (fdwOpen & ACM_STREAMOPENF_QUERY) { + acmDriverClose(had, 0L); + } + break; + } + } + acmDriverClose(had, 0L);*/ + //if(MSACM_pFirstACMDriverID==NULL) + // MSACM_RegisterAllDrivers(); + + for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) + { + /* Check Format */ + if ((int)wadi->wFormatTag != (int)pwfxSrc->wFormatTag) continue; + + ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L); + if (ret == MMSYSERR_NOERROR) { + if ((wad = MSACM_GetDriver(had)) != 0) { + was->obj.pACMDriverID = wad->obj.pACMDriverID; + was->pDrv = wad; + was->hAcmDriver = had; + + ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L); + //lhacm - crash printf("RETOPEN %d\n", ret); + //ret = 0; + if (ret == MMSYSERR_NOERROR) { + if (fdwOpen & ACM_STREAMOPENF_QUERY) { + acmDriverClose(had, 0L); + } + break; + } + } + // no match, close this acm driver and try next one + acmDriverClose(had, 0L); + } + } + if (ret != MMSYSERR_NOERROR) { + ret = ACMERR_NOTPOSSIBLE; + goto errCleanUp; + } + } + ret = MMSYSERR_NOERROR; + if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) { + if (phas) + *phas = (HACMSTREAM)was; + TRACE("=> (%d)\n", ret); + CodecAlloc(); + return ret; + } +errCleanUp: + if (phas) + *phas = (HACMSTREAM)0; + HeapFree(MSACM_hHeap, 0, was); + TRACE("=> (%d)\n", ret); + return ret; +} + + +MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose) +{ + PWINE_ACMSTREAM was; + MMRESULT ret; + + TRACE("(0x%08x, %ld)\n", has, fdwClose); + + if ((was = ACM_GetStream(has)) == NULL) { + return MMSYSERR_INVALHANDLE; + } + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0); + if (ret == MMSYSERR_NOERROR) { + if (was->hAcmDriver) + acmDriverClose(was->hAcmDriver, 0L); + HeapFree(MSACM_hHeap, 0, was); + CodecRelease(); + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamConvert (MSACM32.38) + */ +MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, + DWORD fdwConvert) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + PACMDRVSTREAMHEADER padsh; + + TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert); + + if ((was = ACM_GetStream(has)) == NULL) + return MMSYSERR_INVALHANDLE; + if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) + return MMSYSERR_INVALPARAM; + + if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) + return ACMERR_UNPREPARED; + + /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same + * size. some fields are private to msacm internals, and are exposed + * in ACMSTREAMHEADER in the dwReservedDriver array + */ + padsh = (PACMDRVSTREAMHEADER)pash; + + /* check that pointers have not been modified */ + if (padsh->pbPreparedSrc != padsh->pbSrc || + padsh->cbPreparedSrcLength < padsh->cbSrcLength || + padsh->pbPreparedDst != padsh->pbDst || + padsh->cbPreparedDstLength < padsh->cbDstLength) { + return MMSYSERR_INVALPARAM; + } + + padsh->fdwConvert = fdwConvert; + + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh); + if (ret == MMSYSERR_NOERROR) { + padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE; + } + TRACE("=> (%d)\n", ret); + return ret; +} + + +/*********************************************************************** + * acmStreamPrepareHeader (MSACM32.41) + */ +MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, + DWORD fdwPrepare) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + PACMDRVSTREAMHEADER padsh; + + TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare); + + if ((was = ACM_GetStream(has)) == NULL) + return MMSYSERR_INVALHANDLE; + if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) + return MMSYSERR_INVALPARAM; + if (fdwPrepare) + ret = MMSYSERR_INVALFLAG; + + if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE) + return MMSYSERR_NOERROR; + + /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same + * size. some fields are private to msacm internals, and are exposed + * in ACMSTREAMHEADER in the dwReservedDriver array + */ + padsh = (PACMDRVSTREAMHEADER)pash; + + padsh->fdwConvert = fdwPrepare; + padsh->padshNext = NULL; + padsh->fdwDriver = padsh->dwDriver = 0L; + + padsh->fdwPrepared = 0; + padsh->dwPrepared = 0; + padsh->pbPreparedSrc = 0; + padsh->cbPreparedSrcLength = 0; + padsh->pbPreparedDst = 0; + padsh->cbPreparedDstLength = 0; + + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh); + if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) { + ret = MMSYSERR_NOERROR; + padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE); + padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED; + padsh->fdwPrepared = padsh->fdwStatus; + padsh->dwPrepared = 0; + padsh->pbPreparedSrc = padsh->pbSrc; + padsh->cbPreparedSrcLength = padsh->cbSrcLength; + padsh->pbPreparedDst = padsh->pbDst; + padsh->cbPreparedDstLength = padsh->cbDstLength; + } else { + padsh->fdwPrepared = 0; + padsh->dwPrepared = 0; + padsh->pbPreparedSrc = 0; + padsh->cbPreparedSrcLength = 0; + padsh->pbPreparedDst = 0; + padsh->cbPreparedDstLength = 0; + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamReset (MSACM32.42) + */ +MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(0x%08x, %ld)\n", has, fdwReset); + + if (fdwReset) { + ret = MMSYSERR_INVALFLAG; + } else if ((was = ACM_GetStream(has)) == NULL) { + return MMSYSERR_INVALHANDLE; + } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) { + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0); + } + TRACE("=> (%d)\n", ret); + return ret; +} + +/*********************************************************************** + * acmStreamSize (MSACM32.43) + */ +MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, + LPDWORD pdwOutputBytes, DWORD fdwSize) +{ + PWINE_ACMSTREAM was; + ACMDRVSTREAMSIZE adss; + MMRESULT ret; + + TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize); + + if ((was = ACM_GetStream(has)) == NULL) { + return MMSYSERR_INVALHANDLE; + } + if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) { + return MMSYSERR_INVALFLAG; + } + + *pdwOutputBytes = 0L; + + switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) { + case ACM_STREAMSIZEF_DESTINATION: + adss.cbDstLength = cbInput; + adss.cbSrcLength = 0; + break; + case ACM_STREAMSIZEF_SOURCE: + adss.cbSrcLength = cbInput; + adss.cbDstLength = 0; + break; + default: + return MMSYSERR_INVALFLAG; + } + + adss.cbStruct = sizeof(adss); + adss.fdwSize = fdwSize; + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, + (DWORD)&was->drvInst, (DWORD)&adss); + if (ret == MMSYSERR_NOERROR) { + switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) { + case ACM_STREAMSIZEF_DESTINATION: + *pdwOutputBytes = adss.cbSrcLength; + break; + case ACM_STREAMSIZEF_SOURCE: + *pdwOutputBytes = adss.cbDstLength; + break; + } + } + TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes); + return ret; +} + +/*********************************************************************** + * acmStreamUnprepareHeader (MSACM32.44) + */ +MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, + DWORD fdwUnprepare) +{ + PWINE_ACMSTREAM was; + MMRESULT ret = MMSYSERR_NOERROR; + PACMDRVSTREAMHEADER padsh; + + TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare); + + if ((was = ACM_GetStream(has)) == NULL) + return MMSYSERR_INVALHANDLE; + if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) + return MMSYSERR_INVALPARAM; + + if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) + return ACMERR_UNPREPARED; + + /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same + * size. some fields are private to msacm internals, and are exposed + * in ACMSTREAMHEADER in the dwReservedDriver array + */ + padsh = (PACMDRVSTREAMHEADER)pash; + + /* check that pointers have not been modified */ + if (padsh->pbPreparedSrc != padsh->pbSrc || + padsh->cbPreparedSrcLength < padsh->cbSrcLength || + padsh->pbPreparedDst != padsh->pbDst || + padsh->cbPreparedDstLength < padsh->cbDstLength) { + return MMSYSERR_INVALPARAM; + } + + padsh->fdwConvert = fdwUnprepare; + + ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh); + if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) { + ret = MMSYSERR_NOERROR; + padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED); + } + TRACE("=> (%d)\n", ret); + return ret; +} diff --git a/linphone/win32acm/com.h b/linphone/win32acm/com.h new file mode 100644 index 000000000..39cbdcb49 --- /dev/null +++ b/linphone/win32acm/com.h @@ -0,0 +1,84 @@ +#ifndef AVIFILE_COM_H +#define AVIFILE_COM_H + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#else +#include +#endif + +/** + * Internal functions and structures for COM emulation code. + */ + +#ifndef WIN32 + +#ifdef __cplusplus +extern "C" { +#endif + +void* CoTaskMemAlloc(unsigned long cb); +void CoTaskMemFree(void* cb); + +#ifndef GUID_TYPE +#define GUID_TYPE +typedef struct +{ + uint32_t f1; + uint16_t f2; + uint16_t f3; + uint8_t f4[8]; +} GUID; +#endif + +extern const GUID IID_IUnknown; +extern const GUID IID_IClassFactory; + +typedef long (*GETCLASSOBJECT) (GUID* clsid, const GUID* iid, void** ppv); +int RegisterComClass(const GUID* clsid, GETCLASSOBJECT gcs); +int UnregisterComClass(const GUID* clsid, GETCLASSOBJECT gcs); + +#ifndef STDCALL +#define STDCALL __attribute__((__stdcall__)) +#endif + +struct IUnknown; +struct IClassFactory; +struct IUnknown_vt +{ + long STDCALL (*QueryInterface)(struct IUnknown* _this, const GUID* iid, void** ppv); + long STDCALL (*AddRef)(struct IUnknown* _this) ; + long STDCALL (*Release)(struct IUnknown* _this) ; +} ; + +typedef struct IUnknown +{ + struct IUnknown_vt* vt; +} IUnknown; + +struct IClassFactory_vt +{ + long STDCALL (*QueryInterface)(struct IUnknown* _this, const GUID* iid, void** ppv); + long STDCALL (*AddRef)(struct IUnknown* _this) ; + long STDCALL (*Release)(struct IUnknown* _this) ; + long STDCALL (*CreateInstance)(struct IClassFactory* _this, struct IUnknown* pUnkOuter, const GUID* riid, void** ppvObject); +}; + +struct IClassFactory +{ + struct IClassFactory_vt* vt; +}; + +long CoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter, + long dwClsContext, const GUID* riid, void** ppv); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* WIN32 */ + +#endif /* AVIFILE_COM_H */ diff --git a/linphone/win32acm/config.h b/linphone/win32acm/config.h new file mode 100644 index 000000000..a62e43548 --- /dev/null +++ b/linphone/win32acm/config.h @@ -0,0 +1,51 @@ +/* configuration options for the win32 ACM loader library. + * Please edit these to correspond to what your setup requires. + * So far it has only been tested on x86 Debian Linux (Sid). + * If you discover you need to make changes, refer to config.h.bak + * which is the original bloated version of this file which may + * offer some hints. We are trying to slim this code down as much as + * possible which is why that file is deprecated. + */ + +/* Define this if your system has the "malloc.h" header file */ +#define HAVE_MALLOC_H 1 + + +/* Define this if you have the elf dynamic linker -ldl library */ +#define HAVE_LIBDL 1 + + +/* Define this if your system has the "sys/mman.h" header file */ +#define HAVE_SYS_MMAN_H 1 + +/* Define this if your system has vsscanf */ +#define HAVE_VSSCANF 1 + +/* Define this if you have the kstat kernel statistics library */ +#undef HAVE_LIBKSTAT + +/* nanosleep support */ +#define HAVE_NANOSLEEP 1 + +/* Win32 DLL support */ +#define WIN32_PATH "/usr/local/lib/win32" + +/* enables / disables QTX codecs */ +#define USE_QTX_CODECS 1 + + +/* Extension defines */ +#define ARCH_X86 1 + +#define HAVE_3DNOW 1 // only define if you have 3DNOW (AMD k6-2, AMD Athlon, iDT WinChip, etc.) +#define HAVE_3DNOWEX 1 // only define if you have 3DNOWEX (AMD Athlon, etc.) +#define HAVE_MMX 1 // only define if you have MMX (newer x86 chips, not P54C/PPro) +#define HAVE_MMX2 1 // only define if you have MMX2 (Athlon/PIII/4/CelII) +#define HAVE_SSE 1 // only define if you have SSE (Intel Pentium III/4 or Celeron II) +#undef HAVE_SSE2 // only define if you have SSE2 (Intel Pentium 4) +#undef HAVE_ALTIVEC // only define if you have Altivec (G4) + +#ifdef HAVE_MMX +#define USE_MMX_IDCT 1 +#endif + diff --git a/linphone/win32acm/config.h.bak b/linphone/win32acm/config.h.bak new file mode 100644 index 000000000..96d95b981 --- /dev/null +++ b/linphone/win32acm/config.h.bak @@ -0,0 +1,465 @@ +/* -------- This file has been automatically generated by configure --------- + Note: Any changes in it will be lost when you run configure again. */ + +/* use GNU internationalization */ +#define USE_I18N 1 + +/* use setlocale() function */ +#define USE_SETLOCALE 1 + +/* Runtime CPU detection */ +#undef RUNTIME_CPUDETECT + +/* Dynamic a/v plugins */ +#undef DYNAMIC_PLUGINS + +/* "restrict" keyword */ +#define restrict __restrict + +#define PREFIX "/usr/local" + +/* define this to use simple idct with patched libavcodec */ +#define SIMPLE_IDCT 1 + +#define USE_OSD 1 +#define USE_SUB 1 + +/* enable/disable SIGHANDLER */ +#define ENABLE_SIGHANDLER 1 + +/* Toggles debugging informations */ +#undef MP_DEBUG + +/* Indicates that Ogle's libdvdread is available for DVD playback */ +#define USE_DVDREAD 1 + +/* Indicates that dvdread is from libmpdvdkit */ +#define USE_MPDVDKIT 2 + +/* Additional options for libmpdvdkit*/ +#undef DVD_STRUCT_IN_DVD_H +#define DVD_STRUCT_IN_LINUX_CDROM_H 1 +#undef DVD_STRUCT_IN_SYS_CDIO_H +#undef DVD_STRUCT_IN_SYS_DVDIO_H +#undef DVD_STRUCT_IN_BSDI_DVDIOCTL_DVD_H +#undef HAVE_BSD_DVD_STRUCT +#define HAVE_LINUX_DVD_STRUCT 1 +#undef HAVE_OPENBSD_DVD_STRUCT +#undef DARWIN_DVD_IOCTL +#undef SOLARIS_USCSI +#undef HPUX_SCTL_IO +#define HAVE_STDDEF_H 1 + +/* Common data directory (for fonts, etc) */ +#define DATADIR "/usr/local/share/mplayer" +#define CONFDIR "/usr/local/etc/mplayer" +#define LIBDIR "/usr/local/lib" + +/* Define this to compile stream-caching support, it can be enabled via + -cache */ +#define USE_STREAM_CACHE 1 + +/* Define to include support for XviD/Divx4Linux/OpenDivx */ +#define USE_DIVX + +/* Define to use the new XviD/DivX4Linux library instead of open source OpenDivX */ +/* You have to change DECORE_LIBS in config.mak, too! */ +#define NEW_DECORE 1 + +/* Define if you are using DivX5Linux Decore library */ +#define DECORE_DIVX5 1 + +/* Define if you are using XviD library */ +#define HAVE_XVID 1 +#undef DECORE_XVID +#undef ENCORE_XVID + +/* Define to include support for libdv-0.9.5 */ +#undef HAVE_LIBDV095 + +/* If build mencoder */ +#define HAVE_MENCODER + +/* Indicates if XviD/Divx4linux encore is available + Note: for mencoder */ +#define HAVE_DIVX4ENCORE 1 + +/* Indicates if libmp3lame is available + Note: for mencoder */ +#define HAVE_MP3LAME 393 + +/* Define libmp1e for realtime mpeg encoding (for DXR3 and DVB cards) */ +#undef USE_MP1E + +/* Define this to enable avg. byte/sec-based AVI sync method by default: + (use -bps or -nobps commandline option for run-time method selection) + -bps gives better sync for vbr mp3 audio, it is now default */ +#define AVI_SYNC_BPS 1 + +/* Undefine this if you do not want to select mono audio (left or right) + with a stereo MPEG layer 2/3 audio stream. The command line option + -stereo has three possible values (0 for stereo, 1 for left-only, 2 for + right-only), with 0 being the default. + */ +#define USE_FAKE_MONO 1 + +/* Undefine this if your sound card driver has no working select(). + If you have kernel Oops, player hangups, or just no audio, you should + try to recompile MPlayer with this option disabled! */ +#define HAVE_AUDIO_SELECT 1 + +/* define this to use iconv(3) function to codepage conversions */ +#define USE_ICONV 1 + +/* define this to use RTC (/dev/rtc) for video timers (LINUX only) */ +#define HAVE_RTC 1 + +/* set up max. outburst. use 65536 for ALSA 0.5, for others 16384 is enough */ +#define MAX_OUTBURST 65536 + +/* set up audio OUTBURST. Do not change this! */ +#define OUTBURST 512 + +/* Define this if your system has the header file for the OSS sound interface */ +#define HAVE_SYS_SOUNDCARD_H 1 + +/* Define this if your system has the header file for the OSS sound interface + * in /usr/include */ +#undef HAVE_SOUNDCARD_H + +/* Define this if your system has the sysinfo header */ +#define HAVE_SYS_SYSINFO_H 1 + +/* Define this if your system uses ftello() for off_t seeking */ + +#define HAVE_FTELLO 1 +#ifndef HAVE_FTELLO +# define ftello(a) ftell(a) +#endif + +/* Define this if your system has the "malloc.h" header file */ +#define HAVE_MALLOC_H 1 + +/* memalign is mapped to malloc if unsupported */ +#define HAVE_MEMALIGN 1 +#ifndef HAVE_MEMALIGN +# define memalign(a,b) malloc(b) +#endif + +/* Define this if your system has the "alloca.h" header file */ +#define HAVE_ALLOCA_H 1 + +/* Define this if your system has the "sys/mman.h" header file */ +#define HAVE_SYS_MMAN_H 1 + +/* Define this if you have the elf dynamic linker -ldl library */ +#define HAVE_LIBDL 1 + +/* Define this if you have the kstat kernel statistics library */ +#undef HAVE_LIBKSTAT + +/* Define this if you have zlib */ +#define HAVE_ZLIB 1 + +/* Define this if you have shm support */ +#define HAVE_SHM 1 + +/* Define this if your system has scandir & alphasort */ +#define HAVE_SCANDIR 1 + +/* Define this if your system has strsep */ +#define HAVE_STRSEP 1 + +/* Define this if your system has vsscanf */ +#define HAVE_VSSCANF 1 + +/* LIRC (remote control, see www.lirc.org) support: */ +#undef HAVE_LIRC + +/* DeCSS support using libcss */ +#undef HAVE_LIBCSS + +/* DVD navigation support using libdvdnav */ +#undef USE_DVDNAV + + +/* Define this to enable MPEG 1/2 image postprocessing (requires a FAST CPU!) */ +#define MPEG12_POSTPROC 1 + +/* Define this to enable image postprocessing in libavcodec (requires a FAST CPU!) */ +#define FF_POSTPROCESS 1 + +/* Define to include support for OpenDivx postprocessing */ +#undef HAVE_ODIVX_POSTPROCESS + +/* Win32 DLL support */ +#define USE_WIN32DLL 1 +#define WIN32_PATH "/usr/local/lib/win32" + +/* DirectShow support */ +#define USE_DIRECTSHOW 1 + +/* Mac OS X specific features */ +#undef MACOSX + +/* Build our Win32-loader */ +#define WIN32_LOADER 1 + +/* ffmpeg's libavcodec support (requires libavcodec source) */ +#define USE_LIBAVCODEC 1 +#undef USE_LIBAVCODEC_SO + +/* risky codecs */ +#define CONFIG_RISKY 1 + +/* Use libavcodec's decoders */ +#define CONFIG_DECODERS 1 +/* Use libavcodec's encoders */ +#define CONFIG_ENCODERS 1 + +/* Use codec libs included in mplayer CVS / source dist: */ +#define USE_MP3LIB +#define USE_LIBA52 +#define USE_LIBMPEG2 + +/* Use the SVQ1 decoder in libmpcodecs - we don't want/need it with libavcodec */ +#ifndef USE_LIBAVCODEC +#define USE_SVQ1 +#endif + +/* Use libfame encoder filter */ +#undef USE_LIBFAME + +/* XAnim DLL support */ +#undef USE_XANIM +/* Default search path */ +#undef XACODEC_PATH + +/* RealPlayer DLL support */ +#define USE_REALCODECS 1 +/* Default search path */ +#define REALCODEC_PATH "/usr/lib/RealPlayer8/Codecs" + +/* LIVE.COM Streaming Media library support */ +#undef STREAMING_LIVE_DOT_COM + +/* Use 3dnow/mmxext/sse/mmx optimized fast memcpy() [maybe buggy... signal 4]*/ +#define USE_FASTMEMCPY 1 + +/* Use unrarlib for Vobsubs */ +#define USE_UNRARLIB 1 + +/* gui support, please do not edit this option */ +#undef HAVE_NEW_GUI + +/* Audio output drivers */ +#define USE_OSS_AUDIO 1 +#define PATH_DEV_DSP "/dev/dsp" +#define PATH_DEV_MIXER "/dev/mixer" +#undef HAVE_ALSA5 +#undef HAVE_ALSA9 + +#define USE_ESD 1 +#undef HAVE_SYS_ASOUNDLIB_H +#undef HAVE_ALSA_ASOUNDLIB_H +#undef USE_SUN_AUDIO +#undef USE_SGI_AUDIO +#undef HAVE_WIN32WAVEOUT +#undef HAVE_NAS + +/* Enable fast OSD/SUB renderer (looks ugly, but uses less CPU power) */ +#undef FAST_OSD +#undef FAST_OSD_TABLE + +/* Enable TV Interface support */ +#define USE_TV 1 + +/* Enable EDL support */ +#define USE_EDL + +/* Enable Video 4 Linux TV interface support */ +#undef HAVE_TV_V4L + +/* Enable *BSD BrookTree TV interface support */ +#undef HAVE_TV_BSDBT848 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +#define ARCH_X86 1 + +/* Define this for Cygwin build for win32 */ + + +/* Define this to any prefered value from 386 up to infinity with step 100 */ +#define __CPU__ 686 + +#define MP_WORDSIZE 32 + +#define TARGET_LINUX 1 + +#define HAVE_VCD 1 + +#ifdef sun +#define DEFAULT_CDROM_DEVICE "/vol/dev/aliases/cdrom0" +#define DEFAULT_DVD_DEVICE DEFAULT_CDROM_DEVICE +#elif defined(HPUX) +#define DEFAULT_CDROM_DEVICE "/dev/cdrom" +#define DEFAULT_DVD_DEVICE "/dev/dvd" +#elif defined(WIN32) +#define DEFAULT_CDROM_DEVICE "D:" +#define DEFAULT_DVD_DEVICE "D:" +#elif defined(SYS_DARWIN) +#define DEFAULT_CDROM_DEVICE "/dev/rdiskN" +#define DEFAULT_DVD_DEVICE DEFAULT_CDROM_DEVICE +#else +#define DEFAULT_CDROM_DEVICE "/dev/cdrom" +#define DEFAULT_DVD_DEVICE "/dev/dvd" +#endif + + +/*---------------------------------------------------------------------------- +** +** NOTE: Instead of modifying these definitions here, use the +** --enable/--disable options of the ./configure script! +** See ./configure --help for details. +** +*---------------------------------------------------------------------------*/ + +/* C99 lrintf function available */ +#define HAVE_LRINTF 1 + +/* nanosleep support */ +#define HAVE_NANOSLEEP 1 + +/* termcap flag for getch2.c */ +#define USE_TERMCAP 1 + +/* termios flag for getch2.c */ +#define HAVE_TERMIOS 1 +#undef HAVE_TERMIOS_H +#define HAVE_SYS_TERMIOS_H 1 + +/* enable PNG support */ +#define HAVE_PNG 1 + +/* enable JPEG support */ +#define HAVE_JPEG 1 + +/* enable GIF support */ +#define HAVE_GIF 1 +#define HAVE_GIF_4 1 +#undef HAVE_GIF_TVT_HACK + +/* enable FreeType support */ +#define HAVE_FREETYPE + +/* liblzo support */ +#undef USE_LIBLZO + +/* libmad support */ +#define USE_LIBMAD 1 + +/* enable OggVorbis support */ +#undef HAVE_OGGVORBIS + +/* enable Tremor as vorbis decoder */ +#undef TREMOR + +/* enable FAAD (AAC) support */ +#undef HAVE_FAAD + + +/* enable streaming */ +#define STREAMING 1 + +/* define this to use inet_aton() instead of inet_pton() */ +#undef USE_ATON + +/* enables / disables cdparanoia support */ +#undef HAVE_CDDA + +/* enables / disables VIDIX usage */ +#define CONFIG_VIDIX 1 + +/* enables / disables new input joystick support */ +#undef HAVE_JOYSTICK + +/* enables / disables new config */ +#define NEW_CONFIG 1 + +/* enables / disables QTX codecs */ +#define USE_QTX_CODECS 1 + +/* enables / disables osd menu */ +#undef HAVE_MENU + +/* enables / disables subtitles sorting */ +#define USE_SORTSUB 1 + +/* XMMS input plugin support */ +#undef HAVE_XMMS +#define XMMS_INPUT_PLUGIN_DIR "" + +/* Extension defines */ +#define HAVE_3DNOW 1 // only define if you have 3DNOW (AMD k6-2, AMD Athlon, iDT WinChip, etc.) +#define HAVE_3DNOWEX 1 // only define if you have 3DNOWEX (AMD Athlon, etc.) +#define HAVE_MMX 1 // only define if you have MMX (newer x86 chips, not P54C/PPro) +#define HAVE_MMX2 1 // only define if you have MMX2 (Athlon/PIII/4/CelII) +#define HAVE_SSE 1 // only define if you have SSE (Intel Pentium III/4 or Celeron II) +#undef HAVE_SSE2 // only define if you have SSE2 (Intel Pentium 4) +#undef HAVE_ALTIVEC // only define if you have Altivec (G4) + +#ifdef HAVE_MMX +#define USE_MMX_IDCT 1 +#endif + +#undef HAVE_MLIB // Sun mediaLib, available only on solaris + +/* libmpeg2 uses a different feature test macro for mediaLib */ +#ifdef HAVE_MLIB +#define LIBMPEG2_MLIB 1 +#endif + +/* libvo options */ +#define SCREEN_SIZE_X 1 +#define SCREEN_SIZE_Y 1 +#define HAVE_X11 1 +#define HAVE_XV 1 +#define HAVE_XF86VM 1 +#define HAVE_XINERAMA 1 +#define HAVE_GL 1 +#define HAVE_DGA 1 +#define HAVE_DGA2 1 +#undef HAVE_SDL +/* defined for SDLlib with keyrepeat bugs (before 1.2.1) */ + +#undef HAVE_DIRECTX +#undef HAVE_GGI +#undef HAVE_3DFX +#undef HAVE_TDFXFB +#undef HAVE_DIRECTFB + +#undef HAVE_ZR +#undef HAVE_BL +#undef HAVE_MGA +#undef HAVE_XMGA + +#undef HAVE_FBDEV +#undef USE_CONVERT2FB +#undef HAVE_DXR2 +#undef HAVE_DXR3 +#undef HAVE_DVB +#undef HAVE_SVGALIB +#define HAVE_VESA 1 +#define HAVE_XDPMS 1 +#undef HAVE_AA + +/* used by GUI: */ + + +#if defined(HAVE_GL) || defined(HAVE_X11) || defined(HAVE_XV) +#define X11_FULLSCREEN 1 +#endif + diff --git a/linphone/win32acm/cpudetect.c b/linphone/win32acm/cpudetect.c new file mode 100644 index 000000000..401dadc10 --- /dev/null +++ b/linphone/win32acm/cpudetect.c @@ -0,0 +1,506 @@ +#include "config.h" +#include "cpudetect.h" +#include "mp_msg.h" + +CpuCaps gCpuCaps; + +#ifdef HAVE_MALLOC_H +#include +#endif +#include + +#ifdef ARCH_X86 + +#include +#include + +#ifdef __NetBSD__ +#include +#include +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +#ifdef __linux__ +#include +#endif + +//#define X86_FXSR_MAGIC +/* Thanks to the FreeBSD project for some of this cpuid code, and + * help understanding how to use it. Thanks to the Mesa + * team for SSE support detection and more cpu detect code. + */ + +/* I believe this code works. However, it has only been used on a PII and PIII */ + +static void check_os_katmai_support( void ); + +#if 1 +// return TRUE if cpuid supported +static int has_cpuid() +{ + int a, c; + +// code from libavcodec: + __asm__ __volatile__ ( + /* See if CPUID instruction is supported ... */ + /* ... Get copies of EFLAGS into eax and ecx */ + "pushf\n\t" + "popl %0\n\t" + "movl %0, %1\n\t" + + /* ... Toggle the ID bit in one copy and store */ + /* to the EFLAGS reg */ + "xorl $0x200000, %0\n\t" + "push %0\n\t" + "popf\n\t" + + /* ... Get the (hopefully modified) EFLAGS */ + "pushf\n\t" + "popl %0\n\t" + : "=a" (a), "=c" (c) + : + : "cc" + ); + + return (a!=c); +} +#endif + +static void +do_cpuid(unsigned int ax, unsigned int *p) +{ +#if 0 + __asm __volatile( + "cpuid;" + : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) + : "0" (ax) + ); +#else +// code from libavcodec: + __asm __volatile + ("movl %%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl %%ebx, %%esi" + : "=a" (p[0]), "=S" (p[1]), + "=c" (p[2]), "=d" (p[3]) + : "0" (ax)); +#endif + +} + +void GetCpuCaps( CpuCaps *caps) +{ + unsigned int regs[4]; + unsigned int regs2[4]; + + memset(caps, 0, sizeof(*caps)); + caps->isX86=1; + caps->cl_size=32; /* default */ + if (!has_cpuid()) { + mp_msg(MSGT_CPUDETECT,MSGL_WARN,"CPUID not supported!??? (maybe an old 486?)\n"); + return; + } + do_cpuid(0x00000000, regs); // get _max_ cpuid level and vendor name + mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU vendor name: %.4s%.4s%.4s max cpuid level: %d\n", + (char*) (regs+1),(char*) (regs+3),(char*) (regs+2), regs[0]); + if (regs[0]>=0x00000001) + { + char *tmpstr; + unsigned cl_size; + + do_cpuid(0x00000001, regs2); + + tmpstr=GetCpuFriendlyName(regs, regs2); + mp_msg(MSGT_CPUDETECT,MSGL_INFO,"CPU: %s ",tmpstr); + free(tmpstr); + + caps->cpuType=(regs2[0] >> 8)&0xf; + if(caps->cpuType==0xf){ + // use extended family (P4, IA64) + caps->cpuType=8+((regs2[0]>>20)&255); + } + caps->cpuStepping=regs2[0] & 0xf; + mp_msg(MSGT_CPUDETECT,MSGL_INFO,"(Family: %d, Stepping: %d)\n", + caps->cpuType, caps->cpuStepping); + + // general feature flags: + caps->hasMMX = (regs2[3] & (1 << 23 )) >> 23; // 0x0800000 + caps->hasSSE = (regs2[3] & (1 << 25 )) >> 25; // 0x2000000 + caps->hasSSE2 = (regs2[3] & (1 << 26 )) >> 26; // 0x4000000 + caps->hasMMX2 = caps->hasSSE; // SSE cpus supports mmxext too + cl_size = ((regs2[1] >> 8) & 0xFF)*8; + if(cl_size) caps->cl_size = cl_size; + } + do_cpuid(0x80000000, regs); + if (regs[0]>=0x80000001) { + mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cpuid-level: %d\n",regs[0]&0x7FFFFFFF); + do_cpuid(0x80000001, regs2); + caps->hasMMX |= (regs2[3] & (1 << 23 )) >> 23; // 0x0800000 + caps->hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22; // 0x400000 + caps->has3DNow = (regs2[3] & (1 << 31 )) >> 31; //0x80000000 + caps->has3DNowExt = (regs2[3] & (1 << 30 )) >> 30; + } + if(regs[0]>=0x80000006) + { + do_cpuid(0x80000006, regs2); + mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cache-info: %d\n",regs2[2]&0x7FFFFFFF); + caps->cl_size = regs2[2] & 0xFF; + } + mp_msg(MSGT_CPUDETECT,MSGL_INFO,"Detected cache-line size is %u bytes\n",caps->cl_size); +#if 0 + mp_msg(MSGT_CPUDETECT,MSGL_INFO,"cpudetect: MMX=%d MMX2=%d SSE=%d SSE2=%d 3DNow=%d 3DNowExt=%d\n", + gCpuCaps.hasMMX, + gCpuCaps.hasMMX2, + gCpuCaps.hasSSE, + gCpuCaps.hasSSE2, + gCpuCaps.has3DNow, + gCpuCaps.has3DNowExt ); +#endif + + /* FIXME: Does SSE2 need more OS support, too? */ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) + if (caps->hasSSE) + check_os_katmai_support(); + if (!caps->hasSSE) + caps->hasSSE2 = 0; +#else + caps->hasSSE=0; + caps->hasSSE2 = 0; +#endif +// caps->has3DNow=1; +// caps->hasMMX2 = 0; +// caps->hasMMX = 0; + +#ifndef HAVE_MMX + if(caps->hasMMX) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX supported but disabled\n"); + caps->hasMMX=0; +#endif +#ifndef HAVE_MMX2 + if(caps->hasMMX2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX2 supported but disabled\n"); + caps->hasMMX2=0; +#endif +#ifndef HAVE_SSE + if(caps->hasSSE) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE supported but disabled\n"); + caps->hasSSE=0; +#endif +#ifndef HAVE_SSE2 + if(caps->hasSSE2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE2 supported but disabled\n"); + caps->hasSSE2=0; +#endif +#ifndef HAVE_3DNOW + if(caps->has3DNow) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNow supported but disabled\n"); + caps->has3DNow=0; +#endif +#ifndef HAVE_3DNOWEX + if(caps->has3DNowExt) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNowExt supported but disabled\n"); + caps->has3DNowExt=0; +#endif +} + + +#define CPUID_EXTFAMILY ((regs2[0] >> 20)&0xFF) /* 27..20 */ +#define CPUID_EXTMODEL ((regs2[0] >> 16)&0x0F) /* 19..16 */ +#define CPUID_TYPE ((regs2[0] >> 12)&0x04) /* 13..12 */ +#define CPUID_FAMILY ((regs2[0] >> 8)&0x0F) /* 11..08 */ +#define CPUID_MODEL ((regs2[0] >> 4)&0x0F) /* 07..04 */ +#define CPUID_STEPPING ((regs2[0] >> 0)&0x0F) /* 03..00 */ + +char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]){ +#include "cputable.h" /* get cpuname and cpuvendors */ + char vendor[17]; + char *retname; + int i; + + if (NULL==(retname=(char*)malloc(256))) { + mp_msg(MSGT_CPUDETECT,MSGL_FATAL,"Error: GetCpuFriendlyName() not enough memory\n"); + exit(1); + } + + sprintf(vendor,"%.4s%.4s%.4s",(char*)(regs+1),(char*)(regs+3),(char*)(regs+2)); + + for(i=0; imagic != 0xffff ) { + /* Our signal context has the extended FPU state, so reset the + * divide-by-zero exception mask and clear the divide-by-zero + * exception bit. + */ + sc.fpstate->mxcsr |= 0x00000200; + sc.fpstate->mxcsr &= 0xfffffffb; + } else { + /* If we ever get here, we're completely hosed. + */ + mp_msg(MSGT_CPUDETECT,MSGL_V, "\n\n" ); + mp_msg(MSGT_CPUDETECT,MSGL_V, "SSE enabling test failed badly!" ); + } +} +#endif /* __linux__ && _POSIX_SOURCE && X86_FXSR_MAGIC */ + +/* If we're running on a processor that can do SSE, let's see if we + * are allowed to or not. This will catch 2.4.0 or later kernels that + * haven't been configured for a Pentium III but are running on one, + * and RedHat patched 2.2 kernels that have broken exception handling + * support for user space apps that do SSE. + */ +static void check_os_katmai_support( void ) +{ +#if defined(__FreeBSD__) + int has_sse=0, ret; + size_t len=sizeof(has_sse); + + ret = sysctlbyname("hw.instruction_sse", &has_sse, &len, NULL, 0); + if (ret || !has_sse) + gCpuCaps.hasSSE=0; + +#elif defined(__NetBSD__) +#if __NetBSD_Version__ >= 105250000 + int has_sse, has_sse2, ret, mib[2]; + size_t varlen; + + mib[0] = CTL_MACHDEP; + mib[1] = CPU_SSE; + varlen = sizeof(has_sse); + + mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE... " ); + ret = sysctl(mib, 2, &has_sse, &varlen, NULL, 0); + if (ret < 0 || !has_sse) { + gCpuCaps.hasSSE=0; + mp_msg(MSGT_CPUDETECT,MSGL_V, "no!\n" ); + } else { + gCpuCaps.hasSSE=1; + mp_msg(MSGT_CPUDETECT,MSGL_V, "yes!\n" ); + } + + mib[1] = CPU_SSE2; + varlen = sizeof(has_sse2); + mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE2... " ); + ret = sysctl(mib, 2, &has_sse2, &varlen, NULL, 0); + if (ret < 0 || !has_sse2) { + gCpuCaps.hasSSE2=0; + mp_msg(MSGT_CPUDETECT,MSGL_V, "no!\n" ); + } else { + gCpuCaps.hasSSE2=1; + mp_msg(MSGT_CPUDETECT,MSGL_V, "yes!\n" ); + } +#else + gCpuCaps.hasSSE = 0; + mp_msg(MSGT_CPUDETECT,MSGL_WARN, "No OS support for SSE, disabling to be safe.\n" ); +#endif +#elif defined(__linux__) +#if defined(_POSIX_SOURCE) && defined(X86_FXSR_MAGIC) + struct sigaction saved_sigill; + struct sigaction saved_sigfpe; + + /* Save the original signal handlers. + */ + sigaction( SIGILL, NULL, &saved_sigill ); + sigaction( SIGFPE, NULL, &saved_sigfpe ); + + signal( SIGILL, (void (*)(int))sigill_handler_sse ); + signal( SIGFPE, (void (*)(int))sigfpe_handler_sse ); + + /* Emulate test for OSFXSR in CR4. The OS will set this bit if it + * supports the extended FPU save and restore required for SSE. If + * we execute an SSE instruction on a PIII and get a SIGILL, the OS + * doesn't support Streaming SIMD Exceptions, even if the processor + * does. + */ + if ( gCpuCaps.hasSSE ) { + mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE... " ); + +// __asm __volatile ("xorps %%xmm0, %%xmm0"); + __asm __volatile ("xorps %xmm0, %xmm0"); + + if ( gCpuCaps.hasSSE ) { + mp_msg(MSGT_CPUDETECT,MSGL_V, "yes.\n" ); + } else { + mp_msg(MSGT_CPUDETECT,MSGL_V, "no!\n" ); + } + } + + /* Emulate test for OSXMMEXCPT in CR4. The OS will set this bit if + * it supports unmasked SIMD FPU exceptions. If we unmask the + * exceptions, do a SIMD divide-by-zero and get a SIGILL, the OS + * doesn't support unmasked SIMD FPU exceptions. If we get a SIGFPE + * as expected, we're okay but we need to clean up after it. + * + * Are we being too stringent in our requirement that the OS support + * unmasked exceptions? Certain RedHat 2.2 kernels enable SSE by + * setting CR4.OSFXSR but don't support unmasked exceptions. Win98 + * doesn't even support them. We at least know the user-space SSE + * support is good in kernels that do support unmasked exceptions, + * and therefore to be safe I'm going to leave this test in here. + */ + if ( gCpuCaps.hasSSE ) { + mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE unmasked exceptions... " ); + +// test_os_katmai_exception_support(); + + if ( gCpuCaps.hasSSE ) { + mp_msg(MSGT_CPUDETECT,MSGL_V, "yes.\n" ); + } else { + mp_msg(MSGT_CPUDETECT,MSGL_V, "no!\n" ); + } + } + + /* Restore the original signal handlers. + */ + sigaction( SIGILL, &saved_sigill, NULL ); + sigaction( SIGFPE, &saved_sigfpe, NULL ); + + /* If we've gotten to here and the XMM CPUID bit is still set, we're + * safe to go ahead and hook out the SSE code throughout Mesa. + */ + if ( gCpuCaps.hasSSE ) { + mp_msg(MSGT_CPUDETECT,MSGL_V, "Tests of OS support for SSE passed.\n" ); + } else { + mp_msg(MSGT_CPUDETECT,MSGL_V, "Tests of OS support for SSE failed!\n" ); + } +#else + /* We can't use POSIX signal handling to test the availability of + * SSE, so we disable it by default. + */ + mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, disabling to be safe.\n" ); + gCpuCaps.hasSSE=0; +#endif /* _POSIX_SOURCE && X86_FXSR_MAGIC */ +#else + /* Do nothing on other platforms for now. + */ + mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, leaving disabled.\n" ); + gCpuCaps.hasSSE=0; +#endif /* __linux__ */ +} +#else /* ARCH_X86 */ + +#ifdef SYS_DARWIN +#include +#else +#include +#include + +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t canjump = 0; + +static void sigill_handler (int sig) +{ + if (!canjump) { + signal (sig, SIG_DFL); + raise (sig); + } + + canjump = 0; + siglongjmp (jmpbuf, 1); +} +#endif + +void GetCpuCaps( CpuCaps *caps) +{ + caps->cpuType=0; + caps->cpuStepping=0; + caps->hasMMX=0; + caps->hasMMX2=0; + caps->has3DNow=0; + caps->has3DNowExt=0; + caps->hasSSE=0; + caps->hasSSE2=0; + caps->isX86=0; + caps->hasAltiVec = 0; +#ifdef HAVE_ALTIVEC +#ifdef SYS_DARWIN +/* + rip-off from ffmpeg altivec detection code. + this code also appears on Apple's AltiVec pages. + */ + { + int sels[2] = {CTL_HW, HW_VECTORUNIT}; + int has_vu = 0; + size_t len = sizeof(has_vu); + int err; + + err = sysctl(sels, 2, &has_vu, &len, NULL, 0); + + if (err == 0) + if (has_vu != 0) + caps->hasAltiVec = 1; + } +#else /* SYS_DARWIN */ +/* no Darwin, do it the brute-force way */ +/* this is borrowed from the libmpeg2 library */ + { + signal (SIGILL, sigill_handler); + if (sigsetjmp (jmpbuf, 1)) { + signal (SIGILL, SIG_DFL); + } else { + canjump = 1; + + asm volatile ("mtspr 256, %0\n\t" + "vand %%v0, %%v0, %%v0" + : + : "r" (-1)); + + signal (SIGILL, SIG_DFL); + caps->hasAltiVec = 1; + } + } +#endif /* SYS_DARWIN */ + mp_msg(MSGT_CPUDETECT,MSGL_INFO,"AltiVec %sfound\n", (caps->hasAltiVec ? "" : "not ")); +#endif /* HAVE_ALTIVEC */ +} +#endif /* !ARCH_X86 */ diff --git a/linphone/win32acm/cpudetect.h b/linphone/win32acm/cpudetect.h new file mode 100644 index 000000000..c68013ba7 --- /dev/null +++ b/linphone/win32acm/cpudetect.h @@ -0,0 +1,31 @@ +#ifndef CPUDETECT_H +#define CPUDETECT_H + +#define CPUTYPE_I386 3 +#define CPUTYPE_I486 4 +#define CPUTYPE_I586 5 +#define CPUTYPE_I686 6 + +typedef struct cpucaps_s { + int cpuType; + int cpuStepping; + int hasMMX; + int hasMMX2; + int has3DNow; + int has3DNowExt; + int hasSSE; + int hasSSE2; + int isX86; + unsigned cl_size; /* size of cache line */ + int hasAltiVec; +} CpuCaps; + +extern CpuCaps gCpuCaps; + +void GetCpuCaps(CpuCaps *caps); + +/* returned value is malloc()'ed so free() it after use */ +char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]); + +#endif /* !CPUDETECT_H */ + diff --git a/linphone/win32acm/cputable.h b/linphone/win32acm/cputable.h new file mode 100644 index 000000000..0c52fa306 --- /dev/null +++ b/linphone/win32acm/cputable.h @@ -0,0 +1,474 @@ +/* cputable.h - Maps CPUID to real CPU name. + * Copyleft 2001 by Felix Buenemann + * This file comes under the GNU GPL, see www.fsf.org for more info! + */ + +#define MAX_VENDORS 8 /* Number of CPU Vendors */ + +//#define N_UNKNOWN "unknown" +//#define N_UNKNOWNEXT "unknown extended model" +#define N_UNKNOWN "" +#define N_UNKNOWNEXT "" + +#define F_UNKNOWN { \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN, \ +N_UNKNOWN \ +} + +static const char *cpuname + /* Vendor */ [MAX_VENDORS] + /* Family */ [16] + /* Model */ [16] + ={ + /* Intel Corporation, "GenuineIntel" */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 i386 */ F_UNKNOWN, /* XXX new 386 chips may support CPUID! */ + /* 4 i486 */ { + /* 0 */ "i486DX-25/33", /* only few of these */ + /* 1 */ "i486DX-50", /* support CPUID! */ + /* 2 */ "i486SX", + /* 3 */ "i486DX2", /* CPUID only on new chips! */ + /* 4 */ "i486SL", + /* 5 */ "i486SX2", + /* 6 */ N_UNKNOWN, + /* 7 */ "i486DX2/write-back", /* returns 3 in write-through mode */ + /* 8 */ "i486DX4", + /* 9 */ "i486DX4/write-back", + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWNEXT + }, + /* 5 i586 */ { + /* 0 */ "Pentium P5 A-step", + /* 1 */ "Pentium P5", + /* 2 */ "Pentium P54C", + /* 3 */ "Pentium OverDrive P24T", + /* 4 */ "Pentium MMX P55C", + /* 5 */ N_UNKNOWN, /* XXX DX4 OverDrive? */ + /* 6 */ N_UNKNOWN, /* XXX P5 OverDrive? */ + /* 7 */ "Pentium P54C (new)", + /* 8 */ "Pentium MMX P55C (new)", + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWNEXT + }, + /* 6 i686 */ { + /* 0 */ "PentiumPro A-step", + /* 1 */ "PentiumPro", + /* 2 */ N_UNKNOWN, + /* 3 */ "Pentium II Klamath/Pentium II OverDrive", + /* 4 */ N_UNKNOWN, /* XXX P55CT - OverDrive for P54? */ + /* 5 */ "Celeron Covington/Pentium II Deschutes,Tonga/Pentium II Xeon", + /* 6 */ "Celeron A Mendocino/Pentium II Dixon", + /* 7 */ "Pentium III Katmai/Pentium III Xeon Tanner", + /* 8 */ "Celeron 2/Pentium III Coppermine,Geyserville", + /* 9 */ N_UNKNOWN, + /* A */ "Pentium III Xeon Cascades", + /* B */ "Celeron 2/Pentium III Tualatin", + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWNEXT + }, + /* 7 IA-64 */ { /* FIXME */ + /* 0 */ N_UNKNOWN, + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWNEXT + }, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F extended family (P4/new IA-64)*/ { + /* 0 */ "Pentium 4 Willamette", + /* 1 */ "Pentium 4 Xeon Foster", /*?*/ + /* XXX 0.13µm P4 Northwood ??? */ + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWNEXT + } + }, + /* United Microelectronics Corporation, "UMC UMC UMC " */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 486 (U5) */ { + /* 0 */ N_UNKNOWN, + /* 1 */ "486DX U5D", + /* 2 */ "486SX U5S", + /* 3 */ N_UNKNOWN, + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 5 */ F_UNKNOWN, + /* 6 */ F_UNKNOWN, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + }, + /* Advanced Micro Devices, "AuthenticAMD" (very rare: "AMD ISBETTER") */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 486/5x86 */ { + /* 0 */ N_UNKNOWN, + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ "486DX2", + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ "486DX2/write-back", + /* 8 */ "486DX4/5x86", + /* 9 */ "486DX4/write-back", + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* E */ "5x86", + /* F */ "5x86/write-back" + }, + /* 5 K5/K6 */ { + /* 0 */ "K5 SSA5 (PR75,PR90,PR100)", + /* 1 */ "K5 5k86 (PR120,PR133)", + /* 2 */ "K5 5k86 (PR166)", + /* 3 */ "K5 5k86 (PR200)", + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ "K6", + /* 7 */ "K6 Little Foot", + /* 8 */ "K6-2", + /* 9 */ "K6-III Chomper", + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ "K6-2+/K6-III+ Sharptooth", + /* E */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 6 K7 */ { + /* 0 */ N_UNKNOWN, /* Argon? */ + /* 1 */ "Athlon K7", + /* 2 */ "Athlon K75 Pluto,Orion", + /* 3 */ "Duron SF Spitfire", + /* 4 */ "Athlon TB Thunderbird", + /* 5 */ N_UNKNOWN, + /* 6 */ "Athlon 4 PM Palomino/Athlon MP Multiprocessor/Athlon XP eXtreme Performance", + /* 7 */ "Duron MG Morgan", + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + }, + /* Cyrix Corp./VIA Inc., "CyrixInstead" */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 5x86 */ { + /* 0 */ N_UNKNOWN, + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ "MediaGX", + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ "5x86", /* CPUID maybe only on newer chips */ + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 5 M1 */ { + /* 0 */ "M1 test-sample", /*?*/ + /* 1 */ N_UNKNOWN, + /* 2 */ "6x86 M1", + /* 3 */ N_UNKNOWN, + /* 4 */ "GXm", + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 6 M2 */ { + /* 0 */ "6x86MX M2/M-II", + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ N_UNKNOWN, + /* 5 */ "Cyrix III Joshua (M2 core)", + /* 6 */ "Cyrix III Samuel (WinChip C5A core)", + /* 7 */ "C3 Samuel 2 (WinChip C5B core)", + /* 8 */ N_UNKNOWN, /* XXX Samuel 3/Ezra? */ + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + }, + /* NexGen Inc., "NexGenDriven" */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 */ F_UNKNOWN, + /* 5 Nx586 */ { + /* 0 */ "Nx586/Nx586FPU", /* only newer ones support CPUID! */ + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 6 */ F_UNKNOWN, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + }, + /* IDT/Centaur/VIA, "CentaurHauls" */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 */ F_UNKNOWN, + /* 5 IDT C6 WinChip */ { + /* 0 */ N_UNKNOWN, + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ "WinChip C6", + /* 5 */ N_UNKNOWN, + /* 6 */ "Samuel", + /* 7 */ N_UNKNOWN, + /* 8 */ "WinChip 2 C6+,W2,W2A,W2B", + /* 9 */ "WinChip 3 W3", + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + + }, + /* 6 */ F_UNKNOWN, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + }, + /* Rise, "RiseRiseRise" */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 */ F_UNKNOWN, + /* 5 mP6 */ { + /* 0 */ "mP6 iDragon 6401,6441 Kirin", + /* 1 */ "mP6 iDragon 6510 Lynx", + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ N_UNKNOWN, + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ "mP6 iDragon II", + /* 9 */ "mP6 iDragon II (new)", + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 6 */ F_UNKNOWN, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + }, + /* Transmeta, "GenuineTMx86" */ { + /* 0 */ F_UNKNOWN, + /* 1 */ F_UNKNOWN, + /* 2 */ F_UNKNOWN, + /* 3 */ F_UNKNOWN, + /* 4 */ F_UNKNOWN, + /* 5 Crusoe */ { + /* 0 */ N_UNKNOWN, + /* 1 */ N_UNKNOWN, + /* 2 */ N_UNKNOWN, + /* 3 */ N_UNKNOWN, + /* 4 */ "Crusoe TM3x00,TM5x00", + /* 5 */ N_UNKNOWN, + /* 6 */ N_UNKNOWN, + /* 7 */ N_UNKNOWN, + /* 8 */ N_UNKNOWN, + /* 9 */ N_UNKNOWN, + /* A */ N_UNKNOWN, + /* B */ N_UNKNOWN, + /* E */ N_UNKNOWN, + /* C */ N_UNKNOWN, + /* D */ N_UNKNOWN, + /* F */ N_UNKNOWN + }, + /* 6 */ F_UNKNOWN, + /* 7 */ F_UNKNOWN, + /* 8 */ F_UNKNOWN, + /* 9 */ F_UNKNOWN, + /* A */ F_UNKNOWN, + /* B */ F_UNKNOWN, + /* C */ F_UNKNOWN, + /* D */ F_UNKNOWN, + /* E */ F_UNKNOWN, + /* F */ F_UNKNOWN + } +}; + +#undef N_UNKNOWNEXT +#undef N_UNKNOWN +#undef F_UNKNOWN + +static const struct { + char string[13]; + char name[48]; +} cpuvendors[MAX_VENDORS] ={ + {"GenuineIntel","Intel"}, + {"UMC UMC UMC ","United Microelectronics Corporation"}, + {"AuthenticAMD","Advanced Micro Devices"}, + {"CyrixInstead","Cyrix/VIA"}, + {"NexGenDriven","NexGen"}, + {"CentaurHauls","IDT/Centaur/VIA"}, + {"RiseRiseRise","Rise"}, + {"GenuineTMx86","Transmeta"} +}; + diff --git a/linphone/win32acm/driver.c b/linphone/win32acm/driver.c new file mode 100644 index 000000000..7f41288b2 --- /dev/null +++ b/linphone/win32acm/driver.c @@ -0,0 +1,178 @@ +#include "config.h" + +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#include +#ifdef __FreeBSD__ +#include +#endif + +#include "win32.h" +#include "wine/driver.h" +#include "wine/pe_image.h" +#include "wine/winreg.h" +#include "wine/vfw.h" +#include "registry.h" +#include "ldt_keeper.h" +#include "driver.h" +#include "ext.h" + +extern char* def_path; + +#if 1 + +/* + * STORE_ALL/REST_ALL seems like an attempt to workaround problems due to + * WINAPI/no-WINAPI bustage. + * + * There should be no need for the STORE_ALL/REST_ALL hack once all + * function definitions agree with their prototypes (WINAPI-wise) and + * we make sure, that we do not call these functions without a proper + * prototype in scope. + */ + +#define STORE_ALL +#define REST_ALL +#else +// this asm code is no longer needed +#define STORE_ALL \ + __asm__ __volatile__ ( \ + "push %%ebx\n\t" \ + "push %%ecx\n\t" \ + "push %%edx\n\t" \ + "push %%esi\n\t" \ + "push %%edi\n\t"::) + +#define REST_ALL \ + __asm__ __volatile__ ( \ + "pop %%edi\n\t" \ + "pop %%esi\n\t" \ + "pop %%edx\n\t" \ + "pop %%ecx\n\t" \ + "pop %%ebx\n\t"::) +#endif + +static int needs_free=0; +void SetCodecPath(const char* path) +{ + if(needs_free)free(def_path); + if(path==0) + { + def_path=WIN32_PATH; + needs_free=0; + return; + } + def_path = (char*) malloc(strlen(path)+1); + strcpy(def_path, path); + needs_free=1; +} + +static DWORD dwDrvID = 0; + +LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT message, + LPARAM lParam1, LPARAM lParam2) +{ + DRVR* module=(DRVR*)hDriver; + int result; +#ifndef __svr4__ + char qw[300]; +#endif +#ifdef DETAILED_OUT + printf("SendDriverMessage: driver %X, message %X, arg1 %X, arg2 %X\n", hDriver, message, lParam1, lParam2); +#endif + if (!module || !module->hDriverModule || !module->DriverProc) return -1; +#ifndef __svr4__ + __asm__ __volatile__ ("fsave (%0)\n\t": :"r"(&qw)); +#endif + + Setup_FS_Segment(); + + STORE_ALL; + result=module->DriverProc(module->dwDriverID, hDriver, message, lParam1, lParam2); + REST_ALL; + +#ifndef __svr4__ + __asm__ __volatile__ ("frstor (%0)\n\t": :"r"(&qw)); +#endif + +#ifdef DETAILED_OUT + printf("\t\tResult: %X\n", result); +#endif + return result; +} + +void DrvClose(HDRVR hDriver) +{ + if (hDriver) + { + DRVR* d = (DRVR*)hDriver; + if (d->hDriverModule) + { + Setup_FS_Segment(); + if (d->DriverProc) + { + SendDriverMessage(hDriver, DRV_CLOSE, 0, 0); + d->dwDriverID = 0; + SendDriverMessage(hDriver, DRV_FREE, 0, 0); + } + FreeLibrary(d->hDriverModule); + } + free(d); + } + CodecRelease(); +} + +//DrvOpen(LPCSTR lpszDriverName, LPCSTR lpszSectionName, LPARAM lParam2) +HDRVR DrvOpen(LPARAM lParam2) +{ + NPDRVR hDriver; + int i; + char unknown[0x124]; + const char* filename = (const char*) ((ICOPEN*) lParam2)->pV1Reserved; + +#ifdef MPLAYER + Setup_LDT_Keeper(); + printf("Loading codec DLL: '%s'\n",filename); +#endif + + hDriver = (NPDRVR) malloc(sizeof(DRVR)); + if (!hDriver) + return ((HDRVR) 0); + memset((void*)hDriver, 0, sizeof(DRVR)); + + CodecAlloc(); + Setup_FS_Segment(); + + hDriver->hDriverModule = LoadLibraryA(filename); + if (!hDriver->hDriverModule) + { + printf("Can't open library %s\n", filename); + DrvClose((HDRVR)hDriver); + return ((HDRVR) 0); + } + + hDriver->DriverProc = (DRIVERPROC) GetProcAddress(hDriver->hDriverModule, + "DriverProc"); + if (!hDriver->DriverProc) + { + printf("Library %s is not a valid VfW/ACM codec\n", filename); + DrvClose((HDRVR)hDriver); + return ((HDRVR) 0); + } + + TRACE("DriverProc == %X\n", hDriver->DriverProc); + SendDriverMessage((HDRVR)hDriver, DRV_LOAD, 0, 0); + TRACE("DRV_LOAD Ok!\n"); + SendDriverMessage((HDRVR)hDriver, DRV_ENABLE, 0, 0); + TRACE("DRV_ENABLE Ok!\n"); + hDriver->dwDriverID = ++dwDrvID; // generate new id + + // open driver and remmeber proper DriverID + hDriver->dwDriverID = SendDriverMessage((HDRVR)hDriver, DRV_OPEN, (LPARAM) unknown, lParam2); + TRACE("DRV_OPEN Ok!(%X)\n", hDriver->dwDriverID); + + printf("Loaded DLL driver %s\n", filename); + return (HDRVR)hDriver; +} diff --git a/linphone/win32acm/driver.h b/linphone/win32acm/driver.h new file mode 100644 index 000000000..751f0379e --- /dev/null +++ b/linphone/win32acm/driver.h @@ -0,0 +1,22 @@ +#ifndef loader_driver_h +#define loader_driver_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "wine/windef.h" +#include "wine/driver.h" + +void SetCodecPath(const char* path); +void CodecAlloc(void); +void CodecRelease(void); + +HDRVR DrvOpen(LPARAM lParam2); +void DrvClose(HDRVR hdrvr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linphone/win32acm/elfdll.c b/linphone/win32acm/elfdll.c new file mode 100644 index 000000000..c393c4e29 --- /dev/null +++ b/linphone/win32acm/elfdll.c @@ -0,0 +1,292 @@ +/* + * Elf-dll loader functions + * + * Copyright 1999 Bertho A. Stultiens + */ +#include "config.h" + +#ifdef HAVE_LIBDL + +#include "wine/windef.h" +#include "wine/module.h" +#include "wine/heap.h" +#include "wine/elfdll.h" +#include "wine/debugtools.h" +#include "wine/winerror.h" + +//DEFAULT_DEBUG_CHANNEL(elfdll) + +#include +#include +#include +#include +#include + + +//WINE_MODREF *local_wm=NULL; +extern modref_list* local_wm; + + +/*------------------ HACKS -----------------*/ +extern DWORD fixup_imports(WINE_MODREF *wm); +extern void dump_exports(HMODULE hModule); +/*---------------- END HACKS ---------------*/ + +//char *extra_ld_library_path = "/usr/lib/win32"; +extern char* def_path; + +struct elfdll_image +{ + HMODULE pe_module_start; + DWORD pe_module_size; +}; + + +/**************************************************************************** + * ELFDLL_dlopen + * + * Wrapper for dlopen to search the EXTRA_LD_LIBRARY_PATH from wine.conf + * manually because libdl.so caches the environment and does not accept our + * changes. + */ +void *ELFDLL_dlopen(const char *libname, int flags) +{ + char buffer[256]; + int namelen; + void *handle; + char *ldpath; + + /* First try the default path search of dlopen() */ + handle = dlopen(libname, flags); + if(handle) + return handle; + + /* Now try to construct searches through our extra search-path */ + namelen = strlen(libname); + ldpath = def_path; + while(ldpath && *ldpath) + { + int len; + char *cptr; + char *from; + + from = ldpath; + cptr = strchr(ldpath, ':'); + if(!cptr) + { + len = strlen(ldpath); + ldpath = NULL; + } + else + { + len = cptr - ldpath; + ldpath = cptr + 1; + } + + if(len + namelen + 1 >= sizeof(buffer)) + { + ERR("Buffer overflow! Check EXTRA_LD_LIBRARY_PATH or increase buffer size.\n"); + return NULL; + } + + strncpy(buffer, from, len); + if(len) + { + buffer[len] = '/'; + strcpy(buffer + len + 1, libname); + } + else + strcpy(buffer + len, libname); + + TRACE("Trying dlopen('%s', %d)\n", buffer, flags); + + handle = dlopen(buffer, flags); + if(handle) + return handle; + } + return NULL; +} + + +/**************************************************************************** + * get_sobasename (internal) + * + */ +static LPSTR get_sobasename(LPCSTR path, LPSTR name) +{ + char *cptr; + + /* Strip the path from the library name */ + if((cptr = strrchr(path, '/'))) + { + char *cp = strrchr(cptr+1, '\\'); + if(cp && cp > cptr) + cptr = cp; + } + else + cptr = strrchr(path, '\\'); + + if(!cptr) + cptr = (char *)path; /* No '/' nor '\\' in path */ + else + cptr++; + + strcpy(name, cptr); + cptr = strrchr(name, '.'); + if(cptr) + *cptr = '\0'; /* Strip extension */ + + /* Convert to lower case. + * This must be done manually because it is not sure that + * other modules are accessible. + */ + for(cptr = name; *cptr; cptr++) + *cptr = tolower(*cptr); + + return name; +} + + +/**************************************************************************** + * ELFDLL_CreateModref (internal) + * + * INPUT + * hModule - the header from the elf-dll's data-segment + * path - requested path from original call + * + * OUTPUT + * A WINE_MODREF pointer to the new object + * + * BUGS + * - Does not handle errors due to dependencies correctly + * - path can be wrong + */ +#define RVA(base, va) (((DWORD)base) + ((DWORD)va)) + +static WINE_MODREF *ELFDLL_CreateModref(HMODULE hModule, LPCSTR path) +{ +// IMAGE_NT_HEADERS *nt = PE_HEADER(hModule); + IMAGE_DATA_DIRECTORY *dir; + IMAGE_IMPORT_DESCRIPTOR *pe_import = NULL; + WINE_MODREF *wm; + int len; + HANDLE procheap = GetProcessHeap(); + + wm = (WINE_MODREF *)HeapAlloc(procheap, HEAP_ZERO_MEMORY, sizeof(*wm)); + if(!wm) + return NULL; + + wm->module = hModule; + wm->type = MODULE32_ELF; /* FIXME */ + +// dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT; +// if(dir->Size) +// wm->binfmt.pe.pe_export = (PIMAGE_EXPORT_DIRECTORY)RVA(hModule, dir->VirtualAddress); + +// dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IMPORT; +// if(dir->Size) +// pe_import = wm->binfmt.pe.pe_import = (PIMAGE_IMPORT_DESCRIPTOR)RVA(hModule, dir->VirtualAddress); + +// dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_RESOURCE; +// if(dir->Size) +// wm->binfmt.pe.pe_resource = (PIMAGE_RESOURCE_DIRECTORY)RVA(hModule, dir->VirtualAddress); + + + wm->filename = (char*) malloc(strlen(path)+1); + strcpy(wm->filename, path); + wm->modname = strrchr( wm->filename, '\\' ); + if (!wm->modname) wm->modname = wm->filename; + else wm->modname++; +/* + len = GetShortPathNameA( wm->filename, NULL, 0 ); + wm->short_filename = (char *)HeapAlloc( procheap, 0, len+1 ); + GetShortPathNameA( wm->filename, wm->short_filename, len+1 ); + wm->short_modname = strrchr( wm->short_filename, '\\' ); + if (!wm->short_modname) wm->short_modname = wm->short_filename; + else wm->short_modname++; +*/ + /* Link MODREF into process list */ + +// EnterCriticalSection( &PROCESS_Current()->crit_section ); + + if(local_wm) + { + local_wm->next = (modref_list*) malloc(sizeof(modref_list)); + local_wm->next->prev=local_wm; + local_wm->next->next=NULL; + local_wm->next->wm=wm; + local_wm=local_wm->next; + } + else + { + local_wm = (modref_list*) malloc(sizeof(modref_list)); + local_wm->next=local_wm->prev=NULL; + local_wm->wm=wm; + } + +// LeaveCriticalSection( &PROCESS_Current()->crit_section ); + return wm; +} + +/**************************************************************************** + * ELFDLL_LoadLibraryExA (internal) + * + * Implementation of elf-dll loading for PE modules + */ +WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags) +{ + LPVOID dlhandle; + struct elfdll_image *image; + char name[129]; + char soname[129]; + WINE_MODREF *wm; + + get_sobasename(path, name); + strcpy(soname, name); + strcat(soname, ".so"); + + /* Try to open the elf-dll */ + dlhandle = ELFDLL_dlopen(soname, RTLD_LAZY); + if(!dlhandle) + { + WARN("Could not load %s (%s)\n", soname, dlerror()); + SetLastError( ERROR_FILE_NOT_FOUND ); + return NULL; + } + + /* Get the 'dllname_elfdll_image' variable */ +/* strcpy(soname, name); + strcat(soname, "_elfdll_image"); + image = (struct elfdll_image *)dlsym(dlhandle, soname); + if(!image) + { + ERR("Could not get elfdll image descriptor %s (%s)\n", soname, dlerror()); + dlclose(dlhandle); + SetLastError( ERROR_BAD_FORMAT ); + return NULL; + } + +*/ + wm = ELFDLL_CreateModref((int)dlhandle, path); + if(!wm) + { + ERR("Could not create WINE_MODREF for %s\n", path); + dlclose(dlhandle); + SetLastError( ERROR_OUTOFMEMORY ); + return NULL; + } + + return wm; +} + + +/**************************************************************************** + * ELFDLL_UnloadLibrary (internal) + * + * Unload an elf-dll completely from memory and deallocate the modref + */ +void ELFDLL_UnloadLibrary(WINE_MODREF *wm) +{ +} + +#endif /*HAVE_LIBDL*/ diff --git a/linphone/win32acm/ext.c b/linphone/win32acm/ext.c new file mode 100644 index 000000000..638b0cb48 --- /dev/null +++ b/linphone/win32acm/ext.c @@ -0,0 +1,606 @@ +/******************************************************** + * + * + * Stub functions for Wine module + * + * + ********************************************************/ +#include "config.h" +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "wine/windef.h" +#include "wine/winbase.h" +#include "wine/debugtools.h" +#include "wine/heap.h" +#include "ext.h" + +#if 0 +//REMOVE SIMPLIFY +static void* mymalloc(unsigned int size) +{ + printf("malloc %d\n", size); + return malloc(size); +} + +#undef malloc +#define malloc mymalloc +#endif + +int dbg_header_err( const char *dbg_channel, const char *func ) +{ + return 0; +} +int dbg_header_warn( const char *dbg_channel, const char *func ) +{ + return 0; +} +int dbg_header_fixme( const char *dbg_channel, const char *func ) +{ + return 0; +} +int dbg_header_trace( const char *dbg_channel, const char *func ) +{ + return 0; +} +int dbg_vprintf( const char *format, va_list args ) +{ + return 0; +} +int __vprintf( const char *format, ... ) +{ +#ifdef DETAILED_OUT + va_list va; + va_start(va, format); + vprintf(format, va); + va_end(va); +#endif + return 0; +} + +HANDLE WINAPI GetProcessHeap(void) +{ + return 1; +} + +LPVOID WINAPI HeapAlloc(HANDLE heap, DWORD flags, DWORD size) +{ + static int i = 5; + void* m = (flags & 0x8) ? calloc(size, 1) : malloc(size); + //printf("HeapAlloc %p %d (%d)\n", m, size, flags); + //if (--i == 0) + // abort(); + return m; +} + +WIN_BOOL WINAPI HeapFree(HANDLE heap, DWORD flags, LPVOID mem) +{ + if (mem) free(mem); + //printf("HeapFree %p\n", mem); + //if (!mem) + // abort(); + return 1; +} + +static int last_error; + +DWORD WINAPI GetLastError(void) +{ + return last_error; +} + +VOID WINAPI SetLastError(DWORD error) +{ + last_error=error; +} + +WIN_BOOL WINAPI ReadFile(HANDLE handle, LPVOID mem, DWORD size, LPDWORD result, LPOVERLAPPED flags) +{ + *result=read(handle, mem, size); + return *result; +} +INT WINAPI lstrcmpiA(LPCSTR c1, LPCSTR c2) +{ + return strcasecmp(c1,c2); +} +LPSTR WINAPI lstrcpynA(LPSTR dest, LPCSTR src, INT num) +{ + return strncpy(dest,src,num); +} +INT WINAPI lstrlenA(LPCSTR s) +{ + return strlen(s); +} +INT WINAPI lstrlenW(LPCWSTR s) +{ + int l; + if(!s) + return 0; + l=0; + while(s[l]) + l++; + return l; +} +LPSTR WINAPI lstrcpynWtoA(LPSTR dest, LPCWSTR src, INT count) +{ + LPSTR result = dest; + int moved=0; + if((dest==0) || (src==0)) + return 0; + while(moved0) + { + if (((*s1 | *s2) & 0xff00) || toupper((char)*s1) != toupper((char)*s2)) + { + + if(*s1<*s2) + return -1; + else + if(*s1>*s2) + return 1; + else + if(*s1==0) + return 0; + } + s1++; + s2++; + n--; + } + return 0; +} + +WIN_BOOL WINAPI IsBadReadPtr(LPCVOID data, UINT size) +{ + if(size==0) + return 0; + if(data==NULL) + return 1; + return 0; +} +LPSTR HEAP_strdupA(HANDLE heap, DWORD flags, LPCSTR string) +{ +// return strdup(string); + char* answ = (char*) malloc(strlen(string) + 1); + strcpy(answ, string); + return answ; +} +LPWSTR HEAP_strdupAtoW(HANDLE heap, DWORD flags, LPCSTR string) +{ + int size, i; + WCHAR* answer; + if(string==0) + return 0; + size=strlen(string); + answer = (WCHAR*) malloc(sizeof(WCHAR) * (size + 1)); + for(i=0; i<=size; i++) + answer[i]=(short)string[i]; + return answer; +} +LPSTR HEAP_strdupWtoA(HANDLE heap, DWORD flags, LPCWSTR string) +{ + int size, i; + char* answer; + if(string==0) + return 0; + size=0; + while(string[size]) + size++; + answer = (char*) malloc(size + 2); + for(i=0; i<=size; i++) + answer[i]=(char)string[i]; + return answer; +} + +/*********************************************************************** + * FILE_dommap + */ + +//#define MAP_PRIVATE +//#define MAP_SHARED +#undef MAP_ANON +LPVOID FILE_dommap( int unix_handle, LPVOID start, + DWORD size_high, DWORD size_low, + DWORD offset_high, DWORD offset_low, + int prot, int flags ) +{ + int fd = -1; + int pos; + LPVOID ret; + + if (size_high || offset_high) + printf("offsets larger than 4Gb not supported\n"); + + if (unix_handle == -1) + { +#ifdef MAP_ANON +// printf("Anonymous\n"); + flags |= MAP_ANON; +#else + static int fdzero = -1; + + if (fdzero == -1) + { + if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1) + { + perror( "Cannot open /dev/zero for READ. Check permissions! error: " ); + exit(1); + } + } + fd = fdzero; +#endif /* MAP_ANON */ + /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */ +#ifdef MAP_SHARED + flags &= ~MAP_SHARED; +#endif +#ifdef MAP_PRIVATE + flags |= MAP_PRIVATE; +#endif + } + else fd = unix_handle; +// printf("fd %x, start %x, size %x, pos %x, prot %x\n",fd,start,size_low, offset_low, prot); +// if ((ret = mmap( start, size_low, prot, +// flags, fd, offset_low )) != (LPVOID)-1) + if ((ret = mmap( start, size_low, prot, + MAP_PRIVATE | MAP_FIXED, fd, offset_low )) != (LPVOID)-1) + { +// printf("address %08x\n", *(int*)ret); +// printf("%x\n", ret); + return ret; + } + +// printf("mmap %d\n", errno); + + /* mmap() failed; if this is because the file offset is not */ + /* page-aligned (EINVAL), or because the underlying filesystem */ + /* does not support mmap() (ENOEXEC), we do it by hand. */ + + if (unix_handle == -1) return ret; + if ((errno != ENOEXEC) && (errno != EINVAL)) return ret; + if (prot & PROT_WRITE) + { + /* We cannot fake shared write mappings */ +#ifdef MAP_SHARED + if (flags & MAP_SHARED) return ret; +#endif +#ifdef MAP_PRIVATE + if (!(flags & MAP_PRIVATE)) return ret; +#endif + } +/* printf( "FILE_mmap: mmap failed (%d), faking it\n", errno );*/ + /* Reserve the memory with an anonymous mmap */ + ret = FILE_dommap( -1, start, size_high, size_low, 0, 0, + PROT_READ | PROT_WRITE, flags ); + if (ret == (LPVOID)-1) +// { +// perror( + return ret; + /* Now read in the file */ + if ((pos = lseek( fd, offset_low, SEEK_SET )) == -1) + { + FILE_munmap( ret, size_high, size_low ); +// printf("lseek\n"); + return (LPVOID)-1; + } + read( fd, ret, size_low ); + lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */ + mprotect( ret, size_low, prot ); /* Set the right protection */ +// printf("address %08x\n", *(int*)ret); + return ret; +} + + +/*********************************************************************** + * FILE_munmap + */ +int FILE_munmap( LPVOID start, DWORD size_high, DWORD size_low ) +{ + if (size_high) + printf("offsets larger than 4Gb not supported\n"); + return munmap( start, size_low ); +} +static int mapping_size=0; + +struct file_mapping_s; +typedef struct file_mapping_s +{ + int mapping_size; + char* name; + LPVOID handle; + struct file_mapping_s* next; + struct file_mapping_s* prev; +}file_mapping; +static file_mapping* fm=0; + + + +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 + +HANDLE WINAPI CreateFileMappingA(HANDLE handle, LPSECURITY_ATTRIBUTES lpAttr, + DWORD flProtect, + DWORD dwMaxHigh, DWORD dwMaxLow, + LPCSTR name) +{ + int hFile = (int)handle; + unsigned int len; + LPVOID answer; + int anon=0; + int mmap_access=0; + if(hFile<0) + { + anon=1; + hFile=open("/dev/zero", O_RDWR); + if(hFile<0){ + perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: " ); + return 0; + } + } + if(!anon) + { + len=lseek(hFile, 0, SEEK_END); + lseek(hFile, 0, SEEK_SET); + } + else len=dwMaxLow; + + if(flProtect & PAGE_READONLY) + mmap_access |=PROT_READ; + else + mmap_access |=PROT_READ|PROT_WRITE; + + answer=mmap(NULL, len, mmap_access, MAP_PRIVATE, hFile, 0); + if(anon) + close(hFile); + if(answer!=(LPVOID)-1) + { + if(fm==0) + { + fm = (file_mapping*) malloc(sizeof(file_mapping)); + fm->prev=NULL; + } + else + { + fm->next = (file_mapping*) malloc(sizeof(file_mapping)); + fm->next->prev=fm; + fm=fm->next; + } + fm->next=NULL; + fm->handle=answer; + if(name) + { + fm->name = (char*) malloc(strlen(name)+1); + strcpy(fm->name, name); + } + else + fm->name=NULL; + fm->mapping_size=len; + + if(anon) + close(hFile); + return (HANDLE)answer; + } + return (HANDLE)0; +} +WIN_BOOL WINAPI UnmapViewOfFile(LPVOID handle) +{ + file_mapping* p; + int result; + if(fm==0) + return 0; + for(p=fm; p; p=p->next) + { + if(p->handle==handle) + { + result=munmap((void*)handle, p->mapping_size); + if(p->next)p->next->prev=p->prev; + if(p->prev)p->prev->next=p->next; + if(p->name) + free(p->name); + if(p==fm) + fm=p->prev; + free(p); + return result; + } + } + return 0; +} +//static int va_size=0; +struct virt_alloc_s; +typedef struct virt_alloc_s +{ + int mapping_size; + char* address; + struct virt_alloc_s* next; + struct virt_alloc_s* prev; + int state; +}virt_alloc; +static virt_alloc* vm=0; +#define MEM_COMMIT 0x00001000 +#define MEM_RESERVE 0x00002000 + +LPVOID WINAPI VirtualAlloc(LPVOID address, DWORD size, DWORD type, DWORD protection) +{ + void* answer; + int fd=open("/dev/zero", O_RDWR); + if(fd<0){ + perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: " ); + return NULL; + } + size=(size+0xffff)&(~0xffff); + //printf("VirtualAlloc(0x%08X, %d)\n", address, size); + if(address!=0) + { + //check whether we can allow to allocate this + virt_alloc* str=vm; + while(str) + { + if((unsigned)address>=(unsigned)str->address+str->mapping_size) + { + str=str->prev; + continue; + } + if((unsigned)address+size<(unsigned)str->address) + { + str=str->prev; + continue; + } + if(str->state==0) + { +#warning FIXME + if(((unsigned)address+size<(unsigned)str->address+str->mapping_size) && (type & MEM_COMMIT)) + { + close(fd); + return address; //returning previously reserved memory + } + return NULL; + } + close(fd); + return NULL; + } + answer=mmap(address, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd, 0); + } + else + answer=mmap(address, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE, fd, 0); +// answer=FILE_dommap(-1, address, 0, size, 0, 0, +// PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE); + close(fd); + if(answer==(void*)-1) + { + printf("Error no %d\n", errno); + printf("VirtualAlloc(0x%p, %ld) failed\n", address, size); + return NULL; + } + else + { + virt_alloc *new_vm = (virt_alloc*) malloc(sizeof(virt_alloc)); + new_vm->mapping_size=size; + new_vm->address=(char*)answer; + new_vm->prev=vm; + if(type == MEM_RESERVE) + new_vm->state=0; + else + new_vm->state=1; + if(vm) + vm->next=new_vm; + vm=new_vm; + vm->next=0; + //if(va_size!=0) + // printf("Multiple VirtualAlloc!\n"); + //printf("answer=0x%08x\n", answer); + return answer; + } +} +WIN_BOOL WINAPI VirtualFree(LPVOID address, SIZE_T dwSize, DWORD dwFreeType)//not sure +{ + virt_alloc* str=vm; + int answer; + while(str) + { + if(address!=str->address) + { + str=str->prev; + continue; + } + //printf("VirtualFree(0x%08X, %d - %d)\n", str->address, dwSize, str->mapping_size); + answer=munmap(str->address, str->mapping_size); + if(str->next)str->next->prev=str->prev; + if(str->prev)str->prev->next=str->next; + if(vm==str)vm=str->prev; + free(str); + return 0; + } + return -1; +} + +INT WINAPI WideCharToMultiByte(UINT codepage, DWORD flags, LPCWSTR src, + INT srclen,LPSTR dest, INT destlen, LPCSTR defch, WIN_BOOL* used_defch) +{ + int i; + if(src==0) + return 0; + if ((srclen==-1)&&(dest==0)) return 0; + if(srclen==-1){srclen=0; while(src[srclen++]);} +// for(i=0; iprev) + { + if(p->name==0) + continue; + if(strcmp(p->name, name)==0) + return (HANDLE)p->handle; + } + return 0; +} diff --git a/linphone/win32acm/ext.h b/linphone/win32acm/ext.h new file mode 100644 index 000000000..579e85bec --- /dev/null +++ b/linphone/win32acm/ext.h @@ -0,0 +1,14 @@ +#ifndef loader_ext_h +#define loader_ext_h + +#include "wine/windef.h" + +extern LPVOID FILE_dommap( int unix_handle, LPVOID start, + DWORD size_high, DWORD size_low, + DWORD offset_high, DWORD offset_low, + int prot, int flags ); +extern int FILE_munmap( LPVOID start, DWORD size_high, DWORD size_low ); +extern int wcsnicmp(const unsigned short* s1, const unsigned short* s2, int n); +extern int __vprintf( const char *format, ... ); + +#endif diff --git a/linphone/win32acm/ldt_keeper.c b/linphone/win32acm/ldt_keeper.c new file mode 100644 index 000000000..c4459844f --- /dev/null +++ b/linphone/win32acm/ldt_keeper.c @@ -0,0 +1,259 @@ +/** + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * This file MUST be in main library because LDT must + * be modified before program creates first thread + * - avifile includes this file from C++ code + * and initializes it at the start of player! + * it might sound like a hack and it really is - but + * as aviplay is deconding video with more than just one + * thread currently it's necessary to do it this way + * this might change in the future + */ + +/* applied some modification to make make our xine friend more happy */ +#include "ldt_keeper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#include +// 2.5.xx+ calls this user_desc: +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,47) +#define modify_ldt_ldt_s user_desc +#endif +/* prototype it here, so we won't depend on kernel headers */ +#ifdef __cplusplus +extern "C" { +#endif +int modify_ldt(int func, void *ptr, unsigned long bytecount); +#ifdef __cplusplus +} +#endif +#else +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#include +#include +#endif + +#ifdef __svr4__ +#include +#include + +/* solaris x86: add missing prototype for sysi86() */ +#ifdef __cplusplus +extern "C" { +#endif +int sysi86(int, void*); +#ifdef __cplusplus +} +#endif + +#ifndef NUMSYSLDTS /* SunOS 2.5.1 does not define NUMSYSLDTS */ +#define NUMSYSLDTS 6 /* Let's hope the SunOS 5.8 value is OK */ +#endif + +#define TEB_SEL_IDX NUMSYSLDTS +#endif + +#define LDT_ENTRIES 8192 +#define LDT_ENTRY_SIZE 8 +#pragma pack(4) +struct modify_ldt_ldt_s { + unsigned int entry_number; + unsigned long base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; +}; + +#define MODIFY_LDT_CONTENTS_DATA 0 +#define MODIFY_LDT_CONTENTS_STACK 1 +#define MODIFY_LDT_CONTENTS_CODE 2 +#endif + + +/* user level (privilege level: 3) ldt (1<<2) segment selector */ +#define LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3) + +/* i got this value from wine sources, it's the first free LDT entry */ +#ifndef TEB_SEL_IDX +#define TEB_SEL_IDX 17 +#endif + +#define TEB_SEL LDT_SEL(TEB_SEL_IDX) + +/** + * here is a small logical problem with Restore for multithreaded programs - + * in C++ we use static class for this... + */ + +#ifdef __cplusplus +extern "C" +#endif +void Setup_FS_Segment(void) +{ + __asm__ __volatile__( + "movl %0,%%eax; movw %%ax, %%fs" : : "i" (TEB_SEL) + ); +} + +/* we don't need this - use modify_ldt instead */ +#if 0 +#ifdef __linux__ +/* XXX: why is this routine from libc redefined here? */ +/* NOTE: the redefined version ignores the count param, count is hardcoded as 16 */ +static int LDT_Modify( int func, struct modify_ldt_ldt_s *ptr, + unsigned long count ) +{ + int res; +#ifdef __PIC__ + __asm__ __volatile__( "pushl %%ebx\n\t" + "movl %2,%%ebx\n\t" + "int $0x80\n\t" + "popl %%ebx" + : "=a" (res) + : "0" (__NR_modify_ldt), + "r" (func), + "c" (ptr), + "d"(16)//sizeof(*ptr) from kernel point of view + :"esi" ); +#else + __asm__ __volatile__("int $0x80" + : "=a" (res) + : "0" (__NR_modify_ldt), + "b" (func), + "c" (ptr), + "d"(16) + :"esi"); +#endif /* __PIC__ */ + if (res >= 0) return res; + errno = -res; + return -1; +} +#endif +#endif + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void LDT_EntryToBytes( unsigned long *buffer, const struct modify_ldt_ldt_s *content ) +{ + *buffer++ = ((content->base_addr & 0x0000ffff) << 16) | + (content->limit & 0x0ffff); + *buffer = (content->base_addr & 0xff000000) | + ((content->base_addr & 0x00ff0000)>>16) | + (content->limit & 0xf0000) | + (content->contents << 10) | + ((content->read_exec_only == 0) << 9) | + ((content->seg_32bit != 0) << 22) | + ((content->limit_in_pages != 0) << 23) | + 0xf000; +} +#endif + +void* fs_seg=0; + +ldt_fs_t* Setup_LDT_Keeper(void) +{ + struct modify_ldt_ldt_s array; + int ret; + ldt_fs_t* ldt_fs = (ldt_fs_t*) malloc(sizeof(ldt_fs_t)); + + if (!ldt_fs) + return NULL; + + ldt_fs->fd = open("/dev/zero", O_RDWR); + if(ldt_fs->fd<0){ + perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: "); + return NULL; + } + fs_seg= + ldt_fs->fs_seg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE, + ldt_fs->fd, 0); + if (ldt_fs->fs_seg == (void*)-1) + { + perror("ERROR: Couldn't allocate memory for fs segment"); + close(ldt_fs->fd); + free(ldt_fs); + return NULL; + } + *(void**)((char*)ldt_fs->fs_seg+0x18) = ldt_fs->fs_seg; + array.base_addr=(int)ldt_fs->fs_seg; + array.entry_number=TEB_SEL_IDX; + array.limit=array.base_addr+getpagesize()-1; + array.seg_32bit=1; + array.read_exec_only=0; + array.seg_not_present=0; + array.contents=MODIFY_LDT_CONTENTS_DATA; + array.limit_in_pages=0; +#ifdef __linux__ + //ret=LDT_Modify(0x1, &array, sizeof(struct modify_ldt_ldt_s)); + ret=modify_ldt(0x1, &array, sizeof(struct modify_ldt_ldt_s)); + if(ret<0) + { + perror("install_fs"); + printf("Couldn't install fs segment, expect segfault\n"); + } +#endif /*linux*/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + { + unsigned long d[2]; + + LDT_EntryToBytes( d, &array ); + ret = i386_set_ldt(array.entry_number, (union descriptor *)d, 1); + if (ret < 0) + { + perror("install_fs"); + printf("Couldn't install fs segment, expect segfault\n"); + printf("Did you reconfigure the kernel with \"options USER_LDT\"?\n"); + } + } +#endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */ + +#if defined(__svr4__) + { + struct ssd ssd; + ssd.sel = TEB_SEL; + ssd.bo = array.base_addr; + ssd.ls = array.limit - array.base_addr; + ssd.acc1 = ((array.read_exec_only == 0) << 1) | + (array.contents << 2) | + 0xf0; /* P(resent) | DPL3 | S */ + ssd.acc2 = 0x4; /* byte limit, 32-bit segment */ + if (sysi86(SI86DSCR, &ssd) < 0) { + perror("sysi86(SI86DSCR)"); + printf("Couldn't install fs segment, expect segfault\n"); + } + } +#endif + + Setup_FS_Segment(); + + ldt_fs->prev_struct = (char*)malloc(sizeof(char) * 8); + *(void**)array.base_addr = ldt_fs->prev_struct; + + return ldt_fs; +} + +void Restore_LDT_Keeper(ldt_fs_t* ldt_fs) +{ + if (ldt_fs == NULL || ldt_fs->fs_seg == 0) + return; + if (ldt_fs->prev_struct) + free(ldt_fs->prev_struct); + munmap((char*)ldt_fs->fs_seg, getpagesize()); + ldt_fs->fs_seg = 0; + close(ldt_fs->fd); + free(ldt_fs); +} diff --git a/linphone/win32acm/ldt_keeper.h b/linphone/win32acm/ldt_keeper.h new file mode 100644 index 000000000..d36ebb892 --- /dev/null +++ b/linphone/win32acm/ldt_keeper.h @@ -0,0 +1,22 @@ +#ifndef LDT_KEEPER_H +#define LDT_KEEPER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + void* fs_seg; + char* prev_struct; + int fd; +} ldt_fs_t; + +void Setup_FS_Segment(void); +ldt_fs_t* Setup_LDT_Keeper(void); +void Restore_LDT_Keeper(ldt_fs_t* ldt_fs); +#ifdef __cplusplus +} +#endif + +#endif /* LDT_KEEPER_H */ diff --git a/linphone/win32acm/loader.h b/linphone/win32acm/loader.h new file mode 100644 index 000000000..62549c3f3 --- /dev/null +++ b/linphone/win32acm/loader.h @@ -0,0 +1,35 @@ +/******************************************************** + + Win32 binary loader interface + Copyright 2000 Eugene Kuznetsov (divx@euro.ru) + Shamelessly stolen from Wine project + +*********************************************************/ + +#ifndef _LOADER_H +#define _LOADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "wine/windef.h" +#include "wine/driver.h" +#include "wine/mmreg.h" +/*#include "wine/vfw.h" */ +#include "wine/msacm.h" + +unsigned int _GetPrivateProfileIntA(const char* appname, const char* keyname, int default_value, const char* filename); +int _GetPrivateProfileStringA(const char* appname, const char* keyname, + const char* def_val, char* dest, unsigned int len, const char* filename); +int _WritePrivateProfileStringA(const char* appname, const char* keyname, + const char* string, const char* filename); + +INT WINAPI LoadStringA( HINSTANCE instance, UINT resource_id, + LPSTR buffer, INT buflen ); + +#ifdef __cplusplus +} +#endif +#endif /* __LOADER_H */ + diff --git a/linphone/win32acm/loader_objfix.sh b/linphone/win32acm/loader_objfix.sh new file mode 100755 index 000000000..99eb27a7f --- /dev/null +++ b/linphone/win32acm/loader_objfix.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# This script fixes up symbol mangling in GNU as code of stubs.s. +# This file is licensed under the GPL, more info at http://www.fsf.org/ +for i in "export_names" \ + "printf" \ + "exp_EH_prolog" \ + "unk_exp1" +do +echo "fixing: $i=_$i" +objcopy --redefine-sym "$i=_$i" stubs.o +done diff --git a/linphone/win32acm/module.c b/linphone/win32acm/module.c new file mode 100644 index 000000000..089d8dde7 --- /dev/null +++ b/linphone/win32acm/module.c @@ -0,0 +1,993 @@ +/* + * Modules + * + * Copyright 1995 Alexandre Julliard + */ + +// define for quicktime calls debugging and/or MacOS-level emulation: +#define EMU_QTX_API + +// define for quicktime debugging (verbose logging): +//#define DEBUG_QTX_API + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/windef.h" +#include "wine/winerror.h" +#include "wine/heap.h" +#include "wine/module.h" +#include "wine/pe_image.h" +#include "wine/debugtools.h" + +#undef HAVE_LIBDL + +#ifdef HAVE_LIBDL +#include +#include "wine/elfdll.h" +#endif +#include "win32.h" +#include "driver.h" + +#ifdef EMU_QTX_API +#include "wrapper.h" +static int report_func(void *stack_base, int stack_size, reg386_t *reg, u_int32_t *flags); +static int report_func_ret(void *stack_base, int stack_size, reg386_t *reg, u_int32_t *flags); +#endif + +//#undef TRACE +//#define TRACE printf + +//WINE_MODREF *local_wm=NULL; +modref_list* local_wm=NULL; + +HANDLE SegptrHeap; + +WINE_MODREF* MODULE_FindModule(LPCSTR m) +{ + modref_list* list=local_wm; + TRACE("FindModule: Module %s request\n", m); + if(list==NULL) + return NULL; +// while(strcmp(m, list->wm->filename)) + while(!strstr(list->wm->filename, m)) + { + TRACE("%s: %x\n", list->wm->filename, list->wm->module); + list=list->prev; + if(list==NULL) + return NULL; + } + TRACE("Resolved to %s\n", list->wm->filename); + return list->wm; +} + +static void MODULE_RemoveFromList(WINE_MODREF *mod) +{ + modref_list* list=local_wm; + if(list==0) + return; + if(mod==0) + return; + if((list->prev==NULL)&&(list->next==NULL)) + { + free(list); + local_wm=NULL; +// uninstall_fs(); + return; + } + for(;list;list=list->prev) + { + if(list->wm==mod) + { + if(list->prev) + list->prev->next=list->next; + if(list->next) + list->next->prev=list->prev; + if(list==local_wm) + local_wm=list->prev; + free(list); + return; + } + } + +} + +WINE_MODREF *MODULE32_LookupHMODULE(HMODULE m) +{ + modref_list* list=local_wm; + TRACE("LookupHMODULE: Module %X request\n", m); + if(list==NULL) + { + TRACE("LookupHMODULE failed\n"); + return NULL; + } + while(m!=list->wm->module) + { +// printf("Checking list %X wm %X module %X\n", +// list, list->wm, list->wm->module); + list=list->prev; + if(list==NULL) + { + TRACE("LookupHMODULE failed\n"); + return NULL; + } + } + TRACE("LookupHMODULE hit %p\n", list->wm); + return list->wm; +} + +/************************************************************************* + * MODULE_InitDll + */ +static WIN_BOOL MODULE_InitDll( WINE_MODREF *wm, DWORD type, LPVOID lpReserved ) +{ + WIN_BOOL retv = TRUE; + + static LPCSTR typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH", + "THREAD_ATTACH", "THREAD_DETACH" }; + assert( wm ); + + + /* Skip calls for modules loaded with special load flags */ + + if ( ( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) + || ( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) ) + return TRUE; + + + TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved ); + + /* Call the initialization routine */ + switch ( wm->type ) + { + case MODULE32_PE: + retv = PE_InitDLL( wm, type, lpReserved ); + break; + + case MODULE32_ELF: + /* no need to do that, dlopen() already does */ + break; + + default: + ERR("wine_modref type %d not handled.\n", wm->type ); + retv = FALSE; + break; + } + + /* The state of the module list may have changed due to the call + to PE_InitDLL. We cannot assume that this module has not been + deleted. */ + TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv ); + + return retv; +} + +/************************************************************************* + * MODULE_DllProcessAttach + * + * Send the process attach notification to all DLLs the given module + * depends on (recursively). This is somewhat complicated due to the fact that + * + * - we have to respect the module dependencies, i.e. modules implicitly + * referenced by another module have to be initialized before the module + * itself can be initialized + * + * - the initialization routine of a DLL can itself call LoadLibrary, + * thereby introducing a whole new set of dependencies (even involving + * the 'old' modules) at any time during the whole process + * + * (Note that this routine can be recursively entered not only directly + * from itself, but also via LoadLibrary from one of the called initialization + * routines.) + * + * Furthermore, we need to rearrange the main WINE_MODREF list to allow + * the process *detach* notifications to be sent in the correct order. + * This must not only take into account module dependencies, but also + * 'hidden' dependencies created by modules calling LoadLibrary in their + * attach notification routine. + * + * The strategy is rather simple: we move a WINE_MODREF to the head of the + * list after the attach notification has returned. This implies that the + * detach notifications are called in the reverse of the sequence the attach + * notifications *returned*. + * + * NOTE: Assumes that the process critical section is held! + * + */ +static WIN_BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) +{ + WIN_BOOL retv = TRUE; + int i; + assert( wm ); + + /* prevent infinite recursion in case of cyclical dependencies */ + if ( ( wm->flags & WINE_MODREF_MARKER ) + || ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) ) + return retv; + + TRACE("(%s,%p) - START\n", wm->modname, lpReserved ); + + /* Tag current MODREF to prevent recursive loop */ + wm->flags |= WINE_MODREF_MARKER; + + /* Recursively attach all DLLs this one depends on */ +/* for ( i = 0; retv && i < wm->nDeps; i++ ) + if ( wm->deps[i] ) + retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved ); +*/ + /* Call DLL entry point */ + + //local_wm=wm; + if(local_wm) + { + local_wm->next = (modref_list*) malloc(sizeof(modref_list)); + local_wm->next->prev=local_wm; + local_wm->next->next=NULL; + local_wm->next->wm=wm; + local_wm=local_wm->next; + } + else + { + local_wm = (modref_list*)malloc(sizeof(modref_list)); + local_wm->next=local_wm->prev=NULL; + local_wm->wm=wm; + } + /* Remove recursion flag */ + wm->flags &= ~WINE_MODREF_MARKER; + + if ( retv ) + { + retv = MODULE_InitDll( wm, DLL_PROCESS_ATTACH, lpReserved ); + if ( retv ) + wm->flags |= WINE_MODREF_PROCESS_ATTACHED; + } + + + TRACE("(%s,%p) - END\n", wm->modname, lpReserved ); + + return retv; +} + +/************************************************************************* + * MODULE_DllProcessDetach + * + * Send DLL process detach notifications. See the comment about calling + * sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag + * is set, only DLLs with zero refcount are notified. + */ +static void MODULE_DllProcessDetach( WINE_MODREF* wm, WIN_BOOL bForceDetach, LPVOID lpReserved ) +{ + // WINE_MODREF *wm=local_wm; + modref_list* l = local_wm; + wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED; + MODULE_InitDll( wm, DLL_PROCESS_DETACH, lpReserved ); +/* while (l) + { + modref_list* f = l; + l = l->next; + free(f); + } + local_wm = 0;*/ +} + +/*********************************************************************** + * MODULE_LoadLibraryExA (internal) + * + * Load a PE style module according to the load order. + * + * The HFILE parameter is not used and marked reserved in the SDK. I can + * only guess that it should force a file to be mapped, but I rather + * ignore the parameter because it would be extremely difficult to + * integrate this with different types of module represenations. + * + */ +static WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags ) +{ + DWORD err = GetLastError(); + WINE_MODREF *pwm; + int i; +// module_loadorder_t *plo; + + SetLastError( ERROR_FILE_NOT_FOUND ); + TRACE("Trying native dll '%s'\n", libname); + pwm = PE_LoadLibraryExA(libname, flags); +#ifdef HAVE_LIBDL + if(!pwm) + { + TRACE("Trying ELF dll '%s'\n", libname); + pwm=(WINE_MODREF*)ELFDLL_LoadLibraryExA(libname, flags); + } +#endif +// printf("0x%08x\n", pwm); +// break; + if(pwm) + { + /* Initialize DLL just loaded */ + TRACE("Loaded module '%s' at 0x%08x, \n", libname, pwm->module); + /* Set the refCount here so that an attach failure will */ + /* decrement the dependencies through the MODULE_FreeLibrary call. */ + pwm->refCount++; + + SetLastError( err ); /* restore last error */ + return pwm; + } + + + WARN("Failed to load module '%s'; error=0x%08lx, \n", libname, GetLastError()); + return NULL; +} + +/*********************************************************************** + * MODULE_FreeLibrary + * + * NOTE: Assumes that the process critical section is held! + */ +static WIN_BOOL MODULE_FreeLibrary( WINE_MODREF *wm ) +{ + TRACE("(%s) - START\n", wm->modname ); + + /* Recursively decrement reference counts */ + //MODULE_DecRefCount( wm ); + + /* Call process detach notifications */ + MODULE_DllProcessDetach( wm, FALSE, NULL ); + + PE_UnloadLibrary(wm); + + TRACE("END\n"); + + return TRUE; +} + +/*********************************************************************** + * LoadLibraryExA (KERNEL32) + */ +HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) +{ + WINE_MODREF *wm = 0; + char* listpath[] = { "", "", "/usr/lib/win32", "/usr/local/lib/win32", 0 }; + extern char* def_path; + char path[512]; + char checked[2000]; + int i = -1; + + checked[0] = 0; + if(!libname) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + wm=MODULE_FindModule(libname); + if(wm) return wm->module; + +// if(fs_installed==0) +// install_fs(); + + while (wm == 0 && listpath[++i]) + { + if (i < 2) + { + if (i == 0) + /* check just original file name */ + strncpy(path, libname, 511); + else + /* check default user path */ + strncpy(path, def_path, 300); + } + else if (strcmp(def_path, listpath[i])) + /* path from the list */ + strncpy(path, listpath[i], 300); + else + continue; + + if (i > 0) + { + strcat(path, "/"); + strncat(path, libname, 100); + } + path[511] = 0; + wm = MODULE_LoadLibraryExA( path, hfile, flags ); + + if (!wm) + { + if (checked[0]) + strcat(checked, ", "); + strcat(checked, path); + checked[1500] = 0; + + } + } + if ( wm ) + { + if ( !MODULE_DllProcessAttach( wm, NULL ) ) + { + WARN_(module)("Attach failed for module '%s', \n", libname); + MODULE_FreeLibrary(wm); + SetLastError(ERROR_DLL_INIT_FAILED); + MODULE_RemoveFromList(wm); + wm = NULL; + } + } + + if (!wm) + printf("Win32 LoadLibrary failed to load: %s\n", checked); + + if (strstr(libname,"QuickTime.qts") && wm) + { + void** ptr; + void *dispatch_addr; + int i; + +// dispatch_addr = GetProcAddress(wm->module, "theQuickTimeDispatcher", TRUE); + dispatch_addr = PE_FindExportedFunction(wm, "theQuickTimeDispatcher", TRUE); + if (dispatch_addr == (void *)0x62924c30) + { + fprintf(stderr, "QuickTime5 DLLs found\n"); + ptr = (void **)0x62b75ca4; // dispatch_ptr + for (i=0;i<5;i++) ((char*)0x6299e842)[i]=0x90; // make_new_region ? + for (i=0;i<28;i++) ((char*)0x6299e86d)[i]=0x90; // call__call_CreateCompatibleDC ? + for (i=0;i<5;i++) ((char*)0x6299e898)[i]=0x90; // jmp_to_call_loadbitmap ? + for (i=0;i<9;i++) ((char*)0x6299e8ac)[i]=0x90; // call__calls_OLE_shit ? + for (i=0;i<106;i++) ((char*)0x62a61b10)[i]=0x90; // disable threads +#if 0 + /* CreateThread callers */ + for (i=0;i<5;i++) ((char*)0x629487c5)[i]=0x90; + for (i=0;i<5;i++) ((char*)0x6294b275)[i]=0x90; + for (i=0;i<5;i++) ((char*)0x629a24b1)[i]=0x90; + for (i=0;i<5;i++) ((char*)0x629afc5a)[i]=0x90; + for (i=0;i<5;i++) ((char*)0x62af799c)[i]=0x90; + for (i=0;i<5;i++) ((char*)0x62af7efe)[i]=0x90; + for (i=0;i<5;i++) ((char*)0x62afa33e)[i]=0x90; +#endif + +#if 0 + /* TerminateQTML fix */ + for (i=0;i<47;i++) ((char*)0x62afa3b8)[i]=0x90; // terminate thread + for (i=0;i<47;i++) ((char*)0x62af7f78)[i]=0x90; // terminate thread + for (i=0;i<77;i++) ((char*)0x629a13d5)[i]=0x90; + ((char *)0x6288e0ae)[0] = 0xc3; // font/dc remover + for (i=0;i<24;i++) ((char*)0x6287a1ad)[i]=0x90; // destroy window +#endif + } else if (dispatch_addr == (void *)0x6693b330) + { + fprintf(stderr, "QuickTime6 DLLs found\n"); + ptr = (void **)0x66bb9524; // dispatcher_ptr + for (i=0;i<5;i++) ((char *)0x66a730cc)[i]=0x90; // make_new_region + for (i=0;i<28;i++) ((char *)0x66a730f7)[i]=0x90; // call__call_CreateCompatibleDC + for (i=0;i<5;i++) ((char *)0x66a73122)[i]=0x90; // jmp_to_call_loadbitmap + for (i=0;i<9;i++) ((char *)0x66a73131)[i]=0x90; // call__calls_OLE_shit + for (i=0;i<96;i++) ((char *)0x66aac852)[i]=0x90; // disable threads + } else + { + fprintf(stderr, "Unsupported QuickTime version (%p)\n", + dispatch_addr); + return 0; + } + + fprintf(stderr,"QuickTime.qts patched!!! old entry=%p\n",ptr[0]); + +#ifdef EMU_QTX_API + report_entry = report_func; + report_ret = report_func_ret; + wrapper_target=ptr[0]; + ptr[0]=wrapper; +#endif + } + + return wm ? wm->module : 0; +} + + +/*********************************************************************** + * LoadLibraryA (KERNEL32) + */ +HMODULE WINAPI LoadLibraryA(LPCSTR libname) { + return LoadLibraryExA(libname,0,0); +} + +/*********************************************************************** + * FreeLibrary + */ +WIN_BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) +{ + WIN_BOOL retv = FALSE; + WINE_MODREF *wm; + + wm=MODULE32_LookupHMODULE(hLibModule); + + if ( !wm || !hLibModule ) + { + SetLastError( ERROR_INVALID_HANDLE ); + return 0; + } + else + retv = MODULE_FreeLibrary( wm ); + + MODULE_RemoveFromList(wm); + + /* garbage... */ + if (local_wm == NULL) my_garbagecollection(); + + return retv; +} + +/*********************************************************************** + * MODULE_DecRefCount + * + * NOTE: Assumes that the process critical section is held! + */ +static void MODULE_DecRefCount( WINE_MODREF *wm ) +{ + int i; + + if ( wm->flags & WINE_MODREF_MARKER ) + return; + + if ( wm->refCount <= 0 ) + return; + + --wm->refCount; + TRACE("(%s) refCount: %d\n", wm->modname, wm->refCount ); + + if ( wm->refCount == 0 ) + { + wm->flags |= WINE_MODREF_MARKER; + + for ( i = 0; i < wm->nDeps; i++ ) + if ( wm->deps[i] ) + MODULE_DecRefCount( wm->deps[i] ); + + wm->flags &= ~WINE_MODREF_MARKER; + } +} + +/*********************************************************************** + * GetProcAddress (KERNEL32.257) + */ +FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function ) +{ + return MODULE_GetProcAddress( hModule, function, TRUE ); +} + +#ifdef DEBUG_QTX_API + +struct ComponentParameters { + unsigned char flags; /* call modifiers: sync/async, deferred, immed, etc */ + unsigned char paramSize; /* size in bytes of actual parameters passed to this call */ + short what; /* routine selector, negative for Component management calls */ + long params[1]; /* actual parameters for the indicated routine */ +}; +typedef struct ComponentParameters ComponentParameters; + +static char* component_func(int what){ +switch(what){ +case -1: return "kComponentOpenSelect"; +case -2: return "kComponentCloseSelect"; +case -3: return "kComponentCanDoSelect"; +case -4: return "kComponentVersionSelect"; +case -5: return "kComponentRegisterSelect"; +case -6: return "kComponentTargetSelect"; +case -7: return "kComponentUnregisterSelect"; +} +return "???"; +} + +static char* component_func_type(int type,int what){ +if(type==1) switch(what){ +case 0: return "kImageCodecGetCodecInfoSelect"; +case 1: return "kImageCodecGetCompressionTimeSelect"; +case 5: return "kImageCodecPreDecompressSelect"; +case 6: return "kImageCodecBandDecompressSelect"; +case 0x12: return "kImageCodecDisposeMemorySelect"; +case 0x10: return "kImageCodecIsImageDescriptionEquivalentSelect"; +case 0x14: return "kImageCodecNewImageBufferMemorySelect"; +case 0x28: return "kImageCodecRequestGammaLevelSelect"; +} +return "???"; +} + + +static int c_level=0; + +static int dump_component(char* name,int type,void* _orig, ComponentParameters *params,void** glob){ + int ( *orig)(ComponentParameters *params, void** glob) = _orig; + int ret,i; + + if(params->what<0) + fprintf(stderr,"%*sComponentCall: %s flags=0x%X size=%d what=%d %s\n",3*c_level,"",name,params->flags, params->paramSize, params->what, component_func(params->what)); + else + fprintf(stderr,"%*sComponentCall: %s flags=0x%X size=%d what=0x%X %s\n",3*c_level,"",name,params->flags, params->paramSize, params->what, component_func_type(type,params->what)); + + for(i=0;iparamSize/4;i++) + fprintf(stderr,"%*s param[%d] = 0x%X\n",3*c_level,"",i,params->params[i]); + + ++c_level; + ret=orig(params,glob); + --c_level; + + if(ret>=0x1000) + fprintf(stderr,"%*s return=0x%X\n",3*c_level,"",ret); + else + fprintf(stderr,"%*s return=%d\n",3*c_level,"",ret); + return ret; +} + +#define DECL_COMPONENT(sname,name,type) \ + static void* real_ ## sname = NULL; \ + static int fake_ ## sname(ComponentParameters *params,void** glob){ \ + return dump_component(name,type,real_ ## sname, params, glob); \ + } + +#include "qt_comp.h" + +#undef DECL_COMPONENT + +#include "qt_fv.h" + +#endif + +#ifdef EMU_QTX_API + +static u_int32_t ret_array[4096]; +static int ret_i=0; + +static int report_func(void *stack_base, int stack_size, reg386_t *reg, u_int32_t *flags) +{ +#ifdef DEBUG_QTX_API + int i; + int* dptr; + void* pwrapper=NULL; + void* pptr=NULL; + char* pname=NULL; + int plen=-1; + // find the code: + + dptr=0x62b67ae0;dptr+=2*((reg->eax>>16)&255); +// printf("FUNC: flag=%d ptr=%p\n",dptr[0],dptr[1]); + if(dptr[0]&255){ + dptr=dptr[1];dptr+=4*(reg->eax&65535); +// printf("FUNC: ptr2=%p eax=%p edx=%p\n",dptr[1],dptr[0],dptr[2]); + pwrapper=dptr[1]; pptr=dptr[0]; plen=dptr[2]; + } else { + pwrapper=0x62924910; + switch(dptr[1]){ + case 0x629248d0: + dptr=0x62b672c0;dptr+=2*(reg->eax&65535); +// printf("FUNC: ptr2=%p eax=%p edx=%p\n",0x62924910,dptr[0],dptr[1]); + pptr=dptr[0]; plen=dptr[1]; + break; + case 0x62924e40: + dptr=0x62b67c70;dptr+=2*(reg->eax&65535); +// printf("FUNC: ptr2=%p eax=%p edx=%p\n",0x62924910,dptr[0],dptr[1]); + pptr=dptr[0]; plen=dptr[1]; + break; + case 0x62924e60: + dptr=0x62b68108;if(reg->eax&0x8000) dptr+=2*(reg->eax|0xffff0000); else dptr+=2*(reg->eax&65535); +// printf("FUNC: ptr2=%p eax=%p edx=%p\n",0x62924910,dptr[0],dptr[1]); + pptr=dptr[0]; plen=dptr[1]; + break; + case 0x62924e80: + dptr=0x62b68108;if(reg->eax&0x8000) dptr+=2*(reg->eax|0xffff0000); else dptr+=2*(reg->eax&65535); +// printf("FUNC: ptr2=%p eax=%p edx=%p\n",0x62924910,dptr[0],dptr[1]); + pptr=dptr[0]; plen=dptr[1]; + break; + default: + printf("FUNC: unknown ptr & psize!\n"); + pwrapper=dptr[1]; + } + } + + for(i=0;qt_fv_list[i].name;i++){ + if(qt_fv_list[i].id==reg->eax){ + pname=qt_fv_list[i].name; + break; + } + } + + printf("FUNC[%X/%s]: wrapper=%p func=%p len=%d\n",reg->eax, + pname?pname:"???",pwrapper,pptr,plen); + + printf("FUNC: caller=%p ebx=%p\n",((u_int32_t *)stack_base)[0],reg->ebx); + + if(pname) + printf("%*sENTER(%d): %s(",ret_i*2,"",ret_i,pname); + else + printf("%*sENTER(%d): %X(",ret_i*2,"",ret_i,reg->eax); + for (i=0;i=0x20 && fcc[0]<128 && + fcc[1]>=0x20 && fcc[1]<128 && + fcc[2]>=0x20 && fcc[2]<128 && + fcc[3]>=0x20 && fcc[3]<128) printf("='%c%c%c%c'",fcc[3],fcc[2],fcc[1],fcc[0]); + else if(val>=8 && val<65536) printf("=%d",val); + } + printf(")\n"); + fflush(stdout); + +#endif + +#if 1 + // emulate some functions: + switch(reg->eax){ + // memory management: + case 0x150011: //NewPtrClear + case 0x150012: //NewPtrSysClear + reg->eax=(u_int32_t)malloc(((u_int32_t *)stack_base)[1]); + memset((void *)reg->eax,0,((u_int32_t *)stack_base)[1]); +#ifdef DEBUG_QTX_API + printf("%*sLEAVE(%d): EMULATED! 0x%X\n",ret_i*2,"",ret_i, reg->eax); +#endif + return 1; + case 0x15000F: //NewPtr + case 0x150010: //NewPtrSys + reg->eax=(u_int32_t)malloc(((u_int32_t *)stack_base)[1]); +#ifdef DEBUG_QTX_API + printf("%*sLEAVE(%d): EMULATED! 0x%X\n",ret_i*2,"",ret_i, reg->eax); +#endif + return 1; + case 0x15002f: //DisposePtr + if(((u_int32_t *)stack_base)[1]>=0x60000000) + printf("WARNING! Invalid Ptr handle!\n"); + else + free((void *)((u_int32_t *)stack_base)[1]); + reg->eax=0; +#ifdef DEBUG_QTX_API + printf("%*sLEAVE(%d): EMULATED! 0x%X\n",ret_i*2,"",ret_i, reg->eax); +#endif + return 1; + // mutexes: + case 0x1d0033: //QTMLCreateMutex + reg->eax=0xdeadbabe; +#ifdef DEBUG_QTX_API + printf("%*sLEAVE(%d): EMULATED! 0x%X\n",ret_i*2,"",ret_i, reg->eax); +#endif + return 1; + case 0x1d0034: //QTMLDestroyMutex + case 0x1d0035: //QTMLGrabMutex + case 0x1d0036: //QTMLReturnMutex + case 0x1d003d: //QTMLTryGrabMutex + reg->eax=0; +#ifdef DEBUG_QTX_API + printf("%*sLEAVE(%d): EMULATED! 0x%X\n",ret_i*2,"",ret_i, reg->eax); +#endif + return 1; + } +#endif + +#if 0 + switch(reg->eax){ +// case 0x00010000: +// printf("FUNC: ImageCodecInitialize/ImageCodecGetCodecInfo(ci=%p,&icap=%p)\n",((u_int32_t *)stack_base)[1],((u_int32_t *)stack_base)[4]); +// break; + case 0x00010003: + printf("FUNC: CountComponents(&desc=%p)\n",((u_int32_t *)stack_base)[1]); + break; + case 0x00010004: + printf("FUNC: FindNextComponent(prev=%p,&desc=%p)\n",((u_int32_t *)stack_base)[1],((u_int32_t *)stack_base)[2]); + break; + case 0x00010007: + printf("FUNC: OpenComponent(prev=%p)\n",((u_int32_t *)stack_base)[1]); + break; + case 0x0003008b: + printf("FUNC: QTNewGWorldFromPtr(&pts=%p,fourcc=%.4s,&rect=%p,x1=%p,x2=%p,x3=%p,plane=%p,stride=%d)\n", + ((u_int32_t *)stack_base)[1], + &(((u_int32_t *)stack_base)[2]), + ((u_int32_t *)stack_base)[3], + ((u_int32_t *)stack_base)[4], + ((u_int32_t *)stack_base)[5], + ((u_int32_t *)stack_base)[6], + ((u_int32_t *)stack_base)[7], + ((u_int32_t *)stack_base)[8]); + break; + case 0x001c0018: + printf("FUNC: GetGWorldPixMap(gworld=%p)\n",((u_int32_t *)stack_base)[1]); + break; + case 0x00110001: + printf("FUNC: Gestalt(fourcc=%.4s, &ret=%p)\n",&(((u_int32_t *)stack_base)[1]),((u_int32_t *)stack_base)[2]); + break; + default: { + int i; + for(i=0;qt_fv_list[i].name;i++){ + if(qt_fv_list[i].id==reg->eax){ + printf("FUNC: %s\n",qt_fv_list[i].name); + break; + } + } + } + } + + // print stack/reg information + printf("ENTER(%d) stack = %d bytes @ %p\n" + "eax = 0x%08x edx = 0x%08x ebx = 0x%08x ecx = 0x%08x\n" + "esp = 0x%08x ebp = 0x%08x esi = 0x%08x edi = 0x%08x\n" + "flags = 0x%08x\n", ret_i, + stack_size, stack_base, + reg->eax, reg->edx, reg->ebx, reg->ecx, + reg->esp, reg->ebp, reg->esi, reg->edi, + *flags); +#endif + + // save ret addr: + ret_array[ret_i]=((u_int32_t *)stack_base)[0]; + ++ret_i; + +#if 0 + // print first 7 longs in the stack (return address, arg[1], arg[2] ... ) + printf("stack[] = { "); + for (i=0;i<7;i++) { + printf("%08x ", ((u_int32_t *)stack_base)[i]); + } + printf("}\n\n"); +#endif + +// // mess with function parameters +// ((u_int32_t *)stack_base)[1] = 0x66554433; + +// // mess with return address... +// reg->eax = 0x11223344; + return 0; +} + +static int report_func_ret(void *stack_base, int stack_size, reg386_t *reg, u_int32_t *flags) +{ + int i; + short err; + + // restore ret addr: + --ret_i; + ((u_int32_t *)stack_base)[0]=ret_array[ret_i]; + +#ifdef DEBUG_QTX_API + +#if 1 + printf("%*sLEAVE(%d): 0x%X",ret_i*2,"",ret_i, reg->eax); + err=reg->eax; + if(err && (reg->eax>>16)==0) printf(" = %d",err); + printf("\n"); + fflush(stdout); +#else + // print stack/reg information + printf("LEAVE(%d) stack = %d bytes @ %p\n" + "eax = 0x%08x edx = 0x%08x ebx = 0x%08x ecx = 0x%08x\n" + "esp = 0x%08x ebp = 0x%08x esi = 0x%08x edi = 0x%08x\n" + "flags = 0x%08x\n", ret_i, + stack_size, stack_base, + reg->eax, reg->edx, reg->ebx, reg->ecx, + reg->esp, reg->ebp, reg->esi, reg->edi, + *flags); +#endif + +#if 0 + // print first 7 longs in the stack (return address, arg[1], arg[2] ... ) + printf("stack[] = { "); + for (i=0;i<7;i++) { + printf("%08x ", ((u_int32_t *)stack_base)[i]); + } + printf("}\n\n"); +#endif + +#endif + +// // mess with function parameters +// ((u_int32_t *)stack_base)[1] = 0x66554433; + +// // mess with return address... +// reg->eax = 0x11223344; + return 0; +} + +#endif + +/*********************************************************************** + * MODULE_GetProcAddress (internal) + */ +FARPROC MODULE_GetProcAddress( + HMODULE hModule, /* [in] current module handle */ + LPCSTR function, /* [in] function to be looked up */ + WIN_BOOL snoop ) +{ + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); +// WINE_MODREF *wm=local_wm; + FARPROC retproc; + +#ifdef DEBUG_QTX_API + if (HIWORD(function)) + fprintf(stderr,"XXX GetProcAddress(%08lx,%s)\n",(DWORD)hModule,function); + else + fprintf(stderr,"XXX GetProcAddress(%08lx,%p)\n",(DWORD)hModule,function); +#endif + +// TRACE_(win32)("(%08lx,%s)\n",(DWORD)hModule,function); +// else +// TRACE_(win32)("(%08lx,%p)\n",(DWORD)hModule,function); + + if (!wm) { + SetLastError(ERROR_INVALID_HANDLE); + return (FARPROC)0; + } + switch (wm->type) + { + case MODULE32_PE: + retproc = PE_FindExportedFunction( wm, function, snoop ); + if (!retproc) SetLastError(ERROR_PROC_NOT_FOUND); + break; +#ifdef HAVE_LIBDL + case MODULE32_ELF: + retproc = (FARPROC) dlsym( (void*) wm->module, function); + if (!retproc) SetLastError(ERROR_PROC_NOT_FOUND); + return retproc; +#endif + default: + ERR("wine_modref type %d not handled.\n",wm->type); + SetLastError(ERROR_INVALID_HANDLE); + return (FARPROC)0; + } + +#ifdef EMU_QTX_API + if (HIWORD(function) && retproc){ + +#ifdef DEBUG_QTX_API +#define DECL_COMPONENT(sname,name,type) \ + if(!strcmp(function,name)){ \ + fprintf(stderr,name "dispatcher catched -> %p\n",retproc); \ + real_ ## sname = retproc; retproc = fake_ ## sname; \ + } +#include "qt_comp.h" +#undef DECL_COMPONENT +#endif + + if(!strcmp(function,"theQuickTimeDispatcher") +// || !strcmp(function,"_CallComponentFunctionWithStorage") +// || !strcmp(function,"_CallComponent") + ){ + fprintf(stderr,"theQuickTimeDispatcher catched -> %p\n",retproc); + report_entry = report_func; + report_ret = report_func_ret; + wrapper_target=retproc; + retproc=(FARPROC)wrapper; + } + + } +#endif + + return retproc; +} + +static int acounter = 0; +void CodecAlloc(void) +{ + acounter++; + //printf("**************CODEC ALLOC %d\n", acounter); +} + +void CodecRelease(void) +{ + acounter--; + //printf("**************CODEC RELEASE %d\n", acounter); + if (acounter == 0) + { + for (;;) + { + modref_list* list = local_wm; + if (!local_wm) + break; + //printf("CODECRELEASE %p\n", list); + MODULE_FreeLibrary(list->wm); + MODULE_RemoveFromList(list->wm); + if (local_wm == NULL) + my_garbagecollection(); + } + } +} diff --git a/linphone/win32acm/mp_msg.c b/linphone/win32acm/mp_msg.c new file mode 100644 index 000000000..fdf6d363e --- /dev/null +++ b/linphone/win32acm/mp_msg.c @@ -0,0 +1,174 @@ + +//#define MSG_USE_COLORS + +#include +#include +#include + +#include "config.h" + +#if defined(FOR_MENCODER) || defined(CODECS2HTML) +#undef ENABLE_GUI_CODE +#elif defined(HAVE_NEW_GUI) +#define ENABLE_GUI_CODE HAVE_NEW_GUI +#else +#undef ENABLE_GUI_CODE +#endif + +#if ENABLE_GUI_CODE +#include "Gui/mplayer/widgets.h" +extern void gtkMessageBox( int type,char * str ); +extern int use_gui; +#endif +#include "mp_msg.h" + +/* maximum message length of mp_msg */ +#define MSGSIZE_MAX 3072 + +static int mp_msg_levels[MSGT_MAX]; // verbose level of this module + +#if 1 + +void mp_msg_init(){ +#ifdef USE_I18N + fprintf(stdout, "Using GNU internationalization\n"); + fprintf(stdout, "Original domain: %s\n", textdomain(NULL)); + fprintf(stdout, "Original dirname: %s\n", bindtextdomain(textdomain(NULL),NULL)); + setlocale(LC_ALL, ""); /* set from the environment variables */ + bindtextdomain("mplayer", PREFIX"/share/locale"); + textdomain("mplayer"); + fprintf(stdout, "Current domain: %s\n", textdomain(NULL)); + fprintf(stdout, "Current dirname: %s\n", bindtextdomain(textdomain(NULL),NULL)); +#endif + mp_msg_set_level(MSGL_STATUS); +} + +void mp_msg_set_level(int verbose){ + int i; + for(i=0;imp_msg_levels[x>>8]) return; // do not display + va_start(va, format); + vsnprintf(tmp, MSGSIZE_MAX, mp_gettext(format), va); + va_end(va); + tmp[MSGSIZE_MAX-1] = 0; + +#if ENABLE_GUI_CODE + if(use_gui) + { + switch(x & 255) + { + case MSGL_FATAL: + gtkMessageBox(GTK_MB_FATAL|GTK_MB_SIMPLE, tmp); + break; + case MSGL_ERR: + gtkMessageBox(GTK_MB_ERROR|GTK_MB_SIMPLE, tmp); + break; +#if 0 +// WARNING! Do NOT enable this! There are too many non-critical messages with +// MSGL_WARN, for example: broken SPU packets, codec's bit error messages, +// etc etc, they should not raise up a new window every time. + case MSGL_WARN: + gtkMessageBox(GTK_MB_WARNING|GTK_MB_SIMPLE, tmp); + break; +#endif + } + } +#endif + +#ifdef MSG_USE_COLORS +#if 1 + { int c; + static int flag=1; + if(flag) + for(c=0;c<16;c++) + printf("\033[%d;3%dm*** COLOR TEST %d ***\n",(c>7),c&7,c); + flag=0; + } +#endif + { unsigned char v_colors[10]={9,9,11,14,15,7,6,5,5,5}; + int c=v_colors[(x & 255)]; + fprintf(((x & 255) <= MSGL_WARN)?stderr:stdout, "\033[%d;3%dm",(c>7),c&7); + } +#endif + if ((x & 255) <= MSGL_WARN){ + fprintf(stderr, "%s", tmp);fflush(stderr); + } else { + printf("%s", tmp);fflush(stdout); + } + +#else + va_list va; + if((x&255)>mp_msg_levels[x>>8]) return; // do not display + va_start(va, format); +#if ENABLE_GUI_CODE + if(use_gui){ + char tmp[16*80]; + vsnprintf( tmp,8*80,format,va ); tmp[8*80-1]=0; + switch( x&255 ) { + case MSGL_FATAL: + fprintf( stderr,"%s",tmp ); + fflush(stderr); + gtkMessageBox( GTK_MB_FATAL|GTK_MB_SIMPLE,tmp ); + break; + case MSGL_ERR: + fprintf( stderr,"%s",tmp ); + fflush(stderr); + gtkMessageBox( GTK_MB_ERROR|GTK_MB_SIMPLE,tmp ); + break; + case MSGL_WARN: + fprintf( stderr, "%s",tmp ); + fflush(stdout); + gtkMessageBox( GTK_MB_WARNING|GTK_MB_SIMPLE,tmp ); + break; + default: + fprintf(stderr, "%s",tmp ); + fflush(stdout); + } + } else +#endif + if((x&255)<=MSGL_ERR){ +// fprintf(stderr,"%%%%%% "); + vfprintf(stderr,format, va); + fflush(stderr); + } else { +// printf("%%%%%% "); + vfprintf(stderr,format, va); + fflush(stdout); + } + va_end(va); +#endif +} + +#else + +FILE *mp_msg_file[MSGT_MAX]; // print message to this file (can be stdout/err) +static FILE* mp_msg_last_file=NULL; + +// how to handle errors->stderr messages->stdout ? +void mp_msg( int x, const char *format, ... ){ + if((x&255)>mp_msg_levels[x>>8] || !mp_msg_file[x>>8]) return; // do not display + va_list va; + va_start(va, format); + vfprintf(mp_msg_file[x>>8],format, va); + if(mp_msg_last_file!=mp_msg_file[x>>8]){ + fflush(mp_msg_file[x>>8]); + mp_msg_last_file=mp_msg_file[x>>8]; + } + va_end(va); +} + +#endif diff --git a/linphone/win32acm/mp_msg.h b/linphone/win32acm/mp_msg.h new file mode 100644 index 000000000..c8ab0da6c --- /dev/null +++ b/linphone/win32acm/mp_msg.h @@ -0,0 +1,131 @@ + +#ifndef _MP_MSG_H +#define _MP_MSG_H + +extern int verbose; // defined in mplayer.c + +// verbosity elevel: + +// stuff from level MSGL_FATAL-MSGL_HINT should be translated. + +#define MSGL_FATAL 0 // will exit/abort +#define MSGL_ERR 1 // continues +#define MSGL_WARN 2 // only warning +#define MSGL_HINT 3 // short help message +#define MSGL_INFO 4 // -quiet +#define MSGL_STATUS 5 // v=0 +#define MSGL_V 6 // v=1 +#define MSGL_DBG2 7 // v=2 +#define MSGL_DBG3 8 // v=3 +#define MSGL_DBG4 9 // v=4 + +// code/module: + +#define MSGT_GLOBAL 0 // common player stuff errors +#define MSGT_CPLAYER 1 // console player (mplayer.c) +#define MSGT_GPLAYER 2 // gui player + +#define MSGT_VO 3 // libvo +#define MSGT_AO 4 // libao + +#define MSGT_DEMUXER 5 // demuxer.c (general stuff) +#define MSGT_DS 6 // demux stream (add/read packet etc) +#define MSGT_DEMUX 7 // fileformat-specific stuff (demux_*.c) +#define MSGT_HEADER 8 // fileformat-specific header (*header.c) + +#define MSGT_AVSYNC 9 // mplayer.c timer stuff +#define MSGT_AUTOQ 10 // mplayer.c auto-quality stuff + +#define MSGT_CFGPARSER 11 // cfgparser.c + +#define MSGT_DECAUDIO 12 // av decoder +#define MSGT_DECVIDEO 13 + +#define MSGT_SEEK 14 // seeking code +#define MSGT_WIN32 15 // win32 dll stuff +#define MSGT_OPEN 16 // open.c (stream opening) +#define MSGT_DVD 17 // open.c (DVD init/read/seek) + +#define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser) +#define MSGT_LIRC 19 // lirc_mp.c and input lirc driver + +#define MSGT_STREAM 20 // stream.c +#define MSGT_CACHE 21 // cache2.c + +#define MSGT_MENCODER 22 + +#define MSGT_XACODEC 23 // XAnim codecs + +#define MSGT_TV 24 // TV input subsystem + +#define MSGT_OSDEP 25 // OS Dependant parts (linux/ for now) + +#define MSGT_SPUDEC 26 // spudec.c + +#define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c) + +#define MSGT_INPUT 28 + +#define MSGT_VFILTER 29 + +#define MSGT_OSD 30 + +#define MSGT_NETWORK 31 + +#define MSGT_CPUDETECT 32 + +#define MSGT_CODECCFG 33 + +#define MSGT_SWS 34 + +#define MSGT_VOBSUB 35 +#define MSGT_SUBREADER 36 + +#define MSGT_AFILTER 37 // Audio filter messages + +#define MSGT_MAX 64 + +void mp_msg_init(); +void mp_msg_set_level(int verbose); +int mp_msg_test(int mod, int lev); + +#include "config.h" + +#ifdef TARGET_OS2 +// va_start/vsnprintf seems to be broken under OS2 :( +#define mp_msg(mod,lev, fmt, args... ) do{if((lev)<=mp_msg_levels[mod]) printf( fmt, ## args );}while(0) +#define mp_dbg(mod,lev, args... ) +#else + +#ifdef USE_I18N +#include +#include +#define mp_gettext(String) gettext(String) +#else +#define mp_gettext(String) String +#endif + +void mp_msg_c( int x, const char *format, ... ); + +#ifdef __GNUC__ +#define mp_msg(mod,lev, args... ) mp_msg_c(((mod)<<8)|(lev), ## args ) + +#ifdef MP_DEBUG +#define mp_dbg(mod,lev, args... ) mp_msg_c(((mod)<<8)|(lev), ## args ) +#else +// these messages are only usefull for developers, disable them +#define mp_dbg(mod,lev, args... ) +#endif +#else // not GNU C +#define mp_msg(mod,lev, ... ) mp_msg_c(((mod)<<8)|(lev), __VA_ARGS__) + +#ifdef MP_DEBUG +#define mp_dbg(mod,lev, ... ) mp_msg_c(((mod)<<8)|(lev), __VA_ARGS__) +#else +// these messages are only usefull for developers, disable them +#define mp_dbg(mod,lev, ... ) +#endif +#endif + +#endif +#endif diff --git a/linphone/win32acm/pcmin.raw b/linphone/win32acm/pcmin.raw new file mode 100644 index 000000000..731338ac2 Binary files /dev/null and b/linphone/win32acm/pcmin.raw differ diff --git a/linphone/win32acm/pe_image.c b/linphone/win32acm/pe_image.c new file mode 100644 index 000000000..9ac40ebeb --- /dev/null +++ b/linphone/win32acm/pe_image.c @@ -0,0 +1,964 @@ +/* + * Copyright 1994 Eric Youndale & Erik Bos + * Copyright 1995 Martin von Löwis + * Copyright 1996-98 Marcus Meissner + * + * based on Eric Youndale's pe-test and: + * + * ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP + * make that: + * ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP + */ +/* Notes: + * Before you start changing something in this file be aware of the following: + * + * - There are several functions called recursively. In a very subtle and + * obscure way. DLLs can reference each other recursively etc. + * - If you want to enhance, speed up or clean up something in here, think + * twice WHY it is implemented in that strange way. There is usually a reason. + * Though sometimes it might just be lazyness ;) + * - In PE_MapImage, right before fixup_imports() all external and internal + * state MUST be correct since this function can be called with the SAME image + * AGAIN. (Thats recursion for you.) That means MODREF.module and + * NE_MODULE.module32. + * - Sometimes, we can't use Linux mmap() to mmap() the images directly. + * + * The problem is, that there is not direct 1:1 mapping from a diskimage and + * a memoryimage. The headers at the start are mapped linear, but the sections + * are not. Older x86 pe binaries are 512 byte aligned in file and 4096 byte + * aligned in memory. Linux likes them 4096 byte aligned in memory (due to + * x86 pagesize, this cannot be fixed without a rather large kernel rewrite) + * and 'blocksize' file-aligned (offsets). Since we have 512/1024/2048 (CDROM) + * and other byte blocksizes, we can't always do this. We *can* do this for + * newer pe binaries produced by MSVC 5 and later, since they are also aligned + * to 4096 byte boundaries on disk. + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#include "wine/windef.h" +#include "wine/winbase.h" +#include "wine/winerror.h" +#include "wine/heap.h" +#include "wine/pe_image.h" +#include "wine/module.h" +#include "wine/debugtools.h" +#include "ext.h" +#include "win32.h" + +#define RVA(x) ((void *)((char *)load_addr+(unsigned int)(x))) + +#define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta)) + +extern void* LookupExternal(const char* library, int ordinal); +extern void* LookupExternalByName(const char* library, const char* name); + +static void dump_exports( HMODULE hModule ) +{ + char *Module; + unsigned int i, j; + u_short *ordinal; + u_long *function,*functions; + u_char **name; + unsigned int load_addr = hModule; + + DWORD rva_start = PE_HEADER(hModule)->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + DWORD rva_end = rva_start + PE_HEADER(hModule)->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + IMAGE_EXPORT_DIRECTORY *pe_exports = (IMAGE_EXPORT_DIRECTORY*)RVA(rva_start); + + Module = (char*)RVA(pe_exports->Name); + TRACE("*******EXPORT DATA*******\n"); + TRACE("Module name is %s, %ld functions, %ld names\n", + Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames); + + ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals); + functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions); + name=(u_char**) RVA(pe_exports->AddressOfNames); + + TRACE(" Ord RVA Addr Name\n" ); + for (i=0;iNumberOfFunctions;i++, function++) + { + if (!*function) continue; + if (TRACE_ON(win32)) + { + DPRINTF( "%4ld %08lx %p", i + pe_exports->Base, *function, RVA(*function) ); + + for (j = 0; j < pe_exports->NumberOfNames; j++) + if (ordinal[j] == i) + { + DPRINTF( " %s", (char*)RVA(name[j]) ); + break; + } + if ((*function >= rva_start) && (*function <= rva_end)) + DPRINTF(" (forwarded -> %s)", (char *)RVA(*function)); + DPRINTF("\n"); + } + } +} + +/* Look up the specified function or ordinal in the exportlist: + * If it is a string: + * - look up the name in the Name list. + * - look up the ordinal with that index. + * - use the ordinal as offset into the functionlist + * If it is a ordinal: + * - use ordinal-pe_export->Base as offset into the functionlist + */ +FARPROC PE_FindExportedFunction( + WINE_MODREF *wm, + LPCSTR funcName, + WIN_BOOL snoop ) +{ + u_short * ordinals; + u_long * function; + u_char ** name; + const char *ename = NULL; + int i, ordinal; + PE_MODREF *pem = &(wm->binfmt.pe); + IMAGE_EXPORT_DIRECTORY *exports = pem->pe_export; + unsigned int load_addr = wm->module; + u_long rva_start, rva_end, addr; + char * forward; + + if (HIWORD(funcName)) + TRACE("(%s)\n",funcName); + else + TRACE("(%d)\n",(int)funcName); + if (!exports) { + /* Not a fatal problem, some apps do + * GetProcAddress(0,"RegisterPenApp") which triggers this + * case. + */ + WARN("Module %08x(%s)/MODREF %p doesn't have a exports table.\n",wm->module,wm->modname,pem); + return NULL; + } + ordinals= (u_short*) RVA(exports->AddressOfNameOrdinals); + function= (u_long*) RVA(exports->AddressOfFunctions); + name = (u_char **) RVA(exports->AddressOfNames); + forward = NULL; + rva_start = PE_HEADER(wm->module)->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + rva_end = rva_start + PE_HEADER(wm->module)->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + + if (HIWORD(funcName)) + { + + int min = 0, max = exports->NumberOfNames - 1; + while (min <= max) + { + int res, pos = (min + max) / 2; + ename = (const char*) RVA(name[pos]); + if (!(res = strcmp( ename, funcName ))) + { + ordinal = ordinals[pos]; + goto found; + } + if (res > 0) max = pos - 1; + else min = pos + 1; + } + + for (i = 0; i < exports->NumberOfNames; i++) + { + ename = (const char*) RVA(name[i]); + if (!strcmp( ename, funcName )) + { + ERR( "%s.%s required a linear search\n", wm->modname, funcName ); + ordinal = ordinals[i]; + goto found; + } + } + return NULL; + } + else + { + ordinal = LOWORD(funcName) - exports->Base; + if (snoop && name) + { + for (i = 0; i < exports->NumberOfNames; i++) + if (ordinals[i] == ordinal) + { + ename = RVA(name[i]); + break; + } + } + } + + found: + if (ordinal >= exports->NumberOfFunctions) + { + TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base ); + return NULL; + } + addr = function[ordinal]; + if (!addr) return NULL; + if ((addr < rva_start) || (addr >= rva_end)) + { + FARPROC proc = RVA(addr); + if (snoop) + { + if (!ename) ename = "@"; +// proc = SNOOP_GetProcAddress(wm->module,ename,ordinal,proc); + TRACE("SNOOP_GetProcAddress n/a\n"); + + } + return proc; + } + else + { + WINE_MODREF *wm; + char *forward = RVA(addr); + char module[256]; + char *end = strchr(forward, '.'); + + if (!end) return NULL; + if (end - forward >= sizeof(module)) return NULL; + memcpy( module, forward, end - forward ); + module[end-forward] = 0; + if (!(wm = MODULE_FindModule( module ))) + { + ERR("module not found for forward '%s'\n", forward ); + return NULL; + } + return MODULE_GetProcAddress( wm->module, end + 1, snoop ); + } +} + +static DWORD fixup_imports( WINE_MODREF *wm ) +{ + IMAGE_IMPORT_DESCRIPTOR *pe_imp; + PE_MODREF *pem; + unsigned int load_addr = wm->module; + int i,characteristics_detection=1; + char *modname; + + assert(wm->type==MODULE32_PE); + pem = &(wm->binfmt.pe); + if (pem->pe_export) + modname = (char*) RVA(pem->pe_export->Name); + else + modname = ""; + + + TRACE("Dumping imports list\n"); + + + pe_imp = pem->pe_import; + if (!pe_imp) return 0; + + /* We assume that we have at least one import with !0 characteristics and + * detect broken imports with all characteristsics 0 (notably Borland) and + * switch the detection off for them. + */ + for (i = 0; pe_imp->Name ; pe_imp++) { + if (!i && !pe_imp->u.Characteristics) + characteristics_detection = 0; + if (characteristics_detection && !pe_imp->u.Characteristics) + break; + i++; + } + if (!i) return 0; + + + wm->nDeps = i; + wm->deps = HeapAlloc( GetProcessHeap(), 0, i*sizeof(WINE_MODREF *) ); + + /* load the imported modules. They are automatically + * added to the modref list of the process. + */ + + for (i = 0, pe_imp = pem->pe_import; pe_imp->Name ; pe_imp++) { + WINE_MODREF *wmImp; + IMAGE_IMPORT_BY_NAME *pe_name; + PIMAGE_THUNK_DATA import_list,thunk_list; + char *name = (char *) RVA(pe_imp->Name); + + if (characteristics_detection && !pe_imp->u.Characteristics) + break; + +//#warning FIXME: here we should fill imports + TRACE("Loading imports for %s.dll\n", name); + + if (pe_imp->u.OriginalFirstThunk != 0) { + TRACE("Microsoft style imports used\n"); + import_list =(PIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk); + thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk); + + while (import_list->u1.Ordinal) { + if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) { + int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal); + +// TRACE("--- Ordinal %s,%d\n", name, ordinal); + + thunk_list->u1.Function=LookupExternal(name, ordinal); + } else { + pe_name = (PIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData); +// TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint); + thunk_list->u1.Function=LookupExternalByName(name, pe_name->Name); + } + import_list++; + thunk_list++; + } + } else { + TRACE("Borland style imports used\n"); + thunk_list = (PIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk); + while (thunk_list->u1.Ordinal) { + if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) { + + int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal); + + TRACE("--- Ordinal %s.%d\n",name,ordinal); + thunk_list->u1.Function=LookupExternal( + name, ordinal); + } else { + pe_name=(PIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData); + TRACE("--- %s %s.%d\n", + pe_name->Name,name,pe_name->Hint); + thunk_list->u1.Function=LookupExternalByName( + name, pe_name->Name); + } + thunk_list++; + } + } + } + return 0; +} + +static int calc_vma_size( HMODULE hModule ) +{ + int i,vma_size = 0; + IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(hModule); + + TRACE("Dump of segment table\n"); + TRACE(" Name VSz Vaddr SzRaw Fileadr *Reloc *Lineum #Reloc #Linum Char\n"); + for (i = 0; i< PE_HEADER(hModule)->FileHeader.NumberOfSections; i++) + { + TRACE("%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n", + pe_seg->Name, + pe_seg->Misc.VirtualSize, + pe_seg->VirtualAddress, + pe_seg->SizeOfRawData, + pe_seg->PointerToRawData, + pe_seg->PointerToRelocations, + pe_seg->PointerToLinenumbers, + pe_seg->NumberOfRelocations, + pe_seg->NumberOfLinenumbers, + pe_seg->Characteristics); + vma_size=max(vma_size, pe_seg->VirtualAddress+pe_seg->SizeOfRawData); + vma_size=max(vma_size, pe_seg->VirtualAddress+pe_seg->Misc.VirtualSize); + pe_seg++; + } + return vma_size; +} + +static void do_relocations( unsigned int load_addr, IMAGE_BASE_RELOCATION *r ) +{ + int delta = load_addr - PE_HEADER(load_addr)->OptionalHeader.ImageBase; + int hdelta = (delta >> 16) & 0xFFFF; + int ldelta = delta & 0xFFFF; + + if(delta == 0) + + return; + while(r->VirtualAddress) + { + char *page = (char*) RVA(r->VirtualAddress); + int count = (r->SizeOfBlock - 8)/2; + int i; + TRACE_(fixup)("%x relocations for page %lx\n", + count, r->VirtualAddress); + + for(i=0;iTypeOffset[i] & 0xFFF; + int type = r->TypeOffset[i] >> 12; +// TRACE_(fixup)("patching %x type %x\n", offset, type); + switch(type) + { + case IMAGE_REL_BASED_ABSOLUTE: break; + case IMAGE_REL_BASED_HIGH: + *(short*)(page+offset) += hdelta; + break; + case IMAGE_REL_BASED_LOW: + *(short*)(page+offset) += ldelta; + break; + case IMAGE_REL_BASED_HIGHLOW: + *(int*)(page+offset) += delta; + + break; + case IMAGE_REL_BASED_HIGHADJ: + FIXME("Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n"); + break; + case IMAGE_REL_BASED_MIPS_JMPADDR: + FIXME("Is this a MIPS machine ???\n"); + break; + default: + FIXME("Unknown fixup type\n"); + break; + } + } + r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock); + } +} + + + + + +/********************************************************************** + * PE_LoadImage + * Load one PE format DLL/EXE into memory + * + * Unluckily we can't just mmap the sections where we want them, for + * (at least) Linux does only support offsets which are page-aligned. + * + * BUT we have to map the whole image anyway, for Win32 programs sometimes + * want to access them. (HMODULE32 point to the start of it) + */ +HMODULE PE_LoadImage( int handle, LPCSTR filename, WORD *version ) +{ + HMODULE hModule; + HANDLE mapping; + + IMAGE_NT_HEADERS *nt; + IMAGE_SECTION_HEADER *pe_sec; + IMAGE_DATA_DIRECTORY *dir; + BY_HANDLE_FILE_INFORMATION bhfi; + int i, rawsize, lowest_va, vma_size, file_size = 0; + DWORD load_addr = 0, aoep, reloc = 0; +// struct get_read_fd_request *req = get_req_buffer(); + int unix_handle = handle; + int page_size = getpagesize(); + + +// if ( GetFileInformationByHandle( hFile, &bhfi ) ) +// file_size = bhfi.nFileSizeLow; + file_size=lseek(handle, 0, SEEK_END); + lseek(handle, 0, SEEK_SET); + +//#warning fix CreateFileMappingA + mapping = CreateFileMappingA( handle, NULL, PAGE_READONLY | SEC_COMMIT, + 0, 0, NULL ); + if (!mapping) + { + WARN("CreateFileMapping error %ld\n", GetLastError() ); + return 0; + } +// hModule = (HMODULE)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); + hModule=(HMODULE)mapping; +// CloseHandle( mapping ); + if (!hModule) + { + WARN("MapViewOfFile error %ld\n", GetLastError() ); + return 0; + } + if ( *(WORD*)hModule !=IMAGE_DOS_SIGNATURE) + { + WARN("%s image doesn't have DOS signature, but 0x%04x\n", filename,*(WORD*)hModule); + goto error; + } + + nt = PE_HEADER( hModule ); + + + if ( nt->Signature != IMAGE_NT_SIGNATURE ) + { + WARN("%s image doesn't have PE signature, but 0x%08lx\n", filename, nt->Signature ); + goto error; + } + + + if ( nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 ) + { + MESSAGE("Trying to load PE image for unsupported architecture ("); + switch (nt->FileHeader.Machine) + { + case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break; + case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break; + case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break; + case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break; + case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break; + case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break; + case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break; + default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break; + } + MESSAGE(")\n"); + goto error; + } + + + pe_sec = PE_SECTIONS( hModule ); + rawsize = 0; lowest_va = 0x10000; + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) + { + if (lowest_va > pe_sec[i].VirtualAddress) + lowest_va = pe_sec[i].VirtualAddress; + if (pe_sec[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + continue; + if (pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData > rawsize) + rawsize = pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData; + } + + + if ( file_size && file_size < rawsize ) + { + ERR("PE module is too small (header: %d, filesize: %d), " + "probably truncated download?\n", + rawsize, file_size ); + goto error; + } + + + aoep = nt->OptionalHeader.AddressOfEntryPoint; + if (aoep && (aoep < lowest_va)) + FIXME("VIRUS WARNING: '%s' has an invalid entrypoint (0x%08lx) " + "below the first virtual address (0x%08x) " + "(possibly infected by Tchernobyl/SpaceFiller virus)!\n", + filename, aoep, lowest_va ); + + + /* FIXME: Hack! While we don't really support shared sections yet, + * this checks for those special cases where the whole DLL + * consists only of shared sections and is mapped into the + * shared address space > 2GB. In this case, we assume that + * the module got mapped at its base address. Thus we simply + * check whether the module has actually been mapped there + * and use it, if so. This is needed to get Win95 USER32.DLL + * to work (until we support shared sections properly). + */ + + if ( nt->OptionalHeader.ImageBase & 0x80000000 ) + { + HMODULE sharedMod = (HMODULE)nt->OptionalHeader.ImageBase; + IMAGE_NT_HEADERS *sharedNt = (PIMAGE_NT_HEADERS) + ( (LPBYTE)sharedMod + ((LPBYTE)nt - (LPBYTE)hModule) ); + + /* Well, this check is not really comprehensive, + but should be good enough for now ... */ + if ( !IsBadReadPtr( (LPBYTE)sharedMod, sizeof(IMAGE_DOS_HEADER) ) + && memcmp( (LPBYTE)sharedMod, (LPBYTE)hModule, sizeof(IMAGE_DOS_HEADER) ) == 0 + && !IsBadReadPtr( sharedNt, sizeof(IMAGE_NT_HEADERS) ) + && memcmp( sharedNt, nt, sizeof(IMAGE_NT_HEADERS) ) == 0 ) + { + UnmapViewOfFile( (LPVOID)hModule ); + return sharedMod; + } + } + + + + load_addr = nt->OptionalHeader.ImageBase; + vma_size = calc_vma_size( hModule ); + + load_addr = (DWORD)VirtualAlloc( (void*)load_addr, vma_size, + MEM_RESERVE | MEM_COMMIT, + PAGE_EXECUTE_READWRITE ); + if (load_addr == 0) + { + + FIXME("We need to perform base relocations for %s\n", filename); + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BASERELOC; + if (dir->Size) + reloc = dir->VirtualAddress; + else + { + FIXME( "FATAL: Need to relocate %s, but no relocation records present (%s). Try to run that file directly !\n", + filename, + (nt->FileHeader.Characteristics&IMAGE_FILE_RELOCS_STRIPPED)? + "stripped during link" : "unknown reason" ); + goto error; + } + + /* FIXME: If we need to relocate a system DLL (base > 2GB) we should + * really make sure that the *new* base address is also > 2GB. + * Some DLLs really check the MSB of the module handle :-/ + */ + if ( nt->OptionalHeader.ImageBase & 0x80000000 ) + ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" ); + + load_addr = (DWORD)VirtualAlloc( NULL, vma_size, + MEM_RESERVE | MEM_COMMIT, + PAGE_EXECUTE_READWRITE ); + if (!load_addr) { + FIXME_(win32)( + "FATAL: Couldn't load module %s (out of memory, %d needed)!\n", filename, vma_size); + goto error; + } + } + + TRACE("Load addr is %lx (base %lx), range %x\n", + load_addr, nt->OptionalHeader.ImageBase, vma_size ); + TRACE_(segment)("Loading %s at %lx, range %x\n", + filename, load_addr, vma_size ); + +#if 0 + + *(PIMAGE_DOS_HEADER)load_addr = *(PIMAGE_DOS_HEADER)hModule; + *PE_HEADER( load_addr ) = *nt; + memcpy( PE_SECTIONS(load_addr), PE_SECTIONS(hModule), + sizeof(IMAGE_SECTION_HEADER) * nt->FileHeader.NumberOfSections ); + + + memcpy( load_addr, hModule, lowest_fa ); +#endif + + if ((void*)FILE_dommap( handle, (void *)load_addr, 0, nt->OptionalHeader.SizeOfHeaders, + 0, 0, PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_PRIVATE | MAP_FIXED ) != (void*)load_addr) + { + ERR_(win32)( "Critical Error: failed to map PE header to necessary address.\n"); + goto error; + } + + + pe_sec = PE_SECTIONS( hModule ); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++, pe_sec++) + { + if (!pe_sec->SizeOfRawData || !pe_sec->PointerToRawData) continue; + TRACE("%s: mmaping section %s at %p off %lx size %lx/%lx\n", + filename, pe_sec->Name, (void*)RVA(pe_sec->VirtualAddress), + pe_sec->PointerToRawData, pe_sec->SizeOfRawData, pe_sec->Misc.VirtualSize ); + if ((void*)FILE_dommap( unix_handle, (void*)RVA(pe_sec->VirtualAddress), + 0, pe_sec->SizeOfRawData, 0, pe_sec->PointerToRawData, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_PRIVATE | MAP_FIXED ) != (void*)RVA(pe_sec->VirtualAddress)) + { + + ERR_(win32)( "Critical Error: failed to map PE section to necessary address.\n"); + goto error; + } + if ((pe_sec->SizeOfRawData < pe_sec->Misc.VirtualSize) && + (pe_sec->SizeOfRawData & (page_size-1))) + { + DWORD end = (pe_sec->SizeOfRawData & ~(page_size-1)) + page_size; + if (end > pe_sec->Misc.VirtualSize) end = pe_sec->Misc.VirtualSize; + TRACE("clearing %p - %p\n", + RVA(pe_sec->VirtualAddress) + pe_sec->SizeOfRawData, + RVA(pe_sec->VirtualAddress) + end ); + memset( (char*)RVA(pe_sec->VirtualAddress) + pe_sec->SizeOfRawData, 0, + end - pe_sec->SizeOfRawData ); + } + } + + + if ( reloc ) + do_relocations( load_addr, (IMAGE_BASE_RELOCATION *)RVA(reloc) ); + + + *version = ( (nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) + | (nt->OptionalHeader.MinorSubsystemVersion & 0xff); + + + UnmapViewOfFile( (LPVOID)hModule ); + return (HMODULE)load_addr; + +error: + if (unix_handle != -1) close( unix_handle ); + if (load_addr) + VirtualFree( (LPVOID)load_addr, 0, MEM_RELEASE ); + UnmapViewOfFile( (LPVOID)hModule ); + return 0; +} + +/********************************************************************** + * PE_CreateModule + * + * Create WINE_MODREF structure for loaded HMODULE32, link it into + * process modref_list, and fixup all imports. + * + * Note: hModule must point to a correctly allocated PE image, + * with base relocations applied; the 16-bit dummy module + * associated to hModule must already exist. + * + * Note: This routine must always be called in the context of the + * process that is to own the module to be created. + */ +WINE_MODREF *PE_CreateModule( HMODULE hModule, + LPCSTR filename, DWORD flags, WIN_BOOL builtin ) +{ + DWORD load_addr = (DWORD)hModule; + IMAGE_NT_HEADERS *nt = PE_HEADER(hModule); + IMAGE_DATA_DIRECTORY *dir; + IMAGE_IMPORT_DESCRIPTOR *pe_import = NULL; + IMAGE_EXPORT_DIRECTORY *pe_export = NULL; + IMAGE_RESOURCE_DIRECTORY *pe_resource = NULL; + WINE_MODREF *wm; + int result; + + + + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT; + if (dir->Size) + pe_export = (PIMAGE_EXPORT_DIRECTORY)RVA(dir->VirtualAddress); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IMPORT; + if (dir->Size) + pe_import = (PIMAGE_IMPORT_DESCRIPTOR)RVA(dir->VirtualAddress); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_RESOURCE; + if (dir->Size) + pe_resource = (PIMAGE_RESOURCE_DIRECTORY)RVA(dir->VirtualAddress); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXCEPTION; + if (dir->Size) FIXME("Exception directory ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_SECURITY; + if (dir->Size) FIXME("Security directory ignored\n" ); + + + + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DEBUG; + if (dir->Size) TRACE("Debug directory ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COPYRIGHT; + if (dir->Size) FIXME("Copyright string ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_GLOBALPTR; + if (dir->Size) FIXME("Global Pointer (MIPS) ignored\n" ); + + + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG; + if (dir->Size) FIXME("Load Configuration directory ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT; + if (dir->Size) TRACE("Bound Import directory ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IAT; + if (dir->Size) TRACE("Import Address Table directory ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT; + if (dir->Size) + { + TRACE("Delayed import, stub calls LoadLibrary\n" ); + /* + * Nothing to do here. + */ + +#ifdef ImgDelayDescr + /* + * This code is useful to observe what the heck is going on. + */ + { + ImgDelayDescr *pe_delay = NULL; + pe_delay = (PImgDelayDescr)RVA(dir->VirtualAddress); + TRACE_(delayhlp)("pe_delay->grAttrs = %08x\n", pe_delay->grAttrs); + TRACE_(delayhlp)("pe_delay->szName = %s\n", pe_delay->szName); + TRACE_(delayhlp)("pe_delay->phmod = %08x\n", pe_delay->phmod); + TRACE_(delayhlp)("pe_delay->pIAT = %08x\n", pe_delay->pIAT); + TRACE_(delayhlp)("pe_delay->pINT = %08x\n", pe_delay->pINT); + TRACE_(delayhlp)("pe_delay->pBoundIAT = %08x\n", pe_delay->pBoundIAT); + TRACE_(delayhlp)("pe_delay->pUnloadIAT = %08x\n", pe_delay->pUnloadIAT); + TRACE_(delayhlp)("pe_delay->dwTimeStamp = %08x\n", pe_delay->dwTimeStamp); + } +#endif + } + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR; + if (dir->Size) FIXME("Unknown directory 14 ignored\n" ); + + dir = nt->OptionalHeader.DataDirectory+15; + if (dir->Size) FIXME("Unknown directory 15 ignored\n" ); + + + + + wm = (WINE_MODREF *)HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(*wm) ); + wm->module = hModule; + + if ( builtin ) + wm->flags |= WINE_MODREF_INTERNAL; + if ( flags & DONT_RESOLVE_DLL_REFERENCES ) + wm->flags |= WINE_MODREF_DONT_RESOLVE_REFS; + if ( flags & LOAD_LIBRARY_AS_DATAFILE ) + wm->flags |= WINE_MODREF_LOAD_AS_DATAFILE; + + wm->type = MODULE32_PE; + wm->binfmt.pe.pe_export = pe_export; + wm->binfmt.pe.pe_import = pe_import; + wm->binfmt.pe.pe_resource = pe_resource; + wm->binfmt.pe.tlsindex = -1; + + wm->filename = malloc(strlen(filename)+1); + strcpy(wm->filename, filename ); + wm->modname = strrchr( wm->filename, '\\' ); + if (!wm->modname) wm->modname = wm->filename; + else wm->modname++; + + if ( pe_export ) + dump_exports( hModule ); + + /* Fixup Imports */ + + if ( pe_import + && !( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) + && !( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) + && fixup_imports( wm ) ) + { + /* remove entry from modref chain */ + return NULL; + } + + return wm; + + return wm; +} + +/****************************************************************************** + * The PE Library Loader frontend. + * FIXME: handle the flags. + */ +WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags) +{ + HMODULE hModule32; + WINE_MODREF *wm; + char filename[256]; + int hFile; + WORD version = 0; + + + strncpy(filename, name, sizeof(filename)); + hFile=open(filename, O_RDONLY); + if(hFile==-1) + return NULL; + + + hModule32 = PE_LoadImage( hFile, filename, &version ); + if (!hModule32) + { + SetLastError( ERROR_OUTOFMEMORY ); + return NULL; + } + + if ( !(wm = PE_CreateModule( hModule32, filename, flags, FALSE )) ) + { + ERR( "can't load %s\n", filename ); + SetLastError( ERROR_OUTOFMEMORY ); + return NULL; + } + close(hFile); + //printf("^^^^^^^^^^^^^^^^Alloc VM1 %p\n", wm); + return wm; +} + + +/***************************************************************************** + * PE_UnloadLibrary + * + * Unload the library unmapping the image and freeing the modref structure. + */ +void PE_UnloadLibrary(WINE_MODREF *wm) +{ + TRACE(" unloading %s\n", wm->filename); + + if (wm->filename) + free(wm->filename); + if (wm->short_filename) + free(wm->short_filename); + HeapFree( GetProcessHeap(), 0, wm->deps ); + VirtualFree( (LPVOID)wm->module, 0, MEM_RELEASE ); + HeapFree( GetProcessHeap(), 0, wm ); + //printf("^^^^^^^^^^^^^^^^Free VM1 %p\n", wm); +} + +/***************************************************************************** + * Load the PE main .EXE. All other loading is done by PE_LoadLibraryExA + * FIXME: this function should use PE_LoadLibraryExA, but currently can't + * due to the PROCESS_Create stuff. + */ + + +/* + * This is a dirty hack. + * The win32 DLLs contain an alloca routine, that first probes the soon + * to be allocated new memory *below* the current stack pointer in 4KByte + * increments. After the mem probing below the current %esp, the stack + * pointer is finally decremented to make room for the "alloca"ed memory. + * Maybe the probing code is intended to extend the stack on a windows box. + * Anyway, the linux kernel does *not* extend the stack by simply accessing + * memory below %esp; it segfaults. + * The extend_stack_for_dll_alloca() routine just preallocates a big chunk + * of memory on the stack, for use by the DLLs alloca routine. + */ +static void extend_stack_for_dll_alloca(void) +{ +#ifndef __FreeBSD__ + void* mem=alloca(0x20000); + *(int*)mem=0x1234; +#endif +} + +/* Called if the library is loaded or freed. + * NOTE: if a thread attaches a DLL, the current thread will only do + * DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH + * (SDK) + */ +WIN_BOOL PE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved ) +{ + WIN_BOOL retv = TRUE; + assert( wm->type == MODULE32_PE ); + + + if ((PE_HEADER(wm->module)->FileHeader.Characteristics & IMAGE_FILE_DLL) && + (PE_HEADER(wm->module)->OptionalHeader.AddressOfEntryPoint) + ) { + DLLENTRYPROC entry ; + entry = (void*)PE_FindExportedFunction(wm, "DllMain", 0); + if(entry==NULL) + entry = (void*)RVA_PTR( wm->module,OptionalHeader.AddressOfEntryPoint ); + + TRACE_(relay)("CallTo32(entryproc=%p,module=%08x,type=%ld,res=%p)\n", + entry, wm->module, type, lpReserved ); + + + TRACE("Entering DllMain("); + switch(type) + { + case DLL_PROCESS_DETACH: + TRACE("DLL_PROCESS_DETACH) "); + break; + case DLL_PROCESS_ATTACH: + TRACE("DLL_PROCESS_ATTACH) "); + break; + case DLL_THREAD_DETACH: + TRACE("DLL_THREAD_DETACH) "); + break; + case DLL_THREAD_ATTACH: + TRACE("DLL_THREAD_ATTACH) "); + break; + } + TRACE("for %s\n", wm->filename); + extend_stack_for_dll_alloca(); + retv = entry( wm->module, type, lpReserved ); + } + + return retv; +} + +static LPVOID +_fixup_address(PIMAGE_OPTIONAL_HEADER opt,int delta,LPVOID addr) { + if ( ((DWORD)addr>opt->ImageBase) && + ((DWORD)addrImageBase+opt->SizeOfImage) + ) + + return (LPVOID)(((DWORD)addr)+delta); + else + + return addr; +} diff --git a/linphone/win32acm/pe_resource.c b/linphone/win32acm/pe_resource.c new file mode 100644 index 000000000..f7afcbfce --- /dev/null +++ b/linphone/win32acm/pe_resource.c @@ -0,0 +1,392 @@ +/* + * PE (Portable Execute) File Resources + * + * Copyright 1995 Thomas Sandford + * Copyright 1996 Martin von Loewis + * + * Based on the Win16 resource handling code in loader/resource.c + * Copyright 1993 Robert J. Amstadt + * Copyright 1995 Alexandre Julliard + * Copyright 1997 Marcus Meissner + */ +#include "config.h" + +#include +#include +#include "wine/winestring.h" +#include "wine/windef.h" +#include "wine/pe_image.h" +#include "wine/module.h" +#include "wine/heap.h" +//#include "task.h" +//#include "process.h" +//#include "stackframe.h" +#include "wine/debugtools.h" +#include "ext.h" + +/********************************************************************** + * HMODULE32toPE_MODREF + * + * small helper function to get a PE_MODREF from a passed HMODULE32 + */ +static PE_MODREF* +HMODULE32toPE_MODREF(HMODULE hmod) { + WINE_MODREF *wm; + + wm = MODULE32_LookupHMODULE( hmod ); + if (!wm || wm->type!=MODULE32_PE) + return NULL; + return &(wm->binfmt.pe); +} + +/********************************************************************** + * GetResDirEntryW + * + * Helper function - goes down one level of PE resource tree + * + */ +PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr, + LPCWSTR name,DWORD root, + WIN_BOOL allowdefault) +{ + int entrynum; + PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable; + int namelen; + + if (HIWORD(name)) { + if (name[0]=='#') { + char buf[10]; + + lstrcpynWtoA(buf,name+1,10); + return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault); + } + entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ( + (BYTE *) resdirptr + + sizeof(IMAGE_RESOURCE_DIRECTORY)); + namelen = lstrlenW(name); + for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++) + { + PIMAGE_RESOURCE_DIR_STRING_U str = + (PIMAGE_RESOURCE_DIR_STRING_U) (root + + entryTable[entrynum].u1.s.NameOffset); + if(namelen != str->Length) + continue; + if(wcsnicmp(name,str->NameString,str->Length)==0) + return (PIMAGE_RESOURCE_DIRECTORY) ( + root + + entryTable[entrynum].u2.s.OffsetToDirectory); + } + return NULL; + } else { + entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ( + (BYTE *) resdirptr + + sizeof(IMAGE_RESOURCE_DIRECTORY) + + resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY)); + for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++) + if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name) + return (PIMAGE_RESOURCE_DIRECTORY) ( + root + + entryTable[entrynum].u2.s.OffsetToDirectory); + /* just use first entry if no default can be found */ + if (allowdefault && !name && resdirptr->NumberOfIdEntries) + return (PIMAGE_RESOURCE_DIRECTORY) ( + root + + entryTable[0].u2.s.OffsetToDirectory); + return NULL; + } +} + +/********************************************************************** + * GetResDirEntryA + */ +PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr, + LPCSTR name, DWORD root, + WIN_BOOL allowdefault ) +{ + PIMAGE_RESOURCE_DIRECTORY retv; + LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name ) + : (LPWSTR)name; + + retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault ); + + if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW ); + + return retv; +} + +/********************************************************************** + * PE_FindResourceEx32W + */ +HANDLE PE_FindResourceExW( + WINE_MODREF *wm,LPCWSTR name,LPCWSTR type,WORD lang +) { + PIMAGE_RESOURCE_DIRECTORY resdirptr; + DWORD root; + HANDLE result; + PE_MODREF *pem = &(wm->binfmt.pe); + + if (!pem || !pem->pe_resource) + return 0; + + resdirptr = pem->pe_resource; + root = (DWORD) resdirptr; + if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL) + return 0; + if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL) + return 0; + result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE); + /* Try LANG_NEUTRAL, too */ + if(!result) + return (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)0, root, TRUE); + return result; +} + + +/********************************************************************** + * PE_LoadResource32 + */ +HANDLE PE_LoadResource( WINE_MODREF *wm, HANDLE hRsrc ) +{ + if (!hRsrc || !wm || wm->type!=MODULE32_PE) + return 0; + return (HANDLE) (wm->module + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData); +} + + +/********************************************************************** + * PE_SizeofResource32 + */ +DWORD PE_SizeofResource( HINSTANCE hModule, HANDLE hRsrc ) +{ + /* we don't need hModule */ + if (!hRsrc) + return 0; + return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size; +} + +/********************************************************************** + * PE_EnumResourceTypes32A + */ +WIN_BOOL +PE_EnumResourceTypesA(HMODULE hmod,ENUMRESTYPEPROCA lpfun,LONG lparam) { + PE_MODREF *pem = HMODULE32toPE_MODREF(hmod); + int i; + PIMAGE_RESOURCE_DIRECTORY resdir; + PIMAGE_RESOURCE_DIRECTORY_ENTRY et; + WIN_BOOL ret; + HANDLE heap = GetProcessHeap(); + + if (!pem || !pem->pe_resource) + return FALSE; + + resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource; + et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY)); + ret = FALSE; + for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { + LPSTR name; + + if (et[i].u1.s.NameIsString) + name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset)); + else + name = (LPSTR)(int)et[i].u1.Id; + ret = lpfun(hmod,name,lparam); + if (HIWORD(name)) + HeapFree(heap,0,name); + if (!ret) + break; + } + return ret; +} + +/********************************************************************** + * PE_EnumResourceTypes32W + */ +WIN_BOOL +PE_EnumResourceTypesW(HMODULE hmod,ENUMRESTYPEPROCW lpfun,LONG lparam) { + PE_MODREF *pem = HMODULE32toPE_MODREF(hmod); + int i; + PIMAGE_RESOURCE_DIRECTORY resdir; + PIMAGE_RESOURCE_DIRECTORY_ENTRY et; + WIN_BOOL ret; + + if (!pem || !pem->pe_resource) + return FALSE; + + resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource; + et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY)); + ret = FALSE; + for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { + LPWSTR type; + if (et[i].u1.s.NameIsString) + type = (LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset); + else + type = (LPWSTR)(int)et[i].u1.Id; + + ret = lpfun(hmod,type,lparam); + if (!ret) + break; + } + return ret; +} + +/********************************************************************** + * PE_EnumResourceNames32A + */ +WIN_BOOL +PE_EnumResourceNamesA( + HMODULE hmod,LPCSTR type,ENUMRESNAMEPROCA lpfun,LONG lparam +) { + PE_MODREF *pem = HMODULE32toPE_MODREF(hmod); + int i; + PIMAGE_RESOURCE_DIRECTORY resdir; + PIMAGE_RESOURCE_DIRECTORY_ENTRY et; + WIN_BOOL ret; + HANDLE heap = GetProcessHeap(); + LPWSTR typeW; + + if (!pem || !pem->pe_resource) + return FALSE; + resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource; + if (HIWORD(type)) + typeW = HEAP_strdupAtoW(heap,0,type); + else + typeW = (LPWSTR)type; + resdir = GetResDirEntryW(resdir,typeW,(DWORD)pem->pe_resource,FALSE); + if (HIWORD(typeW)) + HeapFree(heap,0,typeW); + if (!resdir) + return FALSE; + et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY)); + ret = FALSE; + for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { + LPSTR name; + + if (et[i].u1.s.NameIsString) + name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset)); + else + name = (LPSTR)(int)et[i].u1.Id; + ret = lpfun(hmod,type,name,lparam); + if (HIWORD(name)) HeapFree(heap,0,name); + if (!ret) + break; + } + return ret; +} + +/********************************************************************** + * PE_EnumResourceNames32W + */ +WIN_BOOL +PE_EnumResourceNamesW( + HMODULE hmod,LPCWSTR type,ENUMRESNAMEPROCW lpfun,LONG lparam +) { + PE_MODREF *pem = HMODULE32toPE_MODREF(hmod); + int i; + PIMAGE_RESOURCE_DIRECTORY resdir; + PIMAGE_RESOURCE_DIRECTORY_ENTRY et; + WIN_BOOL ret; + + if (!pem || !pem->pe_resource) + return FALSE; + + resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource; + resdir = GetResDirEntryW(resdir,type,(DWORD)pem->pe_resource,FALSE); + if (!resdir) + return FALSE; + et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY)); + ret = FALSE; + for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { + LPWSTR name; + if (et[i].u1.s.NameIsString) + name = (LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset); + else + name = (LPWSTR)(int)et[i].u1.Id; + ret = lpfun(hmod,type,name,lparam); + if (!ret) + break; + } + return ret; +} + +/********************************************************************** + * PE_EnumResourceNames32A + */ +WIN_BOOL +PE_EnumResourceLanguagesA( + HMODULE hmod,LPCSTR name,LPCSTR type,ENUMRESLANGPROCA lpfun, + LONG lparam +) { + PE_MODREF *pem = HMODULE32toPE_MODREF(hmod); + int i; + PIMAGE_RESOURCE_DIRECTORY resdir; + PIMAGE_RESOURCE_DIRECTORY_ENTRY et; + WIN_BOOL ret; + HANDLE heap = GetProcessHeap(); + LPWSTR nameW,typeW; + + if (!pem || !pem->pe_resource) + return FALSE; + + resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource; + if (HIWORD(name)) + nameW = HEAP_strdupAtoW(heap,0,name); + else + nameW = (LPWSTR)name; + resdir = GetResDirEntryW(resdir,nameW,(DWORD)pem->pe_resource,FALSE); + if (HIWORD(nameW)) + HeapFree(heap,0,nameW); + if (!resdir) + return FALSE; + if (HIWORD(type)) + typeW = HEAP_strdupAtoW(heap,0,type); + else + typeW = (LPWSTR)type; + resdir = GetResDirEntryW(resdir,typeW,(DWORD)pem->pe_resource,FALSE); + if (HIWORD(typeW)) + HeapFree(heap,0,typeW); + if (!resdir) + return FALSE; + et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY)); + ret = FALSE; + for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { + /* languages are just ids... I hopem */ + ret = lpfun(hmod,name,type,et[i].u1.Id,lparam); + if (!ret) + break; + } + return ret; +} + +/********************************************************************** + * PE_EnumResourceLanguages32W + */ +WIN_BOOL +PE_EnumResourceLanguagesW( + HMODULE hmod,LPCWSTR name,LPCWSTR type,ENUMRESLANGPROCW lpfun, + LONG lparam +) { + PE_MODREF *pem = HMODULE32toPE_MODREF(hmod); + int i; + PIMAGE_RESOURCE_DIRECTORY resdir; + PIMAGE_RESOURCE_DIRECTORY_ENTRY et; + WIN_BOOL ret; + + if (!pem || !pem->pe_resource) + return FALSE; + + resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource; + resdir = GetResDirEntryW(resdir,name,(DWORD)pem->pe_resource,FALSE); + if (!resdir) + return FALSE; + resdir = GetResDirEntryW(resdir,type,(DWORD)pem->pe_resource,FALSE); + if (!resdir) + return FALSE; + et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY)); + ret = FALSE; + for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { + ret = lpfun(hmod,name,type,et[i].u1.Id,lparam); + if (!ret) + break; + } + return ret; +} diff --git a/linphone/win32acm/registry.c b/linphone/win32acm/registry.c new file mode 100644 index 000000000..1fe90e099 --- /dev/null +++ b/linphone/win32acm/registry.c @@ -0,0 +1,526 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "wine/winbase.h" +#include "wine/winreg.h" +#include "wine/winnt.h" +#include "wine/winerror.h" + +#include "ext.h" +#include "registry.h" + +//#undef TRACE +//#define TRACE printf + +extern char *get_path ( char * ); + +// ...can be set before init_registry() call +char* regpathname = NULL; + +static char* localregpathname = NULL; + +typedef struct reg_handle_s +{ + int handle; + char* name; + struct reg_handle_s* next; + struct reg_handle_s* prev; +} reg_handle_t; + +struct reg_value +{ + int type; + char* name; + int len; + char* value; +}; + +static struct reg_value* regs = NULL; +static int reg_size; +static reg_handle_t* head = NULL; + +#define DIR -25 + +static void create_registry(void); +static void open_registry(void); +static void save_registry(void); +static void init_registry(void); + + +static void create_registry(void){ + if(regs) + { + printf("Logic error: create_registry() called with existing registry\n"); + save_registry(); + return; + } + regs=(struct reg_value*)malloc(3*sizeof(struct reg_value)); + regs[0].type=regs[1].type=DIR; + regs[0].name=(char*)malloc(5); + strcpy(regs[0].name, "HKLM"); + regs[1].name=(char*)malloc(5); + strcpy(regs[1].name, "HKCU"); + regs[0].value=regs[1].value=NULL; + regs[0].len=regs[1].len=0; + reg_size=2; + head = 0; + save_registry(); +} + +static void open_registry(void) +{ + int fd; + int i; + unsigned int len; + if(regs) + { + printf("Multiple open_registry(>\n"); + return; + } + fd = open(localregpathname, O_RDONLY); + if (fd == -1) + { + printf("Creating new registry\n"); + create_registry(); + return; + } + read(fd, ®_size, 4); + regs=(struct reg_value*)malloc(reg_size*sizeof(struct reg_value)); + head = 0; + for(i=0; iname) + free(t->name); + t=t->prev; + free(f); + } + head = 0; + if (regs) + { + int i; + for(i=0; iprev) + { + if(!strcmp(t->name, name)) + { + return t; + } + } + return 0; +} +static struct reg_value* find_value_by_name(const char* name) +{ + int i; + for(i=0; iprev) + { + if(t->handle==handle) + { + return t; + } + } + return 0; +} +static int generate_handle() +{ + static unsigned int zz=249; + zz++; + while((zz==HKEY_LOCAL_MACHINE) || (zz==HKEY_CURRENT_USER)) + zz++; + return zz; +} + +static reg_handle_t* insert_handle(long handle, const char* name) +{ + reg_handle_t* t; + t=(reg_handle_t*)malloc(sizeof(reg_handle_t)); + if(head==0) + { + t->prev=0; + } + else + { + head->next=t; + t->prev=head; + } + t->next=0; + t->name=(char*)malloc(strlen(name)+1); + strcpy(t->name, name); + t->handle=handle; + head=t; + return t; +} +static char* build_keyname(long key, const char* subkey) +{ + char* full_name; + reg_handle_t* t; + if((t=find_handle(key))==0) + { + TRACE("Invalid key\n"); + return NULL; + } + if(subkey==NULL) + subkey=""; + full_name=(char*)malloc(strlen(t->name)+strlen(subkey)+10); + strcpy(full_name, t->name); + strcat(full_name, "\\"); + strcat(full_name, subkey); + return full_name; +} +static struct reg_value* insert_reg_value(int handle, const char* name, int type, const void* value, int len) +{ + reg_handle_t* t; + struct reg_value* v; + char* fullname; + if((fullname=build_keyname(handle, name))==NULL) + { + TRACE("Invalid handle\n"); + return NULL; + } + + if((v=find_value_by_name(fullname))==0) + //creating new value in registry + { + if(regs==0) + create_registry(); + regs=(struct reg_value*)realloc(regs, sizeof(struct reg_value)*(reg_size+1)); + //regs=(struct reg_value*)my_realloc(regs, sizeof(struct reg_value)*(reg_size+1)); + v=regs+reg_size; + reg_size++; + } + else + //replacing old one + { + free(v->value); + free(v->name); + } + TRACE("RegInsert '%s' %p v:%d len:%d\n", name, value, *(int*)value, len); + v->type=type; + v->len=len; + v->value=(char*)malloc(len); + memcpy(v->value, value, len); + v->name=(char*)malloc(strlen(fullname)+1); + strcpy(v->name, fullname); + free(fullname); + save_registry(); + return v; +} + +static void init_registry(void) +{ + TRACE("Initializing registry\n"); + // can't be free-ed - it's static and probably thread + // unsafe structure which is stored in glibc + +#ifdef MPLAYER + regpathname = get_path("registry"); + localregpathname = regpathname; +#else + // regpathname is an external pointer + // + // registry.c is holding it's own internal pointer + // localregpathname - which is being allocate/deallocated + + if (localregpathname == 0) + { + const char* pthn = regpathname; + if (!regpathname) + { + // avifile - for now reading data from user's home + struct passwd* pwent; + pwent = getpwuid(geteuid()); + pthn = pwent->pw_dir; + } + + localregpathname = (char*)malloc(strlen(pthn)+20); + strcpy(localregpathname, pthn); + strcat(localregpathname, "/.registry"); + } +#endif + + open_registry(); + insert_handle(HKEY_LOCAL_MACHINE, "HKLM"); + insert_handle(HKEY_CURRENT_USER, "HKCU"); +} + +static reg_handle_t* find_handle_2(long key, const char* subkey) +{ + char* full_name; + reg_handle_t* t; + if((t=find_handle(key))==0) + { + TRACE("Invalid key\n"); + return (reg_handle_t*)-1; + } + if(subkey==NULL) + return t; + full_name=(char*)malloc(strlen(t->name)+strlen(subkey)+10); + strcpy(full_name, t->name); + strcat(full_name, "\\"); + strcat(full_name, subkey); + t=find_handle_by_name(full_name); + free(full_name); + return t; +} + +long RegOpenKeyExA(long key, const char* subkey, long reserved, long access, int* newkey) +{ + char* full_name; + reg_handle_t* t; + struct reg_value* v; + TRACE("Opening key %s\n", subkey); + + if(!regs) + init_registry() +; +/* t=find_handle_2(key, subkey); + + if(t==0) + return -1; + + if(t==(reg_handle_t*)-1) + return -1; +*/ + full_name=build_keyname(key, subkey); + if(!full_name) + return -1; + TRACE("Opening key Fullname %s\n", full_name); + v=find_value_by_name(full_name); + + t=insert_handle(generate_handle(), full_name); + *newkey=t->handle; + free(full_name); + + return 0; +} +long RegCloseKey(long key) +{ + reg_handle_t *handle; + if(key==(long)HKEY_LOCAL_MACHINE) + return 0; + if(key==(long)HKEY_CURRENT_USER) + return 0; + handle=find_handle(key); + if(handle==0) + return 0; + if(handle->prev) + handle->prev->next=handle->next; + if(handle->next) + handle->next->prev=handle->prev; + if(handle->name) + free(handle->name); + if(handle==head) + head=head->prev; + free(handle); + return 1; +} + +long RegQueryValueExA(long key, const char* value, int* reserved, int* type, int* data, int* count) +{ + struct reg_value* t; + char* c; + TRACE("Querying value %s\n", value); + if(!regs) + init_registry(); + + c=build_keyname(key, value); + if (!c) + return 1; + t=find_value_by_name(c); + free(c); + if (t==0) + return 2; + if (type) + *type=t->type; + if (data) + { + memcpy(data, t->value, (t->len<*count)?t->len:*count); + TRACE("returning %d bytes: %d\n", t->len, *(int*)data); + } + if(*countlen) + { + *count=t->len; + return ERROR_MORE_DATA; + } + else + { + *count=t->len; + } + return 0; +} +long RegCreateKeyExA(long key, const char* name, long reserved, + void* classs, long options, long security, + void* sec_attr, int* newkey, int* status) +{ + reg_handle_t* t; + char* fullname; + struct reg_value* v; + // TRACE("Creating/Opening key %s\n", name); + if(!regs) + init_registry(); + + fullname=build_keyname(key, name); + if (!fullname) + return 1; + TRACE("Creating/Opening key %s\n", fullname); + v=find_value_by_name(fullname); + if(v==0) + { + int qw=45708; + v=insert_reg_value(key, name, DIR, &qw, 4); + if (status) *status=REG_CREATED_NEW_KEY; + // return 0; + } + + t=insert_handle(generate_handle(), fullname); + *newkey=t->handle; + free(fullname); + return 0; +} + +/* +LONG RegEnumValue( + HKEY hKey, // handle to key to query + DWORD dwIndex, // index of value to query + LPTSTR lpValueName, // address of buffer for value string + LPDWORD lpcbValueName, // address for size of value buffer + LPDWORD lpReserved, // reserved + LPDWORD lpType, // address of buffer for type code + LPBYTE lpData, // address of buffer for value data + LPDWORD lpcbData // address for size of data buffer +); +*/ + +long RegEnumValueA(HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count, + LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count) +{ + // currenly just made to support MSZH & ZLIB + //printf("Reg Enum 0x%x %d %s %d data: %p %d %d >%s<\n", hkey, index, + // value, *val_count, data, *count, reg_size, data); + reg_handle_t* t = find_handle(hkey); + if (t && index < 10) + { + struct reg_value* v=find_value_by_name(t->name); + if (v) + { + memcpy(data, v->value, (v->len < *count) ? v->len : *count); + if(*count < v->len) + *count = v->len; + if (type) + *type = v->type; + //printf("Found handle %s\n", v->name); + return 0; + } + } + return ERROR_NO_MORE_ITEMS; +} + +long RegSetValueExA(long key, const char* name, long v1, long v2, const void* data, long size) +{ + struct reg_value* t; + char* c; + TRACE("Request to set value %s %d\n", name, *(const int*)data); + if(!regs) + init_registry(); + + c=build_keyname(key, name); + if(c==NULL) + return 1; + insert_reg_value(key, name, v2, data, size); + free(c); + return 0; +} + +long RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, + LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, + LPFILETIME lpftLastWriteTime) +{ + return ERROR_NO_MORE_ITEMS; +} diff --git a/linphone/win32acm/registry.h b/linphone/win32acm/registry.h new file mode 100644 index 000000000..45a6be692 --- /dev/null +++ b/linphone/win32acm/registry.h @@ -0,0 +1,40 @@ +#ifndef AVIFILE_REGISTRY_H +#define AVIFILE_REGISTRY_H + +/******************************************************** + * + * Declaration of registry access functions + * Copyright 2000 Eugene Kuznetsov (divx@euro.ru) + * + ********************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +void free_registry(void); + +long RegOpenKeyExA(long key, const char* subkey, long reserved, + long access, int* newkey); +long RegCloseKey(long key); +long RegQueryValueExA(long key, const char* value, int* reserved, + int* type, int* data, int* count); +long RegCreateKeyExA(long key, const char* name, long reserved, + void* classs, long options, long security, + void* sec_attr, int* newkey, int* status); +long RegSetValueExA(long key, const char* name, long v1, long v2, + const void* data, long size); + +#ifdef __WINE_WINERROR_H + +long RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, + LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, + LPFILETIME lpftLastWriteTime); +long RegEnumValueA(HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count, + LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count); +#endif +#ifdef __cplusplus +}; +#endif + +#endif // AVIFILE_REGISTRY_H diff --git a/linphone/win32acm/resource.c b/linphone/win32acm/resource.c new file mode 100644 index 000000000..3cb69bd00 --- /dev/null +++ b/linphone/win32acm/resource.c @@ -0,0 +1,482 @@ +/* + * Resources + * + * Copyright 1993 Robert J. Amstadt + * Copyright 1995 Alexandre Julliard + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/winbase.h" +#include "wine/windef.h" +#include "wine/winuser.h" +#include "wine/heap.h" +#include "wine/module.h" +#include "wine/debugtools.h" +#include "wine/winerror.h" +#include "loader.h" + +#define CP_ACP 0 + +WORD WINE_LanguageId=0x409;//english + +#define HRSRC_MAP_BLOCKSIZE 16 + +typedef struct _HRSRC_ELEM +{ + HANDLE hRsrc; + WORD type; +} HRSRC_ELEM; + +typedef struct _HRSRC_MAP +{ + int nAlloc; + int nUsed; + HRSRC_ELEM *elem; +} HRSRC_MAP; + +static HRSRC RES_FindResource2( HMODULE hModule, LPCSTR type, + LPCSTR name, WORD lang, int unicode) +{ + HRSRC hRsrc = 0; + LPWSTR typeStr, nameStr; + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + + if(!wm) + return 0; + /* 32-bit PE module */ + + + if ( HIWORD( type ) && (!unicode)) + typeStr = HEAP_strdupAtoW( GetProcessHeap(), 0, type ); + else + typeStr = (LPWSTR)type; + if ( HIWORD( name ) && (!unicode)) + nameStr = HEAP_strdupAtoW( GetProcessHeap(), 0, name ); + else + nameStr = (LPWSTR)name; + + hRsrc = PE_FindResourceExW( wm, nameStr, typeStr, lang ); + + if ( HIWORD( type ) && (!unicode)) + HeapFree( GetProcessHeap(), 0, typeStr ); + if ( HIWORD( name ) && (!unicode)) + HeapFree( GetProcessHeap(), 0, nameStr ); + + return hRsrc; +} + +/********************************************************************** + * RES_FindResource + */ + +static HRSRC RES_FindResource( HMODULE hModule, LPCSTR type, + LPCSTR name, WORD lang, int unicode ) +{ + HRSRC hRsrc; +// __TRY +// { + hRsrc = RES_FindResource2(hModule, type, name, lang, unicode); +// } +// __EXCEPT(page_fault) +// { +// WARN("page fault\n"); +// SetLastError(ERROR_INVALID_PARAMETER); +// return 0; +// } +// __ENDTRY + return hRsrc; +} + +/********************************************************************** + * RES_SizeofResource + */ +static DWORD RES_SizeofResource( HMODULE hModule, HRSRC hRsrc) +{ + DWORD size = 0; + HRSRC hRsrc32; + +// HMODULE16 hMod16 = MapHModuleLS( hModule ); +// NE_MODULE *pModule = NE_GetPtr( hMod16 ); +// WINE_MODREF *wm = pModule && pModule->module32? +// MODULE32_LookupHMODULE( pModule->module32 ) : NULL; + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + + if ( !hModule || !hRsrc ) return 0; + + /* 32-bit PE module */ + /* If we got a 16-bit hRsrc, convert it */ +// hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc ); + if(!HIWORD(hRsrc)) + { + printf("16-bit hRsrcs not supported\n"); + return 0; + } + size = PE_SizeofResource( hModule, hRsrc ); + return size; +} + +/********************************************************************** + * RES_AccessResource + */ +static HFILE RES_AccessResource( HMODULE hModule, HRSRC hRsrc ) +{ + HFILE hFile = HFILE_ERROR; + + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + + if ( !hModule || !hRsrc ) return HFILE_ERROR; + + /* 32-bit PE module */ + FIXME("32-bit modules not yet supported.\n" ); + hFile = HFILE_ERROR; + + return hFile; +} + +/********************************************************************** + * RES_LoadResource + */ +static HGLOBAL RES_LoadResource( HMODULE hModule, HRSRC hRsrc) +{ + HGLOBAL hMem = 0; + HRSRC hRsrc32; + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + + + if ( !hModule || !hRsrc ) return 0; + + /* 32-bit PE module */ + + /* If we got a 16-bit hRsrc, convert it */ +// hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc ); + if(!HIWORD(hRsrc)) + { + printf("16-bit hRsrcs not supported\n"); + return 0; + } + hMem = PE_LoadResource( wm, hRsrc ); + + return hMem; +} + +/********************************************************************** + * RES_LockResource + */ +static LPVOID RES_LockResource( HGLOBAL handle ) +{ + LPVOID bits = NULL; + + TRACE("(%08x, %s)\n", handle, "PE" ); + + bits = (LPVOID)handle; + + return bits; +} + +/********************************************************************** + * RES_FreeResource + */ +static WIN_BOOL RES_FreeResource( HGLOBAL handle ) +{ + HGLOBAL retv = handle; + return (WIN_BOOL)retv; +} + +/********************************************************************** + * FindResourceA (KERNEL32.128) + */ +HANDLE WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type ) +{ + return RES_FindResource( hModule, type, name, + WINE_LanguageId, 0); +} +HANDLE WINAPI FindResourceW( HMODULE hModule, LPCWSTR name, LPCWSTR type ) +{ + return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name, + WINE_LanguageId, 1); +} + +/********************************************************************** + * FindResourceExA (KERNEL32.129) + */ +HANDLE WINAPI FindResourceExA( HMODULE hModule, + LPCSTR type, LPCSTR name, WORD lang ) +{ + return RES_FindResource( hModule, type, name, + lang, 0 ); +} + +HANDLE WINAPI FindResourceExW( HMODULE hModule, + LPCWSTR type, LPCWSTR name, WORD lang ) +{ + return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name, + lang, 1 ); +} + + + +/********************************************************************** + * LockResource (KERNEL32.384) + */ +LPVOID WINAPI LockResource( HGLOBAL handle ) +{ + return RES_LockResource( handle ); +} + + +/********************************************************************** + * FreeResource (KERNEL32.145) + */ +WIN_BOOL WINAPI FreeResource( HGLOBAL handle ) +{ + return RES_FreeResource( handle ); +} + + +/********************************************************************** + * AccessResource (KERNEL32.64) + */ +INT WINAPI AccessResource( HMODULE hModule, HRSRC hRsrc ) +{ + return RES_AccessResource( hModule, hRsrc ); +} +/********************************************************************** + * SizeofResource (KERNEL32.522) + */ +DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc ) +{ + return RES_SizeofResource( hModule, hRsrc ); +} + + +INT WINAPI LoadStringW( HINSTANCE instance, UINT resource_id, + LPWSTR buffer, INT buflen ); + +/********************************************************************** + * LoadStringA (USER32.375) + */ +INT WINAPI LoadStringA( HINSTANCE instance, UINT resource_id, + LPSTR buffer, INT buflen ) +{ + INT retval; + INT wbuflen; + INT abuflen; + LPWSTR wbuf = NULL; + LPSTR abuf = NULL; + + if ( buffer != NULL && buflen > 0 ) + *buffer = 0; + + wbuflen = LoadStringW(instance,resource_id,NULL,0); + if ( !wbuflen ) + return 0; + wbuflen ++; + + retval = 0; + wbuf = (LPWSTR) HeapAlloc( GetProcessHeap(), 0, wbuflen * sizeof(WCHAR) ); + wbuflen = LoadStringW(instance,resource_id,wbuf,wbuflen); + if ( wbuflen > 0 ) + { + abuflen = WideCharToMultiByte(CP_ACP,0,wbuf,wbuflen,NULL,0,NULL,NULL); + if ( abuflen > 0 ) + { + if ( buffer == NULL || buflen == 0 ) + retval = abuflen; + else + { + abuf = (LPSTR) HeapAlloc( GetProcessHeap(), 0, abuflen * sizeof(CHAR) ); + abuflen = WideCharToMultiByte(CP_ACP,0,wbuf,wbuflen,abuf,abuflen,NULL,NULL); + if ( abuflen > 0 ) + { + abuflen = min(abuflen,buflen - 1); + memcpy( buffer, abuf, abuflen ); + buffer[abuflen] = 0; + retval = abuflen; + } + HeapFree( GetProcessHeap(), 0, abuf ); + } + } + } + HeapFree( GetProcessHeap(), 0, wbuf ); + + return retval; +} + +/********************************************************************** + * LoadStringW (USER32.376) + */ +INT WINAPI LoadStringW( HINSTANCE instance, UINT resource_id, + LPWSTR buffer, INT buflen ) +{ + HGLOBAL hmem; + HRSRC hrsrc; + WCHAR *p; + int string_num; + int i; + + if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */ + resource_id = (UINT)(-((INT)resource_id)); + TRACE("instance = %04x, id = %04x, buffer = %08x, " + "length = %d\n", instance, (int)resource_id, (int) buffer, buflen); + + /* Use bits 4 - 19 (incremented by 1) as resourceid, mask out + * 20 - 31. */ + hrsrc = FindResourceW( instance, (LPCWSTR)(((resource_id>>4)&0xffff)+1), + RT_STRINGW ); + if (!hrsrc) return 0; + hmem = LoadResource( instance, hrsrc ); + if (!hmem) return 0; + + p = (WCHAR*) LockResource(hmem); + string_num = resource_id & 0x000f; + for (i = 0; i < string_num; i++) + p += *p + 1; + + TRACE("strlen = %d\n", (int)*p ); + + if (buffer == NULL) return *p; + i = min(buflen - 1, *p); + if (i > 0) { + memcpy(buffer, p + 1, i * sizeof (WCHAR)); + buffer[i] = (WCHAR) 0; + } else { + if (buflen > 1) { + buffer[0] = (WCHAR) 0; + return 0; + } +#if 0 + WARN("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1); +#endif + } + + TRACE("String loaded !\n"); + return i; +} + +/* Messages...used by FormatMessage32* (KERNEL32.something) + * + * They can be specified either directly or using a message ID and + * loading them from the resource. + * + * The resourcedata has following format: + * start: + * 0: DWORD nrofentries + * nrofentries * subentry: + * 0: DWORD firstentry + * 4: DWORD lastentry + * 8: DWORD offset from start to the stringentries + * + * (lastentry-firstentry) * stringentry: + * 0: WORD len (0 marks end) + * 2: WORD flags + * 4: CHAR[len-4] + * (stringentry i of a subentry refers to the ID 'firstentry+i') + * + * Yes, ANSI strings in win32 resources. Go figure. + */ + +/********************************************************************** + * LoadMessageA (internal) + */ +INT WINAPI LoadMessageA( HMODULE instance, UINT id, WORD lang, + LPSTR buffer, INT buflen ) +{ + HGLOBAL hmem; + HRSRC hrsrc; + PMESSAGE_RESOURCE_DATA mrd; + PMESSAGE_RESOURCE_BLOCK mrb; + PMESSAGE_RESOURCE_ENTRY mre; + int i,slen; + + TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen); + + /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/ + hrsrc = FindResourceExW(instance,RT_MESSAGELISTW,(LPWSTR)1,lang); + if (!hrsrc) return 0; + hmem = LoadResource( instance, hrsrc ); + if (!hmem) return 0; + + mrd = (PMESSAGE_RESOURCE_DATA)LockResource(hmem); + mre = NULL; + mrb = &(mrd->Blocks[0]); + for (i=mrd->NumberOfBlocks;i--;) { + if ((id>=mrb->LowId) && (id<=mrb->HighId)) { + mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mrd)+mrb->OffsetToEntries); + id -= mrb->LowId; + break; + } + mrb++; + } + if (!mre) + return 0; + for (i=id;i--;) { + if (!mre->Length) + return 0; + mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mre)+(mre->Length)); + } + slen=mre->Length; + TRACE(" - strlen=%d\n",slen); + i = min(buflen - 1, slen); + if (buffer == NULL) + return slen; + if (i>0) { + lstrcpynA(buffer,(char*)mre->Text,i); + buffer[i]=0; + } else { + if (buflen>1) { + buffer[0]=0; + return 0; + } + } + if (buffer) + TRACE("'%s' copied !\n", buffer); + return i; +} + + + +/********************************************************************** + * EnumResourceTypesA (KERNEL32.90) + */ +WIN_BOOL WINAPI EnumResourceTypesA( HMODULE hmodule,ENUMRESTYPEPROCA lpfun, + LONG lParam) +{ + /* FIXME: move WINE_MODREF stuff here */ + return PE_EnumResourceTypesA(hmodule,lpfun,lParam); +} + +/********************************************************************** + * EnumResourceNamesA (KERNEL32.88) + */ +WIN_BOOL WINAPI EnumResourceNamesA( HMODULE hmodule, LPCSTR type, + ENUMRESNAMEPROCA lpfun, LONG lParam ) +{ + /* FIXME: move WINE_MODREF stuff here */ + return PE_EnumResourceNamesA(hmodule,type,lpfun,lParam); +} +/********************************************************************** + * EnumResourceLanguagesA (KERNEL32.86) + */ +WIN_BOOL WINAPI EnumResourceLanguagesA( HMODULE hmodule, LPCSTR type, + LPCSTR name, ENUMRESLANGPROCA lpfun, + LONG lParam) +{ + /* FIXME: move WINE_MODREF stuff here */ + return PE_EnumResourceLanguagesA(hmodule,type,name,lpfun,lParam); +} +/********************************************************************** + * LoadResource (KERNEL32.370) + */ +HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc ) +{ + return RES_LoadResource( hModule, hRsrc); +} diff --git a/linphone/win32acm/stubs.s b/linphone/win32acm/stubs.s new file mode 100644 index 000000000..24d99aa9b --- /dev/null +++ b/linphone/win32acm/stubs.s @@ -0,0 +1,35 @@ + .data +.LC0: .string "Called unk_%s\n" + .balign 4 +.globl unk_exp1 +unk_exp1: + pushl %ebp + movl %esp,%ebp + subl $4,%esp + movl $1,-4(%ebp) + movl -4(%ebp),%eax + movl %eax,%ecx + movl %ecx,%edx + sall $4,%edx + subl %eax,%edx + leal 0(,%edx,2),%eax + movl %eax,%edx + addl $export_names,%edx + pushl %edx + pushl $.LC0 + call printf + addl $8,%esp + xorl %eax,%eax + leave + ret +.globl exp_EH_prolog +exp_EH_prolog: + pushl $0xff + pushl %eax + pushl %fs:0 + movl %esp, %fs:0 + movl 12(%esp), %eax + movl %ebp, 12(%esp) + leal 12(%esp), %ebp + pushl %eax + ret diff --git a/linphone/win32acm/test_truespeech.c b/linphone/win32acm/test_truespeech.c new file mode 100644 index 000000000..1cf102490 --- /dev/null +++ b/linphone/win32acm/test_truespeech.c @@ -0,0 +1,438 @@ +/* test_truespeech.c + * + * Copyright 2003 Robert W. Brewer + * and based on some initial code to load the + * TrueSpeech DLL with these libraries by + * Piotr P. Karwasz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "loader.h" +#include "driver.h" +#include "wine/windef.h" +#include "wineacm.h" +#include "string.h" + +#define PCM_INFILE "pcmin.raw" +#define TS_OUTFILE "truespeechout.raw" +#define PCM_OUTFILE "pcmout.raw" + +int verbose=5; +char* get_path(char* x){ return strdup(x);} + +#define TRUESPEECH_FORMAT 0x22 +#define TRUESPEECH_CBSIZE 32 + +// Looks like entire .wav header for a TrueSpeech +// file is 90 bytes long. This means if we assume +// we have a TrueSpeech input file we can just skip +// the first 90 bytes instead of deleting them first +// with a hex editor to create a .raw file. + + + +void* xmalloc(size_t s) +{ + void* p = malloc(s); + if (!p) + { + printf("out of memory\n"); + exit(1); + } + + return p; +} + + +// infilepcm: 1 if infile is pcm, outfile is truespeech +// 0 if infile is truespeech, outfile is pcm +// Returns: +// 0: success +// 1: error +int convertfile(char* infile, char* outfile, int infilepcm) +{ + WAVEFORMATEX *ts_wf = 0; + WAVEFORMATEX pcm_wf; + WAVEFORMATEX *i_wf = 0; + WAVEFORMATEX *o_wf = 0; + HACMSTREAM handle; + MMRESULT ret; + DWORD srcsize = 0; + DWORD destsize = 0; + long* iptr = 0; + PWINE_ACMDRIVERID acmDriver1 = 0; + PWINE_ACMDRIVERID acmDriver2 = 0; + ACMSTREAMHEADER header; + FILE* i_file; + FILE* o_file; + + + // TrueSpeech format + ts_wf = xmalloc(sizeof(WAVEFORMATEX) + TRUESPEECH_CBSIZE); + memset(ts_wf, 0, sizeof(*ts_wf) + TRUESPEECH_CBSIZE); + + ts_wf->wFormatTag = TRUESPEECH_FORMAT; + ts_wf->nChannels = 1; + ts_wf->nSamplesPerSec = 8000; + ts_wf->wBitsPerSample = 1; + ts_wf->nBlockAlign = 32; + ts_wf->nAvgBytesPerSec = 1067; + ts_wf->cbSize = TRUESPEECH_CBSIZE; + + // write extra data needed by TrueSpeech codec found + // from examining a TrueSpeech .wav file header + iptr = (long*)(ts_wf + 1); + *iptr = 0x00f00001; + +// print_wave_header(in_fmt); + + // Typical PCM format, 16-bit signed samples at 8 KHz. + memset(&pcm_wf, 0, sizeof(pcm_wf)); + + pcm_wf.wFormatTag = WAVE_FORMAT_PCM; + pcm_wf.nChannels = 1; + pcm_wf.nSamplesPerSec = 8000; + pcm_wf.wBitsPerSample = 16; + pcm_wf.nBlockAlign = pcm_wf.nChannels * pcm_wf.wBitsPerSample / 8; + pcm_wf.nAvgBytesPerSec = pcm_wf.nSamplesPerSec * pcm_wf.nBlockAlign; + +// print_wave_header(priv->o_wf); + + // decide which way to perform the conversion + if (infilepcm) + { + i_wf = &pcm_wf; + o_wf = ts_wf; + } + else + { + i_wf = ts_wf; + o_wf = &pcm_wf; + } + + // from here on out, everything is pretty generic as long as we + // use i_wf and o_wf + + acmDriver1 = MSACM_RegisterDriver("tssoft32.acm", TRUESPEECH_FORMAT, 0); + if (!acmDriver1) + { + printf("error registering TrueSpeech ACM driver for TrueSpeech\n"); + return 1; + } + + printf("register driver complete for truespeech\n"); + + + acmDriver2 = MSACM_RegisterDriver("tssoft32.acm", WAVE_FORMAT_PCM, 0); + if (!acmDriver2) + { + printf("error registering TrueSpeech ACM driver for PCM\n"); + return 1; + } + + printf("register driver complete for pcm\n"); + + // TrueSpeech isn't confident it can do realtime + // compression. Tell it we don't care and it's happy. + ret = acmStreamOpen(&handle, 0, i_wf, o_wf, 0, 0, 0, + ACM_STREAMOPENF_NONREALTIME); + if (ret) + { + if (ret == ACMERR_NOTPOSSIBLE) + { + printf("invalid codec\n"); + } + else + { + printf("acmStreamOpen error %d\n", ret); + } + + return 1; + } + + printf("audio codec opened\n"); + + // we assume that the format with the largest block alignment is + // the most picky. And it basically turns out that TrueSpeech has + // the largest block alignment. Anyway, we use that block alignment + // to ask for the preferred size of the "other" format's buffer. + // Then we turn around and ask for the first one's preferred buffer + // size based on the other's buffer size, which seems to turn out + // to be its block alignment. Or something like that. + if (i_wf->nBlockAlign > o_wf->nBlockAlign) + { + ret = acmStreamSize(handle, i_wf->nBlockAlign, &destsize, ACM_STREAMSIZEF_SOURCE); + if (ret) + { + printf("acmStreamSize error %d\n", ret); + return 1; + } + + printf("Audio ACM output buffer min. size: %ld\n", destsize); + if (!destsize) + { + printf("ACM codec reports destsize=0\n"); + return 1; + } + + ret = acmStreamSize(handle, destsize, &srcsize, ACM_STREAMSIZEF_DESTINATION); + if (ret) + { + printf("acmStreamSize error\n"); + return 1; + } + + printf("Audio ACM input buffer min. size: %ld\n", srcsize); + } + else + { + ret = acmStreamSize(handle, o_wf->nBlockAlign, &srcsize, ACM_STREAMSIZEF_DESTINATION); + if (ret) + { + printf("acmStreamSize error %d\n", ret); + return 1; + } + + printf("Audio ACM input buffer min. size: %ld\n", srcsize); + if (!srcsize) + { + printf("ACM codec reports srcsize=0\n"); + return 1; + } + + ret = acmStreamSize(handle, srcsize, &destsize, ACM_STREAMSIZEF_SOURCE); + if (ret) + { + printf("acmStreamSize error\n"); + return 1; + } + + printf("Audio ACM input buffer min. size: %ld\n", destsize); + } + + + // set up conversion buffers + + memset(&header, 0, sizeof(header)); + header.cbStruct = sizeof(header); + header.cbSrcLength = srcsize; + header.pbSrc = xmalloc(header.cbSrcLength); + header.cbDstLength = destsize; + header.pbDst = xmalloc(header.cbDstLength); + + ret = acmStreamPrepareHeader(handle, &header, 0); + if (ret) + { + printf("error preparing header\n"); + return 1; + } + + printf("header prepared %lx\n", header.fdwStatus); + + + // open files + i_file = fopen(infile, "rb"); + if (!i_file) + { + printf("error opening input file %s\n", infile); + return 1; + } + + printf("input file opened\n"); + + + o_file = fopen(outfile, "wb"); + if (!o_file) + { + printf("error opening output file %s\n", outfile); + return 1; + } + + + printf("output file opened\n"); + + int inbytes = 0; + + while (1) + { + inbytes = fread(header.pbSrc, 1, srcsize, i_file); + + if (inbytes != srcsize) + { + if (feof(i_file)) + { + printf("end of input file, last byte count %d\n", inbytes); + break; + } + + printf("read error\n"); + return 1; + } + + ret = acmStreamConvert(handle, &header, ACM_STREAMCONVERTF_BLOCKALIGN); + if (ret) + { + printf("conversion error\n"); + return 1; + } + + if (!(header.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)) + { + printf("header not marked done %lx\n", header.fdwStatus); + return 1; + } + + if (header.cbSrcLengthUsed != header.cbSrcLength) + { + printf("didn't use all of source data\n"); + return 1; + } + + printf("converted %d bytes to %d bytes\n", + header.cbSrcLengthUsed, + header.cbDstLengthUsed); + + if (fwrite(header.pbDst, 1, header.cbDstLengthUsed, o_file) != + header.cbDstLengthUsed) + { + printf("error writing file\n"); + return 1; + } + } + + // now convert the remaining bit of the file + // and ask for any leftover stuff + + header.cbSrcLength = inbytes; + while (1) + { + if (header.cbSrcLength) + { + // not a full block, but not quite the "end" either + ret = acmStreamConvert(handle, &header, 0); + } + else + { + // now we're at the end, let's see if anything is left + ret = acmStreamConvert(handle, &header, ACM_STREAMCONVERTF_END); + } + + if (ret) + { + printf("conversion error\n"); + return 1; + } + + if (!(header.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)) + { + printf("header not marked done %lx\n", header.fdwStatus); + return 1; + } + + if (header.cbSrcLengthUsed != header.cbSrcLength) + { + printf("didn't use all of source data\n"); + return 1; + } + + printf("converted %d bytes to %d bytes\n", + header.cbSrcLengthUsed, + header.cbDstLengthUsed); + + if (!header.cbDstLengthUsed) + { + printf("nothing given to output, must be done\n"); + break; + } + + if (fwrite(header.pbDst, 1, header.cbDstLengthUsed, o_file) != + header.cbDstLengthUsed) + { + printf("error writing file\n"); + return 1; + } + + // ensure we are getting the remaining stuff on the next time around + header.cbSrcLength = 0; + } + + + printf("finished converting file\n"); + + + // now close up shop + + fclose(i_file); + fclose(o_file); + + ret = acmStreamUnprepareHeader(handle, &header, 0); + if (ret) + { + printf("error unpreparing header\n"); + return 1; + } + + free(header.pbSrc); + free(header.pbDst); + + + ret = acmStreamClose(handle, 0); + if (ret) + { + printf("error closing acm stream\n"); + return 1; + } + + printf("acm stream closed\n"); + + MSACM_UnregisterDriver(acmDriver1); + + printf("acm driver unregistered for truespeech\n"); + + MSACM_UnregisterDriver(acmDriver2); + + printf("acm driver unregistered for pcm\n"); + + free(ts_wf); + + return 0; +} + + +int main (int argc, char **argv) +{ + printf("converting pcm to truespeech\n"); + + if (convertfile(PCM_INFILE, TS_OUTFILE, 1)) + { + printf("error converting pcm -> truespeech\n"); + return 1; + } + + printf("converting truespeech to pcm\n"); + + if (convertfile(TS_OUTFILE, PCM_OUTFILE, 0)) + { + printf("error converting truespeech -> pcm\n"); + return 1; + } + + printf("all done\n"); + + return 0; +} diff --git a/linphone/win32acm/win32.c b/linphone/win32acm/win32.c new file mode 100644 index 000000000..726aecd91 --- /dev/null +++ b/linphone/win32acm/win32.c @@ -0,0 +1,5184 @@ +/*********************************************************** + +Win32 emulation code. Functions that emulate +responses from corresponding Win32 API calls. +Since we are not going to be able to load +virtually any DLL, we can only implement this +much, adding needed functions with each new codec. + +Basic principle of implementation: it's not good +for DLL to know too much about its environment. + +************************************************************/ + +#include "config.h" + +#ifdef MPLAYER +#ifdef USE_QTX_CODECS +#define QTX +#endif +#define REALPLAYER +//#define LOADLIB_TRY_NATIVE +#endif + +#ifdef QTX +#define PSEUDO_SCREEN_WIDTH /*640*/800 +#define PSEUDO_SCREEN_HEIGHT /*480*/600 +#endif + +#include "wine/winbase.h" +#include "wine/winreg.h" +#include "wine/winnt.h" +#include "wine/winerror.h" +#include "wine/debugtools.h" +#include "wine/module.h" +#include "wine/winuser.h" + +#include +#include "win32.h" + +#include "registry.h" +#include "loader.h" +#include "com.h" +#include "ext.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_KSTAT +#include +#endif + +#if HAVE_VSSCANF +int vsscanf( const char *str, const char *format, va_list ap); +#else +/* system has no vsscanf. try to provide one */ +static int vsscanf( const char *str, const char *format, va_list ap) +{ + long p1 = va_arg(ap, long); + long p2 = va_arg(ap, long); + long p3 = va_arg(ap, long); + long p4 = va_arg(ap, long); + long p5 = va_arg(ap, long); + return sscanf(str, format, p1, p2, p3, p4, p5); +} +#endif + +char* def_path = WIN32_PATH; + +static void do_cpuid(unsigned int ax, unsigned int *regs) +{ + __asm__ __volatile__ + ( + "pushl %%ebx; pushl %%ecx; pushl %%edx;" + ".byte 0x0f, 0xa2;" + "movl %%eax, (%2);" + "movl %%ebx, 4(%2);" + "movl %%ecx, 8(%2);" + "movl %%edx, 12(%2);" + "popl %%edx; popl %%ecx; popl %%ebx;" + : "=a" (ax) + : "0" (ax), "S" (regs) + ); +} +static unsigned int c_localcount_tsc() +{ + int a; + __asm__ __volatile__ + ( + "rdtsc\n\t" + :"=a"(a) + : + :"edx" + ); + return a; +} +static void c_longcount_tsc(long long* z) +{ + __asm__ __volatile__ + ( + "pushl %%ebx\n\t" + "movl %%eax, %%ebx\n\t" + "rdtsc\n\t" + "movl %%eax, 0(%%ebx)\n\t" + "movl %%edx, 4(%%ebx)\n\t" + "popl %%ebx\n\t" + ::"a"(z) + ); +} +static unsigned int c_localcount_notsc() +{ + struct timeval tv; + unsigned limit=~0; + limit/=1000000; + gettimeofday(&tv, 0); + return limit*tv.tv_usec; +} +static void c_longcount_notsc(long long* z) +{ + struct timeval tv; + unsigned long long result; + unsigned limit=~0; + if(!z)return; + limit/=1000000; + gettimeofday(&tv, 0); + result=tv.tv_sec; + result<<=32; + result+=limit*tv.tv_usec; + *z=result; +} +static unsigned int localcount_stub(void); +static void longcount_stub(long long*); +static unsigned int (*localcount)()=localcount_stub; +static void (*longcount)(long long*)=longcount_stub; + +static pthread_mutex_t memmut; + +static unsigned int localcount_stub(void) +{ + unsigned int regs[4]; + do_cpuid(1, regs); + if ((regs[3] & 0x00000010) != 0) + { + localcount=c_localcount_tsc; + longcount=c_longcount_tsc; + } + else + { + localcount=c_localcount_notsc; + longcount=c_longcount_notsc; + } + return localcount(); +} +static void longcount_stub(long long* z) +{ + unsigned int regs[4]; + do_cpuid(1, regs); + if ((regs[3] & 0x00000010) != 0) + { + localcount=c_localcount_tsc; + longcount=c_longcount_tsc; + } + else + { + localcount=c_localcount_notsc; + longcount=c_longcount_notsc; + } + longcount(z); +} + +#ifdef MPLAYER +#include "mp_msg.h" +#endif +int LOADER_DEBUG=1; // active only if compiled with -DDETAILED_OUT +//#define DETAILED_OUT +static inline void dbgprintf(char* fmt, ...) +{ +#ifdef DETAILED_OUT + if(LOADER_DEBUG) + { + FILE* f; + va_list va; + va_start(va, fmt); + f=fopen("./log", "a"); + vprintf(fmt, va); + fflush(stdout); + if(f) + { + vfprintf(f, fmt, va); + fsync(fileno(f)); + fclose(f); + } + va_end(va); + } +#endif +#ifdef MPLAYER + if (verbose > 2) + { + va_list va; + + va_start(va, fmt); + vprintf(fmt, va); +// mp_dbg(MSGT_WIN32, MSGL_DBG3, fmt, va); + va_end(va); + } + fflush(stdout); +#endif +} + + +char export_names[300][32]={ + "name1", + //"name2", + //"name3" +}; +//#define min(x,y) ((x)<(y)?(x):(y)) + +void destroy_event(void* event); + +struct th_list_t; +typedef struct th_list_t{ + int id; + void* thread; + struct th_list_t* next; + struct th_list_t* prev; +} th_list; + + +// have to be cleared by GARBAGE COLLECTOR +static unsigned char* heap=NULL; +static int heap_counter=0; +static tls_t* g_tls=NULL; +static th_list* list=NULL; + +static void test_heap(void) +{ + int offset=0; + if(heap==0) + return; + while(offset20000000) + { + printf("No enough memory\n"); + return 0; + } + *(int*)(heap+heap_counter)=0x433476; + heap_counter+=4; + *(int*)(heap+heap_counter)=size; + heap_counter+=4; + printf("Allocated %d bytes of memory: sys %d, user %d-%d\n", size, heap_counter-8, heap_counter, heap_counter+size); + if(to_zero) + memset(heap+heap_counter, 0, size); + else + memset(heap+heap_counter, 0xcc, size); // make crash reproducable + heap_counter+=size; + return heap+heap_counter-size; +} +static int my_release(char* memory) +{ + // test_heap(); + if(memory==NULL) + { + printf("ERROR: free(0)\n"); + return 0; + } + if(*(int*)(memory-8)!=0x433476) + { + printf("MEMORY CORRUPTION !!!!!!!!!!!!!!!!!!!\n"); + return 0; + } + printf("Freed %d bytes of memory\n", *(int*)(memory-4)); + // memset(memory-8, *(int*)(memory-4), 0xCC); + return 0; +} + +#else +#define GARBAGE +typedef struct alloc_header_t alloc_header; +struct alloc_header_t +{ + // let's keep allocated data 16 byte aligned + alloc_header* prev; + alloc_header* next; + long deadbeef; + long size; + long type; + long reserved1; + long reserved2; + long reserved3; +}; + +#ifdef GARBAGE +static alloc_header* last_alloc = NULL; +static int alccnt = 0; +#endif + +#define AREATYPE_CLIENT 0 +#define AREATYPE_EVENT 1 +#define AREATYPE_MUTEX 2 +#define AREATYPE_COND 3 +#define AREATYPE_CRITSECT 4 + +/* -- critical sections -- */ +struct CRITSECT +{ + pthread_t id; + pthread_mutex_t mutex; + int locked; + long deadbeef; +}; + +void* mreq_private(int size, int to_zero, int type); +void* mreq_private(int size, int to_zero, int type) +{ + int nsize = size + sizeof(alloc_header); + alloc_header* header = (alloc_header* ) malloc(nsize); + if (!header) + return 0; + if (to_zero) + memset(header, 0, nsize); +#ifdef GARBAGE + if (!last_alloc) + { + pthread_mutex_init(&memmut, NULL); + pthread_mutex_lock(&memmut); + } + else + { + pthread_mutex_lock(&memmut); + last_alloc->next = header; /* set next */ + } + + header->prev = last_alloc; + header->next = 0; + last_alloc = header; + alccnt++; + pthread_mutex_unlock(&memmut); +#endif + header->deadbeef = 0xdeadbeef; + header->size = size; + header->type = type; + + //if (alccnt < 40000) printf("MY_REQ: %p\t%d t:%d (cnt:%d)\n", header, size, type, alccnt); + return header + 1; +} + +static int my_release(void* memory) +{ + alloc_header* header = (alloc_header*) memory - 1; +#ifdef GARBAGE + alloc_header* prevmem; + alloc_header* nextmem; + + if (memory == 0) + return 0; + + if (header->deadbeef != (long) 0xdeadbeef) + { + printf("FATAL releasing corrupted memory! %p 0x%lx (%d)\n", header, header->deadbeef, alccnt); + return 0; + } + + pthread_mutex_lock(&memmut); + + switch(header->type) + { + case AREATYPE_EVENT: + destroy_event(memory); + break; + case AREATYPE_COND: + pthread_cond_destroy((pthread_cond_t*)memory); + break; + case AREATYPE_MUTEX: + pthread_mutex_destroy((pthread_mutex_t*)memory); + break; + case AREATYPE_CRITSECT: + pthread_mutex_destroy(&((struct CRITSECT*)memory)->mutex); + break; + default: + //memset(memory, 0xcc, header->size); + ; + } + + header->deadbeef = 0; + prevmem = header->prev; + nextmem = header->next; + + if (prevmem) + prevmem->next = nextmem; + if (nextmem) + nextmem->prev = prevmem; + + if (header == last_alloc) + last_alloc = prevmem; + + alccnt--; + + if (last_alloc) + pthread_mutex_unlock(&memmut); + else + pthread_mutex_destroy(&memmut); + + //if (alccnt < 40000) printf("MY_RELEASE: %p\t%ld (%d)\n", header, header->size, alccnt); +#else + if (memory == 0) + return 0; +#endif + //memset(header + 1, 0xcc, header->size); + free(header); + return 0; +} +#endif + +static inline void* my_mreq(int size, int to_zero) +{ + return mreq_private(size, to_zero, AREATYPE_CLIENT); +} + +static int my_size(void* memory) +{ + if(!memory) return 0; + return ((alloc_header*)memory)[-1].size; +} + +static void* my_realloc(void* memory, int size) +{ + void *ans = memory; + int osize; + if (memory == NULL) + return my_mreq(size, 0); + osize = my_size(memory); + if (osize < size) + { + ans = my_mreq(size, 0); + memcpy(ans, memory, osize); + my_release(memory); + } + return ans; +} + +/* + * + * WINE API - native implementation for several win32 libraries + * + */ + +static int WINAPI ext_unknown() +{ + printf("Unknown func called\n"); + return 0; +} + +static int WINAPI expIsBadWritePtr(void* ptr, unsigned int count) +{ + int result = (count == 0 || ptr != 0) ? 0 : 1; + dbgprintf("IsBadWritePtr(0x%x, 0x%x) => %d\n", ptr, count, result); + return result; +} +static int WINAPI expIsBadReadPtr(void* ptr, unsigned int count) +{ + int result = (count == 0 || ptr != 0) ? 0 : 1; + dbgprintf("IsBadReadPtr(0x%x, 0x%x) => %d\n", ptr, count, result); + return result; +} +static int WINAPI expDisableThreadLibraryCalls(int module) +{ + dbgprintf("DisableThreadLibraryCalls(0x%x) => 0\n", module); + return 0; +} + +static HMODULE WINAPI expGetDriverModuleHandle(DRVR* pdrv) +{ + HMODULE result; + if (pdrv==NULL) + result=0; + else + result=pdrv->hDriverModule; + dbgprintf("GetDriverModuleHandle(%p) => %p\n", pdrv, result); + return result; +} + +#define MODULE_HANDLE_kernel32 ((HMODULE)0x120) +#define MODULE_HANDLE_user32 ((HMODULE)0x121) +#ifdef QTX +#define MODULE_HANDLE_wininet ((HMODULE)0x122) +#define MODULE_HANDLE_ddraw ((HMODULE)0x123) +#define MODULE_HANDLE_advapi32 ((HMODULE)0x124) +#endif + +static HMODULE WINAPI expGetModuleHandleA(const char* name) +{ + WINE_MODREF* wm; + HMODULE result; + if(!name) +#ifdef QTX + result=1; +#else + result=0; +#endif + else + { + wm=MODULE_FindModule(name); + if(wm==0)result=0; + else + result=(HMODULE)(wm->module); + } + if(!result) + { + if(name && (strcasecmp(name, "kernel32")==0 || !strcasecmp(name, "kernel32.dll"))) + result=MODULE_HANDLE_kernel32; +#ifdef QTX + if(name && strcasecmp(name, "user32")==0) + result=MODULE_HANDLE_user32; +#endif + } + dbgprintf("GetModuleHandleA('%s') => 0x%x\n", name, result); + return result; +} + +static void* WINAPI expCreateThread(void* pSecAttr, long dwStackSize, + void* lpStartAddress, void* lpParameter, + long dwFlags, long* dwThreadId) +{ + pthread_t *pth; + // printf("CreateThread:"); + pth = (pthread_t*) my_mreq(sizeof(pthread_t), 0); + pthread_create(pth, NULL, (void*(*)(void*))lpStartAddress, lpParameter); + if(dwFlags) + printf( "WARNING: CreateThread flags not supported\n"); + if(dwThreadId) + *dwThreadId=(long)pth; + if(list==NULL) + { + list=my_mreq(sizeof(th_list), 1); + list->next=list->prev=NULL; + } + else + { + list->next=my_mreq(sizeof(th_list), 0); + list->next->prev=list; + list->next->next=NULL; + list=list->next; + } + list->thread=pth; + dbgprintf("CreateThread(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) => 0x%x\n", + pSecAttr, dwStackSize, lpStartAddress, lpParameter, dwFlags, dwThreadId, pth); + return pth; +} + +struct mutex_list_t; + +struct mutex_list_t +{ + char type; + pthread_mutex_t *pm; + pthread_cond_t *pc; + char state; + char reset; + char name[128]; + int semaphore; + struct mutex_list_t* next; + struct mutex_list_t* prev; +}; +typedef struct mutex_list_t mutex_list; +static mutex_list* mlist=NULL; + +void destroy_event(void* event) +{ + mutex_list* pp=mlist; + // printf("garbage collector: destroy_event(%x)\n", event); + while(pp) + { + if(pp==(mutex_list*)event) + { + if(pp->next) + pp->next->prev=pp->prev; + if(pp->prev) + pp->prev->next=pp->next; + if(mlist==(mutex_list*)event) + mlist=mlist->prev; + /* + pp=mlist; + while(pp) + { + printf("%x => ", pp); + pp=pp->prev; + } + printf("0\n"); + */ + return; + } + pp=pp->prev; + } +} + +static void* WINAPI expCreateEventA(void* pSecAttr, char bManualReset, + char bInitialState, const char* name) +{ + pthread_mutex_t *pm; + pthread_cond_t *pc; + /* + mutex_list* pp; + pp=mlist; + while(pp) + { + printf("%x => ", pp); + pp=pp->prev; + } + printf("0\n"); + */ + if(mlist!=NULL) + { + mutex_list* pp=mlist; + if(name!=NULL) + do + { + if((strcmp(pp->name, name)==0) && (pp->type==0)) + { + dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, 0x%x='%s') => 0x%x\n", + pSecAttr, bManualReset, bInitialState, name, name, pp->pm); + return pp->pm; + } + }while((pp=pp->prev) != NULL); + } + pm=mreq_private(sizeof(pthread_mutex_t), 0, AREATYPE_MUTEX); + pthread_mutex_init(pm, NULL); + pc=mreq_private(sizeof(pthread_cond_t), 0, AREATYPE_COND); + pthread_cond_init(pc, NULL); + if(mlist==NULL) + { + mlist=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT); + mlist->next=mlist->prev=NULL; + } + else + { + mlist->next=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT); + mlist->next->prev=mlist; + mlist->next->next=NULL; + mlist=mlist->next; + } + mlist->type=0; /* Type Event */ + mlist->pm=pm; + mlist->pc=pc; + mlist->state=bInitialState; + mlist->reset=bManualReset; + if(name) + strncpy(mlist->name, name, 127); + else + mlist->name[0]=0; + if(pm==NULL) + dbgprintf("ERROR::: CreateEventA failure\n"); + /* + if(bInitialState) + pthread_mutex_lock(pm); + */ + if(name) + dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, 0x%x='%s') => 0x%x\n", + pSecAttr, bManualReset, bInitialState, name, name, mlist); + else + dbgprintf("CreateEventA(0x%x, 0x%x, 0x%x, NULL) => 0x%x\n", + pSecAttr, bManualReset, bInitialState, mlist); + return mlist; +} + +static void* WINAPI expSetEvent(void* event) +{ + mutex_list *ml = (mutex_list *)event; + dbgprintf("SetEvent(%x) => 0x1\n", event); + pthread_mutex_lock(ml->pm); + if (ml->state == 0) { + ml->state = 1; + pthread_cond_signal(ml->pc); + } + pthread_mutex_unlock(ml->pm); + + return (void *)1; +} +static void* WINAPI expResetEvent(void* event) +{ + mutex_list *ml = (mutex_list *)event; + dbgprintf("ResetEvent(0x%x) => 0x1\n", event); + pthread_mutex_lock(ml->pm); + ml->state = 0; + pthread_mutex_unlock(ml->pm); + + return (void *)1; +} + +static void* WINAPI expWaitForSingleObject(void* object, int duration) +{ + mutex_list *ml = (mutex_list *)object; + // FIXME FIXME FIXME - this value is sometime unititialize !!! + int ret = WAIT_FAILED; + mutex_list* pp=mlist; + if(object == (void*)0xcfcf9898) + { + /** + From GetCurrentThread() documentation: + A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudo handles are not inherited by child processes. + + This handle has the maximum possible access to the thread object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is THREAD_ALL_ACCESS. + + The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function. + **/ + dbgprintf("WaitForSingleObject(thread_handle) called\n"); + return (void*)WAIT_FAILED; + } + dbgprintf("WaitForSingleObject(0x%x, duration %d) =>\n",object, duration); + + // loop below was slightly fixed - its used just for checking if + // this object really exists in our list + if (!ml) + return (void*) ret; + while (pp && (pp->pm != ml->pm)) + pp = pp->prev; + if (!pp) { + dbgprintf("WaitForSingleObject: NotFound\n"); + return (void*)ret; + } + + pthread_mutex_lock(ml->pm); + + switch(ml->type) { + case 0: /* Event */ + if (duration == 0) { /* Check Only */ + if (ml->state == 1) ret = WAIT_FAILED; + else ret = WAIT_OBJECT_0; + } + if (duration == -1) { /* INFINITE */ + if (ml->state == 0) + pthread_cond_wait(ml->pc,ml->pm); + if (ml->reset) + ml->state = 0; + ret = WAIT_OBJECT_0; + } + if (duration > 0) { /* Timed Wait */ + struct timespec abstime; + struct timeval now; + gettimeofday(&now, 0); + abstime.tv_sec = now.tv_sec + (now.tv_usec+duration)/1000000; + abstime.tv_nsec = ((now.tv_usec+duration)%1000000)*1000; + if (ml->state == 0) + ret=pthread_cond_timedwait(ml->pc,ml->pm,&abstime); + if (ret == ETIMEDOUT) ret = WAIT_TIMEOUT; + else ret = WAIT_OBJECT_0; + if (ml->reset) + ml->state = 0; + } + break; + case 1: /* Semaphore */ + if (duration == 0) { + if(ml->semaphore==0) ret = WAIT_FAILED; + else { + ml->semaphore++; + ret = WAIT_OBJECT_0; + } + } + if (duration == -1) { + if (ml->semaphore==0) + pthread_cond_wait(ml->pc,ml->pm); + ml->semaphore--; + } + break; + } + pthread_mutex_unlock(ml->pm); + + dbgprintf("WaitForSingleObject(0x%x, %d): 0x%x => 0x%x \n",object,duration,ml,ret); + return (void *)ret; +} + +#ifdef QTX +static void* WINAPI expWaitForMultipleObjects(int count, const void** objects, + int WaitAll, int duration) +{ + int i; + void *object; + void *ret; + + dbgprintf("WaitForMultipleObjects(%d, 0x%x, %d, duration %d) =>\n", + count, objects, WaitAll, duration); + + for (i = 0; i < count; i++) + { + object = objects[i]; + ret = expWaitForSingleObject(object, duration); + if (WaitAll) + dbgprintf("WaitAll flag not yet supported...\n"); + else + return ret; + } + return NULL; +} + +static void WINAPI expExitThread(int retcode) +{ + dbgprintf("ExitThread(%d)\n", retcode); + pthread_exit(&retcode); +} + +static HANDLE WINAPI expCreateMutexA(void *pSecAttr, + char bInitialOwner, const char *name) +{ + HANDLE mlist = (HANDLE)expCreateEventA(pSecAttr, 0, 0, name); + + if (name) + dbgprintf("CreateMutexA(0x%x, %d, '%s') => 0x%x\n", + pSecAttr, bInitialOwner, name, mlist); + else + dbgprintf("CreateMutexA(0x%x, %d, NULL) => 0x%x\n", + pSecAttr, bInitialOwner, mlist); +#ifndef QTX + /* 10l to QTX, if CreateMutex returns a real mutex, WaitForSingleObject + waits for ever, else it works ;) */ + return mlist; +#endif +} + +static int WINAPI expReleaseMutex(HANDLE hMutex) +{ + dbgprintf("ReleaseMutex(%x) => 1\n", hMutex); + /* FIXME:XXX !! not yet implemented */ + return 1; +} +#endif + +static int pf_set = 0; +static BYTE PF[64] = {0,}; + +static void DumpSystemInfo(const SYSTEM_INFO* si) +{ + dbgprintf(" Processor architecture %d\n", si->u.s.wProcessorArchitecture); + dbgprintf(" Page size: %d\n", si->dwPageSize); + dbgprintf(" Minimum app address: %d\n", si->lpMinimumApplicationAddress); + dbgprintf(" Maximum app address: %d\n", si->lpMaximumApplicationAddress); + dbgprintf(" Active processor mask: 0x%x\n", si->dwActiveProcessorMask); + dbgprintf(" Number of processors: %d\n", si->dwNumberOfProcessors); + dbgprintf(" Processor type: 0x%x\n", si->dwProcessorType); + dbgprintf(" Allocation granularity: 0x%x\n", si->dwAllocationGranularity); + dbgprintf(" Processor level: 0x%x\n", si->wProcessorLevel); + dbgprintf(" Processor revision: 0x%x\n", si->wProcessorRevision); +} + +static void WINAPI expGetSystemInfo(SYSTEM_INFO* si) +{ + /* FIXME: better values for the two entries below... */ + static int cache = 0; + static SYSTEM_INFO cachedsi; + unsigned int regs[4]; + dbgprintf("GetSystemInfo(%p) =>\n", si); + + if (cache) { + memcpy(si,&cachedsi,sizeof(*si)); + DumpSystemInfo(si); + return; + } + memset(PF,0,sizeof(PF)); + pf_set = 1; + + cachedsi.u.s.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; + cachedsi.dwPageSize = getpagesize(); + + /* FIXME: better values for the two entries below... */ + cachedsi.lpMinimumApplicationAddress = (void *)0x00000000; + cachedsi.lpMaximumApplicationAddress = (void *)0x7FFFFFFF; + cachedsi.dwActiveProcessorMask = 1; + cachedsi.dwNumberOfProcessors = 1; + cachedsi.dwProcessorType = PROCESSOR_INTEL_386; + cachedsi.dwAllocationGranularity = 0x10000; + cachedsi.wProcessorLevel = 5; /* pentium */ + cachedsi.wProcessorRevision = 0x0101; + +#ifdef MPLAYER + /* mplayer's way to detect PF's */ + { +#include "cpudetect.h" + extern CpuCaps gCpuCaps; + + if (gCpuCaps.hasMMX) + PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE; + if (gCpuCaps.hasSSE) + PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE; + if (gCpuCaps.has3DNow) + PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = TRUE; + + switch(gCpuCaps.cpuType) + { + case CPUTYPE_I686: + case CPUTYPE_I586: + cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel = 5; + break; + case CPUTYPE_I486: + cachedsi.dwProcessorType = PROCESSOR_INTEL_486; + cachedsi.wProcessorLevel = 4; + break; + case CPUTYPE_I386: + default: + cachedsi.dwProcessorType = PROCESSOR_INTEL_386; + cachedsi.wProcessorLevel = 3; + break; + } + cachedsi.wProcessorRevision = gCpuCaps.cpuStepping; + cachedsi.dwNumberOfProcessors = 1; /* hardcoded */ + + } +#endif + +/* disable cpuid based detection (mplayer's cpudetect.c does this - see above) */ +#ifndef MPLAYER +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__svr4__) + do_cpuid(1, regs); + switch ((regs[0] >> 8) & 0xf) { // cpu family + case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386; + cachedsi.wProcessorLevel= 3; + break; + case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486; + cachedsi.wProcessorLevel= 4; + break; + case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + } + cachedsi.wProcessorRevision = regs[0] & 0xf; // stepping + if (regs[3] & (1 << 8)) + PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE; + if (regs[3] & (1 << 23)) + PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE; + if (regs[3] & (1 << 25)) + PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE; + if (regs[3] & (1 << 31)) + PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = TRUE; + cachedsi.dwNumberOfProcessors=1; +#endif +#endif /* MPLAYER */ + +/* MPlayer: linux detection enabled (based on proc/cpuinfo) for checking + fdiv_bug and fpu emulation flags -- alex/MPlayer */ +#ifdef __linux__ + { + char buf[20]; + char line[200]; + FILE *f = fopen ("/proc/cpuinfo", "r"); + + if (!f) + return; + while (fgets(line,200,f)!=NULL) { + char *s,*value; + + /* NOTE: the ':' is the only character we can rely on */ + if (!(value = strchr(line,':'))) + continue; + /* terminate the valuename */ + *value++ = '\0'; + /* skip any leading spaces */ + while (*value==' ') value++; + if ((s=strchr(value,'\n'))) + *s='\0'; + + /* 2.1 method */ + if (!lstrncmpiA(line, "cpu family",strlen("cpu family"))) { + if (isdigit (value[0])) { + switch (value[0] - '0') { + case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386; + cachedsi.wProcessorLevel= 3; + break; + case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486; + cachedsi.wProcessorLevel= 4; + break; + case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + } + } + /* set the CPU type of the current processor */ + sprintf(buf,"CPU %ld",cachedsi.dwProcessorType); + continue; + } + /* old 2.0 method */ + if (!lstrncmpiA(line, "cpu",strlen("cpu"))) { + if ( isdigit (value[0]) && value[1] == '8' && + value[2] == '6' && value[3] == 0 + ) { + switch (value[0] - '0') { + case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386; + cachedsi.wProcessorLevel= 3; + break; + case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486; + cachedsi.wProcessorLevel= 4; + break; + case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + default:cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; + cachedsi.wProcessorLevel= 5; + break; + } + } + /* set the CPU type of the current processor */ + sprintf(buf,"CPU %ld",cachedsi.dwProcessorType); + continue; + } + if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) { + if (!lstrncmpiA(value,"yes",3)) + PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE; + + continue; + } + if (!lstrncmpiA(line,"fpu",strlen("fpu"))) { + if (!lstrncmpiA(value,"no",2)) + PF[PF_FLOATING_POINT_EMULATED] = TRUE; + + continue; + } + if (!lstrncmpiA(line,"processor",strlen("processor"))) { + /* processor number counts up...*/ + unsigned int x; + + if (sscanf(value,"%d",&x)) + if (x+1>cachedsi.dwNumberOfProcessors) + cachedsi.dwNumberOfProcessors=x+1; + + /* Create a new processor subkey on a multiprocessor + * system + */ + sprintf(buf,"%d",x); + } + if (!lstrncmpiA(line,"stepping",strlen("stepping"))) { + int x; + + if (sscanf(value,"%d",&x)) + cachedsi.wProcessorRevision = x; + } + if + ( (!lstrncmpiA(line,"flags",strlen("flags"))) + || (!lstrncmpiA(line,"features",strlen("features"))) ) + { + if (strstr(value,"cx8")) + PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE; + if (strstr(value,"mmx")) + PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE; + if (strstr(value,"tsc")) + PF[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE; + if (strstr(value,"xmm")) + PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE; + if (strstr(value,"3dnow")) + PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = TRUE; + } + } + fclose (f); + /* + * ad hoc fix for smp machines. + * some problems on WaitForSingleObject,CreateEvent,SetEvent + * CreateThread ...etc.. + * + */ + cachedsi.dwNumberOfProcessors=1; + } +#endif /* __linux__ */ + cache = 1; + memcpy(si,&cachedsi,sizeof(*si)); + DumpSystemInfo(si); +} + +// avoid undefined expGetSystemInfo +static WIN_BOOL WINAPI expIsProcessorFeaturePresent(DWORD v) +{ + WIN_BOOL result = 0; + if (!pf_set) + { + SYSTEM_INFO si; + expGetSystemInfo(&si); + } + if(v<64) result=PF[v]; + dbgprintf("IsProcessorFeaturePresent(0x%x) => 0x%x\n", v, result); + return result; +} + + +static long WINAPI expGetVersion() +{ + dbgprintf("GetVersion() => 0xC0000004\n"); + return 0xC0000004;//Windows 95 +} + +static HANDLE WINAPI expHeapCreate(long flags, long init_size, long max_size) +{ + // printf("HeapCreate:"); + HANDLE result; + if(init_size==0) + result=(HANDLE)my_mreq(0x110000, 0); + else + result=(HANDLE)my_mreq((init_size + 0xfff) & 0x7ffff000 , 0); + dbgprintf("HeapCreate(flags 0x%x, initial size %d, maximum size %d) => 0x%x\n", flags, init_size, max_size, result); + return result; +} + +// this is another dirty hack +// VP31 is releasing one allocated Heap chunk twice +// we will silently ignore this second call... +static void* heapfreehack = 0; +static int heapfreehackshown = 0; +//extern void trapbug(void); +static void* WINAPI expHeapAlloc(HANDLE heap, int flags, int size) +{ + void* z; + /** + Morgan's m3jpeg32.dll v. 2.0 encoder expects that request for + HeapAlloc returns area larger than size argument :-/ + + actually according to M$ Doc HeapCreate size should be rounded + to page boundaries thus we should simulate this + **/ + //if (size == 22276) trapbug(); + z=my_mreq((size + 0xfff) & 0x7ffff000, (flags & HEAP_ZERO_MEMORY)); + if(z==0) + printf("HeapAlloc failure\n"); + dbgprintf("HeapAlloc(heap 0x%x, flags 0x%x, size %d) => 0x%x\n", heap, flags, size, z); + heapfreehack = 0; // reset + return z; +} +static long WINAPI expHeapDestroy(void* heap) +{ + dbgprintf("HeapDestroy(heap 0x%x) => 1\n", heap); + my_release(heap); + return 1; +} + +static long WINAPI expHeapFree(HANDLE heap, DWORD dwFlags, LPVOID lpMem) +{ + dbgprintf("HeapFree(0x%x, 0x%x, pointer 0x%x) => 1\n", heap, dwFlags, lpMem); + if (heapfreehack != lpMem && lpMem != (void*)0xffffffff + && lpMem != (void*)0xbdbdbdbd) + // 0xbdbdbdbd is for i263_drv.drv && libefence + // it seems to be reading from relased memory + // EF_PROTECT_FREE doens't show any probleme + my_release(lpMem); + else + { + if (!heapfreehackshown++) + printf("Info: HeapFree deallocating same memory twice! (%p)\n", lpMem); + } + heapfreehack = lpMem; + return 1; +} +static long WINAPI expHeapSize(int heap, int flags, void* pointer) +{ + long result=my_size(pointer); + dbgprintf("HeapSize(heap 0x%x, flags 0x%x, pointer 0x%x) => %d\n", heap, flags, pointer, result); + return result; +} +static void* WINAPI expHeapReAlloc(HANDLE heap,int flags,void *lpMem,int size) +{ + long orgsize = my_size(lpMem); + dbgprintf("HeapReAlloc() Size %ld org %d\n",orgsize,size); + return my_realloc(lpMem, size); +} +static long WINAPI expGetProcessHeap(void) +{ + dbgprintf("GetProcessHeap() => 1\n"); + return 1; +} +static void* WINAPI expVirtualAlloc(void* v1, long v2, long v3, long v4) +{ + void* z = VirtualAlloc(v1, v2, v3, v4); + if(z==0) + printf("VirtualAlloc failure\n"); + dbgprintf("VirtualAlloc(0x%x, %d, %d, %d) => 0x%x \n",v1,v2,v3,v4, z); + return z; +} +static int WINAPI expVirtualFree(void* v1, int v2, int v3) +{ + int result = VirtualFree(v1,v2,v3); + dbgprintf("VirtualFree(0x%x, %d, %d) => %d\n",v1,v2,v3, result); + return result; +} + +/* we're building a table of critical sections. cs_win pointer uses the DLL + cs_unix is the real structure, we're using cs_win only to identifying cs_unix */ +struct critsecs_list_t +{ + CRITICAL_SECTION *cs_win; + struct CRITSECT *cs_unix; +}; + +/* 'NEWTYPE' is working with VIVO, 3ivX and QTX dll (no more segfaults) -- alex */ +#undef CRITSECS_NEWTYPE +//#define CRITSECS_NEWTYPE 1 + +#ifdef CRITSECS_NEWTYPE +/* increased due to ucod needs more than 32 entries */ +/* and 64 should be enough for everything */ +#define CRITSECS_LIST_MAX 64 +static struct critsecs_list_t critsecs_list[CRITSECS_LIST_MAX]; + +static int critsecs_get_pos(CRITICAL_SECTION *cs_win) +{ + int i; + + for (i=0; i < CRITSECS_LIST_MAX; i++) + if (critsecs_list[i].cs_win == cs_win) + return(i); + return(-1); +} + +static int critsecs_get_unused(void) +{ + int i; + + for (i=0; i < CRITSECS_LIST_MAX; i++) + if (critsecs_list[i].cs_win == NULL) + return(i); + return(-1); +} + +struct CRITSECT *critsecs_get_unix(CRITICAL_SECTION *cs_win) +{ + int i; + + for (i=0; i < CRITSECS_LIST_MAX; i++) + if (critsecs_list[i].cs_win == cs_win && critsecs_list[i].cs_unix) + return(critsecs_list[i].cs_unix); + return(NULL); +} +#endif + +static void WINAPI expInitializeCriticalSection(CRITICAL_SECTION* c) +{ + dbgprintf("InitializeCriticalSection(0x%x)\n", c); + /* if(sizeof(pthread_mutex_t)>sizeof(CRITICAL_SECTION)) + { + printf(" ERROR:::: sizeof(pthread_mutex_t) is %d, expected <=%d!\n", + sizeof(pthread_mutex_t), sizeof(CRITICAL_SECTION)); + return; + }*/ + /* pthread_mutex_init((pthread_mutex_t*)c, NULL); */ +#ifdef CRITSECS_NEWTYPE + { + struct CRITSECT *cs; + int i = critsecs_get_unused(); + + if (i < 0) + { + printf("InitializeCriticalSection(%p) - no more space in list\n", c); + return; + } + dbgprintf("got unused space at %d\n", i); + cs = malloc(sizeof(struct CRITSECT)); + if (!cs) + { + printf("InitializeCriticalSection(%p) - out of memory\n", c); + return; + } + pthread_mutex_init(&cs->mutex, NULL); + cs->locked = 0; + critsecs_list[i].cs_win = c; + critsecs_list[i].cs_unix = cs; + dbgprintf("InitializeCriticalSection -> itemno=%d, cs_win=%p, cs_unix=%p\n", + i, c, cs); + } +#else + { + struct CRITSECT* cs = mreq_private(sizeof(struct CRITSECT) + sizeof(CRITICAL_SECTION), + 0, AREATYPE_CRITSECT); + pthread_mutex_init(&cs->mutex, NULL); + cs->locked=0; + cs->deadbeef = 0xdeadbeef; + *(void**)c = cs; + } +#endif + return; +} + +static void WINAPI expEnterCriticalSection(CRITICAL_SECTION* c) +{ +#ifdef CRITSECS_NEWTYPE + struct CRITSECT* cs = critsecs_get_unix(c); +#else + struct CRITSECT* cs = (*(struct CRITSECT**)c); +#endif + dbgprintf("EnterCriticalSection(0x%x) %p\n",c, cs); + if (!cs) + { + dbgprintf("entered uninitialized critisec!\n"); + expInitializeCriticalSection(c); +#ifdef CRITSECS_NEWTYPE + cs=critsecs_get_unix(c); +#else + cs = (*(struct CRITSECT**)c); +#endif + printf("Win32 Warning: Accessed uninitialized Critical Section (%p)!\n", c); + } + if(cs->locked) + if(cs->id==pthread_self()) + return; + pthread_mutex_lock(&(cs->mutex)); + cs->locked=1; + cs->id=pthread_self(); + return; +} +static void WINAPI expLeaveCriticalSection(CRITICAL_SECTION* c) +{ +#ifdef CRITSECS_NEWTYPE + struct CRITSECT* cs = critsecs_get_unix(c); +#else + struct CRITSECT* cs = (*(struct CRITSECT**)c); +#endif + // struct CRITSECT* cs=(struct CRITSECT*)c; + dbgprintf("LeaveCriticalSection(0x%x) 0x%x\n",c, cs); + if (!cs) + { + printf("Win32 Warning: Leaving uninitialized Critical Section %p!!\n", c); + return; + } + cs->locked=0; + pthread_mutex_unlock(&(cs->mutex)); + return; +} + +static void expfree(void* mem); /* forward declaration */ + +static void WINAPI expDeleteCriticalSection(CRITICAL_SECTION *c) +{ +#ifdef CRITSECS_NEWTYPE + struct CRITSECT* cs = critsecs_get_unix(c); +#else + struct CRITSECT* cs= (*(struct CRITSECT**)c); +#endif + // struct CRITSECT* cs=(struct CRITSECT*)c; + dbgprintf("DeleteCriticalSection(0x%x)\n",c); + +#ifndef GARBAGE + pthread_mutex_destroy(&(cs->mutex)); + // released by GarbageCollector in my_relase otherwise +#endif + my_release(cs); +#ifdef CRITSECS_NEWTYPE + { + int i = critsecs_get_pos(c); + + if (i < 0) + { + printf("DeleteCriticalSection(%p) error (critsec not found)\n", c); + return; + } + + critsecs_list[i].cs_win = NULL; + expfree(critsecs_list[i].cs_unix); + critsecs_list[i].cs_unix = NULL; + dbgprintf("DeleteCriticalSection -> itemno=%d\n", i); + } +#endif + return; +} +static int WINAPI expGetCurrentThreadId() +{ + dbgprintf("GetCurrentThreadId() => %d\n", pthread_self()); + return pthread_self(); +} +static int WINAPI expGetCurrentProcess() +{ + dbgprintf("GetCurrentProcess() => %d\n", getpid()); + return getpid(); +} + +#ifdef QTX +// this version is required for Quicktime codecs (.qtx/.qts) to work. +// (they assume some pointers at FS: segment) + +extern void* fs_seg; + +//static int tls_count; +static int tls_use_map[64]; +static int WINAPI expTlsAlloc() +{ + int i; + for(i=0; i<64; i++) + if(tls_use_map[i]==0) + { + tls_use_map[i]=1; + dbgprintf("TlsAlloc() => %d\n",i); + return i; + } + dbgprintf("TlsAlloc() => -1 (ERROR)\n"); + return -1; +} + +//static int WINAPI expTlsSetValue(DWORD index, void* value) +static int WINAPI expTlsSetValue(int index, void* value) +{ + dbgprintf("TlsSetValue(%d,0x%x) => 1\n",index,value); +// if((index<0) || (index>64)) + if((index>=64)) + return 0; + *(void**)((char*)fs_seg+0x88+4*index) = value; + return 1; +} + +static void* WINAPI expTlsGetValue(DWORD index) +{ + dbgprintf("TlsGetValue(%d)\n",index); +// if((index<0) || (index>64)) + if((index>=64)) return NULL; + return *(void**)((char*)fs_seg+0x88+4*index); +} + +static int WINAPI expTlsFree(int idx) +{ + int index = (int) idx; + dbgprintf("TlsFree(%d)\n",index); + if((index<0) || (index>64)) + return 0; + tls_use_map[index]=0; + return 1; +} + +#else +struct tls_s { + void* value; + int used; + struct tls_s* prev; + struct tls_s* next; +}; + +static void* WINAPI expTlsAlloc() +{ + if (g_tls == NULL) + { + g_tls=my_mreq(sizeof(tls_t), 0); + g_tls->next=g_tls->prev=NULL; + } + else + { + g_tls->next=my_mreq(sizeof(tls_t), 0); + g_tls->next->prev=g_tls; + g_tls->next->next=NULL; + g_tls=g_tls->next; + } + dbgprintf("TlsAlloc() => 0x%x\n", g_tls); + if (g_tls) + g_tls->value=0; /* XXX For Divx.dll */ + return g_tls; +} + +static int WINAPI expTlsSetValue(void* idx, void* value) +{ + tls_t* index = (tls_t*) idx; + int result; + if(index==0) + result=0; + else + { + index->value=value; + result=1; + } + dbgprintf("TlsSetValue(index 0x%x, value 0x%x) => %d \n", index, value, result ); + return result; +} +static void* WINAPI expTlsGetValue(void* idx) +{ + tls_t* index = (tls_t*) idx; + void* result; + if(index==0) + result=0; + else + result=index->value; + dbgprintf("TlsGetValue(index 0x%x) => 0x%x\n", index, result); + return result; +} +static int WINAPI expTlsFree(void* idx) +{ + tls_t* index = (tls_t*) idx; + int result; + if(index==0) + result=0; + else + { + if(index->next) + index->next->prev=index->prev; + if(index->prev) + index->prev->next=index->next; + if (g_tls == index) + g_tls = index->prev; + my_release((void*)index); + result=1; + } + dbgprintf("TlsFree(index 0x%x) => %d\n", index, result); + return result; +} +#endif + +static void* WINAPI expLocalAlloc(int flags, int size) +{ + void* z = my_mreq(size, (flags & GMEM_ZEROINIT)); + if (z == 0) + printf("LocalAlloc() failed\n"); + dbgprintf("LocalAlloc(%d, flags 0x%x) => 0x%x\n", size, flags, z); + return z; +} + +static void* WINAPI expLocalReAlloc(int handle,int size, int flags) +{ + void *newpointer; + int oldsize; + + newpointer=NULL; + if (flags & LMEM_MODIFY) { + dbgprintf("LocalReAlloc MODIFY\n"); + return (void *)handle; + } + oldsize = my_size((void *)handle); + newpointer = my_realloc((void *)handle,size); + dbgprintf("LocalReAlloc(%x %d(old %d), flags 0x%x) => 0x%x\n", handle,size,oldsize, flags,newpointer); + + return newpointer; +} + +static void* WINAPI expLocalLock(void* z) +{ + dbgprintf("LocalLock(0x%x) => 0x%x\n", z, z); + return z; +} + +static void* WINAPI expGlobalAlloc(int flags, int size) +{ + void* z; + dbgprintf("GlobalAlloc(%d, flags 0x%X)\n", size, flags); + + z=my_mreq(size, (flags & GMEM_ZEROINIT)); + //z=calloc(size, 1); + //z=malloc(size); + if(z==0) + printf("GlobalAlloc() failed\n"); + dbgprintf("GlobalAlloc(%d, flags 0x%x) => 0x%x\n", size, flags, z); + return z; +} +static void* WINAPI expGlobalLock(void* z) +{ + dbgprintf("GlobalLock(0x%x) => 0x%x\n", z, z); + return z; +} +// pvmjpg20 - but doesn't work anyway +static int WINAPI expGlobalSize(void* amem) +{ + int size = 100000; +#ifdef GARBAGE + alloc_header* header = last_alloc; + alloc_header* mem = (alloc_header*) amem - 1; + if (amem == 0) + return 0; + pthread_mutex_lock(&memmut); + while (header) + { + if (header->deadbeef != 0xdeadbeef) + { + printf("FATAL found corrupted memory! %p 0x%lx (%d)\n", header, header->deadbeef, alccnt); + break; + } + + if (header == mem) + { + size = header->size; + break; + } + + header = header->prev; + } + pthread_mutex_unlock(&memmut); +#endif + + dbgprintf("GlobalSize(0x%x)\n", amem); + return size; +} +static int WINAPI expLoadStringA(long instance, long id, void* buf, long size) +{ + int result=LoadStringA(instance, id, buf, size); + // if(buf) + dbgprintf("LoadStringA(instance 0x%x, id 0x%x, buffer 0x%x, size %d) => %d ( %s )\n", + instance, id, buf, size, result, buf); + // else + // dbgprintf("LoadStringA(instance 0x%x, id 0x%x, buffer 0x%x, size %d) => %d\n", + // instance, id, buf, size, result); + return result; +} + +static long WINAPI expMultiByteToWideChar(long v1, long v2, char* s1, long siz1, short* s2, int siz2) +{ +#warning FIXME + int i; + int result; + if(s2==0) + result=1; + else + { + if(siz1>siz2/2)siz1=siz2/2; + for(i=1; i<=siz1; i++) + { + *s2=*s1; + if(!*s1)break; + s2++; + s1++; + } + result=i; + } + if(s1) + dbgprintf("MultiByteToWideChar(codepage %d, flags 0x%x, string 0x%x='%s'," + "size %d, dest buffer 0x%x, dest size %d) => %d\n", + v1, v2, s1, s1, siz1, s2, siz2, result); + else + dbgprintf("MultiByteToWideChar(codepage %d, flags 0x%x, string NULL," + "size %d, dest buffer 0x%x, dest size %d) =>\n", + v1, v2, siz1, s2, siz2, result); + return result; +} +static void wch_print(const short* str) +{ + dbgprintf(" src: "); + while(*str)dbgprintf("%c", *str++); + dbgprintf("\n"); +} +static long WINAPI expWideCharToMultiByte(long v1, long v2, short* s1, long siz1, + char* s2, int siz2, char* c3, int* siz3) +{ + int result; + dbgprintf("WideCharToMultiByte(codepage %d, flags 0x%x, src 0x%x, src size %d, " + "dest 0x%x, dest size %d, defch 0x%x, used_defch 0x%x)", v1, v2, s1, siz1, s2, siz2, c3, siz3); + result=WideCharToMultiByte(v1, v2, s1, siz1, s2, siz2, c3, siz3); + dbgprintf("=> %d\n", result); + //if(s1)wch_print(s1); + if(s2)dbgprintf(" dest: %s\n", s2); + return result; +} +static long WINAPI expGetVersionExA(OSVERSIONINFOA* c) +{ + dbgprintf("GetVersionExA(0x%x) => 1\n"); + c->dwOSVersionInfoSize=sizeof(*c); + c->dwMajorVersion=4; + c->dwMinorVersion=0; + c->dwBuildNumber=0x4000457; +#if 1 + // leave it here for testing win9x-only codecs + c->dwPlatformId=VER_PLATFORM_WIN32_WINDOWS; + strcpy(c->szCSDVersion, " B"); +#else + c->dwPlatformId=VER_PLATFORM_WIN32_NT; // let's not make DLL assume that it can read CR* registers + strcpy(c->szCSDVersion, "Service Pack 3"); +#endif + dbgprintf(" Major version: 4\n Minor version: 0\n Build number: 0x4000457\n" + " Platform Id: VER_PLATFORM_WIN32_NT\n Version string: 'Service Pack 3'\n"); + return 1; +} +static HANDLE WINAPI expCreateSemaphoreA(char* v1, long init_count, + long max_count, char* name) +{ + pthread_mutex_t *pm; + pthread_cond_t *pc; + mutex_list* pp; + /* + printf("CreateSemaphoreA(%p = %s)\n", name, (name ? name : "")); + pp=mlist; + while(pp) + { + printf("%p => ", pp); + pp=pp->prev; + } + printf("0\n"); + */ + if(mlist!=NULL) + { + mutex_list* pp=mlist; + if(name!=NULL) + do + { + if((strcmp(pp->name, name)==0) && (pp->type==1)) + { + dbgprintf("CreateSemaphoreA(0x%x, init_count %d, max_count %d, name 0x%x='%s') => 0x%x\n", + v1, init_count, max_count, name, name, mlist); + return (HANDLE)mlist; + } + }while((pp=pp->prev) != NULL); + } + pm=mreq_private(sizeof(pthread_mutex_t), 0, AREATYPE_MUTEX); + pthread_mutex_init(pm, NULL); + pc=mreq_private(sizeof(pthread_cond_t), 0, AREATYPE_COND); + pthread_cond_init(pc, NULL); + if(mlist==NULL) + { + mlist=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT); + mlist->next=mlist->prev=NULL; + } + else + { + mlist->next=mreq_private(sizeof(mutex_list), 00, AREATYPE_EVENT); + mlist->next->prev=mlist; + mlist->next->next=NULL; + mlist=mlist->next; + // printf("new semaphore %p\n", mlist); + } + mlist->type=1; /* Type Semaphore */ + mlist->pm=pm; + mlist->pc=pc; + mlist->state=0; + mlist->reset=0; + mlist->semaphore=init_count; + if(name!=NULL) + strncpy(mlist->name, name, 64); + else + mlist->name[0]=0; + if(pm==NULL) + dbgprintf("ERROR::: CreateSemaphoreA failure\n"); + if(name) + dbgprintf("CreateSemaphoreA(0x%x, init_count %d, max_count %d, name 0x%x='%s') => 0x%x\n", + v1, init_count, max_count, name, name, mlist); + else + dbgprintf("CreateSemaphoreA(0x%x, init_count %d, max_count %d, name 0) => 0x%x\n", + v1, init_count, max_count, mlist); + return (HANDLE)mlist; +} + +static long WINAPI expReleaseSemaphore(long hsem, long increment, long* prev_count) +{ + // The state of a semaphore object is signaled when its count + // is greater than zero and nonsignaled when its count is equal to zero + // Each time a waiting thread is released because of the semaphore's signaled + // state, the count of the semaphore is decreased by one. + mutex_list *ml = (mutex_list *)hsem; + + pthread_mutex_lock(ml->pm); + if (prev_count != 0) *prev_count = ml->semaphore; + if (ml->semaphore == 0) pthread_cond_signal(ml->pc); + ml->semaphore += increment; + pthread_mutex_unlock(ml->pm); + dbgprintf("ReleaseSemaphore(semaphore 0x%x, increment %d, prev_count 0x%x) => 1\n", + hsem, increment, prev_count); + return 1; +} + + +static long WINAPI expRegOpenKeyExA(long key, const char* subkey, long reserved, long access, int* newkey) +{ + long result=RegOpenKeyExA(key, subkey, reserved, access, newkey); + dbgprintf("RegOpenKeyExA(key 0x%x, subkey %s, reserved %d, access 0x%x, pnewkey 0x%x) => %d\n", + key, subkey, reserved, access, newkey, result); + if(newkey)dbgprintf(" New key: 0x%x\n", *newkey); + return result; +} +static long WINAPI expRegCloseKey(long key) +{ + long result=RegCloseKey(key); + dbgprintf("RegCloseKey(0x%x) => %d\n", key, result); + return result; +} +static long WINAPI expRegQueryValueExA(long key, const char* value, int* reserved, int* type, int* data, int* count) +{ + long result=RegQueryValueExA(key, value, reserved, type, data, count); + dbgprintf("RegQueryValueExA(key 0x%x, value %s, reserved 0x%x, data 0x%x, count 0x%x)" + " => 0x%x\n", key, value, reserved, data, count, result); + if(data && count)dbgprintf(" read %d bytes: '%s'\n", *count, data); + return result; +} +static long WINAPI expRegCreateKeyExA(long key, const char* name, long reserved, + void* classs, long options, long security, + void* sec_attr, int* newkey, int* status) +{ + long result=RegCreateKeyExA(key, name, reserved, classs, options, security, sec_attr, newkey, status); + dbgprintf("RegCreateKeyExA(key 0x%x, name 0x%x='%s', reserved=0x%x," + " 0x%x, 0x%x, 0x%x, newkey=0x%x, status=0x%x) => %d\n", + key, name, name, reserved, classs, options, security, sec_attr, newkey, status, result); + if(!result && newkey) dbgprintf(" New key: 0x%x\n", *newkey); + if(!result && status) dbgprintf(" New key status: 0x%x\n", *status); + return result; +} +static long WINAPI expRegSetValueExA(long key, const char* name, long v1, long v2, void* data, long size) +{ + long result=RegSetValueExA(key, name, v1, v2, data, size); + dbgprintf("RegSetValueExA(key 0x%x, name '%s', 0x%x, 0x%x, data 0x%x -> 0x%x '%s', size=%d) => %d", + key, name, v1, v2, data, *(int*)data, data, size, result); + return result; +} + +static long WINAPI expRegOpenKeyA (long hKey, LPCSTR lpSubKey, int* phkResult) +{ + long result=RegOpenKeyExA(hKey, lpSubKey, 0, 0, phkResult); + dbgprintf("RegOpenKeyExA(key 0x%x, subkey '%s', 0x%x) => %d\n", + hKey, lpSubKey, phkResult, result); + if(!result && phkResult) dbgprintf(" New key: 0x%x\n", *phkResult); + return result; +} + +static DWORD WINAPI expRegEnumValueA(HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count, + LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count) +{ + return RegEnumValueA(hkey, index, value, val_count, + reserved, type, data, count); +} + +static DWORD WINAPI expRegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, + LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, + LPFILETIME lpftLastWriteTime) +{ + return RegEnumKeyExA(hKey, dwIndex, lpName, lpcbName, lpReserved, lpClass, + lpcbClass, lpftLastWriteTime); +} + +static long WINAPI expQueryPerformanceCounter(long long* z) +{ + longcount(z); + dbgprintf("QueryPerformanceCounter(0x%x) => 1 ( %Ld )\n", z, *z); + return 1; +} + +/* + * return CPU clock (in kHz), using linux's /proc filesystem (/proc/cpuinfo) + */ +static double linux_cpuinfo_freq() +{ + double freq=-1; + FILE *f; + char line[200]; + char *s,*value; + + f = fopen ("/proc/cpuinfo", "r"); + if (f != NULL) { + while (fgets(line,sizeof(line),f)!=NULL) { + /* NOTE: the ':' is the only character we can rely on */ + if (!(value = strchr(line,':'))) + continue; + /* terminate the valuename */ + *value++ = '\0'; + /* skip any leading spaces */ + while (*value==' ') value++; + if ((s=strchr(value,'\n'))) + *s='\0'; + + if (!strncasecmp(line, "cpu MHz",strlen("cpu MHz")) + && sscanf(value, "%lf", &freq) == 1) { + freq*=1000; + break; + } + } + fclose(f); + } + return freq; +} + + +static double solaris_kstat_freq() +{ +#if defined(HAVE_LIBKSTAT) && defined(KSTAT_DATA_INT32) + /* + * try to extract the CPU speed from the solaris kernel's kstat data + */ + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *kdata; + int mhz = 0; + + kc = kstat_open(); + if (kc != NULL) + { + ksp = kstat_lookup(kc, "cpu_info", 0, "cpu_info0"); + + /* kstat found and name/value pairs? */ + if (ksp != NULL && ksp->ks_type == KSTAT_TYPE_NAMED) + { + /* read the kstat data from the kernel */ + if (kstat_read(kc, ksp, NULL) != -1) + { + /* + * lookup desired "clock_MHz" entry, check the expected + * data type + */ + kdata = (kstat_named_t *)kstat_data_lookup(ksp, "clock_MHz"); + if (kdata != NULL && kdata->data_type == KSTAT_DATA_INT32) + mhz = kdata->value.i32; + } + } + kstat_close(kc); + } + + if (mhz > 0) + return mhz * 1000.; +#endif /* HAVE_LIBKSTAT */ + return -1; // kstat stuff is not available, CPU freq is unknown +} + +/* + * Measure CPU freq using the pentium's time stamp counter register (TSC) + */ +static double tsc_freq() +{ + static double ofreq=0.0; + int i; + int x,y; + i=time(NULL); + if (ofreq != 0.0) return ofreq; + while(i==time(NULL)); + x=localcount(); + i++; + while(i==time(NULL)); + y=localcount(); + ofreq = (double)(y-x)/1000.; + return ofreq; +} + +static double CPU_Freq() +{ + double freq; + + if ((freq = linux_cpuinfo_freq()) > 0) + return freq; + + if ((freq = solaris_kstat_freq()) > 0) + return freq; + + return tsc_freq(); +} + +static long WINAPI expQueryPerformanceFrequency(long long* z) +{ + *z=(long long)CPU_Freq(); + dbgprintf("QueryPerformanceFrequency(0x%x) => 1 ( %Ld )\n", z, *z); + return 1; +} +static long WINAPI exptimeGetTime() +{ + struct timeval t; + long result; + gettimeofday(&t, 0); + result=1000*t.tv_sec+t.tv_usec/1000; + dbgprintf("timeGetTime() => %d\n", result); + return result; +} +static void* WINAPI expLocalHandle(void* v) +{ + dbgprintf("LocalHandle(0x%x) => 0x%x\n", v, v); + return v; +} + +static void* WINAPI expGlobalHandle(void* v) +{ + dbgprintf("GlobalHandle(0x%x) => 0x%x\n", v, v); + return v; +} +static int WINAPI expGlobalUnlock(void* v) +{ + dbgprintf("GlobalUnlock(0x%x) => 1\n", v); + return 1; +} +static void* WINAPI expGlobalFree(void* v) +{ + dbgprintf("GlobalFree(0x%x) => 0\n", v); + my_release(v); + //free(v); + return 0; +} + +static void* WINAPI expGlobalReAlloc(void* v, int size, int flags) +{ + void* result=my_realloc(v, size); + //void* result=realloc(v, size); + dbgprintf("GlobalReAlloc(0x%x, size %d, flags 0x%x) => 0x%x\n", v,size,flags,result); + return result; +} + +static int WINAPI expLocalUnlock(void* v) +{ + dbgprintf("LocalUnlock(0x%x) => 1\n", v); + return 1; +} +// +static void* WINAPI expLocalFree(void* v) +{ + dbgprintf("LocalFree(0x%x) => 0\n", v); + my_release(v); + return 0; +} +static HRSRC WINAPI expFindResourceA(HMODULE module, char* name, char* type) +{ + HRSRC result; + + result=FindResourceA(module, name, type); + dbgprintf("FindResourceA(module 0x%x, name 0x%x(%s), type 0x%x(%s)) => 0x%x\n", + module, name, HIWORD(name) ? name : "UNICODE", type, HIWORD(type) ? type : "UNICODE", result); + return result; +} + +extern HRSRC WINAPI LoadResource(HMODULE, HRSRC); +static HGLOBAL WINAPI expLoadResource(HMODULE module, HRSRC res) +{ + HGLOBAL result=LoadResource(module, res); + dbgprintf("LoadResource(module 0x%x, resource 0x%x) => 0x%x\n", module, res, result); + return result; +} +static void* WINAPI expLockResource(long res) +{ + void* result=LockResource(res); + dbgprintf("LockResource(0x%x) => 0x%x\n", res, result); + return result; +} +static int WINAPI expFreeResource(long res) +{ + int result=FreeResource(res); + dbgprintf("FreeResource(0x%x) => %d\n", res, result); + return result; +} +//bool fun(HANDLE) +//!0 on success +static int WINAPI expCloseHandle(long v1) +{ + dbgprintf("CloseHandle(0x%x) => 1\n", v1); + /* do not close stdin,stdout and stderr */ + if (v1 > 2) + if (!close(v1)) + return 0; + return 1; +} + +static const char* WINAPI expGetCommandLineA() +{ + dbgprintf("GetCommandLineA() => \"c:\\aviplay.exe\"\n"); + return "c:\\aviplay.exe"; +} +static short envs[]={'p', 'a', 't', 'h', ' ', 'c', ':', '\\', 0, 0}; +static LPWSTR WINAPI expGetEnvironmentStringsW() +{ + dbgprintf("GetEnvironmentStringsW() => 0\n", envs); + return 0; +} +static void * WINAPI expRtlZeroMemory(void *p, size_t len) +{ + void* result=memset(p,0,len); + dbgprintf("RtlZeroMemory(0x%x, len %d) => 0x%x\n",p,len,result); + return result; +} +static void * WINAPI expRtlMoveMemory(void *dst, void *src, size_t len) +{ + void* result=memmove(dst,src,len); + dbgprintf("RtlMoveMemory (dest 0x%x, src 0x%x, len %d) => 0x%x\n",dst,src,len,result); + return result; +} + +static void * WINAPI expRtlFillMemory(void *p, int ch, size_t len) +{ + void* result=memset(p,ch,len); + dbgprintf("RtlFillMemory(0x%x, char 0x%x, len %d) => 0x%x\n",p,ch,len,result); + return result; +} +static int WINAPI expFreeEnvironmentStringsW(short* strings) +{ + dbgprintf("FreeEnvironmentStringsW(0x%x) => 1\n", strings); + return 1; +} +static int WINAPI expFreeEnvironmentStringsA(char* strings) +{ + dbgprintf("FreeEnvironmentStringsA(0x%x) => 1\n", strings); + return 1; +} + +static const char ch_envs[]= +"__MSVCRT_HEAP_SELECT=__GLOBAL_HEAP_SELECTED,1\r\n" +"PATH=C:\\;C:\\windows\\;C:\\windows\\system\r\n"; +static LPCSTR WINAPI expGetEnvironmentStrings() +{ + dbgprintf("GetEnvironmentStrings() => 0x%x\n", ch_envs); + return (LPCSTR)ch_envs; + // dbgprintf("GetEnvironmentStrings() => 0\n"); + // return 0; +} + +static int WINAPI expGetStartupInfoA(STARTUPINFOA *s) +{ + int i; + dbgprintf("GetStartupInfoA(0x%x) => 1\n"); + memset(s, 0, sizeof(*s)); + s->cb=sizeof(*s); + // s->lpReserved="Reserved"; + // s->lpDesktop="Desktop"; + // s->lpTitle="Title"; + // s->dwX=s->dwY=0; + // s->dwXSize=s->dwYSize=200; + s->dwFlags=s->wShowWindow=1; + // s->hStdInput=s->hStdOutput=s->hStdError=0x1234; + dbgprintf(" cb=%d\n", s->cb); + dbgprintf(" lpReserved='%s'\n", s->lpReserved); + dbgprintf(" lpDesktop='%s'\n", s->lpDesktop); + dbgprintf(" lpTitle='%s'\n", s->lpTitle); + dbgprintf(" dwX=%d dwY=%d dwXSize=%d dwYSize=%d\n", + s->dwX, s->dwY, s->dwXSize, s->dwYSize); + dbgprintf(" dwXCountChars=%d dwYCountChars=%d dwFillAttribute=%d\n", + s->dwXCountChars, s->dwYCountChars, s->dwFillAttribute); + dbgprintf(" dwFlags=0x%x wShowWindow=0x%x cbReserved2=0x%x\n", + s->dwFlags, s->wShowWindow, s->cbReserved2); + dbgprintf(" lpReserved2=0x%x hStdInput=0x%x hStdOutput=0x%x hStdError=0x%x\n", + s->lpReserved2, s->hStdInput, s->hStdOutput, s->hStdError); + return 1; +} + +static int WINAPI expGetStdHandle(int z) +{ + dbgprintf("GetStdHandle(0x%x) => 0x%x\n", z+0x1234); + return z+0x1234; +} + +#ifdef QTX +#define FILE_HANDLE_quicktimeqts ((HANDLE)0x444) +#define FILE_HANDLE_quicktimeqtx ((HANDLE)0x445) +#endif + +static int WINAPI expGetFileType(int handle) +{ + dbgprintf("GetFileType(0x%x) => 0x3 = pipe\n", handle); + return 0x3; +} +#ifdef QTX +static int WINAPI expGetFileAttributesA(char *filename) +{ + dbgprintf("GetFileAttributesA(%s) => FILE_ATTR_NORMAL\n", filename); + if (strstr(filename, "QuickTime.qts")) + return FILE_ATTRIBUTE_SYSTEM; + return FILE_ATTRIBUTE_NORMAL; +} +#endif +static int WINAPI expSetHandleCount(int count) +{ + dbgprintf("SetHandleCount(0x%x) => 1\n", count); + return 1; +} +static int WINAPI expGetACP(void) +{ + dbgprintf("GetACP() => 0\n"); + return 0; +} +extern WINE_MODREF *MODULE32_LookupHMODULE(HMODULE m); +static int WINAPI expGetModuleFileNameA(int module, char* s, int len) +{ + WINE_MODREF *mr; + int result; + //printf("File name of module %X (%s) requested\n", module, s); + + if (module == 0 && len >= 12) + { + /* return caller program name */ + strcpy(s, "aviplay.dll"); + result=1; + } + else if(s==0) + result=0; + else + if(len<35) + result=0; + else + { + result=1; + strcpy(s, "c:\\windows\\system\\"); + mr=MODULE32_LookupHMODULE(module); + if(mr==0)//oops + strcat(s, "aviplay.dll"); + else + if(strrchr(mr->filename, '/')==NULL) + strcat(s, mr->filename); + else + strcat(s, strrchr(mr->filename, '/')+1); + } + if(!s) + dbgprintf("GetModuleFileNameA(0x%x, 0x%x, %d) => %d\n", + module, s, len, result); + else + dbgprintf("GetModuleFileNameA(0x%x, 0x%x, %d) => %d ( '%s' )\n", + module, s, len, result, s); + return result; +} + +static int WINAPI expSetUnhandledExceptionFilter(void* filter) +{ + dbgprintf("SetUnhandledExceptionFilter(0x%x) => 1\n", filter); + return 1;//unsupported and probably won't ever be supported +} + +static int WINAPI expLoadLibraryA(char* name) +{ + int result = 0; + char* lastbc; + int i; + if (!name) + return -1; + // we skip to the last backslash + // this is effectively eliminating weird characters in + // the text output windows + + lastbc = strrchr(name, '\\'); + if (lastbc) + { + int i; + lastbc++; + for (i = 0; 1 ;i++) + { + name[i] = *lastbc++; + if (!name[i]) + break; + } + } + if(strncmp(name, "c:\\windows\\", 11)==0) name += 11; + if(strncmp(name, ".\\", 2)==0) name += 2; + + dbgprintf("Entering LoadLibraryA(%s)\n", name); + + // PIMJ and VIVO audio are loading kernel32.dll + if (strcasecmp(name, "kernel32.dll") == 0 || strcasecmp(name, "kernel32") == 0) + return MODULE_HANDLE_kernel32; +// return ERROR_SUCCESS; /* yeah, we have also the kernel32 calls */ + /* exported -> do not return failed! */ + + if (strcasecmp(name, "user32.dll") == 0 || strcasecmp(name, "user32") == 0) +// return MODULE_HANDLE_kernel32; + return MODULE_HANDLE_user32; + +#ifdef QTX + if (strcasecmp(name, "wininet.dll") == 0 || strcasecmp(name, "wininet") == 0) + return MODULE_HANDLE_wininet; + if (strcasecmp(name, "ddraw.dll") == 0 || strcasecmp(name, "ddraw") == 0) + return MODULE_HANDLE_ddraw; + if (strcasecmp(name, "advapi32.dll") == 0 || strcasecmp(name, "advapi32") == 0) + return MODULE_HANDLE_advapi32; +#endif + + result=LoadLibraryA(name); + dbgprintf("Returned LoadLibraryA(0x%x='%s'), def_path=%s => 0x%x\n", name, name, def_path, result); + + return result; +} + +static int WINAPI expFreeLibrary(int module) +{ +#ifdef QTX + int result=0; /* FIXME:XXX: qtx svq3 frees up qt.qts */ +#else + int result=FreeLibrary(module); +#endif + dbgprintf("FreeLibrary(0x%x) => %d\n", module, result); + return result; +} + +static void* WINAPI expGetProcAddress(HMODULE mod, char* name) +{ + void* result; + switch(mod){ + case MODULE_HANDLE_kernel32: + result=LookupExternalByName("kernel32.dll", name); break; + case MODULE_HANDLE_user32: + result=LookupExternalByName("user32.dll", name); break; +#ifdef QTX + case MODULE_HANDLE_wininet: + result=LookupExternalByName("wininet.dll", name); break; + case MODULE_HANDLE_ddraw: + result=LookupExternalByName("ddraw.dll", name); break; + case MODULE_HANDLE_advapi32: + result=LookupExternalByName("advapi32.dll", name); break; +#endif + default: + result=GetProcAddress(mod, name); + } + dbgprintf("GetProcAddress(0x%x, '%s') => 0x%x\n", mod, name, result); + return result; +} + +static long WINAPI expCreateFileMappingA(int hFile, void* lpAttr, + long flProtect, long dwMaxHigh, + long dwMaxLow, const char* name) +{ + long result=CreateFileMappingA(hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, name); + if(!name) + dbgprintf("CreateFileMappingA(file 0x%x, lpAttr 0x%x," + "flProtect 0x%x, dwMaxHigh 0x%x, dwMaxLow 0x%x, name 0) => %d\n", + hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, result); + else + dbgprintf("CreateFileMappingA(file 0x%x, lpAttr 0x%x," + "flProtect 0x%x, dwMaxHigh 0x%x, dwMaxLow 0x%x, name 0x%x='%s') => %d\n", + hFile, lpAttr, flProtect, dwMaxHigh, dwMaxLow, name, name, result); + return result; +} + +static long WINAPI expOpenFileMappingA(long hFile, long hz, const char* name) +{ + long result=OpenFileMappingA(hFile, hz, name); + if(!name) + dbgprintf("OpenFileMappingA(0x%x, 0x%x, 0) => %d\n", + hFile, hz, result); + else + dbgprintf("OpenFileMappingA(0x%x, 0x%x, 0x%x='%s') => %d\n", + hFile, hz, name, name, result); + return result; +} + +static void* WINAPI expMapViewOfFile(HANDLE file, DWORD mode, DWORD offHigh, + DWORD offLow, DWORD size) +{ + dbgprintf("MapViewOfFile(0x%x, 0x%x, 0x%x, 0x%x, size %d) => 0x%x\n", + file,mode,offHigh,offLow,size,(char*)file+offLow); + return (char*)file+offLow; +} + +static void* WINAPI expUnmapViewOfFile(void* view) +{ + dbgprintf("UnmapViewOfFile(0x%x) => 0\n", view); + return 0; +} + +static void* WINAPI expSleep(int time) +{ +#if HAVE_NANOSLEEP + /* solaris doesn't have thread safe usleep */ + struct timespec tsp; + tsp.tv_sec = time / 1000000; + tsp.tv_nsec = (time % 1000000) * 1000; + nanosleep(&tsp, NULL); +#else + usleep(time); +#endif + dbgprintf("Sleep(%d) => 0\n", time); + return 0; +} + +// why does IV32 codec want to call this? I don't know ... +static int WINAPI expCreateCompatibleDC(int hdc) +{ + int dc = 0;//0x81; + //dbgprintf("CreateCompatibleDC(%d) => 0x81\n", hdc); + dbgprintf("CreateCompatibleDC(%d) => %d\n", hdc, dc); + return dc; +} + +static int WINAPI expGetDeviceCaps(int hdc, int unk) +{ + dbgprintf("GetDeviceCaps(0x%x, %d) => 0\n", hdc, unk); +#ifdef QTX + #define BITSPIXEL 12 + #define PLANES 14 + if (unk == BITSPIXEL) + return 24; + if (unk == PLANES) + return 1; +#endif + return 1; +} + +static WIN_BOOL WINAPI expDeleteDC(int hdc) +{ + dbgprintf("DeleteDC(0x%x) => 0\n", hdc); + if (hdc == 0x81) + return 1; + return 0; +} + +static WIN_BOOL WINAPI expDeleteObject(int hdc) +{ + dbgprintf("DeleteObject(0x%x) => 1\n", hdc); + /* FIXME - implement code here */ + return 1; +} + +/* btvvc32.drv wants this one */ +static void* WINAPI expGetWindowDC(int hdc) +{ + dbgprintf("GetWindowDC(%d) => 0x0\n", hdc); + return 0; +} + +#ifdef QTX +static int WINAPI expGetWindowRect(HWND win, RECT *r) +{ + dbgprintf("GetWindowRect(0x%x, 0x%x) => 1\n", win, r); + /* (win == 0) => desktop */ + r->right = PSEUDO_SCREEN_WIDTH; + r->left = 0; + r->bottom = PSEUDO_SCREEN_HEIGHT; + r->top = 0; + return 1; +} + +static int WINAPI expMonitorFromWindow(HWND win, int flags) +{ + dbgprintf("MonitorFromWindow(0x%x, 0x%x) => 0\n", win, flags); + return 0; +} + +static int WINAPI expMonitorFromRect(RECT *r, int flags) +{ + dbgprintf("MonitorFromRect(0x%x, 0x%x) => 0\n", r, flags); + return 0; +} + +static int WINAPI expMonitorFromPoint(void *p, int flags) +{ + dbgprintf("MonitorFromPoint(0x%x, 0x%x) => 0\n", p, flags); + return 0; +} + +static int WINAPI expEnumDisplayMonitors(void *dc, RECT *r, + int WINAPI (*callback_proc)(), void *callback_param) +{ + dbgprintf("EnumDisplayMonitors(0x%x, 0x%x, 0x%x, 0x%x) => ?\n", + dc, r, callback_proc, callback_param); + return callback_proc(0, dc, r, callback_param); +} + +#if 0 +typedef struct tagMONITORINFO { + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; +#endif + +#define CCHDEVICENAME 8 +typedef struct tagMONITORINFOEX { + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; + +static int WINAPI expGetMonitorInfoA(void *mon, LPMONITORINFO lpmi) +{ + dbgprintf("GetMonitorInfoA(0x%x, 0x%x) => 1\n", mon, lpmi); + + lpmi->rcMonitor.right = lpmi->rcWork.right = PSEUDO_SCREEN_WIDTH; + lpmi->rcMonitor.left = lpmi->rcWork.left = 0; + lpmi->rcMonitor.bottom = lpmi->rcWork.bottom = PSEUDO_SCREEN_HEIGHT; + lpmi->rcMonitor.top = lpmi->rcWork.top = 0; + + lpmi->dwFlags = 1; /* primary monitor */ + + if (lpmi->cbSize == sizeof(MONITORINFOEX)) + { + LPMONITORINFOEX lpmiex = (LPMONITORINFOEX)lpmi; + dbgprintf("MONITORINFOEX!\n"); + strncpy(lpmiex->szDevice, "Monitor1", CCHDEVICENAME); + } + + return 1; +} + +static int WINAPI expEnumDisplayDevicesA(const char *device, int devnum, + void *dispdev, int flags) +{ + dbgprintf("EnumDisplayDevicesA(0x%x = %s, %d, 0x%x, %x) => 1\n", + device, device, devnum, dispdev, flags); + return 1; +} + +static int WINAPI expIsWindowVisible(HWND win) +{ + dbgprintf("IsWindowVisible(0x%x) => 1\n", win); + return 1; +} + +static HWND WINAPI expGetActiveWindow(void) +{ + dbgprintf("GetActiveWindow() => 0\n"); + return (HWND)0; +} + +static int WINAPI expGetClassNameA(HWND win, LPTSTR classname, int maxcount) +{ + strncat(classname, "QuickTime", maxcount); + dbgprintf("GetClassNameA(0x%x, 0x%x, %d) => %d\n", + win, classname, maxcount, strlen(classname)); + return strlen(classname); +} + +#define LPWNDCLASS void * +static int WINAPI expGetClassInfoA(HINSTANCE inst, LPCSTR classname, LPWNDCLASS wndclass) +{ + dbgprintf("GetClassInfoA(0x%x, 0x%x = %s, 0x%x) => 1\n", inst, + classname, classname, wndclass); + return 1; +} + +static int WINAPI expGetWindowLongA(HWND win, int index) +{ + dbgprintf("GetWindowLongA(0x%x, %d) => 0\n", win, index); + return 1; +} + +static int WINAPI expGetObjectA(HGDIOBJ hobj, int objsize, LPVOID obj) +{ + dbgprintf("GetObjectA(0x%x, %d, 0x%x) => %d\n", hobj, objsize, obj, objsize); + return objsize; +} + +static int WINAPI expCreateRectRgn(int x, int y, int width, int height) +{ + dbgprintf("CreateRectRgn(%d, %d, %d, %d) => 0\n", x, y, width, height); + return 0; +} + +static int WINAPI expEnumWindows(int (*callback_func)(), void *callback_param) +{ + int i, i2; + dbgprintf("EnumWindows(0x%x, 0x%x) => 1\n", callback_func, callback_param); + i = callback_func(0, callback_param); + i2 = callback_func(1, callback_param); + return i && i2; +} + +static int WINAPI expGetWindowThreadProcessId(HWND win, int *pid_data) +{ + int tid = pthread_self(); + dbgprintf("GetWindowThreadProcessId(0x%x, 0x%x) => %d\n", + win, pid_data, tid); + if (pid_data) + (int)*pid_data = tid; + return tid; +} + +//HWND WINAPI CreateWindowExA(DWORD,LPCSTR,LPCSTR,DWORD,INT,INT, +// INT,INT,HWND,HMENU,HINSTANCE,LPVOID); + +static HWND WINAPI expCreateWindowExA(int exstyle, const char *classname, + const char *winname, int style, int x, int y, int w, int h, + HWND parent, HMENU menu, HINSTANCE inst, LPVOID param) +{ + printf("CreateWindowEx() called\n"); + dbgprintf("CreateWindowEx(%d, 0x%x = %s, 0x%x = %s, %d, %d, %d, %d, %d, 0x%x, 0x%x, 0x%x, 0x%x) => 1\n", + exstyle, classname, classname, winname, winname, style, x, y, w, h, + parent, menu, inst, param); + printf("CreateWindowEx() called okey\n"); + return 1; +} + +static int WINAPI expwaveOutGetNumDevs(void) +{ + dbgprintf("waveOutGetNumDevs() => 0\n"); + return 0; +} +#endif + +/* + * Returns the number of milliseconds, modulo 2^32, since the start + * of the wineserver. + */ +static int WINAPI expGetTickCount(void) +{ + static int tcstart = 0; + struct timeval t; + int tc; + gettimeofday( &t, NULL ); + tc = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - tcstart; + if (tcstart == 0) + { + tcstart = 0; + tc = 0; + } + dbgprintf("GetTickCount() => %d\n", tc); + return tc; +} + +static int WINAPI expCreateFontA(void) +{ + dbgprintf("CreateFontA() => 0x0\n"); + return 1; +} + +/* tried to get pvmjpg work in a different way - no success */ +static int WINAPI expDrawTextA(int hDC, char* lpString, int nCount, + LPRECT lpRect, unsigned int uFormat) +{ + dbgprintf("expDrawTextA(%p,...) => 8\n", hDC); + return 8; +} + +static int WINAPI expGetPrivateProfileIntA(const char* appname, + const char* keyname, + int default_value, + const char* filename) +{ + int size=255; + char buffer[256]; + char* fullname; + int result; + + buffer[255]=0; + if(!(appname && keyname && filename) ) + { + dbgprintf("GetPrivateProfileIntA('%s', '%s', %d, '%s') => %d\n", appname, keyname, default_value, filename, default_value ); + return default_value; + } + fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename)); + strcpy(fullname, "Software\\IniFileMapping\\"); + strcat(fullname, appname); + strcat(fullname, "\\"); + strcat(fullname, keyname); + strcat(fullname, "\\"); + strcat(fullname, filename); + result=RegQueryValueExA(HKEY_LOCAL_MACHINE, fullname, NULL, NULL, (int*)buffer, &size); + if((size>=0)&&(size<256)) + buffer[size]=0; + // printf("GetPrivateProfileIntA(%s, %s, %s) -> %s\n", appname, keyname, filename, buffer); + free(fullname); + if(result) + result=default_value; + else + result=atoi(buffer); + dbgprintf("GetPrivateProfileIntA('%s', '%s', %d, '%s') => %d\n", appname, keyname, default_value, filename, result); + return result; +} +static int WINAPI expGetProfileIntA(const char* appname, + const char* keyname, + int default_value) +{ + dbgprintf("GetProfileIntA -> "); + return expGetPrivateProfileIntA(appname, keyname, default_value, "default"); +} + +static int WINAPI expGetPrivateProfileStringA(const char* appname, + const char* keyname, + const char* def_val, + char* dest, unsigned int len, + const char* filename) +{ + int result; + int size; + char* fullname; + dbgprintf("GetPrivateProfileStringA('%s', '%s', def_val '%s', 0x%x, 0x%x, '%s')", appname, keyname, def_val, dest, len, filename ); + if(!(appname && keyname && filename) ) return 0; + fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename)); + strcpy(fullname, "Software\\IniFileMapping\\"); + strcat(fullname, appname); + strcat(fullname, "\\"); + strcat(fullname, keyname); + strcat(fullname, "\\"); + strcat(fullname, filename); + size=len; + result=RegQueryValueExA(HKEY_LOCAL_MACHINE, fullname, NULL, NULL, (int*)dest, &size); + free(fullname); + if(result) + { + strncpy(dest, def_val, size); + if (strlen(def_val)< size) size = strlen(def_val); + } + dbgprintf(" => %d ( '%s' )\n", size, dest); + return size; +} +static int WINAPI expWritePrivateProfileStringA(const char* appname, + const char* keyname, + const char* string, + const char* filename) +{ + int size=256; + char* fullname; + dbgprintf("WritePrivateProfileStringA('%s', '%s', '%s', '%s')", appname, keyname, string, filename ); + if(!(appname && keyname && filename) ) + { + dbgprintf(" => -1\n"); + return -1; + } + fullname=(char*)malloc(50+strlen(appname)+strlen(keyname)+strlen(filename)); + strcpy(fullname, "Software\\IniFileMapping\\"); + strcat(fullname, appname); + strcat(fullname, "\\"); + strcat(fullname, keyname); + strcat(fullname, "\\"); + strcat(fullname, filename); + RegSetValueExA(HKEY_LOCAL_MACHINE, fullname, 0, REG_SZ, (int*)string, strlen(string)); + // printf("RegSetValueExA(%s,%d)\n", string, strlen(string)); + // printf("WritePrivateProfileStringA(%s, %s, %s, %s)\n", appname, keyname, string, filename ); + free(fullname); + dbgprintf(" => 0\n"); + return 0; +} + +unsigned int _GetPrivateProfileIntA(const char* appname, const char* keyname, INT default_value, const char* filename) +{ + return expGetPrivateProfileIntA(appname, keyname, default_value, filename); +} +int _GetPrivateProfileStringA(const char* appname, const char* keyname, + const char* def_val, char* dest, unsigned int len, const char* filename) +{ + return expGetPrivateProfileStringA(appname, keyname, def_val, dest, len, filename); +} +int _WritePrivateProfileStringA(const char* appname, const char* keyname, + const char* string, const char* filename) +{ + return expWritePrivateProfileStringA(appname, keyname, string, filename); +} + + + +static int WINAPI expDefDriverProc(int _private, int id, int msg, int arg1, int arg2) +{ + dbgprintf("DefDriverProc(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) => 0\n", _private, id, msg, arg1, arg2); + return 0; +} + +static int WINAPI expSizeofResource(int v1, int v2) +{ + int result=SizeofResource(v1, v2); + dbgprintf("SizeofResource(0x%x, 0x%x) => %d\n", v1, v2, result); + return result; +} + +static int WINAPI expGetLastError() +{ + int result=GetLastError(); + dbgprintf("GetLastError() => 0x%x\n", result); + return result; +} + +static void WINAPI expSetLastError(int error) +{ + dbgprintf("SetLastError(0x%x)\n", error); + SetLastError(error); +} + +static int WINAPI expStringFromGUID2(GUID* guid, char* str, int cbMax) +{ + int result=snprintf(str, cbMax, "%.8x-%.4x-%.4x-%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", + guid->f1, guid->f2, guid->f3, + (unsigned char)guid->f4[0], (unsigned char)guid->f4[1], + (unsigned char)guid->f4[2], (unsigned char)guid->f4[3], + (unsigned char)guid->f4[4], (unsigned char)guid->f4[5], + (unsigned char)guid->f4[6], (unsigned char)guid->f4[7]); + dbgprintf("StringFromGUID2(0x%x, 0x%x='%s', %d) => %d\n", guid, str, str, cbMax, result); + return result; +} + + +static int WINAPI expGetFileVersionInfoSizeA(const char* name, int* lpHandle) +{ + dbgprintf("GetFileVersionInfoSizeA(0x%x='%s', 0x%X) => 0\n", name, name, lpHandle); + return 0; +} + +static int WINAPI expIsBadStringPtrW(const short* string, int nchars) +{ + int result; + if(string==0)result=1; else result=0; + dbgprintf("IsBadStringPtrW(0x%x, %d) => %d", string, nchars, result); + if(string)wch_print(string); + return result; +} +static int WINAPI expIsBadStringPtrA(const char* string, int nchars) +{ + return expIsBadStringPtrW((const short*)string, nchars); +} +static long WINAPI expInterlockedExchangeAdd( long* dest, long incr ) +{ + long ret; + __asm__ __volatile__ + ( + "lock; xaddl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (incr) + : "memory" + ); + return ret; +} + +static long WINAPI expInterlockedCompareExchange( unsigned long* dest, unsigned long exchange, unsigned long comperand) +{ + unsigned long retval = *dest; + if(*dest == comperand) + *dest = exchange; + return retval; +} + +static long WINAPI expInterlockedIncrement( long* dest ) +{ + long result=expInterlockedExchangeAdd( dest, 1 ) + 1; + dbgprintf("InterlockedIncrement(0x%x => %d) => %d\n", dest, *dest, result); + return result; +} +static long WINAPI expInterlockedDecrement( long* dest ) +{ + long result=expInterlockedExchangeAdd( dest, -1 ) - 1; + dbgprintf("InterlockedDecrement(0x%x => %d) => %d\n", dest, *dest, result); + return result; +} + +static void WINAPI expOutputDebugStringA( const char* string ) +{ + dbgprintf("OutputDebugStringA(0x%x='%s')\n", string); + fprintf(stderr, "DEBUG: %s\n", string); +} + +static int WINAPI expGetDC(int hwnd) +{ + dbgprintf("GetDC(0x%x) => 1\n", hwnd); + return 1; +} + +static int WINAPI expReleaseDC(int hwnd, int hdc) +{ + dbgprintf("ReleaseDC(0x%x, 0x%x) => 1\n", hwnd, hdc); + return 1; +} + +static int WINAPI expGetDesktopWindow() +{ + dbgprintf("GetDesktopWindow() => 0\n"); + return 0; +} + +static int cursor[100]; + +static int WINAPI expLoadCursorA(int handle,LPCSTR name) +{ + dbgprintf("LoadCursorA(%d, 0x%x='%s') => 0x%x\n", handle, name, (int)&cursor[0]); + return (int)&cursor[0]; +} +static int WINAPI expSetCursor(void *cursor) +{ + dbgprintf("SetCursor(0x%x) => 0x%x\n", cursor, cursor); + return (int)cursor; +} +static int WINAPI expGetCursorPos(void *cursor) +{ + dbgprintf("GetCursorPos(0x%x) => 0x%x\n", cursor, cursor); + return 1; +} +#ifdef QTX +static int show_cursor = 0; +static int WINAPI expShowCursor(int show) +{ + dbgprintf("ShowCursor(%d) => %d\n", show, show); + if (show) + show_cursor++; + else + show_cursor--; + return show_cursor; +} +#endif +static int WINAPI expRegisterWindowMessageA(char *message) +{ + dbgprintf("RegisterWindowMessageA(%s)\n", message); + return 1; +} +static int WINAPI expGetProcessVersion(int pid) +{ + dbgprintf("GetProcessVersion(%d)\n", pid); + return 1; +} +static int WINAPI expGetCurrentThread(void) +{ +#warning FIXME! + dbgprintf("GetCurrentThread() => %x\n", 0xcfcf9898); + return 0xcfcf9898; +} +static int WINAPI expGetOEMCP(void) +{ + dbgprintf("GetOEMCP()\n"); + return 1; +} +static int WINAPI expGetCPInfo(int cp,void *info) +{ + dbgprintf("GetCPInfo()\n"); + return 0; +} +#ifdef QTX +#define SM_CXSCREEN 0 +#define SM_CYSCREEN 1 +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#endif +static int WINAPI expGetSystemMetrics(int index) +{ + dbgprintf("GetSystemMetrics(%d)\n", index); +#ifdef QTX + switch(index) + { + case SM_XVIRTUALSCREEN: + case SM_YVIRTUALSCREEN: + return 0; + case SM_CXSCREEN: + case SM_CXVIRTUALSCREEN: + return PSEUDO_SCREEN_WIDTH; + case SM_CYSCREEN: + case SM_CYVIRTUALSCREEN: + return PSEUDO_SCREEN_HEIGHT; + case SM_CMONITORS: + return 1; + } +#endif + return 1; +} +static int WINAPI expGetSysColor(int index) +{ + dbgprintf("GetSysColor(%d) => 1\n", index); + return 1; +} +static int WINAPI expGetSysColorBrush(int index) +{ + dbgprintf("GetSysColorBrush(%d)\n", index); + return 1; +} + + + +static int WINAPI expGetSystemPaletteEntries(int hdc, int iStartIndex, int nEntries, void* lppe) +{ + dbgprintf("GetSystemPaletteEntries(0x%x, 0x%x, 0x%x, 0x%x) => 0\n", + hdc, iStartIndex, nEntries, lppe); + return 0; +} + +/* + typedef struct _TIME_ZONE_INFORMATION { + long Bias; + char StandardName[32]; + SYSTEMTIME StandardDate; + long StandardBias; + char DaylightName[32]; + SYSTEMTIME DaylightDate; + long DaylightBias; + } TIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; + */ + +static int WINAPI expGetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation) +{ + const short name[]={'C', 'e', 'n', 't', 'r', 'a', 'l', ' ', 'S', 't', 'a', + 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e', 0}; + const short pname[]={'C', 'e', 'n', 't', 'r', 'a', 'l', ' ', 'D', 'a', 'y', + 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e', 0}; + dbgprintf("GetTimeZoneInformation(0x%x) => TIME_ZONE_ID_STANDARD\n"); + memset(lpTimeZoneInformation, 0, sizeof(TIME_ZONE_INFORMATION)); + lpTimeZoneInformation->Bias=360;//GMT-6 + memcpy(lpTimeZoneInformation->StandardName, name, sizeof(name)); + lpTimeZoneInformation->StandardDate.wMonth=10; + lpTimeZoneInformation->StandardDate.wDay=5; + lpTimeZoneInformation->StandardDate.wHour=2; + lpTimeZoneInformation->StandardBias=0; + memcpy(lpTimeZoneInformation->DaylightName, pname, sizeof(pname)); + lpTimeZoneInformation->DaylightDate.wMonth=4; + lpTimeZoneInformation->DaylightDate.wDay=1; + lpTimeZoneInformation->DaylightDate.wHour=2; + lpTimeZoneInformation->DaylightBias=-60; + return TIME_ZONE_ID_STANDARD; +} + +static void WINAPI expGetLocalTime(SYSTEMTIME* systime) +{ + time_t local_time; + struct tm *local_tm; + struct timeval tv; + + dbgprintf("GetLocalTime(0x%x)\n"); + gettimeofday(&tv, NULL); + local_time=tv.tv_sec; + local_tm=localtime(&local_time); + + systime->wYear = local_tm->tm_year + 1900; + systime->wMonth = local_tm->tm_mon + 1; + systime->wDayOfWeek = local_tm->tm_wday; + systime->wDay = local_tm->tm_mday; + systime->wHour = local_tm->tm_hour; + systime->wMinute = local_tm->tm_min; + systime->wSecond = local_tm->tm_sec; + systime->wMilliseconds = (tv.tv_usec / 1000) % 1000; + dbgprintf(" Year: %d\n Month: %d\n Day of week: %d\n" + " Day: %d\n Hour: %d\n Minute: %d\n Second: %d\n" + " Milliseconds: %d\n", + systime->wYear, systime->wMonth, systime->wDayOfWeek, systime->wDay, + systime->wHour, systime->wMinute, systime->wSecond, systime->wMilliseconds); +} + +static int WINAPI expGetSystemTime(SYSTEMTIME* systime) +{ + time_t local_time; + struct tm *local_tm; + struct timeval tv; + + dbgprintf("GetSystemTime(0x%x)\n", systime); + gettimeofday(&tv, NULL); + local_time=tv.tv_sec; + local_tm=gmtime(&local_time); + + systime->wYear = local_tm->tm_year + 1900; + systime->wMonth = local_tm->tm_mon + 1; + systime->wDayOfWeek = local_tm->tm_wday; + systime->wDay = local_tm->tm_mday; + systime->wHour = local_tm->tm_hour; + systime->wMinute = local_tm->tm_min; + systime->wSecond = local_tm->tm_sec; + systime->wMilliseconds = (tv.tv_usec / 1000) % 1000; + dbgprintf(" Year: %d\n Month: %d\n Day of week: %d\n" + " Day: %d\n Hour: %d\n Minute: %d\n Second: %d\n" + " Milliseconds: %d\n", + systime->wYear, systime->wMonth, systime->wDayOfWeek, systime->wDay, + systime->wHour, systime->wMinute, systime->wSecond, systime->wMilliseconds); + return 0; +} + +#define SECS_1601_TO_1970 ((369 * 365 + 89) * 86400ULL) +static void WINAPI expGetSystemTimeAsFileTime(FILETIME* systime) +{ + struct tm *local_tm; + struct timeval tv; + unsigned long long secs; + + dbgprintf("GetSystemTime(0x%x)\n", systime); + gettimeofday(&tv, NULL); + secs = (tv.tv_sec + SECS_1601_TO_1970) * 10000000; + secs += tv.tv_usec * 10; + systime->dwLowDateTime = secs & 0xffffffff; + systime->dwHighDateTime = (secs >> 32); +} + +static int WINAPI expGetEnvironmentVariableA(const char* name, char* field, int size) +{ + char *p; + // printf("%s %x %x\n", name, field, size); + if(field)field[0]=0; + /* + p = getenv(name); + if (p) strncpy(field,p,size); + */ + if (strcmp(name,"__MSVCRT_HEAP_SELECT")==0) + strcpy(field,"__GLOBAL_HEAP_SELECTED,1"); + dbgprintf("GetEnvironmentVariableA(0x%x='%s', 0x%x, %d) => %d\n", name, name, field, size, strlen(field)); + return strlen(field); +} + +static int WINAPI expSetEnvironmentVariableA(const char *name, const char *value) +{ + dbgprintf("SetEnvironmentVariableA(%s, %s)\n", name, value); + return 0; +} + +static void* WINAPI expCoTaskMemAlloc(ULONG cb) +{ + return my_mreq(cb, 0); +} +static void WINAPI expCoTaskMemFree(void* cb) +{ + my_release(cb); +} + + + + +void* CoTaskMemAlloc(unsigned long cb) +{ + return expCoTaskMemAlloc(cb); +} +void CoTaskMemFree(void* cb) +{ + expCoTaskMemFree(cb); +} + +struct COM_OBJECT_INFO +{ + GUID clsid; + long (*GetClassObject) (GUID* clsid, const GUID* iid, void** ppv); +}; + +static struct COM_OBJECT_INFO* com_object_table=0; +static int com_object_size=0; +int RegisterComClass(const GUID* clsid, GETCLASSOBJECT gcs) +{ + if(!clsid || !gcs) + return -1; + com_object_table=realloc(com_object_table, sizeof(struct COM_OBJECT_INFO)*(++com_object_size)); + com_object_table[com_object_size-1].clsid=*clsid; + com_object_table[com_object_size-1].GetClassObject=gcs; + return 0; +} + +int UnregisterComClass(const GUID* clsid, GETCLASSOBJECT gcs) +{ + int found = 0; + int i = 0; + if(!clsid || !gcs) + return -1; + + if (com_object_table == 0) + printf("Warning: UnregisterComClass() called without any registered class\n"); + while (i < com_object_size) + { + if (found && i > 0) + { + memcpy(&com_object_table[i - 1].clsid, + &com_object_table[i].clsid, sizeof(GUID)); + com_object_table[i - 1].GetClassObject = + com_object_table[i].GetClassObject; + } + else if (memcmp(&com_object_table[i].clsid, clsid, sizeof(GUID)) == 0 + && com_object_table[i].GetClassObject == gcs) + { + found++; + } + i++; + } + if (found) + { + if (--com_object_size == 0) + { + free(com_object_table); + com_object_table = 0; + } + } + return 0; +} + + +const GUID IID_IUnknown = +{ + 0x00000000, 0x0000, 0x0000, + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +}; +const GUID IID_IClassFactory = +{ + 0x00000001, 0x0000, 0x0000, + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +}; + +static long WINAPI expCoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter, + long dwClsContext, const GUID* riid, void** ppv) +{ + int i; + struct COM_OBJECT_INFO* ci=0; + for(i=0; iGetClassObject(rclsid, riid, ppv); + return i; +} + +long CoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter, + long dwClsContext, const GUID* riid, void** ppv) +{ + return expCoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); +} + +static int WINAPI expIsRectEmpty(CONST RECT *lprc) +{ + int r = 0; + int w,h; +//trapbug(); + if (lprc) + { + w = lprc->right - lprc->left; + h = lprc->bottom - lprc->top; + if (w <= 0 || h <= 0) + r = 1; + } + else + r = 1; + + dbgprintf("IsRectEmpty(%p) => %s\n", lprc, (r) ? "TRUE" : "FALSE"); + //printf("Rect: left: %d, top: %d, right: %d, bottom: %d\n", lprc->left, lprc->top, lprc->right, lprc->bottom); +// return 0; // wmv9? + return r; // TM20 +} + +static int _adjust_fdiv=0; //what's this? - used to adjust division + + + + +static unsigned int WINAPI expGetTempPathA(unsigned int len, char* path) +{ + dbgprintf("GetTempPathA(%d, 0x%x)", len, path); + if(len<5) + { + dbgprintf(" => 0\n"); + return 0; + } + strcpy(path, "/tmp"); + dbgprintf(" => 5 ( '/tmp' )\n"); + return 5; +} +/* + FYI: + typedef struct + { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + CHAR cFileName[260]; + CHAR cAlternateFileName[14]; + } WIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; + */ + +static DIR* qtx_dir=NULL; + +static WIN_BOOL WINAPI expFindNextFileA(HANDLE h,LPWIN32_FIND_DATAA lpfd) +{ +#ifdef QTX + dbgprintf("FindNextFileA(0x%x, 0x%x) => 0\n", h, lpfd); + if(h==FILE_HANDLE_quicktimeqtx){ + struct dirent* d; + if(!qtx_dir) return 0; + while((d=readdir(qtx_dir))){ + char* x=strrchr(d->d_name,'.'); + if(!x) continue; + if(strcmp(x,".qtx")) continue; + strcpy(lpfd->cFileName,d->d_name); +// sprintf(lpfd->cAlternateFileName,"%-8s.qtx",d->d_name); + strcpy(lpfd->cAlternateFileName,"foobar.qtx"); + printf("### FindNext: %s\n",lpfd->cFileName); + return 1; + } + closedir(qtx_dir); qtx_dir=NULL; + return 0; + } +#endif + return 0; +} + +static HANDLE WINAPI expFindFirstFileA(LPCSTR s, LPWIN32_FIND_DATAA lpfd) +{ + dbgprintf("FindFirstFileA(0x%x='%s', 0x%x) => 0\n", s, s, lpfd); +// printf("\n### FindFirstFileA('%s')...\n",s); +#ifdef QTX + if(strstr(s, "quicktime\\*.QTX")){ + dbgprintf("FindFirstFileA(0x%x='%s', 0x%x) => QTX\n", s, s, lpfd); + printf("\n### Searching for QuickTime plugins (*.qtx) at %s...\n",def_path); + qtx_dir=opendir(def_path); + if(!qtx_dir) return (HANDLE)-1; + memset(lpfd,0,sizeof(*lpfd)); + if(expFindNextFileA(FILE_HANDLE_quicktimeqtx,lpfd)) + return FILE_HANDLE_quicktimeqtx; + printf("loader: Couldn't find the QuickTime plugins (.qtx files) at %s\n",def_path); + return (HANDLE)-1; + } +#if 0 + if(strstr(s, "QuickTime.qts")){ + dbgprintf("FindFirstFileA(0x%x='%s', 0x%x) => QTS\n", s, s, lpfd); +// if(!strcmp(s,"C:\\windows\\QuickTime.qts\\QuickTime.qts\\*.QTX")) +// return (HANDLE)-1; + strcpy(lpfd->cFileName, "QuickTime.qts"); + strcpy(lpfd->cAlternateFileName, "QuickT~1.qts"); + return FILE_HANDLE_quicktimeqts; + } +#endif +#endif + if(strstr(s, "*.vwp")){ + // hack for VoxWare codec plugins: + strcpy(lpfd->cFileName, "msms001.vwp"); + strcpy(lpfd->cAlternateFileName, "msms001.vwp"); + return (HANDLE)0; + } + // return 'file not found' + return (HANDLE)-1; +} + +static WIN_BOOL WINAPI expFindClose(HANDLE h) +{ + dbgprintf("FindClose(0x%x) => 0\n", h); +#ifdef QTX +// if(h==FILE_HANDLE_quicktimeqtx && qtx_dir){ +// closedir(qtx_dir); +// qtx_dir=NULL; +// } +#endif + return 0; +} +static UINT WINAPI expSetErrorMode(UINT i) +{ + dbgprintf("SetErrorMode(%d) => 0\n", i); + return 0; +} +static UINT WINAPI expGetWindowsDirectoryA(LPSTR s,UINT c) +{ + char windir[]="c:\\windows"; + int result; + strncpy(s, windir, c); + result=1+((c %d\n", s, c, result); + return result; +} +#ifdef QTX +static UINT WINAPI expGetCurrentDirectoryA(UINT c, LPSTR s) +{ + char curdir[]="c:\\"; + int result; + strncpy(s, curdir, c); + result=1+((c %d\n", s, c, result); + return result; +} + +static int WINAPI expSetCurrentDirectoryA(const char *pathname) +{ + dbgprintf("SetCurrentDirectoryA(0x%x = %s) => 1\n", pathname, pathname); +#if 0 + if (strrchr(pathname, '\\')) + chdir(strcat(strrchr(pathname, '\\')+1, '/')); + else + chdir(pathname); +#endif + return 1; +} + +static int WINAPI expCreateDirectoryA(const char *pathname, void *sa) +{ + dbgprintf("CreateDirectory(0x%x = %s, 0x%x) => 1\n", + pathname, pathname, sa); +#if 0 + p = strrchr(pathname, '\\')+1; + strcpy(&buf[0], p); /* should be strncpy */ + if (!strlen(p)) + { + buf[0] = '.'; + buf[1] = 0; + } +#if 0 + if (strrchr(pathname, '\\')) + mkdir(strcat(strrchr(pathname, '\\')+1, '/'), 666); + else + mkdir(pathname, 666); +#endif + mkdir(&buf); +#endif + return 1; +} +#endif +static WIN_BOOL WINAPI expDeleteFileA(LPCSTR s) +{ + dbgprintf("DeleteFileA(0x%x='%s') => 0\n", s, s); + return 0; +} +static WIN_BOOL WINAPI expFileTimeToLocalFileTime(const FILETIME* cpf, LPFILETIME pf) +{ + dbgprintf("FileTimeToLocalFileTime(0x%x, 0x%x) => 0\n", cpf, pf); + return 0; +} + +static UINT WINAPI expGetTempFileNameA(LPCSTR cs1,LPCSTR cs2,UINT i,LPSTR ps) +{ + char mask[16]="/tmp/AP_XXXXXX"; + int result; + dbgprintf("GetTempFileNameA(0x%x='%s', 0x%x='%s', %d, 0x%x)", cs1, cs1, cs2, cs2, i, ps); + if(i && i<10) + { + dbgprintf(" => -1\n"); + return -1; + } + result=mkstemp(mask); + sprintf(ps, "AP%d", result); + dbgprintf(" => %d\n", strlen(ps)); + return strlen(ps); +} +// +// This func might need proper implementation if we want AngelPotion codec. +// They try to open APmpeg4v1.apl with it. +// DLL will close opened file with CloseHandle(). +// +static HANDLE WINAPI expCreateFileA(LPCSTR cs1,DWORD i1,DWORD i2, + LPSECURITY_ATTRIBUTES p1, DWORD i3,DWORD i4,HANDLE i5) +{ + dbgprintf("CreateFileA(0x%x='%s', %d, %d, 0x%x, %d, %d, 0x%x)\n", cs1, cs1, i1, + i2, p1, i3, i4, i5); + if((!cs1) || (strlen(cs1)<2))return -1; + +#ifdef QTX + if(strstr(cs1, "QuickTime.qts")) + { + int result; + char* tmp=(char*)malloc(strlen(def_path)+50); + strcpy(tmp, def_path); + strcat(tmp, "/"); + strcat(tmp, "QuickTime.qts"); + result=open(tmp, O_RDONLY); + free(tmp); + return result; + } + if(strstr(cs1, ".qtx")) + { + int result; + char* tmp=(char*)malloc(strlen(def_path)+250); + char* x=strrchr(cs1,'\\'); + sprintf(tmp,"%s/%s",def_path,x?(x+1):cs1); +// printf("### Open: %s -> %s\n",cs1,tmp); + result=open(tmp, O_RDONLY); + free(tmp); + return result; + } +#endif + + if(strncmp(cs1, "AP", 2) == 0) + { + int result; + char* tmp=(char*)malloc(strlen(def_path)+50); + strcpy(tmp, def_path); + strcat(tmp, "/"); + strcat(tmp, "APmpg4v1.apl"); + result=open(tmp, O_RDONLY); + free(tmp); + return result; + } + if (strstr(cs1, "vp3")) + { + int r; + int flg = 0; + char* tmp=(char*)malloc(20 + strlen(cs1)); + strcpy(tmp, "/tmp/"); + strcat(tmp, cs1); + r = 4; + while (tmp[r]) + { + if (tmp[r] == ':' || tmp[r] == '\\') + tmp[r] = '_'; + r++; + } + if (GENERIC_READ & i1) + flg |= O_RDONLY; + else if (GENERIC_WRITE & i1) + { + flg |= O_WRONLY; + printf("Warning: openning filename %s %d (flags; 0x%x) for write\n", tmp, r, flg); + } + r=open(tmp, flg); + free(tmp); + return r; + } + +#if 0 + /* we need this for some virtualdub filters */ + { + int r; + int flg = 0; + if (GENERIC_READ & i1) + flg |= O_RDONLY; + else if (GENERIC_WRITE & i1) + { + flg |= O_WRONLY; + printf("Warning: openning filename %s %d (flags; 0x%x) for write\n", cs1, r, flg); + } + r=open(cs1, flg); + return r; + } +#endif + + return atoi(cs1+2); +} +static UINT WINAPI expGetSystemDirectoryA( + char* lpBuffer, // address of buffer for system directory + UINT uSize // size of directory buffer +){ + dbgprintf("GetSystemDirectoryA(%p,%d)\n", lpBuffer,uSize); + if(!lpBuffer) strcpy(lpBuffer,"."); + return 1; +} +/* +static char sysdir[]="."; +static LPCSTR WINAPI expGetSystemDirectoryA() +{ + dbgprintf("GetSystemDirectoryA() => 0x%x='%s'\n", sysdir, sysdir); + return sysdir; +} +*/ +static DWORD WINAPI expGetFullPathNameA +( + LPCTSTR lpFileName, + DWORD nBufferLength, + LPTSTR lpBuffer, + LPTSTR lpFilePart +){ + if(!lpFileName) return 0; + dbgprintf("GetFullPathNameA('%s',%d,%p,%p)\n",lpFileName,nBufferLength, + lpBuffer, lpFilePart); +#if 0 +#ifdef QTX + strcpy(lpFilePart, "Quick123.qts"); +#else + strcpy(lpFilePart, lpFileName); +#endif +#else + if (strrchr(lpFileName, '\\')) + lpFilePart = strrchr(lpFileName, '\\'); + else + lpFilePart = lpFileName; +#endif + strcpy(lpBuffer, lpFileName); +// strncpy(lpBuffer, lpFileName, rindex(lpFileName, '\\')-lpFileName); + return strlen(lpBuffer); +} + +static DWORD WINAPI expGetShortPathNameA +( + LPCSTR longpath, + LPSTR shortpath, + DWORD shortlen +){ + if(!longpath) return 0; + dbgprintf("GetShortPathNameA('%s',%p,%d)\n",longpath,shortpath,shortlen); + strcpy(shortpath,longpath); + return strlen(shortpath); +} + +static WIN_BOOL WINAPI expReadFile(HANDLE h,LPVOID pv,DWORD size,LPDWORD rd,LPOVERLAPPED unused) +{ + int result; + dbgprintf("ReadFile(%d, 0x%x, %d -> 0x%x)\n", h, pv, size, rd); + result=read(h, pv, size); + if(rd)*rd=result; + if(!result)return 0; + return 1; +} + +static WIN_BOOL WINAPI expWriteFile(HANDLE h,LPCVOID pv,DWORD size,LPDWORD wr,LPOVERLAPPED unused) +{ + int result; + dbgprintf("WriteFile(%d, 0x%x, %d -> 0x%x)\n", h, pv, size, wr); + if(h==1234)h=1; + result=write(h, pv, size); + if(wr)*wr=result; + if(!result)return 0; + return 1; +} +static DWORD WINAPI expSetFilePointer(HANDLE h, LONG val, LPLONG ext, DWORD whence) +{ + int wh; + dbgprintf("SetFilePointer(%d, 0x%x, 0x%x = %d, %d)\n", h, val, ext, *ext, whence); + //why would DLL want temporary file with >2Gb size? + switch(whence) + { + case FILE_BEGIN: + wh=SEEK_SET;break; + case FILE_END: + wh=SEEK_END;break; + case FILE_CURRENT: + wh=SEEK_CUR;break; + default: + return -1; + } +#ifdef QTX + if (val == 0 && ext != 0) + val = val&(*ext); +#endif + return lseek(h, val, wh); +} + +static HDRVR WINAPI expOpenDriverA(LPCSTR szDriverName, LPCSTR szSectionName, + LPARAM lParam2) +{ + dbgprintf("OpenDriverA(0x%x='%s', 0x%x='%s', 0x%x) => -1\n", szDriverName, szDriverName, szSectionName, szSectionName, lParam2); + return -1; +} +static HDRVR WINAPI expOpenDriver(LPCSTR szDriverName, LPCSTR szSectionName, + LPARAM lParam2) +{ + dbgprintf("OpenDriver(0x%x='%s', 0x%x='%s', 0x%x) => -1\n", szDriverName, szDriverName, szSectionName, szSectionName, lParam2); + return -1; +} + + +static WIN_BOOL WINAPI expGetProcessAffinityMask(HANDLE hProcess, + LPDWORD lpProcessAffinityMask, + LPDWORD lpSystemAffinityMask) +{ + dbgprintf("GetProcessAffinityMask(0x%x, 0x%x, 0x%x) => 1\n", + hProcess, lpProcessAffinityMask, lpSystemAffinityMask); + if(lpProcessAffinityMask)*lpProcessAffinityMask=1; + if(lpSystemAffinityMask)*lpSystemAffinityMask=1; + return 1; +} + +static int WINAPI expMulDiv(int nNumber, int nNumerator, int nDenominator) +{ + static const long long max_int=0x7FFFFFFFLL; + static const long long min_int=-0x80000000LL; + long long tmp=(long long)nNumber*(long long)nNumerator; + dbgprintf("expMulDiv %d * %d / %d\n", nNumber, nNumerator, nDenominator); + if(!nDenominator)return 1; + tmp/=nDenominator; + if(tmpmax_int) return 1; + return (int)tmp; +} + +static LONG WINAPI explstrcmpiA(const char* str1, const char* str2) +{ + LONG result=strcasecmp(str1, str2); + dbgprintf("strcmpi(0x%x='%s', 0x%x='%s') => %d\n", str1, str1, str2, str2, result); + return result; +} + +static LONG WINAPI explstrlenA(const char* str1) +{ + LONG result=strlen(str1); + dbgprintf("strlen(0x%x='%.50s') => %d\n", str1, str1, result); + return result; +} + +static LONG WINAPI explstrcpyA(char* str1, const char* str2) +{ + int result= (int) strcpy(str1, str2); + dbgprintf("strcpy(0x%.50x, 0x%.50x='%.50s') => %d\n", str1, str2, str2, result); + return result; +} +static LONG WINAPI explstrcpynA(char* str1, const char* str2,int len) +{ + int result; + if (strlen(str2)>len) + result = (int) strncpy(str1, str2,len); + else + result = (int) strcpy(str1,str2); + dbgprintf("strncpy(0x%x, 0x%x='%s' len %d strlen %d) => %x\n", str1, str2, str2,len, strlen(str2),result); + return result; +} +static LONG WINAPI explstrcatA(char* str1, const char* str2) +{ + int result= (int) strcat(str1, str2); + dbgprintf("strcat(0x%x, 0x%x='%s') => %d\n", str1, str2, str2, result); + return result; +} + + +static LONG WINAPI expInterlockedExchange(long *dest, long l) +{ + long retval = *dest; + *dest = l; + return retval; +} + +static void WINAPI expInitCommonControls(void) +{ + dbgprintf("InitCommonControls called!\n"); + return; +} + +#ifdef QTX +/* needed by QuickTime.qts */ +static HWND WINAPI expCreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy, + HWND parent, INT id, HINSTANCE inst, + HWND buddy, INT maxVal, INT minVal, INT curVal) +{ + dbgprintf("CreateUpDownControl(...)\n"); + return 0; +} +#endif + +/* alex: implement this call! needed for 3ivx */ +static HRESULT WINAPI expCoCreateFreeThreadedMarshaler(void *pUnkOuter, void **ppUnkInner) +{ + dbgprintf("CoCreateFreeThreadedMarshaler(%p, %p) called!\n", + pUnkOuter, ppUnkInner); +// return 0; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +static int WINAPI expDuplicateHandle(HANDLE hSourceProcessHandle, // handle to source process + HANDLE hSourceHandle, // handle to duplicate + HANDLE hTargetProcessHandle, // handle to target process + HANDLE* lpTargetHandle, // duplicate handle + DWORD dwDesiredAccess, // requested access + int bInheritHandle, // handle inheritance option + DWORD dwOptions // optional actions + ) +{ + dbgprintf("DuplicateHandle(%p, %p, %p, %p, 0x%x, %d, %d) called\n", + hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, + lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions); + *lpTargetHandle = hSourceHandle; + return 1; +} + +// required by PIM1 codec (used by win98 PCTV Studio capture sw) +static HRESULT WINAPI expCoInitialize( + LPVOID lpReserved /* [in] pointer to win32 malloc interface + (obsolete, should be NULL) */ + ) +{ + /* + * Just delegate to the newer method. + */ + return 0; //CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); +} + +static DWORD WINAPI expSetThreadAffinityMask +( + HANDLE hThread, + DWORD dwThreadAffinityMask +){ + return 0; +}; + +/* + * no WINAPI functions - CDECL + */ +static void* expmalloc(int size) +{ + //printf("malloc"); + // return malloc(size); + void* result=my_mreq(size,0); + dbgprintf("malloc(0x%x) => 0x%x\n", size,result); + if(result==0) + printf("WARNING: malloc() failed\n"); + return result; +} +static void expfree(void* mem) +{ + // return free(mem); + dbgprintf("free(%p)\n", mem); + my_release(mem); +} +/* needed by atrac3.acm */ +static void *expcalloc(int num, int size) +{ + void* result=my_mreq(num*size,1); + dbgprintf("calloc(%d,%d) => %p\n", num,size,result); + if(result==0) + printf("WARNING: calloc() failed\n"); + return result; +} +static void* expnew(int size) +{ + // printf("NEW:: Call from address %08x\n STACK DUMP:\n", *(-1+(int*)&size)); + // printf("%08x %08x %08x %08x\n", + // size, *(1+(int*)&size), + // *(2+(int*)&size),*(3+(int*)&size)); + void* result; + assert(size >= 0); + + result=my_mreq(size,0); + dbgprintf("new(%d) => %p\n", size, result); + if (result==0) + printf("WARNING: new() failed\n"); + return result; + +} +static int expdelete(void* memory) +{ + dbgprintf("delete(%p)\n", memory); + my_release(memory); + return 0; +} + +/* + * local definition - we need only the last two members at this point + * otherwice we would have to introduce here GUIDs and some more types.. + */ +typedef struct __attribute__((__packed__)) +{ + char hay[0x40]; + unsigned long cbFormat; //0x40 + char* pbFormat; //0x44 +} MY_MEDIA_TYPE; +static HRESULT WINAPI expMoCopyMediaType(MY_MEDIA_TYPE* dest, const MY_MEDIA_TYPE* src) +{ + if (!dest || !src) + return E_POINTER; + memcpy(dest, src, sizeof(MY_MEDIA_TYPE)); + if (dest->cbFormat) + { + dest->pbFormat = (char*) my_mreq(dest->cbFormat, 0); + if (!dest->pbFormat) + return E_OUTOFMEMORY; + memcpy(dest->pbFormat, src->pbFormat, dest->cbFormat); + } + return S_OK; +} +static HRESULT WINAPI expMoInitMediaType(MY_MEDIA_TYPE* dest, DWORD cbFormat) +{ + if (!dest) + return E_POINTER; + memset(dest, 0, sizeof(MY_MEDIA_TYPE)); + if (cbFormat) + { + dest->pbFormat = (char*) my_mreq(cbFormat, 0); + if (!dest->pbFormat) + return E_OUTOFMEMORY; + } + return S_OK; +} +static HRESULT WINAPI expMoCreateMediaType(MY_MEDIA_TYPE** dest, DWORD cbFormat) +{ + if (!dest) + return E_POINTER; + *dest = my_mreq(sizeof(MY_MEDIA_TYPE), 0); + return expMoInitMediaType(*dest, cbFormat); +} +static HRESULT WINAPI expMoDuplicateMediaType(MY_MEDIA_TYPE** dest, const void* src) +{ + if (!dest) + return E_POINTER; + *dest = my_mreq(sizeof(MY_MEDIA_TYPE), 0); + return expMoCopyMediaType(*dest, src); +} +static HRESULT WINAPI expMoFreeMediaType(MY_MEDIA_TYPE* dest) +{ + if (!dest) + return E_POINTER; + if (dest->pbFormat) + { + my_release(dest->pbFormat); + dest->pbFormat = 0; + dest->cbFormat = 0; + } + return S_OK; +} +static HRESULT WINAPI expMoDeleteMediaType(MY_MEDIA_TYPE* dest) +{ + if (!dest) + return E_POINTER; + expMoFreeMediaType(dest); + my_release(dest); + return S_OK; +} + + +#if 0 +static int exp_initterm(int v1, int v2) +{ + dbgprintf("_initterm(0x%x, 0x%x) => 0\n", v1, v2); + return 0; +} +#else +/* merged from wine - 2002.04.21 */ +typedef void (*_INITTERMFUNC)(); +static int exp_initterm(_INITTERMFUNC *start, _INITTERMFUNC *end) +{ + dbgprintf("_initterm(0x%x, 0x%x) %p\n", start, end, *start); + while (start < end) + { + if (*start) + { + //printf("call _initfunc: from: %p %d\n", *start); + // ok this trick with push/pop is necessary as otherwice + // edi/esi registers are being trashed + void* p = *start; + __asm__ __volatile__ + ( + "pushl %%ebx \n\t" + "pushl %%ecx \n\t" + "pushl %%edx \n\t" + "pushl %%edi \n\t" + "pushl %%esi \n\t" + "call *%%eax \n\t" + "popl %%esi \n\t" + "popl %%edi \n\t" + "popl %%edx \n\t" + "popl %%ecx \n\t" + "popl %%ebx \n\t" + : + : "a"(p) + : "memory" + ); + //printf("done %p %d:%d\n", end); + } + start++; + } + return 0; +} +#endif + +static void* exp__dllonexit() +{ + // FIXME extract from WINE + return NULL; +} + +static int expwsprintfA(char* string, char* format, ...) +{ + va_list va; + int result; + va_start(va, format); + result = vsprintf(string, format, va); + dbgprintf("wsprintfA(0x%x, '%s', ...) => %d\n", string, format, result); + va_end(va); + return result; +} + +static int expsprintf(char* str, const char* format, ...) +{ + va_list args; + int r; + dbgprintf("sprintf(%s, %s)\n", str, format); + va_start(args, format); + r = vsprintf(str, format, args); + va_end(args); + return r; +} +static int expsscanf(const char* str, const char* format, ...) +{ + va_list args; + int r; + dbgprintf("sscanf(%s, %s)\n", str, format); + va_start(args, format); + r = vsscanf(str, format, args); + va_end(args); + return r; +} +static void* expfopen(const char* path, const char* mode) +{ + printf("fopen: \"%s\" mode:%s\n", path, mode); + //return fopen(path, mode); + return fdopen(0, mode); // everything on screen +} +static int expfprintf(void* stream, const char* format, ...) +{ + va_list args; + int r = 0; + dbgprintf("fprintf(%p, %s, ...)\n", stream, format); +#if 1 + va_start(args, format); + r = vfprintf((FILE*) stream, format, args); + va_end(args); +#endif + return r; +} + +static int expprintf(const char* format, ...) +{ + va_list args; + int r; + dbgprintf("printf(%s, ...)\n", format); + va_start(args, format); + r = vprintf(format, args); + va_end(args); + return r; +} + +static char* expgetenv(const char* varname) +{ + char* v = getenv(varname); + dbgprintf("getenv(%s) => %s\n", varname, v); + return v; +} + +static void* expwcscpy(WCHAR* dst, const WCHAR* src) +{ + WCHAR* p = dst; + while ((*p++ = *src++)) + ; + return dst; +} + +static char* expstrrchr(char* string, int value) +{ + char* result=strrchr(string, value); + if(result) + dbgprintf("strrchr(0x%x='%s', %d) => 0x%x='%s'", string, string, value, result, result); + else + dbgprintf("strrchr(0x%x='%s', %d) => 0", string, string, value); + return result; +} + +static char* expstrchr(char* string, int value) +{ + char* result=strchr(string, value); + if(result) + dbgprintf("strchr(0x%x='%s', %d) => 0x%x='%s'", string, string, value, result, result); + else + dbgprintf("strchr(0x%x='%s', %d) => 0", string, string, value); + return result; +} +static int expstrlen(char* str) +{ + int result=strlen(str); + dbgprintf("strlen(0x%x='%s') => %d\n", str, str, result); + return result; +} +static char* expstrcpy(char* str1, const char* str2) +{ + char* result= strcpy(str1, str2); + dbgprintf("strcpy(0x%x, 0x%x='%s') => %p\n", str1, str2, str2, result); + return result; +} +static char* expstrncpy(char* str1, const char* str2, size_t count) +{ + char* result= strncpy(str1, str2, count); + dbgprintf("strncpy(0x%x, 0x%x='%s', %d) => %p\n", str1, str2, str2, count, result); + return result; +} +static int expstrcmp(const char* str1, const char* str2) +{ + int result=strcmp(str1, str2); + dbgprintf("strcmp(0x%x='%s', 0x%x='%s') => %d\n", str1, str1, str2, str2, result); + return result; +} +static int expstrncmp(const char* str1, const char* str2,int x) +{ + int result=strncmp(str1, str2,x); + dbgprintf("strcmp(0x%x='%s', 0x%x='%s') => %d\n", str1, str1, str2, str2, result); + return result; +} +static char* expstrcat(char* str1, const char* str2) +{ + char* result = strcat(str1, str2); + dbgprintf("strcat(0x%x='%s', 0x%x='%s') => %p\n", str1, str1, str2, str2, result); + return result; +} +static char* exp_strdup(const char* str1) +{ + int l = strlen(str1); + char* result = (char*) my_mreq(l + 1,0); + if (result) + strcpy(result, str1); + dbgprintf("_strdup(0x%x='%s') => %p\n", str1, str1, result); + return result; +} +static int expisalnum(int c) +{ + int result= (int) isalnum(c); + dbgprintf("isalnum(0x%x='%c' => %d\n", c, c, result); + return result; +} +static int expisspace(int c) +{ + int result= (int) isspace(c); + dbgprintf("isspace(0x%x='%c' => %d\n", c, c, result); + return result; +} +static int expisalpha(int c) +{ + int result= (int) isalpha(c); + dbgprintf("isalpha(0x%x='%c' => %d\n", c, c, result); + return result; +} +static int expisdigit(int c) +{ + int result= (int) isdigit(c); + dbgprintf("isdigit(0x%x='%c' => %d\n", c, c, result); + return result; +} +static void* expmemmove(void* dest, void* src, int n) +{ + void* result = memmove(dest, src, n); + dbgprintf("memmove(0x%x, 0x%x, %d) => %p\n", dest, src, n, result); + return result; +} +static int expmemcmp(void* dest, void* src, int n) +{ + int result = memcmp(dest, src, n); + dbgprintf("memcmp(0x%x, 0x%x, %d) => %d\n", dest, src, n, result); + return result; +} +static void* expmemcpy(void* dest, void* src, int n) +{ + void *result = memcpy(dest, src, n); + dbgprintf("memcpy(0x%x, 0x%x, %d) => %p\n", dest, src, n, result); + return result; +} +static void* expmemset(void* dest, int c, size_t n) +{ + void *result = memset(dest, c, n); + dbgprintf("memset(0x%x, %d, %d) => %p\n", dest, c, n, result); + return result; +} +static time_t exptime(time_t* t) +{ + time_t result = time(t); + dbgprintf("time(0x%x) => %d\n", t, result); + return result; +} + +static int exprand(void) +{ + return rand(); +} + +static void expsrand(int seed) +{ + srand(seed); +} + +#if 1 + +// prefered compilation with -O2 -ffast-math ! + +static double explog10(double x) +{ + /*printf("Log10 %f => %f 0x%Lx\n", x, log10(x), *((int64_t*)&x));*/ + return log10(x); +} + +static double expcos(double x) +{ + /*printf("Cos %f => %f 0x%Lx\n", x, cos(x), *((int64_t*)&x));*/ + return cos(x); +} + +/* doens't work */ +static long exp_ftol_wrong(double x) +{ + return (long) x; +} + +#else + +static void explog10(void) +{ + __asm__ __volatile__ + ( + "fldl 8(%esp) \n\t" + "fldln2 \n\t" + "fxch %st(1) \n\t" + "fyl2x \n\t" + ); +} + +static void expcos(void) +{ + __asm__ __volatile__ + ( + "fldl 8(%esp) \n\t" + "fcos \n\t" + ); +} + +#endif + +// this seem to be the only how to make this function working properly +// ok - I've spent tremendous amount of time (many many many hours +// of debuging fixing & testing - it's almost unimaginable - kabi + +// _ftol - operated on the float value which is already on the FPU stack + +static void exp_ftol(void) +{ + __asm__ __volatile__ + ( + "sub $12, %esp \n\t" + "fstcw -2(%ebp) \n\t" + "wait \n\t" + "movw -2(%ebp), %ax \n\t" + "orb $0x0C, %ah \n\t" + "movw %ax, -4(%ebp) \n\t" + "fldcw -4(%ebp) \n\t" + "fistpl -12(%ebp) \n\t" + "fldcw -2(%ebp) \n\t" + "movl -12(%ebp), %eax \n\t" + //Note: gcc 3.03 does not do the following op if it + // knows that ebp=esp + "movl %ebp, %esp \n\t" + ); +} + +#warning check for _CIpow +static double exp_CIpow(double x, double y) +{ + /*printf("Pow %f %f 0x%Lx 0x%Lx => %f\n", x, y, *((int64_t*)&x), *((int64_t*)&y), pow(x, y));*/ + return pow(x, y); +} + +static double exppow(double x, double y) +{ + /*printf("Pow %f %f 0x%Lx 0x%Lx => %f\n", x, y, *((int64_t*)&x), *((int64_t*)&y), pow(x, y));*/ + return pow(x, y); +} + +static double expldexp(double x, int expo) +{ + /*printf("Cos %f => %f 0x%Lx\n", x, cos(x), *((int64_t*)&x));*/ + return ldexp(x, expo); +} + +static double expfrexp(double x, int* expo) +{ + /*printf("Cos %f => %f 0x%Lx\n", x, cos(x), *((int64_t*)&x));*/ + return frexp(x, expo); +} + + + +static int exp_stricmp(const char* s1, const char* s2) +{ + return strcasecmp(s1, s2); +} + +/* from declaration taken from Wine sources - this fountion seems to be + * undocumented in any M$ doc */ +static int exp_setjmp3(void* jmpbuf, int x) +{ + //dbgprintf("!!!!UNIMPLEMENTED: setjmp3(%p, %d) => 0\n", jmpbuf, x); + //return 0; + __asm__ __volatile__ + ( + //"mov 4(%%esp), %%edx \n\t" + "mov (%%esp), %%eax \n\t" + "mov %%eax, (%%edx) \n\t" // store ebp + + //"mov %%ebp, (%%edx) \n\t" + "mov %%ebx, 4(%%edx) \n\t" + "mov %%edi, 8(%%edx) \n\t" + "mov %%esi, 12(%%edx) \n\t" + "mov %%esp, 16(%%edx) \n\t" + + "mov 4(%%esp), %%eax \n\t" + "mov %%eax, 20(%%edx) \n\t" + + "movl $0x56433230, 32(%%edx) \n\t" // VC20 ?? + "movl $0, 36(%%edx) \n\t" + : // output + : "d"(jmpbuf) // input + : "eax" + ); +#if 1 + __asm__ __volatile__ + ( + "mov %%fs:0, %%eax \n\t" // unsure + "mov %%eax, 24(%%edx) \n\t" + "cmp $0xffffffff, %%eax \n\t" + "jnz l1 \n\t" + "mov %%eax, 28(%%edx) \n\t" + "l1: \n\t" + : + : + : "eax" + ); +#endif + + return 0; +} + +static DWORD WINAPI expGetCurrentProcessId(void) +{ + dbgprintf("GetCurrentProcessId(void) => %d\n", getpid()); + return getpid(); //(DWORD)NtCurrentTeb()->pid; +} + + +typedef struct { + UINT wPeriodMin; + UINT wPeriodMax; +} TIMECAPS, *LPTIMECAPS; + +static MMRESULT WINAPI exptimeGetDevCaps(LPTIMECAPS lpCaps, UINT wSize) +{ + dbgprintf("timeGetDevCaps(%p, %u) !\n", lpCaps, wSize); + + lpCaps->wPeriodMin = 1; + lpCaps->wPeriodMax = 65535; + return 0; +} + +static MMRESULT WINAPI exptimeBeginPeriod(UINT wPeriod) +{ + dbgprintf("timeBeginPeriod(%u) !\n", wPeriod); + + if (wPeriod < 1 || wPeriod > 65535) return 96+1; //TIMERR_NOCANDO; + return 0; +} + +#ifdef QTX +static MMRESULT WINAPI exptimeEndPeriod(UINT wPeriod) +{ + dbgprintf("timeEndPeriod(%u) !\n", wPeriod); + + if (wPeriod < 1 || wPeriod > 65535) return 96+1; //TIMERR_NOCANDO; + return 0; +} +#endif + +static void WINAPI expGlobalMemoryStatus( + LPMEMORYSTATUS lpmem +) { + static MEMORYSTATUS cached_memstatus; + static int cache_lastchecked = 0; + SYSTEM_INFO si; + FILE *f; + + if (time(NULL)==cache_lastchecked) { + memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS)); + return; + } + +#if 1 + f = fopen( "/proc/meminfo", "r" ); + if (f) + { + char buffer[256]; + int total, used, free, shared, buffers, cached; + + lpmem->dwLength = sizeof(MEMORYSTATUS); + lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0; + lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0; + while (fgets( buffer, sizeof(buffer), f )) + { + /* old style /proc/meminfo ... */ + if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached )) + { + lpmem->dwTotalPhys += total; + lpmem->dwAvailPhys += free + buffers + cached; + } + if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free )) + { + lpmem->dwTotalPageFile += total; + lpmem->dwAvailPageFile += free; + } + + /* new style /proc/meminfo ... */ + if (sscanf(buffer, "MemTotal: %d", &total)) + lpmem->dwTotalPhys = total*1024; + if (sscanf(buffer, "MemFree: %d", &free)) + lpmem->dwAvailPhys = free*1024; + if (sscanf(buffer, "SwapTotal: %d", &total)) + lpmem->dwTotalPageFile = total*1024; + if (sscanf(buffer, "SwapFree: %d", &free)) + lpmem->dwAvailPageFile = free*1024; + if (sscanf(buffer, "Buffers: %d", &buffers)) + lpmem->dwAvailPhys += buffers*1024; + if (sscanf(buffer, "Cached: %d", &cached)) + lpmem->dwAvailPhys += cached*1024; + } + fclose( f ); + + if (lpmem->dwTotalPhys) + { + DWORD TotalPhysical = lpmem->dwTotalPhys+lpmem->dwTotalPageFile; + DWORD AvailPhysical = lpmem->dwAvailPhys+lpmem->dwAvailPageFile; + lpmem->dwMemoryLoad = (TotalPhysical-AvailPhysical) + / (TotalPhysical / 100); + } + } else +#endif + { + /* FIXME: should do something for other systems */ + lpmem->dwMemoryLoad = 0; + lpmem->dwTotalPhys = 16*1024*1024; + lpmem->dwAvailPhys = 16*1024*1024; + lpmem->dwTotalPageFile = 16*1024*1024; + lpmem->dwAvailPageFile = 16*1024*1024; + } + expGetSystemInfo(&si); + lpmem->dwTotalVirtual = si.lpMaximumApplicationAddress-si.lpMinimumApplicationAddress; + /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */ + lpmem->dwAvailVirtual = lpmem->dwTotalVirtual-64*1024; + memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS)); + cache_lastchecked = time(NULL); + + /* it appears some memory display programs want to divide by these values */ + if(lpmem->dwTotalPageFile==0) + lpmem->dwTotalPageFile++; + + if(lpmem->dwAvailPageFile==0) + lpmem->dwAvailPageFile++; +} + +/********************************************************************** + * SetThreadPriority [KERNEL32.@] Sets priority for thread. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +static WIN_BOOL WINAPI expSetThreadPriority( + HANDLE hthread, /* [in] Handle to thread */ + INT priority) /* [in] Thread priority level */ +{ + dbgprintf("SetThreadPriority(%p,%d)\n",hthread,priority); + return TRUE; +} + +static void WINAPI expExitProcess( DWORD status ) +{ + printf("EXIT - code %ld\n",status); + exit(status); +} + +static INT WINAPI expMessageBoxA(HWND hWnd, LPCSTR text, LPCSTR title, UINT type){ + printf("MSGBOX '%s' '%s' (%d)\n",text,title,type); +#ifdef QTX + if (type == MB_ICONHAND && !strlen(text) && !strlen(title)) + return IDIGNORE; +#endif + return IDOK; +} + +/* these are needed for mss1 */ + +/* defined in stubs.s */ +void exp_EH_prolog(void); + +#include +static WINAPI inline unsigned long int exphtonl(unsigned long int hostlong) +{ +// dbgprintf("htonl(%x) => %x\n", hostlong, htonl(hostlong)); + return htonl(hostlong); +} + +static WINAPI inline unsigned long int expntohl(unsigned long int netlong) +{ +// dbgprintf("ntohl(%x) => %x\n", netlong, ntohl(netlong)); + return ntohl(netlong); +} +static void WINAPI expVariantInit(void* p) +{ + printf("InitCommonControls called!\n"); + return; +} + +int expRegisterClassA(const void/*WNDCLASSA*/ *wc) +{ + dbgprintf("RegisterClassA(%p) => random id\n", wc); + return time(NULL); /* be precise ! */ +} + +int expUnregisterClassA(const char *className, HINSTANCE hInstance) +{ + dbgprintf("UnregisterClassA(%s, %p) => 0\n", className, hInstance); + return 0; +} + +#ifdef QTX +/* should be fixed bcs it's not fully strlen equivalent */ +static int expSysStringByteLen(void *str) +{ + dbgprintf("SysStringByteLen(%p) => %d\n", str, strlen(str)); + return strlen(str); +} + +static int expDirectDrawCreate(void) +{ + dbgprintf("DirectDrawCreate(...) => NULL\n"); + return 0; +} + +#if 1 +typedef struct tagPALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; +} PALETTEENTRY; + +/* reversed the first 2 entries */ +typedef struct tagLOGPALETTE { + WORD palNumEntries; + WORD palVersion; + PALETTEENTRY palPalEntry[1]; +} LOGPALETTE; + +static HPALETTE WINAPI expCreatePalette(CONST LOGPALETTE *lpgpl) +{ + HPALETTE test; + int i; + + dbgprintf("CreatePalette(%x) => NULL\n", lpgpl); + + i = sizeof(LOGPALETTE)+((lpgpl->palNumEntries-1)*sizeof(PALETTEENTRY)); + test = (HPALETTE)malloc(i); + memcpy((void *)test, lpgpl, i); + + return test; +} +#else +static int expCreatePalette(void) +{ + dbgprintf("CreatePalette(...) => NULL\n"); + return NULL; +} +#endif + +static int WINAPI expGetClientRect(HWND win, RECT *r) +{ + dbgprintf("GetClientRect(0x%x, 0x%x) => 1\n", win, r); + r->right = PSEUDO_SCREEN_WIDTH; + r->left = 0; + r->bottom = PSEUDO_SCREEN_HEIGHT; + r->top = 0; + return 1; +} + +#if 0 +typedef struct tagPOINT { + LONG x; + LONG y; +} POINT, *PPOINT; +#endif + +static int WINAPI expClientToScreen(HWND win, POINT *p) +{ + dbgprintf("ClientToScreen(0x%x, 0x%x = %d,%d) => 1\n", win, p, p->x, p->y); + p->x = 0; + p->y = 0; + return 1; +} +#endif + +/* for m3jpeg */ +static int WINAPI expSetThreadIdealProcessor(HANDLE thread, int proc) +{ + dbgprintf("SetThreadIdealProcessor(0x%x, %x) => 0\n", thread, proc); + return 0; +} + +static int WINAPI expMessageBeep(int type) +{ + dbgprintf("MessageBeep(%d) => 1\n", type); + return 1; +} + +static int WINAPI expDialogBoxParamA(void *inst, const char *name, + HWND parent, void *dialog_func, void *init_param) +{ + dbgprintf("DialogBoxParamA(0x%x, 0x%x = %s, 0x%x, 0x%x, 0x%x) => 0x42424242\n", + inst, name, name, parent, dialog_func, init_param); + return 0x42424242; +} + +/* needed by imagepower mjpeg2k */ +static void *exprealloc(void *ptr, size_t size) +{ + dbgprintf("realloc(0x%x, %x)\n", ptr, size); + if (!ptr) + return my_mreq(size,0); + else + return my_realloc(ptr, size); +} + +struct exports +{ + char name[64]; + int id; + void* func; +}; +struct libs +{ + char name[64]; + int length; + struct exports* exps; +}; + +#define FF(X,Y) \ + {#X, Y, (void*)exp##X}, + +struct exports exp_kernel32[]= +{ + FF(IsBadWritePtr, 357) + FF(IsBadReadPtr, 354) + FF(IsBadStringPtrW, -1) + FF(IsBadStringPtrA, -1) + FF(DisableThreadLibraryCalls, -1) + FF(CreateThread, -1) + FF(CreateEventA, -1) + FF(SetEvent, -1) + FF(ResetEvent, -1) + FF(WaitForSingleObject, -1) +#ifdef QTX + FF(WaitForMultipleObjects, -1) + FF(ExitThread, -1) + FF(CreateMutexA,-1) + FF(ReleaseMutex,-1) +#endif + FF(GetSystemInfo, -1) + FF(GetVersion, 332) + FF(HeapCreate, 461) + FF(HeapAlloc, -1) + FF(HeapDestroy, -1) + FF(HeapFree, -1) + FF(HeapSize, -1) + FF(HeapReAlloc,-1) + FF(GetProcessHeap, -1) + FF(VirtualAlloc, -1) + FF(VirtualFree, -1) + FF(InitializeCriticalSection, -1) + FF(EnterCriticalSection, -1) + FF(LeaveCriticalSection, -1) + FF(DeleteCriticalSection, -1) + FF(TlsAlloc, -1) + FF(TlsFree, -1) + FF(TlsGetValue, -1) + FF(TlsSetValue, -1) + FF(GetCurrentThreadId, -1) + FF(GetCurrentProcess, -1) + FF(LocalAlloc, -1) + FF(LocalReAlloc,-1) + FF(LocalLock, -1) + FF(GlobalAlloc, -1) + FF(GlobalReAlloc, -1) + FF(GlobalLock, -1) + FF(GlobalSize, -1) + FF(MultiByteToWideChar, 427) + FF(WideCharToMultiByte, -1) + FF(GetVersionExA, -1) + FF(CreateSemaphoreA, -1) + FF(QueryPerformanceCounter, -1) + FF(QueryPerformanceFrequency, -1) + FF(LocalHandle, -1) + FF(LocalUnlock, -1) + FF(LocalFree, -1) + FF(GlobalHandle, -1) + FF(GlobalUnlock, -1) + FF(GlobalFree, -1) + FF(LoadResource, -1) + FF(ReleaseSemaphore, -1) + FF(FindResourceA, -1) + FF(LockResource, -1) + FF(FreeResource, -1) + FF(SizeofResource, -1) + FF(CloseHandle, -1) + FF(GetCommandLineA, -1) + FF(GetEnvironmentStringsW, -1) + FF(FreeEnvironmentStringsW, -1) + FF(FreeEnvironmentStringsA, -1) + FF(GetEnvironmentStrings, -1) + FF(GetStartupInfoA, -1) + FF(GetStdHandle, -1) + FF(GetFileType, -1) +#ifdef QTX + FF(GetFileAttributesA, -1) +#endif + FF(SetHandleCount, -1) + FF(GetACP, -1) + FF(GetModuleFileNameA, -1) + FF(SetUnhandledExceptionFilter, -1) + FF(LoadLibraryA, -1) + FF(GetProcAddress, -1) + FF(FreeLibrary, -1) + FF(CreateFileMappingA, -1) + FF(OpenFileMappingA, -1) + FF(MapViewOfFile, -1) + FF(UnmapViewOfFile, -1) + FF(Sleep, -1) + FF(GetModuleHandleA, -1) + FF(GetProfileIntA, -1) + FF(GetPrivateProfileIntA, -1) + FF(GetPrivateProfileStringA, -1) + FF(WritePrivateProfileStringA, -1) + FF(GetLastError, -1) + FF(SetLastError, -1) + FF(InterlockedIncrement, -1) + FF(InterlockedDecrement, -1) + FF(GetTimeZoneInformation, -1) + FF(OutputDebugStringA, -1) + FF(GetLocalTime, -1) + FF(GetSystemTime, -1) + FF(GetSystemTimeAsFileTime, -1) + FF(GetEnvironmentVariableA, -1) + FF(SetEnvironmentVariableA, -1) + FF(RtlZeroMemory,-1) + FF(RtlMoveMemory,-1) + FF(RtlFillMemory,-1) + FF(GetTempPathA,-1) + FF(FindFirstFileA,-1) + FF(FindNextFileA,-1) + FF(FindClose,-1) + FF(FileTimeToLocalFileTime,-1) + FF(DeleteFileA,-1) + FF(ReadFile,-1) + FF(WriteFile,-1) + FF(SetFilePointer,-1) + FF(GetTempFileNameA,-1) + FF(CreateFileA,-1) + FF(GetSystemDirectoryA,-1) + FF(GetWindowsDirectoryA,-1) +#ifdef QTX + FF(GetCurrentDirectoryA,-1) + FF(SetCurrentDirectoryA,-1) + FF(CreateDirectoryA,-1) +#endif + FF(GetShortPathNameA,-1) + FF(GetFullPathNameA,-1) + FF(SetErrorMode, -1) + FF(IsProcessorFeaturePresent, -1) + FF(GetProcessAffinityMask, -1) + FF(InterlockedExchange, -1) + FF(InterlockedCompareExchange, -1) + FF(MulDiv, -1) + FF(lstrcmpiA, -1) + FF(lstrlenA, -1) + FF(lstrcpyA, -1) + FF(lstrcatA, -1) + FF(lstrcpynA,-1) + FF(GetProcessVersion,-1) + FF(GetCurrentThread,-1) + FF(GetOEMCP,-1) + FF(GetCPInfo,-1) + FF(DuplicateHandle,-1) + FF(GetTickCount, -1) + FF(SetThreadAffinityMask,-1) + FF(GetCurrentProcessId,-1) + FF(GlobalMemoryStatus,-1) + FF(SetThreadPriority,-1) + FF(ExitProcess,-1) + {"LoadLibraryExA", -1, (void*)&LoadLibraryExA}, + FF(SetThreadIdealProcessor,-1) +}; + +struct exports exp_msvcrt[]={ + FF(malloc, -1) + FF(_initterm, -1) + FF(__dllonexit, -1) + FF(free, -1) + {"??3@YAXPAX@Z", -1, expdelete}, + {"??2@YAPAXI@Z", -1, expnew}, + {"_adjust_fdiv", -1, (void*)&_adjust_fdiv}, + FF(strrchr, -1) + FF(strchr, -1) + FF(strlen, -1) + FF(strcpy, -1) + FF(strncpy, -1) + FF(wcscpy, -1) + FF(strcmp, -1) + FF(strncmp, -1) + FF(strcat, -1) + FF(_stricmp,-1) + FF(_strdup,-1) + FF(_setjmp3,-1) + FF(isalnum, -1) + FF(isspace, -1) + FF(isalpha, -1) + FF(isdigit, -1) + FF(memmove, -1) + FF(memcmp, -1) + FF(memset, -1) + FF(memcpy, -1) + FF(time, -1) + FF(rand, -1) + FF(srand, -1) + FF(log10, -1) + FF(pow, -1) + FF(cos, -1) + FF(_ftol,-1) + FF(_CIpow,-1) + FF(ldexp,-1) + FF(frexp,-1) + FF(sprintf,-1) + FF(sscanf,-1) + FF(fopen,-1) + FF(fprintf,-1) + FF(printf,-1) + FF(getenv,-1) +#ifdef MPLAYER + FF(_EH_prolog,-1) +#endif + FF(calloc,-1) + {"ceil",-1,(void*)&ceil}, +/* needed by imagepower mjpeg2k */ + {"clock",-1,(void*)&clock}, + {"memchr",-1,(void*)&memchr}, + {"vfprintf",-1,(void*)&vfprintf}, +// {"realloc",-1,(void*)&realloc}, + FF(realloc,-1) + {"puts",-1,(void*)&puts} +}; +struct exports exp_winmm[]={ + FF(GetDriverModuleHandle, -1) + FF(timeGetTime, -1) + FF(DefDriverProc, -1) + FF(OpenDriverA, -1) + FF(OpenDriver, -1) + FF(timeGetDevCaps, -1) + FF(timeBeginPeriod, -1) +#ifdef QTX + FF(timeEndPeriod, -1) + FF(waveOutGetNumDevs, -1) +#endif +}; +struct exports exp_user32[]={ + FF(LoadStringA, -1) + FF(wsprintfA, -1) + FF(GetDC, -1) + FF(GetDesktopWindow, -1) + FF(ReleaseDC, -1) + FF(IsRectEmpty, -1) + FF(LoadCursorA,-1) + FF(SetCursor,-1) + FF(GetCursorPos,-1) +#ifdef QTX + FF(ShowCursor,-1) +#endif + FF(RegisterWindowMessageA,-1) + FF(GetSystemMetrics,-1) + FF(GetSysColor,-1) + FF(GetSysColorBrush,-1) + FF(GetWindowDC, -1) + FF(DrawTextA, -1) + FF(MessageBoxA, -1) + FF(RegisterClassA, -1) + FF(UnregisterClassA, -1) +#ifdef QTX + FF(GetWindowRect, -1) + FF(MonitorFromWindow, -1) + FF(MonitorFromRect, -1) + FF(MonitorFromPoint, -1) + FF(EnumDisplayMonitors, -1) + FF(GetMonitorInfoA, -1) + FF(EnumDisplayDevicesA, -1) + FF(GetClientRect, -1) + FF(ClientToScreen, -1) + FF(IsWindowVisible, -1) + FF(GetActiveWindow, -1) + FF(GetClassNameA, -1) + FF(GetClassInfoA, -1) + FF(GetWindowLongA, -1) + FF(EnumWindows, -1) + FF(GetWindowThreadProcessId, -1) + FF(CreateWindowExA, -1) +#endif + FF(MessageBeep, -1) + FF(DialogBoxParamA, -1) +}; +struct exports exp_advapi32[]={ + FF(RegCloseKey, -1) + FF(RegCreateKeyExA, -1) + FF(RegEnumKeyExA, -1) + FF(RegEnumValueA, -1) + FF(RegOpenKeyA, -1) + FF(RegOpenKeyExA, -1) + FF(RegQueryValueExA, -1) + FF(RegSetValueExA, -1) +}; +struct exports exp_gdi32[]={ + FF(CreateCompatibleDC, -1) + FF(CreateFontA, -1) + FF(DeleteDC, -1) + FF(DeleteObject, -1) + FF(GetDeviceCaps, -1) + FF(GetSystemPaletteEntries, -1) +#ifdef QTX + FF(CreatePalette, -1) + FF(GetObjectA, -1) + FF(CreateRectRgn, -1) +#endif +}; +struct exports exp_version[]={ + FF(GetFileVersionInfoSizeA, -1) +}; +struct exports exp_ole32[]={ + FF(CoCreateFreeThreadedMarshaler,-1) + FF(CoCreateInstance, -1) + FF(CoInitialize, -1) + FF(CoTaskMemAlloc, -1) + FF(CoTaskMemFree, -1) + FF(StringFromGUID2, -1) +}; +// do we really need crtdll ??? +// msvcrt is the correct place probably... +struct exports exp_crtdll[]={ + FF(memcpy, -1) + FF(wcscpy, -1) +}; +struct exports exp_comctl32[]={ + FF(StringFromGUID2, -1) + FF(InitCommonControls, 17) +#ifdef QTX + FF(CreateUpDownControl, 16) +#endif +}; +struct exports exp_wsock32[]={ + FF(htonl,8) + FF(ntohl,14) +}; +struct exports exp_msdmo[]={ + FF(memcpy, -1) // just test + FF(MoCopyMediaType, -1) + FF(MoCreateMediaType, -1) + FF(MoDeleteMediaType, -1) + FF(MoDuplicateMediaType, -1) + FF(MoFreeMediaType, -1) + FF(MoInitMediaType, -1) +}; +struct exports exp_oleaut32[]={ + FF(VariantInit, 8) +#ifdef QTX + FF(SysStringByteLen, 149) +#endif +}; + +/* realplayer8: + DLL Name: PNCRT.dll + vma: Hint/Ord Member-Name + 22ff4 615 free + 2302e 250 _ftol + 22fea 666 malloc + 2303e 609 fprintf + 2305e 167 _adjust_fdiv + 23052 280 _initterm + + 22ffc 176 _beginthreadex + 23036 284 _iob + 2300e 85 __CxxFrameHandler + 23022 411 _purecall +*/ +#ifdef REALPLAYER +struct exports exp_pncrt[]={ + FF(malloc, -1) // just test + FF(free, -1) // just test + FF(fprintf, -1) // just test + {"_adjust_fdiv", -1, (void*)&_adjust_fdiv}, + FF(_ftol,-1) + FF(_initterm, -1) + {"??3@YAXPAX@Z", -1, expdelete}, + {"??2@YAPAXI@Z", -1, expnew}, + FF(__dllonexit, -1) + FF(strncpy, -1) + FF(_CIpow,-1) + FF(calloc,-1) + FF(memmove, -1) +}; +#endif + +#ifdef QTX +struct exports exp_ddraw[]={ + FF(DirectDrawCreate, -1) +}; +#endif + +#define LL(X) \ + {#X".dll", sizeof(exp_##X)/sizeof(struct exports), exp_##X}, + +struct libs libraries[]={ + LL(kernel32) + LL(msvcrt) + LL(winmm) + LL(user32) + LL(advapi32) + LL(gdi32) + LL(version) + LL(ole32) + LL(oleaut32) + LL(crtdll) + LL(comctl32) + LL(wsock32) + LL(msdmo) +#ifdef REALPLAYER + LL(pncrt) +#endif +#ifdef QTX + LL(ddraw) +#endif +}; + +static void ext_stubs(void) +{ + // expects: + // ax position index + // cx address of printf function +#if 1 + __asm__ __volatile__ + ( + "push %%edx \n\t" + "movl $0xdeadbeef, %%eax \n\t" + "movl $0xdeadbeef, %%edx \n\t" + "shl $5, %%eax \n\t" // ax * 32 + "addl $0xdeadbeef, %%eax \n\t" // overwrite export_names + "pushl %%eax \n\t" + "pushl $0xdeadbeef \n\t" // overwrite called_unk + "call *%%edx \n\t" // printf (via dx) + "addl $8, %%esp \n\t" + "xorl %%eax, %%eax \n\t" + "pop %%edx \n\t" + : + : + : "eax" + ); +#else + __asm__ __volatile__ + ( + "push %%edx \n\t" + "movl $0, %%eax \n\t" + "movl $0, %%edx \n\t" + "shl $5, %%eax \n\t" // ax * 32 + "addl %0, %%eax \n\t" + "pushl %%eax \n\t" + "pushl %1 \n\t" + "call *%%edx \n\t" // printf (via dx) + "addl $8, %%esp \n\t" + "xorl %%eax, %%eax \n\t" + "pop %%edx \n\t" + ::"m"(*export_names), "m"(*called_unk) + : "memory", "edx", "eax" + ); +#endif + +} + +//static void add_stub(int pos) + +extern int unk_exp1; +static int pos=0; +static char extcode[20000];// place for 200 unresolved exports +static const char* called_unk = "Called unk_%s\n"; + +static void* add_stub(void) +{ + // generated code in runtime! + char* answ = (char*)extcode+pos*0x30; +#if 0 + memcpy(answ, &unk_exp1, 0x64); + *(int*)(answ+9)=pos; + *(int*)(answ+47)-=((int)answ-(int)&unk_exp1); +#endif + memcpy(answ, ext_stubs, 0x2f); // 0x2c is current size + //answ[4] = 0xb8; // movl $0, eax (0xb8 0x00000000) + *((int*) (answ + 5)) = pos; + //answ[9] = 0xba; // movl $0, edx (0xba 0x00000000) + *((long*) (answ + 10)) = (long)printf; + //answ[17] = 0x05; // addl $0, eax (0x05 0x00000000) + *((long*) (answ + 18)) = (long)export_names; + //answ[23] = 0x68; // pushl $0 (0x68 0x00000000) + *((long*) (answ + 24)) = (long)called_unk; + pos++; + return (void*)answ; +} + +void* LookupExternal(const char* library, int ordinal) +{ + int i,j; + if(library==0) + { + printf("ERROR: library=0\n"); + return (void*)ext_unknown; + } + // printf("%x %x\n", &unk_exp1, &unk_exp2); + + printf("External func %s:%d\n", library, ordinal); + + for(i=0; i150)return 0; + sprintf(export_names[pos], "%s:%d", library, ordinal); + return add_stub(); +} + +void* LookupExternalByName(const char* library, const char* name) +{ + char* answ; + int i,j; + // return (void*)ext_unknown; + if(library==0) + { + printf("ERROR: library=0\n"); + return (void*)ext_unknown; + } + if(name==0) + { + printf("ERROR: name=0\n"); + return (void*)ext_unknown; + } + dbgprintf("External func %s:%s\n", library, name); + for(i=0; i150)return 0;// to many symbols + strcpy(export_names[pos], name); + return add_stub(); +} + +void my_garbagecollection(void) +{ +#ifdef GARBAGE + int unfree = 0, unfreecnt = 0; + + int max_fatal = 8; + free_registry(); + while (last_alloc) + { + alloc_header* mem = last_alloc + 1; + unfree += my_size(mem); + unfreecnt++; + if (my_release(mem) != 0) + // avoid endless loop when memory is trashed + if (--max_fatal < 0) + break; + } + printf("Total Unfree %d bytes cnt %d [%p,%d]\n",unfree, unfreecnt, last_alloc, alccnt); +#endif + g_tls = NULL; + list = NULL; +} diff --git a/linphone/win32acm/win32.h b/linphone/win32acm/win32.h new file mode 100644 index 000000000..46512ada9 --- /dev/null +++ b/linphone/win32acm/win32.h @@ -0,0 +1,40 @@ +#ifndef loader_win32_h +#define loader_win32_h + +#include + +#include "wine/windef.h" +#include "wine/winbase.h" +#include "com.h" + +#ifdef AVIFILE +#ifdef __GNUC__ +#include "avm_output.h" +#ifndef __cplusplus +#define printf(a, ...) avm_printf("Win32 plugin", a, ## __VA_ARGS__) +#endif +#endif +#endif + +extern void my_garbagecollection(void); + +typedef struct { + UINT uDriverSignature; + HINSTANCE hDriverModule; + DRIVERPROC DriverProc; + DWORD dwDriverID; +} DRVR; + +typedef DRVR *PDRVR; +typedef DRVR *NPDRVR; +typedef DRVR *LPDRVR; + +typedef struct tls_s tls_t; + + +extern void* LookupExternal(const char* library, int ordinal); +extern void* LookupExternalByName(const char* library, const char* name); +extern int expRegisterClassA(const void/*WNDCLASSA*/ *wc); +extern int expUnregisterClassA(const char *className, HINSTANCE hInstance); + +#endif diff --git a/linphone/win32acm/win32codec.c b/linphone/win32acm/win32codec.c new file mode 100644 index 000000000..f3f353fe8 --- /dev/null +++ b/linphone/win32acm/win32codec.c @@ -0,0 +1,256 @@ +/* + Copyright 2003 Robert W. Brewer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include + +#include "win32codec.h" +#include "loader.h" +#include "driver.h" +#include "wine/windef.h" +#include "wineacm.h" + +/* FIXME figure out a better way to deal with these two things. */ +int verbose=5; +char* get_path(char* x){ return strdup(x);} + + +Win32CodecDriver* win32codec_create_driver(const char* dllName, + short formatTag, + int encodeFlag) +{ + Win32CodecDriver* d = 0; + short format = formatTag; + + d = malloc(sizeof(Win32CodecDriver)); + if (!d) + { + return 0; + } + + if (encodeFlag) + { + format = WAVE_FORMAT_PCM; + } + + d->id = MSACM_RegisterDriver(dllName, format, 0); + if (!d->id) + { + free(d); + return 0; + } + + return d; +} + + +void win32codec_destroy_driver(Win32CodecDriver* d) +{ + MSACM_UnregisterDriver(d->id); + free(d); +} + + + +Win32Codec* win32codec_create(const WAVEFORMATEX* wf, + int encode) +{ + Win32Codec* c = 0; + WAVEFORMATEX pcm_wf; + WAVEFORMATEX* i_wf = 0; + WAVEFORMATEX* o_wf = 0; + MMRESULT ret; + + c = malloc(sizeof(Win32Codec)); + if (!c) + { + return 0; + } + + /* Typical PCM format, 16-bit signed linear samples at + the same rate and number of channels as the desired + codec. + */ + memset(&pcm_wf, 0, sizeof(pcm_wf)); + + pcm_wf.wFormatTag = WAVE_FORMAT_PCM; + pcm_wf.nChannels = wf->nChannels; + pcm_wf.nSamplesPerSec = wf->nSamplesPerSec; + pcm_wf.wBitsPerSample = 16; + pcm_wf.nBlockAlign = pcm_wf.nChannels * pcm_wf.wBitsPerSample / 8; + pcm_wf.nAvgBytesPerSec = pcm_wf.nSamplesPerSec * pcm_wf.nBlockAlign; + + /* decide which way to perform the conversion */ + if (encode) + { + i_wf = &pcm_wf; + o_wf = wf; + } + else + { + i_wf = wf; + o_wf = &pcm_wf; + } + + /* Some codecs (like TrueSpeech) aren't confident they + can do realtime compression. + Tell it we don't care and it's happy. + */ + ret = acmStreamOpen(&c->handle, 0, i_wf, o_wf, 0, 0, 0, + ACM_STREAMOPENF_NONREALTIME); + if (ret) + { + free(c); + return 0; + } + + /* calculate minimum sizes to use for conversions */ + /* we assume that the format with the largest block alignment is + the most picky. And it basically turns out that TrueSpeech has + the largest block alignment. Anyway, we use that block alignment + to ask for the preferred size of the "other" format's buffer. + Then we turn around and ask for the first one's preferred buffer + size based on the other's buffer size, which seems to turn out + to be its block alignment. Or something like that. + */ + if (i_wf->nBlockAlign > o_wf->nBlockAlign) + { + ret = acmStreamSize(c->handle, i_wf->nBlockAlign, &c->min_outsize, + ACM_STREAMSIZEF_SOURCE); + if (ret) + { + acmStreamClose(c->handle, 0); + free(c); + return 0; + } + + if (!c->min_outsize) + { + acmStreamClose(c->handle, 0); + free(c); + return 0; + } + + ret = acmStreamSize(c->handle, c->min_outsize, &c->min_insize, + ACM_STREAMSIZEF_DESTINATION); + if (ret) + { + acmStreamClose(c->handle, 0); + free(c); + return 0; + } + } + else + { + ret = acmStreamSize(c->handle, o_wf->nBlockAlign, &c->min_insize, + ACM_STREAMSIZEF_DESTINATION); + if (ret) + { + acmStreamClose(c->handle, 0); + free(c); + return 0; + } + + if (!c->min_insize) + { + acmStreamClose(c->handle, 0); + free(c); + return 0; + } + + ret = acmStreamSize(c->handle, c->min_insize, &c->min_outsize, + ACM_STREAMSIZEF_SOURCE); + if (ret) + { + acmStreamClose(c->handle, 0); + free(c); + return 0; + } + } + + return c; +} + + + +void win32codec_destroy(Win32Codec* c) +{ + /* FIXME need to put this back. See TODO file + for ideas. + */ + printf("Warning: win32codec_destroy() stubbed out\n"); +/* acmStreamClose(c->handle, 0); */ + free(c); +} + + + +signed long win32codec_convert(Win32Codec* c, + const void* inbuf, long inlen, + void* outbuf, long outlen) +{ + ACMSTREAMHEADER header; + MMRESULT ret; + signed long rval; + + /* set up conversion buffers */ + memset(&header, 0, sizeof(header)); + header.cbStruct = sizeof(header); + header.cbSrcLength = inlen; + header.pbSrc = inbuf; + header.cbDstLength = outlen; + header.pbDst = outbuf; + + ret = acmStreamPrepareHeader(c->handle, &header, 0); + if (ret) + { + return -1; + } + + /* convert */ + ret = acmStreamConvert(c->handle, &header, 0); + if (ret) + { + return -1; + } + + if (!(header.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)) + { + return -1; + } + + if (header.cbSrcLengthUsed != header.cbSrcLength) + { + return -1; + } + + /* not sure if the header is still valid after unpreparing, + so let's save this off + */ + rval = header.cbDstLengthUsed; + + /* seemed to succeed, now unprepare the header */ + ret = acmStreamUnprepareHeader(c->handle, &header, 0); + if (ret) + { + return -1; + } + + return rval; +} + diff --git a/linphone/win32acm/win32codec.h b/linphone/win32acm/win32codec.h new file mode 100644 index 000000000..b63bdcb71 --- /dev/null +++ b/linphone/win32acm/win32codec.h @@ -0,0 +1,92 @@ +#ifndef _WIN32CODEC_H_ +#define _WIN32CODEC_H_ + +/* + Copyright 2003 Robert W. Brewer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + Wrapper for Windows ACM functions mainly designed to make it easier + to write Linphone codecs, but may be useful in other applications + too. +*/ + + +#include "wine/msacm.h" +#include "wineacm.h" + +typedef struct _Win32Codec +{ + HACMSTREAM handle; + unsigned int min_insize; + unsigned int min_outsize; +} Win32Codec; + + +typedef struct _Win32CodecDriver +{ + PWINE_ACMDRIVERID id; +} Win32CodecDriver; + + +/* Register an ACM DLL for the corresponding formatTag. + This should be called twice for each type of codec + needed, once with the encode flag set to encoding + and once for decoding (assuming both will be used). + Under the hood a PCM registration is made when encoding + is requested. Many instances + of a Win32Codec in the corresponding encode/decode mode can + be created after the DLL is registered with this call. + Returns 0 if driver could not be created. +*/ +Win32CodecDriver* win32codec_create_driver(const char* dllName, + short formatTag, + int encodeFlag); + +void win32codec_destroy_driver(Win32CodecDriver* d); + + + + +/* Create a codec that can handle 1 stream of data + in a single direction only. If encode is 1, the + data will originate in 16-bit signed linear PCM format at the + sampling rate and number of channels given in wf and be converted to wf. + If encode is 0, it will originate in the codec specified + by wf and be converted to 16-bit signed linear PCM at the same + sampling rate and number of channels. + + Returns 0 if codec cannot be created correctly. +*/ +Win32Codec* win32codec_create(const WAVEFORMATEX* wf, + int encodeFlag); +void win32codec_destroy(Win32Codec* c); + + +/* Best to use a multiple of min_insize and min_outsize + for inlen and outlen. + Returns: + -1: conversion failure + >= 0: number of bytes used in outbuf +*/ +signed long win32codec_convert(Win32Codec* c, const void* inbuf, long inlen, + void* outbuf, long outlen); + + + + +#endif /* _WIN32CODEC_H_ */ diff --git a/linphone/win32acm/wine/basetsd.h b/linphone/win32acm/wine/basetsd.h new file mode 100644 index 000000000..7b5d3aba9 --- /dev/null +++ b/linphone/win32acm/wine/basetsd.h @@ -0,0 +1,145 @@ +/* + * Compilers that uses ILP32, LP64 or P64 type models + * for both Win32 and Win64 are supported by this file. + */ + +#ifndef __WINE_BASETSD_H +#define __WINE_BASETSD_H + +#ifdef __WINE__ +#include "config.h" +#endif /* defined(__WINE__) */ + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +/* + * Win32 was easy to implement under Unix since most (all?) 32-bit + * Unices uses the same type model (ILP32) as Win32, where int, long + * and pointer are 32-bit. + * + * Win64, however, will cause some problems when implemented under Unix. + * Linux/{Alpha, Sparc64} and most (all?) other 64-bit Unices uses + * the LP64 type model where int is 32-bit and long and pointer are + * 64-bit. Win64 on the other hand uses the P64 (sometimes called LLP64) + * type model where int and long are 32 bit and pointer is 64-bit. + */ + +/* Type model indepent typedefs */ + +typedef char __int8; +typedef unsigned char __uint8; + +typedef short __int16; +typedef unsigned short __uint16; + +typedef int __int32; +typedef unsigned int __uint32; + +typedef long long __int64; +typedef unsigned long long __uint64; + +#if defined(_WIN64) + +typedef __uint32 __ptr32; +typedef void *__ptr64; + +#else /* FIXME: defined(_WIN32) */ + +typedef void *__ptr32; +typedef __uint64 __ptr64; + +#endif + +/* Always signed and 32 bit wide */ + +typedef __int32 LONG32; +//typedef __int32 INT32; + +typedef LONG32 *PLONG32; +//typedef INT32 *PINT32; + +/* Always unsigned and 32 bit wide */ + +typedef __uint32 ULONG32; +typedef __uint32 DWORD32; +typedef __uint32 UINT32; + +typedef ULONG32 *PULONG32; +typedef DWORD32 *PDWORD32; +typedef UINT32 *PUINT32; + +/* Always signed and 64 bit wide */ + +typedef __int64 LONG64; +typedef __int64 INT64; + +typedef LONG64 *PLONG64; +typedef INT64 *PINT64; + +/* Always unsigned and 64 bit wide */ + +typedef __uint64 ULONG64; +typedef __uint64 DWORD64; +typedef __uint64 UINT64; + +typedef ULONG64 *PULONG64; +typedef DWORD64 *PDWORD64; +typedef UINT64 *PUINT64; + +/* Win32 or Win64 dependent typedef/defines. */ + +#ifdef _WIN64 + +typedef __int64 INT_PTR, *PINT_PTR; +typedef __uint64 UINT_PTR, *PUINT_PTR; + +#define MAXINT_PTR 0x7fffffffffffffff +#define MININT_PTR 0x8000000000000000 +#define MAXUINT_PTR 0xffffffffffffffff + +typedef __int32 HALF_PTR, *PHALF_PTR; +typedef __int32 UHALF_PTR, *PUHALF_PTR; + +#define MAXHALF_PTR 0x7fffffff +#define MINHALF_PTR 0x80000000 +#define MAXUHALF_PTR 0xffffffff + +typedef __int64 LONG_PTR, *PLONG_PTR; +typedef __uint64 ULONG_PTR, *PULONG_PTR; +typedef __uint64 DWORD_PTR, *PDWORD_PTR; + +#else /* FIXME: defined(_WIN32) */ + +typedef __int32 INT_PTR, *PINT_PTR; +typedef __uint32 UINT_PTR, *PUINT_PTR; + +#define MAXINT_PTR 0x7fffffff +#define MININT_PTR 0x80000000 +#define MAXUINT_PTR 0xffffffff + +typedef __int16 HALF_PTR, *PHALF_PTR; +typedef __uint16 UHALF_PTR, *PUHALF_PTR; + +#define MAXUHALF_PTR 0xffff +#define MAXHALF_PTR 0x7fff +#define MINHALF_PTR 0x8000 + +typedef __int32 LONG_PTR, *PLONG_PTR; +typedef __uint32 ULONG_PTR, *PULONG_PTR; +typedef __uint32 DWORD_PTR, *PDWORD_PTR; + +#endif /* defined(_WIN64) || defined(_WIN32) */ + +typedef INT_PTR SSIZE_T, *PSSIZE_T; +typedef UINT_PTR SIZE_T, *PSIZE_T; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* !defined(__WINE_BASETSD_H) */ + + + diff --git a/linphone/win32acm/wine/debugtools.h b/linphone/win32acm/wine/debugtools.h new file mode 100644 index 000000000..ce2448db8 --- /dev/null +++ b/linphone/win32acm/wine/debugtools.h @@ -0,0 +1,93 @@ + +#ifndef __WINE_DEBUGTOOLS_H +#define __WINE_DEBUGTOOLS_H + +#ifdef __WINE__ /* Debugging interface is internal to Wine */ + +#include +#include "config.h" +#include "windef.h" + +struct _GUID; + +/* Internal definitions (do not use these directly) */ + +enum __DEBUG_CLASS { __DBCL_FIXME, __DBCL_ERR, __DBCL_WARN, __DBCL_TRACE, __DBCL_COUNT }; + +#ifndef NO_TRACE_MSGS +# define __GET_DEBUGGING_trace(dbch) ((dbch)[0] & (1 << __DBCL_TRACE)) +#else +# define __GET_DEBUGGING_trace(dbch) 0 +#endif + +#ifndef NO_DEBUG_MSGS +# define __GET_DEBUGGING_warn(dbch) ((dbch)[0] & (1 << __DBCL_WARN)) +# define __GET_DEBUGGING_fixme(dbch) ((dbch)[0] & (1 << __DBCL_FIXME)) +#else +# define __GET_DEBUGGING_warn(dbch) 0 +# define __GET_DEBUGGING_fixme(dbch) 0 +#endif + +/* define error macro regardless of what is configured */ +#define __GET_DEBUGGING_err(dbch) ((dbch)[0] & (1 << __DBCL_ERR)) + +#define __GET_DEBUGGING(dbcl,dbch) __GET_DEBUGGING_##dbcl(dbch) +#define __SET_DEBUGGING(dbcl,dbch,on) \ + ((on) ? ((dbch)[0] |= 1 << (dbcl)) : ((dbch)[0] &= ~(1 << (dbcl)))) + +#ifndef __GNUC__ +#define __FUNCTION__ "" +#endif + +#define __DPRINTF(dbcl,dbch) \ + (!__GET_DEBUGGING(dbcl,(dbch)) || (dbg_header_##dbcl((dbch),__FUNCTION__),0)) ? \ + (void)0 : (void)dbg_printf + +/* Exported definitions and macros */ + +/* These function return a printable version of a string, including + quotes. The string will be valid for some time, but not indefinitely + as strings are re-used. */ +extern LPCSTR debugstr_an (LPCSTR s, int n); +extern LPCSTR debugstr_wn (LPCWSTR s, int n); +extern LPCSTR debugres_a (LPCSTR res); +extern LPCSTR debugres_w (LPCWSTR res); +extern LPCSTR debugstr_guid( const struct _GUID *id ); +extern LPCSTR debugstr_hex_dump (const void *ptr, int len); +extern int dbg_header_err( const char *dbg_channel, const char *func ); +extern int dbg_header_warn( const char *dbg_channel, const char *func ); +extern int dbg_header_fixme( const char *dbg_channel, const char *func ); +extern int dbg_header_trace( const char *dbg_channel, const char *func ); +extern int dbg_vprintf( const char *format, va_list args ); + +static inline LPCSTR debugstr_a( LPCSTR s ) { return debugstr_an( s, 80 ); } +static inline LPCSTR debugstr_w( LPCWSTR s ) { return debugstr_wn( s, 80 ); } + +#ifdef __GNUC__ +extern int dbg_printf(const char *format, ...) __attribute__((format (printf,1,2))); +#else +extern int dbg_printf(const char *format, ...); +#endif + +#define TRACE_(X) TRACE +#define WARN_(X) TRACE +#define WARN TRACE +#define ERR_(X) printf +#define ERR printf +#define FIXME_(X) TRACE +#define FIXME TRACE + +#define TRACE_ON(X) 1 +#define ERR_ON(X) 1 + +#define DECLARE_DEBUG_CHANNEL(ch) \ + extern char dbch_##ch[]; +#define DEFAULT_DEBUG_CHANNEL(ch) \ + extern char dbch_##ch[]; static char * const __dbch_default = dbch_##ch; + +#define DPRINTF dbg_printf +#define MESSAGE dbg_printf + +#endif /* __WINE__ */ + +#endif /* __WINE_DEBUGTOOLS_H */ diff --git a/linphone/win32acm/wine/driver.h b/linphone/win32acm/wine/driver.h new file mode 100644 index 000000000..dc8661aa3 --- /dev/null +++ b/linphone/win32acm/wine/driver.h @@ -0,0 +1,112 @@ +/* + * Drivers definitions + */ + +#ifndef __WINE_DRIVER_H +#define __WINE_DRIVER_H + +#include "windef.h" + +#define MMSYSERR_BASE 0 + +#define MMSYSERR_NOERROR 0 /* no error */ +#define MMSYSERR_ERROR (MMSYSERR_BASE + 1) /* unspecified error */ +#define MMSYSERR_BADDEVICEID (MMSYSERR_BASE + 2) /* device ID out of range */ +#define MMSYSERR_NOTENABLED (MMSYSERR_BASE + 3) /* driver failed enable */ +#define MMSYSERR_ALLOCATED (MMSYSERR_BASE + 4) /* device already allocated */ +#define MMSYSERR_INVALHANDLE (MMSYSERR_BASE + 5) /* device handle is invalid */ +#define MMSYSERR_NODRIVER (MMSYSERR_BASE + 6) /* no device driver present */ +#define MMSYSERR_NOMEM (MMSYSERR_BASE + 7) /* memory allocation error */ +#define MMSYSERR_NOTSUPPORTED (MMSYSERR_BASE + 8) /* function isn't supported */ +#define MMSYSERR_BADERRNUM (MMSYSERR_BASE + 9) /* error value out of range */ +#define MMSYSERR_INVALFLAG (MMSYSERR_BASE + 10) /* invalid flag passed */ +#define MMSYSERR_INVALPARAM (MMSYSERR_BASE + 11) /* invalid parameter passed */ +#define MMSYSERR_LASTERROR (MMSYSERR_BASE + 11) /* last error in range */ + +#define DRV_LOAD 0x0001 +#define DRV_ENABLE 0x0002 +#define DRV_OPEN 0x0003 +#define DRV_CLOSE 0x0004 +#define DRV_DISABLE 0x0005 +#define DRV_FREE 0x0006 +#define DRV_CONFIGURE 0x0007 +#define DRV_QUERYCONFIGURE 0x0008 +#define DRV_INSTALL 0x0009 +#define DRV_REMOVE 0x000A +#define DRV_EXITSESSION 0x000B +#define DRV_EXITAPPLICATION 0x000C +#define DRV_POWER 0x000F + +#define DRV_RESERVED 0x0800 +#define DRV_USER 0x4000 + +#define DRVCNF_CANCEL 0x0000 +#define DRVCNF_OK 0x0001 +#define DRVCNF_RESTART 0x0002 + +#define DRVEA_NORMALEXIT 0x0001 +#define DRVEA_ABNORMALEXIT 0x0002 + +#define DRV_SUCCESS 0x0001 +#define DRV_FAILURE 0x0000 + +#define GND_FIRSTINSTANCEONLY 0x00000001 + +#define GND_FORWARD 0x00000000 +#define GND_REVERSE 0x00000002 + +typedef struct { + DWORD dwDCISize; + LPCSTR lpszDCISectionName; + LPCSTR lpszDCIAliasName; +} DRVCONFIGINFO16, *LPDRVCONFIGINFO16; + +typedef struct { + DWORD dwDCISize; + LPCWSTR lpszDCISectionName; + LPCWSTR lpszDCIAliasName; +} DRVCONFIGINFO, *LPDRVCONFIGINFO; + + +/* GetDriverInfo16 references this structure, so this a struct defined + * in the Win16 API. + * GetDriverInfo has been deprecated in Win32. + */ +typedef struct +{ + UINT16 length; + HDRVR16 hDriver; + HINSTANCE16 hModule; + CHAR szAliasName[128]; +} DRIVERINFOSTRUCT16, *LPDRIVERINFOSTRUCT16; + +LRESULT WINAPI DefDriverProc16(DWORD dwDevID, HDRVR16 hDriv, UINT16 wMsg, + LPARAM dwParam1, LPARAM dwParam2); +LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hdrvr, + UINT Msg, LPARAM lParam1, LPARAM lParam2); +HDRVR16 WINAPI OpenDriver16(LPCSTR szDriverName, LPCSTR szSectionName, + LPARAM lParam2); +HDRVR WINAPI OpenDriverA(LPCSTR szDriverName, LPCSTR szSectionName, + LPARAM lParam2); +HDRVR WINAPI OpenDriverW(LPCWSTR szDriverName, LPCWSTR szSectionName, + LPARAM lParam2); +#define OpenDriver WINELIB_NAME_AW(OpenDriver) +LRESULT WINAPI CloseDriver16(HDRVR16 hDriver, LPARAM lParam1, LPARAM lParam2); +LRESULT WINAPI CloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2); +LRESULT WINAPI SendDriverMessage16( HDRVR16 hDriver, UINT16 message, + LPARAM lParam1, LPARAM lParam2 ); +LRESULT WINAPI SendDriverMessage( HDRVR hDriver, UINT message, + LPARAM lParam1, LPARAM lParam2 ); +HMODULE16 WINAPI GetDriverModuleHandle16(HDRVR16 hDriver); +HMODULE WINAPI GetDriverModuleHandle(HDRVR hDriver); + +DWORD WINAPI GetDriverFlags( HDRVR hDriver ); +#ifdef __WINE__ +/* this call (GetDriverFlags) is not documented, nor the flags returned. + * here are Wine only definitions + */ +#define WINE_GDF_EXIST 0x80000000 +#define WINE_GDF_16BIT 0x10000000 +#endif + +#endif /* __WINE_DRIVER_H */ diff --git a/linphone/win32acm/wine/elfdll.h b/linphone/win32acm/wine/elfdll.h new file mode 100644 index 000000000..1f356856f --- /dev/null +++ b/linphone/win32acm/wine/elfdll.h @@ -0,0 +1,14 @@ +#ifndef __WINE_ELFDLL_H +#define __WINE_ELFDLL_H + +#include "module.h" +#include "windef.h" + +WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags); +HINSTANCE16 ELFDLL_LoadModule16(LPCSTR libname); +void ELFDLL_UnloadLibrary(WINE_MODREF *wm); + +void *ELFDLL_dlopen(const char *libname, int flags); +extern char *extra_ld_library_path; + +#endif diff --git a/linphone/win32acm/wine/heap.h b/linphone/win32acm/wine/heap.h new file mode 100644 index 000000000..bd0604b75 --- /dev/null +++ b/linphone/win32acm/wine/heap.h @@ -0,0 +1,56 @@ +/* + * Win32 heap definitions + * + * Copyright 1996 Alexandre Julliard + */ + +#ifndef __WINE_HEAP_H +#define __WINE_HEAP_H + +#include "config.h" + +#include "winbase.h" + +extern HANDLE SystemHeap; +extern HANDLE SegptrHeap; + +extern int HEAP_IsInsideHeap( HANDLE heap, DWORD flags, LPCVOID ptr ); +extern SEGPTR HEAP_GetSegptr( HANDLE heap, DWORD flags, LPCVOID ptr ); +extern LPSTR HEAP_strdupA( HANDLE heap, DWORD flags, LPCSTR str ); +extern LPWSTR HEAP_strdupW( HANDLE heap, DWORD flags, LPCWSTR str ); +extern LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str ); +extern LPSTR HEAP_strdupWtoA( HANDLE heap, DWORD flags, LPCWSTR str ); + +/* SEGPTR helper macros */ + +#define SEGPTR_ALLOC(size) \ + (HeapAlloc( SegptrHeap, 0, (size) )) +#define SEGPTR_NEW(type) \ + ((type *)HeapAlloc( SegptrHeap, 0, sizeof(type) )) +#define SEGPTR_STRDUP(str) \ + (HIWORD(str) ? HEAP_strdupA( SegptrHeap, 0, (str) ) : (LPSTR)(str)) +#define SEGPTR_STRDUP_WtoA(str) \ + (HIWORD(str) ? HEAP_strdupWtoA( SegptrHeap, 0, (str) ) : (LPSTR)(str)) + /* define an inline function, a macro won't do */ +static inline SEGPTR WINE_UNUSED SEGPTR_Get(LPCVOID ptr) { + return (HIWORD(ptr) ? HEAP_GetSegptr( SegptrHeap, 0, ptr ) : (SEGPTR)ptr); +} +#define SEGPTR_GET(ptr) SEGPTR_Get(ptr) +#define SEGPTR_FREE(ptr) \ + (HIWORD(ptr) ? HeapFree( SegptrHeap, 0, (ptr) ) : 0) + +/* system heap private data */ +/* you must lock the system heap before using this structure */ +typedef struct +{ + void *gdi; /* GDI heap */ + void *user; /* USER handle table */ + void *cursor; /* cursor information */ + void *queue; /* message queues descriptor */ + void *win; /* windows descriptor */ + void *root; /* X11 root window */ +} SYSTEM_HEAP_DESCR; + +extern SYSTEM_HEAP_DESCR *SystemHeapDescr; + +#endif /* __WINE_HEAP_H */ diff --git a/linphone/win32acm/wine/ldt.h b/linphone/win32acm/wine/ldt.h new file mode 100644 index 000000000..f87ecc14e --- /dev/null +++ b/linphone/win32acm/wine/ldt.h @@ -0,0 +1,98 @@ +/* + * LDT copy + * + * Copyright 1995 Alexandre Julliard + */ + +#ifndef __WINE_LDT_H +#define __WINE_LDT_H + +#include "windef.h" +enum seg_type +{ + SEGMENT_DATA = 0, + SEGMENT_STACK = 1, + SEGMENT_CODE = 2 +}; + + /* This structure represents a real LDT entry. */ + /* It is used by get_ldt_entry() and set_ldt_entry(). */ +typedef struct +{ + unsigned long base; /* base address */ + unsigned long limit; /* segment limit (in pages or bytes) */ + int seg_32bit; /* is segment 32-bit? */ + int read_only; /* is segment read-only? */ + int limit_in_pages; /* is the limit in pages or bytes? */ + enum seg_type type; /* segment type */ +} ldt_entry; +#ifdef __cplusplus +extern "C" +{ +#endif +extern void LDT_BytesToEntry( const unsigned long *buffer, ldt_entry *content); +extern void LDT_EntryToBytes( unsigned long *buffer, const ldt_entry *content); +extern int LDT_GetEntry( int entry, ldt_entry *content ); +extern int LDT_SetEntry( int entry, const ldt_entry *content ); +extern void LDT_Print( int start, int length ); + + + /* This structure is used to build the local copy of the LDT. */ +typedef struct +{ + unsigned long base; /* base address or 0 if entry is free */ + unsigned long limit; /* limit in bytes or 0 if entry is free */ +} ldt_copy_entry; + +#define LDT_SIZE 8192 + +extern ldt_copy_entry ldt_copy[LDT_SIZE]; + +#define __AHSHIFT 3 /* don't change! */ +#define __AHINCR (1 << __AHSHIFT) + +#define SELECTOR_TO_ENTRY(sel) (((int)(sel) & 0xffff) >> __AHSHIFT) +#define ENTRY_TO_SELECTOR(i) ((i) ? (((int)(i) << __AHSHIFT) | 7) : 0) +#define IS_LDT_ENTRY_FREE(i) (!(ldt_flags_copy[(i)] & LDT_FLAGS_ALLOCATED)) +#define IS_SELECTOR_FREE(sel) (IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel))) +#define GET_SEL_BASE(sel) (ldt_copy[SELECTOR_TO_ENTRY(sel)].base) +#define GET_SEL_LIMIT(sel) (ldt_copy[SELECTOR_TO_ENTRY(sel)].limit) + +/* Convert a segmented ptr (16:16) to a linear (32) pointer */ + +#define PTR_SEG_OFF_TO_LIN(seg,off) \ + ((void*)(GET_SEL_BASE(seg) + (unsigned int)(off))) +#define PTR_SEG_TO_LIN(ptr) \ + PTR_SEG_OFF_TO_LIN(SELECTOROF(ptr),OFFSETOF(ptr)) +#define PTR_SEG_OFF_TO_SEGPTR(seg,off) \ + ((SEGPTR)MAKELONG(off,seg)) +#define PTR_SEG_OFF_TO_HUGEPTR(seg,off) \ + PTR_SEG_OFF_TO_SEGPTR( (seg) + (HIWORD(off) << __AHSHIFT), LOWORD(off) ) + +#define W32S_APPLICATION() (PROCESS_Current()->flags & PDB32_WIN32S_PROC) +#define W32S_OFFSET 0x10000 +#define W32S_APP2WINE(addr, offset) ((addr)? (DWORD)(addr) + (DWORD)(offset) : 0) +#define W32S_WINE2APP(addr, offset) ((addr)? (DWORD)(addr) - (DWORD)(offset) : 0) + +extern unsigned char ldt_flags_copy[LDT_SIZE]; + +#define LDT_FLAGS_TYPE 0x03 /* Mask for segment type */ +#define LDT_FLAGS_READONLY 0x04 /* Segment is read-only (data) */ +#define LDT_FLAGS_EXECONLY 0x04 /* Segment is execute-only (code) */ +#define LDT_FLAGS_32BIT 0x08 /* Segment is 32-bit (code or stack) */ +#define LDT_FLAGS_BIG 0x10 /* Segment is big (limit is in pages) */ +#define LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated (no longer free) */ + +#define GET_SEL_FLAGS(sel) (ldt_flags_copy[SELECTOR_TO_ENTRY(sel)]) + +#define FIRST_LDT_ENTRY_TO_ALLOC 17 + +/* Determine if sel is a system selector (i.e. not managed by Wine) */ +#define IS_SELECTOR_SYSTEM(sel) \ + (!((sel) & 4) || (SELECTOR_TO_ENTRY(sel) < FIRST_LDT_ENTRY_TO_ALLOC)) +#define IS_SELECTOR_32BIT(sel) \ + (IS_SELECTOR_SYSTEM(sel) || (GET_SEL_FLAGS(sel) & LDT_FLAGS_32BIT)) +#ifdef __cplusplus +} +#endif +#endif /* __WINE_LDT_H */ diff --git a/linphone/win32acm/wine/mmreg.h b/linphone/win32acm/wine/mmreg.h new file mode 100644 index 000000000..e59ae0a47 --- /dev/null +++ b/linphone/win32acm/wine/mmreg.h @@ -0,0 +1,242 @@ +/* + * mmreg.h - Declarations for ??? + */ + +#ifndef __WINE_MMREG_H +#define __WINE_MMREG_H + +/*********************************************************************** + * Defines/Enums + */ + +#ifndef _ACM_WAVEFILTER +#define _ACM_WAVEFILTER + +#include "windef.h" + +#define WAVE_FILTER_UNKNOWN 0x0000 +#define WAVE_FILTER_DEVELOPMENT 0xFFFF + +typedef struct __attribute__((__packed__)) _WAVEFILTER { + DWORD cbStruct; + DWORD dwFilterTag; + DWORD fdwFilter; + DWORD dwReserved[5]; +} WAVEFILTER, *PWAVEFILTER, *NPWAVEFILTER, *LPWAVEFILTER; +#endif /* _ACM_WAVEFILTER */ + +#ifndef WAVE_FILTER_VOLUME +#define WAVE_FILTER_VOLUME 0x0001 + +typedef struct __attribute__((__packed__)) _WAVEFILTER_VOLUME { + WAVEFILTER wfltr; + DWORD dwVolume; +} VOLUMEWAVEFILTER, *PVOLUMEWAVEFILTER, *NPVOLUMEWAVEFILTER, *LPVOLUMEWAVEFILTER; +#endif /* WAVE_FILTER_VOLUME */ + +#ifndef WAVE_FILTER_ECHO +#define WAVE_FILTER_ECHO 0x0002 + +typedef struct __attribute__((__packed__)) WAVEFILTER_ECHO { + WAVEFILTER wfltr; + DWORD dwVolume; + DWORD dwDelay; +} ECHOWAVEFILTER, *PECHOWAVEFILTER, *NPECHOWAVEFILTER, *LPECHOWAVEFILTER; +#endif /* WAVEFILTER_ECHO */ + +#ifndef _WAVEFORMATEX_ +#define _WAVEFORMATEX_ +typedef struct __attribute__((__packed__)) _WAVEFORMATEX { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX; +#endif /* _WAVEFORMATEX_ */ + +#ifndef GUID_TYPE +#define GUID_TYPE +typedef struct +{ + unsigned long f1; + unsigned short f2; + unsigned short f3; + unsigned char f4[8]; +} GUID; +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; /* bits of precision */ + WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ + WORD wReserved; /* If neither applies, set to zero. */ + } Samples; + DWORD dwChannelMask; /* which channels are */ + /* present in stream */ + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif // !_WAVEFORMATEXTENSIBLE_ + +typedef struct mpeglayer3waveformat_tag { + WORD wFormatTag WINE_PACKED; + WORD nChannels WINE_PACKED; + DWORD nSamplesPerSec WINE_PACKED; + DWORD nAvgBytesPerSec WINE_PACKED; + WORD nBlockAlign WINE_PACKED; + WORD wBitsPerSample WINE_PACKED; + WORD cbSize WINE_PACKED; + WORD wID WINE_PACKED; + DWORD fdwFlags WINE_PACKED; + WORD nBlockSize WINE_PACKED; + WORD nFramesPerBlock WINE_PACKED; + WORD nCodecDelay WINE_PACKED; +} MPEGLAYER3WAVEFORMAT; + +/* WAVE form wFormatTag IDs */ + +#define WAVE_FORMAT_UNKNOWN 0x0000 /* Microsoft Corporation */ +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 /* Microsoft Corporation */ +#define WAVE_FORMAT_VSELP 0x0004 /* Compaq Computer Corp. */ +#define WAVE_FORMAT_IBM_CVSD 0x0005 /* IBM Corporation */ +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +#define WAVE_FORMAT_DTS 0x0008 /* Microsoft Corporation */ +#define WAVE_FORMAT_OKI_ADPCM 0x0010 /* OKI */ +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +#define WAVE_FORMAT_IMA_ADPCM (WAVE_FORMAT_DVI_ADPCM) /* Intel Corporation */ +#define WAVE_FORMAT_MEDIASPACE_ADPCM 0x0012 /* Videologic */ +#define WAVE_FORMAT_SIERRA_ADPCM 0x0013 /* Sierra Semiconductor Corp */ +#define WAVE_FORMAT_G723_ADPCM 0x0014 /* Antex Electronics Corporation */ +#define WAVE_FORMAT_DIGISTD 0x0015 /* DSP Solutions, Inc. */ +#define WAVE_FORMAT_DIGIFIX 0x0016 /* DSP Solutions, Inc. */ +#define WAVE_FORMAT_DIALOGIC_OKI_ADPCM 0x0017 /* Dialogic Corporation */ +#define WAVE_FORMAT_MEDIAVISION_ADPCM 0x0018 /* Media Vision, Inc. */ +#define WAVE_FORMAT_CU_CODEC 0x0019 /* Hewlett-Packard Company */ +#define WAVE_FORMAT_YAMAHA_ADPCM 0x0020 /* Yamaha Corporation of America */ +#define WAVE_FORMAT_SONARC 0x0021 /* Speech Compression */ +#define WAVE_FORMAT_DSPGROUP_TRUESPEECH 0x0022 /* DSP Group, Inc */ +#define WAVE_FORMAT_ECHOSC1 0x0023 /* Echo Speech Corporation */ +#define WAVE_FORMAT_AUDIOFILE_AF36 0x0024 /* Virtual Music, Inc. */ +#define WAVE_FORMAT_APTX 0x0025 /* Audio Processing Technology */ +#define WAVE_FORMAT_AUDIOFILE_AF10 0x0026 /* Virtual Music, Inc. */ +#define WAVE_FORMAT_PROSODY_1612 0x0027 /* Aculab plc */ +#define WAVE_FORMAT_LRC 0x0028 /* Merging Technologies S.A. */ +#define WAVE_FORMAT_DOLBY_AC2 0x0030 /* Dolby Laboratories */ +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +#define WAVE_FORMAT_MSNAUDIO 0x0032 /* Microsoft Corporation */ +#define WAVE_FORMAT_ANTEX_ADPCME 0x0033 /* Antex Electronics Corporation */ +#define WAVE_FORMAT_CONTROL_RES_VQLPC 0x0034 /* Control Resources Limited */ +#define WAVE_FORMAT_DIGIREAL 0x0035 /* DSP Solutions, Inc. */ +#define WAVE_FORMAT_DIGIADPCM 0x0036 /* DSP Solutions, Inc. */ +#define WAVE_FORMAT_CONTROL_RES_CR10 0x0037 /* Control Resources Limited */ +#define WAVE_FORMAT_NMS_VBXADPCM 0x0038 /* Natural MicroSystems */ +#define WAVE_FORMAT_CS_IMAADPCM 0x0039 /* Crystal Semiconductor IMA ADPCM */ +#define WAVE_FORMAT_ECHOSC3 0x003A /* Echo Speech Corporation */ +#define WAVE_FORMAT_ROCKWELL_ADPCM 0x003B /* Rockwell International */ +#define WAVE_FORMAT_ROCKWELL_DIGITALK 0x003C /* Rockwell International */ +#define WAVE_FORMAT_XEBEC 0x003D /* Xebec Multimedia Solutions Limited */ +#define WAVE_FORMAT_G721_ADPCM 0x0040 /* Antex Electronics Corporation */ +#define WAVE_FORMAT_G728_CELP 0x0041 /* Antex Electronics Corporation */ +#define WAVE_FORMAT_MSG723 0x0042 /* Microsoft Corporation */ +#define WAVE_FORMAT_MPEG 0x0050 /* Microsoft Corporation */ +#define WAVE_FORMAT_RT24 0x0052 /* InSoft, Inc. */ +#define WAVE_FORMAT_PAC 0x0053 /* InSoft, Inc. */ +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +#define WAVE_FORMAT_LUCENT_G723 0x0059 /* Lucent Technologies */ +#define WAVE_FORMAT_CIRRUS 0x0060 /* Cirrus Logic */ +#define WAVE_FORMAT_ESPCM 0x0061 /* ESS Technology */ +#define WAVE_FORMAT_VOXWARE 0x0062 /* Voxware Inc */ +#define WAVE_FORMAT_CANOPUS_ATRAC 0x0063 /* Canopus, co., Ltd. */ +#define WAVE_FORMAT_G726_ADPCM 0x0064 /* APICOM */ +#define WAVE_FORMAT_G722_ADPCM 0x0065 /* APICOM */ +#define WAVE_FORMAT_DSAT_DISPLAY 0x0067 /* Microsoft Corporation */ +#define WAVE_FORMAT_VOXWARE_BYTE_ALIGNED 0x0069 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_AC8 0x0070 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_AC10 0x0071 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_AC16 0x0072 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_AC20 0x0073 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_RT24 0x0074 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_RT29 0x0075 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_RT29HW 0x0076 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_VR12 0x0077 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_VR18 0x0078 /* Voxware Inc */ +#define WAVE_FORMAT_VOXWARE_TQ40 0x0079 /* Voxware Inc */ +#define WAVE_FORMAT_SOFTSOUND 0x0080 /* Softsound, Ltd. */ +#define WAVE_FORMAT_VOXWARE_TQ60 0x0081 /* Voxware Inc */ +#define WAVE_FORMAT_MSRT24 0x0082 /* Microsoft Corporation */ +#define WAVE_FORMAT_G729A 0x0083 /* AT&T Labs, Inc. */ +#define WAVE_FORMAT_MVI_MVI2 0x0084 /* Motion Pixels */ +#define WAVE_FORMAT_DF_G726 0x0085 /* DataFusion Systems (Pty) (Ltd) */ +#define WAVE_FORMAT_DF_GSM610 0x0086 /* DataFusion Systems (Pty) (Ltd) */ +#define WAVE_FORMAT_ISIAUDIO 0x0088 /* Iterated Systems, Inc. */ +#define WAVE_FORMAT_ONLIVE 0x0089 /* OnLive! Technologies, Inc. */ +#define WAVE_FORMAT_SBC24 0x0091 /* Siemens Business Communications Sys */ +#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 /* Sonic Foundry */ +#define WAVE_FORMAT_MEDIASONIC_G723 0x0093 /* MediaSonic */ +#define WAVE_FORMAT_PROSODY_8KBPS 0x0094 /* Aculab plc */ +#define WAVE_FORMAT_ZYXEL_ADPCM 0x0097 /* ZyXEL Communications, Inc. */ +#define WAVE_FORMAT_PHILIPS_LPCBB 0x0098 /* Philips Speech Processing */ +#define WAVE_FORMAT_PACKED 0x0099 /* Studer Professional Audio AG */ +#define WAVE_FORMAT_MALDEN_PHONYTALK 0x00A0 /* Malden Electronics Ltd. */ +#define WAVE_FORMAT_RHETOREX_ADPCM 0x0100 /* Rhetorex Inc. */ +#define WAVE_FORMAT_IRAT 0x0101 /* BeCubed Software Inc. */ +#define WAVE_FORMAT_VIVO_G723 0x0111 /* Vivo Software */ +#define WAVE_FORMAT_VIVO_SIREN 0x0112 /* Vivo Software */ +#define WAVE_FORMAT_DIGITAL_G723 0x0123 /* Digital Equipment Corporation */ +#define WAVE_FORMAT_SANYO_LD_ADPCM 0x0125 /* Sanyo Electric Co., Ltd. */ +#define WAVE_FORMAT_SIPROLAB_ACEPLNET 0x0130 /* Sipro Lab Telecom Inc. */ +#define WAVE_FORMAT_SIPROLAB_ACELP4800 0x0131 /* Sipro Lab Telecom Inc. */ +#define WAVE_FORMAT_SIPROLAB_ACELP8V3 0x0132 /* Sipro Lab Telecom Inc. */ +#define WAVE_FORMAT_SIPROLAB_G729 0x0133 /* Sipro Lab Telecom Inc. */ +#define WAVE_FORMAT_SIPROLAB_G729A 0x0134 /* Sipro Lab Telecom Inc. */ +#define WAVE_FORMAT_SIPROLAB_KELVIN 0x0135 /* Sipro Lab Telecom Inc. */ +#define WAVE_FORMAT_G726ADPCM 0x0140 /* Dictaphone Corporation */ +#define WAVE_FORMAT_QUALCOMM_PUREVOICE 0x0150 /* Qualcomm, Inc. */ +#define WAVE_FORMAT_QUALCOMM_HALFRATE 0x0151 /* Qualcomm, Inc. */ +#define WAVE_FORMAT_TUBGSM 0x0155 /* Ring Zero Systems, Inc. */ +#define WAVE_FORMAT_MSAUDIO1 0x0160 /* Microsoft Corporation */ +#define WAVE_FORMAT_CREATIVE_ADPCM 0x0200 /* Creative Labs, Inc */ +#define WAVE_FORMAT_CREATIVE_FASTSPEECH8 0x0202 /* Creative Labs, Inc */ +#define WAVE_FORMAT_CREATIVE_FASTSPEECH10 0x0203 /* Creative Labs, Inc */ +#define WAVE_FORMAT_UHER_ADPCM 0x0210 /* UHER informatic GmbH */ +#define WAVE_FORMAT_QUARTERDECK 0x0220 /* Quarterdeck Corporation */ +#define WAVE_FORMAT_ILINK_VC 0x0230 /* I-link Worldwide */ +#define WAVE_FORMAT_RAW_SPORT 0x0240 /* Aureal Semiconductor */ +#define WAVE_FORMAT_IPI_HSX 0x0250 /* Interactive Products, Inc. */ +#define WAVE_FORMAT_IPI_RPELP 0x0251 /* Interactive Products, Inc. */ +#define WAVE_FORMAT_CS2 0x0260 /* Consistent Software */ +#define WAVE_FORMAT_SONY_SCX 0x0270 /* Sony Corp. */ +#define WAVE_FORMAT_FM_TOWNS_SND 0x0300 /* Fujitsu Corp. */ +#define WAVE_FORMAT_BTV_DIGITAL 0x0400 /* Brooktree Corporation */ +#define WAVE_FORMAT_QDESIGN_MUSIC 0x0450 /* QDesign Corporation */ +#define WAVE_FORMAT_VME_VMPCM 0x0680 /* AT&T Labs, Inc. */ +#define WAVE_FORMAT_TPC 0x0681 /* AT&T Labs, Inc. */ +#define WAVE_FORMAT_OLIGSM 0x1000 /* Ing C. Olivetti & C., S.p.A. */ +#define WAVE_FORMAT_OLIADPCM 0x1001 /* Ing C. Olivetti & C., S.p.A. */ +#define WAVE_FORMAT_OLICELP 0x1002 /* Ing C. Olivetti & C., S.p.A. */ +#define WAVE_FORMAT_OLISBC 0x1003 /* Ing C. Olivetti & C., S.p.A. */ +#define WAVE_FORMAT_OLIOPR 0x1004 /* Ing C. Olivetti & C., S.p.A. */ +#define WAVE_FORMAT_LH_CODEC 0x1100 /* Lernout & Hauspie */ +#define WAVE_FORMAT_NORRIS 0x1400 /* Norris Communications, Inc. */ +#define WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS 0x1500 /* AT&T Labs, Inc. */ +#define WAVE_FORMAT_DVM 0x2000 /* FAST Multimedia AG */ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE /* Microsoft */ +#endif // !defined(WAVE_FORMAT_EXTENSIBLE) +// +// the WAVE_FORMAT_DEVELOPMENT format tag can be used during the +// development phase of a new wave format. Before shipping, you MUST +// acquire an official format tag from Microsoft. +// +#define WAVE_FORMAT_DEVELOPMENT (0xFFFF) + + +#endif /* __WINE_MMREG_H */ diff --git a/linphone/win32acm/wine/module.h b/linphone/win32acm/wine/module.h new file mode 100644 index 000000000..6f6b31a0a --- /dev/null +++ b/linphone/win32acm/wine/module.h @@ -0,0 +1,149 @@ +/* + * Module definitions + * + * Copyright 1995 Alexandre Julliard + */ + +#ifndef __WINE_MODULE_H +#define __WINE_MODULE_H + +#include "windef.h" +#include "pe_image.h" + + +typedef struct { + BYTE type; + BYTE flags; + BYTE segnum; + WORD offs WINE_PACKED; +} ET_ENTRY; + +typedef struct { + WORD first; /* ordinal */ + WORD last; /* ordinal */ + WORD next; /* bundle */ +} ET_BUNDLE; + + + /* In-memory segment table */ +typedef struct +{ + WORD filepos; /* Position in file, in sectors */ + WORD size; /* Segment size on disk */ + WORD flags; /* Segment flags */ + WORD minsize; /* Min. size of segment in memory */ + HANDLE16 hSeg; /* Selector or handle (selector - 1) */ + /* of segment in memory */ +} SEGTABLEENTRY; + + + /* Self-loading modules contain this structure in their first segment */ + +#include "pshpack1.h" + +typedef struct +{ + WORD version; /* Must be "A0" (0x3041) */ + WORD reserved; + FARPROC16 BootApp; /* startup procedure */ + FARPROC16 LoadAppSeg; /* procedure to load a segment */ + FARPROC16 reserved2; + FARPROC16 MyAlloc; /* memory allocation procedure, + * wine must write this field */ + FARPROC16 EntryAddrProc; + FARPROC16 ExitProc; /* exit procedure */ + WORD reserved3[4]; + FARPROC16 SetOwner; /* Set Owner procedure, exported by wine */ +} SELFLOADHEADER; + + /* Parameters for LoadModule() */ +typedef struct +{ + HGLOBAL16 hEnvironment; /* Environment segment */ + SEGPTR cmdLine WINE_PACKED; /* Command-line */ + SEGPTR showCmd WINE_PACKED; /* Code for ShowWindow() */ + SEGPTR reserved WINE_PACKED; +} LOADPARAMS16; + +typedef struct +{ + LPSTR lpEnvAddress; + LPSTR lpCmdLine; + UINT16 *lpCmdShow; + DWORD dwReserved; +} LOADPARAMS; + +#include "poppack.h" + +/* internal representation of 32bit modules. per process. */ +typedef enum { + MODULE32_PE = 1, + MODULE32_ELF, + MODULE32_ELFDLL +} MODULE32_TYPE; + +typedef struct _wine_modref +{ + struct _wine_modref *next; + struct _wine_modref *prev; + MODULE32_TYPE type; + union { + PE_MODREF pe; + ELF_MODREF elf; + } binfmt; + + HMODULE module; + + int nDeps; + struct _wine_modref **deps; + + int flags; + int refCount; + + char *filename; + char *modname; + char *short_filename; + char *short_modname; +} WINE_MODREF; + +#define WINE_MODREF_INTERNAL 0x00000001 +#define WINE_MODREF_NO_DLL_CALLS 0x00000002 +#define WINE_MODREF_PROCESS_ATTACHED 0x00000004 +#define WINE_MODREF_LOAD_AS_DATAFILE 0x00000010 +#define WINE_MODREF_DONT_RESOLVE_REFS 0x00000020 +#define WINE_MODREF_MARKER 0x80000000 + + + +/* Resource types */ +typedef struct resource_typeinfo_s NE_TYPEINFO; +typedef struct resource_nameinfo_s NE_NAMEINFO; + +#define NE_SEG_TABLE(pModule) \ + ((SEGTABLEENTRY *)((char *)(pModule) + (pModule)->seg_table)) + +#define NE_MODULE_TABLE(pModule) \ + ((WORD *)((char *)(pModule) + (pModule)->modref_table)) + +#define NE_MODULE_NAME(pModule) \ + (((OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo))->szPathName) + +struct modref_list_t; + +typedef struct modref_list_t +{ + WINE_MODREF* wm; + struct modref_list_t *next; + struct modref_list_t *prev; +} modref_list; + + +/* module.c */ +extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, WIN_BOOL snoop ); +extern WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hModule ); +extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); + +/* resource.c */ +extern INT WINAPI AccessResource(HMODULE,HRSRC); + +#endif /* __WINE_MODULE_H */ diff --git a/linphone/win32acm/wine/msacm.h b/linphone/win32acm/wine/msacm.h new file mode 100644 index 000000000..10e87e61a --- /dev/null +++ b/linphone/win32acm/wine/msacm.h @@ -0,0 +1,943 @@ +/* + * msacm.h - Declarations for MSACM + */ + +#ifndef __WINE_MSACM_H +#define __WINE_MSACM_H + +#include "windef.h" +#include "driver.h" +#include "mmreg.h" + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +//typedef WORD VERSION; /* major (high byte), minor (low byte) */ + +typedef UINT16 MMVERSION16; +typedef UINT MMVERSION; +typedef UINT16 MCIDEVICEID16; +typedef UINT MCIDEVICEID; +typedef UINT16 MMRESULT16; +typedef UINT MMRESULT; +typedef DWORD FOURCC; /* a four character code */ + + + +#if !defined(WAVE_FORMAT_PCM) +#define WAVE_FORMAT_PCM 1 +#endif + +/*********************************************************************** + * Defines/Enums + */ + +#define ACMERR_BASE 512 +#define ACMERR_NOTPOSSIBLE (ACMERR_BASE + 0) +#define ACMERR_BUSY (ACMERR_BASE + 1) +#define ACMERR_UNPREPARED (ACMERR_BASE + 2) +#define ACMERR_CANCELED (ACMERR_BASE + 3) + +#define MM_ACM_OPEN MM_STREAM_OPEN +#define MM_ACM_CLOSE MM_STREAM_CLOSE +#define MM_ACM_DONE MM_STREAM_DONE + +#define ACM_DRIVERADDF_FUNCTION 0x00000003L +#define ACM_DRIVERADDF_NOTIFYHWND 0x00000004L +#define ACM_DRIVERADDF_TYPEMASK 0x00000007L +#define ACM_DRIVERADDF_LOCAL 0x00000000L +#define ACM_DRIVERADDF_GLOBAL 0x00000008L + +#define ACMDRIVERDETAILS_SHORTNAME_CHARS 32 +#define ACMDRIVERDETAILS_LONGNAME_CHARS 128 +#define ACMDRIVERDETAILS_COPYRIGHT_CHARS 80 +#define ACMDRIVERDETAILS_LICENSING_CHARS 128 +#define ACMDRIVERDETAILS_FEATURES_CHARS 512 + +#define ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC mmioFOURCC('a', 'u', 'd', 'c') +#define ACMDRIVERDETAILS_FCCCOMP_UNDEFINED mmioFOURCC('\0', '\0', '\0', '\0') + +#define ACMDRIVERDETAILS_SUPPORTF_CODEC 0x00000001L +#define ACMDRIVERDETAILS_SUPPORTF_CONVERTER 0x00000002L +#define ACMDRIVERDETAILS_SUPPORTF_FILTER 0x00000004L +#define ACMDRIVERDETAILS_SUPPORTF_HARDWARE 0x00000008L +#define ACMDRIVERDETAILS_SUPPORTF_ASYNC 0x00000010L +#define ACMDRIVERDETAILS_SUPPORTF_LOCAL 0x40000000L +#define ACMDRIVERDETAILS_SUPPORTF_DISABLED 0x80000000L + +#define ACM_DRIVERENUMF_NOLOCAL 0x40000000L +#define ACM_DRIVERENUMF_DISABLED 0x80000000L + +#define ACM_DRIVERPRIORITYF_ENABLE 0x00000001L +#define ACM_DRIVERPRIORITYF_DISABLE 0x00000002L +#define ACM_DRIVERPRIORITYF_ABLEMASK 0x00000003L +#define ACM_DRIVERPRIORITYF_BEGIN 0x00010000L +#define ACM_DRIVERPRIORITYF_END 0x00020000L +#define ACM_DRIVERPRIORITYF_DEFERMASK 0x00030000L + +#define MM_ACM_FILTERCHOOSE 0x8000 + +#define FILTERCHOOSE_MESSAGE 0 +#define FILTERCHOOSE_FILTERTAG_VERIFY (FILTERCHOOSE_MESSAGE+0) +#define FILTERCHOOSE_FILTER_VERIFY (FILTERCHOOSE_MESSAGE+1) +#define FILTERCHOOSE_CUSTOM_VERIFY (FILTERCHOOSE_MESSAGE+2) + +#define ACMFILTERCHOOSE_STYLEF_SHOWHELP 0x00000004L +#define ACMFILTERCHOOSE_STYLEF_ENABLEHOOK 0x00000008L +#define ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATE 0x00000010L +#define ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATEHANDLE 0x00000020L +#define ACMFILTERCHOOSE_STYLEF_INITTOFILTERSTRUCT 0x00000040L +#define ACMFILTERCHOOSE_STYLEF_CONTEXTHELP 0x00000080L + +#define ACMFILTERDETAILS_FILTER_CHARS 128 + +#define ACM_FILTERDETAILSF_INDEX 0x00000000L +#define ACM_FILTERDETAILSF_FILTER 0x00000001L +#define ACM_FILTERDETAILSF_QUERYMASK 0x0000000FL + +#define ACMFILTERTAGDETAILS_FILTERTAG_CHARS 48 + +#define ACM_FILTERTAGDETAILSF_INDEX 0x00000000L +#define ACM_FILTERTAGDETAILSF_FILTERTAG 0x00000001L +#define ACM_FILTERTAGDETAILSF_LARGESTSIZE 0x00000002L +#define ACM_FILTERTAGDETAILSF_QUERYMASK 0x0000000FL + +#define ACM_FILTERENUMF_DWFILTERTAG 0x00010000L + +#define ACMHELPMSGSTRINGA "acmchoose_help" +#define ACMHELPMSGSTRINGW L"acmchoose_help" +#define ACMHELPMSGSTRING16 "acmchoose_help" + +#define ACMHELPMSGCONTEXTMENUA "acmchoose_contextmenu" +#define ACMHELPMSGCONTEXTMENUW L"acmchoose_contextmenu" +#define ACMHELPMSGCONTEXTMENU16 "acmchoose_contextmenu" + +#define ACMHELPMSGCONTEXTHELPA "acmchoose_contexthelp" +#define ACMHELPMSGCONTEXTHELPW L"acmchoose_contexthelp" +#define ACMHELPMSGCONTEXTHELP16 "acmchoose_contexthelp" + +#define MM_ACM_FORMATCHOOSE 0x8000 + +#define FORMATCHOOSE_MESSAGE 0 +#define FORMATCHOOSE_FORMATTAG_VERIFY (FORMATCHOOSE_MESSAGE+0) +#define FORMATCHOOSE_FORMAT_VERIFY (FORMATCHOOSE_MESSAGE+1) +#define FORMATCHOOSE_CUSTOM_VERIFY (FORMATCHOOSE_MESSAGE+2) + +#define ACMFORMATCHOOSE_STYLEF_SHOWHELP 0x00000004L +#define ACMFORMATCHOOSE_STYLEF_ENABLEHOOK 0x00000008L +#define ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE 0x00000010L +#define ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATEHANDLE 0x00000020L +#define ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT 0x00000040L +#define ACMFORMATCHOOSE_STYLEF_CONTEXTHELP 0x00000080L + +#define ACMFORMATDETAILS_FORMAT_CHARS 128 + +#define ACM_FORMATDETAILSF_INDEX 0x00000000L +#define ACM_FORMATDETAILSF_FORMAT 0x00000001L +#define ACM_FORMATDETAILSF_QUERYMASK 0x0000000FL + +#define ACM_FORMATENUMF_WFORMATTAG 0x00010000L +#define ACM_FORMATENUMF_NCHANNELS 0x00020000L +#define ACM_FORMATENUMF_NSAMPLESPERSEC 0x00040000L +#define ACM_FORMATENUMF_WBITSPERSAMPLE 0x00080000L +#define ACM_FORMATENUMF_CONVERT 0x00100000L +#define ACM_FORMATENUMF_SUGGEST 0x00200000L +#define ACM_FORMATENUMF_HARDWARE 0x00400000L +#define ACM_FORMATENUMF_INPUT 0x00800000L +#define ACM_FORMATENUMF_OUTPUT 0x01000000L + +#define ACM_FORMATSUGGESTF_WFORMATTAG 0x00010000L +#define ACM_FORMATSUGGESTF_NCHANNELS 0x00020000L +#define ACM_FORMATSUGGESTF_NSAMPLESPERSEC 0x00040000L +#define ACM_FORMATSUGGESTF_WBITSPERSAMPLE 0x00080000L +#define ACM_FORMATSUGGESTF_TYPEMASK 0x00FF0000L + +#define ACMFORMATTAGDETAILS_FORMATTAG_CHARS 48 + +#define ACM_FORMATTAGDETAILSF_INDEX 0x00000000L +#define ACM_FORMATTAGDETAILSF_FORMATTAG 0x00000001L +#define ACM_FORMATTAGDETAILSF_LARGESTSIZE 0x00000002L +#define ACM_FORMATTAGDETAILSF_QUERYMASK 0x0000000FL + +#define ACM_METRIC_COUNT_DRIVERS 1 +#define ACM_METRIC_COUNT_CODECS 2 +#define ACM_METRIC_COUNT_CONVERTERS 3 +#define ACM_METRIC_COUNT_FILTERS 4 +#define ACM_METRIC_COUNT_DISABLED 5 +#define ACM_METRIC_COUNT_HARDWARE 6 +#define ACM_METRIC_COUNT_LOCAL_DRIVERS 20 +#define ACM_METRIC_COUNT_LOCAL_CODECS 21 +#define ACM_METRIC_COUNT_LOCAL_CONVERTERS 22 +#define ACM_METRIC_COUNT_LOCAL_FILTERS 23 +#define ACM_METRIC_COUNT_LOCAL_DISABLED 24 +#define ACM_METRIC_HARDWARE_WAVE_INPUT 30 +#define ACM_METRIC_HARDWARE_WAVE_OUTPUT 31 +#define ACM_METRIC_MAX_SIZE_FORMAT 50 +#define ACM_METRIC_MAX_SIZE_FILTER 51 +#define ACM_METRIC_DRIVER_SUPPORT 100 +#define ACM_METRIC_DRIVER_PRIORITY 101 + +#define ACM_STREAMCONVERTF_BLOCKALIGN 0x00000004 +#define ACM_STREAMCONVERTF_START 0x00000010 +#define ACM_STREAMCONVERTF_END 0x00000020 + +#define ACMSTREAMHEADER_STATUSF_DONE 0x00010000L +#define ACMSTREAMHEADER_STATUSF_PREPARED 0x00020000L +#define ACMSTREAMHEADER_STATUSF_INQUEUE 0x00100000L + +#define ACM_STREAMOPENF_QUERY 0x00000001 +#define ACM_STREAMOPENF_ASYNC 0x00000002 +#define ACM_STREAMOPENF_NONREALTIME 0x00000004 + +#define ACM_STREAMSIZEF_SOURCE 0x00000000L +#define ACM_STREAMSIZEF_DESTINATION 0x00000001L +#define ACM_STREAMSIZEF_QUERYMASK 0x0000000FL + +#define ACMDM_USER (DRV_USER + 0x0000) +#define ACMDM_RESERVED_LOW (DRV_USER + 0x2000) +#define ACMDM_RESERVED_HIGH (DRV_USER + 0x2FFF) + +#define ACMDM_BASE ACMDM_RESERVED_LOW + +#define ACMDM_DRIVER_ABOUT (ACMDM_BASE + 11) + +/*********************************************************************** + * Callbacks + */ + +typedef WIN_BOOL CALLBACK ( *ACMDRIVERENUMCB)( + HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL16 CALLBACK ( *ACMDRIVERENUMCB16)( + HACMDRIVERID16 hadid, DWORD dwInstance, DWORD fdwSupport +); + +typedef UINT CALLBACK ( *ACMFILTERCHOOSEHOOKPROCA)( + HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam +); + +typedef UINT CALLBACK ( *ACMFILTERCHOOSEHOOKPROCW)( + HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam +); + +typedef UINT CALLBACK ( *ACMFILTERCHOOSEHOOKPROC16)( + HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam +); + +typedef UINT CALLBACK ( *ACMFORMATCHOOSEHOOKPROCA)( + HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam +); + +typedef UINT CALLBACK ( *ACMFORMATCHOOSEHOOKPROCW)( + HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam +); + +typedef UINT16 CALLBACK ( *ACMFORMATCHOOSEHOOKPROC16)( + HWND16 hwnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam +); + +/*********************************************************************** + * Structures + */ + +typedef struct _ACMDRIVERDETAILSA +{ + DWORD cbStruct; + + FOURCC fccType; + FOURCC fccComp; + + WORD wMid; + WORD wPid; + + DWORD vdwACM; + DWORD vdwDriver; + + DWORD fdwSupport; + DWORD cFormatTags; + DWORD cFilterTags; + + HICON hicon; + + CHAR szShortName[ACMDRIVERDETAILS_SHORTNAME_CHARS]; + CHAR szLongName[ACMDRIVERDETAILS_LONGNAME_CHARS]; + CHAR szCopyright[ACMDRIVERDETAILS_COPYRIGHT_CHARS]; + CHAR szLicensing[ACMDRIVERDETAILS_LICENSING_CHARS]; + CHAR szFeatures[ACMDRIVERDETAILS_FEATURES_CHARS]; +} ACMDRIVERDETAILSA, *PACMDRIVERDETAILSA; + +typedef struct _ACMDRIVERDETAILSW +{ + DWORD cbStruct; + + FOURCC fccType; + FOURCC fccComp; + + WORD wMid; + WORD wPid; + + DWORD vdwACM; + DWORD vdwDriver; + + DWORD fdwSupport; + DWORD cFormatTags; + DWORD cFilterTags; + + HICON hicon; + + WCHAR szShortName[ACMDRIVERDETAILS_SHORTNAME_CHARS]; + WCHAR szLongName[ACMDRIVERDETAILS_LONGNAME_CHARS]; + WCHAR szCopyright[ACMDRIVERDETAILS_COPYRIGHT_CHARS]; + WCHAR szLicensing[ACMDRIVERDETAILS_LICENSING_CHARS]; + WCHAR szFeatures[ACMDRIVERDETAILS_FEATURES_CHARS]; +} ACMDRIVERDETAILSW, *PACMDRIVERDETAILSW; + +typedef struct _ACMDRIVERDETAILS16 +{ + DWORD cbStruct; + + FOURCC fccType; + FOURCC fccComp; + + WORD wMid; + WORD wPid; + + DWORD vdwACM; + DWORD vdwDriver; + + DWORD fdwSupport; + DWORD cFormatTags; + DWORD cFilterTags; + + HICON16 hicon; + + CHAR szShortName[ACMDRIVERDETAILS_SHORTNAME_CHARS]; + CHAR szLongName[ACMDRIVERDETAILS_LONGNAME_CHARS]; + CHAR szCopyright[ACMDRIVERDETAILS_COPYRIGHT_CHARS]; + CHAR szLicensing[ACMDRIVERDETAILS_LICENSING_CHARS]; + CHAR szFeatures[ACMDRIVERDETAILS_FEATURES_CHARS]; +} ACMDRIVERDETAILS16, *NPACMDRIVERDETAILS16, *LPACMDRIVERDETAILS16; + +typedef struct _ACMFILTERCHOOSEA +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND hwndOwner; + + PWAVEFILTER pwfltr; + DWORD cbwfltr; + + LPCSTR pszTitle; + + CHAR szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; + CHAR szFilter[ACMFILTERDETAILS_FILTER_CHARS]; + LPSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + PWAVEFILTER pwfltrEnum; + + HINSTANCE hInstance; + LPCSTR pszTemplateName; + LPARAM lCustData; + ACMFILTERCHOOSEHOOKPROCA pfnHook; +} ACMFILTERCHOOSEA, *PACMFILTERCHOOSEA; + +typedef struct _ACMFILTERCHOOSEW +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND hwndOwner; + + PWAVEFILTER pwfltr; + DWORD cbwfltr; + + LPCWSTR pszTitle; + + WCHAR szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; + WCHAR szFilter[ACMFILTERDETAILS_FILTER_CHARS]; + LPWSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + PWAVEFILTER pwfltrEnum; + + HINSTANCE hInstance; + LPCWSTR pszTemplateName; + LPARAM lCustData; + ACMFILTERCHOOSEHOOKPROCW pfnHook; +} ACMFILTERCHOOSEW, *PACMFILTERCHOOSEW; + +typedef struct _ACMFILTERCHOOSE16 +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND16 hwndOwner; + + LPWAVEFILTER pwfltr; + DWORD cbwfltr; + + LPCSTR pszTitle; + + char szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; + char szFilter[ACMFILTERDETAILS_FILTER_CHARS]; + LPSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + LPWAVEFILTER pwfltrEnum; + + HINSTANCE16 hInstance; + LPCSTR pszTemplateName; + LPARAM lCustData; + ACMFILTERCHOOSEHOOKPROC16 pfnHook; +} ACMFILTERCHOOSE16, *NPACMFILTERCHOOSE16, *LPACMFILTERCHOOSE16; + +typedef struct _ACMFILTERDETAILSA +{ + DWORD cbStruct; + DWORD dwFilterIndex; + DWORD dwFilterTag; + DWORD fdwSupport; + PWAVEFILTER pwfltr; + DWORD cbwfltr; + CHAR szFilter[ACMFILTERDETAILS_FILTER_CHARS]; +} ACMFILTERDETAILSA, *PACMFILTERDETAILSA; + +typedef struct _ACMFILTERDETAILSW +{ + DWORD cbStruct; + DWORD dwFilterIndex; + DWORD dwFilterTag; + DWORD fdwSupport; + PWAVEFILTER pwfltr; + DWORD cbwfltr; + WCHAR szFilter[ACMFILTERDETAILS_FILTER_CHARS]; +} ACMFILTERDETAILSW, *PACMFILTERDETAILSW; + +typedef struct _ACMFILTERDETAILS16 +{ + DWORD cbStruct; + DWORD dwFilterIndex; + DWORD dwFilterTag; + DWORD fdwSupport; + LPWAVEFILTER pwfltr; + DWORD cbwfltr; + CHAR szFilter[ACMFILTERDETAILS_FILTER_CHARS]; +} ACMFILTERDETAILS16, *NPACMFILTERDETAILS16, *LPACMFILTERDETAILS16; + +typedef struct _ACMFILTERTAGDETAILSA +{ + DWORD cbStruct; + DWORD dwFilterTagIndex; + DWORD dwFilterTag; + DWORD cbFilterSize; + DWORD fdwSupport; + DWORD cStandardFilters; + CHAR szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; +} ACMFILTERTAGDETAILSA, *PACMFILTERTAGDETAILSA; + +typedef struct _ACMFILTERTAGDETAILSW +{ + DWORD cbStruct; + DWORD dwFilterTagIndex; + DWORD dwFilterTag; + DWORD cbFilterSize; + DWORD fdwSupport; + DWORD cStandardFilters; + WCHAR szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; +} ACMFILTERTAGDETAILSW, *PACMFILTERTAGDETAILSW; + +typedef struct _ACMFILTERTAGDETAILS16 +{ + DWORD cbStruct; + DWORD dwFilterTagIndex; + DWORD dwFilterTag; + DWORD cbFilterSize; + DWORD fdwSupport; + DWORD cStandardFilters; + CHAR szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; +} ACMFILTERTAGDETAILS16, *NPACMFILTERTAGDETAILS16, *LPACMFILTERTAGDETAILS16; + +typedef struct _ACMFORMATCHOOSEA +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND hwndOwner; + + PWAVEFORMATEX pwfx; + DWORD cbwfx; + LPCSTR pszTitle; + + CHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; + CHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; + + LPSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + PWAVEFORMATEX pwfxEnum; + + HINSTANCE hInstance; + LPCSTR pszTemplateName; + LPARAM lCustData; + ACMFORMATCHOOSEHOOKPROCA pfnHook; +} ACMFORMATCHOOSEA, *PACMFORMATCHOOSEA; + +typedef struct _ACMFORMATCHOOSEW +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND hwndOwner; + + PWAVEFORMATEX pwfx; + DWORD cbwfx; + LPCWSTR pszTitle; + + WCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; + WCHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; + + LPWSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + LPWAVEFORMATEX pwfxEnum; + + HINSTANCE hInstance; + LPCWSTR pszTemplateName; + LPARAM lCustData; + ACMFORMATCHOOSEHOOKPROCW pfnHook; +} ACMFORMATCHOOSEW, *PACMFORMATCHOOSEW; + +typedef struct _ACMFORMATCHOOSE16 +{ + DWORD cbStruct; + DWORD fdwStyle; + + HWND16 hwndOwner; + + LPWAVEFORMATEX pwfx; + DWORD cbwfx; + LPCSTR pszTitle; + + CHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; + CHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; + + LPSTR pszName; + DWORD cchName; + + DWORD fdwEnum; + LPWAVEFORMATEX pwfxEnum; + + HINSTANCE16 hInstance; + LPCSTR pszTemplateName; + LPARAM lCustData; + ACMFORMATCHOOSEHOOKPROC16 pfnHook; +} ACMFORMATCHOOSE16, *NPACMFORMATCHOOSE16, *LPACMFORMATCHOOSE16; + +typedef struct _ACMFORMATDETAILSA +{ + DWORD cbStruct; + DWORD dwFormatIndex; + DWORD dwFormatTag; + DWORD fdwSupport; + PWAVEFORMATEX pwfx; + DWORD cbwfx; + CHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; +} ACMFORMATDETAILSA, *PACMFORMATDETAILSA; + +typedef struct _ACMFORMATDETAILSW +{ + DWORD cbStruct; + DWORD dwFormatIndex; + DWORD dwFormatTag; + DWORD fdwSupport; + PWAVEFORMATEX pwfx; + DWORD cbwfx; + WCHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; +} ACMFORMATDETAILSW, *PACMFORMATDETAILSW; + +typedef struct _ACMFORMATDETAILS16 +{ + DWORD cbStruct; + DWORD dwFormatIndex; + DWORD dwFormatTag; + DWORD fdwSupport; + LPWAVEFORMATEX pwfx; + DWORD cbwfx; + CHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS]; +} ACMFORMATDETAILS16, *NPACMFORMATDETAILS16, *LPACMFORMATDETAILS16; + +typedef struct _ACMFORMATTAGDETAILSA +{ + DWORD cbStruct; + DWORD dwFormatTagIndex; + DWORD dwFormatTag; + DWORD cbFormatSize; + DWORD fdwSupport; + DWORD cStandardFormats; + CHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; +} ACMFORMATTAGDETAILSA, *PACMFORMATTAGDETAILSA; + +typedef struct _ACMFORMATTAGDETAILSW +{ + DWORD cbStruct; + DWORD dwFormatTagIndex; + DWORD dwFormatTag; + DWORD cbFormatSize; + DWORD fdwSupport; + DWORD cStandardFormats; + WCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; +} ACMFORMATTAGDETAILSW, *PACMFORMATTAGDETAILSW; + +typedef struct _ACMFORMATTAGDETAILS16 +{ + DWORD cbStruct; + DWORD dwFormatTagIndex; + DWORD dwFormatTag; + DWORD cbFormatSize; + DWORD fdwSupport; + DWORD cStandardFormats; + CHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; +} ACMFORMATTAGDETAILS16, *NPACMFORMATTAGDETAILS16, *LPACMFORMATTAGDETAILS16; + +typedef struct _ACMSTREAMHEADER +{ + DWORD cbStruct; + DWORD fdwStatus; + DWORD dwUser; + LPBYTE pbSrc; + DWORD cbSrcLength; + DWORD cbSrcLengthUsed; + DWORD dwSrcUser; + LPBYTE pbDst; + DWORD cbDstLength; + DWORD cbDstLengthUsed; + DWORD dwDstUser; + DWORD dwReservedDriver[10]; +} ACMSTREAMHEADER16, *NPACMSTREAMHEADER16, *LPACMSTREAMHEADER16, + ACMSTREAMHEADER, *PACMSTREAMHEADER; + +/*********************************************************************** + * Callbacks 2 + */ + +typedef WIN_BOOL CALLBACK ( *ACMFILTERENUMCBA)( + HACMDRIVERID hadid, PACMFILTERDETAILSA pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFILTERENUMCBW)( + HACMDRIVERID hadid, PACMFILTERDETAILSW pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL16 CALLBACK ( *ACMFILTERENUMCB16)( + HACMDRIVERID16 hadid, LPACMFILTERDETAILS16 pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFILTERTAGENUMCBA)( + HACMDRIVERID hadid, PACMFILTERTAGDETAILSA paftd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFILTERTAGENUMCBW)( + HACMDRIVERID hadid, PACMFILTERTAGDETAILSW paftd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL16 CALLBACK ( *ACMFILTERTAGENUMCB16)( + HACMDRIVERID16 hadid, LPACMFILTERTAGDETAILS16 paftd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFORMATENUMCBA)( + HACMDRIVERID hadid, PACMFORMATDETAILSA pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFORMATENUMCBW)( + HACMDRIVERID hadid, PACMFORMATDETAILSW pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL16 CALLBACK ( *ACMFORMATENUMCB16)( + HACMDRIVERID16 hadid, LPACMFORMATDETAILS16 pafd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFORMATTAGENUMCBA)( + HACMDRIVERID hadid, PACMFORMATTAGDETAILSA paftd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL CALLBACK ( *ACMFORMATTAGENUMCBW)( + HACMDRIVERID hadid, PACMFORMATTAGDETAILSW paftd, + DWORD dwInstance, DWORD fdwSupport +); + +typedef WIN_BOOL16 CALLBACK ( *ACMFORMATTAGENUMCB16)( + HACMDRIVERID16 hadid, LPACMFORMATTAGDETAILS16 paftd, + DWORD dwInstance, DWORD fdwSupport +); + +/*********************************************************************** + * Functions - Win16 + */ + +DWORD WINAPI acmGetVersion16( +); +MMRESULT16 WINAPI acmMetrics16( + HACMOBJ16 hao, UINT16 uMetric, LPVOID pMetric +); +MMRESULT16 WINAPI acmDriverEnum16( + ACMDRIVERENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmDriverDetails16( + HACMDRIVERID16 hadid, LPACMDRIVERDETAILS16 padd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmDriverAdd16( + LPHACMDRIVERID16 phadid, HINSTANCE16 hinstModule, + LPARAM lParam, DWORD dwPriority, DWORD fdwAdd +); +MMRESULT16 WINAPI acmDriverRemove16( + HACMDRIVERID16 hadid, DWORD fdwRemove +); +MMRESULT16 WINAPI acmDriverOpen16( + LPHACMDRIVER16 phad, HACMDRIVERID16 hadid, DWORD fdwOpen +); +MMRESULT16 WINAPI acmDriverClose16( + HACMDRIVER16 had, DWORD fdwClose +); +LRESULT WINAPI acmDriverMessage16( + HACMDRIVER16 had, UINT16 uMsg, LPARAM lParam1, LPARAM lParam2 +); +MMRESULT16 WINAPI acmDriverID16( + HACMOBJ16 hao, LPHACMDRIVERID16 phadid, DWORD fdwDriverID +); +MMRESULT16 WINAPI acmDriverPriority16( + HACMDRIVERID16 hadid, DWORD dwPriority, DWORD fdwPriority +); +MMRESULT16 WINAPI acmFormatTagDetails16( + HACMDRIVER16 had, LPACMFORMATTAGDETAILS16 paftd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFormatTagEnum16( + HACMDRIVER16 had, LPACMFORMATTAGDETAILS16 paftd, + ACMFORMATTAGENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmFormatChoose16( + LPACMFORMATCHOOSE16 pafmtc +); +MMRESULT16 WINAPI acmFormatDetails16( + HACMDRIVER16 had, LPACMFORMATDETAILS16 pafd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFormatEnum16( + HACMDRIVER16 had, LPACMFORMATDETAILS16 pafd, + ACMFORMATENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmFormatSuggest16( + HACMDRIVER16 had, LPWAVEFORMATEX pwfxSrc, + LPWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest +); +MMRESULT16 WINAPI acmFilterTagDetails16( + HACMDRIVER16 had, LPACMFILTERTAGDETAILS16 paftd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFilterTagEnum16( + HACMDRIVER16 had, LPACMFILTERTAGDETAILS16 paftd, + ACMFILTERTAGENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmFilterChoose16( + LPACMFILTERCHOOSE16 pafltrc +); +MMRESULT16 WINAPI acmFilterDetails16( + HACMDRIVER16 had, LPACMFILTERDETAILS16 pafd, DWORD fdwDetails +); +MMRESULT16 WINAPI acmFilterEnum16( + HACMDRIVER16 had, LPACMFILTERDETAILS16 pafd, + ACMFILTERENUMCB16 fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT16 WINAPI acmStreamOpen16( + LPHACMSTREAM16 phas, HACMDRIVER16 had, + LPWAVEFORMATEX pwfxSrc, LPWAVEFORMATEX pwfxDst, + LPWAVEFILTER pwfltr, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen +); +MMRESULT16 WINAPI acmStreamClose16( + HACMSTREAM16 has, DWORD fdwClose +); +MMRESULT16 WINAPI acmStreamSize16( + HACMSTREAM16 has, DWORD cbInput, + LPDWORD pdwOutputBytes, DWORD fdwSize +); +MMRESULT16 WINAPI acmStreamConvert16( + HACMSTREAM16 has, LPACMSTREAMHEADER16 pash, DWORD fdwConvert +); +MMRESULT16 WINAPI acmStreamReset16( + HACMSTREAM16 has, DWORD fdwReset +); +MMRESULT16 WINAPI acmStreamPrepareHeader16( + HACMSTREAM16 has, LPACMSTREAMHEADER16 pash, DWORD fdwPrepare +); +MMRESULT16 WINAPI acmStreamUnprepareHeader16( + HACMSTREAM16 has, LPACMSTREAMHEADER16 pash, DWORD fdwUnprepare +); + +/*********************************************************************** + * Functions - Win32 + */ + +MMRESULT WINAPI acmDriverAddA( + PHACMDRIVERID phadid, HINSTANCE hinstModule, + LPARAM lParam, DWORD dwPriority, DWORD fdwAdd +); +MMRESULT WINAPI acmDriverAddW( + PHACMDRIVERID phadid, HINSTANCE hinstModule, + LPARAM lParam, DWORD dwPriority, DWORD fdwAdd +); +MMRESULT WINAPI acmDriverClose( + HACMDRIVER had, DWORD fdwClose +); +MMRESULT WINAPI acmDriverDetailsA( + HACMDRIVERID hadid, PACMDRIVERDETAILSA padd, DWORD fdwDetails +); +MMRESULT WINAPI acmDriverDetailsW( + HACMDRIVERID hadid, PACMDRIVERDETAILSW padd, DWORD fdwDetails +); +MMRESULT WINAPI acmDriverEnum( + ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmDriverID( + HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID +); +LRESULT WINAPI acmDriverMessage( + HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2 +); +MMRESULT WINAPI acmDriverOpen( + PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen +); +MMRESULT WINAPI acmDriverPriority( + HACMDRIVERID hadid, DWORD dwPriority, DWORD fdwPriority +); +MMRESULT WINAPI acmDriverRemove( + HACMDRIVERID hadid, DWORD fdwRemove +); +MMRESULT WINAPI acmFilterChooseA( + PACMFILTERCHOOSEA pafltrc +); +MMRESULT WINAPI acmFilterChooseW( + PACMFILTERCHOOSEW pafltrc +); +MMRESULT WINAPI acmFilterDetailsA( + HACMDRIVER had, PACMFILTERDETAILSA pafd, DWORD fdwDetails +); +MMRESULT WINAPI acmFilterDetailsW( + HACMDRIVER had, PACMFILTERDETAILSW pafd, DWORD fdwDetails +); +MMRESULT WINAPI acmFilterEnumA( + HACMDRIVER had, PACMFILTERDETAILSA pafd, + ACMFILTERENUMCBA fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFilterEnumW( + HACMDRIVER had, PACMFILTERDETAILSW pafd, + ACMFILTERENUMCBW fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFilterTagDetailsA( + HACMDRIVER had, PACMFILTERTAGDETAILSA paftd, DWORD fdwDetails +); +MMRESULT WINAPI acmFilterTagDetailsW( + HACMDRIVER had, PACMFILTERTAGDETAILSW paftd, DWORD fdwDetails +); +MMRESULT WINAPI acmFilterTagEnumA( + HACMDRIVER had, PACMFILTERTAGDETAILSA paftd, + ACMFILTERTAGENUMCBA fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFilterTagEnumW( + HACMDRIVER had, PACMFILTERTAGDETAILSW paftd, + ACMFILTERTAGENUMCBW fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFormatChooseA( + PACMFORMATCHOOSEA pafmtc +); +MMRESULT WINAPI acmFormatChooseW( + PACMFORMATCHOOSEW pafmtc +); +MMRESULT WINAPI acmFormatDetailsA( + HACMDRIVER had, PACMFORMATDETAILSA pafd, DWORD fdwDetails +); +MMRESULT WINAPI acmFormatDetailsW( + HACMDRIVER had, PACMFORMATDETAILSW pafd, DWORD fdwDetails +); +MMRESULT WINAPI acmFormatEnumA( + HACMDRIVER had, PACMFORMATDETAILSA pafd, + ACMFORMATENUMCBA fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFormatEnumW( + HACMDRIVER had, PACMFORMATDETAILSW pafd, + ACMFORMATENUMCBW fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFormatSuggest( + HACMDRIVER had, PWAVEFORMATEX pwfxSrc, PWAVEFORMATEX pwfxDst, + DWORD cbwfxDst, DWORD fdwSuggest +); +MMRESULT WINAPI acmFormatTagDetailsA( + HACMDRIVER had, PACMFORMATTAGDETAILSA paftd, DWORD fdwDetails +); +MMRESULT WINAPI acmFormatTagDetailsW( + HACMDRIVER had, PACMFORMATTAGDETAILSW paftd, DWORD fdwDetails +); +MMRESULT WINAPI acmFormatTagEnumA( + HACMDRIVER had, PACMFORMATTAGDETAILSA paftd, + ACMFORMATTAGENUMCBA fnCallback, DWORD dwInstance, DWORD fdwEnum +); +MMRESULT WINAPI acmFormatTagEnumW( + HACMDRIVER had, PACMFORMATTAGDETAILSW paftd, + ACMFORMATTAGENUMCBW fnCallback, DWORD dwInstance, DWORD fdwEnum +); +DWORD WINAPI acmGetVersion( +); +MMRESULT WINAPI acmMetrics( + HACMOBJ hao, UINT uMetric, LPVOID pMetric +); +MMRESULT WINAPI acmStreamClose( + HACMSTREAM has, DWORD fdwClose +); +MMRESULT WINAPI acmStreamConvert( + HACMSTREAM has, PACMSTREAMHEADER pash, DWORD fdwConvert +); +MMRESULT WINAPI acmStreamMessage( + HACMSTREAM has, UINT uMsg, LPARAM lParam1, LPARAM lParam2 +); +MMRESULT WINAPI acmStreamOpen( + PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc, + PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen +); +MMRESULT WINAPI acmStreamPrepareHeader( + HACMSTREAM has, PACMSTREAMHEADER pash, DWORD fdwPrepare +); +MMRESULT WINAPI acmStreamReset( + HACMSTREAM has, DWORD fdwReset +); +MMRESULT WINAPI acmStreamSize( + HACMSTREAM has, DWORD cbInput, + LPDWORD pdwOutputBytes, DWORD fdwSize +); +MMRESULT WINAPI acmStreamUnprepareHeader( + HACMSTREAM has, PACMSTREAMHEADER pash, DWORD fdwUnprepare +); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* __WINE_MSACM_H */ + + diff --git a/linphone/win32acm/wine/msacmdrv.h b/linphone/win32acm/wine/msacmdrv.h new file mode 100644 index 000000000..2e23a17d7 --- /dev/null +++ b/linphone/win32acm/wine/msacmdrv.h @@ -0,0 +1,203 @@ +/* + * msacmdrv.h - Declarations for MSACM driver + */ + +#ifndef __WINE_MSACMDRV_H +#define __WINE_MSACMDRV_H + +#include "windef.h" +#include "msacm.h" + +/*********************************************************************** + * Types + */ + +/*********************************************************************** + * Defines/Enums + */ + +#define MAKE_ACM_VERSION(mjr, mnr, bld) \ + (((long)(mjr)<<24) | ((long)(mnr)<<16) | ((long)bld)) + +#define ACMDRVOPENDESC_SECTIONNAME_CHARS + +#define ACMDM_DRIVER_NOTIFY (ACMDM_BASE + 1) +#define ACMDM_DRIVER_DETAILS (ACMDM_BASE + 10) + +#define ACMDM_HARDWARE_WAVE_CAPS_INPUT (ACMDM_BASE + 20) +#define ACMDM_HARDWARE_WAVE_CAPS_OUTPUT (ACMDM_BASE + 21) + +#define ACMDM_FORMATTAG_DETAILS (ACMDM_BASE + 25) +#define ACMDM_FORMAT_DETAILS (ACMDM_BASE + 26) +#define ACMDM_FORMAT_SUGGEST (ACMDM_BASE + 27) + +#define ACMDM_FILTERTAG_DETAILS (ACMDM_BASE + 50) +#define ACMDM_FILTER_DETAILS (ACMDM_BASE + 51) + +#define ACMDM_STREAM_OPEN (ACMDM_BASE + 76) +#define ACMDM_STREAM_CLOSE (ACMDM_BASE + 77) +#define ACMDM_STREAM_SIZE (ACMDM_BASE + 78) +#define ACMDM_STREAM_CONVERT (ACMDM_BASE + 79) +#define ACMDM_STREAM_RESET (ACMDM_BASE + 80) +#define ACMDM_STREAM_PREPARE (ACMDM_BASE + 81) +#define ACMDM_STREAM_UNPREPARE (ACMDM_BASE + 82) +#define ACMDM_STREAM_UPDATE (ACMDM_BASE + 83) + +/*********************************************************************** + * Structures + */ + +typedef struct _ACMDRVOPENDESCA +{ + DWORD cbStruct; + FOURCC fccType; + FOURCC fccComp; + DWORD dwVersion; + DWORD dwFlags; + DWORD dwError; + LPCSTR pszSectionName; + LPCSTR pszAliasName; + DWORD dnDevNode; +} ACMDRVOPENDESCA, *PACMDRVOPENDESCA; + +typedef struct _ACMDRVOPENDESCW +{ + DWORD cbStruct; + FOURCC fccType; + FOURCC fccComp; + DWORD dwVersion; + DWORD dwFlags; + DWORD dwError; + LPCWSTR pszSectionName; + LPCWSTR pszAliasName; + DWORD dnDevNode; +} ACMDRVOPENDESCW, *PACMDRVOPENDESCW; + +typedef struct _ACMDRVOPENDESC16 +{ + DWORD cbStruct; + FOURCC fccType; + FOURCC fccComp; + DWORD dwVersion; + DWORD dwFlags; + DWORD dwError; + LPCSTR pszSectionName; + LPCSTR pszAliasName; + DWORD dnDevNode; +} ACMDRVOPENDESC16, *NPACMDRVOPENDESC16, *LPACMDRVOPENDESC16; + +typedef struct _ACMDRVSTREAMINSTANCE16 +{ + DWORD cbStruct; + LPWAVEFORMATEX pwfxSrc; + LPWAVEFORMATEX pwfxDst; + LPWAVEFILTER pwfltr; + DWORD dwCallback; + DWORD dwInstance; + DWORD fdwOpen; + DWORD fdwDriver; + DWORD dwDriver; + HACMSTREAM16 has; +} ACMDRVSTREAMINSTANCE16, *NPACMDRVSTREAMINSTANCE16, *LPACMDRVSTREAMINSTANCE16; + +typedef struct _ACMDRVSTREAMINSTANCE +{ + DWORD cbStruct; + PWAVEFORMATEX pwfxSrc; + PWAVEFORMATEX pwfxDst; + PWAVEFILTER pwfltr; + DWORD dwCallback; + DWORD dwInstance; + DWORD fdwOpen; + DWORD fdwDriver; + DWORD dwDriver; + HACMSTREAM has; +} ACMDRVSTREAMINSTANCE, *PACMDRVSTREAMINSTANCE; + + +typedef struct _ACMDRVSTREAMHEADER16 *LPACMDRVSTREAMHEADER16; +typedef struct _ACMDRVSTREAMHEADER16 { + DWORD cbStruct; + DWORD fdwStatus; + DWORD dwUser; + LPBYTE pbSrc; + DWORD cbSrcLength; + DWORD cbSrcLengthUsed; + DWORD dwSrcUser; + LPBYTE pbDst; + DWORD cbDstLength; + DWORD cbDstLengthUsed; + DWORD dwDstUser; + + DWORD fdwConvert; + LPACMDRVSTREAMHEADER16 *padshNext; + DWORD fdwDriver; + DWORD dwDriver; + + /* Internal fields for ACM */ + DWORD fdwPrepared; + DWORD dwPrepared; + LPBYTE pbPreparedSrc; + DWORD cbPreparedSrcLength; + LPBYTE pbPreparedDst; + DWORD cbPreparedDstLength; +} ACMDRVSTREAMHEADER16, *NPACMDRVSTREAMHEADER16; + +typedef struct _ACMDRVSTREAMHEADER *PACMDRVSTREAMHEADER; +typedef struct _ACMDRVSTREAMHEADER { + DWORD cbStruct; + DWORD fdwStatus; + DWORD dwUser; + LPBYTE pbSrc; + DWORD cbSrcLength; + DWORD cbSrcLengthUsed; + DWORD dwSrcUser; + LPBYTE pbDst; + DWORD cbDstLength; + DWORD cbDstLengthUsed; + DWORD dwDstUser; + + DWORD fdwConvert; + PACMDRVSTREAMHEADER *padshNext; + DWORD fdwDriver; + DWORD dwDriver; + + /* Internal fields for ACM */ + DWORD fdwPrepared; + DWORD dwPrepared; + LPBYTE pbPreparedSrc; + DWORD cbPreparedSrcLength; + LPBYTE pbPreparedDst; + DWORD cbPreparedDstLength; +} ACMDRVSTREAMHEADER; + +typedef struct _ACMDRVSTREAMSIZE +{ + DWORD cbStruct; + DWORD fdwSize; + DWORD cbSrcLength; + DWORD cbDstLength; +} ACMDRVSTREAMSIZE16, *NPACMDRVSTREAMSIZE16, *LPACMDRVSTREAMSIZE16, + ACMDRVSTREAMSIZE, *PACMDRVSTREAMSIZE; + +typedef struct _ACMDRVFORMATSUGGEST16 +{ + DWORD cbStruct; + DWORD fdwSuggest; + LPWAVEFORMATEX pwfxSrc; + DWORD cbwfxSrc; + LPWAVEFORMATEX pwfxDst; + DWORD cbwfxDst; +} ACMDRVFORMATSUGGEST16, *NPACMDRVFORMATSUGGEST, *LPACMDRVFORMATSUGGEST; + +typedef struct _ACMDRVFORMATSUGGEST +{ + DWORD cbStruct; + DWORD fdwSuggest; + PWAVEFORMATEX pwfxSrc; + DWORD cbwfxSrc; + PWAVEFORMATEX pwfxDst; + DWORD cbwfxDst; +} ACMDRVFORMATSUGGEST, *PACMDRVFORMATSUGGEST; + +#endif /* __WINE_MSACMDRV_H */ diff --git a/linphone/win32acm/wine/ntdef.h b/linphone/win32acm/wine/ntdef.h new file mode 100644 index 000000000..edf0af86c --- /dev/null +++ b/linphone/win32acm/wine/ntdef.h @@ -0,0 +1,101 @@ +#ifndef __WINE_NTDEF_H +#define __WINE_NTDEF_H + +#include "basetsd.h" +#include "windef.h" + +#include "pshpack1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NTAPI __stdcall + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef OPTIONAL +#define OPTIONAL +#endif + +#ifndef VOID +#define VOID void +#endif + +typedef LONG NTSTATUS; +typedef NTSTATUS *PNTSTATUS; + +typedef short CSHORT; +typedef CSHORT *PCSHORT; + +typedef WCHAR * PWCHAR; + +/* NT lowlevel Strings (handled by Rtl* functions in NTDLL) + * If they are zero terminated, Length does not include the terminating 0. + */ + +typedef struct _STRING { + USHORT Length; + USHORT MaximumLength; + PSTR Buffer; +} STRING,*PSTRING,ANSI_STRING,*PANSI_STRING; + +typedef struct _CSTRING { + USHORT Length; + USHORT MaximumLength; + PCSTR Buffer; +} CSTRING,*PCSTRING; + +typedef struct _UNICODE_STRING { + USHORT Length; /* bytes */ + USHORT MaximumLength; /* bytes */ + PWSTR Buffer; +} UNICODE_STRING,*PUNICODE_STRING; + +/* + Objects +*/ + +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_VALID_ATTRIBUTES 0x000003F2L + +typedef struct _OBJECT_ATTRIBUTES +{ ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; /* type SECURITY_DESCRIPTOR */ + PVOID SecurityQualityOfService; /* type SECURITY_QUALITY_OF_SERVICE */ +} OBJECT_ATTRIBUTES; + +typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; + +#define InitializeObjectAttributes(p,n,a,r,s) \ +{ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ +} + + +#ifdef __cplusplus +} +#endif + +#include "poppack.h" + +#endif diff --git a/linphone/win32acm/wine/pe_image.h b/linphone/win32acm/wine/pe_image.h new file mode 100644 index 000000000..3f550ba46 --- /dev/null +++ b/linphone/win32acm/wine/pe_image.h @@ -0,0 +1,81 @@ +#ifndef __WINE_PE_IMAGE_H +#define __WINE_PE_IMAGE_H + +#include "winnt.h" +#include "winbase.h" + +#define PE_HEADER(module) \ + ((IMAGE_NT_HEADERS*)((LPBYTE)(module) + \ + (((IMAGE_DOS_HEADER*)(module))->e_lfanew))) + +#define PE_SECTIONS(module) \ + ((IMAGE_SECTION_HEADER*)((LPBYTE)&PE_HEADER(module)->OptionalHeader + \ + PE_HEADER(module)->FileHeader.SizeOfOptionalHeader)) + +#define RVA_PTR(module,field) ((LPBYTE)(module) + PE_HEADER(module)->field) + +/* modreference used for attached processes + * all section are calculated here, relocations etc. + */ +typedef struct { + PIMAGE_IMPORT_DESCRIPTOR pe_import; + PIMAGE_EXPORT_DIRECTORY pe_export; + PIMAGE_RESOURCE_DIRECTORY pe_resource; + int tlsindex; +} PE_MODREF; + +struct _wine_modref; +extern int PE_unloadImage(HMODULE hModule); +extern FARPROC PE_FindExportedFunction(struct _wine_modref *wm, LPCSTR funcName, WIN_BOOL snoop); +extern WIN_BOOL PE_EnumResourceTypesA(HMODULE,ENUMRESTYPEPROCA,LONG); +extern WIN_BOOL PE_EnumResourceTypesW(HMODULE,ENUMRESTYPEPROCW,LONG); +extern WIN_BOOL PE_EnumResourceNamesA(HMODULE,LPCSTR,ENUMRESNAMEPROCA,LONG); +extern WIN_BOOL PE_EnumResourceNamesW(HMODULE,LPCWSTR,ENUMRESNAMEPROCW,LONG); +extern WIN_BOOL PE_EnumResourceLanguagesA(HMODULE,LPCSTR,LPCSTR,ENUMRESLANGPROCA,LONG); +extern WIN_BOOL PE_EnumResourceLanguagesW(HMODULE,LPCWSTR,LPCWSTR,ENUMRESLANGPROCW,LONG); +extern HRSRC PE_FindResourceExW(struct _wine_modref*,LPCWSTR,LPCWSTR,WORD); +extern DWORD PE_SizeofResource(HMODULE,HRSRC); +extern struct _wine_modref *PE_LoadLibraryExA(LPCSTR, DWORD); +extern void PE_UnloadLibrary(struct _wine_modref *); +extern HGLOBAL PE_LoadResource(struct _wine_modref *wm,HRSRC); +extern HMODULE PE_LoadImage( int hFile, LPCSTR filename, WORD *version ); +extern struct _wine_modref *PE_CreateModule( HMODULE hModule, LPCSTR filename, + DWORD flags, WIN_BOOL builtin ); +extern WIN_BOOL PE_CreateProcess( HANDLE hFile, LPCSTR filename, LPCSTR cmd_line, LPCSTR env, + LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, + WIN_BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, + LPPROCESS_INFORMATION info ); + +extern void PE_InitTls(void); +extern WIN_BOOL PE_InitDLL(struct _wine_modref *wm, DWORD type, LPVOID lpReserved); + +extern PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA(PIMAGE_RESOURCE_DIRECTORY,LPCSTR,DWORD,WIN_BOOL); +extern PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY,LPCWSTR,DWORD,WIN_BOOL); + +typedef DWORD CALLBACK (*DLLENTRYPROC)(HMODULE,DWORD,LPVOID); + +typedef struct { + WORD popl WINE_PACKED; /* 0x8f 0x05 */ + DWORD addr_popped WINE_PACKED;/* ... */ + BYTE pushl1 WINE_PACKED; /* 0x68 */ + DWORD newret WINE_PACKED; /* ... */ + BYTE pushl2 WINE_PACKED; /* 0x68 */ + DWORD origfun WINE_PACKED; /* original function */ + BYTE ret1 WINE_PACKED; /* 0xc3 */ + WORD addesp WINE_PACKED; /* 0x83 0xc4 */ + BYTE nrofargs WINE_PACKED; /* nr of arguments to add esp, */ + BYTE pushl3 WINE_PACKED; /* 0x68 */ + DWORD oldret WINE_PACKED; /* Filled out from popl above */ + BYTE ret2 WINE_PACKED; /* 0xc3 */ +} ELF_STDCALL_STUB; + +typedef struct { + void* dlhandle; + ELF_STDCALL_STUB *stubs; +} ELF_MODREF; + +extern struct _wine_modref *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags); +extern void ELF_UnloadLibrary(struct _wine_modref *); +extern FARPROC ELF_FindExportedFunction(struct _wine_modref *wm, LPCSTR funcName); + +#endif /* __WINE_PE_IMAGE_H */ diff --git a/linphone/win32acm/wine/poppack.h b/linphone/win32acm/wine/poppack.h new file mode 100644 index 000000000..710479159 --- /dev/null +++ b/linphone/win32acm/wine/poppack.h @@ -0,0 +1,15 @@ +#ifdef __WINE_PSHPACK_H +#undef __WINE_PSHPACK_H + +#if defined(__GNUC__) || defined(__SUNPRO_C) +#pragma pack() +#elif defined(__SUNPRO_CC) +#warning "Assumes default alignment is 4" +#pragma pack(4) +#elif !defined(RC_INVOKED) +#error "Restoration of the previous alignment isn't supported by the compiler" +#endif /* defined(__GNUC__) || defined(__SUNPRO_C) ; !defined(RC_INVOKED) */ + +#else /* defined(__WINE_PSHPACK_H) */ +#error "Popping alignment isn't possible since no alignment has been pushed" +#endif /* defined(__WINE_PSHPACK_H) */ diff --git a/linphone/win32acm/wine/pshpack1.h b/linphone/win32acm/wine/pshpack1.h new file mode 100644 index 000000000..e560250c2 --- /dev/null +++ b/linphone/win32acm/wine/pshpack1.h @@ -0,0 +1,13 @@ +#ifndef __WINE_PSHPACK_H +#define __WINE_PSHPACK_H 1 + +#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +//#pragma pack(1) +#elif !defined(RC_INVOKED) +#error "1 as alignment isn't supported by the compiler" +#endif /* defined(__GNUC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) ; !defined(RC_INVOKED) */ + +#else /* !defined(__WINE_PSHPACK_H) */ +#error "Nested pushing of alignment isn't supported by the compiler" +#endif /* !defined(__WINE_PSHPACK_H) */ + diff --git a/linphone/win32acm/wine/pshpack2.h b/linphone/win32acm/wine/pshpack2.h new file mode 100644 index 000000000..887b1e17b --- /dev/null +++ b/linphone/win32acm/wine/pshpack2.h @@ -0,0 +1,12 @@ +#ifndef __WINE_PSHPACK_H +#define __WINE_PSHPACK_H 2 + +#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +//#pragma pack(2) +#elif !defined(RC_INVOKED) +#error "2 as alignment isn't supported by the compiler" +#endif /* defined(__GNUC__) || defined(__SUNPRO_CC) ; !defined(RC_INVOKED) */ + +#else /* !defined(__WINE_PSHPACK_H) */ +#error "Nested pushing of alignment isn't supported by the compiler" +#endif /* !defined(__WINE_PSHPACK_H) */ diff --git a/linphone/win32acm/wine/pshpack4.h b/linphone/win32acm/wine/pshpack4.h new file mode 100644 index 000000000..9fdaf70a7 --- /dev/null +++ b/linphone/win32acm/wine/pshpack4.h @@ -0,0 +1,15 @@ +#ifndef __WINE_PSHPACK_H +#define __WINE_PSHPACK_H 4 + +#if defined(__GNUC__) || defined(__SUNPRO_CC) +//#pragma pack(4) +#elif defined(__SUNPRO_C) +//#pragma pack() +#elif !defined(RC_INVOKED) +#error "4 as alignment isn't supported by the compiler" +#endif /* defined(__GNUC__) || defined(__SUNPRO_CC) ; !defined(RC_INVOKED) */ + +#else /* !defined(__WINE_PSHPACK_H) */ +#error "Nested pushing of alignment isn't supported by the compiler" +#endif /* !defined(__WINE_PSHPACK_H) */ + diff --git a/linphone/win32acm/wine/pshpack8.h b/linphone/win32acm/wine/pshpack8.h new file mode 100644 index 000000000..74d13a472 --- /dev/null +++ b/linphone/win32acm/wine/pshpack8.h @@ -0,0 +1,12 @@ +#ifndef __WINE_PSHPACK_H +#define __WINE_PSHPACK_H 8 + +#if 0 +//#pragma pack(8) +#elif !defined(RC_INVOKED) +#error "8 as alignment is not supported" +#endif /* 0 ; !defined(RC_INVOKED) */ + +#else /* !defined(__WINE_PSHPACK_H) */ +#error "Nested pushing of alignment isn't supported by the compiler" +#endif /* !defined(__WINE_PSHPACK_H) */ diff --git a/linphone/win32acm/wine/vfw.h b/linphone/win32acm/wine/vfw.h new file mode 100644 index 000000000..cfaf46ee8 --- /dev/null +++ b/linphone/win32acm/wine/vfw.h @@ -0,0 +1,668 @@ +#ifndef __WINE_VFW_H +#define __WINE_VFW_H +//#include "pshpack1.h" +#ifdef __cplusplus +extern "C" { +#endif +#ifndef __WINE_WINGDI_H + +typedef struct __attribute__((__packed__)) +{ + short bfType; + long bfSize; + short bfReserved1; + short bfReserved2; + long bfOffBits; +} BITMAPFILEHEADER; + +#ifndef _BITMAPINFOHEADER_ +#define _BITMAPINFOHEADER_ +typedef struct __attribute__((__packed__)) +{ + int biSize; + int biWidth; + int biHeight; + short biPlanes; + short biBitCount; + int biCompression; + int biSizeImage; + int biXPelsPerMeter; + int biYPelsPerMeter; + int biClrUsed; + int biClrImportant; +} BITMAPINFOHEADER, *PBITMAPINFOHEADER, *LPBITMAPINFOHEADER; +typedef struct { + BITMAPINFOHEADER bmiHeader; + int bmiColors[1]; +} BITMAPINFO, *LPBITMAPINFO; +#endif + +#endif +#define VFWAPI +#define VFWAPIV +#ifndef __WINE_WINDEF_H +typedef long (__stdcall__ *DRIVERPROC)(long,HDRVR,unsigned int,long,long); +#endif + + + +#ifndef mmioFOURCC +#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \ + ( (long)(unsigned char)(ch0) | ( (long)(unsigned char)(ch1) << 8 ) | \ + ( (long)(unsigned char)(ch2) << 16 ) | ( (long)(unsigned char)(ch3) << 24 ) ) +#endif + +#ifndef aviTWOCC +#define aviTWOCC(ch0, ch1) ((short)(unsigned char)(ch0) | ((short)(unsigned char)(ch1) << 8)) +#endif + +#define ICTYPE_VIDEO mmioFOURCC('v', 'i', 'd', 'c') +#define ICTYPE_AUDIO mmioFOURCC('a', 'u', 'd', 'c') + + +/* Installable Compressor M? */ + +/* HIC struct (same layout as Win95 one) */ +typedef struct tagWINE_HIC { + long magic; /* 00: 'Smag' */ + HANDLE curthread; /* 04: */ + long type; /* 08: */ + long handler; /* 0C: */ + HDRVR hdrv; /* 10: */ + long driverid; /* 14:(handled by SendDriverMessage)*/ + DRIVERPROC driverproc; /* 18:(handled by SendDriverMessage)*/ + long x1; /* 1c: name? */ + short x2; /* 20: */ + long x3; /* 22: */ + /* 26: */ +} WINE_HIC; + +/* error return codes */ +#define ICERR_OK 0 +#define ICERR_DONTDRAW 1 +#define ICERR_NEWPALETTE 2 +#define ICERR_GOTOKEYFRAME 3 +#define ICERR_STOPDRAWING 4 + +#define ICERR_UNSUPPORTED -1 +#define ICERR_BADFORMAT -2 +#define ICERR_MEMORY -3 +#define ICERR_INTERNAL -4 +#define ICERR_BADFLAGS -5 +#define ICERR_BADPARAM -6 +#define ICERR_BADSIZE -7 +#define ICERR_BADHANDLE -8 +#define ICERR_CANTUPDATE -9 +#define ICERR_ABORT -10 +#define ICERR_ERROR -100 +#define ICERR_BADBITDEPTH -200 +#define ICERR_BADIMAGESIZE -201 + +#define ICERR_CUSTOM -400 + +/* ICM Messages */ +#define ICM_USER (DRV_USER+0x0000) + +/* ICM driver message range */ +#define ICM_RESERVED_LOW (DRV_USER+0x1000) +#define ICM_RESERVED_HIGH (DRV_USER+0x2000) +#define ICM_RESERVED ICM_RESERVED_LOW + +#define ICM_GETSTATE (ICM_RESERVED+0) +#define ICM_SETSTATE (ICM_RESERVED+1) +#define ICM_GETINFO (ICM_RESERVED+2) + +#define ICM_CONFIGURE (ICM_RESERVED+10) +#define ICM_ABOUT (ICM_RESERVED+11) +/* */ + +#define ICM_GETDEFAULTQUALITY (ICM_RESERVED+30) +#define ICM_GETQUALITY (ICM_RESERVED+31) +#define ICM_SETQUALITY (ICM_RESERVED+32) + +#define ICM_SET (ICM_RESERVED+40) +#define ICM_GET (ICM_RESERVED+41) + +/* 2 constant FOURCC codes */ +#define ICM_FRAMERATE mmioFOURCC('F','r','m','R') +#define ICM_KEYFRAMERATE mmioFOURCC('K','e','y','R') + +#define ICM_COMPRESS_GET_FORMAT (ICM_USER+4) +#define ICM_COMPRESS_GET_SIZE (ICM_USER+5) +#define ICM_COMPRESS_QUERY (ICM_USER+6) +#define ICM_COMPRESS_BEGIN (ICM_USER+7) +#define ICM_COMPRESS (ICM_USER+8) +#define ICM_COMPRESS_END (ICM_USER+9) + +#define ICM_DECOMPRESS_GET_FORMAT (ICM_USER+10) +#define ICM_DECOMPRESS_QUERY (ICM_USER+11) +#define ICM_DECOMPRESS_BEGIN (ICM_USER+12) +#define ICM_DECOMPRESS (ICM_USER+13) +#define ICM_DECOMPRESS_END (ICM_USER+14) +#define ICM_DECOMPRESS_SET_PALETTE (ICM_USER+29) +#define ICM_DECOMPRESS_GET_PALETTE (ICM_USER+30) + +#define ICM_DRAW_QUERY (ICM_USER+31) +#define ICM_DRAW_BEGIN (ICM_USER+15) +#define ICM_DRAW_GET_PALETTE (ICM_USER+16) +#define ICM_DRAW_START (ICM_USER+18) +#define ICM_DRAW_STOP (ICM_USER+19) +#define ICM_DRAW_END (ICM_USER+21) +#define ICM_DRAW_GETTIME (ICM_USER+32) +#define ICM_DRAW (ICM_USER+33) +#define ICM_DRAW_WINDOW (ICM_USER+34) +#define ICM_DRAW_SETTIME (ICM_USER+35) +#define ICM_DRAW_REALIZE (ICM_USER+36) +#define ICM_DRAW_FLUSH (ICM_USER+37) +#define ICM_DRAW_RENDERBUFFER (ICM_USER+38) + +#define ICM_DRAW_START_PLAY (ICM_USER+39) +#define ICM_DRAW_STOP_PLAY (ICM_USER+40) + +#define ICM_DRAW_SUGGESTFORMAT (ICM_USER+50) +#define ICM_DRAW_CHANGEPALETTE (ICM_USER+51) + +#define ICM_GETBUFFERSWANTED (ICM_USER+41) + +#define ICM_GETDEFAULTKEYFRAMERATE (ICM_USER+42) + +#define ICM_DECOMPRESSEX_BEGIN (ICM_USER+60) +#define ICM_DECOMPRESSEX_QUERY (ICM_USER+61) +#define ICM_DECOMPRESSEX (ICM_USER+62) +#define ICM_DECOMPRESSEX_END (ICM_USER+63) + +#define ICM_COMPRESS_FRAMES_INFO (ICM_USER+70) +#define ICM_SET_STATUS_PROC (ICM_USER+72) + +/* structs */ + +typedef struct { + long dwSize; /* 00: size */ + long fccType; /* 04: type 'vidc' usually */ + long fccHandler; /* 08: */ + long dwVersion; /* 0c: version of compman opening you */ + long dwFlags; /* 10: LOshort is type specific */ + LRESULT dwError; /* 14: */ + void* pV1Reserved; /* 18: */ + void* pV2Reserved; /* 1c: */ + long dnDevNode; /* 20: */ + /* 24: */ +} ICOPEN,*LPICOPEN; + +#define ICCOMPRESS_KEYFRAME 0x00000001L + +typedef struct { + long dwFlags; + LPBITMAPINFOHEADER lpbiOutput; + void* lpOutput; + LPBITMAPINFOHEADER lpbiInput; + const void* lpInput; + long* lpckid; + long* lpdwFlags; + long lFrameNum; + long dwFrameSize; + long dwQuality; + LPBITMAPINFOHEADER lpbiPrev; + void* lpPrev; +} ICCOMPRESS; + +long VFWAPIV ICCompress( + HIC hic,long dwFlags,LPBITMAPINFOHEADER lpbiOutput,void* lpData, + LPBITMAPINFOHEADER lpbiInput,void* lpBits,long* lpckid, + long* lpdwFlags,long lFrameNum,long dwFrameSize,long dwQuality, + LPBITMAPINFOHEADER lpbiPrev,void* lpPrev +); + + +#define ICCompressGetFormat(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic,ICM_COMPRESS_GET_FORMAT,(long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + ) + +#define ICCompressGetFormatSize(hic,lpbi) ICCompressGetFormat(hic,lpbi,NULL) + +#define ICGetDefaultKeyFrameRate(hic,lpint) \ + ICSendMessage( \ + hic, ICM_GETDEFAULTKEYFRAMERATE, \ + (long)(void*)(lpint), \ + 0 ) + +#define ICGetDefaultQuality(hic,lpint) \ + ICSendMessage( \ + hic, ICM_GETDEFAULTQUALITY, \ + (long)(void*)(lpint), \ + 0 ) + + +#define ICCompressBegin(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic, ICM_COMPRESS_BEGIN, (long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + ) + +#define ICCompressGetSize(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic, ICM_COMPRESS_GET_SIZE, (long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + ) + +#define ICCompressQuery(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic, ICM_COMPRESS_QUERY, (long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + ) + + +#define ICCompressEnd(hic) ICSendMessage(hic, ICM_COMPRESS_END, 0, 0) + +/* ICCOMPRESSFRAMES.dwFlags */ +#define ICCOMPRESSFRAMES_PADDING 0x00000001 +typedef struct { + long dwFlags; + LPBITMAPINFOHEADER lpbiOutput; + LPARAM lOutput; + LPBITMAPINFOHEADER lpbiInput; + LPARAM lInput; + long lStartFrame; + long lFrameCount; + long lQuality; + long lDataRate; + long lKeyRate; + long dwRate; + long dwScale; + long dwOverheadPerFrame; + long dwReserved2; + long CALLBACK (*GetData)(LPARAM lInput,long lFrame,void* lpBits,long len); + long CALLBACK (*PutData)(LPARAM lOutput,long lFrame,void* lpBits,long len); +} ICCOMPRESSFRAMES; + +/* Values for wMode of ICOpen() */ +#define ICMODE_COMPRESS 1 +#define ICMODE_DECOMPRESS 2 +#define ICMODE_FASTDECOMPRESS 3 +#define ICMODE_QUERY 4 +#define ICMODE_FASTCOMPRESS 5 +#define ICMODE_DRAW 8 + +/* quality flags */ +#define ICQUALITY_LOW 0 +#define ICQUALITY_HIGH 10000 +#define ICQUALITY_DEFAULT -1 + +typedef struct { + long dwSize; /* 00: */ + long fccType; /* 04:compressor type 'vidc' 'audc' */ + long fccHandler; /* 08:compressor sub-type 'rle ' 'jpeg' 'pcm '*/ + long dwFlags; /* 0c:flags LOshort is type specific */ + long dwVersion; /* 10:version of the driver */ + long dwVersionICM; /* 14:version of the ICM used */ + /* + * under Win32, the driver always returns UNICODE strings. + */ + WCHAR szName[16]; /* 18:short name */ + WCHAR szDescription[128]; /* 38:long name */ + WCHAR szDriver[128]; /* 138:driver that contains compressor*/ + /* 238: */ +} ICINFO; + +/* ICINFO.dwFlags */ +#define VIDCF_QUALITY 0x0001 /* supports quality */ +#define VIDCF_CRUNCH 0x0002 /* supports crunching to a frame size */ +#define VIDCF_TEMPORAL 0x0004 /* supports inter-frame compress */ +#define VIDCF_COMPRESSFRAMES 0x0008 /* wants the compress all frames message */ +#define VIDCF_DRAW 0x0010 /* supports drawing */ +#define VIDCF_FASTTEMPORALC 0x0020 /* does not need prev frame on compress */ +#define VIDCF_FASTTEMPORALD 0x0080 /* does not need prev frame on decompress */ +#define VIDCF_QUALITYTIME 0x0040 /* supports temporal quality */ + +#define VIDCF_FASTTEMPORAL (VIDCF_FASTTEMPORALC|VIDCF_FASTTEMPORALD) + + +/* function shortcuts */ +/* ICM_ABOUT */ +#define ICMF_ABOUT_QUERY 0x00000001 + +#define ICQueryAbout(hic) \ + (ICSendMessage(hic,ICM_ABOUT,(long)-1,ICMF_ABOUT_QUERY)==ICERR_OK) + +#define ICAbout(hic, hwnd) ICSendMessage(hic,ICM_ABOUT,(long)(unsigned int)(hwnd),0) + +/* ICM_CONFIGURE */ +#define ICMF_CONFIGURE_QUERY 0x00000001 +#define ICQueryConfigure(hic) \ + (ICSendMessage(hic,ICM_CONFIGURE,(long)-1,ICMF_CONFIGURE_QUERY)==ICERR_OK) + +#define ICConfigure(hic,hwnd) \ + ICSendMessage(hic,ICM_CONFIGURE,(long)(unsigned int)(hwnd),0) + +/* Decompression stuff */ +#define ICDECOMPRESS_HURRYUP 0x80000000 /* don't draw just buffer (hurry up!) */ +#define ICDECOMPRESS_UPDATE 0x40000000 /* don't draw just update screen */ +#define ICDECOMPRESS_PREROL 0x20000000 /* this frame is before real start */ +#define ICDECOMPRESS_NULLFRAME 0x10000000 /* repeat last frame */ +#define ICDECOMPRESS_NOTKEYFRAME 0x08000000 /* this frame is not a key frame */ + +typedef struct { + long dwFlags; /* flags (from AVI index...) */ + LPBITMAPINFOHEADER lpbiInput; /* BITMAPINFO of compressed data */ + const void* lpInput; /* compressed data */ + LPBITMAPINFOHEADER lpbiOutput; /* DIB to decompress to */ + void* lpOutput; + long ckid; /* ckid from AVI file */ +} ICDECOMPRESS; + +typedef struct { + long dwFlags; + LPBITMAPINFOHEADER lpbiSrc; + const void* lpSrc; + LPBITMAPINFOHEADER lpbiDst; + void* lpDst; + + /* changed for ICM_DECOMPRESSEX */ + INT xDst; /* destination rectangle */ + INT yDst; + INT dxDst; + INT dyDst; + + INT xSrc; /* source rectangle */ + INT ySrc; + INT dxSrc; + INT dySrc; +} ICDECOMPRESSEX; + + +long VFWAPIV ICDecompress(HIC hic,long dwFlags,LPBITMAPINFOHEADER lpbiFormat,void* lpData,LPBITMAPINFOHEADER lpbi,void* lpBits); +long VFWAPIV ICDecompressEx(HIC hic,long dwFlags,LPBITMAPINFOHEADER lpbiFormat,void* lpData,LPBITMAPINFOHEADER lpbi,void* lpBits); +long VFWAPIV ICUniversalEx(HIC hic,int command,LPBITMAPINFOHEADER lpbiFormat,LPBITMAPINFOHEADER lpbi); + + +#define ICDecompressBegin(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic, ICM_DECOMPRESS_BEGIN, (long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + ) + +#define ICDecompressBeginEx(hic, lpbiInput, lpbiOutput) \ + ICUniversalEx( \ + hic, ICM_DECOMPRESSEX_BEGIN, (lpbiInput), \ + (lpbiOutput) \ + ) + +#define ICDecompressQuery(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic,ICM_DECOMPRESS_QUERY, (long)(void*)(lpbiInput), \ + (long) (void*)(lpbiOutput) \ + ) + +#define ICDecompressQueryEx(hic, lpbiInput, lpbiOutput) \ + ICUniversalEx( \ + hic,ICM_DECOMPRESSEX_QUERY, (lpbiInput), \ + (lpbiOutput) \ + ) + +#define ICDecompressGetFormat(hic, lpbiInput, lpbiOutput) \ + ((long)ICSendMessage( \ + hic,ICM_DECOMPRESS_GET_FORMAT, (long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + )) + +#define ICDecompressGetFormatSize(hic, lpbi) \ + ICDecompressGetFormat(hic, lpbi, NULL) + +#define ICDecompressGetPalette(hic, lpbiInput, lpbiOutput) \ + ICSendMessage( \ + hic, ICM_DECOMPRESS_GET_PALETTE, (long)(void*)(lpbiInput), \ + (long)(void*)(lpbiOutput) \ + ) + +#define ICDecompressSetPalette(hic,lpbiPalette) \ + ICSendMessage( \ + hic,ICM_DECOMPRESS_SET_PALETTE, \ + (long)(void*)(lpbiPalette),0 \ + ) + +#define ICDecompressEnd(hic) ICSendMessage(hic, ICM_DECOMPRESS_END, 0, 0) +#define ICDecompressEndEx(hic) ICSendMessage(hic,ICM_DECOMPRESSEX_END, 0, 0) + +#define ICDRAW_QUERY 0x00000001L /* test for support */ +#define ICDRAW_FULLSCREEN 0x00000002L /* draw to full screen */ +#define ICDRAW_HDC 0x00000004L /* draw to a HDC/HWND */ + + +WIN_BOOL VFWAPI ICInfo(long fccType, long fccHandler, ICINFO * lpicinfo); +LRESULT VFWAPI ICGetInfo(HIC hic,ICINFO *picinfo, long cb); +HIC VFWAPI ICOpen(long fccType, long fccHandler, UINT wMode); +//HIC VFWAPI ICOpenFunction(long fccType, long fccHandler, unsigned int wMode, void* lpfnHandler); + +LRESULT VFWAPI ICClose(HIC hic); +LRESULT VFWAPI ICSendMessage(HIC hic, unsigned int msg, long dw1, long dw2); +//HIC VFWAPI ICLocate(long fccType, long fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, short wFlags); + +int VFWAPI ICDoSomething(void); + +long VFWAPIV ICDrawBegin( + HIC hic, + long dwFlags,/* flags */ + HPALETTE hpal, /* palette to draw with */ + HWND hwnd, /* window to draw to */ + HDC hdc, /* HDC to draw to */ + INT xDst, /* destination rectangle */ + INT yDst, + INT dxDst, + INT dyDst, + LPBITMAPINFOHEADER lpbi, /* format of frame to draw */ + INT xSrc, /* source rectangle */ + INT ySrc, + INT dxSrc, + INT dySrc, + long dwRate, /* frames/second = (dwRate/dwScale) */ + long dwScale +); + +/* as passed to ICM_DRAW_BEGIN (FIXME: correct only for Win32?) */ +typedef struct { + long dwFlags; + HPALETTE hpal; + HWND hwnd; + HDC hdc; + INT xDst; + INT yDst; + INT dxDst; + INT dyDst; + LPBITMAPINFOHEADER lpbi; + INT xSrc; + INT ySrc; + INT dxSrc; + INT dySrc; + long dwRate; + long dwScale; +} ICDRAWBEGIN; + +#define ICDRAW_HURRYUP 0x80000000L /* don't draw just buffer (hurry up!) */ +#define ICDRAW_UPDATE 0x40000000L /* don't draw just update screen */ +#define ICDRAW_PREROLL 0x20000000L /* this frame is before real start */ +#define ICDRAW_NULLFRAME 0x10000000L /* repeat last frame */ +#define ICDRAW_NOTKEYFRAME 0x08000000L /* this frame is not a key frame */ + +typedef struct { + long dwFlags; + void* lpFormat; + void* lpData; + long cbData; + long lTime; +} ICDRAW; + +long VFWAPIV ICDraw(HIC hic,long dwFlags,void* lpFormat,void* lpData,long cbData,long lTime); + + +#define AVIGETFRAMEF_BESTDISPLAYFMT 1 + +typedef struct _AVISTREAMINFOA { + long fccType; + long fccHandler; + long dwFlags; /* AVIIF_* */ + long dwCaps; + short wPriority; + short wLanguage; + long dwScale; + long dwRate; /* dwRate / dwScale == samples/second */ + long dwStart; + long dwLength; /* In units above... */ + long dwInitialFrames; + long dwSuggestedBufferSize; + long dwQuality; + long dwSampleSize; + RECT rcFrame; + long dwEditCount; + long dwFormatChangeCount; + char szName[64]; +} AVISTREAMINFOA, * LPAVISTREAMINFOA, *PAVISTREAMINFOA; + +typedef struct _AVISTREAMINFOW { + long fccType; + long fccHandler; + long dwFlags; + long dwCaps; + short wPriority; + short wLanguage; + long dwScale; + long dwRate; /* dwRate / dwScale == samples/second */ + long dwStart; + long dwLength; /* In units above... */ + long dwInitialFrames; + long dwSuggestedBufferSize; + long dwQuality; + long dwSampleSize; + RECT rcFrame; + long dwEditCount; + long dwFormatChangeCount; + short szName[64]; +} AVISTREAMINFOW, * LPAVISTREAMINFOW, *PAVISTREAMINFOW; +DECL_WINELIB_TYPE_AW(AVISTREAMINFO) +DECL_WINELIB_TYPE_AW(LPAVISTREAMINFO) +DECL_WINELIB_TYPE_AW(PAVISTREAMINFO) + +#define AVISTREAMINFO_DISABLED 0x00000001 +#define AVISTREAMINFO_FORMATCHANGES 0x00010000 + +/* AVIFILEINFO.dwFlags */ +#define AVIFILEINFO_HASINDEX 0x00000010 +#define AVIFILEINFO_MUSTUSEINDEX 0x00000020 +#define AVIFILEINFO_ISINTERLEAVED 0x00000100 +#define AVIFILEINFO_WASCAPTUREFILE 0x00010000 +#define AVIFILEINFO_COPYRIGHTED 0x00020000 + +/* AVIFILEINFO.dwCaps */ +#define AVIFILECAPS_CANREAD 0x00000001 +#define AVIFILECAPS_CANWRITE 0x00000002 +#define AVIFILECAPS_ALLKEYFRAMES 0x00000010 +#define AVIFILECAPS_NOCOMPRESSION 0x00000020 + +typedef struct _AVIFILEINFOW { + long dwMaxBytesPerSec; + long dwFlags; + long dwCaps; + long dwStreams; + long dwSuggestedBufferSize; + long dwWidth; + long dwHeight; + long dwScale; + long dwRate; + long dwLength; + long dwEditCount; + short szFileType[64]; +} AVIFILEINFOW, * LPAVIFILEINFOW, *PAVIFILEINFOW; + +typedef struct _AVIFILEINFOA { + long dwMaxBytesPerSec; + long dwFlags; + long dwCaps; + long dwStreams; + long dwSuggestedBufferSize; + long dwWidth; + long dwHeight; + long dwScale; + long dwRate; + long dwLength; + long dwEditCount; + char szFileType[64]; +} AVIFILEINFOA, * LPAVIFILEINFOA, *PAVIFILEINFOA; + +DECL_WINELIB_TYPE_AW(AVIFILEINFO) +DECL_WINELIB_TYPE_AW(PAVIFILEINFO) +DECL_WINELIB_TYPE_AW(LPAVIFILEINFO) + +/* AVICOMPRESSOPTIONS.dwFlags. determines presence of fields in below struct */ +#define AVICOMPRESSF_INTERLEAVE 0x00000001 +#define AVICOMPRESSF_DATARATE 0x00000002 +#define AVICOMPRESSF_KEYFRAMES 0x00000004 +#define AVICOMPRESSF_VALID 0x00000008 + +typedef struct { + long fccType; /* stream type, for consistency */ + long fccHandler; /* compressor */ + long dwKeyFrameEvery; /* keyframe rate */ + long dwQuality; /* compress quality 0-10,000 */ + long dwBytesPerSecond; /* unsigned chars per second */ + long dwFlags; /* flags... see below */ + void* lpFormat; /* save format */ + long cbFormat; + void* lpParms; /* compressor options */ + long cbParms; + long dwInterleaveEvery; /* for non-video streams only */ +} AVICOMPRESSOPTIONS, *LPAVICOMPRESSOPTIONS,*PAVICOMPRESSOPTIONS; + + + +typedef struct { + long cbSize; // set to sizeof(COMPVARS) before + // calling ICCompressorChoose + long dwFlags; // see below... + HIC hic; // HIC of chosen compressor + long fccType; // basically ICTYPE_VIDEO + long fccHandler; // handler of chosen compressor or + // "" or "DIB " + LPBITMAPINFO lpbiIn; // input format + LPBITMAPINFO lpbiOut; // output format - will compress to this + void* lpBitsOut; + void* lpBitsPrev; + long lFrame; + long lKey; // key frames how often? + long lDataRate; // desired data rate KB/Sec + long lQ; // desired quality + long lKeyCount; + void* lpState; // state of compressor + long cbState; // size of the state +} COMPVARS, *PCOMPVARS; + +// FLAGS for dwFlags element of COMPVARS structure: + + +#define AVIERR_OK 0 +#define MAKE_AVIERR(error) MAKE_SCODE(SEVERITY_ERROR,FACILITY_ITF,0x4000+error) + +#define AVIERR_UNSUPPORTED MAKE_AVIERR(101) +#define AVIERR_BADFORMAT MAKE_AVIERR(102) +#define AVIERR_MEMORY MAKE_AVIERR(103) +#define AVIERR_INTERNAL MAKE_AVIERR(104) +#define AVIERR_BADFLAGS MAKE_AVIERR(105) +#define AVIERR_BADPARAM MAKE_AVIERR(106) +#define AVIERR_BADSIZE MAKE_AVIERR(107) +#define AVIERR_BADHANDLE MAKE_AVIERR(108) +#define AVIERR_FILEREAD MAKE_AVIERR(109) +#define AVIERR_FILEWRITE MAKE_AVIERR(110) +#define AVIERR_FILEOPEN MAKE_AVIERR(111) +#define AVIERR_COMPRESSOR MAKE_AVIERR(112) +#define AVIERR_NOCOMPRESSOR MAKE_AVIERR(113) +#define AVIERR_READONLY MAKE_AVIERR(114) +#define AVIERR_NODATA MAKE_AVIERR(115) +#define AVIERR_BUFFERTOOSMALL MAKE_AVIERR(116) +#define AVIERR_CANTCOMPRESS MAKE_AVIERR(117) +#define AVIERR_USERABORT MAKE_AVIERR(198) +#define AVIERR_ERROR MAKE_AVIERR(199) + +#ifdef __cplusplus +} +#endif +#endif /* __WINE_VFW_H */ diff --git a/linphone/win32acm/wine/winbase.h b/linphone/win32acm/wine/winbase.h new file mode 100644 index 000000000..8746da891 --- /dev/null +++ b/linphone/win32acm/wine/winbase.h @@ -0,0 +1,1791 @@ +#ifndef __WINE_WINBASE_H +#define __WINE_WINBASE_H + +#include "basetsd.h" +#include "winnt.h" +#include "winestring.h" +#include "pshpack1.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct tagCOORD { + INT16 x; + INT16 y; +} COORD, *LPCOORD; + + + /* Windows Exit Procedure flag values */ +#define WEP_FREE_DLL 0 +#define WEP_SYSTEM_EXIT 1 + +typedef DWORD CALLBACK (*LPTHREAD_START_ROUTINE)(LPVOID); + +#define EXCEPTION_DEBUG_EVENT 1 +#define CREATE_THREAD_DEBUG_EVENT 2 +#define CREATE_PROCESS_DEBUG_EVENT 3 +#define EXIT_THREAD_DEBUG_EVENT 4 +#define EXIT_PROCESS_DEBUG_EVENT 5 +#define LOAD_DLL_DEBUG_EVENT 6 +#define UNLOAD_DLL_DEBUG_EVENT 7 +#define OUTPUT_DEBUG_STRING_EVENT 8 +#define RIP_EVENT 9 + +typedef struct _EXCEPTION_DEBUG_INFO { + EXCEPTION_RECORD ExceptionRecord; + DWORD dwFirstChance; +} EXCEPTION_DEBUG_INFO; + +typedef struct _CREATE_THREAD_DEBUG_INFO { + HANDLE hThread; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; +} CREATE_THREAD_DEBUG_INFO; + +typedef struct _CREATE_PROCESS_DEBUG_INFO { + HANDLE hFile; + HANDLE hProcess; + HANDLE hThread; + LPVOID lpBaseOfImage; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + LPVOID lpImageName; + WORD fUnicode; +} CREATE_PROCESS_DEBUG_INFO; + +typedef struct _EXIT_THREAD_DEBUG_INFO { + DWORD dwExitCode; +} EXIT_THREAD_DEBUG_INFO; + +typedef struct _EXIT_PROCESS_DEBUG_INFO { + DWORD dwExitCode; +} EXIT_PROCESS_DEBUG_INFO; + +typedef struct _LOAD_DLL_DEBUG_INFO { + HANDLE hFile; + LPVOID lpBaseOfDll; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpImageName; + WORD fUnicode; +} LOAD_DLL_DEBUG_INFO; + +typedef struct _UNLOAD_DLL_DEBUG_INFO { + LPVOID lpBaseOfDll; +} UNLOAD_DLL_DEBUG_INFO; + +typedef struct _OUTPUT_DEBUG_STRING_INFO { + LPSTR lpDebugStringData; + WORD fUnicode; + WORD nDebugStringLength; +} OUTPUT_DEBUG_STRING_INFO; + +typedef struct _RIP_INFO { + DWORD dwError; + DWORD dwType; +} RIP_INFO; + +typedef struct _DEBUG_EVENT { + DWORD dwDebugEventCode; + DWORD dwProcessId; + DWORD dwThreadId; + union { + EXCEPTION_DEBUG_INFO Exception; + CREATE_THREAD_DEBUG_INFO CreateThread; + CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; + EXIT_THREAD_DEBUG_INFO ExitThread; + EXIT_PROCESS_DEBUG_INFO ExitProcess; + LOAD_DLL_DEBUG_INFO LoadDll; + UNLOAD_DLL_DEBUG_INFO UnloadDll; + OUTPUT_DEBUG_STRING_INFO DebugString; + RIP_INFO RipInfo; + } u; +} DEBUG_EVENT, *LPDEBUG_EVENT; + +#define OFS_MAXPATHNAME 128 +typedef struct +{ + BYTE cBytes; + BYTE fFixedDisk; + WORD nErrCode; + BYTE reserved[4]; + BYTE szPathName[OFS_MAXPATHNAME]; +} OFSTRUCT, *LPOFSTRUCT; + +#define OF_READ 0x0000 +#define OF_WRITE 0x0001 +#define OF_READWRITE 0x0002 +#define OF_SHARE_COMPAT 0x0000 +#define OF_SHARE_EXCLUSIVE 0x0010 +#define OF_SHARE_DENY_WRITE 0x0020 +#define OF_SHARE_DENY_READ 0x0030 +#define OF_SHARE_DENY_NONE 0x0040 +#define OF_PARSE 0x0100 +#define OF_DELETE 0x0200 +#define OF_VERIFY 0x0400 /* Used with OF_REOPEN */ +#define OF_SEARCH 0x0400 /* Used without OF_REOPEN */ +#define OF_CANCEL 0x0800 +#define OF_CREATE 0x1000 +#define OF_PROMPT 0x2000 +#define OF_EXIST 0x4000 +#define OF_REOPEN 0x8000 + +/* SetErrorMode values */ +#define SEM_FAILCRITICALERRORS 0x0001 +#define SEM_NOGPFAULTERRORBOX 0x0002 +#define SEM_NOALIGNMENTFAULTEXCEPT 0x0004 +#define SEM_NOOPENFILEERRORBOX 0x8000 + +/* CopyFileEx flags */ +#define COPY_FILE_FAIL_IF_EXISTS 0x00000001 +#define COPY_FILE_RESTARTABLE 0x00000002 +#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x00000004 + +/* GetTempFileName() Flags */ +#define TF_FORCEDRIVE 0x80 + +#define DRIVE_CANNOTDETERMINE 0 +#define DRIVE_DOESNOTEXIST 1 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 +/* Win32 additions */ +#define DRIVE_CDROM 5 +#define DRIVE_RAMDISK 6 + +/* The security attributes structure */ +typedef struct _SECURITY_ATTRIBUTES +{ + DWORD nLength; + LPVOID lpSecurityDescriptor; + WIN_BOOL bInheritHandle; +} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + +#ifndef _FILETIME_ +#define _FILETIME_ +/* 64 bit number of 100 nanoseconds intervals since January 1, 1601 */ +typedef struct +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, *LPFILETIME; +#endif /* _FILETIME_ */ + +/* Find* structures */ +typedef struct +{ + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + CHAR cFileName[260]; + CHAR cAlternateFileName[14]; +} WIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; + +typedef struct +{ + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + WCHAR cFileName[260]; + WCHAR cAlternateFileName[14]; +} WIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; + +DECL_WINELIB_TYPE_AW(WIN32_FIND_DATA) +DECL_WINELIB_TYPE_AW(LPWIN32_FIND_DATA) + +typedef struct +{ + LPVOID lpData; + DWORD cbData; + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + } Foo; +} PROCESS_HEAP_ENTRY, *LPPROCESS_HEAP_ENTRY; + +#define PROCESS_HEAP_REGION 0x0001 +#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x0002 +#define PROCESS_HEAP_ENTRY_BUSY 0x0004 +#define PROCESS_HEAP_ENTRY_MOVEABLE 0x0010 +#define PROCESS_HEAP_ENTRY_DDESHARE 0x0020 + +#define INVALID_HANDLE_VALUE16 ((HANDLE16) -1) +#define INVALID_HANDLE_VALUE ((HANDLE) -1) + +#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) + +/* comm */ + +#define CBR_110 0xFF10 +#define CBR_300 0xFF11 +#define CBR_600 0xFF12 +#define CBR_1200 0xFF13 +#define CBR_2400 0xFF14 +#define CBR_4800 0xFF15 +#define CBR_9600 0xFF16 +#define CBR_14400 0xFF17 +#define CBR_19200 0xFF18 +#define CBR_38400 0xFF1B +#define CBR_56000 0xFF1F +#define CBR_128000 0xFF23 +#define CBR_256000 0xFF27 + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 + +#define IGNORE 0 +#define INFINITE16 0xFFFF +#define INFINITE 0xFFFFFFFF + +#define CE_RXOVER 0x0001 +#define CE_OVERRUN 0x0002 +#define CE_RXPARITY 0x0004 +#define CE_FRAME 0x0008 +#define CE_BREAK 0x0010 +#define CE_CTSTO 0x0020 +#define CE_DSRTO 0x0040 +#define CE_RLSDTO 0x0080 +#define CE_TXFULL 0x0100 +#define CE_PTO 0x0200 +#define CE_IOE 0x0400 +#define CE_DNS 0x0800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID -1 +#define IE_OPEN -2 +#define IE_NOPEN -3 +#define IE_MEMORY -4 +#define IE_DEFAULT -5 +#define IE_HARDWARE -10 +#define IE_BYTESIZE -11 +#define IE_BAUDRATE -12 + +#define EV_RXCHAR 0x0001 +#define EV_RXFLAG 0x0002 +#define EV_TXEMPTY 0x0004 +#define EV_CTS 0x0008 +#define EV_DSR 0x0010 +#define EV_RLSD 0x0020 +#define EV_BREAK 0x0040 +#define EV_ERR 0x0080 +#define EV_RING 0x0100 +#define EV_PERR 0x0200 +#define EV_CTSS 0x0400 +#define EV_DSRS 0x0800 +#define EV_RLSDS 0x1000 +#define EV_RINGTE 0x2000 +#define EV_RingTe EV_RINGTE + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define SETBREAK 8 +#define CLRBREAK 9 + +#define GETBASEIRQ 10 + +/* Purge functions for Comm Port */ +#define PURGE_TXABORT 0x0001 /* Kill the pending/current writes to the + comm port */ +#define PURGE_RXABORT 0x0002 /*Kill the pending/current reads to + the comm port */ +#define PURGE_TXCLEAR 0x0004 /* Kill the transmit queue if there*/ +#define PURGE_RXCLEAR 0x0008 /* Kill the typeahead buffer if there*/ + + +/* Modem Status Flags */ +#define MS_CTS_ON ((DWORD)0x0010) +#define MS_DSR_ON ((DWORD)0x0020) +#define MS_RING_ON ((DWORD)0x0040) +#define MS_RLSD_ON ((DWORD)0x0080) + +#define RTS_CONTROL_DISABLE 0 +#define RTS_CONTROL_ENABLE 1 +#define RTS_CONTROL_HANDSHAKE 2 +#define RTS_CONTROL_TOGGLE 3 + +#define DTR_CONTROL_DISABLE 0 +#define DTR_CONTROL_ENABLE 1 +#define DTR_CONTROL_HANDSHAKE 2 + +#define CSTF_CTSHOLD 0x01 +#define CSTF_DSRHOLD 0x02 +#define CSTF_RLSDHOLD 0x04 +#define CSTF_XOFFHOLD 0x08 +#define CSTF_XOFFSENT 0x10 +#define CSTF_EOF 0x20 +#define CSTF_TXIM 0x40 + +#define MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i))) +#define MAKEINTRESOURCEW(i) (LPWSTR)((DWORD)((WORD)(i))) +#define MAKEINTRESOURCE WINELIB_NAME_AW(MAKEINTRESOURCE) + +/* Predefined resource types */ +#define RT_CURSORA MAKEINTRESOURCEA(1) +#define RT_CURSORW MAKEINTRESOURCEW(1) +#define RT_CURSOR WINELIB_NAME_AW(RT_CURSOR) +#define RT_BITMAPA MAKEINTRESOURCEA(2) +#define RT_BITMAPW MAKEINTRESOURCEW(2) +#define RT_BITMAP WINELIB_NAME_AW(RT_BITMAP) +#define RT_ICONA MAKEINTRESOURCEA(3) +#define RT_ICONW MAKEINTRESOURCEW(3) +#define RT_ICON WINELIB_NAME_AW(RT_ICON) +#define RT_MENUA MAKEINTRESOURCEA(4) +#define RT_MENUW MAKEINTRESOURCEW(4) +#define RT_MENU WINELIB_NAME_AW(RT_MENU) +#define RT_DIALOGA MAKEINTRESOURCEA(5) +#define RT_DIALOGW MAKEINTRESOURCEW(5) +#define RT_DIALOG WINELIB_NAME_AW(RT_DIALOG) +#define RT_STRINGA MAKEINTRESOURCEA(6) +#define RT_STRINGW MAKEINTRESOURCEW(6) +#define RT_STRING WINELIB_NAME_AW(RT_STRING) +#define RT_FONTDIRA MAKEINTRESOURCEA(7) +#define RT_FONTDIRW MAKEINTRESOURCEW(7) +#define RT_FONTDIR WINELIB_NAME_AW(RT_FONTDIR) +#define RT_FONTA MAKEINTRESOURCEA(8) +#define RT_FONTW MAKEINTRESOURCEW(8) +#define RT_FONT WINELIB_NAME_AW(RT_FONT) +#define RT_ACCELERATORA MAKEINTRESOURCEA(9) +#define RT_ACCELERATORW MAKEINTRESOURCEW(9) +#define RT_ACCELERATOR WINELIB_NAME_AW(RT_ACCELERATOR) +#define RT_RCDATAA MAKEINTRESOURCEA(10) +#define RT_RCDATAW MAKEINTRESOURCEW(10) +#define RT_RCDATA WINELIB_NAME_AW(RT_RCDATA) +#define RT_MESSAGELISTA MAKEINTRESOURCEA(11) +#define RT_MESSAGELISTW MAKEINTRESOURCEW(11) +#define RT_MESSAGELIST WINELIB_NAME_AW(RT_MESSAGELIST) +#define RT_GROUP_CURSORA MAKEINTRESOURCEA(12) +#define RT_GROUP_CURSORW MAKEINTRESOURCEW(12) +#define RT_GROUP_CURSOR WINELIB_NAME_AW(RT_GROUP_CURSOR) +#define RT_GROUP_ICONA MAKEINTRESOURCEA(14) +#define RT_GROUP_ICONW MAKEINTRESOURCEW(14) +#define RT_GROUP_ICON WINELIB_NAME_AW(RT_GROUP_ICON) + + +#define LMEM_FIXED 0 +#define LMEM_MOVEABLE 0x0002 +#define LMEM_NOCOMPACT 0x0010 +#define LMEM_NODISCARD 0x0020 +#define LMEM_ZEROINIT 0x0040 +#define LMEM_MODIFY 0x0080 +#define LMEM_DISCARDABLE 0x0F00 +#define LMEM_DISCARDED 0x4000 +#define LMEM_LOCKCOUNT 0x00FF + +#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) + +#define GMEM_FIXED 0x0000 +#define GMEM_MOVEABLE 0x0002 +#define GMEM_NOCOMPACT 0x0010 +#define GMEM_NODISCARD 0x0020 +#define GMEM_ZEROINIT 0x0040 +#define GMEM_MODIFY 0x0080 +#define GMEM_DISCARDABLE 0x0100 +#define GMEM_NOT_BANKED 0x1000 +#define GMEM_SHARE 0x2000 +#define GMEM_DDESHARE 0x2000 +#define GMEM_NOTIFY 0x4000 +#define GMEM_LOWER GMEM_NOT_BANKED +#define GMEM_DISCARDED 0x4000 +#define GMEM_LOCKCOUNT 0x00ff +#define GMEM_INVALID_HANDLE 0x8000 + +#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) +#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) + + +typedef struct tagMEMORYSTATUS +{ + DWORD dwLength; + DWORD dwMemoryLoad; + DWORD dwTotalPhys; + DWORD dwAvailPhys; + DWORD dwTotalPageFile; + DWORD dwAvailPageFile; + DWORD dwTotalVirtual; + DWORD dwAvailVirtual; +} MEMORYSTATUS, *LPMEMORYSTATUS; + + +#ifndef NOLOGERROR + +/* LogParamError and LogError values */ + +/* Error modifier bits */ +#define ERR_WARNING 0x8000 +#define ERR_PARAM 0x4000 + +#define ERR_SIZE_MASK 0x3000 +#define ERR_BYTE 0x1000 +#define ERR_WORD 0x2000 +#define ERR_DWORD 0x3000 + +/* LogParamError() values */ + +/* Generic parameter values */ +#define ERR_BAD_VALUE 0x6001 +#define ERR_BAD_FLAGS 0x6002 +#define ERR_BAD_INDEX 0x6003 +#define ERR_BAD_DVALUE 0x7004 +#define ERR_BAD_DFLAGS 0x7005 +#define ERR_BAD_DINDEX 0x7006 +#define ERR_BAD_PTR 0x7007 +#define ERR_BAD_FUNC_PTR 0x7008 +#define ERR_BAD_SELECTOR 0x6009 +#define ERR_BAD_STRING_PTR 0x700a +#define ERR_BAD_HANDLE 0x600b + +/* KERNEL parameter errors */ +#define ERR_BAD_HINSTANCE 0x6020 +#define ERR_BAD_HMODULE 0x6021 +#define ERR_BAD_GLOBAL_HANDLE 0x6022 +#define ERR_BAD_LOCAL_HANDLE 0x6023 +#define ERR_BAD_ATOM 0x6024 +#define ERR_BAD_HFILE 0x6025 + +/* USER parameter errors */ +#define ERR_BAD_HWND 0x6040 +#define ERR_BAD_HMENU 0x6041 +#define ERR_BAD_HCURSOR 0x6042 +#define ERR_BAD_HICON 0x6043 +#define ERR_BAD_HDWP 0x6044 +#define ERR_BAD_CID 0x6045 +#define ERR_BAD_HDRVR 0x6046 + +/* GDI parameter errors */ +#define ERR_BAD_COORDS 0x7060 +#define ERR_BAD_GDI_OBJECT 0x6061 +#define ERR_BAD_HDC 0x6062 +#define ERR_BAD_HPEN 0x6063 +#define ERR_BAD_HFONT 0x6064 +#define ERR_BAD_HBRUSH 0x6065 +#define ERR_BAD_HBITMAP 0x6066 +#define ERR_BAD_HRGN 0x6067 +#define ERR_BAD_HPALETTE 0x6068 +#define ERR_BAD_HMETAFILE 0x6069 + + +/* LogError() values */ + +/* KERNEL errors */ +#define ERR_GALLOC 0x0001 +#define ERR_GREALLOC 0x0002 +#define ERR_GLOCK 0x0003 +#define ERR_LALLOC 0x0004 +#define ERR_LREALLOC 0x0005 +#define ERR_LLOCK 0x0006 +#define ERR_ALLOCRES 0x0007 +#define ERR_LOCKRES 0x0008 +#define ERR_LOADMODULE 0x0009 + +/* USER errors */ +#define ERR_CREATEDLG 0x0040 +#define ERR_CREATEDLG2 0x0041 +#define ERR_REGISTERCLASS 0x0042 +#define ERR_DCBUSY 0x0043 +#define ERR_CREATEWND 0x0044 +#define ERR_STRUCEXTRA 0x0045 +#define ERR_LOADSTR 0x0046 +#define ERR_LOADMENU 0x0047 +#define ERR_NESTEDBEGINPAINT 0x0048 +#define ERR_BADINDEX 0x0049 +#define ERR_CREATEMENU 0x004a + +/* GDI errors */ +#define ERR_CREATEDC 0x0080 +#define ERR_CREATEMETA 0x0081 +#define ERR_DELOBJSELECTED 0x0082 +#define ERR_SELBITMAP 0x0083 + + + +/* Debugging support (DEBUG SYSTEM ONLY) */ +typedef struct +{ + UINT16 flags; + DWORD dwOptions WINE_PACKED; + DWORD dwFilter WINE_PACKED; + CHAR achAllocModule[8] WINE_PACKED; + DWORD dwAllocBreak WINE_PACKED; + DWORD dwAllocCount WINE_PACKED; +} WINDEBUGINFO, *LPWINDEBUGINFO; + +/* WINDEBUGINFO flags values */ +#define WDI_OPTIONS 0x0001 +#define WDI_FILTER 0x0002 +#define WDI_ALLOCBREAK 0x0004 + +/* dwOptions values */ +#define DBO_CHECKHEAP 0x0001 +#define DBO_BUFFERFILL 0x0004 +#define DBO_DISABLEGPTRAPPING 0x0010 +#define DBO_CHECKFREE 0x0020 + +#define DBO_SILENT 0x8000 + +#define DBO_TRACEBREAK 0x2000 +#define DBO_WARNINGBREAK 0x1000 +#define DBO_NOERRORBREAK 0x0800 +#define DBO_NOFATALBREAK 0x0400 +#define DBO_INT3BREAK 0x0100 + +/* DebugOutput flags values */ +#define DBF_TRACE 0x0000 +#define DBF_WARNING 0x4000 +#define DBF_ERROR 0x8000 +#define DBF_FATAL 0xc000 + +/* dwFilter values */ +#define DBF_KERNEL 0x1000 +#define DBF_KRN_MEMMAN 0x0001 +#define DBF_KRN_LOADMODULE 0x0002 +#define DBF_KRN_SEGMENTLOAD 0x0004 +#define DBF_USER 0x0800 +#define DBF_GDI 0x0400 +#define DBF_MMSYSTEM 0x0040 +#define DBF_PENWIN 0x0020 +#define DBF_APPLICATION 0x0008 +#define DBF_DRIVER 0x0010 + +#endif /* NOLOGERROR */ + +typedef struct { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; +} SYSTEMTIME, *LPSYSTEMTIME; + +/* The 'overlapped' data structure used by async I/O functions. + */ +typedef struct { + DWORD Internal; + DWORD InternalHigh; + DWORD Offset; + DWORD OffsetHigh; + HANDLE hEvent; +} OVERLAPPED, *LPOVERLAPPED; + +/* Process startup information. + */ + +/* STARTUPINFO.dwFlags */ +#define STARTF_USESHOWWINDOW 0x00000001 +#define STARTF_USESIZE 0x00000002 +#define STARTF_USEPOSITION 0x00000004 +#define STARTF_USECOUNTCHARS 0x00000008 +#define STARTF_USEFILLATTRIBUTE 0x00000010 +#define STARTF_RUNFULLSCREEN 0x00000020 +#define STARTF_FORCEONFEEDBACK 0x00000040 +#define STARTF_FORCEOFFFEEDBACK 0x00000080 +#define STARTF_USESTDHANDLES 0x00000100 +#define STARTF_USEHOTKEY 0x00000200 + +typedef struct { + DWORD cb; /* 00: size of struct */ + LPSTR lpReserved; /* 04: */ + LPSTR lpDesktop; /* 08: */ + LPSTR lpTitle; /* 0c: */ + DWORD dwX; /* 10: */ + DWORD dwY; /* 14: */ + DWORD dwXSize; /* 18: */ + DWORD dwYSize; /* 1c: */ + DWORD dwXCountChars; /* 20: */ + DWORD dwYCountChars; /* 24: */ + DWORD dwFillAttribute; /* 28: */ + DWORD dwFlags; /* 2c: */ + WORD wShowWindow; /* 30: */ + WORD cbReserved2; /* 32: */ + BYTE *lpReserved2; /* 34: */ + HANDLE hStdInput; /* 38: */ + HANDLE hStdOutput; /* 3c: */ + HANDLE hStdError; /* 40: */ +} STARTUPINFOA, *LPSTARTUPINFOA; + +typedef struct { + DWORD cb; + LPWSTR lpReserved; + LPWSTR lpDesktop; + LPWSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + BYTE *lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; +} STARTUPINFOW, *LPSTARTUPINFOW; + +DECL_WINELIB_TYPE_AW(STARTUPINFO) +DECL_WINELIB_TYPE_AW(LPSTARTUPINFO) + +typedef struct { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; +} PROCESS_INFORMATION,*LPPROCESS_INFORMATION; + +typedef struct { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; +} TIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; + +#define TIME_ZONE_ID_UNKNOWN 0 +#define TIME_ZONE_ID_STANDARD 1 +#define TIME_ZONE_ID_DAYLIGHT 2 + +/* CreateProcess: dwCreationFlag values + */ +#define DEBUG_PROCESS 0x00000001 +#define DEBUG_ONLY_THIS_PROCESS 0x00000002 +#define CREATE_SUSPENDED 0x00000004 +#define DETACHED_PROCESS 0x00000008 +#define CREATE_NEW_CONSOLE 0x00000010 +#define NORMAL_PRIORITY_CLASS 0x00000020 +#define IDLE_PRIORITY_CLASS 0x00000040 +#define HIGH_PRIORITY_CLASS 0x00000080 +#define REALTIME_PRIORITY_CLASS 0x00000100 +#define CREATE_NEW_PROCESS_GROUP 0x00000200 +#define CREATE_UNICODE_ENVIRONMENT 0x00000400 +#define CREATE_SEPARATE_WOW_VDM 0x00000800 +#define CREATE_SHARED_WOW_VDM 0x00001000 +#define CREATE_DEFAULT_ERROR_MODE 0x04000000 +#define CREATE_NO_WINDOW 0x08000000 +#define PROFILE_USER 0x10000000 +#define PROFILE_KERNEL 0x20000000 +#define PROFILE_SERVER 0x40000000 + + +/* File object type definitions + */ +#define FILE_TYPE_UNKNOWN 0 +#define FILE_TYPE_DISK 1 +#define FILE_TYPE_CHAR 2 +#define FILE_TYPE_PIPE 3 +#define FILE_TYPE_REMOTE 32768 + +/* File creation flags + */ +#define FILE_FLAG_WRITE_THROUGH 0x80000000UL +#define FILE_FLAG_OVERLAPPED 0x40000000L +#define FILE_FLAG_NO_BUFFERING 0x20000000L +#define FILE_FLAG_RANDOM_ACCESS 0x10000000L +#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000L +#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000L +#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000L +#define FILE_FLAG_POSIX_SEMANTICS 0x01000000L +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 + +/* Standard handle identifiers + */ +#define STD_INPUT_HANDLE ((DWORD) -10) +#define STD_OUTPUT_HANDLE ((DWORD) -11) +#define STD_ERROR_HANDLE ((DWORD) -12) + +typedef struct +{ + int dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + int dwVolumeSerialNumber; + int nFileSizeHigh; + int nFileSizeLow; + int nNumberOfLinks; + int nFileIndexHigh; + int nFileIndexLow; +} BY_HANDLE_FILE_INFORMATION ; + + +typedef struct _SYSTEM_POWER_STATUS +{ + WIN_BOOL16 ACLineStatus; + BYTE BatteryFlag; + BYTE BatteryLifePercent; + BYTE reserved; + DWORD BatteryLifeTime; + DWORD BatteryFullLifeTime; +} SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS; + +typedef struct _MEMORY_BASIC_INFORMATION +{ + LPVOID BaseAddress; + LPVOID AllocationBase; + DWORD AllocationProtect; + DWORD RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; +} MEMORY_BASIC_INFORMATION,*LPMEMORY_BASIC_INFORMATION; + + +typedef WIN_BOOL CALLBACK (*CODEPAGE_ENUMPROCA)(LPSTR); +typedef WIN_BOOL CALLBACK (*CODEPAGE_ENUMPROCW)(LPWSTR); +DECL_WINELIB_TYPE_AW(CODEPAGE_ENUMPROC) +typedef WIN_BOOL CALLBACK (*LOCALE_ENUMPROCA)(LPSTR); +typedef WIN_BOOL CALLBACK (*LOCALE_ENUMPROCW)(LPWSTR); +DECL_WINELIB_TYPE_AW(LOCALE_ENUMPROC) + +typedef struct tagSYSTEM_INFO +{ + union { + DWORD dwOemId; /* Obsolete field - do not use */ + struct { + WORD wProcessorArchitecture; + WORD wReserved; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress; + LPVOID lpMaximumApplicationAddress; + DWORD dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; +} SYSTEM_INFO, *LPSYSTEM_INFO; + +/* {G,S}etPriorityClass */ +#define NORMAL_PRIORITY_CLASS 0x00000020 +#define IDLE_PRIORITY_CLASS 0x00000040 +#define HIGH_PRIORITY_CLASS 0x00000080 +#define REALTIME_PRIORITY_CLASS 0x00000100 + +typedef WIN_BOOL CALLBACK (*ENUMRESTYPEPROCA)(HMODULE,LPSTR,LONG); +typedef WIN_BOOL CALLBACK (*ENUMRESTYPEPROCW)(HMODULE,LPWSTR,LONG); +typedef WIN_BOOL CALLBACK (*ENUMRESNAMEPROCA)(HMODULE,LPCSTR,LPSTR,LONG); +typedef WIN_BOOL CALLBACK (*ENUMRESNAMEPROCW)(HMODULE,LPCWSTR,LPWSTR,LONG); +typedef WIN_BOOL CALLBACK (*ENUMRESLANGPROCA)(HMODULE,LPCSTR,LPCSTR,WORD,LONG); +typedef WIN_BOOL CALLBACK (*ENUMRESLANGPROCW)(HMODULE,LPCWSTR,LPCWSTR,WORD,LONG); + +DECL_WINELIB_TYPE_AW(ENUMRESTYPEPROC) +DECL_WINELIB_TYPE_AW(ENUMRESNAMEPROC) +DECL_WINELIB_TYPE_AW(ENUMRESLANGPROC) + +/* flags that can be passed to LoadLibraryEx */ +#define DONT_RESOLVE_DLL_REFERENCES 0x00000001 +#define LOAD_LIBRARY_AS_DATAFILE 0x00000002 +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 + +/* ifdef _x86_ ... */ +typedef struct _LDT_ENTRY { + WORD LimitLow; + WORD BaseLow; + union { + struct { + BYTE BaseMid; + BYTE Flags1;/*Declare as bytes to avoid alignment problems */ + BYTE Flags2; + BYTE BaseHi; + } Bytes; + struct { + unsigned BaseMid : 8; + unsigned Type : 5; + unsigned Dpl : 2; + unsigned Pres : 1; + unsigned LimitHi : 4; + unsigned Sys : 1; + unsigned Reserved_0 : 1; + unsigned Default_Big : 1; + unsigned Granularity : 1; + unsigned BaseHi : 8; + } Bits; + } HighWord; +} LDT_ENTRY, *LPLDT_ENTRY; + + +typedef enum _GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard +} GET_FILEEX_INFO_LEVELS; + +typedef struct _WIN32_FILE_ATTRIBUTES_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; +} WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; + +typedef struct _DllVersionInfo { + DWORD cbSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformID; +} DLLVERSIONINFO; + +/* + * This one seems to be a Win32 only definition. It also is defined with + * WINAPI instead of CALLBACK in the windows headers. + */ +typedef DWORD WINAPI (*LPPROGRESS_ROUTINE)(LARGE_INTEGER, LARGE_INTEGER, LARGE_INTEGER, + LARGE_INTEGER, DWORD, DWORD, HANDLE, + HANDLE, LPVOID); + + +#define WAIT_FAILED 0xffffffff +#define WAIT_OBJECT_0 0 +#define WAIT_ABANDONED STATUS_ABANDONED_WAIT_0 +#define WAIT_ABANDONED_0 STATUS_ABANDONED_WAIT_0 +#define WAIT_IO_COMPLETION STATUS_USER_APC +#define WAIT_TIMEOUT STATUS_TIMEOUT +#define STILL_ACTIVE STATUS_PENDING + +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 + +#define MEM_COMMIT 0x00001000 +#define MEM_RESERVE 0x00002000 +#define MEM_DECOMMIT 0x00004000 +#define MEM_RELEASE 0x00008000 +#define MEM_FREE 0x00010000 +#define MEM_PRIVATE 0x00020000 +#define MEM_MAPPED 0x00040000 +#define MEM_TOP_DOWN 0x00100000 +#ifdef __WINE__ +#define MEM_SYSTEM 0x80000000 +#endif + +#define SEC_FILE 0x00800000 +#define SEC_IMAGE 0x01000000 +#define SEC_RESERVE 0x04000000 +#define SEC_COMMIT 0x08000000 +#define SEC_NOCACHE 0x10000000 + +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 + +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_PERSISTENT_ACLS 0x00000008 + +#define FILE_MAP_COPY 0x00000001 +#define FILE_MAP_WRITE 0x00000002 +#define FILE_MAP_READ 0x00000004 +#define FILE_MAP_ALL_ACCESS 0x000f001f + +#define MOVEFILE_REPLACE_EXISTING 0x00000001 +#define MOVEFILE_COPY_ALLOWED 0x00000002 +#define MOVEFILE_DELAY_UNTIL_REBOOT 0x00000004 + +#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH +#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES +#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK + +#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION +#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT +#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT +#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP +#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED +#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND +#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO +#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT +#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION +#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW +#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK +#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW +#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO +#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW +#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION +#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR +#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION +#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION +#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW +#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION +#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION +#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE +#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT + +/* Wine extension; Windows doesn't have a name for this code */ +#define EXCEPTION_CRITICAL_SECTION_WAIT 0xc0000194 + +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 + +#define HANDLE_FLAG_INHERIT 0x00000001 +#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 + +#define HINSTANCE_ERROR 32 + +#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN +#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX +#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) +#define THREAD_PRIORITY_ERROR_RETURN (0x7fffffff) +#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT +#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE + +/* Could this type be considered opaque? */ +typedef struct { + LPVOID DebugInfo; + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + DWORD Reserved; +}CRITICAL_SECTION; + +#ifdef __WINE__ +#define CRITICAL_SECTION_INIT { 0, -1, 0, 0, 0, 0 } +#endif + +typedef struct { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; +} OSVERSIONINFO16; + +typedef struct { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; +} OSVERSIONINFOA; + +typedef struct { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; +} OSVERSIONINFOW; + +DECL_WINELIB_TYPE_AW(OSVERSIONINFO) + +#define VER_PLATFORM_WIN32s 0 +#define VER_PLATFORM_WIN32_WINDOWS 1 +#define VER_PLATFORM_WIN32_NT 2 + +typedef struct tagCOMSTAT +{ + DWORD status; + DWORD cbInQue; + DWORD cbOutQue; +} COMSTAT,*LPCOMSTAT; + +typedef struct tagDCB +{ + DWORD DCBlength; + DWORD BaudRate; + unsigned fBinary :1; + unsigned fParity :1; + unsigned fOutxCtsFlow :1; + unsigned fOutxDsrFlow :1; + unsigned fDtrControl :2; + unsigned fDsrSensitivity :1; + unsigned fTXContinueOnXoff :1; + unsigned fOutX :1; + unsigned fInX :1; + unsigned fErrorChar :1; + unsigned fNull :1; + unsigned fRtsControl :2; + unsigned fAbortOnError :1; + unsigned fDummy2 :17; + WORD wReserved; + WORD XonLim; + WORD XoffLim; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + char XonChar; + char XoffChar; + char ErrorChar; + char EofChar; + char EvtChar; +} DCB, *LPDCB; + + + +typedef struct tagCOMMTIMEOUTS { + DWORD ReadIntervalTimeout; + DWORD ReadTotalTimeoutMultiplier; + DWORD ReadTotalTimeoutConstant; + DWORD WriteTotalTimeoutMultiplier; + DWORD WriteTotalTimeoutConstant; +} COMMTIMEOUTS,*LPCOMMTIMEOUTS; + +#include "poppack.h" + +typedef void CALLBACK (*PAPCFUNC)(ULONG_PTR); +typedef void CALLBACK (*PTIMERAPCROUTINE)(LPVOID,DWORD,DWORD); + +WIN_BOOL WINAPI ClearCommError(INT,LPDWORD,LPCOMSTAT); +WIN_BOOL WINAPI BuildCommDCBA(LPCSTR,LPDCB); +WIN_BOOL WINAPI BuildCommDCBW(LPCWSTR,LPDCB); +#define BuildCommDCB WINELIB_NAME_AW(BuildCommDCB) +WIN_BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR,LPDCB,LPCOMMTIMEOUTS); +WIN_BOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR,LPDCB,LPCOMMTIMEOUTS); +#define BuildCommDCBAndTimeouts WINELIB_NAME_AW(BuildCommDCBAndTimeouts) +WIN_BOOL WINAPI GetCommTimeouts(HANDLE,LPCOMMTIMEOUTS); +WIN_BOOL WINAPI SetCommTimeouts(HANDLE,LPCOMMTIMEOUTS); +WIN_BOOL WINAPI GetCommState(INT,LPDCB); +WIN_BOOL WINAPI SetCommState(INT,LPDCB); +WIN_BOOL WINAPI TransmitCommChar(INT,CHAR); +WIN_BOOL WINAPI SetupComm(HANDLE, DWORD, DWORD); +WIN_BOOL WINAPI GetCommProperties(HANDLE, LPDCB *); + +/*DWORD WINAPI GetVersion( void );*/ +WIN_BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16*); +WIN_BOOL WINAPI GetVersionExA(OSVERSIONINFOA*); +WIN_BOOL WINAPI GetVersionExW(OSVERSIONINFOW*); +#define GetVersionEx WINELIB_NAME_AW(GetVersionEx) + +/*int WinMain(HINSTANCE, HINSTANCE prev, char *cmd, int show);*/ + +void WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit); +void WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit); +WIN_BOOL WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit); +void WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit); +void WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit); +void WINAPI MakeCriticalSectionGlobal(CRITICAL_SECTION *lpCrit); +WIN_BOOL WINAPI GetProcessWorkingSetSize(HANDLE,LPDWORD,LPDWORD); +DWORD WINAPI QueueUserAPC(PAPCFUNC,HANDLE,ULONG_PTR); +void WINAPI RaiseException(DWORD,DWORD,DWORD,const LPDWORD); +WIN_BOOL WINAPI SetProcessWorkingSetSize(HANDLE,DWORD,DWORD); +WIN_BOOL WINAPI TerminateProcess(HANDLE,DWORD); +WIN_BOOL WINAPI TerminateThread(HANDLE,DWORD); +WIN_BOOL WINAPI GetExitCodeThread(HANDLE,LPDWORD); + +/* GetBinaryType return values. + */ + +#define SCS_32BIT_BINARY 0 +#define SCS_DOS_BINARY 1 +#define SCS_WOW_BINARY 2 +#define SCS_PIF_BINARY 3 +#define SCS_POSIX_BINARY 4 +#define SCS_OS216_BINARY 5 + +WIN_BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ); +WIN_BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ); +#define GetBinaryType WINELIB_NAME_AW(GetBinaryType) + +WIN_BOOL16 WINAPI GetWinDebugInfo16(LPWINDEBUGINFO,UINT16); +WIN_BOOL16 WINAPI SetWinDebugInfo16(LPWINDEBUGINFO); +/* Declarations for functions that exist only in Win32 */ + + +WIN_BOOL WINAPI AttachThreadInput(DWORD,DWORD,WIN_BOOL); +WIN_BOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR,HANDLE,DWORD,PGENERIC_MAPPING,PPRIVILEGE_SET,LPDWORD,LPDWORD,LPWIN_BOOL); +WIN_BOOL WINAPI AdjustTokenPrivileges(HANDLE,WIN_BOOL,LPVOID,DWORD,LPVOID,LPDWORD); +WIN_BOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID *); +WIN_BOOL WINAPI AllocateLocallyUniqueId(PLUID); +WIN_BOOL WINAPI AllocConsole(void); +WIN_BOOL WINAPI AreFileApisANSI(void); +WIN_BOOL WINAPI BackupEventLogA(HANDLE,LPCSTR); +WIN_BOOL WINAPI BackupEventLogW(HANDLE,LPCWSTR); +#define BackupEventLog WINELIB_NAME_AW(BackupEventLog) +WIN_BOOL WINAPI Beep(DWORD,DWORD); +WIN_BOOL WINAPI CancelWaitableTimer(HANDLE); +WIN_BOOL WINAPI ClearEventLogA(HANDLE,LPCSTR); +WIN_BOOL WINAPI ClearEventLogW(HANDLE,LPCWSTR); +#define ClearEventLog WINELIB_NAME_AW(ClearEventLog) +WIN_BOOL WINAPI CloseEventLog(HANDLE); +WIN_BOOL WINAPI CloseHandle(HANDLE); +WIN_BOOL WINAPI ContinueDebugEvent(DWORD,DWORD,DWORD); +HANDLE WINAPI ConvertToGlobalHandle(HANDLE hSrc); +WIN_BOOL WINAPI CopyFileA(LPCSTR,LPCSTR,WIN_BOOL); +WIN_BOOL WINAPI CopyFileW(LPCWSTR,LPCWSTR,WIN_BOOL); +#define CopyFile WINELIB_NAME_AW(CopyFile) +WIN_BOOL WINAPI CopyFileExA(LPCSTR, LPCSTR, LPPROGRESS_ROUTINE, LPVOID, LPWIN_BOOL, DWORD); +WIN_BOOL WINAPI CopyFileExW(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPWIN_BOOL, DWORD); +#define CopyFileEx WINELIB_NAME_AW(CopyFileEx) +WIN_BOOL WINAPI CopySid(DWORD,PSID,PSID); +INT WINAPI CompareFileTime(LPFILETIME,LPFILETIME); +HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES,WIN_BOOL,WIN_BOOL,LPCSTR); +HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES,WIN_BOOL,WIN_BOOL,LPCWSTR); +#define CreateEvent WINELIB_NAME_AW(CreateEvent) +HANDLE WINAPI CreateFileA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES, + DWORD,DWORD,HANDLE); +HANDLE WINAPI CreateFileW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES, + DWORD,DWORD,HANDLE); +#define CreateFile WINELIB_NAME_AW(CreateFile) +HANDLE WINAPI CreateFileMappingA(HANDLE,LPSECURITY_ATTRIBUTES,DWORD, + DWORD,DWORD,LPCSTR); +HANDLE WINAPI CreateFileMappingW(HANDLE,LPSECURITY_ATTRIBUTES,DWORD, + DWORD,DWORD,LPCWSTR); +#define CreateFileMapping WINELIB_NAME_AW(CreateFileMapping) +HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES,WIN_BOOL,LPCSTR); +HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES,WIN_BOOL,LPCWSTR); +#define CreateMutex WINELIB_NAME_AW(CreateMutex) +WIN_BOOL WINAPI CreatePipe(PHANDLE,PHANDLE,LPSECURITY_ATTRIBUTES,DWORD); +WIN_BOOL WINAPI CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES, + LPSECURITY_ATTRIBUTES,WIN_BOOL,DWORD,LPVOID,LPCSTR, + LPSTARTUPINFOA,LPPROCESS_INFORMATION); +WIN_BOOL WINAPI CreateProcessW(LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES, + LPSECURITY_ATTRIBUTES,WIN_BOOL,DWORD,LPVOID,LPCWSTR, + LPSTARTUPINFOW,LPPROCESS_INFORMATION); +#define CreateProcess WINELIB_NAME_AW(CreateProcess) +HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCSTR); +HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCWSTR); +#define CreateSemaphore WINELIB_NAME_AW(CreateSemaphore) +HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES,DWORD,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD); +HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES,WIN_BOOL,LPCSTR); +HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES,WIN_BOOL,LPCWSTR); +#define CreateWaitableTimer WINELIB_NAME_AW(CreateWaitableTimer) +WIN_BOOL WINAPI DebugActiveProcess(DWORD); +void WINAPI DebugBreak(void); +WIN_BOOL WINAPI DeregisterEventSource(HANDLE); +WIN_BOOL WINAPI DisableThreadLibraryCalls(HMODULE); +WIN_BOOL WINAPI DosDateTimeToFileTime(WORD,WORD,LPFILETIME); +WIN_BOOL WINAPI DuplicateHandle(HANDLE,HANDLE,HANDLE,HANDLE*,DWORD,WIN_BOOL,DWORD); +WIN_BOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags); +WIN_BOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags); +#define EnumDateFormats WINELIB_NAME_AW(EnumDateFormats) +WIN_BOOL WINAPI EnumResourceLanguagesA(HMODULE,LPCSTR,LPCSTR, + ENUMRESLANGPROCA,LONG); +WIN_BOOL WINAPI EnumResourceLanguagesW(HMODULE,LPCWSTR,LPCWSTR, + ENUMRESLANGPROCW,LONG); +#define EnumResourceLanguages WINELIB_NAME_AW(EnumResourceLanguages) +WIN_BOOL WINAPI EnumResourceNamesA(HMODULE,LPCSTR,ENUMRESNAMEPROCA, + LONG); +WIN_BOOL WINAPI EnumResourceNamesW(HMODULE,LPCWSTR,ENUMRESNAMEPROCW, + LONG); +#define EnumResourceNames WINELIB_NAME_AW(EnumResourceNames) +WIN_BOOL WINAPI EnumResourceTypesA(HMODULE,ENUMRESTYPEPROCA,LONG); +WIN_BOOL WINAPI EnumResourceTypesW(HMODULE,ENUMRESTYPEPROCW,LONG); +#define EnumResourceTypes WINELIB_NAME_AW(EnumResourceTypes) +WIN_BOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA,DWORD); +WIN_BOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW,DWORD); +#define EnumSystemCodePages WINELIB_NAME_AW(EnumSystemCodePages) +WIN_BOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA,DWORD); +WIN_BOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW,DWORD); +#define EnumSystemLocales WINELIB_NAME_AW(EnumSystemLocales) +WIN_BOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags); +WIN_BOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags); +#define EnumTimeFormats WINELIB_NAME_AW(EnumTimeFormats) +WIN_BOOL WINAPI EqualSid(PSID, PSID); +WIN_BOOL WINAPI EqualPrefixSid(PSID,PSID); +VOID WINAPI ExitProcess(DWORD) WINE_NORETURN; +VOID WINAPI ExitThread(DWORD) WINE_NORETURN; +DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR,LPSTR,DWORD); +DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR,LPWSTR,DWORD); +#define ExpandEnvironmentStrings WINELIB_NAME_AW(ExpandEnvironmentStrings) +WIN_BOOL WINAPI FileTimeToDosDateTime(const FILETIME*,LPWORD,LPWORD); +WIN_BOOL WINAPI FileTimeToLocalFileTime(const FILETIME*,LPFILETIME); +WIN_BOOL WINAPI FileTimeToSystemTime(const FILETIME*,LPSYSTEMTIME); +HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR,WIN_BOOL,DWORD); +HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR,WIN_BOOL,DWORD); +#define FindFirstChangeNotification WINELIB_NAME_AW(FindFirstChangeNotification) +WIN_BOOL WINAPI FindNextChangeNotification(HANDLE); +WIN_BOOL WINAPI FindCloseChangeNotification(HANDLE); +HRSRC WINAPI FindResourceExA(HMODULE,LPCSTR,LPCSTR,WORD); +HRSRC WINAPI FindResourceExW(HMODULE,LPCWSTR,LPCWSTR,WORD); +#define FindResourceEx WINELIB_NAME_AW(FindResourceEx) +WIN_BOOL WINAPI FlushConsoleInputBuffer(HANDLE); +WIN_BOOL WINAPI FlushFileBuffers(HANDLE); +WIN_BOOL WINAPI FlushViewOfFile(LPCVOID, DWORD); +DWORD WINAPI FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR, + DWORD,LPDWORD); +DWORD WINAPI FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, + DWORD,LPDWORD); +#define FormatMessage WINELIB_NAME_AW(FormatMessage) +WIN_BOOL WINAPI FreeConsole(void); +WIN_BOOL WINAPI FreeEnvironmentStringsA(LPSTR); +WIN_BOOL WINAPI FreeEnvironmentStringsW(LPWSTR); +#define FreeEnvironmentStrings WINELIB_NAME_AW(FreeEnvironmentStrings) +PVOID WINAPI FreeSid(PSID); +UINT WINAPI GetACP(void); +LPCSTR WINAPI GetCommandLineA(void); +LPCWSTR WINAPI GetCommandLineW(void); +#define GetCommandLine WINELIB_NAME_AW(GetCommandLine) +WIN_BOOL WINAPI GetComputerNameA(LPSTR,LPDWORD); +WIN_BOOL WINAPI GetComputerNameW(LPWSTR,LPDWORD); +#define GetComputerName WINELIB_NAME_AW(GetComputerName) +UINT WINAPI GetConsoleCP(void); +WIN_BOOL WINAPI GetConsoleMode(HANDLE,LPDWORD); +UINT WINAPI GetConsoleOutputCP(void); +DWORD WINAPI GetConsoleTitleA(LPSTR,DWORD); +DWORD WINAPI GetConsoleTitleW(LPWSTR,DWORD); +#define GetConsoleTitle WINELIB_NAME_AW(GetConsoleTitle) +WIN_BOOL WINAPI GetCommMask(HANDLE, LPDWORD); +WIN_BOOL WINAPI GetCommModemStatus(HANDLE, LPDWORD); +HANDLE WINAPI GetCurrentProcess(void); +HANDLE WINAPI GetCurrentThread(void); +INT WINAPI GetDateFormatA(LCID,DWORD,LPSYSTEMTIME,LPCSTR,LPSTR,INT); +INT WINAPI GetDateFormatW(LCID,DWORD,LPSYSTEMTIME,LPCWSTR,LPWSTR,INT); +#define GetDateFormat WINELIB_NAME_AW(GetDateFormat) +LPSTR WINAPI GetEnvironmentStringsA(void); +LPWSTR WINAPI GetEnvironmentStringsW(void); +#define GetEnvironmentStrings WINELIB_NAME_AW(GetEnvironmentStrings) +DWORD WINAPI GetEnvironmentVariableA(LPCSTR,LPSTR,DWORD); +DWORD WINAPI GetEnvironmentVariableW(LPCWSTR,LPWSTR,DWORD); +#define GetEnvironmentVariable WINELIB_NAME_AW(GetEnvironmentVariable) +WIN_BOOL WINAPI GetFileAttributesExA(LPCSTR,GET_FILEEX_INFO_LEVELS,LPVOID); +WIN_BOOL WINAPI GetFileAttributesExW(LPCWSTR,GET_FILEEX_INFO_LEVELS,LPVOID); +#define GetFileattributesEx WINELIB_NAME_AW(GetFileAttributesEx) +DWORD WINAPI GetFileInformationByHandle(HANDLE,BY_HANDLE_FILE_INFORMATION*); +WIN_BOOL WINAPI GetFileSecurityA(LPCSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,LPDWORD); +WIN_BOOL WINAPI GetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,LPDWORD); +#define GetFileSecurity WINELIB_NAME_AW(GetFileSecurity) +DWORD WINAPI GetFileSize(HANDLE,LPDWORD); +WIN_BOOL WINAPI GetFileTime(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME); +DWORD WINAPI GetFileType(HANDLE); +DWORD WINAPI GetFullPathNameA(LPCSTR,DWORD,LPSTR,LPSTR*); +DWORD WINAPI GetFullPathNameW(LPCWSTR,DWORD,LPWSTR,LPWSTR*); +#define GetFullPathName WINELIB_NAME_AW(GetFullPathName) +WIN_BOOL WINAPI GetHandleInformation(HANDLE,LPDWORD); +COORD WINAPI GetLargestConsoleWindowSize(HANDLE); +DWORD WINAPI GetLengthSid(PSID); +VOID WINAPI GetLocalTime(LPSYSTEMTIME); +DWORD WINAPI GetLogicalDrives(void); +DWORD WINAPI GetLongPathNameA(LPCSTR,LPSTR,DWORD); +DWORD WINAPI GetLongPathNameW(LPCWSTR,LPWSTR,DWORD); +#define GetLongPathName WINELIB_NAME_AW(GetLongPathName) +WIN_BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE,LPDWORD); +WIN_BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD); +WIN_BOOL WINAPI GetNumberOfEventLogRecords(HANDLE,PDWORD); +UINT WINAPI GetOEMCP(void); +WIN_BOOL WINAPI GetOldestEventLogRecord(HANDLE,PDWORD); +DWORD WINAPI GetPriorityClass(HANDLE); +DWORD WINAPI GetProcessVersion(DWORD); +WIN_BOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR_CONTROL,LPDWORD); +WIN_BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,LPWIN_BOOL,PACL *,LPWIN_BOOL); +WIN_BOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR,PSID *,LPWIN_BOOL); +DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR); +WIN_BOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR,PSID *,LPWIN_BOOL); +WIN_BOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR,LPWIN_BOOL,PACL *,LPWIN_BOOL); +PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID); +DWORD WINAPI GetSidLengthRequired(BYTE); +PDWORD WINAPI GetSidSubAuthority(PSID,DWORD); +PUCHAR WINAPI GetSidSubAuthorityCount(PSID); +DWORD WINAPI GetShortPathNameA(LPCSTR,LPSTR,DWORD); +DWORD WINAPI GetShortPathNameW(LPCWSTR,LPWSTR,DWORD); +#define GetShortPathName WINELIB_NAME_AW(GetShortPathName) +HFILE WINAPI GetStdHandle(DWORD); +WIN_BOOL WINAPI GetStringTypeExA(LCID,DWORD,LPCSTR,INT,LPWORD); +WIN_BOOL WINAPI GetStringTypeExW(LCID,DWORD,LPCWSTR,INT,LPWORD); +#define GetStringTypeEx WINELIB_NAME_AW(GetStringTypeEx) +VOID WINAPI GetSystemInfo(LPSYSTEM_INFO); +WIN_BOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS); +VOID WINAPI GetSystemTime(LPSYSTEMTIME); +VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME); +INT WINAPI GetTimeFormatA(LCID,DWORD,LPSYSTEMTIME,LPCSTR,LPSTR,INT); +INT WINAPI GetTimeFormatW(LCID,DWORD,LPSYSTEMTIME,LPCWSTR,LPWSTR,INT); +#define GetTimeFormat WINELIB_NAME_AW(GetTimeFormat) +WIN_BOOL WINAPI GetThreadContext(HANDLE,CONTEXT *); +LCID WINAPI GetThreadLocale(void); +INT WINAPI GetThreadPriority(HANDLE); +WIN_BOOL WINAPI GetThreadSelectorEntry(HANDLE,DWORD,LPLDT_ENTRY); +WIN_BOOL WINAPI GetThreadTimes(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME,LPFILETIME); +WIN_BOOL WINAPI GetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,LPVOID,DWORD,LPDWORD); +WIN_BOOL WINAPI GetUserNameA(LPSTR,LPDWORD); +WIN_BOOL WINAPI GetUserNameW(LPWSTR,LPDWORD); +#define GetUserName WINELIB_NAME_AW(GetUserName) +VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS); +LPVOID WINAPI HeapAlloc(HANDLE,DWORD,DWORD); +DWORD WINAPI HeapCompact(HANDLE,DWORD); +HANDLE WINAPI HeapCreate(DWORD,DWORD,DWORD); +WIN_BOOL WINAPI HeapDestroy(HANDLE); +WIN_BOOL WINAPI HeapFree(HANDLE,DWORD,LPVOID); +WIN_BOOL WINAPI HeapLock(HANDLE); +LPVOID WINAPI HeapReAlloc(HANDLE,DWORD,LPVOID,DWORD); +DWORD WINAPI HeapSize(HANDLE,DWORD,LPVOID); +WIN_BOOL WINAPI HeapUnlock(HANDLE); +WIN_BOOL WINAPI HeapValidate(HANDLE,DWORD,LPCVOID); +WIN_BOOL WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY); +WIN_BOOL WINAPI InitializeSid(PSID,PSID_IDENTIFIER_AUTHORITY,BYTE); +WIN_BOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR); +WIN_BOOL WINAPI IsValidSid(PSID); +WIN_BOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL); +WIN_BOOL WINAPI IsDBCSLeadByteEx(UINT,BYTE); +WIN_BOOL WINAPI IsProcessorFeaturePresent(DWORD); +WIN_BOOL WINAPI IsValidLocale(DWORD,DWORD); +WIN_BOOL WINAPI LookupAccountSidA(LPCSTR,PSID,LPSTR,LPDWORD,LPSTR,LPDWORD,PSID_NAME_USE); +WIN_BOOL WINAPI LookupAccountSidW(LPCWSTR,PSID,LPWSTR,LPDWORD,LPWSTR,LPDWORD,PSID_NAME_USE); +#define LookupAccountSid WINELIB_NAME_AW(LookupAccountSidW) +WIN_BOOL WINAPI LocalFileTimeToFileTime(const FILETIME*,LPFILETIME); +WIN_BOOL WINAPI LockFile(HANDLE,DWORD,DWORD,DWORD,DWORD); +WIN_BOOL WINAPI LockFileEx(HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED); +WIN_BOOL WINAPI LookupPrivilegeValueA(LPCSTR,LPCSTR,LPVOID); +WIN_BOOL WINAPI LookupPrivilegeValueW(LPCWSTR,LPCWSTR,LPVOID); +#define LookupPrivilegeValue WINELIB_NAME_AW(LookupPrivilegeValue) +WIN_BOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,LPDWORD); +HMODULE WINAPI MapHModuleSL(HMODULE16); +HMODULE16 WINAPI MapHModuleLS(HMODULE); +SEGPTR WINAPI MapLS(LPVOID); +LPVOID WINAPI MapSL(SEGPTR); +LPVOID WINAPI MapViewOfFile(HANDLE,DWORD,DWORD,DWORD,DWORD); +LPVOID WINAPI MapViewOfFileEx(HANDLE,DWORD,DWORD,DWORD,DWORD,LPVOID); +WIN_BOOL WINAPI MoveFileA(LPCSTR,LPCSTR); +WIN_BOOL WINAPI MoveFileW(LPCWSTR,LPCWSTR); +#define MoveFile WINELIB_NAME_AW(MoveFile) +WIN_BOOL WINAPI MoveFileExA(LPCSTR,LPCSTR,DWORD); +WIN_BOOL WINAPI MoveFileExW(LPCWSTR,LPCWSTR,DWORD); +#define MoveFileEx WINELIB_NAME_AW(MoveFileEx) +INT WINAPI MultiByteToWideChar(UINT,DWORD,LPCSTR,INT,LPWSTR,INT); +WIN_BOOL WINAPI NotifyChangeEventLog(HANDLE,HANDLE); +INT WINAPI WideCharToMultiByte(UINT,DWORD,LPCWSTR,INT,LPSTR,INT,LPCSTR,WIN_BOOL*); +HANDLE WINAPI OpenBackupEventLogA(LPCSTR,LPCSTR); +HANDLE WINAPI OpenBackupEventLogW(LPCWSTR,LPCWSTR); +#define OpenBackupEventLog WINELIB_NAME_AW(OpenBackupEventLog) +HANDLE WINAPI OpenEventA(DWORD,WIN_BOOL,LPCSTR); +HANDLE WINAPI OpenEventW(DWORD,WIN_BOOL,LPCWSTR); +#define OpenEvent WINELIB_NAME_AW(OpenEvent) +HANDLE WINAPI OpenEventLogA(LPCSTR,LPCSTR); +HANDLE WINAPI OpenEventLogW(LPCWSTR,LPCWSTR); +#define OpenEventLog WINELIB_NAME_AW(OpenEventLog) +HANDLE WINAPI OpenFileMappingA(DWORD,WIN_BOOL,LPCSTR); +HANDLE WINAPI OpenFileMappingW(DWORD,WIN_BOOL,LPCWSTR); +#define OpenFileMapping WINELIB_NAME_AW(OpenFileMapping) +HANDLE WINAPI OpenMutexA(DWORD,WIN_BOOL,LPCSTR); +HANDLE WINAPI OpenMutexW(DWORD,WIN_BOOL,LPCWSTR); +#define OpenMutex WINELIB_NAME_AW(OpenMutex) +HANDLE WINAPI OpenProcess(DWORD,WIN_BOOL,DWORD); +WIN_BOOL WINAPI OpenProcessToken(HANDLE,DWORD,PHANDLE); +HANDLE WINAPI OpenSemaphoreA(DWORD,WIN_BOOL,LPCSTR); +HANDLE WINAPI OpenSemaphoreW(DWORD,WIN_BOOL,LPCWSTR); +#define OpenSemaphore WINELIB_NAME_AW(OpenSemaphore) +WIN_BOOL WINAPI OpenThreadToken(HANDLE,DWORD,WIN_BOOL,PHANDLE); +HANDLE WINAPI OpenWaitableTimerA(DWORD,WIN_BOOL,LPCSTR); +HANDLE WINAPI OpenWaitableTimerW(DWORD,WIN_BOOL,LPCWSTR); +#define OpenWaitableTimer WINELIB_NAME_AW(OpenWaitableTimer) +WIN_BOOL WINAPI PulseEvent(HANDLE); +WIN_BOOL WINAPI PurgeComm(HANDLE,DWORD); +DWORD WINAPI QueryDosDeviceA(LPCSTR,LPSTR,DWORD); +DWORD WINAPI QueryDosDeviceW(LPCWSTR,LPWSTR,DWORD); +#define QueryDosDevice WINELIB_NAME_AW(QueryDosDevice) +WIN_BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER); +WIN_BOOL WINAPI ReadConsoleA(HANDLE,LPVOID,DWORD,LPDWORD,LPVOID); +WIN_BOOL WINAPI ReadConsoleW(HANDLE,LPVOID,DWORD,LPDWORD,LPVOID); +#define ReadConsole WINELIB_NAME_AW(ReadConsole) +WIN_BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE,LPSTR,DWORD, + COORD,LPDWORD); +#define ReadConsoleOutputCharacter WINELIB_NAME_AW(ReadConsoleOutputCharacter) +WIN_BOOL WINAPI ReadEventLogA(HANDLE,DWORD,DWORD,LPVOID,DWORD,DWORD *,DWORD *); +WIN_BOOL WINAPI ReadEventLogW(HANDLE,DWORD,DWORD,LPVOID,DWORD,DWORD *,DWORD *); +#define ReadEventLog WINELIB_NAME_AW(ReadEventLog) +WIN_BOOL WINAPI ReadFile(HANDLE,LPVOID,DWORD,LPDWORD,LPOVERLAPPED); +HANDLE WINAPI RegisterEventSourceA(LPCSTR,LPCSTR); +HANDLE WINAPI RegisterEventSourceW(LPCWSTR,LPCWSTR); +#define RegisterEventSource WINELIB_NAME_AW(RegisterEventSource) +WIN_BOOL WINAPI ReleaseMutex(HANDLE); +WIN_BOOL WINAPI ReleaseSemaphore(HANDLE,LONG,LPLONG); +WIN_BOOL WINAPI ReportEventA(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCSTR *,LPVOID); +WIN_BOOL WINAPI ReportEventW(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCWSTR *,LPVOID); +#define ReportEvent WINELIB_NAME_AW(ReportEvent) +WIN_BOOL WINAPI ResetEvent(HANDLE); +DWORD WINAPI ResumeThread(HANDLE); +WIN_BOOL WINAPI RevertToSelf(void); +DWORD WINAPI SearchPathA(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*); +DWORD WINAPI SearchPathW(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPWSTR,LPWSTR*); +#define SearchPath WINELIB_NAME_AW(SearchPath) +WIN_BOOL WINAPI SetCommMask(INT,DWORD); +WIN_BOOL WINAPI SetComputerNameA(LPCSTR); +WIN_BOOL WINAPI SetComputerNameW(LPCWSTR); +#define SetComputerName WINELIB_NAME_AW(SetComputerName) +WIN_BOOL WINAPI SetConsoleCursorPosition(HANDLE,COORD); +WIN_BOOL WINAPI SetConsoleMode(HANDLE,DWORD); +WIN_BOOL WINAPI SetConsoleTitleA(LPCSTR); +WIN_BOOL WINAPI SetConsoleTitleW(LPCWSTR); +#define SetConsoleTitle WINELIB_NAME_AW(SetConsoleTitle) +WIN_BOOL WINAPI SetEndOfFile(HANDLE); +WIN_BOOL WINAPI SetEnvironmentVariableA(LPCSTR,LPCSTR); +WIN_BOOL WINAPI SetEnvironmentVariableW(LPCWSTR,LPCWSTR); +#define SetEnvironmentVariable WINELIB_NAME_AW(SetEnvironmentVariable) +WIN_BOOL WINAPI SetEvent(HANDLE); +VOID WINAPI SetFileApisToANSI(void); +VOID WINAPI SetFileApisToOEM(void); +DWORD WINAPI SetFilePointer(HANDLE,LONG,LPLONG,DWORD); +WIN_BOOL WINAPI SetFileSecurityA(LPCSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR); +WIN_BOOL WINAPI SetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR); +#define SetFileSecurity WINELIB_NAME_AW(SetFileSecurity) +WIN_BOOL WINAPI SetFileTime(HANDLE,const FILETIME*,const FILETIME*,const FILETIME*); +WIN_BOOL WINAPI SetHandleInformation(HANDLE,DWORD,DWORD); +WIN_BOOL WINAPI SetPriorityClass(HANDLE,DWORD); +WIN_BOOL WINAPI SetLocalTime(const SYSTEMTIME*); +WIN_BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,WIN_BOOL,PACL,WIN_BOOL); +WIN_BOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR,PSID,WIN_BOOL); +WIN_BOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR,PSID,WIN_BOOL); +WIN_BOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR,WIN_BOOL,PACL,WIN_BOOL); +WIN_BOOL WINAPI SetStdHandle(DWORD,HANDLE); +WIN_BOOL WINAPI SetSystemPowerState(WIN_BOOL,WIN_BOOL); +WIN_BOOL WINAPI SetSystemTime(const SYSTEMTIME*); +DWORD WINAPI SetThreadAffinityMask(HANDLE,DWORD); +WIN_BOOL WINAPI SetThreadContext(HANDLE,const CONTEXT *); +WIN_BOOL WINAPI SetThreadLocale(LCID); +WIN_BOOL WINAPI SetThreadPriority(HANDLE,INT); +WIN_BOOL WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION); +WIN_BOOL WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,LPVOID,WIN_BOOL); +VOID WINAPI Sleep(DWORD); +DWORD WINAPI SleepEx(DWORD,WIN_BOOL); +DWORD WINAPI SuspendThread(HANDLE); +WIN_BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME*,LPFILETIME); +DWORD WINAPI TlsAlloc(void); +WIN_BOOL WINAPI TlsFree(DWORD); +LPVOID WINAPI TlsGetValue(DWORD); +WIN_BOOL WINAPI TlsSetValue(DWORD,LPVOID); +VOID WINAPI UnMapLS(SEGPTR); +WIN_BOOL WINAPI UnlockFile(HANDLE,DWORD,DWORD,DWORD,DWORD); +WIN_BOOL WINAPI UnmapViewOfFile(LPVOID); +LPVOID WINAPI VirtualAlloc(LPVOID,DWORD,DWORD,DWORD); +WIN_BOOL WINAPI VirtualFree(LPVOID,SIZE_T,DWORD); +WIN_BOOL WINAPI VirtualLock(LPVOID,DWORD); +WIN_BOOL WINAPI VirtualProtect(LPVOID,DWORD,DWORD,LPDWORD); +WIN_BOOL WINAPI VirtualProtectEx(HANDLE,LPVOID,DWORD,DWORD,LPDWORD); +DWORD WINAPI VirtualQuery(LPCVOID,LPMEMORY_BASIC_INFORMATION,DWORD); +DWORD WINAPI VirtualQueryEx(HANDLE,LPCVOID,LPMEMORY_BASIC_INFORMATION,DWORD); +WIN_BOOL WINAPI VirtualUnlock(LPVOID,DWORD); +WIN_BOOL WINAPI WaitCommEvent(HANDLE,LPDWORD,LPOVERLAPPED); +WIN_BOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT,DWORD); +DWORD WINAPI WaitForMultipleObjects(DWORD,const HANDLE*,WIN_BOOL,DWORD); +DWORD WINAPI WaitForMultipleObjectsEx(DWORD,const HANDLE*,WIN_BOOL,DWORD,WIN_BOOL); +DWORD WINAPI WaitForSingleObject(HANDLE,DWORD); +DWORD WINAPI WaitForSingleObjectEx(HANDLE,DWORD,WIN_BOOL); +WIN_BOOL WINAPI WriteConsoleA(HANDLE,LPCVOID,DWORD,LPDWORD,LPVOID); +WIN_BOOL WINAPI WriteConsoleW(HANDLE,LPCVOID,DWORD,LPDWORD,LPVOID); +#define WriteConsole WINELIB_NAME_AW(WriteConsole) +WIN_BOOL WINAPI WriteFile(HANDLE,LPCVOID,DWORD,LPDWORD,LPOVERLAPPED); +LANGID WINAPI GetSystemDefaultLangID(void); +LCID WINAPI GetSystemDefaultLCID(void); +LANGID WINAPI GetUserDefaultLangID(void); +LCID WINAPI GetUserDefaultLCID(void); +ATOM WINAPI AddAtomA(LPCSTR); +ATOM WINAPI AddAtomW(LPCWSTR); +#define AddAtom WINELIB_NAME_AW(AddAtom) +UINT WINAPI CompareStringA(DWORD,DWORD,LPCSTR,DWORD,LPCSTR,DWORD); +UINT WINAPI CompareStringW(DWORD,DWORD,LPCWSTR,DWORD,LPCWSTR,DWORD); +#define CompareString WINELIB_NAME_AW(CompareString) +WIN_BOOL WINAPI CreateDirectoryA(LPCSTR,LPSECURITY_ATTRIBUTES); +WIN_BOOL WINAPI CreateDirectoryW(LPCWSTR,LPSECURITY_ATTRIBUTES); +#define CreateDirectory WINELIB_NAME_AW(CreateDirectory) +WIN_BOOL WINAPI CreateDirectoryExA(LPCSTR,LPCSTR,LPSECURITY_ATTRIBUTES); +WIN_BOOL WINAPI CreateDirectoryExW(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES); +#define CreateDirectoryEx WINELIB_NAME_AW(CreateDirectoryEx) +WIN_BOOL WINAPI DefineDosDeviceA(DWORD,LPCSTR,LPCSTR); +#define DefineHandleTable(w) ((w),TRUE) +ATOM WINAPI DeleteAtom(ATOM); +WIN_BOOL WINAPI DeleteFileA(LPCSTR); +WIN_BOOL WINAPI DeleteFileW(LPCWSTR); +#define DeleteFile WINELIB_NAME_AW(DeleteFile) +void WINAPI FatalAppExitA(UINT,LPCSTR); +void WINAPI FatalAppExitW(UINT,LPCWSTR); +#define FatalAppExit WINELIB_NAME_AW(FatalAppExit) +ATOM WINAPI FindAtomA(LPCSTR); +ATOM WINAPI FindAtomW(LPCWSTR); +#define FindAtom WINELIB_NAME_AW(FindAtom) +WIN_BOOL WINAPI FindClose(HANDLE); +HANDLE16 WINAPI FindFirstFile16(LPCSTR,LPWIN32_FIND_DATAA); +HANDLE WINAPI FindFirstFileA(LPCSTR,LPWIN32_FIND_DATAA); +HANDLE WINAPI FindFirstFileW(LPCWSTR,LPWIN32_FIND_DATAW); +#define FindFirstFile WINELIB_NAME_AW(FindFirstFile) +WIN_BOOL16 WINAPI FindNextFile16(HANDLE16,LPWIN32_FIND_DATAA); +WIN_BOOL WINAPI FindNextFileA(HANDLE,LPWIN32_FIND_DATAA); +WIN_BOOL WINAPI FindNextFileW(HANDLE,LPWIN32_FIND_DATAW); +#define FindNextFile WINELIB_NAME_AW(FindNextFile) +HRSRC WINAPI FindResourceA(HMODULE,LPCSTR,LPCSTR); +HRSRC WINAPI FindResourceW(HMODULE,LPCWSTR,LPCWSTR); +#define FindResource WINELIB_NAME_AW(FindResource) +VOID WINAPI FreeLibrary16(HINSTANCE16); +WIN_BOOL WINAPI FreeLibrary(HMODULE); +#define FreeModule(handle) FreeLibrary(handle) +#define FreeProcInstance(proc) /*nothing*/ +WIN_BOOL WINAPI FreeResource(HGLOBAL); +UINT WINAPI GetAtomNameA(ATOM,LPSTR,INT); +UINT WINAPI GetAtomNameW(ATOM,LPWSTR,INT); +#define GetAtomName WINELIB_NAME_AW(GetAtomName) +UINT WINAPI GetCurrentDirectoryA(UINT,LPSTR); +UINT WINAPI GetCurrentDirectoryW(UINT,LPWSTR); +#define GetCurrentDirectory WINELIB_NAME_AW(GetCurrentDirectory) +WIN_BOOL WINAPI GetDiskFreeSpaceA(LPCSTR,LPDWORD,LPDWORD,LPDWORD,LPDWORD); +WIN_BOOL WINAPI GetDiskFreeSpaceW(LPCWSTR,LPDWORD,LPDWORD,LPDWORD,LPDWORD); +#define GetDiskFreeSpace WINELIB_NAME_AW(GetDiskFreeSpace) +WIN_BOOL WINAPI GetDiskFreeSpaceExA(LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER); +WIN_BOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER); +#define GetDiskFreeSpaceEx WINELIB_NAME_AW(GetDiskFreeSpaceEx) +UINT WINAPI GetDriveTypeA(LPCSTR); +UINT WINAPI GetDriveTypeW(LPCWSTR); +#define GetDriveType WINELIB_NAME_AW(GetDriveType) +DWORD WINAPI GetFileAttributesA(LPCSTR); +DWORD WINAPI GetFileAttributesW(LPCWSTR); +#define GetFileAttributes WINELIB_NAME_AW(GetFileAttributes) +#define GetFreeSpace(w) (0x100000L) +UINT WINAPI GetLogicalDriveStringsA(UINT,LPSTR); +UINT WINAPI GetLogicalDriveStringsW(UINT,LPWSTR); +#define GetLogicalDriveStrings WINELIB_NAME_AW(GetLogicalDriveStrings) +INT WINAPI GetLocaleInfoA(LCID,LCTYPE,LPSTR,INT); +INT WINAPI GetLocaleInfoW(LCID,LCTYPE,LPWSTR,INT); +#define GetLocaleInfo WINELIB_NAME_AW(GetLocaleInfo) +DWORD WINAPI GetModuleFileNameA(HMODULE,LPSTR,DWORD); +DWORD WINAPI GetModuleFileNameW(HMODULE,LPWSTR,DWORD); +#define GetModuleFileName WINELIB_NAME_AW(GetModuleFileName) +HMODULE WINAPI GetModuleHandleA(LPCSTR); +HMODULE WINAPI GetModuleHandleW(LPCWSTR); +#define GetModuleHandle WINELIB_NAME_AW(GetModuleHandle) +WIN_BOOL WINAPI GetOverlappedResult(HANDLE,LPOVERLAPPED,LPDWORD,WIN_BOOL); +UINT WINAPI GetPrivateProfileIntA(LPCSTR,LPCSTR,INT,LPCSTR); +UINT WINAPI GetPrivateProfileIntW(LPCWSTR,LPCWSTR,INT,LPCWSTR); +#define GetPrivateProfileInt WINELIB_NAME_AW(GetPrivateProfileInt) +INT WINAPI GetPrivateProfileSectionA(LPCSTR,LPSTR,DWORD,LPCSTR); +INT WINAPI GetPrivateProfileSectionW(LPCWSTR,LPWSTR,DWORD,LPCWSTR); +#define GetPrivateProfileSection WINELIB_NAME_AW(GetPrivateProfileSection) +DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR,DWORD,LPCSTR); +DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR,DWORD,LPCWSTR); +#define GetPrivateProfileSectionNames WINELIB_NAME_AW(GetPrivateProfileSectionNames) +INT WINAPI GetPrivateProfileStringA(LPCSTR,LPCSTR,LPCSTR,LPSTR,UINT,LPCSTR); +INT WINAPI GetPrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,UINT,LPCWSTR); +#define GetPrivateProfileString WINELIB_NAME_AW(GetPrivateProfileString) +WIN_BOOL WINAPI GetPrivateProfileStructA(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR); +WIN_BOOL WINAPI GetPrivateProfileStructW(LPCWSTR,LPCWSTR,LPVOID,UINT,LPCWSTR); +#define GetPrivateProfileStruct WINELIB_NAME_AW(GetPrivateProfileStruct) +FARPROC WINAPI GetProcAddress(HMODULE,LPCSTR); +UINT WINAPI GetProfileIntA(LPCSTR,LPCSTR,INT); +UINT WINAPI GetProfileIntW(LPCWSTR,LPCWSTR,INT); +#define GetProfileInt WINELIB_NAME_AW(GetProfileInt) +INT WINAPI GetProfileSectionA(LPCSTR,LPSTR,DWORD); +INT WINAPI GetProfileSectionW(LPCWSTR,LPWSTR,DWORD); +#define GetProfileSection WINELIB_NAME_AW(GetProfileSection) +INT WINAPI GetProfileStringA(LPCSTR,LPCSTR,LPCSTR,LPSTR,UINT); +INT WINAPI GetProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,UINT); +#define GetProfileString WINELIB_NAME_AW(GetProfileString) +VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA); +VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW); +#define GetStartupInfo WINELIB_NAME_AW(GetStartupInfo) +WIN_BOOL WINAPI GetStringTypeA(LCID,DWORD,LPCSTR,INT,LPWORD); +WIN_BOOL WINAPI GetStringTypeW(DWORD,LPCWSTR,INT,LPWORD); +#define GetStringType WINELIB_NAME_AW(GetStringType) +UINT WINAPI GetSystemDirectoryA(LPSTR,UINT); +UINT WINAPI GetSystemDirectoryW(LPWSTR,UINT); +#define GetSystemDirectory WINELIB_NAME_AW(GetSystemDirectory) +UINT WINAPI GetTempFileNameA(LPCSTR,LPCSTR,UINT,LPSTR); +UINT WINAPI GetTempFileNameW(LPCWSTR,LPCWSTR,UINT,LPWSTR); +#define GetTempFileName WINELIB_NAME_AW(GetTempFileName) +UINT WINAPI GetTempPathA(UINT,LPSTR); +UINT WINAPI GetTempPathW(UINT,LPWSTR); +#define GetTempPath WINELIB_NAME_AW(GetTempPath) +LONG WINAPI GetVersion(void); +WIN_BOOL WINAPI GetExitCodeProcess(HANDLE,LPDWORD); +WIN_BOOL WINAPI GetVolumeInformationA(LPCSTR,LPSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPSTR,DWORD); +WIN_BOOL WINAPI GetVolumeInformationW(LPCWSTR,LPWSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR,DWORD); +#define GetVolumeInformation WINELIB_NAME_AW(GetVolumeInformation) +UINT WINAPI GetWindowsDirectoryA(LPSTR,UINT); +UINT WINAPI GetWindowsDirectoryW(LPWSTR,UINT); +#define GetWindowsDirectory WINELIB_NAME_AW(GetWindowsDirectory) +HGLOBAL16 WINAPI GlobalAlloc16(UINT16,DWORD); +HGLOBAL WINAPI GlobalAlloc(UINT,DWORD); +DWORD WINAPI GlobalCompact(DWORD); +UINT WINAPI GlobalFlags(HGLOBAL); +HGLOBAL16 WINAPI GlobalFree16(HGLOBAL16); +HGLOBAL WINAPI GlobalFree(HGLOBAL); +HGLOBAL WINAPI GlobalHandle(LPCVOID); +WORD WINAPI GlobalFix16(HGLOBAL16); +VOID WINAPI GlobalFix(HGLOBAL); +LPVOID WINAPI GlobalLock16(HGLOBAL16); +LPVOID WINAPI GlobalLock(HGLOBAL); +HGLOBAL WINAPI GlobalReAlloc(HGLOBAL,DWORD,UINT); +DWORD WINAPI GlobalSize16(HGLOBAL16); +DWORD WINAPI GlobalSize(HGLOBAL); +VOID WINAPI GlobalUnfix16(HGLOBAL16); +VOID WINAPI GlobalUnfix(HGLOBAL); +WIN_BOOL16 WINAPI GlobalUnlock16(HGLOBAL16); +WIN_BOOL WINAPI GlobalUnlock(HGLOBAL); +WIN_BOOL16 WINAPI GlobalUnWire16(HGLOBAL16); +WIN_BOOL WINAPI GlobalUnWire(HGLOBAL); +SEGPTR WINAPI GlobalWire16(HGLOBAL16); +LPVOID WINAPI GlobalWire(HGLOBAL); +WIN_BOOL WINAPI InitAtomTable(DWORD); +WIN_BOOL WINAPI IsBadCodePtr(FARPROC); +WIN_BOOL WINAPI IsBadHugeReadPtr(LPCVOID,UINT); +WIN_BOOL WINAPI IsBadHugeWritePtr(LPVOID,UINT); +WIN_BOOL WINAPI IsBadReadPtr(LPCVOID,UINT); +WIN_BOOL WINAPI IsBadStringPtrA(LPCSTR,UINT); +WIN_BOOL WINAPI IsBadStringPtrW(LPCWSTR,UINT); +#define IsBadStringPtr WINELIB_NAME_AW(IsBadStringPtr) +WIN_BOOL WINAPI IsBadWritePtr(LPVOID,UINT); +WIN_BOOL WINAPI IsDBCSLeadByte(BYTE); +WIN_BOOL WINAPI IsDebuggerPresent(void); +HINSTANCE16 WINAPI LoadLibrary16(LPCSTR); +HMODULE WINAPI LoadLibraryA(LPCSTR); +HMODULE WINAPI LoadLibraryW(LPCWSTR); +#define LoadLibrary WINELIB_NAME_AW(LoadLibrary) +HMODULE WINAPI LoadLibraryExA(LPCSTR,HANDLE,DWORD); +HMODULE WINAPI LoadLibraryExW(LPCWSTR,HANDLE,DWORD); +#define LoadLibraryEx WINELIB_NAME_AW(LoadLibraryEx) +HINSTANCE16 WINAPI LoadModule16(LPCSTR,LPVOID); +HINSTANCE WINAPI LoadModule(LPCSTR,LPVOID); +HGLOBAL WINAPI LoadResource(HMODULE,HRSRC); +HLOCAL WINAPI LocalAlloc(UINT,DWORD); +UINT WINAPI LocalCompact(UINT); +UINT WINAPI LocalFlags(HLOCAL); +HLOCAL WINAPI LocalFree(HLOCAL); +HLOCAL WINAPI LocalHandle(LPCVOID); +LPVOID WINAPI LocalLock(HLOCAL); +HLOCAL WINAPI LocalReAlloc(HLOCAL,DWORD,UINT); +UINT WINAPI LocalShrink(HGLOBAL,UINT); +UINT WINAPI LocalSize(HLOCAL); +WIN_BOOL WINAPI LocalUnlock(HLOCAL); +LPVOID WINAPI LockResource(HGLOBAL); +#define LockSegment(handle) GlobalFix((HANDLE)(handle)) +#define MakeProcInstance(proc,inst) (proc) +HFILE16 WINAPI OpenFile16(LPCSTR,OFSTRUCT*,UINT16); +HFILE WINAPI OpenFile(LPCSTR,OFSTRUCT*,UINT); +VOID WINAPI OutputDebugStringA(LPCSTR); +VOID WINAPI OutputDebugStringW(LPCWSTR); +#define OutputDebugString WINELIB_NAME_AW(OutputDebugString) +WIN_BOOL WINAPI ReadProcessMemory(HANDLE, LPCVOID, LPVOID, DWORD, LPDWORD); +WIN_BOOL WINAPI RemoveDirectoryA(LPCSTR); +WIN_BOOL WINAPI RemoveDirectoryW(LPCWSTR); +#define RemoveDirectory WINELIB_NAME_AW(RemoveDirectory) +WIN_BOOL WINAPI SetCurrentDirectoryA(LPCSTR); +WIN_BOOL WINAPI SetCurrentDirectoryW(LPCWSTR); +#define SetCurrentDirectory WINELIB_NAME_AW(SetCurrentDirectory) +UINT WINAPI SetErrorMode(UINT); +WIN_BOOL WINAPI SetFileAttributesA(LPCSTR,DWORD); +WIN_BOOL WINAPI SetFileAttributesW(LPCWSTR,DWORD); +#define SetFileAttributes WINELIB_NAME_AW(SetFileAttributes) +UINT WINAPI SetHandleCount(UINT); +#define SetSwapAreaSize(w) (w) +WIN_BOOL WINAPI SetVolumeLabelA(LPCSTR,LPCSTR); +WIN_BOOL WINAPI SetVolumeLabelW(LPCWSTR,LPCWSTR); +#define SetVolumeLabel WINELIB_NAME_AW(SetVolumeLabel) +DWORD WINAPI SizeofResource(HMODULE,HRSRC); +#define UnlockSegment(handle) GlobalUnfix((HANDLE)(handle)) +WIN_BOOL WINAPI WritePrivateProfileSectionA(LPCSTR,LPCSTR,LPCSTR); +WIN_BOOL WINAPI WritePrivateProfileSectionW(LPCWSTR,LPCWSTR,LPCWSTR); +#define WritePrivateProfileSection WINELIB_NAME_AW(WritePrivateProfileSection) +WIN_BOOL WINAPI WritePrivateProfileStringA(LPCSTR,LPCSTR,LPCSTR,LPCSTR); +WIN_BOOL WINAPI WritePrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR); +#define WritePrivateProfileString WINELIB_NAME_AW(WritePrivateProfileString) +WIN_BOOL WINAPI WriteProfileSectionA(LPCSTR,LPCSTR); +WIN_BOOL WINAPI WriteProfileSectionW(LPCWSTR,LPCWSTR); +#define WritePrivateProfileSection WINELIB_NAME_AW(WritePrivateProfileSection) +WIN_BOOL WINAPI WritePrivateProfileStructA(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR); +WIN_BOOL WINAPI WritePrivateProfileStructW(LPCWSTR,LPCWSTR,LPVOID,UINT,LPCWSTR); +#define WritePrivateProfileStruct WINELIB_NAME_AW(WritePrivateProfileStruct) +WIN_BOOL WINAPI WriteProcessMemory(HANDLE, LPVOID, LPVOID, DWORD, LPDWORD); +WIN_BOOL WINAPI WriteProfileStringA(LPCSTR,LPCSTR,LPCSTR); +WIN_BOOL WINAPI WriteProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR); +#define WriteProfileString WINELIB_NAME_AW(WriteProfileString) +#define Yield32() +LPSTR WINAPI lstrcatA(LPSTR,LPCSTR); +LPWSTR WINAPI lstrcatW(LPWSTR,LPCWSTR); +#define lstrcat WINELIB_NAME_AW(lstrcat) +LPSTR WINAPI lstrcpyA(LPSTR,LPCSTR); +LPWSTR WINAPI lstrcpyW(LPWSTR,LPCWSTR); +#define lstrcpy WINELIB_NAME_AW(lstrcpy) +LPSTR WINAPI lstrcpynA(LPSTR,LPCSTR,INT); +LPWSTR WINAPI lstrcpynW(LPWSTR,LPCWSTR,INT); +#define lstrcpyn WINELIB_NAME_AW(lstrcpyn) +INT WINAPI lstrlenA(LPCSTR); +INT WINAPI lstrlenW(LPCWSTR); +#define lstrlen WINELIB_NAME_AW(lstrlen) +HINSTANCE WINAPI WinExec(LPCSTR,UINT); +LONG WINAPI _hread(HFILE,LPVOID,LONG); +LONG WINAPI _hwrite(HFILE,LPCSTR,LONG); +HFILE WINAPI _lcreat(LPCSTR,INT); +HFILE WINAPI _lclose(HFILE); +LONG WINAPI _llseek(HFILE,LONG,INT); +HFILE WINAPI _lopen(LPCSTR,INT); +UINT WINAPI _lread(HFILE,LPVOID,UINT); +UINT WINAPI _lwrite(HFILE,LPCSTR,UINT); +SEGPTR WINAPI WIN16_GlobalLock16(HGLOBAL16); +INT WINAPI lstrcmpA(LPCSTR,LPCSTR); +INT WINAPI lstrcmpW(LPCWSTR,LPCWSTR); +#define lstrcmp WINELIB_NAME_AW(lstrcmp) +INT WINAPI lstrcmpiA(LPCSTR,LPCSTR); +INT WINAPI lstrcmpiW(LPCWSTR,LPCWSTR); +#define lstrcmpi WINELIB_NAME_AW(lstrcmpi) + +/* compatibility macros */ +#define FillMemory RtlFillMemory +#define MoveMemory RtlMoveMemory +#define ZeroMemory RtlZeroMemory +#define CopyMemory RtlCopyMemory + +DWORD WINAPI GetCurrentProcessId(void); +DWORD WINAPI GetCurrentThreadId(void); +DWORD WINAPI GetLastError(void); +HANDLE WINAPI GetProcessHeap(void); +PVOID WINAPI InterlockedCompareExchange(PVOID*,PVOID,PVOID); +LONG WINAPI InterlockedDecrement(PLONG); +LONG WINAPI InterlockedExchange(PLONG,LONG); +LONG WINAPI InterlockedExchangeAdd(PLONG,LONG); +LONG WINAPI InterlockedIncrement(PLONG); +VOID WINAPI SetLastError(DWORD); + +#ifdef __WINE__ +#define GetCurrentProcess() ((HANDLE)0xffffffff) +#define GetCurrentThread() ((HANDLE)0xfffffffe) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_WINBASE_H */ diff --git a/linphone/win32acm/wine/windef.h b/linphone/win32acm/wine/windef.h new file mode 100644 index 000000000..85b84255a --- /dev/null +++ b/linphone/win32acm/wine/windef.h @@ -0,0 +1,666 @@ +/* + * Basic types definitions + * + * Copyright 1996 Alexandre Julliard + */ + +#ifndef __WINE_WINDEF_H +#define __WINE_WINDEF_H + +#ifdef __WINE__ +# include "config.h" +# undef UNICODE +#endif + +#ifdef _EGCS_ +#define __stdcall +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Misc. constants. */ + +#ifdef FALSE +#undef FALSE +#endif +#define FALSE 0 + +#ifdef TRUE +#undef TRUE +#endif +#define TRUE 1 + +#ifdef NULL +#undef NULL +#endif +#define NULL 0 + +/* Macros to map Winelib names to the correct implementation name */ +/* depending on __WINE__ and UNICODE macros. */ +/* Note that Winelib is purely Win32. */ + +#ifdef __WINE__ +# define WINELIB_NAME_AW(func) \ + func##_must_be_suffixed_with_W_or_A_in_this_context \ + func##_must_be_suffixed_with_W_or_A_in_this_context +#else /* __WINE__ */ +# ifdef UNICODE +# define WINELIB_NAME_AW(func) func##W +# else +# define WINELIB_NAME_AW(func) func##A +# endif /* UNICODE */ +#endif /* __WINE__ */ + +#ifdef __WINE__ +# define DECL_WINELIB_TYPE_AW(type) /* nothing */ +#else /* __WINE__ */ +# define DECL_WINELIB_TYPE_AW(type) typedef WINELIB_NAME_AW(type) type; +#endif /* __WINE__ */ + +#ifndef NONAMELESSSTRUCT +# if defined(__WINE__) || !defined(_FORCENAMELESSSTRUCT) +# define NONAMELESSSTRUCT +# endif +#endif /* !defined(NONAMELESSSTRUCT) */ + +#ifndef NONAMELESSUNION +# if defined(__WINE__) || !defined(_FORCENAMELESSUNION) || !defined(__cplusplus) +# define NONAMELESSUNION +# endif +#endif /* !defined(NONAMELESSUNION) */ + +#ifndef NONAMELESSSTRUCT +#define DUMMYSTRUCTNAME +#define DUMMYSTRUCTNAME1 +#define DUMMYSTRUCTNAME2 +#define DUMMYSTRUCTNAME3 +#define DUMMYSTRUCTNAME4 +#define DUMMYSTRUCTNAME5 +#else /* !defined(NONAMELESSSTRUCT) */ +#define DUMMYSTRUCTNAME s +#define DUMMYSTRUCTNAME1 s1 +#define DUMMYSTRUCTNAME2 s2 +#define DUMMYSTRUCTNAME3 s3 +#define DUMMYSTRUCTNAME4 s4 +#define DUMMYSTRUCTNAME5 s5 +#endif /* !defined(NONAMELESSSTRUCT) */ + +#ifndef NONAMELESSUNION +#define DUMMYUNIONNAME +#define DUMMYUNIONNAME1 +#define DUMMYUNIONNAME2 +#define DUMMYUNIONNAME3 +#define DUMMYUNIONNAME4 +#define DUMMYUNIONNAME5 +#else /* !defined(NONAMELESSUNION) */ +#define DUMMYUNIONNAME u +#define DUMMYUNIONNAME1 u1 +#define DUMMYUNIONNAME2 u2 +#define DUMMYUNIONNAME3 u3 +#define DUMMYUNIONNAME4 u4 +#define DUMMYUNIONNAME5 u5 +#endif /* !defined(NONAMELESSUNION) */ + +/* Calling conventions definitions */ + +#ifdef __i386__ +# if defined(__GNUC__) && ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) +# ifndef _EGCS_ +#define __stdcall __attribute__((__stdcall__)) +#define __cdecl __attribute__((__cdecl__)) +# define __RESTORE_ES __asm__ __volatile__("pushl %ds\n\tpopl %es") +# endif +# else +// # error You need gcc >= 2.7 to build Wine on a 386 +# endif +#else +# define __stdcall +# define __cdecl +# define __RESTORE_ES +#endif + +#define CALLBACK __stdcall +#define WINAPI __stdcall +#define APIPRIVATE __stdcall +#define PASCAL __stdcall +#define pascal __stdcall +#define _pascal __stdcall +#if !defined(__CYGWIN__) +#define _stdcall __stdcall +#define _fastcall __stdcall +#define __fastcall __stdcall +#endif +#define __export __stdcall +#define CDECL __cdecl +#define _CDECL __cdecl +#define cdecl __cdecl +#if !defined(__CYGWIN__) +#define _cdecl __cdecl +#endif +#define WINAPIV __cdecl +#define APIENTRY WINAPI + +#if !defined(__CYGWIN__) +#define __declspec(x) +#endif +#define dllimport +#define dllexport + +#define CONST const + +/* Standard data types. These are the same for emulator and library. */ + +typedef void VOID; +typedef int INT; +typedef unsigned int UINT; +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef unsigned int ULONG; +typedef unsigned char BYTE; +typedef long LONG; +typedef short SHORT; +typedef unsigned short USHORT; +typedef char CHAR; +typedef unsigned char UCHAR; + +typedef LONG SCODE; + +/* Some systems might have wchar_t, but we really need 16 bit characters */ +typedef unsigned short WCHAR; +typedef int WIN_BOOL; +typedef double DATE; +typedef double DOUBLE; +typedef long long LONGLONG; +typedef unsigned long long ULONGLONG; + +/* FIXME: Wine does not compile with strict on, therefore strict + * handles are presently only usable on machines where sizeof(UINT) == + * sizeof(void*). HANDLEs are supposed to be void* but a large amount + * of WINE code operates on HANDLES as if they are UINTs. So to WINE + * they exist as UINTs but to the Winelib user who turns on strict, + * they exist as void*. If there is a size difference between UINT and + * void* then things get ugly. */ +#ifdef STRICT +typedef VOID* HANDLE; +#else +typedef UINT HANDLE; +#endif + + +typedef HANDLE *LPHANDLE; + +/* Integer types. These are the same for emulator and library. */ +typedef UINT WPARAM; +typedef LONG LPARAM; +typedef LONG HRESULT; +typedef LONG LRESULT; +typedef WORD ATOM; +typedef WORD CATCHBUF[9]; +typedef WORD *LPCATCHBUF; +typedef HANDLE HHOOK; +typedef HANDLE HMONITOR; +typedef DWORD LCID; +typedef WORD LANGID; +typedef DWORD LCTYPE; +typedef float FLOAT; + +/* Pointers types. These are the same for emulator and library. */ +/* winnt types */ +typedef VOID *PVOID; +typedef const void *PCVOID; +typedef CHAR *PCHAR; +typedef UCHAR *PUCHAR; +typedef BYTE *PBYTE; +typedef WORD *PWORD; +typedef USHORT *PUSHORT; +typedef SHORT *PSHORT; +typedef ULONG *PULONG; +typedef LONG *PLONG; +typedef DWORD *PDWORD; +/* common win32 types */ +typedef CHAR *LPSTR; +typedef CHAR *PSTR; +typedef const CHAR *LPCSTR; +typedef const CHAR *PCSTR; +typedef WCHAR *LPWSTR; +typedef WCHAR *PWSTR; +typedef const WCHAR *LPCWSTR; +typedef const WCHAR *PCWSTR; +typedef BYTE *LPBYTE; +typedef WORD *LPWORD; +typedef DWORD *LPDWORD; +typedef LONG *LPLONG; +typedef VOID *LPVOID; +typedef const VOID *LPCVOID; +typedef INT *PINT; +typedef INT *LPINT; +typedef UINT *PUINT; +typedef UINT *LPUINT; +typedef FLOAT *PFLOAT; +typedef FLOAT *LPFLOAT; +typedef WIN_BOOL *PWIN_BOOL; +typedef WIN_BOOL *LPWIN_BOOL; + +/* Special case: a segmented pointer is just a pointer in the user's code. */ + +#ifdef __WINE__ +typedef DWORD SEGPTR; +#else +typedef void* SEGPTR; +#endif /* __WINE__ */ + +/* Handle types that exist both in Win16 and Win32. */ + +#ifdef STRICT +#define DECLARE_HANDLE(a) \ + typedef struct a##__ { int unused; } *a; \ + typedef a *P##a; \ + typedef a *LP##a +#else /*STRICT*/ +#define DECLARE_HANDLE(a) \ + typedef HANDLE a; \ + typedef a *P##a; \ + typedef a *LP##a +#endif /*STRICT*/ + +DECLARE_HANDLE(HACMDRIVERID); +DECLARE_HANDLE(HACMDRIVER); +DECLARE_HANDLE(HACMOBJ); +DECLARE_HANDLE(HACMSTREAM); +DECLARE_HANDLE(HMETAFILEPICT); + +DECLARE_HANDLE(HACCEL); +DECLARE_HANDLE(HBITMAP); +DECLARE_HANDLE(HBRUSH); +DECLARE_HANDLE(HCOLORSPACE); +DECLARE_HANDLE(HCURSOR); +DECLARE_HANDLE(HDC); +DECLARE_HANDLE(HDROP); +DECLARE_HANDLE(HDRVR); +DECLARE_HANDLE(HDWP); +DECLARE_HANDLE(HENHMETAFILE); +DECLARE_HANDLE(HFILE); +DECLARE_HANDLE(HFONT); +DECLARE_HANDLE(HICON); +DECLARE_HANDLE(HINSTANCE); +DECLARE_HANDLE(HKEY); +DECLARE_HANDLE(HMENU); +DECLARE_HANDLE(HMETAFILE); +DECLARE_HANDLE(HMIDI); +DECLARE_HANDLE(HMIDIIN); +DECLARE_HANDLE(HMIDIOUT); +DECLARE_HANDLE(HMIDISTRM); +DECLARE_HANDLE(HMIXER); +DECLARE_HANDLE(HMIXEROBJ); +DECLARE_HANDLE(HMMIO); +DECLARE_HANDLE(HPALETTE); +DECLARE_HANDLE(HPEN); +DECLARE_HANDLE(HQUEUE); +DECLARE_HANDLE(HRGN); +DECLARE_HANDLE(HRSRC); +DECLARE_HANDLE(HTASK); +DECLARE_HANDLE(HWAVE); +DECLARE_HANDLE(HWAVEIN); +DECLARE_HANDLE(HWAVEOUT); +DECLARE_HANDLE(HWINSTA); +DECLARE_HANDLE(HDESK); +DECLARE_HANDLE(HWND); +DECLARE_HANDLE(HKL); +DECLARE_HANDLE(HIC); +DECLARE_HANDLE(HRASCONN); + +/* Handle types that must remain interchangeable even with strict on */ + +typedef HINSTANCE HMODULE; +typedef HANDLE HGDIOBJ; +typedef HANDLE HGLOBAL; +typedef HANDLE HLOCAL; +typedef HANDLE GLOBALHANDLE; +typedef HANDLE LOCALHANDLE; + +/* Callback function pointers types */ +//WIN_BOOL CALLBACK DATEFMT_ENUMPROCA(LPSTR); + +typedef WIN_BOOL CALLBACK (* DATEFMT_ENUMPROCA)(LPSTR); +typedef WIN_BOOL CALLBACK (* DATEFMT_ENUMPROCW)(LPWSTR); +DECL_WINELIB_TYPE_AW(DATEFMT_ENUMPROC) +typedef WIN_BOOL CALLBACK (*DLGPROC)(HWND,UINT,WPARAM,LPARAM); +typedef LRESULT CALLBACK (*DRIVERPROC)(DWORD,HDRVR,UINT,LPARAM,LPARAM); +typedef INT CALLBACK (*EDITWORDBREAKPROCA)(LPSTR,INT,INT,INT); +typedef INT CALLBACK (*EDITWORDBREAKPROCW)(LPWSTR,INT,INT,INT); +DECL_WINELIB_TYPE_AW(EDITWORDBREAKPROC) +typedef LRESULT CALLBACK (*FARPROC)(); +typedef INT CALLBACK (*PROC)(); +typedef WIN_BOOL CALLBACK (*GRAYSTRINGPROC)(HDC,LPARAM,INT); +typedef LRESULT CALLBACK (*HOOKPROC)(INT,WPARAM,LPARAM); +typedef WIN_BOOL CALLBACK (*PROPENUMPROCA)(HWND,LPCSTR,HANDLE); +typedef WIN_BOOL CALLBACK (*PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); +DECL_WINELIB_TYPE_AW(PROPENUMPROC) +typedef WIN_BOOL CALLBACK (*PROPENUMPROCEXA)(HWND,LPCSTR,HANDLE,LPARAM); +typedef WIN_BOOL CALLBACK (*PROPENUMPROCEXW)(HWND,LPCWSTR,HANDLE,LPARAM); +DECL_WINELIB_TYPE_AW(PROPENUMPROCEX) +typedef WIN_BOOL CALLBACK (* TIMEFMT_ENUMPROCA)(LPSTR); +typedef WIN_BOOL CALLBACK (* TIMEFMT_ENUMPROCW)(LPWSTR); +DECL_WINELIB_TYPE_AW(TIMEFMT_ENUMPROC) +typedef VOID CALLBACK (*TIMERPROC)(HWND,UINT,UINT,DWORD); +typedef WIN_BOOL CALLBACK (*WNDENUMPROC)(HWND,LPARAM); +typedef LRESULT CALLBACK (*WNDPROC)(HWND,UINT,WPARAM,LPARAM); + +/*---------------------------------------------------------------------------- +** FIXME: Better isolate Wine's reliance on the xxx16 type definitions. +** For now, we just isolate them to make the situation clear. +**--------------------------------------------------------------------------*/ +/* + * Basic type definitions for 16 bit variations on Windows types. + * These types are provided mostly to insure compatibility with + * 16 bit windows code. + */ + +#ifndef __WINE_WINDEF16_H +#define __WINE_WINDEF16_H + +#include "windef.h" + +/* Standard data types */ + + /* FIXME horrible hack! lpc10 encoder also defines INT16 */ +#ifndef __LPC10_H__ +typedef short INT16; +#endif + +typedef unsigned short UINT16; +typedef unsigned short WIN_BOOL16; + +typedef UINT16 HANDLE16; +typedef HANDLE16 *LPHANDLE16; + +typedef UINT16 WPARAM16; +typedef INT16 *LPINT16; +typedef UINT16 *LPUINT16; + +#define DECLARE_HANDLE16(a) \ + typedef HANDLE16 a##16; \ + typedef a##16 *P##a##16; \ + typedef a##16 *NP##a##16; \ + typedef a##16 *LP##a##16 + +DECLARE_HANDLE16(HACMDRIVERID); +DECLARE_HANDLE16(HACMDRIVER); +DECLARE_HANDLE16(HACMOBJ); +DECLARE_HANDLE16(HACMSTREAM); +DECLARE_HANDLE16(HMETAFILEPICT); + +DECLARE_HANDLE16(HACCEL); +DECLARE_HANDLE16(HBITMAP); +DECLARE_HANDLE16(HBRUSH); +DECLARE_HANDLE16(HCOLORSPACE); +DECLARE_HANDLE16(HCURSOR); +DECLARE_HANDLE16(HDC); +DECLARE_HANDLE16(HDROP); +DECLARE_HANDLE16(HDRVR); +DECLARE_HANDLE16(HDWP); +DECLARE_HANDLE16(HENHMETAFILE); +DECLARE_HANDLE16(HFILE); +DECLARE_HANDLE16(HFONT); +DECLARE_HANDLE16(HICON); +DECLARE_HANDLE16(HINSTANCE); +DECLARE_HANDLE16(HKEY); +DECLARE_HANDLE16(HMENU); +DECLARE_HANDLE16(HMETAFILE); +DECLARE_HANDLE16(HMIDI); +DECLARE_HANDLE16(HMIDIIN); +DECLARE_HANDLE16(HMIDIOUT); +DECLARE_HANDLE16(HMIDISTRM); +DECLARE_HANDLE16(HMIXER); +DECLARE_HANDLE16(HMIXEROBJ); +DECLARE_HANDLE16(HMMIO); +DECLARE_HANDLE16(HPALETTE); +DECLARE_HANDLE16(HPEN); +DECLARE_HANDLE16(HQUEUE); +DECLARE_HANDLE16(HRGN); +DECLARE_HANDLE16(HRSRC); +DECLARE_HANDLE16(HTASK); +DECLARE_HANDLE16(HWAVE); +DECLARE_HANDLE16(HWAVEIN); +DECLARE_HANDLE16(HWAVEOUT); +DECLARE_HANDLE16(HWINSTA); +DECLARE_HANDLE16(HDESK); +DECLARE_HANDLE16(HWND); +DECLARE_HANDLE16(HKL); +DECLARE_HANDLE16(HIC); +DECLARE_HANDLE16(HRASCONN); +#undef DECLARE_HANDLE16 + +typedef HINSTANCE16 HMODULE16; +typedef HANDLE16 HGDIOBJ16; +typedef HANDLE16 HGLOBAL16; +typedef HANDLE16 HLOCAL16; + +/* The SIZE structure */ +typedef struct +{ + INT16 cx; + INT16 cy; +} SIZE16, *PSIZE16, *LPSIZE16; + +/* The POINT structure */ + +typedef struct +{ + INT16 x; + INT16 y; +} POINT16, *PPOINT16, *LPPOINT16; + +/* The RECT structure */ + +typedef struct +{ + INT16 left; + INT16 top; + INT16 right; + INT16 bottom; +} RECT16, *LPRECT16; + +/* Callback function pointers types */ + +typedef LRESULT CALLBACK (*DRIVERPROC16)(DWORD,HDRVR16,UINT16,LPARAM,LPARAM); +typedef WIN_BOOL16 CALLBACK (*DLGPROC16)(HWND16,UINT16,WPARAM16,LPARAM); +typedef INT16 CALLBACK (*EDITWORDBREAKPROC16)(LPSTR,INT16,INT16,INT16); +typedef LRESULT CALLBACK (*FARPROC16)(); +typedef INT16 CALLBACK (*PROC16)(); +typedef WIN_BOOL16 CALLBACK (*GRAYSTRINGPROC16)(HDC16,LPARAM,INT16); +typedef LRESULT CALLBACK (*HOOKPROC16)(INT16,WPARAM16,LPARAM); +typedef WIN_BOOL16 CALLBACK (*PROPENUMPROC16)(HWND16,SEGPTR,HANDLE16); +typedef VOID CALLBACK (*TIMERPROC16)(HWND16,UINT16,UINT16,DWORD); +typedef LRESULT CALLBACK (*WNDENUMPROC16)(HWND16,LPARAM); +typedef LRESULT CALLBACK (*WNDPROC16)(HWND16,UINT16,WPARAM16,LPARAM); + +#endif /* __WINE_WINDEF16_H */ + +/* Define some empty macros for compatibility with Windows code. */ + +#ifndef __WINE__ +#define NEAR +#define FAR +#define near +#define far +#define _near +#define _far +#define IN +#define OUT +#define OPTIONAL +#endif /* __WINE__ */ + +/* Macro for structure packing. */ + +#ifdef __GNUC__ +#ifndef _EGCS_ +#define WINE_PACKED __attribute__((packed)) +#define WINE_UNUSED __attribute__((unused)) +#define WINE_NORETURN __attribute__((noreturn)) +#endif +#else +#define WINE_PACKED /* nothing */ +#define WINE_UNUSED /* nothing */ +#define WINE_NORETURN /* nothing */ +#endif + +/* Macros to split words and longs. */ + +#define LOBYTE(w) ((BYTE)(WORD)(w)) +#define HIBYTE(w) ((BYTE)((WORD)(w) >> 8)) + +#define LOWORD(l) ((WORD)(DWORD)(l)) +#define HIWORD(l) ((WORD)((DWORD)(l) >> 16)) + +#define SLOWORD(l) ((INT16)(LONG)(l)) +#define SHIWORD(l) ((INT16)((LONG)(l) >> 16)) + +#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8)) +#define MAKELONG(low,high) ((LONG)(((WORD)(low)) | (((DWORD)((WORD)(high))) << 16))) +#define MAKELPARAM(low,high) ((LPARAM)MAKELONG(low,high)) +#define MAKEWPARAM(low,high) ((WPARAM)MAKELONG(low,high)) +#define MAKELRESULT(low,high) ((LRESULT)MAKELONG(low,high)) +#define MAKEINTATOM(atom) ((LPCSTR)MAKELONG((atom),0)) + +#define SELECTOROF(ptr) (HIWORD(ptr)) +#define OFFSETOF(ptr) (LOWORD(ptr)) + +#ifdef __WINE__ +/* macros to set parts of a DWORD (not in the Windows API) */ +#define SET_LOWORD(dw,val) ((dw) = ((dw) & 0xffff0000) | LOWORD(val)) +#define SET_LOBYTE(dw,val) ((dw) = ((dw) & 0xffffff00) | LOBYTE(val)) +#define SET_HIBYTE(dw,val) ((dw) = ((dw) & 0xffff00ff) | (LOWORD(val) & 0xff00)) +#define ADD_LOWORD(dw,val) ((dw) = ((dw) & 0xffff0000) | LOWORD((DWORD)(dw)+(val))) +#endif + +/* Macros to access unaligned or wrong-endian WORDs and DWORDs. */ +/* Note: These macros are semantically broken, at least for wrc. wrc + spits out data in the platform's current binary format, *not* in + little-endian format. These macros are used throughout the resource + code to load and store data to the resources. Since it is unlikely + that we'll ever be dealing with little-endian resource data, the + byte-swapping nature of these macros has been disabled. Rather than + remove the use of these macros from the resource loading code, the + macros have simply been disabled. In the future, someone may want + to reactivate these macros for other purposes. In that case, the + resource code will have to be modified to use different macros. */ + +#if 1 +#define PUT_WORD(ptr,w) (*(WORD *)(ptr) = (w)) +#define GET_WORD(ptr) (*(WORD *)(ptr)) +#define PUT_DWORD(ptr,dw) (*(DWORD *)(ptr) = (dw)) +#define GET_DWORD(ptr) (*(DWORD *)(ptr)) +#else +#define PUT_WORD(ptr,w) (*(BYTE *)(ptr) = LOBYTE(w), \ + *((BYTE *)(ptr) + 1) = HIBYTE(w)) +#define GET_WORD(ptr) ((WORD)(*(BYTE *)(ptr) | \ + (WORD)(*((BYTE *)(ptr)+1) << 8))) +#define PUT_DWORD(ptr,dw) (PUT_WORD((ptr),LOWORD(dw)), \ + PUT_WORD((WORD *)(ptr)+1,HIWORD(dw))) +#define GET_DWORD(ptr) ((DWORD)(GET_WORD(ptr) | \ + ((DWORD)GET_WORD((WORD *)(ptr)+1) << 16))) +#endif /* 1 */ + +/* min and max macros */ +#define __max(a,b) (((a) > (b)) ? (a) : (b)) +#define __min(a,b) (((a) < (b)) ? (a) : (b)) +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define _MAX_PATH 260 +#define MAX_PATH 260 +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 255 +#define _MAX_EXT 256 + +#define HFILE_ERROR16 ((HFILE16)-1) +#define HFILE_ERROR ((HFILE)-1) + +/* The SIZE structure */ +typedef struct tagSIZE +{ + INT cx; + INT cy; +} SIZE, *PSIZE, *LPSIZE; + + +typedef SIZE SIZEL, *PSIZEL, *LPSIZEL; + +#define CONV_SIZE16TO32(s16,s32) \ + ((s32)->cx = (INT)(s16)->cx, (s32)->cy = (INT)(s16)->cy) +#define CONV_SIZE32TO16(s32,s16) \ + ((s16)->cx = (INT16)(s32)->cx, (s16)->cy = (INT16)(s32)->cy) + +/* The POINT structure */ +typedef struct tagPOINT +{ + LONG x; + LONG y; +} POINT, *PPOINT, *LPPOINT; + +typedef struct _POINTL +{ + LONG x; + LONG y; +} POINTL; + +#define CONV_POINT16TO32(p16,p32) \ + ((p32)->x = (INT)(p16)->x, (p32)->y = (INT)(p16)->y) +#define CONV_POINT32TO16(p32,p16) \ + ((p16)->x = (INT16)(p32)->x, (p16)->y = (INT16)(p32)->y) + +#define MAKEPOINT16(l) (*((POINT16 *)&(l))) + +/* The POINTS structure */ + +typedef struct tagPOINTS +{ + SHORT x; + SHORT y; +} POINTS, *PPOINTS, *LPPOINTS; + + +#define MAKEPOINTS(l) (*((POINTS *)&(l))) + + +/* The RECT structure */ +typedef struct tagRECT +{ + short left; + short top; + short right; + short bottom; +} RECT, *PRECT, *LPRECT; +typedef const RECT *LPCRECT; + + +typedef struct tagRECTL +{ + LONG left; + LONG top; + LONG right; + LONG bottom; +} RECTL, *PRECTL, *LPRECTL; + +typedef const RECTL *LPCRECTL; + +#define CONV_RECT16TO32(r16,r32) \ + ((r32)->left = (INT)(r16)->left, (r32)->top = (INT)(r16)->top, \ + (r32)->right = (INT)(r16)->right, (r32)->bottom = (INT)(r16)->bottom) +#define CONV_RECT32TO16(r32,r16) \ + ((r16)->left = (INT16)(r32)->left, (r16)->top = (INT16)(r32)->top, \ + (r16)->right = (INT16)(r32)->right, (r16)->bottom = (INT16)(r32)->bottom) + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_WINDEF_H */ diff --git a/linphone/win32acm/wine/windows.h b/linphone/win32acm/wine/windows.h new file mode 100644 index 000000000..cd62a0327 --- /dev/null +++ b/linphone/win32acm/wine/windows.h @@ -0,0 +1,38 @@ +#ifndef __WINE_WINDOWS_H +#define __WINE_WINDOWS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "shell.h" +#include "winreg.h" +#include "winnetwk.h" +#include "winver.h" +#include "lzexpand.h" +#include "shellapi.h" +#include "ole2.h" +#include "winnls.h" +#include "objbase.h" +#include "winspool.h" + +#if 0 + Where does this belong? Nobody uses this stuff anyway. +typedef struct { + BYTE i; /* much more .... */ +} KANJISTRUCT; +typedef KANJISTRUCT *LPKANJISTRUCT; +typedef KANJISTRUCT *NPKANJISTRUCT; +typedef KANJISTRUCT *PKANJISTRUCT; + + +#endif /* 0 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_WINDOWS_H */ diff --git a/linphone/win32acm/wine/winerror.h b/linphone/win32acm/wine/winerror.h new file mode 100644 index 000000000..0c78792b9 --- /dev/null +++ b/linphone/win32acm/wine/winerror.h @@ -0,0 +1,1658 @@ +#ifndef __WINE_WINERROR_H +#define __WINE_WINERROR_H + + +extern int WIN32_LastError; + +#define FACILITY_NULL 0 +#define FACILITY_RPC 1 +#define FACILITY_DISPATCH 2 +#define FACILITY_STORAGE 3 +#define FACILITY_ITF 4 +#define FACILITY_WIN32 7 +#define FACILITY_WINDOWS 8 +#define FACILITY_SSPI 9 +#define FACILITY_CONTROL 10 +#define FACILITY_CERT 11 +#define FACILITY_INTERNET 12 + +#define SEVERITY_ERROR 1 + + +#define MAKE_HRESULT(sev,fac,code) \ + ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) +#define MAKE_SCODE(sev,fac,code) \ + ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) +#define SUCCEEDED(stat) ((HRESULT)(stat)>=0) +#define FAILED(stat) ((HRESULT)(stat)<0) + +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) + +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1FFF) +#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1FFF) + +/* ERROR_UNKNOWN is a placeholder for error conditions which haven't + * been tested yet so we're not exactly sure what will be returned. + * All instances of ERROR_UNKNOWN should be tested under Win95/NT + * and replaced. + */ +#define ERROR_UNKNOWN 99999 + +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 + +#define NO_ERROR 0 +#define ERROR_SUCCESS 0 +#define ERROR_INVALID_FUNCTION 1 +#define ERROR_FILE_NOT_FOUND 2 +#define ERROR_PATH_NOT_FOUND 3 +#define ERROR_TOO_MANY_OPEN_FILES 4 +#define ERROR_ACCESS_DENIED 5 +#define ERROR_INVALID_HANDLE 6 +#define ERROR_ARENA_TRASHED 7 +#define ERROR_NOT_ENOUGH_MEMORY 8 +#define ERROR_INVALID_BLOCK 9 +#define ERROR_BAD_ENVIRONMENT 10 +#define ERROR_BAD_FORMAT 11 +#define ERROR_INVALID_ACCESS 12 +#define ERROR_INVALID_DATA 13 +#define ERROR_OUTOFMEMORY 14 +#define ERROR_INVALID_DRIVE 15 +#define ERROR_CURRENT_DIRECTORY 16 +#define ERROR_NOT_SAME_DEVICE 17 +#define ERROR_NO_MORE_FILES 18 +#define ERROR_WRITE_PROTECT 19 +#define ERROR_BAD_UNIT 20 +#define ERROR_NOT_READY 21 +#define ERROR_BAD_COMMAND 22 +#define ERROR_CRC 23 +#define ERROR_BAD_LENGTH 24 +#define ERROR_SEEK 25 +#define ERROR_NOT_DOS_DISK 26 +#define ERROR_SECTOR_NOT_FOUND 27 +#define ERROR_OUT_OF_PAPER 28 +#define ERROR_WRITE_FAULT 29 +#define ERROR_READ_FAULT 30 +#define ERROR_GEN_FAILURE 31 +#define ERROR_SHARING_VIOLATION 32 +#define ERROR_LOCK_VIOLATION 33 +#define ERROR_WRONG_DISK 34 +#define ERROR_SHARING_BUFFER_EXCEEDED 36 +#define ERROR_HANDLE_EOF 38 +#define ERROR_HANDLE_DISK_FULL 39 +#define ERROR_NOT_SUPPORTED 50 +#define ERROR_REM_NOT_LIST 51 +#define ERROR_DUP_NAME 52 +#define ERROR_BAD_NETPATH 53 +#define ERROR_NETWORK_BUSY 54 +#define ERROR_DEV_NOT_EXIST 55 +#define ERROR_TOO_MANY_CMDS 56 +#define ERROR_ADAP_HDW_ERR 57 +#define ERROR_BAD_NET_RESP 58 +#define ERROR_UNEXP_NET_ERR 59 +#define ERROR_BAD_REM_ADAP 60 +#define ERROR_PRINTQ_FULL 61 +#define ERROR_NO_SPOOL_SPACE 62 +#define ERROR_PRINT_CANCELLED 63 +#define ERROR_NETNAME_DELETED 64 +#define ERROR_NETWORK_ACCESS_DENIED 65 +#define ERROR_BAD_DEV_TYPE 66 +#define ERROR_BAD_NET_NAME 67 +#define ERROR_TOO_MANY_NAMES 68 +#define ERROR_TOO_MANY_SESS 69 +#define ERROR_SHARING_PAUSED 70 +#define ERROR_REQ_NOT_ACCEP 71 +#define ERROR_REDIR_PAUSED 72 +#define ERROR_FILE_EXISTS 80 +#define ERROR_CANNOT_MAKE 82 +#define ERROR_FAIL_I24 83 +#define ERROR_OUT_OF_STRUCTURES 84 +#define ERROR_ALREADY_ASSIGNED 85 +#define ERROR_INVALID_PASSWORD 86 +#define ERROR_INVALID_PARAMETER 87 +#define ERROR_NET_WRITE_FAULT 88 +#define ERROR_NO_PROC_SLOTS 89 +#define ERROR_TOO_MANY_SEMAPHORES 100 +#define ERROR_EXCL_SEM_ALREADY_OWNED 101 +#define ERROR_SEM_IS_SET 102 +#define ERROR_TOO_MANY_SEM_REQUESTS 103 +#define ERROR_INVALID_AT_INTERRUPT_TIME 104 +#define ERROR_SEM_OWNER_DIED 105 +#define ERROR_SEM_USER_LIMIT 106 +#define ERROR_DISK_CHANGE 107 +#define ERROR_DRIVE_LOCKED 108 +#define ERROR_BROKEN_PIPE 109 +#define ERROR_OPEN_FAILED 110 +#define ERROR_BUFFER_OVERFLOW 111 +#define ERROR_DISK_FULL 112 +#define ERROR_NO_MORE_SEARCH_HANDLES 113 +#define ERROR_INVALID_TARGET_HANDLE 114 +#define ERROR_INVALID_CATEGORY 117 +#define ERROR_INVALID_VERIFY_SWITCH 118 +#define ERROR_BAD_DRIVER_LEVEL 119 +#define ERROR_CALL_NOT_IMPLEMENTED 120 +#define ERROR_SEM_TIMEOUT 121 +#define ERROR_INSUFFICIENT_BUFFER 122 +#define ERROR_INVALID_NAME 123 +#define ERROR_INVALID_LEVEL 124 +#define ERROR_NO_VOLUME_LABEL 125 +#define ERROR_MOD_NOT_FOUND 126 +#define ERROR_PROC_NOT_FOUND 127 +#define ERROR_WAIT_NO_CHILDREN 128 +#define ERROR_CHILD_NOT_COMPLETE 129 +#define ERROR_DIRECT_ACCESS_HANDLE 130 +#define ERROR_NEGATIVE_SEEK 131 +#define ERROR_SEEK_ON_DEVICE 132 +#define ERROR_IS_JOIN_TARGET 133 +#define ERROR_IS_JOINED 134 +#define ERROR_IS_SUBSTED 135 +#define ERROR_NOT_JOINED 136 +#define ERROR_NOT_SUBSTED 137 +#define ERROR_JOIN_TO_JOIN 138 +#define ERROR_SUBST_TO_SUBST 139 +#define ERROR_JOIN_TO_SUBST 140 +#define ERROR_SUBST_TO_JOIN 141 +#define ERROR_BUSY_DRIVE 142 +#define ERROR_SAME_DRIVE 143 +#define ERROR_DIR_NOT_ROOT 144 +#define ERROR_DIR_NOT_EMPTY 145 +#define ERROR_IS_SUBST_PATH 146 +#define ERROR_IS_JOIN_PATH 147 +#define ERROR_PATH_BUSY 148 +#define ERROR_IS_SUBST_TARGET 149 +#define ERROR_SYSTEM_TRACE 150 +#define ERROR_INVALID_EVENT_COUNT 151 +#define ERROR_TOO_MANY_MUXWAITERS 152 +#define ERROR_INVALID_LIST_FORMAT 153 +#define ERROR_LABEL_TOO_LONG 154 +#define ERROR_TOO_MANY_TCBS 155 +#define ERROR_SIGNAL_REFUSED 156 +#define ERROR_DISCARDED 157 +#define ERROR_NOT_LOCKED 158 +#define ERROR_BAD_THREADID_ADDR 159 +#define ERROR_BAD_ARGUMENTS 160 +#define ERROR_BAD_PATHNAME 161 +#define ERROR_SIGNAL_PENDING 162 +#define ERROR_MAX_THRDS_REACHED 164 +#define ERROR_LOCK_FAILED 167 +#define ERROR_BUSY 170 +#define ERROR_CANCEL_VIOLATION 173 +#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174 +#define ERROR_INVALID_SEGMENT_NUMBER 180 +#define ERROR_INVALID_ORDINAL 182 +#define ERROR_ALREADY_EXISTS 183 +#define ERROR_INVALID_FLAG_NUMBER 186 +#define ERROR_SEM_NOT_FOUND 187 +#define ERROR_INVALID_STARTING_CODESEG 188 +#define ERROR_INVALID_STACKSEG 189 +#define ERROR_INVALID_MODULETYPE 190 +#define ERROR_INVALID_EXE_SIGNATURE 191 +#define ERROR_EXE_MARKED_INVALID 192 +#define ERROR_BAD_EXE_FORMAT 193 +#define ERROR_ITERATED_DATA_EXCEEDS_64k 194 +#define ERROR_INVALID_MINALLOCSIZE 195 +#define ERROR_DYNLINK_FROM_INVALID_RING 196 +#define ERROR_IOPL_NOT_ENABLED 197 +#define ERROR_INVALID_SEGDPL 198 +#define ERROR_AUTODATASEG_EXCEEDS_64k 199 +#define ERROR_RING2SEG_MUST_BE_MOVABLE 200 +#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201 +#define ERROR_INFLOOP_IN_RELOC_CHAIN 202 +#define ERROR_ENVVAR_NOT_FOUND 203 +#define ERROR_NO_SIGNAL_SENT 205 +#define ERROR_FILENAME_EXCED_RANGE 206 +#define ERROR_RING2_STACK_IN_USE 207 +#define ERROR_META_EXPANSION_TOO_LONG 208 +#define ERROR_INVALID_SIGNAL_NUMBER 209 +#define ERROR_THREAD_1_INACTIVE 210 +#define ERROR_LOCKED 212 +#define ERROR_TOO_MANY_MODULES 214 +#define ERROR_NESTING_NOT_ALLOWED 215 +#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216 +#define ERROR_BAD_PIPE 230 +#define ERROR_PIPE_BUSY 231 +#define ERROR_NO_DATA 232 +#define ERROR_PIPE_NOT_CONNECTED 233 +#define ERROR_MORE_DATA 234 +#define ERROR_VC_DISCONNECTED 240 +#define ERROR_INVALID_EA_NAME 254 +#define ERROR_EA_LIST_INCONSISTENT 255 +#define ERROR_NO_MORE_ITEMS 259 +#define ERROR_CANNOT_COPY 266 +#define ERROR_DIRECTORY 267 +#define ERROR_EAS_DIDNT_FIT 275 +#define ERROR_EA_FILE_CORRUPT 276 +#define ERROR_EA_TABLE_FULL 277 +#define ERROR_INVALID_EA_HANDLE 278 +#define ERROR_EAS_NOT_SUPPORTED 282 +#define ERROR_NOT_OWNER 288 +#define ERROR_TOO_MANY_POSTS 298 +#define ERROR_PARTIAL_COPY 299 +#define ERROR_OPLOCK_NOT_GRANTED 300 +#define ERROR_INVALID_OPLOCK_PROTOCOL 301 +#define ERROR_MR_MID_NOT_FOUND 317 +#define ERROR_INVALID_ADDRESS 487 +#define ERROR_ARITHMETIC_OVERFLOW 534 +#define ERROR_PIPE_CONNECTED 535 +#define ERROR_PIPE_LISTENING 536 +#define ERROR_EA_ACCESS_DENIED 994 +#define ERROR_OPERATION_ABORTED 995 +#define ERROR_IO_INCOMPLETE 996 +#define ERROR_IO_PENDING 997 +#define ERROR_NOACCESS 998 +#define ERROR_SWAPERROR 999 +#define ERROR_STACK_OVERFLOW 1001 +#define ERROR_INVALID_MESSAGE 1002 +#define ERROR_CAN_NOT_COMPLETE 1003 +#define ERROR_INVALID_FLAGS 1004 +#define ERROR_UNRECOGNIZED_VOLUME 1005 +#define ERROR_FILE_INVALID 1006 +#define ERROR_FULLSCREEN_MODE 1007 +#define ERROR_NO_TOKEN 1008 +#define ERROR_BADDB 1009 +#define ERROR_BADKEY 1010 +#define ERROR_CANTOPEN 1011 +#define ERROR_CANTREAD 1012 +#define ERROR_CANTWRITE 1013 +#define ERROR_REGISTRY_RECOVERED 1014 +#define ERROR_REGISTRY_CORRUPT 1015 +#define ERROR_REGISTRY_IO_FAILED 1016 +#define ERROR_NOT_REGISTRY_FILE 1017 +#define ERROR_KEY_DELETED 1018 +#define ERROR_NO_LOG_SPACE 1019 +#define ERROR_KEY_HAS_CHILDREN 1020 +#define ERROR_CHILD_MUST_BE_VOLATILE 1021 +#define ERROR_NOTIFY_ENUM_DIR 1022 +#define ERROR_DEPENDENT_SERVICES_RUNNING 1051 +#define ERROR_INVALID_SERVICE_CONTROL 1052 +#define ERROR_SERVICE_REQUEST_TIMEOUT 1053 +#define ERROR_SERVICE_NO_THREAD 1054 +#define ERROR_SERVICE_DATABASE_LOCKED 1055 +#define ERROR_SERVICE_ALREADY_RUNNING 1056 +#define ERROR_INVALID_SERVICE_ACCOUNT 1057 +#define ERROR_SERVICE_DISABLED 1058 +#define ERROR_CIRCULAR_DEPENDENCY 1059 +#define ERROR_SERVICE_DOES_NOT_EXIST 1060 +#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061 +#define ERROR_SERVICE_NOT_ACTIVE 1062 +#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063 +#define ERROR_EXCEPTION_IN_SERVICE 1064 +#define ERROR_DATABASE_DOES_NOT_EXIST 1065 +#define ERROR_SERVICE_SPECIFIC_ERROR 1066 +#define ERROR_PROCESS_ABORTED 1067 +#define ERROR_SERVICE_DEPENDENCY_FAIL 1068 +#define ERROR_SERVICE_LOGON_FAILED 1069 +#define ERROR_SERVICE_START_HANG 1070 +#define ERROR_INVALID_SERVICE_LOCK 1071 +#define ERROR_SERVICE_MARKED_FOR_DELETE 1072 +#define ERROR_SERVICE_EXISTS 1073 +#define ERROR_ALREADY_RUNNING_LKG 1074 +#define ERROR_SERVICE_DEPENDENCY_DELETED 1075 +#define ERROR_BOOT_ALREADY_ACCEPTED 1076 +#define ERROR_SERVICE_NEVER_STARTED 1077 +#define ERROR_DUPLICATE_SERVICE_NAME 1078 +#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079 +#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080 +#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081 +#define ERROR_NO_RECOVERY_PROGRAM 1082 +#define ERROR_SERVICE_NOT_IN_EXE 1083 +#define ERROR_END_OF_MEDIA 1100 +#define ERROR_FILEMARK_DETECTED 1101 +#define ERROR_BEGINNING_OF_MEDIA 1102 +#define ERROR_SETMARK_DETECTED 1103 +#define ERROR_NO_DATA_DETECTED 1104 +#define ERROR_PARTITION_FAILURE 1105 +#define ERROR_INVALID_BLOCK_LENGTH 1106 +#define ERROR_DEVICE_NOT_PARTITIONED 1107 +#define ERROR_UNABLE_TO_LOCK_MEDIA 1108 +#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109 +#define ERROR_MEDIA_CHANGED 1110 +#define ERROR_BUS_RESET 1111 +#define ERROR_NO_MEDIA_IN_DRIVE 1112 +#define ERROR_NO_UNICODE_TRANSLATION 1113 +#define ERROR_DLL_INIT_FAILED 1114 +#define ERROR_SHUTDOWN_IN_PROGRESS 1115 +#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116 +#define ERROR_IO_DEVICE 1117 +#define ERROR_SERIAL_NO_DEVICE 1118 +#define ERROR_IRQ_BUSY 1119 +#define ERROR_MORE_WRITES 1120 +#define ERROR_COUNTER_TIMEOUT 1121 +#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122 +#define ERROR_FLOPPY_WRONG_CYLINDER 1123 +#define ERROR_FLOPPY_UNKNOWN_ERROR 1124 +#define ERROR_FLOPPY_BAD_REGISTERS 1125 +#define ERROR_DISK_RECALIBRATE_FAILED 1126 +#define ERROR_DISK_OPERATION_FAILED 1127 +#define ERROR_DISK_RESET_FAILED 1128 +#define ERROR_EOM_OVERFLOW 1129 +#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130 +#define ERROR_POSSIBLE_DEADLOCK 1131 +#define ERROR_MAPPED_ALIGNMENT 1132 +#define ERROR_SET_POWER_STATE_VETOED 1140 +#define ERROR_SET_POWER_STATE_FAILED 1141 +#define ERROR_TOO_MANY_LINKS 1142 +#define ERROR_OLD_WIN_VERSION 1150 +#define ERROR_APP_WRONG_OS 1151 +#define ERROR_SINGLE_INSTANCE_APP 1152 +#define ERROR_RMODE_APP 1153 +#define ERROR_INVALID_DLL 1154 +#define ERROR_NO_ASSOCIATION 1155 +#define ERROR_DDE_FAIL 1156 +#define ERROR_DLL_NOT_FOUND 1157 +#define ERROR_NO_MORE_USER_HANDLES 1158 +#define ERROR_MESSAGE_SYNC_ONLY 1159 +#define ERROR_SOURCE_ELEMENT_EMPTY 1160 +#define ERROR_DESTINATION_ELEMENT_FULL 1161 +#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162 +#define ERROR_MAGAZINE_NOT_PRESENT 1163 +#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164 +#define ERROR_DEVICE_REQUIRES_CLEANING 1165 +#define ERROR_DEVICE_DOOR_OPEN 1166 +#define ERROR_DEVICE_NOT_CONNECTED 1167 +#define ERROR_NOT_FOUND 1168 +#define ERROR_NO_MATCH 1169 +#define ERROR_SET_NOT_FOUND 1170 +#define ERROR_POINT_NOT_FOUND 1171 +#define ERROR_NO_TRACKING_SERVICE 1172 +#define ERROR_NO_VOLUME_ID 1173 +#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175 +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176 +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177 +#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178 +#define ERROR_JOURNAL_NOT_ACTIVE 1179 +#define ERROR_POTENTIAL_FILE_FOUND 1180 +#define ERROR_JOURNAL_ENTRY_DELETED 1181 +#define ERROR_BAD_DEVICE 1200 +#define ERROR_CONNECTION_UNAVAIL 1201 +#define ERROR_DEVICE_ALREADY_REMEMBERED 1202 +#define ERROR_NO_NET_OR_BAD_PATH 1203 +#define ERROR_BAD_PROVIDER 1204 +#define ERROR_CANNOT_OPEN_PROFILE 1205 +#define ERROR_BAD_PROFILE 1206 +#define ERROR_NOT_CONTAINER 1207 +#define ERROR_EXTENDED_ERROR 1208 +#define ERROR_INVALID_GROUPNAME 1209 +#define ERROR_INVALID_COMPUTERNAME 1210 +#define ERROR_INVALID_EVENTNAME 1211 +#define ERROR_INVALID_DOMAINNAME 1212 +#define ERROR_INVALID_SERVICENAME 1213 +#define ERROR_INVALID_NETNAME 1214 +#define ERROR_INVALID_SHARENAME 1215 +#define ERROR_INVALID_PASSWORDNAME 1216 +#define ERROR_INVALID_MESSAGENAME 1217 +#define ERROR_INVALID_MESSAGEDEST 1218 +#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219 +#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220 +#define ERROR_DUP_DOMAINNAME 1221 +#define ERROR_NO_NETWORK 1222 +#define ERROR_CANCELLED 1223 +#define ERROR_USER_MAPPED_FILE 1224 +#define ERROR_CONNECTION_REFUSED 1225 +#define ERROR_GRACEFUL_DISCONNECT 1226 +#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227 +#define ERROR_ADDRESS_NOT_ASSOCIATED 1228 +#define ERROR_CONNECTION_INVALID 1229 +#define ERROR_CONNECTION_ACTIVE 1230 +#define ERROR_NETWORK_UNREACHABLE 1231 +#define ERROR_HOST_UNREACHABLE 1232 +#define ERROR_PROTOCOL_UNREACHABLE 1233 +#define ERROR_PORT_UNREACHABLE 1234 +#define ERROR_REQUEST_ABORTED 1235 +#define ERROR_CONNECTION_ABORTED 1236 +#define ERROR_RETRY 1237 +#define ERROR_CONNECTION_COUNT_LIMIT 1238 +#define ERROR_LOGIN_TIME_RESTRICTION 1239 +#define ERROR_LOGIN_WKSTA_RESTRICTION 1240 +#define ERROR_INCORRECT_ADDRESS 1241 +#define ERROR_ALREADY_REGISTERED 1242 +#define ERROR_SERVICE_NOT_FOUND 1243 +#define ERROR_NOT_AUTHENTICATED 1244 +#define ERROR_NOT_LOGGED_ON 1245 +#define ERROR_CONTINUE 1246 +#define ERROR_ALREADY_INITIALIZED 1247 +#define ERROR_NO_MORE_DEVICES 1248 +#define ERROR_NO_SUCH_SITE 1249 +#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250 +#define ERROR_ONLY_IF_CONNECTED 1251 +#define ERROR_OVERRIDE_NOCHANGES 1252 +#define ERROR_BAD_USER_PROFILE 1253 +#define ERROR_NOT_SUPPORTED_ON_SBS 1254 +#define ERROR_NOT_ALL_ASSIGNED 1300 +#define ERROR_SOME_NOT_MAPPED 1301 +#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302 +#define ERROR_LOCAL_USER_SESSION_KEY 1303 +#define ERROR_NULL_LM_PASSWORD 1304 +#define ERROR_UNKNOWN_REVISION 1305 +#define ERROR_REVISION_MISMATCH 1306 +#define ERROR_INVALID_OWNER 1307 +#define ERROR_INVALID_PRIMARY_GROUP 1308 +#define ERROR_NO_IMPERSONATION_TOKEN 1309 +#define ERROR_CANT_DISABLE_MANDATORY 1310 +#define ERROR_NO_LOGON_SERVERS 1311 +#define ERROR_NO_SUCH_LOGON_SESSION 1312 +#define ERROR_NO_SUCH_PRIVILEGE 1313 +#define ERROR_PRIVILEGE_NOT_HELD 1314 +#define ERROR_INVALID_ACCOUNT_NAME 1315 +#define ERROR_USER_EXISTS 1316 +#define ERROR_NO_SUCH_USER 1317 +#define ERROR_GROUP_EXISTS 1318 +#define ERROR_NO_SUCH_GROUP 1319 +#define ERROR_MEMBER_IN_GROUP 1320 +#define ERROR_MEMBER_NOT_IN_GROUP 1321 +#define ERROR_LAST_ADMIN 1322 +#define ERROR_WRONG_PASSWORD 1323 +#define ERROR_ILL_FORMED_PASSWORD 1324 +#define ERROR_PASSWORD_RESTRICTION 1325 +#define ERROR_LOGON_FAILURE 1326 +#define ERROR_ACCOUNT_RESTRICTION 1327 +#define ERROR_INVALID_LOGON_HOURS 1328 +#define ERROR_INVALID_WORKSTATION 1329 +#define ERROR_PASSWORD_EXPIRED 1330 +#define ERROR_ACCOUNT_DISABLED 1331 +#define ERROR_NONE_MAPPED 1332 +#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333 +#define ERROR_LUIDS_EXHAUSTED 1334 +#define ERROR_INVALID_SUB_AUTHORITY 1335 +#define ERROR_INVALID_ACL 1336 +#define ERROR_INVALID_SID 1337 +#define ERROR_INVALID_SECURITY_DESCR 1338 +#define ERROR_BAD_INHERITANCE_ACL 1340 +#define ERROR_SERVER_DISABLED 1341 +#define ERROR_SERVER_NOT_DISABLED 1342 +#define ERROR_INVALID_ID_AUTHORITY 1343 +#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344 +#define ERROR_INVALID_GROUP_ATTRIBUTES 1345 +#define ERROR_BAD_IMPERSONATION_LEVEL 1346 +#define ERROR_CANT_OPEN_ANONYMOUS 1347 +#define ERROR_BAD_VALIDATION_CLASS 1348 +#define ERROR_BAD_TOKEN_TYPE 1349 +#define ERROR_NO_SECURITY_ON_OBJECT 1350 +#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351 +#define ERROR_INVALID_SERVER_STATE 1352 +#define ERROR_INVALID_DOMAIN_STATE 1353 +#define ERROR_INVALID_DOMAIN_ROLE 1354 +#define ERROR_NO_SUCH_DOMAIN 1355 +#define ERROR_DOMAIN_EXISTS 1356 +#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357 +#define ERROR_INTERNAL_DB_CORRUPTION 1358 +#define ERROR_INTERNAL_ERROR 1359 +#define ERROR_GENERIC_NOT_MAPPED 1360 +#define ERROR_BAD_DESCRIPTOR_FORMAT 1361 +#define ERROR_NOT_LOGON_PROCESS 1362 +#define ERROR_LOGON_SESSION_EXISTS 1363 +#define ERROR_NO_SUCH_PACKAGE 1364 +#define ERROR_BAD_LOGON_SESSION_STATE 1365 +#define ERROR_LOGON_SESSION_COLLISION 1366 +#define ERROR_INVALID_LOGON_TYPE 1367 +#define ERROR_CANNOT_IMPERSONATE 1368 +#define ERROR_RXACT_INVALID_STATE 1369 +#define ERROR_RXACT_COMMIT_FAILURE 1370 +#define ERROR_SPECIAL_ACCOUNT 1371 +#define ERROR_SPECIAL_GROUP 1372 +#define ERROR_SPECIAL_USER 1373 +#define ERROR_MEMBERS_PRIMARY_GROUP 1374 +#define ERROR_TOKEN_ALREADY_IN_USE 1375 +#define ERROR_NO_SUCH_ALIAS 1376 +#define ERROR_MEMBER_NOT_IN_ALIAS 1377 +#define ERROR_MEMBER_IN_ALIAS 1378 +#define ERROR_ALIAS_EXISTS 1379 +#define ERROR_LOGON_NOT_GRANTED 1380 +#define ERROR_TOO_MANY_SECRETS 1381 +#define ERROR_SECRET_TOO_LONG 1382 +#define ERROR_INTERNAL_DB_ERROR 1383 +#define ERROR_TOO_MANY_CONTEXT_IDS 1384 +#define ERROR_LOGON_TYPE_NOT_GRANTED 1385 +#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386 +#define ERROR_NO_SUCH_MEMBER 1387 +#define ERROR_INVALID_MEMBER 1388 +#define ERROR_TOO_MANY_SIDS 1389 +#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390 +#define ERROR_NO_INHERITANCE 1391 +#define ERROR_FILE_CORRUPT 1392 +#define ERROR_DISK_CORRUPT 1393 +#define ERROR_NO_USER_SESSION_KEY 1394 +#define ERROR_LICENSE_QUOTA_EXCEEDED 1395 +#define ERROR_WRONG_TARGET_NAME 1396 +#define ERROR_MUTUAL_AUTH_FAILED 1397 +#define ERROR_TIME_SKEW 1398 +#define ERROR_INVALID_WINDOW_HANDLE 1400 +#define ERROR_INVALID_MENU_HANDLE 1401 +#define ERROR_INVALID_CURSOR_HANDLE 1402 +#define ERROR_INVALID_ACCEL_HANDLE 1403 +#define ERROR_INVALID_HOOK_HANDLE 1404 +#define ERROR_INVALID_DWP_HANDLE 1405 +#define ERROR_TLW_WITH_WSCHILD 1406 +#define ERROR_CANNOT_FIND_WND_CLASS 1407 +#define ERROR_WINDOW_OF_OTHER_THREAD 1408 +#define ERROR_HOTKEY_ALREADY_REGISTERED 1409 +#define ERROR_CLASS_ALREADY_EXISTS 1410 +#define ERROR_CLASS_DOES_NOT_EXIST 1411 +#define ERROR_CLASS_HAS_WINDOWS 1412 +#define ERROR_INVALID_INDEX 1413 +#define ERROR_INVALID_ICON_HANDLE 1414 +#define ERROR_PRIVATE_DIALOG_INDEX 1415 +#define ERROR_LISTBOX_ID_NOT_FOUND 1416 +#define ERROR_NO_WILDCARD_CHARACTERS 1417 +#define ERROR_CLIPBOARD_NOT_OPEN 1418 +#define ERROR_HOTKEY_NOT_REGISTERED 1419 +#define ERROR_WINDOW_NOT_DIALOG 1420 +#define ERROR_CONTROL_ID_NOT_FOUND 1421 +#define ERROR_INVALID_COMBOBOX_MESSAGE 1422 +#define ERROR_WINDOW_NOT_COMBOBOX 1423 +#define ERROR_INVALID_EDIT_HEIGHT 1424 +#define ERROR_DC_NOT_FOUND 1425 +#define ERROR_INVALID_HOOK_FILTER 1426 +#define ERROR_INVALID_FILTER_PROC 1427 +#define ERROR_HOOK_NEEDS_HMOD 1428 +#define ERROR_GLOBAL_ONLY_HOOK 1429 +#define ERROR_JOURNAL_HOOK_SET 1430 +#define ERROR_HOOK_NOT_INSTALLED 1431 +#define ERROR_INVALID_LB_MESSAGE 1432 +#define ERROR_SETCOUNT_ON_BAD_LB 1433 +#define ERROR_LB_WITHOUT_TABSTOPS 1434 +#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435 +#define ERROR_CHILD_WINDOW_MENU 1436 +#define ERROR_NO_SYSTEM_MENU 1437 +#define ERROR_INVALID_MSGBOX_STYLE 1438 +#define ERROR_INVALID_SPI_VALUE 1439 +#define ERROR_SCREEN_ALREADY_LOCKED 1440 +#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441 +#define ERROR_NOT_CHILD_WINDOW 1442 +#define ERROR_INVALID_GW_COMMAND 1443 +#define ERROR_INVALID_THREAD_ID 1444 +#define ERROR_NON_MDICHILD_WINDOW 1445 +#define ERROR_POPUP_ALREADY_ACTIVE 1446 +#define ERROR_NO_SCROLLBARS 1447 +#define ERROR_INVALID_SCROLLBAR_RANGE 1448 +#define ERROR_INVALID_SHOWWIN_COMMAND 1449 +#define ERROR_NO_SYSTEM_RESOURCES 1450 +#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451 +#define ERROR_PAGED_SYSTEM_RESOURCES 1452 +#define ERROR_WORKING_SET_QUOTA 1453 +#define ERROR_PAGEFILE_QUOTA 1454 +#define ERROR_COMMITMENT_LIMIT 1455 +#define ERROR_MENU_ITEM_NOT_FOUND 1456 +#define ERROR_INVALID_KEYBOARD_HANDLE 1457 +#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458 +#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459 +#define ERROR_TIMEOUT 1460 +#define ERROR_INVALID_MONITOR_HANDLE 1461 +#define ERROR_EVENTLOG_FILE_CORRUPT 1500 +#define ERROR_EVENTLOG_CANT_START 1501 +#define ERROR_LOG_FILE_FULL 1502 +#define ERROR_EVENTLOG_FILE_CHANGED 1503 +#define ERROR_INSTALL_SERVICE_FAILURE 1601 +#define ERROR_INSTALL_USEREXIT 1602 +#define ERROR_INSTALL_FAILURE 1603 +#define ERROR_INSTALL_SUSPEND 1604 +#define ERROR_UNKNOWN_PRODUCT 1605 +#define ERROR_UNKNOWN_FEATURE 1606 +#define ERROR_UNKNOWN_COMPONENT 1607 +#define ERROR_UNKNOWN_PROPERTY 1608 +#define ERROR_INVALID_HANDLE_STATE 1609 +#define ERROR_BAD_CONFIGURATION 1610 +#define ERROR_INDEX_ABSENT 1611 +#define ERROR_INSTALL_SOURCE_ABSENT 1612 +#define ERROR_INSTALL_PACKAGE_VERSION 1613 +#define ERROR_PRODUCT_UNINSTALLED 1614 +#define ERROR_BAD_QUERY_SYNTAX 1615 +#define ERROR_INVALID_FIELD 1616 +#define ERROR_DEVICE_REMOVED 1617 +#define ERROR_INSTALL_ALREADY_RUNNING 1618 +#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619 +#define ERROR_INSTALL_PACKAGE_INVALID 1620 +#define ERROR_INSTALL_UI_FAILURE 1621 +#define ERROR_INSTALL_LOG_FAILURE 1622 +#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623 +#define ERROR_INSTALL_TRANSFORM_FAILURE 1624 +#define ERROR_INSTALL_PACKAGE_REJECTED 1625 +#define ERROR_FUNCTION_NOT_CALLED 1626 +#define ERROR_FUNCTION_FAILED 1627 +#define ERROR_INVALID_TABLE 1628 +#define ERROR_DATATYPE_MISMATCH 1629 +#define ERROR_UNSUPPORTED_TYPE 1630 +#define ERROR_CREATE_FAILED 1631 +#define ERROR_INSTALL_TEMP_UNWRITABLE 1632 +#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633 +#define ERROR_INSTALL_NOTUSED 1634 +#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635 +#define ERROR_PATCH_PACKAGE_INVALID 1636 +#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637 +#define ERROR_PRODUCT_VERSION 1638 +#define ERROR_INVALID_COMMAND_LINE 1639 +#define ERROR_INSTALL_REMOTE_DISALLOWED 1640 +#define ERROR_SUCCESS_REBOOT_INITIATED 1641 +#define RPC_S_INVALID_STRING_BINDING 1700 +#define RPC_S_WRONG_KIND_OF_BINDING 1701 +#define RPC_S_INVALID_BINDING 1702 +#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703 +#define RPC_S_INVALID_RPC_PROTSEQ 1704 +#define RPC_S_INVALID_STRING_UUID 1705 +#define RPC_S_INVALID_ENDPOINT_FORMAT 1706 +#define RPC_S_INVALID_NET_ADDR 1707 +#define RPC_S_NO_ENDPOINT_FOUND 1708 +#define RPC_S_INVALID_TIMEOUT 1709 +#define RPC_S_OBJECT_NOT_FOUND 1710 +#define RPC_S_ALREADY_REGISTERED 1711 +#define RPC_S_TYPE_ALREADY_REGISTERED 1712 +#define RPC_S_ALREADY_LISTENING 1713 +#define RPC_S_NO_PROTSEQS_REGISTERED 1714 +#define RPC_S_NOT_LISTENING 1715 +#define RPC_S_UNKNOWN_MGR_TYPE 1716 +#define RPC_S_UNKNOWN_IF 1717 +#define RPC_S_NO_BINDINGS 1718 +#define RPC_S_NO_PROTSEQS 1719 +#define RPC_S_CANT_CREATE_ENDPOINT 1720 +#define RPC_S_OUT_OF_RESOURCES 1721 +#define RPC_S_SERVER_UNAVAILABLE 1722 +#define RPC_S_SERVER_TOO_BUSY 1723 +#define RPC_S_INVALID_NETWORK_OPTIONS 1724 +#define RPC_S_NO_CALL_ACTIVE 1725 +#define RPC_S_CALL_FAILED 1726 +#define RPC_S_CALL_FAILED_DNE 1727 +#define RPC_S_PROTOCOL_ERROR 1728 +#define RPC_S_UNSUPPORTED_TRANS_SYN 1730 +#define RPC_S_UNSUPPORTED_TYPE 1732 +#define RPC_S_INVALID_TAG 1733 +#define RPC_S_INVALID_BOUND 1734 +#define RPC_S_NO_ENTRY_NAME 1735 +#define RPC_S_INVALID_NAME_SYNTAX 1736 +#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737 +#define RPC_S_UUID_NO_ADDRESS 1739 +#define RPC_S_DUPLICATE_ENDPOINT 1740 +#define RPC_S_UNKNOWN_AUTHN_TYPE 1741 +#define RPC_S_MAX_CALLS_TOO_SMALL 1742 +#define RPC_S_STRING_TOO_LONG 1743 +#define RPC_S_PROTSEQ_NOT_FOUND 1744 +#define RPC_S_PROCNUM_OUT_OF_RANGE 1745 +#define RPC_S_BINDING_HAS_NO_AUTH 1746 +#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747 +#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748 +#define RPC_S_INVALID_AUTH_IDENTITY 1749 +#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750 +#define EPT_S_INVALID_ENTRY 1751 +#define EPT_S_CANT_PERFORM_OP 1752 +#define EPT_S_NOT_REGISTERED 1753 +#define RPC_S_NOTHING_TO_EXPORT 1754 +#define RPC_S_INCOMPLETE_NAME 1755 +#define RPC_S_INVALID_VERS_OPTION 1756 +#define RPC_S_NO_MORE_MEMBERS 1757 +#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758 +#define RPC_S_INTERFACE_NOT_FOUND 1759 +#define RPC_S_ENTRY_ALREADY_EXISTS 1760 +#define RPC_S_ENTRY_NOT_FOUND 1761 +#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762 +#define RPC_S_INVALID_NAF_ID 1763 +#define RPC_S_CANNOT_SUPPORT 1764 +#define RPC_S_NO_CONTEXT_AVAILABLE 1765 +#define RPC_S_INTERNAL_ERROR 1766 +#define RPC_S_ZERO_DIVIDE 1767 +#define RPC_S_ADDRESS_ERROR 1768 +#define RPC_S_FP_DIV_ZERO 1769 +#define RPC_S_FP_UNDERFLOW 1770 +#define RPC_S_FP_OVERFLOW 1771 +#define RPC_X_NO_MORE_ENTRIES 1772 +#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773 +#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774 +#define RPC_X_SS_IN_NULL_CONTEXT 1775 +#define RPC_X_SS_CONTEXT_DAMAGED 1777 +#define RPC_X_SS_HANDLES_MISMATCH 1778 +#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779 +#define RPC_X_NULL_REF_POINTER 1780 +#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781 +#define RPC_X_BYTE_COUNT_TOO_SMALL 1782 +#define RPC_X_BAD_STUB_DATA 1783 +#define ERROR_INVALID_USER_BUFFER 1784 +#define ERROR_UNRECOGNIZED_MEDIA 1785 +#define ERROR_NO_TRUST_LSA_SECRET 1786 +#define ERROR_NO_TRUST_SAM_ACCOUNT 1787 +#define ERROR_TRUSTED_DOMAIN_FAILURE 1788 +#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789 +#define ERROR_TRUST_FAILURE 1790 +#define RPC_S_CALL_IN_PROGRESS 1791 +#define ERROR_NETLOGON_NOT_STARTED 1792 +#define ERROR_ACCOUNT_EXPIRED 1793 +#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794 +#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795 +#define ERROR_UNKNOWN_PORT 1796 +#define ERROR_UNKNOWN_PRINTER_DRIVER 1797 +#define ERROR_UNKNOWN_PRINTPROCESSOR 1798 +#define ERROR_INVALID_SEPARATOR_FILE 1799 +#define ERROR_INVALID_PRIORITY 1800 +#define ERROR_INVALID_PRINTER_NAME 1801 +#define ERROR_PRINTER_ALREADY_EXISTS 1802 +#define ERROR_INVALID_PRINTER_COMMAND 1803 +#define ERROR_INVALID_DATATYPE 1804 +#define ERROR_INVALID_ENVIRONMENT 1805 +#define RPC_S_NO_MORE_BINDINGS 1806 +#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807 +#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808 +#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809 +#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810 +#define ERROR_SERVER_HAS_OPEN_HANDLES 1811 +#define ERROR_RESOURCE_DATA_NOT_FOUND 1812 +#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813 +#define ERROR_RESOURCE_NAME_NOT_FOUND 1814 +#define ERROR_RESOURCE_LANG_NOT_FOUND 1815 +#define ERROR_NOT_ENOUGH_QUOTA 1816 +#define RPC_S_NO_INTERFACES 1817 +#define RPC_S_CALL_CANCELLED 1818 +#define RPC_S_BINDING_INCOMPLETE 1819 +#define RPC_S_COMM_FAILURE 1820 +#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821 +#define RPC_S_NO_PRINC_NAME 1822 +#define RPC_S_NOT_RPC_ERROR 1823 +#define RPC_S_UUID_LOCAL_ONLY 1824 +#define RPC_S_SEC_PKG_ERROR 1825 +#define RPC_S_NOT_CANCELLED 1826 +#define RPC_X_INVALID_ES_ACTION 1827 +#define RPC_X_WRONG_ES_VERSION 1828 +#define RPC_X_WRONG_STUB_VERSION 1829 +#define RPC_X_INVALID_PIPE_OBJECT 1830 +#define RPC_X_WRONG_PIPE_ORDER 1831 +#define RPC_X_WRONG_PIPE_VERSION 1832 +#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898 +#define EPT_S_CANT_CREATE 1899 +#define RPC_S_INVALID_OBJECT 1900 +#define ERROR_INVALID_TIME 1901 +#define ERROR_INVALID_FORM_NAME 1902 +#define ERROR_INVALID_FORM_SIZE 1903 +#define ERROR_ALREADY_WAITING 1904 +#define ERROR_PRINTER_DELETED 1905 +#define ERROR_INVALID_PRINTER_STATE 1906 +#define ERROR_PASSWORD_MUST_CHANGE 1907 +#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908 +#define ERROR_ACCOUNT_LOCKED_OUT 1909 +#define OR_INVALID_OXID 1910 +#define OR_INVALID_OID 1911 +#define OR_INVALID_SET 1912 +#define RPC_S_SEND_INCOMPLETE 1913 +#define RPC_S_INVALID_ASYNC_HANDLE 1914 +#define RPC_S_INVALID_ASYNC_CALL 1915 +#define RPC_X_PIPE_CLOSED 1916 +#define RPC_X_PIPE_DISCIPLINE_ERROR 1917 +#define RPC_X_PIPE_EMPTY 1918 +#define ERROR_NO_SITENAME 1919 +#define ERROR_CANT_ACCESS_FILE 1920 +#define ERROR_CANT_RESOLVE_FILENAME 1921 +#define RPC_S_ENTRY_TYPE_MISMATCH 1922 +#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923 +#define RPC_S_INTERFACE_NOT_EXPORTED 1924 +#define RPC_S_PROFILE_NOT_ADDED 1925 +#define RPC_S_PRF_ELT_NOT_ADDED 1926 +#define RPC_S_PRF_ELT_NOT_REMOVED 1927 +#define RPC_S_GRP_ELT_NOT_ADDED 1928 +#define RPC_S_GRP_ELT_NOT_REMOVED 1929 +#define ERROR_INVALID_PIXEL_FORMAT 2000 +#define ERROR_BAD_DRIVER 2001 +#define ERROR_INVALID_WINDOW_STYLE 2002 +#define ERROR_METAFILE_NOT_SUPPORTED 2003 +#define ERROR_TRANSFORM_NOT_SUPPORTED 2004 +#define ERROR_CLIPPING_NOT_SUPPORTED 2005 +#define ERROR_INVALID_CMM 2010 +#define ERROR_INVALID_PROFILE 2011 +#define ERROR_TAG_NOT_FOUND 2012 +#define ERROR_TAG_NOT_PRESENT 2013 +#define ERROR_DUPLICATE_TAG 2014 +#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015 +#define ERROR_PROFILE_NOT_FOUND 2016 +#define ERROR_INVALID_COLORSPACE 2017 +#define ERROR_ICM_NOT_ENABLED 2018 +#define ERROR_DELETING_ICM_XFORM 2019 +#define ERROR_INVALID_TRANSFORM 2020 +#define ERROR_COLORSPACE_MISMATCH 2021 +#define ERROR_INVALID_COLORINDEX 2022 +#define ERROR_CONNECTED_OTHER_PASSWORD 2108 +#define ERROR_BAD_USERNAME 2202 +#define ERROR_NOT_CONNECTED 2250 +#define ERROR_OPEN_FILES 2401 +#define ERROR_ACTIVE_CONNECTIONS 2402 +#define ERROR_DEVICE_IN_USE 2404 +#define ERROR_UNKNOWN_PRINT_MONITOR 3000 +#define ERROR_PRINTER_DRIVER_IN_USE 3001 +#define ERROR_SPOOL_FILE_NOT_FOUND 3002 +#define ERROR_SPL_NO_STARTDOC 3003 +#define ERROR_SPL_NO_ADDJOB 3004 +#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005 +#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006 +#define ERROR_INVALID_PRINT_MONITOR 3007 +#define ERROR_PRINT_MONITOR_IN_USE 3008 +#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009 +#define ERROR_SUCCESS_REBOOT_REQUIRED 3010 +#define ERROR_SUCCESS_RESTART_REQUIRED 3011 +#define ERROR_PRINTER_NOT_FOUND 3012 +#define ERROR_WINS_INTERNAL 4000 +#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001 +#define ERROR_STATIC_INIT 4002 +#define ERROR_INC_BACKUP 4003 +#define ERROR_FULL_BACKUP 4004 +#define ERROR_REC_NON_EXISTENT 4005 +#define ERROR_RPL_NOT_ALLOWED 4006 +#define ERROR_DHCP_ADDRESS_CONFLICT 4100 +#define ERROR_WMI_GUID_NOT_FOUND 4200 +#define ERROR_WMI_INSTANCE_NOT_FOUND 4201 +#define ERROR_WMI_ITEMID_NOT_FOUND 4202 +#define ERROR_WMI_TRY_AGAIN 4203 +#define ERROR_WMI_DP_NOT_FOUND 4204 +#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205 +#define ERROR_WMI_ALREADY_ENABLED 4206 +#define ERROR_WMI_GUID_DISCONNECTED 4207 +#define ERROR_WMI_SERVER_UNAVAILABLE 4208 +#define ERROR_WMI_DP_FAILED 4209 +#define ERROR_WMI_INVALID_MOF 4210 +#define ERROR_WMI_INVALID_REGINFO 4211 +#define ERROR_WMI_ALREADY_DISABLED 4212 +#define ERROR_WMI_READ_ONLY 4213 +#define ERROR_WMI_SET_FAILURE 4214 +#define ERROR_INVALID_MEDIA 4300 +#define ERROR_INVALID_LIBRARY 4301 +#define ERROR_INVALID_MEDIA_POOL 4302 +#define ERROR_DRIVE_MEDIA_MISMATCH 4303 +#define ERROR_MEDIA_OFFLINE 4304 +#define ERROR_LIBRARY_OFFLINE 4305 +#define ERROR_EMPTY 4306 +#define ERROR_NOT_EMPTY 4307 +#define ERROR_MEDIA_UNAVAILABLE 4308 +#define ERROR_RESOURCE_DISABLED 4309 +#define ERROR_INVALID_CLEANER 4310 +#define ERROR_UNABLE_TO_CLEAN 4311 +#define ERROR_OBJECT_NOT_FOUND 4312 +#define ERROR_DATABASE_FAILURE 4313 +#define ERROR_DATABASE_FULL 4314 +#define ERROR_MEDIA_INCOMPATIBLE 4315 +#define ERROR_RESOURCE_NOT_PRESENT 4316 +#define ERROR_INVALID_OPERATION 4317 +#define ERROR_MEDIA_NOT_AVAILABLE 4318 +#define ERROR_DEVICE_NOT_AVAILABLE 4319 +#define ERROR_REQUEST_REFUSED 4320 +#define ERROR_INVALID_DRIVE_OBJECT 4321 +#define ERROR_LIBRARY_FULL 4322 +#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323 +#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324 +#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325 +#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326 +#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327 +#define ERROR_TRANSPORT_FULL 4328 +#define ERROR_CONTROLLING_IEPORT 4329 +#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330 +#define ERROR_CLEANER_SLOT_SET 4331 +#define ERROR_CLEANER_SLOT_NOT_SET 4332 +#define ERROR_CLEANER_CARTRIDGE_SPENT 4333 +#define ERROR_UNEXPECTED_OMID 4334 +#define ERROR_CANT_DELETE_LAST_ITEM 4335 +#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336 +#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337 +#define ERROR_INDIGENOUS_TYPE 4338 +#define ERROR_NO_SUPPORTING_DRIVES 4339 +#define ERROR_FILE_OFFLINE 4350 +#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351 +#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352 +#define ERROR_NOT_A_REPARSE_POINT 4390 +#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391 +#define ERROR_INVALID_REPARSE_DATA 4392 +#define ERROR_REPARSE_TAG_INVALID 4393 +#define ERROR_REPARSE_TAG_MISMATCH 4394 +#define ERROR_VOLUME_NOT_SIS_ENABLED 4500 +#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001 +#define ERROR_DEPENDENCY_NOT_FOUND 5002 +#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003 +#define ERROR_RESOURCE_NOT_ONLINE 5004 +#define ERROR_HOST_NODE_NOT_AVAILABLE 5005 +#define ERROR_RESOURCE_NOT_AVAILABLE 5006 +#define ERROR_RESOURCE_NOT_FOUND 5007 +#define ERROR_SHUTDOWN_CLUSTER 5008 +#define ERROR_CANT_EVICT_ACTIVE_NODE 5009 +#define ERROR_OBJECT_ALREADY_EXISTS 5010 +#define ERROR_OBJECT_IN_LIST 5011 +#define ERROR_GROUP_NOT_AVAILABLE 5012 +#define ERROR_GROUP_NOT_FOUND 5013 +#define ERROR_GROUP_NOT_ONLINE 5014 +#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015 +#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016 +#define ERROR_RESMON_CREATE_FAILED 5017 +#define ERROR_RESMON_ONLINE_FAILED 5018 +#define ERROR_RESOURCE_ONLINE 5019 +#define ERROR_QUORUM_RESOURCE 5020 +#define ERROR_NOT_QUORUM_CAPABLE 5021 +#define ERROR_CLUSTER_SHUTTING_DOWN 5022 +#define ERROR_INVALID_STATE 5023 +#define ERROR_RESOURCE_PROPERTIES_STORED 5024 +#define ERROR_NOT_QUORUM_CLASS 5025 +#define ERROR_CORE_RESOURCE 5026 +#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027 +#define ERROR_QUORUMLOG_OPEN_FAILED 5028 +#define ERROR_CLUSTERLOG_CORRUPT 5029 +#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030 +#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031 +#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032 +#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033 +#define ERROR_QUORUM_OWNER_ALIVE 5034 +#define ERROR_NETWORK_NOT_AVAILABLE 5035 +#define ERROR_NODE_NOT_AVAILABLE 5036 +#define ERROR_ALL_NODES_NOT_AVAILABLE 5037 +#define ERROR_RESOURCE_FAILED 5038 +#define ERROR_CLUSTER_INVALID_NODE 5039 +#define ERROR_CLUSTER_NODE_EXISTS 5040 +#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041 +#define ERROR_CLUSTER_NODE_NOT_FOUND 5042 +#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043 +#define ERROR_CLUSTER_NETWORK_EXISTS 5044 +#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045 +#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046 +#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047 +#define ERROR_CLUSTER_INVALID_REQUEST 5048 +#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049 +#define ERROR_CLUSTER_NODE_DOWN 5050 +#define ERROR_CLUSTER_NODE_UNREACHABLE 5051 +#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052 +#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053 +#define ERROR_CLUSTER_INVALID_NETWORK 5054 +#define ERROR_CLUSTER_NODE_UP 5056 +#define ERROR_CLUSTER_IPADDR_IN_USE 5057 +#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058 +#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059 +#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060 +#define ERROR_CLUSTER_NODE_ALREADY_UP 5061 +#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062 +#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063 +#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064 +#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065 +#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066 +#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067 +#define ERROR_INVALID_OPERATION_ON_QUORUM 5068 +#define ERROR_DEPENDENCY_NOT_ALLOWED 5069 +#define ERROR_CLUSTER_NODE_PAUSED 5070 +#define ERROR_NODE_CANT_HOST_RESOURCE 5071 +#define ERROR_CLUSTER_NODE_NOT_READY 5072 +#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073 +#define ERROR_CLUSTER_JOIN_ABORTED 5074 +#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075 +#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076 +#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077 +#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078 +#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079 +#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080 +#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081 +#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082 +#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083 +#define ERROR_RESMON_INVALID_STATE 5084 +#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085 +#define ERROR_QUORUM_DISK_NOT_FOUND 5086 +#define ERROR_DATABASE_BACKUP_CORRUPT 5087 +#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088 +#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089 +#define ERROR_ENCRYPTION_FAILED 6000 +#define ERROR_DECRYPTION_FAILED 6001 +#define ERROR_FILE_ENCRYPTED 6002 +#define ERROR_NO_RECOVERY_POLICY 6003 +#define ERROR_NO_EFS 6004 +#define ERROR_WRONG_EFS 6005 +#define ERROR_NO_USER_KEYS 6006 +#define ERROR_FILE_NOT_ENCRYPTED 6007 +#define ERROR_NOT_EXPORT_FORMAT 6008 +#define ERROR_FILE_READ_ONLY 6009 +#define ERROR_DIR_EFS_DISALLOWED 6010 +#define ERROR_EFS_SERVER_NOT_TRUSTED 6011 +#define ERROR_NO_BROWSER_SERVERS_FOUND 6118 +#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200 +#define ERROR_CTX_WINSTATION_NAME_INVALID 7001 +#define ERROR_CTX_INVALID_PD 7002 +#define ERROR_CTX_PD_NOT_FOUND 7003 +#define ERROR_CTX_WD_NOT_FOUND 7004 +#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005 +#define ERROR_CTX_SERVICE_NAME_COLLISION 7006 +#define ERROR_CTX_CLOSE_PENDING 7007 +#define ERROR_CTX_NO_OUTBUF 7008 +#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009 +#define ERROR_CTX_INVALID_MODEMNAME 7010 +#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011 +#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012 +#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013 +#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014 +#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015 +#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016 +#define ERROR_CTX_TD_ERROR 7017 +#define ERROR_CTX_WINSTATION_NOT_FOUND 7022 +#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023 +#define ERROR_CTX_WINSTATION_BUSY 7024 +#define ERROR_CTX_BAD_VIDEO_MODE 7025 +#define ERROR_CTX_GRAPHICS_INVALID 7035 +#define ERROR_CTX_LOGON_DISABLED 7037 +#define ERROR_CTX_NOT_CONSOLE 7038 +#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040 +#define ERROR_CTX_CONSOLE_DISCONNECT 7041 +#define ERROR_CTX_CONSOLE_CONNECT 7042 +#define ERROR_CTX_SHADOW_DENIED 7044 +#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045 +#define ERROR_CTX_INVALID_WD 7049 +#define ERROR_CTX_SHADOW_INVALID 7050 +#define ERROR_CTX_SHADOW_DISABLED 7051 +#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052 +#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053 +#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054 +#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055 +#define ERROR_CTX_LICENSE_EXPIRED 7056 +#define FRS_ERR_INVALID_API_SEQUENCE 8001 +#define FRS_ERR_STARTING_SERVICE 8002 +#define FRS_ERR_STOPPING_SERVICE 8003 +#define FRS_ERR_INTERNAL_API 8004 +#define FRS_ERR_INTERNAL 8005 +#define FRS_ERR_SERVICE_COMM 8006 +#define FRS_ERR_INSUFFICIENT_PRIV 8007 +#define FRS_ERR_AUTHENTICATION 8008 +#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009 +#define FRS_ERR_PARENT_AUTHENTICATION 8010 +#define FRS_ERR_CHILD_TO_PARENT_COMM 8011 +#define FRS_ERR_PARENT_TO_CHILD_COMM 8012 +#define FRS_ERR_SYSVOL_POPULATE 8013 +#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014 +#define FRS_ERR_SYSVOL_IS_BUSY 8015 +#define FRS_ERR_SYSVOL_DEMOTE 8016 +#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017 +#define ERROR_DS_NOT_INSTALLED 8200 +#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201 +#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202 +#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203 +#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204 +#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205 +#define ERROR_DS_BUSY 8206 +#define ERROR_DS_UNAVAILABLE 8207 +#define ERROR_DS_NO_RIDS_ALLOCATED 8208 +#define ERROR_DS_NO_MORE_RIDS 8209 +#define ERROR_DS_INCORRECT_ROLE_OWNER 8210 +#define ERROR_DS_RIDMGR_INIT_ERROR 8211 +#define ERROR_DS_OBJ_CLASS_VIOLATION 8212 +#define ERROR_DS_CANT_ON_NON_LEAF 8213 +#define ERROR_DS_CANT_ON_RDN 8214 +#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215 +#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216 +#define ERROR_DS_GC_NOT_AVAILABLE 8217 +#define ERROR_SHARED_POLICY 8218 +#define ERROR_POLICY_OBJECT_NOT_FOUND 8219 +#define ERROR_POLICY_ONLY_IN_DS 8220 +#define ERROR_PROMOTION_ACTIVE 8221 +#define ERROR_NO_PROMOTION_ACTIVE 8222 +#define ERROR_DS_OPERATIONS_ERROR 8224 +#define ERROR_DS_PROTOCOL_ERROR 8225 +#define ERROR_DS_TIMELIMIT_EXCEEDED 8226 +#define ERROR_DS_SIZELIMIT_EXCEEDED 8227 +#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228 +#define ERROR_DS_COMPARE_FALSE 8229 +#define ERROR_DS_COMPARE_TRUE 8230 +#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231 +#define ERROR_DS_STRONG_AUTH_REQUIRED 8232 +#define ERROR_DS_INAPPROPRIATE_AUTH 8233 +#define ERROR_DS_AUTH_UNKNOWN 8234 +#define ERROR_DS_REFERRAL 8235 +#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236 +#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237 +#define ERROR_DS_INAPPROPRIATE_MATCHING 8238 +#define ERROR_DS_CONSTRAINT_VIOLATION 8239 +#define ERROR_DS_NO_SUCH_OBJECT 8240 +#define ERROR_DS_ALIAS_PROBLEM 8241 +#define ERROR_DS_INVALID_DN_SYNTAX 8242 +#define ERROR_DS_IS_LEAF 8243 +#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244 +#define ERROR_DS_UNWILLING_TO_PERFORM 8245 +#define ERROR_DS_LOOP_DETECT 8246 +#define ERROR_DS_NAMING_VIOLATION 8247 +#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248 +#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249 +#define ERROR_DS_SERVER_DOWN 8250 +#define ERROR_DS_LOCAL_ERROR 8251 +#define ERROR_DS_ENCODING_ERROR 8252 +#define ERROR_DS_DECODING_ERROR 8253 +#define ERROR_DS_FILTER_UNKNOWN 8254 +#define ERROR_DS_PARAM_ERROR 8255 +#define ERROR_DS_NOT_SUPPORTED 8256 +#define ERROR_DS_NO_RESULTS_RETURNED 8257 +#define ERROR_DS_CONTROL_NOT_FOUND 8258 +#define ERROR_DS_CLIENT_LOOP 8259 +#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260 +#define ERROR_DS_ROOT_MUST_BE_NC 8301 +#define ERROR_DS_ADD_REPLICA_INHIBITED 8302 +#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303 +#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304 +#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305 +#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306 +#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307 +#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308 +#define ERROR_DS_USER_BUFFER_TO_SMALL 8309 +#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310 +#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311 +#define ERROR_DS_OBJ_TOO_LARGE 8312 +#define ERROR_DS_BAD_INSTANCE_TYPE 8313 +#define ERROR_DS_MASTERDSA_REQUIRED 8314 +#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315 +#define ERROR_DS_MISSING_REQUIRED_ATT 8316 +#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317 +#define ERROR_DS_ATT_ALREADY_EXISTS 8318 +#define ERROR_DS_CANT_ADD_ATT_VALUES 8320 +#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321 +#define ERROR_DS_RANGE_CONSTRAINT 8322 +#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323 +#define ERROR_DS_CANT_REM_MISSING_ATT 8324 +#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325 +#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326 +#define ERROR_DS_NO_CHAINING 8327 +#define ERROR_DS_NO_CHAINED_EVAL 8328 +#define ERROR_DS_NO_PARENT_OBJECT 8329 +#define ERROR_DS_PARENT_IS_AN_ALIAS 8330 +#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331 +#define ERROR_DS_CHILDREN_EXIST 8332 +#define ERROR_DS_OBJ_NOT_FOUND 8333 +#define ERROR_DS_ALIASED_OBJ_MISSING 8334 +#define ERROR_DS_BAD_NAME_SYNTAX 8335 +#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336 +#define ERROR_DS_CANT_DEREF_ALIAS 8337 +#define ERROR_DS_OUT_OF_SCOPE 8338 +#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340 +#define ERROR_DS_GENERIC_ERROR 8341 +#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342 +#define ERROR_DS_CLASS_NOT_DSA 8343 +#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344 +#define ERROR_DS_ILLEGAL_SUPERIOR 8345 +#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346 +#define ERROR_DS_NAME_TOO_MANY_PARTS 8347 +#define ERROR_DS_NAME_TOO_LONG 8348 +#define ERROR_DS_NAME_VALUE_TOO_LONG 8349 +#define ERROR_DS_NAME_UNPARSEABLE 8350 +#define ERROR_DS_NAME_TYPE_UNKNOWN 8351 +#define ERROR_DS_NOT_AN_OBJECT 8352 +#define ERROR_DS_SEC_DESC_TOO_SHORT 8353 +#define ERROR_DS_SEC_DESC_INVALID 8354 +#define ERROR_DS_NO_DELETED_NAME 8355 +#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356 +#define ERROR_DS_NCNAME_MUST_BE_NC 8357 +#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358 +#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359 +#define ERROR_DS_INVALID_DMD 8360 +#define ERROR_DS_OBJ_GUID_EXISTS 8361 +#define ERROR_DS_NOT_ON_BACKLINK 8362 +#define ERROR_DS_NO_CROSSREF_FOR_NC 8363 +#define ERROR_DS_SHUTTING_DOWN 8364 +#define ERROR_DS_UNKNOWN_OPERATION 8365 +#define ERROR_DS_INVALID_ROLE_OWNER 8366 +#define ERROR_DS_COULDNT_CONTACT_FSMO 8367 +#define ERROR_DS_CROSS_NC_DN_RENAME 8368 +#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369 +#define ERROR_DS_REPLICATOR_ONLY 8370 +#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371 +#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372 +#define ERROR_DS_NAME_REFERENCE_INVALID 8373 +#define ERROR_DS_CROSS_REF_EXISTS 8374 +#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375 +#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376 +#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377 +#define ERROR_DS_DUP_RDN 8378 +#define ERROR_DS_DUP_OID 8379 +#define ERROR_DS_DUP_MAPI_ID 8380 +#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381 +#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382 +#define ERROR_DS_SEMANTIC_ATT_TEST 8383 +#define ERROR_DS_SYNTAX_MISMATCH 8384 +#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385 +#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386 +#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387 +#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388 +#define ERROR_DS_AUX_CLS_TEST_FAIL 8389 +#define ERROR_DS_NONEXISTENT_POSS_SUP 8390 +#define ERROR_DS_SUB_CLS_TEST_FAIL 8391 +#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392 +#define ERROR_DS_EXISTS_IN_AUX_CLS 8393 +#define ERROR_DS_EXISTS_IN_SUB_CLS 8394 +#define ERROR_DS_EXISTS_IN_POSS_SUP 8395 +#define ERROR_DS_RECALCSCHEMA_FAILED 8396 +#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397 +#define ERROR_DS_CANT_DELETE 8398 +#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399 +#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400 +#define ERROR_DS_CANT_CACHE_ATT 8401 +#define ERROR_DS_CANT_CACHE_CLASS 8402 +#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403 +#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404 +#define ERROR_DS_CANT_RETRIEVE_DN 8405 +#define ERROR_DS_MISSING_SUPREF 8406 +#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407 +#define ERROR_DS_CODE_INCONSISTENCY 8408 +#define ERROR_DS_DATABASE_ERROR 8409 +#define ERROR_DS_GOVERNSID_MISSING 8410 +#define ERROR_DS_MISSING_EXPECTED_ATT 8411 +#define ERROR_DS_NCNAME_MISSING_CR_REF 8412 +#define ERROR_DS_SECURITY_CHECKING_ERROR 8413 +#define ERROR_DS_SCHEMA_NOT_LOADED 8414 +#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415 +#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416 +#define ERROR_DS_GCVERIFY_ERROR 8417 +#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418 +#define ERROR_DS_CANT_FIND_DSA_OBJ 8419 +#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420 +#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421 +#define ERROR_DS_CANT_RETRIEVE_CHILD 8422 +#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423 +#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424 +#define ERROR_DS_BAD_HIERARCHY_FILE 8425 +#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426 +#define ERROR_DS_CONFIG_PARAM_MISSING 8427 +#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428 +#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429 +#define ERROR_DS_INTERNAL_FAILURE 8430 +#define ERROR_DS_UNKNOWN_ERROR 8431 +#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432 +#define ERROR_DS_REFUSING_FSMO_ROLES 8433 +#define ERROR_DS_MISSING_FSMO_SETTINGS 8434 +#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435 +#define ERROR_DS_DRA_GENERIC 8436 +#define ERROR_DS_DRA_INVALID_PARAMETER 8437 +#define ERROR_DS_DRA_BUSY 8438 +#define ERROR_DS_DRA_BAD_DN 8439 +#define ERROR_DS_DRA_BAD_NC 8440 +#define ERROR_DS_DRA_DN_EXISTS 8441 +#define ERROR_DS_DRA_INTERNAL_ERROR 8442 +#define ERROR_DS_DRA_INCONSISTENT_DIT 8443 +#define ERROR_DS_DRA_CONNECTION_FAILED 8444 +#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445 +#define ERROR_DS_DRA_OUT_OF_MEM 8446 +#define ERROR_DS_DRA_MAIL_PROBLEM 8447 +#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448 +#define ERROR_DS_DRA_REF_NOT_FOUND 8449 +#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450 +#define ERROR_DS_DRA_DB_ERROR 8451 +#define ERROR_DS_DRA_NO_REPLICA 8452 +#define ERROR_DS_DRA_ACCESS_DENIED 8453 +#define ERROR_DS_DRA_NOT_SUPPORTED 8454 +#define ERROR_DS_DRA_RPC_CANCELLED 8455 +#define ERROR_DS_DRA_SOURCE_DISABLED 8456 +#define ERROR_DS_DRA_SINK_DISABLED 8457 +#define ERROR_DS_DRA_NAME_COLLISION 8458 +#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459 +#define ERROR_DS_DRA_MISSING_PARENT 8460 +#define ERROR_DS_DRA_PREEMPTED 8461 +#define ERROR_DS_DRA_ABANDON_SYNC 8462 +#define ERROR_DS_DRA_SHUTDOWN 8463 +#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464 +#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465 +#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466 +#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467 +#define ERROR_DS_DUP_LINK_ID 8468 +#define ERROR_DS_NAME_ERROR_RESOLVING 8469 +#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470 +#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471 +#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472 +#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473 +#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474 +#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475 +#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476 +#define ERROR_DS_DRA_REPL_PENDING 8477 +#define ERROR_DS_DS_REQUIRED 8478 +#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479 +#define ERROR_DS_NON_BASE_SEARCH 8480 +#define ERROR_DS_CANT_RETRIEVE_ATTS 8481 +#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482 +#define ERROR_DS_EPOCH_MISMATCH 8483 +#define ERROR_DS_SRC_NAME_MISMATCH 8484 +#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485 +#define ERROR_DS_DST_NC_MISMATCH 8486 +#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487 +#define ERROR_DS_SRC_GUID_MISMATCH 8488 +#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489 +#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490 +#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491 +#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492 +#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493 +#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494 +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495 +#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496 +#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497 +#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498 +#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499 +#define ERROR_DS_INVALID_SEARCH_FLAG 8500 +#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501 +#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502 +#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503 +#define ERROR_DS_SAM_INIT_FAILURE 8504 +#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505 +#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506 +#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507 +#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508 +#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509 +#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510 +#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511 +#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512 +#define ERROR_DS_INVALID_GROUP_TYPE 8513 +#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514 +#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515 +#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516 +#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517 +#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518 +#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519 +#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520 +#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521 +#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522 +#define ERROR_DS_NAMING_MASTER_GC 8523 +#define ERROR_DS_LOOKUP_FAILURE 8524 +#define ERROR_DS_COULDNT_UPDATE_SPNS 8525 +#define ERROR_DS_CANT_RETRIEVE_SD 8526 +#define ERROR_DS_KEY_NOT_UNIQUE 8527 +#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528 +#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529 +#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530 +#define ERROR_DS_CANT_START 8531 +#define ERROR_DS_INIT_FAILURE 8532 +#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533 +#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534 +#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535 +#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536 +#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537 +#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538 +#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539 +#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540 +#define ERROR_SAM_INIT_FAILURE 8541 +#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542 +#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543 +#define ERROR_DS_DRA_EARLIER_SCHEMA_CONLICT 8544 +#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545 +#define ERROR_DS_NC_STILL_HAS_DSAS 8546 +#define ERROR_DS_GC_REQUIRED 8547 +#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548 +#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549 +#define ERROR_DS_CANT_ADD_TO_GC 8550 +#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551 +#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552 +#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553 +#define ERROR_DS_INVALID_NAME_FOR_SPN 8554 +#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555 +#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556 +#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557 +#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558 +#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559 +#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560 +#define DNS_ERROR_RCODE_FORMAT_ERROR 9001 +#define DNS_ERROR_RCODE_SERVER_FAILURE 9002 +#define DNS_ERROR_RCODE_NAME_ERROR 9003 +#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004 +#define DNS_ERROR_RCODE_REFUSED 9005 +#define DNS_ERROR_RCODE_YXDOMAIN 9006 +#define DNS_ERROR_RCODE_YXRRSET 9007 +#define DNS_ERROR_RCODE_NXRRSET 9008 +#define DNS_ERROR_RCODE_NOTAUTH 9009 +#define DNS_ERROR_RCODE_NOTZONE 9010 +#define DNS_ERROR_RCODE_BADSIG 9016 +#define DNS_ERROR_RCODE_BADKEY 9017 +#define DNS_ERROR_RCODE_BADTIME 9018 +#define DNS_INFO_NO_RECORDS 9501 +#define DNS_ERROR_BAD_PACKET 9502 +#define DNS_ERROR_NO_PACKET 9503 +#define DNS_ERROR_RCODE 9504 +#define DNS_ERROR_UNSECURE_PACKET 9505 +#define DNS_ERROR_INVALID_TYPE 9551 +#define DNS_ERROR_INVALID_IP_ADDRESS 9552 +#define DNS_ERROR_INVALID_PROPERTY 9553 +#define DNS_ERROR_TRY_AGAIN_LATER 9554 +#define DNS_ERROR_NOT_UNIQUE 9555 +#define DNS_ERROR_NON_RFC_NAME 9556 +#define DNS_STATUS_FQDN 9557 +#define DNS_STATUS_DOTTED_NAME 9558 +#define DNS_STATUS_SINGLE_PART_NAME 9559 +#define DNS_ERROR_INVALID_NAME_CHAR 9560 +#define DNS_ERROR_NUMERIC_NAME 9561 +#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601 +#define DNS_ERROR_NO_ZONE_INFO 9602 +#define DNS_ERROR_INVALID_ZONE_OPERATION 9603 +#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604 +#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605 +#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606 +#define DNS_ERROR_ZONE_LOCKED 9607 +#define DNS_ERROR_ZONE_CREATION_FAILED 9608 +#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609 +#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610 +#define DNS_ERROR_INVALID_ZONE_TYPE 9611 +#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612 +#define DNS_ERROR_ZONE_NOT_SECONDARY 9613 +#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614 +#define DNS_ERROR_WINS_INIT_FAILED 9615 +#define DNS_ERROR_NEED_WINS_SERVERS 9616 +#define DNS_ERROR_NBSTAT_INIT_FAILED 9617 +#define DNS_ERROR_SOA_DELETE_INVALID 9618 +#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651 +#define DNS_ERROR_INVALID_DATAFILE_NAME 9652 +#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653 +#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654 +#define DNS_ERROR_DATAFILE_PARSING 9655 +#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701 +#define DNS_ERROR_RECORD_FORMAT 9702 +#define DNS_ERROR_NODE_CREATION_FAILED 9703 +#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704 +#define DNS_ERROR_RECORD_TIMED_OUT 9705 +#define DNS_ERROR_NAME_NOT_IN_ZONE 9706 +#define DNS_ERROR_CNAME_LOOP 9707 +#define DNS_ERROR_NODE_IS_CNAME 9708 +#define DNS_ERROR_CNAME_COLLISION 9709 +#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710 +#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711 +#define DNS_ERROR_SECONDARY_DATA 9712 +#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713 +#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714 +#define DNS_WARNING_PTR_CREATE_FAILED 9715 +#define DNS_WARNING_DOMAIN_UNDELETED 9716 +#define DNS_ERROR_DS_UNAVAILABLE 9717 +#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718 +#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719 +#define DNS_INFO_AXFR_COMPLETE 9751 +#define DNS_ERROR_AXFR 9752 +#define DNS_INFO_ADDED_LOCAL_WINS 9753 +#define DNS_STATUS_CONTINUE_NEEDED 9801 +#define DNS_ERROR_NO_TCPIP 9851 +#define DNS_ERROR_NO_DNS_SERVERS 9852 + +/* HRESULT values for OLE, SHELL and other Interface stuff */ +/* the codes 4000-40ff are reserved for OLE */ +#define NOERROR 0L +#define S_OK ((HRESULT)0L) +#define S_FALSE ((HRESULT)1L) + +#define DISP_E_UNKNOWNINTERFACE 0x80020001L +#define DISP_E_MEMBERNOTFOUND 0x80020003L +#define DISP_E_PARAMNOTFOUND 0x80020004L +#define DISP_E_TYPEMISMATCH 0x80020005L +#define DISP_E_UNKNOWNNAME 0x80020006L +#define DISP_E_NONAMEDARGS 0x80020007L +#define DISP_E_BADVARTYPE 0x80020008L +#define DISP_E_EXCEPTION 0x80020009L +#define DISP_E_OVERFLOW 0x8002000AL +#define DISP_E_BADINDEX 0x8002000BL +#define DISP_E_UNKNOWNLCID 0x8002000CL +#define DISP_E_ARRAYISLOCKED 0x8002000DL +#define DISP_E_BADPARAMCOUNT 0x8002000EL +#define DISP_E_PARAMNOTOPTIONAL 0x8002000FL + +#define TYPE_E_ELEMENTNOTFOUND 0x8002802BL +#define TYPE_E_CANTLOADLIBRARY 0x80029C4AL + +/* OLE Clipboard */ +#define CLIPBRD_E_FIRST 0x800401D0L +#define CLIPBRD_E_LAST 0x800401DFL +#define CLIPBRD_S_FIRST 0x000401D0L +#define CLIPBRD_S_LAST 0x000401DFL +#define CLIPBRD_E_CANT_OPEN 0x800401D0L +#define CLIPBRD_E_CANT_EMPTY 0x800401D1L +#define CLIPBRD_E_CANT_SET 0x800401D2L +#define CLIPBRD_E_BAD_DATA 0x800401D3L +#define CLIPBRD_E_CANT_CLOSE 0x800401D4L + +/* Drag and Drop */ +#define DRAGDROP_S_DROP 0x00040100L +#define DRAGDROP_S_CANCEL 0x00040101L +#define DRAGDROP_E_NOTREGISTERED 0x80040100L +#define DRAGDROP_E_ALREADYREGISTERED 0x80040101L +#define DRAGDROP_S_USEDEFAULTCURSORS 0x00040102L + +#define E_UNEXPECTED 0x8000FFFF + +#define E_NOTIMPL 0x80004001 +#define E_NOINTERFACE 0x80004002 +#define E_POINTER 0x80004003 +#define E_ABORT 0x80004004 +#define E_FAIL 0x80004005 +#define E_UNSPEC E_FAIL /* must to be defined (used by FileMoniker, IOleLink and DoDragDrop as a return value) */ + +/*#define CO_E_INIT_TLS 0x80004006 +#define CO_E_INIT_SHARED_ALLOCATOR 0x80004007 +#define CO_E_INIT_MEMORY_ALLOCATOR 0x80004008 +#define CO_E_INIT_CLASS_CACHE 0x80004009 +#define CO_E_INIT_RPC_CHANNEL 0x8000400A +#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL 0x8000400B +#define CO_E_INIT_TLS_CHANNEL_CONTROL 0x8000400C +#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR 0x8000400D +#define CO_E_INIT_SCM_MUTEX_EXISTS 0x8000400E +#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS 0x8000400F +#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE 0x80004010 +#define CO_E_INIT_SCM_EXEC_FAILURE 0x80004011 +#define CO_E_INIT_ONLY_SINGLE_THREADED 0x80004012 */ + +#define CO_S_NOTALLINTERFACES 0x00080012 +#define CO_E_NOTINITIALIZED 0x800401F0 +#define CO_E_ERRORINDLL 0x800401F9 +#define CO_E_OBJISREG 0x800401FB + +#define OLE_E_FIRST 0x80040000L +#define OLE_E_LAST 0x800400FFL +#define OLE_S_FIRST 0x00040000L +#define OLE_S_LAST 0x000400FFL + +#define OLE_E_ENUM_NOMORE 0x80040002 +#define OLE_E_ADVISENOTSUPPORTED 0x80040003 +#define OLE_E_NOCONNECTION 0x80040004 +#define OLE_E_NOTRUNNING 0x80040005 +#define OLE_E_NOCACHE 0x80040006 +#define OLE_E_BLANK 0x80040007 +#define OLE_E_NOT_INPLACEACTIVE 0x80040010 +#define OLE_E_STATIC 0x8004000B +#define OLE_E_PROMPTSAVECANCELLED 0x8004000C +#define OLE_S_USEREG 0x00040000 +#define OLE_S_STATIC 0x00040001 + +#define DV_E_FORMATETC 0x80040064 +#define DV_E_DVASPECT 0x8004006B +#define DV_E_LINDEX 0x80040068 +#define DV_E_TYMED 0x80040069 + +#define CLASS_E_NOAGGREGATION 0x80040110 +#define CLASS_E_CLASSNOTAVAILABLE 0x80040111 + +#define DATA_S_SAMEFORMATETC 0x80040130 + +#define E_ACCESSDENIED 0x80070005 +#define E_HANDLE 0x80070006 +#define E_OUTOFMEMORY 0x8007000E +#define E_INVALIDARG 0x80070057 + +/*#define OLE_E_FIRST 0x80040000L */ +/*#define OLE_E_LAST 0x800400FFL */ +/*#define OLE_S_FIRST 0x00040000L */ +/*#define OLE_S_LAST 0x000400FFL */ + +#define MK_S_REDUCED_TO_SELF 0x000401E2 +#define MK_S_ME 0x000401E4 +#define MK_S_HIM 0x000401E5 +#define MK_S_US 0x000401E6 +#define MK_S_MONIKERALREADYREGISTERED 0x000401E7 + +#define MK_E_EXCEEDEDDEADLINE 0x800401E1 +#define MK_E_NEEDGENERIC 0x800401E2 +#define MK_E_UNAVAILABLE 0x800401E3 +#define MK_E_SYNTAX 0x800401E4 +#define MK_E_NOOBJECT 0x800401E5 +#define MK_E_INVALIDEXTENSION 0x800401E6 +#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED 0x800401E7 +#define MK_E_NOTBINDABLE 0x800401E8 +#define MK_E_NOTBOUND 0x800401E9 +#define MK_E_CANTOPENFILE 0x800401EA +#define MK_E_MIUSTBOTHERUSER 0x800401EB +#define MK_E_NOINVERSE 0x800401EC +#define MK_E_NOSTORAGE 0x800401ED +#define MK_E_NOPREFIX 0x800401EE + +#define STG_E_INVALIDFUNCTION 0x80030001 +#define STG_E_FILENOTFOUND 0x80030002 +#define STG_E_PATHNOTFOUND 0x80030003 +#define STG_E_TOOMANYOPENFILES 0x80030004 +#define STG_E_ACCESSDENIED 0x80030005 +#define STG_E_INVALIDHANDLE 0x80030006 +#define STG_E_INSUFFICIENTMEMORY 0x80030008 +#define STG_E_INVALIDPOINTER 0x80030009 +#define STG_E_NOMOREFILES 0x80030012 +#define STG_E_DISKISWRITEPROTECTED 0x80030013 +#define STG_E_SEEKERROR 0x80030019 +#define STG_E_WRITEFAULT 0x8003001D +#define STG_E_READFAULT 0x8003001E +#define STG_E_SHAREVIOLATION 0x80030020 +#define STG_E_LOCKVIOLATION 0x80030021 +#define STG_E_FILEALREADYEXISTS 0x80030050 +#define STG_E_INVALIDPARAMETER 0x80030057 +#define STG_E_MEDIUMFULL 0x80030070 +#define STG_E_ABNORMALAPIEXIT 0x800300FA +#define STG_E_INVALIDHEADER 0x800300FB +#define STG_E_INVALIDNAME 0x800300FC +#define STG_E_UNKNOWN 0x800300FD +#define STG_E_UNIMPLEMENTEDFUNCTION 0x800300FE +#define STG_E_INVALIDFLAG 0x800300FF +#define STG_E_INUSE 0x80030100 +#define STG_E_NOTCURRENT 0x80030101 +#define STG_E_REVERTED 0x80030102 +#define STG_E_CANTSAVE 0x80030103 +#define STG_E_OLDFORMAT 0x80030104 +#define STG_E_OLDDLL 0x80030105 +#define STG_E_SHAREREQUIRED 0x80030106 +#define STG_E_NOTFILEBASEDSTORAGE 0x80030107 +#define STG_E_EXTANTMARSHALLINGS 0x80030108 + +#define CONVERT10_E_OLESTREAM_GET 0x800401C0 +#define CONVERT10_E_OLESTREAM_PUT 0x800401C1 +#define CONVERT10_E_OLESTREAM_FMT 0x800401C2 +#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB 0x800401C3 +#define CONVERT10_E_STG_FMT 0x800401C4 +#define CONVERT10_E_STG_NO_STD_STREAM 0x800401C5 +#define CONVERT10_E_STG_DIB_TO_BITMAP 0x800401C6 + +/* alten versionen +#define E_NOTIMPL 0x80000001 +#define E_OUTOFMEMORY 0x80000002 +#define E_INVALIDARG 0x80000003 +#define E_NOINTERFACE 0x80000004 +#define E_POINTER 0x80000005 +#define E_HANDLE 0x80000006 +#define E_ABORT 0x80000007 +#define E_FAIL 0x80000008 +#define E_ACCESSDENIED 0x80000009 */ + +/* Obtained from lcc-win32 include files */ +#define GDI_ERROR 0xffffffff + + +/* registry errors */ +#define REGDB_E_READREGDB 0x80040150 +#define REGDB_E_CLASSNOTREG 0x80040154 + +#define INPLACE_E_NOTUNDOABLE 0x800401A0 +#define INPLACE_E_NOTOOLSPACE 0x800401A1 + +#define DATA_E_FORMATETC DV_E_FORMATETC + +#define CLASSFACTORY_E_FIRST 0x80040110L +#define CLASSFACTORY_E_LAST 0x8004011FL +#define CLASSFACTORY_S_FIRST 0x80040110L +#define CLASSFACTORY_S_LAST 0x8004011FL + +#define CLASS_E_NOTLICENSED (CLASSFACTORY_E_FIRST+2) +#define CLASS_E_NOAGGREGATION 0x80040110 +#define CLASS_E_CLASSNOTAVAILABLE 0x80040111 + + +#define OLEOBJ_E_NOVERBS 0x00040180L +#define OLEOBJ_E_INVALIDVERB 0x00040181L +#define OLEOBJ_S_INVALIDVERB 0x00040180L + +#endif /* __WINE_WINERROR_H */ diff --git a/linphone/win32acm/wine/winestring.h b/linphone/win32acm/wine/winestring.h new file mode 100644 index 000000000..5b66dc803 --- /dev/null +++ b/linphone/win32acm/wine/winestring.h @@ -0,0 +1,13 @@ +#ifndef __WINE_WINE_WINESTRING_H +#define __WINE_WINE_WINESTRING_H + +#include "windef.h" + +LPWSTR WINAPI lstrcpyAtoW(LPWSTR,LPCSTR); +LPSTR WINAPI lstrcpyWtoA(LPSTR,LPCWSTR); +LPWSTR WINAPI lstrcpynAtoW(LPWSTR,LPCSTR,INT); +LPSTR WINAPI lstrcpynWtoA(LPSTR,LPCWSTR,INT); + +#define lstrncmpiA strncasecmp + +#endif /* __WINE_WINE_WINESTRING_H */ diff --git a/linphone/win32acm/wine/winnt.h b/linphone/win32acm/wine/winnt.h new file mode 100644 index 000000000..401c39889 --- /dev/null +++ b/linphone/win32acm/wine/winnt.h @@ -0,0 +1,2668 @@ +/* + * Win32 definitions for Windows NT + * + * Copyright 1996 Alexandre Julliard + */ + +#ifndef __WINE_WINNT_H +#define __WINE_WINNT_H + +#include "windef.h" + +#ifndef RC_INVOKED +#include +#endif + +#include "pshpack1.h" +/* Defines */ + +/* Argument 1 passed to the DllEntryProc. */ +#define DLL_PROCESS_DETACH 0 /* detach process (unload library) */ +#define DLL_PROCESS_ATTACH 1 /* attach process (load library) */ +#define DLL_THREAD_ATTACH 2 /* attach new thread */ +#define DLL_THREAD_DETACH 3 /* detach thread */ + + +/* u.x.wProcessorArchitecture (NT) */ +#define PROCESSOR_ARCHITECTURE_INTEL 0 +#define PROCESSOR_ARCHITECTURE_MIPS 1 +#define PROCESSOR_ARCHITECTURE_ALPHA 2 +#define PROCESSOR_ARCHITECTURE_PPC 3 +#define PROCESSOR_ARCHITECTURE_SHX 4 +#define PROCESSOR_ARCHITECTURE_ARM 5 +#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF + +/* dwProcessorType */ +#define PROCESSOR_INTEL_386 386 +#define PROCESSOR_INTEL_486 486 +#define PROCESSOR_INTEL_PENTIUM 586 +#define PROCESSOR_INTEL_860 860 +#define PROCESSOR_MIPS_R2000 2000 +#define PROCESSOR_MIPS_R3000 3000 +#define PROCESSOR_MIPS_R4000 4000 +#define PROCESSOR_ALPHA_21064 21064 +#define PROCESSOR_PPC_601 601 +#define PROCESSOR_PPC_603 603 +#define PROCESSOR_PPC_604 604 +#define PROCESSOR_PPC_620 620 +#define PROCESSOR_HITACHI_SH3 10003 +#define PROCESSOR_HITACHI_SH3E 10004 +#define PROCESSOR_HITACHI_SH4 10005 +#define PROCESSOR_MOTOROLA_821 821 +#define PROCESSOR_SHx_SH3 103 +#define PROCESSOR_SHx_SH4 104 +#define PROCESSOR_STRONGARM 2577 +#define PROCESSOR_ARM720 1824 /* 0x720 */ +#define PROCESSOR_ARM820 2080 /* 0x820 */ +#define PROCESSOR_ARM920 2336 /* 0x920 */ +#define PROCESSOR_ARM_7TDMI 70001 + +#define ANYSIZE_ARRAY 1 + +#define MINCHAR 0x80 +#define MAXCHAR 0x7f +#define MINSHORT 0x8000 +#define MAXSHORT 0x7fff +#define MINLONG 0x80000000 +#define MAXLONG 0x7fffffff +#define MAXBYTE 0xff +#define MAXWORD 0xffff +#define MAXDWORD 0xffffffff + +#define FIELD_OFFSET(type, field) \ + ((LONG)(INT)&(((type *)0)->field)) + +#define CONTAINING_RECORD(address, type, field) \ + ((type *)((PCHAR)(address) - (PCHAR)(&((type *)0)->field))) + +/* Types */ + +/* TCHAR data types definitions for Winelib. */ +/* These types are _not_ defined for the emulator, because they */ +/* depend on the UNICODE macro that only exists in user's code. */ + +//#ifndef __WINE__ +# ifdef UNICODE +typedef WCHAR TCHAR, *PTCHAR; +typedef LPWSTR PTSTR, LPTSTR; +typedef LPCWSTR PCTSTR, LPCTSTR; +#define __TEXT(string) L##string /*probably wrong */ +# else /* UNICODE */ +typedef char TCHAR, *PTCHAR; +typedef LPSTR PTSTR, LPTSTR; +typedef LPCSTR PCTSTR, LPCTSTR; +#define __TEXT(string) string +# endif /* UNICODE */ +//#endif /* __WINE__ */ +#define TEXT(quote) __TEXT(quote) + +typedef BYTE BOOLEAN; +typedef BOOLEAN *PBOOLEAN; + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY, *PLIST_ENTRY; + +typedef struct _SINGLE_LIST_ENTRY { + struct _SINGLE_LIST_ENTRY *Next; +} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; + +/* Heap flags */ + +#define HEAP_NO_SERIALIZE 0x00000001 +#define HEAP_GROWABLE 0x00000002 +#define HEAP_GENERATE_EXCEPTIONS 0x00000004 +#define HEAP_ZERO_MEMORY 0x00000008 +#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 +#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 +#define HEAP_FREE_CHECKING_ENABLED 0x00000040 +#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 +#define HEAP_CREATE_ALIGN_16 0x00010000 +#define HEAP_CREATE_ENABLE_TRACING 0x00020000 +#define HEAP_WINE_SEGPTR 0x01000000 /* Not a Win32 flag */ +#define HEAP_WINE_CODESEG 0x02000000 /* Not a Win32 flag */ +#define HEAP_WINE_CODE16SEG 0x04000000 /* Not a Win32 flag */ +#define HEAP_WINE_SHARED 0x08000000 /* Not a Win32 flag */ + +/* Processor feature flags. */ +#define PF_FLOATING_POINT_PRECISION_ERRATA 0 +#define PF_FLOATING_POINT_EMULATED 1 +#define PF_COMPARE_EXCHANGE_DOUBLE 2 +#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 +#define PF_PPC_MOVEMEM_64BIT_OK 4 +#define PF_ALPHA_BYTE_INSTRUCTIONS 5 +/* based on wine-20010510 -- alex */ +#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 +#define PF_AMD3D_INSTRUCTIONS_AVAILABLE 7 +#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 + +/* The Win32 register context */ + +/* CONTEXT is the CPU-dependent context; it should be used */ +/* wherever a platform-specific context is needed (e.g. exception */ +/* handling, Win32 register functions). */ + +/* CONTEXT86 is the i386-specific context; it should be used */ +/* wherever only a 386 context makes sense (e.g. DOS interrupts, */ +/* Win16 register functions), so that this code can be compiled */ +/* on all platforms. */ + +#define SIZE_OF_80387_REGISTERS 80 + +typedef struct _FLOATING_SAVE_AREA +{ + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; + DWORD Cr0NpxState; +} FLOATING_SAVE_AREA, *PFLOATING_SAVE_AREA; + +typedef struct _CONTEXT86 +{ + DWORD ContextFlags; + + /* These are selected by CONTEXT_DEBUG_REGISTERS */ + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + + /* These are selected by CONTEXT_FLOATING_POINT */ + FLOATING_SAVE_AREA FloatSave; + + /* These are selected by CONTEXT_SEGMENTS */ + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + + /* These are selected by CONTEXT_INTEGER */ + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + + /* These are selected by CONTEXT_CONTROL */ + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; +} CONTEXT86; + +#define CONTEXT_X86 0x00010000 +#define CONTEXT_i386 CONTEXT_X86 +#define CONTEXT_i486 CONTEXT_X86 + +#define CONTEXT86_CONTROL (CONTEXT_i386 | 0x0001) /* SS:SP, CS:IP, FLAGS, BP */ +#define CONTEXT86_INTEGER (CONTEXT_i386 | 0x0002) /* AX, BX, CX, DX, SI, DI */ +#define CONTEXT86_SEGMENTS (CONTEXT_i386 | 0x0004) /* DS, ES, FS, GS */ +#define CONTEXT86_FLOATING_POINT (CONTEXT_i386 | 0x0008L) /* 387 state */ +#define CONTEXT86_DEBUG_REGISTERS (CONTEXT_i386 | 0x0010L) /* DB 0-3,6,7 */ +#define CONTEXT86_FULL (CONTEXT86_CONTROL | CONTEXT86_INTEGER | CONTEXT86_SEGMENTS) + +/* i386 context definitions */ +#ifdef __i386__ + +#define CONTEXT_CONTROL CONTEXT86_CONTROL +#define CONTEXT_INTEGER CONTEXT86_INTEGER +#define CONTEXT_SEGMENTS CONTEXT86_SEGMENTS +#define CONTEXT_FLOATING_POINT CONTEXT86_FLOATING_POINT +#define CONTEXT_DEBUG_REGISTERS CONTEXT86_DEBUG_REGISTERS +#define CONTEXT_FULL CONTEXT86_FULL + +typedef CONTEXT86 CONTEXT; + +#endif /* __i386__ */ + +/* Alpha context definitions */ +#if defined(_ALPHA_) || defined(__alpha__) + +#define CONTEXT_ALPHA 0x00020000 + +#define CONTEXT_CONTROL (CONTEXT_ALPHA | 0x00000001L) +#define CONTEXT_FLOATING_POINT (CONTEXT_ALPHA | 0x00000002L) +#define CONTEXT_INTEGER (CONTEXT_ALPHA | 0x00000004L) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER) + +typedef struct _CONTEXT +{ + /* selected by CONTEXT_FLOATING_POINT */ + ULONGLONG FltF0; + ULONGLONG FltF1; + ULONGLONG FltF2; + ULONGLONG FltF3; + ULONGLONG FltF4; + ULONGLONG FltF5; + ULONGLONG FltF6; + ULONGLONG FltF7; + ULONGLONG FltF8; + ULONGLONG FltF9; + ULONGLONG FltF10; + ULONGLONG FltF11; + ULONGLONG FltF12; + ULONGLONG FltF13; + ULONGLONG FltF14; + ULONGLONG FltF15; + ULONGLONG FltF16; + ULONGLONG FltF17; + ULONGLONG FltF18; + ULONGLONG FltF19; + ULONGLONG FltF20; + ULONGLONG FltF21; + ULONGLONG FltF22; + ULONGLONG FltF23; + ULONGLONG FltF24; + ULONGLONG FltF25; + ULONGLONG FltF26; + ULONGLONG FltF27; + ULONGLONG FltF28; + ULONGLONG FltF29; + ULONGLONG FltF30; + ULONGLONG FltF31; + + /* selected by CONTEXT_INTEGER */ + ULONGLONG IntV0; + ULONGLONG IntT0; + ULONGLONG IntT1; + ULONGLONG IntT2; + ULONGLONG IntT3; + ULONGLONG IntT4; + ULONGLONG IntT5; + ULONGLONG IntT6; + ULONGLONG IntT7; + ULONGLONG IntS0; + ULONGLONG IntS1; + ULONGLONG IntS2; + ULONGLONG IntS3; + ULONGLONG IntS4; + ULONGLONG IntS5; + ULONGLONG IntFp; + ULONGLONG IntA0; + ULONGLONG IntA1; + ULONGLONG IntA2; + ULONGLONG IntA3; + ULONGLONG IntA4; + ULONGLONG IntA5; + ULONGLONG IntT8; + ULONGLONG IntT9; + ULONGLONG IntT10; + ULONGLONG IntT11; + ULONGLONG IntRa; + ULONGLONG IntT12; + ULONGLONG IntAt; + ULONGLONG IntGp; + ULONGLONG IntSp; + ULONGLONG IntZero; + + /* selected by CONTEXT_FLOATING_POINT */ + ULONGLONG Fpcr; + ULONGLONG SoftFpcr; + + /* selected by CONTEXT_CONTROL */ + ULONGLONG Fir; + DWORD Psr; + DWORD ContextFlags; + DWORD Fill[4]; +} CONTEXT; + +#define _QUAD_PSR_OFFSET HighSoftFpcr +#define _QUAD_FLAGS_OFFSET HighFir + +#endif /* _ALPHA_ */ + +/* Mips context definitions */ +#ifdef _MIPS_ + +#define CONTEXT_R4000 0x00010000 + +#define CONTEXT_CONTROL (CONTEXT_R4000 | 0x00000001) +#define CONTEXT_FLOATING_POINT (CONTEXT_R4000 | 0x00000002) +#define CONTEXT_INTEGER (CONTEXT_R4000 | 0x00000004) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER) + +typedef struct _CONTEXT +{ + DWORD Argument[4]; + /* These are selected by CONTEXT_FLOATING_POINT */ + DWORD FltF0; + DWORD FltF1; + DWORD FltF2; + DWORD FltF3; + DWORD FltF4; + DWORD FltF5; + DWORD FltF6; + DWORD FltF7; + DWORD FltF8; + DWORD FltF9; + DWORD FltF10; + DWORD FltF11; + DWORD FltF12; + DWORD FltF13; + DWORD FltF14; + DWORD FltF15; + DWORD FltF16; + DWORD FltF17; + DWORD FltF18; + DWORD FltF19; + DWORD FltF20; + DWORD FltF21; + DWORD FltF22; + DWORD FltF23; + DWORD FltF24; + DWORD FltF25; + DWORD FltF26; + DWORD FltF27; + DWORD FltF28; + DWORD FltF29; + DWORD FltF30; + DWORD FltF31; + + /* These are selected by CONTEXT_INTEGER */ + DWORD IntZero; + DWORD IntAt; + DWORD IntV0; + DWORD IntV1; + DWORD IntA0; + DWORD IntA1; + DWORD IntA2; + DWORD IntA3; + DWORD IntT0; + DWORD IntT1; + DWORD IntT2; + DWORD IntT3; + DWORD IntT4; + DWORD IntT5; + DWORD IntT6; + DWORD IntT7; + DWORD IntS0; + DWORD IntS1; + DWORD IntS2; + DWORD IntS3; + DWORD IntS4; + DWORD IntS5; + DWORD IntS6; + DWORD IntS7; + DWORD IntT8; + DWORD IntT9; + DWORD IntK0; + DWORD IntK1; + DWORD IntGp; + DWORD IntSp; + DWORD IntS8; + DWORD IntRa; + DWORD IntLo; + DWORD IntHi; + + /* These are selected by CONTEXT_FLOATING_POINT */ + DWORD Fsr; + + /* These are selected by CONTEXT_CONTROL */ + DWORD Fir; + DWORD Psr; + + DWORD ContextFlags; + DWORD Fill[2]; +} CONTEXT; + +#endif /* _MIPS_ */ + +/* PowerPC context definitions */ +#ifdef __PPC__ + +#define CONTEXT_CONTROL 0x0001 +#define CONTEXT_FLOATING_POINT 0x0002 +#define CONTEXT_INTEGER 0x0004 +#define CONTEXT_DEBUG_REGISTERS 0x0008 +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER) + +typedef struct +{ + /* These are selected by CONTEXT_FLOATING_POINT */ + double Fpr0; + double Fpr1; + double Fpr2; + double Fpr3; + double Fpr4; + double Fpr5; + double Fpr6; + double Fpr7; + double Fpr8; + double Fpr9; + double Fpr10; + double Fpr11; + double Fpr12; + double Fpr13; + double Fpr14; + double Fpr15; + double Fpr16; + double Fpr17; + double Fpr18; + double Fpr19; + double Fpr20; + double Fpr21; + double Fpr22; + double Fpr23; + double Fpr24; + double Fpr25; + double Fpr26; + double Fpr27; + double Fpr28; + double Fpr29; + double Fpr30; + double Fpr31; + double Fpscr; + + /* These are selected by CONTEXT_INTEGER */ + DWORD Gpr0; + DWORD Gpr1; + DWORD Gpr2; + DWORD Gpr3; + DWORD Gpr4; + DWORD Gpr5; + DWORD Gpr6; + DWORD Gpr7; + DWORD Gpr8; + DWORD Gpr9; + DWORD Gpr10; + DWORD Gpr11; + DWORD Gpr12; + DWORD Gpr13; + DWORD Gpr14; + DWORD Gpr15; + DWORD Gpr16; + DWORD Gpr17; + DWORD Gpr18; + DWORD Gpr19; + DWORD Gpr20; + DWORD Gpr21; + DWORD Gpr22; + DWORD Gpr23; + DWORD Gpr24; + DWORD Gpr25; + DWORD Gpr26; + DWORD Gpr27; + DWORD Gpr28; + DWORD Gpr29; + DWORD Gpr30; + DWORD Gpr31; + + DWORD Cr; + DWORD Xer; + + /* These are selected by CONTEXT_CONTROL */ + DWORD Msr; + DWORD Iar; + DWORD Lr; + DWORD Ctr; + + DWORD ContextFlags; + DWORD Fill[3]; + + /* These are selected by CONTEXT_DEBUG_REGISTERS */ + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr4; + DWORD Dr5; + DWORD Dr6; + DWORD Dr7; +} CONTEXT; + +typedef struct _STACK_FRAME_HEADER +{ + DWORD BackChain; + DWORD GlueSaved1; + DWORD GlueSaved2; + DWORD Reserved1; + DWORD Spare1; + DWORD Spare2; + + DWORD Parameter0; + DWORD Parameter1; + DWORD Parameter2; + DWORD Parameter3; + DWORD Parameter4; + DWORD Parameter5; + DWORD Parameter6; + DWORD Parameter7; +} STACK_FRAME_HEADER,*PSTACK_FRAME_HEADER; + +#endif /* __PPC__ */ + +#ifdef __sparc__ + +/* + * FIXME: + * + * There is no official CONTEXT structure defined for the SPARC + * architecture, so I just made one up. + * + * This structure is valid only for 32-bit SPARC architectures, + * not for 64-bit SPARC. + * + * Note that this structure contains only the 'top-level' registers; + * the rest of the register window chain is not visible. + * + * The layout follows the Solaris 'prgregset_t' structure. + * + */ + +#define CONTEXT_SPARC 0x10000000 + +#define CONTEXT_CONTROL (CONTEXT_SPARC | 0x00000001) +#define CONTEXT_FLOATING_POINT (CONTEXT_SPARC | 0x00000002) +#define CONTEXT_INTEGER (CONTEXT_SPARC | 0x00000004) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER) + +typedef struct _CONTEXT +{ + DWORD ContextFlags; + + /* These are selected by CONTEXT_INTEGER */ + DWORD g0; + DWORD g1; + DWORD g2; + DWORD g3; + DWORD g4; + DWORD g5; + DWORD g6; + DWORD g7; + DWORD o0; + DWORD o1; + DWORD o2; + DWORD o3; + DWORD o4; + DWORD o5; + DWORD o6; + DWORD o7; + DWORD l0; + DWORD l1; + DWORD l2; + DWORD l3; + DWORD l4; + DWORD l5; + DWORD l6; + DWORD l7; + DWORD i0; + DWORD i1; + DWORD i2; + DWORD i3; + DWORD i4; + DWORD i5; + DWORD i6; + DWORD i7; + + /* These are selected by CONTEXT_CONTROL */ + DWORD psr; + DWORD pc; + DWORD npc; + DWORD y; + DWORD wim; + DWORD tbr; + + /* FIXME: floating point registers missing */ + +} CONTEXT; + +#endif /* __sparc__ */ + +#if !defined(CONTEXT_FULL) && !defined(RC_INVOKED) +#error You need to define a CONTEXT for your CPU +#endif + +typedef CONTEXT *PCONTEXT; +typedef HANDLE *PHANDLE; + +#ifdef __WINE__ + +/* Macros for easier access to i386 context registers */ + +#define EAX_reg(context) ((context)->Eax) +#define EBX_reg(context) ((context)->Ebx) +#define ECX_reg(context) ((context)->Ecx) +#define EDX_reg(context) ((context)->Edx) +#define ESI_reg(context) ((context)->Esi) +#define EDI_reg(context) ((context)->Edi) +#define EBP_reg(context) ((context)->Ebp) + +#define CS_reg(context) ((context)->SegCs) +#define DS_reg(context) ((context)->SegDs) +#define ES_reg(context) ((context)->SegEs) +#define FS_reg(context) ((context)->SegFs) +#define GS_reg(context) ((context)->SegGs) +#define SS_reg(context) ((context)->SegSs) + +#define EFL_reg(context) ((context)->EFlags) +#define EIP_reg(context) ((context)->Eip) +#define ESP_reg(context) ((context)->Esp) + +#define AX_reg(context) (*(WORD*)&EAX_reg(context)) +#define BX_reg(context) (*(WORD*)&EBX_reg(context)) +#define CX_reg(context) (*(WORD*)&ECX_reg(context)) +#define DX_reg(context) (*(WORD*)&EDX_reg(context)) +#define SI_reg(context) (*(WORD*)&ESI_reg(context)) +#define DI_reg(context) (*(WORD*)&EDI_reg(context)) +#define BP_reg(context) (*(WORD*)&EBP_reg(context)) + +#define AL_reg(context) (*(BYTE*)&EAX_reg(context)) +#define AH_reg(context) (*((BYTE*)&EAX_reg(context)+1)) +#define BL_reg(context) (*(BYTE*)&EBX_reg(context)) +#define BH_reg(context) (*((BYTE*)&EBX_reg(context)+1)) +#define CL_reg(context) (*(BYTE*)&ECX_reg(context)) +#define CH_reg(context) (*((BYTE*)&ECX_reg(context)+1)) +#define DL_reg(context) (*(BYTE*)&EDX_reg(context)) +#define DH_reg(context) (*((BYTE*)&EDX_reg(context)+1)) + +#define SET_CFLAG(context) (EFL_reg(context) |= 0x0001) +#define RESET_CFLAG(context) (EFL_reg(context) &= ~0x0001) +#define SET_ZFLAG(context) (EFL_reg(context) |= 0x0040) +#define RESET_ZFLAG(context) (EFL_reg(context) &= ~0x0040) + +#define ISV86(context) (EFL_reg(context) & 0x00020000) +#define V86BASE(context) ((context)->Dr7) /* ugly */ + + +/* Macros to retrieve the current context */ + +#ifdef __i386__ + +#ifdef NEED_UNDERSCORE_PREFIX +# define __ASM_NAME(name) "_" name +#else +# define __ASM_NAME(name) name +#endif + +#ifdef __GNUC__ +# define __ASM_GLOBAL_FUNC(name,code) \ + __asm__( ".align 4\n\t" \ + ".globl " __ASM_NAME(#name) "\n\t" \ + ".type " __ASM_NAME(#name) ",@function\n" \ + __ASM_NAME(#name) ":\n\t" \ + code ); +#else /* __GNUC__ */ +# define __ASM_GLOBAL_FUNC(name,code) \ + void __asm_dummy_##name(void) { \ + asm( ".align 4\n\t" \ + ".globl " __ASM_NAME(#name) "\n\t" \ + ".type " __ASM_NAME(#name) ",@function\n" \ + __ASM_NAME(#name) ":\n\t" \ + code ); \ + } +#endif /* __GNUC__ */ + +#define _DEFINE_REGS_ENTRYPOINT( name, fn, args ) \ + __ASM_GLOBAL_FUNC( name, \ + "call " __ASM_NAME("CALL32_Regs") "\n\t" \ + ".long " __ASM_NAME(#fn) "\n\t" \ + ".byte " #args ", " #args ) +#define DEFINE_REGS_ENTRYPOINT_0( name, fn ) \ + _DEFINE_REGS_ENTRYPOINT( name, fn, 0 ) +#define DEFINE_REGS_ENTRYPOINT_1( name, fn, t1 ) \ + _DEFINE_REGS_ENTRYPOINT( name, fn, 4 ) +#define DEFINE_REGS_ENTRYPOINT_2( name, fn, t1, t2 ) \ + _DEFINE_REGS_ENTRYPOINT( name, fn, 8 ) +#define DEFINE_REGS_ENTRYPOINT_3( name, fn, t1, t2, t3 ) \ + _DEFINE_REGS_ENTRYPOINT( name, fn, 12 ) +#define DEFINE_REGS_ENTRYPOINT_4( name, fn, t1, t2, t3, t4 ) \ + _DEFINE_REGS_ENTRYPOINT( name, fn, 16 ) + +#endif /* __i386__ */ + +#ifdef __sparc__ +/* FIXME: use getcontext() to retrieve full context */ +#define _GET_CONTEXT \ + CONTEXT context; \ + do { memset(&context, 0, sizeof(CONTEXT)); \ + context.ContextFlags = CONTEXT_CONTROL; \ + context.pc = (DWORD)__builtin_return_address(0); \ + } while (0) + +#define DEFINE_REGS_ENTRYPOINT_0( name, fn ) \ + void WINAPI name ( void ) \ + { _GET_CONTEXT; fn( &context ); } +#define DEFINE_REGS_ENTRYPOINT_1( name, fn, t1 ) \ + void WINAPI name ( t1 a1 ) \ + { _GET_CONTEXT; fn( a1, &context ); } +#define DEFINE_REGS_ENTRYPOINT_2( name, fn, t1, t2 ) \ + void WINAPI name ( t1 a1, t2 a2 ) \ + { _GET_CONTEXT; fn( a1, a2, &context ); } +#define DEFINE_REGS_ENTRYPOINT_3( name, fn, t1, t2, t3 ) \ + void WINAPI name ( t1 a1, t2 a2, t3 a3 ) \ + { _GET_CONTEXT; fn( a1, a2, a3, &context ); } +#define DEFINE_REGS_ENTRYPOINT_4( name, fn, t1, t2, t3, t4 ) \ + void WINAPI name ( t1 a1, t2 a2, t3 a3, t4 a4 ) \ + { _GET_CONTEXT; fn( a1, a2, a3, a4, &context ); } + +#endif /* __sparc__ */ + +#ifndef DEFINE_REGS_ENTRYPOINT_0 +#error You need to define DEFINE_REGS_ENTRYPOINT macros for your CPU +#endif + +#ifdef __i386__ +# define GET_IP(context) ((LPVOID)(context)->Eip) +#endif +#ifdef __sparc__ +# define GET_IP(context) ((LPVOID)(context)->pc) +#endif + +#if !defined(GET_IP) && !defined(RC_INVOKED) +# error You must define GET_IP for this CPU +#endif + +#endif /* __WINE__ */ + +/* + * Exception codes + */ + +#define STATUS_SUCCESS 0x00000000 +#define STATUS_WAIT_0 0x00000000 +#define STATUS_ABANDONED_WAIT_0 0x00000080 +#define STATUS_USER_APC 0x000000C0 +#define STATUS_TIMEOUT 0x00000102 +#define STATUS_PENDING 0x00000103 + +#define STATUS_GUARD_PAGE_VIOLATION 0x80000001 +#define STATUS_DATATYPE_MISALIGNMENT 0x80000002 +#define STATUS_BREAKPOINT 0x80000003 +#define STATUS_SINGLE_STEP 0x80000004 +#define STATUS_BUFFER_OVERFLOW 0x80000005 +#define STATUS_NO_MORE_FILES 0x80000006 +#define STATUS_WAKE_SYSTEM_DEBUGGER 0x80000007 + +#define STATUS_HANDLES_CLOSED 0x8000000A +#define STATUS_NO_INHERITANCE 0x8000000B +#define STATUS_GUID_SUBSTITUTION_MADE 0x8000000C +#define STATUS_PARTIAL_COPY 0x8000000D +#define STATUS_DEVICE_PAPER_EMPTY 0x8000000E +#define STATUS_DEVICE_POWERED_OFF 0x8000000F +#define STATUS_DEVICE_OFF_LINE 0x80000010 +#define STATUS_DEVICE_BUSY 0x80000011 +#define STATUS_NO_MORE_EAS 0x80000012 +#define STATUS_INVALID_EA_NAME 0x80000013 +#define STATUS_EA_LIST_INCONSISTENT 0x80000014 +#define STATUS_INVALID_EA_FLAG 0x80000015 +#define STATUS_VERIFY_REQUIRED 0x80000016 +#define STATUS_EXTRANEOUS_INFORMATION 0x80000017 +#define STATUS_RXACT_COMMIT_NECESSARY 0x80000018 +#define STATUS_NO_MORE_ENTRIES 0x8000001A +#define STATUS_FILEMARK_DETECTED 0x8000001B +#define STATUS_MEDIA_CHANGED 0x8000001C +#define STATUS_BUS_RESET 0x8000001D +#define STATUS_END_OF_MEDIA 0x8000001E +#define STATUS_BEGINNING_OF_MEDIA 0x8000001F +#define STATUS_MEDIA_CHECK 0x80000020 +#define STATUS_SETMARK_DETECTED 0x80000021 +#define STATUS_NO_DATA_DETECTED 0x80000022 +#define STATUS_REDIRECTOR_HAS_OPEN_HANDLES 0x80000023 +#define STATUS_SERVER_HAS_OPEN_HANDLES 0x80000024 +#define STATUS_ALREADY_DISCONNECTED 0x80000025 +#define STATUS_LONGJUMP 0x80000026 + +#define STATUS_UNSUCCESSFUL 0xC0000001 +#define STATUS_NOT_IMPLEMENTED 0xC0000002 +#define STATUS_INVALID_INFO_CLASS 0xC0000003 +#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 +#define STATUS_ACCESS_VIOLATION 0xC0000005 +#define STATUS_IN_PAGE_ERROR 0xC0000006 +#define STATUS_PAGEFILE_QUOTA 0xC0000007 +#define STATUS_INVALID_HANDLE 0xC0000008 +#define STATUS_BAD_INITIAL_STACK 0xC0000009 +#define STATUS_BAD_INITIAL_PC 0xC000000A +#define STATUS_INVALID_CID 0xC000000B +#define STATUS_TIMER_NOT_CANCELED 0xC000000C +#define STATUS_INVALID_PARAMETER 0xC000000D +#define STATUS_NO_SUCH_DEVICE 0xC000000E +#define STATUS_NO_SUCH_FILE 0xC000000F +#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define STATUS_END_OF_FILE 0xC0000011 +#define STATUS_WRONG_VOLUME 0xC0000012 +#define STATUS_NO_MEDIA_IN_DEVICE 0xC0000013 +#define STATUS_UNRECOGNIZED_MEDIA 0xC0000014 +#define STATUS_NONEXISTENT_SECTOR 0xC0000015 +#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 +#define STATUS_NO_MEMORY 0xC0000017 +#define STATUS_CONFLICTING_ADDRESSES 0xC0000018 +#define STATUS_NOT_MAPPED_VIEW 0xC0000019 +#define STATUS_UNABLE_TO_FREE_VM 0xC000001A +#define STATUS_UNABLE_TO_DELETE_SECTION 0xC000001B +#define STATUS_INVALID_SYSTEM_SERVICE 0xC000001C +#define STATUS_ILLEGAL_INSTRUCTION 0xC000001D +#define STATUS_INVALID_LOCK_SEQUENCE 0xC000001E +#define STATUS_INVALID_VIEW_SIZE 0xC000001F +#define STATUS_INVALID_FILE_FOR_SECTION 0xC0000020 +#define STATUS_ALREADY_COMMITTED 0xC0000021 +#define STATUS_ACCESS_DENIED 0xC0000022 +#define STATUS_BUFFER_TOO_SMALL 0xC0000023 +#define STATUS_OBJECT_TYPE_MISMATCH 0xC0000024 +#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025 +#define STATUS_INVALID_DISPOSITION 0xC0000026 +#define STATUS_UNWIND 0xC0000027 +#define STATUS_BAD_STACK 0xC0000028 +#define STATUS_INVALID_UNWIND_TARGET 0xC0000029 +#define STATUS_NOT_LOCKED 0xC000002A +#define STATUS_PARITY_ERROR 0xC000002B +#define STATUS_UNABLE_TO_DECOMMIT_VM 0xC000002C +#define STATUS_NOT_COMMITTED 0xC000002D +#define STATUS_INVALID_PORT_ATTRIBUTES 0xC000002E +#define STATUS_PORT_MESSAGE_TOO_LONG 0xC000002F +#define STATUS_INVALID_PARAMETER_MIX 0xC0000030 +#define STATUS_INVALID_QUOTA_LOWER 0xC0000031 +#define STATUS_DISK_CORRUPT_ERROR 0xC0000032 +#define STATUS_OBJECT_NAME_INVALID 0xC0000033 +#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 +#define STATUS_OBJECT_NAME_COLLISION 0xC0000035 +#define STATUS_PORT_DISCONNECTED 0xC0000037 +#define STATUS_DEVICE_ALREADY_ATTACHED 0xC0000038 +#define STATUS_OBJECT_PATH_INVALID 0xC0000039 +#define STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A +#define STATUS_PATH_SYNTAX_BAD 0xC000003B +#define STATUS_DATA_OVERRUN 0xC000003C +#define STATUS_DATA_LATE_ERROR 0xC000003D +#define STATUS_DATA_ERROR 0xC000003E +#define STATUS_CRC_ERROR 0xC000003F +#define STATUS_SECTION_TOO_BIG 0xC0000040 +#define STATUS_PORT_CONNECTION_REFUSED 0xC0000041 +#define STATUS_INVALID_PORT_HANDLE 0xC0000042 +#define STATUS_SHARING_VIOLATION 0xC0000043 +#define STATUS_QUOTA_EXCEEDED 0xC0000044 +#define STATUS_INVALID_PAGE_PROTECTION 0xC0000045 +#define STATUS_MUTANT_NOT_OWNED 0xC0000046 +#define STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000047 +#define STATUS_PORT_ALREADY_SET 0xC0000048 +#define STATUS_SUSPEND_COUNT_EXCEEDED 0xC000004A +#define STATUS_LOCK_NOT_GRANTED 0xC0000054 /* FIXME: not sure */ +#define STATUS_FILE_LOCK_CONFLICT 0xC0000055 /* FIXME: not sure */ +#define STATUS_UNKNOWN_REVISION 0xC0000058 +#define STATUS_INVALID_SECURITY_DESCR 0xC0000079 +#define STATUS_DISK_FULL 0xC000007F +#define STATUS_SECTION_NOT_EXTENDED 0xC0000087 +#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C +#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D +#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E +#define STATUS_FLOAT_INEXACT_RESULT 0xC000008F +#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090 +#define STATUS_FLOAT_OVERFLOW 0xC0000091 +#define STATUS_FLOAT_STACK_CHECK 0xC0000092 +#define STATUS_FLOAT_UNDERFLOW 0xC0000093 +#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094 +#define STATUS_INTEGER_OVERFLOW 0xC0000095 +#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096 +#define STATUS_MEDIA_WRITE_PROTECTED 0XC00000A2 +#define STATUS_INVALID_PARAMETER_2 0xC00000F0 +#define STATUS_STACK_OVERFLOW 0xC00000FD +#define STATUS_DIRECTORY_NOT_EMPTY 0xC0000101 +#define STATUS_TOO_MANY_OPENED_FILES 0xC000011F +#define STATUS_CONTROL_C_EXIT 0xC000013A +#define STATUS_PIPE_BROKEN 0xC000014B +#define STATUS_NOT_REGISTRY_FILE 0xC000015C +#define STATUS_PARTITION_FAILURE 0xC0000172 +#define STATUS_INVALID_BLOCK_LENGTH 0xC0000173 +#define STATUS_DEVICE_NOT_PARTITIONED 0xC0000174 +#define STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000175 +#define STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000176 +#define STATUS_EOM_OVERFLOW 0xC0000177 +#define STATUS_NO_MEDIA 0xC0000178 +#define STATUS_NO_SUCH_MEMBER 0xC000017A +#define STATUS_INVALID_MEMBER 0xC000017B +#define STATUS_KEY_DELETED 0xC000017C +#define STATUS_NO_LOG_SPACE 0xC000017D +#define STATUS_TOO_MANY_SIDS 0xC000017E +#define STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC000017F +#define STATUS_KEY_HAS_CHILDREN 0xC0000180 +#define STATUS_CHILD_MUST_BE_VOLATILE 0xC0000181 +#define STATUS_DEVICE_CONFIGURATION_ERROR0xC0000182 +#define STATUS_DRIVER_INTERNAL_ERROR 0xC0000183 +#define STATUS_INVALID_DEVICE_STATE 0xC0000184 +#define STATUS_IO_DEVICE_ERROR 0xC0000185 +#define STATUS_DEVICE_PROTOCOL_ERROR 0xC0000186 +#define STATUS_BACKUP_CONTROLLER 0xC0000187 +#define STATUS_LOG_FILE_FULL 0xC0000188 +#define STATUS_TOO_LATE 0xC0000189 +#define STATUS_NO_TRUST_LSA_SECRET 0xC000018A +#define STATUS_NO_TRUST_SAM_ACCOUNT 0xC000018B +#define STATUS_TRUSTED_DOMAIN_FAILURE 0xC000018C +#define STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC000018D +#define STATUS_EVENTLOG_FILE_CORRUPT 0xC000018E +#define STATUS_EVENTLOG_CANT_START 0xC000018F +#define STATUS_TRUST_FAILURE 0xC0000190 +#define STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000191 +#define STATUS_NETLOGON_NOT_STARTED 0xC0000192 +#define STATUS_ACCOUNT_EXPIRED 0xC0000193 +#define STATUS_POSSIBLE_DEADLOCK 0xC0000194 +#define STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000195 +#define STATUS_REMOTE_SESSION_LIMIT 0xC0000196 +#define STATUS_EVENTLOG_FILE_CHANGED 0xC0000197 +#define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000198 +#define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000199 +#define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC000019A +#define STATUS_DOMAIN_TRUST_INCONSISTENT 0xC000019B +#define STATUS_FS_DRIVER_REQUIRED 0xC000019C + +#define STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000204 + +#define MAXIMUM_WAIT_OBJECTS 64 +#define MAXIMUM_SUSPEND_COUNT 127 + + +/* + * Return values from the actual exception handlers + */ + +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +/* + * Return values from filters in except() and from UnhandledExceptionFilter + */ + +#define EXCEPTION_EXECUTE_HANDLER 1 +#define EXCEPTION_CONTINUE_SEARCH 0 +#define EXCEPTION_CONTINUE_EXECUTION -1 + +/* + * From OS/2 2.0 exception handling + * Win32 seems to use the same flags as ExceptionFlags in an EXCEPTION_RECORD + */ + +#define EH_NONCONTINUABLE 0x01 +#define EH_UNWINDING 0x02 +#define EH_EXIT_UNWIND 0x04 +#define EH_STACK_INVALID 0x08 +#define EH_NESTED_CALL 0x10 + +#define EXCEPTION_CONTINUABLE 0 +#define EXCEPTION_NONCONTINUABLE EH_NONCONTINUABLE + +/* + * The exception record used by Win32 to give additional information + * about exception to exception handlers. + */ + +#define EXCEPTION_MAXIMUM_PARAMETERS 15 + +typedef struct __EXCEPTION_RECORD +{ + DWORD ExceptionCode; + DWORD ExceptionFlags; + struct __EXCEPTION_RECORD *ExceptionRecord; + + LPVOID ExceptionAddress; + DWORD NumberParameters; + DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; +} EXCEPTION_RECORD, *PEXCEPTION_RECORD; + +/* + * The exception pointers structure passed to exception filters + * in except() and the UnhandledExceptionFilter(). + */ + +typedef struct _EXCEPTION_POINTERS +{ + PEXCEPTION_RECORD ExceptionRecord; + PCONTEXT ContextRecord; +} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS; + + +/* + * The exception frame, used for registering exception handlers + * Win32 cares only about this, but compilers generally emit + * larger exception frames for their own use. + */ + +struct __EXCEPTION_FRAME; + +typedef DWORD (*PEXCEPTION_HANDLER)(PEXCEPTION_RECORD,struct __EXCEPTION_FRAME*, + PCONTEXT,struct __EXCEPTION_FRAME **); + +typedef struct __EXCEPTION_FRAME +{ + struct __EXCEPTION_FRAME *Prev; + PEXCEPTION_HANDLER Handler; +} EXCEPTION_FRAME, *PEXCEPTION_FRAME; + +#include "poppack.h" + +/* + * function pointer to a exception filter + */ + +typedef LONG CALLBACK (*PTOP_LEVEL_EXCEPTION_FILTER)(PEXCEPTION_POINTERS ExceptionInfo); +typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; + +DWORD WINAPI UnhandledExceptionFilter( PEXCEPTION_POINTERS epointers ); +LPTOP_LEVEL_EXCEPTION_FILTER +WINAPI SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER filter ); + +/* status values for ContinueDebugEvent */ +#define DBG_CONTINUE 0x00010002 +#define DBG_TERMINATE_THREAD 0x40010003 +#define DBG_TERMINATE_PROCESS 0x40010004 +#define DBG_CONTROL_C 0x40010005 +#define DBG_CONTROL_BREAK 0x40010008 +#define DBG_EXCEPTION_NOT_HANDLED 0x80010001 + +typedef struct _NT_TIB +{ + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union { + PVOID FiberData; + DWORD Version; + } DUMMYUNIONNAME; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; +} NT_TIB, *PNT_TIB; + +struct _TEB; +/* +#if defined(__i386__) && defined(__GNUC__) +extern inline struct _TEB * WINAPI NtCurrentTeb(void); +extern inline struct _TEB * WINAPI NtCurrentTeb(void) +{ + struct _TEB *teb; + __asm__(".byte 0x64\n\tmovl (0x18),%0" : "=r" (teb)); + return teb; +} +#else +extern struct _TEB * WINAPI NtCurrentTeb(void); +#endif +*/ + +/* + * File formats definitions + */ + +typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; /* 00: MZ Header signature */ + WORD e_cblp; /* 02: Bytes on last page of file */ + WORD e_cp; /* 04: Pages in file */ + WORD e_crlc; /* 06: Relocations */ + WORD e_cparhdr; /* 08: Size of header in paragraphs */ + WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ + WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ + WORD e_ss; /* 0e: Initial (relative) SS value */ + WORD e_sp; /* 10: Initial SP value */ + WORD e_csum; /* 12: Checksum */ + WORD e_ip; /* 14: Initial IP value */ + WORD e_cs; /* 16: Initial (relative) CS value */ + WORD e_lfarlc; /* 18: File address of relocation table */ + WORD e_ovno; /* 1a: Overlay number */ + WORD e_res[4]; /* 1c: Reserved words */ + WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ + WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ + WORD e_res2[10]; /* 28: Reserved words */ + DWORD e_lfanew; /* 3c: Offset to extended header */ +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +/* + * This is the Windows executable (NE) header. + * the name IMAGE_OS2_HEADER is misleading, but in the SDK this way. + */ +typedef struct +{ + WORD ne_magic; /* 00 NE signature 'NE' */ + BYTE ne_ver; /* 02 Linker version number */ + BYTE ne_rev; /* 03 Linker revision number */ + WORD ne_enttab; /* 04 Offset to entry table relative to NE */ + WORD ne_cbenttab; /* 06 Length of entry table in bytes */ + LONG ne_crc; /* 08 Checksum */ + WORD ne_flags; /* 0c Flags about segments in this file */ + WORD ne_autodata; /* 0e Automatic data segment number */ + WORD ne_heap; /* 10 Initial size of local heap */ + WORD ne_stack; /* 12 Initial size of stack */ + DWORD ne_csip; /* 14 Initial CS:IP */ + DWORD ne_sssp; /* 18 Initial SS:SP */ + WORD ne_cseg; /* 1c # of entries in segment table */ + WORD ne_cmod; /* 1e # of entries in module reference tab. */ + WORD ne_cbnrestab; /* 20 Length of nonresident-name table */ + WORD ne_segtab; /* 22 Offset to segment table */ + WORD ne_rsrctab; /* 24 Offset to resource table */ + WORD ne_restab; /* 26 Offset to resident-name table */ + WORD ne_modtab; /* 28 Offset to module reference table */ + WORD ne_imptab; /* 2a Offset to imported name table */ + DWORD ne_nrestab; /* 2c Offset to nonresident-name table */ + WORD ne_cmovent; /* 30 # of movable entry points */ + WORD ne_align; /* 32 Logical sector alignment shift count */ + WORD ne_cres; /* 34 # of resource segments */ + BYTE ne_exetyp; /* 36 Flags indicating target OS */ + BYTE ne_flagsothers; /* 37 Additional information flags */ + WORD fastload_offset; /* 38 Offset to fast load area (should be ne_pretthunks)*/ + WORD fastload_length; /* 3a Length of fast load area (should be ne_psegrefbytes) */ + WORD ne_swaparea; /* 3c Reserved by Microsoft */ + WORD ne_expver; /* 3e Expected Windows version number */ +} IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; + +typedef struct _IMAGE_VXD_HEADER { + WORD e32_magic; + BYTE e32_border; + BYTE e32_worder; + DWORD e32_level; + WORD e32_cpu; + WORD e32_os; + DWORD e32_ver; + DWORD e32_mflags; + DWORD e32_mpages; + DWORD e32_startobj; + DWORD e32_eip; + DWORD e32_stackobj; + DWORD e32_esp; + DWORD e32_pagesize; + DWORD e32_lastpagesize; + DWORD e32_fixupsize; + DWORD e32_fixupsum; + DWORD e32_ldrsize; + DWORD e32_ldrsum; + DWORD e32_objtab; + DWORD e32_objcnt; + DWORD e32_objmap; + DWORD e32_itermap; + DWORD e32_rsrctab; + DWORD e32_rsrccnt; + DWORD e32_restab; + DWORD e32_enttab; + DWORD e32_dirtab; + DWORD e32_dircnt; + DWORD e32_fpagetab; + DWORD e32_frectab; + DWORD e32_impmod; + DWORD e32_impmodcnt; + DWORD e32_impproc; + DWORD e32_pagesum; + DWORD e32_datapage; + DWORD e32_preload; + DWORD e32_nrestab; + DWORD e32_cbnrestab; + DWORD e32_nressum; + DWORD e32_autodata; + DWORD e32_debuginfo; + DWORD e32_debuglen; + DWORD e32_instpreload; + DWORD e32_instdemand; + DWORD e32_heapsize; + BYTE e32_res3[12]; + DWORD e32_winresoff; + DWORD e32_winreslen; + WORD e32_devid; + WORD e32_ddkver; +} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER; + + +/* These defines describe the meanings of the bits in the Characteristics + field */ + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/* These are the settings of the Machine field. */ +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I860 0x14d +#define IMAGE_FILE_MACHINE_I386 0x14c +#define IMAGE_FILE_MACHINE_R3000 0x162 +#define IMAGE_FILE_MACHINE_R4000 0x166 +#define IMAGE_FILE_MACHINE_R10000 0x168 +#define IMAGE_FILE_MACHINE_ALPHA 0x184 +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +/* Possible Magic values */ +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +/* These are indexes into the DataDirectory array */ +#define IMAGE_FILE_EXPORT_DIRECTORY 0 +#define IMAGE_FILE_IMPORT_DIRECTORY 1 +#define IMAGE_FILE_RESOURCE_DIRECTORY 2 +#define IMAGE_FILE_EXCEPTION_DIRECTORY 3 +#define IMAGE_FILE_SECURITY_DIRECTORY 4 +#define IMAGE_FILE_BASE_RELOCATION_TABLE 5 +#define IMAGE_FILE_DEBUG_DIRECTORY 6 +#define IMAGE_FILE_DESCRIPTION_STRING 7 +#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */ +#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9 +#define IMAGE_FILE_CALLBACK_DIRECTORY 10 + +/* Directory Entries, indices into the DataDirectory array */ + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +/* Subsystem Values */ + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */ +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem*/ +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct _IMAGE_OPTIONAL_HEADER { + + /* Standard fields */ + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + /* NT additional fields */ + + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_FIRST_SECTION(ntheader) \ + ((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +/* These defines are for the Characteristics bitfield. */ +/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */ +/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */ +/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */ +/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */ +/* #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - Reserved */ +/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */ +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 + +/* 0x00002000 - Reserved */ +/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ +#define IMAGE_SCN_MEM_FARDATA 0x00008000 + +/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */ +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +/* 0x00800000 - Unused */ + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 + + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#include "pshpack2.h" + +typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; + DWORD Long; + } Name; + DWORD LongName[2]; + } N; + DWORD Value; + SHORT SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; +} IMAGE_SYMBOL; +typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; + +#define IMAGE_SIZEOF_SYMBOL 18 + +typedef struct _IMAGE_LINENUMBER { + union { + DWORD SymbolTableIndex; + DWORD VirtualAddress; + } Type; + WORD Linenumber; +} IMAGE_LINENUMBER; +typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +typedef union _IMAGE_AUX_SYMBOL { + struct { + DWORD TagIndex; + union { + struct { + WORD Linenumber; + WORD Size; + } LnSz; + DWORD TotalSize; + } Misc; + union { + struct { + DWORD PointerToLinenumber; + DWORD PointerToNextFunction; + } Function; + struct { + WORD Dimension[4]; + } Array; + } FcnAry; + WORD TvIndex; + } Sym; + struct { + BYTE Name[IMAGE_SIZEOF_SYMBOL]; + } File; + struct { + DWORD Length; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD CheckSum; + SHORT Number; + BYTE Selection; + } Section; +} IMAGE_AUX_SYMBOL; +typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; + +#define IMAGE_SIZEOF_AUX_SYMBOL 18 + +#include "poppack.h" + +#define IMAGE_SYM_UNDEFINED (SHORT)0 +#define IMAGE_SYM_ABSOLUTE (SHORT)-1 +#define IMAGE_SYM_DEBUG (SHORT)-2 + +#define IMAGE_SYM_TYPE_NULL 0x0000 +#define IMAGE_SYM_TYPE_VOID 0x0001 +#define IMAGE_SYM_TYPE_CHAR 0x0002 +#define IMAGE_SYM_TYPE_SHORT 0x0003 +#define IMAGE_SYM_TYPE_INT 0x0004 +#define IMAGE_SYM_TYPE_LONG 0x0005 +#define IMAGE_SYM_TYPE_FLOAT 0x0006 +#define IMAGE_SYM_TYPE_DOUBLE 0x0007 +#define IMAGE_SYM_TYPE_STRUCT 0x0008 +#define IMAGE_SYM_TYPE_UNION 0x0009 +#define IMAGE_SYM_TYPE_ENUM 0x000A +#define IMAGE_SYM_TYPE_MOE 0x000B +#define IMAGE_SYM_TYPE_BYTE 0x000C +#define IMAGE_SYM_TYPE_WORD 0x000D +#define IMAGE_SYM_TYPE_UINT 0x000E +#define IMAGE_SYM_TYPE_DWORD 0x000F +#define IMAGE_SYM_TYPE_PCODE 0x8000 + +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 1 +#define IMAGE_SYM_DTYPE_FUNCTION 2 +#define IMAGE_SYM_DTYPE_ARRAY 3 + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 + +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 + +#define N_BTMASK 0x000F +#define N_TMASK 0x0030 +#define N_TMASK1 0x00C0 +#define N_TMASK2 0x00F0 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +#define BTYPE(x) ((x) & N_BTMASK) + +#ifndef ISPTR +#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) +#endif + +#ifndef ISFCN +#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) +#endif + +#ifndef ISARY +#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) +#endif + +#ifndef ISTAG +#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) +#endif + +#ifndef INCREF +#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) +#endif + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 +#define IMAGE_COMDAT_SELECT_LARGEST 6 +#define IMAGE_COMDAT_SELECT_NEWEST 7 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/* Export module directory */ + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + LPDWORD *AddressOfFunctions; + LPDWORD *AddressOfNames; + LPWORD *AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + +/* Import name entry */ +typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; +} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; + +/* Import thunk */ +typedef struct _IMAGE_THUNK_DATA { + union { + LPBYTE ForwarderString; + FARPROC Function; + DWORD Ordinal; + PIMAGE_IMPORT_BY_NAME AddressOfData; + } u1; +} IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA; + +/* Import module directory */ + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; /* 0 for terminating null import descriptor */ + PIMAGE_THUNK_DATA OriginalFirstThunk; /* RVA to original unbound IAT */ + } u; + DWORD TimeDateStamp; /* 0 if not bound, + * -1 if bound, and real date\time stamp + * in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT + * (new BIND) + * otherwise date/time stamp of DLL bound to + * (Old BIND) + */ + DWORD ForwarderChain; /* -1 if no forwarders */ + DWORD Name; + /* RVA to IAT (if bound this IAT has actual addresses) */ + PIMAGE_THUNK_DATA FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR +{ + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD NumberOfModuleForwarderRefs; +/* Array of zero or more IMAGE_BOUND_FORWARDER_REF follows */ +} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR; + +typedef struct _IMAGE_BOUND_FORWARDER_REF +{ + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD Reserved; +} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF; + +typedef struct _IMAGE_BASE_RELOCATION +{ + DWORD VirtualAddress; + DWORD SizeOfBlock; + WORD TypeOffset[1]; +} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; + +typedef struct _IMAGE_RELOCATION +{ + union { + DWORD VirtualAddress; + DWORD RelocCount; + } u; + DWORD SymbolTableIndex; + WORD Type; +} IMAGE_RELOCATION; +typedef IMAGE_RELOCATION *PIMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +/* generic relocation types */ +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_SECTION 6 +#define IMAGE_REL_BASED_REL 7 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ +#define IMAGE_REL_BASED_DIR64 10 +#define IMAGE_REL_BASED_HIGH3ADJ 11 + +/* I386 relocation types */ +#define IMAGE_REL_I386_ABSOLUTE 0 +#define IMAGE_REL_I386_DIR16 1 +#define IMAGE_REL_I386_REL16 2 +#define IMAGE_REL_I386_DIR32 6 +#define IMAGE_REL_I386_DIR32NB 7 +#define IMAGE_REL_I386_SEG12 9 +#define IMAGE_REL_I386_SECTION 10 +#define IMAGE_REL_I386_SECREL 11 +#define IMAGE_REL_I386_REL32 20 + +/* MIPS relocation types */ +#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 +#define IMAGE_REL_MIPS_REFHALF 0x0001 +#define IMAGE_REL_MIPS_REFWORD 0x0002 +#define IMAGE_REL_MIPS_JMPADDR 0x0003 +#define IMAGE_REL_MIPS_REFHI 0x0004 +#define IMAGE_REL_MIPS_REFLO 0x0005 +#define IMAGE_REL_MIPS_GPREL 0x0006 +#define IMAGE_REL_MIPS_LITERAL 0x0007 +#define IMAGE_REL_MIPS_SECTION 0x000A +#define IMAGE_REL_MIPS_SECREL 0x000B +#define IMAGE_REL_MIPS_SECRELLO 0x000C +#define IMAGE_REL_MIPS_SECRELHI 0x000D +#define IMAGE_REL_MIPS_JMPADDR16 0x0010 +#define IMAGE_REL_MIPS_REFWORDNB 0x0022 +#define IMAGE_REL_MIPS_PAIR 0x0025 + +/* ALPHA relocation types */ +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 +#define IMAGE_REL_ALPHA_REFLONG 0x0001 +#define IMAGE_REL_ALPHA_REFQUAD 0x0002 +#define IMAGE_REL_ALPHA_GPREL 0x0003 +#define IMAGE_REL_ALPHA_LITERAL 0x0004 +#define IMAGE_REL_ALPHA_LITUSE 0x0005 +#define IMAGE_REL_ALPHA_GPDISP 0x0006 +#define IMAGE_REL_ALPHA_BRADDR 0x0007 +#define IMAGE_REL_ALPHA_HINT 0x0008 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 +#define IMAGE_REL_ALPHA_REFHI 0x000A +#define IMAGE_REL_ALPHA_REFLO 0x000B +#define IMAGE_REL_ALPHA_PAIR 0x000C +#define IMAGE_REL_ALPHA_MATCH 0x000D +#define IMAGE_REL_ALPHA_SECTION 0x000E +#define IMAGE_REL_ALPHA_SECREL 0x000F +#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 +#define IMAGE_REL_ALPHA_SECRELLO 0x0011 +#define IMAGE_REL_ALPHA_SECRELHI 0x0012 +#define IMAGE_REL_ALPHA_REFQ3 0x0013 +#define IMAGE_REL_ALPHA_REFQ2 0x0014 +#define IMAGE_REL_ALPHA_REFQ1 0x0015 +#define IMAGE_REL_ALPHA_GPRELLO 0x0016 +#define IMAGE_REL_ALPHA_GPRELHI 0x0017 + +/* PowerPC relocation types */ +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 +#define IMAGE_REL_PPC_ADDR64 0x0001 +#define IMAGE_REL_PPC_ADDR 0x0002 +#define IMAGE_REL_PPC_ADDR24 0x0003 +#define IMAGE_REL_PPC_ADDR16 0x0004 +#define IMAGE_REL_PPC_ADDR14 0x0005 +#define IMAGE_REL_PPC_REL24 0x0006 +#define IMAGE_REL_PPC_REL14 0x0007 +#define IMAGE_REL_PPC_TOCREL16 0x0008 +#define IMAGE_REL_PPC_TOCREL14 0x0009 +#define IMAGE_REL_PPC_ADDR32NB 0x000A +#define IMAGE_REL_PPC_SECREL 0x000B +#define IMAGE_REL_PPC_SECTION 0x000C +#define IMAGE_REL_PPC_IFGLUE 0x000D +#define IMAGE_REL_PPC_IMGLUE 0x000E +#define IMAGE_REL_PPC_SECREL16 0x000F +#define IMAGE_REL_PPC_REFHI 0x0010 +#define IMAGE_REL_PPC_REFLO 0x0011 +#define IMAGE_REL_PPC_PAIR 0x0012 +#define IMAGE_REL_PPC_SECRELLO 0x0013 +#define IMAGE_REL_PPC_SECRELHI 0x0014 +#define IMAGE_REL_PPC_GPREL 0x0015 +#define IMAGE_REL_PPC_TYPEMASK 0x00FF +/* modifier bits */ +#define IMAGE_REL_PPC_NEG 0x0100 +#define IMAGE_REL_PPC_BRTAKEN 0x0200 +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 +#define IMAGE_REL_PPC_TOCDEFN 0x0800 + +/* SH3 ? relocation type */ +#define IMAGE_REL_SH3_ABSOLUTE 0x0000 +#define IMAGE_REL_SH3_DIRECT16 0x0001 +#define IMAGE_REL_SH3_DIRECT 0x0002 +#define IMAGE_REL_SH3_DIRECT8 0x0003 +#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 +#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 +#define IMAGE_REL_SH3_DIRECT4 0x0006 +#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 +#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 +#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 +#define IMAGE_REL_SH3_PCREL8_LONG 0x000A +#define IMAGE_REL_SH3_PCREL12_WORD 0x000B +#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C +#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D +#define IMAGE_REL_SH3_SECTION 0x000E +#define IMAGE_REL_SH3_SECREL 0x000F +#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 + +/* ARM (Archimedes?) relocation types */ +#define IMAGE_REL_ARM_ABSOLUTE 0x0000 +#define IMAGE_REL_ARM_ADDR 0x0001 +#define IMAGE_REL_ARM_ADDR32NB 0x0002 +#define IMAGE_REL_ARM_BRANCH24 0x0003 +#define IMAGE_REL_ARM_BRANCH11 0x0004 +#define IMAGE_REL_ARM_SECTION 0x000E +#define IMAGE_REL_ARM_SECREL 0x000F + +/* IA64 relocation types */ +#define IMAGE_REL_IA64_ABSOLUTE 0x0000 +#define IMAGE_REL_IA64_IMM14 0x0001 +#define IMAGE_REL_IA64_IMM22 0x0002 +#define IMAGE_REL_IA64_IMM64 0x0003 +#define IMAGE_REL_IA64_DIR 0x0004 +#define IMAGE_REL_IA64_DIR64 0x0005 +#define IMAGE_REL_IA64_PCREL21B 0x0006 +#define IMAGE_REL_IA64_PCREL21M 0x0007 +#define IMAGE_REL_IA64_PCREL21F 0x0008 +#define IMAGE_REL_IA64_GPREL22 0x0009 +#define IMAGE_REL_IA64_LTOFF22 0x000A +#define IMAGE_REL_IA64_SECTION 0x000B +#define IMAGE_REL_IA64_SECREL22 0x000C +#define IMAGE_REL_IA64_SECREL64I 0x000D +#define IMAGE_REL_IA64_SECREL 0x000E +#define IMAGE_REL_IA64_LTOFF64 0x000F +#define IMAGE_REL_IA64_DIR32NB 0x0010 +#define IMAGE_REL_IA64_RESERVED_11 0x0011 +#define IMAGE_REL_IA64_RESERVED_12 0x0012 +#define IMAGE_REL_IA64_RESERVED_13 0x0013 +#define IMAGE_REL_IA64_RESERVED_14 0x0014 +#define IMAGE_REL_IA64_RESERVED_15 0x0015 +#define IMAGE_REL_IA64_RESERVED_16 0x0016 +#define IMAGE_REL_IA64_ADDEND 0x001F + +/* archive format */ + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER +{ + BYTE Name[16]; + BYTE Date[12]; + BYTE UserID[6]; + BYTE GroupID[6]; + BYTE Mode[8]; + BYTE Size[10]; + BYTE EndHeader[2]; +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +/* + * Resource directory stuff + */ +typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; + /* IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; */ +} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + +typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + union { + struct { + unsigned NameOffset:31; + unsigned NameIsString:1; + } s; + DWORD Name; + WORD Id; + } u1; + union { + DWORD OffsetToData; + struct { + unsigned OffsetToDirectory:31; + unsigned DataIsDirectory:1; + } s; + } u2; +} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + +typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { + WORD Length; + CHAR NameString[ 1 ]; +} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; + +typedef struct _IMAGE_RESOURCE_DIR_STRING_U { + WORD Length; + WCHAR NameString[ 1 ]; +} IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; + +typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + DWORD OffsetToData; + DWORD Size; + DWORD CodePage; + DWORD ResourceHandle; +} IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; + + +typedef VOID CALLBACK (*PIMAGE_TLS_CALLBACK)( + LPVOID DllHandle,DWORD Reason,LPVOID Reserved +); + +typedef struct _IMAGE_TLS_DIRECTORY { + DWORD StartAddressOfRawData; + DWORD EndAddressOfRawData; + LPDWORD AddressOfIndex; + PIMAGE_TLS_CALLBACK *AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; +} IMAGE_TLS_DIRECTORY,*PIMAGE_TLS_DIRECTORY; + +typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; +} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; + +#define IMAGE_DEBUG_TYPE_UNKNOWN 0 +#define IMAGE_DEBUG_TYPE_COFF 1 +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 +#define IMAGE_DEBUG_TYPE_FPO 3 +#define IMAGE_DEBUG_TYPE_MISC 4 +#define IMAGE_DEBUG_TYPE_EXCEPTION 5 +#define IMAGE_DEBUG_TYPE_FIXUP 6 +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 +#define IMAGE_DEBUG_TYPE_BORLAND 9 +#define IMAGE_DEBUG_TYPE_RESERVED10 10 + +typedef struct _IMAGE_COFF_SYMBOLS_HEADER { + DWORD NumberOfSymbols; + DWORD LvaToFirstSymbol; + DWORD NumberOfLinenumbers; + DWORD LvaToFirstLinenumber; + DWORD RvaToFirstByteOfCode; + DWORD RvaToLastByteOfCode; + DWORD RvaToFirstByteOfData; + DWORD RvaToLastByteOfData; +} IMAGE_COFF_SYMBOLS_HEADER, *PIMAGE_COFF_SYMBOLS_HEADER; + +#define FRAME_FPO 0 +#define FRAME_TRAP 1 +#define FRAME_TSS 2 +#define FRAME_NONFPO 3 + +typedef struct _FPO_DATA { + DWORD ulOffStart; + DWORD cbProcSize; + DWORD cdwLocals; + WORD cdwParams; + unsigned cbProlog : 8; + unsigned cbRegs : 3; + unsigned fHasSEH : 1; + unsigned fUseBP : 1; + unsigned reserved : 1; + unsigned cbFrame : 2; +} FPO_DATA, *PFPO_DATA; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + PVOID LockPrefixTable; + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD Reserved1; + PVOID EditList; + DWORD Reserved[1]; +} IMAGE_LOAD_CONFIG_DIRECTORY, *PIMAGE_LOAD_CONFIG_DIRECTORY; + +typedef struct _IMAGE_FUNCTION_ENTRY { + DWORD StartingAddress; + DWORD EndingAddress; + DWORD EndOfPrologue; +} IMAGE_FUNCTION_ENTRY, *PIMAGE_FUNCTION_ENTRY; + +/* This is the structure that appears at the very start of a .DBG file. */ + +typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { + WORD Signature; + WORD Flags; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + DWORD NumberOfSections; + DWORD ExportedNamesSize; + DWORD DebugDirectorySize; + DWORD SectionAlignment; + DWORD Reserved[ 2 ]; +} IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; + +#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 + + +typedef struct tagMESSAGE_RESOURCE_ENTRY { + WORD Length; + WORD Flags; + BYTE Text[1]; +} MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; +#define MESSAGE_RESOURCE_UNICODE 0x0001 + +typedef struct tagMESSAGE_RESOURCE_BLOCK { + DWORD LowId; + DWORD HighId; + DWORD OffsetToEntries; +} MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; + +typedef struct tagMESSAGE_RESOURCE_DATA { + DWORD NumberOfBlocks; + MESSAGE_RESOURCE_BLOCK Blocks[ 1 ]; +} MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; + +/* + * Here follows typedefs for security and tokens. + */ + +/* + * First a constant for the following typdefs. + */ + +#define ANYSIZE_ARRAY 1 + +/* FIXME: Orphan. What does it point to? */ +typedef PVOID PACCESS_TOKEN; + +/* + * TOKEN_INFORMATION_CLASS + */ + +typedef enum _TOKEN_INFORMATION_CLASS { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics +} TOKEN_INFORMATION_CLASS; + +#ifndef _SECURITY_DEFINED +#define _SECURITY_DEFINED + +#include "pshpack1.h" + +typedef DWORD ACCESS_MASK, *PACCESS_MASK; + +typedef struct _GENERIC_MAPPING { + ACCESS_MASK GenericRead; + ACCESS_MASK GenericWrite; + ACCESS_MASK GenericExecute; + ACCESS_MASK GenericAll; +} GENERIC_MAPPING, *PGENERIC_MAPPING; + +#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED +#define SID_IDENTIFIER_AUTHORITY_DEFINED +typedef struct { + BYTE Value[6]; +} SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY,*LPSID_IDENTIFIER_AUTHORITY; +#endif /* !defined(SID_IDENTIFIER_AUTHORITY_DEFINED) */ + +#ifndef SID_DEFINED +#define SID_DEFINED +typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[1]; +} SID,*PSID; +#endif /* !defined(SID_DEFINED) */ + +#define SID_REVISION (1) /* Current revision */ +#define SID_MAX_SUB_AUTHORITIES (15) /* current max subauths */ +#define SID_RECOMMENDED_SUB_AUTHORITIES (1) /* recommended subauths */ + + +/* + * ACL + */ + +#define ACL_REVISION1 1 +#define ACL_REVISION2 2 +#define ACL_REVISION3 3 +#define ACL_REVISION4 4 + +#define MIN_ACL_REVISION ACL_REVISION2 +#define MAX_ACL_REVISION ACL_REVISION4 + +typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; +} ACL, *PACL; + +/* SECURITY_DESCRIPTOR */ +#define SECURITY_DESCRIPTOR_REVISION 1 +#define SECURITY_DESCRIPTOR_REVISION1 1 + + +#define SE_OWNER_DEFAULTED 0x0001 +#define SE_GROUP_DEFAULTED 0x0002 +#define SE_DACL_PRESENT 0x0004 +#define SE_DACL_DEFAULTED 0x0008 +#define SE_SACL_PRESENT 0x0010 +#define SE_SACL_DEFAULTED 0x0020 +#define SE_SELF_RELATIVE 0x8000 + +typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION; +typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL; + +/* The security descriptor structure */ +typedef struct { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + DWORD Owner; + DWORD Group; + DWORD Sacl; + DWORD Dacl; +} SECURITY_DESCRIPTOR_RELATIVE, *PISECURITY_DESCRIPTOR_RELATIVE; + +typedef struct { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; +} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR; + +#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) + +#include "poppack.h" + +#endif /* _SECURITY_DEFINED */ + +#include "pshpack1.h" + +/* + * SID_AND_ATTRIBUTES + */ + +typedef struct _SID_AND_ATTRIBUTES { + PSID Sid; + DWORD Attributes; +} SID_AND_ATTRIBUTES ; + +/* security entities */ +#define SECURITY_NULL_RID (0x00000000L) +#define SECURITY_WORLD_RID (0x00000000L) +#define SECURITY_LOCAL_RID (0X00000000L) + +#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} + +/* S-1-1 */ +#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} + +/* S-1-2 */ +#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} + +/* S-1-3 */ +#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} +#define SECURITY_CREATOR_OWNER_RID (0x00000000L) +#define SECURITY_CREATOR_GROUP_RID (0x00000001L) +#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) +#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) + +/* S-1-4 */ +#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} + +/* S-1-5 */ +#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} +#define SECURITY_DIALUP_RID 0x00000001L +#define SECURITY_NETWORK_RID 0x00000002L +#define SECURITY_BATCH_RID 0x00000003L +#define SECURITY_INTERACTIVE_RID 0x00000004L +#define SECURITY_LOGON_IDS_RID 0x00000005L +#define SECURITY_SERVICE_RID 0x00000006L +#define SECURITY_ANONYMOUS_LOGON_RID 0x00000007L +#define SECURITY_PROXY_RID 0x00000008L +#define SECURITY_ENTERPRISE_CONTROLLERS_RID 0x00000009L +#define SECURITY_PRINCIPAL_SELF_RID 0x0000000AL +#define SECURITY_AUTHENTICATED_USER_RID 0x0000000BL +#define SECURITY_RESTRICTED_CODE_RID 0x0000000CL +#define SECURITY_TERMINAL_SERVER_RID 0x0000000DL +#define SECURITY_LOCAL_SYSTEM_RID 0x00000012L +#define SECURITY_NT_NON_UNIQUE 0x00000015L +#define SECURITY_BUILTIN_DOMAIN_RID 0x00000020L + +#define DOMAIN_GROUP_RID_ADMINS 0x00000200L +#define DOMAIN_GROUP_RID_USERS 0x00000201L +#define DOMAIN_GROUP_RID_GUESTS 0x00000202L + +#define DOMAIN_ALIAS_RID_ADMINS 0x00000220L +#define DOMAIN_ALIAS_RID_USERS 0x00000221L +#define DOMAIN_ALIAS_RID_GUESTS 0x00000222L + +#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID + +#define SECURITY_LOGON_IDS_RID_COUNT (3L) + +/* + * TOKEN_USER + */ + +typedef struct _TOKEN_USER { + SID_AND_ATTRIBUTES User; +} TOKEN_USER; + +/* + * TOKEN_GROUPS + */ + +typedef struct _TOKEN_GROUPS { + DWORD GroupCount; + SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; +} TOKEN_GROUPS; + +/* + * LUID_AND_ATTRIBUTES + */ + +typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + } DUMMYSTRUCTNAME; + LONGLONG QuadPart; +} LARGE_INTEGER, *LPLARGE_INTEGER, *PLARGE_INTEGER; + +typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + } DUMMYSTRUCTNAME; + LONGLONG QuadPart; +} ULARGE_INTEGER, *LPULARGE_INTEGER, *PULARGE_INTEGER; + +/* + * Locally Unique Identifier + */ + +typedef LARGE_INTEGER LUID,*PLUID; + +typedef struct _LUID_AND_ATTRIBUTES { + LUID Luid; + DWORD Attributes; +} LUID_AND_ATTRIBUTES; + +/* + * PRIVILEGE_SET + */ + +typedef struct _PRIVILEGE_SET { + DWORD PrivilegeCount; + DWORD Control; + LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; +} PRIVILEGE_SET, *PPRIVILEGE_SET; + +/* + * TOKEN_PRIVILEGES + */ + +typedef struct _TOKEN_PRIVILEGES { + DWORD PrivilegeCount; + LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; +} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES; + +/* + * TOKEN_OWNER + */ + +typedef struct _TOKEN_OWNER { + PSID Owner; +} TOKEN_OWNER; + +/* + * TOKEN_PRIMARY_GROUP + */ + +typedef struct _TOKEN_PRIMARY_GROUP { + PSID PrimaryGroup; +} TOKEN_PRIMARY_GROUP; + + +/* + * TOKEN_DEFAULT_DACL + */ + +typedef struct _TOKEN_DEFAULT_DACL { + PACL DefaultDacl; +} TOKEN_DEFAULT_DACL; + +/* + * TOKEN_SOURCEL + */ + +typedef struct _TOKEN_SOURCE { + char Sourcename[8]; + LUID SourceIdentifier; +} TOKEN_SOURCE; + +/* + * TOKEN_TYPE + */ + +typedef enum tagTOKEN_TYPE { + TokenPrimary = 1, + TokenImpersonation +} TOKEN_TYPE; + +/* + * SECURITY_IMPERSONATION_LEVEL + */ + +typedef enum _SECURITY_IMPERSONATION_LEVEL { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation +} SECURITY_IMPERSONATION_LEVEL, *PSECURITY_IMPERSONATION_LEVEL; + + +typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE, + * PSECURITY_CONTEXT_TRACKING_MODE; +/* + * Quality of Service + */ + +typedef struct _SECURITY_QUALITY_OF_SERVICE { + DWORD Length; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; + WIN_BOOL EffectiveOnly; +} SECURITY_QUALITY_OF_SERVICE, *PSECURITY_QUALITY_OF_SERVICE; + +/* + * TOKEN_STATISTICS + */ + +typedef struct _TOKEN_STATISTICS { + LUID TokenId; + LUID AuthenticationId; + LARGE_INTEGER ExpirationTime; + TOKEN_TYPE TokenType; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + DWORD DynamicCharged; + DWORD DynamicAvailable; + DWORD GroupCount; + DWORD PrivilegeCount; + LUID ModifiedId; +} TOKEN_STATISTICS; + +/* + * ACLs of NT + */ + +#define ACL_REVISION 2 + +#define ACL_REVISION1 1 +#define ACL_REVISION2 2 + +/* ACEs, directly starting after an ACL */ +typedef struct _ACE_HEADER { + BYTE AceType; + BYTE AceFlags; + WORD AceSize; +} ACE_HEADER,*PACE_HEADER; + +/* AceType */ +#define ACCESS_ALLOWED_ACE_TYPE 0 +#define ACCESS_DENIED_ACE_TYPE 1 +#define SYSTEM_AUDIT_ACE_TYPE 2 +#define SYSTEM_ALARM_ACE_TYPE 3 + +/* inherit AceFlags */ +#define OBJECT_INHERIT_ACE 0x01 +#define CONTAINER_INHERIT_ACE 0x02 +#define NO_PROPAGATE_INHERIT_ACE 0x04 +#define INHERIT_ONLY_ACE 0x08 +#define VALID_INHERIT_FLAGS 0x0F + +/* AceFlags mask for what events we (should) audit */ +#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40 +#define FAILED_ACCESS_ACE_FLAG 0x80 + +/* different ACEs depending on AceType + * SidStart marks the begin of a SID + * so the thing finally looks like this: + * 0: ACE_HEADER + * 4: ACCESS_MASK + * 8... : SID + */ +typedef struct _ACCESS_ALLOWED_ACE { + ACE_HEADER Header; + DWORD Mask; + DWORD SidStart; +} ACCESS_ALLOWED_ACE,*PACCESS_ALLOWED_ACE; + +typedef struct _ACCESS_DENIED_ACE { + ACE_HEADER Header; + DWORD Mask; + DWORD SidStart; +} ACCESS_DENIED_ACE,*PACCESS_DENIED_ACE; + +typedef struct _SYSTEM_AUDIT_ACE { + ACE_HEADER Header; + DWORD Mask; + DWORD SidStart; +} SYSTEM_AUDIT_ACE,*PSYSTEM_AUDIT_ACE; + +typedef struct _SYSTEM_ALARM_ACE { + ACE_HEADER Header; + DWORD Mask; + DWORD SidStart; +} SYSTEM_ALARM_ACE,*PSYSTEM_ALARM_ACE; + +typedef enum tagSID_NAME_USE { + SidTypeUser = 1, + SidTypeGroup, + SidTypeDomain, + SidTypeAlias, + SidTypeWellKnownGroup, + SidTypeDeletedAccount, + SidTypeInvalid, + SidTypeUnknown +} SID_NAME_USE,*PSID_NAME_USE; + +/* Access rights */ + +#define DELETE 0x00010000 +#define READ_CONTROL 0x00020000 +#define WRITE_DAC 0x00040000 +#define WRITE_OWNER 0x00080000 +#define SYNCHRONIZE 0x00100000 +#define STANDARD_RIGHTS_REQUIRED 0x000f0000 + +#define STANDARD_RIGHTS_READ READ_CONTROL +#define STANDARD_RIGHTS_WRITE READ_CONTROL +#define STANDARD_RIGHTS_EXECUTE READ_CONTROL + +#define STANDARD_RIGHTS_ALL 0x001f0000 + +#define SPECIFIC_RIGHTS_ALL 0x0000ffff + +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 + +#define MAXIMUM_ALLOWED 0x02000000 +#define ACCESS_SYSTEM_SECURITY 0x01000000 + +#define EVENT_MODIFY_STATE 0x0002 +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define SEMAPHORE_MODIFY_STATE 0x0002 +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define MUTEX_MODIFY_STATE 0x0001 +#define MUTEX_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1) + +#define PROCESS_TERMINATE 0x0001 +#define PROCESS_CREATE_THREAD 0x0002 +#define PROCESS_VM_OPERATION 0x0008 +#define PROCESS_VM_READ 0x0010 +#define PROCESS_VM_WRITE 0x0020 +#define PROCESS_DUP_HANDLE 0x0040 +#define PROCESS_CREATE_PROCESS 0x0080 +#define PROCESS_SET_QUOTA 0x0100 +#define PROCESS_SET_INFORMATION 0x0200 +#define PROCESS_QUERY_INFORMATION 0x0400 +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xfff) + +#define THREAD_TERMINATE 0x0001 +#define THREAD_SUSPEND_RESUME 0x0002 +#define THREAD_GET_CONTEXT 0x0008 +#define THREAD_SET_CONTEXT 0x0010 +#define THREAD_SET_INFORMATION 0x0020 +#define THREAD_QUERY_INFORMATION 0x0040 +#define THREAD_SET_THREAD_TOKEN 0x0080 +#define THREAD_IMPERSONATE 0x0100 +#define THREAD_DIRECT_IMPERSONATION 0x0200 +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff) + +#define THREAD_BASE_PRIORITY_LOWRT 15 +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_BASE_PRIORITY_MIN -2 +#define THREAD_BASE_PRIORITY_IDLE -15 + +#define FILE_READ_DATA 0x0001 /* file & pipe */ +#define FILE_LIST_DIRECTORY 0x0001 /* directory */ +#define FILE_WRITE_DATA 0x0002 /* file & pipe */ +#define FILE_ADD_FILE 0x0002 /* directory */ +#define FILE_APPEND_DATA 0x0004 /* file */ +#define FILE_ADD_SUBDIRECTORY 0x0004 /* directory */ +#define FILE_CREATE_PIPE_INSTANCE 0x0004 /* named pipe */ +#define FILE_READ_EA 0x0008 /* file & directory */ +#define FILE_READ_PROPERTIES FILE_READ_EA +#define FILE_WRITE_EA 0x0010 /* file & directory */ +#define FILE_WRITE_PROPERTIES FILE_WRITE_EA +#define FILE_EXECUTE 0x0020 /* file */ +#define FILE_TRAVERSE 0x0020 /* directory */ +#define FILE_DELETE_CHILD 0x0040 /* directory */ +#define FILE_READ_ATTRIBUTES 0x0080 /* all */ +#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | \ + FILE_READ_ATTRIBUTES | FILE_READ_EA | \ + SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | \ + FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | \ + FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_EXECUTE | \ + FILE_READ_ATTRIBUTES | SYNCHRONIZE) + + +/* File attribute flags + */ +#define FILE_SHARE_READ 0x00000001L +#define FILE_SHARE_WRITE 0x00000002L +#define FILE_SHARE_DELETE 0x00000004L +#define FILE_ATTRIBUTE_READONLY 0x00000001L +#define FILE_ATTRIBUTE_HIDDEN 0x00000002L +#define FILE_ATTRIBUTE_SYSTEM 0x00000004L +#define FILE_ATTRIBUTE_LABEL 0x00000008L /* Not in Windows API */ +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010L +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020L +#define FILE_ATTRIBUTE_NORMAL 0x00000080L +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100L +#define FILE_ATTRIBUTE_ATOMIC_WRITE 0x00000200L +#define FILE_ATTRIBUTE_XACTION_WRITE 0x00000400L +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800L +#define FILE_ATTRIBUTE_OFFLINE 0x00001000L + +/* File alignments (NT) */ +#define FILE_BYTE_ALIGNMENT 0x00000000 +#define FILE_WORD_ALIGNMENT 0x00000001 +#define FILE_LONG_ALIGNMENT 0x00000003 +#define FILE_QUAD_ALIGNMENT 0x00000007 +#define FILE_OCTA_ALIGNMENT 0x0000000f +#define FILE_32_BYTE_ALIGNMENT 0x0000001f +#define FILE_64_BYTE_ALIGNMENT 0x0000003f +#define FILE_128_BYTE_ALIGNMENT 0x0000007f +#define FILE_256_BYTE_ALIGNMENT 0x000000ff +#define FILE_512_BYTE_ALIGNMENT 0x000001ff + +#define REG_NONE 0 /* no type */ +#define REG_SZ 1 /* string type (ASCII) */ +#define REG_EXPAND_SZ 2 /* string, includes %ENVVAR% (expanded by caller) (ASCII) */ +#define REG_BINARY 3 /* binary format, callerspecific */ +/* YES, REG_DWORD == REG_DWORD_LITTLE_ENDIAN */ +#define REG_DWORD 4 /* DWORD in little endian format */ +#define REG_DWORD_LITTLE_ENDIAN 4 /* DWORD in little endian format */ +#define REG_DWORD_BIG_ENDIAN 5 /* DWORD in big endian format */ +#define REG_LINK 6 /* symbolic link (UNICODE) */ +#define REG_MULTI_SZ 7 /* multiple strings, delimited by \0, terminated by \0\0 (ASCII) */ +#define REG_RESOURCE_LIST 8 /* resource list? huh? */ +#define REG_FULL_RESOURCE_DESCRIPTOR 9 /* full resource descriptor? huh? */ +#define REG_RESOURCE_REQUIREMENTS_LIST 10 + +/* ----------------------------- begin registry ----------------------------- */ + +/* Registry security values */ +#define OWNER_SECURITY_INFORMATION 0x00000001 +#define GROUP_SECURITY_INFORMATION 0x00000002 +#define DACL_SECURITY_INFORMATION 0x00000004 +#define SACL_SECURITY_INFORMATION 0x00000008 + +#define REG_OPTION_RESERVED 0x00000000 +#define REG_OPTION_NON_VOLATILE 0x00000000 +#define REG_OPTION_VOLATILE 0x00000001 +#define REG_OPTION_CREATE_LINK 0x00000002 +#define REG_OPTION_BACKUP_RESTORE 0x00000004 /* FIXME */ +#define REG_OPTION_OPEN_LINK 0x00000008 +#define REG_LEGAL_OPTION (REG_OPTION_RESERVED| \ + REG_OPTION_NON_VOLATILE| \ + REG_OPTION_VOLATILE| \ + REG_OPTION_CREATE_LINK| \ + REG_OPTION_BACKUP_RESTORE| \ + REG_OPTION_OPEN_LINK) + + +#define REG_CREATED_NEW_KEY 0x00000001 +#define REG_OPENED_EXISTING_KEY 0x00000002 + +/* For RegNotifyChangeKeyValue */ +#define REG_NOTIFY_CHANGE_NAME 0x1 + +#define KEY_QUERY_VALUE 0x00000001 +#define KEY_SET_VALUE 0x00000002 +#define KEY_CREATE_SUB_KEY 0x00000004 +#define KEY_ENUMERATE_SUB_KEYS 0x00000008 +#define KEY_NOTIFY 0x00000010 +#define KEY_CREATE_LINK 0x00000020 + +#define KEY_READ ((STANDARD_RIGHTS_READ| \ + KEY_QUERY_VALUE| \ + KEY_ENUMERATE_SUB_KEYS| \ + KEY_NOTIFY) \ + & (~SYNCHRONIZE) \ + ) +#define KEY_WRITE ((STANDARD_RIGHTS_WRITE| \ + KEY_SET_VALUE| \ + KEY_CREATE_SUB_KEY) \ + & (~SYNCHRONIZE) \ + ) +#define KEY_EXECUTE ((KEY_READ) \ + & (~SYNCHRONIZE)) \ + ) +#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL| \ + KEY_QUERY_VALUE| \ + KEY_SET_VALUE| \ + KEY_CREATE_SUB_KEY| \ + KEY_ENUMERATE_SUB_KEYS| \ + KEY_NOTIFY| \ + KEY_CREATE_LINK) \ + & (~SYNCHRONIZE) \ + ) +/* ------------------------------ end registry ------------------------------ */ + + +#define RtlEqualMemory(Destination, Source, Length) (!memcmp((Destination),(Source),(Length))) +#define RtlMoveMemory(Destination, Source, Length) memmove((Destination),(Source),(Length)) +#define RtlCopyMemory(Destination, Source, Length) memcpy((Destination),(Source),(Length)) +#define RtlFillMemory(Destination, Length, Fill) memset((Destination),(Fill),(Length)) +#define RtlZeroMemory(Destination, Length) memset((Destination),0,(Length)) + +#include "poppack.h" + +#endif /* __WINE_WINNT_H */ diff --git a/linphone/win32acm/wine/winreg.h b/linphone/win32acm/wine/winreg.h new file mode 100644 index 000000000..8c290b58f --- /dev/null +++ b/linphone/win32acm/wine/winreg.h @@ -0,0 +1,57 @@ +/* + * Win32 registry defines (see also winnt.h) + */ +#ifndef __WINE_WINREG_H +#define __WINE_WINREG_H + +#include "winbase.h" +#include "winnt.h" + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +/* +#define SHELL_ERROR_SUCCESS 0L +#define SHELL_ERROR_BADDB 1L +#define SHELL_ERROR_BADKEY 2L +#define SHELL_ERROR_CANTOPEN 3L +#define SHELL_ERROR_CANTREAD 4L +#define SHELL_ERROR_CANTWRITE 5L +#define SHELL_ERROR_OUTOFMEMORY 6L +#define SHELL_ERROR_INVALID_PARAMETER 7L +#define SHELL_ERROR_ACCESS_DENIED 8L +*/ + +#define HKEY_CLASSES_ROOT ((HKEY) 0x80000000) +#define HKEY_CURRENT_USER ((HKEY) 0x80000001) +#define HKEY_LOCAL_MACHINE ((HKEY) 0x80000002) +#define HKEY_USERS ((HKEY) 0x80000003) +#define HKEY_PERFORMANCE_DATA ((HKEY) 0x80000004) +#define HKEY_CURRENT_CONFIG ((HKEY) 0x80000005) +#define HKEY_DYN_DATA ((HKEY) 0x80000006) + +/* + * registry provider structs + */ +typedef struct value_entA +{ LPSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; +} VALENTA, *PVALENTA; + +typedef struct value_entW { + LPWSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; +} VALENTW, *PVALENTW; + +typedef ACCESS_MASK REGSAM; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* __WINE_WINREG_H */ diff --git a/linphone/win32acm/wine/winuser.h b/linphone/win32acm/wine/winuser.h new file mode 100644 index 000000000..d74864ef7 --- /dev/null +++ b/linphone/win32acm/wine/winuser.h @@ -0,0 +1,2929 @@ +#ifndef _WINUSER_ +#define _WINUSER_ + +#ifndef RC_INVOKED +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pshpack1.h" + +/* flags for HIGHCONTRAST dwFlags field */ +#define HCF_HIGHCONTRASTON 0x00000001 +#define HCF_AVAILABLE 0x00000002 +#define HCF_HOTKEYACTIVE 0x00000004 +#define HCF_CONFIRMHOTKEY 0x00000008 +#define HCF_HOTKEYSOUND 0x00000010 +#define HCF_INDICATOR 0x00000020 +#define HCF_HOTKEYAVAILABLE 0x00000040 + +typedef struct tagHIGHCONTRASTA +{ + UINT cbSize; + DWORD dwFlags; + LPSTR lpszDefaultScheme; +} HIGHCONTRASTA, *LPHIGHCONTRASTA; + +typedef struct tagHIGHCONTRASTW +{ + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszDefaultScheme; +} HIGHCONTRASTW, *LPHIGHCONTRASTW; + +DECL_WINELIB_TYPE_AW(HIGHCONTRAST) +DECL_WINELIB_TYPE_AW(LPHIGHCONTRAST) + +typedef struct +{ + UINT message; + UINT paramL; + UINT paramH; + DWORD time; + HWND hwnd; +} EVENTMSG, *LPEVENTMSG; + + + /* Mouse hook structure */ + +typedef struct +{ + POINT pt; + HWND hwnd; + UINT wHitTestCode; + DWORD dwExtraInfo; +} MOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT, *LPMOUSEHOOKSTRUCT; + + + /* Hardware hook structure */ + +typedef struct +{ + HWND hWnd; + UINT wMessage; + WPARAM wParam; + LPARAM lParam; +} HARDWAREHOOKSTRUCT, *LPHARDWAREHOOKSTRUCT; + + + /* Debug hook structure */ + +typedef struct +{ + DWORD idThread; + DWORD idThreadInstaller; + LPARAM lParam; + WPARAM wParam; + INT code; +} DEBUGHOOKINFO, *LPDEBUGHOOKINFO; + +#define HKL_PREV 0 +#define HKL_NEXT 1 + +#define KLF_ACTIVATE 0x00000001 +#define KLF_SUBSTITUTE_OK 0x00000002 +#define KLF_UNLOADPREVIOUS 0x00000004 +#define KLF_REORDER 0x00000008 +#define KLF_REPLACELANG 0x00000010 +#define KLF_NOTELLSHELL 0x00000080 + +#define KL_NAMELENGTH 9 + + /***** Dialogs *****/ +#ifdef FSHIFT +/* Gcc on Solaris has a version of this that we don't care about. */ +#undef FSHIFT +#endif + +#define FVIRTKEY TRUE /* Assumed to be == TRUE */ +#define FNOINVERT 0x02 +#define FSHIFT 0x04 +#define FCONTROL 0x08 +#define FALT 0x10 + + +typedef struct tagANIMATIONINFO +{ + UINT cbSize; + INT iMinAnimate; +} ANIMATIONINFO, *LPANIMATIONINFO; + +typedef struct tagNMHDR +{ + HWND hwndFrom; + UINT idFrom; + UINT code; +} NMHDR, *LPNMHDR; + +typedef struct +{ + UINT cbSize; + INT iTabLength; + INT iLeftMargin; + INT iRightMargin; + UINT uiLengthDrawn; +} DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; + +#define WM_USER 0x0400 + +#define DT_EDITCONTROL 0x00002000 +#define DT_PATH_ELLIPSIS 0x00004000 +#define DT_END_ELLIPSIS 0x00008000 +#define DT_MODIFYSTRING 0x00010000 +#define DT_RTLREADING 0x00020000 +#define DT_WORD_ELLIPSIS 0x00040000 + +typedef struct +{ + LPARAM lParam; + WPARAM16 wParam; + UINT16 message; + HWND16 hwnd; +} CWPSTRUCT16, *LPCWPSTRUCT16; + +typedef struct +{ + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; +} CWPSTRUCT, *LPCWPSTRUCT; + + + +typedef struct +{ + LRESULT lResult; + LPARAM lParam; + WPARAM16 wParam; + DWORD message; + HWND16 hwnd; +} CWPRETSTRUCT16, *LPCWPRETSTRUCT16; + +typedef struct +{ + LRESULT lResult; + LPARAM lParam; + WPARAM wParam; + DWORD message; + HWND hwnd; +} CWPRETSTRUCT, *LPCWPRETSTRUCT; + +typedef struct +{ + UINT length; + UINT flags; + UINT showCmd; + POINT ptMinPosition WINE_PACKED; + POINT ptMaxPosition WINE_PACKED; + RECT rcNormalPosition WINE_PACKED; +} WINDOWPLACEMENT, *LPWINDOWPLACEMENT; + + + /* WINDOWPLACEMENT flags */ +#define WPF_SETMINPOSITION 0x0001 +#define WPF_RESTORETOMAXIMIZED 0x0002 + +/***** Dialogs *****/ + + /* cbWndExtra bytes for dialog class */ +#define DLGWINDOWEXTRA 30 + +/* Button control styles */ +#define BS_PUSHBUTTON 0x00000000L +#define BS_DEFPUSHBUTTON 0x00000001L +#define BS_CHECKBOX 0x00000002L +#define BS_AUTOCHECKBOX 0x00000003L +#define BS_RADIOBUTTON 0x00000004L +#define BS_3STATE 0x00000005L +#define BS_AUTO3STATE 0x00000006L +#define BS_GROUPBOX 0x00000007L +#define BS_USERBUTTON 0x00000008L +#define BS_AUTORADIOBUTTON 0x00000009L +#define BS_OWNERDRAW 0x0000000BL +#define BS_LEFTTEXT 0x00000020L + +#define BS_TEXT 0x00000000L +#define BS_ICON 0x00000040L +#define BS_BITMAP 0x00000080L +#define BS_LEFT 0x00000100L +#define BS_RIGHT 0x00000200L +#define BS_CENTER 0x00000300L +#define BS_TOP 0x00000400L +#define BS_BOTTOM 0x00000800L +#define BS_VCENTER 0x00000C00L +#define BS_PUSHLIKE 0x00001000L +#define BS_MULTILINE 0x00002000L +#define BS_NOTIFY 0x00004000L +#define BS_FLAT 0x00008000L + + /* Dialog styles */ +#define DS_ABSALIGN 0x0001 +#define DS_SYSMODAL 0x0002 +#define DS_3DLOOK 0x0004 /* win95 */ +#define DS_FIXEDSYS 0x0008 /* win95 */ +#define DS_NOFAILCREATE 0x0010 /* win95 */ +#define DS_LOCALEDIT 0x0020 +#define DS_SETFONT 0x0040 +#define DS_MODALFRAME 0x0080 +#define DS_NOIDLEMSG 0x0100 +#define DS_SETFOREGROUND 0x0200 /* win95 */ +#define DS_CONTROL 0x0400 /* win95 */ +#define DS_CENTER 0x0800 /* win95 */ +#define DS_CENTERMOUSE 0x1000 /* win95 */ +#define DS_CONTEXTHELP 0x2000 /* win95 */ + + + /* Dialog messages */ +#define DM_GETDEFID (WM_USER+0) +#define DM_SETDEFID (WM_USER+1) + +#define DC_HASDEFID 0x534b + +/* Owner draw control types */ +#define ODT_MENU 1 +#define ODT_LISTBOX 2 +#define ODT_COMBOBOX 3 +#define ODT_BUTTON 4 +#define ODT_STATIC 5 + +/* Owner draw actions */ +#define ODA_DRAWENTIRE 0x0001 +#define ODA_SELECT 0x0002 +#define ODA_FOCUS 0x0004 + +/* Owner draw state */ +#define ODS_SELECTED 0x0001 +#define ODS_GRAYED 0x0002 +#define ODS_DISABLED 0x0004 +#define ODS_CHECKED 0x0008 +#define ODS_FOCUS 0x0010 +#define ODS_COMBOBOXEDIT 0x1000 +#define ODS_HOTLIGHT 0x0040 +#define ODS_INACTIVE 0x0080 + +/* Edit control styles */ +#define ES_LEFT 0x00000000 +#define ES_CENTER 0x00000001 +#define ES_RIGHT 0x00000002 +#define ES_MULTILINE 0x00000004 +#define ES_UPPERCASE 0x00000008 +#define ES_LOWERCASE 0x00000010 +#define ES_PASSWORD 0x00000020 +#define ES_AUTOVSCROLL 0x00000040 +#define ES_AUTOHSCROLL 0x00000080 +#define ES_NOHIDESEL 0x00000100 +#define ES_OEMCONVERT 0x00000400 +#define ES_READONLY 0x00000800 +#define ES_WANTRETURN 0x00001000 +#define ES_NUMBER 0x00002000 + +/* OEM Resource Ordinal Numbers */ +#define OBM_CLOSED 32731 +#define OBM_RADIOCHECK 32732 +#define OBM_TRTYPE 32733 +#define OBM_LFARROWI 32734 +#define OBM_RGARROWI 32735 +#define OBM_DNARROWI 32736 +#define OBM_UPARROWI 32737 +#define OBM_COMBO 32738 +#define OBM_MNARROW 32739 +#define OBM_LFARROWD 32740 +#define OBM_RGARROWD 32741 +#define OBM_DNARROWD 32742 +#define OBM_UPARROWD 32743 +#define OBM_RESTORED 32744 +#define OBM_ZOOMD 32745 +#define OBM_REDUCED 32746 +#define OBM_RESTORE 32747 +#define OBM_ZOOM 32748 +#define OBM_REDUCE 32749 +#define OBM_LFARROW 32750 +#define OBM_RGARROW 32751 +#define OBM_DNARROW 32752 +#define OBM_UPARROW 32753 +#define OBM_CLOSE 32754 +#define OBM_OLD_RESTORE 32755 +#define OBM_OLD_ZOOM 32756 +#define OBM_OLD_REDUCE 32757 +#define OBM_BTNCORNERS 32758 +#define OBM_CHECKBOXES 32759 +#define OBM_CHECK 32760 +#define OBM_BTSIZE 32761 +#define OBM_OLD_LFARROW 32762 +#define OBM_OLD_RGARROW 32763 +#define OBM_OLD_DNARROW 32764 +#define OBM_OLD_UPARROW 32765 +#define OBM_SIZE 32766 +#define OBM_OLD_CLOSE 32767 + +#define OCR_BUMMER 100 +#define OCR_DRAGOBJECT 101 + +#define OCR_NORMAL 32512 +#define OCR_IBEAM 32513 +#define OCR_WAIT 32514 +#define OCR_CROSS 32515 +#define OCR_UP 32516 +#define OCR_SIZE 32640 +#define OCR_ICON 32641 +#define OCR_SIZENWSE 32642 +#define OCR_SIZENESW 32643 +#define OCR_SIZEWE 32644 +#define OCR_SIZENS 32645 +#define OCR_SIZEALL 32646 +#define OCR_ICOCUR 32647 +#define OCR_NO 32648 +#define OCR_APPSTARTING 32650 +#define OCR_HELP 32651 /* only defined in wine */ + +#define OIC_SAMPLE 32512 +#define OIC_HAND 32513 +#define OIC_QUES 32514 +#define OIC_BANG 32515 +#define OIC_NOTE 32516 +#define OIC_PORTRAIT 32517 +#define OIC_LANDSCAPE 32518 +#define OIC_WINEICON 32519 +#define OIC_FOLDER 32520 +#define OIC_FOLDER2 32521 +#define OIC_FLOPPY 32522 +#define OIC_CDROM 32523 +#define OIC_HDISK 32524 +#define OIC_NETWORK 32525 + +#define COLOR_SCROLLBAR 0 +#define COLOR_BACKGROUND 1 +#define COLOR_ACTIVECAPTION 2 +#define COLOR_INACTIVECAPTION 3 +#define COLOR_MENU 4 +#define COLOR_WINDOW 5 +#define COLOR_WINDOWFRAME 6 +#define COLOR_MENUTEXT 7 +#define COLOR_WINDOWTEXT 8 +#define COLOR_CAPTIONTEXT 9 +#define COLOR_ACTIVEBORDER 10 +#define COLOR_INACTIVEBORDER 11 +#define COLOR_APPWORKSPACE 12 +#define COLOR_HIGHLIGHT 13 +#define COLOR_HIGHLIGHTTEXT 14 +#define COLOR_BTNFACE 15 +#define COLOR_BTNSHADOW 16 +#define COLOR_GRAYTEXT 17 +#define COLOR_BTNTEXT 18 +#define COLOR_INACTIVECAPTIONTEXT 19 +#define COLOR_BTNHIGHLIGHT 20 +/* win95 colors */ +#define COLOR_3DDKSHADOW 21 +#define COLOR_3DLIGHT 22 +#define COLOR_INFOTEXT 23 +#define COLOR_INFOBK 24 +#define COLOR_DESKTOP COLOR_BACKGROUND +#define COLOR_3DFACE COLOR_BTNFACE +#define COLOR_3DSHADOW COLOR_BTNSHADOW +#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT +#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT +#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT +/* win98 colors */ +#define COLOR_ALTERNATEBTNFACE 25 /* undocumented, constant's name unknown */ +#define COLOR_HOTLIGHT 26 +#define COLOR_GRADIENTACTIVECAPTION 27 +#define COLOR_GRADIENTINACTIVECAPTION 28 + + /* WM_CTLCOLOR values */ +#define CTLCOLOR_MSGBOX 0 +#define CTLCOLOR_EDIT 1 +#define CTLCOLOR_LISTBOX 2 +#define CTLCOLOR_BTN 3 +#define CTLCOLOR_DLG 4 +#define CTLCOLOR_SCROLLBAR 5 +#define CTLCOLOR_STATIC 6 + +/* Edit control messages */ +#define EM_GETSEL 0x00b0 +#define EM_SETSEL 0x00b1 +#define EM_GETRECT 0x00b2 +#define EM_SETRECT 0x00b3 +#define EM_SETRECTNP 0x00b4 +#define EM_SCROLL 0x00b5 +#define EM_LINESCROLL 0x00b6 +#define EM_SCROLLCARET 0x00b7 +#define EM_GETMODIFY 0x00b8 +#define EM_SETMODIFY 0x00b9 +#define EM_GETLINECOUNT 0x00ba +#define EM_LINEINDEX 0x00bb +#define EM_SETHANDLE 0x00bc +#define EM_GETHANDLE 0x00bd +#define EM_GETTHUMB 0x00be +/* FIXME : missing from specs 0x00bf and 0x00c0 */ +#define EM_LINELENGTH 0x00c1 +#define EM_REPLACESEL 0x00c2 +/* FIXME : missing from specs 0x00c3 */ +#define EM_GETLINE 0x00c4 +#define EM_LIMITTEXT 0x00c5 +#define EM_CANUNDO 0x00c6 +#define EM_UNDO 0x00c7 +#define EM_FMTLINES 0x00c8 +#define EM_LINEFROMCHAR 0x00c9 +/* FIXME : missing from specs 0x00ca */ +#define EM_SETTABSTOPS 0x00cb +#define EM_SETPASSWORDCHAR 0x00cc +#define EM_EMPTYUNDOBUFFER 0x00cd +#define EM_GETFIRSTVISIBLELINE 0x00ce +#define EM_SETREADONLY 0x00cf +#define EM_SETWORDBREAKPROC 0x00d0 +#define EM_GETWORDBREAKPROC 0x00d1 +#define EM_GETPASSWORDCHAR 0x00d2 +#define EM_SETMARGINS 0x00d3 +#define EM_GETMARGINS 0x00d4 +#define EM_GETLIMITTEXT 0x00d5 +#define EM_POSFROMCHAR 0x00d6 +#define EM_CHARFROMPOS 0x00d7 +/* a name change since win95 */ +#define EM_SETLIMITTEXT EM_LIMITTEXT + +/* EDITWORDBREAKPROC code values */ +#define WB_LEFT 0 +#define WB_RIGHT 1 +#define WB_ISDELIMITER 2 + +/* Edit control notification codes */ +#define EN_SETFOCUS 0x0100 +#define EN_KILLFOCUS 0x0200 +#define EN_CHANGE 0x0300 +#define EN_UPDATE 0x0400 +#define EN_ERRSPACE 0x0500 +#define EN_MAXTEXT 0x0501 +#define EN_HSCROLL 0x0601 +#define EN_VSCROLL 0x0602 + +/* New since win95 : EM_SETMARGIN parameters */ +#define EC_LEFTMARGIN 0x0001 +#define EC_RIGHTMARGIN 0x0002 +#define EC_USEFONTINFO 0xffff + + +/* Messages */ + + /* WM_GETDLGCODE values */ + + +#define WM_NULL 0x0000 +#define WM_CREATE 0x0001 +#define WM_DESTROY 0x0002 +#define WM_MOVE 0x0003 +#define WM_SIZEWAIT 0x0004 +#define WM_SIZE 0x0005 +#define WM_ACTIVATE 0x0006 +#define WM_SETFOCUS 0x0007 +#define WM_KILLFOCUS 0x0008 +#define WM_SETVISIBLE 0x0009 +#define WM_ENABLE 0x000a +#define WM_SETREDRAW 0x000b +#define WM_SETTEXT 0x000c +#define WM_GETTEXT 0x000d +#define WM_GETTEXTLENGTH 0x000e +#define WM_PAINT 0x000f +#define WM_CLOSE 0x0010 +#define WM_QUERYENDSESSION 0x0011 +#define WM_QUIT 0x0012 +#define WM_QUERYOPEN 0x0013 +#define WM_ERASEBKGND 0x0014 +#define WM_SYSCOLORCHANGE 0x0015 +#define WM_ENDSESSION 0x0016 +#define WM_SYSTEMERROR 0x0017 +#define WM_SHOWWINDOW 0x0018 +#define WM_CTLCOLOR 0x0019 +#define WM_WININICHANGE 0x001a +#define WM_SETTINGCHANGE WM_WININICHANGE +#define WM_DEVMODECHANGE 0x001b +#define WM_ACTIVATEAPP 0x001c +#define WM_FONTCHANGE 0x001d +#define WM_TIMECHANGE 0x001e +#define WM_CANCELMODE 0x001f +#define WM_SETCURSOR 0x0020 +#define WM_MOUSEACTIVATE 0x0021 +#define WM_CHILDACTIVATE 0x0022 +#define WM_QUEUESYNC 0x0023 +#define WM_GETMINMAXINFO 0x0024 + +#define WM_PAINTICON 0x0026 +#define WM_ICONERASEBKGND 0x0027 +#define WM_NEXTDLGCTL 0x0028 +#define WM_ALTTABACTIVE 0x0029 +#define WM_SPOOLERSTATUS 0x002a +#define WM_DRAWITEM 0x002b +#define WM_MEASUREITEM 0x002c +#define WM_DELETEITEM 0x002d +#define WM_VKEYTOITEM 0x002e +#define WM_CHARTOITEM 0x002f +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_SETHOTKEY 0x0032 +#define WM_GETHOTKEY 0x0033 +#define WM_FILESYSCHANGE 0x0034 +#define WM_ISACTIVEICON 0x0035 +#define WM_QUERYPARKICON 0x0036 +#define WM_QUERYDRAGICON 0x0037 +#define WM_QUERYSAVESTATE 0x0038 +#define WM_COMPAREITEM 0x0039 +#define WM_TESTING 0x003a + +#define WM_OTHERWINDOWCREATED 0x003c +#define WM_OTHERWINDOWDESTROYED 0x003d +#define WM_ACTIVATESHELLWINDOW 0x003e + +#define WM_COMPACTING 0x0041 + +#define WM_COMMNOTIFY 0x0044 +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 +#define WM_POWER 0x0048 + + /* Win32 4.0 messages */ +#define WM_COPYDATA 0x004a +#define WM_CANCELJOURNAL 0x004b +#define WM_NOTIFY 0x004e +#define WM_HELP 0x0053 +#define WM_NOTIFYFORMAT 0x0055 + +#define WM_CONTEXTMENU 0x007b +#define WM_STYLECHANGING 0x007c +#define WM_STYLECHANGED 0x007d +#define WM_DISPLAYCHANGE 0x007e +#define WM_GETICON 0x007f +#define WM_SETICON 0x0080 + + /* Non-client system messages */ +#define WM_NCCREATE 0x0081 +#define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 +#define WM_NCHITTEST 0x0084 +#define WM_NCPAINT 0x0085 +#define WM_NCACTIVATE 0x0086 + +#define WM_GETDLGCODE 0x0087 +#define WM_SYNCPAINT 0x0088 +#define WM_SYNCTASK 0x0089 + + /* Non-client mouse messages */ +#define WM_NCMOUSEMOVE 0x00a0 +#define WM_NCLBUTTONDOWN 0x00a1 +#define WM_NCLBUTTONUP 0x00a2 +#define WM_NCLBUTTONDBLCLK 0x00a3 +#define WM_NCRBUTTONDOWN 0x00a4 +#define WM_NCRBUTTONUP 0x00a5 +#define WM_NCRBUTTONDBLCLK 0x00a6 +#define WM_NCMBUTTONDOWN 0x00a7 +#define WM_NCMBUTTONUP 0x00a8 +#define WM_NCMBUTTONDBLCLK 0x00a9 + + /* Keyboard messages */ +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_KEYFIRST WM_KEYDOWN +#define WM_KEYLAST 0x0108 + +/* Win32 4.0 messages for IME */ +#define WM_IME_STARTCOMPOSITION 0x010d +#define WM_IME_ENDCOMPOSITION 0x010e +#define WM_IME_COMPOSITION 0x010f +#define WM_IME_KEYLAST 0x010f + +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 +#define WM_SYSTIMER 0x0118 + + /* scroll messages */ +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 + +/* Menu messages */ +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 + +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 + +#define WM_LBTRACKPOINT 0x0131 + + /* Win32 CTLCOLOR messages */ +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 + + /* Mouse messages */ +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_MOUSEFIRST WM_MOUSEMOVE + + +#define WM_MOUSELAST WM_MOUSEWHEEL + +#define WHEEL_DELTA 120 +#define WHEEL_PAGESCROLL (UINT_MAX) +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 +#define WM_NEXTMENU 0x0213 + + /* Win32 4.0 messages */ +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 + + /* MDI messages */ +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 +#define WM_MDIREFRESHMENU 0x0234 + + /* D&D messages */ +#define WM_DROPOBJECT 0x022A +#define WM_QUERYDROPOBJECT 0x022B +#define WM_BEGINDRAG 0x022C +#define WM_DRAGLOOP 0x022D +#define WM_DRAGSELECT 0x022E +#define WM_DRAGMOVE 0x022F +#define WM_MDISETMENU 0x0230 + +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 + + +/* Win32 4.0 messages for IME */ +#define WM_IME_SETCONTEXT 0x0281 +#define WM_IME_NOTIFY 0x0282 +#define WM_IME_CONTROL 0x0283 +#define WM_IME_COMPOSITIONFULL 0x0284 +#define WM_IME_SELECT 0x0285 +#define WM_IME_CHAR 0x0286 +/* Win32 5.0 messages for IME */ +#define WM_IME_REQUEST 0x0288 + +/* Win32 4.0 messages for IME */ +#define WM_IME_KEYDOWN 0x0290 +#define WM_IME_KEYUP 0x0291 + +/* Clipboard command messages */ +#define WM_CUT 0x0300 +#define WM_COPY 0x0301 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 + +/* Clipboard owner messages */ +#define WM_RENDERFORMAT 0x0305 +#define WM_RENDERALLFORMATS 0x0306 +#define WM_DESTROYCLIPBOARD 0x0307 + +/* Clipboard viewer messages */ +#define WM_DRAWCLIPBOARD 0x0308 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_VSCROLLCLIPBOARD 0x030A +#define WM_SIZECLIPBOARD 0x030B +#define WM_ASKCBFORMATNAME 0x030C +#define WM_CHANGECBCHAIN 0x030D +#define WM_HSCROLLCLIPBOARD 0x030E + +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTEISCHANGING 0x0310 +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 + +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 + + /* FIXME: This does not belong to any libwine interface header */ + /* MFC messages [360-38f] */ + +#define WM_QUERYAFXWNDPROC 0x0360 +#define WM_SIZEPARENT 0x0361 +#define WM_SETMESSAGESTRING 0x0362 +#define WM_IDLEUPDATECMDUI 0x0363 +#define WM_INITIALUPDATE 0x0364 +#define WM_COMMANDHELP 0x0365 +#define WM_HELPHITTEST 0x0366 +#define WM_EXITHELPMODE 0x0367 +#define WM_RECALCPARENT 0x0368 +#define WM_SIZECHILD 0x0369 +#define WM_KICKIDLE 0x036A +#define WM_QUERYCENTERWND 0x036B +#define WM_DISABLEMODAL 0x036C +#define WM_FLOATSTATUS 0x036D +#define WM_ACTIVATETOPLEVEL 0x036E +#define WM_QUERY3DCONTROLS 0x036F +#define WM_SOCKET_NOTIFY 0x0373 +#define WM_SOCKET_DEAD 0x0374 +#define WM_POPMESSAGESTRING 0x0375 +#define WM_OCC_LOADFROMSTREAM 0x0376 +#define WM_OCC_LOADFROMSTORAGE 0x0377 +#define WM_OCC_INITNEW 0x0378 +#define WM_OCC_LOADFROMSTREAM_EX 0x037A +#define WM_OCC_LOADFROMSTORAGE_EX 0x037B +#define WM_QUEUE_SENTINEL 0x0379 + +#define WM_PENWINFIRST 0x0380 +#define WM_PENWINLAST 0x038F + +/* end of MFC messages */ + +/* FIXME: The following two lines do not belong to any libwine interface header */ +#define WM_COALESCE_FIRST 0x0390 +#define WM_COALESCE_LAST 0x039F + +#define WM_APP 0x8000 + + +#define DLGC_WANTARROWS 0x0001 +#define DLGC_WANTTAB 0x0002 +#define DLGC_WANTALLKEYS 0x0004 +#define DLGC_WANTMESSAGE 0x0004 +#define DLGC_HASSETSEL 0x0008 +#define DLGC_DEFPUSHBUTTON 0x0010 +#define DLGC_UNDEFPUSHBUTTON 0x0020 +#define DLGC_RADIOBUTTON 0x0040 +#define DLGC_WANTCHARS 0x0080 +#define DLGC_STATIC 0x0100 +#define DLGC_BUTTON 0x2000 + +/* Standard dialog button IDs */ +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 +#define IDCLOSE 8 +#define IDHELP 9 + +/****** Window classes ******/ + +typedef struct tagCREATESTRUCTA +{ + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + INT cy; + INT cx; + INT y; + INT x; + LONG style; + LPCSTR lpszName; + LPCSTR lpszClass; + DWORD dwExStyle; +} CREATESTRUCTA, *LPCREATESTRUCTA; + +typedef struct +{ + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + INT cy; + INT cx; + INT y; + INT x; + LONG style; + LPCWSTR lpszName; + LPCWSTR lpszClass; + DWORD dwExStyle; +} CREATESTRUCTW, *LPCREATESTRUCTW; + +DECL_WINELIB_TYPE_AW(CREATESTRUCT) +DECL_WINELIB_TYPE_AW(LPCREATESTRUCT) + +typedef struct +{ + HDC hdc; + WIN_BOOL fErase; + RECT rcPaint; + WIN_BOOL fRestore; + WIN_BOOL fIncUpdate; + BYTE rgbReserved[32]; +} PAINTSTRUCT, *PPAINTSTRUCT, *LPPAINTSTRUCT; + +typedef struct +{ + HMENU hWindowMenu; + UINT idFirstChild; +} CLIENTCREATESTRUCT, *LPCLIENTCREATESTRUCT; + + +typedef struct +{ + LPCSTR szClass; + LPCSTR szTitle; + HINSTANCE hOwner; + INT x; + INT y; + INT cx; + INT cy; + DWORD style; + LPARAM lParam; +} MDICREATESTRUCTA, *LPMDICREATESTRUCTA; + +typedef struct +{ + LPCWSTR szClass; + LPCWSTR szTitle; + HINSTANCE hOwner; + INT x; + INT y; + INT cx; + INT cy; + DWORD style; + LPARAM lParam; +} MDICREATESTRUCTW, *LPMDICREATESTRUCTW; + +DECL_WINELIB_TYPE_AW(MDICREATESTRUCT) +DECL_WINELIB_TYPE_AW(LPMDICREATESTRUCT) + +#define MDITILE_VERTICAL 0x0000 +#define MDITILE_HORIZONTAL 0x0001 +#define MDITILE_SKIPDISABLED 0x0002 + +#define MDIS_ALLCHILDSTYLES 0x0001 + +typedef struct { + DWORD styleOld; + DWORD styleNew; +} STYLESTRUCT, *LPSTYLESTRUCT; + + /* Offsets for GetWindowLong() and GetWindowWord() */ +#define GWL_USERDATA (-21) +#define GWL_EXSTYLE (-20) +#define GWL_STYLE (-16) +#define GWW_ID (-12) +#define GWL_ID GWW_ID +#define GWW_HWNDPARENT (-8) +#define GWL_HWNDPARENT GWW_HWNDPARENT +#define GWW_HINSTANCE (-6) +#define GWL_HINSTANCE GWW_HINSTANCE +#define GWL_WNDPROC (-4) +#define DWL_MSGRESULT 0 +#define DWL_DLGPROC 4 +#define DWL_USER 8 + + /* GetWindow() constants */ +#define GW_HWNDFIRST 0 +#define GW_HWNDLAST 1 +#define GW_HWNDNEXT 2 +#define GW_HWNDPREV 3 +#define GW_OWNER 4 +#define GW_CHILD 5 + + /* WM_GETMINMAXINFO struct */ +typedef struct +{ + POINT ptReserved; + POINT ptMaxSize; + POINT ptMaxPosition; + POINT ptMinTrackSize; + POINT ptMaxTrackSize; +} MINMAXINFO, *PMINMAXINFO, *LPMINMAXINFO; + + + /* RedrawWindow() flags */ +#define RDW_INVALIDATE 0x0001 +#define RDW_INTERNALPAINT 0x0002 +#define RDW_ERASE 0x0004 +#define RDW_VALIDATE 0x0008 +#define RDW_NOINTERNALPAINT 0x0010 +#define RDW_NOERASE 0x0020 +#define RDW_NOCHILDREN 0x0040 +#define RDW_ALLCHILDREN 0x0080 +#define RDW_UPDATENOW 0x0100 +#define RDW_ERASENOW 0x0200 +#define RDW_FRAME 0x0400 +#define RDW_NOFRAME 0x0800 + +/* debug flags */ +#define DBGFILL_ALLOC 0xfd +#define DBGFILL_FREE 0xfb +#define DBGFILL_BUFFER 0xf9 +#define DBGFILL_STACK 0xf7 + + /* WM_WINDOWPOSCHANGING/CHANGED struct */ +typedef struct tagWINDOWPOS +{ + HWND hwnd; + HWND hwndInsertAfter; + INT x; + INT y; + INT cx; + INT cy; + UINT flags; +} WINDOWPOS, *PWINDOWPOS, *LPWINDOWPOS; + + + /* WM_MOUSEACTIVATE return values */ +#define MA_ACTIVATE 1 +#define MA_ACTIVATEANDEAT 2 +#define MA_NOACTIVATE 3 +#define MA_NOACTIVATEANDEAT 4 + + /* WM_ACTIVATE wParam values */ +#define WA_INACTIVE 0 +#define WA_ACTIVE 1 +#define WA_CLICKACTIVE 2 + +/* WM_GETICON/WM_SETICON params values */ +#define ICON_SMALL 0 +#define ICON_BIG 1 + + /* WM_NCCALCSIZE parameter structure */ +typedef struct +{ + RECT rgrc[3]; + WINDOWPOS *lppos; +} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS; + + + /* WM_NCCALCSIZE return flags */ +#define WVR_ALIGNTOP 0x0010 +#define WVR_ALIGNLEFT 0x0020 +#define WVR_ALIGNBOTTOM 0x0040 +#define WVR_ALIGNRIGHT 0x0080 +#define WVR_HREDRAW 0x0100 +#define WVR_VREDRAW 0x0200 +#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) +#define WVR_VALIDRECTS 0x0400 + + /* WM_NCHITTEST return codes */ +#define HTERROR (-2) +#define HTTRANSPARENT (-1) +#define HTNOWHERE 0 +#define HTCLIENT 1 +#define HTCAPTION 2 +#define HTSYSMENU 3 +#define HTSIZE 4 +#define HTMENU 5 +#define HTHSCROLL 6 +#define HTVSCROLL 7 +#define HTMINBUTTON 8 +#define HTMAXBUTTON 9 +#define HTLEFT 10 +#define HTRIGHT 11 +#define HTTOP 12 +#define HTTOPLEFT 13 +#define HTTOPRIGHT 14 +#define HTBOTTOM 15 +#define HTBOTTOMLEFT 16 +#define HTBOTTOMRIGHT 17 +#define HTBORDER 18 +#define HTGROWBOX HTSIZE +#define HTREDUCE HTMINBUTTON +#define HTZOOM HTMAXBUTTON +#define HTOBJECT 19 +#define HTCLOSE 20 +#define HTHELP 21 +#define HTSIZEFIRST HTLEFT +#define HTSIZELAST HTBOTTOMRIGHT + + /* WM_SYSCOMMAND parameters */ +#ifdef SC_SIZE /* at least HP-UX: already defined in /usr/include/sys/signal.h */ +#undef SC_SIZE +#endif +#define SC_SIZE 0xf000 +#define SC_MOVE 0xf010 +#define SC_MINIMIZE 0xf020 +#define SC_MAXIMIZE 0xf030 +#define SC_NEXTWINDOW 0xf040 +#define SC_PREVWINDOW 0xf050 +#define SC_CLOSE 0xf060 +#define SC_VSCROLL 0xf070 +#define SC_HSCROLL 0xf080 +#define SC_MOUSEMENU 0xf090 +#define SC_KEYMENU 0xf100 +#define SC_ARRANGE 0xf110 +#define SC_RESTORE 0xf120 +#define SC_TASKLIST 0xf130 +#define SC_SCREENSAVE 0xf140 +#define SC_HOTKEY 0xf150 + +#define CS_VREDRAW 0x0001 +#define CS_HREDRAW 0x0002 +#define CS_KEYCVTWINDOW 0x0004 +#define CS_DBLCLKS 0x0008 +#define CS_OWNDC 0x0020 +#define CS_CLASSDC 0x0040 +#define CS_PARENTDC 0x0080 +#define CS_NOKEYCVT 0x0100 +#define CS_NOCLOSE 0x0200 +#define CS_SAVEBITS 0x0800 +#define CS_BYTEALIGNCLIENT 0x1000 +#define CS_BYTEALIGNWINDOW 0x2000 +#define CS_GLOBALCLASS 0x4000 +#define CS_IME 0x00010000 + +#define PRF_CHECKVISIBLE 0x00000001L +#define PRF_NONCLIENT 0x00000002L +#define PRF_CLIENT 0x00000004L +#define PRF_ERASEBKGND 0x00000008L +#define PRF_CHILDREN 0x00000010L +#define PRF_OWNED 0x00000020L + + /* Offsets for GetClassLong() and GetClassWord() */ +#define GCL_MENUNAME (-8) +#define GCW_HBRBACKGROUND (-10) +#define GCL_HBRBACKGROUND GCW_HBRBACKGROUND +#define GCW_HCURSOR (-12) +#define GCL_HCURSOR GCW_HCURSOR +#define GCW_HICON (-14) +#define GCL_HICON GCW_HICON +#define GCW_HMODULE (-16) +#define GCL_HMODULE GCW_HMODULE +#define GCW_CBWNDEXTRA (-18) +#define GCL_CBWNDEXTRA GCW_CBWNDEXTRA +#define GCW_CBCLSEXTRA (-20) +#define GCL_CBCLSEXTRA GCW_CBCLSEXTRA +#define GCL_WNDPROC (-24) +#define GCW_STYLE (-26) +#define GCL_STYLE GCW_STYLE +#define GCW_ATOM (-32) +#define GCW_HICONSM (-34) +#define GCL_HICONSM GCW_HICONSM + + +/***** Window hooks *****/ + + /* Hook values */ +#define WH_MIN (-1) +#define WH_MSGFILTER (-1) +#define WH_JOURNALRECORD 0 +#define WH_JOURNALPLAYBACK 1 +#define WH_KEYBOARD 2 +#define WH_GETMESSAGE 3 +#define WH_CALLWNDPROC 4 +#define WH_CBT 5 +#define WH_SYSMSGFILTER 6 +#define WH_MOUSE 7 +#define WH_HARDWARE 8 +#define WH_DEBUG 9 +#define WH_SHELL 10 +#define WH_FOREGROUNDIDLE 11 +#define WH_CALLWNDPROCRET 12 +#define WH_MAX 12 + +#define WH_MINHOOK WH_MIN +#define WH_MAXHOOK WH_MAX +#define WH_NB_HOOKS (WH_MAXHOOK-WH_MINHOOK+1) + + /* Hook action codes */ +#define HC_ACTION 0 +#define HC_GETNEXT 1 +#define HC_SKIP 2 +#define HC_NOREMOVE 3 +#define HC_NOREM HC_NOREMOVE +#define HC_SYSMODALON 4 +#define HC_SYSMODALOFF 5 + + /* CallMsgFilter() values */ +#define MSGF_DIALOGBOX 0 +#define MSGF_MESSAGEBOX 1 +#define MSGF_MENU 2 +#define MSGF_MOVE 3 +#define MSGF_SIZE 4 +#define MSGF_SCROLLBAR 5 +#define MSGF_NEXTWINDOW 6 +#define MSGF_MAINLOOP 8 +#define MSGF_USER 4096 + +typedef struct +{ + UINT style; + WNDPROC lpfnWndProc; + INT cbClsExtra; + INT cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; +} WNDCLASSA, *LPWNDCLASSA; + +typedef struct +{ + UINT style; + WNDPROC lpfnWndProc; + INT cbClsExtra; + INT cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; +} WNDCLASSW, *LPWNDCLASSW; + +DECL_WINELIB_TYPE_AW(WNDCLASS) +DECL_WINELIB_TYPE_AW(LPWNDCLASS) + +typedef struct { + DWORD dwData; + DWORD cbData; + LPVOID lpData; +} COPYDATASTRUCT, *PCOPYDATASTRUCT, *LPCOPYDATASTRUCT; + +typedef struct { + HMENU hmenuIn; + HMENU hmenuNext; + HWND hwndNext; +} MDINEXTMENU, *PMDINEXTMENU, *LPMDINEXTMENU; + +/* WinHelp internal structure */ +typedef struct { + WORD size; + WORD command; + LONG data; + LONG reserved; + WORD ofsFilename; + WORD ofsData; +} WINHELP,*LPWINHELP; + +typedef struct +{ + UINT16 mkSize; + BYTE mkKeyList; + BYTE szKeyphrase[1]; +} MULTIKEYHELP, *LPMULTIKEYHELP; + +typedef struct { + WORD wStructSize; + WORD x; + WORD y; + WORD dx; + WORD dy; + WORD wMax; + char rgchMember[2]; +} HELPWININFO, *LPHELPWININFO; + +#define HELP_CONTEXT 0x0001 +#define HELP_QUIT 0x0002 +#define HELP_INDEX 0x0003 +#define HELP_CONTENTS 0x0003 +#define HELP_HELPONHELP 0x0004 +#define HELP_SETINDEX 0x0005 +#define HELP_SETCONTENTS 0x0005 +#define HELP_CONTEXTPOPUP 0x0008 +#define HELP_FORCEFILE 0x0009 +#define HELP_KEY 0x0101 +#define HELP_COMMAND 0x0102 +#define HELP_PARTIALKEY 0x0105 +#define HELP_MULTIKEY 0x0201 +#define HELP_SETWINPOS 0x0203 +#define HELP_CONTEXTMENU 0x000a +#define HELP_FINDER 0x000b +#define HELP_WM_HELP 0x000c +#define HELP_SETPOPUP_POS 0x000d + +#define HELP_TCARD 0x8000 +#define HELP_TCARD_DATA 0x0010 +#define HELP_TCARD_OTHER_CALLER 0x0011 + + + /* ChangeDisplaySettings return codes */ + +#define DISP_CHANGE_SUCCESSFUL 0 +#define DISP_CHANGE_RESTART 1 +#define DISP_CHANGE_FAILED (-1) +#define DISP_CHANGE_BADMODE (-2) +#define DISP_CHANGE_NOTUPDATED (-3) +#define DISP_CHANGE_BADFLAGS (-4) +#define DISP_CHANGE_BADPARAM (-5) + +/* ChangeDisplaySettings.dwFlags */ +#define CDS_UPDATEREGISTRY 0x00000001 +#define CDS_TEST 0x00000002 +#define CDS_FULLSCREEN 0x00000004 +#define CDS_GLOBAL 0x00000008 +#define CDS_SET_PRIMARY 0x00000010 +#define CDS_RESET 0x40000000 +#define CDS_SETRECT 0x20000000 +#define CDS_NORESET 0x10000000 + +/* flags to FormatMessage */ +#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 +#define FORMAT_MESSAGE_FROM_STRING 0x00000400 +#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 +#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 +#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000 +#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF + +typedef struct +{ + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + INT cbClsExtra; + INT cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + HICON hIconSm; +} WNDCLASSEXA, *LPWNDCLASSEXA; + +typedef struct +{ + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + INT cbClsExtra; + INT cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + HICON hIconSm; +} WNDCLASSEXW, *LPWNDCLASSEXW; + +DECL_WINELIB_TYPE_AW(WNDCLASSEX) +DECL_WINELIB_TYPE_AW(LPWNDCLASSEX) + +typedef struct tagMSG +{ + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; +} MSG, *LPMSG; + +#define POINTSTOPOINT(pt, pts) \ + { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); \ + (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } + +#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x), (short)((pt).y))) + + +/* Cursors / Icons */ + +typedef struct { + WIN_BOOL fIcon; + DWORD xHotspot; + DWORD yHotspot; + HBITMAP hbmMask; + HBITMAP hbmColor; +} ICONINFO,*LPICONINFO; + + +/* this is the 6 byte accel struct used in Win32 when presented to the user */ +typedef struct +{ + BYTE fVirt; + BYTE pad0; + WORD key; + WORD cmd; +} ACCEL, *LPACCEL; + +/* this is the 8 byte accel struct used in Win32 resources (internal only) */ +typedef struct +{ + BYTE fVirt; + BYTE pad0; + WORD key; + WORD cmd; + WORD pad1; +} PE_ACCEL, *LPPE_ACCEL; + + +/* Flags for TrackPopupMenu */ +#define TPM_LEFTBUTTON 0x0000 +#define TPM_RIGHTBUTTON 0x0002 +#define TPM_LEFTALIGN 0x0000 +#define TPM_CENTERALIGN 0x0004 +#define TPM_RIGHTALIGN 0x0008 +#define TPM_TOPALIGN 0x0000 +#define TPM_VCENTERALIGN 0x0010 +#define TPM_BOTTOMALIGN 0x0020 +#define TPM_HORIZONTAL 0x0000 +#define TPM_VERTICAL 0x0040 +#define TPM_NONOTIFY 0x0080 +#define TPM_RETURNCMD 0x0100 + +typedef struct +{ + UINT cbSize; + RECT rcExclude; +} TPMPARAMS, *LPTPMPARAMS; + +/* FIXME: not sure this one is correct */ +typedef struct { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + DWORD dwItemData; + LPSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; +} MENUITEMINFOA, *LPMENUITEMINFOA; + +typedef struct { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + DWORD dwItemData; + LPWSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; +} MENUITEMINFOW, *LPMENUITEMINFOW; + +DECL_WINELIB_TYPE_AW(MENUITEMINFO) +DECL_WINELIB_TYPE_AW(LPMENUITEMINFO) + +typedef struct { + DWORD cbSize; + DWORD fMask; + DWORD dwStyle; + UINT cyMax; + HBRUSH hbrBack; + DWORD dwContextHelpID; + DWORD dwMenuData; +} MENUINFO, *LPMENUINFO; + +typedef MENUINFO const * LPCMENUINFO; + +#define MIM_MAXHEIGHT 0x00000001 +#define MIM_BACKGROUND 0x00000002 +#define MIM_HELPID 0x00000004 +#define MIM_MENUDATA 0x00000008 +#define MIM_STYLE 0x00000010 +#define MIM_APPLYTOSUBMENUS 0x80000000 + +typedef struct { + WORD versionNumber; + WORD offset; +} MENUITEMTEMPLATEHEADER, *PMENUITEMTEMPLATEHEADER; + + +typedef struct { + WORD mtOption; + WORD mtID; + WCHAR mtString[1]; +} MENUITEMTEMPLATE, *PMENUITEMTEMPLATE; + + +typedef VOID MENUTEMPLATE; +typedef PVOID *LPMENUTEMPLATE; + +/* Field specifiers for MENUITEMINFO[AW] type. */ +#define MIIM_STATE 0x00000001 +#define MIIM_ID 0x00000002 +#define MIIM_SUBMENU 0x00000004 +#define MIIM_CHECKMARKS 0x00000008 +#define MIIM_TYPE 0x00000010 +#define MIIM_DATA 0x00000020 +#define MIIM_STRING 0x00000040 +#define MIIM_BITMAP 0x00000080 +#define MIIM_FTYPE 0x00000100 + +#define HBMMENU_CALLBACK ((HBITMAP) -1) +#define HBMMENU_SYSTEM ((HBITMAP) 1) +#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) +#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) +#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) +#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) +#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) +#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) +#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) +#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) +#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) + +/* DrawState defines ... */ +typedef WIN_BOOL CALLBACK (*DRAWSTATEPROC)(HDC,LPARAM,WPARAM,INT,INT); + +/* WM_H/VSCROLL commands */ +#define SB_LINEUP 0 +#define SB_LINELEFT 0 +#define SB_LINEDOWN 1 +#define SB_LINERIGHT 1 +#define SB_PAGEUP 2 +#define SB_PAGELEFT 2 +#define SB_PAGEDOWN 3 +#define SB_PAGERIGHT 3 +#define SB_THUMBPOSITION 4 +#define SB_THUMBTRACK 5 +#define SB_TOP 6 +#define SB_LEFT 6 +#define SB_BOTTOM 7 +#define SB_RIGHT 7 +#define SB_ENDSCROLL 8 + +/* Scroll bar selection constants */ +#define SB_HORZ 0 +#define SB_VERT 1 +#define SB_CTL 2 +#define SB_BOTH 3 + +/* Scrollbar styles */ +#define SBS_HORZ 0x0000L +#define SBS_VERT 0x0001L +#define SBS_TOPALIGN 0x0002L +#define SBS_LEFTALIGN 0x0002L +#define SBS_BOTTOMALIGN 0x0004L +#define SBS_RIGHTALIGN 0x0004L +#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L +#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L +#define SBS_SIZEBOX 0x0008L +#define SBS_SIZEGRIP 0x0010L + +/* EnableScrollBar() flags */ +#define ESB_ENABLE_BOTH 0x0000 +#define ESB_DISABLE_BOTH 0x0003 + +#define ESB_DISABLE_LEFT 0x0001 +#define ESB_DISABLE_RIGHT 0x0002 + +#define ESB_DISABLE_UP 0x0001 +#define ESB_DISABLE_DOWN 0x0002 + +#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT +#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT + +/* Win32 button control messages */ +#define BM_GETCHECK 0x00f0 +#define BM_SETCHECK 0x00f1 +#define BM_GETSTATE 0x00f2 +#define BM_SETSTATE 0x00f3 +#define BM_SETSTYLE 0x00f4 +#define BM_CLICK 0x00f5 +#define BM_GETIMAGE 0x00f6 +#define BM_SETIMAGE 0x00f7 +/* Winelib button control messages */ + +/* Button notification codes */ +#define BN_CLICKED 0 +#define BN_PAINT 1 +#define BN_HILITE 2 +#define BN_UNHILITE 3 +#define BN_DISABLE 4 +#define BN_DOUBLECLICKED 5 + +/* Button states */ +#define BST_UNCHECKED 0x0000 +#define BST_CHECKED 0x0001 +#define BST_INDETERMINATE 0x0002 +#define BST_PUSHED 0x0004 +#define BST_FOCUS 0x0008 + +/* Static Control Styles */ +#define SS_LEFT 0x00000000L +#define SS_CENTER 0x00000001L +#define SS_RIGHT 0x00000002L +#define SS_ICON 0x00000003L +#define SS_BLACKRECT 0x00000004L +#define SS_GRAYRECT 0x00000005L +#define SS_WHITERECT 0x00000006L +#define SS_BLACKFRAME 0x00000007L +#define SS_GRAYFRAME 0x00000008L +#define SS_WHITEFRAME 0x00000009L + +#define SS_SIMPLE 0x0000000BL +#define SS_LEFTNOWORDWRAP 0x0000000CL + +#define SS_OWNERDRAW 0x0000000DL +#define SS_BITMAP 0x0000000EL +#define SS_ENHMETAFILE 0x0000000FL + +#define SS_ETCHEDHORZ 0x00000010L +#define SS_ETCHEDVERT 0x00000011L +#define SS_ETCHEDFRAME 0x00000012L +#define SS_TYPEMASK 0x0000001FL + +#define SS_NOPREFIX 0x00000080L +#define SS_NOTIFY 0x00000100L +#define SS_CENTERIMAGE 0x00000200L +#define SS_RIGHTJUST 0x00000400L +#define SS_REALSIZEIMAGE 0x00000800L +#define SS_SUNKEN 0x00001000L + +/* Static Control Messages */ +#define STM_SETICON 0x0170 +#define STM_GETICON 0x0171 +#define STM_SETIMAGE 0x0172 +#define STM_GETIMAGE 0x0173 + +/* Scrollbar messages */ +#define SBM_SETPOS 0x00e0 +#define SBM_GETPOS 0x00e1 +#define SBM_SETRANGE 0x00e2 +#define SBM_GETRANGE 0x00e3 +#define SBM_ENABLE_ARROWS 0x00e4 +#define SBM_SETRANGEREDRAW 0x00e6 +#define SBM_SETSCROLLINFO 0x00e9 +#define SBM_GETSCROLLINFO 0x00ea + +/* Scrollbar info */ +typedef struct +{ + UINT cbSize; + UINT fMask; + INT nMin; + INT nMax; + UINT nPage; + INT nPos; + INT nTrackPos; +} SCROLLINFO, *LPSCROLLINFO; + +/* GetScrollInfo() flags */ +#define SIF_RANGE 0x0001 +#define SIF_PAGE 0x0002 +#define SIF_POS 0x0004 +#define SIF_DISABLENOSCROLL 0x0008 +#define SIF_TRACKPOS 0x0010 +#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) + +/* Listbox styles */ +#define LBS_NOTIFY 0x0001 +#define LBS_SORT 0x0002 +#define LBS_NOREDRAW 0x0004 +#define LBS_MULTIPLESEL 0x0008 +#define LBS_OWNERDRAWFIXED 0x0010 +#define LBS_OWNERDRAWVARIABLE 0x0020 +#define LBS_HASSTRINGS 0x0040 +#define LBS_USETABSTOPS 0x0080 +#define LBS_NOINTEGRALHEIGHT 0x0100 +#define LBS_MULTICOLUMN 0x0200 +#define LBS_WANTKEYBOARDINPUT 0x0400 +#define LBS_EXTENDEDSEL 0x0800 +#define LBS_DISABLENOSCROLL 0x1000 +#define LBS_NODATA 0x2000 +#define LBS_NOSEL 0x4000 +#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) + +/* Listbox messages */ +#define LB_ADDSTRING 0x0180 +#define LB_INSERTSTRING 0x0181 +#define LB_DELETESTRING 0x0182 +#define LB_SELITEMRANGEEX 0x0183 +#define LB_RESETCONTENT 0x0184 +#define LB_SETSEL 0x0185 +#define LB_SETCURSEL 0x0186 +#define LB_GETSEL 0x0187 +#define LB_GETCURSEL 0x0188 +#define LB_GETTEXT 0x0189 +#define LB_GETTEXTLEN 0x018a +#define LB_GETCOUNT 0x018b +#define LB_SELECTSTRING 0x018c +#define LB_DIR 0x018d +#define LB_GETTOPINDEX 0x018e +#define LB_FINDSTRING 0x018f +#define LB_GETSELCOUNT 0x0190 +#define LB_GETSELITEMS 0x0191 +#define LB_SETTABSTOPS 0x0192 +#define LB_GETHORIZONTALEXTENT 0x0193 +#define LB_SETHORIZONTALEXTENT 0x0194 +#define LB_SETCOLUMNWIDTH 0x0195 +#define LB_ADDFILE 0x0196 +#define LB_SETTOPINDEX 0x0197 +#define LB_GETITEMRECT 0x0198 +#define LB_GETITEMDATA 0x0199 +#define LB_SETITEMDATA 0x019a +#define LB_SELITEMRANGE 0x019b +#define LB_SETANCHORINDEX 0x019c +#define LB_GETANCHORINDEX 0x019d +#define LB_SETCARETINDEX 0x019e +#define LB_GETCARETINDEX 0x019f +#define LB_SETITEMHEIGHT 0x01a0 +#define LB_GETITEMHEIGHT 0x01a1 +#define LB_FINDSTRINGEXACT 0x01a2 +#define LB_CARETON 0x01a3 +#define LB_CARETOFF 0x01a4 +#define LB_SETLOCALE 0x01a5 +#define LB_GETLOCALE 0x01a6 +#define LB_SETCOUNT 0x01a7 +#define LB_INITSTORAGE 0x01a8 +#define LB_ITEMFROMPOINT 0x01a9 + +/* Listbox notification codes */ +#define LBN_ERRSPACE (-2) +#define LBN_SELCHANGE 1 +#define LBN_DBLCLK 2 +#define LBN_SELCANCEL 3 +#define LBN_SETFOCUS 4 +#define LBN_KILLFOCUS 5 + +/* Listbox message return values */ +#define LB_OKAY 0 +#define LB_ERR (-1) +#define LB_ERRSPACE (-2) + +#define LB_CTLCODE 0L + +/* Combo box styles */ +#define CBS_SIMPLE 0x0001L +#define CBS_DROPDOWN 0x0002L +#define CBS_DROPDOWNLIST 0x0003L +#define CBS_OWNERDRAWFIXED 0x0010L +#define CBS_OWNERDRAWVARIABLE 0x0020L +#define CBS_AUTOHSCROLL 0x0040L +#define CBS_OEMCONVERT 0x0080L +#define CBS_SORT 0x0100L +#define CBS_HASSTRINGS 0x0200L +#define CBS_NOINTEGRALHEIGHT 0x0400L +#define CBS_DISABLENOSCROLL 0x0800L + +#define CBS_UPPERCASE 0x2000L +#define CBS_LOWERCASE 0x4000L + + +/* Combo box messages */ +#define CB_GETEDITSEL 0x0140 +#define CB_LIMITTEXT 0x0141 +#define CB_SETEDITSEL 0x0142 +#define CB_ADDSTRING 0x0143 +#define CB_DELETESTRING 0x0144 +#define CB_DIR 0x0145 +#define CB_GETCOUNT 0x0146 +#define CB_GETCURSEL 0x0147 +#define CB_GETLBTEXT 0x0148 +#define CB_GETLBTEXTLEN 0x0149 +#define CB_INSERTSTRING 0x014a +#define CB_RESETCONTENT 0x014b +#define CB_FINDSTRING 0x014c +#define CB_SELECTSTRING 0x014d +#define CB_SETCURSEL 0x014e +#define CB_SHOWDROPDOWN 0x014f +#define CB_GETITEMDATA 0x0150 +#define CB_SETITEMDATA 0x0151 +#define CB_GETDROPPEDCONTROLRECT 0x0152 +#define CB_SETITEMHEIGHT 0x0153 +#define CB_GETITEMHEIGHT 0x0154 +#define CB_SETEXTENDEDUI 0x0155 +#define CB_GETEXTENDEDUI 0x0156 +#define CB_GETDROPPEDSTATE 0x0157 +#define CB_FINDSTRINGEXACT 0x0158 +#define CB_SETLOCALE 0x0159 +#define CB_GETLOCALE 0x015a +#define CB_GETTOPINDEX 0x015b +#define CB_SETTOPINDEX 0x015c +#define CB_GETHORIZONTALEXTENT 0x015d +#define CB_SETHORIZONTALEXTENT 0x015e +#define CB_GETDROPPEDWIDTH 0x015f +#define CB_SETDROPPEDWIDTH 0x0160 +#define CB_INITSTORAGE 0x0161 + +/* Combo box notification codes */ +#define CBN_ERRSPACE (-1) +#define CBN_SELCHANGE 1 +#define CBN_DBLCLK 2 +#define CBN_SETFOCUS 3 +#define CBN_KILLFOCUS 4 +#define CBN_EDITCHANGE 5 +#define CBN_EDITUPDATE 6 +#define CBN_DROPDOWN 7 +#define CBN_CLOSEUP 8 +#define CBN_SELENDOK 9 +#define CBN_SELENDCANCEL 10 + +/* Combo box message return values */ +#define CB_OKAY 0 +#define CB_ERR (-1) +#define CB_ERRSPACE (-2) + +#define MB_OK 0x00000000 +#define MB_OKCANCEL 0x00000001 +#define MB_ABORTRETRYIGNORE 0x00000002 +#define MB_YESNOCANCEL 0x00000003 +#define MB_YESNO 0x00000004 +#define MB_RETRYCANCEL 0x00000005 +#define MB_TYPEMASK 0x0000000F + +#define MB_ICONHAND 0x00000010 +#define MB_ICONQUESTION 0x00000020 +#define MB_ICONEXCLAMATION 0x00000030 +#define MB_ICONASTERISK 0x00000040 +#define MB_USERICON 0x00000080 +#define MB_ICONMASK 0x000000F0 + +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND + +#define MB_DEFBUTTON1 0x00000000 +#define MB_DEFBUTTON2 0x00000100 +#define MB_DEFBUTTON3 0x00000200 +#define MB_DEFBUTTON4 0x00000300 +#define MB_DEFMASK 0x00000F00 + +#define MB_APPLMODAL 0x00000000 +#define MB_SYSTEMMODAL 0x00001000 +#define MB_TASKMODAL 0x00002000 +#define MB_MODEMASK 0x00003000 + +#define MB_HELP 0x00004000 +#define MB_NOFOCUS 0x00008000 +#define MB_MISCMASK 0x0000C000 + +#define MB_SETFOREGROUND 0x00010000 +#define MB_DEFAULT_DESKTOP_ONLY 0x00020000 +#define MB_SERVICE_NOTIFICATION 0x00040000 +#define MB_TOPMOST 0x00040000 +#define MB_RIGHT 0x00080000 +#define MB_RTLREADING 0x00100000 + +#define HELPINFO_WINDOW 0x0001 +#define HELPINFO_MENUITEM 0x0002 + +/* Structure pointed to by lParam of WM_HELP */ +typedef struct +{ + UINT cbSize; /* Size in bytes of this struct */ + INT iContextType; /* Either HELPINFO_WINDOW or HELPINFO_MENUITEM */ + INT iCtrlId; /* Control Id or a Menu item Id. */ + HANDLE hItemHandle; /* hWnd of control or hMenu. */ + DWORD dwContextId; /* Context Id associated with this item */ + POINT MousePos; /* Mouse Position in screen co-ordinates */ +} HELPINFO,*LPHELPINFO; + +typedef void CALLBACK (*MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); + +typedef struct +{ + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpszText; + LPCSTR lpszCaption; + DWORD dwStyle; + LPCSTR lpszIcon; + DWORD dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; +} MSGBOXPARAMSA,*LPMSGBOXPARAMSA; + +typedef struct +{ + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCWSTR lpszText; + LPCWSTR lpszCaption; + DWORD dwStyle; + LPCWSTR lpszIcon; + DWORD dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; +} MSGBOXPARAMSW,*LPMSGBOXPARAMSW; + +DECL_WINELIB_TYPE_AW(MSGBOXPARAMS) +DECL_WINELIB_TYPE_AW(LPMSGBOXPARAMS) + +typedef struct _numberfmt32a { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPCSTR lpDecimalSep; + LPCSTR lpThousandSep; + UINT NegativeOrder; +} NUMBERFMTA; + +typedef struct _numberfmt32w { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPCWSTR lpDecimalSep; + LPCWSTR lpThousandSep; + UINT NegativeOrder; +} NUMBERFMTW; + +typedef struct _currencyfmt32a +{ + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPCSTR lpDecimalSep; + LPCSTR lpThousandSep; + UINT NegativeOrder; + UINT PositiveOrder; + LPCSTR lpCurrencySymbol; +} CURRENCYFMTA; + +typedef struct _currencyfmt32w +{ + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPCWSTR lpDecimalSep; + LPCWSTR lpThousandSep; + UINT NegativeOrder; + UINT PositiveOrder; + LPCWSTR lpCurrencySymbol; +} CURRENCYFMTW; + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + +#define MONITORINFOF_PRIMARY 0x00000001 + +typedef struct tagMONITORINFO +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; + + +typedef WIN_BOOL CALLBACK (*MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); + +/* FIXME: use this instead of LPCVOID for CreateDialogIndirectParam + and DialogBoxIndirectParam */ +typedef struct tagDLGTEMPLATE +{ + DWORD style; + DWORD dwExtendedStyle; + WORD cdit; + short x; + short y; + short cx; + short cy; +} DLGTEMPLATE; + +typedef DLGTEMPLATE *LPDLGTEMPLATEA; +typedef DLGTEMPLATE *LPDLGTEMPLATEW; +#define LPDLGTEMPLATE WINELIB_NAME_AW(LPDLGTEMPLATE) +typedef const DLGTEMPLATE *LPCDLGTEMPLATEA; +typedef const DLGTEMPLATE *LPCDLGTEMPLATEW; +#define LPCDLGTEMPLATE WINELIB_NAME_AW(LPCDLGTEMPLATE) + +typedef struct tagDLGITEMTEMPLATE +{ + DWORD style; + DWORD dwExtendedStyle; + short x; + short y; + short cx; + short cy; + WORD id; +} DLGITEMTEMPLATE; + +typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; +typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; +#define LPDLGITEMTEMPLATE WINELIB_NAME_AW(LPDLGITEMTEMPLATE) +typedef const DLGITEMTEMPLATE *LPCDLGITEMTEMPLATEA; +typedef const DLGITEMTEMPLATE *LPCDLGITEMTEMPLATEW; +#define LPCDLGITEMTEMPLATE WINELIB_NAME_AW(LPCDLGITEMTEMPLATE) + + + /* CBT hook values */ +#define HCBT_MOVESIZE 0 +#define HCBT_MINMAX 1 +#define HCBT_QS 2 +#define HCBT_CREATEWND 3 +#define HCBT_DESTROYWND 4 +#define HCBT_ACTIVATE 5 +#define HCBT_CLICKSKIPPED 6 +#define HCBT_KEYSKIPPED 7 +#define HCBT_SYSCOMMAND 8 +#define HCBT_SETFOCUS 9 + + /* CBT hook structures */ + +typedef struct +{ + CREATESTRUCTA *lpcs; + HWND hwndInsertAfter; +} CBT_CREATEWNDA, *LPCBT_CREATEWNDA; + +typedef struct +{ + CREATESTRUCTW *lpcs; + HWND hwndInsertAfter; +} CBT_CREATEWNDW, *LPCBT_CREATEWNDW; + +DECL_WINELIB_TYPE_AW(CBT_CREATEWND) +DECL_WINELIB_TYPE_AW(LPCBT_CREATEWND) + +typedef struct +{ + WIN_BOOL fMouse; + HWND hWndActive; +} CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT; + + +/* modifiers for RegisterHotKey */ +#define MOD_ALT 0x0001 +#define MOD_CONTROL 0x0002 +#define MOD_SHIFT 0x0004 +#define MOD_WIN 0x0008 + +/* ids for RegisterHotKey */ +#define IDHOT_SNAPWINDOW (-1) /* SHIFT-PRINTSCRN */ +#define IDHOT_SNAPDESKTOP (-2) /* PRINTSCRN */ + + /* keybd_event flags */ +#define KEYEVENTF_EXTENDEDKEY 0x0001 +#define KEYEVENTF_KEYUP 0x0002 +#define KEYEVENTF_WINE_FORCEEXTENDED 0x8000 + + /* mouse_event flags */ +#define MOUSEEVENTF_MOVE 0x0001 +#define MOUSEEVENTF_LEFTDOWN 0x0002 +#define MOUSEEVENTF_LEFTUP 0x0004 +#define MOUSEEVENTF_RIGHTDOWN 0x0008 +#define MOUSEEVENTF_RIGHTUP 0x0010 +#define MOUSEEVENTF_MIDDLEDOWN 0x0020 +#define MOUSEEVENTF_MIDDLEUP 0x0040 +#define MOUSEEVENTF_WHEEL 0x0800 +#define MOUSEEVENTF_ABSOLUTE 0x8000 + +/* ExitWindows() flags */ +#define EW_RESTARTWINDOWS 0x0042 +#define EW_REBOOTSYSTEM 0x0043 +#define EW_EXITANDEXECAPP 0x0044 + +/* ExitWindowsEx() flags */ +#define EWX_LOGOFF 0 +#define EWX_SHUTDOWN 1 +#define EWX_REBOOT 2 +#define EWX_FORCE 4 +#define EWX_POWEROFF 8 + +/* SetLastErrorEx types */ +#define SLE_ERROR 0x00000001 +#define SLE_MINORERROR 0x00000002 +#define SLE_WARNING 0x00000003 + +/* Predefined resources */ +#define IDI_APPLICATIONA MAKEINTRESOURCEA(32512) +#define IDI_APPLICATIONW MAKEINTRESOURCEW(32512) +#define IDI_APPLICATION WINELIB_NAME_AW(IDI_APPLICATION) +#define IDI_HANDA MAKEINTRESOURCEA(32513) +#define IDI_HANDW MAKEINTRESOURCEW(32513) +#define IDI_HAND WINELIB_NAME_AW(IDI_HAND) +#define IDI_QUESTIONA MAKEINTRESOURCEA(32514) +#define IDI_QUESTIONW MAKEINTRESOURCEW(32514) +#define IDI_QUESTION WINELIB_NAME_AW(IDI_QUESTION) +#define IDI_EXCLAMATIONA MAKEINTRESOURCEA(32515) +#define IDI_EXCLAMATIONW MAKEINTRESOURCEW(32515) +#define IDI_EXCLAMATION WINELIB_NAME_AW(IDI_EXCLAMATION) +#define IDI_ASTERISKA MAKEINTRESOURCEA(32516) +#define IDI_ASTERISKW MAKEINTRESOURCEW(32516) +#define IDI_ASTERISK WINELIB_NAME_AW(IDI_ASTERISK) + +#define IDC_BUMMERA MAKEINTRESOURCEA(100) +#define IDC_BUMMERW MAKEINTRESOURCEW(100) +#define IDC_BUMMER WINELIB_NAME_AW(IDC_BUMMER) +#define IDC_ARROWA MAKEINTRESOURCEA(32512) +#define IDC_ARROWW MAKEINTRESOURCEW(32512) +#define IDC_ARROW WINELIB_NAME_AW(IDC_ARROW) +#define IDC_IBEAMA MAKEINTRESOURCEA(32513) +#define IDC_IBEAMW MAKEINTRESOURCEW(32513) +#define IDC_IBEAM WINELIB_NAME_AW(IDC_IBEAM) +#define IDC_WAITA MAKEINTRESOURCEA(32514) +#define IDC_WAITW MAKEINTRESOURCEW(32514) +#define IDC_WAIT WINELIB_NAME_AW(IDC_WAIT) +#define IDC_CROSSA MAKEINTRESOURCEA(32515) +#define IDC_CROSSW MAKEINTRESOURCEW(32515) +#define IDC_CROSS WINELIB_NAME_AW(IDC_CROSS) +#define IDC_UPARROWA MAKEINTRESOURCEA(32516) +#define IDC_UPARROWW MAKEINTRESOURCEW(32516) +#define IDC_UPARROW WINELIB_NAME_AW(IDC_UPARROW) +#define IDC_SIZEA MAKEINTRESOURCEA(32640) +#define IDC_SIZEW MAKEINTRESOURCEW(32640) +#define IDC_SIZE WINELIB_NAME_AW(IDC_SIZE) +#define IDC_ICONA MAKEINTRESOURCEA(32641) +#define IDC_ICONW MAKEINTRESOURCEW(32641) +#define IDC_ICON WINELIB_NAME_AW(IDC_ICON) +#define IDC_SIZENWSEA MAKEINTRESOURCEA(32642) +#define IDC_SIZENWSEW MAKEINTRESOURCEW(32642) +#define IDC_SIZENWSE WINELIB_NAME_AW(IDC_SIZENWSE) +#define IDC_SIZENESWA MAKEINTRESOURCEA(32643) +#define IDC_SIZENESWW MAKEINTRESOURCEW(32643) +#define IDC_SIZENESW WINELIB_NAME_AW(IDC_SIZENESW) +#define IDC_SIZEWEA MAKEINTRESOURCEA(32644) +#define IDC_SIZEWEW MAKEINTRESOURCEW(32644) +#define IDC_SIZEWE WINELIB_NAME_AW(IDC_SIZEWE) +#define IDC_SIZENSA MAKEINTRESOURCEA(32645) +#define IDC_SIZENSW MAKEINTRESOURCEW(32645) +#define IDC_SIZENS WINELIB_NAME_AW(IDC_SIZENS) +#define IDC_SIZEALLA MAKEINTRESOURCEA(32646) +#define IDC_SIZEALLW MAKEINTRESOURCEW(32646) +#define IDC_SIZEALL WINELIB_NAME_AW(IDC_SIZEALL) +#define IDC_NOA MAKEINTRESOURCEA(32648) +#define IDC_NOW MAKEINTRESOURCEW(32648) +#define IDC_NO WINELIB_NAME_AW(IDC_NO) +#define IDC_APPSTARTINGA MAKEINTRESOURCEA(32650) +#define IDC_APPSTARTINGW MAKEINTRESOURCEW(32650) +#define IDC_APPSTARTING WINELIB_NAME_AW(IDC_APPSTARTING) +#define IDC_HELPA MAKEINTRESOURCEA(32651) +#define IDC_HELPW MAKEINTRESOURCEW(32651) +#define IDC_HELP WINELIB_NAME_AW(IDC_HELP) + +#define MNC_IGNORE 0 +#define MNC_CLOSE 1 +#define MNC_EXECUTE 2 +#define MNC_SELECT 3 + +/* SystemParametersInfo */ +/* defines below are for all win versions */ +#define SPI_GETBEEP 1 +#define SPI_SETBEEP 2 +#define SPI_GETMOUSE 3 +#define SPI_SETMOUSE 4 +#define SPI_GETBORDER 5 +#define SPI_SETBORDER 6 +#define SPI_GETKEYBOARDSPEED 10 +#define SPI_SETKEYBOARDSPEED 11 +#define SPI_LANGDRIVER 12 +#define SPI_ICONHORIZONTALSPACING 13 +#define SPI_GETSCREENSAVETIMEOUT 14 +#define SPI_SETSCREENSAVETIMEOUT 15 +#define SPI_GETSCREENSAVEACTIVE 16 +#define SPI_SETSCREENSAVEACTIVE 17 +#define SPI_GETGRIDGRANULARITY 18 +#define SPI_SETGRIDGRANULARITY 19 +#define SPI_SETDESKWALLPAPER 20 +#define SPI_SETDESKPATTERN 21 +#define SPI_GETKEYBOARDDELAY 22 +#define SPI_SETKEYBOARDDELAY 23 +#define SPI_ICONVERTICALSPACING 24 +#define SPI_GETICONTITLEWRAP 25 +#define SPI_SETICONTITLEWRAP 26 +#define SPI_GETMENUDROPALIGNMENT 27 +#define SPI_SETMENUDROPALIGNMENT 28 +#define SPI_SETDOUBLECLKWIDTH 29 +#define SPI_SETDOUBLECLKHEIGHT 30 +#define SPI_GETICONTITLELOGFONT 31 +#define SPI_SETDOUBLECLICKTIME 32 +#define SPI_SETMOUSEBUTTONSWAP 33 +#define SPI_SETICONTITLELOGFONT 34 +#define SPI_GETFASTTASKSWITCH 35 +#define SPI_SETFASTTASKSWITCH 36 +#define SPI_SETDRAGFULLWINDOWS 37 +#define SPI_GETDRAGFULLWINDOWS 38 + +#define SPI_GETFILTERKEYS 50 +#define SPI_SETFILTERKEYS 51 +#define SPI_GETTOGGLEKEYS 52 +#define SPI_SETTOGGLEKEYS 53 +#define SPI_GETMOUSEKEYS 54 +#define SPI_SETMOUSEKEYS 55 +#define SPI_GETSHOWSOUNDS 56 +#define SPI_SETSHOWSOUNDS 57 +#define SPI_GETSTICKYKEYS 58 +#define SPI_SETSTICKYKEYS 59 +#define SPI_GETACCESSTIMEOUT 60 +#define SPI_SETACCESSTIMEOUT 61 + +#define SPI_GETSOUNDSENTRY 64 +#define SPI_SETSOUNDSENTRY 65 + +/* defines below are for all win versions WINVER >= 0x0400 */ +#define SPI_SETDRAGFULLWINDOWS 37 +#define SPI_GETDRAGFULLWINDOWS 38 +#define SPI_GETNONCLIENTMETRICS 41 +#define SPI_SETNONCLIENTMETRICS 42 +#define SPI_GETMINIMIZEDMETRICS 43 +#define SPI_SETMINIMIZEDMETRICS 44 +#define SPI_GETICONMETRICS 45 +#define SPI_SETICONMETRICS 46 +#define SPI_SETWORKAREA 47 +#define SPI_GETWORKAREA 48 +#define SPI_SETPENWINDOWS 49 + +#define SPI_GETSERIALKEYS 62 +#define SPI_SETSERIALKEYS 63 +#define SPI_GETHIGHCONTRAST 66 +#define SPI_SETHIGHCONTRAST 67 +#define SPI_GETKEYBOARDPREF 68 +#define SPI_SETKEYBOARDPREF 69 +#define SPI_GETSCREENREADER 70 +#define SPI_SETSCREENREADER 71 +#define SPI_GETANIMATION 72 +#define SPI_SETANIMATION 73 +#define SPI_GETFONTSMOOTHING 74 +#define SPI_SETFONTSMOOTHING 75 +#define SPI_SETDRAGWIDTH 76 +#define SPI_SETDRAGHEIGHT 77 +#define SPI_SETHANDHELD 78 +#define SPI_GETLOWPOWERTIMEOUT 79 +#define SPI_GETPOWEROFFTIMEOUT 80 +#define SPI_SETLOWPOWERTIMEOUT 81 +#define SPI_SETPOWEROFFTIMEOUT 82 +#define SPI_GETLOWPOWERACTIVE 83 +#define SPI_GETPOWEROFFACTIVE 84 +#define SPI_SETLOWPOWERACTIVE 85 +#define SPI_SETPOWEROFFACTIVE 86 +#define SPI_SETCURSORS 87 +#define SPI_SETICONS 88 +#define SPI_GETDEFAULTINPUTLANG 89 +#define SPI_SETDEFAULTINPUTLANG 90 +#define SPI_SETLANGTOGGLE 91 +#define SPI_GETWINDOWSEXTENSION 92 +#define SPI_SETMOUSETRAILS 93 +#define SPI_GETMOUSETRAILS 94 +#define SPI_SETSCREENSAVERRUNNING 97 +#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING + +/* defines below are for all win versions (_WIN32_WINNT >= 0x0400) || + * (_WIN32_WINDOWS > 0x0400) */ +#define SPI_GETMOUSEHOVERWIDTH 98 +#define SPI_SETMOUSEHOVERWIDTH 99 +#define SPI_GETMOUSEHOVERHEIGHT 100 +#define SPI_SETMOUSEHOVERHEIGHT 101 +#define SPI_GETMOUSEHOVERTIME 102 +#define SPI_SETMOUSEHOVERTIME 103 +#define SPI_GETWHEELSCROLLLINES 104 +#define SPI_SETWHEELSCROLLLINES 105 + +#define SPI_GETSHOWIMEUI 110 +#define SPI_SETSHOWIMEUI 111 + +/* defines below are for all win versions WINVER >= 0x0500 */ +#define SPI_GETMOUSESPEED 112 +#define SPI_SETMOUSESPEED 113 +#define SPI_GETSCREENSAVERRUNNING 114 + +#define SPI_GETACTIVEWINDOWTRACKING 0x1000 +#define SPI_SETACTIVEWINDOWTRACKING 0x1001 +#define SPI_GETMENUANIMATION 0x1002 +#define SPI_SETMENUANIMATION 0x1003 +#define SPI_GETCOMBOBOXANIMATION 0x1004 +#define SPI_SETCOMBOBOXANIMATION 0x1005 +#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 +#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 +#define SPI_GETGRADIENTCAPTIONS 0x1008 +#define SPI_SETGRADIENTCAPTIONS 0x1009 +#define SPI_GETMENUUNDERLINES 0x100A +#define SPI_SETMENUUNDERLINES 0x100B +#define SPI_GETACTIVEWNDTRKZORDER 0x100C +#define SPI_SETACTIVEWNDTRKZORDER 0x100D +#define SPI_GETHOTTRACKING 0x100E +#define SPI_SETHOTTRACKING 0x100F +#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 +#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 +#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 +#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 +#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 +#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 + +/* SystemParametersInfo flags */ + +#define SPIF_UPDATEINIFILE 1 +#define SPIF_SENDWININICHANGE 2 +#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE + + + + +/* Window Styles */ +#define WS_OVERLAPPED 0x00000000L +#define WS_POPUP 0x80000000L +#define WS_CHILD 0x40000000L +#define WS_MINIMIZE 0x20000000L +#define WS_VISIBLE 0x10000000L +#define WS_DISABLED 0x08000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_MAXIMIZE 0x01000000L +#define WS_CAPTION 0x00C00000L +#define WS_BORDER 0x00800000L +#define WS_DLGFRAME 0x00400000L +#define WS_VSCROLL 0x00200000L +#define WS_HSCROLL 0x00100000L +#define WS_SYSMENU 0x00080000L +#define WS_THICKFRAME 0x00040000L +#define WS_GROUP 0x00020000L +#define WS_TABSTOP 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_TILED WS_OVERLAPPED +#define WS_ICONIC WS_MINIMIZE +#define WS_SIZEBOX WS_THICKFRAME +#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME| WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) +#define WS_CHILDWINDOW (WS_CHILD) +#define WS_TILEDWINDOW (WS_OVERLAPPEDWINDOW) + +/* Window extended styles */ +#define WS_EX_DLGMODALFRAME 0x00000001L +#define WS_EX_DRAGDETECT 0x00000002L +#define WS_EX_NOPARENTNOTIFY 0x00000004L +#define WS_EX_TOPMOST 0x00000008L +#define WS_EX_ACCEPTFILES 0x00000010L +#define WS_EX_TRANSPARENT 0x00000020L + +/* New Win95/WinNT4 styles */ +#define WS_EX_MDICHILD 0x00000040L +#define WS_EX_TOOLWINDOW 0x00000080L +#define WS_EX_WINDOWEDGE 0x00000100L +#define WS_EX_CLIENTEDGE 0x00000200L +#define WS_EX_CONTEXTHELP 0x00000400L +#define WS_EX_RIGHT 0x00001000L +#define WS_EX_LEFT 0x00000000L +#define WS_EX_RTLREADING 0x00002000L +#define WS_EX_LTRREADING 0x00000000L +#define WS_EX_LEFTSCROLLBAR 0x00004000L +#define WS_EX_RIGHTSCROLLBAR 0x00000000L +#define WS_EX_CONTROLPARENT 0x00010000L +#define WS_EX_STATICEDGE 0x00020000L +#define WS_EX_APPWINDOW 0x00040000L + +#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE|WS_EX_CLIENTEDGE) +#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_TOPMOST) + +/* WINE internal... */ +#define WS_EX_TRAYWINDOW 0x80000000L + +/* Window scrolling */ +#define SW_SCROLLCHILDREN 0x0001 +#define SW_INVALIDATE 0x0002 +#define SW_ERASE 0x0004 + +/* CreateWindow() coordinates */ +#define CW_USEDEFAULT ((INT)0x80000000) + +/* ChildWindowFromPointEx Flags */ +#define CWP_ALL 0x0000 +#define CWP_SKIPINVISIBLE 0x0001 +#define CWP_SKIPDISABLED 0x0002 +#define CWP_SKIPTRANSPARENT 0x0004 + + /* PeekMessage() options */ +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 +#define PM_NOYIELD 0x0002 + +/* WM_SHOWWINDOW wParam codes */ +#define SW_PARENTCLOSING 1 +#define SW_OTHERMAXIMIZED 2 +#define SW_PARENTOPENING 3 +#define SW_OTHERRESTORED 4 + + /* ShowWindow() codes */ +#define SW_HIDE 0 +#define SW_SHOWNORMAL 1 +#define SW_NORMAL 1 +#define SW_SHOWMINIMIZED 2 +#define SW_SHOWMAXIMIZED 3 +#define SW_MAXIMIZE 3 +#define SW_SHOWNOACTIVATE 4 +#define SW_SHOW 5 +#define SW_MINIMIZE 6 +#define SW_SHOWMINNOACTIVE 7 +#define SW_SHOWNA 8 +#define SW_RESTORE 9 +#define SW_SHOWDEFAULT 10 +#define SW_MAX 10 +#define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */ + + /* WM_SIZE message wParam values */ +#define SIZE_RESTORED 0 +#define SIZE_MINIMIZED 1 +#define SIZE_MAXIMIZED 2 +#define SIZE_MAXSHOW 3 +#define SIZE_MAXHIDE 4 +#define SIZENORMAL SIZE_RESTORED +#define SIZEICONIC SIZE_MINIMIZED +#define SIZEFULLSCREEN SIZE_MAXIMIZED +#define SIZEZOOMSHOW SIZE_MAXSHOW +#define SIZEZOOMHIDE SIZE_MAXHIDE + +/* SetWindowPos() and WINDOWPOS flags */ +#define SWP_NOSIZE 0x0001 +#define SWP_NOMOVE 0x0002 +#define SWP_NOZORDER 0x0004 +#define SWP_NOREDRAW 0x0008 +#define SWP_NOACTIVATE 0x0010 +#define SWP_FRAMECHANGED 0x0020 /* The frame changed: send WM_NCCALCSIZE */ +#define SWP_SHOWWINDOW 0x0040 +#define SWP_HIDEWINDOW 0x0080 +#define SWP_NOCOPYBITS 0x0100 +#define SWP_NOOWNERZORDER 0x0200 /* Don't do owner Z ordering */ + +#define SWP_DRAWFRAME SWP_FRAMECHANGED +#define SWP_NOREPOSITION SWP_NOOWNERZORDER + +#define SWP_NOSENDCHANGING 0x0400 +#define SWP_DEFERERASE 0x2000 +#define SWP_ASYNCWINDOWPOS 0x4000 + +#define HWND_DESKTOP ((HWND)0) +#define HWND_BROADCAST ((HWND)0xffff) + +/* SetWindowPos() hwndInsertAfter field values */ +#define HWND_TOP ((HWND)0) +#define HWND_BOTTOM ((HWND)1) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) + +#define MF_INSERT 0x0000 +#define MF_CHANGE 0x0080 +#define MF_APPEND 0x0100 +#define MF_DELETE 0x0200 +#define MF_REMOVE 0x1000 +#define MF_END 0x0080 + +#define MF_ENABLED 0x0000 +#define MF_GRAYED 0x0001 +#define MF_DISABLED 0x0002 +#define MF_STRING 0x0000 +#define MF_BITMAP 0x0004 +#define MF_UNCHECKED 0x0000 +#define MF_CHECKED 0x0008 +#define MF_POPUP 0x0010 +#define MF_MENUBARBREAK 0x0020 +#define MF_MENUBREAK 0x0040 +#define MF_UNHILITE 0x0000 +#define MF_HILITE 0x0080 +#define MF_OWNERDRAW 0x0100 +#define MF_USECHECKBITMAPS 0x0200 +#define MF_BYCOMMAND 0x0000 +#define MF_BYPOSITION 0x0400 +#define MF_SEPARATOR 0x0800 +#define MF_DEFAULT 0x1000 +#define MF_SYSMENU 0x2000 +#define MF_HELP 0x4000 +#define MF_RIGHTJUSTIFY 0x4000 +#define MF_MOUSESELECT 0x8000 + +/* Flags for extended menu item types. */ +#define MFT_STRING MF_STRING +#define MFT_BITMAP MF_BITMAP +#define MFT_MENUBARBREAK MF_MENUBARBREAK +#define MFT_MENUBREAK MF_MENUBREAK +#define MFT_OWNERDRAW MF_OWNERDRAW +#define MFT_RADIOCHECK 0x00000200L +#define MFT_SEPARATOR MF_SEPARATOR +#define MFT_RIGHTORDER 0x00002000L +#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY + +/* Flags for extended menu item states. */ +#define MFS_GRAYED 0x00000003L +#define MFS_DISABLED MFS_GRAYED +#define MFS_CHECKED MF_CHECKED +#define MFS_HILITE MF_HILITE +#define MFS_ENABLED MF_ENABLED +#define MFS_UNCHECKED MF_UNCHECKED +#define MFS_UNHILITE MF_UNHILITE +#define MFS_DEFAULT MF_DEFAULT +#define MFS_MASK 0x0000108BL +#define MFS_HOTTRACKDRAWN 0x10000000L +#define MFS_CACHEDBMP 0x20000000L +#define MFS_BOTTOMGAPDROP 0x40000000L +#define MFS_TOPGAPDROP 0x80000000L +#define MFS_GAPDROP 0xC0000000L + +/* for GetMenuDefaultItem */ +#define GMDI_USEDISABLED 0x0001L +#define GMDI_GOINTOPOPUPS 0x0002L + +#define DT_TOP 0 +#define DT_LEFT 0 +#define DT_CENTER 1 +#define DT_RIGHT 2 +#define DT_VCENTER 4 +#define DT_BOTTOM 8 +#define DT_WORDBREAK 16 +#define DT_SINGLELINE 32 +#define DT_EXPANDTABS 64 +#define DT_TABSTOP 128 +#define DT_NOCLIP 256 +#define DT_EXTERNALLEADING 512 +#define DT_CALCRECT 1024 +#define DT_NOPREFIX 2048 +#define DT_INTERNAL 4096 + +/* DrawCaption()/DrawCaptionTemp() flags */ +#define DC_ACTIVE 0x0001 +#define DC_SMALLCAP 0x0002 +#define DC_ICON 0x0004 +#define DC_TEXT 0x0008 +#define DC_INBUTTON 0x0010 + +/* DrawEdge() flags */ +#define BDR_RAISEDOUTER 0x0001 +#define BDR_SUNKENOUTER 0x0002 +#define BDR_RAISEDINNER 0x0004 +#define BDR_SUNKENINNER 0x0008 + +#define BDR_OUTER 0x0003 +#define BDR_INNER 0x000c +#define BDR_RAISED 0x0005 +#define BDR_SUNKEN 0x000a + +#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) +#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) +#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) + +/* border flags */ +#define BF_LEFT 0x0001 +#define BF_TOP 0x0002 +#define BF_RIGHT 0x0004 +#define BF_BOTTOM 0x0008 +#define BF_DIAGONAL 0x0010 +#define BF_MIDDLE 0x0800 /* Fill in the middle */ +#define BF_SOFT 0x1000 /* For softer buttons */ +#define BF_ADJUST 0x2000 /* Calculate the space left over */ +#define BF_FLAT 0x4000 /* For flat rather than 3D borders */ +#define BF_MONO 0x8000 /* For monochrome borders */ +#define BF_TOPLEFT (BF_TOP | BF_LEFT) +#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) +#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) +#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) +#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) +#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) +#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) + +/* DrawFrameControl() uType's */ + +#define DFC_CAPTION 1 +#define DFC_MENU 2 +#define DFC_SCROLL 3 +#define DFC_BUTTON 4 + +/* uState's */ + +#define DFCS_CAPTIONCLOSE 0x0000 +#define DFCS_CAPTIONMIN 0x0001 +#define DFCS_CAPTIONMAX 0x0002 +#define DFCS_CAPTIONRESTORE 0x0003 +#define DFCS_CAPTIONHELP 0x0004 /* Windows 95 only */ + +#define DFCS_MENUARROW 0x0000 +#define DFCS_MENUCHECK 0x0001 +#define DFCS_MENUBULLET 0x0002 +#define DFCS_MENUARROWRIGHT 0x0004 + +#define DFCS_SCROLLUP 0x0000 +#define DFCS_SCROLLDOWN 0x0001 +#define DFCS_SCROLLLEFT 0x0002 +#define DFCS_SCROLLRIGHT 0x0003 +#define DFCS_SCROLLCOMBOBOX 0x0005 +#define DFCS_SCROLLSIZEGRIP 0x0008 +#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 + +#define DFCS_BUTTONCHECK 0x0000 +#define DFCS_BUTTONRADIOIMAGE 0x0001 +#define DFCS_BUTTONRADIOMASK 0x0002 /* to draw nonsquare button */ +#define DFCS_BUTTONRADIO 0x0004 +#define DFCS_BUTTON3STATE 0x0008 +#define DFCS_BUTTONPUSH 0x0010 + +/* additional state of the control */ + +#define DFCS_INACTIVE 0x0100 +#define DFCS_PUSHED 0x0200 +#define DFCS_CHECKED 0x0400 +#define DFCS_ADJUSTRECT 0x2000 /* exclude surrounding edge */ +#define DFCS_FLAT 0x4000 +#define DFCS_MONO 0x8000 + +/* Image type */ +#define DST_COMPLEX 0x0000 +#define DST_TEXT 0x0001 +#define DST_PREFIXTEXT 0x0002 +#define DST_ICON 0x0003 +#define DST_BITMAP 0x0004 + +/* State type */ +#define DSS_NORMAL 0x0000 +#define DSS_UNION 0x0010 /* Gray string appearance */ +#define DSS_DISABLED 0x0020 +#define DSS_DEFAULT 0x0040 /* Make it bold */ +#define DSS_MONO 0x0080 +#define DSS_RIGHT 0x8000 + +typedef struct +{ + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemAction; + UINT itemState; + HWND hwndItem; + HDC hDC; + RECT rcItem WINE_PACKED; + DWORD itemData WINE_PACKED; +} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT; + + +typedef struct +{ + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemWidth; + UINT itemHeight; + DWORD itemData; +} MEASUREITEMSTRUCT, *PMEASUREITEMSTRUCT, *LPMEASUREITEMSTRUCT; + + +typedef struct +{ + UINT CtlType; + UINT CtlID; + UINT itemID; + HWND hwndItem; + DWORD itemData; +} DELETEITEMSTRUCT, *LPDELETEITEMSTRUCT; + + +typedef struct +{ + UINT CtlType; + UINT CtlID; + HWND hwndItem; + UINT itemID1; + DWORD itemData1; + UINT itemID2; + DWORD itemData2; + DWORD dwLocaleId; +} COMPAREITEMSTRUCT, *PCOMPAREITEMSTRUCT, *LPCOMPAREITEMSTRUCT; + + +/* WM_KEYUP/DOWN/CHAR HIWORD(lParam) flags */ +#define KF_EXTENDED 0x0100 +#define KF_DLGMODE 0x0800 +#define KF_MENUMODE 0x1000 +#define KF_ALTDOWN 0x2000 +#define KF_REPEAT 0x4000 +#define KF_UP 0x8000 + +/* Virtual key codes */ +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +/* 0x05-0x07 Undefined */ +#define VK_BACK 0x08 +#define VK_TAB 0x09 +/* 0x0A-0x0B Undefined */ +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +/* 0x0E-0x0F Undefined */ +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 +/* 0x15-0x19 Reserved for Kanji systems */ +/* 0x1A Undefined */ +#define VK_ESCAPE 0x1B +/* 0x1C-0x1F Reserved for Kanji systems */ +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A /* OEM specific in Windows 3.1 SDK */ +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F +#define VK_0 0x30 +#define VK_1 0x31 +#define VK_2 0x32 +#define VK_3 0x33 +#define VK_4 0x34 +#define VK_5 0x35 +#define VK_6 0x36 +#define VK_7 0x37 +#define VK_8 0x38 +#define VK_9 0x39 +/* 0x3A-0x40 Undefined */ +#define VK_A 0x41 +#define VK_B 0x42 +#define VK_C 0x43 +#define VK_D 0x44 +#define VK_E 0x45 +#define VK_F 0x46 +#define VK_G 0x47 +#define VK_H 0x48 +#define VK_I 0x49 +#define VK_J 0x4A +#define VK_K 0x4B +#define VK_L 0x4C +#define VK_M 0x4D +#define VK_N 0x4E +#define VK_O 0x4F +#define VK_P 0x50 +#define VK_Q 0x51 +#define VK_R 0x52 +#define VK_S 0x53 +#define VK_T 0x54 +#define VK_U 0x55 +#define VK_V 0x56 +#define VK_W 0x57 +#define VK_X 0x58 +#define VK_Y 0x59 +#define VK_Z 0x5A + +#define VK_LWIN 0x5B +#define VK_RWIN 0x5C +#define VK_APPS 0x5D +/* 0x5E-0x5F Unassigned */ +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_F17 0x80 +#define VK_F18 0x81 +#define VK_F19 0x82 +#define VK_F20 0x83 +#define VK_F21 0x84 +#define VK_F22 0x85 +#define VK_F23 0x86 +#define VK_F24 0x87 +/* 0x88-0x8F Unassigned */ +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +/* 0x92-0x9F Unassigned */ +/* + * differencing between right and left shift/control/alt key. + * Used only by GetAsyncKeyState() and GetKeyState(). + */ +#define VK_LSHIFT 0xA0 +#define VK_RSHIFT 0xA1 +#define VK_LCONTROL 0xA2 +#define VK_RCONTROL 0xA3 +#define VK_LMENU 0xA4 +#define VK_RMENU 0xA5 +/* 0xA6-0xB9 Unassigned */ +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +/* 0xC1-0xDA Unassigned */ +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +/* 0xDF-0xE4 OEM specific */ + +#define VK_PROCESSKEY 0xE5 + +/* 0xE6 OEM specific */ +/* 0xE7-0xE8 Unassigned */ +/* 0xE9-0xF5 OEM specific */ + +#define VK_ATTN 0xF6 +#define VK_CRSEL 0xF7 +#define VK_EXSEL 0xF8 +#define VK_EREOF 0xF9 +#define VK_PLAY 0xFA +#define VK_ZOOM 0xFB +#define VK_NONAME 0xFC +#define VK_PA1 0xFD +#define VK_OEM_CLEAR 0xFE + + /* Key status flags for mouse events */ +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 + + /* Queue status flags */ +#define QS_KEY 0x0001 +#define QS_MOUSEMOVE 0x0002 +#define QS_MOUSEBUTTON 0x0004 +#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) +#define QS_POSTMESSAGE 0x0008 +#define QS_TIMER 0x0010 +#define QS_PAINT 0x0020 +#define QS_SENDMESSAGE 0x0040 +#define QS_HOTKEY 0x0080 +#define QS_INPUT (QS_MOUSE | QS_KEY) +#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) +#define QS_ALLINPUT (QS_ALLEVENTS | QS_SENDMESSAGE) + +#define DDL_READWRITE 0x0000 +#define DDL_READONLY 0x0001 +#define DDL_HIDDEN 0x0002 +#define DDL_SYSTEM 0x0004 +#define DDL_DIRECTORY 0x0010 +#define DDL_ARCHIVE 0x0020 + +#define DDL_POSTMSGS 0x2000 +#define DDL_DRIVES 0x4000 +#define DDL_EXCLUSIVE 0x8000 + + /* Shell hook values */ +#define HSHELL_WINDOWCREATED 1 +#define HSHELL_WINDOWDESTROYED 2 +#define HSHELL_ACTIVATESHELLWINDOW 3 + +/* Predefined Clipboard Formats */ +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_METAFILEPICT 3 +#define CF_SYLK 4 +#define CF_DIF 5 +#define CF_TIFF 6 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_PALETTE 9 +#define CF_PENDATA 10 +#define CF_RIFF 11 +#define CF_WAVE 12 +#define CF_ENHMETAFILE 14 +#define CF_HDROP 15 +#define CF_LOCALE 16 +#define CF_MAX 17 + +#define CF_OWNERDISPLAY 0x0080 +#define CF_DSPTEXT 0x0081 +#define CF_DSPBITMAP 0x0082 +#define CF_DSPMETAFILEPICT 0x0083 + +/* "Private" formats don't get GlobalFree()'d */ +#define CF_PRIVATEFIRST 0x0200 +#define CF_PRIVATELAST 0x02FF + +/* "GDIOBJ" formats do get DeleteObject()'d */ +#define CF_GDIOBJFIRST 0x0300 +#define CF_GDIOBJLAST 0x03FF + + +/* DragObject stuff */ + +typedef struct +{ + HWND16 hWnd; + HANDLE16 hScope; + WORD wFlags; + HANDLE16 hList; + HANDLE16 hOfStruct; + POINT16 pt WINE_PACKED; + LONG l WINE_PACKED; +} DRAGINFO, *LPDRAGINFO; + +#define DRAGOBJ_PROGRAM 0x0001 +#define DRAGOBJ_DATA 0x0002 +#define DRAGOBJ_DIRECTORY 0x0004 +#define DRAGOBJ_MULTIPLE 0x0008 +#define DRAGOBJ_EXTERNAL 0x8000 + +#define DRAG_PRINT 0x544E5250 +#define DRAG_FILE 0x454C4946 + +/* types of LoadImage */ +#define IMAGE_BITMAP 0 +#define IMAGE_ICON 1 +#define IMAGE_CURSOR 2 +#define IMAGE_ENHMETAFILE 3 + +/* loadflags to LoadImage */ +#define LR_DEFAULTCOLOR 0x0000 +#define LR_MONOCHROME 0x0001 +#define LR_COLOR 0x0002 +#define LR_COPYRETURNORG 0x0004 +#define LR_COPYDELETEORG 0x0008 +#define LR_LOADFROMFILE 0x0010 +#define LR_LOADTRANSPARENT 0x0020 +#define LR_DEFAULTSIZE 0x0040 +#define LR_VGA_COLOR 0x0080 +#define LR_LOADMAP3DCOLORS 0x1000 +#define LR_CREATEDIBSECTION 0x2000 +#define LR_COPYFROMRESOURCE 0x4000 +#define LR_SHARED 0x8000 + +/* Flags for DrawIconEx. */ +#define DI_MASK 1 +#define DI_IMAGE 2 +#define DI_NORMAL (DI_MASK | DI_IMAGE) +#define DI_COMPAT 4 +#define DI_DEFAULTSIZE 8 + + /* misc messages */ +#define WM_CPL_LAUNCH (WM_USER + 1000) +#define WM_CPL_LAUNCHED (WM_USER + 1001) + +/* WM_NOTIFYFORMAT commands and return values */ +#define NFR_ANSI 1 +#define NFR_UNICODE 2 +#define NF_QUERY 3 +#define NF_REQUERY 4 + +#include "poppack.h" +#define EnumTaskWindows(handle,proc,lparam) \ + EnumThreadWindows(handle,proc,lparam) +#define OemToAnsiA OemToCharA +#define OemToAnsiW OemToCharW +#define OemToAnsi WINELIB_NAME_AW(OemToAnsi) +#define OemToAnsiBuffA OemToCharBuffA +#define OemToAnsiBuffW OemToCharBuffW +#define OemToAnsiBuff WINELIB_NAME_AW(OemToAnsiBuff) +#define AnsiToOemA CharToOemA +#define AnsiToOemW CharToOemW +#define AnsiToOem WINELIB_NAME_AW(AnsiToOem) +#define AnsiToOemBuffA CharToOemBuffA +#define AnsiToOemBuffW CharToOemBuffW +#define AnsiToOemBuff WINELIB_NAME_AW(AnsiToOemBuff) +/* NOTE: This is SYSTEM.3, not USER.182, which is also named KillSystemTimer */ +WORD WINAPI SYSTEM_KillSystemTimer( WORD ); + +/* Extra functions that don't exist in the Windows API */ + +HPEN WINAPI GetSysColorPen(INT); +INT WINAPI LoadMessageA(HMODULE,UINT,WORD,LPSTR,INT); +INT WINAPI LoadMessageW(HMODULE,UINT,WORD,LPWSTR,INT); + +VOID WINAPI ScreenSwitchEnable16(WORD); + +#define WC_DIALOG (LPSTR)((DWORD)((WORD)( 0x8002))) + +#ifdef __cplusplus +} +#endif + +#endif /* _WINUSER_ */ diff --git a/linphone/win32acm/wineacm.h b/linphone/win32acm/wineacm.h new file mode 100644 index 000000000..959cb3d76 --- /dev/null +++ b/linphone/win32acm/wineacm.h @@ -0,0 +1,72 @@ +#ifndef WINEACM_H +#define WINEACM_H +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/*********************************************************************** + * Wine specific - Win32 + */ + + +#include "wine/msacmdrv.h" + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + + +typedef struct _WINE_ACMDRIVERID *PWINE_ACMDRIVERID; +typedef struct _WINE_ACMDRIVER *PWINE_ACMDRIVER; + +typedef struct _WINE_ACMOBJ +{ + PWINE_ACMDRIVERID pACMDriverID; +} WINE_ACMOBJ, *PWINE_ACMOBJ; + +typedef struct _WINE_ACMDRIVER +{ + WINE_ACMOBJ obj; + HDRVR hDrvr; + DRIVERPROC pfnDriverProc; + PWINE_ACMDRIVER pNextACMDriver; + int iUsage; +} WINE_ACMDRIVER; + +typedef struct _WINE_ACMSTREAM +{ + WINE_ACMOBJ obj; + PWINE_ACMDRIVER pDrv; + ACMDRVSTREAMINSTANCE drvInst; + HACMDRIVER hAcmDriver; +} WINE_ACMSTREAM, *PWINE_ACMSTREAM; + +typedef struct _WINE_ACMDRIVERID +{ + LPSTR pszFileName; + WORD wFormatTag; + HINSTANCE hInstModule; /* NULL if global */ + DWORD dwProcessID; /* ID of process which installed a local driver */ + WIN_BOOL bEnabled; + PWINE_ACMDRIVER pACMDriverList; + PWINE_ACMDRIVERID pNextACMDriverID; + PWINE_ACMDRIVERID pPrevACMDriverID; +} WINE_ACMDRIVERID; + +/* From internal.c */ +extern HANDLE MSACM_hHeap; +extern PWINE_ACMDRIVERID MSACM_pFirstACMDriverID; +extern PWINE_ACMDRIVERID MSACM_pLastACMDriverID; + +PWINE_ACMDRIVERID MSACM_RegisterDriver(const char* pszFileName, + WORD wFormatTag, + HINSTANCE hinstModule); +PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p); +void MSACM_UnregisterAllDrivers(void); +PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID); +PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver); +PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* WINEACM_H */ diff --git a/linphone/win32acm/wrapper.S b/linphone/win32acm/wrapper.S new file mode 100644 index 000000000..fe2d85619 --- /dev/null +++ b/linphone/win32acm/wrapper.S @@ -0,0 +1,83 @@ +.section .data +.globl caller_return +caller_return: + .long 0 +.globl report_entry +report_entry: + .long null_call +.globl report_ret +report_ret: + .long null_call +.global wrapper_target +wrapper_target: + .long null_call + +.section .text +.globl null_call + .type null_call, @function + .balign 16,0x90 +null_call: + ret +.globl wrapper + .type wrapper, @function + .balign 16,0x90 +wrapper: + pusha # store registers (EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI) + pushf # store flags + + push %ebp # set up a stack frame + movl %esp, %ebp + + leal 4(%ebp), %eax # push flags addr + push %eax + leal 8(%ebp), %eax # push registers addr + push %eax + + leal 40(%ebp), %edx + movl (%ebp), %eax + subl %edx, %eax + push %eax + push %edx + + call *report_entry # report entry + + test %eax, %eax + jnz .Ldone + + leave # restore %esp, %ebp + popf # restore flags + popa # restore registers + + popl caller_return # switch return addresses + pushl $.Lwrapper_return + + jmp *wrapper_target # wrapper_target should return at .Lwrapper_return + + .balign 16, 0x90 +.Lwrapper_return: + pushl caller_return # restore the original return address + pusha # more for reference sake here + pushf + + push %ebp # set up a stack frame + movl %esp, %ebp + + leal 4(%ebp), %eax # push flags addr + push %eax + leal 8(%ebp), %eax # push registers addr + push %eax + + leal 40(%ebp), %edx # push stack top address (relative to our entry) + movl (%ebp), %eax + subl %edx, %eax # calculate difference between entry and previous frame + push %eax + push %edx + + call *report_ret # report the return information (same args) +.Ldone: + + leave + popf + popa + ret + diff --git a/linphone/win32acm/wrapper.h b/linphone/win32acm/wrapper.h new file mode 100644 index 000000000..e307c0e65 --- /dev/null +++ b/linphone/win32acm/wrapper.h @@ -0,0 +1,20 @@ +#ifndef _WRAPPER_H +#define _WRAPPER_H + +#include + +typedef struct { + u_int32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; +} reg386_t; + +typedef int (*wrapper_func_t)(void *stack_base, int stack_size, reg386_t *reg, u_int32_t *flags); + +extern wrapper_func_t report_entry, report_ret; + +extern void (*wrapper_target)(void); + +extern int wrapper(void); +extern int null_call(void); + +#endif /* _WRAPPER_H */ + diff --git a/p2pproxy/.classpath b/p2pproxy/.classpath new file mode 100644 index 000000000..49212745e --- /dev/null +++ b/p2pproxy/.classpath @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/p2pproxy/.cvsignore b/p2pproxy/.cvsignore new file mode 100644 index 000000000..da41270a3 --- /dev/null +++ b/p2pproxy/.cvsignore @@ -0,0 +1,5 @@ +eclipsebuild +.settings +antbuild* +P2pNetwork-* +sipp2 diff --git a/p2pproxy/.gcjbuilder b/p2pproxy/.gcjbuilder new file mode 100644 index 000000000..1084bf2f2 --- /dev/null +++ b/p2pproxy/.gcjbuilder @@ -0,0 +1,21 @@ + + 0 + 0 + + 0 + + + + 0 + + 2 + + + + + + + debug + p2pproxy + make + \ No newline at end of file diff --git a/p2pproxy/.project b/p2pproxy/.project new file mode 100644 index 000000000..67cec9a6f --- /dev/null +++ b/p2pproxy/.project @@ -0,0 +1,17 @@ + + + p2pproxy + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/p2pproxy/bin/p2pproxy-cmd.bat b/p2pproxy/bin/p2pproxy-cmd.bat new file mode 100644 index 000000000..f1fc5f0c8 --- /dev/null +++ b/p2pproxy/bin/p2pproxy-cmd.bat @@ -0,0 +1,2 @@ +@echo off +"%JAVA_HOME%\bin\java.exe" -cp p2pproxy.jar org.linphone.p2pproxy.core.utils.AccountManagerCli %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/p2pproxy/bin/p2pproxy-cmd.sh b/p2pproxy/bin/p2pproxy-cmd.sh new file mode 100644 index 000000000..1598057d7 --- /dev/null +++ b/p2pproxy/bin/p2pproxy-cmd.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec ${JAVA_HOME}/bin/java -cp p2pproxy.jar org.linphone.p2pproxy.core.utils.AccountManagerCli $* \ No newline at end of file diff --git a/p2pproxy/bin/p2pproxy.bat b/p2pproxy/bin/p2pproxy.bat new file mode 100644 index 000000000..21eaf9330 --- /dev/null +++ b/p2pproxy/bin/p2pproxy.bat @@ -0,0 +1,2 @@ +@echo off +"%JAVA_HOME%\bin\java.exe" -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=6789 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar p2pproxy.jar %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/p2pproxy/bin/p2pproxy.sh b/p2pproxy/bin/p2pproxy.sh new file mode 100644 index 000000000..91f319160 --- /dev/null +++ b/p2pproxy/bin/p2pproxy.sh @@ -0,0 +1,9 @@ +#!/bin/sh +if [ -z "$P2P_JMX_PORT"] ; then + P2P_JMX_PORT=6789 +fi +exec ${JAVA_HOME}/bin/java -Dcom.sun.management.jmxremote \ + -Dcom.sun.management.jmxremote.port=${P2P_JMX_PORT} \ + -Dcom.sun.management.jmxremote.authenticate=false \ + -Dcom.sun.management.jmxremote.ssl=false \ + -jar p2pproxy.jar $* \ No newline at end of file diff --git a/p2pproxy/build.xml b/p2pproxy/build.xml new file mode 100644 index 000000000..40e1a9cef --- /dev/null +++ b/p2pproxy/build.xml @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ChangeRequest.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ChangeRequest.java new file mode 100644 index 000000000..bf83df66c --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ChangeRequest.java @@ -0,0 +1,81 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import de.javawi.jstun.util.*; + +public class ChangeRequest extends MessageAttribute { + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + boolean changeIP = false; + boolean changePort = false; + + public ChangeRequest() { + super(MessageAttribute.MessageAttributeType.ChangeRequest); + } + + public boolean isChangeIP() { + return changeIP; + } + + public boolean isChangePort() { + return changePort; + } + + public void setChangeIP() { + changeIP = true; + } + + public void setChangePort() { + changePort = true; + } + + public byte[] getBytes() throws UtilityException { + byte[] result = new byte[8]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(4), 0, result, 2, 2); + + // change request header + if (changeIP) result[7] = Utility.integerToOneByte(4); + if (changePort) result[7] = Utility.integerToOneByte(2); + if (changeIP && changePort) result[7] = Utility.integerToOneByte(6); + return result; + } + + public static ChangeRequest parse(byte[] data) throws MessageAttributeParsingException { + try { + if (data.length < 4) { + throw new MessageAttributeParsingException("Data array too short"); + } + ChangeRequest cr = new ChangeRequest(); + int status = Utility.oneByteToInteger(data[3]); + switch (status) { + case 0: break; + case 2: cr.setChangePort(); break; + case 4: cr.setChangeIP(); break; + case 6: cr.setChangeIP(); cr.setChangePort(); break; + default: throw new MessageAttributeParsingException("Status parsing error"); + } + return cr; + } catch (UtilityException ue) { + throw new MessageAttributeParsingException("Parsing error"); + } + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ChangedAddress.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ChangedAddress.java new file mode 100644 index 000000000..ce06b603c --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ChangedAddress.java @@ -0,0 +1,30 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.logging.Logger; + + +public class ChangedAddress extends MappedResponseChangedSourceAddressReflectedFrom { + private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.ChangedAddress"); + + public ChangedAddress() { + super(MessageAttribute.MessageAttributeType.ChangedAddress); + } + + public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException { + ChangedAddress ca = new ChangedAddress(); + MappedResponseChangedSourceAddressReflectedFrom.parse(ca, data); + logger.finer("Message Attribute: Changed Address parsed: " + ca.toString() + "."); + return ca; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Data.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Data.java new file mode 100644 index 000000000..71452ad2f --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Data.java @@ -0,0 +1,20 @@ +package de.javawi.jstun.attribute; + +import java.util.logging.Logger; + +import de.javawi.jstun.util.UtilityException; + +public class Data extends MessageAttribute { + private static Logger logger = Logger.getLogger(Data.class.getName()); + @Override + public byte[] getBytes() throws UtilityException { + // TODO Auto-generated method stub + return null; + } + public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException { + Data ma = new Data(); + + logger.finer("Message Attribute: Data Address parsed: " + ma.toString() + "."); + return ma; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Dummy.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Dummy.java new file mode 100644 index 000000000..8e780dcc0 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Dummy.java @@ -0,0 +1,42 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import de.javawi.jstun.util.Utility; +import de.javawi.jstun.util.UtilityException; + +public class Dummy extends MessageAttribute { + int lengthValue; + public Dummy() { + super(MessageAttributeType.Dummy); + } + + public void setLengthValue(int length) { + this.lengthValue = length; + } + + public byte[] getBytes() throws UtilityException { + byte[] result = new byte[lengthValue + 4]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(lengthValue), 0, result, 2, 2); + return result; + } + + public static Dummy parse(byte[] data) { + Dummy dummy = new Dummy(); + dummy.setLengthValue(data.length); + return dummy; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ErrorCode.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ErrorCode.java new file mode 100644 index 000000000..04436dd7c --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ErrorCode.java @@ -0,0 +1,104 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import de.javawi.jstun.util.Utility; +import de.javawi.jstun.util.UtilityException; + +public class ErrorCode extends MessageAttribute { + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0 |Class| Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reason Phrase (variable) .. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + int responseCode; + String reason; + + public ErrorCode() { + super(MessageAttribute.MessageAttributeType.ErrorCode); + } + + public void setResponseCode(int responseCode) throws MessageAttributeException { + switch (responseCode) { + case 400: reason = "Bad Request"; break; + case 401: reason = "Unauthorized"; break; + case 420: reason = "Unkown Attribute"; break; + case 430: reason = "Stale Credentials"; break; + case 431: reason = "Integrity Check Failure"; break; + case 432: reason = "Missing Username"; break; + case 433: reason = "Use TLS"; break; + case 500: reason = "Server Error"; break; + case 600: reason = "Global Failure"; break; + default: throw new MessageAttributeException("Response Code is not valid"); + } + this.responseCode = responseCode; + } + + public int getResponseCode() { + return responseCode; + } + + public String getReason() { + return reason; + } + + public byte[] getBytes() throws UtilityException { + int length = reason.length(); + // length adjustment + if ((length % 4) != 0) { + length += 4 - (length % 4); + } + // message attribute header + length += 4; + byte[] result = new byte[length]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(length-4), 0, result, 2, 2); + + // error code header + int classHeader = (int) Math.floor(((double)responseCode)/100); + result[6] = Utility.integerToOneByte(classHeader); + result[7] = Utility.integerToOneByte(responseCode%100); + byte[] reasonArray = reason.getBytes(); + System.arraycopy(reasonArray, 0, result, 8, reasonArray.length); + return result; + } + + public static ErrorCode parse(byte[] data) throws MessageAttributeParsingException { + try { + if (data.length < 4) { + throw new MessageAttributeParsingException("Data array too short"); + } + byte classHeaderByte = data[3]; + int classHeader = Utility.oneByteToInteger(classHeaderByte); + if ((classHeader < 1) || (classHeader > 6)) throw new MessageAttributeParsingException("Class parsing error"); + byte numberByte = data[4]; + int number = Utility.oneByteToInteger(numberByte); + if ((number < 0) || (number > 99)) throw new MessageAttributeParsingException("Number parsing error"); + int responseCode = (classHeader * 100) + number; + ErrorCode result = new ErrorCode(); + result.setResponseCode(responseCode); + return result; + } catch (UtilityException ue) { + throw new MessageAttributeParsingException("Parsing error"); + } catch (MessageAttributeException mae) { + throw new MessageAttributeParsingException("Parsing error"); + } + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MappedAddress.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MappedAddress.java new file mode 100644 index 000000000..bdb84acfe --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MappedAddress.java @@ -0,0 +1,29 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.logging.Logger; + + +public class MappedAddress extends MappedResponseChangedSourceAddressReflectedFrom { + private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.MappedAddress"); + public MappedAddress() { + super(MessageAttribute.MessageAttributeType.MappedAddress); + } + + public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException { + MappedAddress ma = new MappedAddress(); + MappedResponseChangedSourceAddressReflectedFrom.parse(ma, data); + logger.finer("Message Attribute: Mapped Address parsed: " + ma.toString() + "."); + return ma; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MappedResponseChangedSourceAddressReflectedFrom.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MappedResponseChangedSourceAddressReflectedFrom.java new file mode 100644 index 000000000..252e96052 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MappedResponseChangedSourceAddressReflectedFrom.java @@ -0,0 +1,107 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import de.javawi.jstun.util.*; + +public class MappedResponseChangedSourceAddressReflectedFrom extends MessageAttribute { + int port; + Address address; + + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |x x x x x x x x| Family | Port | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + public MappedResponseChangedSourceAddressReflectedFrom() { + super(); + try { + port = 0; + address = new Address("0.0.0.0"); + } catch (UtilityException ue) { + ue.getMessage(); + ue.printStackTrace(); + } + } + + public MappedResponseChangedSourceAddressReflectedFrom(MessageAttribute.MessageAttributeType type) { + super(type); + } + + public int getPort() { + return port; + } + + public Address getAddress() { + return address; + } + + public void setPort(int port) throws MessageAttributeException { + if ((port > 65536) || (port < 0)) { + throw new MessageAttributeException("Port value " + port + " out of range."); + } + this.port = port; + } + + public void setAddress(Address address) { + this.address = address; + } + + public byte[] getBytes() throws UtilityException { + byte[] result = new byte[12]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(8), 0, result, 2, 2); + + // mappedaddress header + // family + result[5] = Utility.integerToOneByte(0x01); + // port + System.arraycopy(Utility.integerToTwoBytes(port), 0, result, 6, 2); + // address + System.arraycopy(address.getBytes(), 0, result, 8, 4); + return result; + } + + protected static MappedResponseChangedSourceAddressReflectedFrom parse(MappedResponseChangedSourceAddressReflectedFrom ma, byte[] data) throws MessageAttributeParsingException { + try { + if (data.length < 8) { + throw new MessageAttributeParsingException("Data array too short"); + } + int family = Utility.oneByteToInteger(data[1]); + if (family != 0x01) throw new MessageAttributeParsingException("Family " + family + " is not supported"); + byte[] portArray = new byte[2]; + System.arraycopy(data, 2, portArray, 0, 2); + ma.setPort(Utility.twoBytesToInteger(portArray)); + int firstOctet = Utility.oneByteToInteger(data[4]); + int secondOctet = Utility.oneByteToInteger(data[5]); + int thirdOctet = Utility.oneByteToInteger(data[6]); + int fourthOctet = Utility.oneByteToInteger(data[7]); + ma.setAddress(new Address(firstOctet, secondOctet, thirdOctet, fourthOctet)); + return ma; + } catch (UtilityException ue) { + throw new MessageAttributeParsingException("Parsing error"); + } catch (MessageAttributeException mae) { + throw new MessageAttributeParsingException("Port parsing error"); + } + } + + public String toString() { + return "Address " +address.toString() + ", Port " + port; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttribute.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttribute.java new file mode 100644 index 000000000..2c1f1ef7f --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttribute.java @@ -0,0 +1,135 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.logging.*; + +import de.javawi.jstun.util.*; + + +public abstract class MessageAttribute implements MessageAttributeInterface { + private static Logger logger = Logger.getLogger("de.javawi.stun.util.MessageAttribute"); + MessageAttributeType type; + + public MessageAttribute() { + } + + public MessageAttribute(MessageAttributeType type) { + setType(type); + } + + public void setType(MessageAttributeType type) { + this.type = type; + } + + public MessageAttribute.MessageAttributeType getType() { + return type; + } + + public static int typeToInteger(MessageAttributeType type) { + if (type == MessageAttributeType.MappedAddress) return MAPPEDADDRESS; + if (type == MessageAttributeType.ResponseAddress) return RESPONSEADDRESS; + if (type == MessageAttributeType.ChangeRequest) return CHANGEREQUEST; + if (type == MessageAttributeType.SourceAddress) return SOURCEADDRESS; + if (type == MessageAttributeType.ChangedAddress) return CHANGEDADDRESS; + if (type == MessageAttributeType.Username) return USERNAME; + if (type == MessageAttributeType.Password) return PASSWORD; + if (type == MessageAttributeType.MessageIntegrity) return MESSAGEINTEGRITY; + if (type == MessageAttributeType.ErrorCode) return ERRORCODE; + if (type == MessageAttributeType.UnknownAttribute) return UNKNOWNATTRIBUTE; + if (type == MessageAttributeType.ReflectedFrom) return REFLECTEDFROM; + if (type == MessageAttributeType.Dummy) return DUMMY; + //turn + if (type == MessageAttributeType.ChannelNumber) return CHANNELNUMBER; + if (type == MessageAttributeType.LifeTime) return LIFETIME; + if (type == MessageAttributeType.Bandwidth ) return BANDWIDTH; + if (type == MessageAttributeType.PeerAddress ) return PEERADDRESS; + if (type == MessageAttributeType.Data ) return DATA; + if (type == MessageAttributeType.RelayAddress ) return RELAYADDRESS; + if (type == MessageAttributeType.RequestedProps ) return REQUESTEDPROPS; + if (type == MessageAttributeType.RequestedTransport ) return REQUESTEDTRANSPORT; + if (type == MessageAttributeType.ReservationToken ) return RESERVATIONTOKEN; + return -1; + } + + public static MessageAttributeType intToType(long type) { + if (type == MAPPEDADDRESS) return MessageAttributeType.MappedAddress; + if (type == RESPONSEADDRESS) return MessageAttributeType.ResponseAddress; + if (type == CHANGEREQUEST) return MessageAttributeType.ChangeRequest; + if (type == SOURCEADDRESS) return MessageAttributeType.SourceAddress; + if (type == CHANGEDADDRESS) return MessageAttributeType.ChangedAddress; + if (type == USERNAME) return MessageAttributeType.Username; + if (type == PASSWORD) return MessageAttributeType.Password; + if (type == MESSAGEINTEGRITY) return MessageAttributeType.MessageIntegrity; + if (type == ERRORCODE) return MessageAttributeType.ErrorCode; + if (type == UNKNOWNATTRIBUTE) return MessageAttributeType.UnknownAttribute; + if (type == REFLECTEDFROM) return MessageAttributeType.ReflectedFrom; + if (type == DUMMY) return MessageAttributeType.Dummy; + //turn + if (type == CHANNELNUMBER) return MessageAttributeType.ChannelNumber; + if (type == LIFETIME) return MessageAttributeType.LifeTime; + if (type == BANDWIDTH) return MessageAttributeType.Bandwidth; + if (type == PEERADDRESS) return MessageAttributeType.PeerAddress; + if (type == DATA) return MessageAttributeType.Data; + if (type == RELAYADDRESS) return MessageAttributeType.RelayAddress; + if (type == REQUESTEDPROPS) return MessageAttributeType.RequestedProps; + if (type == REQUESTEDTRANSPORT) return MessageAttributeType.RequestedTransport; + if (type == RESERVATIONTOKEN) return MessageAttributeType.ReservationToken; + return null; + } + + abstract public byte[] getBytes() throws UtilityException; + //abstract public MessageAttribute parse(byte[] data) throws MessageAttributeParsingException; + + public int getLength() throws UtilityException { + int length = getBytes().length; + return length; + } + + public static MessageAttribute parseCommonHeader(byte[] data) throws MessageAttributeParsingException { + try { + byte[] typeArray = new byte[2]; + System.arraycopy(data, 0, typeArray, 0, 2); + int type = Utility.twoBytesToInteger(typeArray); + byte[] lengthArray = new byte[2]; + System.arraycopy(data, 2, lengthArray, 0, 2); + int lengthValue = Utility.twoBytesToInteger(lengthArray); + byte[] valueArray = new byte[lengthValue]; + System.arraycopy(data, 4, valueArray, 0, lengthValue); + MessageAttribute ma; + switch (type) { + case MAPPEDADDRESS: ma = MappedAddress.parse(valueArray); break; + case RESPONSEADDRESS: ma = ResponseAddress.parse(valueArray); break; + case CHANGEREQUEST: ma = ChangeRequest.parse(valueArray); break; + case SOURCEADDRESS: ma = SourceAddress.parse(valueArray); break; + case CHANGEDADDRESS: ma = ChangedAddress.parse(valueArray); break; + case USERNAME: ma = Username.parse(valueArray); break; + case PASSWORD: ma = Password.parse(valueArray); break; + case MESSAGEINTEGRITY: ma = MessageIntegrity.parse(valueArray); break; + case ERRORCODE: ma = ErrorCode.parse(valueArray); break; + case UNKNOWNATTRIBUTE: ma = UnknownAttribute.parse(valueArray); break; + case REFLECTEDFROM: ma = ReflectedFrom.parse(valueArray); break; + default: + if (type <= 0x7fff) { + throw new UnknownMessageAttributeException("Unkown mandatory message attribute", intToType(type)); + } else { + logger.finer("MessageAttribute with type " + type + " unkown."); + ma = Dummy.parse(valueArray); + break; + } + } + return ma; + } catch (UtilityException ue) { + throw new MessageAttributeParsingException("Parsing error"); + } + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeException.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeException.java new file mode 100644 index 000000000..a8109cfd1 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeException.java @@ -0,0 +1,20 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +public class MessageAttributeException extends Exception { + private static final long serialVersionUID = 3258131345099404850L; + + public MessageAttributeException(String mesg) { + super(mesg); + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeInterface.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeInterface.java new file mode 100644 index 000000000..8c55d7806 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeInterface.java @@ -0,0 +1,68 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +public interface MessageAttributeInterface { + public enum MessageAttributeType { MappedAddress + , ResponseAddress + , ChangeRequest + , SourceAddress + , ChangedAddress + , Username + , Password + , MessageIntegrity + , ErrorCode + , UnknownAttribute + , ReflectedFrom + , Dummy + , ChannelNumber + , LifeTime + , Bandwidth + , PeerAddress + , Data + , RelayAddress + , RequestedProps + , RequestedTransport + , ReservationToken}; + final static int MAPPEDADDRESS = 0x0001; + final static int RESPONSEADDRESS = 0x0002; + final static int CHANGEREQUEST = 0x0003; + final static int SOURCEADDRESS = 0x0004; + final static int CHANGEDADDRESS = 0x0005; + final static int USERNAME = 0x0006; + final static int PASSWORD = 0x0007; + final static int MESSAGEINTEGRITY = 0x0008; + final static int ERRORCODE = 0x0009; + final static int UNKNOWNATTRIBUTE = 0x000a; + final static int REFLECTEDFROM = 0x000b; + final static int DUMMY = 0x0000; +// turn attributes +// 0x000C: CHANNEL-NUMBER +// 0x000D: LIFETIME +// 0x0010: BANDWIDTH +// 0x0012: PEER-ADDRESS +// 0x0013: DATA +// 0x0016: RELAY-ADDRESS +// 0x0018: REQUESTED-PROPS +// 0x0019: REQUESTED-TRANSPORT +// 0x0022: RESERVATION-TOKEN + final static int CHANNELNUMBER = 0x000C; + final static int LIFETIME = 0x000D; + final static int BANDWIDTH = 0x0010; + final static int PEERADDRESS = 0x0012; + final static int DATA = 0x0013; + final static int RELAYADDRESS = 0x0016; + final static int REQUESTEDPROPS = 0x0018; + final static int REQUESTEDTRANSPORT = 0x0019; + final static int RESERVATIONTOKEN = 0x0022; + +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeParsingException.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeParsingException.java new file mode 100644 index 000000000..d20278976 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageAttributeParsingException.java @@ -0,0 +1,20 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +public class MessageAttributeParsingException extends MessageAttributeException { + private static final long serialVersionUID = 3258409534426263605L; + + public MessageAttributeParsingException(String mesg) { + super(mesg); + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageIntegrity.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageIntegrity.java new file mode 100644 index 000000000..7aa7df3d7 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/MessageIntegrity.java @@ -0,0 +1,27 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +public class MessageIntegrity extends MessageAttribute { + // incomplete message integrity implementation + public MessageIntegrity() { + super(MessageAttribute.MessageAttributeType.MessageIntegrity); + } + + public byte[] getBytes() { + return new byte[0]; + } + + public static MessageIntegrity parse(byte[] data) { + return new MessageIntegrity(); + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Password.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Password.java new file mode 100644 index 000000000..679a193d9 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Password.java @@ -0,0 +1,64 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import de.javawi.jstun.util.Utility; +import de.javawi.jstun.util.UtilityException; + +public class Password extends MessageAttribute { + String password; + + public Password() { + super(MessageAttribute.MessageAttributeType.Password); + } + + public Password(String password) { + super(MessageAttribute.MessageAttributeType.Password); + setPassword(password); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public byte[] getBytes() throws UtilityException { + int length = password.length(); + // password header + if ((length % 4) != 0) { + length += 4 - (length % 4); + } + // message attribute header + length += 4; + byte[] result = new byte[length]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(length - 4), 0, result, 2, 2); + + // password header + byte[] temp = password.getBytes(); + System.arraycopy(temp, 0, result, 4, temp.length); + return result; + } + + public static Password parse(byte[] data) { + Password result = new Password(); + String password = new String(data); + result.setPassword(password); + return result; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ReflectedFrom.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ReflectedFrom.java new file mode 100644 index 000000000..e29831431 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ReflectedFrom.java @@ -0,0 +1,31 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.logging.Logger; + +public class ReflectedFrom extends MappedResponseChangedSourceAddressReflectedFrom { + private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.ReflectedFrom"); + + public ReflectedFrom() { + super(MessageAttribute.MessageAttributeType.ReflectedFrom); + } + + public static ReflectedFrom parse(byte[] data) throws MessageAttributeParsingException { + ReflectedFrom result = new ReflectedFrom(); + MappedResponseChangedSourceAddressReflectedFrom.parse(result, data); + logger.finer("Message Attribute: ReflectedFrom parsed: " + result.toString() + "."); + return result; + } + + +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ResponseAddress.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ResponseAddress.java new file mode 100644 index 000000000..40c73bd0b --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/ResponseAddress.java @@ -0,0 +1,29 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.logging.Logger; + + +public class ResponseAddress extends MappedResponseChangedSourceAddressReflectedFrom { + private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.ResponseAddress"); + public ResponseAddress() { + super(MessageAttribute.MessageAttributeType.ResponseAddress); + } + + public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException { + ResponseAddress ra = new ResponseAddress(); + MappedResponseChangedSourceAddressReflectedFrom.parse(ra, data); + logger.finer("Message Attribute: Response Address parsed: " + ra.toString() + "."); + return ra; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/SourceAddress.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/SourceAddress.java new file mode 100644 index 000000000..070d7d8d0 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/SourceAddress.java @@ -0,0 +1,29 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.logging.Logger; + + +public class SourceAddress extends MappedResponseChangedSourceAddressReflectedFrom { + private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.SourceAddress"); + public SourceAddress() { + super(MessageAttribute.MessageAttributeType.SourceAddress); + } + + public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException { + SourceAddress sa = new SourceAddress(); + MappedResponseChangedSourceAddressReflectedFrom.parse(sa, data); + logger.finer("Message Attribute: Source Address parsed: " + sa.toString() + "."); + return sa; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/UnknownAttribute.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/UnknownAttribute.java new file mode 100644 index 000000000..04f1abb8b --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/UnknownAttribute.java @@ -0,0 +1,82 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import java.util.*; + +import de.javawi.jstun.util.Utility; +import de.javawi.jstun.util.UtilityException; + +public class UnknownAttribute extends MessageAttribute { + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Attribute 1 Type | Attribute 2 Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Attribute 3 Type | Attribute 4 Type ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + Vector unkown = new Vector(); + + public UnknownAttribute() { + super(MessageAttribute.MessageAttributeType.UnknownAttribute); + } + + public void addAttribute(MessageAttributeType attribute) { + unkown.add(attribute); + } + + public byte[] getBytes() throws UtilityException { + int length = 0; + if (unkown.size()%2 == 1) { + length = 2 * (unkown.size() + 1) + 4; + } else { + length = 2 * unkown.size() + 4; + } + byte[] result = new byte[length]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(length - 4), 0, result, 2, 2); + + // unkown attribute header + Iterator it = unkown.iterator(); + while(it.hasNext()) { + MessageAttributeType attri = it.next(); + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(attri)), 0, result, 4, 2); + } + // padding + if (unkown.size()%2 == 1) { + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(unkown.elementAt(1))), 0, result, 4, 2); + } + return result; + } + + public static UnknownAttribute parse(byte[] data) throws MessageAttributeParsingException { + try { + UnknownAttribute result = new UnknownAttribute(); + if (data.length % 4 != 0) throw new MessageAttributeParsingException("Data array too short"); + for (int i = 0; i < data.length; i += 4) { + byte[] temp = new byte[4]; + System.arraycopy(data, i, temp, 0, 4); + long attri = Utility.fourBytesToLong(temp); + result.addAttribute(MessageAttribute.intToType(attri)); + } + return result; + } catch (UtilityException ue) { + throw new MessageAttributeParsingException("Parsing error"); + } + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/UnknownMessageAttributeException.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/UnknownMessageAttributeException.java new file mode 100644 index 000000000..4ddd49229 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/UnknownMessageAttributeException.java @@ -0,0 +1,18 @@ +package de.javawi.jstun.attribute; + +import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType; + +public class UnknownMessageAttributeException extends MessageAttributeParsingException { + private static final long serialVersionUID = 5375193544145543299L; + + private MessageAttributeType type; + + public UnknownMessageAttributeException(String mesg, MessageAttributeType type) { + super(mesg); + this.type = type; + } + + public MessageAttributeType getType() { + return type; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Username.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Username.java new file mode 100644 index 000000000..1afaec7b1 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/attribute/Username.java @@ -0,0 +1,64 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.attribute; + +import de.javawi.jstun.util.Utility; +import de.javawi.jstun.util.UtilityException; + +public class Username extends MessageAttribute { + String username; + + public Username() { + super(MessageAttribute.MessageAttributeType.Username); + } + + public Username(String username) { + super(MessageAttribute.MessageAttributeType.Username); + setUsername(username); + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public byte[] getBytes() throws UtilityException { + int length = username.length(); + // username header + if ((length % 4) != 0) { + length += 4 - (length % 4); + } + // message attribute header + length += 4; + byte[] result = new byte[length]; + // message attribute header + // type + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + // length + System.arraycopy(Utility.integerToTwoBytes(length-4), 0, result, 2, 2); + + // username header + byte[] temp = username.getBytes(); + System.arraycopy(temp, 0, result, 4, temp.length); + return result; + } + + public static Username parse(byte[] data) { + Username result = new Username(); + String username = new String(data); + result.setUsername(username); + return result; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeader.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeader.java new file mode 100644 index 000000000..1e6dab58b --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeader.java @@ -0,0 +1,202 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.header; + +import de.javawi.jstun.attribute.*; +import de.javawi.jstun.util.*; + +import java.util.*; +import java.util.logging.*; + +public class MessageHeader implements MessageHeaderInterface { + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | STUN Message Type | Message Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * Transaction ID + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + private static Logger logger = Logger.getLogger("de.javawi.stun.header.MessageHeader"); + MessageHeaderType type; + byte[] id = new byte[16]; + + TreeMap ma = new TreeMap(); + + public MessageHeader() { + super(); + } + + public MessageHeader(MessageHeaderType type) { + super(); + setType(type); + } + + public void setType(MessageHeaderType type) { + this.type = type; + } + + public MessageHeaderType getType() { + return type; + } + + public static int typeToInteger(MessageHeaderType type) { + if (type == MessageHeaderType.BindingRequest) return BINDINGREQUEST; + if (type == MessageHeaderType.BindingResponse) return BINDINGRESPONSE; + if (type == MessageHeaderType.BindingErrorResponse) return BINDINGERRORRESPONSE; + if (type == MessageHeaderType.SharedSecretRequest) return SHAREDSECRETREQUEST; + if (type == MessageHeaderType.SharedSecretResponse) return SHAREDSECRETRESPONSE; + if (type == MessageHeaderType.SharedSecretErrorResponse) return SHAREDSECRETERRORRESPONSE; + //turn headers + if (type == MessageHeaderType.AllocateRequest) return ALLOCATEREQUEST; + if (type == MessageHeaderType.AllocateResponse) return ALLOCATERESPONSE; + if (type == MessageHeaderType.AllocateErrorResponse) return ALLOCATEERRORRESPONSE; + if (type == MessageHeaderType.RefreshRequest) return REFRESHREQUEST; + if (type == MessageHeaderType.RefreshResponse) return REFRESHRESPONSE; + if (type == MessageHeaderType.RefreshErrorResponse) return REFRESHERRORRESPONSE; + if (type == MessageHeaderType.ChannelBindRequest) return CHANNELBINDREQUEST; + if (type == MessageHeaderType.ChannelBindResponse) return CHANNELBINDRESPONSE; + if (type == MessageHeaderType.ChannelBindErrorResponse) return CHANNELBINDERRORRESPONSE; + + + return -1; + } + + public void setTransactionID(byte[] id) { + System.arraycopy(id, 0, this.id, 0, 16); + } + + public void generateTransactionID() throws UtilityException { + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 0, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 2, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 4, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 6, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 8, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 10, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 12, 2); + System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 14, 2); + } + + public byte[] getTransactionID() { + byte[] idCopy = new byte[id.length]; + System.arraycopy(id, 0, idCopy, 0, id.length); + return idCopy; + } + + public boolean equalTransactionID(MessageHeader header) { + byte[] idHeader = header.getTransactionID(); + if (idHeader.length != 16) return false; + if ((idHeader[0] == id[0]) && (idHeader[1] == id[1]) && (idHeader[2] == id[2]) && (idHeader[3] == id[3]) && + (idHeader[4] == id[4]) && (idHeader[5] == id[5]) && (idHeader[6] == id[6]) && (idHeader[7] == id[7]) && + (idHeader[8] == id[8]) && (idHeader[9] == id[9]) && (idHeader[10] == id[10]) && (idHeader[11] == id[11]) && + (idHeader[12] == id[12]) && (idHeader[13] == id[13]) && (idHeader[14] == id[14]) && (idHeader[15] == id[15])) { + return true; + } else { + return false; + } + } + + public void addMessageAttribute(MessageAttribute attri) { + ma.put(attri.getType(), attri); + } + + public MessageAttribute getMessageAttribute(MessageAttribute.MessageAttributeType type) { + return ma.get(type); + } + + public byte[] getBytes() throws UtilityException { + int length = 20; + Iterator it = ma.keySet().iterator(); + while (it.hasNext()) { + MessageAttribute attri = ma.get(it.next()); + length += attri.getLength(); + } + // add attribute size + attributes.getSize(); + byte[] result = new byte[length]; + System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2); + System.arraycopy(Utility.integerToTwoBytes(length-20), 0, result, 2, 2); + System.arraycopy(id, 0, result, 4, 16); + + // arraycopy of attributes + int offset = 20; + it = ma.keySet().iterator(); + while (it.hasNext()) { + MessageAttribute attri = ma.get(it.next()); + System.arraycopy(attri.getBytes(), 0, result, offset, attri.getLength()); + offset += attri.getLength(); + } + return result; + } + + public int getLength() throws UtilityException { + return getBytes().length; + } + + public void parseAttributes(byte[] data) throws MessageAttributeParsingException { + try { + byte[] lengthArray = new byte[2]; + System.arraycopy(data, 2, lengthArray, 0, 2); + int length = Utility.twoBytesToInteger(lengthArray); + System.arraycopy(data, 4, id, 0, 16); + byte[] cuttedData; + int offset = 20; + while (length > 0) { + cuttedData = new byte[length]; + System.arraycopy(data, offset, cuttedData, 0, length); + MessageAttribute ma = MessageAttribute.parseCommonHeader(cuttedData); + addMessageAttribute(ma); + length -= ma.getLength(); + offset += ma.getLength(); + } + } catch (UtilityException ue) { + throw new MessageAttributeParsingException("Parsing error"); + } + } + + public static MessageHeader parseHeader(byte[] data) throws MessageHeaderParsingException { + try { + MessageHeader mh = new MessageHeader(); + byte[] typeArray = new byte[2]; + System.arraycopy(data, 0, typeArray, 0, 2); + int type = Utility.twoBytesToInteger(typeArray); + switch (type) { + case BINDINGREQUEST: mh.setType(MessageHeaderType.BindingRequest); logger.finer("Binding Request received."); break; + case BINDINGRESPONSE: mh.setType(MessageHeaderType.BindingResponse); logger.finer("Binding Response received."); break; + case BINDINGERRORRESPONSE: mh.setType(MessageHeaderType.BindingErrorResponse); logger.finer("Binding Error Response received."); break; + case SHAREDSECRETREQUEST: mh.setType(MessageHeaderType.SharedSecretRequest); logger.finer("Shared Secret Request received."); break; + case SHAREDSECRETRESPONSE: mh.setType(MessageHeaderType.SharedSecretResponse); logger.finer("Shared Secret Response received."); break; + case SHAREDSECRETERRORRESPONSE: mh.setType(MessageHeaderType.SharedSecretErrorResponse); logger.finer("Shared Secret Error Response received.");break; + //turn + case ALLOCATEREQUEST: mh.setType(MessageHeaderType.AllocateRequest); logger.finer("Allocate Request received."); break; + case ALLOCATERESPONSE: mh.setType(MessageHeaderType.AllocateResponse); logger.finer("Allocate Response received."); break; + case ALLOCATEERRORRESPONSE: mh.setType(MessageHeaderType.AllocateErrorResponse); logger.finer("Allocate Errro received."); break; + case REFRESHREQUEST: mh.setType(MessageHeaderType.RefreshRequest); logger.finer("Refresh Request received."); break; + case REFRESHRESPONSE: mh.setType(MessageHeaderType.RefreshResponse); logger.finer("Refresh Response received."); break; + case REFRESHERRORRESPONSE: mh.setType(MessageHeaderType.RefreshErrorResponse); logger.finer("Refresh Error received."); break; + case CHANNELBINDREQUEST: mh.setType(MessageHeaderType.ChannelBindRequest); logger.finer("ChannelBind Request received."); break; + case CHANNELBINDRESPONSE: mh.setType(MessageHeaderType.ChannelBindResponse); logger.finer("ChannelBind Response received."); break; + case CHANNELBINDERRORRESPONSE: mh.setType(MessageHeaderType.ChannelBindErrorResponse); logger.finer("ChannelBind Error received."); break; + default: throw new MessageHeaderParsingException("Message type " + type + "is not supported"); + } + return mh; + } catch (UtilityException ue) { + throw new MessageHeaderParsingException("Parsing error"); + } + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderException.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderException.java new file mode 100644 index 000000000..f4a9fa498 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderException.java @@ -0,0 +1,20 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.header; + +public class MessageHeaderException extends Exception { + private static final long serialVersionUID = 3689066248944103737L; + + public MessageHeaderException(String mesg) { + super(mesg); + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderInterface.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderInterface.java new file mode 100644 index 000000000..1b7a2cfe6 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderInterface.java @@ -0,0 +1,61 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.header; + +public interface MessageHeaderInterface { + public enum MessageHeaderType { BindingRequest + , BindingResponse + , BindingErrorResponse + , SharedSecretRequest + , SharedSecretResponse + , SharedSecretErrorResponse + , AllocateRequest + , AllocateResponse + , AllocateErrorResponse + , RefreshRequest + , RefreshResponse + , RefreshErrorResponse + , ChannelBindRequest + , ChannelBindResponse + , ChannelBindErrorResponse + ,SendIndication + ,DataIndication}; + final static int BINDINGREQUEST = 0x0001; + final static int BINDINGRESPONSE = 0x0101; + final static int BINDINGERRORRESPONSE = 0x0111; + final static int SHAREDSECRETREQUEST = 0x0002; + final static int SHAREDSECRETRESPONSE = 0x0102; + final static int SHAREDSECRETERRORRESPONSE = 0x0112; + +// TURN defines ten new Message Types: +//Request/Response Transactions +//0x003 : Allocate +//0x004 : Refresh +//0x009 : ChannelBind +//0x006 : Send +//0x007 : Data + + + final static int ALLOCATEREQUEST = 0x0003; + final static int ALLOCATERESPONSE = 0x0103; + final static int ALLOCATEERRORRESPONSE = 0x0113; + final static int REFRESHREQUEST = 0x0004; + final static int REFRESHRESPONSE = 0x0104; + final static int REFRESHERRORRESPONSE = 0x0114; + final static int CHANNELBINDREQUEST = 0x0009; + final static int CHANNELBINDRESPONSE = 0x0109; + final static int CHANNELBINDERRORRESPONSE = 0x0119; + final static int SENDINDICATION = 0x0006; + final static int DATAINDICATION = 0x0007; + + +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderParsingException.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderParsingException.java new file mode 100644 index 000000000..d5192ef28 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/header/MessageHeaderParsingException.java @@ -0,0 +1,20 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.header; + +public class MessageHeaderParsingException extends MessageHeaderException { + private static final long serialVersionUID = 3544393617029607478L; + + public MessageHeaderParsingException(String mesg) { + super(mesg); + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/BindingLifetimeTest.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/BindingLifetimeTest.java new file mode 100644 index 000000000..1dca91b47 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/BindingLifetimeTest.java @@ -0,0 +1,192 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test; + +import java.util.logging.*; +import java.util.*; +import java.io.*; +import java.net.*; + +import de.javawi.jstun.attribute.*; +import de.javawi.jstun.header.*; +import de.javawi.jstun.util.UtilityException; + +public class BindingLifetimeTest { + private static Logger logger = Logger.getLogger("de.javawi.stun.test.BindingLifetimeTest"); + String stunServer; + int port; + int timeout = 300; //ms + MappedAddress ma; + Timer timer; + DatagramSocket initialSocket; + + // start value for binary search - should be carefully choosen + int upperBinarySearchLifetime = 345000; // ms + int lowerBinarySearchLifetime = 0; + int binarySearchLifetime = ( upperBinarySearchLifetime + lowerBinarySearchLifetime ) / 2; + + // lifetime value + int lifetime = -1; // -1 means undefined. + boolean completed = false; + + public BindingLifetimeTest(String stunServer, int port) { + super(); + this.stunServer = stunServer; + this.port = port; + timer = new Timer(true); + } + + public void test() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException { + initialSocket = new DatagramSocket(); + initialSocket.connect(InetAddress.getByName(stunServer), port); + initialSocket.setSoTimeout(timeout); + + if (bindingCommunicationInitialSocket()) { + return; + } + BindingLifetimeTask task = new BindingLifetimeTask(); + timer.schedule(task, binarySearchLifetime); + logger.finer("Timer scheduled initially: " + binarySearchLifetime + "."); + } + + private boolean bindingCommunicationInitialSocket() throws UtilityException, IOException, MessageHeaderParsingException, MessageAttributeParsingException { + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + ChangeRequest changeRequest = new ChangeRequest(); + sendMH.addMessageAttribute(changeRequest); + byte[] data = sendMH.getBytes(); + + DatagramPacket send = new DatagramPacket(data, data.length, InetAddress.getByName(stunServer), port); + initialSocket.send(send); + logger.finer("Binding Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + initialSocket.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress); + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + logger.config("Message header contains an Errorcode message attribute."); + return true; + } + if (ma == null) { + logger.config("Response does not contain a Mapped Address message attribute."); + return true; + } + return false; + } + + public int getLifetime() { + return lifetime; + } + + public boolean isCompleted() { + return completed; + } + + public void setUpperBinarySearchLifetime(int upperBinarySearchLifetime) { + this.upperBinarySearchLifetime = upperBinarySearchLifetime; + binarySearchLifetime = ( upperBinarySearchLifetime + lowerBinarySearchLifetime ) / 2; + } + + class BindingLifetimeTask extends TimerTask { + + public BindingLifetimeTask() { + super(); + } + + public void run() { + try { + lifetimeQuery(); + } catch (Exception e) { + logger.config("Unhandled Exception. BindLifetimeTasks stopped."); + e.printStackTrace(); + } + } + + public void lifetimeQuery() throws UtilityException, MessageAttributeException, MessageHeaderParsingException, MessageAttributeParsingException, IOException { + try { + DatagramSocket socket = new DatagramSocket(); + socket.connect(InetAddress.getByName(stunServer), port); + socket.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + ChangeRequest changeRequest = new ChangeRequest(); + ResponseAddress responseAddress = new ResponseAddress(); + responseAddress.setAddress(ma.getAddress()); + responseAddress.setPort(ma.getPort()); + sendMH.addMessageAttribute(changeRequest); + sendMH.addMessageAttribute(responseAddress); + byte[] data = sendMH.getBytes(); + + DatagramPacket send = new DatagramPacket(data, data.length, InetAddress.getByName(stunServer), port); + socket.send(send); + logger.finer("Binding Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + initialSocket.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + logger.config("Message header contains errorcode message attribute."); + return; + } + logger.finer("Binding Response received."); + if (upperBinarySearchLifetime == (lowerBinarySearchLifetime + 1)) { + logger.config("BindingLifetimeTest completed. UDP binding lifetime: " + binarySearchLifetime + "."); + completed = true; + return; + } + lifetime = binarySearchLifetime; + logger.finer("Lifetime update: " + lifetime + "."); + lowerBinarySearchLifetime = binarySearchLifetime; + binarySearchLifetime = ( upperBinarySearchLifetime + lowerBinarySearchLifetime ) / 2; + if (binarySearchLifetime > 0) { + BindingLifetimeTask task = new BindingLifetimeTask(); + timer.schedule(task, binarySearchLifetime); + logger.finer("Timer scheduled: " + binarySearchLifetime + "."); + } else { + completed = true; + } + } catch (SocketTimeoutException ste) { + logger.finest("Read operation at query socket timeout."); + if (upperBinarySearchLifetime == (lowerBinarySearchLifetime + 1)) { + logger.config("BindingLifetimeTest completed. UDP binding lifetime: " + binarySearchLifetime + "."); + completed = true; + return; + } + upperBinarySearchLifetime = binarySearchLifetime; + binarySearchLifetime = ( upperBinarySearchLifetime + lowerBinarySearchLifetime ) / 2; + if (binarySearchLifetime > 0) { + if (bindingCommunicationInitialSocket()) { + return; + } + BindingLifetimeTask task = new BindingLifetimeTask(); + timer.schedule(task, binarySearchLifetime); + logger.finer("Timer scheduled: " + binarySearchLifetime + "."); + } else { + completed = true; + } + } + } + } +} + diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/DiscoveryInfo.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/DiscoveryInfo.java new file mode 100644 index 000000000..abaab15eb --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/DiscoveryInfo.java @@ -0,0 +1,153 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test; + +import java.net.*; + +public class DiscoveryInfo { + private InetAddress testIP; + private boolean error = false; + private int errorResponseCode = 0; + private String errorReason; + private boolean openAccess = false; + private boolean blockedUDP = false; + private boolean fullCone = false; + private boolean restrictedCone = false; + private boolean portRestrictedCone = false; + private boolean symmetric = false; + private boolean symmetricUDPFirewall = false; + private InetAddress publicIP; + + public DiscoveryInfo(InetAddress testIP) { + this.testIP = testIP; + } + + public boolean isError() { + return error; + } + + public void setError(int responseCode, String reason) { + this.error = true; + this.errorResponseCode = responseCode; + this.errorReason = reason; + } + + public boolean isOpenAccess() { + if (error) return false; + return openAccess; + } + + public void setOpenAccess() { + this.openAccess = true; + } + + public boolean isBlockedUDP() { + if (error) return false; + return blockedUDP; + } + + public void setBlockedUDP() { + this.blockedUDP = true; + } + + public boolean isFullCone() { + if (error) return false; + return fullCone; + } + + public void setFullCone() { + this.fullCone = true; + } + + public boolean isPortRestrictedCone() { + if (error) return false; + return portRestrictedCone; + } + + public void setPortRestrictedCone() { + this.portRestrictedCone = true; + } + + public boolean isRestrictedCone() { + if (error) return false; + return restrictedCone; + } + + public void setRestrictedCone() { + this.restrictedCone = true; + } + + public boolean isSymmetric() { + if (error) return false; + return symmetric; + } + + public void setSymmetric() { + this.symmetric = true; + } + + public boolean isSymmetricUDPFirewall() { + if (error) return false; + return symmetricUDPFirewall; + } + + public void setSymmetricUDPFirewall() { + this.symmetricUDPFirewall = true; + } + + public InetAddress getPublicIP() { + return publicIP; + } + + public InetAddress getLocalIP() { + return testIP; + } + + public void setPublicIP(InetAddress publicIP) { + this.publicIP = publicIP; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("Network interface: "); + try { + sb.append(NetworkInterface.getByInetAddress(testIP).getName()); + } catch (SocketException se) { + sb.append("unknown"); + } + sb.append("\n"); + sb.append("Local IP address: "); + sb.append(testIP.getHostAddress()); + sb.append("\n"); + if (error) { + sb.append(errorReason + " - Responsecode: " + errorResponseCode); + return sb.toString(); + } + sb.append("Result: "); + if (openAccess) sb.append("Open access to the Internet.\n"); + if (blockedUDP) sb.append("Firewall blocks UDP.\n"); + if (fullCone) sb.append("Full Cone NAT handles connections.\n"); + if (restrictedCone) sb.append("Restricted Cone NAT handles connections.\n"); + if (portRestrictedCone) sb.append("Port restricted Cone NAT handles connections.\n"); + if (symmetric) sb.append("Symmetric Cone NAT handles connections.\n"); + if (symmetricUDPFirewall) sb.append ("Symmetric UDP Firewall handles connections.\n"); + if (!openAccess && !blockedUDP && !fullCone && !restrictedCone && !portRestrictedCone && !symmetric && !symmetricUDPFirewall) sb.append("unkown\n"); + sb.append("Public IP address: "); + if (publicIP != null) { + sb.append(publicIP.getHostAddress()); + } else { + sb.append("unknown"); + } + sb.append("\n"); + return sb.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/DiscoveryTest.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/DiscoveryTest.java new file mode 100644 index 000000000..4f940adfe --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/DiscoveryTest.java @@ -0,0 +1,351 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.logging.Logger; + + + + + +import de.javawi.jstun.attribute.ChangeRequest; +import de.javawi.jstun.attribute.ChangedAddress; +import de.javawi.jstun.attribute.ErrorCode; +import de.javawi.jstun.attribute.MappedAddress; +import de.javawi.jstun.attribute.MessageAttribute; +import de.javawi.jstun.attribute.MessageAttributeException; +import de.javawi.jstun.attribute.MessageAttributeParsingException; +import de.javawi.jstun.header.MessageHeader; +import de.javawi.jstun.header.MessageHeaderParsingException; +import de.javawi.jstun.util.UtilityException; + +public class DiscoveryTest { + private static Logger logger = Logger.getLogger("de.javawi.stun.test.DiscoveryTest"); + InetAddress iaddress; + String stunServer; + int port; + int timeoutInitValue = 300; //ms + MappedAddress ma = null; + ChangedAddress ca = null; + boolean nodeNatted = true; + DatagramSocket socketTest1 = null; + DiscoveryInfo di = null; + + public DiscoveryTest(InetAddress iaddress , String stunServer, int port) { + super(); + this.iaddress = iaddress; + this.stunServer = stunServer; + this.port = port; + } + + public DiscoveryInfo test() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException{ + ma = null; + ca = null; + nodeNatted = true; + socketTest1 = null; + di = new DiscoveryInfo(iaddress); + + if (test1()) { + if (test2()) { + if (test1Redo()) { + test3(); + } + } + } + + socketTest1.close(); + + return di; + } + + private boolean test1() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageHeaderParsingException { + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + try { + // Test 1 including response + socketTest1 = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + socketTest1.setReuseAddress(true); + socketTest1.connect(InetAddress.getByName(stunServer), port); + socketTest1.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + socketTest1.send(send); + logger.finer("Test 1: Binding Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + socketTest1.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + + ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress); + ca = (ChangedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ChangedAddress); + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.config("Message header contains an Errorcode message attribute."); + return false; + } + if ((ma == null) || (ca == null)) { + di.setError(700, "The server is sending an incomplete response (Mapped Address and Changed Address message attributes are missing). The client should not retry."); + logger.config("Response does not contain a Mapped Address or Changed Address message attribute."); + return false; + } else { + di.setPublicIP(ma.getAddress().getInetAddress()); + if ((ma.getPort() == socketTest1.getLocalPort()) && (ma.getAddress().getInetAddress().equals(socketTest1.getLocalAddress()))) { + logger.fine("Node is not natted."); + nodeNatted = false; + } else { + logger.fine("Node is natted."); + } + return true; + } + } catch (SocketTimeoutException ste) { + if (timeSinceFirstTransmission < 7900) { + logger.finer("Test 1: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + // node is not capable of udp communication + logger.finer("Test 1: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + di.setBlockedUDP(); + logger.fine("Node is not capable of UDP communication."); + return false; + } + } + } + } + + private boolean test2() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException { + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + try { + // Test 2 including response + DatagramSocket sendSocket = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + sendSocket.connect(InetAddress.getByName(stunServer), port); + sendSocket.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + changeRequest.setChangeIP(); + changeRequest.setChangePort(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + sendSocket.send(send); + logger.finer("Test 2: Binding Request sent."); + + int localPort = sendSocket.getLocalPort(); + InetAddress localAddress = sendSocket.getLocalAddress(); + + sendSocket.close(); + + DatagramSocket receiveSocket = new DatagramSocket(localPort, localAddress); + receiveSocket.connect(ca.getAddress().getInetAddress(), ca.getPort()); + receiveSocket.setSoTimeout(timeout); + + MessageHeader receiveMH = new MessageHeader(); + while(!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + receiveSocket.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.config("Message header contains an Errorcode message attribute."); + return false; + } + if (!nodeNatted) { + di.setOpenAccess(); + logger.fine("Node has open access to the Internet (or, at least the node is behind a full-cone NAT without translation)."); + } else { + di.setFullCone(); + logger.fine("Node is behind a full-cone NAT."); + } + return false; + } catch (SocketTimeoutException ste) { + if (timeSinceFirstTransmission < 7900) { + logger.finer("Test 2: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + logger.finer("Test 2: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + if (!nodeNatted) { + di.setSymmetricUDPFirewall(); + logger.fine("Node is behind a symmetric UDP firewall."); + return false; + } else { + // not is natted + // redo test 1 with address and port as offered in the changed-address message attribute + return true; + } + } + } + } + } + + private boolean test1Redo() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageHeaderParsingException{ + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + // redo test 1 with address and port as offered in the changed-address message attribute + try { + // Test 1 with changed port and address values + socketTest1.connect(ca.getAddress().getInetAddress(), ca.getPort()); + socketTest1.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + socketTest1.send(send); + logger.finer("Test 1 redo with changed address: Binding Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + socketTest1.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + MappedAddress ma2 = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress); + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.config("Message header contains an Errorcode message attribute."); + return false; + } + if (ma2 == null) { + di.setError(700, "The server is sending an incomplete response (Mapped Address message attribute is missing). The client should not retry."); + logger.config("Response does not contain a Mapped Address message attribute."); + return false; + } else { + if ((ma.getPort() != ma2.getPort()) || (!(ma.getAddress().getInetAddress().equals(ma2.getAddress().getInetAddress())))) { + di.setSymmetric(); + logger.fine("Node is behind a symmetric NAT."); + return false; + } + } + return true; + } catch (SocketTimeoutException ste2) { + if (timeSinceFirstTransmission < 7900) { + logger.config("Test 1 redo with changed address: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + logger.config("Test 1 redo with changed address: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + return false; + } + } + } + } + + private void test3() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException { + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + try { + // Test 3 including response + DatagramSocket sendSocket = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + sendSocket.connect(InetAddress.getByName(stunServer), port); + sendSocket.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + changeRequest.setChangePort(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + sendSocket.send(send); + logger.finer("Test 3: Binding Request sent."); + + int localPort = sendSocket.getLocalPort(); + InetAddress localAddress = sendSocket.getLocalAddress(); + + sendSocket.close(); + + DatagramSocket receiveSocket = new DatagramSocket(localPort, localAddress); + receiveSocket.connect(InetAddress.getByName(stunServer), ca.getPort()); + receiveSocket.setSoTimeout(timeout); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + receiveSocket.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.config("Message header contains an Errorcode message attribute."); + return; + } + if (nodeNatted) { + di.setRestrictedCone(); + logger.fine("Node is behind a restricted NAT."); + return; + } + } catch (SocketTimeoutException ste) { + if (timeSinceFirstTransmission < 7900) { + logger.finer("Test 3: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + logger.finer("Test 3: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + di.setPortRestrictedCone(); + logger.fine("Node is behind a port restricted NAT."); + return; + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/BindingLifetimeTestDemo.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/BindingLifetimeTestDemo.java new file mode 100644 index 000000000..37e20f846 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/BindingLifetimeTestDemo.java @@ -0,0 +1,47 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test.demo; + +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +import de.javawi.jstun.test.BindingLifetimeTest; + +public class BindingLifetimeTestDemo { + public static void main(String args[]) { + try { + Handler fh = new FileHandler("logging.txt"); + fh.setFormatter(new SimpleFormatter()); + Logger.getLogger("de.javawi.stun").addHandler(fh); + Logger.getLogger("de.javawi.stun").setLevel(Level.ALL); + BindingLifetimeTest test = new BindingLifetimeTest("iphone-stun.freenet.de", 3478); + // iphone-stun.freenet.de:3478 + // larry.gloo.net:3478 + // stun.xten.net:3478 + test.test(); + boolean continueWhile = true; + while(continueWhile) { + Thread.sleep(5000); + if (test.getLifetime() != -1) { + System.out.println("Lifetime: " + test.getLifetime() + " Finished: " + test.isCompleted()); + if (test.isCompleted()) continueWhile = false; + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/DiscoveryTestDemo.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/DiscoveryTestDemo.java new file mode 100644 index 000000000..76a6c17e7 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/DiscoveryTestDemo.java @@ -0,0 +1,75 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test.demo; + +import java.net.BindException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +import de.javawi.jstun.test.DiscoveryTest; + +public class DiscoveryTestDemo implements Runnable { + InetAddress iaddress; + + public DiscoveryTestDemo(InetAddress iaddress) { + this.iaddress = iaddress; + } + + public void run() { + try { + DiscoveryTest test = new DiscoveryTest(iaddress, "jstun.javawi.de", 3478); + //DiscoveryTest test = new DiscoveryTest(iaddress, "stun.sipgate.net", 10000); + // iphone-stun.freenet.de:3478 + // larry.gloo.net:3478 + // stun.xten.net:3478 + // stun.sipgate.net:10000 + System.out.println(test.test()); + } catch (BindException be) { + System.out.println(iaddress.toString() + ": " + be.getMessage()); + } catch (Exception e) { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + } + + public static void main(String args[]) { + try { + Handler fh = new FileHandler("logging.txt"); + fh.setFormatter(new SimpleFormatter()); + Logger.getLogger("de.javawi.stun").addHandler(fh); + Logger.getLogger("de.javawi.stun").setLevel(Level.ALL); + + Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); + while (ifaces.hasMoreElements()) { + NetworkInterface iface = ifaces.nextElement(); + Enumeration iaddresses = iface.getInetAddresses(); + while (iaddresses.hasMoreElements()) { + InetAddress iaddress = iaddresses.nextElement(); + if (Class.forName("java.net.Inet4Address").isInstance(iaddress)) { + if ((!iaddress.isLoopbackAddress()) && (!iaddress.isLinkLocalAddress())) { + Thread thread = new Thread(new DiscoveryTestDemo(iaddress)); + thread.start(); + } + } + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/StunServer.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/StunServer.java new file mode 100644 index 000000000..b72ffe7c2 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/StunServer.java @@ -0,0 +1,263 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test.demo; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Vector; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +import de.javawi.jstun.attribute.ChangeRequest; +import de.javawi.jstun.attribute.ChangedAddress; +import de.javawi.jstun.attribute.MappedAddress; +import de.javawi.jstun.attribute.MessageAttributeException; +import de.javawi.jstun.attribute.MessageAttributeParsingException; +import de.javawi.jstun.attribute.ResponseAddress; +import de.javawi.jstun.attribute.SourceAddress; +import de.javawi.jstun.attribute.UnknownAttribute; +import de.javawi.jstun.attribute.UnknownMessageAttributeException; +import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType; +import de.javawi.jstun.header.MessageHeader; +import de.javawi.jstun.header.MessageHeaderParsingException; +import de.javawi.jstun.header.MessageHeaderInterface.MessageHeaderType; +import de.javawi.jstun.util.Address; +import de.javawi.jstun.util.UtilityException; + +/* + * This class implements a STUN server as described in RFC 3489. + * The server requires a machine that is dual-homed to be functional. + */ +public class StunServer { + private static Logger logger = Logger.getLogger("de.javawi.stun.test.StunServer"); + Vector sockets; + + public StunServer(int primaryPort, InetAddress primary, int secondaryPort, InetAddress secondary) throws SocketException { + sockets = new Vector(); + sockets.add(new DatagramSocket(primaryPort, primary)); + sockets.add(new DatagramSocket(secondaryPort, primary)); + sockets.add(new DatagramSocket(primaryPort, secondary)); + sockets.add(new DatagramSocket(secondaryPort, secondary)); + } + + public void start() throws SocketException { + for (DatagramSocket socket : sockets) { + socket.setReceiveBufferSize(2000); + StunServerReceiverThread ssrt = new StunServerReceiverThread(socket); + ssrt.start(); + } + } + + /* + * Inner class to handle incoming packets and react accordingly. + * I decided not to start a thread for every received Binding Request, because the time + * required to receive a Binding Request, parse it, generate a Binding Response and send + * it varies only between 2 and 4 milliseconds. This amount of time is small enough so + * that no extra thread is needed for incoming Binding Request. + */ + class StunServerReceiverThread extends Thread { + private DatagramSocket receiverSocket; + private DatagramSocket changedPort; + private DatagramSocket changedIP; + private DatagramSocket changedPortIP; + + StunServerReceiverThread(DatagramSocket datagramSocket) { + this.receiverSocket = datagramSocket; + for (DatagramSocket socket : sockets) { + if ((socket.getLocalPort() != receiverSocket.getLocalPort()) && + (socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedPort = socket; + if ((socket.getLocalPort() == receiverSocket.getLocalPort()) && + (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedIP = socket; + if ((socket.getLocalPort() != receiverSocket.getLocalPort()) && + (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedPortIP = socket; + } + } + + public void run() { + while (true) { + try { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + receiverSocket.receive(receive); + logger.finest(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " datagram received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort()); + MessageHeader receiveMH = MessageHeader.parseHeader(receive.getData()); + try { + receiveMH.parseAttributes(receive.getData()); + if (receiveMH.getType() == MessageHeaderType.BindingRequest) { + logger.config(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " Binding Request received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort()); + ChangeRequest cr = (ChangeRequest) receiveMH.getMessageAttribute(MessageAttributeType.ChangeRequest); + if (cr == null) throw new MessageAttributeException("Message attribute change request is not set."); + ResponseAddress ra = (ResponseAddress) receiveMH.getMessageAttribute(MessageAttributeType.ResponseAddress); + + MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingResponse); + sendMH.setTransactionID(receiveMH.getTransactionID()); + + // Mapped address attribute + MappedAddress ma = new MappedAddress(); + ma.setAddress(new Address(receive.getAddress().getAddress())); + ma.setPort(receive.getPort()); + sendMH.addMessageAttribute(ma); + // Changed address attribute + ChangedAddress ca = new ChangedAddress(); + ca.setAddress(new Address(changedPortIP.getLocalAddress().getAddress())); + ca.setPort(changedPortIP.getLocalPort()); + sendMH.addMessageAttribute(ca); + if (cr.isChangePort() && (!cr.isChangeIP())) { + logger.finer("Change port received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(changedPort.getLocalAddress().getAddress())); + sa.setPort(changedPort.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + changedPort.send(send); + logger.config(changedPort.getLocalAddress().getHostAddress() + ":" + changedPort.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } else if ((!cr.isChangePort()) && cr.isChangeIP()) { + logger.finer("Change ip received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(changedIP.getLocalAddress().getAddress())); + sa.setPort(changedIP.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + changedIP.send(send); + logger.config(changedIP.getLocalAddress().getHostAddress() + ":" + changedIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } else if ((!cr.isChangePort()) && (!cr.isChangeIP())) { + logger.finer("Nothing received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(receiverSocket.getLocalAddress().getAddress())); + sa.setPort(receiverSocket.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + receiverSocket.send(send); + logger.config(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } else if (cr.isChangePort() && cr.isChangeIP()) { + logger.finer("Change port and ip received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(changedPortIP.getLocalAddress().getAddress())); + sa.setPort(changedPortIP.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + changedPortIP.send(send); + logger.config(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } + } + } catch (UnknownMessageAttributeException umae) { + umae.printStackTrace(); + // Generate Binding error response + MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingErrorResponse); + sendMH.setTransactionID(receiveMH.getTransactionID()); + + // Unknown attributes + UnknownAttribute ua = new UnknownAttribute(); + ua.addAttribute(umae.getType()); + sendMH.addMessageAttribute(ua); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + receiverSocket.send(send); + logger.config(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Error Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } + } catch (IOException ioe) { + ioe.printStackTrace(); + } catch (MessageAttributeParsingException mape) { + mape.printStackTrace(); + } catch (MessageAttributeException mae) { + mae.printStackTrace(); + } catch (MessageHeaderParsingException mhpe) { + mhpe.printStackTrace(); + } catch (UtilityException ue) { + ue.printStackTrace(); + } catch (ArrayIndexOutOfBoundsException aioobe) { + aioobe.printStackTrace(); + } + } + } + } + + /* + * To invoke the STUN server two IP addresses and two ports are required. + */ + public static void main(String args[]) { + try { + if (args.length != 4) { + System.out.println("usage: java de.javawi.jstun.test.demo.StunServer PORT1 IP1 PORT2 IP2"); + System.out.println(); + System.out.println(" PORT1 - the first port that should be used by the server"); + System.out.println(" IP1 - the first ip address that should be used by the server"); + System.out.println(" PORT2 - the second port that should be used by the server"); + System.out.println(" IP2 - the second ip address that should be used by the server"); + System.exit(0); + } + Handler fh = new FileHandler("logging_server.txt"); + fh.setFormatter(new SimpleFormatter()); + Logger.getLogger("de.javawi.stun").addHandler(fh); + Logger.getLogger("de.javawi.stun").setLevel(Level.ALL); + StunServer ss = new StunServer(Integer.parseInt(args[0]), + InetAddress.getByName(args[1]), + Integer.parseInt(args[2]), + InetAddress.getByName(args[3])); + ss.start(); + } catch (SocketException se) { + se.printStackTrace(); + } catch (UnknownHostException uhe) { + uhe.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/ice/Candidate.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/ice/Candidate.java new file mode 100644 index 000000000..22dd58fb5 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/ice/Candidate.java @@ -0,0 +1,115 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test.demo.ice; + +import java.net.DatagramSocket; +import java.net.SocketException; +import java.net.UnknownHostException; + +import de.javawi.jstun.util.Address; +import de.javawi.jstun.util.UtilityException; + +public class Candidate implements Comparable { + // The ieft-mmusic-ice-12 draft is not non-ambigious about the number of types. + // Chapter 5.1 defines 3 and 4 types on page 16 and page 17, respectively. + public enum CandidateType { Local, ServerReflexive, PeerReflexive, Relayed }; + + private DatagramSocket socket; + private CandidateType type; + private short componentId; + private int priority; + private int foundationId; + private Candidate base; + private boolean isInUse; + + public Candidate(Address address, short componentId) throws SocketException, UnknownHostException, UtilityException { + this.socket = new DatagramSocket(0, address.getInetAddress()); + this.type = CandidateType.Local; + this.componentId = componentId; + this.priority = 0; + this.base = this; + this.isInUse = false; + } + + public Candidate(Address address, CandidateType type, short componentId, Candidate base) throws SocketException, UnknownHostException, UtilityException { + this.socket = new DatagramSocket(0, address.getInetAddress()); + this.type = type; + setComponentId(componentId); + this.priority = 0; + this.base = base; + this.isInUse = false; + } + + public void setBase(Candidate base) { + this.base = base; + } + + public Candidate getBase() { + return base; + } + + public CandidateType getCandidateType() { + return type; + } + + public void setComponentId(short componentId) { + if ((componentId < 1) || (componentId > 256)) throw new IllegalArgumentException(componentId + " is not between 1 and 256 inclusive."); + this.componentId = componentId; + } + + public short getComponentId() { + return componentId; + } + + public void setFoundationId(int foundationId) { + this.foundationId = foundationId; + } + + public int getFoundationId() { + return foundationId; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public int getPriority() { + return priority; + } + + public Address getAddress() throws UtilityException { + return new Address(socket.getLocalAddress().getAddress()); + } + + public int getPort() { + return socket.getLocalPort(); + } + + public void setInUse(boolean isInUse) { + this.isInUse = isInUse; + } + + public boolean getInUse() { + return isInUse; + } + + public int compareTo(Object arg0) { + Candidate cand = (Candidate) arg0; + return cand.getPriority() - getPriority(); + } + + public boolean equals(Object o) { + if (o == null) return false; + if ((((Candidate) o).socket.equals(socket)) && (((Candidate) o).base.equals(base))) return true; + return false; + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/ice/ICENegociator.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/ice/ICENegociator.java new file mode 100644 index 000000000..502528c5b --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/test/demo/ice/ICENegociator.java @@ -0,0 +1,146 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.test.demo.ice; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import de.javawi.jstun.test.DiscoveryInfo; +import de.javawi.jstun.test.DiscoveryTest; +import de.javawi.jstun.test.demo.ice.Candidate.CandidateType; +import de.javawi.jstun.util.Address; + +public class ICENegociator { + // type preference must be an integere from 0 (=lowest) to 126 (=highest) (inclusive) + private final static int LOCAL_PREFERENCE = 0; + private final static int SERVER_REFLEXIVE_PREFERENCE = 42; + private final static int PEER_REFLEXIVE_PREFERENCE = 84; + private final static int RELAYED_PREFERENCE = 126; + + // component id + private short componentId; + + // candidates + HashSet candidates; + + public ICENegociator(short componentId) { + this.componentId = componentId; + candidates = new HashSet(); + } + + /* + * This method gathers candidate addresses as described in draft-ietf-mmusic-ice-12.txt Chapter 2.1 + * Unfortunately, only the candidates of the direct attached network interfaces and server reflexive + * addreses are gathered. So far, no support for relayed candidates is available (because I am not + * aware of any STUN relay server). + */ + public void gatherCandidateAddresses() { + candidates = new HashSet(); + try { + Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); + while (ifaces.hasMoreElements()) { + NetworkInterface iface = ifaces.nextElement(); + Enumeration iaddresses = iface.getInetAddresses(); + while (iaddresses.hasMoreElements()) { + InetAddress iaddress = iaddresses.nextElement(); + if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress()) { + // add host candidate + Candidate local = new Candidate(new Address(iaddress.getAddress()), componentId); + candidates.add(local); + // add server reflexive address + DiscoveryTest test = new DiscoveryTest(iaddress, "iphone-stun.freenet.de", 3478); + DiscoveryInfo di = test.test(); + if (di.getPublicIP() != null) { + Candidate cand = new Candidate(new Address(di.getPublicIP().getAddress()), CandidateType.ServerReflexive, componentId, local); + cand.setComponentId(componentId); + candidates.add(cand); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void prioritizeCandidates() { + // count number of candidate types + int numberLocal = 0; + int numberServerReflexive = 0; + int numberPeerReflexive = 0; + int numberRelayed = 0; + // count number of candidates of a particular type + Iterator iterCandidates = candidates.iterator(); + while (iterCandidates.hasNext()) { + Candidate cand = iterCandidates.next(); + CandidateType type = cand.getCandidateType(); + if (type == CandidateType.Local) numberLocal++; + else if (type == CandidateType.ServerReflexive) numberServerReflexive++; + else if (type == CandidateType.PeerReflexive) numberPeerReflexive++; + else if (type == CandidateType.Relayed) numberRelayed++; + } + // assign priorities + iterCandidates = candidates.iterator(); + while (iterCandidates.hasNext()) { + int typeValue = 0; + int localValue = 0; + int componentValue = 0; + Candidate cand = iterCandidates.next(); + CandidateType type = cand.getCandidateType(); + if (type == CandidateType.Local) { + typeValue = LOCAL_PREFERENCE; + localValue = numberLocal--; + } + else if (type == CandidateType.ServerReflexive) { + typeValue = SERVER_REFLEXIVE_PREFERENCE; + localValue = numberServerReflexive--; + } + else if (type == CandidateType.PeerReflexive) { + typeValue = PEER_REFLEXIVE_PREFERENCE; + localValue = numberPeerReflexive--; + } + else if (type == CandidateType.Relayed) { + typeValue = RELAYED_PREFERENCE; + localValue = numberRelayed--; + } + componentValue = cand.getComponentId(); + int priority = ((2 ^ 24) * typeValue) + ((2 ^ 8) * localValue) + componentValue; + cand.setPriority(priority); + } + } + + public List getSortedCandidates() { + Vector sortedCandidates = new Vector(candidates); + Collections.sort(sortedCandidates); + return sortedCandidates; + } + + public static void main(String args[]) { + ICENegociator cc = new ICENegociator((short) 1); + // gather candidates + cc.gatherCandidateAddresses(); + // priorize candidates + cc.prioritizeCandidates(); + // get SortedCandidates + List sortedCandidates = cc.getSortedCandidates(); + + // sent sorted candidate addresses to peer over SDP + // received sorted candidate addresses of peer over SDP + + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/Address.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/Address.java new file mode 100644 index 000000000..46ad1a0ef --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/Address.java @@ -0,0 +1,102 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.util; + +import java.util.*; +import java.net.*; + +public class Address { + int firstOctet; + int secondOctet; + int thirdOctet; + int fourthOctet; + + public Address(int firstOctet, int secondOctet, int thirdOctet, int fourthOctet) throws UtilityException { + if ((firstOctet < 0) || (firstOctet > 255) || (secondOctet < 0) || (secondOctet > 255) || (thirdOctet < 0) || (thirdOctet > 255) || (fourthOctet < 0) || (fourthOctet > 255)) { + throw new UtilityException("Address is malformed."); + } + this.firstOctet = firstOctet; + this.secondOctet = secondOctet; + this.thirdOctet = thirdOctet; + this.fourthOctet = fourthOctet; + } + + public Address(String address) throws UtilityException { + StringTokenizer st = new StringTokenizer(address, "."); + if (st.countTokens() != 4) { + throw new UtilityException("4 octets in address string are required."); + } + int i = 0; + while (st.hasMoreTokens()) { + int temp = Integer.parseInt(st.nextToken()); + if ((temp < 0) || (temp > 255)) { + throw new UtilityException("Address is in incorrect format."); + } + switch (i) { + case 0: firstOctet = temp; ++i; break; + case 1: secondOctet = temp; ++i; break; + case 2: thirdOctet = temp; ++i; break; + case 3: fourthOctet = temp; ++i; break; + } + } + } + + public Address(byte[] address) throws UtilityException { + if (address.length < 4) { + throw new UtilityException("4 bytes are required."); + } + firstOctet = Utility.oneByteToInteger(address[0]); + secondOctet = Utility.oneByteToInteger(address[1]); + thirdOctet = Utility.oneByteToInteger(address[2]); + fourthOctet = Utility.oneByteToInteger(address[3]); + } + + public String toString() { + return firstOctet + "." + secondOctet + "." + thirdOctet + "." + fourthOctet; + } + + public byte[] getBytes() throws UtilityException { + byte[] result = new byte[4]; + result[0] = Utility.integerToOneByte(firstOctet); + result[1] = Utility.integerToOneByte(secondOctet); + result[2] = Utility.integerToOneByte(thirdOctet); + result[3] = Utility.integerToOneByte(fourthOctet); + return result; + } + + public InetAddress getInetAddress() throws UtilityException, UnknownHostException { + byte[] address = new byte[4]; + address[0] = Utility.integerToOneByte(firstOctet); + address[1] = Utility.integerToOneByte(secondOctet); + address[2] = Utility.integerToOneByte(thirdOctet); + address[3] = Utility.integerToOneByte(fourthOctet); + return InetAddress.getByAddress(address); + } + + public boolean equals(Object obj) { + if (obj == null) return false; + try { + byte[] data1 = this.getBytes(); + byte[] data2 = ((Address) obj).getBytes(); + if ((data1[0] == data2[0]) && (data1[1] == data2[1]) && + (data1[2] == data2[2]) && (data1[3] == data2[3])) return true; + return false; + } catch (UtilityException ue) { + return false; + } + } + + public int hashCode() { + return (firstOctet << 24) + (secondOctet << 16) + (thirdOctet << 8) + fourthOctet; + } + +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/Utility.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/Utility.java new file mode 100644 index 000000000..91c2d88e9 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/Utility.java @@ -0,0 +1,68 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.util; + +public class Utility { + + public static final byte integerToOneByte(int value) throws UtilityException { + if ((value > Math.pow(2,15)) || (value < 0)) { + throw new UtilityException("Integer value " + value + " is larger than 2^15"); + } + return (byte)(value & 0xFF); + } + + public static final byte[] integerToTwoBytes(int value) throws UtilityException { + byte[] result = new byte[2]; + if ((value > Math.pow(2,31)) || (value < 0)) { + throw new UtilityException("Integer value " + value + " is larger than 2^31"); + } + result[0] = (byte)((value >>> 8) & 0xFF); + result[1] = (byte)(value & 0xFF); + return result; + } + + public static final byte[] integerToFourBytes(int value) throws UtilityException { + byte[] result = new byte[4]; + if ((value > Math.pow(2,63)) || (value < 0)) { + throw new UtilityException("Integer value " + value + " is larger than 2^63"); + } + result[0] = (byte)((value >>> 24) & 0xFF); + result[1] = (byte)((value >>> 16) & 0xFF); + result[2] = (byte)((value >>> 8) & 0xFF); + result[3] = (byte)(value & 0xFF); + return result; + } + + public static final int oneByteToInteger(byte value) throws UtilityException { + return (int)value & 0xFF; + } + + public static final int twoBytesToInteger(byte[] value) throws UtilityException { + if (value.length < 2) { + throw new UtilityException("Byte array too short!"); + } + int temp0 = value[0] & 0xFF; + int temp1 = value[1] & 0xFF; + return ((temp0 << 8) + temp1); + } + + public static final long fourBytesToLong(byte[] value) throws UtilityException { + if (value.length < 4) { + throw new UtilityException("Byte array too short!"); + } + int temp0 = value[0] & 0xFF; + int temp1 = value[1] & 0xFF; + int temp2 = value[2] & 0xFF; + int temp3 = value[3] & 0xFF; + return (((long)temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3); + } +} diff --git a/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/UtilityException.java b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/UtilityException.java new file mode 100644 index 000000000..d6f65fa75 --- /dev/null +++ b/p2pproxy/dependencies-src/jstun-src-0.7.1/de/javawi/jstun/util/UtilityException.java @@ -0,0 +1,21 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package de.javawi.jstun.util; + +public class UtilityException extends Exception { + private static final long serialVersionUID = 3545800974716581680L; + + UtilityException(String mesg) { + super(mesg); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/pom.xml b/p2pproxy/dependencies-src/jxse-src-2.5/api/pom.xml new file mode 100644 index 000000000..4f467d1c9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/pom.xml @@ -0,0 +1,15 @@ + + + net.jxta.platform + jxta + 1.0 + ../pom.xml + + 4.0.0 + jxta-api + net.jxta.platform + jxta-api + jar + 1.0 + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/Version.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/Version.java new file mode 100644 index 000000000..f6604de0f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/Version.java @@ -0,0 +1,149 @@ +/* + * + * ==================================================================== + * + * Copyright (c) 2001 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta; + +import java.lang.Package; + +/** + * Provides easy access to Java Package information for the JXSE API. + */ +public final class Version { + + /** + * Returns the package. + * + * @return The specification title. + */ + public static Package getPackage() { + return Version.class.getPackage(); + } + + /** + * Returns the specification title. + * + * @return The specification title. + */ + public static String getSpecTitle() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getSpecificationTitle(); + } + + /** + * Returns the specification vendor. + * + * @return The specification vendor. + */ + public static String getSpecVendor() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getSpecificationVendor(); + } + + /** + * Returns the specification version. + * + * @return The specification version. + */ + public static String getSpecVersion() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getSpecificationVersion(); + } + + /** + * Returns the specification title. + * + * @return The specification title. + */ + public static String getImplTitle() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getImplementationTitle(); + } + + /** + * Returns the specification vendor. + * + * @return The specification vendor. + */ + public static String getImplVendor() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getImplementationVendor(); + } + + /** + * Returns the specification version. + * + * @return The specification version. + */ + public static String getImplVersion() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getImplementationVersion(); + } + + /** + * This class is a singleton. + */ + private Version() { + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/access/AccessService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/access/AccessService.java new file mode 100644 index 000000000..e5183e820 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/access/AccessService.java @@ -0,0 +1,146 @@ +/* + * + * ==================================================================== + * + * Copyright (c) 2001 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.access; + + +import net.jxta.credential.Credential; +import net.jxta.credential.PrivilegedOperation; +import net.jxta.document.Element; +import net.jxta.service.Service; + + +/** + * The Access Service is used by JXTA Applications and Services to determine if + specific operations are permitted for a particular identity. + * + *

Each Access Service implementation provides a mechanism for determining + * if, for a given operation and identity, the operation is permitted. + **/ +public interface AccessService extends Service { + + /** + * The result of an access check. + **/ + public enum AccessResult { + + /** + * State is unknown or could not be established. + * + *

The operation should not be performed. + * + *

This result may not be used by all Access Service + * implementations. + **/ + UNDETERMINED, /** + * Operation is disallowed. + * + *

The operation should not be performed. + * + **/ DISALLOWED, /** + * Operation is permitted. + * + *

The operation should be performed. + * + **/ PERMITTED, /** + * Operation would be permitted, but one (or more) of the provided + * credentials was expired. + * + *

The operation should not be performed. + * + *

This result may not be used by all Access Service + * implementations. + **/ PERMITTED_EXPIRED + } + + /** + * Determine if a privileged operation is permitted for a given identity. + * + * @param operation The operation which is being requested or {@code null}. + * {@code null} signifies that the operation is unimportant though the + * credential must be valid. + * @param credential The identity which is requesting or {@code null}. A + * {@code null} value indicates that no credential is available. + * @return the result of the access check. + **/ + public AccessResult doAccessCheck(PrivilegedOperation operation, Credential credential); + + /** + * Create a new privileged operation with the specified subject. Each + * operation is also associated with an identity, the offerer. Generally + * the privileged operation is cryptographically signed by the offerer. + * + * @see net.jxta.credential.Credential + * + * @param subject The subject of the operation. This usually identifies + * what operation is being requested. + * @param offerer The identity which is offering the operation. + * @return The privileged operation object + **/ + public PrivilegedOperation newPrivilegedOperation(Object subject, Credential offerer); + + /** + * Read a privileged operation from a portion of a structured document. + * + * @param source The root of the document portion containing the serialized + * representation of the privileged operation. + * @return The privileged operation object. + **/ + public PrivilegedOperation newPrivilegedOperation(Element source); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/access/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/access/package.html new file mode 100644 index 000000000..e9f7516ff --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/access/package.html @@ -0,0 +1,23 @@ + + + + + + + The Access Service provides a framework for using the identities created + with the Membership Service to control whether specific operations are + permitted. + +

The Access Service, like the Membership Service, is not associated with + a particular JXTA protocol. Each Access Service implementation is + responsible for its own protocol definition (if any). This approach is used + primarily so that JXTA bridges well to existing common Membership and Access + technologies. For example; PKI, LDAP Kerberos, NTLM and API based interfaces + such as PAM and JAAS. + + @see net.jxta.credential.Credential + @see net.jxta.credential.PrivilegedOperation + @see net.jxta.membership.MembershipService + @see JXTA Protocols Specification : Protocols + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/Codat.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/Codat.java new file mode 100644 index 000000000..75a45844a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/Codat.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.codat; + + +import net.jxta.document.Document; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroupID; + +import java.io.IOException; + + +/** + * The common container for managing content within JXTA. A Codat consists of: + *

    + *
  • Content data for the Codat in the form of a JXTA + * {@link net.jxta.document.Document}.
  • + *
  • A persistent canonical identifier for the Codat in the form of a + * {@link net.jxta.codat.CodatID}.
  • + *
  • An optional CodatID for an associated Codat for which this Codat is + * metadata.
  • + *
+ * + * @see net.jxta.codat.CodatID + * @see net.jxta.document.Document + */ +public class Codat { + + /** + * CodatID of this Codat. A persistent canonical identifier for this Codat. + */ + private final CodatID id; + + /** + * CodatID for an associated Codat for which this Codat is metadata. This + * may be the CodatId of another Codat in the same Peer Group or + * null. + */ + private final CodatID metaId; + + /** + * Contains the data of this Codat. + */ + private final Document doc; + + /** + * Constructs a Codat instance with a new CodatId given a PeerGroupID and + * a Document. + * + * @param groupID The peer group to which this Codat will belong. + * @param about The CodatID of an associated Codat for which this Codat is + * metadata or null if there is no associated Codat. + * @param document Document which contains the content data for this Codat. + * @throws IOException if there is an error accessing the document. + */ + public Codat(PeerGroupID groupID, CodatID about, Document document) throws IOException { + this(IDFactory.newCodatID(groupID, document.getStream()), about, document); + } + + /** + * Constructs a Codat instance for an existing Codat given it's + * CodatID and a document. + *

+ *

This implementation does not verify that the CodatID matches the + * provided Document. + * + * @param id CodatId of the new Codat. + * @param about CodatID of an associated Codat for which this Codat is metadata. + * @param document Document which contains the content data for this Codat. + */ + public Codat(CodatID id, CodatID about, Document document) { + if (null == id) { + throw new IllegalArgumentException("CodatID may not be null."); + } + + if (null == document) { + throw new IllegalArgumentException("Document may not be null."); + } + + this.id = id; + this.metaId = about; + this.doc = document; + } + + /** + * Returns the CodatID of this Codat. + * + * @return The CodatID of this Codat. + */ + public ID getCodatID() { + return id; + } + + /** + * Returns the CodatID of an associated Codat for which this Codat is + * metadata or null if there is no associated Codat. + * + * @return CodatID The CodatID of an associated Codat for which this Codat + * is metadata or null if there is no associated Codat. + */ + public ID getMetaID() { + return metaId; + } + + /** + * Returns a Document containing the data of this Codat. + * + * @return A Document containing the data of this Codat. + */ + public Document getDocument() { + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/CodatID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/CodatID.java new file mode 100644 index 000000000..5e7c94d75 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/CodatID.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.codat; + + +import java.net.URI; +import net.jxta.id.ID; + + +/** + * An identifier that enables canonical references to be made to a Codat within + * the context of a specific peer group. + *

+ *

A CodatID is formed by the conjuction of:

    + *
  • a PeerGroupID
  • + *
  • a randomly chosen value that has a high probability of being unique
  • + *
  • an optional SHA1 cryptographic hash of the Codat contents
+ *

+ *

Codats which contain static content will normally include the hash value + * as part of their CodatID. + * + * @see net.jxta.codat.Codat + * @see net.jxta.peergroup.PeerGroupID + */ +public abstract class CodatID extends ID { + + /** + * Creates an ID by parsing the given URI. + * + *

This convenience factory method works as if by invoking the + * {@link net.jxta.id.IDFactory#fromURI(URI)} method; any + * {@link java.net.URISyntaxException} thrown is caught and wrapped in a + * new {@link IllegalArgumentException} object, which is then thrown. + * + *

This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link net.jxta.id.IDFactory}, + * which throws {@link java.net.URISyntaxException} directly, should be used + * situations where a ID is being constructed from user input or from some + * other source that may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException If {@code fromURI} is {@code null}. + * @throws IllegalArgumentException If the given URI is not a valid ID. + */ + public static CodatID create(URI fromURI) { + return (CodatID) ID.create(fromURI); + } + + /** + * {@inheritDoc} + */ + public CodatID intern() { + return (CodatID) super.intern(); + } + + /** + * Returns PeerGroupID of the Peer Group to which this Codat ID belongs. + * + * @return PeerGroupID of the Peer Group which this ID is part of. + */ + public abstract ID getPeerGroupID(); + + /** + * Returns true if this CodatID is associated with a static Codat. + * + * @return true if the codatId is for a Codat with static content + * otherwise false. + */ + public abstract boolean isStatic(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/Metadata.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/Metadata.java new file mode 100644 index 000000000..1d1f7bbd9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/Metadata.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.codat; + + +import net.jxta.document.Document; +import net.jxta.peergroup.PeerGroupID; + +import java.io.IOException; + + +/** + * Medata Codats are special codats that contain information about another + * Codat. Multiple medata Codats can refer to the same Codat. Medata codats can + * hold any kind of information about a codat, such as a symbolic name, + * description, index and searching information, etc. + * + * @see net.jxta.codat.Codat + * @see net.jxta.codat.CodatID + * @see net.jxta.document.Document + */ +public class Metadata extends Codat { + + /** + * Constructs a Metadata instance with a new CodatId given a PeerGroupID, + * the CodatID of the associated Codat and a Document. + * + * @param groupID The peer group to which this Codat will belong. + * @param about The CodatID of an associated Codat for which this Codat is + * metadata or null if there is no associated Codat. + * @param document Document which contains the content data for this Codat. + * @throws IOException if there is an error accessing the document. + */ + public Metadata(PeerGroupID groupID, CodatID about, Document document) throws IOException { + super(groupID, about, document); + } + + /** + * Constructs a Metadata instance for an existing Codat given it's + * CodatID, the CodatID of the associated Codat and a Document. + *

+ *

This implementation does not verify that the CodatID matches the + * provided Document. + * + * @param id CodatId of the new Codat. + * @param about CodatID of an associated Codat for which this Codat is metadata. + * @param document Document which contains the content data for this Codat. + */ + public Metadata(CodatID id, CodatID about, Document document) { + super(id, about, document); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/package.html new file mode 100644 index 000000000..7b4aa9a5a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/codat/package.html @@ -0,0 +1,15 @@ + + + + + + +Codats are container objects that can hold both data or code and are +associated with a JXTA ID. + +@see net.jxta.id +@see JXTA Protocols + Specification : Protocols + + +file:///home/mike/code/jxta/spec/www/v1.0/docbook/JXTAProtocols.html#overview-codats diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/AuthenticationCredential.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/AuthenticationCredential.java new file mode 100644 index 000000000..081e8364c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/AuthenticationCredential.java @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.credential; + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.service.Service; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + +/** + * Authenication credentials are used by JXTA Membership Services as the + * basis for applications for peergroup membership. The AuthenticationCredential + * provides two important pieces of inforamtion: + *

    + *
  • the authetication method being requested
  • + *
  • identity information which will be provided to that authentication + * method.
  • + *
      + *

      + * Not all authentication methods use the identity nformation. + * + * @see net.jxta.credential.Credential + * @see net.jxta.membership.MembershipService + * @see net.jxta.membership.Authenticator + */ +public final class AuthenticationCredential implements Credential { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(AuthenticationCredential.class.getName()); + + /** + * the authentication method which will be requested when this credential is + * provided during "apply" to a peergroup membership service. + */ + private String authenticationMethod = null; + + /** + * Any optional information which is required by the requested authentication method. + */ + private Element identityInfo = null; + + /** + * The peergroup of this AuthenticationCredential + */ + private final PeerGroup peergroup; + + /** + * Creates new AuthenticationCredential + * + * @param peergroup The peergroup context in which this + * AuthenticationCredential is created. + * @param method The authentication method which will be requested when the + * AuthentiationCredential is provided to the peergroup Membership Service. + * Authentication methods are specific to Membership services. Consult the + * Documentation for the Membership service you will be authenticating + * against in order to determine the valid method values. Every + * Membership service should support a default authentication method which + * can be specified as null. + * @param indentityInfo Optional additional information which is used by the + * authentication method or null. This information is passed to the + * authentication method during the apply operation of the Membership + * Service. Consult the documentation for the specific Membership Service + * you are using for details on how this information is used (if at all). + */ + public AuthenticationCredential(PeerGroup peergroup, String method, Element indentityInfo) { + this.peergroup = peergroup; + + authenticationMethod = method; + + if (null != indentityInfo) { + this.identityInfo = StructuredDocumentUtils.copyAsDocument(indentityInfo); + } + } + + /** + * Creates new AuthenticationCredential + * + * @param peergroup The peergroup context in which this + * AuthenticationCredential is created. + * @param root the document containing the serialized representation of the + * AuthenticationCredential. + */ + public AuthenticationCredential(PeerGroup peergroup, Element root) { + + this.peergroup = peergroup; + + initialize(root); + } + + /** + * {@inheritDoc} + *

      + * AuthenticationCredentials are created in the context of a PeerGroup + * though they are generally independant of peergroups. The intent is that + * the AuthenticationCredential will be passed to the MembershipService + * service of the same peergroup as the AuthenticationCredenitals. + * + * @return PeerGroupID associated with this AuthenticationCredential. + */ + public ID getPeerGroupID() { + return peergroup.getPeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public ID getPeerID() { + return peergroup.getPeerID(); + } + + /** + * {@inheritDoc} + */ + public Service getSourceService() { + return null; + } + + /** + * {@inheritDoc} + *

      + * AuthenticationCredential are never expired. The Authenticator will + * determine the true validity from the included identity info. + */ + public boolean isExpired() { + return false; + } + + /** + * {@inheritDoc} + *

      + * AuthenticationCredential are always valid, the Authenticator will + * determine the true validity from the included identity info. + */ + public boolean isValid() { + return true; + } + + /** + * {@inheritDoc} + *

      + * There is no straightforward mechansim for identifying the subject + * unfortunately. + */ + public Object getSubject() { + return null; + } + + /** + * Write credential into a document. as is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out and "text/xml" which + * provides an XML format. + * + * @param as The mime media type of the encoding format being requested. + * @return the StructuredDocument which represents this credential. + * @throws Exception When errors occur. + */ + public StructuredDocument getDocument(MimeMediaType as) throws Exception { + + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + ((Attributable) doc).addAttribute("type", "AuthenticationCredential"); + } + + Element e = doc.createElement("Method", getMethod()); + + doc.appendChild(e); + + e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + doc.appendChild(e); + + e = doc.createElement("PeerID", getPeerID().toString()); + doc.appendChild(e); + + if (null != identityInfo) { + e = doc.createElement("IdentityInfo"); + doc.appendChild(e); + + StructuredDocumentUtils.copyElements(doc, e, identityInfo); + } + + return doc; + } + + /** + * Returns the authentication method which this AuthenticationCredential + * will be requesting when it is provided to a Membership Service during the + * "Apply" operation. + * + * @return String containing the authentication method being requested. + */ + public String getMethod() { + return authenticationMethod; + } + + protected void setMethod(String authenticationMethod) { + this.authenticationMethod = authenticationMethod; + } + + /** + * Returns the StructuredDocument Element containing the identity information which was + * originally provided when this AuthenticationCredential was created. + * + * @return StructuredDocument Element containing the identity information which was + * originally provided when this AuthenticationCredential was created. + */ + public Element getIdentityInfo() { + return (null == identityInfo) ? null : StructuredDocumentUtils.copyAsDocument(identityInfo); + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + */ + protected boolean handleElement(TextElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + URI gID = new URI(elem.getTextValue()); + ID pgid = IDFactory.fromURI(gID); + + if (!pgid.equals(getPeerGroupID())) { + throw new IllegalArgumentException("Operation is from a different group. " + pgid + " != " + getPeerGroupID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Unusable ID in advertisement: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("PeerID")) { + try { + URI pID = new URI(elem.getTextValue()); + ID pid = IDFactory.fromURI(pID); + + if (!pid.equals(getPeerID())) { + throw new IllegalArgumentException("Operation is from a different group. " + pid + " != " + getPeerID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad Peer ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a peer id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Method")) { + setMethod(elem.getTextValue()); + return true; + } + + if (elem.getName().equals("IdentityInfo")) { + Enumeration firstChild = elem.getChildren(); + + if (!firstChild.hasMoreElements()) { + throw new IllegalArgumentException("Missing identity info"); + } + + identityInfo = StructuredDocumentUtils.copyAsDocument((Element) firstChild.nextElement()); + + return true; + } + + // element was not handled + return false; + } + + /** + * Intialize from a portion of a structured document. + * + * @param root the element + */ + protected void initialize(Element root) { + + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + TextElement doc = (TextElement) root; + + String typedoctype = ""; + + if (root instanceof Attributable) { + Attribute itsType = ((Attributable) root).getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + } + + String doctype = doc.getName(); + + if (!"jxta:AuthenticationCredential".equals(doctype) && !"jxta:AuthenticationCredential".equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandleded element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + // FIXME bondolo@jxta.org 20030409 check things + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/Credential.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/Credential.java new file mode 100644 index 000000000..9a42252bd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/Credential.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.credential; + + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.id.ID; +import net.jxta.service.Service; + + +/** + * Credentials provide the basic mechanisms for securely establishing and + * communicating identity within JXTA. Credentials have three different roles + * within JXTA: + *

      + *

        + *
      • Authentication credentials are associated with authentication methods + * and are used to provide information required for authentication. Each + * {@link net.jxta.credential.AuthenticationCredential AuthenticationCredential} + * implementation is specific to its associated + * {@link net.jxta.membership.Authenticator Authenticator}. Authentication + * Credentials are normally created by constructing a document which follows + * a schema provided by the authentication method.
      • + *

        + *

      • Identity credentials associate an identity with a peer. The peer may + * request operations to be performed using that identity. Identity Credentials + * are created by successfully completing authentication with a Membership + * Service.
      • + *

        + *

      • Privileged operations associate an operation with an identity. To + * request a remote peer to perform some operation an application or service + * provides a {@link net.jxta.credential.PrivilegedOperation} and an + * identity credential along with the request. The remote peer determines if + * the operation is permitted for the specified identity and if it is permitted, + * completes the operation.
      • + *
      + *

      + *

      The XML representation of a Credential uses the following very simple + * schema. Credential implementations extend this schema as needed. + *

      + *

      + * <xs:complexType name="Cred">
      + *   <xs:all>
      + *   </xs:all>
      + * </xs:complexType>
      + * 
      + */ +public interface Credential { + + /** + * Returns the peerGroupID associated with this credential. + * + * @return The peerGroupID associated with this credential. + */ + public ID getPeerGroupID(); + + /** + * Returns the peerID associated with this credential. + * + * @return The peerID associated with this credential. + */ + public ID getPeerID(); + + /** + * Returns the service which generated this credential. + * + * @return The service which generated this credential. + */ + public Service getSourceService(); + + /** + * Returns {@code true} if this credential is expired. Some credential + * implementations may never expire. + * + * @return {@code true} if this credential is expired, otherwise + * {@code false}. + */ + public boolean isExpired(); + + /** + * Returns {@code true} if this credential is currently valid. + * + * @return {@code true} if the credential is currently valid, otherwise + * {@code false}. + */ + public boolean isValid(); + + /** + * Returns the subject of this credential. The Objects returned must + * support {@link Object#equals(Object)} and {@link Object#hashCode()}. + * + * @return The subject of the credential as an abstract object. + */ + public Object getSubject(); + + /** + * Write credential into a document. asMimeType is a mime + * media-type specification and provides the form of the document which is + * being requested. Two standard document forms are defined. + * "{@code text/plain}" encodes the document in a "pretty-print" format + * for human viewing and "{@code text/xml}" which provides an XML format. + *

      + *

      Depending on the credential format this document may be + * cryptographically signed to prevent alteration. + * + * @param asMimeType MimeMediaType format representation requested + * @return The credential serialized to a Document. + * @throws Exception if an error occurs + */ + public StructuredDocument getDocument(MimeMediaType asMimeType) throws Exception; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/CredentialPCLSupport.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/CredentialPCLSupport.java new file mode 100644 index 000000000..16bc378d1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/CredentialPCLSupport.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.credential; + + +import java.beans.PropertyChangeListener; + + +/** + * Provides Property Change Listener support for Credentials. + */ +public interface CredentialPCLSupport { + + /** + * Property name for the expired bound property. + */ + public final static String EXPIRED_CREDENTIAL_PROPERTY = "expired"; + + /** + * Property name for valid bound property. + */ + public final static String VALID_CREDENTIAL_PROPERTY = "valid"; + + /** + * Add a listener + * + * @param listener the listener + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + /** + * Add a listener. Available properties from all Credentials are : + *

      + *

        + *
      • expired
      • + *
      • valid
      • + *
      + * + * @param propertyName the property to watch + * @param listener the listener + */ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); + + /** + * Remove a listener + * + * @param listener the listener + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/CredentialValidator.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/CredentialValidator.java new file mode 100644 index 000000000..8e57de9a7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/CredentialValidator.java @@ -0,0 +1,71 @@ +/* +Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.credential; + + +/** + * CredentialValidator defines the interface for allowing external validation of a credential + * + */ +public interface CredentialValidator { + + /** + * Called when a credential verfication is needed. + * @param cred the credential to verify, Credential can be null. + * @return true if verified + */ + public boolean checkCred(Credential cred); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/PrivilegedOperation.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/PrivilegedOperation.java new file mode 100644 index 000000000..e8c83c968 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/PrivilegedOperation.java @@ -0,0 +1,81 @@ +/* + + * + * ==================================================================== + * + * Copyright (c) 2001 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.credential; + + +/** + * A Privileged Operation is an identifier for an operation whose usage is + * restricted. It is represented as a credential so that users and providers + * can prevent the unauthorized creation of privledges. + *

      + *

      Each operation is associated with an offerer. The offerer is the + * identity which created the operation. + */ +public interface PrivilegedOperation extends Credential { + + /** + * Returns the offerer of this operation. The offerer is the identity which + * created the operation. + * + * @return the offerer of the operation. + */ + public Credential getOfferer(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/package.html new file mode 100644 index 000000000..4c201736b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/credential/package.html @@ -0,0 +1,13 @@ + + + + + + +Credentials provide the basic mechanisms for securly establishing and +communicating identity within JXTA. + +@see JXTA Protocols + Specification : Protocols + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryEvent.java new file mode 100644 index 000000000..0c6cdabf3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryEvent.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.discovery; + + +import java.util.Enumeration; +import java.util.EventObject; +import net.jxta.document.Advertisement; +import net.jxta.protocol.DiscoveryResponseMsg; + + +/** + * Container for DiscoveryService events. The source of the event is the Endpoint + * address of the responding peer + */ +public class DiscoveryEvent extends EventObject { + + private final DiscoveryResponseMsg response; + private final int queryID; + + /** + * Creates a new event + * + * @see net.jxta.protocol.DiscoveryResponseMsg + * @see net.jxta.protocol.ResolverResponseMsg + * + * @param source The source of the event is the Endpoint address of the responding peer + * @param response The response message for which this event is being generated. + * @param queryid The query id associated with the response returned in this event + */ + public DiscoveryEvent(Object source, DiscoveryResponseMsg response, int queryid) { + super(source); + this.response = response; + this.queryID = queryid; + } + + /** + * Returns the response associated with the event + * + * @return DiscoveryResponseMsg + * + * @see net.jxta.protocol.DiscoveryResponseMsg + */ + public DiscoveryResponseMsg getResponse() { + + return response; + } + + /** + * Returns the query id associated with the response returned in this event + * + * @return query id associated with the response + */ + public int getQueryID() { + + return queryID; + } + + /** + * Returns an array of advertisements contained in the DiscoveryResponse + * for this event. + * + * @return Enumeration of Advertisements + */ + public Enumeration getSearchResults() { + + return response.getAdvertisements(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryListener.java new file mode 100644 index 000000000..f3d47e7dd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryListener.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.discovery; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving {@link DiscoveryEvent}s from the + * Discovery Service. + * + * The following 2 examples illustrate how to implement a + * DiscoverListener: + * + *

      Example 1: + *

      + * DiscoveryListener myListener = new DiscoveryListener() {
      + *   public void discoveryEvent(DiscoveryEvent e) {
      + *     DiscoveryResponseMsg msg = e.getResponse();
      + *     if (myQueryID == e.getQueryID()) {
      + *       int advCount = msg.getResponseCount();
      + *     }
      + *   }
      + *   discovery.addDiscoveryListener(myListener);
      + *   int myQueryID = discovery.getRemoteAdvertisements(address,
      + *     discovery.GROUP, attr, val,threshold);
      + * 
      + * + *

      Example 2: + *

      + * public class JxtaAppDemo implements Runnable, DiscoveryListener {
      + *          ..
      + *          ..
      + *  public void discoveryEvent(DiscoveryEvent ev) {
      + *
      + *     DiscoveryResponseMsg res = ev.getResponse();
      + *     ..
      + *     ..
      + *     // see tutorial example 2 for full source
      + *     // JXTA Tutorials
      + *     }
      + * }
      + * 
      + * + * @see net.jxta.discovery.DiscoveryService + * @see net.jxta.discovery.DiscoveryEvent + **/ +public interface DiscoveryListener extends EventListener { + + /** + * Called to handle an event from the Discovery Service. + * + * @param event the discovery event + */ + void discoveryEvent(DiscoveryEvent event); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryService.java new file mode 100644 index 000000000..62ce541f7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/DiscoveryService.java @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.discovery; + + +import java.io.IOException; +import java.util.Enumeration; + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.service.Service; + + +/** + * Provides an asynchronous mechanism for discovering Advertisement (Peers, + * Groups, Pipes, Modules, etc.). The scope of discovery queries can be + * controlled by specifying a name and attribute pair, and/or a threshold. + * The threshold is an upper limit the requesting peer specifies for + * responding peers not to exceed. Each JXTA Peer Group has an instance of + * a DiscoveryService. The scope of discovery is limited to the group. For + * example : + * + *

      A peer in the soccer group invokes the soccer group's DiscoveryService + * to discover pipe advertisements for the Score tracker service in the group, + * and is interested in a maximum of 10 Advertisements from each peer: + *

      + *  discovery.getRemoteAdvertisements(null, discovery.ADV,
      + *                                    "Name", "Score tracker*", 10, null);
      + *
      + * 
      + * + *

      In the above example, peers that are part of the soccer group would + * respond. After a getRemoteAdvertisements call is made and the peers respond, + * a call to getLocalAdvertisements can be made to retrieve results that have + * been found and added to the local group cache. Alternately, a call to + * addDiscoveryListener() will provide asynchronous notification of discovered + * advertisements. + * + *

      When an Advertisement is published, it is stored, and indexed in the + * peer's local cache. The Advertisement indexes are also shared with + * Rendezvous peers. Advertisement indexes may not be shared with other + * peers immediately, but may be updated as part of a periodic process. The + * Discovery Service currently updates remote indexes every 30 seconds. + * + *

      It is important to note that what is shared with the rendezvous peer is + * the index and expiration of the advertisement, not the advertisement. The + * indexes are republished whenever the peer establishes a new connection with + * a different rendezvous peer. + * + *

      Distributed index garbage collection. A rendezvous peer will GC indexes for + * a specific peer when it receive a disconnect message, or it has determined + * that a peer is no longer reachable, the latter action is a lazy GC and is + * triggered by messenger creation failures which results in a mark and sweep at + * a future point in time. + * + *

      DiscoveryService also provides a mechanism for publishing advertisements, + * so that they may be discovered. The rules to follow when publishing are: + * + *

        + *
      • + * Use the current discovery service to publish advertisements private to the + * group. + *
        discovery.publish(adv);
        + * 
      • + * + *
      • Use the parent's discovery to publish advertisements that public outside + * of the group. Example : a peer would like publish the "soccer" group in the + * NetPeerGroup + *
        + *        parent=soccerGroup.getParent();
        + *        discovery= parent.getDiscoveryService()
        + *        discovery.publish(adv);
        + * 
      • + *
      + * + *

      The threshold can be utilized in peer discovery in situations where a peer + * is only interested in other peers, and not about additional peers they may + * know about. To achieve this effect for peer discovery set the Threshold to + * 0 (zero). + * + *

      Advertisements are often stored in a persistent local cache. This cache + * can improve performance and responsiveness by retaining advertisements + * between restarts. + * + *@see net.jxta.service.Service + *@see net.jxta.resolver.ResolverService + *@see net.jxta.protocol.DiscoveryQueryMsg + *@see net.jxta.protocol.DiscoveryResponseMsg + *@see net.jxta.protocol.ResolverQueryMsg + *@see net.jxta.protocol.ResolverResponseMsg + */ +public interface DiscoveryService extends Service { + + /** + * Discovery type Peer + */ + public final static int PEER = 0; + + /** + * Discovery type Group + */ + public final static int GROUP = 1; + + /** + * Discovery type Advertisement + */ + public final static int ADV = 2; + + /** + * Default lifetime time for advertisements. This is the maximum + * amount of time which the advertisement will remain valid. If the + * advertisement remains valid after this time, then the creator will + * need to republish the advertisement. + */ + public final static long DEFAULT_LIFETIME = 1000L * 60L * 60L * 24L * 365L; + + /** + * Default expiration time for advertisements. This is the amount of + * time which advertisements will live in caches. After this time, the + * advertisement should be refreshed from the source. + */ + public final static long DEFAULT_EXPIRATION = 1000L * 60L * 60L * 2L; + + /** + * Infinite lifetime for advertisements. The advertisement is valid + * forever. (well maybe it will expire when the sun burns out, but not + * before then). + */ + public final static long INFINITE_LIFETIME = Long.MAX_VALUE; + + /** + * Specifies that the advertisement will have no expiration and will be + * kept indefinitely. + */ + public final static long NO_EXPIRATION = Long.MAX_VALUE; + + /** + * Discover advertisements from remote peers. This does not normally + * provide an exhaustive search. Instead it provides a "best efforts" + * search which will provide a selection of advertisements of matching the + * search criteria. The selection of advertisements returned may be random + * or predictable depending upon the network configuration and no + * particular behaviour should be assumed. In general the narrower the + * query specified the more exhaustive the responses will be. + * + *

      Discovery can be performed in two ways :

        + *
      • With a null peerid - The discovery query is + * propagated on via the Rendezvous Service and via local sub-net + * utilizing IP multicast.
      • + *
      • With a provided peerid - The discovery query is forwarded to the + * specified peer.
      • + *
      + * + *

      The scope of advertisements returned can be narrowed by specifying + * an {@code attribute} and {@code value} pair. The {@code attribute} is + * a case-sensitive string matching the name of an Advertisement XML tag + * who's values will be matched by the {@code value}. Only a limited number + * of Advertisement XML fields are indexed. {@link + * net.jxta.document.Advertisement#getIndexFields()} will return the + * fields on which you may query for a particular Advertisement type. + * + *

      The {@code value} is a case-insensitive string who's value is + * matched against the values of {@code attribute} fields of Advertisements. + * The {@code} value may be of several forms : + *

        + *
      • {@code null} - Don't care. All advertisements with the matching + * {@code attribute} will be returned.
      • + *
      • exact value - Only advertisements with an {@code attribute} + * field who's value exactly matches the string {@code value} will be + * returned.
      • + *
      • wild card - Only advertisements with an {@code attribute} + * field who's value matches the wild card expression {@code value} + * will be returned. eg. The following expressions all match against + * "FooBar": + *
          + *
        • {@code foO*}
        • + *
        • {@code *Bar}
        • + *
        • {@code *oBA*}
        • + *
      • + *
      + * + * @param peerid If provided the query will be forwarded to the specified + * peer. If {@code null} then the query will be propagated through the + * network to peers with matching Advertisements. + * @param type Discovery type; PEER, GROUP or ADV. + * @param attribute indexed element name (see advertisement(s) for a + * list of indexed fields. A null attribute indicates any advertisement + * of specified type + * @param value value of attribute to narrow discovery to. Valid values for + * this parameter are null (don't care), Exact value, or use of wild + * card(s) (e.g. if a Advertisement defines FooBar , a value + * of "*bar", "foo*", or "*ooB*", will return the Advertisement + * @param threshold The maximum number of matching advertisements which + * be returned by each responding peer. A {@code threshold} of 0, and + * {@code type} of {@code PEER} has a special behaviour. + * @return query ID for this discovery query. + */ + public int getRemoteAdvertisements(String peerid, int type, String attribute, String value, int threshold); + + /** + * Discover advertisements from remote peers. This does not normally + * provide an exhaustive search. Instead it provides a "best efforts" + * search which will provide a selection of advertisements of matching the + * search criteria. The selection of advertisements returned may be random + * or predictable depending upon the network configuration and no + * particular behaviour should be assumed. In general the narrower the + * query specified the more exhaustive the responses will be. + * + *

      Discovery can be performed in two ways :

        + *
      • With a {@code null} peerid - The discovery query is + * propagated on via the Rendezvous Service and via local sub-net + * utilizing IP multicast.
      • + *
      • With a provided peerid - The discovery query is forwarded to the + * specified peer.
      • + *
      + * + *

      The scope of advertisements returned can be narrowed by specifying + * an {@code attribute} and {@code value} pair. The {@code attribute} is + * a case-sensitive string matching the name of an Advertisement XML tag + * who's values will be matched by the {@code value}. Only a limited number + * of Advertisement XML fields are indexed. {@link + * net.jxta.document.Advertisement#getIndexFields()} will return the + * fields on which you may query for a particular Advertisement type. + * + *

      The {@code value} is a case-insensitive string who's value is + * matched against the values of {@code attribute} fields of Advertisements. + * The {@code} value may be of several forms : + *

        + *
      • {@code null} - Don't care. All advertisements with the matching + * {@code attribute} will be returned.
      • + *
      • exact value - Only advertisements with an {@code attribute} + * field who's value exactly matches the string {@code value} will be + * returned.
      • + *
      • wild card - Only advertisements with an {@code attribute} + * field who's value matches the wild card expression {@code value} + * will be returned. eg. The following expressions all match against + * "FooBar": + *
          + *
        • {@code fOo*}
        • + *
        • {@code *bAr}
        • + *
        • {@code *OBa*}
        • + *
      • + *
      + * + * @param peerid If provided the query will be forwarded to the specified + * peer. If {@code null} then the query will be propagated through the + * network to peers with matching Advertisements. + * @param type Discovery type; PEER, GROUP or ADV. + * @param attribute indexed element name (see Advertisement(s) for a + * list of indexed fields. A null attribute indicates any advertisement + * of specified type + * @param value value of attribute to narrow discovery to. Valid values + * for this parameter or {@code null} (don't care), Exact value, or use + * of wild card(s) (e.g. if a Advertisement defines FooBar, + * a value of "*bar", "foo*", or "*ooB*", will return the Advertisement + * @param threshold The maximum number of matching advertisements which + * be returned by each responding peer. A {@code threshold} of 0, and + * {@code type} of {@code PEER} has a special behaviour. + * @param listener The listener which will be called when advertisement + * which match this query are discovered or {@code null} if no + * callback is desired. + * @return query ID for this discovery query. + */ + public int getRemoteAdvertisements(String peerid, int type, String attribute, String value, int threshold, DiscoveryListener listener); + + /** + * Retrieve locally stored Advertisements. This is an exhaustive search of + * the locally cached results. All valid known matching results will be + * returned. + * + * @param type Discovery type; PEER, GROUP or ADV. + * @param attribute indexed element name (see Advertisement(s) for a + * list of indexed fields. {@code null} indicates any advertisement + * of specified type + * @param value value of attribute to narrow discovery to valid + * values for this parameter are {@code null} (don't care), Exact + * value, or use of wild card(s) (e.g. if a Advertisement defines + * FooBar , a value of "*bar", "foo*", or "*ooB*", will + * return the Advertisement + * @return Enumeration of stored advertisements. + * @throws IOException Thrown if an error occurs during retrieval. + */ + public Enumeration getLocalAdvertisements(int type, String attribute, String value) throws IOException; + + /** + * Publish an Advertisement. The Advertisement will expire automatically + * on the local peer after DEFAULT_LIFETIME and will expire on + * other peers after DEFAULT_EXPIRATION. + * + *

      When an Advertisement is published, it is stored, and indexed in the + * peer's local cache. The Advertisement indexes are also shared with + * Rendezvous peers. Advertisement indexes may not be shared with other + * peers immediately, but may be updated as part of a periodic process. The + * Discovery Service currently publishes index updates every 30 seconds. + * + * @param adv The Advertisement to publish. + * @throws IOException When an error occurs during Advertisement publication. + */ + public void publish(Advertisement adv) throws IOException; + + /** + * Publish an Advertisement. The Advertisement will expire automatically + * after the specified time. A peer that discovers this advertisement will + * hold it for about expiration or lifetime milliseconds, + * whichever is smaller. + * + *

      When an Advertisement is published, it is stored, and indexed in the + * peer's local cache. The Advertisement indexes are also shared with + * Rendezvous peers. Advertisement indexes may not be shared with other + * peers immediately, but may be updated as part of a periodic process. The + * Discovery Service currently publishes index updates every 30 seconds. + * + * @param adv The Advertisement to publish. + * @param lifetime Duration in relative milliseconds that this advertisement will exist. + * @param expiration Duration in relative milliseconds that this advertisement will be cached by other peers. + * @throws IOException When an error occurs during Advertisement publication. + */ + public void publish(Advertisement adv, long lifetime, long expiration) throws IOException; + + /** + * Publish an Advertisement via propagation to other peers on the network. + * This does not result in the advertisement being stored locally. The + * Advertisement will be published with an expiration time of + * DEFAULT_EXPIRATION. + * + * @param adv Advertisement to publish. + */ + public void remotePublish(Advertisement adv); + + /** + * Publish an Advertisement via propagation to other peers on the network. + * This does not result in the advertisement being stored locally. + * + * @param adv The Advertisement to publish. + * @param expiration Duration in relative milliseconds that this + * Advertisement will be cached by other peers. + */ + public void remotePublish(Advertisement adv, long expiration); + + /** + * Publish an Advertisement to another peer on the network. + * This does not result in the advertisement being stored locally. The + * Advertisement will be published with an expiration time of + * DEFAULT_EXPIRATION. + * + *@param peerid The ID of a peer, specifying null results in + * propagation within the group. + *@param adv The Advertisement to publish. + */ + public void remotePublish(String peerid, Advertisement adv); + + /** + * Publish an Advertisement to another peer on the network. This does not + * result in the advertisement being stored locally. + * + * @param peerid id of a peer, specifying null results in a propagate + * within the group + * @param adv The Advertisement to publish. + * @param expiration Duration in relative milliseconds that this + * Advertisement will be cached by other peers. + */ + public void remotePublish(String peerid, Advertisement adv, long expiration); + + /** + * Removes the specified Advertisement from the cache of locally stored + * Advertisements. + * + * @param adv Advertisement to remove. + * @throws IOException If there is a problem removing the advertisement. + */ + public void flushAdvertisement(Advertisement adv) throws IOException; + + /** + * Removes the specified Advertisement from the cache of locally stored + * Advertisements. + * + * @param id The {@link Advertisement#getID()} value of the + * Advertisement to be removed. + * @param type Discovery type PEER, GROUP, ADV. + * @throws IOException If there is a problem removing the advertisement. + */ + public void flushAdvertisements(String id, int type) throws IOException; + + /** + * Returns the maximum duration in milliseconds for which this document + * will be cached by peers other than the publisher. This value is either + * the stored lifetime or the remaining lifetime of the document, whichever + * is less. + * + * @param id Document ID, Peer ID, or PeerGroup ID + * @param type Discovery type PEER, GROUP, ADV + * @return The number of milliseconds that other peers will be told to + * retain this Advertisement in their local caches. -1 is returned if + * the Advertisement is not known or already expired. + */ + public long getAdvExpirationTime(ID id, int type); + + /** + * Returns the maximum duration in milliseconds for which this document + * should be kept in local cache. + * + * @param id Document ID, Peer ID, or PeerGroup ID + * @param type Discovery type PEER, GROUP, ADV + * @return The number of milliseconds this Advertisement will remain in the + * local cache unless refreshed before that time. -1 is returned if the + * Advertisement is not known or already expired. + */ + public long getAdvLifeTime(ID id, int type); + + /** + * Returns the maximum duration in milliseconds for which this document + * will be cached by peers other than the publisher. This value is either + * the stored lifetime or the remaining lifetime of the document, whichever + * is less. + * + * @param adv Advertisement + * @return The number of milliseconds that other peers will be told to + * retain this Advertisement in their local caches. -1 is returned if + * the Advertisement is not known or already expired. + */ + public long getAdvExpirationTime(Advertisement adv); + + /** + * Returns the maximum duration in milliseconds for which this document + * should be kept in local cache. + * + * @param adv Advertisement + * @return The number of milliseconds this Advertisement will remain in the + * local cache unless refreshed before that time. -1 is returned if the + * Advertisement is not known or already expired. + */ + public long getAdvLifeTime(Advertisement adv); + + /** + * Register a Discovery listener. The Discovery listener will be called + * whenever Advertisement responses are received from remote peers by the + * Discovery Service. + * + * @param listener the DiscoveryListener + */ + public void addDiscoveryListener(DiscoveryListener listener); + + /** + * Remove a Discovery listener which was previously registered with + * {@link #getRemoteAdvertisements(String,int,String,String,int,DiscoveryListener) getRemoteAdvertisements()} + * or {@link #addDiscoveryListener(DiscoveryListener) addDiscoveryListener()}. + * + * @param listener The listener to be removed. + * @return true if the listener was successfully removed, false otherwise + */ + public boolean removeDiscoveryListener(DiscoveryListener listener); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/package.html new file mode 100644 index 000000000..c304dd162 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/discovery/package.html @@ -0,0 +1,15 @@ + + + + + + + The JXTA Discovery Service provides an asynchronous mechanism for + discovering Peer Advertisements, Group Advertisements, and other general + JXTA Advertisements (pipes, services, etc.). + + @see net.jxta.resolver + @see net.jxta.document.Advertisement + @see JXTA Protocols Specification : Peer Discovery Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Advertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Advertisement.java new file mode 100644 index 000000000..88b88c8ef --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Advertisement.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; +import java.lang.reflect.Method; + +import net.jxta.id.ID; + + +/** + * Advertisements are core JXTA objects that are used to advertise Peers, + * PeerGroups, Services, Pipes or other JXTA resources. Advertisements provide + * a platform independent representation of core platform objects that can be + * exchanged between different platform implementations (Java, C, etc.). + * + *

      Each Advertisement holds a document that represents the advertisement. + * Advertisements are typically represented as a text document (XML). The + * {@link Advertisement#getDocument(MimeMediaType) getDocument(mimetype)} + * method is used to generate representations of the advertisement. Different + * representations are available via mime type selection. Typical mime types + * are "text/xml" or "text/plain" that generate textual representations for the + * Advertisements. + * + *

      Advertisements are created via {@link AdvertisementFactory} rather than + * through use of constructors. This is done because public the Advertisement + * sub-classes are typically abstract. The actual implementations are provided + * by private sub-classes. + * + * @see net.jxta.document.AdvertisementFactory + * @see net.jxta.document.ExtendableAdvertisement + * @see net.jxta.id.ID + * @see net.jxta.document.Document + * @see net.jxta.document.MimeMediaType + */ +public abstract class Advertisement { + + /** + * {@inheritDoc} + */ + @Override + public Advertisement clone() throws CloneNotSupportedException { + return (Advertisement) super.clone(); + } + + /** + * Return a string representation of this advertisement. The string will + * contain the advertisement pretty-print formatted as a UTF-8 encoded XML + * Document. + * + * @return A String containing the advertisement. + */ + @Override + public String toString() { + XMLDocument doc = (XMLDocument) getDocument(MimeMediaType.XMLUTF8); + + // Force pretty printing + doc.addAttribute("xml:space", "default"); + + return doc.toString(); + } + + /** + * Returns the identifying type of this Advertisement. + * + *

      Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

      +     *      Advertisement adv = module.getSomeAdv();
      +     *      String advType = adv.getAdvertisementType();
      +     *  
      + * + *

      This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * {@code Advertisement.getAdvertisementType()} no matter what the real + * type of the advertisement. + * + * @return The type of advertisement. + */ + public static String getAdvertisementType() { + throw new UnsupportedOperationException( + "Advertisement : sub-class failed to override getAdvertisementType. getAdvertisementType() is static and is *not* polymorphic."); + } + + /** + * Returns the identifying type of this Advertisement. Unlike + * {@link #getAdvertisementType()} this method will return the correct + * runtime type of an Advertisement object. + *

      + * This implementation is provided for existing advertisements which do not + * provide their own implementation. In most cases you should provide your + * own implementation for efficiency reasons. + * + * @since JXSE 2.1.1 + * @return The identifying type of this Advertisement. + */ + public String getAdvType() { + try { + Method getAdvertisementTypeMethod = this.getClass().getMethod("getAdvertisementType", (Class[]) null); + String result = (String) getAdvertisementTypeMethod.invoke(null, (Object[]) null); + + return result; + } catch (NoSuchMethodException failed) { + UnsupportedOperationException failure = new UnsupportedOperationException("Could not get Advertisement type."); + + failure.initCause(failed); + throw failure; + } catch (IllegalAccessException failed) { + SecurityException failure = new SecurityException("Could not get Advertisement type."); + + failure.initCause(failed); + throw failure; + } catch (InvocationTargetException failed) { + UndeclaredThrowableException failure = new UndeclaredThrowableException(failed, "Failed getting Advertisement type."); + + failure.initCause(failed.getCause()); + throw failure; + } + } + + /** + * Write this advertisement into a document of the requested type. Two + * standard document forms are defined. "text/plain" encodes + * the document in a "pretty-print" format for human viewing and + * "text/xml" which provides an XML format. + * + * @param asMimeType MimeMediaType format representation requested. + * @return The {@code Advertisement} represented as a {@code Document} of + * the requested MIME Media Type. + */ + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * Returns an ID which identifies this {@code Advertisement} as uniquely as + * possible. This ID is typically used as the primary key for indexing of + * the Advertisement within databases. + *

      + * Each advertisement sub-class must choose an appropriate implementation + * which returns canonical and relatively unique ID values for it's + * instances. Since this ID is commonly used for indexing, the IDs returned + * must be as unique as possible to avoid collisions. The value for the ID + * returned can either be: + *

      + *

        + *
      • An ID which is already part of the advertisement definition + * and is relatively unique between advertisements instances. For + * example, the Peer Advertisement returns the Peer ID.
      • + * + *
      • A static CodatID which is generated via some canonical process + * which will produce the same value each time and different values for + * different advertisements of the same type.
      • + * + *
      • ID.nullID for advertisement types which are not readily indexed. + *
      • + *
      + *

      + * For Advertisement types which normally return non-ID.nullID values + * no ID should be returned when asked to generate an ID while the + * Advertisement is an inconsistent state (example: uninitialized index + * fields). Instead {@link java.lang.IllegalStateException} should be + * thrown. + * + * @return An ID that relatively uniquely identifies this advertisement + * or {@code ID.nullID} if this advertisement is of a type that is not + * normally indexed. + */ + public abstract ID getID(); + + /** + * Returns the element names on which this advertisement should be indexed. + * + * @return The element names on which this advertisement should be indexed. + */ + public abstract String[] getIndexFields(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/AdvertisementFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/AdvertisementFactory.java new file mode 100644 index 000000000..aa870cdfd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/AdvertisementFactory.java @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.InputStream; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +import java.io.IOException; +import java.util.NoSuchElementException; +import java.util.MissingResourceException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.util.ClassFactory; + + +/** + * A Factory class for constructing Advertisements. This class abstracts the + * the implementations used to represent and create advertisements. + * + *

      Advertisements are core objects that are used to advertise a Peer, a + * PeerGroup, a Service, a Pipe, etc. The Advertisement class provides a + * platform independent representation of core objects that can be exchanged + * between different implementations (Java, C). + * + *

      The AdvertisementFactory extends the ClassFactory to register the various + * types of advertisements into an internal table. The factory is called with + * the Advertisement type requested to create the corresponding advertisement + * type. + * + *

      The set of Advertisements types supported is loaded from the JXTA + * classpath via the service provider interface. + * + * @see net.jxta.document.Advertisement + * @see net.jxta.document.Document + * @see net.jxta.document.MimeMediaType + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.protocol.PeerAdvertisement + * @see net.jxta.protocol.PeerGroupAdvertisement + * @see net.jxta.protocol.PipeAdvertisement + */ +public class AdvertisementFactory extends ClassFactory { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(AdvertisementFactory.class.getName()); + + /** + * Interface for instantiators of Advertisements + */ + public interface Instantiator { + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + String getAdvertisementType(); + + /** + * Constructs an instance of {@link Advertisement} matching the type + * specified by the advertisementType parameter. + * + * + * @return The instance of {@link Advertisement}. + */ + Advertisement newInstance(); + + /** + * Constructs an instance of {@link Advertisement} matching the type + * specified by the advertisementType parameter. + * + * @param root Specifies a portion of a @link StructuredDocument} which + * will be converted into an Advertisement. + * @return The instance of {@link Advertisement}. + */ + Advertisement newInstance(net.jxta.document.Element root); + } + + /** + * This class is a singleton. This is the instance that backs the + * static methods. + */ + private final static AdvertisementFactory factory = new AdvertisementFactory(); + + /** + * This is the map of mime-types and constructors used by + * {@code newAdvertisement}. + */ + private final Map encodings = new HashMap(); + + /** + * If true then the pre-defined set of StructuredDocument sub-classes has + * been registered from the property containing them. + */ + private boolean loadedProperty = false; + + /** + * Private constructor. This class is not meant to be instantiated except + * by itself. + * + */ + private AdvertisementFactory() {} + + /** + * Registers the pre-defined set of Advertisement sub-classes so that + * this factory can construct them. + * + * @return true if at least one of the Advertisement sub-classes could + * be registered otherwise false. + */ + private synchronized boolean loadProviders() { + if (!factory.loadedProperty) { + factory.loadedProperty = registerProviders(Advertisement.class.getName()); + } + + return factory.loadedProperty; + } + + /** + * {@inheritDoc} + */ + @Override + protected Map getAssocTable() { + return encodings; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getClassOfInstantiators() { + // our key is the doctype names. + return Instantiator.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getClassForKey() { + // our key is the doctype names. + return java.lang.String.class; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean registerAssoc(String className) { + boolean registeredSomething = false; + + try { + Class advClass = Class.forName(className + "$Instantiator"); + + Instantiator instantiator = (Instantiator) advClass.newInstance(); + + String advType = instantiator.getAdvertisementType(); + + registeredSomething = registerAdvertisementInstance(advType, instantiator); + } catch (Exception all) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to register \'" + className + "\'", all); + } + } + + return registeredSomething; + } + + /** + * Register an instantiator for and advertisement type to allow instances + * of that type to be created. + * + * @param rootType the identifying value for this advertisement instance + * type. + * @param instantiator the instantiator to use in constructing objects + * of this rootType. + * @return boolean true if the rootType type is registered. If there is + * already a constructor for this type then false will be returned. + */ + public static boolean registerAdvertisementInstance(String rootType, Instantiator instantiator) { + boolean result = factory.registerAssoc(rootType, instantiator); + + return result; + } + + /** + * Constructs a new instance of {@link Advertisement} matching the type + * specified by the {@code advertisementType} parameter. + * + * @param advertisementType Specifies the type of advertisement to create. + * @return The instance of {@link Advertisement}. + * @throws NoSuchElementException if there is no matching advertisement type. + */ + public static Advertisement newAdvertisement(String advertisementType) { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(advertisementType); + + Advertisement a = instantiator.newInstance(); + + return a; + } + + /** + * Constructs an instance of {@link Advertisement} from the provided + * InputStream. The content type of the stream is declared via + * the mimetype parameter. + * + * @deprecated Please convert your code to construct an {@code XMLDocument} + * using {@code StructuredDocumentFactory} and then call + * {@link AdvertisementFactory#newAdvertisement(XMLElement)}. For example : + *

      +     *   XMLDocument xml = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, is );
      +     * 
      + * or frequently: + *

      +     *   XMLDocument xml = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( msgElement );
      +     * 
      + * followed by: + *

      +     *   Advertisement adv = AdvertisementFactory.newAdvertisement(xml);
      +     * 
      + * + * @param mimetype Specifies the mime media type of the stream being read. + * @param stream input stream used to read data to construct the advertisement + * @return The instance of {@link Advertisement} + * @throws IOException error reading message from input stream + * @throws NoSuchElementException if there is no matching advertisement type + * for the type of document read in. + */ + @Deprecated + public static Advertisement newAdvertisement(MimeMediaType mimetype, InputStream stream) throws IOException { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(mimetype, stream); + + if (!(doc instanceof XMLDocument)) { + throw new IllegalArgumentException("Advertisements must be XML"); + } + + return newAdvertisement((XMLDocument) doc); + } + + /** + * Reconstructs an instance of {@link Advertisement} from the provided + * Reader. The content type of the reader is declared via the + * mimetype parameter. + * + * @deprecated Please convert your code to construct an {@code XMLDocument} + * using {@code StructuredDocumentFactory} and then call + * {@link AdvertisementFactory#newAdvertisement(XMLElement)}. For example : + *

      +     *   XMLDocument xml = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, reader );
      +     * 
      + * or frequently: + *

      +     *   XMLDocument xml = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( msgElement );
      +     * 
      + * followed by: + *

      +     *   Advertisement adv = AdvertisementFactory.newAdvertisement(xml);
      +     * 
      + * + * @param mimetype Specifies the mime media type of the stream being read. + * @param source used to read data to construct the advertisement. + * @return The instance of {@link Advertisement} + * @throws IOException error reading message from input stream + * @throws NoSuchElementException if there is no matching advertisement type + * for the type of document read in. + * @throws UnsupportedOperationException if the specified mime type is not + * associated with a text oriented document type. + */ + @Deprecated + public static Advertisement newAdvertisement(MimeMediaType mimetype, Reader source) throws IOException { + StructuredTextDocument doc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(mimetype, source); + + return newAdvertisement(doc); + } + + /** + * Reconstructs an instance of {@link Advertisement} matching the type + * specified by the {@code root} parameter. + * + * @deprecated Advertisements must be encoded in XML. This is a legacy + * static constructor. You should convert your code to use the + * {@link AdvertisementFactory#newAdvertisement(XMLElement) XMLElement} + * version. + * + * @param root Specifies a portion of a StructuredDocument which will be + * converted into an Advertisement. + * @return The instance of {@link Advertisement}. + * @throws NoSuchElementException if there is no advertisement type + * matching the type of the root node. + */ + @Deprecated + public static Advertisement newAdvertisement(TextElement root) { + if (!(root instanceof XMLElement)) { + throw new IllegalArgumentException("Advertisements must be XML"); + } + + return newAdvertisement((XMLElement) root); + } + + /** + * Reconstructs an instance of {@link Advertisement} matching the type + * specified by the {@code root} parameter. + * + * @param root Specifies a portion of an XMLElement which will be + * converted into an Advertisement. + * @return The instance of {@link Advertisement}. + * @throws NoSuchElementException if there is no advertisement type + * matching the type of the root node. + */ + public static Advertisement newAdvertisement(XMLElement root) { + factory.loadProviders(); + + Instantiator instantiator = null; + + // The base type of the advertisement may be overridden by a type + // declaration. If this is the case, then we try to use that as the + // key rather than the root name. + Attribute type = root.getAttribute("type"); + + if (null != type) { + try { + instantiator = factory.getInstantiator(type.getValue()); + } catch (NoSuchElementException notThere) { + // do nothing, its not fatal + ; + } + } + + // Don't have an instantiator for the type attribute, try the root name + if (null == instantiator) { + instantiator = factory.getInstantiator(root.getName()); + } + + Advertisement a = instantiator.newInstance(root); + + return a; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Attributable.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Attributable.java new file mode 100644 index 000000000..eee489008 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Attributable.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.util.Enumeration; + + +/** + * Interface for name value pairs to be associated with some base object. + * + * @see net.jxta.document.Attribute + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.Element + */ +public interface Attributable { + + /** + * Adds an attribute with the given name and value. Some implementations + * may support only a single value for each distinct name. Others may + * support multiple values for each name. If the value being provided + * replaces some other value then that value is returned otherwise null + * is returned. + * + * @param name name of the attribute. + * @param value value for the attribute. + * @return String containing previous value for this name if the value + * is being replaced otherwise null. + */ + String addAttribute(String name, String value); + + /** + * Adds an attribute with the given name and value. Some implementations + * may support only a single value for each distinct name. Others may + * support multiple values for each name. If the value being provided + * replaces some other value then that value is returned otherwise null + * is returned. + * + * @param newAttrib new attribute. + * @return String containing previous value for this name if the value + * is being replaced otherwise null. + */ + String addAttribute(Attribute newAttrib); + + /** + * Returns an enumerations of the attributes associated with this object. + * Each element is of type Attribute. + * + * @return Enumeration the attributes associated with this object. + */ + Enumeration getAttributes(); + + /** + * Returns a single attribute which matches the name provided. If no such + * named attribute exists then null is returned. For implementations of + * this interface which support multiple values for each name only the + * first value will be returned. To access all values for a name you must + * use getAttributes. + * + * @param name the attribute name + * @return Attribute the attributes matching the given name. + */ + Attribute getAttribute(String name); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Attribute.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Attribute.java new file mode 100644 index 000000000..1d746627b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Attribute.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +/** + * A name value pair which is associated with some base object. + * + * @see net.jxta.document.Attributable + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.Element + * + **/ +public class Attribute { + + /** + * The object which this attribute extends. + **/ + private Attributable owner; + + /** + * Our name + **/ + private String name; + + /** + * Our value + **/ + private String value; + + /** + * Constructor for a new attribute which can be added to an + * {@link Attributable}. + * + * @param name Name for this attribute. + * @param value Value for this attribute. + **/ + public Attribute(String name, String value) { + this(null, name, value); + } + + /** + * Constructor for a new attribute which is associated with an + * @link Attributable} object. + * + * @param owner The Atrributable owner of this attribute or null. + * @param name Name for this attribute. + * @param value Value for this attribute. + **/ + public Attribute(Attributable owner, String name, String value) { + this.owner = owner; + this.name = name; + this.value = value; + } + + /** + * {@inheritDoc} + **/ + @Override + protected Object clone() { + return this; // immutable so we can return self. + } + + /** + * {@inheritDoc} + + * The two attributes are the same if they have + * the same owner, name and value. + * + * @param target Attribute to be checked with + * @return boolean if the attributes are equal otherwise false. + **/ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof Attribute) { + Attribute targAttrib = (Attribute) target; + + boolean result = ((owner.equals(targAttrib.owner)) && name.equals(targAttrib.name) && value.equals(targAttrib.name)); + + return result; + } else { + return false; + } + } + + /** + * {@inheritDoc} + **/ + @Override + public int hashCode() { + int result = name.hashCode() ^ value.hashCode(); + + result ^= (null != owner) ? owner.hashCode() : 0; + return result; + } + + /** + * {@inheritDoc} + **/ + @Override + public String toString() { + return "<" + name + " = \"" + value + "\">"; + } + + /** + * Return name of this attribute + * + * @return String containing the attribute's name. + **/ + public String getName() { + return name; + } + + /** + * Return the {@link Attributable} which is the owner of this attribute. + * + * @return Attributable object which owns this attribute. + **/ + public Attributable getOwner() { + return owner; + } + + /** + * Return value of this attribute + * + * @return String containing the attribute's value. + **/ + public String getValue() { + return value; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/BinaryDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/BinaryDocument.java new file mode 100644 index 000000000..04b6c9194 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/BinaryDocument.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + + +/** + * This class is an implementation of the Document interface. It is perhaps the + * simplest implementation of the Document interface possible. + */ +public class BinaryDocument implements Document { + + /** + * Our Mime Media Types + */ + private static final MimeMediaType[] myTypes = { + MimeMediaType.AOS + }; + + /** + * Storage for our bytes. + */ + private final byte[] ourBytes; + + /** + * The MIME type of this document. + */ + private final MimeMediaType ourType; + + /** + * Returns the MIME Media types supported by this this Document per + * {@link IETF RFC 2046 MIME : Media Types}. + *

      + * Jxta does not currently support the 'Multipart' or 'Message' media types. + * + * @return An array of MimeMediaType objects containing the MIME Media Type + * for this Document. + */ + public static MimeMediaType[] getSupportedMimeTypes() { + return (myTypes.clone()); + } + + /** + * Creates new BinaryDocument from a byte array. The data in the array is + * not copied. If you intend to modify the array after creating a document + * then you should pass a copy of the data instead. + * + * @param someBytes Contains a byte array which will serve as our data. + */ + public BinaryDocument(byte[] someBytes) { + this(someBytes, myTypes[0]); + } + + /** + * Creates new BinaryDocument from a byte array. The data in the array is + * not copied. If you intend to modify the array after creating a document + * then you should pass a copy of the data instead. + * + * @param someBytes Contains a byte array which will serve as our data. + * @param type The MIME media type for this document. + */ + public BinaryDocument(byte[] someBytes, MimeMediaType type) { + ourBytes = someBytes; + ourType = type; + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getMimeType() { + return ourType; + } + + /** + * {@inheritDoc} + */ + public String getFileExtension() { + return StructuredDocumentFactory.getFileExtensionForMimeType(ourType); + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + return (new ByteArrayInputStream(ourBytes)); + } + + /** + * {@inheritDoc} + */ + public void sendToStream(OutputStream stream) throws IOException { + stream.write(ourBytes); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Document.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Document.java new file mode 100644 index 000000000..016d8f1bb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Document.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.InputStream; +import java.io.OutputStream; + +import java.io.IOException; + + +/** + * A simple typed container for data. A {@code Document} is presented as a + * byte stream with an associated type. The data type is specified using a + * MIME Media Type (as defined by + * {@link IETF RFC 2046 MIME : Media Types}). + * + * @see net.jxta.document.MimeMediaType + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.StructuredDocumentFactory + */ +public interface Document extends DocumentStreamIO { + + /** + * Returns the MIME Media type of this {@code Document} per + * {@link IETF RFC 2046 MIME : Media Types}. + * + *

      JXTA does not currently support the 'Multipart' or + * 'Message' media types. + * + * @return The MIME Media Type for this {@code Document}. + */ + MimeMediaType getMimeType(); + + /** + * Returns the file extension type used by this {@code Document}. This + * value is usually chosen based upon the MIME Media Type. + * + * @return An appropriate file extension for this {@code Document}. + */ + String getFileExtension(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentByteArrayIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentByteArrayIO.java new file mode 100644 index 000000000..dba00eee9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentByteArrayIO.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.nio.ByteBuffer; + + +/** + * Provides {@code byte} array based interfaces for manipulating + * {@code Document} contents. + * + * @see net.jxta.document.Document + */ +public interface DocumentByteArrayIO { + + /** + * Returns the {@code Document} as a sequence of bytes. + */ + byte[] getBytes(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentByteBufferIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentByteBufferIO.java new file mode 100644 index 000000000..2131e16d5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentByteBufferIO.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.nio.ByteBuffer; + + +/** + * Provides {@code ByteBuffer} based interfaces for manipulating + * {@code Document} contents. + * + * @see java.nio.ByteBuffer + * @see net.jxta.document.Document + */ +public interface DocumentByteBufferIO { + + /** + * Returns the {@code Document} as a sequence of ByteBuffers + */ + ByteBuffer[] getByteBuffers(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentStreamIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentStreamIO.java new file mode 100644 index 000000000..c3e9734fc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/DocumentStreamIO.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.InputStream; +import java.io.OutputStream; + +import java.io.IOException; + + +/** + * Provides stream based interfaces for manipulating {@code Document} contents. + * + * @see net.jxta.document.Document + */ +public interface DocumentStreamIO { + + /** + * Returns the stream of bytes which represents the content of this + * {@code Document}. + * + * @return An {@link java.io.InputStream} containing the bytes + * of this {@code Document}. + * @throws IOException For errors while writing the {@code Document}. + */ + InputStream getStream() throws IOException; + + /** + * Send the contents of this {@code Document} to the specified stream. + * + * @param stream The OutputStream to which the {@code Document} will + * be written. + * @throws IOException For errors while writing the {@code Document}. + */ + void sendToStream(OutputStream stream) throws IOException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Element.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Element.java new file mode 100644 index 000000000..b73bd8d7f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/Element.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.document; + + +import java.util.Enumeration; + + +/** + * An element represents a portion of a {@link StructuredDocument}. An element + * is identifiable by a key and may also optionally have a + * value. Each Element also maintains a collection of references + * to other elements, its children. Elements can be + * composed into arbitrary hierarchical structures forming complex data + * structures. + * + *

      Element instances are always associated with a + * {@link StructuredDocument}. A {@link StructuredDocument} is a specialized + * form of Element with additional features that make it appropriate for + * acting as the root of a hierarchy of elements. + * + * @see net.jxta.document.Document + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.StructuredDocumentFactory + * @see net.jxta.document.StructuredTextDocument + * @see net.jxta.document.TextElement + */ +public interface Element> { + + /** + * Get the key associated with this Element. + * + * @return The key of this Element. + */ + Object getKey(); + + /** + * Get the value (if any) associated with this Element. + * + * @return The value of this element, if any, otherwise null. + */ + Object getValue(); + + /** + * Get the root document element of the hierarchy this element belongs to. + * + * @return The root document element of this element's hierarchy. + */ + StructuredDocument getRoot(); + + /** + * Get the parent element of this element. If this Element has not been + * inserted into the Document then null is returned. If this + * element is the root element of the Document then it returns itself. ie., + * this == this.getParent(). + * + * @return The parent of this element. If the element has no parent + * then null will be returned. If the element is the root Element of the + * hierarchy then it will return itself. + */ + E getParent(); + + /** + * Add a child element to this element. The child element must be from the + * document as the element it is to be added to. Elements are created using + * either {@link StructuredDocument#createElement(Object)} or + * {@link StructuredDocument#createElement(Object, Object)}. + * + * @param element The element to be added as a child. + */ + void appendChild(E element); + + /** + * Returns an enumeration of the immediate children of this element. + * + * @return Enumeration containing all of the children of this element. + */ + Enumeration getChildren(); + + /** + * Returns an enumeration of the immediate children of this element who + * match the specified key. + * + * @param key The key which will be matched against. + * @return Enumeration containing all of the matching children of this + * element. + */ + Enumeration getChildren(Object key); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/ExtendableAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/ExtendableAdvertisement.java new file mode 100644 index 000000000..70e71ab7a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/ExtendableAdvertisement.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +/** + * Extendable advertisements provide features for allowing inheritance of + * advertisement types. The core and standard JXTA advertisements all allow + * extension by extending this class. + * + * @see net.jxta.document.Advertisement + * @see net.jxta.document.AdvertisementFactory + * @see net.jxta.document.Document + * @see net.jxta.document.MimeMediaType + */ +public abstract class ExtendableAdvertisement extends Advertisement { + + /** + * If {@code true} then the advertisement will be pretty print formatted + * when it is output as XML. Currently this must be specified at + * construction time as it is normally a preference per advertisement type. + */ + private transient boolean formatted; + + /** + * Default constructor. The advertisement will *not* be pretty-printed when + * it is output as XML. + */ + protected ExtendableAdvertisement() { + this(false); + } + + /** + * @param formatted If {@code true} then the advertisement will be pretty + * print formatted when it is output as XML. + */ + protected ExtendableAdvertisement(boolean formatted) { + this.formatted = formatted; + } + + /** + * Returns the base type of this advertisement hierarchy. Typically, only + * the most basic advertisement of a type will implement this method and + * declare it as final. + * + * @return String the base type of advertisements in this hierarchy. + */ + public abstract String getBaseAdvType(); + + /** + * Process an individual element from the document during parse. Normally, + * implementations will allow the base advertisements a chance to handle + * the element before attempting to handle the element themselves. ie. + *

      + *

      
      +     *  protected boolean handleElement(Element elem) {
      +     *
      +     *      if (super.handleElement()) {
      +     *           // it's been handled.
      +     *           return true;
      +     *           }
      +     *      ... handle elements here ...
      +     *
      +     *      // we don't know how to handle the element
      +     *      return false;
      +     *      }
      +     *  
      + * + * @param elem The element to be processed. + * @return {@code true} if the element was recognized, otherwise false. + */ + protected boolean handleElement(Element elem) { + // we don't handle any elements. + return false; + } + + /** + * Process an individual attribute from the document root node. Normally, + * implementations will allow the base advertisements a chance to handle + * the attribute before attempting to handle the element themselves. ie. + *

      + *

      
      +     *  protected boolean handleAttribute( Attribute elem ) {
      +     * 

      + * if (super.handleAttribute()) { + * // it's been handled. + * return true; + * } + * + * ... handle attributes here ... + * + * // we don't know how to handle the attribute + * return false; + * } + *

      + * + * @param attrib The attribute to be processed. + * @return {@code true} if the attribute was recognized, otherwise false. + */ + protected boolean handleAttribute(Attribute attrib) { + + // "handle" the attributes that we choose to ignore. + if ("xmlns:jxta".equals(attrib.getName())) { + return true; + } else if ("xml:space".equals(attrib.getName())) { + return true; + } else if ("type".equals(attrib.getName())) { + return true; + } + + return false; + } + + /** + * {@inheritDoc} + *

      + * We don't have any content to add, just build the document instance and + * return it to implementations that actually do something with it. + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + Document adv = StructuredDocumentFactory.newStructuredDocument(encodeAs, getBaseAdvType()); + + if (!(adv instanceof Attributable)) { + throw new IllegalArgumentException("Advertisements require document type with attribute support."); + } + + if (adv instanceof XMLDocument) { + XMLDocument xmlAdv = (XMLDocument) adv; + + xmlAdv.addAttribute("xmlns:jxta", "http://jxta.org"); + if (!formatted) { + xmlAdv.addAttribute("xml:space", "preserve"); + } + } + + if (!getBaseAdvType().equals(getAdvType())) { + ((Attributable) adv).addAttribute("type", getAdvType()); + } + + return adv; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/FileDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/FileDocument.java new file mode 100644 index 000000000..bcee2c9fd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/FileDocument.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.OutputStream; + +import java.io.IOException; + + +/** + * This class presents a Document interface for a specific file on disk. + */ +public class FileDocument implements Document { + + private final static int BUFFER_SIZE = 4096; + + /** + * File which backs this document. + */ + private final File file; + + /** + * MIME media type of this document. + **/ + private final MimeMediaType type; + + /** + * Create a new File Document. + **/ + public FileDocument(File file) { + this(file, StructuredDocumentFactory.getMimeTypeForFileExtension(getFileExtension(file))); + } + + /** + * Create a new File Document. + */ + public FileDocument(File file, MimeMediaType type) { + if (file.isDirectory()) { + throw(new IllegalArgumentException("File cannot be a directory")); + } + + if (!file.exists()) { + throw(new IllegalArgumentException("File must exist")); + } + + this.file = file; + this.type = type.intern(); + } + + /** + * {@inheritDoc} + * + *

      Returns everything after the last '.' in the filename, or the + * empty string if the file name does not contain a '.'. + **/ + public String getFileExtension() { + return getFileExtension(file); + } + + /** + *

      Returns everything after the last '.' in the filename, or the + * empty string if the file name does not contain a '.'. + **/ + private static String getFileExtension(File file) { + + String fileName = file.getName(); + int idx = fileName.lastIndexOf('.'); + + if (idx < 0 || idx == fileName.length()) { + return ""; + } else { + return fileName.substring(idx + 1); + } + } + + /** + * {@inheritDoc} + **/ + public MimeMediaType getMimeType() { + return type; + } + + /** + * {@inheritDoc} + **/ + public InputStream getStream() throws IOException { + return new FileInputStream(file); + } + + /** + * {@inheritDoc} + **/ + public void sendToStream(OutputStream sink) throws IOException { + InputStream source = getStream(); + int c; + byte[] buf = new byte[BUFFER_SIZE]; + + do { + c = source.read(buf); + + if (-1 == c) { + break; + } + + sink.write(buf, 0, c); + } while (true); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/MimeMediaType.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/MimeMediaType.java new file mode 100644 index 000000000..c044aacb7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/MimeMediaType.java @@ -0,0 +1,835 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.*; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.*; + + +/** + * MIME Media Types are used to describe the format of data streams. MIME + * Media Types are defined by + * {@link IETF RFC 2046 MIME : Media Types}. + * This class manages parsing of Mime Media Types from strings and piecemeal + * construction of Mime Media Type descriptors. + *

      + *

      Note : This implementation does not include support for the character + * encoding techniques described by : + * {@link IETF RFC 2046 MIME : Media Types}. + * + * @see net.jxta.document.Document + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.StructuredDocumentFactory + * @see net.jxta.document.StructuredTextDocument + */ +public class MimeMediaType implements Serializable { + + /** + * Magic value for this format of serialization version. + */ + private final static long serialVersionUID = 7546247036878523161L; + + private final static String CTL = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" + + "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" + "\u007f"; + + private final static String space = "\u0020"; + private final static String LWSP_char = space + "\u0009"; + private final static String param_sep = LWSP_char + ";"; + private final static String tspecials = "()<>@,;:\\\"/[]?="; + private final static String terminator = CTL + space + tspecials; + + /** + * A canonical map of Mime Media Types. + */ + private static final Map> interned = new WeakHashMap>(); + + /** + * Common Mime Media Type for arbitrary unparsed binary data. + */ + public static final MimeMediaType AOS = new MimeMediaType("application", "octet-stream").intern(); + + /** + * Common Mime Media Type for text encoded using the default character + * encoding for this JVM. The default character encoding is specified by + * the JDK System property "file.encoding". + *

      + *

      The default encoding varies with host platform and locale. This + * media type must not be used for any documents which + * will be exchanged with other peers (as they may be using different + * default character encodings). + */ + public static final MimeMediaType TEXT_DEFAULTENCODING = new MimeMediaType("text", "plain").intern(); + + /** + * Common Mime Media Type for plain text encoded as UTF-8 characters. This + * type is used by JXTA for all strings. + */ + public static final MimeMediaType TEXTUTF8 = new MimeMediaType("text", "plain", "charset=\"UTF-8\"").intern(); + + /** + * Common Mime Media Type for XML encoded using the default character + * encoding for this JVM. The default character encoding is specified by + * the JDK System property "file.encoding". + *

      + *

      The default encoding varies with host platform and locale. This + * media type must not be used for any documents which + * will be exchanged with other peers (as they may be using different + * default character encodings). + */ + public static final MimeMediaType XML_DEFAULTENCODING = new MimeMediaType("text", "xml").intern(); + + /** + * Common Mime Media Type for XML encoded using the default character + * encoding for this JVM. The default character encoding is specified by + * the JDK System property "file.encoding". + *

      + *

      The default encoding varies with host platform and locale. This + * media type must not be used for any documents which + * will be exchanged with other peers (as they may be using different + * default character encodings). + */ + public static final MimeMediaType APPLICATION_XML_DEFAULTENCODING = new MimeMediaType("application", "xml").intern(); + + /** + * Common Mime Media Type for XML encoded as UTF-8 characters. This type is + * used by JXTA for all protocol messages and metadata. + */ + public static final MimeMediaType XMLUTF8 = new MimeMediaType("text", "xml", "charset=\"UTF-8\"").intern(); + + /** + * The primary media type + */ + private transient String type = null; + + /** + * The specific media sub-type + */ + private transient String subtype = null; + + /** + * The parameters for this media type + */ + private transient List parameters = new ArrayList(); + + /** + * The hashcode value for this mime media type. + */ + private transient int cachedHashCode = 0; + + /** + * manages a media type parameter. + */ + private static class parameter implements Comparable { + + /** + * Attribute name. + */ + final String attribute; + + /** + * Value for the attribute. Includes quoting characters if they are + * needed for outputting this value. + */ + final String value; + + parameter(String attr, String val) { + attribute = attr; + value = val; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof parameter)) { + return false; + } + + parameter asParameter = (parameter) obj; + + return attribute.equalsIgnoreCase(asParameter.attribute) && asParameter.value.equals(value); + + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return attribute.toLowerCase().hashCode() * 6037 + value.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return attribute + "=" + outputForm(value); + } + + /** + * {@inheritDoc} + */ + public int compareTo(parameter asParameter) { + if (this == asParameter) { + return 0; + } + + int result = attribute.compareToIgnoreCase(asParameter.attribute); + + if (0 != result) { + return result; + } + + return value.compareTo(asParameter.value); + } + + private static String outputForm(String val) { + StringBuilder result = new StringBuilder(); + + if (-1 == findNextSeperator(val)) { + result.append(val); + } else { + // needs quoting + result.append('\"'); + for (int eachChar = 0; eachChar < val.length(); eachChar++) { + char aChar = val.charAt(eachChar); + + if (('\\' == aChar) || ('\"' == aChar) || ('\r' == aChar)) { + // needs escaping. + result.append('\\'); + } + result.append(aChar); + } + result.append('\"'); + } + return result.toString(); + } + } + + /** + * Creates a new MimeMediaType + * + * @param mimetype string representing a mime-type + */ + public MimeMediaType(String mimetype) { + + String cleaned = mimetype.trim(); + + if (0 == cleaned.length()) { + throw new IllegalArgumentException("input cannot be empty"); + } + + // determine the type + int typeSepAt = findNextSeperator(cleaned); + + if ((-1 == typeSepAt) || (0 == typeSepAt) || ('/' != cleaned.charAt(typeSepAt))) { + throw new IllegalArgumentException("expected seperator or seperator in unexpected location"); + } + + setType(cleaned.substring(0, typeSepAt)); + + // determine the sub-type + int subtypeSepAt = findNextSeperator(cleaned, typeSepAt + 1); + + String itsParams = ""; + + if (-1 == subtypeSepAt) { + setSubtype(cleaned.substring(typeSepAt + 1)); + } else { + setSubtype(cleaned.substring(typeSepAt + 1, subtypeSepAt)); + itsParams = cleaned.substring(subtypeSepAt); + // include the seperator, its significant + } + + parseParams(itsParams, false); + } + + /** + * Creates a new type/subtype MimeMediaType + * + * @param type string representing a mime type + * @param subtype string representing a mime subtype + */ + public MimeMediaType(String type, String subtype) { + this(type, subtype, null); + } + + /** + * Creates a new type/subtype MimeMediaType + * + * @param type string representing a mime type + * @param subtype string representing a mime subtype + * @param parameters parameters to the mime-type constructor + */ + public MimeMediaType(String type, String subtype, String parameters) { + setType(type); + setSubtype(subtype); + if (null != parameters) { + parseParams(parameters, false); + } + } + + /** + * Creates a new type/subtype MimeMediaType with the specified parameters. + * The parameters are copied from the source mime type and additional params + * are added. If replace is true, then the provided params will overwrite + * the params from the source mime type. + * + * @param type the source mime type + * @param params parameters to the mime-type constructor + * @param replace parameters if true then provided params should replace + * existing params else they are accumulated. + */ + public MimeMediaType(MimeMediaType type, String params, boolean replace) { + setType(type.getType()); + setSubtype(type.getSubtype()); + parameters.addAll(type.parameters); + + parseParams(params, replace); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof MimeMediaType)) { + return false; + } + + MimeMediaType asMMT = (MimeMediaType) obj; + + if (!type.equalsIgnoreCase(asMMT.type)) { + return false; + } + + if (!subtype.equalsIgnoreCase(asMMT.subtype)) { + return false; + } + + List myParams = new ArrayList(parameters); + List itsParams = new ArrayList(asMMT.parameters); + + Collections.sort(myParams); + Collections.sort(itsParams); + + return myParams.equals(itsParams); + } + + /** + * Similar to {@link #equals(Object)}, but ignores any parameters. Compares + * only the type and sub-type. + * + * @param obj the object to compare + * @return true if equal + */ + public boolean equalsIngoringParams(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof MimeMediaType)) { + return false; + } + + MimeMediaType likeMe = (MimeMediaType) obj; + + boolean retValue = getType().equalsIgnoreCase(likeMe.getType()) && getSubtype().equalsIgnoreCase(likeMe.getSubtype()); + + return retValue; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + if (0 == cachedHashCode) { + List myParams = new ArrayList(parameters); + + Collections.sort(myParams); + + int calcedHash = type.hashCode() * 2467 + subtype.hashCode() * 3943 + myParams.hashCode(); + + cachedHashCode = (0 != calcedHash) ? calcedHash : 1; + } + + return cachedHashCode; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder retValue = new StringBuilder(getMimeMediaType()); + + for (parameter parameter : parameters) { + retValue.append(';'); + parameter aParam = parameter; + + retValue.append(aParam.toString()); + } + return retValue.toString(); + } + + /** + * Returns the "base" MIME media type of this type. ie. with no parameters. + * + * @return The "base" MIME media type of this MimeMediaType. + */ + public MimeMediaType getBaseMimeMediaType() { + return new MimeMediaType(type, subtype).intern(); + } + + /** + * Returns the "base" MIME media type of this type. ie. with no parameters. + * + * @return The "base" MIME media type of this type. ie. with no parameters. + */ + public String getMimeMediaType() { + StringBuilder retValue = new StringBuilder(type.length() + 1 + subtype.length()); + + retValue.append(type); + retValue.append('/'); + retValue.append(subtype); + + return retValue.toString(); + } + + /** + * Get type of the mime-type + * + * @return type of the mime-type + */ + public String getType() { + return type; + } + + /** + * Check if the mime-type is for provisional. See Section 2.1 of + * {@link IETF RFC 2048 MIME : Registration Procedures} + * + * @return boolean true if it is a provisional type + */ + public boolean isExperimentalType() { + if ((null == type) || (type.length() < 2)) { + return false; + } + + if (type.startsWith("x-") || type.startsWith("x.")) { + return true; + } + + return null != subtype && subtype.length() >= 2 && (subtype.startsWith("x-") || subtype.startsWith("x.")); + + } + + /** + * Set the type of MimeMediaType + * + * @param type type value + */ + private void setType(String type) { + if (null == type) { + throw new IllegalArgumentException("type cannot be null"); + } + + String cleaned = type.trim().toLowerCase(Locale.US); + + if (0 == cleaned.length()) { + throw new IllegalArgumentException("type cannot be null"); + } + + if (-1 != findNextSeperator(cleaned)) { + throw new IllegalArgumentException("type cannot contain a seperator"); + } + + this.type = cleaned; + } + + /** + * Get the Subtype of the mime-type + * + * @return subtype of the mime-type + */ + public String getSubtype() { + return subtype; + } + + /** + * Check if the mime-type is for debugging. This method will be + * removed + * + * @return boolean true if it is a debugging type + */ + public boolean isExperimentalSubtype() { + if ((null == subtype) || (subtype.length() < 2)) { + return false; + } + + return (('x' == subtype.charAt(0)) && ('-' == subtype.charAt(1))); + } + + /** + * Set the subtype of MimeMediaType + * + * @param subtype subtype value + */ + private void setSubtype(String subtype) { + if (null == subtype) { + throw new IllegalArgumentException("subtype cannot be null"); + } + + String cleaned = subtype.trim().toLowerCase(Locale.US); + + if (0 == cleaned.length()) { + throw new IllegalArgumentException("subtype cannot be null"); + } + + if (-1 != findNextSeperator(cleaned)) { + throw new IllegalArgumentException("subtype cannot contain a seperator"); + } + + this.subtype = cleaned; + } + + /** + * Get the value of the first occurance of the specified parameter from the + * parameter list. + * + * @param param the parameter to retrieve. + * @return the value of the specifid parameter or null if the parameter was + * not found. + */ + public String getParameter(String param) { + for (parameter parameter : parameters) { + parameter aParam = parameter; + + if (aParam.attribute.equalsIgnoreCase(param)) { + return aParam.value; + } + } + return null; + } + + /** + * Parses the parametes portion of a MIME Media Type specification. + * + * @param itsParams parse a string for mime parameters. + * @param replace parameters if true then provided params should replace + * existing params else they are accumulated. + */ + private void parseParams(String itsParams, boolean replace) { + int currentCharIdx = 0; + String currentAttribute = null; + boolean inSeperator = true; + boolean inComment = false; + boolean inAttribute = false; + StringBuffer currentValue = null; + boolean inValue = false; + boolean inQuoted = false; + boolean nextEscaped = false; + + while (currentCharIdx < itsParams.length()) { + char currentChar = itsParams.charAt(currentCharIdx); + + if (inSeperator) { + if ('(' == currentChar) { + inSeperator = false; + inComment = true; + } else if (-1 == param_sep.indexOf(currentChar)) { + inSeperator = false; + inAttribute = true; + currentCharIdx--; // unget + } + } else if (inComment) { + if (nextEscaped) { + nextEscaped = false; + } else { + if ('\\' == currentChar) { + nextEscaped = true; + } else if (')' == currentChar) { + inComment = false; + inSeperator = true; + } else if ('\r' == currentChar) { + throw new IllegalArgumentException("malformed mime parameter at idx = " + currentCharIdx); + } + } + } else if (inAttribute) { + int endAttr = findNextSeperator(itsParams, currentCharIdx); + + if ((-1 == endAttr) || ('=' != itsParams.charAt(endAttr)) || (0 == (endAttr - currentCharIdx))) { + throw new IllegalArgumentException("malformed mime parameter at idx = " + currentCharIdx); + } + + currentAttribute = itsParams.substring(currentCharIdx, endAttr).toLowerCase(Locale.US); + + currentCharIdx = endAttr; // skip the equals. + inAttribute = false; + inValue = true; + inQuoted = false; + nextEscaped = false; + currentValue = new StringBuffer(); + } else if (inValue) { + if (inQuoted) { + if (nextEscaped) { + currentValue.append(currentChar); + nextEscaped = false; + } else { + if ('\\' == currentChar) { + nextEscaped = true; + } else if ('"' == currentChar) { + inQuoted = false; + } else if ('\r' == currentChar) { + throw new IllegalArgumentException("malformed mime parameter at idx = " + currentCharIdx); + } else { + currentValue.append(currentChar); + } + } + } else if (-1 == terminator.indexOf(currentChar)) { + currentValue.append(currentChar); + } else { + if ('"' == currentChar) { + inQuoted = true; + } else { + parameter newparam = new parameter(currentAttribute, currentValue.toString()); + + if (replace) { + while (parameters.remove(newparam)) {} + } + + parameters.add(newparam); + + inValue = false; + inSeperator = true; + currentCharIdx--; // unget + } + } + } else { + throw new IllegalArgumentException("malformed mime parameter at idx = " + currentCharIdx); + } + + currentCharIdx++; + } + + // finish off the last value. + if (inValue) { + if (nextEscaped || inQuoted) { + throw new IllegalArgumentException("malformed mime parameter at idx = " + currentCharIdx); + } + + parameter newparam = new parameter(currentAttribute, currentValue.toString()); + + if (replace) { + while (parameters.remove(newparam)) {} + } + + parameters.add(newparam); + + inValue = false; + inSeperator = true; + } + + if (!inSeperator) { + throw new IllegalArgumentException("malformed mime parameter at idx = " + currentCharIdx); + } + } + + /** + * Find next separator position in mime-type + * + * @param source source location + * @return int separator location + */ + private static int findNextSeperator(String source) { + return findNextSeperator(source, 0); + } + + /** + * Find next separator position in mime-type + * + * @param source source location + * @param from from location + * @return int separator location + */ + private static int findNextSeperator(String source, int from) { + + int seperator = -1; + + // find a seperator + for (int eachChar = from; eachChar < source.length(); eachChar++) { + if (-1 != terminator.indexOf(source.charAt(eachChar))) { + seperator = eachChar; + break; + } + } + + return seperator; + } + + /** + * Returns a MimeMediaType with a value represented by the specified String. + *

      + * This method may produce better results than using the constructor + * the same parameter set in that: + *

      + * + * new MimeMediaType( string ) != new MimeMediaType( string ) + * + *

      + * while for common types: + *

      + * + * MimeMediaType.valueOf( string ) == MimeMediaType.valueOf( string ) + * + */ + public static MimeMediaType valueOf(String mimetype) { + return new MimeMediaType(mimetype).intern(); + } + + /** + * Read this Object in for Java Serialization + * + * @param s The stream from which the Object will be read. + * @throws IOException for errors reading from the input stream. + * @throws ClassNotFoundException if the serialized representation contains + * references to classes which cannot be found. + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + s.defaultReadObject(); + + MimeMediaType readType = MimeMediaType.valueOf(s.readUTF()); + + type = readType.type; + subtype = readType.subtype; + parameters = readType.parameters; + } + + /** + * Return the interned form of the ID. + */ + private Object readResolve() throws ObjectStreamException { + return intern(); + } + + /** + * Write this Object out for Java Serialization + * + * @param s The stream to which the Object will be written. + * @throws IOException for errors writing to the output stream. + */ + private void writeObject(ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + + s.writeUTF(toString()); + } + + /** + * Returns a canonical representation for the MimeMediaType object. + *

      + *

      A pool of MimeMediaType, is maintained privately by the class. + *

      + *

      When the intern method is invoked, if the pool already contains a + * MimeMediaType equal to this MimeMediaType object as determined by the + * equals(Object) method, then the MimeMediaType from the pool is returned. + * Otherwise, this MimeMediaType object is added to the pool and a reference + * to this MimeMediaType object is returned. + *

      + *

      It follows that for any two MimeMediaType s and t, + * s.intern() == t.intern() is true if and only if s.equals(t) + * is true. + * + * @return a MimeMediaType that has the same value as this type, but is + * guaranteed to be from a pool of unique types. + */ + public MimeMediaType intern() { + synchronized (MimeMediaType.class) { + Reference common = interned.get(this); + + MimeMediaType result; + + if (null == common) { + common = new WeakReference(this); + interned.put(this, common); + result = this; + } else { + result = common.get(); + if (null == result) { + interned.put(this, new WeakReference(this)); + result = this; + } + } + + return result; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocument.java new file mode 100644 index 000000000..73e19ddd7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocument.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +/** + * An extension of {@link Document} which allows the content of a document to be + * specified by a hierarchy of elements. This allows the content of many + * document types to be manipulated in an abstract way without regard to the + * physical representation of the documents. + * + *

      StructuredDocuments are one of the elementary components that is + * manipulated by the JXTA core. StructuredDocuments are used to represent most + * core objects such as peer, peergroup or pipe advertisements. + * + * @see net.jxta.document.Document + * @see net.jxta.document.StructuredTextDocument + * @see net.jxta.document.StructuredDocumentFactory + **/ +public interface StructuredDocument> extends Document, Element { + + /** + * Create a new element without value. + * + * @param key The key of the element to be created. + * @return The new element. + **/ + E createElement(Object key); + + /** + * Create a new element with value. + * + * @param key The name of the element to be created. + * @param value The value of the element to be created or + * null if no value is desired. + * @return The new element. + **/ + E createElement(Object key, Object value); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentFactory.java new file mode 100644 index 000000000..74154edd3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentFactory.java @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.InputStream; +import java.io.Reader; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import java.io.IOException; +import java.util.MissingResourceException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.util.ClassFactory; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.TextMessageElement; + + +/** + * A factory for constructing instances of {@link StructuredDocument}. + * Behind the scenes, it also provides for the registration of the mime-types + * and constructors needed to accomplish the construction. All supported + * mime-types will need to register their implementation in this factory. + * + * @see net.jxta.document.Document + * @see net.jxta.document.StructuredTextDocument + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.MimeMediaType + */ +public final class StructuredDocumentFactory extends ClassFactory { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(StructuredDocumentFactory.class.getName()); + + /** + * Interface for instantiators of StructuredDocuments + */ + public interface Instantiator { + + /** + * For mapping between extensions and MIME types. + */ + class ExtensionMapping extends Object { + + /** + * The extension + */ + private final String extension; + + /** + * MIME type it maps to + */ + private final MimeMediaType mimetype; + + /** + * default constructor + */ + public ExtensionMapping(String extension, MimeMediaType mimetype) { + this.extension = extension; + this.mimetype = (null != mimetype) ? mimetype.intern() : null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof ExtensionMapping) { + ExtensionMapping likeMe = (ExtensionMapping) target; + + if (!extension.equals(likeMe.extension)) { + return false; + } + + if ((null == mimetype) && (null == likeMe.mimetype)) { + return true; + } + + if ((null == mimetype) || (null == likeMe.mimetype)) { + return false; + } + + return mimetype.equals(likeMe.mimetype); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int hash = extension.hashCode(); + + if (null != mimetype) { + hash ^= mimetype.hashCode(); + } + + return hash; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return extension + " -> " + ((null != mimetype) ? mimetype.toString() : ""); + } + + /** + * Returns the extension which is part of this mapping. + * + * @return the extension which is part of this mapping. + */ + public String getExtension() { + return extension; + } + + /** + * Returns the MIME Media Type which is part of this mapping. + * + * @return the MIME Media Type which is part of this mapping. + */ + public MimeMediaType getMimeMediaType() { + return mimetype; + } + } + + /** + * Returns the MIME Media types supported by this this Document per + * {@link IETF RFC 2046 MIME : Media Types}. + * + *

      JXTA does not currently support the 'Multipart' or 'Message' + * media types. + * + * @return An array of MimeMediaType objects containing the MIME Media Type + * for this Document. + */ + MimeMediaType[] getSupportedMimeTypes(); + + /** + * Returns the mapping of file extension and mime-types for this type + * of document. The default extension is mapped to the 'null' mime-type + * and should only be used if no other mapping matches. + * + * @return An array of objects containing file extensions + */ + ExtensionMapping[] getSupportedFileExtensions(); + + /** + * Create a new structured document of the type specified by doctype. + * + * @param mimeType The MIME type to be associated with this instance. + * the base type must be one of the types returned by + * getSupportedMimeTypes. Some implementations may accept + * parameters in the params section of the MIME type. + * @param doctype Type for the base node of the document. + * @return StructuredDocument instance. + */ + StructuredDocument newInstance(MimeMediaType mimeType, String doctype); + + /** + * Create a new structured document of the type specified by doctype. + * + * @param mimeType The MIME type to be associated with this instance. + * The base type must be one of the types returned by + * getSupportedMimeTypes. Some implementations may accept + * parameters in the params section of the MIME type. + * @param doctype Type for the base node of the document. + * @param value Value for the base node of the document. + * @return {@link StructuredDocument} instance. + */ + StructuredDocument newInstance(MimeMediaType mimeType, String doctype, String value); + + /** + * Create a structured document from a stream containing an appropriately serialized + * instance of the same document. + * + * @param mimeType The MIME type to be associated with this instance. + * The base type must be one of the types returned by + * getSupportedMimeTypes. Some implementations may accept + * parameters in the params section of the MIME type. + * @param source The {@code Inputstream} from which to read the + * document. + * @return {@link StructuredDocument} instance. + * @throws IOException Thrown for problems reading from the source. + */ + StructuredDocument newInstance(MimeMediaType mimeType, InputStream source) throws IOException; + } + + + /** + * Interface for instantiators of StructuredTextDocuments + */ + public interface TextInstantiator extends Instantiator { + + /** + * Create a structured document from a Reader containing an appropriately serialized + * instance of the same document. + * + * @param mimeType The MIME type to be associated with this instance. + * The base type must be one of the types returned by + * getSupportedMimeTypes. Some implementations may accept + * parameters in the params section of the MIME type. + * @param source {@code Reader} from which to read the instance. + * @return {@link StructuredDocument} instance. + * @throws IOException Thrown for problems reading from the source. + */ + StructuredDocument newInstance(MimeMediaType mimeType, Reader source) throws IOException; + } + + /** + * This class is a singleton. This is the instance that backs the + * static methods. + */ + private static final StructuredDocumentFactory factory = new StructuredDocumentFactory(); + + /** + * This is the map of mime-types and instantiators used by + * newStructuredDocument. + */ + private final Map encodings = new HashMap(); + + /** + * This is the map of extensions to mime-types used by + * {@link #getMimeTypeForFileExtension(String) } + */ + private final Map extToMime = new HashMap(); + + /** + * This is the map of mime-types to extensions used by + * {@link #getFileExtensionForMimeType(MimeMediaType mimetype) } + */ + private final Map mimeToExt = new HashMap(); + + /** + * If true then the pre-defined set of StructuredDocument sub-classes has + * been registered from the property containing them. + */ + private boolean loadedProperty = false; + + /** + * Private constructor. This class is not meant to be instantiated except + * by itself. + * + */ + private StructuredDocumentFactory() {} + + /** + * Registers the pre-defined set of StructuredDocument sub-classes so that + * this factory can construct them. + * + * @return true if at least one of the StructuredDocument sub-classes could + * be registered otherwise false. + */ + private synchronized boolean loadProviders() { + if (factory.loadedProperty) { + return true; + } + + factory.loadedProperty = registerProviders(StructuredDocument.class.getName()); + + return factory.loadedProperty; + } + + /** + * {@inheritDoc} + */ + @Override + protected Map getAssocTable() { + return encodings; + } + + /** + * {@inheritDoc} + */ + @Override + protected Class getClassForKey() { + return MimeMediaType.class; + } + + /** + * {@inheritDoc} + */ + @Override + protected Class getClassOfInstantiators() { + // our key is the doctype names. + return Instantiator.class; + } + + /** + * {@inheritDoc} + * + *

      We override the standard implementation to get the MIME type from + * the class and use that as the key to register the class with the factory. + * + * @param className The class name which will be registered. + * @return boolean true if the class was registered otherwise false. + */ + @Override + protected boolean registerAssoc(String className) { + boolean registeredSomething = false; + + LOG.finer("Registering : " + className); + + try { + Class docClass = Class.forName(className); + + Instantiator instantiator = (Instantiator) docClass.getField("INSTANTIATOR").get(null); + + MimeMediaType[] mimeTypes = instantiator.getSupportedMimeTypes(); + + for (int eachType = 0; eachType < mimeTypes.length; eachType++) { + LOG.finer(" Registering Type : " + mimeTypes[eachType].getMimeMediaType()); + registeredSomething |= registerInstantiator(mimeTypes[eachType], instantiator); + } + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to register \'" + className + "\'", all); + } + } + + return registeredSomething; + } + + /** + * Returns the preferred extension for a given mime-type. If there is no + * mapping or no preferred extension for this MIME type then null is + * returned. + * + * @param mimetype the MimeMediaType we wish to know the file extension for. + * @return String containing the extension or null for mime-types with no + * known association. + */ + public static String getFileExtensionForMimeType(MimeMediaType mimetype) { + factory.loadProviders(); + + return factory.mimeToExt.get(mimetype.getBaseMimeMediaType()); + } + + /** + * Returns the preferred mime-type for a given file extension. If there is + * no mapping then null is returned. + * + * @param extension The extension we wish to know the mime-type for. + * @return MimeMediaType associated with this file extension. + */ + public static MimeMediaType getMimeTypeForFileExtension(String extension) { + factory.loadProviders(); + + MimeMediaType result = factory.extToMime.get(extension); + + return result; + } + + /** + * Register an instantiator object a mime-type of documents to be + * constructed. + * + * @param mimetype the mime-type associated. + * @param instantiator the instantiator that wants to be registered.. + * @return boolean true if the instantiator for this mime-type is now + * registered. If there was already an instantiator this mime-type then + * false will be returned. + * @throws SecurityException there were permission problems registering + * the instantiator. + */ + public static boolean registerInstantiator(MimeMediaType mimetype, Instantiator instantiator) { + boolean registered = factory.registerAssoc(mimetype.getBaseMimeMediaType(), instantiator); + + if (registered) { + Instantiator.ExtensionMapping[] extensions = instantiator.getSupportedFileExtensions(); + + for (int eachExt = 0; eachExt < extensions.length; eachExt++) { + if (null != extensions[eachExt].getMimeMediaType()) { + factory.extToMime.put(extensions[eachExt].getExtension(), extensions[eachExt].getMimeMediaType().intern()); + + factory.mimeToExt.put(extensions[eachExt].getMimeMediaType(), extensions[eachExt].getExtension()); + + // And the base version. + factory.mimeToExt.put(extensions[eachExt].getMimeMediaType().getBaseMimeMediaType(), extensions[eachExt].getExtension()); + } + } + } + + return registered; + } + + /** + * Constructs an instance of {@link StructuredDocument} matching + * the mime-type specified by the mimetype parameter. The + * doctype parameter identifies the base type of the + * {@link StructuredDocument}. + * + * @param mimetype Specifies the mime media type to be associated with + * the {@link StructuredDocument} to be created. + * @param doctype Specifies the root type of the {@link StructuredDocument} + * to be created. + * @return StructuredDocument The instance of {@link StructuredDocument} + * or null if it could not be created. + * @throws NoSuchElementException invalid mime-media-type + */ + public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, String doctype) { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType()); + + return instantiator.newInstance(mimetype, doctype); + } + + /** + * Constructs an instance of {@link StructuredDocument} matching + * the mime-type specified by the mimetype parameter. The + * doctype parameter identifies the base type of the + * {@link StructuredDocument}. Value supplies a value for the root + * element. + * + * @param mimetype Specifies the mime media type to be associated with + * the {@link StructuredDocument} to be created. + * @param doctype Specifies the root type of the {@link StructuredDocument} + * to be created. + * @param value Specifies a value for the root element. + * @return StructuredDocument The instance of {@link StructuredDocument} + * or null if it could not be created. + * @throws NoSuchElementException if the mime-type has not been registered. + */ + public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, String doctype, String value) { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType()); + + return instantiator.newInstance(mimetype, doctype, value); + } + + /** + * Constructs an instance of {@link StructuredDocument} matching + * the mime-type specified by the mimetype parameter. The + * doctype parameter identifies the base type of the + * {@link StructuredDocument}. + * + * @param mimetype Specifies the mime media type to be associated with the + * {@link StructuredDocument} to be created. + * @param stream Contains an InputStream from which the document will be + * constructed. + * @return StructuredDocument The instance of {@link StructuredDocument} + * or null if it could not be created. + * @throws IOException If there is a problem reading from the stream. + * @throws NoSuchElementException if the mime-type has not been registered. + */ + public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, InputStream stream) throws IOException { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType()); + + return instantiator.newInstance(mimetype, stream); + } + + /** + * Constructs an instance of {@link StructuredDocument} matching + * the mime-type specified by the mimetype parameter. The + * doctype parameter identifies the base type of the + * {@link StructuredDocument}. + * + * @param mimetype Specifies the mime media type to be associated with the + * {@link StructuredDocument} to be created. + * @param reader A Reader from which the document will be constructed. + * @return StructuredDocument The instance of {@link StructuredDocument} + * or {@code null} if it could not be created. + * @throws IOException If there is a problem reading from the stream. + * @throws NoSuchElementException if the mime-type has not been registered. + * @throws UnsupportedOperationException if the mime-type provided is not + * a text oriented MIME type. + */ + public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, Reader reader) throws IOException { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType()); + + if (!(instantiator instanceof TextInstantiator)) { + // XXX 20020502 bondolo@jxta.org we could probably do something + // really inefficient that would allow it to work, but better not to. + // if ReaderInputStream existed, it would be easy to do. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning( "Document Class \'" + instantiator.getClass().getName() + "\' associated with \'" + mimetype + + "\' is not a text oriented document"); + } + + throw new UnsupportedOperationException( "Document Class '" + instantiator.getClass().getName() + + "' associated with '" + mimetype + "' is not a text oriented document"); + } + + return ((TextInstantiator) instantiator).newInstance(mimetype, reader); + } + + /** + * Constructs an instance of {@link StructuredDocument} based upon the + * content of the provided message element. + * + * @param element The message element from which to create the document. + * @return StructuredDocument The instance of {@link StructuredDocument} + * or null if it could not be created. + * @throws IOException If there is a problem reading from the stream. + * @throws NoSuchElementException if the mime-type has not been registered. + */ + public static StructuredDocument newStructuredDocument(MessageElement element) throws IOException { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(element.getMimeType().getBaseMimeMediaType()); + + if ((instantiator instanceof TextInstantiator) && (element instanceof TextMessageElement)) { + return ((TextInstantiator) instantiator).newInstance(element.getMimeType(), ((TextMessageElement) element).getReader()); + } else { + return instantiator.newInstance(element.getMimeType(), element.getStream()); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentUtils.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentUtils.java new file mode 100644 index 000000000..0a3b07da7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentUtils.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.util.Enumeration; + + +/** + * Provides a number of static utility members which are helpful in + * manipluating StructuredDocuments. + * + **/ +public final class StructuredDocumentUtils { + + /** + * A singleton class, not meant to be constructed + **/ + private StructuredDocumentUtils() { + ; + } + + /** + * Recursively copy children elements of from into the + * the element intoElement of document intoDoc. + * + *

      BEWARE that this does NOT copy the TEXTVALUE (if any) of the + * fromParent element, ONLY CHILDREN. All other elements + * are fully copied, including their textValue. + * + *

      It is not possible to copy a textValue in an existing element. + * + * @param intoDoc the document into which the elements will be + * copied. + * @param intoElement the element which will serve as the parent for + * the elements being copied. + * @param from the parent element of the elements which will be copied. + **/ + public static void copyChildren(StructuredDocument intoDoc, Element intoElement, Element from) { + + for (Enumeration eachChild = from.getChildren(); eachChild.hasMoreElements();) { + + Element aChild = (Element) eachChild.nextElement(); + Element newElement = intoDoc.createElement(aChild.getKey(), aChild.getValue()); + + intoElement.appendChild(newElement); + + // copy attributes if any + if ((aChild instanceof Attributable) && (newElement instanceof Attributable)) { + Enumeration eachAttrib = ((Attributable) aChild).getAttributes(); + + while (eachAttrib.hasMoreElements()) { + Attribute anAttrib = (Attribute) eachAttrib.nextElement(); + + ((Attributable) newElement).addAttribute(anAttrib.getName(), anAttrib.getValue()); + } + } + + // recurse to add the children. + copyChildren(intoDoc, newElement, aChild); + } + } + + /** + * Recursively copy elements beginnging with from into the + * document identified by intoDoc. + * + * @param intoDoc the document into which the elements which will be + * copied. + * @param intoElement the element which will serve as the parent for + * the elements being copied. + * @param from the root element of the hierarchy which will be copied. + * @param newName the root element being copied is renamed + * newName. + * @return The added element. + * + **/ + public static Element copyElements(StructuredDocument intoDoc, Element intoElement, Element from, Object newName) { + + Element newElement = intoDoc.createElement(newName, from.getValue()); + + intoElement.appendChild(newElement); + + boolean hasType = false; + + // copy attributes if any + if (newElement instanceof Attributable) { + + if (from instanceof Attributable) { + Enumeration eachAttrib = ((Attributable) from).getAttributes(); + + while (eachAttrib.hasMoreElements()) { + Attribute anAttrib = (Attribute) eachAttrib.nextElement(); + String attribName = anAttrib.getName(); + + if (attribName.equals("type")) { + hasType = true; + } + ((Attributable) newElement).addAttribute(attribName, anAttrib.getValue()); + } + } + + // If "from" happens to be a document, and if it happens to be renamed, and if it does not have an explicit type + // attribute, then preserve the document type, which we assume is the original name, converted to string, as a type + // attribute. It is an XMLism. It may be wrong or at least ineffective for other kinds of structured documents. If + // it one day becomes an issue, it will have to be resolved by having a method specific to each kind of structured + // document and dedicated to correcting type loss. + + Object origName = from.getKey().toString(); + + if ((!hasType) && (!newName.equals(origName)) && (from instanceof Document)) { + ((Attributable) newElement).addAttribute("type", origName.toString()); + } + } + + StructuredDocumentUtils.copyChildren(intoDoc, newElement, from); + + return newElement; + } + + /** + * Recursively copy elements beginnging with from into the + * document identified by intoDoc. + * + * @param intoDoc the document into which the elements which will be + * copied. + * @param intoElement the element which will serve as the parent for + * the elements being copied. + * @param from the root element of the hierarchy which will be copied. + * @return The added element. + **/ + public static Element copyElements(StructuredDocument intoDoc, Element intoElement, Element from) { + + return copyElements(intoDoc, intoElement, from, from.getKey()); + } + + /** + * Copies the specified element or document into a standalone document of + * same type. The from for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +/** + * Extends {@link StructuredDocument} to provide accessors appropriate for text + * based documents. + * + * @see net.jxta.document.Document + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.TextDocument + * @see net.jxta.document.Element + * @see net.jxta.document.TextElement + * @see net.jxta.document.StructuredDocumentFactory + */ +public interface StructuredTextDocument> extends TextDocument, StructuredDocument, TextElement { + + /** + * Create a new element without value. + * + * @param name The name of the element to be created. + * @return The new element. + */ + T createElement(String name); + + /** + * Create a new element with value. + * + * @param name The name of the element to be created. + * @param value The value of the element to be created. + * @return The new element. + */ + T createElement(String name, String value); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocument.java new file mode 100644 index 000000000..701a5b18c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocument.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.Writer; +import java.io.Reader; + +import java.io.IOException; + + +/** + * Extends {@link net.jxta.document.Document} for text documents. + * + * @see net.jxta.document.Document + */ +public interface TextDocument extends Document, TextDocumentReaderIO {} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharArrayIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharArrayIO.java new file mode 100644 index 000000000..9ad6c2c6a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharArrayIO.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.Writer; +import java.io.Reader; + +import java.io.IOException; + + +/** + * Provides {@code char} array based interfaces for manipulating + * {@code TextDocument}s. + */ +public interface TextDocumentCharArrayIO { + + /** + * Returns the sequence of characters which represents the content of the + * {@code TextDocument}. + * + * @return A character array containing the characters of the + * {@code TextDocument}. + */ + char[] getChars(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharBufferIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharBufferIO.java new file mode 100644 index 000000000..304602cc2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharBufferIO.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.Writer; +import java.io.Reader; + +import java.io.IOException; + + +/** + * Provides {@code Reader}/{@code Writer} based interfaces for manipulating + * {@code TextDocument}s. + */ +public interface TextDocumentCharBufferIO { + + /** + * Returns the sequence of characters which represents the content of the + * {@code TextDocument}. + * + * @return A character array containing the characters of the + * {@code TextDocument}. + */ + CharSequence getCharSequence(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharSequenceIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharSequenceIO.java new file mode 100644 index 000000000..fda5b2753 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentCharSequenceIO.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.nio.CharBuffer; + + +/** + * Provides {@code Reader}/{@code Writer} based interfaces for manipulating + * {@code TextDocument}s. + */ +public interface TextDocumentCharSequenceIO { + + /** + * Returns the sequence of characters which represents the content of the + * {@code TextDocument}. + * + * @return A sequence of {@code CharBuffer}s containing the characters of + * the {@code TextDocument}. + */ + CharBuffer getCharBuffers(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentReaderIO.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentReaderIO.java new file mode 100644 index 000000000..a1742ab6f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextDocumentReaderIO.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.io.Writer; +import java.io.Reader; + +import java.io.IOException; + + +/** + * Provides {@code Reader}/{@code Writer} based interfaces for manipulating + * {@code TextDocument}s. + */ +public interface TextDocumentReaderIO { + + /** + * Returns the sequence of characters which represents the content of the + * {@code TextDocument}. + * + * @return An {@link java.io.Reader} containing the characters of the + * {@code TextDocument}. + * @throws IOException If an I/O error occurs. + */ + Reader getReader() throws IOException; + + /** + * Send the contents of this {@code TextDocument} to the specified + * Writer. + * + * @param writer The {@link java.io.Writer} to which the characters of the + * {@code TextDocument} will be written. + * @throws IOException If an I/O error occurs. + */ + void sendToWriter(Writer writer) throws IOException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextElement.java new file mode 100644 index 000000000..c816cee9b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/TextElement.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.util.Enumeration; + + +/** + * Extends {@link Element} to provide {@link java.lang.String} oriented + * accessors for instances of {@link StructuredTextDocument} + * + * @see net.jxta.document.Document + * @see net.jxta.document.Element + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.StructuredTextDocument + */ +public interface TextElement> extends Element { + + /** + * {@inheritDoc} + */ + String getKey(); + + /** + * {@inheritDoc} + */ + String getValue(); + + /** + * {@inheritDoc} + */ + StructuredTextDocument getRoot(); + + /** + * Get the name associated with an element. + * + * @return A string containing the name of this element. + */ + String getName(); + + /** + * Get the value (if any) associated with an element. + * + * @return A string containing the value of this element, if any, otherwise null. + */ + String getTextValue(); + + /** + * Returns an enumeration of the immediate children of this element whose + * name match the specified string. + * + * @param name The name which will be matched against. + * @return An enumeration containing all of the children of this element. + */ + Enumeration getChildren(String name); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/XMLDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/XMLDocument.java new file mode 100644 index 000000000..1424da1e6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/XMLDocument.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +/** + * Common interfaces for all {@link net.jxta.document.StructuredTextDocument} + * which are implemented by XML Documents. Appropriate for advertisements and + * messages. + */ +public interface XMLDocument> extends XMLElement, StructuredTextDocument { + + /** + * {@inheritDoc} + */ + X createElement(String name); + + /** + * {@inheritDoc} + */ + X createElement(String name, String value); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/XMLElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/XMLElement.java new file mode 100644 index 000000000..091ffc8ee --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/XMLElement.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.document; + + +import java.util.Enumeration; + + +/** + * Common definition of XML Elements. Appropriate for advertisements and + * messages. + */ +public interface XMLElement> extends TextElement, Attributable { + + /** + * {@inheritDoc} + */ + XMLDocument getRoot(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/package.html new file mode 100644 index 000000000..e579d09e2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/package.html @@ -0,0 +1,13 @@ + + + + + + + JXTA Documents are containers for both structured and unstructured data. + Advertisements are used to describe JXTA resources such as peers, groups, + services, and codats. + + @see JXTA Protocols Specification : Advertisementss + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/AbstractMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/AbstractMessenger.java new file mode 100644 index 000000000..d81cba5eb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/AbstractMessenger.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.util.AbstractSimpleSelectable; +import net.jxta.util.SimpleSelectable; + +import java.io.IOException; +import java.io.InterruptedIOException; + + +/** + * An AbstractMessenger is used to implement messengers (for example, by transport modules). + * It supplies the convenience, bw compatible, obvious, or otherwise rarely changed methods. + * Many method cannot be overloaded in order to ensure standard behaviour. + * The rest is left to implementations. + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.Message + */ +public abstract class AbstractMessenger extends AbstractSimpleSelectable implements Messenger { + + /** + * The default Maximum Transmission Unit. + */ + protected static final long DEFAULT_MTU = Long.parseLong(System.getProperty("net.jxta.MTU", "65536")); + + /** + * The destination address of messages sent on this messenger. + */ + protected final EndpointAddress dstAddress; + + /** + * The stateLock that we share with the implementation. + * This permits to implement waitState in a totally generic way: waitState depends only on the lock + * (provided at construction), and on getState(), supplied by the implementation. + */ + private Object stateLock; + + /** + * Create a new abstract messenger. + *

      + * Warning: This class needs to know the object on which to waitState must synchronize. It is generally impossible + * to pass it at construction because it is not yet constructed. Instead implementations MUST call {@link #setStateLock} + * from their constructor. + * + * @param dest who messages should be addressed to + */ + public AbstractMessenger(EndpointAddress dest) { + dstAddress = dest; + } + + /** + * {@inheritDoc} + *

      + * A simple implementation for debugging. Do not depend upon the format. + */ + @Override + public String toString() { + return super.toString() + " {" + dstAddress + "}"; + } + + /** + * Specifies the object on which waitState must synchronize. + * + * @param stateLock The object on which waitState must synchronize. This has to be the object that gets notified when the + * implementation changes its state. Changing state is defined as "any operation that causes the result of the + * getState method to change". Implementations that use the MessengerState state machine should typically use the + * MessengerState object as their state lock, but it is not assumed. + */ + protected void setStateLock(Object stateLock) { + this.stateLock = stateLock; + } + + /* + * Messenger methods implementations. + */ + + /** + * {@inheritDoc} + *

      + * This is here for backward compatibility reasons. The notion of long term unemployment still exists, but is no-longer part + * of the API. Self closing for unemployment is now a built-in feature of messengers. + */ + @Deprecated + public final boolean isIdle() { + return false; + } + + /** + * {@inheritDoc} + */ + @Deprecated + public final boolean isSynchronous() { + return false; + } + + /** + * {@inheritDoc} + */ + public final EndpointAddress getDestinationAddress() { + return dstAddress; + } + + /** + * {@inheritDoc} + */ + @Deprecated + public final EndpointAddress getDestinationAddressObject() { + return dstAddress; + } + + /** + * {@inheritDoc} + *

      It is not always enforced. At least this much can always be sent. + */ + public long getMTU() { + return DEFAULT_MTU; + } + + /** + * {@inheritDoc} + *

      + * This is a minimal implementation. It may not detect closure + * initiated by the other side unless the messenger was actually used + * since. A more accurate (but not mandatory implementation) would + * actually go and check the underlying connection, if relevant...unless + * breakage initiated by the other side is actually reported asynchronously + * when it happens. Breakage detection from the other side need not + * be reported atomically with its occurrence. This not very important + * since we canonicalize transport messengers and so do not need to + * aggressively collect closed ones. When not used, messengers die by themselves. + */ + public boolean isClosed() { + return (getState() & USABLE) == 0; + } + + /** + * {@inheritDoc} + */ + public final void flush() throws IOException { + int currentState = 0; + + try { + currentState = waitState(IDLE, 0); + } catch (InterruptedException ie) { + InterruptedIOException iio = new InterruptedIOException("flush() interrupted"); + + iio.initCause(ie); + throw iio; + } + + if ((currentState & (CLOSED | USABLE)) != 0) { + return; + } + + throw new IOException("Messenger was unexpectedly closed."); + } + + /** + * {@inheritDoc} + */ + public final boolean sendMessage(Message msg) throws IOException { + return sendMessage(msg, null, null); + } + + /** + * {@inheritDoc} + * + */ + public void sendMessage(Message msg, String service, String serviceParam, OutgoingMessageEventListener listener) { + throw new UnsupportedOperationException("This legacy method is not supported by this messenger."); + } + + /** + * {@inheritDoc} + */ + public final boolean sendMessage(Message msg, String rService, String rServiceParam) throws IOException { + + // We have to retrieve the failure from the message and throw it if its an IOException, this is what the API + // says that this method does. + + if (sendMessageN(msg, rService, rServiceParam)) { + return true; + } + + Object failed = msg.getMessageProperty(Messenger.class); + + if ((failed == null) || !(failed instanceof OutgoingMessageEvent)) { + // huh ? + return false; + } + + Throwable t = ((OutgoingMessageEvent) failed).getFailure(); + + if (t == null) { + // Must be saturation, then. (No throw for that). + return false; + } + + // Now see how we can manage to throw it. + if (t instanceof IOException) { + throw (IOException) t; + } else if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else if (t instanceof Error) { + throw (Error) t; + } + + IOException failure = new IOException("Failure sending message"); + + failure.initCause(t); + + throw failure; + } + + /** + * {@inheritDoc} + *

      + * This method synchronizes on the lock object supplied at construction. + */ + public final int waitState(int wantedStates, long timeout) throws InterruptedException { + synchronized (stateLock) { + if (timeout == 0) { + while ((wantedStates & getState()) == 0) { + stateLock.wait(); + } + return getState(); + } + + if (timeout < 0) { + stateLock.wait(timeout); // let it throw the appropriate error. + } + + long start = System.currentTimeMillis(); + long end = start + timeout; + + if (end < start) { + end = Long.MAX_VALUE; + } + long left = end - start; + + while ((left > 0) && (wantedStates & getState()) == 0) { + + stateLock.wait(left); + + left = end - System.currentTimeMillis(); + } + + return getState(); + } + } + + /* + * SimpleSelectable implementation. + */ + + /** + * Implements a default for all AbstractMessengers: mirror the event to our selectors. This is what is needed by all the + * known AbstractMessengers that register themselves somewhere. (That is ChannelMessengers). + * FIXME - jice@jxta.org 20040413: Not sure that this is the best default. + * + * @param changedObject Ignored. + */ + public void itemChanged(SimpleSelectable changedObject) { + notifyChange(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/AsyncChannelMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/AsyncChannelMessenger.java new file mode 100644 index 000000000..ff8607ebf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/AsyncChannelMessenger.java @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +import net.jxta.peergroup.PeerGroupID; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +/** + * Extends Channel Messenger behaviour to provide asynchronous message sending + * via queuing. + */ +public abstract class AsyncChannelMessenger extends ChannelMessenger { + + /* + * Logger + * private final static transient Logger LOG = Logger.getLogger(AsyncChannelMessenger.class.getName()); + */ + + /** + * {@code true} if we have deliberately closed our one message input queue. + */ + private boolean inputClosed = false; + + /** + * {@code true} if we have deliberately stopped sending. + */ + private boolean outputClosed = false; + + /** + * Actions that we defer to after returning from event methods. In other + * words, they cannot be done with the lock held, or they require calling + * more event methods. + */ + private enum DeferredAction { + + /** + * No action deferred. + */ + ACTION_NONE, + /** + * Must send the current message. + */ + ACTION_SEND, + /** + * Must report failure to connect. + */ + ACTION_CONNECT + } + + /** + * The current deferred action. + */ + private DeferredAction deferredAction = DeferredAction.ACTION_NONE; + + /** + * The messages queue. + */ + private final BlockingQueue queue; + + /** + * State lock and engine. + */ + private final AsyncChannelMessengerState stateMachine; + + /** + * Our statemachine implementation; just connects the standard MessengerState action methods to + * this object. + */ + private class AsyncChannelMessengerState extends MessengerState { + + protected AsyncChannelMessengerState(boolean connected) { + super(connected); + } + + /* + * The required action methods. + */ + + /** + * {@inheritDoc} + */ + @Override + protected void connectAction() { + deferredAction = DeferredAction.ACTION_CONNECT; + } + + /** + * {@inheritDoc} + */ + @Override + protected void startAction() { + deferredAction = DeferredAction.ACTION_SEND; + } + + /** + * {@inheritDoc} + */ + @Override + protected void closeInputAction() { + // We're synchronized here. (invoked from stateMachine) + inputClosed = true; + } + + /** + * {@inheritDoc} + */ + @Override + protected void closeOutputAction() { + // We're synchronized here. (invoked from stateMachine) + outputClosed = true; + } + + /** + * {@inheritDoc} + */ + @Override + protected void failAllAction() { + + // The queue is now closed, so we can rest assured that the last + // message is really the last one. This is a synchronous action. The + // state machine assumes that it is done when we return. There is no + // need to signal completion with an idleEvent. + PendingMessage theMsg; + + while (true) { + theMsg = null; + + synchronized (stateMachine) { + theMsg = queue.poll(); + } + + if (theMsg == null) { + return; + } + + Message currentMsg = theMsg.msg; + Throwable currentFailure = theMsg.failure; + + if (currentFailure == null) { + currentFailure = new IOException("Messenger unexpectedly closed"); + } + + OutgoingMessageEvent event = new OutgoingMessageEvent(currentMsg, currentFailure); + + currentMsg.setMessageProperty(Messenger.class, event); + } + } + } + + + /** + * The representation of a queued message. It is shared between this + * abstract class and any implementation. + */ + protected static class PendingMessage { + final Message msg; + final String service; + final String param; + Throwable failure; + + PendingMessage(Message msg, String service, String param) { + this.msg = msg; + this.service = service; + this.param = param; + this.failure = null; + } + } + + /** + * Create a new AsyncChannelMessenger. + * + * @param baseAddress The network address messages go to; regardless of + * service, param, or group. + * @param redirection Group to which the messages must be redirected. This + * is used to implement the automatic group segregation which has become a + * de-facto standard. If not null, the unique portion of the specified + * groupID is prepended with {@link #InsertedServicePrefix} and inserted in + * every message's destination address in place of the the original service + * name, which gets shifted into the beginning of the service parameter. The + * opposite is done on arrival to restore the original destination address + * before the message is delivered to the listener in the the specified + * group. Messages that already bear a group redirection are not affected. + * @param origService The default destination service for messages sent + * without specifying a different service. + * @param origServiceParam The default destination service parameter for + * messages sent without specifying a different service parameter. + * @param queueSize the queue size that channels should have. + * @param connected true if the channel is created in the connected state. + */ + public AsyncChannelMessenger(EndpointAddress baseAddress, PeerGroupID redirection, String origService, String origServiceParam, int queueSize, boolean connected) { + + super(baseAddress, redirection, origService, origServiceParam); + + stateMachine = new AsyncChannelMessengerState(connected); + + queue = new ArrayBlockingQueue(queueSize); + + // We synchronize our state with the sharedMessenger's stateMachine. + // Logic would dictate that we pass it to super(), but it is not itself + // constructed until super() returns. No way around it. + + setStateLock(stateMachine); + } + + /** + * {@inheritDoc} + */ + public final void close() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.closeEvent(); + action = eventCalled(true); + } + + // We called an event. State may have changed. + notifyChange(); + + performDeferredAction(action); + } + + /** + * This internal method does the common part of sending the message on + * behalf of both sendMessageN and sendMessageB. + *

      It is not quite possible to implement sendMessageB as a wrapper + * around sendMessageN without some internal cooperation. At least not in + * an efficient manner. sendMessageB must not set the message property: + * either it fails and throws, or it returns successfully and the property + * is set later. This is required so that messages can be retried when + * failing synchronously (through a blocking messenger typically, but the + * semantic has to be uniform). + *

      Each of sendMessageB and sendMessageN takes care of status reporting + * on its own terms. + * + * @param msg the message to send + * @param rService destination service + * @param rServiceParam destination param + * @return The outcome from that one attempt. {@code true} means done. + * {@code false} means saturated. When {@code true} is returned, it means + * that the fate of the message will be decided asynchronously, so we do + * not have any details, yet. + * @throws IOException is thrown if this messenger is closed. + * @throws InterruptedException if interrupted + */ + private boolean sendMessageCommon(Message msg, String rService, String rServiceParam) throws IOException, InterruptedException { + + String service = effectiveService(rService); + String serviceParam = effectiveParam(rService, rServiceParam); + boolean queued = true; + boolean change = false; + DeferredAction action = DeferredAction.ACTION_NONE; + + synchronized (stateMachine) { + if (inputClosed) { + throw new IOException("This messenger is closed. It cannot be used to send messages."); + } + + boolean wasEmpty = queue.isEmpty(); + + if (queue.remainingCapacity() > 1) { + queue.put(new PendingMessage(msg, service, serviceParam)); + + // Still not saturated. If we weren't idle either, then nothing worth mentionning. + if (wasEmpty) { + change = true; + stateMachine.msgsEvent(); + action = eventCalled(false); + } + } else if (1 == queue.remainingCapacity()) { + queue.put(new PendingMessage(msg, service, serviceParam)); + + // Now saturated. + stateMachine.saturatedEvent(); + action = eventCalled(false); + change = true; + } else { + // Was already saturated. + queued = false; + } + } + + if (queued && change) { + // If not queued, there was no change of condition as far as + // outsiders are concerned. (redundant saturatedEvent, only + // defensive; to guarantee statemachine in sync). else, if the + // saturation state did not change, we have no state change to + // notify. + notifyChange(); + } + + performDeferredAction(action); + + // Before we return, make sure that this channel remains referenced if + // it has messages. It could become unreferenced if it is not yet + // resolved and the application lets go of it after sending messages. + // This means that we may need to do something only in the resolpending + // and resolsaturated cases. The way we do this test, there can be false + // positives. They're dealt with as part of the action that is carried + // out. + if ((stateMachine.getState() & (Messenger.RESOLPENDING | Messenger.RESOLSATURATED)) != 0) { + resolPendingImpl(); + } + + return queued; + } + + /** + * {@inheritDoc} + */ + public final boolean sendMessageN(Message msg, String rService, String rServiceParam) { + + try { + if (sendMessageCommon(msg, rService, rServiceParam)) { + // If it worked the message is queued; the outcome will be notified later. + return true; + } + // Non-blocking and queue full: report overflow. + msg.setMessageProperty(Messenger.class, OutgoingMessageEvent.OVERFLOW); + } catch (IOException oie) { + msg.setMessageProperty(Messenger.class, new OutgoingMessageEvent(msg, oie)); + } catch (InterruptedException interrupted) { + msg.setMessageProperty(Messenger.class, new OutgoingMessageEvent(msg, interrupted)); + } + return false; + } + + /** + * {@inheritDoc} + */ + public final void sendMessageB(Message msg, String rService, String rServiceParam) throws IOException { + + try { + while (true) { + // if sendMessageCommon says "true" it worked. + if (sendMessageCommon(msg, rService, rServiceParam)) { + return; + } + // Do a shallow check on the queue. If it seems empty (without getting into a critical section to + // verify it), then yielding is good bet. It is a lot cheaper and smoother than waiting. + // Note the message should be enqueued now. yielding makes sense now if the queue is empty + if (queue.isEmpty()) { + Thread.yield(); + } + + // If we reached this far, it is neither closed, nor ok. So it was saturated. + synchronized (stateMachine) { + // Cheaper than waitState. sendMessageCommon already does the relevant state checks. + stateMachine.wait(); + } + } + } catch (InterruptedException ie) { + InterruptedIOException iie = new InterruptedIOException("Message send interrupted"); + + iie.initCause(ie); + throw iie; + } + } + + /** + * {@inheritDoc} + */ + public final void resolve() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.resolveEvent(); + action = eventCalled(true); + } + notifyChange(); + performDeferredAction(action); // we expect connect but let the state machine decide. + } + + /** + * {@inheritDoc} + */ + public final int getState() { + return stateMachine.getState(); + } + + /** + * {@inheritDoc} + */ + @Override + public final Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam) { + // Channels don't make channels. + return null; + } + + /** + * Three exposed methods may need to inject new events in the system: + * sendMessageN, close, and shutdown. + * Since they can all cause actions, and since connectAction and + * startAction are deferred, it seems possible that one of the actions + * caused by send, close, or shutdown be called while connectAction or + * startAction are in progress. + *

      However, the state machine gives us a few guarantees: connectAction + * and startAction can never nest. We will not be asked to perform one while + * still performing the other. Only the synchronous actions closeInput, + * closeOutput, or failAll can possibly be requested in the interval. We + * could make more assumptions and simplify the code, but rather keep at + * least some flexibility. + *

      + * DEAD LOCK WARNING: the implementor's method invoke some of our call backs + * while synchronized. Then our call backs synchronize on the state machine + * in here. This nesting order must always be respected. As a result, we can + * never invoke implementors methods while synchronized. Hence the + * deferredAction processing. + * + * @param action the action + */ + private void performDeferredAction(DeferredAction action) { + switch (action) { + case ACTION_SEND: + startImpl(); + break; + + case ACTION_CONNECT: + connectImpl(); + break; + } + } + + /** + * A shortHand for a frequently used sequence. MUST be called while + * synchronized on stateMachine. + * + * @param notifyAll If {@code true} then this is a life-cycle event and all + * waiters on the stateMachine should be notified. If {@code false} then + * only a single waiter will be notified for simple activity events. + * @return the deferred action. + */ + private DeferredAction eventCalled(boolean notifyAll) { + DeferredAction action = deferredAction; + + deferredAction = DeferredAction.ACTION_NONE; + if (notifyAll) { + stateMachine.notifyAll(); + } else { + stateMachine.notify(); + } + return action; + } + + /* + * Implement the methods that our shared messenger will use to report progress. + */ + + /** + * The implementation will invoke this method when it becomes resolved, + * after connectImpl was invoked. + */ + protected void up() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.upEvent(); + action = eventCalled(true); + } + notifyChange(); + performDeferredAction(action); // we expect start but let the state machine decide. + } + + /** + * The implementation invokes this method when it becomes broken. + */ + protected void down() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.downEvent(); + action = eventCalled(true); + } + notifyChange(); + performDeferredAction(action); // we expect connect but let the state machine decide. + } + + /** + * Here, we behave like a queue to the shared messenger. When we report + * being empty, though, we're automatically removed from the active queues + * list. We'll go back there the next time we have something to send by + * calling startImpl. + * + * @return pending message + */ + protected PendingMessage peek() { + + PendingMessage theMsg; + DeferredAction action = DeferredAction.ACTION_NONE; + + synchronized (stateMachine) { + // We like the msg to keep occupying space in the queue until it's + // out the door. That way, idleness (that is, not currently working + // on a message), is always consistent with queue emptyness. + + theMsg = queue.peek(); + if (theMsg == null) { + stateMachine.idleEvent(); + action = eventCalled(false); + + // We do not notifyChange, here, because, if the queue is empty, + // it was already notified when the last message was popped. The + // call to idleEvent is only defensive programming to make extra + // sure the state machine is in sync. + + return null; + } + + if (outputClosed) { + // We've been asked to stop sending. Which, if we were sending, + // must be notified by either an idle event or a down + // event. Nothing needs to happen to the shared messenger. We're + // just a channel. + stateMachine.downEvent(); + action = eventCalled(true); + theMsg = null; + } + } + + notifyChange(); + performDeferredAction(action); // we expect none but let the state machine decide. + return theMsg; + } + + /** + * Returns the number of elements in this collection. If this collection + * contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection + */ + protected int size() { + return queue.size(); + } + + /** + * One message done. Update the saturated/etc state accordingly. + * + * @return true if there are more messages after the one we removed. + */ + protected boolean poll() { + + boolean result; + DeferredAction action; + + synchronized (stateMachine) { + queue.poll(); + + if (queue.peek() == null) { + stateMachine.idleEvent(); + action = eventCalled(false); + result = false; + } else { + stateMachine.msgsEvent(); + action = eventCalled(false); + result = true; + } + } + + notifyChange(); + performDeferredAction(action); // we expect none but let the state machine decide. + + return result; + } + + /** + * We invoke this method to be placed on the list of channels that have + * message to send. + *

      + * NOTE that it is the shared messenger responsibility to synchronize so + * that we cannot be added to the active list just before we get removed + * due to reporting an empty queue in parallel. So, if we report an empty + * queue and have a new message to send before the shared messenger removes + * us form the active list, startImpl will block until the removal is done. + * Then we'll be added back. + *

      + * If it cannot be done, it means that the shared messenger is no longer + * usable. It may call down() in sequence. Out of defensiveness, it should + * do so without holding its lock. + */ + protected abstract void startImpl(); + + /** + * We invoke this method to be placed on the list of channels that are + * waiting for resolution. + *

      + * If it cannot be done, it means that the shared messenger is no longer + * usable. It may call down() in sequence. Out of defensiveness, it should + * do so without holding its lock. If the messenger is already resolved it + * may call up() in sequence. Same wisdom applies. It is a good idea to + * create channels in the resolved state if the shared messenger is already + * resolved. That avoids this extra contortion. + */ + protected abstract void connectImpl(); + + /** + * This is invoked to inform the implementation that this channel is now in + * the resolPending or resolSaturated state. This is specific to this type + * of channels. The shared messenger must make sure that this channel + * remains strongly referenced, even though it is not resolved, because + * there are messages in it. It is valid for an application to let go of a + * channel after sending a message, even if the channel is not yet + * resolved. The message will go if/when the channel resolves. This method + * may be invoked redundantly and even once the channel is no longer among + * the one awaiting resolution. The implementation must be careful to + * ignore such calls. + */ + protected abstract void resolPendingImpl(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ByteArrayMessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ByteArrayMessageElement.java new file mode 100644 index 000000000..f2892b7e2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ByteArrayMessageElement.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.document.MimeMediaType; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.zip.CRC32; +import java.util.zip.Checksum; + + +/** + * A Message Element using byte arrays for the element data. + * + *

      This implementation does not copy the byte array provided and assumes + * that the contents of the byte array will not change through out the lifetime + * of the MessageElement. + * + *

      some synchronization is due to optimization in {@link #getBytes(boolean)} + * which replaces value of internal member {@link #b}. + */ +public class ByteArrayMessageElement extends MessageElement { + + /** + * Logger + */ + private static transient final Logger LOG = Logger.getLogger(ByteArrayMessageElement.class.getName()); + + /** + * The bytes of this element. + */ + protected byte[] b; + + /** + * This is the offset of our data within the array + */ + protected int offset; + + /** + * length of the element data. sometimes the same as b.length, but may be + * lesser. + */ + protected int len; + + /** + * Create a new Message Element. The contents of the provided byte array + * are not copied during construction. + * + * @param name Name of the MessageElement. May be the empty string ("") if + * the MessageElement is not named. + * @param type Type of the MessageElement. null is the same as specifying + * the type "Application/Octet-stream". + * @param b A byte array containing the contents of this element. + * @param sig optional message digest/digital signature element or null if + * no signature is desired. + */ + public ByteArrayMessageElement(String name, MimeMediaType type, byte[] b, MessageElement sig) { + this(name, type, b, 0, b.length, sig); + } + + /** + * Create a new MessageElement, The contents of the provided byte array are + * not copied during construction. + * + * @param name Name of the MessageElement. May be the empty string ("") if + * the MessageElement is not named. + * @param type Type of the MessageElement. null is the same as specifying + * the type "Application/Octet-stream". + * @param b A byte array containing the contents of this element. + * @param offset all bytes before this location in b + * will be ignored. + * @param sig optional message digest/digital signature elemnent or null if + * no signature is desired. + */ + public ByteArrayMessageElement(String name, MimeMediaType type, byte[] b, int offset, MessageElement sig) { + this(name, type, b, offset, b.length - offset, sig); + } + + /** + * Create a new Element, but dont add it to the message. The contents of + * the byte array are not copied during construction. + * + * @param name Name of the MessageElement. May be the empty string ("") if + * the MessageElement is not named. + * @param type Type of the MessageElement. null is the same as specifying + * the type "Application/Octet-stream". + * @param b A byte array containing the contents of this Element. + * @param offset all bytes before this location will be ignored. + * @param len number of bytes to include + * @param sig optional message digest/digital signature element or null if + * no signature is desired. + */ + public ByteArrayMessageElement(String name, MimeMediaType type, byte[] b, int offset, int len, MessageElement sig) { + super(name, type, sig); + + if (null == b) { + throw new IllegalArgumentException("byte array must not be null"); + } + + if (len < 0) { + throw new IllegalArgumentException("len must be >= 0 : " + len); + } + + if (offset < 0) { + throw new IllegalArgumentException("offset must within byte array : " + offset); + } + + if ((0 != len) && (offset >= b.length)) { + throw new IllegalArgumentException("offset must be positioned within byte array : " + offset + "," + len); + } + + if (((offset + len) > b.length) || ((offset + len) < 0)) { + throw new IllegalArgumentException("offset + len must be positioned within byte array"); + } + + // if we get an empty request and a non-empty buffer, we don't use the provided buffer. + if ((0 == len) && (0 != b.length)) { + b = new byte[len]; + offset = 0; + } + + this.b = b; + this.offset = offset; + this.len = len; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof MessageElement) { + if (!super.equals(target)) { + return false; + } + + if (target instanceof ByteArrayMessageElement) { + ByteArrayMessageElement likeMe = (ByteArrayMessageElement) target; + + synchronized (this) { + synchronized (likeMe) { + if (likeMe.len != len) { + return false; + } + + for (int eachByte = len - 1; eachByte >= 0; eachByte--) { + if (likeMe.b[likeMe.offset + eachByte] != b[offset + eachByte]) { + return false; + } + } + } + } + + return true; + } else { + // have to do a slow stream comparison. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + try { + MessageElement likeMe = (MessageElement) target; + + InputStream myStream = getStream(); + InputStream itsStream = likeMe.getStream(); + + int mine; + int its; + + do { + mine = myStream.read(); + its = itsStream.read(); + + if (mine != its) { + return false; + } // content didn't match + + } while ((-1 != mine) && (-1 != its)); + + return ((-1 == mine) && (-1 == its)); // end at the same time? + } catch (IOException fatal) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "MessageElements could not be compared.", fatal); + } + + throw new IllegalStateException("MessageElements could not be compared." + fatal); + } + } + } + + return false; // not a message element + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized int hashCode() { + Checksum crc = new CRC32(); + + crc.update(b, offset, len); + int dataHash = (int) crc.getValue(); + + int result = super.hashCode() * 6037 + // a prime + dataHash; + + return (0 != result) ? result : 1; + } + + /** + * {@inheritDoc} + *

      + * Returns the string representation of this element. The 'charset' + * parameter of the mimetype, if any, is used to determine encoding. If + * the charset specified is unsupported then the default encoding will be + * used. + * + * @return String string representation of this message element. + */ + @Override + public synchronized String toString() { + String result; + + if (null != cachedToString) { + result = cachedToString.get(); + + if (null != result) { + return result; + } + } + + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("creating toString of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + String charset = type.getParameter("charset"); + + try { + if (null == charset) { + result = new String(b, offset, len); + } else { + result = new String(b, offset, len, charset); + } + } catch (UnsupportedEncodingException caught) { + result = new String(b, offset, len); + } + + cachedToString = new SoftReference(result); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public long getByteLength() { + return len; + } + + /** + * {@inheritDoc} + *

      + *

      synchronized so that we can replace our internal buffer with + * the buffer we are returning if we were using a shared buffer. + */ + @Override + public synchronized byte[] getBytes(boolean copy) { + if ((!copy) && (0 == offset) && (b.length == len)) { + return b; + } + + byte[] result = new byte[len]; + + System.arraycopy(b, offset, result, 0, len); + + // if we were using a sub-array we can switch to using this copy. + if (!copy) { + b = result; + offset = 0; + } + + return result; + } + + /** + * {@inheritDoc} + */ + public synchronized InputStream getStream() { + return new ByteArrayInputStream(b, offset, len); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendToStream(OutputStream sendTo) throws IOException { + byte[] sending; + int sendingOffset; + + // locals enable us to reduce the time which the object is synchronized. + synchronized (this) { + sending = b; + sendingOffset = offset; + } + + sendTo.write(sending, sendingOffset, len); + } + + /** + * Returns the contents of this element as a byte array. If this elements + * was originally constructed from a intact byte array, the array returned + * is a "shared" copy of the byte array used by this element. If this + * element was constructed with an offset of other than zero and a length + * different than the length of the source array then this function WILL + * RETURN A COPY OF THE BYTE ARRAY. + * + * @return a byte array containing the contents of this element. + */ + public byte[] getBytes() { + return getBytes(false); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ChannelMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ChannelMessenger.java new file mode 100644 index 000000000..38beb6621 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ChannelMessenger.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.peergroup.PeerGroupID; + + +/** + * A Channel Messenger provides an exclusive interface to the shared messenger. + *

      + * What is typically exclusive is the message queue, addressing parameters + * that are not usefully shared (serviceName, serviceParam), and if needed + * cross-group address rewriting parameters. + *

      + * This class is provided as a base for implementing such channel messengers, + * which are typically what Messenger.getChannelMessenger() needs to return. + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.Message + */ +public abstract class ChannelMessenger extends AbstractMessenger implements Messenger { + + /** + * insertedServicePrefix This is how all valid inserted services start. This + * lets us recognize if a message already has an inserted service. Then we + * must not add another one. Only the top-most one counts. Since insertion + * is only done here, the constant is defined here. Even if historically it + * was done within the endpoint implementation, it has become a protocol now. + */ + public static final String InsertedServicePrefix = "EndpointService:"; + + private String insertedService; + + /** + * The worker that implements sendMessage-with-listener for this channel. If + * there's none, sendMessage-with-listener will throw an exception. Channels + * returned by getMessenger methods all have one already. It is up to the + * invoker of getChannelMessenger to supply one or not. + */ + private ListenerAdaptor messageWatcher; + + protected String origService; + + protected String origServiceParam; + + /** + * Figure out what the service string will be after mangling (if required) + * and applying relevant defaults. + * + * @param service The service name in the unmangled address. + * @return String The service name in the mangled address. + */ + protected String effectiveService(String service) { + + // No redirection required. Just apply the default service. + if (insertedService == null) { + return (service == null) ? origService : service; + } + + // Check if redirection is applicable. + return ((service != null) && service.startsWith(InsertedServicePrefix)) ? service : insertedService; + } + + /** + * Figure out what the param string will be after mangling (if required) and + * applying relevant defaults. + * + * @param service The service name in the unmangled address. + * @param serviceParam The service parameter in the unmangled address. + * @return String The service parameter in the mangled address. + */ + protected String effectiveParam(String service, String serviceParam) { + + // No redirection required. Or not applicable. Just apply the default param. + if ((insertedService == null) || ((service != null) && service.startsWith(InsertedServicePrefix))) { + return (serviceParam == null) ? origServiceParam : serviceParam; + } + + // Apply redirection. We need the effective service, now. + if (service == null) { + service = origService; + } + + if (serviceParam == null) { + serviceParam = origServiceParam; + } + + return ((null != service) && (null != serviceParam)) ? (service + "/" + serviceParam) : service; + } + + /** + * Give this channel the watcher that it must use whenever sendMessage(...,listener) is used. If not set, + * sendMessage(..., listener) will throw. + * + * @param messageWatcher the listener + */ + public void setMessageWatcher(ListenerAdaptor messageWatcher) { + this.messageWatcher = messageWatcher; + } + + /** + * Create a new ChannelMessenger + * + * @param baseAddress The network address messages go to; regardless of service, param, or group. + * @param groupRedirection Group to which the messages must be redirected. This is used to implement the automatic group + * segregation which has become a de-facto standard. If not null, the unique portion of the specified groupID is + * prepended with {@link #InsertedServicePrefix} and inserted in every message's destination address in place of the + * the original service name, which gets shifted into the beginning of the service parameter. The opposite is done + * on arrival to restore the original destination address before the message is delivered to the listener in the + * the specified group. Messages that already bear a group redirection are not affected. + * @param origService The default destination service for messages sent without specifying a different service. + * @param origServiceParam The default destination service parameter for messages sent without specifying a different service + * parameter. + */ + public ChannelMessenger(EndpointAddress baseAddress, PeerGroupID groupRedirection, String origService, String origServiceParam) { + + // FIXME: The inserted service business is really messy. Group seggregation does not have to be the endpoint service's + // business. It should be specified by the app as part of the destination address. What we're doing here + // is simply enforcing what could just be a convention. + + super(baseAddress); + if (groupRedirection == null) { + insertedService = null; + } else { + insertedService = InsertedServicePrefix + groupRedirection.getUniqueValue().toString(); + } + this.origService = origService; + this.origServiceParam = origServiceParam; + } + + /** + * {@inheritDoc} + *

      + * By default a channel refuses to make a channel. + */ + public Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam) { + return null; + } + + /** + * {@inheritDoc} + * + */ + @Override + public void sendMessage(Message msg, String service, String serviceParam, OutgoingMessageEventListener listener) { + if (messageWatcher == null) { + throw new UnsupportedOperationException("This channel was not configured to emulate this legacy method."); + } + + // Cleanup the message from any existing result prop since we're going to use select. + msg.setMessageProperty(Messenger.class, null); + + // Tell the watcher to select that message. + messageWatcher.watchMessage(listener, msg); + + sendMessageN(msg, service, serviceParam); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointAddress.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointAddress.java new file mode 100644 index 000000000..e804f579c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointAddress.java @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +import net.jxta.id.ID; +import net.jxta.logging.Logging; + +import java.lang.ref.SoftReference; +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Describes a destination to which JXTA messages may be sent. This may be: + *

      + * + *

        + *
      • A Pipe
      • + *
      • A Peergroup (propagate)
      • + *
      • A Peer
      • + *
      • A Message Transport for a Peer
      • + *
      + *

      + * An Endpoint Address is a specialized interpretation of a URI. + * Wherever it makes sense you should use a URI in preference to an Endpoint + * Address. An Endpoint Address is composed of four components: a protocol + * (also called a scheme), a protocol address (also called an authority), an + * optional service name and optional service parameter. + *

      + * The Protocol

        + *
      • Describes the method of addressing used by the remainder of the + * endpoint address.
      • + *
      • Indicates how the address will be resolved, ie. who will resolve it.
      • + *
      • Corresponds to the "scheme" portion of a URI in W3C parlance. + *
      • May not contain the ":" character. + *
      + *

      + * The Protocol Address

        + *
      • Describes the destination entity of this address.
      • + *
      • Form is dependant upon the protocol being used.
      • + *
      • Corresponds to the "Authority" portion of a URI in W3C parlance. + *
      • May not contain the "/" character. + *
      + *

      + * The Service Name (optional)

        + *
      • Describes the service that is the destination. A service cannot be + * a protocol address because a service must have a location; a group or a + * specific peer.
      • + *
      • Form is dependant upon service intent. This is matched as a UTF8 + * string.
      • + *
      • May not contain the "/" character. + *
      + * + *

      The Service Parameter (optional)

        + *
      • Describes parameters for the service.
      • + *
      • Form is dependant upon service intent. This is matched as a UTF-8 + * string (if it is used for matching).
      • + *
      + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.Messenger + * @see net.jxta.pipe.PipeService + */ +public class EndpointAddress { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(EndpointAddress.class.getName()); + + /** + * If {@code true} then endpoint addresses based upon IDs are represented + * using the "jxta://" form. If false then they are presented using the + * "urn:jxta:" form. The two forms are meant to be logically equivalent. + */ + private final static boolean IDS_USE_JXTA_URL_FORM = true; + + /** + * The default protocol value for Endpoint Addresses based upon JXTA IDs. + */ + private final static String JXTA_ID_PROTOCOL = ID.URIEncodingName + ":" + ID.URNNamespace; + + /** + * if true then the address is a url, otherwise its a uri (likely a urn). + */ + private boolean hierarchical = true; + + /** + * Describes the method of addressing used by the remainder of the + * endpoint address. + */ + private String protocol = null; + + /** + * Describes the destination entity of this address. + */ + private String protocolAddress = null; + + /** + * Describes the service that is the destination. + */ + private String service = null; + + /** + * Describes parameters for the service. + */ + private String serviceParam = null; + + /** + * cached calculated hash code. + */ + private transient int cachedHashCode = 0; + + /** + * cached copy of string representation. + */ + private transient SoftReference cachedToString = null; + + /** + * Returns an unmodifiable clone of the provided EndpointAddress. + * + * @param address the address to be cloned. + * @return the unmodifiable address clone. + * @deprecated All EndpointAddresses are now unmodifiable so this method is + * no longer needed. + */ + @Deprecated + public static EndpointAddress unmodifiableEndpointAddress(EndpointAddress address) { + return address; + } + + /** + * Builds an Address from a string + * + * @param address the string representation of the address. + */ + public EndpointAddress(String address) { + parseURI(address); + } + + /** + * Create an EndpointAddress whose value is initialized from the provided + * URI. + * + * @param address the URI representation of the address. + */ + public EndpointAddress(URI address) { + this(address.toString()); + } + + /** + * Constructor which builds an endpoint address from a base address and + * replacement service and params + * + * @param base The EndpointAddress on which the new EndpointAddress will be based + * @param service The service name for the endpoint address or + * {@code null} if there is no service name. + * @param serviceParam The service parameter for the endpoint address or + * {@code null} if there is no parameter. + */ + public EndpointAddress(EndpointAddress base, String service, String serviceParam) { + setProtocolName(base.getProtocolName()); + setProtocolAddress(base.getProtocolAddress()); + setServiceName(service); + setServiceParameter(serviceParam); + } + + /** + * Constructor which builds an address the four standard constituent parts. + * + * @param protocol The addressing scheme to be used for the endpoint address. + * @param address The destination for the endpoint address. + * @param service The service name for the endpoint address or + * {@code null} if there is no service name. + * @param serviceParam The service parameter for the endpoint address or + * {@code null} if there is no parameter. + */ + public EndpointAddress(String protocol, String address, String service, String serviceParam) { + setProtocolName(protocol); + setProtocolAddress(address); + setServiceName(service); + setServiceParameter(serviceParam); + } + + /** + * Constructor which builds an address from a standard jxta id and a + * service and param. + * + * @param id the ID which will be the destination of the endpoint address. + * @param service The service name for the endpoint address or + * {@code null} if there is no service name. + * @param serviceParam The service parameter for the endpoint address or + * {@code null} if there is no parameter. + */ + public EndpointAddress(ID id, String service, String serviceParam) { + setProtocolName(JXTA_ID_PROTOCOL); + setProtocolAddress(id.getUniqueValue().toString()); + setServiceName(service); + setServiceParameter(serviceParam); + } + + /** + * {@inheritDoc} + * + * @deprecated EndpointAddress objects are immutable and never need to be + * cloned. + */ + @Override + @Deprecated + public EndpointAddress clone() { + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof EndpointAddress) { + EndpointAddress likeMe = (EndpointAddress) target; + + boolean result = (hierarchical == likeMe.hierarchical) && protocol.equalsIgnoreCase(likeMe.protocol) + && protocolAddress.equalsIgnoreCase(likeMe.protocolAddress) + && ((service != null) + ? ((likeMe.service != null) && service.equals(likeMe.service)) + : (likeMe.service == null)) + && ((serviceParam != null) + ? ((likeMe.serviceParam != null) && serviceParam.equals(likeMe.serviceParam)) + : (likeMe.serviceParam == null)); + + return result; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + if (0 == cachedHashCode) { + int calcedHashCode = protocol.toLowerCase().hashCode(); + + calcedHashCode += protocolAddress.hashCode() * 5741; // a prime + calcedHashCode += ((service != null) ? service.hashCode() : 1) * 7177; // a prime + calcedHashCode += ((serviceParam != null) ? serviceParam.hashCode() : 1) * 6733; // a prime + + cachedHashCode = (0 == calcedHashCode) ? 1 : calcedHashCode; + } + + return cachedHashCode; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized String toString() { + String result; + + if (null != cachedToString) { + result = cachedToString.get(); + + if (null != result) { + return result; + } + } + + StringBuilder newResult = new StringBuilder(protocol.length() + protocolAddress.length() + 64); + + newResult.append(protocol); + + if (hierarchical) { + newResult.append("://"); + } else { + newResult.append(':'); + } + + newResult.append(protocolAddress); + + if (null != service) { + if (hierarchical) { + newResult.append('/'); + } else { + newResult.append('#'); + } + newResult.append(service); + + if (null != serviceParam) { + newResult.append('/'); + newResult.append(serviceParam); + } + } + + result = newResult.toString(); + + cachedToString = new SoftReference(result); + + return result; + } + + /** + * Return a URI which represents the endpoint address. + * + * @return a URI which represents the endpoint address. + */ + public URI toURI() { + return URI.create(toString()); + } + + /** + * Return a String that contains the name of the protocol + * contained in the EndpointAddress + * + * @return a String containing the protocol name + */ + public String getProtocolName() { + return protocol; + } + + /** + * Return a String that contains the protocol address contained + * in the EndpointAddress + * + * @return a String containing the protocol address + */ + public String getProtocolAddress() { + return protocolAddress; + } + + /** + * Return a String that contains the service name contained in + * the EndpointAddress + * + * @return a String containing the service name + */ + public String getServiceName() { + return service; + } + + /** + * Return a String that contains the service parameter contained + * in the EndpointAddress + * + * @return a String containing the protocol name + */ + public String getServiceParameter() { + return serviceParam; + } + + /** + * Set the protocol name. + * + * @param name String containing the name of the protocol + */ + private void setProtocolName(String name) { + if ((null == name) || (0 == name.length())) { + throw new IllegalArgumentException("name must be non-null and contain at least one character"); + } + + if (-1 != name.indexOf("/")) { + throw new IllegalArgumentException("name may not contain '/' character"); + } + + // XXX 20070207 bondolo We explicitly force all use of either "jxta" or "urn:jxta" to our prefered form. + if (IDS_USE_JXTA_URL_FORM) { + if (JXTA_ID_PROTOCOL.equals(name)) { + name = "jxta"; + } + } else { + if ("jxta".equals(name)) { + name = JXTA_ID_PROTOCOL; + } + } + + int colonAt = name.indexOf(':'); + + if (-1 == colonAt) { + hierarchical = true; + } else { + if (!"urn".equalsIgnoreCase(name.substring(0, colonAt))) { + throw new IllegalArgumentException("Only urn may contain colon"); + } + + if (colonAt == (name.length() - 1)) { + throw new IllegalArgumentException("empty urn namespace!"); + } + + hierarchical = false; + } + + protocol = name; + cachedToString = null; + } + + /** + * Set the protocol address. + * + * @param address String containing the peer address. + */ + private void setProtocolAddress(String address) { + if ((null == address) || (0 == address.length())) { + throw new IllegalArgumentException("address must be non-null and contain at least one character"); + } + + if (-1 != address.indexOf("/")) { + throw new IllegalArgumentException("address may not contain '/' character"); + } + + protocolAddress = address; + cachedToString = null; + } + + /** + * Set the service name. + * + * @param name String containing the name of the destination service + */ + private void setServiceName(String name) { + if (null != name) { + if (-1 != name.indexOf("/")) { + throw new IllegalArgumentException("service name may not contain '/' character"); + } + } + + service = name; + cachedToString = null; + } + + /** + * Set the service parameter + * + * @param param String containing the service parameter + */ + private void setServiceParameter(String param) { + serviceParam = param; + cachedToString = null; + } + + /** + * Parse any EndpointAddress from a URI + * + * @param addr endpoint address to parse + */ + private void parseURI(String addr) { + int index = addr.indexOf("://"); + + if (index == -1) { + parseURN(addr); + } else { + parseURL(addr); + } + } + + /** + * Parse an EndpointAddress from a URN + * + * @param addr endpoint address to parse + */ + private void parseURN(String addr) { + int protocolEnd = addr.indexOf(':'); + + if (-1 == protocolEnd) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Address is not a valid URI: " + addr); + } + throw new IllegalArgumentException("Address is not a valid URI: " + addr); + } + + if (!"urn".equalsIgnoreCase(addr.substring(0, protocolEnd))) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Address is unrecognized URI form: " + addr); + } + throw new IllegalArgumentException("Address is unrecognized URI form: " + addr); + } + + if ((addr.length() - 1) == protocolEnd) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Address URN does not have a namespace: " + addr); + } + throw new IllegalArgumentException("Address URN does not have a namespace: " + addr); + } + + // gather the namespace as well. + int namespaceEnd = addr.indexOf(':', protocolEnd + 1); + + if (-1 == namespaceEnd) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Address URN does not have a namespace: " + addr); + } + throw new IllegalArgumentException("Address URN does not have a namespace: " + addr); + } + + setProtocolName(addr.substring(0, namespaceEnd)); + + if ((addr.length() - 1) == namespaceEnd) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Address URN does not have a NSS portion: " + addr); + } + throw new IllegalArgumentException("Address URN does not have a NSS portion: " + addr); + } + + // check for service and param + int nssEnd = addr.indexOf('#', namespaceEnd + 1); + + if (-1 == nssEnd) { + setProtocolAddress(addr.substring(namespaceEnd + 1)); + } else { + setProtocolAddress(addr.substring(namespaceEnd + 1, nssEnd)); + + int serviceEnd = addr.indexOf('/', nssEnd + 1); + + if (-1 == serviceEnd) { + setServiceName(addr.substring(nssEnd + 1)); + } else { + setServiceName(addr.substring(nssEnd + 1, serviceEnd)); + + setServiceParameter(addr.substring(serviceEnd + 1)); + } + } + } + + /** + * Parse and EndpointAddress from a URL + * + * @param addr endpoint address to parse + */ + private void parseURL(String addr) { + String remainder; + + int index = addr.indexOf("://"); + + if (index == -1) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Address is not in absolute form: " + addr); + } + throw new IllegalArgumentException("Address is not in absolute form: " + addr); + } + + if (0 == index) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Protocol is missing: " + addr); + } + throw new IllegalArgumentException("Protocol is missing: " + addr); + } + + try { + setProtocolName(addr.substring(0, index)); + remainder = addr.substring(index + 3); + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Protocol address is missing: " + addr); + } + throw new IllegalArgumentException("Protocol address is missing: " + addr); + } + index = remainder.indexOf("/"); + if (index == -1) { + setProtocolAddress(remainder); + return; + } + + setProtocolAddress(remainder.substring(0, index)); + + remainder = remainder.substring(index + 1); + + index = remainder.indexOf("/"); + if (index == -1) { + setServiceName(remainder); + return; + } + + setServiceName(remainder.substring(0, index)); + + remainder = remainder.substring(index + 1); + + setServiceParameter(remainder); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointListener.java new file mode 100644 index 000000000..a61d3cc9e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointListener.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +/** + * A listener for messages. The listener is invoked for each incoming message + * which is destined for this listener. Various services register + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.Message + */ +public interface EndpointListener { + + /** + * This method is invoked by the EndpointService for each incoming message + * which is addressed to this listener. + * + * @param message Incoming message + * @param srcAddr Endpoint Address of the source of the message. + * @param dstAddr Endpoint Address of the destination of the message. + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointService.java new file mode 100644 index 000000000..27a8bf3c3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/EndpointService.java @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.peergroup.PeerGroup; +import net.jxta.service.Service; + +import java.io.IOException; +import java.util.Iterator; + + +/** + * The EndpointService provides the API for sending and receiving messages + * between peers. In general, applications and services use the + * {@link net.jxta.pipe.PipeService}, or {@link net.jxta.socket.JxtaSocket} + * rather than using this API directly. + */ +public interface EndpointService extends Service, EndpointListener { + + /** + * Low Priority Messenger Event Listener. + */ + public static final int LowPrecedence = 0; + + /** + * Medium Priority Messenger Event Listener. + */ + public static final int MediumPrecedence = 1; + + /** + * High Priority Messenger Event Listener. + */ + public static final int HighPrecedence = 2; + + /** + * Returns the group to which this EndpointService is attached. + * + * @return the group. + */ + public PeerGroup getGroup(); + + /** + * Returns a messenger to the specified destination. + *

      + * The canonical messenger is shared between all channels who's + * destination contain the same protocol name and protocol address, in all + * groups that have access to the same transport. The ChannelMessenger + * returned is configured to send messages to the specified service name and + * service param when these are not specified at the time of sending. + *

      + * The channel will also ensure delivery to this EndpointService's group + * on arrival. The channel is not shared with any other module. That is, + * each endpoint service interface object (as returned by {@link + * net.jxta.peergroup.PeerGroup#getEndpointService()}) will return a + * different channel messenger for the same destination. However, there is + * no guarantee that two invocations of the same endpoint service interface + * object for the same destination will return different channel objects. + * Notably, if the result of a previous invocation is still strongly + * referenced and in a {@link Messenger#USABLE} state, then that is what + * this method will return. + *

      + * This method returns immediately. The messenger is not necessarily + * resolved (the required underlying connection established, for example), + * and it might never resolve at all. Changes in the state of a messenger + * may monitored with {@link Messenger#getState} and + * {@link Messenger#waitState}. One may monitor multiple + * {@link Messenger messengers} (and {@link Message Messages}) at a time by + * using a {@link net.jxta.util.SimpleSelector}. One may also arrange to + * have a listener invoked when resolution is complete by using + * {@link ListenerAdaptor}. + *

      + * The {@code hint} is interpreted by the transport. The only transport + * known to consider hints is the endpoint router, and the hint is a route. + * As a result, if addr is in the form: jxta://uniqueID, then hint may be a + * RouteAdvertisement. If that route is valid the router will add it to + * it's cache of route and may then use it to successfully create a messenger + * to the given destination. There is no guarantee at this time that the + * route will end up being the one specified, nor that this route will be + * used only for this messenger (likely the opposite), nor that it will + * remain in use in the future, nor that it will be used at all. However, if + * there is no other route, and if the specified route is valid, it will be + * used rather than seeking an alternative. + * + * @param addr The complete destination address. + * @param hint A optional hint to be supplied to whichever transport ends-up + * making the real messenger. May be {@code null}, when no hint applies. + * @return A messenger for the specified destination address or {@code null} + * if the address is not handled by any of the available Message Transports. + * The messenger, if returned, is not necessarily functional, nor resolved. + * @see net.jxta.endpoint.ChannelMessenger + */ + public Messenger getMessengerImmediate(EndpointAddress addr, Object hint); + + /** + * Returns a messenger for the specified destination address. + *

      + * Behaves like {@link #getMessengerImmediate(EndpointAddress,Object)}, + * except that the invoker is blocked until the Messenger either resolves or + * it is determined that no usable messenger can be created. + * + * @param addr The destination address. + * @param hint A optional hint to be supplied to whichever transport ends-up + * making the real messenger. May be {@code null}, when no hint applies. + * @return A messenger for the specified destination address or {@code null} + * if the destination address is not reachable. + */ + public Messenger getMessenger(EndpointAddress addr, Object hint); + + /** + * Creates and maps a canonical messenger to the specified destination. + *

      + * Behaves like {@link #getMessengerImmediate(EndpointAddress,Object)} + * except that it returns a canonical messenger. + *

      + * The messenger is said to be canonical, because there is only one such + * live object for any given destination address. The term "live", + * here means that the messenger is not in any of the + * {@link Messenger#TERMINAL} states as defined by {@link MessengerState}. + * Therefore, for a given destination there may be any number of messengers + * in a {@link Messenger#TERMINAL} state, but at most one in any other state. + * As long as such an object exists, all calls to + * {@code getCanonicalMessenger()} for the same address return this very + * object. + *

      + * When first created, a canonical messenger is usually in the + * {@link Messenger#UNRESOLVED} state. It becomes resolved by obtaining an + * actual transport messenger to the destination upon the first attempt at + * using it or when first forced to attempt resolution. Should resolution + * fail at that point, it becomes {@link Messenger#UNRESOLVABLE}. Otherwise, + * subsequent, failures are repaired automatically by obtaining a new + * transport messenger when needed. If a failure cannot be repaired, the + * messenger becomes {@link Messenger#BROKEN}. + *

      + * {@code getCanonicalMessenger()} is a recursive function. + * Exploration of the parent endpoint is done automatically. + *

      + * Note 1: This method is the most fundamental messenger + * instantiation method. It creates a different messenger for each variant + * of destination address passed to the constructor. In general invokers + * should use plain addresses; stripped of any service-specific destination. + *

      + * Note 2: The messengers that this method returns, are not + * generally meant to be used directly. They provide a single queue for all + * invokers, and do not perform group redirection and only support only a + * subset of the {@code sendMessage()} methods. One must get a properly + * configured channel in order to send messages. + *

      + * If one of the other {@code getMessenger()} methods fits the + * application needs, it should be preferred. + * + * @param addr The destination address. It is recommended, though not + * mandatory, that the address be stripped of its service name and service + * param elements. + * @param hint An object, of a type specific to the protocol of the address, + * that may be provide additional information to the transport in + * establishing the connection. Typically but not necessarily, this is a + * route advertisement. If the transport cannot use the hint, or if it is + * {@code null}, it will be ignored. + * @return A Canonical messenger that obtains transport messengers to the + * specified address, from LOCAL transports. Returns {@code null} if no + * local transport handles this type address. + */ + public Messenger getCanonicalMessenger(EndpointAddress addr, Object hint); + + /** + * Removes the specified listener. + * + * @param listener The listener that would have been called. + * @param priority Priority set from which to remove this listener. + * @return true if the listener was removed, otherwise false. + */ + public boolean removeMessengerEventListener(MessengerEventListener listener, int priority); + + /** + * Adds the specified listener for all messenger creation. + * + * @param listener The listener that will be called. + * @param priority Order of precedence requested (from 0 to 2). 2 has the + * highest precedence. Listeners are called in decreasing order of + * precedence. Listeners with equal precedence are called in an unspecified + * order. There cannot be more than one listener object for a given + * precedence. Redundant calls have no effect. + * @return true if the listener was added, otherwise false. + */ + public boolean addMessengerEventListener(MessengerEventListener listener, int priority); + + /** + * Propagates (broadcasts) a message via all available Message Transports. + * Each Message Transport that implements propagation will send the message + * using it's broadcast functionality to a configured broadcast address. Any + * peers in the same network scope listening on that broadcast address will + * receive the propagated message. + *

      + * The message will be sent using the default TTL value (which is + * unspecified). + * + * @param message The message to be propagated. The message will not be + * modified by this method. + * @param serviceName The name of the destination service. + * @param serviceParam An optional parameter for the destination service or + * {@code null}. + * @throws IOException Thrown if the message could not be propagated. + */ + public void propagate(Message message, String serviceName, String serviceParam) throws IOException; + + /** + * Propagates (broadcasts) a message via all available Message Transports. + * Each Message Transport that implements propagation will send the message + * using it's broadcast functionality to a configured broadcast address. Any + * peers in the same network scope listening on that broadcast address will + * receive the propagated message. + * + * @param message The message to be propagated. The message will not be + * modified by this method. + * @param serviceName The name of the destination service. + * @param serviceParam An optional parameter for the destination service or + * {@code null}. + * @param initialTTL The requested initial TTL for this message. The actual + * TTL value used may be lower than this value but will never be higher. + */ + public void propagate(Message message, String serviceName, String serviceParam, int initialTTL); + + /** + * Verifies that the given address can be reached. The method, and accuracy + * of the verification depends upon each Message Transport. In some cases + * the address may be contacted to determine connectivity but this is not + * guaranteed. + * + * @param addr is the Endpoint Address to ping. + * @return {@code true} if the address can be reached otherwise {@code false}. + * @deprecated The cost of performing this operation is generally the same + * as getting a Messenger for the destination. Using {@code getMessenger()} + * is a better approach because the resulting Messenger is generally needed + * soon after ping. + */ + @Deprecated + public boolean ping(EndpointAddress addr); + + /** + * Add a listener for the specified address. + *

      + * A single registered listener will be called for incoming messages + * when (in order of preference) :

        + *
      1. The service name and service parameter match exactly to the + * service name and service parameter specified in the destination + * address of the message.
      2. + *

        + *

      3. The service name matches exactly the service name from the + * message destination address and service parameter is {@code null}. + *
      4. + *
      + * + * @param listener The listener which will be called when messages are + * received for the registered destination. + * @param serviceName The name of the service destination which will be + * matched against incoming message destination endpoint addresses. + * @param serviceParam An optional service parameter value which will be + * matched against destination endpoint addresses. May be null. + * @return true if the listener was registered, otherwise false. + */ + public boolean addIncomingMessageListener(EndpointListener listener, String serviceName, String serviceParam); + + /** + * Get the listener for the specified address. + * + * @param serviceName The service name to which the listener is registered. + * @param serviceParam The service parameter to which the listener is + * registered. May be {@code null}. + * @return The currently registered listener or {@code null} if there is no + * listener for the specified name and parameter. + */ + public EndpointListener getIncomingMessageListener(String serviceName, String serviceParam); + + /** + * Remove the listener for the specified address. + * + * @param serviceName The service name to which the listener is registered. + * @param serviceParam The service parameter to which the listener is + * registered. May be {@code null}. + * @return The listener which was removed or {@code null} if there was + * no listener for the specified name and parameter. + */ + public EndpointListener removeIncomingMessageListener(String serviceName, String serviceParam); + + /** + * Registers a message filter listener. Each message will be tested against + * the list of filters as part of its sending or receiving. + *

      + * The listener is invoked for a message when: + *

        + *
      • The message contains a message element which matches exactly the + * values specified by namespace and name.
      • + * + *
      • The message contains a message element who's namespace value + * matches exactly the specified namespace value and the specified name is + * {@code null}.
      • + * + *
      • The message contains a message element who's names value matches + * exactly the specified name value and the specified namespace is + * {@code null}.
      • + * + *
      • The specified name value and the specified namespace are both + * {@code null}.
      • + *
      + * + * @param listener The filter which will be called. + * @param namespace Only messages containing elements of this namespace + * which also match the 'name' parameter will be processed. {@code null} + * may be use to specify all namespaces. + * @param name only messages containing elements of this name which also + * match the 'namespace' parameter will be processed. {@code null} may be + * use to specify all names. + */ + public void addIncomingMessageFilterListener(MessageFilterListener listener, String namespace, String name); + + /** + * Registers a message filter listener. Each message will be tested against + * the list of filters as part of its sending or receiving. + *

      + * The listener is invoked for a message when: + *

        + *
      • The message contains a message element which matches exactly the + * values specified by namespace and name.
      • + * + *
      • The message contains a message element who's namespace value + * matches exactly the specified namespace value and the specified name is + * {@code null}.
      • + * + *
      • The message contains a message element who's names value matches + * exactly the specified name value and the specified namespace is + * {@code null}.
      • + * + *
      • The specified name value and the specified namespace are both + * {@code null}.
      • + *
      + * + * @param listener The filter which will be called. + * @param namespace Only messages containing elements of this namespace + * which also match the 'name' parameter will be processed. {@code null} + * may be used to specify all namespaces. + * @param name only messages containing elements of this name which also + * match the 'namespace' parameter will be processed. {@code null} may be + * use to specify all names. + */ + public void addOutgoingMessageFilterListener(MessageFilterListener listener, String namespace, String name); + + /** + * Removes the given listener previously registered under the given element + * name + * + * @param listener the listener to remove + * @param namespace the name space + * @param name the name + * @return the removed listener + */ + public MessageFilterListener removeIncomingMessageFilterListener(MessageFilterListener listener, String namespace, String name); + + /** + * Removes the given listener previously registered under the given element + * name. + * + * @param listener the listener to remove + * @param namespace the name space + * @param name the name + * @return the removed listener + */ + public MessageFilterListener removeOutgoingMessageFilterListener(MessageFilterListener listener, String namespace, String name); + + /** + * Delivers the provided message to the correct listener as specified by + * the message's destination address. + *

      + * Two additional common message elements are optionally used by Message + * Transports in conjunction with the Endpoint Service. Message Transports + * may typically provide received messages to the Endpoint Service + * containing these elements and the Endpoint service will dispatch the + * messages based upon their content. Message Transports may use alternate + * mechanisms for determining message source and destination addresses and + * need not use these elements. + *

      + * The {@code jxta:EndpointSourceAddress} Message Element contains an + * Endpoint Address for the source of this message. The source address has a + * variety of meanings based upon the usage of the underlying Message + * Transport. For low level transports such as TCP or HTTP the source + * address is the return address of the peer from which the message was + * received, ie. the hop address. For higher level Message Transports such + * as the Endpoint Router Transport or the TLS transport the source address + * is the virtual Endpoint Address of the peer which originated the message + * regardless of any intervening hops the message may have made. + *

      + * The {@code jxta:EndpointDestinationAddress} Message Element contains an + * Endpoint Address which will be used by the Endpoint Service to dispatch a + * received message to the recipient specified by the service name and + * service parameter. The protocol address is also provided to the recipient + * service and can be used in some protocols for determining how the message + * was received. For example a service may wish to handle messages which + * were sent directly differently than messages which were sent via + * propagation. + * + * @param msg The message to be delivered. + * @deprecated Please convert your code to use the + * {@link EndpointListener#processIncomingMessage(Message,EndpointAddress,EndpointAddress)} + * method instead. The addressing method used by demux() was never part of + * the formal JXTA protocol specification but was a defacto part because + * demux() depended upon it. + */ + @Deprecated + public void demux(Message msg); + + /** + * Adds the specified MessageTransport to this endpoint. A MessageTransport + * may only be added if there are no other equivalent MessageTransports + * available (as determined by {@link Object#equals(Object) equals()}). + *

      + * The MessageTransport becomes usable by the endpoint service to send + * unicast messages and optionally propagation and ping messages if it is a + * {@link net.jxta.endpoint.MessageSender}. The endpoint service becomes + * usable by this MessageTransport to handle incoming messages if it is a + * {@link MessageReceiver}. + * + * @param transport the MessageTransport to be installed. + * @return A messenger event listener to invoke when incoming messengers are + * created or {@code null} if the MessageTransport was not installed. + */ + public MessengerEventListener addMessageTransport(MessageTransport transport); + + /** + * Removes the given MessageTransport protocol from this endpoint service. + *

      + * Transports remove themselves from the list when stopped. This method + * is normally only called from the stoppApp method of the transport. To + * cleanly remove a transport, call the transport's + * {@link net.jxta.platform.Module#stopApp() stopApp()}and allow it to call + * this method. + * + * @param transpt the MessageTransport to be removed. + * @return {@code true} if the Message Transport was removed, otherwise + * {@code false}. + */ + public boolean removeMessageTransport(MessageTransport transpt); + + /** + * Get an iterator of the MessageTransports available to this + * EndpointService. + * + * @return the iterator of all message transports. + */ + public Iterator getAllMessageTransports(); + + /** + * Get a Message Transport by protocol name. + * + * @param name The protocol name of the MessageTransport. + * @return The Message Transport for the specified protocol name or + * {@code null} if there is no matching Message Transport + */ + public MessageTransport getMessageTransport(String name); + + /** + * Returns a Messenger that may be used to send messages via this endpoint + * to the specified destination. + * + * @param addr the destination address. + * @return The messenger or {@code null} is returned if the destination + * address is not reachable. + */ + public Messenger getMessenger(EndpointAddress addr); + + /** + * Asynchronously acquire a messenger for the specified address. The + * listener will be called when the messenger has been constructed. + * + * @param listener the listener to call when the messenger is ready. + * @param addr the destination for the messenger. + * @param hint the messenger hint, if any, otherwise null. + * @return {@code true} if the messenger is queued for construction + * otherwise {@code false}. + * @deprecated This method is being phased out. Prefer one of the other + * non-blocking variants. If a listener style paradigm is required, use + * {@link ListenerAdaptor} which emulates this functionality. + */ + @Deprecated + public boolean getMessenger(MessengerEventListener listener, EndpointAddress addr, Object hint); + + /** + * Returns a Direct Messenger that may be used to send messages via this endpoint to the specified destination. + *

      + * Direct messengers are non self destructive, they must be explicilty closed. + * + * @param addr the destination address. + * @param hint the messenger hint, if any, otherwise null. + * @param exclusive if true avoids caching the messenger + * @return The messenger or {@code null} is returned if the destination address is not reachable. + * @throws IllegalArgumentException if hint is not of RouteAdvertisement, or PeerAdvertisement type. + */ + public Messenger getDirectMessenger(EndpointAddress addr, Object hint, boolean exclusive); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/InputStreamMessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/InputStreamMessageElement.java new file mode 100644 index 000000000..16b30edc6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/InputStreamMessageElement.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.document.MimeMediaType; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.SequenceInputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.zip.CRC32; +import java.util.zip.Checksum; + + +/** + * A Message Element using {@link java.io.InputStream} as the source for the + * element data. This implementation copies all of the data from the stream at + * the time of creation. + *

      + * InputStreamMessageElement is not as efficient as other message element types + * and should only be used when an input stream is the only available source for + * the element data. + */ +public class InputStreamMessageElement extends MessageElement { + + /** + * The bytes of this element. + */ + protected final List databytes; + + /** + * The length of the data. + */ + protected final long length; + + /** + * Cached Hash Code + */ + protected transient int cachedHashCode = 0; + + /** + * Create a new MessageElement. This constructor copies the data as needed + * and closes the stream upon completion. + * + * @param name Name of the MessageElement. May be the empty string ("") if + * the MessageElement is not named. + * @param type Type of the MessageElement. null is the same as specifying + * the type "Application/Octet-stream". + * @param in the stream containing the body of the MessageElement. The + * stream will be closed by the MessageElement. + * @param sig optional message digest/digital signature element or null if + * no signature is desired. + * @throws IOException If there is a problem reading from the source stream. + */ + public InputStreamMessageElement(String name, MimeMediaType type, InputStream in, MessageElement sig) throws IOException { + this(name, type, in, Long.MAX_VALUE, sig); + } + + /** + * Create a new Message Element. + * + * @param name Name of the MessageElement. May be the empty string ("") if + * the MessageElement is not named. + * @param type Type of the MessageElement. null is the same as specifying + * the type "Application/Octet-stream". + * @param in the stream containing the body of the MessageElement. + * The stream will NOT be closed unless EOF is unexpectedly reached. + * @param len The size of the Element will be limited to len bytes + * from the stream. If you are using the stream interface and know + * the size of the stream, specifying it here improves performance + * and space efficiency a lot. The stream must contain at least + * len bytes. + * @param sig optional message digest/digital signature element or null if + * no signature is desired. + * @throws IOException if there is a problem reading from the source stream + */ + public InputStreamMessageElement(String name, MimeMediaType type, InputStream in, long len, MessageElement sig) throws IOException { + super(name, type, sig); + + if ((len < 0)) { + throw new IllegalArgumentException("len must be >= 0"); + } + + // copy the data from the stream + databytes = CopyToDataBytes(in, len); + + // calculate the length + long buffersSum = 0; + for (byte[] aBuffer : databytes) { + buffersSum += aBuffer.length; + } + + length = buffersSum; + + // fail if the length is not as promised. + if ((len != Long.MAX_VALUE) && (len != length)) { + throw new IllegalArgumentException("Stream was shorter than promised length."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof MessageElement) { + if (!super.equals(target)) { + return false; + } + + if (target instanceof InputStreamMessageElement) { + // have to do a slow stream comparison. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + + MessageElement likeMe = (MessageElement) target; + + try { + InputStream myStream = getStream(); + InputStream itsStream = likeMe.getStream(); + + int mine; + int its; + + do { + mine = myStream.read(); + its = itsStream.read(); + + if (mine != its) { + return false; + } // content didn't match + + } while ((-1 != mine) && (-1 != its)); + + return ((-1 == mine) && (-1 == its)); // end at the same time? + } catch (IOException fatal) { + throw new IllegalStateException("MessageElements could not be compared." + fatal); + } + } + } + + return false; // not a new message element + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized int hashCode() { + if (0 == cachedHashCode) { + Checksum crc = new CRC32(); + + for (byte[] aBuffer : databytes) { + crc.update(aBuffer, 0, aBuffer.length); + } + + int result = super.hashCode() + (int) crc.getValue() * 6037; // a prime + + cachedHashCode = 0 != result ? result : 1; + } + + return cachedHashCode; + } + + /** + * {@inheritDoc} + */ + @Override + public long getByteLength() { + return length; + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + List buffers = new ArrayList(); + + for (byte[] aBuffer : databytes) { + buffers.add(new ByteArrayInputStream(aBuffer)); + } + + return new SequenceInputStream(Collections.enumeration(buffers)); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendToStream(OutputStream sendTo) throws IOException { + for (byte[] aBuffer : databytes) { + sendTo.write(aBuffer); + } + } + + /** + * Copy data from a stream with best possible efficiency. Unfortunately, + * this still results in a lot of copying since we have often have no + * fore-knowledge of the length of the stream. + * + * @param in the stream to copy from + * @param limit the maximum number of bytes to copy from the stream. + * Long.LONG_MAX will read until EOF. + * @return A list of buffers. + * @throws IOException if there is a problem reading from the stream. + */ + protected List CopyToDataBytes(InputStream in, long limit) throws IOException { + final long INITIAL_INTERMEDIATE_BUFFERSIZE = 6; + final long MAXIMUM_INTERMEDIATE_BUFFERSIZE = 18; + + List buffs = new ArrayList(); + boolean atEOF = false; + long read = 0; + long currentIntermediateBufferSize = INITIAL_INTERMEDIATE_BUFFERSIZE; + + // build a list of buffers containing all the element data. + do { + long readRequest = (limit - read); + + if (Long.MAX_VALUE == limit) { + readRequest = Math.min(readRequest, (1L << currentIntermediateBufferSize)); + } + readRequest = Math.min(readRequest, Integer.MAX_VALUE); // limited by size of arrays which are Integer indexed. + + byte[] nextBuffer = new byte[(int) readRequest]; + int offsetInThisBuffer = 0; + + // fully read the buffer if we can. + do { + int readLength = in.read(nextBuffer, offsetInThisBuffer, nextBuffer.length - offsetInThisBuffer); + + if (readLength == -1) { + atEOF = true; + break; + } + + offsetInThisBuffer += readLength; + } while (offsetInThisBuffer < nextBuffer.length); + + // handle the final buffer. + if (atEOF) { + byte[] anotherBuffer = new byte[offsetInThisBuffer]; + + System.arraycopy(nextBuffer, 0, anotherBuffer, 0, offsetInThisBuffer); + nextBuffer = anotherBuffer; + } + + read += nextBuffer.length; + buffs.add(nextBuffer); + + if (currentIntermediateBufferSize < MAXIMUM_INTERMEDIATE_BUFFERSIZE) { + currentIntermediateBufferSize++; + } + } while (!atEOF && (read < limit)); + + // we are done, close if we are at EOF. + if (atEOF) { + in.close(); + in = null; + } + return buffs; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ListenerAdaptor.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ListenerAdaptor.java new file mode 100644 index 000000000..4ebc94e02 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ListenerAdaptor.java @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +import net.jxta.logging.Logging; +import net.jxta.util.SimpleSelectable; +import net.jxta.util.SimpleSelectable.IdentityReference; +import net.jxta.util.SimpleSelector; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The legacy getMessenger asynchronous API never returns any object to the invoker until a messenger could actually be made, + * allowing the application to supply a listener to be invoked when the operation completes. The legacy Messenger API also + * provides a method to send messages that calls a listener to report the outcome of the operation.

      + *

      + * The model has changed, so that an asynchronous messenger is made unresolved and returned immediately to the invoker, which can + * then request opening or even just send a message to force the opening. Subsequently, the messenger can be used as a control + * block to monitor progress with {@link Messenger#register} and {@link Messenger#waitState}.

      + *

      + * Likewise, the outcome of sending a message is a property of that message. Messages can be selected to monitor property changes + * with {@link Message#register} and {@link net.jxta.endpoint.Message#getMessageProperty(Object)} (the outcome property key is + * Messenger.class). + *

      + * This class here provides the legacy listener model on top of the new model for applications that prefer listeners. This class + * is used internally to emulate the legacy listener behaviour, so that applications do not need to be adapted.

      + *

      + * Note: one instance of this class gets instantiated by each EndpointService interface. However, it does not start using any + * resources until it first gets used.

      + */ +public class ListenerAdaptor implements Runnable { + + // FIXME - jice 20040413: Eventhough it is not as critical as it used to be we should get rid of old, never resolved entries. + // Attempts are supposed to always fail or succeed rather soon. Here, we trust transports in that matter. Is it safe ? + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ListenerAdaptor.class.getName()); + + /** + * The in progress messages. + */ + private final Map inprogress = new HashMap(32); + + /** + * The thread that does the work. + */ + private Thread bgThread = null; + + /** + * The selector that we use to watch messengers progress. + */ + private final SimpleSelector selector = new SimpleSelector(); + + /** + * Have we been shutdown? + */ + private volatile boolean shutdown = false; + + /** + * The exceutor service. + */ + private final Executor executor; + + /** + * The ThreadGroup in which this adaptor will run. + */ + private final ThreadGroup threadGroup; + + /** + * Standard Constructor + * + * @param threadGroup The ThreadGroup in which this adaptor will run. + */ + public ListenerAdaptor(ThreadGroup threadGroup) { + this(threadGroup, null); + } + /** + * Creates a ListenerAdaptor with a threadpool for notification callback. + * + * @param threadGroup The ThreadGroup in which this adaptor will run. + * @param executor the excutor to use for notification callback + */ + public ListenerAdaptor(ThreadGroup threadGroup, Executor executor) { + this.executor = executor; + this.threadGroup = threadGroup; + } + + /** + * Cannot be re-started. Do not call once shutdown. + */ + private synchronized void init() { + assert !shutdown; + + if (bgThread != null) { + return; + } + + bgThread = new Thread(threadGroup, this, "Listener Adaptor"); + bgThread.setDaemon(true); + bgThread.start(); + } + + public synchronized void shutdown() { + shutdown = true; + + // Stop the thread if it was ever created. + Thread bg = bgThread; + if (bg != null) { + bg.interrupt(); + } + } + + /** + * Stop watching a given selectable. + * + * @param ts the selectable + */ + private void forgetSelectable(SimpleSelectable ts) { + // Either way, we're done with this one. + ts.unregister(selector); + + synchronized (this) { + inprogress.remove(ts.getIdentityReference()); + } + } + + /** + * Select the given message and invoke the given listener when the message sending is complete. + * + * @param listener The listener to invoke. If null the resolution will take place, but obviously no listener will be invoked. + * @param message The message being sent. + * @return true if the message was registered successfully or the listener is null. If true it is guaranteed that the listener + * will be invoked unless null. If false, it is guaranteed that the listener will not be invoked. + */ + public boolean watchMessage(OutgoingMessageEventListener listener, Message message) { + synchronized (this) { + if (shutdown) { + return false; + } + + if (listener == null) { + // We're done, then. The invoker does not really care. + return true; + } + + // Init if needed. + init(); + + // First we must ensure that if the state changes we'll get to handle it. + MessageListenerContainer allListeners = (MessageListenerContainer) inprogress.get(message.getIdentityReference()); + + if (allListeners == null) { + allListeners = new MessageListenerContainer(); + inprogress.put(message.getIdentityReference(), allListeners); + } + allListeners.add(listener); + } + + // When we do that, the selector gets notified. Therefore always check the initial state automatically. If the + // selectable is already done with, the listener will be called by the selector's handler. + message.register(selector); + + return true; + } + + /** + * Select the given messenger and invoke the given listener when the messenger is resolved. + * + * @param listener The listener to invoke. If null the resolution will take place, but obviously no listener will be invoked. + * @param messenger The messenger being resolved. + * @return true if the messenger was registered successfully or the listener is null. If true it is guaranteed that the listener + * will be invoked unless null. If false, it is guaranteed that the listener will not be invoked. + */ + public boolean watchMessenger(MessengerEventListener listener, Messenger messenger) { + synchronized (this) { + + if (shutdown) { + return false; + } + + if (listener == null) { + // We're done, then. The invoker does not really care. + return true; + } + + // Init if needed. + init(); + + // First we must ensure that if the state changes we'll get to handle it. + MessengerListenerContainer allListeners = (MessengerListenerContainer) inprogress.get(messenger.getIdentityReference()); + + if (allListeners == null) { + // Use ArrayList. The code is optimized for that. + allListeners = new MessengerListenerContainer(); + inprogress.put(messenger.getIdentityReference(), allListeners); + } + allListeners.add(listener); + } + + // When we do that, the selector get notified. Therefore we will always check the initial state automatically. If the + // selectable is already done with, the listener will be called by the selector's handler. + messenger.register(selector); + + return true; + } + + /* + * Any sort of listener type. + */ + static abstract class ListenerContainer extends ArrayList { + + public ListenerContainer() { + super(1); + } + + protected abstract void giveUp(S what, Throwable how); + + protected abstract void process(S what); + } + + + /** + * For messages + */ + @SuppressWarnings("serial") + class MessageListenerContainer extends ListenerContainer { + + private void messageDone(Message message, OutgoingMessageEvent event) { + // Note: synchronization is externally provided. When this method is invoked, this + // object has already been removed from the map, so the list of listener cannot change. + + if (event == OutgoingMessageEvent.SUCCESS) { + // Replace it with a msg-specific one. + event = new OutgoingMessageEvent(message, null); + + for (OutgoingMessageEventListener eachListener : this) { + try { + eachListener.messageSendSucceeded(event); + } catch (Throwable any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught throwable from listener", any); + } + } + } + } else { + if (event == OutgoingMessageEvent.OVERFLOW) { + // Replace it with a msg-specific one. + event = new OutgoingMessageEvent(message, null); + } + + for (OutgoingMessageEventListener eachListener : this) { + try { + eachListener.messageSendFailed(event); + } catch (Throwable any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught throwable in listener", any); + } + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void process(Message message) { + OutgoingMessageEvent event = (OutgoingMessageEvent) message.getMessageProperty(Messenger.class); + + if (event == null) { + return; + } + + // Remove this container-selectable binding + forgetSelectable(message); + + // Invoke app listeners + messageDone(message, event); + } + + /** + * {@inheritDoc} + */ + @Override + protected void giveUp(Message m, Throwable how) { + messageDone(m, new OutgoingMessageEvent(m, how)); + } + } + + /** + * For messengers + */ + @SuppressWarnings("serial") + class MessengerListenerContainer extends ListenerContainer { + + private void messengerDone(Messenger messenger) { + + // Note: synchronization is externally provided. When this method is invoked, this + // object has already been removed from the map, so the list of listener cannot change. + + MessengerEvent event = new MessengerEvent(ListenerAdaptor.this, messenger, null); + + for (MessengerEventListener eachListener : this) { + try { + eachListener.messengerReady(event); + } catch (Throwable any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught throwable in listener", any); + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void process(Messenger messenger) { + if ((messenger.getState() & (Messenger.RESOLVED | Messenger.TERMINAL)) == 0) { + return; + } + + // Remove this container-selectable binding + forgetSelectable(messenger); + + if ((messenger.getState() & Messenger.USABLE) == 0) { + messenger = null; + } + + // Invoke app listeners + messengerDone(messenger); + } + + /** + * {@inheritDoc} + */ + @Override + protected void giveUp(Messenger m, Throwable how) { + messengerDone(null); + } + } + + /** + * {@inheritDoc} + */ + public void run() { + try { + while (!shutdown) { + try { + Collection changed = selector.select(); + for (SimpleSelectable simpleSelectable : changed) { + ListenerContainer listeners; + synchronized (this) { + listeners = inprogress.get(simpleSelectable.getIdentityReference()); + } + if (listeners == null) { + simpleSelectable.unregister(selector); + continue; + } + if (executor == null) { + listeners.process(simpleSelectable); + } else { + executor.execute(new ListenerProcessor(listeners, simpleSelectable)); + } + } + } catch (InterruptedException ie) { + Thread.interrupted(); + } + } + } catch (Throwable anyOther) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in background thread", anyOther); + } + + // There won't be any other thread. This thing is dead if that + // happens. And it really shouldn't. + synchronized (this) { + shutdown = true; + } + } finally { + try { + // It's only us now. Stopped is true. + IOException failed = new IOException("Endpoint interface terminated"); + for (Map.Entry entry : inprogress.entrySet()) { + SimpleSelectable simpleSelectable = entry.getKey().getObject(); + ListenerContainer listeners = entry.getValue(); + simpleSelectable.unregister(selector); + + if (listeners != null) { + listeners.giveUp(simpleSelectable, failed); + } + } + inprogress.clear(); + } catch (Throwable anyOther) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable while shutting down background thread", anyOther); + } + } + bgThread = null; + } + } + + /** + * A small class for processing individual messages. + */ + private class ListenerProcessor implements Runnable { + + private SimpleSelectable simpleSelectable; + private ListenerContainer listeners; + ListenerProcessor(ListenerContainer listeners, SimpleSelectable simpleSelectable) { + this.listeners = listeners; + this.simpleSelectable = simpleSelectable; + } + + public void run() { + listeners.process(simpleSelectable); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/Message.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/Message.java new file mode 100644 index 000000000..134699a84 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/Message.java @@ -0,0 +1,1444 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import java.io.IOException; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.atomic.AtomicInteger; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.MimeMediaType; +import net.jxta.util.AbstractSimpleSelectable; +import net.jxta.util.SimpleSelectable; + +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +/** + * Messages are abstract containers for protocol messages within JXTA. Services + * and applications are expected to use Messages as the basis for any protocols + * implemented within JXTA. Messages are exchanged through the + * {@link net.jxta.endpoint.EndpointService} or + * {@link net.jxta.pipe.PipeService}. + *

      + * A Message is composed of an ordered list of zero or more + * {@link net.jxta.endpoint.MessageElement MessageElements}. Each + * {@link net.jxta.endpoint.MessageElement} is associated with a namespace at + * the time it is added to the message. Duplicate + * {@link net.jxta.endpoint.MessageElement MessageElements} are permitted. + *

      + * Messages are not synchronized. All of the iterators returned by this + * implementation are "fail-fast". Concurrent modification of messages from + * multiple threads will produce unexpected results and + * {@code ConcurrentModificationException}. + * + * @see net.jxta.endpoint.MessageElement + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.pipe.InputPipe + * @see net.jxta.pipe.OutputPipe + * @see net.jxta.pipe.PipeService + */ +public class Message extends AbstractSimpleSelectable implements Serializable { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(Message.class.getName()); + + /** + * Magic value for this format of serialization version. + */ + private static final long serialVersionUID = 3418026921074097757L; + + /** + * If {@code true}, then modification logging be activated. This is a very + * expensive option as it causes a stack crawl to be captured for every + * message modification. + *

      + * To enable modification tracking, set to {@code true} and recompile. + */ + protected static final boolean LOG_MODIFICATIONS = false; + + /** + * If {@code true}, then a special tracking element is added to every + * message. This provides the ability to follow messages throughout the + * network. If a message has a tracking element then it will be used in + * the {@code toString()} representation. + *

      + * The element is currently named "Tracking UUID" and is stored in the + * "jxta" namespace. The element contains an IETF version 1 UUID in string + * form. + *

      + * To enable addition of a tracking element to every message, set the + * Java System Property {@code net.jxta.endpoint.Message.globalTracking} to + * {@code true} and restart your JXTA application. + * + * @see java.lang.System#setProperty(String,String) + */ + protected static final boolean GLOBAL_TRACKING_ELEMENT = + Boolean.getBoolean(Message.class.getName() + ".globalTracking"); + + /** + * Incremented for each standalone message instance. {@see #lineage} for + * information about how message numbers can be used. + */ + private static transient AtomicInteger messagenumber = new AtomicInteger(1); + + /** + * This string identifies the namespace which is assumed when calls are + * made that don't include a namespace specification. + */ + protected final String defaultNamespace; + + /** + * the namespaces in this message and the elements in each. + */ + protected transient Map> namespaces = new HashMap>(); + + /** + * List of the elements. + */ + protected transient List elements = new ArrayList(); + + /** + * Message properties HashMap + */ + protected transient Map properties = Collections.synchronizedMap(new HashMap()); + + /** + * A list of {@link java.lang.Integer} which details the lineage (history + * of cloning) that produced this message. This message's number is index + * 0, all of the ancestors are in order at higher indexes. + *

      + * Message numbers are not part of the message content and are only + * stored locally. The are useful for following messages throughout their + * lifetime and is normally shown as part of the toString() + * display for Messages. + */ + protected transient List lineage = new ArrayList(); + + /** + * Modification count of this message. Can be used to detect message being + * concurrently modified when message is shared. + *

      + * The modification count is part of the {@code toString()} display for + * Messages. + */ + protected transient volatile int modCount = 0; + + /** + * cached aggregate size of all the member elements. Used by + * {@link #getByteLength()} + */ + protected transient long cachedByteLength = 0; + + /** + * modcount at the time the message length was last calculated. Used by + * {@link #getByteLength()} + */ + protected transient int cachedByteLengthModCount = -1; + + /** + * If true then the message is modifiable. This is primarily + * intended as a diagnostic tool for detecting concurrent modification. + * + * @deprecated You really should not depend on this feature. + */ + @Deprecated + public boolean modifiable = true; + + /** + * If {@code LOG_MODIFICATIONS} is {@code true} then this will contain + * the history of modifications this message. + *

      + *

        + *
      • Values are {@link java.lang.Throwable} with the description + * field formatted as timeInAbsoluteMillis : threadName. + *
      • + *
      + */ + protected transient List modHistory; + + /** + * A ListIterator for MessageElements which also provides the ability to + * determine the namespace of the current message element. Message Elements + * are iterated in the order in which they were added to the Message. + *

      + * This Iterator returned is not synchronized with the message. If you + * modify the state of the Message, the iterator will throw + * ConcurrentModificationException when {@code next()} or + * {@code previous()} is called. + */ + public class ElementIterator implements ListIterator { + + /** + * The elements being iterated. + */ + ListIterator list; + + /** + * The current element + */ + element current = null; + + /** + * The modCount at the time when the iterator was created. + */ + transient int origModCount; + + /** + * Intialize the iterator from a list iterator. + * + * @param list The ListIterator we are managing. + */ + ElementIterator(ListIterator list) { + origModCount = Message.this.getMessageModCount(); + this.list = list; + } + + /** + * {@inheritDoc} + */ + public boolean hasNext() { + if (origModCount != Message.this.getMessageModCount()) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + throw failure; + } + return list.hasNext(); + } + + /** + * {@inheritDoc} + */ + public MessageElement next() { + if (origModCount != Message.this.getMessageModCount()) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + throw failure; + } + + current = list.next(); + return current.element; + } + + /** + * {@inheritDoc} + */ + public int nextIndex() { + return list.nextIndex(); + } + + /** + * {@inheritDoc} + */ + public boolean hasPrevious() { + if (origModCount != Message.this.getMessageModCount()) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + throw failure; + } + + return list.hasPrevious(); + } + + /** + * {@inheritDoc} + */ + public MessageElement previous() { + if (origModCount != Message.this.getMessageModCount()) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + throw failure; + } + + current = list.previous(); + return current.element; + } + + /** + * {@inheritDoc} + */ + public int previousIndex() { + return list.previousIndex(); + } + + /** + * {@inheritDoc} + *

      + * Not provided because the namespace cannot be specified. + */ + public void add(MessageElement obj) { + throw new UnsupportedOperationException("add() not supported"); + } + + /** + * {@inheritDoc} + */ + public void remove() { + if (origModCount != Message.this.getMessageModCount()) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + + throw failure; + } + + if (null == current) { + throw new IllegalStateException("no current element, call next() or previous()"); + } + + ListIterator elsPosition = Message.this.elements.listIterator(); + ListIterator nsPosition = namespaces.get(current.namespace).listIterator(); + + int currentPrevious = list.previousIndex(); + + // restart this iterator + while (list.previousIndex() >= 0) { + list.previous(); + } + + // readvance to the current position, but track in ns list and master list + while (list.previousIndex() < currentPrevious) { + element anElement = list.next(); + + try { + // advance to the same element in the master list. + element anElsElement; + + do { + anElsElement = elsPosition.next(); + } while (anElement != anElsElement); + + // advance to the same element in the ns list. + MessageElement anNsElement; + + if (current.namespace.equals(anElement.namespace)) { + do { + anNsElement = nsPosition.next(); + } while (anElement.element != anNsElement); + } + } catch (NoSuchElementException ranOut) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + + throw failure; + } + } + + elsPosition.remove(); + nsPosition.remove(); + list.remove(); + origModCount = Message.this.incMessageModCount(); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Removed " + current.namespace + "::" + current.element.getElementName() + "/" + + current.element.getClass().getName() + "@" + current.element.hashCode() + " from " + Message.this); + } + current = null; + } + + /** + * {@inheritDoc} + *

      + * Replacement MessageElement will be in the same name space as the + * replaced element. + */ + public void set(MessageElement obj) { + if (origModCount != Message.this.getMessageModCount()) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. "); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + throw failure; + } + + if (null == current) { + throw new IllegalStateException("no current element, call next() or previous()"); + } + + ListIterator elsPosition = Message.this.elements.listIterator(); + ListIterator nsPosition = namespaces.get(current.namespace).listIterator(); + + int currentPrevious = list.previousIndex(); + + // restart this iterator + while (list.previousIndex() >= 0) { + list.previous(); + } + + // readvance to the current position, but track in ns list and master list + while (list.previousIndex() < currentPrevious) { + element anElement = list.next(); + + try { + // advance to the same element in the master list. + element anElsElement; + + do { + anElsElement = elsPosition.next(); + } while (anElement != anElsElement); + + // advance to the same element in the ns list. + MessageElement anNsElement; + + if (current.namespace.equals(anElement.namespace)) { + do { + anNsElement = nsPosition.next(); + } while (anElement.element != anNsElement); + } + } catch (NoSuchElementException ranOut) { + RuntimeException failure = new ConcurrentModificationException( + Message.this + " concurrently modified. Iterator was made at mod " + origModCount); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + Message.this + " concurrently modified. iterator mod=" + origModCount + " current mod=" + + Message.this.getMessageModCount() + "\n" + getMessageModHistory(), + failure); + } + throw failure; + } + } + + Message.element newCurrent = new Message.element(current.namespace, obj, null); + + elsPosition.set(newCurrent); + nsPosition.set(obj); + list.set(newCurrent); + origModCount = Message.this.incMessageModCount(); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Replaced " + current.namespace + "::" + current.element.getElementName() + "/" + + current.element.getClass().getName() + "@" + current.element.hashCode() + " with " + + newCurrent.namespace + "::" + newCurrent.element.getElementName() + "/" + + newCurrent.element.getClass().getName() + "@" + newCurrent.element.hashCode() + " in " + Message.this); + } + current = newCurrent; + } + + /** + * return the namespace of the current element. + * + * @return String containing the name space of the current element. + */ + public String getNamespace() { + if (null == current) { + throw new IllegalStateException("no current element, call next() or previous()"); + } + + return current.namespace; + } + + /** + * Return the signature element of the current element. + * + * @return The signature element of the current element. + */ + public MessageElement getSignature() { + if (null == current) { + throw new IllegalStateException("no current element, call next() or previous()"); + } + + return (null != current.signature) ? current.signature : current.element.getSignature(); + } + } + + + /** + * Holds an element, its namespace and optionally an override signature + * element. + */ + protected static class element { + final String namespace; + final MessageElement element; + final MessageElement signature; + + element(String namespace, MessageElement element, MessageElement signature) { + this.namespace = namespace; + this.element = element; + this.signature = signature; + } + } + + /** + * Standard Constructor for messages. The default namespace will be the + * empty string ("") + */ + public Message() { + this("", false); + } + + /** + * Standard Constructor for messages. + * + * @param defaultNamespace the namespace which is assumed by methods which + * do not require a namespace specification. + */ + protected Message(String defaultNamespace) { + this(defaultNamespace, false); + } + + /** + * Standard Constructor for messages. + * + * @param defaultNamespace the namespace which is assumed by methods which + * do not require a namespace specification. + * @param clone If {@code true} then we are creating a clone. + */ + private Message(String defaultNamespace, boolean clone) { + this.defaultNamespace = defaultNamespace; + + lineage.add(messagenumber.getAndIncrement()); + + if (LOG_MODIFICATIONS) { + modHistory = new ArrayList(); + incMessageModCount(); + } + + if (!clone && GLOBAL_TRACKING_ELEMENT) { + UUID tracking = UUIDFactory.newSeqUUID(); + + MessageElement trackingElement = new StringMessageElement("Tracking UUID", tracking.toString(), null); + + addMessageElement("jxta", trackingElement); + } + } + + /** + * {@inheritDoc} + *

      + * Duplicates the Message. The returned duplicate is a real copy. It may + * be freely modified without causing change to the originally cloned + * message. + * + * @return Message a Message that is a copy of the original message + */ + @Override + public Message clone() { + Message clone = new Message(getDefaultNamespace(), true ); + + clone.lineage.addAll(lineage); + clone.elements.addAll(elements); + + for (String aNamespace : namespaces.keySet()) { + List namespaceElements = namespaces.get(aNamespace); + + List newNamespaceElements = new ArrayList(namespaceElements.size()); + + newNamespaceElements.addAll(namespaceElements); + clone.namespaces.put(aNamespace, newNamespaceElements); + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Created clone " + clone + " of " + this); + } + + return clone; + } + + /** + * {@inheritDoc} + *

      + * Compare this Message against another. Returns {@code true} if all of the + * elements are identical and in the same order. Message properties + * (setProperty()/getProperty()) are not considered in the calculation. + * + * @param target The Message to compare against. + * @return {@code true} if the elements are identical otherwise + * {@code false}. + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof Message) { + Message likeMe = (Message) target; + + ElementIterator myElements = getMessageElements(); + ElementIterator itsElements = likeMe.getMessageElements(); + + while (myElements.hasNext()) { + if (!itsElements.hasNext()) { + return false; // it has fewer than i do. + } + + MessageElement mine = myElements.next(); + MessageElement its = itsElements.next(); + + if (!myElements.getNamespace().equals(itsElements.getNamespace())) { + return false; // elements not in the same namespace + } + + if (!mine.equals(its)) { + return false; // content didnt match + } + } + + return (!itsElements.hasNext()); // ran out at the same time? + } + + return false; // not a message + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = 0; + Iterator eachElement = getMessageElements(); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + + result += anElement.hashCode(); + result *= 6037; // a prime + } + + if (0 == result) { + result = 1; + } + + return result; + } + + /** + * {@inheritDoc} + *

      + * This implementation is intended to assist debugging. You should not + * depend upon the format of the result. + */ + @Override + public String toString() { + StringBuilder toString = new StringBuilder(128); + + toString.append(getClass().getName()); + toString.append('@'); + toString.append(super.hashCode()); + toString.append('('); + toString.append(modCount); + toString.append("){"); + + Iterator allLineage = getMessageLineage(); + + while (allLineage.hasNext()) { + toString.append(allLineage.next().toString()); + if (allLineage.hasNext()) { + toString.append(','); + } + } + + toString.append('}'); + + if (GLOBAL_TRACKING_ELEMENT) { + toString.append("["); + Iterator eachUUID = getMessageElements("jxta", "Tracking UUID"); + + while (eachUUID.hasNext()) { + toString.append("["); + toString.append(eachUUID.next().toString()); + toString.append("]"); + if (eachUUID.hasNext()) { + toString.append(','); + } + } + toString.append("]"); + } + + return toString.toString(); + } + + /** + * Read this Object in for Java Serialization + * + * @param s The stream from which the Object will be read. + * @throws IOException for errors reading from the input stream. + * @throws ClassNotFoundException if the serialized representation contains + * references to classes which cannot be found. + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + // reads defaultNamespace, modifiable flag + s.defaultReadObject(); + + MimeMediaType readType = new MimeMediaType(s.readUTF()); + + // XXX bondolo 20040307 Should do something with encoding here. + + Message readMessage = WireFormatMessageFactory.fromWire(s, readType, null); + + namespaces = readMessage.namespaces; + elements = readMessage.elements; + + if (!namespaces.containsKey(defaultNamespace)) { + throw new IOException("Corrupted Object--does not contain required namespace."); + } + + properties = new HashMap(); + lineage = new ArrayList(); + + lineage.add(messagenumber.getAndIncrement()); + + if (LOG_MODIFICATIONS) { + modHistory = new ArrayList(); + incMessageModCount(); + } + } + + /** + * Write this Object out for Java Serialization + * + * @param s The stream to which the Object will be written. + * @throws IOException for errors writing to the output stream. + */ + private void writeObject(ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + + MimeMediaType writeType = WireFormatMessageFactory.DEFAULT_WIRE_MIME; + + s.writeUTF(writeType.toString()); + + // XXX bondolo 20040307 Should do something with encoding here. + + WireFormatMessage serialed = WireFormatMessageFactory.toWire(this, writeType, null); + + serialed.sendToStream(s); + } + + /** + * Return the default Namespace of this message. + * + * @return The default namespace for this message. + */ + protected String getDefaultNamespace() { + return defaultNamespace; + } + + /** + * Add a MessageElement into the message. The MessageElement is stored in + * the default namespace. + * + * @param add the Element to add to the message. + */ + public void addMessageElement(MessageElement add) { + + addMessageElement(null, add); + } + + /** + * Add a MessageElement into the message using the specified namespace. + * + * @param namespace contains the namespace of the element to add. You can + * specify null as a shorthand for the default namespace. + * @param add the MessageElement to add to the message. + */ + public void addMessageElement(String namespace, MessageElement add) { + addMessageElement(namespace, add, null); + } + + /** + * Add a MessageElement into the Message using the specified namespace. + * + * @param namespace contains the namespace of the element to add. You can + * specify null as a shorthand for the default namespace. + * @param add the MessageElement to add to the message. + * @param signature The signature MessageElement associated with the + * MessageElement. This allows for an alternate signature element to the + * signature element associated with the message element. + */ + public void addMessageElement(String namespace, MessageElement add, MessageElement signature) { + if (null == namespace) { + namespace = getDefaultNamespace(); + } + + if (null == add) { + throw new IllegalArgumentException("Message Element must be non-null"); + } + + elements.add(new element(namespace, add, signature)); + + List namespaceElements = namespaces.get(namespace); + + if (null == namespaceElements) { + namespaceElements = new ArrayList(); + namespaces.put(namespace, namespaceElements); + } + + namespaceElements.add(add); + incMessageModCount(); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( "Added " + namespace + "::" + add.getElementName() + "/" + + add.getClass().getName() + "@" + add.hashCode() + " to " + this); + } + } + + /** + * Replace a {@link net.jxta.endpoint.MessageElement} in the message. This + * method will remove all MessageElement instances in the default namespace + * which match the specified name (if any) and then insert the replacement + * element. The existing version of the element is returned, if more than + * one matching element was removed, a random matching element is returned. + *

      + * For greatest control over element replacement, use the + * {@link java.util.ListIterator#set(java.lang.Object)} method as returned + * by {@link #getMessageElements()}, + * {@link #getMessageElements(java.lang.String)} or + * {@link #getMessageElementsOfNamespace(java.lang.String)} + * + * @param replacement the Element to be inserted into to the message. + * @return One of the elements which was replaced or null if no existing + * matching item was located. + */ + public MessageElement replaceMessageElement(MessageElement replacement) { + return replaceMessageElement(null, replacement); + } + + /** + * Replace a {@link net.jxta.endpoint.MessageElement} in the message using the specified + * namespace. This method will remove all MessageElement instances which + * match the specified name (if any) and then insert the replacement + * element. The existing version of the element is returned, if more than + * one matching element was removed, a random matching element is returned. + *

      + * For greatest control over element replacement, use the + * {@link java.util.ListIterator#set(java.lang.Object)} method as returned + * by {@link #getMessageElements()}, + * {@link #getMessageElements(java.lang.String)} or + * {@link #getMessageElementsOfNamespace(java.lang.String)} + * + * @param namespace contains the namespace of the element to be replaced. + * You can specify null as a shorthand for the default namespace. + * @param replacement the Element to be inserted into to the message. + * @return One of the elements which was replaced or null if no existing + * matching item was located. + */ + public MessageElement replaceMessageElement(String namespace, MessageElement replacement) { + if (null == namespace) { + namespace = getDefaultNamespace(); + } + + if (null == replacement) { + throw new IllegalArgumentException("Message Element must be non-null"); + } + + MessageElement removed = null; + Iterator allMatching = getMessageElements(namespace, replacement.getElementName()); + + while (allMatching.hasNext()) { + MessageElement anElement = allMatching.next(); + + allMatching.remove(); + removed = anElement; + } + + addMessageElement(namespace, replacement); // updates mod count + + return removed; + } + + /** + * Returns an iterator of the namespaces present in this message. + * + * @return iterator of strings of the namespaces of this message. + */ + public Iterator getMessageNamespaces() { + return Collections.unmodifiableMap(namespaces).keySet().iterator(); + } + + /** + * Retrieve a message element by name from the message without regard to + * namespace. If there is more than one message element with this name, the + * first message element will be returned. + * + * @param name The name of the message element to attempt to retrieve. + * @return Element the element or null if no matching element could be + * found. + */ + public MessageElement getMessageElement(String name) { + Iterator eachElement = elements.listIterator(); + + while (eachElement.hasNext()) { + element anElement = eachElement.next(); + + if (name.equals(anElement.element.getElementName())) { + return anElement.element; + } + } + + return null; + } + + /** + * Retrieve a message element by name in the specified namespace from the + * message. If there is more than one message element matching this name, + * the first message element will be returned. + * + * @param namespace contains the namespace of the element to get. You can + * specify {@code null} as a shorthand for the default namespace. + * @param name The name of the message element to retrieve. + * @return The Message Element or {@code null} if no matching message + * element could be found. + */ + public MessageElement getMessageElement(String namespace, String name) { + if (null == namespace) { + namespace = getDefaultNamespace(); + } + + List namespaceElements = namespaces.get(namespace); + + // no namespace means no element. + if (null == namespaceElements) { + return null; + } + + Iterator eachElement = namespaceElements.listIterator(); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + + if (name.equals(anElement.getElementName())) { + return anElement; + } + } + + return null; + } + + /** + * Returns a list iterator of all of the elements contained in this message. + * Elements from all namespaces are returned. + *

      + * The iterator returned is not synchronized with the message and will + * throw {@link java.util.ConcurrentModificationException} if the + * message is modified. + * + * @return Enumeration of Elements. + */ + public ElementIterator getMessageElements() { + List theMsgElements = new ArrayList(elements); + + return new ElementIterator(theMsgElements.listIterator()); + } + + /** + * Returns a list iterator of all of the elements contained in this + * message who's name matches the specified name. Elements from all + * namespaces are returned. Message Elements are iterated in the order in + * which they were added to the Message. + *

      + * The iterator returned is not synchronized with the message and will + * throw {@link java.util.ConcurrentModificationException} if the + * message is modified. + * + * @param name the name of the elements to match against + * @return iterator of the elements matching the specified name, if any. + */ + public ElementIterator getMessageElements(String name) { + List theMsgElements = new ArrayList(elements.size()); + + for (element anElement : elements) { + if (name.equals(anElement.element.getElementName())) { + theMsgElements.add(anElement); + } + } + + return new ElementIterator(theMsgElements.listIterator()); + } + + /** + * Returns a list iterator of all of the elements contained in this message + * which match the specified namespace. Message Elements are iterated in + * the order in which they were added to the Message. + *

      + * The ListIterator returned is not synchronized with the message. If + * you modify the state of the Message, the iterator will throw + * ConcurrentModificationException when {@code next()} or + * {@code previous()} is called. + * + * @param namespace contains the namespace which must be matched in the + * elements returned. You can specify {@code null} as a shorthand for the + * default namespace. + * @return Iterator of Message Elements matching namespace. + */ + public ElementIterator getMessageElementsOfNamespace(String namespace) { + List theMsgElements = new ArrayList(elements.size()); + + if (null == namespace) { + namespace = getDefaultNamespace(); + } + + for (element anElement : elements) { + if (namespace.equals(anElement.namespace)) { + theMsgElements.add(anElement); + } + } + + return new ElementIterator(theMsgElements.listIterator()); + } + + /** + * Returns a list iterator of all of the elements contained in the + * specified namespace who's name matches the specified name in the order + * in which they were added to the Message. + *

      + * The iterator returned is not synchronized with the message and will + * throw {@link java.util.ConcurrentModificationException} if the message + * is modified. + * + * @param namespace The namespace which must be matched in the elements + * returned. You can specify {@code null} as a shorthand for the default + * namespace. + * @param name The name of the elements to retrieve. + * @return Iterator of Message Elements matching namespace and name. + */ + public ElementIterator getMessageElements(String namespace, String name) { + List theMsgElements = new ArrayList(elements.size()); + + if (null == namespace) { + namespace = getDefaultNamespace(); + } + + for (element anElement : elements) { + if (namespace.equals(anElement.namespace) && name.equals(anElement.element.getElementName())) { + theMsgElements.add(anElement); + } + } + + return new ElementIterator(theMsgElements.listIterator()); + } + + /** + * Returns a list iterator of all of the elements contained in this message + * whose mime-type matchs the given in the order they were added to the + * message. Elements from all namespaces are returned. + *

      + * The iterator returned is not synchronized with the message and will + * throw {@link java.util.ConcurrentModificationException} if the + * message is modified. + * + * @param type contains the type of the elements to get + * @return Iterator of Message Elements matching type. + */ + public ElementIterator getMessageElements(MimeMediaType type) { + List theMsgElements = new ArrayList(elements.size()); + + ListIterator eachElement = elements.listIterator(); + + while (eachElement.hasNext()) { + element anElement = eachElement.next(); + + if (type.equals(anElement.element.getMimeType())) { + theMsgElements.add(anElement); + } + } + + return new ElementIterator(theMsgElements.listIterator()); + } + + /** + * Returns a list iterator of all of the elements contained in this message + * whose type matches the given in the order they were added to the message. + *

      + * The iterator returned is not synchronized with the message and will + * throw {@link java.util.ConcurrentModificationException} if the + * message is modified. + * + * @param namespace contains the namespace which must be matched in the + * elements returned. You can specify null as a shorthand for the default + * namespace. + * @param type contains the type of the elements to get + * @return Iterator of Message Elements matching namespace and matching + * type. + */ + public ElementIterator getMessageElements(String namespace, MimeMediaType type) { + List theMsgElements = new ArrayList(elements.size()); + + if (null == namespace) { + namespace = getDefaultNamespace(); + } + + for (element anElement : elements) { + if (namespace.equals(anElement.namespace) && type.equals(anElement.element.getMimeType())) { + theMsgElements.add(anElement); + } + } + + return new ElementIterator(theMsgElements.listIterator()); + } + + /** + * Remove an the first occurrence of the provided MessageElement from the + * message. + * + * @param remove the Element to remove from the message. + * @return boolean returns true if the element was removed, otherwise false. + */ + public boolean removeMessageElement(MessageElement remove) { + Iterator eachElement = getMessageElements(); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + + if (remove == anElement) { + eachElement.remove(); // updates mod count + + return true; + } + } + + return false; + } + + /** + * Remove the first occurrence of the provided MessageElement within the + * specified namespace from the message. You can specify null as a + * shorthand for the default namespace. + * + * @param namespace the namespace from which the element is to be removed. + * @param remove the Element to remove from the message. + * @return boolean returns true if the element was removed, otherwise false. + */ + public boolean removeMessageElement(String namespace, MessageElement remove) { + Iterator eachElement = getMessageElementsOfNamespace(namespace); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + + if (remove == anElement) { + eachElement.remove(); // updates mod count + + return true; + } + } + + return false; + } + + /** + * Removes all of the elements in all namespaces from the message. Also + * clears any properties set for this message. + */ + public void clear() { + elements.clear(); + namespaces.clear(); + properties.clear(); + // a cleared message has no ancestors + lineage.retainAll(Collections.singletonList(lineage.get(0))); + + incMessageModCount(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Cleared " + this); + } + } + + /** + * Returns the aggregate size of all the member elements. + * + * @return the sum of all element sizes in bytes. + */ + public synchronized long getByteLength() { + if (modCount != cachedByteLengthModCount) { + cachedByteLength = 0; + Iterator eachElement = getMessageElements(); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + + cachedByteLength += anElement.getByteLength(); + } + + cachedByteLengthModCount = modCount; + } + + return cachedByteLength; + } + + /** + * Returns the modification count of this message. This ever ascending + * number can be used to determine if the message has been modified by + * another thread or for use in caching of parts of the message structure. + * + * @return the modification count of this message. + */ + public int getMessageModCount() { + return modCount; + } + + /** + * Returns the modification count of this message. This ever ascending + * number can be used to determine if the message has been modified by + * another thread or for use in caching of parts of the message structure. + * + * @return the modification count of this message. + */ + protected synchronized int incMessageModCount() { + modCount++; + + if (LOG_MODIFICATIONS) { + modHistory.add(new Throwable(Long.toString(System.currentTimeMillis()) + " : " + Thread.currentThread().getName())); + } + + if (!modifiable) { + IllegalStateException failure = new IllegalStateException("Unmodifiable message should not have been modified"); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + throw failure; + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Modification to " + this); + } + + return modCount; + } + + /** + * Returns a String containing the modification history for this message + * + * @return a String containing the modification history for this message. + */ + public synchronized String getMessageModHistory() { + + if (LOG_MODIFICATIONS) { + StringBuilder modHistoryStr = new StringBuilder("Message Modification History for "); + + modHistoryStr.append(toString()); + modHistoryStr.append("\n\n"); + for (int eachMod = modHistory.size() - 1; eachMod >= 0; eachMod--) { + StringWriter aStackStr = new StringWriter(); + Throwable aStack = modHistory.get(eachMod); + + aStack.printStackTrace(new PrintWriter(aStackStr)); + modHistoryStr.append("Modification #"); + modHistoryStr.append(eachMod + 1); + modHistoryStr.append(":\n\n"); + modHistoryStr.append(aStackStr.toString()); + modHistoryStr.append("\n"); + } + return modHistoryStr.toString(); + } else { + return "Modification history tracking is disabled"; + } + } + + /** + * Returns the message number of this message. Message Numbers are intended + * to assist with debugging and the management of message cloning. + *

      + * Each message is assigned a unique number upon creation. Message + * Numbers are monotonically increasing for each message created. + *

      + * Message Numbers are transient, ie. if the message object is + * serialized then the message number after deserialization will be + * probably be a different value. Message numbers should not be used to + * record permanent relationships between messages. + * + * @return int this message's message number. + */ + public int getMessageNumber() { + return lineage.get(0); + } + + /** + * Returns an iterator which describes the lineage of this message. Each + * entry is an {@link java.lang.Integer} Message Number. The first entry is + * this message's number, following entries are the ancestors of this + * message. + * + * @return an Iterator of {@link java.lang.Integer}. Each entry is a + * message number. + */ + public Iterator getMessageLineage() { + return Collections.unmodifiableList(lineage).iterator(); + } + + /** + * Associate a transient property with this message. if there was a + * previous value for the key provided then it is returned. This feature is + * useful for managing the state of messages during processing and for + * caching. Message Properties are not transmitted as part of the + * Message when the message is serialized! + *

      + * The setting of particular keys may be controlled by a Java Security + * Manager. Keys of type 'java.lang.Class' are checked against the caller of + * this method. Only callers which are instances of the key class may modify + * the property. This check is not possible through reflection. All other + * types of keys are unchecked. + * + * @param key the property key + * @param value the value for the property + * @return previous value for the property or null if no previous + */ + public Object setMessageProperty(Object key, Object value) { + + /* + if( key instanceof java.lang.Class ) { + Class keyClass = (Class) key; + SecurityManager secure = new SecurityManager() { + public boolean checkCallerOfClass( Class toCheck ) { + Class [] context = getClassContext(); + + return toCheck.isAssignableFrom( context[2] ); + } + }; + + if( !secure.checkCallerOfClass( keyClass ) ) { + throw new SecurityException( "You can't set that key from this context." ); + } + } + */ + + Object res = properties.put(key, value); + + // Any property addition (including redundant) is notified. Removals are + // too, since removal is done by assigning null. + + // Exception: when removing what was not there: no notification. + + if (res != null || value != null) { + notifyChange(); + } + + return res; + } + + /** + * Retrieves a transient property from the set for this message. + * + * @param key the property key. + * @return value for the property or null if no property for this key. + */ + public Object getMessageProperty(Object key) { + + return properties.get(key); + } + + /** + * {@inheritDoc} + */ + public void itemChanged(SimpleSelectable o) {// For now, messages are not themselves registered with anything. + // Therefore itemChanged does not do a thing. + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageElement.java new file mode 100644 index 000000000..5c004c975 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageElement.java @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Map; + +import java.io.UnsupportedEncodingException; +import java.util.UUID; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.util.CountingOutputStream; +import net.jxta.util.DevNullOutputStream; + +// imported for implementation of {@link #getSequentialName()} +import net.jxta.impl.id.UUID.UUIDFactory; + + +/** + * JXTA Message Elements are used to add data to a JXTA Message. Message + * Elements are immutable objects. A Message Element may be shared amongst as + * many messages as is desired. + *

      + * Several Message Element sub-classes are provided for handling various types + * of data. All Message Elements are internally converted to raw bytes when sent + * as part of a Message. The various Message Element flavors are provided for + * convenience and efficiency. They enable the simplest creation and most + * efficient conversion from the individual data types to the appropriate binary + * data. Because Message Elements are merely a convenient representation for + * binary data the object type of Message Element received by a peer may not + * be the same as was sent by the sending peer. Even though the Message + * Element container may change during transmission the data contained in the + * Message Element is faithfully preserved. + *

      + * A Message Element is composed of four components: + *

      + *

        + *
      • An optional name. This may be any {@link java.lang.String}. Unnamed + * elements are assumed to have the name "" (the empty string).
      • + *
      • An optional {@link net.jxta.document.MimeMediaType}. If not specified + * the Mime Media Type is assumed to be "Application/Octet-Stream".
      • + *
      • Data. Sub-classes of MessageElement allow you to create elements based + * on a variety of data formats.
      • + *
      • An optional signature. This is a Message Element that is associated to + * this element and may contain a cryptographic signature/hash of this message + * element. + *
      • + *
      + *

      + *

      The data contained within a MessageElement is accessible in four ways: + *

      + *

        + *
      • As an {@link java.io.InputStream} from {@link #getStream()}
      • + *
      • Sending the data a {@link java.io.OutputStream} via {@link #sendToStream(OutputStream)}
      • + *
      • As a {@link java.lang.String} from {@link #toString()}
      • + *
      • As a byte array from from {@link #getBytes(boolean)}
      • + *
      + * + * @see net.jxta.endpoint.Message + */ +public abstract class MessageElement implements Document { + + /** + * Logger + */ + private static transient final Logger LOG = Logger.getLogger(MessageElement.class.getName()); + + /** + * The name of this element. May be the empty string ("") if the element is + * unnamed. + */ + protected final String name; + + /** + * The type of this element. + */ + protected final MimeMediaType type; + + /** + * The optional element which digitally signs or digests this element. + * If null then the element is has no signature element. + */ + protected final MessageElement sig; + + /** + * message properties hashmap + */ + private Map properties = null; + + /** + * cached result of {@link #getByteLength()} operation. + */ + protected transient long cachedGetByteLength = -1; + + /** + * cached result of {@link #getBytes(boolean)} operation. + */ + protected transient SoftReference cachedGetBytes = null; + + /** + * cached result of {@link #toString()} operation. + */ + protected transient SoftReference cachedToString = null; + + /** + * Returns a pseudo-random unique string which can be used as an element + * name. + * + * @return String containing a pseudo-random value + */ + public static String getUniqueName() { + return UUID.randomUUID().toString(); + } + + /** + * Returns a string containing a pseudo-random unique string. The result of + * String.compare() will be consistent with the order in which + * results were returned from this function. + *

      + *

      Security Consideration : Be aware that the pseudo random portion of + * the names generated by this string are shared amongst all peer groups + * running in the same classloader. You may be at a risk for loss of + * anonymity if you use the element names produced in more than one peer + * group. + * + * @return String containing a pseudo-random value. The result of + * String.compare() will be consistent with the order in + * which results were returned from this function. + */ + public static String getSequentialName() { + return UUIDFactory.newSeqUUID().toString(); + } + + /** + * Internal constructor for initializing everything but the data. + * + * @param name Name of the Element. May be the empty string ("") if + * the Element is not named. + * @param type Type of the Element. null is equivalent to specifying + * the type "Application/Octet-stream" + * @param sig optional message digest/digital signature element. If + * no signature is to be specified, pass null. + */ + protected MessageElement(String name, MimeMediaType type, MessageElement sig) { + this.name = (null != name) ? name : ""; + + this.type = (null != type) ? type.intern() : MimeMediaType.AOS; + + if ((null != sig) && (null != sig.sig)) { + throw new IllegalArgumentException("Invalid Signature Element. Signatures may not have signatures."); + } + + this.sig = sig; + } + + /** + * {@inheritDoc} + * + * @deprecated Since Message Elements are immutable this method does + * nothing useful. + */ + @Override + @Deprecated + public final MessageElement clone() { + return this; + } + + /** + * {@inheritDoc} + *

      + *

      Elements are considered equal if they have the same name, type and + * signatures. Element data is not considered by this implementation as + * it is mostly intended for subclass use. + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; // same object + } + + if (target instanceof MessageElement) { + MessageElement likeMe = (MessageElement) target; + + // sig is nullable so test seperatly. + boolean sigequals = (null != sig) ? sig.equals(likeMe.sig) : (null == likeMe.sig); + + return sigequals && name.equals(likeMe.name) && type.equals(likeMe.type); + } + + return false; // not a MessageElement + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int sigHash = ((null != getSignature()) && (this != getSignature())) ? getSignature().hashCode() : 1; + + int result = sigHash * 2467 + // a prime + getElementName().hashCode() * 3943 + // also a prime + getMimeType().hashCode(); + + return (0 != result) ? result : 1; + } + + /** + * {@inheritDoc} + *

      + *

      Returns a String representation of the element data. The + * 'charset' parameter of the message element's mimetype, if + * any, is used to determine encoding. If the charset specified is + * unsupported then the default encoding will be used. + *

      + *

      synchronized for caching purposes. + */ + @Override + public synchronized String toString() { + String result; + + if (null != cachedToString) { + result = cachedToString.get(); + + if (null != result) { + return result; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("creating toString of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + String charset = type.getParameter("charset"); + + StringBuilder theString = new StringBuilder(); + + Reader asString; + + try { + if (null == charset) { + asString = new InputStreamReader(getStream()); + } else { + try { + asString = new InputStreamReader(getStream(), charset); + } catch (UnsupportedEncodingException caught) { + throw new IllegalStateException("Unsupported charset : " + charset); + } + } + + char[] characters = new char[256]; + + do { + int res = asString.read(characters); + + if (res < 0) { + break; + } + + theString.append(characters, 0, res); + } while (true); + + result = theString.toString(); + + cachedToString = new SoftReference(result); + return result; + } catch (IOException caught) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not generate string for element. ", caught); + } + + throw new IllegalStateException("Could not generate string for element. " + caught); + } + } + + /** + * Returns the name of the MessageElement. Unnamed elements will return + * the empty string (""); + * + * @return String containing the name of the MessageElement. + */ + public String getElementName() { + return name; + } + + /** + * {@inheritDoc} + *

      + *

      Will return "Application/Octet-Stream" if no type was originally + * specified. + */ + public MimeMediaType getMimeType() { + return type; + } + + /** + * {@inheritDoc} + *

      + *

      We use the "unknown" extension and leave it to sub-classes to + * extend this. If we had a mailcap facility we could do better + * classification based on mimetype. + */ + public String getFileExtension() { + return "???"; + } + + /** + * Returns the size of the element data in bytes. + * + * @return long containing the size of the element data. + */ + public synchronized long getByteLength() { + if (cachedGetByteLength >= 0) { + return cachedGetByteLength; + } + + CountingOutputStream countBytes = new CountingOutputStream(new DevNullOutputStream()); + + try { + sendToStream(countBytes); + cachedGetByteLength = countBytes.getBytesWritten(); + return cachedGetByteLength; + } catch (IOException caught) { + throw new IllegalStateException("Could not get length of element : " + caught.toString()); + } + } + + /** + * Returns a byte array which contains the element data. The byte array + * returned may be shared amongst all copies of the element, + * do not modify it. The copy parameter allows you to request a + * private, modifiable copy of the element data. + *

      + *

      This implementation builds the byte array from the stream. + * + * @param copy If true then the result can be modified without damaging the state of this + * MessageElement. If false, then the result may be a shared copy of the data and + * should be considered read-only. + * @return byte[] Contents of message element. + */ + public synchronized byte[] getBytes(boolean copy) { + byte[] result; + + if (null != cachedGetBytes) { + result = cachedGetBytes.get(); + + if (null != result) { + if (copy) { + byte[] theCopy = new byte[result.length]; + + System.arraycopy(theCopy, 0, result, 0, result.length); + } else { + return result; + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("creating getBytes of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + long len = getByteLength(); + + if (len > Integer.MAX_VALUE) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("MessageElement is too large to be stored in a byte array."); + } + + throw new IllegalStateException("MessageElement is too large to be stored in a byte array."); + } + + result = new byte[(int) len]; + + try { + DataInput di = new DataInputStream(getStream()); + + di.readFully(result); + } catch (IOException caught) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to get bytes of Message Element. ", caught); + } + throw new IllegalStateException("Failed to get bytes of Message Element. " + caught); + } + + // if this is supposed to be a shared buffer then we can cache it. + if (!copy) { + cachedGetBytes = new SoftReference(result); + } + + return result; + } + + /** + * {@inheritDoc} + *

      + *

      This version probably has sub-optimal performance. Sub-classes + * should override this implementation. + */ + public void sendToStream(OutputStream sendTo) throws IOException { + copyInputStreamToOutputStream(getStream(), sendTo); + } + + /** + * Returns the element containing the digest/digital signature for + * this element + * + * @return Element containing the digital signature. + */ + public MessageElement getSignature() { + + return sig; + } + + /** + * Associate a transient property with this element. If there was a previous + * value for the key provided then it is returned. + *

      + *

      Element properties are useful for managing the state of element + * during processing. Element properties are not transmitted with the + * message element when the message element is sent as part of a message. + *

      + *

      The setting of particular keys may be controlled by a Java Security + * Manager. Keys of type 'java.lang.Class' are checked against the caller of + * this method. Only callers which are instances of the key class may modify + * the property. This check is not possible through reflection. All other + * types of keys are unchecked. + * + * @param key the property key + * @param value the value for the property + * @return previous value for the property or null if no previous + */ + public synchronized Object setElementProperty(Object key, Object value) { + + /* + if( key instanceof java.lang.Class ) { + Class keyClass = (Class) key; + SecurityManager secure = new SecurityManager() { + public boolean checkCallerOfClass( Class toCheck ) { + Class [] context = getClassContext(); + + return toCheck.isAssignableFrom( context[2] ); + } + }; + + if( !secure.checkCallerOfClass( keyClass ) ) { + throw new SecurityException( "You can't set that key from this context." ); + } + } + */ + + if (null == properties) { + properties = new HashMap(); + } + + return properties.put(key, value); + } + + /** + * Retrieves a transient property from the set for this element. + * + *

      Element properties are useful for managing the state of element + * during processing. Element properties are not transmitted with the + * message element when the message element is sent as part of a message. + * + * @param key the property key. + * @return value for the property or null if there is no property for this + * key. + */ + public Object getElementProperty(Object key) { + + if (null == properties) { + return null; + } + + return properties.get(key); + } + + /** + * Copies an input stream to an output stream with buffering. + * + * @param source The stream to copy from. + * @param sink The stream to send the data to. + * @throws IOException if there is a problem copying the data + */ + protected static void copyInputStreamToOutputStream(InputStream source, OutputStream sink) throws IOException { + int c; + byte[] buf = new byte[4096]; + + do { + c = source.read(buf); + + if (-1 == c) { + break; + } + + sink.write(buf, 0, c); + } while (true); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageFilterListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageFilterListener.java new file mode 100644 index 000000000..1fd9d76d1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageFilterListener.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + + +/** + * This interface is used by Message Filters. + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.Message + */ +public interface MessageFilterListener { + + /** + * This method is invoked by the EndpointService for each message for which + * this filter is registered. + *

      + * The src and destination addresses are the addresses as they were + * before any filters were run upon the message. If your filter is dependant + * upon the current value of thse addresses it should examine the message + * directly. + * + * @param message Incoming message + * @param srcAddr Endpoint Address of the original source of the message + * @param dstAddr Endpoint Address of the original destination of the message + * @return Message The potentially modified or alternate message. If null + * is returned then the message has been discarded. + */ + public Message filterMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessagePropagater.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessagePropagater.java new file mode 100644 index 000000000..d105c2a48 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessagePropagater.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +/** + * A MessagePropagater is a MessageTransport that can send propagated + * (multicast) messages. + * + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.Message + * @see net.jxta.endpoint.Messenger + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.MessageSender + * @see net.jxta.endpoint.MessageReceiver + */ +public interface MessagePropagater extends MessageTransport { + + /** + * Returns the {@link EndpointAddress} which will be used as the source + * address for all messages sent by this message sender. This is the + * "preferred" address to which replies should be sent. This address is not + * necessarily the best or only address by which the peer may be reached. + *

      + * The public address may also be for a different message transport. + * + * @return an EndpointAddress containing the public address for this + * message receiver. + */ + public EndpointAddress getPublicAddress(); + + /** + * Propagates a Message via this Message Transport. + * + * @param msg The Message to be propagated. + * @param serviceName Contains the name of the destination service, if any. + * This will be integrated into the destination address. + * @param serviceParams Contains the parameters associated with the service, + * if any. This will be integrated into the destination address. + * @param initialTTL The requested initial TTL for this message. This value + * may be reduced by the implementation. + * @return {@code true} if the Message was propagated otherwise + * {@code false}. + */ + public boolean propagate(Message msg, String serviceName, String serviceParams, int initialTTL); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageReceiver.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageReceiver.java new file mode 100644 index 000000000..766e20a6f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageReceiver.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import java.util.Iterator; + + +/** + * A MessageReceiver is a MessageTransport that is capable of receiving messages. + * A MessageReceiver receives messages from the network and hands them to the + * the {@link EndpointService} for processing. A Message Receiver is known by + * the {@link EndpointAddress EndpointAddresses} it provides. + * + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.EndpointService + **/ +public interface MessageReceiver extends MessageTransport { + + /** + * Returns an Iterator of all of the + * {@link EndpointAddress EndpointAddresses} by which this + * MessageReceiver is reachable. The list is in order of + * "preference" with the most "preferred" EndpointAddress being at the + * beginning of the list. + * + * @return an Iterator of EndpointAddresses. + */ + public Iterator getPublicAddresses(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageSender.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageSender.java new file mode 100644 index 000000000..84fad1982 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageSender.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import java.io.IOException; + + +/** + * A MessageSender is a MessageTransport that is able to send messages to + * remote peers using some protocol. MessageSenders provide facilities for + * sending point-to-point (unicast) messages. + * + *

      MessageSenders additionally describe themselves in terms of their + * abilities. + *

      + *
      {@link #isConnectionOriented()}
      Indicates that the + * Message Transport can provide efficient transport of a series of messages to + * the same destination
      + *
      {link@ #allowRouting()}
      Indicates that the Message Transport + * can be used in the routing of messages to destinations which are not + * directly reachable via this transport.
      + *
      + * + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.Message + * @see net.jxta.endpoint.Messenger + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.MessageReceiver + * @see net.jxta.endpoint.MessagePropagater + */ +public interface MessageSender extends MessageTransport { + + /** + * Returns the {@link EndpointAddress} which will be used as the source + * address for all messages sent by this message sender. This is the + * "preferred" address to which replies should be sent. This address is not + * necessarily the best or only address by which the peer may be reached. + * + *

      The public address may also be for a different message transport. + * + * @return an EndpointAddress containing the public address for this + * message receiver. + */ + public EndpointAddress getPublicAddress(); + + /** + * Returns {@code true} if the Message Transport is connection oriented + * (like TCP/IP). Indicates that the Message Transport can provide + * efficient transport of a series of messages to the same destination. + * + * @return {@code true} if the Message Transport is connection oriented. + */ + public boolean isConnectionOriented(); + + /** + * Returns true if the Message Transport can be used by the EndpointRouter. + * Indicates that the Message Transport can be used in the routing of + * messages to destinations which are not directly reachable via this + * transport. + * + *

      More specifically, this Message Transport will be used to route + * messages who's final destination is not one of the endpoint + * addresses available from {@code getReachableEndpointAddresses}. + * + * @return true if the protocol can be used by the EndpointRouter + */ + public boolean allowsRouting(); + + /** + * Return a {@link Messenger} for sending messages to the specified + * destination {@link EndpointAddress}. + * + @param dest The destination address for which a messenger is requested. + * @param hint An optional hint for the transport to use when creating the + * messenger. The format of the hint is specific to each Message Transport + * and may be {@code null} if no hint is provided. + * @return a Messenger or {@code null} if the destination is not reachable. + */ + public Messenger getMessenger(EndpointAddress dest, Object hint); + + /** + * Returns {@code true} if the specified destination address is reachable + * via this Message Transport otherwise returns {@code false}. + * + * @deprecated This operation is often very expensive and usually + * duplicates the work of {@link #getMessenger}. If you want to determine + * the reachability of a destination, get a Messenger to the destination. + * + * @param addr Address to ping + * @return {@code true} if the specified destination address is reachable + * via this Message Transport otherwise returns {@code false}. + */ + @Deprecated + public boolean ping(EndpointAddress addr); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageTransport.java new file mode 100644 index 000000000..36584caea --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessageTransport.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +/** + * A MessageTransport is responsible for sending and/or receiving JXTA + * messages from an external network. A MessageTransport may use whatever + * protocol it wishes in transporting messages. Messages passed to + * MessageTransports are required to pass the messages cleanly (unaltered). + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.MessageSender + * @see net.jxta.endpoint.MessageReceiver + */ +public interface MessageTransport { + + /** + * Returns a String containing the name of the protocol used by this + * MessageTransport. The value will match the "protocol" portion of all + * {@link EndpointAddress}. + * + * @return a String containing the name of the protocol used by this + * MessageTransport. + */ + public String getProtocolName(); + + /** + * Returns the endpoint service with which this MessageTransport is + * registered. If it is unregistered then null will be returned. + * + * @return the EndpointService with which this MessageTransport is + * registered. + */ + public EndpointService getEndpointService(); + + /** + * Pass a transport control object to a message transport. + * + * @param operation Object that specifies the type of control operation + * to be performed + * @param value Object that specifies a value object associated + * with the control operation + * @return returned object + * @deprecated Under development, may change. + */ + @Deprecated + public Object transportControl(Object operation, Object value); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/Messenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/Messenger.java new file mode 100644 index 000000000..34b163370 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/Messenger.java @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.peergroup.PeerGroupID; +import net.jxta.util.SimpleSelectable; + +import java.io.IOException; + + +/** + * A Messenger is used to send messages to a destination. + *

      + * This interface specifies the allowed observable states for a messenger. (fine grain). This serves to normalize + * the state machines of the various messenger implementations and allows for more meaningful diagnostics. Implementations may + * use substates by adding high order bits, but these should never be reported by the public state observation methods. Most + * implementations will not use all these states. + *

      + *

      Each valid state is represented by a integer that is a power of 2. + *

      + *

      The (coarse grain) constants: USABLE, RESOLVED, TERMINAL, IDLE, SATURATED represent meaningful partitions of the space of + * states. + *

      + *

      The value of each constant is the bitwise OR of the states for which a given predicate is true: usable or not, + * confirmed or not, etc. Therefore the value of predicate p in state s is (s & p)!=0. + *

      + *

      These particular predicates are chosen so that they have a relevant truth value for all states. Therefore the bitwise negation + * of the corresponding constants represents the obvious: ~USABLE really lists all states that mean "not USABLE". + *

      + *

      These constants may be combined by bit logic operators to represent more predicates. {@link #waitState} accepts such values as + * a parameter. + *

      + *

      Applications should depend on the coarse grain constants, rather than those denoting discrete states. + * + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.util.SimpleSelector + * @see net.jxta.endpoint.EndpointAddress + * @see net.jxta.endpoint.Message + * @see MessengerState + */ +public interface Messenger extends SimpleSelectable { + + /** + * No message was ever submitted for sending. No connection has ever been attempted. + */ + public static final int UNRESOLVED = 0x1; + + /** + * Initial connection is being attempted. No message is pending. + */ + public static final int RESOLVING = 0x2; + + /** + * Currently connected. No message is pending (being sent implies pending). + */ + public static final int CONNECTED = 0x4; + + /** + * Currently not connected. No message is pending. + */ + public static final int DISCONNECTED = 0x8; + + /** + * Initial connection is being attempted. Messages are pending. + */ + public static final int RESOLPENDING = 0x10; + + /** + * Initial connection is being attempted. Messages are pending. New messages may not be submitted at this time. + */ + public static final int RESOLSATURATED = 0x20; + + /** + * Currently connected and sending messages. + */ + public static final int SENDING = 0x40; + + /** + * Currently sending messages.New messages may not be submitted at this time. + */ + public static final int SENDINGSATURATED = 0x80; + + /** + * Currently trying to re-establish connection. Messages are pending. + */ + public static final int RECONNECTING = 0x100; + + /** + * Currently trying to re-establish connection. New messages may not be submitted at this time. + */ + public static final int RECONSATURATED = 0x200; + + /** + * Attempting initial connection. Close has been requested. Messages are pending. + * New messages may no longer be submitted. + */ + public static final int RESOLCLOSING = 0x400; + + /** + * Currently sending messages. Close has been requested. New messages may no longer be submitted. + */ + public static final int CLOSING = 0x800; + + /** + * Trying to re-establish connection. Close has been requested. Messages are pending. + * New messages may no longer be submitted. + */ + public static final int RECONCLOSING = 0x1000; + + /** + * Failed to establish initial connection. Pending messages are being rejected. New messages may no longer be submitted. + */ + public static final int UNRESOLVING = 0x2000; + + /** + * Failed to re-establish connection. Pending messages are being rejected. New messages may no longer be submitted. + */ + public static final int BREAKING = 0x4000; + + /** + * Breaking established connection for expedite closure. Pending messages are being rejected. + * New messages may no longer be submitted. + */ + public static final int DISCONNECTING = 0x8000; + + /** + * Failed to establish initial connection. New messages may no longer be submitted. State will never change again. + */ + public static final int UNRESOLVABLE = 0x10000; + + /** + * Failed to re-establish connection. New messages may no longer be submitted. State will never change again. + */ + public static final int BROKEN = 0x20000; + + /** + * Closed as requested. All pending messages could be sent. New messages may no longer be submitted. + * State will never change again. + */ + public static final int CLOSED = 0x40000; + + /** + * The bitwise OR of all valid states. + */ + public static final int ANYSTATE = 0x7FFFF; + + /* Predicates. */ + + /** + * Composite state.

      + *

      + * Not known to be broken. + * Messenger may be used to send messages. Viability has not been evaluated yet. + * This is the most useful predicate to applications. USABLE means that + * it is reasonable to try and send a message. + */ + public static final int USABLE = (UNRESOLVED | RESOLVING | CONNECTED | DISCONNECTED | RESOLPENDING | RESOLSATURATED | SENDING + | SENDINGSATURATED | RECONNECTING | RECONSATURATED); + + /** + * Composite state. + *

      + *

        + *
      • Messenger was once resolved.

        + *
      • Messenger was at least once proven viable. Current usability is + * not asserted. For example a messenger may be found to be in a + * TERMINAL state, but also be in a RESOLVED state. Thus proving that + * the destination of the messenger is sometimes valid.
      • + *
      + */ + public static final int RESOLVED = (CONNECTED | SENDING | SENDINGSATURATED | CLOSING | CLOSED | DISCONNECTED | RECONNECTING + | RECONSATURATED | RECONCLOSING | BREAKING | DISCONNECTING | BROKEN); + + /** + * Composite state. + *

      + * Messenger has terminated its useful life. State will never change any more. + */ + public static final int TERMINAL = (UNRESOLVABLE | CLOSED | BROKEN); + + /** + * Composite state. + *

      + * Any message that may have been submitted in the past has been either sent or failed already. + * If a messenger is in a state IDLE & RESOLVED & USABLE, then the expected delay in sending a message + * is minimal. + */ + public static final int IDLE = (UNRESOLVED | RESOLVING | CONNECTED | DISCONNECTED | UNRESOLVABLE | CLOSED | BROKEN); + + /** + * Composite state. + *

      + * This messenger cannot take new messages for now. All available buffering space is occupied. + * Note that only the usable states can be saturated. Once a messenger is in the process of terminating + * and thus takes no new messages anyway, it no-longer shows as saturated. + */ + public static final int SATURATED = (RESOLSATURATED | SENDINGSATURATED | RECONSATURATED); + + /** + * Returns the current state. + * + * @return one of the legal discrete state values. + */ + public int getState(); + + /** + * Blocks unless and until the current state is or has become one of the desired values. The observable states are guaranteed + * to be represented by a single bit. Multiple desired values may be specified by passing them ORed together. + *

      + * This class defines the list of constants that may be used and how these may be combined. + *

      + * Note that the state can change as soon as this method returns, so any observation is only an indication of the + * past. Synchronizing on the object itself has no other effect than interfering with other threads doing the same. Obviously, + * certain transitions cannot happen unless a new message is submitted. So unless another thread is using a messenger, it is + * safe to assume that a non-saturated messenger will not become saturated spontaneously. Note that messengers returned by + * different endpoint service interface objects (what {@link net.jxta.peergroup.PeerGroup#getEndpointService()} returns) are + * different. However a given endpoint interface object will return an existing messenger to the same exact destination if + * there is a {@link Messenger#USABLE} one. + *

      + * With an unshared messenger, one can wait for any change with {@code waitState(~getState(), 0);}. + *

      + * Note that it is advisable to always include {@link #TERMINAL} as part + * of the desired states with unless being blocked past the messenger + * termination is an acceptable behaviour. + *

      + * Examples:

      + *

      + * Ensure that the messenger can take more messages (or is {@code UNUSABLE}): {@code waitState(~SATURATED)}

      + *

      + * Ensure that all submitted messages have been sent: {@code waitState(TERMINAL | IDLE)} + *

      + * Ensure that the messenger is already resolved and can take more messages: {@code waitState(TERMINAL | (RESOLVED & ~SATURATED))} + * + * @param wantedStates The binary OR of the desired states. + * @param timeout The maximum number of milliseconds to wait. A timeout of 0 means no time limit. + * @return The desired state that was reached or the current state when time ran out. + * @throws InterruptedException If the invoking thread was interrupted before the condition was realized. + */ + int waitState(int wantedStates, long timeout) throws InterruptedException; + + /** + * Returns {@code true} if this messenger is closed and no longer + * accepting messages to be sent. This is a shortcut for + * {@code (getState() & USABLE == 0)}. Once closed, a messenger should be + * discarded. + * + * @return {@code true} if this messenger is closed, otherwise {@code false}. + */ + boolean isClosed(); + + /** + * Returns an indication of whether this messenger may be worth closing. + * + * @return {@code true} if the messenger is idle otherwise {@code false}. + * @deprecated no longer relevant and always false. This notably is not equivalent to the {@link #IDLE} state. + */ + @Deprecated + boolean isIdle(); + + /** + * Returns {@code true} if the sendMessage methods of + * this messenger are fully synchronous. + * + * @deprecated all messengers are asynchronous, and the {@link #sendMessageB} method is always blocking. + * + * @return true if synchronous + */ + @Deprecated + boolean isSynchronous(); + + /** + * Returns the destination of this messenger. + * + * @return The destination address of this messenger + * @see Messenger#getLogicalDestinationAddress() + */ + EndpointAddress getDestinationAddress(); + + /** + * Returns the internal EndpointAddress object of the destination of the user. + * This method is intended to be used for applications that require a weak + * or soft reference to an EndpointMessenger: the returned Endpoint Address + * object will be unreferenced when this messenger will finalize. + * + * @deprecated EndpointAddress is now immutable which means that this result + * is the same as {@link #getDestinationAddress()}. This method will be + * eventually removed. + * + * @return EndpointAddress the destination address of this messenger + * @see #getDestinationAddress() + */ + @Deprecated + EndpointAddress getDestinationAddressObject(); + + /** + * Returns the logical destination of this messenger. This may be a + * different address than is returned by + * {@link #getDestinationAddress() getDestinationAddress} and refers to + * the entity which is located at the destination address. + *

      + * By analogy, a telephone number would be the destination address, and + * the owner of that telephone number would be the logical destination. + * Each logical destination may be known by one or more destination + * addresses. + * + * @return EndpointAddress the logical destination address of this messenger. + * @see #getDestinationAddress() + */ + EndpointAddress getLogicalDestinationAddress(); + + /** + * Returns the maximum message size that this messenger can be used to send. + * The limit refers to the cumulative size of application level elements. + * The various {@code sendMessage()} variants will refuse to send messages + * that exceed this limit. + * + * @return the limit. + */ + long getMTU(); + + /** + * If applicable, returns another messenger that will send messages to the same destination address than this one, but with + * the specified default service and serviceParam, possibly rewriting addresses to ensure delivery through the specified + * redirection. This is not generally useful to applications and most messengers will return null. This method is needed + * by the EndpointService when interacting with Messengers provided by Transport modules. If you are not implementing a + * Transport module, then you can ignore this method. + *

      + * Important: The channel so obtained is not configured to support the {@link #sendMessage(Message,String,String, + *OutgoingMessageEventListener)} legacy method. If use of this method is desired, {@link ChannelMessenger#setMessageWatcher} + * must be used first. + * + * @param redirection The requested redirection. The resulting channel messenger will use this to force + * delivery of the message only in the specified group (or possibly descendents, but not parents). If null the local + * group is assumed. This redirection is applied only to messages that are sent to a service name and service param that + * do not imply a group redirection. + * @param service The service to which the resulting channel will send messages, when they are not sent to a + * specified service. + * @param serviceParam The service parameter that the resulting channel will use to send messages, when no parameter is + * specified. + * @return a channelMessenger as specified. + * @see MessageSender#getMessenger(EndpointAddress,Object) + */ + Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam); + + /** + * Close this messenger after processing any pending messages. This method + * is not blocking. Upon return, the messenger will be in one of the non + * {@link #USABLE} states, which means that no message may be sent through + * it. Any other effect of this method, such as an underlying connection + * being closed, or all pending messages being processed, may be deferred + * indefinitely. When the messenger has completely processed the closure + * request, it will be in one of the {@link #TERMINAL} states (which are + * also {@link #IDLE} states). Therefore, if one is interested in the + * outcome of the closure, one may wait for the messenger to be in a + * {@link #TERMINAL} or {@link #IDLE} state, and check which it is. + * {@link #CLOSED} denotes success (all outstanding messages have been + * sent), as opposed to {@link #UNRESOLVABLE} or {@link #BROKEN}. + */ + void close(); + + /** + * Makes sure that all outstanding messages have been processed; + * successfully or not. This method waits unless and until the state of the + * messenger is an {@link #IDLE} state. If the reached state is neither + * {@link #CLOSED} or any {@link #USABLE} state, then it throws an + * IOException. Else it returns silently.

      + * + *

      If another thread keeps sending messages, this method may never + * return. + * + *

      This method is deliberately simple. If a timeout needs to be + * provided, or if more detailed conditions are required, the + * {@link #waitState(int,long)} and {@link #getState()} methods should be + * used. For example : + * + *

      +     * int myFlush(long notTooLong) {
      +     *   messenger.waitState(IDLE, notTooLong);
      +     *   if ((messenger.getState() & IDLE) == 0) return TOOLONG;
      +     *   if ((messenger.getState() & USABLE) != 0) return FLUSHED;
      +     *   if (messenger.getState() == CLOSED) return CLOSEDANDFLUSHED;
      +     *   return BROKEN;
      +     * }
      +     * 
      + * + *

      Note: {@link #close()} being asynchronous, it is valid to invoke + * flush() after close() as a form of synchronous + * variant of close(). If this messenger is not shared with any + * other thread, then invoking flush() before + * close is a more familiar means of achieving the same effect. + * + * @throws IOException This messenger failed before processing all + * outstanding messages successfully. + */ + void flush() throws IOException; + + /** + * Force the messenger to start resolving if it is not resolved yet. Any + * attempt at sending a message has the same effect, but the message may + * fail as a result, depending upon the method used. + */ + void resolve(); + + /** + * Simple sending: blocks until the message was accepted for sending or the messenger is not {@link #USABLE}; whichever occurs + * first. If a service name and service param are specified, they will replace those specified at construction for the + * purpose of sending this message only.

      + *

      + * Error Handling: + *

      + *

        + *
      • An {@link java.io.IOException} means that this message is invalid or that this messenger is now in one of the non {@link + * #USABLE} states and may no longer send new messages, and means that the message was not sent. The exact state of the + * messenger may be obtained from the {@link #getState()} method. If no exception is thrown, the message is accepted for + * sending and may or may not be fully processed.
      • + *

        + *

      • The invoker may have confirmation of completion by observing the message's properties. When the message has been + * fully processed, {@link Message#getMessageProperty(Object) Message#getMessageProperty(Messenger.class)} will return an + * object of class {@link OutgoingMessageEvent}. Changes in a message's set of properties may be tracked by selecting the + * message. If an exception was thrown, the message's properties will not be modified + *

        + *

      • There is no guarantee that the process of sending the message will not fail after that method returned. If this messenger + * subsequently reaches an {@link #IDLE} state that is either {@link #CLOSED} or a {@link #USABLE} state, then it may be inferred + * that all outstanding messages have been processed without this messenger detecting an error.
      • + *
      + *

      + *

      WARNING: The Message object should not be reused or modified until completely processed. Concurrent modification + * of a message while a messenger is sending the message will produce incorrect and unpredictable results. If completion is + * not monitored, the message should never be reused. If necessary, a clone of the message may be provided to + * {@link #sendMessageB}: + *

      + *

      +     *     messenger.sendMessageB( (Message) myMessage.clone(), theService, theParam );
      +     * 
      + *

      + * There is no guarantee that a message successfully sent will actually be received.

      + * + * @param msg the message + * @param service Optionally replaces the service in the destination + * address. If {@code null} then the destination address's default + * service will be used. If the empty string ("") is used then + * no service is included in the destination address. + * @param serviceParam Optionally replaces the service param in the + * destination address. If {@code null} then the destination address's + * default service parameter will be used. If the empty string ("") is used + * then no service param is included in the destination address. + * @throws IOException Thrown if the message cannot be sent. + */ + void sendMessageB(Message msg, String service, String serviceParam) throws IOException; + + /** + * Sends a message to the destination specified at construction. If a service name and service param are specified, they will + * replace those specified at construction for the purpose of sending this message only. + *

      + * This method is identical to {@link #sendMessage(Message,String,String)}, except that it does not throw an exception. The invoker + * has to retrieve a detailed status from the message if needed. + *

      + * Error Handling:

        + *
      • A return result of {@code false} indicates that the message was not accepted to be sent. This may be due to + * local resource limits being reached or to the messenger being in a state that is not {@link #USABLE} or to the message + * being invalid. The exact cause of the failure can be retrieved from the message by using + * {@link Message#getMessageProperty(Object) Message.getMessageProperty(Messenger.class)}. If appropriate, + * another attempt at sending the message, may be made after waiting for the congestion to clear (for example by using + * {@link #waitState(int,long)}).
      • + *

        + *

      • A return result of {@code true} indicates that the message was accepted for sending. It does not imply that + * the message will be sent or that the destination will receive the message. There will be no indication by this method + * of any errors in sending the message. If this messenger subsequently reaches an {@link #IDLE} state that is either {@link + * #CLOSED} or a {@link #USABLE} state, then it may be inferred that all outstanding messages have been processed without this + * messenger detecting an error.
      • + *

        + *

      • The invoker may have confirmation of completion (successful or not) by observing the message's properties. When the + * message has been fully processed, {@link Message#getMessageProperty(Object) Message.getMessageProperty(Messenger.class)} + * will return an object of class {@link OutgoingMessageEvent}. Changes in a message's set of properties may be tracked by + * selecting the message.
      • + *
      + *

      + *

      WARNING: The Message object should not be reused or modified until completely processed. Concurrent modification + * of a message while a messenger is sending the message will produce incorrect and unpredictable results. If completion is + * not monitored, the message should never be reused. If necessary, a clone of the message may be provided to + * {@link #sendMessageN}: + *

      + *

      +     *     messenger.sendMessageN( (Message) myMessage.clone(), theService, theParam );
      +     * 
      + *

      + * There is no guarantee that a message successfully sent will actually be received.

      + * + * @param msg The message to send. + * @param service Optionally replaces the service in the destination + * address. If {@code null} then the destination address's default + * service will be used. If the empty string ("") is used then + * no service is included in the destination address. + * @param serviceParam Optionally replaces the service param in the + * destination address. If {@code null} then the destination address's + * default service parameter will be used. If the empty string ("") is used + * then no service param is included in the destination address. + * @return boolean {@code true} if the message has been accepted for sending, otherwise {@code false}. + */ + boolean sendMessageN(Message msg, String service, String serviceParam); + + /** + * Sends a message to the destination specified at construction as if by + * invoking {@link #sendMessage(Message,String,String) sendMessage(msg, null, null)} + * + * @param msg The message to send. + * @return boolean {@code true} if the message has been accepted for sending, otherwise {@code false}. + * @throws IOException Thrown if the message cannot be sent. + */ + boolean sendMessage(Message msg) throws IOException; + + /** + * Sends a message to the destination specified at construction. If a service name and service param are specified, they will + * replace those specified at construction for the purpose of sending this message only. + *

      + * Error Handling: + *

      + *

        + *

        + *

      • An {@link java.io.IOException} means that this message is invalid or that this messenger is now in one of the + * non {@link #USABLE} states and may no longer send new messages, and that the message was not sent. The exact state of + * the messenger may be obtained from the {@link #getState()} method.
      • + *

        + *

      • A return result of {@code false} indicates that the message was not accepted to be sent. Usually this is due to + * local resource limits being reached. If needed, another attempt at sending the message, may be made after waiting for the + * congestion to clear (for example by using {@link #waitState(int,long)}).
      • + *

        + *

      • A return result of {@code true} indicates that the message was accepted for sending. It does not imply that + * the message will be sent or that the destination will receive the message. There will be no immediate indication of any + * errors in sending the message. If this messenger subsequently reaches an {@link #IDLE} state that is either {@link #CLOSED} + * or a {@link #USABLE} state, then it may be inferred that all outstanding messages have been processed without this + * messenger detecting an error.
      • + *

        + *

      • The invoker may have confirmation of completion by observing the message's properties. When the message has been fully + * processed, {@link Message#getMessageProperty(Object) Message.getMessageProperty(Messenger.class)} will return + * an object of class {@link OutgoingMessageEvent}. Changes in a message's set of properties may be tracked by selecting + * the message. + *

        + *

      + *

      + *

      WARNING: The Message object should not be reused or modified until completely processed. Concurrent modification + * of a message while a messenger is sending the message will produce incorrect and unpredictable results. If completion is + * not monitored, the message should never be reused. If necessary, a clone of the message may be provided to + * sendMessage: + *

      + *

      +     *     messenger.sendMessage( (Message) myMessage.clone(), theService, theParam );
      +     * 
      + *

      + * There is no guarantee that a message successfully sent will actually be received.

      + *

      + * Limitation: using this method along with {@link net.jxta.util.SimpleSelector#select} on the same message may occasionally + * cause some errors to not be thrown. Prefer {@link #sendMessageN} when using {@link net.jxta.util.SimpleSelector#select}. + *

      + * This is a legacy method. Modern code should prefer the other methods and select messages. + * + * @param msg The message to send. + * @param service Optionally replaces the service in the destination + * address. If {@code null} then the destination address's default + * service will be used. If the empty string ("") is used then + * no service is included in the destination address. + * @param serviceParam Optionally replaces the service param in the + * destination address. If {@code null} then the destination address's + * default service parameter will be used. If the empty string ("") is used + * then no service param is included in the destination address. + * @return boolean {@code true} if the message has been accepted for sending, otherwise {@code false}. + * @throws IOException Thrown if the message cannot be sent. + */ + boolean sendMessage(Message msg, String service, String serviceParam) throws IOException; + + /** + * Sends a message to the destination specified at construction. If a service name and service param are specified, they will + * replace those specified at construction for the purpose of sending this message only. + *

      + * WARNING: The Message object should not be reused or modified until the message has been fully processed. + * Concurrent modification of a message while a messenger is sending the message will produce incorrect and unpredictable + * results. If a listener is provided it is invoked after the message is considered fully processed. However it is recommended + * not to reuse or otherwise modify a messages after sending it. If necessary, a clone of the message may be provided to + * sendMessage: + *

      + *

      +     *     messenger.sendMessage( (Message) myMessage.clone() );
      +     * 
      + *

      + * Error Handling: + *

      + *

        + *

        + *

      • If a listener was provided, it will always be invoked. Depending upon the outcome either the + * {@link OutgoingMessageEventListener#messageSendFailed(OutgoingMessageEvent)} or the {@link + * OutgoingMessageEventListener#messageSendSucceeded(OutgoingMessageEvent)} method will be invoked:

        + *

        + *

          + *

          + *

        • If the message could not be accepted for sending due to temporary resource saturation, + * messageSendFailed will be invoked. The {@link Throwable} object returned by the {@link + * OutgoingMessageEvent#getFailure()} method of the passed event object will be null.
        • + *

          + *

        • If the message could not be accepted for sending due to the messenger not being {@link #USABLE}, + * messageSendFailed will be invoked. The {@link Throwable} object returned by the {@link + * OutgoingMessageEvent#getFailure()} method of the passed event object will reflect the messenger's condition.
        • + *

          + *

        • If the message is accepted for sending but later fails, then messageSendFailed will be invoked. The + * {@link Throwable} object returned by the {@link OutgoingMessageEvent#getFailure()} method of the passed event object + * will reflect the origin of the failure.
        • + *

          + *

        • If the message is accepted for sending and later succeeds, then messageSendSucceeded will be + * invoked.
        • + *

          + *

      • + *

        + *

      • If a listener was provided, it is always possible that it is invoked before this method returns.
      • + *

        + *

      • If no listener was provided, There will be no notification of any errors nor success in sending the message. If + * this messenger subsequently reaches an {@link #IDLE} state that is either {@link #CLOSED} or a {@link #USABLE} state, then it + * may be inferred that all outstanding messages have been processed without this messenger detecting an error.
      • + *

        + *

      • This method does not throw exceptions. As a result, when used with a {@code null} listener, it provides very + * little feedback to the invoker. A messenger should be abandoned once it is in one of the {@link #TERMINAL} states.
      • + *

        + *

      + *

      + * As with all sendMessage methods, success is not a guarantee that the message will actually be received. + *

      + *

      This is a legacy method. Modern code should prefer the other methods and select messages. If a listener API is preferred, it is possible to use a {@link ListenerAdaptor} object explicitly to have a listener called. + * + * @param msg The message to send. + * @param service Optionally replaces the service in the destination + * address. If {@code null} then the destination address's default + * service will be used. If the empty string ("") is used then + * no service is included in the destination address. + * @param serviceParam Optionally replaces the service param in the + * destination address. If {@code null} then the destination address's + * default service parameter will be used. If the empty string ("") is used + * then no service param is included in the destination address. + * @param listener listener for events about this message or null if no notification is desired. + * @throws UnsupportedOperationException If this messenger is not a channel or was not given a {@link ListenerAdaptor}. + * (all messengers obtained through {@link EndpointService#getMessenger} are configured properly. + */ + void sendMessage(Message msg, String service, String serviceParam, OutgoingMessageEventListener listener); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerEvent.java new file mode 100644 index 000000000..bcf4b6a1b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerEvent.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +/** + * An event which indicates that a messenger has been successfully created. + *

      + * The source of Message Transport providing the messenger. + * + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.Messenger + * @see net.jxta.endpoint.EndpointService + */ +public class MessengerEvent extends java.util.EventObject { + + /** + * The newly created messenger. + */ + final transient Messenger messenger; + + /** + * The destination address of the messenger. + */ + final EndpointAddress connectionAddress; + + /** + * Creates a new instance of MessengerEvent + * + * @param source The source of Message Transport providing the messenger + * @param messenger the messenger + * @param connectionAddress The connection address + */ + public MessengerEvent(Object source, Messenger messenger, EndpointAddress connectionAddress) { + super(source); + + this.messenger = messenger; + this.connectionAddress = connectionAddress; + } + + public Messenger getMessenger() { + return messenger; + } + + public EndpointAddress getConnectionAddress() { + return connectionAddress; + } + + /** + * {@inheritDoc} + *

      + * A simple implementation for debugging. Don't depend upon this format. + */ + @Override + public String toString() { + return source.toString() + "-->" + messenger.toString() + " (" + connectionAddress + ")"; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerEventListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerEventListener.java new file mode 100644 index 000000000..09896027e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerEventListener.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +import java.util.EventListener; + +/** + * A listener for MessengerEvents. + */ +public interface MessengerEventListener extends EventListener { + + /** + * A messenger is ready. + * + * @param event The Messenger Event. + * @return {@code true} if the listener wants to claim the Messenger. + * (Normally means that it will not be offered to any other listener). + */ + public boolean messengerReady(MessengerEvent event); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerState.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerState.java new file mode 100644 index 000000000..df7c1cd6a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerState.java @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +/** + * The complete standard messenger life cycle state machine that all messengers + * must obey. Compliant messengers can be built by implementing and using this + * class as an engine to orchestrate discrete operations. + *

      + * In order to use this class, one must implement the various abstract Action + * methods, so that they trigger the required operations. + *

      + * Synchronization has to be externally provided and usually needs to extend + * around sections wider than just the invocation of this class' methods. For + * example, if the user of this class maintains a queue, the state of the queue + * must be kept consistent with the invocation of {@link #msgsEvent}, + * {@link #saturatedEvent}, and {@link #idleEvent}, which all denote different + * states of that queue. It is suggested to use the instance of this class as + * the synchronization object. + */ +public abstract class MessengerState { + + // All the transition map setup is rather terse because java tends to make + // it extremely verbose. We do not want to end up with 1000 lines of code + // for what amounts to initializing a table. + + // Below is a method reference. It permits putting "what to do" in a field. + // The {@code doIt()} method is given the target object because we want our + // entire transition table to be a static singleton. Otherwise it would cost + // too much initializing each instance of this class. + + private interface Action { + public void doIt(MessengerState messengerState); + } + + // Action method "pointers". + // The transition table is static. Otherwise it would cost too much initializing each instance of this class. + + private final static Action Connect = new Action() { + public void doIt(MessengerState messengerState) { + messengerState.connectAction(); + } + }; + private final static Action Closein = new Action() { + public void doIt(MessengerState s) { + s.closeInputAction(); + } + }; + private final static Action Start = new Action() { + public void doIt(MessengerState s) { + s.startAction(); + } + }; + private final static Action Closeout = new Action() { + public void doIt(MessengerState messengerState) { + messengerState.closeOutputAction(); + } + }; + private final static Action Failall = new Action() { + public void doIt(MessengerState messengerState) { + messengerState.failAllAction(); + } + }; + private final static Action Closeio = new Action() { + public void doIt(MessengerState s) { + s.closeInputAction(); + s.closeOutputAction(); + } + }; + private final static Action Closefail = new Action() { + public void doIt(MessengerState messengerState) { + messengerState.closeInputAction(); + messengerState.failAllAction(); + } + }; + private final static Action Nop = new Action() { + public void doIt(MessengerState messengerState) { + } + }; + + /** + * The transition each event causes when in that state. + */ + private static class State { + private final int number; + + private State stResolve; + private Action acResolve; + + private State stMsgs; + private Action acMsgs; + + private State stSaturated; + private Action acSaturated; + + private State stClose; + private Action acClose; + + private State stShutdown; + private Action acShutdown; + + private State stUp; + private Action acUp; + + private State stDown; + private Action acDown; + + private State stIdle; + private Action acIdle; + + State(int stateNum) { + number = stateNum; + } + + void init(Object[] data) { + stResolve = (State) data[0]; + acResolve = (Action) data[1]; + stMsgs = (State) data[2]; + acMsgs = (Action) data[3]; + stSaturated = (State) data[4]; + acSaturated = (Action) data[5]; + stClose = (State) data[6]; + acClose = (Action) data[7]; + stShutdown = (State) data[8]; + acShutdown = (Action) data[9]; + stUp = (State) data[10]; + acUp = (Action) data[11]; + stDown = (State) data[12]; + acDown = (Action) data[13]; + stIdle = (State) data[14]; + acIdle = (Action) data[15]; + } + } + + + // All the states. (We put them together in a class essentially to simplify initialization). + private static class TransitionMap { + + private final static State Unresolved = new State(Messenger.UNRESOLVED); + private final static State ResPending = new State(Messenger.RESOLPENDING); + private final static State Resolving = new State(Messenger.RESOLVING); + private final static State ResolSat = new State(Messenger.RESOLSATURATED); + private final static State Connected = new State(Messenger.CONNECTED); + private final static State Disconned = new State(Messenger.DISCONNECTED); + private final static State Reconning = new State(Messenger.RECONNECTING); + private final static State ReconSat = new State(Messenger.RECONSATURATED); + private final static State Sending = new State(Messenger.SENDING); + private final static State SendingSat = new State(Messenger.SENDINGSATURATED); + private final static State ResClosing = new State(Messenger.RESOLCLOSING); + private final static State ReconClosing = new State(Messenger.RECONCLOSING); + private final static State Closing = new State(Messenger.CLOSING); + private final static State Disconning = new State(Messenger.DISCONNECTING); + private final static State Unresable = new State(Messenger.UNRESOLVABLE); + private final static State Closed = new State(Messenger.CLOSED); + private final static State Broken = new State(Messenger.BROKEN); + + // The states need to exist before init, because they refer to each other. + // We overwrite them in-place with the complete data. + + private final static Object[][] INIT_TRANSITION_MAP = { + + /* STATE resolve, msgs, saturated, close, shutdown, up, down, idle */ + + /* UNRESOLVED */ + {Resolving, Connect, ResPending, Connect, ResolSat, Connect, Closed, Closein, Broken, Closein, Connected, Nop, Unresolved, Nop, Unresolved, Nop}, + + /* RESOLPENDING */ + {ResPending, Nop, ResPending, Nop, ResolSat, Nop, ResClosing, Closein, Broken, Closefail, Sending, Start, Unresable, Closefail, Resolving, Nop}, + + /* RESOLVING */ + {Resolving, Nop, ResPending, Nop, ResolSat, Nop, Closed, Closein, Broken, Closein, Connected, Nop, Unresable, Closein, Resolving, Nop}, + + /* RESOLSATURATED */ + {ResolSat, Nop, ResPending, Nop, ResolSat, Nop, ResClosing, Closein, Broken, Closefail, SendingSat, Start, Unresable, Closefail, Resolving, Nop}, + + /* CONNECTED */ + {Connected, Nop, Sending, Start, SendingSat, Start, Closed, Closeio, Broken, Closeio, Connected, Nop, Disconned, Nop, Connected, Nop}, + + /* DISCONNECTED */ + {Disconned, Nop, Reconning, Connect, ReconSat, Connect, Closed, Closein, Broken, Closein, Connected, Nop, Disconned, Nop, Disconned, Nop}, + + /* RECONNECTING */ + {Reconning, Nop, Reconning, Nop, ReconSat, Nop, ReconClosing, Closein, Broken, Closefail, Sending, Start, Broken, Closefail, Disconned, Nop}, + + /* RECONSATURATED */ + {ReconSat, Nop, Reconning, Nop, ReconSat, Nop, ReconClosing, Closein, Broken, Closefail, SendingSat, Start, Broken, Closefail, Disconned, Nop}, + + /* SENDING */ + {Sending, Nop, Sending, Nop, SendingSat, Nop, Closing, Closein, Disconning, Closeio, Sending, Nop, Reconning, Connect, Connected, Nop}, + + /* SENDINGSATURATED*/ + {SendingSat, Nop, Sending, Nop, SendingSat, Nop, Closing, Closein, Disconning, Closeio, SendingSat, Nop, ReconSat, Connect, Connected, Nop}, + + /* RESOLCLOSING */ + {ResClosing, Nop, ResClosing, Nop, ResClosing, Nop, ResClosing, Nop, Broken, Failall, Closing, Start, Unresable, Failall, ResClosing, Nop}, + + /* RECONCLOSING */ + {ReconClosing, Nop, ReconClosing, Nop, ReconClosing, Nop, ReconClosing, Nop, Broken, Failall, Closing, Start, Broken, Failall, ReconClosing, Nop}, + + /* CLOSING */ + {Closing, Nop, Closing, Nop, Closing, Nop, Closing, Nop, Disconning, Closeout, Closing, Nop, ReconClosing, Connect, Closed, Closeout}, + + /* DISCONNECTING */ + {Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Broken, Failall, Broken, Nop}, + + /* UNRESOLVABLE */ + {Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Closeout, Unresable, Nop, Unresable, Nop}, + + /* CLOSED */ + {Closed, Nop, Closed, Nop, Closed, Nop, Closed, Nop, Closed, Nop, Closed, Closeout, Closed, Nop, Closed, Nop}, + + /* BROKEN */ + {Broken, Nop, Broken, Nop, Broken, Nop, Broken, Nop, Broken, Nop, Broken, Closeout, Broken, Nop, Broken, Nop} + }; + + static { + // install the transitions map in its proper place. + Unresolved.init(INIT_TRANSITION_MAP[0]); + ResPending.init(INIT_TRANSITION_MAP[1]); + Resolving.init(INIT_TRANSITION_MAP[2]); + ResolSat.init(INIT_TRANSITION_MAP[3]); + Connected.init(INIT_TRANSITION_MAP[4]); + Disconned.init(INIT_TRANSITION_MAP[5]); + Reconning.init(INIT_TRANSITION_MAP[6]); + ReconSat.init(INIT_TRANSITION_MAP[7]); + Sending.init(INIT_TRANSITION_MAP[8]); + SendingSat.init(INIT_TRANSITION_MAP[9]); + ResClosing.init(INIT_TRANSITION_MAP[10]); + ReconClosing.init(INIT_TRANSITION_MAP[11]); + Closing.init(INIT_TRANSITION_MAP[12]); + Disconning.init(INIT_TRANSITION_MAP[13]); + Unresable.init(INIT_TRANSITION_MAP[14]); + Closed.init(INIT_TRANSITION_MAP[15]); + Broken.init(INIT_TRANSITION_MAP[16]); + } + } + + /** + * The current state! + */ + private volatile State state = null; + + /** + * Constructs a new messenger state machine. + *

      + * The transition map is static and we refer to it only to grab the first + * state. After that, states refer to each other. The only reason they are + * members in the map is so that we can make references during init. + * + * @param connected If true, the initial state is {@link Messenger#CONNECTED} otherwise {@link Messenger#UNRESOLVED}. + */ + protected MessengerState(boolean connected) { + + state = connected ? TransitionMap.Connected : TransitionMap.Unresolved; + } + + /** + * @return The current state. + */ + public int getState() { + // getState is always just a peek. It needs no sync. + return state.number; + } + + /** + * Event input. + */ + public void resolveEvent() { + Action a = state.acResolve; + + state = state.stResolve; + a.doIt(this); + } + + /** + * Message event + */ + public void msgsEvent() { + Action a = state.acMsgs; + + state = state.stMsgs; + a.doIt(this); + } + + /** + * Saturated Event + */ + public void saturatedEvent() { + Action a = state.acSaturated; + + state = state.stSaturated; + a.doIt(this); + } + + /** + * Close Event + */ + public void closeEvent() { + Action a = state.acClose; + + state = state.stClose; + a.doIt(this); + } + + /** + * Shutdown Event + */ + public void shutdownEvent() { + Action a = state.acShutdown; + + state = state.stShutdown; + a.doIt(this); + } + + /** + * Up Event + */ + public void upEvent() { + Action a = state.acUp; + + state = state.stUp; + a.doIt(this); + } + + /** + * Down Event + */ + public void downEvent() { + Action a = state.acDown; + + state = state.stDown; + a.doIt(this); + } + + /** + * Idle Event + */ + public void idleEvent() { + Action a = state.acIdle; + + state = state.stIdle; + a.doIt(this); + } + + /** + * Actions they're always called in sequence by event methods. + * + * Actions must not call event methods in sequence. + **/ + + /** + * Try to make a connection. Called whenever transitioning from a state that neither needs nor has a connection to a state + * that needs a connection and does not have it. Call upEvent when successful, or downEvent when failed. + */ + protected abstract void connectAction(); + + /** + * Start sending. Called whenever transitioning to a state that has both a connection and messages to send from a state that + * lacked either attributes. So, will be called after sending stopped due to broken cnx or idle condition. Call downEvent + * when stopping due to broken or closed connection, call {@link #idleEvent} when no pending message is left. + */ + protected abstract void startAction(); + + /** + * Reject new messages from now on. Called whenever transitioning from a state that is {@link Messenger#USABLE} to a state + * that is not. No event expected once done. + */ + protected abstract void closeInputAction(); + + /** + * Drain pending messages, all failed. Called once output is down and there are still pending messages. + * Call {@link #idleEvent} when done, as a normal result of no pending messages being left. + */ + protected abstract void failAllAction(); + + /** + * Force close output. Called whenever the underlying connection is to be discarded and never to be needed again. That is + * either because orderly close has completed, or shutdown is in progress. No event expected once done, but this action + * must cause any sending in progress to stop eventually. The fact that the sending has stopped must be reported as + * usual: either with a {@link #downEvent}, if the output closure caused the sending process to fail, or with an {@link + * #idleEvent} if the sending of the last message could be sent successfully despite the attempt at interrupting it. + *

      + * Sending is said to be in progress if, and only if, the last call to startAction is more recent than the last call to + * {@link #idleEvent} or {@link #downEvent}. + *

      + * It is advisable to also cancel an ongoing connect action, but not mandatory. If a {@link #connectAction} later succeeds, + * then {@link #upEvent} must be called as usual. This will result in another call to {@link #closeOutputAction}. + */ + protected abstract void closeOutputAction(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/OutgoingMessageEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/OutgoingMessageEvent.java new file mode 100644 index 000000000..47133f16d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/OutgoingMessageEvent.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +/** + * An event which provides notification of the the transmission status of an + * outgoing message. The source of the event is the Message object. + */ +public class OutgoingMessageEvent extends java.util.EventObject { + + // Two low-cost msg events for reporting to selectors: success does not require an exception. An exception is too expensive + // for overflow. The message component is useless for select but we need a dummy src in order to construct an Event. Note, + // to convert OVERFLOW or SUCCESS to listener-compatible events, clone them and set the message member. Other events are + // already all right. + public static final OutgoingMessageEvent SUCCESS = new OutgoingMessageEvent(); + public static final OutgoingMessageEvent OVERFLOW = new OutgoingMessageEvent(); + + private Throwable failure = null; + + /** + * Create an Outgoing Message Event with a dummy src (message + * is not specified because the event is a constant). + */ + public OutgoingMessageEvent() { + super("Unspecified"); + } + + /** + * Create an Outgoing Message Event. + * + * @param source the message for which the event is occurring. + */ + public OutgoingMessageEvent(Message source) { + super(source); + } + + /** + * Create an Outgoing Message Event. + * + * @param source The message for which the event is occurring. + * @param failure The failure associated with this event. + */ + public OutgoingMessageEvent(Message source, Throwable failure) { + super(source); + this.failure = failure; + } + + /** + * Get the failure associated with this event, if any. + * + * @return the Throwable associated with the failure, if any. + * null if there was no associated failure. + */ + public Throwable getFailure() { + return failure; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/OutgoingMessageEventListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/OutgoingMessageEventListener.java new file mode 100644 index 000000000..9b458e14e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/OutgoingMessageEventListener.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +/** + * A listener for events concerning the status of outgoing messages. + */ +public interface OutgoingMessageEventListener extends java.util.EventListener { + + /** + * The message identified by the event could not be sent. + *

      + * The cause of the failure, if any, is available from + * {@link OutgoingMessageEvent#getFailure()}. Failures while sending + * messages have several causes : + *

      + *

        + *
      • An {@link java.io.IOException} means that the messenger cannot + * send the message and the messenger will accept no further messages + * to be sent.
      • + *

        + *

      • A {@link java.lang.RuntimeException} mean that the message was + * not sent, but retries may or may not be possible based upon the + * status returned by {@link Messenger#isClosed()}.
      • + *

        + *

      • null means that the message was not sent, but may + * be retried. Usually the failure is due to local resource limits + * being exceeded. Attempts may be made to later resend the message, + * usually after waiting for congestion to clear.
      • + *
      + * @param event the event + */ + void messageSendFailed(OutgoingMessageEvent event); + + /** + * The message identified by the event was successfully sent. Successfully + * sending a message is not a guarantee that it will be successfully + * received by the destination. + * @param event the event + */ + void messageSendSucceeded(OutgoingMessageEvent event); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/StringMessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/StringMessageElement.java new file mode 100644 index 000000000..432542434 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/StringMessageElement.java @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + + +import net.jxta.document.MimeMediaType; +import net.jxta.logging.Logging; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.lang.ref.SoftReference; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A Message Element using character strings for the element data. + */ +public class StringMessageElement extends TextMessageElement { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(StringMessageElement.class.getName()); + + /** + * The MIME media type we will be use for encoding {@code String}s when no + * encoding is specified. + */ + private static final MimeMediaType DEFAULT_TEXT_ENCODING = new MimeMediaType(MimeMediaType.TEXT_DEFAULTENCODING, "charset=\"" + Charset.defaultCharset().name() + "\"", true).intern(); + + /** + * The data for this Message Element. + */ + protected String data; + + /** + * Returns an appropriate mime type for the given encoding name. The + * mimetype will contain the canonical name of the encoding. + * + * @param encoding name of the desired encoding. + * @return the mime type. + * @throws java.io.UnsupportedEncodingException + * if the mime is unsupported + */ + private static MimeMediaType makeMimeType(String encoding) throws UnsupportedEncodingException { + InputStreamReader getEncoding = new InputStreamReader(new ByteArrayInputStream(new byte[0]), encoding); + + String canonicalName = getEncoding.getEncoding(); + + return new MimeMediaType(MimeMediaType.TEXT_DEFAULTENCODING, "charset=\"" + canonicalName + "\"", true).intern(); + } + + /** + * Create a new Message Element from the provided String. The String will + * be encoded for transmission using UTF-8. + * + * @param name Name of the Element. May be the empty string ("") or null if + * the Element is not named. + * @param value A String containing the contents of this element. + * @param sig Message digest/digital signature element. If no signature is + * to be specified, pass null. + * @throws IllegalArgumentException if value is + * null. + */ + public StringMessageElement(String name, String value, MessageElement sig) { + super(name, MimeMediaType.TEXTUTF8, sig); + + if (null == value) { + throw new IllegalArgumentException("value must be non-null"); + } + + data = value; + } + + /** + * Create a new Message Element from the provided String. The string will + * be encoded for transmission using specified character encoding. + * + * @param name Name of the MessageElement. May be the empty string ("") or + * null if the MessageElement is not named. + * @param value A String containing the contents of this element. + * @param encoding Name of the character encoding to use. If + * null then the system default character encoding will be + * used. (Using the system default character encoding should be used with + * extreme caution). + * @param sig Message digest/digital signature element. If no signature is + * to be specified, pass null. + * @throws IllegalArgumentException if value is + * null. + * @throws UnsupportedEncodingException if the requested encoding is not + * supported. + */ + public StringMessageElement(String name, String value, String encoding, MessageElement sig) throws UnsupportedEncodingException { + super(name, (null == encoding) ? DEFAULT_TEXT_ENCODING : makeMimeType(encoding), sig); + + if (null == value) { + throw new IllegalArgumentException("value must be non-null"); + } + + data = value; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof MessageElement) { + if (!super.equals(target)) { + return false; + } + + if (target instanceof StringMessageElement) { + StringMessageElement likeMe = (StringMessageElement) target; + + return data.equals(likeMe.data); // same chars? + } else if (target instanceof TextMessageElement) { + // have to do a slow char by char comparison. Still better than the stream since it saves encoding. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + + TextMessageElement likeMe = (TextMessageElement) target; + + try { + Reader myReader = getReader(); + Reader itsReader = likeMe.getReader(); + + int mine; + int its; + + do { + mine = myReader.read(); + its = itsReader.read(); + + if (mine != its) { + return false; + } // content didn't match + + } while ((-1 != mine) && (-1 != its)); + + return ((-1 == mine) && (-1 == its)); // end at the same time? + } catch (IOException fatal) { + IllegalStateException failure = new IllegalStateException("MessageElements could not be compared."); + + failure.initCause(fatal); + throw failure; + } + } else { + // have to do a slow stream comparison. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + + MessageElement likeMe = (MessageElement) target; + + try { + InputStream myStream = getStream(); + InputStream itsStream = likeMe.getStream(); + + int mine; + int its; + + do { + mine = myStream.read(); + its = itsStream.read(); + + if (mine != its) { + return false; + } // content didn't match + + } while ((-1 != mine) && (-1 != its)); + + return ((-1 == mine) && (-1 == its)); // end at the same time? + } catch (IOException fatal) { + IllegalStateException failure = new IllegalStateException("MessageElements could not be compared."); + + failure.initCause(fatal); + throw failure; + } + } + } + + return false; // not a new message element + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = super.hashCode() * 6037 + // a prime + data.hashCode(); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return data; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized byte[] getBytes(boolean copy) { + byte[] cachedBytes = null; + + if (null != cachedGetBytes) { + cachedBytes = cachedGetBytes.get(); + } + + if (null == cachedBytes) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Creating getBytes of " + getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(this))); + } + + String charset = type.getParameter("charset"); + + try { + cachedBytes = data.getBytes(charset); + } catch (UnsupportedEncodingException caught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "MessageElement Data could not be generated", caught); + } + IllegalStateException failure = new IllegalStateException("MessageElement Data could not be generated"); + + failure.initCause(caught); + throw failure; + } + + cachedGetBytes = new SoftReference(cachedBytes); + } + + if (!copy) { + return cachedBytes; + } + + byte[] bytesCopy = cachedBytes.clone(); + + return bytesCopy; + } + + /** + * {@inheritDoc} + */ + @Override + public long getCharLength() { + return data.length(); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized char[] getChars(boolean copy) { + char[] cachedChars = null; + + if (null != cachedGetChars) { + cachedChars = cachedGetChars.get(); + } + + if (null == cachedChars) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("creating cachedGetChars of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + cachedChars = new char[data.length()]; + + data.getChars(0, data.length(), cachedChars, 0); + + // if this is supposed to be a shared buffer then we can cache it. + + cachedGetChars = new SoftReference(cachedChars); + } + + if (!copy) { + return cachedChars; + } + + char[] copyChars = cachedChars.clone(); + + return copyChars; + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + byte cachedBytes[] = null; + + synchronized (this) { + if (null != cachedGetBytes) { + cachedBytes = cachedGetBytes.get(); + } + } + + if (null != cachedBytes) { + return new ByteArrayInputStream(cachedBytes); + } else { + String charset = type.getParameter("charset"); + return new CharSequenceInputStream(data, charset); + } + } + + /** + * {@inheritDoc} + * + * @return InputStream of the stream containing element data. + * @throws IOException when there is a problem getting a reader. + */ + public Reader getReader() throws IOException { + + return new StringReader(data); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendToStream(OutputStream sendTo) throws IOException { + + sendTo.write(getBytes(false)); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendToWriter(Writer sendTo) throws IOException { + sendTo.write(data); + } + + /** + * + **/ + private static class CharSequenceInputStream extends InputStream { + + private final CharBuffer charData; + + private final CharsetEncoder conversion; + + private boolean marked = false; + private byte mark_multiByteChar[]; + private int mark_position; + + private byte multiByteChar[]; + private int position; + + /** + * @param s the char sequence + * @param encoding the charset encoding + */ + CharSequenceInputStream(CharSequence s, String encoding) { + charData = CharBuffer.wrap(s); + + Charset encodingCharset = Charset.forName(encoding); + + conversion = encodingCharset.newEncoder(); + conversion.onMalformedInput(CodingErrorAction.REPLACE); + conversion.onUnmappableCharacter(CodingErrorAction.REPLACE); + + int maxBytes = new Float(conversion.maxBytesPerChar()).intValue(); + + multiByteChar = new byte[maxBytes]; + position = multiByteChar.length; + } + + /** + * {@inheritDoc} + */ + @Override + public void mark(int ignored) { + charData.mark(); + mark_multiByteChar = multiByteChar.clone(); + mark_position = position; + marked = true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean markSupported() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void reset() throws IOException { + + if (!marked) { + throw new IOException("reset() called before mark()"); + } + + charData.reset(); + multiByteChar = mark_multiByteChar.clone(); + position = mark_position; + } + + /** + * {@inheritDoc} + */ + @Override + public int read() throws IOException { + // prefill the buffer + while (multiByteChar.length == position) { + int readsome = read(multiByteChar, 0, multiByteChar.length); + + if (-1 == readsome) { + return -1; + } + + position = multiByteChar.length - readsome; + + if ((0 != position) && (0 != readsome)) { + System.arraycopy(multiByteChar, 0, multiByteChar, position, readsome); + } + } + + return (multiByteChar[position++] & 0xFF); + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] buffer) throws IOException { + return read(buffer, 0, buffer.length); + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] buffer, int offset, int length) throws IOException { + // handle partial characters; + if (multiByteChar.length != position) { + int copying = Math.min(length, multiByteChar.length - position); + + System.arraycopy(multiByteChar, position, buffer, offset, copying); + position += copying; + return copying; + } + + ByteBuffer bb = ByteBuffer.wrap(buffer, offset, length); + + int before = bb.remaining(); + + CoderResult result = conversion.encode(charData, bb, true); + + int readin = before - bb.remaining(); + + if (CoderResult.UNDERFLOW == result) { + if (0 == readin) { + return -1; + } else { + return readin; + } + } + + if (CoderResult.OVERFLOW == result) { + return readin; + } + + result.throwException(); + + // NEVERREACHED + return 0; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/TextDocumentMessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/TextDocumentMessageElement.java new file mode 100644 index 000000000..763c257d8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/TextDocumentMessageElement.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + + +import net.jxta.document.MimeMediaType; +import net.jxta.document.TextDocument; +import net.jxta.logging.Logging; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.lang.ref.SoftReference; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A Message Element using JXTA TextDocument for the element data. + */ +public class TextDocumentMessageElement extends TextMessageElement { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(TextDocumentMessageElement.class.getName()); + + /** + * The data for this element. + */ + protected TextDocument doc; + + /** + * Create a new Message Element from the provided Document. + * + * @param name Name of the Element. May be the empty string ("") or null if + * the Element is not named. + * @param doc A Document containing the contents of this element. + * @param sig optional message digest/digital signature elemnent. If + * no signature is to be specified, pass null. + */ + public TextDocumentMessageElement(String name, TextDocument doc, MessageElement sig) { + super(name, doc.getMimeType(), sig); + + this.doc = doc; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof MessageElement) { + if (!super.equals(target)) { + return false; + } + + if (target instanceof TextMessageElement) { + // have to do a slow char by char comparison. Still better than the stream since it saves encoding. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + + TextMessageElement likeMe = (TextMessageElement) target; + + try { + Reader myReader = getReader(); + Reader itsReader = likeMe.getReader(); + + int mine; + int its; + + do { + mine = myReader.read(); + its = itsReader.read(); + + if (mine != its) { + return false; + } // content didn't match + + } while ((-1 != mine) && (-1 != its)); + + return ((-1 == mine) && (-1 == its)); // end at the same time? + } catch (IOException fatal) { + throw new IllegalStateException("MessageElements could not be compared." + fatal); + } + } else { + // have to do a slow stream comparison. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + + MessageElement likeMe = (MessageElement) target; + + try { + InputStream myStream = getStream(); + InputStream itsStream = likeMe.getStream(); + + int mine; + int its; + + do { + mine = myStream.read(); + its = itsStream.read(); + + if (mine != its) { + return false; + } // content didn't match + + } while ((-1 != mine) && (-1 != its)); + + return ((-1 == mine) && (-1 == its)); // end at the same time? + } catch (IOException fatal) { + throw new IllegalStateException("MessageElements could not be compared." + fatal); + } + } + } + + return false; // not a new message element + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = super.hashCode() * 6037 + // a prime + toString().hashCode(); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized String toString() { + String result; + + if (null != cachedToString) { + result = cachedToString.get(); + + if (null != result) { + return result; + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("creating toString of " + getClass().getName() + "@" + super.hashCode()); + } + + result = doc.toString(); + cachedToString = new SoftReference(result); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public MimeMediaType getMimeType() { + return doc.getMimeType(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getFileExtension() { + return doc.getFileExtension(); + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + byte[] sending = getBytes(false); + + return new ByteArrayInputStream(sending); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendToStream(OutputStream sendTo) throws IOException { + + byte[] sending = getBytes(false); + + sendTo.write(sending, 0, sending.length); + } + + /** + * {@inheritDoc} + */ + public Reader getReader() throws IOException { + + return doc.getReader(); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendToWriter(Writer sendTo) throws IOException { + doc.sendToWriter(sendTo); + } + + /** + * {@inheritDoc} + */ + @Override + public byte[] getBytes(boolean copy) { + byte[] result; + + if (null != cachedGetBytes) { + result = cachedGetBytes.get(); + + if (null != result) { + if (copy) { + byte[] theCopy = new byte[result.length]; + + System.arraycopy(theCopy, 0, result, 0, result.length); + } else { + return result; + } + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("creating getBytes of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + String charset = type.getParameter("charset"); + + if (null == charset) { + result = toString().getBytes(); + } else { + try { + result = toString().getBytes(charset); + } catch (UnsupportedEncodingException caught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "MessageElement Data could not be generated", caught); + } + throw new IllegalStateException("MessageElement Data could not be generated due to " + caught.getMessage()); + } + } + + // if this is supposed to be a shared buffer then we can cache it. + if (!copy) { + cachedGetBytes = new SoftReference(result); + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public long getCharLength() { + return toString().length(); + } + + /** + * {@inheritDoc} + */ + @Override + public char[] getChars(boolean copy) { + char[] result; + + if (null != cachedGetChars) { + result = cachedGetChars.get(); + + if (null != result) { + if (copy) { + char[] theCopy = new char[result.length]; + + System.arraycopy(theCopy, 0, result, 0, result.length); + } else { + return result; + } + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("creating getChars of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + String asString = toString(); + + result = asString.toCharArray(); + + // if this is supposed to be a shared buffer then we can cache it. + if (!copy) { + cachedGetChars = new SoftReference(result); + } + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/TextMessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/TextMessageElement.java new file mode 100644 index 000000000..4f866a1d3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/TextMessageElement.java @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + + +import net.jxta.document.MimeMediaType; +import net.jxta.document.TextDocument; +import net.jxta.logging.Logging; +import net.jxta.util.CountingWriter; +import net.jxta.util.DevNullWriter; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.ref.SoftReference; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * An extension of MessageElement for managing elements that are composed of + * character text. (as opposed to raw bytes). + *

      + * The data contained within a {@code TextMessageElement} is accessible in three + * additional ways to those provided by {@code MessageElement} : + *

      + *

        + *
      • As an {@link java.io.Reader} from {@link #getReader()}
      • + *
      • Sending the data a {@link java.io.Writer} via {@link #sendToWriter(Writer)}
      • + *
      • As a char array from from {@link #getChars(boolean)}
      • + *
      + * + */ +public abstract class TextMessageElement extends MessageElement implements TextDocument { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(TextMessageElement.class.getName()); + + /** + * cached result of {@link #getCharLength()} operation. + */ + protected transient long cachedGetCharLength = -1; + + /** + * cached result of {@link #getBytes(boolean)} operation. + */ + protected transient SoftReference cachedGetChars = null; + + /** + * Internal constructor for initializaing everything but the data. + * + * @param name Name of the Element. May be the empty string ("") if + * the Element is not named. + * @param type Type of the Element. null is equivalent to specifying + * the type "Application/Octet-stream" + * @param sig optional message digest/digital signature elemnent. If + * no signature is to be specified, pass null. + */ + protected TextMessageElement(String name, MimeMediaType type, MessageElement sig) { + super(name, type, sig); + } + + /** + * {@inheritDoc} + *

      + * synchronized for caching purposes. + */ + @Override + public synchronized String toString() { + String result; + + if (null != cachedToString) { + result = cachedToString.get(); + + if (null != result) { + return result; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("creating toString of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + StringBuilder theString = new StringBuilder(); + + try { + Reader asString = getReader(); + char[] characters = new char[256]; + + do { + int res = asString.read(characters); + + if (res < 0) { + break; + } + + theString.append(characters, 0, res); + } while (true); + + result = theString.toString(); + + cachedToString = new SoftReference(result); + return result; + } catch (IOException caught) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not generate string for element. ", caught); + } + + throw new IllegalStateException("Could not generate string for element. " + caught); + } + } + + /** + * {@inheritDoc} + *

      + * We use the "text" extension and leave it to sub-classes to extend + * this. + */ + @Override + public String getFileExtension() { + return "txt"; + } + + /** + * Returns the size of the element data in characters + *

      + * synchronized for caching purposes. + * + * @return long containing the size of the element data. + */ + public synchronized long getCharLength() { + if (cachedGetCharLength >= 0) { + return cachedGetCharLength; + } + + CountingWriter countChars = new CountingWriter(new DevNullWriter()); + + try { + sendToWriter(countChars); + cachedGetByteLength = countChars.getCharsWritten(); + return cachedGetByteLength; + } catch (IOException caught) { + throw new IllegalStateException("Could not get length of element : " + caught.toString()); + } + } + + /** + * Returns a char array which contains the element data. The char array + * returned may be shared amongst all copies of the element, + * do not modify it. The copy parameter allows you to request a + * private, modifiable copy of the element data. + *

      + * synchronized for caching purposes. + * + * @param copy return a copy if true + * @return char[] Contents of message element. + */ + public synchronized char[] getChars(boolean copy) { + char[] result; + + if (null != cachedGetChars) { + result = cachedGetChars.get(); + + if (null != result) { + if (copy) { + char[] theCopy = new char[result.length]; + + System.arraycopy(theCopy, 0, result, 0, result.length); + } else { + return result; + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("creating getChars of " + getClass().getName() + '@' + Integer.toHexString(hashCode())); + } + + long len = getCharLength(); + + if (len > Integer.MAX_VALUE) { + throw new IllegalStateException("MessageElement is too large to be stored in a char array."); + } + + result = new char[(int) len]; + + try { + Reader reader = getReader(); + + int toRead = (int) len; + int offset = 0; + + do { + int read = reader.read(result, offset, toRead); + + if (-1 == read) { + break; + } + + toRead -= read; + offset += read; + } while (toRead < len); + + if (toRead != 0) { + IOException failure = new IOException("Unexpected EOF"); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failure.getMessage(), failure); + } + + throw failure; + } + } catch (IOException caught) { + IllegalStateException failure = new IllegalStateException("Failed to get bytes of Message Element"); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failure.getMessage(), caught); + } + throw failure; + } + + // if this is supposed to be a shared buffer then we can cache it. + if (!copy) { + cachedGetChars = new SoftReference(result); + } + + return result; + } + + /** + * {@inheritDoc} + *

      + * This version probably has sub-optimal performance. Sub-classes + * should override this implementation if possible. + */ + public void sendToWriter(Writer sendTo) throws IOException { + copyReaderToWriter(getReader(), sendTo); + } + + /** + * Copies a reader to a writer with buffering. + * + * @param source The reader to copy from. + * @param sink The writer to send the data to. + * @throws IOException if there is a problem copying the data + */ + private void copyReaderToWriter(Reader source, Writer sink) throws IOException { + int c; + char[] buf = new char[4096]; + + do { + c = source.read(buf); + + if (-1 == c) { + break; + } + + sink.write(buf, 0, c); + } while (true); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ThreadedMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ThreadedMessenger.java new file mode 100644 index 000000000..995c7570d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/ThreadedMessenger.java @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroupID; + +import java.io.IOException; +import java.util.WeakHashMap; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This is a messenger meant to be shared by multiple channels and automatically + * distribute the available bandwidth among the channels. This one is implemented + * with a dedicated background thread. + */ +public abstract class ThreadedMessenger extends AbstractMessenger implements Runnable { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ThreadedMessenger.class.getName()); + + /** + * Our thread group. + */ + private final static transient ThreadGroup myThreadGroup = new ThreadGroup("Threaded Messengers"); + + /** + * The logical destination address of the other party (if we know it). + */ + private volatile EndpointAddress logicalDestination = null; + + /** + * true if we have deliberately closed our input queue. + */ + private volatile boolean inputClosed = false; + + /** + * Need to know which group the transports we use live in, so that we can suppress channel redirection when in the same group. + * This is currently the norm. + */ + private PeerGroupID homeGroupID = null; + + /** + * The duration in milliseconds which the background thread will remain + * idle before quitting. + */ + private static final long THREAD_IDLE_DEAD = 15000; + + /* + * Actions that we defer to after returning from event methods. In other + * words, they cannot be done with the lock held, or they require calling + * more event methods. Because this messenger can take only one message at a + * time, actions do not cascade much. It may happen that the invoking thread + * is required to perform closure after performing send. That's about it. + * In addition, there's always only one deferred action per event. The only + * actions that cluster are closeInput and closeOutput. We do not defer + * those. + */ + private enum DeferredAction { + + /** + * No action deferred. + */ + ACTION_NONE, + + /** + * Must send the current message. + */ + ACTION_SEND, + + /** + * Must report failure to connect. + */ + ACTION_CONNECT + } + + /** + * The current deferred action. + */ + private DeferredAction deferredAction = DeferredAction.ACTION_NONE; + + /** + * The current background thread. + */ + private volatile Thread bgThread = null; + + /** + * The number of messages which may be queued for in each channel. + */ + private final int channelQueueSize; + + /** + * The active channel queue. + */ + private final BlockingQueue activeChannels = new LinkedBlockingQueue(); + + /** + * The resolving channels set. This is unordered. We use a weak hash map because abandoned channels could otherwise + * accumulate in-there until the resolution attempt completes. A buggy application could easily do much damage. + *

      + * Note: a channel with at least one message in it is not considered abandoned. To prevent it from disappearing we set a + * strong reference as the value in the map. A buggy application can do great damage, still, by queuing a single message + * and then abandoning the channel. This is has to be dealt with at another level; limiting the number of channels + * per application, or having a global limit on messages...TBD. + */ + private final WeakHashMap resolvingChannels = new WeakHashMap(4); + + /** + * A default channel where we put messages that are send directly through + * this messenger rather than via one of its channels. + */ + private ThreadedMessengerChannel defaultChannel = null; + + /** + * State lock and engine. + */ + private final ThreadedMessengerState stateMachine = new ThreadedMessengerState(); + + /** + * The implementation of channel messenger that getChannelMessenger returns: + */ + private class ThreadedMessengerChannel extends AsyncChannelMessenger { + + public ThreadedMessengerChannel(EndpointAddress baseAddress, PeerGroupID redirection, String origService, String origServiceParam, int queueSize, boolean connected) { + super(baseAddress, redirection, origService, origServiceParam, queueSize, connected); + } + + /** + * {@inheritDoc} + *

      + * We're supposed to return the complete destination, including + * service and param specific to that channel. It is not clear, whether + * this should include the cross-group mangling, though. Historically, + * it does not. + */ + public EndpointAddress getLogicalDestinationAddress() { + return logicalDestination; + } + + /** + * {@inheritDoc} + */ + @Override + protected void startImpl() { + if (!addToActiveChannels(this)) { + // We do not need to hold our lock to call this, and it is just as well since it could re-enter. + down(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void connectImpl() { + + // If it cannot be done, it is because we known that we will never be able to generate the resulting event. That means + // that either the shared messenger is already resolved, or that it is already dead. In that case, we invoke down/up + // in sequence accordingly. + // + // NOTE: the shared messenger may become dead 1 ns from now...that or 1 hour makes no difference, the channel will + // notice when it first tries to send, in that case. The otherway around is more obvious: If the shared messenger is + // not USABLE, it cannot come back. + // + // addToResolvingChannels() garantees us that if it returns true, either of the channel's down or up methods will be + // invoked at some point. + + if (!addToResolvingChannels(this)) { + if ((ThreadedMessenger.this.getState() & USABLE) != 0) { + up(); + } else { + down(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void resolPendingImpl() { + // If this channel is still among the ones pending resolution, make sure + // it becomes strongly referenced. + strongRefResolvingChannel(this); + } + + } + + + /** + * Our statemachine implementation; just connects the standard AbstractMessengerState action methods to + * this object. + */ + private class ThreadedMessengerState extends MessengerState { + + protected ThreadedMessengerState() { + super(false); + } + + /* + * The required action methods. + */ + + /** + * {@inheritDoc} + */ + @Override + protected void connectAction() { + deferAction(DeferredAction.ACTION_CONNECT); + } + + /** + * {@inheritDoc} + */ + @Override + protected void startAction() { + deferAction(DeferredAction.ACTION_SEND); + } + + /** + * {@inheritDoc} + *

      + * This is a synchronous action. The state machine assumes that it + * is done when we return. There is No need (nor means) to signal + * completion. No need for synchronization either: we're already + * synchronized. + */ + @Override + protected void closeInputAction() { + inputClosed = true; + ThreadedMessengerChannel[] channels = resolvingChannels.keySet().toArray(new ThreadedMessengerChannel[0]); + + resolvingChannels.clear(); + int i = channels.length; + + while (i-- > 0) { + channels[i].down(); + } + channels = null; + } + + /** + * {@inheritDoc} + */ + @Override + protected void closeOutputAction() { + // This will break the cnx; thereby causing a down event if we have a send in progress. + // If the cnx does not break before the current message is sent, then the message will be sent successfully, + // resulting in an idle event. Either of these events is enough to complete the shutdown process. + closeImpl(); + } + + /** + * {@inheritDoc} + *

      + * The input is now closed, so we can rest assured that the last + * channel is really the last one. + * This is a synchronous action. The state machine assumes that it is + * done when we return. There is no need to signal completion with an + * idleEvent. + * No need for synchronization either: we're already synchronized. + */ + @Override + protected void failAllAction() { + + while (true) { + ThreadedMessengerChannel theChannel; + + theChannel = activeChannels.poll(); + if (theChannel == null) { + break; + } + theChannel.down(); + } + } + } + + /** + * Create a new ThreadedMessenger. + * + * @param homeGroupID the group that this messenger works for. This is the group of the endpoint service or transport + * that created this messenger. + * @param destination where messages should be addressed to + * @param logicalDestination the expected logical address of the destination. Pass null if unknown/irrelevant + * @param channelQueueSize The queue size that channels should have. + */ + public ThreadedMessenger(PeerGroupID homeGroupID, EndpointAddress destination, EndpointAddress logicalDestination, int channelQueueSize) { + + super(destination); + + this.homeGroupID = homeGroupID; + + // We tell our super class that we synchronize our state on the stateMachine object. Logic would dictate + // that we pass it to super(), but it is not itself constructed until super() returns. No way around it. + + setStateLock(stateMachine); + + this.logicalDestination = logicalDestination; + this.channelQueueSize = channelQueueSize; + } + + /** + * Runs the state machine until there's nothing left to do. + *

      + * Three exposed methods may need to inject new events in the system: sendMessageN, close, and shutdown. Since they can both + * cause actions, and since connectAction and startAction are deferred, it seems possible that one of the + * actions caused by send, close, or shutdown be called while connectAction or startAction are in progress. + *

      + * However, the state machine gives us a few guarantees: All the actions except closeInput and closeOutput have an *end* + * event. No state transition that results in an action other than closeInput or closeOutput, may occur until the end event + * for an on-going action has been called. + *

      + * We perform closeInput and closeOutput on the fly, so none of the exposed methods are capable of producing deferred actions + * while an action is already deferred. So, there is at most one deferred action after returning from an event method, + * regardless the number of concurrent threads invoking the exposed methods, and it can only happen once per deferred action + * performed. + */ + public void run() { + + try { + while (true) { + switch (nextAction()) { + case ACTION_NONE: + return; + + case ACTION_SEND: + send(); + break; + + case ACTION_CONNECT: + connect(); + break; + } + } + } catch (Throwable any) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught throwable in background thread", any); + // Hope the next thread has more luck. It'll need it. + } + } finally { + synchronized (stateMachine) { + bgThread = null; + } + } + } + + private void deferAction(DeferredAction action) { + deferredAction = action; + + if (bgThread == null) { + bgThread = new Thread(myThreadGroup, this, "ThreadedMessenger for " + getDestinationAddress()); + bgThread.setDaemon(true); + bgThread.start(); + } + } + + private DeferredAction nextAction() { + + long quitAt = System.currentTimeMillis() + THREAD_IDLE_DEAD; + + synchronized (stateMachine) { + while (deferredAction == DeferredAction.ACTION_NONE) { + // Still nothing to do. Is it time to quit, or where we just awakened for nothing ? + if (System.currentTimeMillis() > quitAt) { + // Ok. Time to quit. + return DeferredAction.ACTION_NONE; + } + + // We do not need to wakeup exactly on the deadline, so there's no need to + // recompute the deadline. THREAD_IDLE_DEAD is comparatively short. + try { + stateMachine.wait(THREAD_IDLE_DEAD); + } catch (InterruptedException ie) { + // Only shutdown can force termination. + Thread.interrupted(); + } + } + + DeferredAction action = deferredAction; + + deferredAction = DeferredAction.ACTION_NONE; + return action; + } + } + + /** + * Performs the ACTION_SEND deferred action: sends the messages in our channel queues until there's none left or + * we are forced to stop by connection breakage. + * @throws InterruptedException if interrupted + */ + private void send() throws InterruptedException { + + ThreadedMessengerChannel theChannel; + + synchronized (stateMachine) { + theChannel = activeChannels.peek(); + if (theChannel == null) { + // No notifyChange: this is defensive code. NotifyChange() should have been called already. + stateMachine.idleEvent(); + stateMachine.notifyAll(); + return; + } + } + + while (true) { + AsyncChannelMessenger.PendingMessage theMsg = theChannel.peek(); + + if (theMsg == null) { + // done with that channel for now. (And it knows it). Move to the next channel. Actually + // it should have been removed when we popped the last message, except if we went down upon sending it. + // In that later case, we leave the channel queue as is so that we cannot have to report, idle + // in the same time than down. + synchronized (stateMachine) { + activeChannels.poll(); + theChannel = activeChannels.peek(); + if (theChannel != null) { + continue; // Nothing changes; we do not call msgsEvent because we never call saturatedEvent either. + } + // Done with all channels. We're now idle. + + stateMachine.idleEvent(); + stateMachine.notifyAll(); + } + notifyChange(); + return; + } + + Message currentMsg = theMsg.msg; + String currentService = theMsg.service; + String currentParam = theMsg.param; + + try { + sendMessageBImpl(currentMsg, currentService, currentParam); + } catch (Throwable any) { + + // When the current message fails, we leave it in there. sendMessageBImpl does not report failures. So that we can retry if + // applicable. It is up to us to report failures. See failall in AsyncChannel. However, there is a risk that a bad + // message causes this messenger to go down repeatedly. We need some kind of safeguard. So, if there's already a failure + // recorded for this message, we bounce it. + synchronized (stateMachine) { + if (theMsg.failure != null) { + theChannel.poll(); + currentMsg.setMessageProperty(Messenger.class, new OutgoingMessageEvent(currentMsg, theMsg.failure)); + } else { + theMsg.failure = any; + } + stateMachine.downEvent(); + stateMachine.notifyAll(); + } + notifyChange(); + return; + } + + synchronized (stateMachine) { + // Remove the message sent + theChannel.poll(); + // Rotate the queues (Things are quite a bit simpler if there's a single still active channel + // and it's frequent, so it's worth checking) + boolean empty = (theChannel.peek() == null); + + if ((activeChannels.size() != 1) || empty) { + activeChannels.poll(); + if (!empty) { + // We're not done with that channel. Put it back at the end + activeChannels.put(theChannel); + } + + // Get the next channel. + theChannel = activeChannels.peek(); + if (theChannel == null) { + // Done with all channels. We're now idle. + stateMachine.idleEvent(); + stateMachine.notifyAll(); + } + } // else {continue to use the current channel} + } + + if (theChannel == null) { + notifyChange(); + // We're about to go wait(). Yielding is a good bet. It is + // very inexpenssive and may be all it takes to get a new job + // queued. + Thread.yield(); + return; + } + } + } + + /** + * Performs the ACTION_CONNECT deferred action. Generates a down event if it does not work. + */ + private void connect() { + boolean worked = connectImpl(); + ThreadedMessengerChannel[] channels = null; + + synchronized (stateMachine) { + if (worked) { + + // we can now get the logical destination from the underlying implementation (likely obtained from a transport + // messenger) + + EndpointAddress effectiveLogicalDest = getLogicalDestinationImpl(); + + if (logicalDestination == null) { + // We did not know what was supposed to be on the other side. Anything will do. + logicalDestination = effectiveLogicalDest; + stateMachine.upEvent(); + channels = resolvingChannels.keySet().toArray(new ThreadedMessengerChannel[0]); + resolvingChannels.clear(); + } else if (logicalDestination.equals(effectiveLogicalDest)) { + // Good. It's what we expected. + stateMachine.upEvent(); + + channels = resolvingChannels.keySet().toArray(new ThreadedMessengerChannel[0]); + resolvingChannels.clear(); + } else { + // Ooops, not what we wanted. Can't connect then. (force close the underlying cnx). + closeImpl(); + stateMachine.downEvent(); + } + + } else { + stateMachine.downEvent(); + } + stateMachine.notifyAll(); + } + + // If it worked, we need to tell all the channels that were waiting for resolution. + // If it did not work, the outcome depends upon what will happen after the down event. + // It's ok to do that outside of sync. Channel.up may synchronize, but it never calls + // this class while synchronized. + if (channels != null) { + + int i = channels.length; + + while (i-- > 0) { + channels[i].up(); + } + channels = null; + } + + notifyChange(); + } + + /* + * Messenger API top level methods. + */ + + /** + * The endpoint service may call this to cause an orderly closure of its messengers. + */ + protected final void shutdown() { + synchronized (stateMachine) { + stateMachine.shutdownEvent(); + stateMachine.notifyAll(); + } + notifyChange(); + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getLogicalDestinationAddress() { + + // If it's not resolved, we can't know what the logical destination is, unless we had an expectation. + // And if we had, the messenger will fail as soon as we discover that the expectation is wrong. + // In most if not all cases, either we have an expectation, or the messenger comes already resolved. + // Otherwise, if you need the logical destination, you must resolve first. We do not want this method + // to be blocking. + return logicalDestination; + } + + /** + * {@inheritDoc} + */ + public void close() { + synchronized (stateMachine) { + stateMachine.closeEvent(); + stateMachine.notifyAll(); + } + notifyChange(); + } + + /** + * {@inheritDoc} + *

      + * In this case, this method is here out of principle but is not really expected to be invoked. The normal way + * of using a ThreadedMessenger is through its channels. We do provide a default channel that all invokers that go around + * channels will share. That could be useful to send rare out of band messages for example. + */ + public final boolean sendMessageN(Message msg, String service, String serviceParam) { + + synchronized (stateMachine) { + if (defaultChannel == null) { + // Need a default channel. + defaultChannel = new ThreadedMessengerChannel(getDestinationAddress(), null, null, null, channelQueueSize, false); + } + } + + return defaultChannel.sendMessageN(msg, service, serviceParam); + } + + /** + * {@inheritDoc} + */ + public final void sendMessageB(Message msg, String service, String serviceParam) throws IOException { + + synchronized (stateMachine) { + if (defaultChannel == null) { + // Need a default channel. + defaultChannel = new ThreadedMessengerChannel(getDestinationAddress(), null, null, null, channelQueueSize, false); + } + } + + defaultChannel.sendMessageB(msg, service, serviceParam); + } + + private boolean addToActiveChannels(ThreadedMessengerChannel channel) { + + synchronized (stateMachine) { + if (inputClosed) { + return false; + } + + try { + activeChannels.put(channel); + } catch (InterruptedException failed) { + Thread.interrupted(); + return false; + } + + // There are items in the queue now. + stateMachine.msgsEvent(); + + // We called an event. The state may have changed. Notify waiters. + stateMachine.notifyAll(); + } + + notifyChange(); + + return true; + } + + private void strongRefResolvingChannel(ThreadedMessengerChannel channel) { + + // If, and only if, this channel is already among the resolving channels, add a strong ref + // to it. This is invoked when a message is queued to that channel while it is still + // resolving. However we must verify its presence in the resolvingChannels map: this method + // may be called while the channel has been removed from the list, but has not been told + // yet. + synchronized (stateMachine) { + if (resolvingChannels.containsKey(channel)) { + resolvingChannels.put(channel, channel); + } + } + } + + private boolean addToResolvingChannels(ThreadedMessengerChannel channel) { + + synchronized (stateMachine) { + // If we're in a state where no resolution event will ever occur, we must not add anything to the list. + if ((stateMachine.getState() & (RESOLVED | TERMINAL)) != 0) { + return false; + } + + // We use the weak map only for the weak part, not for the map part. + resolvingChannels.put(channel, null); + + stateMachine.resolveEvent(); + stateMachine.notifyAll(); + } + + notifyChange(); + return true; + } + + /** + * {@inheritDoc} + */ + public final void resolve() { + synchronized (stateMachine) { + stateMachine.resolveEvent(); + stateMachine.notifyAll(); + } + notifyChange(); + } + + /** + * {@inheritDoc} + */ + public final int getState() { + return stateMachine.getState(); + } + + /** + * {@inheritDoc} + */ + public Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam) { + + // Our transport is always in the same group. If the channel's target group is the same, no group + // redirection is ever needed. + // are we happily resolved ? + return new ThreadedMessengerChannel(getDestinationAddress(), homeGroupID.equals(redirection) ? null : redirection, service, + serviceParam, channelQueueSize, (stateMachine.getState() & (RESOLVED & USABLE)) != 0); + } + + /* + * Abstract methods to be provided by implementor. These are fully expected + * to be blocking and may be implemented by invoking transport blocking + * methods, such as EndpointServiceImpl.getLocalTransportMessenger() or + * whateverTransportMessengerWasObtained.sendMessageB(). Should the + * underlying code be non-blocking, these impl methods must simulate it. If + * it's not obvious to do, then this base class is not a good choice. + */ + + /** + * {@inheritDoc} + */ + protected abstract void closeImpl(); + + /** + * Make underlying connection. + * + * @return true if successful + */ + protected abstract boolean connectImpl(); + + /** + * Send a message blocking as needed until the message is sent. + * + * @param msg The message to send. + * @param service The destination service. + * @param param The destination serivce param. + * @throws IOException Thrown for errors encountered while sending the message. + */ + protected abstract void sendMessageBImpl(Message msg, String service, String param) throws IOException; + + /** + * {@inheritDoc} + */ + protected abstract EndpointAddress getLogicalDestinationImpl(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/WireFormatMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/WireFormatMessage.java new file mode 100644 index 000000000..e28c3297d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/WireFormatMessage.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.endpoint; + + +import java.nio.ByteBuffer; +import net.jxta.document.Document; +import net.jxta.document.DocumentByteBufferIO; +import net.jxta.document.MimeMediaType; + + +/** + * A wire serialization of an abstract message. + * + * @see net.jxta.endpoint.Message + * @see net.jxta.endpoint.WireFormatMessageFactory + */ +public interface WireFormatMessage extends Document, DocumentByteBufferIO { + + /** + * Returns the encoding used for this content. May be {@code null} for + * unencoded (raw) content. + * + * @return The encoding used for this message. + */ + MimeMediaType getContentEncoding(); + + /** + * Returns the size of the serialized and encoded form of the message in bytes. + * + * @return The size of the serialized and encoded message in bytes. + */ + long getByteLength(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/WireFormatMessageFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/WireFormatMessageFactory.java new file mode 100644 index 000000000..707fc0fa6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/WireFormatMessageFactory.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.endpoint; + + +import net.jxta.document.MimeMediaType; +import net.jxta.logging.Logging; +import net.jxta.util.ClassFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Hashtable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class is a class factory for Wire Format Messages. This class abstracts + * The implementation of Wire Format Messages and allows for construction based + * on the MimeType of InputStreams. + *

      + * The WireFormatMessageFactory extends the ClassFactory to register the + * various Message wire format implementations into a static hashtable. The + * factory is called with the Mime type requested to create the corresponding + * Wire Format type. + * + * @see net.jxta.endpoint.Message + * @see net.jxta.endpoint.WireFormatMessage + * @see net.jxta.util.ClassFactory + * @see net.jxta.document.MimeMediaType + */ +public final class WireFormatMessageFactory extends ClassFactory { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(WireFormatMessageFactory.class.getName()); + + /** + * The mime media type of preferred/default wire format. + */ + public static final MimeMediaType DEFAULT_WIRE_MIME = new MimeMediaType("application/x-jxta-msg").intern(); + + /** + * Interface for instantiators of wire format messages. + */ + public interface Instantiator { + + /** + * Returns the list of mime types supported by this serialization. All of + * mimetypes in this list should have no mime type parameters. + * + * @return Returns the list of mime types supported by this serialization. + */ + public MimeMediaType[] getSupportedMimeTypes(); + + /** + * Returns a list of the content encodings supported by this serialization. + * These content encodings apply to both the overall coding of the message + * and to the encoding of individual elements. + * + * @return a list of the content encodings supported by this serialization. + */ + public MimeMediaType[] getSupportedContentEncodings(); + + /** + * Create a WireFormatMessage from an abstract message. It is an error + * (though lazily enforced) to modify the abstract message during the + * lifetime of the WireFormatMessage. + * + * @param msg the message for which a serialization is desired. + * @param type the the serialization form desired. This can include + * mime parameters to control options. + * @param preferedContentEncoding An array of acceptable message encodings + * in descending order of preference. any or none of these encoding options + * may be used. May be null for unencoded messages. + * @return a proxy object for the abstract message which is a + * representation of the message in its serialized form. + */ + public WireFormatMessage toWire(Message msg, MimeMediaType type, MimeMediaType[] preferedContentEncoding); + + /** + * Create an abstract message from a serialization. + * + * @param is The message stream. Message serializations must either use + * internal data or EOF to determine the length of the stream. + * @param type Declared message type of the stream including any optional + * configuration parameters. + * @param contentEncoding Content encoding (including optional parameters) + * which has been applied to the message. May be null for unencoded messages. + * @return a proxy object for the abstract message which is a + * representation of the message in its serialized form. + * @throws java.io.IOException if an io error occurs + */ + public Message fromWire(InputStream is, MimeMediaType type, MimeMediaType contentEncoding) throws IOException; + + /** + * Create an abstract message from a serialization. + * + * @param buffer The byte buffer. Message serializations must either use + * internal data or EOF to determine the length of the stream. + * @param type Declared message type of the stream including any optional + * configuration parameters. + * @param contentEncoding Content encoding (including optional parameters) + * which has been applied to the message. May be null for unencoded messages. + * @return a proxy object for the abstract message which is a + * representation of the message in its serialized form. + * @throws java.io.IOException if an io error occurs + */ + public Message fromBuffer(ByteBuffer buffer, MimeMediaType type, MimeMediaType contentEncoding) throws IOException; + } + + /** + * This is the map of mime-types and constructors used by + * newStructuredDocument. + */ + private Map encodings = new Hashtable(); + + /** + * If true then the pre-defined set of StructuredDocument sub-classes has + * been registered from the property containing them. + */ + private volatile boolean loadedProperty = false; + + /** + * This class is in fact a singleton. This is the instance that backs the + * static methods. + */ + private static WireFormatMessageFactory factory = new WireFormatMessageFactory(); + + /** + * Private constructor. This class is not meant to be instantiated except + * by itself. + */ + private WireFormatMessageFactory() {} + + /** + * Registers the pre-defined set of WireFormatMessage sub-classes so that + * this factory can construct them. + * + * @return true if at least one of the WireFormatMessage sub-classes could + * be registered otherwise false. + */ + private synchronized boolean loadProviders() { + if (!factory.loadedProperty) { + factory.loadedProperty = registerProviders(WireFormatMessage.class.getName()); + } + + return factory.loadedProperty; + } + + /** + * {@inheritDoc} + */ + @Override + protected Map getAssocTable() { + return encodings; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getClassOfInstantiators() { + // our key is the doctype names. + return Instantiator.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getClassForKey() { + // our key is the mime types. + return MimeMediaType.class; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean registerAssoc(String className) { + boolean registeredSomething = false; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Registering : " + className); + } + + try { + Class msgClass = Class.forName(className); + + Instantiator instantiator = (Instantiator) (msgClass.getField("INSTANTIATOR").get(null)); + + MimeMediaType[] mimeTypes = instantiator.getSupportedMimeTypes(); + + for (MimeMediaType mimeType : mimeTypes) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(" Registering Type : " + mimeType); + } + + registeredSomething |= registerInstantiator(mimeType, instantiator); + } + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to register \'" + className + "\'", all); + } + } + + return registeredSomething; + } + + /** + * Register an instantiator object a mime-type of documents to be + * constructed. + * + * @param mimetype the mime-type associated. + * @param instantiator the instantiator that wants to be registered.. + * @return boolean true if the instantiator for this mime-type is now + * registered. If there was already an instantiator this mime-type then + * false will be returned. + * @throws SecurityException there were permission problems registering + * the instantiator. + */ + public static boolean registerInstantiator(MimeMediaType mimetype, Instantiator instantiator) { + boolean registered = factory.registerAssoc(mimetype, instantiator); + + return registered; + } + + /** + * Constructs an instance of {@link WireFormatMessage} matching the type + * specified by the type parameter. + * + * @param msg the message for which a serialization is desired. + * @param type the the serialization form desired. This can include + * mime parameters to control options. + * @param preferedEncodings An array of acceptable message encodings + * in descending order of preference. any or none of these encoding options + * may be used. May be null for unencoded messages. + * @return a proxy object for the abstract message which is a + * representation of the message in its serialized form. + */ + public static WireFormatMessage toWire(Message msg, MimeMediaType type, MimeMediaType[] preferedEncodings) { + factory.loadProviders(); + + Instantiator instantiator = factory.getInstantiator(type.getBaseMimeMediaType()); + + return instantiator.toWire(msg, type, preferedEncodings); + } + + /** + * Constructs an instance of Message from matching the type + * specified by the type parameter. + * + * @param is The message stream. Message serializations must either use + * internal data or EOF to determine the length of the stream. + * @param type Declared message type of the stream including any optional + * configuration parameters. + * @param contentEncoding Content encoding (including optional parameters) + * which has been applied to the message. May be null for unencoded messages. + * @return the new abstract message. + * @throws java.io.IOException if an io error occurs + */ + public static Message fromWire(InputStream is, MimeMediaType type, MimeMediaType contentEncoding) throws IOException { + factory.loadProviders(); + + Instantiator instantiator; + + try { + instantiator = factory.getInstantiator(type.getBaseMimeMediaType()); + } catch (NoSuchElementException badType) { + throw new IOException("Unable to deserialize message of type: " + type); + } + + return instantiator.fromWire(is, type, contentEncoding); + } + + /** + * Constructs an instance of Message from matching the type + * specified by the type parameter. + * + * @param buffer The message buffer. Message serializations must either use + * internal data or EOF to determine the length of the stream. + * @param type Declared message type of the stream including any optional + * configuration parameters. + * @param contentEncoding Content encoding (including optional parameters) + * which has been applied to the message. May be null for unencoded messages. + * @return the new abstract message. + * @throws java.io.IOException if an io error occurs + */ + public static Message fromBuffer(ByteBuffer buffer, MimeMediaType type, MimeMediaType contentEncoding) throws IOException { + factory.loadProviders(); + + Instantiator instantiator; + + try { + instantiator = factory.getInstantiator(type.getBaseMimeMediaType()); + } catch (NoSuchElementException badType) { + throw new IOException("Unable to deserialize message of type: " + type); + } + + return instantiator.fromBuffer(buffer, type, contentEncoding); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/package.html new file mode 100644 index 000000000..83bbbe58e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/package.html @@ -0,0 +1,12 @@ + + + + + + + Provides interfaces and classes used for the addressing, filtering, sending, + and receiving of messages within JXTA. + + @see JXTA Protocols Specification + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ConfiguratorException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ConfiguratorException.java new file mode 100644 index 000000000..70b6078b2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ConfiguratorException.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.exception; + + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +/** + * This class maintains a {@link java.util.List} of all possible {@link + * java.lang.Throwable causes} that may be generated as a part of the + * configuration process. + * + * @author james todd [gonzo at jxta dot org] + */ + +public class ConfiguratorException extends JxtaException { + + private List causes = null; + + /** + * Constucts a {@link JxtaException} with no specified details. + */ + public ConfiguratorException() { + super(); + } + + /** + * Constructs a {@link JxtaException} with the specified message. + * + * @param msg message + */ + public ConfiguratorException(String msg) { + super(msg); + } + + /** + * Constructs a {@link JxtaException} with the specified {@link + * java.lang.Throwable cause}. + * + * @param ex cause + */ + public ConfiguratorException(Throwable ex) { + super(); + + addCause(ex); + } + + /** + * Constructs a {@link JxtaException} with the specified message and {@link + * java.lang.Throwable cause}. + * + * @param msg message + * @param ex cause + */ + public ConfiguratorException(String msg, Throwable ex) { + super(msg); + + addCause(ex); + } + + /** + * Constructs a {@link JxtaException} with the specified {@link + * java.util.List} of {@link java.lang.Throwable causes}. + * + * @param ex causes + */ + public ConfiguratorException(List ex) { + super(); + + addCauses(ex); + } + + /** + * Constructs a {@link JxtaException} with the specified message in + * addition to the {@link java.util.List} of {@link java.lang.Throwable + * causes}. + * + * @param msg message + * @param ex causes + */ + public ConfiguratorException(String msg, List ex) { + super(msg); + + addCauses(ex); + } + + /** + * Retrieve the {@link java.lang.Throwable causes} as a {@link + * java.util.List}. + * + * @return The causes + */ + public List getCauses() { + return this.causes != null ? this.causes : Collections.emptyList(); + } + + /** + * Add a cause of type {@link java.lang.Throwable}. + * + * @param c The cause + */ + public void addCause(Throwable c) { + if (c != null) { + if (this.causes == null) { + this.causes = new ArrayList(); + } + + this.causes.add(c); + } + } + + /** + * Add a {@link java.util.List} of {@link java.lang.Throwable causes}. + * + * @param c The causes + */ + public void addCauses(List c) { + if (c != null) { + for (Object aC : c) { + addCause((Throwable) aC); + } + } + } + + /** + * @inheritDoc

      Overload printStackTrace() to support multiple {@link java.lang.Throwable causes}. + */ + @Override + public void printStackTrace() { + super.printStackTrace(); + + for (Object o : getCauses()) { + ((Throwable) o).printStackTrace(); + } + } + + /** + * @param ps Description of the Parameter + * @inheritDoc

      Overload printStackTrace({@link java.io.PrintStream}) to support + * multiple {@link java.lang.Throwable causes}. + */ + @Override + public void printStackTrace(PrintStream ps) { + super.printStackTrace(ps); + + ps.println("Caused by:"); + int count = 1; + + for (Object o : getCauses()) { + Throwable t = (Throwable) o; + + ps.print("Cause #" + count++ + " : "); + + t.printStackTrace(ps); + } + } + + /** + * @param pw Description of the Parameter + * @inheritDoc

      Overload printStackTrace({@link java.io.PrintWriter}) to support + * multiple {@link java.lang.Throwable causes}. + */ + @Override + public void printStackTrace(PrintWriter pw) { + super.printStackTrace(pw); + + pw.println("Caused by:"); + int count = 1; + + for (Object o : getCauses()) { + Throwable t = (Throwable) o; + + pw.print("Cause #" + count++ + " : "); + + t.printStackTrace(pw); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/JxtaError.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/JxtaError.java new file mode 100644 index 000000000..f7cab0846 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/JxtaError.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.exception; + + +/** + * Thrown when JXTA cannot continue running. + */ + +public class JxtaError extends Error { + + /** + * Construct a new JxtaError with no detailed message. + * + */ + public JxtaError() {} + + public JxtaError(String msg) { + super(msg); + } + + public JxtaError(String msg, Throwable cause) { + super(msg, cause); + } + + public JxtaError(Throwable cause) { + super(cause); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/JxtaException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/JxtaException.java new file mode 100644 index 000000000..01ad8dc70 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/JxtaException.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.exception; + + +/** + * The class JxtaException and its subclasses are a form of Exception that + * indicates conditions that a reasonable application might want to catch. + * + */ +@SuppressWarnings("serial") +public class JxtaException extends Exception { + + /** + * Constructs an Exception with no specified detail message. + */ + public JxtaException() { + super(); + } + + /** + * Constructs an Exception with the specified detail message. + * + *@param message the detail message. + */ + public JxtaException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public JxtaException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param message message the detail message + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public JxtaException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/PeerGroupException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/PeerGroupException.java new file mode 100644 index 000000000..297fc4925 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/PeerGroupException.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.exception; + + +/** + * Generic Peer group exception + * + */ + +public class PeerGroupException extends JxtaException { + + /** + * Constructs an Exception with no specified detail message. + */ + public PeerGroupException() { + super(); + } + + /** + * Constructs an Exception with the specified detail message. + * + *@param message the detail message. + */ + public PeerGroupException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public PeerGroupException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param message message the detail message + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public PeerGroupException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ProtocolNotSupportedException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ProtocolNotSupportedException.java new file mode 100644 index 000000000..feb4c5fb4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ProtocolNotSupportedException.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.exception; + + +/** + * Signals that an error occurred while attempting to access an + * endpoint protocol + * + */ +public class ProtocolNotSupportedException extends JxtaException { + + /** + * Constructs an Exception with no specified detail message. + */ + public ProtocolNotSupportedException() { + super(); + } + + /** + * Constructs an Exception with the specified detail message. + * + *@param message the detail message. + */ + public ProtocolNotSupportedException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public ProtocolNotSupportedException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param message message the detail message + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public ProtocolNotSupportedException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ServiceNotFoundException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ServiceNotFoundException.java new file mode 100644 index 000000000..11b792275 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/ServiceNotFoundException.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.exception; + + +/** + * Signals that an error occurred while trying to access a peer group service + * + */ +public class ServiceNotFoundException extends JxtaException { + + /** + * Constructs an Exception with no specified detail message. + */ + public ServiceNotFoundException() { + super(); + } + + /** + * Constructs an Exception with the specified detail message. + * + *@param message the detail message. + */ + public ServiceNotFoundException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public ServiceNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param message message the detail message + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public ServiceNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/UnknownServiceException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/UnknownServiceException.java new file mode 100644 index 000000000..bd5317427 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/UnknownServiceException.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.exception; + + +/** + * Signals that an error occurred while trying to access a service + * + */ + +public class UnknownServiceException extends JxtaException { + + /** + * Constructs an Exception with no specified detail message. + */ + public UnknownServiceException() { + super(); + } + + /** + * Constructs an Exception with the specified detail message. + * + *@param message the detail message. + */ + public UnknownServiceException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public UnknownServiceException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *@param message message the detail message + *@param cause the cause (which is saved for later retrieval by the + * Throwable.getCause() method). + * (A null value is permitted, and indicates that the + * cause is nonexistent or unknown.) + */ + public UnknownServiceException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/package.html new file mode 100644 index 000000000..1fd5f0176 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/exception/package.html @@ -0,0 +1,9 @@ + + + + + + + Exception classes commonly used by JXTA Components. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/ID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/ID.java new file mode 100644 index 000000000..44f52d8f4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/ID.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.id; + + +import java.io.ObjectStreamException; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.net.URI; +import java.net.URL; +import java.util.Map; +import java.util.WeakHashMap; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; + + +/** + * IDs are used to uniquely identify peers, peer groups, pipes and other + * types of objects manipulated by the JXTA APIs. + * + * @see net.jxta.id.IDFactory + * @see net.jxta.codat.CodatID + * @see net.jxta.peer.PeerID + * @see net.jxta.peergroup.PeerGroupID + * @see net.jxta.pipe.PipeID + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.platform.ModuleSpecID + * @see JXTA Protocols Specification : IDs + */ +public abstract class ID implements java.io.Serializable { + + /** + * Collection of interned IDs. All IDs visible within in the VM are + * contained within this table. + */ + private static final Map> interned = new WeakHashMap>(1000); + + /** + * This defines the URI scheme that we will be using to present JXTA IDs. + * JXTA IDs are encoded for presentation into URIs (see + * {@link IETF RFC 2396 Uniform Resource Identifiers (URI) : Generic Syntax} + * ) as URNs (see + * {@link IETF RFC 2141 Uniform Resource Names (URN) Syntax} + * ). + */ + public static final String URIEncodingName = "urn"; + + /** + * This defines the URN Namespace that we will be using to present JXTA IDs. + * The namespace allows URN resolvers to determine which sub-resolver to use + * to resolve URN references. All JXTA IDs are presented in this namespace. + */ + public static final String URNNamespace = "jxta"; + + /** + * The null ID. The NullID is often used as a placeholder in fields which + * are uninitialized. + * + *

      This is a singleton within the scope of a VM. + */ + public static final ID nullID = (new NullID()).intern(); + + /** + * + * Creates an ID by parsing the given URI. + * + *

      This convenience factory method works as if by invoking the + * {@link IDFactory#fromURI(URI)} method; any {@link URISyntaxException} + * thrown is caught and wrapped in a new {@link IllegalArgumentException} + * object, which is then thrown. + * + *

      This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link IDFactory}, which throws + * {@link URISyntaxException} directly, should be used situations where a + * ID is being constructed from user input or from some other source that + * may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException + * If fromURI is null + * + * @throws IllegalArgumentException + * If the given URI is not a valid ID. + */ + public static ID create(URI fromURI) { + try { + return IDFactory.fromURI(fromURI); + } catch (URISyntaxException badid) { + IllegalArgumentException failure = new IllegalArgumentException(); + + failure.initCause(badid); + throw failure; + } + } + + /** + * Constructor for IDs. IDs are constructed using the {@link IDFactory} or + * {@link #create(URI)}. + * + */ + protected ID() {} + + /** + * Returns a string representation of the ID. This representation should be + * used primarily for debugging purposes. For most other situations IDs + * should be externalized as Java URI Objects via {@link #toURI()}. + * + *

      The default implementation is the toString() of the ID + * represented as a URI. + * + * @return String containing the URI + * + */ + @Override + public String toString() { + return toURI().toString(); + } + + /** + * Return the interned form of the ID. + */ + private Object readResolve() throws ObjectStreamException { + return intern(); + } + + /** + * Returns a string identifier which indicates which ID format is + * used by this ID instance. + * + * @return a string identifier which indicates which ID format is + * used by this ID instance. + */ + public abstract String getIDFormat(); + + /** + * Returns an object containing the unique value of the ID. This object + * must provide implementations of toString(), equals() and hashCode() that + * are canonical and consistent from run-to-run given the same input values. + * Beyond this nothing should be assumed about the nature of this object. + * For some implementations the object returned may be this. + * + * @return Object which can provide canonical representations of the ID. + */ + public abstract Object getUniqueValue(); + + /** + * Returns a URL representation of the ID. The + * {@link net.jxta.id.IDFactory JXTA ID Factory} can be used to construct + * ID Objects from URLs containing JXTA IDs. + * + * @deprecated URIs are now the preferred way of manipulating IDs + * + * @see net.jxta.id.IDFactory#fromURL( java.net.URL ) + * + * @return URL Object containing the URI + */ + @Deprecated + public URL getURL() { + try { + return IDFactory.jxtaURL(URIEncodingName, "", URNNamespace + ":" + getUniqueValue()); + } catch (MalformedURLException caught) { + IllegalStateException failure = new IllegalStateException("Environment incorrectly intialized."); + + failure.initCause(caught); + throw failure; + } + } + + /** + * Returns a canonical representation for the ID object. + * + *

      A pool of IDs, is maintained privately by the class. + * + *

      When the intern() method is invoked, if the pool already contains a + * ID equal to this ID object as determined by the + * equals(Object) method, then the ID from the pool is returned. + * Otherwise, this ID object is added to the pool and a reference + * to this ID object is returned. + * + *

      It follows that for any two ID s and t, + * s.intern() == t.intern() is true if and only if s.equals(t) + * is true. + * + * @return a ID that has the same value as this type, but is guaranteed to + * be from a pool of unique types. + */ + protected ID intern() { + synchronized (ID.class) { + Reference common = interned.get(this); + + ID result = null; + + if (null != common) { + result = common.get(); + } + + if (null == result) { + interned.put(this, new WeakReference(this)); + result = this; + } + + return result; + } + } + + /** + * Returns a URI representation of the ID. {@link java.net.URI URIs} are + * the preferred way of externalizing and presenting JXTA IDs. The + * {@link net.jxta.id.IDFactory JXTA ID Factory} can be used to construct + * ID Objects from URIs containing JXTA IDs. + * + * @see net.jxta.id.IDFactory#fromURI( java.net.URI ) + * + * @return URI Object containing the URI + */ + public URI toURI() { + return URI.create(URIEncodingName + ":" + URNNamespace + ":" + getUniqueValue()); + } +} + + +/** + * The NullID is often used as a placeholder in fields which are uninitialized. + */ +final class NullID extends ID { + final static String JXTAFormat = "jxta"; + + final static String UNIQUEVALUE = "Null"; + + /** + * NullID is not intended to be constructed. You should use the + * {@link #nullID} constant instead. + */ + NullID() {} + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + return (this == target); // null is only itself. + } + + /** + * deserialization has to point back to the singleton in this VM. + */ + private Object readResolve() { + return ID.nullID; + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return JXTAFormat; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + UNIQUEVALUE; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/IDFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/IDFactory.java new file mode 100644 index 000000000..8e2297a12 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/IDFactory.java @@ -0,0 +1,1210 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.id; + + +import java.io.InputStream; +import java.lang.reflect.Field; +import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.ResourceBundle; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.UnknownServiceException; +import java.util.MissingResourceException; +import java.util.NoSuchElementException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.codat.CodatID; +import net.jxta.id.jxta.IDFormat; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.PipeID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.util.ClassFactory; + + +/** + * A factory class for creating new ID instances and for constructing ID + * instances from external representations such as strings or URIs. + * + *

      When possible the factory will create IDs of the same ID Format as any + * base ids provided. For example, PipeIDs will be created to be the same ID + * Format as the PeerGroupID provided. + * + *

      Some ID constructors allow specification of "seed" information. Each ID + * Format may use this seed information as it chooses or may require seed + * information of a specific form. In some cases the seed information will be + * used literally as provided to construct the resulting ID, but ID Formats + * may also choose to ignore the seed information entirely, use it as random + * number generator seed values, etc. Consult the implementation documentation + * for the ID Formats of interest to see how the seed information is used by + * each ID Format. + * + * @see net.jxta.id.ID + * @see net.jxta.util.ClassFactory + * @see JXTA Protocols Specification : IDs + */ +public final class IDFactory extends ClassFactory { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(IDFactory.class.getName()); + + /** + * A map of the ID Formats to instantiators. + * + */ + private final Map idFormats = new HashMap(); + + /** + * Identifies the ID format to use when creating new ID instances. + */ + private final String idNewInstances; + + /** + * This class is a singleton. This is the instance that backs the + * static methods. + */ + private final static IDFactory factory = new IDFactory(); + + /** + * Interface for instantiators of IDs. Each ID Format registered with the + * ID Factory implements a class with this interface. + */ + public interface Instantiator { + + /** + * Returns the ID Format value associated with this ID Format + * + * @return String containing the ID format value for this format. + */ + public String getSupportedIDFormat(); + + /** + * Construct a new ID instance from a JXTA ID contained in a URL. + * + * @deprecated Convert to {@code fromURI}. + * + * @param source URL which will be decoded to create a new ID instance. + * @return ID containing the new ID instance initialized from the URL. + * @throws UnknownServiceException Is thrown if the URL provided is of + * a format unrecognized by this JXTA implementation. + * @throws MalformedURLException Is thrown if the URL provided is not + * a valid, recognized JXTA URL. + */ + @Deprecated + public ID fromURL(URL source) throws MalformedURLException, UnknownServiceException; + + /** + * Construct a new ID instance from a JXTA ID contained in a URI. + * + * @param source URI which will be decoded to create a new ID instance. + * @return ID containing the new ID instance initialized from the source. + * @throws URISyntaxException if the URI provided is not a valid, + * recognized JXTA URI. + */ + public ID fromURI(URI source) throws URISyntaxException; + + /** + * Construct a new ID instance from the scheme specific portion of a jxta + * URN. + * + * @param source the scheme specific portion of a jxta URN. + * @return ID containing the new ID instance initialized from the source. + * @throws URISyntaxException if the URI provided is not a valid, + * recognized JXTA URI. + */ + public ID fromURNNamespaceSpecificPart(String source) throws URISyntaxException; + + /** + * Creates a new CodatID Instance. A new random CodatID is created for + * the provided Peer Group. This type of CodatID can be used as a + * canonical reference for dynamic content. + * + * @see net.jxta.codat.Codat + * + * @param groupID The group to which this content will belong. + * @return The newly created CodatID. + */ + public CodatID newCodatID(PeerGroupID groupID); + + /** + * Creates a new CodatID instance. A new CodatID is created for the + * provided Peer Group. This type of CodatID can be used as a + * canonical reference for dynamic content. + * + *

      This variant of CodatID allows you to create "Well-known" codats + * within the context of diverse groups. This can be useful for common + * services that need to do discovery without advertisements or for + * network organization services. Because of the potential for ID + * collisions and the difficulties with maintaining common service + * interfaces this variant of CodatID should be used with great caution + * and pre-planning. + * + * @see net.jxta.codat.Codat + * + * @param groupID The group to which this content will belong. + * @param seed The seed information which will be used in creating the + * codatID. The seed information should be at least four bytes in + * length, though longer values are better. + * @return The newly created CodatID. + */ + public CodatID newCodatID(PeerGroupID groupID, byte[] seed); + + /** + * Creates a new CodatID instance. A new random CodatID is created for + * the provided Peer Group and contains a hash value for the Codat data. + * This type of Codat ID is most appropriate for static content. By + * including a hash value this form of Codat ID provides greater + * assurance of the canonical property of IDs. It also allows the + * document content returned when this ID is used to be verified to + * ensure it has not been altered. + * + * @see net.jxta.codat.Codat + * + * @param groupID The group to which this ID will belong. + * @param in The InputStream from which the content hash is calculated. + * The stream is read until EOF and then closed. + * @return The newly created CodatID. + * @throws IOException I/O Error reading document + */ + public CodatID newCodatID(PeerGroupID groupID, InputStream in) throws IOException; + + /** + * Creates a new CodatID instance. A new CodatID is created for the + * provided Peer Group and contains a hash value for the Codat data. + * By including a hash value this form of Codat ID provides greater + * assurance of the canonical property of IDs. It also allows the + * document content returned when this ID is used to be verified to + * ensure it has not been altered. This type of Codat ID is most + * appropriate for static content. + * + *

      This variant of CodatID allows you to create "Well-known" codats + * within the context of diverse groups. This can be useful for common + * services that need to do discovery without advertisements or for + * network organization services. Because of the potential for ID + * collisions and the difficulties with maintaining common service + * interfaces this variant of CodatID should be used with great caution + * and pre-planning. + * + * @see net.jxta.codat.Codat + * + * @param groupID The group to which this ID will belong. + * @param seed The seed information which will be used in creating the + * codat ID. The seed information should be at least four bytes in + * length, though longer values are better. + * @param in The InputStream from which the content hash is calculated. + * The stream is read until EOF and then closed. + * @return The newly created CodatID. + * @throws IOException I/O Error reading document + */ + public CodatID newCodatID(PeerGroupID groupID, byte[] seed, InputStream in) throws IOException; + + /** + * Creates a new PeerID instance. A new random peer id will be generated. + * The PeerID will be a member of the provided group. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param groupID the group to which this PeerID will belong. + * @return The newly created PeerID. + */ + public PeerID newPeerID(PeerGroupID groupID); + + /** + * Creates a new PeerID instance. A new PeerID will be generated. + * The PeerID will be a member of the provided group. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param groupID the group to which this PeerID will belong. + * @param seed The seed information which will be used in creating the + * PeerID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return The newly created PeerID. + */ + public PeerID newPeerID(PeerGroupID groupID, byte[] seed); + + /** + * Creates a new PeerGroupID instance. A new random peer group id will be + * generated. The PeerGroupID will be created using the default ID Format. + * + * @see net.jxta.peergroup.PeerGroup + * + * @return The newly created PeerGroupID. + */ + public PeerGroupID newPeerGroupID(); + + /** + * Creates a new PeerGroupID instance. A new PeerGroupID will be + * generated using the provided seed information. The PeerGroupID will + * be created using the default ID Format. + * + *

      This method allows you to create "Well-known" PeerGroupIDs. + * This is similar to how the JXTA "World Peer Group" and "Net + * Peer Group". "Well-known" IDs can be useful for common services + * that need to do discovery without advertisements or for network + * organization services. Because of the potential for ID collisions + * and the difficulties with maintaining common service interfaces this + * variant of PeerGroupID should be used with great caution and + * pre-planning. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param seed The seed information which will be used in creating the + * PeerGroupID. The seed information should be at least four bytes in + * length, though longer values are better. + * @return The newly created PeerGroupID. + */ + public PeerGroupID newPeerGroupID(byte[] seed); + + /** + * Creates a new PeerGroupID instance with the specified parent group. + * A new random peer group id will be generated. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param parent The group which will be the parent of this group. + * @return The newly created PeerGroupID. + */ + public PeerGroupID newPeerGroupID(PeerGroupID parent); + + /** + * Creates a new PeerGroupID instance with the specified parent group. + * A new PeerGroupID will be generated using the provided seed + * information. + * + *

      This method allows you to create "Well-known" PeerGroupIDs. + * This is similar to how the JXTA "World Peer Group" and "Net + * Peer Group". "Well-known" IDs can be useful for common services + * that need to do discovery without advertisements or for network + * organization services. Because of the potential for ID collisions + * and the difficulties with maintaining common service interfaces this + * variant of PeerGroupID should be used with great caution and + * pre-planning. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param parent The group which will be the parent of this group. + * @param seed The seed information which will be used in creating the + * PeerGroupID. The seed information should be at least four bytes in + * length, though longer values are better. + * @return The newly created PeerGroupID. + */ + public PeerGroupID newPeerGroupID(PeerGroupID parent, byte[] seed); + + /** + * Creates a new PipeID instance. A new random PipeID will be generated. + * + * + * @param groupID The group to which this Pipe ID will belong. + * @return The newly created PipeID. + */ + public PipeID newPipeID(PeerGroupID groupID); + + /** + * Creates a new PipeID instance. A new pipe id will be generated with + * the provided seed information. The Pipe ID will be a member of the + * provided group. + * + *

      This variant of PipeID allows you to create "Well-known" pipes + * within the context of diverse groups. This can be useful for common + * services that need to do discovery without advertisements or for + * network organization services. Because of the potential for ID + * collisions and the difficulties with maintaining common service + * interfaces this variant of PipeID should be used with great caution + * and pre-planning. + * + * + * @param groupID the group to which this Pipe ID will belong. + * @param seed The seed information which will be used in creating the + * pipeID. The seed information should be at least four bytes in + * length, though longer values are better. + * @return the newly created PipeID. + */ + public PipeID newPipeID(PeerGroupID groupID, byte[] seed); + + /** + * Creates a new ModuleClassID instance. A new random ModuleClassID + * will be generated with a zero value role identifier. This form of + * ModuleClassID is appropriate for cases where the module does not + * need to be distinguished from other instances of the same Module. + * The ModuleClassID will be created using the default ID Format. + * + * @see net.jxta.platform.Module + * + * @return The newly created ModuleClassID. + */ + public ModuleClassID newModuleClassID(); + + /** + * Creates a new ModuleClassID instance. A new random ModuleClassID + * will be generated with a a random value role identifier and a base + * class of the provided ModuleClassID. This form of ModuleClassID is + * appropriate for cases where it is necessary to distinguish instances + * of the same service interface. + * + * @see net.jxta.platform.Module + * + * @param baseClass The ModuleClassID which will be used as a base + * class for this new role value instance. + * @return The newly created ModuleClassID. + */ + public ModuleClassID newModuleClassID(ModuleClassID baseClass); + + /** + * Creates a new ModuleSpecID instance. A new random ModuleSpecID will + * be generated. + * + * @see net.jxta.platform.Module + * + * @param baseClass The ModuleClassID which will be used as a base + * class for this new ModuleSpecID. + * @return The newly created ModuleSpecID. + */ + public ModuleSpecID newModuleSpecID(ModuleClassID baseClass); + } + + + /** + * @deprecated This interface formerly contained optional URI based + * construction methods. These have now been moved to the primary + * instantiator interface in preparation for the removal of the URL + * based interfaces. This interface will be removed in a future release. + */ + @Deprecated + public interface URIInstantiator extends Instantiator {} + + /** + * Standard Constructor. This class is a singleton so the only constructor + * is private. + * + *

      Uses net.jxta.impl.config.properties file as the + * source for settings. + * + *

      Example entry from the file net.jxta.impl.config.properties : + * + *

      
      +     * #Default type of ID to use when creating an ID (this should not be changed in most implementations).
      +     * IDNewInstances=uuid
      +     * 
      + */ + private IDFactory() { + // required format + registerAssoc("net.jxta.id.jxta.IDFormat"); + + // required by this implementation. + registerAssoc("net.jxta.impl.id.unknown.IDFormat"); + + // Register a list of classes for association with an ID format + registerProviders(ID.class.getName()); + + try { + // Get our resource bundle + ResourceBundle jxtaRsrcs = ResourceBundle.getBundle("net.jxta.impl.config"); + + // set the default ID Format. + idNewInstances = jxtaRsrcs.getString("IDNewInstances").trim(); + } catch (MissingResourceException notFound) { + // This is an error because we can't start without a concept of ID. + IllegalStateException failure = + new IllegalStateException("Could not initialize ID defaults", notFound); + LOG.log(Level.SEVERE, "Cound not initialize IDFactory", failure); + throw failure; + } + } + + /** + * Used by ClassFactory methods to get the mapping of ID types to constructors. + * + * @return the mapping of ID types to instantiators. + */ + @Override + protected Map getAssocTable() { + return idFormats; + } + + /** + * Used by ClassFactory methods to ensure that all keys used with the mapping are + * of the correct type. + * + * @return Class object of the key type. + */ + @Override + protected Class getClassForKey() { + return String.class; + } + + /** + * Used by ClassFactory methods to ensure that all of the instance classes + * which register with this factory have the correct base class + * + * @return Class object of the key type. + */ + @Override + protected Class getClassOfInstantiators() { + return Instantiator.class; + } + + /** + * Register a class with the factory from its class name. We override the + * standard implementation to get the id format from the class and + * use that as the key to register the class with the factory. + * + * @param className The class name which will be registered. + * @return boolean true if the class was registered otherwise false. + */ + @Override + public boolean registerAssoc(String className) { + boolean registeredSomething = false; + + try { + Class idClass; + + try { + idClass = Class.forName(className); + + if (null == idClass) { + throw new ClassNotFoundException("forName() result was null"); + } + } catch (ClassNotFoundException notThere) { + LOG.severe("Could not find class named : " + className); + return false; + } catch (NoClassDefFoundError notThere) { + LOG.severe("Could not find class named : " + className); + return false; + } + + Field instantiatorField; + + try { + instantiatorField = idClass.getField("INSTANTIATOR"); + + if (null == instantiatorField) { + throw new NoSuchFieldException("getField() result was null for field 'INSTANTIATOR'"); + // caught locally + } + } catch (NoSuchFieldException notThere) { + LOG.severe("Could not find INSTANTIATOR field in class named : " + className); + return false; + } + + if (!Instantiator.class.isAssignableFrom(instantiatorField.getType())) { + throw new ClassCastException("INSTANTIATOR is not of type " + Instantiator.class.getName()); + } + + Instantiator instantiator = (Instantiator) instantiatorField.get(null); + + if (null == instantiator) { + LOG.severe("INSTANTIATOR field is null for class : " + className); + return false; + } + + String idFormat = instantiator.getSupportedIDFormat(); + + registeredSomething = registerAssoc(idFormat, instantiator); + } catch (Exception failed) { + LOG.log(Level.SEVERE, "Failed to register class : " + className, failed); + } + + return registeredSomething; + } + + /** + * Returns a String containing the name of the default ID Format. + * + * @return The current default ID Format. + */ + public static String getDefaultIDFormat() { + return factory.idNewInstances; + } + + /** + * Construct a new ID instance from a JXTA ID contained in a URI. + * + * @param source URI which will be decoded to create a new ID instance. + * @return ID containing the new ID instance initialized from the URI. + * @throws URISyntaxException If the URI provided is not a valid, + * recognized JXTA URI. + */ + public static ID fromURI(URI source) throws URISyntaxException { + ID result = null; + + // check the protocol + if (!ID.URIEncodingName.equalsIgnoreCase(source.getScheme())) { + throw new URISyntaxException(source.toString(), "URI scheme was not as expected."); + } + + String decoded = source.getSchemeSpecificPart(); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new URISyntaxException(source.toString(), "URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new URISyntaxException(source.toString(), + "URN namespace was not as expected. (" + + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + int dashAt = decoded.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new URISyntaxException(source.toString(), "URN jxta namespace IDFormat was missing."); + } + + // get the encoding used for this id + String format = decoded.substring(0, dashAt); + + Instantiator instantiator; + + try { + instantiator = factory.getInstantiator(format); + } catch (NoSuchElementException itsUnknown) { + instantiator = factory.getInstantiator("unknown"); + } + + result = instantiator.fromURNNamespaceSpecificPart(decoded); + + return result.intern(); + } + + /** + * Construct a new ID instance from a JXTA ID contained in a URI. + * + * @deprecated Use of URLs for representing JXTA IDs and this method are + * deprecated. Convert to using {@link #fromURI( URI )} instead. + * + * @param source URI which will be decoded to create a new ID instance. + * @return ID containing the new ID instance initialized from the URI. + * @throws UnknownServiceException Is thrown if the URI provided is of a + * format unrecognized by this JXTA implementation. + * @throws MalformedURLException Is thrown if the URI provided is not + * a valid, recognized JXTA URI. + */ + @Deprecated + public static ID fromURL(URL source) throws MalformedURLException, UnknownServiceException { + + ID result = null; + + // check the protocol + if (!ID.URIEncodingName.equalsIgnoreCase(source.getProtocol())) { + throw new UnknownServiceException("URI protocol type was not as expected."); + } + + String encoded = source.getFile(); + + // Decode the URN to convert any % encodings and convert it from UTF8. + String decoded = sun.net.www.protocol.urn.Handler.decodeURN(encoded); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new MalformedURLException("URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new MalformedURLException( + "URN namespace was not as expected. (" + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + int dashAt = decoded.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new UnknownServiceException("URN Encodingtype was missing."); + } + + // get the encoding used for this id + decoded = decoded.substring(0, dashAt); + + Instantiator instantiator; + + try { + instantiator = factory.getInstantiator(decoded); + } catch (NoSuchElementException itsUnknown) { + instantiator = factory.getInstantiator("unknown"); + } + + result = instantiator.fromURL(source); + + return result.intern(); + } + + /** + * Creates a new CodatID Instance. A new random CodatID is created for + * the provided Peer Group. This type of CodatID can be used as a + * canonical reference for dynamic content. + * + * @see net.jxta.codat.Codat + * + * @param groupID the group to which this content will belong. + * @return The newly created CodatID. + */ + public static CodatID newCodatID(PeerGroupID groupID) { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newCodatID(groupID).intern(); + } + + /** + * Creates a new CodatID instance. A new CodatID is created for the + * provided Peer Group. This type of CodatID can be used as a + * canonical reference for dynamic content. + * + *

      This variant of CodatID allows you to create "Well-known" codats + * within the context of diverse groups. This can be useful for common + * services that need to do discovery without advertisements or for + * network organization services. Because of the potential for ID + * collisions and the difficulties with maintaining common service + * interfaces this variant of CodatID should be used with great caution + * and pre-planning. + * + * @see net.jxta.codat.Codat + * + * @param groupID the group to which this content will belong. + * @param seed The seed information which will be used in creating the + * codatID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return The newly created CodatID. + */ + public static CodatID newCodatID(PeerGroupID groupID, byte[] seed) { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newCodatID(groupID, seed).intern(); + } + + /** + * Creates a new CodatID instance. A new random CodatID is created for + * the provided Peer Group and contains a hash value for the Codat data. + * This type of Codat ID is most appropriate for static content. By + * including a hash value this form of Codat ID provides greater assurance + * of the canonical property of IDs. It also allows the document content + * returned when this ID is used to be verified to ensure it has not been + * altered. + * + * @see net.jxta.codat.Codat + * + * @param groupID The group to which this ID will belong. + * @param in The InputStream from which the content hash is calculated. + * The stream is read until EOF and then closed. + * @return The newly created CodatID. + * @throws IOException I/O Error reading document + */ + public static CodatID newCodatID(PeerGroupID groupID, InputStream in) throws IOException { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newCodatID(groupID, in).intern(); + } + + /** + * Creates a new CodatID instance. A new CodatID is created for the + * provided Peer Group and contains a hash value for the Codat data. + * By including a hash value this form of Codat ID provides greater + * assurance of the canonical property of IDs. It also allows the + * document content returned when this ID is used to be verified to + * ensure it has not been altered. This type of Codat ID is most + * appropriate for static content. + * + *

      This variant of CodatID allows you to create "Well-known" codats + * within the context of diverse groups. This can be useful for common + * services that need to do discovery without advertisements or for + * network organization services. Because of the potential for ID + * collisions and the difficulties with maintaining common service + * interfaces this variant of CodatID should be used with great caution + * and pre-planning. + * + * @see net.jxta.codat.Codat + * + * @param groupID The group to which this ID will belong. + * @param seed The seed information which will be used in creating the + * codat ID. The seed information should be at least four bytes in length, + * though longer values are better. + * @param in The InputStream from which the content hash is calculated. + * The stream is read until EOF and then closed. + * @return The newly created CodatID. + * @throws IOException I/O Error reading document + */ + public static CodatID newCodatID(PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newCodatID(groupID, seed, in).intern(); + } + + /** + * Creates a new PeerID instance. A new random peer id will be generated. + * The PeerID will be a member of the provided group. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param groupID the group to which this PeerID will belong. + * @return The newly created PeerID. + */ + public static PeerID newPeerID(PeerGroupID groupID) { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newPeerID(groupID).intern(); + } + + /** + * Creates a new PeerID instance. A new PeerID will be generated. + * The PeerID will be a member of the provided group. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param groupID the group to which this PeerID will belong. + * @param seed The seed information which will be used in creating the + * PeerID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return The newly created PeerID. + */ + public static PeerID newPeerID(PeerGroupID groupID, byte[] seed) { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newPeerID(groupID, seed).intern(); + } + + /** + * Creates a new PeerGroupID instance. A new random peer group id will be + * generated. The PeerGroupID will be created using the default ID Format. + * + * @see net.jxta.peergroup.PeerGroup + * + * @return The newly created PeerGroupID. + */ + public static PeerGroupID newPeerGroupID() { + return newPeerGroupID(factory.idNewInstances).intern(); + } + + /** + * Creates a new PeerGroupID instance using the specified ID Format. + * A new random peer group id will be generated. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param idformat The ID Format to be used for crating the Peer Group ID. + * @return The newly created PeerGroupID. + */ + public static PeerGroupID newPeerGroupID(String idformat) { + Instantiator instantiator = factory.getInstantiator(idformat); + + return instantiator.newPeerGroupID().intern(); + } + + /** + * Creates a new PeerGroupID instance. A new PeerGroupID will be + * generated using the provided seed information. The PeerGroupID will + * be created using the default ID Format. + * + *

      This method allows you to create "Well-known" PeerGroupIDs. + * This is similar to how the JXTA "World Peer Group" and "Net + * Peer Group". "Well-known" IDs can be useful for common services + * that need to do discovery without advertisements or for network + * organization services. Because of the potential for ID collisions + * and the difficulties with maintaining common service interfaces this + * variant of PeerGroupID should be used with great caution and + * pre-planning. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param seed The seed information which will be used in creating the + * PeerGroupID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return The newly created PeerGroupID. + */ + public static PeerGroupID newPeerGroupID(byte[] seed) { + return newPeerGroupID(factory.idNewInstances, seed).intern(); + } + + /** + * Creates a new PeerGroupID instance. A new PeerGroupID will be + * generated using the provided seed information. The PeerGroupID will + * be created using the default ID Format. + * + *

      This method allows you to create "Well-known" PeerGroupIDs. + * This is similar to how the JXTA "World Peer Group" and "Net + * Peer Group". "Well-known" IDs can be useful for common services + * that need to do discovery without advertisements or for network + * organization services. Because of the potential for ID collisions + * and the difficulties with maintaining common service interfaces this + * variant of PeerGroupID should be used with great caution and + * pre-planning. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param idformat The ID Format of the new Peer Group ID. + * @param seed The seed information which will be used in creating the + * PeerGroupID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return The newly created PeerGroupID. + */ + public static PeerGroupID newPeerGroupID(String idformat, byte[] seed) { + Instantiator instantiator = factory.getInstantiator(idformat); + + return instantiator.newPeerGroupID(seed).intern(); + } + + /** + * Creates a new PeerGroupID instance with the specified parent group. + * A new random peer group id will be generated. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param parent The group which will be the parent of this group. + * @return The newly created PeerGroupID. + */ + public static PeerGroupID newPeerGroupID(PeerGroupID parent) { + String useFormat = parent.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newPeerGroupID(parent).intern(); + } + + /** + * Creates a new PeerGroupID instance with the specified parent group. + * A new PeerGroupID will be generated using the provided seed + * information. + * + *

      This method allows you to create "Well-known" PeerGroupIDs. + * This is similar to how the JXTA "World Peer Group" and "Net + * Peer Group". "Well-known" IDs can be useful for common services + * that need to do discovery without advertisements or for network + * organization services. Because of the potential for ID collisions + * and the difficulties with maintaining common service interfaces this + * variant of PeerGroupID should be used with great caution and + * pre-planning. + * + * @see net.jxta.peergroup.PeerGroup + * + * @param parent The group which will be the parent of this group. + * @param seed The seed information which will be used in creating the + * PeerGroupID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return The newly created PeerGroupID. + */ + public static PeerGroupID newPeerGroupID(PeerGroupID parent, byte[] seed) { + String useFormat = parent.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newPeerGroupID(parent, seed).intern(); + } + + /** + * Creates a new PipeID instance. A new random PipeID will be generated. + * + * @param groupID The group to which this Pipe ID will belong. + * @return The newly created PipeID. + */ + public static PipeID newPipeID(PeerGroupID groupID) { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newPipeID(groupID).intern(); + } + + /** + * Creates a new PipeID instance. A new pipe id will be generated with the + * provided seed information. The Pipe ID will be a member of the provided + * group. + * + *

      This variant of PipeID allows you to create "Well-known" pipes + * within the context of diverse groups. This can be useful for common + * services that need to do discovery without advertisements or for + * network organization services. Because of the potential for ID + * collisions and the difficulties with maintaining common service + * interfaces this variant of PipeID should be used with great caution + * and pre-planning. + * + * @param groupID the group to which this Pipe ID will belong. + * @param seed The seed information which will be used in creating the + * pipeID. The seed information should be at least four bytes in length, + * though longer values are better. + * @return the newly created PipeID. + */ + public static PipeID newPipeID(PeerGroupID groupID, byte[] seed) { + String useFormat = groupID.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newPipeID(groupID, seed).intern(); + } + + /** + * Creates a new ModuleClassID instance. A new random ModuleClassID will + * be generated with a zero value role identifier. This form of + * ModuleClassID is appropriate for cases where the module does not + * need to be distinguished from other instances of the same Module. + * The ModuleClassID will be created using the default ID Format. + * + * @see net.jxta.platform.Module + * + * @return The newly created ModuleClassID. + */ + public static ModuleClassID newModuleClassID() { + return newModuleClassID(factory.idNewInstances).intern(); + } + + /** + * Creates a new ModuleClassID instance using the specified ID Format. + * A new random ModuleClassID will be generated with a zero value role + * identifier. This form of ModuleClassID is appropriate for cases + * where the module does not need to be distinguished from other + * instances of the same Module. + * + * @see net.jxta.platform.Module + * + * @param idformat The ID Format of the new ModuleClassID. + * @return The newly created ModuleClassID. + */ + public static ModuleClassID newModuleClassID(String idformat) { + Instantiator instantiator = factory.getInstantiator(idformat); + + return instantiator.newModuleClassID().intern(); + } + + /** + * Creates a new ModuleClassID instance. A new random ModuleClassID will + * be generated with a a random value role identifier and a base class of + * the provided ModuleClassID. This form of ModuleClassID is + * appropriate for cases where it is necessary to distinguish instances + * of the same service interface. + * + * @see net.jxta.platform.Module + * + * @param baseClass The ModuleClassID which will be used as a base + * class for this new role value instance. + * @return The newly created ModuleClassID. + */ + public static ModuleClassID newModuleClassID(ModuleClassID baseClass) { + String useFormat = baseClass.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newModuleClassID(baseClass).intern(); + } + + /** + * Creates a new ModuleSpecID instance. A new random ModuleSpecID will + * be generated. + * + * @see net.jxta.platform.Module + * + * @param baseClass The ModuleClassID which will be used as a base + * class for this new ModuleSpecID. + * @return The newly created ModuleSpecID. + */ + public static ModuleSpecID newModuleSpecID(ModuleClassID baseClass) { + String useFormat = baseClass.getIDFormat(); + + // is the group netpg or worldpg? + if (IDFormat.INSTANTIATOR.getSupportedIDFormat().equals(useFormat)) { + useFormat = factory.idNewInstances; + } + + Instantiator instantiator = factory.getInstantiator(useFormat); + + return instantiator.newModuleSpecID(baseClass).intern(); + } + + /** + * This method should be used instead of using + * {@code new java.net.URL( )} to create URLs for use with IDFactory. + * URL construction can cause classes to be loaded using the system + * classLoader (JXTA IDs require the class + * {@code sun.net.www.protocol.urn.Handler} for Sun JVMs). + * This class loading will fail in many environments such as web-servers, + * servlet containers, application servers, or java web start where a user + * class loader is used to load all JXTA resources. + * + * @deprecated You should convert code which creates JXTA IDs to instead + * use {@code IDFactory.fromURI( new URI(...) )}. This method was only + * provided to overcome problems with registration of URL handlers in + * foreign class loader environments (Servlets, Applets, JNLP, etc.). + * + * @param protocol The protocol for this URL + * @param host The host for this URL + * @param file The file for this URL + * @return a newly created URL for the resource specified. + * @throws MalformedURLException if an unknown protocol is specified. + */ + @Deprecated + public static URL jxtaURL(String protocol, String host, String file) throws MalformedURLException { + return new URL(protocol, host, -1, file, sun.net.www.protocol.urn.Handler.handler); + } + + /** + * This method should be used instead of using + * {@code new java.net.URL( )} to create URLs for use with IDFactory. + * URL construction can cause classes to be loaded using the system + * classLoader (JXTA IDs require the class + * {@code sun.net.www.protocol.urn.Handler} for Sun JVMs). + * This class loading will fail in many environments such as web-servers, + * servlet containers, application servers, or java web start where a user + * class loader is used to load all JXTA resources. + * + * @deprecated You should convert code which creates JXTA IDs from strings + * to instead use {IDFactory.fromURI( new URI(String) )}. This + * method was only provided to overcome problems with registration of URL + * handlers in foreign class loader environments (Servlets, Applets, JNLP, + * etc.). + * + * @param uri The {@code String} to parse as a URL. + * @return a newly created URL for the resource specified. + * @throws MalformedURLException if an unknown protocol is specified. + */ + @Deprecated + public static URL jxtaURL(String uri) throws MalformedURLException { + final String file = net.jxta.id.ID.URNNamespace + ":"; + URL urlCnxt = jxtaURL(net.jxta.id.ID.URIEncodingName, "", file); + + return new URL(urlCnxt, uri); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/IDFormat.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/IDFormat.java new file mode 100644 index 000000000..80fa3c21d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/IDFormat.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.id.jxta; + + +import net.jxta.id.IDFactory; + + +/** + * The 'jxta' ID Format is used for the presentation of a limited number of + * well-known ids. These are the null id, the world peer group id, and the + * default net peer group id. JXTA depends on being able to refer to these + * standard entities in a common way regardless of what other id formats are + * used, indeed this ID Format and these ids exist so that there are not a + * different representations for the ids of these entities with each ID Format. + * + *

      Rather than return its own version of these well known IDs, each ID + * Format MUST return these IDs as appropriate. + * + *

        + *
      • the null id - the NullID is often used as a placeholder in fields which + * are uninitialized.
      • + * + *
      • the world peer group id - the id of the world peer group.
      • + * + *
      • the default net peer group id - the id of the default net peer group.
      • + *
      + * + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + @see JXTA Protocols Specification : IDs + @see JXTA Protocols Specification : ?jxta? ID Format + * + **/ +public final class IDFormat { + + /** + * The name associated with this ID Format. + */ + final static String JXTAFormat = "jxta"; + + /** + * The instantiator for this ID Format which is used by the IDFactory. + * + * @since JXTA 1.0 + **/ + public static final IDFactory.URIInstantiator INSTANTIATOR = new Instantiator(); + + /** + * Private Constructor. This class cannot be instantiated. + **/ + private IDFormat() {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/Instantiator.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/Instantiator.java new file mode 100644 index 000000000..cb6f438d8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/Instantiator.java @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.id.jxta; + + +import net.jxta.codat.CodatID; +import net.jxta.id.ID; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.PipeID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.UnknownServiceException; +import java.security.ProviderException; + + +/** + * Instantiator for the 'jxta' ID Format. + * + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.id.jxta.IDFormat + */ +final class Instantiator implements net.jxta.id.IDFactory.URIInstantiator { + + /** + * This table maps the textual values of the well known ids to the + * singleton classes which match those textual names. + */ + final static Object[][] wellKnownIDs = { + { net.jxta.id.ID.nullID.getUniqueValue(), net.jxta.id.ID.nullID} + , + + { net.jxta.peergroup.PeerGroupID.worldPeerGroupID.getUniqueValue(), net.jxta.peergroup.PeerGroupID.worldPeerGroupID} + , + + { + net.jxta.peergroup.PeerGroupID.defaultNetPeerGroupID.getUniqueValue() + , + net.jxta.peergroup.PeerGroupID.defaultNetPeerGroupID} + }; + + /** + * {@inheritDoc} + */ + public String getSupportedIDFormat() { + return IDFormat.JXTAFormat; + } + + /** + * {@inheritDoc} + */ + @Deprecated + public ID fromURL(URL source) throws MalformedURLException, UnknownServiceException { + + // check the protocol + if (!ID.URIEncodingName.equalsIgnoreCase(source.getProtocol())) { + throw new UnknownServiceException("URI protocol type was not as expected."); + } + + String encoded = source.getFile(); + + int colonAt = encoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new UnknownServiceException("URN namespace was missing."); + } + + // check the namespace + if (!ID.URNNamespace.equalsIgnoreCase(encoded.substring(0, colonAt))) { + throw new UnknownServiceException("URN namespace was not as expected."); + } + + // skip the namespace portion and the colon + encoded = encoded.substring(colonAt + 1); + + int dashAt = encoded.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new UnknownServiceException("JXTA ID Format was missing."); + } + + if (!encoded.substring(0, dashAt).equals(getSupportedIDFormat())) { + throw new UnknownServiceException("JXTA ID Format was not as expected."); + } + + for (Object[] wellKnownID : wellKnownIDs) { + if (encoded.equalsIgnoreCase(wellKnownID[0].toString())) { + return (ID) wellKnownID[1]; + } + } + + throw new MalformedURLException("unrecognized id"); + } + + /** + * {@inheritDoc} + */ + public CodatID newCodatID(PeerGroupID groupID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public CodatID newCodatID(PeerGroupID groupID, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public CodatID newCodatID(PeerGroupID groupID, InputStream in) throws IOException { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public CodatID newCodatID(PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public PeerID newPeerID(PeerGroupID groupID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public PeerID newPeerID(PeerGroupID groupID, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID() { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public PipeID newPipeID(PeerGroupID groupID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public PipeID newPipeID(PeerGroupID groupID, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public ModuleClassID newModuleClassID() { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public ModuleClassID newModuleClassID(ModuleClassID classID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public ModuleSpecID newModuleSpecID(ModuleClassID classID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + */ + public ID fromURI(URI source) throws URISyntaxException { + + // check the protocol + if (!ID.URIEncodingName.equalsIgnoreCase(source.getScheme())) { + throw new URISyntaxException(source.toString(), "URI scheme was not as expected."); + } + + String decoded = source.getSchemeSpecificPart(); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new URISyntaxException(source.toString(), "URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new URISyntaxException(source.toString() + , + "URN namespace was not as expected. (" + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + return fromURNNamespaceSpecificPart(decoded); + } + + /** + * {@inheritDoc} + */ + public ID fromURNNamespaceSpecificPart(String source) throws URISyntaxException { + int dashAt = source.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new URISyntaxException(source, "URN jxta namespace IDFormat was missing."); + } + + if (!source.substring(0, dashAt).equals(getSupportedIDFormat())) { + throw new URISyntaxException(source, "JXTA ID Format was not as expected."); + } + + for (Object[] wellKnownID : wellKnownIDs) { + if (source.equalsIgnoreCase(wellKnownID[0].toString())) { + return (ID) wellKnownID[1]; + } + } + + throw new URISyntaxException(source, "unrecognized id"); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/package.html new file mode 100644 index 000000000..2e98afe45 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/jxta/package.html @@ -0,0 +1,29 @@ + + + + + + + The 'jxta' ID Format is used for the presentation of a limited number of + well-known ids. These are the null id, the world peer group id, and the + default net peer group id. JXTA depends on being able to refer to these + standard entities in a common way regardless of what other id formats are + used, indeed this ID format and these ids exist so that there are not a + different representations for the ids of these entities with each id format. + +

      Rather than return its own version of these well known ids, each ID + format MUST return these IDs as appropriate. + +

        +
      • the null id - the NullID is often used as a placeholder in fields which + are uninitialized.
      • + +
      • the world peer group id - the id of the world peer group.
      • + +
      • the default net peer group id - the id of the default net peer group.
      • +
      + + @see JXTA Protocols Specification : IDs + @see JXTA Protocols Specification : ?jxta? ID Format + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/package.html new file mode 100644 index 000000000..85423115a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/id/package.html @@ -0,0 +1,12 @@ + + + + + + + IDs are used within JXTA to refer to peers, peer groups, pipes and other + types of resources. + + @see JXTA Protocols Specification : IDs + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/logging/Logging.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/logging/Logging.java new file mode 100644 index 000000000..b1624cd98 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/logging/Logging.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2001-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.logging; + + +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class defines constants for JXTA JSE's logging facilities. In this + * implementation the constants are initialized based upon the value of the + * Java System property {@code net.jxta.logging.Logging}. This implementation + * defines all of the public constants as {@code final} which enables the + * JVM/JIT to optimize out the logging code when appropriately configured. + *

      + *

      Alternate implementations of this class could; + *

      + *

        + *
      • Initialize the public constants with manifest constants, ie. + * {@code true} or {@code false} which would allow the Java compiler to + * optimize out logging code at compile time.
      • + *

        + *

      • Remove the {@code final} qualifier from the constants and provide + * additional methods to dynamically set the logging configuration at runtime. + *
      • + *
      + * + * To control logging within applications : + * + *
      + * 
      + * System.setProperty("net.jxta.logging.Logging", "FINEST");
      + * System.setProperty("net.jxta.level", "FINEST");
      + * System.setProperty("java.util.logging.config.file", "/home/userhome/logging.properties");
      + * 
      + * 
      + * + *

      + * Sample logging properties : + *

      + *

      + * 
      + * # default file output is in user's home directory.
      + * java.util.logging.FileHandler.pattern = %h/java%u.log
      + * java.util.logging.FileHandler.limit = 50000
      + * java.util.logging.FileHandler.count = 1
      + * java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
      + * 
      + * # Limit the message that are printed on the console to INFO and above
      + * java.util.logging.ConsoleHandler.level = FINEST
      + * java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
      + *
      + * # Facility specific properties.
      + * # Provides extra control for each logger.
      + * #
      + * # For example, set the net.jxta.impi.pipe.PipeResolver logger to only log SEVERE
      + * # messages:
      + * net.jxta.impi.pipe.PipeResolver.level = FINEST
      + * 
      + * 
      + */ +public final class Logging { + + /** + * Our Logger ! + */ + private final static Logger LOG = Logger.getLogger(Logging.class.getName()); + + /** + * The name of the system property from which we will attempt to read our + * logging configuration. + */ + public final static String JXTA_LOGGING_PROPERTY = "net.jxta.logging.Logging"; + + /** + * The default logging level. + */ + private final static Level DEFAULT_LOGGING_LEVEL = Level.FINEST; + + /** + * The logging level for this run. + */ + public final static Level MIN_SHOW_LEVEL; + + /** + * Is Level.FINEST enabled? + */ + public final static boolean SHOW_FINEST; + + /** + * Is Level.FINER enabled? + */ + public final static boolean SHOW_FINER; + + /** + * Is Level.FINE enabled? + */ + public final static boolean SHOW_FINE; + + /** + * Is Level.CONFIG enabled? + */ + public final static boolean SHOW_CONFIG; + + /** + * Is Level.INFO enabled? + */ + public final static boolean SHOW_INFO; + + /** + * Is Level.WARNING enabled? + */ + public final static boolean SHOW_WARNING; + + /** + * Is Level.SEVERE enabled? + */ + public final static boolean SHOW_SEVERE; + + /* Initialize the constants */ + static { + Level setLevel = DEFAULT_LOGGING_LEVEL; + + try { + String propertyLevel = System.getProperty(JXTA_LOGGING_PROPERTY); + + if (null != propertyLevel) { + setLevel = Level.parse(propertyLevel); + } + } catch (SecurityException disallowed) { + LOG.log(Level.WARNING, "Could not read configuration property.", disallowed); + } + + // Set the default level for the JXTA packages so that everything below + // inherits our default. + MIN_SHOW_LEVEL = setLevel; + + SHOW_FINEST = MIN_SHOW_LEVEL.intValue() <= Level.FINEST.intValue(); + SHOW_FINER = MIN_SHOW_LEVEL.intValue() <= Level.FINER.intValue(); + SHOW_FINE = MIN_SHOW_LEVEL.intValue() <= Level.FINE.intValue(); + SHOW_CONFIG = MIN_SHOW_LEVEL.intValue() <= Level.CONFIG.intValue(); + SHOW_INFO = MIN_SHOW_LEVEL.intValue() <= Level.INFO.intValue(); + SHOW_WARNING = MIN_SHOW_LEVEL.intValue() <= Level.WARNING.intValue(); + SHOW_SEVERE = MIN_SHOW_LEVEL.intValue() <= Level.SEVERE.intValue(); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Logging enabled for level : " + MIN_SHOW_LEVEL); + } + } + + /** + * This class is not meant be instantiated. + */ + private Logging() {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/logging/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/logging/package.html new file mode 100644 index 000000000..d2b0468fc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/logging/package.html @@ -0,0 +1,39 @@ + + + + + + + Provides global control over use of logging by JXSE. + +

      The provided Logging.java file is only one of several + practical implementations. The implementation strategies for + Logging.java fall into three basic categories: + +

      +
      final static SHOW_* = <value>;
      +
      All of the SHOW_ fields are defined with literal + expressions allowing their value to be calculated at compile time. This + varient allows JXSE to be compiled such that logging is entirely + disabled (if <value> is false) and + the logging code is not even present in the compiled bytecode.
      + +
      final static SHOW_*;
      +
      The default. All of the SHOW_ fields are defined in + a static initializer based upon a calculated value. Since their value + cannot be known at compile time the resulting bytecode will contain + the conditional logging code. Since the SHOW_ fields are + final the JVM JIT can still optimize the bytecode as it is + dynamically compiled.
      + +
      static SHOW_*;
      +
      All of the SHOW_ fields are defined in + a static initializer based upon a calculated value and may be redefined + at any time. Since their value cannot be known at compile time the + resulting bytecode will contain the conditional logging code. The values + of the SHOW_ may be changed at any time to dynamically + alter the logging behaviour. +
      +
      + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/Authenticator.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/Authenticator.java new file mode 100644 index 000000000..8f1973654 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/Authenticator.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.membership; + + +import net.jxta.credential.AuthenticationCredential; + + +/** + * An Authenticator is returned by the + * {@linkplain MembershipService#apply(AuthenticationCredential) apply()} to the + * Membership Service of a peergroup. The Membership + When the authenticator has been completed it is + * returned to the Membership Service via the "Join" operation. + * + *

      The mechanism for completing the authentication object is unique for each + * authentication method. (That's the whole point of writing a Membership + * Service). The only common operation is isReadyForJoin, which + * provides information as to whether you have completed the authenticator + * correctly. + * + * @see net.jxta.membership.MembershipService + * @see net.jxta.credential.Credential + * @see net.jxta.credential.AuthenticationCredential + */ +public interface Authenticator { + + /** + * Returns the name of this authentication method. This should be the same + * name which was used in the Authentication credential. + * + * @return String containing the name of this authentication method. + **/ + public String getMethodName(); + + /** + * Return the Authentication Credential associated with this authenticator, + * if any. + * + * @return the AutheticationCredential which was provided to the + * {@link MembershipService#apply(AuthenticationCredential)}. + **/ + public AuthenticationCredential getAuthenticationCredential(); + + /** + * Returns the service which generated this authenticator. This is the + * service which provided this authenticator and the service which will + * accept this authenticator when the authenticator is + * completed. + * + * @return the MembershipService service associated with this authenticator. + **/ + public MembershipService getSourceService(); + + /** + * Returns true if this Authenticator has been satisfied and is ready + * for submission to {@link MembershipService#join(Authenticator)}. Some + * authenticators may behave asynchronously and this method can be used to + * determine if the authentication process has completed. + *

      This method provides no distinction between incomplete authentication + * and failed authentication. + * + * @see MembershipService#join(Authenticator) + * + * @return true if the authenticator object is complete and ready for + * submitting to the Membership Service service for + * {@link MembershipService#join(Authenticator)}, otherwise false. + **/ + public boolean isReadyForJoin(); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/InteractiveAuthenticator.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/InteractiveAuthenticator.java new file mode 100644 index 000000000..24a2322ec --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/InteractiveAuthenticator.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.membership; + + +/** + * Extension to standard Authenticator for authenticators which support + * interactive authentication with a human user. + * + *

      May be requested as authentication method + * "InteractiveAuthentication" of Membership services which support + * it. (this will be an alias for one of the service's own methods). + **/ +public interface InteractiveAuthenticator extends Authenticator { + + /** + * Perform user interface interaction with user. If result is + * false then + * {@link net.jxta.membership.Authenticator#isReadyForJoin()} will + * also return false. + * + * @return true if the interaction was not cancelled otherwise + * false. + **/ + public boolean interact(); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/MembershipService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/MembershipService.java new file mode 100644 index 000000000..398d20584 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/MembershipService.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.membership; + + +import java.beans.PropertyChangeListener; +import java.util.Enumeration; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.credential.Credential; +import net.jxta.document.Element; +import net.jxta.service.Service; + +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; + + +/** + * Allows a peer to establish an identity within a peer group. Identities are + * used by services and applications to determine the capabilities available to + * peers. A peer have any number of identities at one time. Once an identity + * has been established a Credential object is available which allows the peer + * to prove that it rightfully has that identity. + * + *

      The sequence for associating an identity with a peer within a peer + * group is as follows: + * + *

      + * + * + * + * + * + * + * + * + *
      ApplyAn application or service provides the membership service with an + * initial credential which may be used by the membership service to determine + * the method of authentication to be used for establishing the identity. + * If the membership service implementations allows authentication using the + * requested mechanism then an {@link Authenticator} object is returned. + *
      JoinThe application or service completes the authenticator. This may involve + * presenting a user interface, completing challenges, etc. How the + * authenticator is completed depends on the type of membership service and + * authenticator in use. + * + *

      Once completed, the authenticator is returned to the membership service. + * If the authenticator has been correctly completed, a new credential for the + * new identity will be available to the peer from the membership service. + *

      ResignWhenever the application or service no longer wishes to no longer use the + * identities it has claimed, it may resign from the peergroup. This will cause + * any identity credentials held by the membership service to discarded. + *
      + * + * @see net.jxta.credential.Credential + * @see net.jxta.credential.AuthenticationCredential + * + */ +public interface MembershipService extends Service { + + /** + * Property name for the default credential bound property. + */ + public final static String DEFAULT_CREDENTIAL_PROPERTY = "defaultCredential"; + + /** + * Property name for credential addition bound property. + */ + public final static String ADD_CREDENTIAL_PROPERTY = "addCredential"; + + /** + * Request the necessary credentials to join the group with which this + * service is associated. + * + * @param application The authentication Credential associated with this + * membership application. See + * {@link net.jxta.credential.AuthenticationCredential} + * for more information. + * @return An Authenticator for the membership service. + * + * @throws PeerGroupException Thrown in the event of errors. + * @throws ProtocolNotSupportedException if the authentication method requested + * in the application is not supported by this service. + */ + public Authenticator apply(AuthenticationCredential application) throws PeerGroupException, ProtocolNotSupportedException; + + /** + * Join the group by virtue of the completed authentication provided. + * + * @param authenticated the completed authentication. + * @return Credential the credential for this completed authentication. + * @throws PeerGroupException Thrown in the event of errors. + */ + public Credential join(Authenticator authenticated) throws PeerGroupException; + + /** + * Resign all credentials which were previously gained through prior + * {@link #join(Authenticator) join()} operations. + * + * @throws PeerGroupException Thrown in the event of errors. + */ + public void resign() throws PeerGroupException; + + /** + * Returns the default credential for this peer. + * + * @return The current default Credential or {@code null} if there is no + * current default. + * @throws PeerGroupException Thrown in the event of errors. + */ + public Credential getDefaultCredential() throws PeerGroupException; + + /** + * Returns the current credentials for this peer. + * + * @return Enumeration of the Credentials currently associated with this + * peer for this peergroup. + * @throws PeerGroupException Thrown in the event of errors. + */ + public Enumeration getCurrentCredentials() throws PeerGroupException; + + /** + * Returns the authentication credentials which were used to establish the + * current identities. + * + * @deprecated This interface is being removed in favour of individual + * Credentials providing their AuthenticationCredential as appropriate. + * + * @return Enumeration of the AuthenticationCredentials which were used to + * establish the current identities. + * @throws PeerGroupException Thrown in the event of errors. + */ + @Deprecated + public Enumeration getAuthCredentials() throws PeerGroupException; + + /** + * Given a fragment of a StructuredDocument, reconstruct a Credential object + * from that fragment. + * + * @return Credential The created credential + * @param element The StructuredDocument fragment to use for building the + * credential. + * @throws PeerGroupException Thrown in the event of errors. + * @throws Exception Thrown in the event of errors. + */ + public Credential makeCredential(Element element) throws PeerGroupException, Exception; + + /** + * Add a listener + * + * @param listener the listener + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + /** + * Add a listener. Available properties from all Membership Services are : + * + *

        + *
      • {@code defaultCredential}
      • + *
      • {@code addCredential}
      • + *
      + * + *

      Membership Services may offer additional properties. + * + * @param propertyName The property to watch + * @param listener The listener + */ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); + + /** + * Remove a listener + * + * @param listener the listener + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/doc-files/memberAndAccess.png b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/doc-files/memberAndAccess.png new file mode 100644 index 000000000..993ca71b7 Binary files /dev/null and b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/doc-files/memberAndAccess.png differ diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/package.html new file mode 100644 index 000000000..44e272ccf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/membership/package.html @@ -0,0 +1,30 @@ + + + + + + + The Membership Service allows a peer to establish an identity within a peer + group. A peer have any number of identities at one time. Once an identity + has been established a credential object is available which allows the peer + to prove that it rightfully has that identity. Applications and services + may restrict certain operations to specific identities. JXTA J2SE provides + the Access Service to assist applications in matching privledges to + identities. + +

      The Membership Service is not associated with a particular JXTA + protocol. Each Membership Service implementation is responsible for its own + protocol definition (if any). This approach is used primarily so that JXTA + bridges well to existing common Membership and Access technologies. For + example; PKI, Kerberos, NTLM and API based interfaces such as PAM and JAAS. + +

      + Diagram
+showing common flow of usage for Membership and Access Services + + @see net.jxta.credential.Credential + @see net.jxta.credential.AuthenticationCredential + @see net.jxta.access.AccessService + @see JXTA Protocols Specification : Protocols + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorEvent.java new file mode 100644 index 000000000..befd0941a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorEvent.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.peergroup.*; +import net.jxta.peer.*; + + +/** + * Information regarding a Remote Monitor's Report + **/ +public class MonitorEvent { + + /** Report received and is available in the event **/ + public static final int OK = 200; + + /** Report will not come because the registration was cancelled locally **/ + public static final int CANCELLED_LOCALLY = 201; + + /** Report will not come because the registration was cancelled remotely **/ + public static final int CANCELLED_REMOTELY = 202; + + /** Report will not come because the of a Timeout **/ + public static final int TIMEOUT = 203; + + /** Report will not come because the Remote peer has refused it (for security, not supported or load reasons) **/ + public static final int REFUSED = 204; + + /** Report will not come because the requested report rate is not supported/invalid **/ + public static final int INVALID_REPORT_RATE = 205; + + /** Report will not come because the provided MonitorFilter was invalid **/ + public static final int INVALID_MONITOR_FILTER = 206; + + /** Further Reports will not come because the lease was cancelled **/ + public static final int LEASE_CANCELLED = 207; + + /** Further Reports will not come because the lease renewal request did not receive a response. + * In all likelihood the remote peer has failed (ie crashed) + **/ + public static final int LEASE_RENEWAL_TIMEOUT = 208; + + /** Internal Error processing Reports, probably due to a bad Monitor Implementation **/ + public static final int ERROR = 209; + + /** Further Reports will not come because this PeerGroup was destroyed locally **/ + public static final int PEERGROUP_DESTROYED = 210; + + private int type; + private int requestId; + private PeerID peerID; + private PeerGroupID peerGroupID; + private MonitorFilter monitorFilter; // FIX-ME: Is this necessary? + private long reportRate; // FIX-ME: Is this necessary? + private long leaseTime; // FIX-ME: Is this necessary? + private MonitorReport monitorReport; + + private MonitorEvent() {} + + public MonitorEvent(PeerGroupID peerGroupID, MonitorReport monitorReport) { + this.peerGroupID = peerGroupID; + this.monitorReport = monitorReport; + } + + /** + * Get the Type of Event (one of the above constants) + * + */ + public int getType() { + return type; + } + + /** + * PeerID of reporting Peer. My PeerID if local + */ + public PeerID getPeerID() { + return peerID; + } + + /** + * PeerGroup of reported event + */ + public PeerGroupID getPeerGroupID() { + return peerGroupID; + } + + /** + * MonitorFilter provided when the report was requested + */ + public MonitorFilter getMonitorFilter() { + return monitorFilter; + } + + /** + * Reporting rate (unless Cumulative) specified when the report was requested + */ + public long getReportRate() { + return reportRate; + } + + /** + * Most recent Lease time granted (not specified if a cumulative Report) + */ + public long getLeaseTime() { + return leaseTime; + } + + /** + * Get the corresponding MonitorReport + */ + public MonitorReport getMonitorReport() { + return monitorReport; + } + + /** + * The Validated MonitorFilter from the registration or query + * + * @return MonitorFilter + */ + public MonitorFilter getValidMonitorFilter() { + return monitorFilter; + } + + /** + * Convenience factory method + */ + public static MonitorEvent createRemoteMonitorReportEvent(PeerID peerID, int requestId, MonitorReport monitorReport) { + MonitorEvent event = new MonitorEvent(); + + event.type = OK; + event.peerID = peerID; + event.requestId = requestId; + event.monitorReport = monitorReport; + return event; + } + + /** + * Convenience factory method + */ + public static MonitorEvent createFailureEvent(int type, PeerID peerID, int requestId) { + MonitorEvent event = new MonitorEvent(); + + event.type = type; + event.peerID = peerID; + event.requestId = requestId; + return event; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorException.java new file mode 100644 index 000000000..ca4df0438 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorException.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.exception.*; + +@SuppressWarnings("serial") +public class MonitorException extends JxtaException { + + /** Monitoring Not Supported **/ + public final static int METERING_NOT_SUPPORTED = 7000; + + /** Error during Serialization/Deserialization **/ + public final static int SERIALIZATION = 7001; + + /** Monitor Report Provided **/ + public final static int MONITOR_REPORT = 7002; + + /** Invalid MonitorFilter **/ + public final static int FILTER_EXCEPTION = 7003; + + private int type; + + /** + * MonitorException + * + * @param type (see above) + * @param message + */ + public MonitorException(int type, String message) { + super(message); + this.type = type; + } + + /** + * MonitorException + * + * @param type + * @param message + * @param e + */ + public MonitorException(int type, String message, Exception e) { + super(message, e); + this.type = type; + } + + /** + * get Type of event (see constants above) + */ + public int getType() { + return type; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorFilter.java new file mode 100644 index 000000000..06acba896 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorFilter.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.document.*; +import net.jxta.id.*; +import net.jxta.platform.*; +import net.jxta.util.documentSerializable.*; +import java.util.*; +import java.net.*; +import net.jxta.exception.*; +import net.jxta.util.*; + + +/** + * A Monitor Filter specifies which service-specific metrics should be obtained by the Monitor. + * It contains a collection of ServiceMonitor specific ServiceMonitorFilters. + * + **/ +public class MonitorFilter implements DocumentSerializable { + private String description; + private Map serviceMonitorFilters = new HashMap(); + private List unknownModuleClassIDs; + + /** + * MonitorFilter + * + **/ + public MonitorFilter() {} + + /** + * MonitorFilter + * + * @param description + **/ + public MonitorFilter(String description) { + this.description = description; + } + + /** + * Add a ServiceMonitorFilter to this MonitorFilter + * + * @param serviceMonitorFilter Service Specific Filter + * @exception MonitorFilterException + * @return ServiceMonitorFilter Modified Filter to the capabilities of the service + **/ + public ServiceMonitorFilter addServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter) throws MonitorFilterException { + ModuleClassID moduleClassID = serviceMonitorFilter.getModuleClassID(); + + if (serviceMonitorFilters.get(moduleClassID) != null) { + throw new MonitorFilterException("Attempt to add a second Monitor Filter for: " + moduleClassID); + } + serviceMonitorFilters.put(moduleClassID, serviceMonitorFilter); + return serviceMonitorFilter; + } + + /** + * Get ServiceMonitorFilter subfilter + * + * @param moduleClassID ServiceMonitor's moduleClassID + * @return ServiceMonitorFilter SubFilter or null if not found + **/ + public ServiceMonitorFilter getServiceMonitorFilter(ModuleClassID moduleClassID) { + return serviceMonitorFilters.get(moduleClassID); + } + + /** + * remove ServiceMonitorFilter + * + * @param moduleClassID ServiceMonitor's moduleClassID + **/ + public void removeServiceMonitorFilter(ModuleClassID moduleClassID) { + serviceMonitorFilters.remove(moduleClassID); + } + + /** + * Get the number of subfilters + * + * @return int + **/ + public int getServiceMonitorFilterCount() { + return serviceMonitorFilters.size(); + } + + /** + * get ModuleClassIDs of contained subfilters + * + * @return Iterator of ServiceMonitor ClassIDs + **/ + public Iterator getModuleClassIDs() { + return serviceMonitorFilters.keySet().iterator(); + } + + /** + * Get Iterator of all ServiceMonitorFilters subfilters + * + * @return Iterator of all ServiceMonitorFilters subfilters + **/ + public Iterator getServiceMonitorFilters() { + return serviceMonitorFilters.values().iterator(); + } + + /** + * Were any filters removed from this MonitorFilter (particularly when received remotely and deserialized) + * + **/ + public boolean isUnknownModuleClassIDs() { + return (unknownModuleClassIDs != null); + } + + /** + * Get a list of ModuleClassIDs for subfilters that could not be deserialized because they weren't registered + * @see MonitorResources + * + * @return Iterator + **/ + public Iterator getUnknownModuleClassIDs() { + if (unknownModuleClassIDs != null) { + return unknownModuleClassIDs.iterator(); + } else { + return new LinkedList().iterator(); + } + } + + /** + * Get Description + * + **/ + public String getDescription() { + return description; + } + + /** + * {@inheritDoc} + **/ + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addString(element, "description", description); + + for (Iterator i = serviceMonitorFilters.values().iterator(); i.hasNext();) { + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) i.next(); + + Element serviceElement = DocumentSerializableUtilities.createChildElement(element, "service"); + + DocumentSerializableUtilities.addString(serviceElement, "moduleClassID" + , + serviceMonitorFilter.getModuleClassID().toString()); + DocumentSerializableUtilities.addDocumentSerializable(serviceElement, "serviceFilter", serviceMonitorFilter); + } + } + + /** + * {@inheritDoc} + **/ + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element serviceElement = (TextElement) e.nextElement(); + String tagName = (String) serviceElement.getKey(); + + if (tagName.equals("service")) { + try { + ModuleClassID moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(serviceElement, "moduleClassID", "ERROR"))); + + try { + ServiceMonitorFilter serviceMonitorFilter = MonitorResources.createServiceMonitorFilter(moduleClassID); + + serviceMonitorFilter.init(moduleClassID); + Element serviceMonitorFilterElement = DocumentSerializableUtilities.getChildElement(serviceElement + , + "serviceFilter"); + + serviceMonitorFilter.initializeFrom(serviceMonitorFilterElement); + serviceMonitorFilters.put(moduleClassID, serviceMonitorFilter); + } catch (Exception ex) { + if (unknownModuleClassIDs == null) { + unknownModuleClassIDs = new LinkedList(); + } + + unknownModuleClassIDs.add(moduleClassID); + } + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't get ModuleClassID", jex); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorFilterException.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorFilterException.java new file mode 100644 index 000000000..b0d459ef5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorFilterException.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.platform.*; + + +/** + * Monitor Filter Exception + */ +public class MonitorFilterException extends MonitorException { + public final static String SERVICE_NOT_SUPPORTED = "Service Not Supported"; + public final static String REPORT_RATE_NOT_SUPPORTED = "Report Rate Not Supported"; + ModuleClassID moduleClassID; + long reportRate; + + /** + * MonitorFilterException + * + * @param message + **/ + public MonitorFilterException(String message) { + super(MonitorException.FILTER_EXCEPTION, message); + } + + /** + * MonitorFilterException + * + * @param message + * @param e + **/ + public MonitorFilterException(String message, Exception e) { + super(MonitorException.FILTER_EXCEPTION, message, e); + } + + /** + * MonitorFilterException + * + * @param message + * @param moduleClassID + **/ + public MonitorFilterException(String message, ModuleClassID moduleClassID) { + super(MonitorException.FILTER_EXCEPTION, message); + this.moduleClassID = moduleClassID; + } + + /** + * MonitorFilterException + * + * @param message + * @param reportRate + **/ + public MonitorFilterException(String message, long reportRate) { + super(MonitorException.FILTER_EXCEPTION, message); + this.reportRate = reportRate; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorListener.java new file mode 100644 index 000000000..59ffc1f18 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorListener.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +/** + * Monitor Listener for Local or Remote Monitoring + **/ +package net.jxta.meter; + + +public interface MonitorListener { + + /** + * A Report is ready for Processing. It may either be a cumulative or delta Report + * + * @param monitorEvent Event containing MonitorReport + **/ + public void processMonitorReport(MonitorEvent monitorEvent); + + /** + * Monitor Reporting has been cancelled. The Event contains the reason + * + * @param monitorEvent Event containing Reason + **/ + public void monitorReportingCancelled(MonitorEvent monitorEvent); + + /** + * Request for Monitoring Failed + * + * @param monitorEvent Event containing Reason + **/ + public void monitorRequestFailed(MonitorEvent monitorEvent); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorReport.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorReport.java new file mode 100644 index 000000000..3be7ab2b1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorReport.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import java.net.URI; +import java.net.URISyntaxException; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.id.*; +import net.jxta.peer.*; +import net.jxta.platform.*; +import net.jxta.util.*; +import net.jxta.exception.*; + +import java.util.*; + + +/** + * A Monitor Report contains service-specific metrics for each service specified in the + * corresponding MonitorFilter (provided when the report was requested). + * + **/ +public class MonitorReport implements DocumentSerializable { + private long toTime; + private long fromTime; + private boolean isCumulative; + private Map serviceMetrics = new HashMap(); + private List unknownModuleClassIDs; + + /** + * Monitor Reports are generally not created by applications, but by the Monitor or PeerInfoService + * + **/ + public MonitorReport() {} + + /** + * Monitor Reports are generally not created by applications, but by the Monitor or PeerInfoService + * + * @param fromTime + * @param toTime + * @param isCumulative + **/ + public MonitorReport(long fromTime, long toTime, boolean isCumulative) { + this.fromTime = fromTime; + this.toTime = toTime; + this.isCumulative = isCumulative; + } + + /** + * Begin time that this report is representing + **/ + public long getFromTime() { + return fromTime; + } + + /** + * End time that this report is representing + * + * @return long + **/ + public long getToTime() { + return toTime; + } + + /** + * Does this report contain metrics from the last time the monitor was reset or is this a delta report + **/ + public boolean isCumulative() { + return isCumulative; + } + + /** + * Get the contained service-specific ServiceMetrics + * + **/ + public Iterator getServiceMetrics() { + return serviceMetrics.values().iterator(); + } + + /** + * Get the contained service-specific ServiceMetric for the specified ServiceMonitor's classID + * + * @param moduleClassID ServiceMonitor's classID + * @return ServiceMetric ServiceMetric or null if Not Found + **/ + public ServiceMetric getServiceMetric(ModuleClassID moduleClassID) { + return serviceMetrics.get(moduleClassID); + } + + /** + * addServiceMetric are generally not created by applications, but by the Monitor or PeerInfoService + **/ + public void addServiceMetric(ServiceMetric serviceMetric) { + serviceMetrics.put(serviceMetric.getModuleClassID(), serviceMetric); + } + + /** + * addServiceMetric are generally not created by applications, but by the Monitor or PeerInfoService + **/ + public void addServiceMetric(ModuleClassID moduleClassID, ServiceMetric serviceMetric) { + serviceMetrics.put(moduleClassID, serviceMetric); + } + + /** + * Did this report contain any serviceMetrics for which there weren't registered ServiceMetric classes + * @see MonitorResources + **/ + public boolean isUnknownModuleClassIDs() { + return (unknownModuleClassIDs != null); + } + + /** + * Get iterator of ModuleClassIDs of serviceMetrics for which there weren't registered ServiceMetric classes + * + * @return Iterator + **/ + public Iterator getUnknownModuleClassIDs() { + if (unknownModuleClassIDs != null) { + return unknownModuleClassIDs.iterator(); + } else { + return new LinkedList().iterator(); + } + } + + /** + * {@inheritDoc} + **/ + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addLong(element, "toTime", toTime); + DocumentSerializableUtilities.addLong(element, "fromTime", fromTime); + DocumentSerializableUtilities.addBoolean(element, "isCumulative", isCumulative); + + for (Iterator i = serviceMetrics.values().iterator(); i.hasNext();) { + ServiceMetric serviceMetric = (ServiceMetric) i.next(); + + Element serviceMetricElement = DocumentSerializableUtilities.createChildElement(element, "service"); + + DocumentSerializableUtilities.addString(serviceMetricElement, "moduleClassID" + , + serviceMetric.getModuleClassID().toString()); + DocumentSerializableUtilities.addDocumentSerializable(serviceMetricElement, "serviceMetric", serviceMetric); + } + + } + + /** + * {@inheritDoc} + **/ + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("toTime")) { + toTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("fromTime")) { + fromTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("isCumulative")) { + isCumulative = DocumentSerializableUtilities.getBoolean(childElement); + } else if (tagName.equals("service")) { + try { + ModuleClassID moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement, "moduleClassID", "ERROR"))); + + try { + ServiceMetric serviceMetric = MonitorResources.createServiceMetric(moduleClassID); + + serviceMetric.init(moduleClassID); + Element serviceMetricElement = DocumentSerializableUtilities.getChildElement(childElement, "serviceMetric"); + + serviceMetric.initializeFrom(serviceMetricElement); + serviceMetrics.put(moduleClassID, serviceMetric); + } catch (Exception ex) { + if (unknownModuleClassIDs == null) { + unknownModuleClassIDs = new LinkedList(); + } + + unknownModuleClassIDs.add(moduleClassID); + } + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't get ModuleClassID", jex); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorResources.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorResources.java new file mode 100644 index 000000000..cf593fa67 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/MonitorResources.java @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import java.net.URI; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; +import net.jxta.exception.JxtaException; +import net.jxta.id.ID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.util.AdvertisementUtilities; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; + + +/** + * Registration point for types of ServiceMonitors's Advertisements, ServiceMetrics and ServiceMonitorFilters + * based upon the ModuleClassID for the ServiceMonitor + **/ + +public class MonitorResources { + public static final String SERVICE_MONITOR_TAG = "serviceMonitor"; + public static final String SERVICE_MONITOR_ADVERTISEMENT_TAG = ModuleImplAdvertisement.getAdvertisementType(); + public static final String CLASS_ID_TAG = "moduleClassID"; + public static final String SERVICE_TITLE_TAG = "serviceTitle"; + public static final String SERVICE_MONITOR_IMPL_TAG = "serviceMonitorImpl"; + public static final String METRIC_CLASS_TAG = "serviceMetric"; + public static final String FILTER_CLASS_TAG = "serviceMonitorFilter"; + + private static Map registeredMonitorResources = new Hashtable(); + + /** + * Prefix string for all of the Well Known IDs declared in this interface. + **/ + private static final String WK_ID_PREFIX = ID.URIEncodingName + ":" + ID.URNNamespace + ":uuid-DeadBeefDeafBabaFeedBabe"; + + /** + * Well known classes for the basic service Monitors. + + * To keep their string representation shorter, we put our small spec + * or role pseudo unique ID at the front of the second UUID string. + * Base classes do not need an explicit second UUID string because it is + * all 0. + * The type is always the last two characters, nomatter the total length. + */ + + /** + * Well known module class identifier: monitor service + */ + public static final ModuleClassID monitorServiceClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000011F05")); + + /** + * Well known module class identifier: resolver service + */ + public static final ModuleClassID resolverServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010205")); + + /** + * Well known module class identifier: discovery service + */ + public static final ModuleClassID discoveryServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010305")); + + /** + * Well known module class identifier: pipe service + */ + public static final ModuleClassID pipeServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010405")); + + /** + * Well known module class identifier: membership service + */ + public static final ModuleClassID membershipServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010505")); + + /** + * Well known module class identifier: rendezvous service + */ + public static final ModuleClassID rendezvousServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010605")); + + /** + * Well known module class identifier: peerinfo service + */ + public static final ModuleClassID peerinfoServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010705")); + + /** + * Well known module class identifier: endpoint service + */ + public static final ModuleClassID endpointServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010805")); + + /* + * FIXME: EndpointProtocols should probably all be of the same class + * and of different specs and roles... But we'll take a shortcut for now. + */ + + /** + * Well known module class identifier: transport protocol + */ + public static final ModuleClassID transportServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010905")); + + /** + * Well known module class identifier: router protocol + */ + public static final ModuleClassID routerServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010B05")); + + /** + * Well known module class identifier: tlsProtocol + */ + public static final ModuleClassID tlsProtoServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "00000105")); + + /** + * Well known module class identifier: ProxyService + */ + public static final ModuleClassID proxyServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010E05")); + + /** + * Well known module class identifier: RelayProtocol + */ + public static final ModuleClassID relayServiceMonitorClassID = (ModuleClassID) + ID.create(URI.create(WK_ID_PREFIX + "0000010F05")); + + /** + * Well known service specification identifier: the standard monitor + */ + public static final ModuleSpecID refMonitorServiceSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "0000011F0106")); + + /** + * Well known service specification identifier: the standard resolver + */ + public static final ModuleSpecID refResolverServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001020106")); + + /** + * Well known service specification identifier: the standard discovery + */ + public static final ModuleSpecID refDiscoveryServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001030106")); + + /** + * Well known service specification identifier: the standard pipe + */ + public static final ModuleSpecID refPipeServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001040106")); + + /** + * Well known service specification identifier: the standard membership + */ + public static final ModuleSpecID refMembershipServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001050106")); + + /** + * Well known service specification identifier: the standard rendezvous + */ + public static final ModuleSpecID refRendezvousServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001060106")); + + /** + * Well known service specification identifier: the standard peerinfo + */ + public static final ModuleSpecID refPeerinfoServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001070106")); + + /** + * Well known service specification identifier: the standard endpoint + */ + public static final ModuleSpecID refEndpointServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001080106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * transport Service Monitor + */ + public static final ModuleSpecID refTransportServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "000001090106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * router + */ + public static final ModuleSpecID refRouterServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "0000010B0106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * tls endpoint protocol + */ + public static final ModuleSpecID refTlsServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "0000010D0106")); + + /** + * Well known application: the Proxy + */ + public static final ModuleSpecID refProxyServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "0000010E0106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * relay endpoint protocol + */ + public static final ModuleSpecID refRelayServiceMonitorSpecID = (ModuleSpecID) + ID.create(URI.create(WK_ID_PREFIX + "0000010F0106")); + + private static ModuleClassID standardServiceMonitorClassIDs[] = new ModuleClassID[] { + resolverServiceMonitorClassID, rendezvousServiceMonitorClassID, endpointServiceMonitorClassID + , + transportServiceMonitorClassID }; + + public static ModuleImplAdvertisement getReferenceAllPurposeMonitorServiceImplAdvertisement(boolean includeTransports) { + ModuleImplAdvertisement moduleImplAdvertisement = AdvertisementUtilities.createModuleImplAdvertisement( + refMonitorServiceSpecID, "net.jxta.impl.meter.MonitorManager", "Service Monitor"); + StructuredTextDocument param = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument( + MimeMediaType.XMLUTF8, "serviceMonitor"); + + addServiceMonitorServiceAdvertisement(param, refResolverServiceMonitorSpecID, "Resolver" + , + "net.jxta.impl.resolver.resolverMeter.ResolverServiceMonitor" + , + "net.jxta.impl.resolver.resolverMeter.ResolverServiceMetric" + , + "net.jxta.impl.resolver.resolverMeter.ResolverServiceMonitorFilter"); + + addServiceMonitorServiceAdvertisement(param, refEndpointServiceMonitorSpecID, "Endpoint" + , + "net.jxta.impl.endpoint.endpointMeter.EndpointServiceMonitor" + , + "net.jxta.impl.endpoint.endpointMeter.EndpointServiceMetric" + , + "net.jxta.impl.endpoint.endpointMeter.EndpointServiceMonitorFilter"); + + addServiceMonitorServiceAdvertisement(param, refTransportServiceMonitorSpecID, "Transport" + , + "net.jxta.impl.endpoint.transportMeter.TransportServiceMonitor" + , + "net.jxta.impl.endpoint.transportMeter.TransportServiceMetric" + , + "net.jxta.impl.endpoint.transportMeter.TransportServiceMonitorFilter"); + + addServiceMonitorServiceAdvertisement(param, refRendezvousServiceMonitorSpecID, "Rendezvous" + , + "net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMonitor" + , + "net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMetric" + , + "net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMonitorFilter"); + + moduleImplAdvertisement.setParam(param); + return moduleImplAdvertisement; + } + + private static void addServiceMonitorServiceAdvertisement(Element root, ModuleSpecID moduleSpecID, String title, String implClassName, String metricClassName, String filterClassName) { + ModuleImplAdvertisement moduleImplAdvertisement = createServiceMonitorModuleImplAdvertisement(moduleSpecID, title + , + implClassName, metricClassName, filterClassName); + + Element serviceMonitorElement = DocumentSerializableUtilities.createChildElement(root, SERVICE_MONITOR_TAG); + + ModuleClassID moduleClassID = moduleSpecID.getBaseClass(); + + DocumentSerializableUtilities.addString(serviceMonitorElement, CLASS_ID_TAG, moduleClassID.toString()); + + Element serviceMonitorAdvertisementElement = DocumentSerializableUtilities.createChildElement(serviceMonitorElement + , + SERVICE_MONITOR_ADVERTISEMENT_TAG); + Element advDoc = (Element) moduleImplAdvertisement.getDocument(MimeMediaType.XMLUTF8); + + DocumentSerializableUtilities.copyChildren(serviceMonitorAdvertisementElement, advDoc); + } + + public static ModuleImplAdvertisement createServiceMonitorModuleImplAdvertisement(ModuleSpecID moduleSpecID, String title, String implClassName, String metricClassName, String filterClassName) { + ModuleImplAdvertisement moduleImplAdvertisement = AdvertisementUtilities.createModuleImplAdvertisement(moduleSpecID + , + implClassName, "Service Monitor"); + + StructuredTextDocument param = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument( + MimeMediaType.XMLUTF8, "serviceMonitor"); + + DocumentSerializableUtilities.addString(param, SERVICE_TITLE_TAG, title); + DocumentSerializableUtilities.addString(param, METRIC_CLASS_TAG, metricClassName); + DocumentSerializableUtilities.addString(param, FILTER_CLASS_TAG, filterClassName); + moduleImplAdvertisement.setParam(param); + + return moduleImplAdvertisement; + } + + public static ModuleImplAdvertisement getServiceMonitorImplAdvertisement(ModuleClassID serviceMonitorModuleClassID, ModuleImplAdvertisement monitorServiceImplAdvertisement) { + + String classIDText = serviceMonitorModuleClassID.toString(); + + StructuredDocument param = monitorServiceImplAdvertisement.getParam(); + + for (Enumeration e = param.getChildren(SERVICE_MONITOR_TAG); e.hasMoreElements();) { + Element serviceMonitorElement = (Element) e.nextElement(); + + String serviceMonitorClassIDText = DocumentSerializableUtilities.getString(serviceMonitorElement, CLASS_ID_TAG, ""); + + if (classIDText.equals(serviceMonitorClassIDText)) { + TextElement serviceMonitorAdvertisementElement = (TextElement) DocumentSerializableUtilities.getChildElement( + serviceMonitorElement, SERVICE_MONITOR_ADVERTISEMENT_TAG); + + return (ModuleImplAdvertisement) AdvertisementFactory.newAdvertisement(serviceMonitorAdvertisementElement); + } + } + + return null; + + } + + private static class ServiceResource { + String serviceMonitorClassName; + Class serviceMonitorClass; + String serviceMonitorFilterClassName; + Class serviceMonitorFilterClass; + String serviceMetricClassName; + Class serviceMetricClass; + + ServiceResource(ModuleImplAdvertisement moduleImplAdvertisement) throws JxtaException { + try { + serviceMonitorClassName = moduleImplAdvertisement.getCode(); + + serviceMonitorFilterClassName = getServiceMonitorFilterClassName(moduleImplAdvertisement); + serviceMonitorFilterClass = Class.forName(serviceMonitorFilterClassName); + + if (!(ServiceMonitorFilter.class).isAssignableFrom(serviceMonitorFilterClass)) { + throw new JxtaException( + "Bad ServiceMonitorImplAdvertisment: " + serviceMonitorFilterClassName + + " is not a ServiceMonitorFilter"); + } + + serviceMetricClassName = getServiceMetricClassName(moduleImplAdvertisement); + serviceMetricClass = Class.forName(serviceMetricClassName); + + if (!(ServiceMetric.class).isAssignableFrom(serviceMetricClass)) { + throw new JxtaException( + "Bad ServiceMonitorImplAdvertisment: " + serviceMetricClassName + " is not a ServiceMetric"); + } + } catch (Exception e) { + throw new JxtaException("Bad ServiceMonitorImplAdvertisment: Unable to load constituent parts", e); + } + } + } + + /** + * Register the Implementation Advertisement for a ServiceMonitor Type + * This contains the Monitor, Metric and Filter classNames + */ + public static void registerServiceMonitorModuleImplAdvertisement(ModuleImplAdvertisement moduleImplAdvertisement) throws JxtaException { + ModuleClassID moduleClassID = moduleImplAdvertisement.getModuleSpecID().getBaseClass(); + + if (registeredMonitorResources.get(moduleClassID) != null) { + return; + } + + registeredMonitorResources.put(moduleClassID, new ServiceResource(moduleImplAdvertisement)); + } + + /** + * Create an empty ServiceMonitorFilter for the corresponding ModuleClassID + * + * @exception JxtaException If not found or other errors + */ + public static ServiceMonitorFilter createServiceMonitorFilter(ModuleClassID moduleClassID) throws MonitorFilterException { + try { + ServiceResource serviceResource = registeredMonitorResources.get(moduleClassID); + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) serviceResource.serviceMonitorFilterClass.newInstance(); + + serviceMonitorFilter.init(moduleClassID); + return serviceMonitorFilter; + } catch (Exception e) { + throw new MonitorFilterException("Unable to Create Filter: " + moduleClassID); // this should never happen, we already did our checks + } + } + + /** + * Create an empty Service Metric for the corresponding ModuleClassID + * + * @exception JxtaException If not found or other errors + */ + public static ServiceMetric createServiceMetric(ModuleClassID moduleClassID) throws JxtaException { + try { + ServiceResource serviceResource = registeredMonitorResources.get(moduleClassID); + ServiceMetric serviceMetric = (ServiceMetric) serviceResource.serviceMetricClass.newInstance(); + + serviceMetric.init(moduleClassID); + return serviceMetric; + } catch (Exception e) { + throw new JxtaException("Unable to Create Service Metric"); // this should never happen, we already did our checks + } + } + + /** + * get ServiceMetric ClassName from its ImplAdvertisement + */ + public static String getServiceMetricClassName(ModuleImplAdvertisement serviceMonitorModuleImplAdvertisement) { + Element param = serviceMonitorModuleImplAdvertisement.getParam(); + + return DocumentSerializableUtilities.getString(param, METRIC_CLASS_TAG, null); + } + + /** + * get ServiceMonitorFilter ClassName from its ImplAdvertisement + */ + public static String getServiceMonitorFilterClassName(ModuleImplAdvertisement serviceMonitorModuleImplAdvertisement) { + Element param = serviceMonitorModuleImplAdvertisement.getParam(); + + return DocumentSerializableUtilities.getString(param, FILTER_CLASS_TAG, null); + } + + /** + * Get a list of all registered Service Monitor types + */ + public static ModuleClassID[] getRegisteredModuleClassIDs() { + return standardServiceMonitorClassIDs.clone(); + } + + /** + * Get the name of standard Monitor Type + **/ + public static String getMonitorTypeName(ModuleClassID moduleClassID) { + if (moduleClassID.equals(monitorServiceClassID)) { + return "monitor"; + } + + if (moduleClassID.equals(resolverServiceMonitorClassID)) { + return "Resolver"; + } + + if (moduleClassID.equals(discoveryServiceMonitorClassID)) { + return "Discovery"; + } + + if (moduleClassID.equals(pipeServiceMonitorClassID)) { + return "Pipe"; + } + + if (moduleClassID.equals(membershipServiceMonitorClassID)) { + return "Membership"; + } + + if (moduleClassID.equals(rendezvousServiceMonitorClassID)) { + return "Rendezvous"; + } + + if (moduleClassID.equals(peerinfoServiceMonitorClassID)) { + return "PeerInfo"; + } + + if (moduleClassID.equals(endpointServiceMonitorClassID)) { + return "Endpoint"; + } + + if (moduleClassID.equals(transportServiceMonitorClassID)) { + return "Transport"; + } + + if (moduleClassID.equals(routerServiceMonitorClassID)) { + return "monitor"; + } + + if (moduleClassID.equals(tlsProtoServiceMonitorClassID)) { + return "Tls"; + } + + if (moduleClassID.equals(proxyServiceMonitorClassID)) { + return "Proxy"; + } + + if (moduleClassID.equals(relayServiceMonitorClassID)) { + return "Relay"; + } + + return null; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfo.java new file mode 100644 index 000000000..69645fe8c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfo.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import java.net.URI; +import java.util.Enumeration; + +import java.net.URISyntaxException; + +import net.jxta.document.Element; +import net.jxta.id.IDFactory; +import net.jxta.platform.ModuleClassID; +import net.jxta.util.documentSerializable.DocumentSerializable; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; + +import net.jxta.exception.JxtaException; + + +/** + * The Monitoring Capabilities of a Local or Remote Peer as a list of ServiceMonitor ClassIDs and supported Reporting Rates. + **/ +public class PeerMonitorInfo implements DocumentSerializable { + public static final PeerMonitorInfo NO_PEER_MONITOR_INFO = new PeerMonitorInfo(false, null, null, 0, 0); + private boolean allowsMonitoring; + private ModuleClassID[] moduleClassIDs; + private long[] reportRates; + private long lastResetTime; + private long runningTime; + + /** + * PeerMonitorInfo + * + */ + public PeerMonitorInfo() {} + + /** + * PeerMonitorInfo + * + * @param allowsMonitoring + * @param moduleClassIDs + * @param reportRates + */ + public PeerMonitorInfo(boolean allowsMonitoring, ModuleClassID[] moduleClassIDs, long[] reportRates, long lastResetTime, long runningTime) { + this.allowsMonitoring = allowsMonitoring; + this.moduleClassIDs = moduleClassIDs; + this.reportRates = reportRates; + this.lastResetTime = lastResetTime; + this.runningTime = runningTime; + } + + /** + * Allows Monitoring + */ + public boolean allowsMonitoring() { + return allowsMonitoring; + } + + /** + * Get Suported Reporting Rates (in Milliseconds) + * + * @return long[] + */ + public long[] getReportRates() { + return reportRates; + } + + /** + * Get Suported Service Monitors as a list of ModuleClassIDs + */ + public ModuleClassID[] getModuleClassIDs() { + return moduleClassIDs; + } + + /** + * Get Time that the Monitor was last Reset (probably same as startTime) + */ + public long getLastResetTime() { + return lastResetTime; + } + + /** + * Get the running time since the monitor was reset (probably same as upTime) + */ + public long getRunningTime() { + return runningTime; + } + + /** + * @inheritDoc + **/ + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addBoolean(element, "allowsMonitoring", allowsMonitoring); + DocumentSerializableUtilities.addLong(element, "lastResetTime", lastResetTime); + DocumentSerializableUtilities.addLong(element, "runningTime", runningTime); + + if (allowsMonitoring) { + DocumentSerializableUtilities.addInt(element, "numModuleClassIDs", moduleClassIDs.length); + for (int i = 0; i < moduleClassIDs.length; i++) { + ModuleClassID moduleClassID = moduleClassIDs[i]; + + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + + DocumentSerializableUtilities.addInt(element, "numReportRates", reportRates.length); + for (int i = 0; i < reportRates.length; i++) { + long reportRate = reportRates[i]; + + DocumentSerializableUtilities.addLong(element, "reportRate", reportRate); + } + } + } + + /** + * @inheritDoc + **/ + public void initializeFrom(Element element) throws DocumentSerializationException { + int numModuleClassIDs = DocumentSerializableUtilities.getInt(element, "numModuleClassIDs", 0); + + moduleClassIDs = new ModuleClassID[numModuleClassIDs]; + int moduleClassIDIndex = 0; + + int numReportRates = DocumentSerializableUtilities.getInt(element, "numReportRates", 0); + + reportRates = new long[numReportRates]; + int reportRateIndex = 0; + + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (Element) e.nextElement(); + String key = (String) childElement.getKey(); + + if (key.equals("allowsMonitoring")) { + allowsMonitoring = DocumentSerializableUtilities.getBoolean(childElement); + } else if (key.equals("lastResetTime")) { + lastResetTime = DocumentSerializableUtilities.getLong(childElement); + } else if (key.equals("runningTime")) { + runningTime = DocumentSerializableUtilities.getLong(childElement); + } else if (key.equals("reportRate")) { + long reportRate = DocumentSerializableUtilities.getLong(childElement); + + reportRates[reportRateIndex] = reportRate; + reportRateIndex++; + } else if (key.equals("moduleClassID")) { + try { + ModuleClassID moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + + moduleClassIDs[moduleClassIDIndex] = moduleClassID; + moduleClassIDIndex++; + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't get ModuleClassID", jex); + } + } + } + + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfoEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfoEvent.java new file mode 100644 index 000000000..a7655f633 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfoEvent.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.peer.PeerID; + + +/** + * Event containing status of request for remote PeerMonitorInfo + **/ +public class PeerMonitorInfoEvent { + + PeerID peerID; + PeerMonitorInfo peerMonitorInfo; + + /** + * PeerMonitorInfoEvent + * + * @param peerID + * @param peerMonitorInfo + */ + public PeerMonitorInfoEvent(PeerID peerID, PeerMonitorInfo peerMonitorInfo) { + this.peerID = peerID; + this.peerMonitorInfo = peerMonitorInfo; + } + + /** + * Get PeerID of remote Peer + * + * @return PeerID + */ + public PeerID getPeerID() { + return peerID; + } + + /** + * PeerMonitorInfo of remote peer + * + * @return PeerMonitorInfo + */ + public PeerMonitorInfo getPeerMonitorInfo() { + return peerMonitorInfo; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfoListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfoListener.java new file mode 100644 index 000000000..aa5875bd3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/PeerMonitorInfoListener.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +/** + * PeerInfo Reporting capabilities Received from a Remote Monitor + */ +public interface PeerMonitorInfoListener { + + /** + * PeerMonitorInfo has arrived + * + * @param peerMonitorInfoEvent Event contains PeerMonitorInfo + */ + public void peerMonitorInfoReceived(PeerMonitorInfoEvent peerMonitorInfoEvent); + + /** + * PeerMonitorInfo is not forthcoming due to Timeout + * + * @param peerMonitorInfoEvent contains PeerID of remote Peer + */ + public void peerMonitorInfoNotReceived(PeerMonitorInfoEvent peerMonitorInfoEvent); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMetric.java new file mode 100644 index 000000000..5e565e25e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMetric.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.util.documentSerializable.*; +import net.jxta.platform.*; + + +/** + * The base interface for Service-Specific Metrics to be included in a Monitor Report + **/ +public interface ServiceMetric extends DocumentSerializable { + + /** + * init + * + * @param moduleClassID + */ + public void init(ModuleClassID moduleClassID); + + /** + * getModuleClassID + * + * @return ModuleClassID + */ + public ModuleClassID getModuleClassID(); + + /** + * Additively Merge Metrics from this Metric + * + * @param otherServiceMetric The metric being merged into this metric + */ + public void mergeMetrics(ServiceMetric otherServiceMetric); + + /** + * Subtractively Remove Metrics from this Metric + * + * @param otherServiceMetric The metric being removed into this metric + */ + public void diffMetrics(ServiceMetric otherServiceMetric); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMonitor.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMonitor.java new file mode 100644 index 000000000..7e72fa150 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMonitor.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.*; + + +/** + * The base interface for all ServiceMonitors + * For complete information about Service Monitors see the + * Document Designing and Implementing Service Monitors + */ +public interface ServiceMonitor extends Module { + + /** + * Get ModuleClassID of this ServiceMonitor + */ + public ModuleClassID getModuleClassID(); + + /** + * Get ServiceMetrics accrued in during this pulse interval + * + * @param serviceMonitorFilter Filter Metrics based upon this MonitorFilter + * @param fromTime Beginning time as determined by the MonitorManager + * @param toTime Ending time as determined by the MonitorManager + * @param pulseIndex Pulse Index of the reporting rate Pyramid + * @param reportRate Reporting Rate (corresponding to the PulseNumber's index) + */ + public ServiceMetric getServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime, int pulseIndex, long reportRate); + + /** + * A request for a cumulative Report(s) are coming, prepare to receive them + * @see #endCumulativeReport() + * + */ + public void beginCumulativeReport(); + + /** + * Get ServiceMetrics since the start (or last reset time) of this ServiceMonitor. + * Calls to this will only occurr between calls to beginCumulativeReport() and endCumulativeReport() + * @see #beginCumulativeReport() + * @see #endCumulativeReport() + * @param serviceMonitorFilter Filter Metrics based upon this MonitorFilter + * @param fromTime Beginning time as determined by the MonitorManager + * @param toTime Ending time as determined by the MonitorManager + */ + public ServiceMetric getCumulativeServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime); + + /** + * Indication that the flurry of requests for cumulative Report is over + * @see #beginCumulativeReport() + */ + public void endCumulativeReport(); + + /** + * Validate ServiceMonitorFilter for a cumulative Report + */ + public void validateCumulativeServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter) throws MonitorFilterException; + + /** + * Validate ServiceMonitorFilter for a periodic Reporting + */ + public void validateServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, long reportRate) throws MonitorFilterException; + + /** + * Transform the provided ServiceMonitorFilter into one that is supported for cumulative reporting + */ + public ServiceMonitorFilter createSupportedCumulativeServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter) throws MonitorFilterException; + + /** + * Transform the provided ServiceMonitorFilter into one that is supported for periodic reporting at the specified rate + */ + public ServiceMonitorFilter createSupportedServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, long reportRate) throws MonitorFilterException; + + /** + * Information that the Monitor Manager has accepted a Monitoring for this filter at this rate + * + * @param serviceMonitorFilter Accepted Filter + * @param reportRateIndex Pulse Index into pyramid of accepted rate + * @param reportRate Accepted reporting rate + * @param newRate Is this a new reporting rate (ie you don't have any currently registered at this rate) + */ + public void serviceMonitorFilterRegistered(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex, long reportRate, boolean newRate); + + /** + * Information that the Monitor Manager is deregistering the Monitoring for this filter at this rate + * + * @param serviceMonitorFilter Deregistered Filter + * @param reportRateIndex Pulse Index into pyramid of deregistered filter + * @param reportRate Reporting rate of deregistered filter + * @param retiredRate Is this a retired filter the last one registered at this rate (ie you don't have to keep metrics for this rate any longer) + */ + public void serviceMonitorFilterDeregistered(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex, long reportRate, boolean retiredRate); + + /** + * Clean up. The PeerGroup is probably about to be destroyed + */ + public void destroy(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMonitorFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMonitorFilter.java new file mode 100644 index 000000000..72ac4e232 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/ServiceMonitorFilter.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.meter; + + +import net.jxta.util.documentSerializable.*; +import net.jxta.platform.*; + + +/** + * The base interface for all ServiceMonitorFilters. + * See the Service-Specific filter for any interesting information + */ +public interface ServiceMonitorFilter extends DocumentSerializable { + + /** + * init + * + * @param moduleClassID + */ + public void init(ModuleClassID moduleClassID); + + /** + * get ModuleClassID + */ + public ModuleClassID getModuleClassID(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/package.html new file mode 100644 index 000000000..dc046f319 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/meter/package.html @@ -0,0 +1,10 @@ + + + + + + + Provides logging and monitoring facilities for debugging and auditing of + messaging and service invocation within JXTA. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/overview.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/overview.html new file mode 100644 index 000000000..e731cd15b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/overview.html @@ -0,0 +1,26 @@ + + + + + + + These packages provide the standard API for the JXTA Protocols using + Java Standard Edition 5.0. The implementation is divided into two + parts: the JSE Standard JXTA API (these packages) and the + JSE JXTA Reference Implementation +

      + Additional optional packages which are useful for developers building JXTA + applications can be found in the + JSE JXTA Extensions + + +

      Important Note: Applications and services are very + strongly encouraged to not import classes or interfaces from the + implementation packages. Specificially do not import from + net.jxta.impl.*. The content of these packages may change + significantly (including removal) from release to release with no advance + notice. + + @see JXTA Protocols Specification + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerID.java new file mode 100644 index 000000000..fbd517a77 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerID.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peer; + + +import java.net.URI; +import net.jxta.id.ID; + + +/** + * This class implements a PeerID. Each peer is assigned a unique peer id. + * + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.peergroup.PeerGroupID + */ +public abstract class PeerID extends ID { + + /** + * Creates an ID by parsing the given URI. + * + *

      This convenience factory method works as if by invoking the + * {@link net.jxta.id.IDFactory#fromURI(URI)} method; any + * {@link java.net.URISyntaxException} thrown is caught and wrapped in a + * new {@link IllegalArgumentException} object, which is then thrown. + * + *

      This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link net.jxta.id.IDFactory}, + * which throws {@link java.net.URISyntaxException} directly, should be used + * situations where a ID is being constructed from user input or from some + * other source that may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException If {@code fromURI} is {@code null}. + * @throws IllegalArgumentException If the given URI is not a valid ID. + */ + public static PeerID create(URI fromURI) { + return (PeerID) ID.create(fromURI); + } + + /** + * {@inheritDoc} + */ + public PeerID intern() { + return (PeerID) super.intern(); + } + + /** + * Returns PeerGroupID of the Peer Group to which this Peer ID belongs. + * + * @return PeerGroupID of the Peer Group to which this Peer ID belongs. + */ + public abstract ID getPeerGroupID(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoEvent.java new file mode 100644 index 000000000..6f08b77fd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoEvent.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.peer; + + +import java.util.EventObject; + +import net.jxta.protocol.PeerInfoResponseMessage; + + +/** + * Container for PeerInfoEvent events. + */ +public class PeerInfoEvent extends EventObject { + + private PeerInfoResponseMessage piResp = null; + private int queryID = -1; + + /** + * Creates a new event + * + *@param source The object on which the Event initially occurred + *@param queryid The query id associated with the response returned in + * this event + *@param piResp PeerInfoResponseMessage received + *@see net.jxta.protocol.ResolverResponseMsg + */ + + public PeerInfoEvent(Object source, PeerInfoResponseMessage piResp, int queryid) { + super(source); + this.piResp = piResp; + this.queryID = queryid; + + } + + /** + * Returns the response associated with the event + * + *@return PeerInfoResponseMessage + *@see net.jxta.protocol.ResolverResponseMsg + */ + public PeerInfoResponseMessage getPeerInfoResponseMessage() { + + return piResp; + } + + /** + * Returns The query id associated with the response returned in this + * event + * + *@return query id associated with the response + */ + public int getQueryID() { + + return queryID; + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoListener.java new file mode 100644 index 000000000..0ac3b92b4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoListener.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peer; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving PeerInfoService events. + * + * The following example illustrates how to implement a PeerInfoListener: + * + * + *

      + *        PeerInfoListener myPeerListener = new PeerInfoListener() {
      + *            public void peerInfoResponse(PeerInfoEvent e) {
      + *                PeerInfoResponseMessage adv = e.getPeerInfoResponse();
      + *                if (myQueryID == e.getQueryID()) {
      + *                 ...
      + *                 ...
      + *                }
      + *            }
      + *        peerinfo.addPeerInfoListener(myPeerListener);
      + *        int myQueryID = peerinfo.getRemotePeerInfo(peer);
      + * 
      + */ + +public interface PeerInfoListener extends EventListener { + + /** + * PeerInfoService Event + * + * @param event the peer info event + */ + void peerInfoResponse(PeerInfoEvent event); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoService.java new file mode 100644 index 000000000..f148a0ab6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/PeerInfoService.java @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peer; + + +import net.jxta.meter.*; +import net.jxta.platform.ModuleClassID; +import net.jxta.service.Service; + + +/** + * The PeerInfoService is a generic API for getting information about + * the local Peer as well as remote Peers.

      + *

      + * The most important type of information about a Peer may be gotten through + * the Monitoring Service that may be accessed via the PeerInfoService. The + * Monitoring Service provides an open mechanism for reporting any type of + * Metrics gathered on a Peer by a ServiceMonitor. Attached Service Monitors + * are identified by their ModuleClassID. A ServiceMonitor may monitor anything + * (ie it is not restricted to JXTA Services).

      + *

      + * There are several methods for accessing the capabilities and metrics + * from ServiceMonitors + * attached to the Peer (either locally or from remote peers).

      + *

      + * Cumulative MonitorReports containing metrics since the Monitoring began + * (or was reset) on a local/remote Peer may be obtained. Alternatively, you may + * register listeners get periodic MonitorReports (at a specified rate) of + * metrics (since the previous report). The amount of information obtained (either + * cumulatively or periodically) is determined by a MonitorFilter whi + *

      + * The PeerInfoService utilizes the ResolverService to send queries and receive + * responses (PeerInfoQueryMessage / PeerInfoResponseMessage). These contain + * requests and responses that are specific to the type of info being requested. + * Depending upon the type of information requested, a peer may provide multiple + * varying responses over time (as is the case for periodic remote peer Monitoring).

      + *

      + * At the time of writing this documentation Service Monitoring is the only type + * of Peer Information available though the implementation and underlying protocol + * can support other types of information.

      + *

      + * See the document: + *

        + *
      • JXTA Metering and Monitoring Project
      • + *
      • The JXTA Metering and Monitoring Project Architecture
      • + *
      • Building and Configuring JXTA with Monitoring Capabilities
      • + *
      • JXTA Monitor: GUI Rendering of Metered Peer Info
      • + *
      + * + * @see net.jxta.meter.MonitorFilter + * @see net.jxta.meter.MonitorReport + * @see net.jxta.meter.ServiceMonitor + * @see net.jxta.meter.PeerMonitorInfo + * @see net.jxta.protocol.PeerInfoQueryMessage + * @see net.jxta.protocol.PeerInfoResponseMessage + * @since JXTA 1.0 + */ + +public interface PeerInfoService extends Service { + + /** + * See if Local Monitoring is available on this Peer + * Local monitoring is only available if you are using a version of + * of jxta.jar that was build with metering activated.

      + *

      + * See the document: + *

        + *
      • Building and Configuring JXTA with Monitoring Capabilities
      • + *
      + * + * @return true if local monitoring is available + */ + public boolean isLocalMonitoringAvailable(); + + /** + * See if Local monitoring is available from a specific ServiceMonitor. + * Local monitoring is only available if you are using a version of + * of jxta.jar that was build with metering activated.

      + *

      + * See the document: + *

        + *
      • Building and Configuring JXTA with Monitoring Capabilities
      • + *
      + * + * @param moduleClassID The Module classID of the ServiceMonitor. Note that the ServiceMonitor + * moduleClassID is not the same as moduleClassID of the Service + * being monitored. + * @return true if local monitoring is available for a specific module + */ + public boolean isLocalMonitoringAvailable(ModuleClassID moduleClassID); + + /** + * Asynchronous reporting of Monitored data may be obtained only at rates supported by + * the MonitorManager on the peer. This method returns the locally supported rates (in milliseconds) + * @return all supported rates + */ + public long[] getSupportedReportRates(); + + /** + * Asynchronous reporting of Monitored data may be obtained only at rates supported by + * the MonitorManager on the peer. This method validates whether a specific + * rate (in milliseconds) is locally supported. + * @param reportRate the report rate to check + * @return true if a report rate is supported + */ + public boolean isSupportedReportRate(long reportRate); + + /** + * Asynchronous reporting of Monitored data may be obtained only at rates supported by + * the MonitorManager on the peer. This method supplies the closest (rounded up) + * rate (in milliseconds) to the specified rate that is locally supported. + * @param desiredReportRate the desired rate + * @return the desired rate + */ + public long getBestReportRate(long desiredReportRate); + + /** + * Obtain the monitoring capabilities of the Local Peer.

      + * The PeerMonitorInfo provides: + *

        + *
      • Whether any monitoring is available for this Peer
      • + *
      • The supported rates of asynchronous monitoring
      • + *
      • A list (as ModuleClassIDs) of ServiceMonitors attached to this Peer
      • + *
      + * @return PeerMonitorInfo + */ + public PeerMonitorInfo getPeerMonitorInfo(); + + /** + * Obtain the monitoring capabilities of a Remote Peer.

      + * The PeerMonitorInfo provides: + *

        + *
      • Whether any monitoring is available for this Peer
      • + *
      • The supported rates of asynchronous monitoring
      • + *
      • A list (as ModuleClassIDs) of ServiceMonitors attached to this Peer
      • + *
      + *

      + * Via the PeerMonitorInfoListener, you will be informed of the PeerMonitorInfo or why it was + * not provided (error, timeout, unavailable, etc) + * + * @param peerID The PeerID of the Peer you wish information about + * @param peerMonitorInfoListener The Listener to be told about the obtained PeerMonitorInfo + * @param timeout Generate a timeout event if no answer has been received in this time (in Milliseconds) + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public void getPeerMonitorInfo(PeerID peerID, PeerMonitorInfoListener peerMonitorInfoListener, long timeout) throws MonitorException; + + /** + * Get a MonitorReport of total accumulated metrics from the ServiceMonitors (specified in the + * MonitorFilter) since they were created/reset for the local Peer. + * + * @param monitorFilter The MonitorFilter containing the specific ServiceMonitors and types of Service Metrics desired + * @return the report + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public MonitorReport getCumulativeMonitorReport(MonitorFilter monitorFilter) throws MonitorException; + + /** + * Get a MonitorReport of total accumulated metrics from the ServiceMonitors (specified in the + * MonitorFilter) since they were created/reset for the specified remote Peer. + * + * @param peerID The PeerID of the Peer you wish information about + * @param monitorFilter The MonitorFilter containing the specific ServiceMonitors and types of Service Metrics desired + * @param monitorListener The Listener to obtain the report when it arrives (or timed out) + * @param timeout The timeout for reporting that the information has not arrived. + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public void getCumulativeMonitorReport(PeerID peerID, MonitorFilter monitorFilter, MonitorListener monitorListener, long timeout) throws MonitorException; + + /** + * Get MonitorReports at a specified rates of metrics accrued over time from the ServiceMonitors + * (specified in the MonitorFilter) about the local Peer. For many applications it is required to obtain metrics from + * the beginning of time and then augment over time as more data arrives.

      + *

      + * There is a problem with the following approach: + *

        + *
      1. Call getCumulativeMonitorReport to get the cumulative totals
      2. + *
      3. Call addMonitorListener to get periodic changes
      4. + *
      5. Add the periodic data to the totals
      6. + *
      + *

      + * Because of a potential race condition related to metrics that are measured between the two calls it is + * possible to lose some metrics. To address this, this method supports this by combining them into a single + * call that allows you to specify whether you wish the first report delivered to be a cumulative report. + * + * @param monitorFilter The MonitorFilter containing the specific ServiceMonitors and types of Service Metrics desired + * @param reportRate The rate at which you wish metric delta reports + * @param includeCumulative Should the first report you receive be the cumulative data since the ServiceMonitors were created/reset? + * @param monitorListener The Listener to obtain the report when it arrives (or timed out) + * @return report rate + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public long addMonitorListener(MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener) throws MonitorException; + + /** + * Get MonitorReports at a specified rates of metrics accrued over time from the ServiceMonitors + * (specified in the MonitorFilter) about the specified remote Peer. For many applications it is required to obtain metrics from + * the beginning of time and then augment over time as more data arrives.

      + *

      + * There is a problem with the following approach: + *

        + *
      1. Call getCumulativeMonitorReport to get the cumulative totals
      2. + *
      3. Call addMonitorListener to get periodic changes
      4. + *
      5. Add the periodic data to the totals
      6. + *
      + *

      + * Because of a potential race condition related to metrics that are measured between the two calls it is + * possible to lose some metrics. To address this, this method supports this by combining them into a single + * call that allows you to specify whether you wish the first report delivered to be a cumulative report. + * + * @param peerID The PeerID of the Peer you wish information about + * @param monitorFilter The MonitorFilter containing the specific ServiceMonitors and types of Service Metrics desired + * @param reportRate The rate at which you wish metric delta reports + * @param includeCumulative Should the first report you receive be the cumulative data since the ServiceMonitors were created/reset? + * @param monitorListener The Listener to obtain the report when it arrives (or timed out) + * @param timeout The timeout for reporting that the information has not arrived. + * @param lease the lease + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public void addRemoteMonitorListener(PeerID peerID, MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener, long lease, long timeout) throws MonitorException; + + /** + * Stop the periodic reporting for all registered filters corresponding to this MonitorListener + * @param monitorListener the monitor listener + * @return true if successfully removed + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public boolean removeMonitorListener(MonitorListener monitorListener) throws MonitorException; + + /** + * Stop the periodic reporting for all registered filters to the specified Peer corresponding to this MonitorListener. + * + * @param peerID The Peer that you wish to deregister periodic reporting + * @param monitorListener The MonitorListener that was originally registered + * @param timeout The timeout for reporting that the remote listener was acknowledged as deregistered + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public void removeRemoteMonitorListener(PeerID peerID, MonitorListener monitorListener, long timeout) throws MonitorException; + + /** + * Stop the periodic reporting for all registered filters to the all remote Peers corresponding to this MonitorListener. + * + * @param monitorListener The MonitorListener that was originally registered + * @param timeout The timeout for reporting that the remote listener was acknowledged as deregistered + * @throws net.jxta.meter.MonitorException if a monitor error occurs + */ + public void removeRemoteMonitorListener(MonitorListener monitorListener, long timeout) throws MonitorException; +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/package.html new file mode 100644 index 000000000..0d36f16c4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peer/package.html @@ -0,0 +1,18 @@ + + + + + + + Provides definition for the standard JXTA Peer Info Service. There + is no JXSE object directly associated with the peer. The state of the + current peer is expressed through the {@link net.jxta.peergroup.PeerGroup} + object. + + @see net.jxta.peergroup.PeerGroup + @see net.jxta.protocol.PeerAdvertisement + @see net.jxta.id.ID + + @see JXTA Protocols Specification : Peer Info Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/Configurator.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/Configurator.java new file mode 100644 index 000000000..fa72befc9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/Configurator.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.peergroup; + + +import net.jxta.exception.ConfiguratorException; +import net.jxta.protocol.ConfigParams; + + +/** + * A configurator is responsible for the persistence and validation of + * configuration parameters. + * + * @deprecated This interface has been replaced with the {@link net.jxta.platform.NetworkConfigurator}. + **/ +@Deprecated +public interface Configurator { + + /** + * Retrieve the parameters associated with this configuration from the + * default location. If necessary the parameters will be created or an + * opportunity to adjust them will be provided. + * + * @return The configuration parameters. + * @throws ConfiguratorException If there was a failure in retrieving the + * parameters. This is normally a chained exception to the underlying + * cause. + **/ + public ConfigParams getConfigParams() throws ConfiguratorException; + + /** + * Sets the parameters associated with this configuration object to the + * provided values. + * + * @deprecated Configuration parameters should be set individually via + * whatever interfaces implementing configurator provides. This method + * over-writes all configuration settings in an unpredictable way. + * + * @param cp The parameters to be associated with this configuration. + **/ + @Deprecated + public void setConfigParams(ConfigParams cp); + + /** + * Retrieves the persisted parameters associated with this configuration + * from the standard location. + * + * @deprecated Loading of existing configuration is best accomplished by use + * of specific constructors of the implementing configurator. This method + * complicates the state management of configuration parameters and may have + * unpredictable results depending upon the constructor and configuration + * set methods used prior to it's execution. + * + * @return The configuration parameters. + * @throws ConfiguratorException If there was a failure in retrieving the + * persisted parameters. This is normally a chained exception to the + * underlying cause. + **/ + @Deprecated + public ConfigParams load() throws ConfiguratorException; + + /** + * Persist the parameters associated with this configuration to the + * standard location. + * + * @return true if the configuration was successfully saved + * otherwise false. If the parameters are not persisted then + * false/code> is returned. + * @throws ConfiguratorException If there was a failure in persisting the + * parameters. This is normally a chained exception to the underlying + * cause. + **/ + public boolean save() throws ConfiguratorException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/LightWeightPeerGroup.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/LightWeightPeerGroup.java new file mode 100644 index 000000000..67dff0323 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/LightWeightPeerGroup.java @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peergroup; + + +import net.jxta.access.AccessService; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.Element; +import net.jxta.endpoint.EndpointService; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peer.PeerInfoService; +import net.jxta.pipe.PipeService; +import net.jxta.platform.JxtaLoader; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.resolver.ResolverService; +import net.jxta.service.Service; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.net.URI; +import java.util.Collections; +import java.util.Iterator; + + +/** + * LightWeightPeerGroup is a class intended to help + * building PeerGroup that can inherit one or more + * services from a parent PeerGroup. + *

      + * An LightWeightPeerGroup implements PeerGroup and is to + * be used like a PeerGroup by applications. + *

      + * This class is intended to be extended/implemented. + *

      + * Note: unlike implementations of peer groups that existed until JXTA 2.2, + * LightweightPeergroup permits to implement groups that borrow all or + * part of their services to a parent group. One needs to remember + * that peers in various such subgroups of a given parent groups may + * implicitly all share the same services if that is what the PeerGroup + * implementing LightWeightPeerGroup is doing. Please refer to the documentation + * of PeerGroups extending LightWeigthPeerGroup do understand which + * services are shared, and which are not. + */ + +public class LightWeightPeerGroup implements PeerGroup { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(LightWeightPeerGroup.class.getName()); + + private PeerGroup group = null; + private ID assignedID = null; + private ModuleImplAdvertisement implAdv = null; + private final PeerGroupAdvertisement adv; + + /** + * Constructor + *

      + * All classes that extend this class must invoke this + * constructor. + * + * @param adv PeerGroupAdvertisement of this LightWeightPeerGroup. + * Note that only the PeerGroupID is used. + */ + public LightWeightPeerGroup(PeerGroupAdvertisement adv) { + this.adv = adv; + } + + /*********************************************************** + ** Module API + ***********************************************************/ + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) { + this.group = group; + this.assignedID = assignedID; + this.implAdv = (ModuleImplAdvertisement) implAdv; + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] args) { + if (null == group) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("No base peer group defined."); + } + return -1; + } + + return START_OK; + } + + /** + * {@inheritDoc} + */ + public void stopApp() {} + + /** + * {@inheritDoc} + */ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdv; + } + + /*********************************************************** + ** PeerGroup API + ***********************************************************/ + + /** + * {@inheritDoc} + */ + public ThreadGroup getHomeThreadGroup() { + if (group != null) { + return group.getHomeThreadGroup(); + } else { + return null; + } + } + + /*********************************************************** + ** PeerGroup API + ***********************************************************/ + + /** + * {@inheritDoc} + */ + public URI getStoreHome() { + if (group != null) { + return group.getStoreHome(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public JxtaLoader getLoader() { + if (group != null) { + return group.getLoader(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public PeerGroup getParentGroup() { + + try { + return group; + } catch (Exception ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("LightWeightPeerGroup is a base PeerGroup: no parent"); + } + throw new RuntimeException("LightWeightPeerGroup is a base PeerGroup: no parent"); + } + } + + /** + * {@inheritDoc} + */ + public boolean isRendezvous() { + + return group != null && group.isRendezvous(); + } + + /** + * {@inheritDoc} + */ + public PeerGroupAdvertisement getPeerGroupAdvertisement() { + + if (adv != null) { + return adv; + } else if (group != null) { + return group.getPeerGroupAdvertisement(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public PeerAdvertisement getPeerAdvertisement() { + + if (group != null) { + return group.getPeerAdvertisement(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public Service lookupService(ID name) throws ServiceNotFoundException { + + if (group != null) { + return group.lookupService(name); + } else { + throw new ServiceNotFoundException("Not implemented"); + } + } + + /** + * {@inheritDoc} + */ + public Service lookupService(ID name, int ignoredForNow) throws ServiceNotFoundException { + + if (group != null) { + return group.lookupService(name); + } else { + throw new ServiceNotFoundException("Not implemented"); + } + } + + /** + * {@inheritDoc} + */ + public Iterator getRoleMap(ID name) { + + if (group != null) { + return group.getRoleMap(name); + } else { + // No translation; use the given name in a singleton. + return Collections.singletonList(name).iterator(); + } + } + + /** + * {@inheritDoc} + */ + public boolean compatible(Element compat) { + + return group != null && group.compatible(compat); + } + + /** + * {@inheritDoc} + */ + public Module loadModule(ID assignedID, Advertisement impl) throws ProtocolNotSupportedException, PeerGroupException { + + if (group != null) { + return group.loadModule(assignedID, impl); + } else { + throw new ProtocolNotSupportedException("LightWeightPeerGroup does not implement this operation"); + } + } + + /** + * {@inheritDoc} + */ + public Module loadModule(ID assignedID, ModuleSpecID specID, int where) { + + if (group != null) { + return group.loadModule(assignedID, specID, where); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public void publishGroup(String name, String description) throws IOException { + + if (group != null) { + group.publishGroup(name, description); + } else { + throw new IOException("Not implemented"); + } + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(Advertisement pgAdv) throws PeerGroupException { + + if (group != null) { + return group.newGroup(pgAdv); + } else { + throw new PeerGroupException("Not implemented"); + } + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(PeerGroupID gid, Advertisement impl, String name, String description) throws PeerGroupException { + + if (group != null) { + return group.newGroup(gid, impl, name, description); + } else { + throw new PeerGroupException("Not implemented"); + } + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(PeerGroupID gid) throws PeerGroupException { + + if (group != null) { + return group.newGroup(gid); + } else { + throw new PeerGroupException("Not implemented"); + } + } + + /* + * shortcuts to the well-known services, in order to avoid calls to lookup. + */ + + /** + * {@inheritDoc} + */ + public RendezVousService getRendezVousService() { + + if (group != null) { + return group.getRendezVousService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + + if (group != null) { + return group.getEndpointService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public ResolverService getResolverService() { + if (group != null) { + return group.getResolverService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public DiscoveryService getDiscoveryService() { + if (group != null) { + return group.getDiscoveryService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public PeerInfoService getPeerInfoService() { + if (group != null) { + return group.getPeerInfoService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public MembershipService getMembershipService() { + if (group != null) { + return group.getMembershipService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public PipeService getPipeService() { + if (group != null) { + return group.getPipeService(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public AccessService getAccessService() { + if (group != null) { + return group.getAccessService(); + } else { + return null; + } + } + + /* + * A few convenience methods. This information is available from + * the peer and peergroup advertisement. + */ + + /** + * {@inheritDoc} + */ + public PeerGroupID getPeerGroupID() { + + if (adv != null) { + return (PeerGroupID) adv.getID(); + } else if (group != null) { + return group.getPeerGroupID(); + } else { + throw new RuntimeException("No PeerGroupID"); + } + } + + /** + * {@inheritDoc} + */ + public PeerID getPeerID() { + + if (group != null) { + return group.getPeerID(); + } else { + throw new RuntimeException("No PeerID"); + } + } + + /** + * {@inheritDoc} + */ + public String getPeerGroupName() { + + if (adv != null) { + return adv.getName(); + } else if (group != null) { + return group.getPeerGroupName(); + } else { + throw new RuntimeException("No name"); + } + } + + /** + * {@inheritDoc} + */ + public String getPeerName() { + + if (group != null) { + return group.getPeerName(); + } else { + throw new RuntimeException("No name"); + } + } + + /** + * {@inheritDoc} + */ + public ConfigParams getConfigAdvertisement() { + + if (group != null) { + return group.getConfigAdvertisement(); + } else { + throw new RuntimeException("No ConfigAdvertisement"); + } + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() throws Exception { + + if (group != null) { + return group.getAllPurposePeerGroupImplAdvertisement(); + } else { + throw new RuntimeException("Not implemented"); + } + } + + /** + * {@inheritDoc} + */ + public void unref() {} + + /** + * {@inheritDoc} + */ + public PeerGroup getWeakInterface() { + + /** + * A LightWeightPeerGroup is already a weak reference + * that is not shareable, therefore, return self as + * a weak reference. + **/ + + return this; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/NetPeerGroupFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/NetPeerGroupFactory.java new file mode 100644 index 000000000..df66d6d61 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/NetPeerGroupFactory.java @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peergroup; + + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; + +import net.jxta.impl.protocol.PeerGroupConfigAdv; +import net.jxta.impl.peergroup.GenericPeerGroup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A factory for instantiating a Network Peer Group instances. The Network Peer + * Group is the base peer group for applications and services within the JXTA + * network. Most applications and services will instantiate their own peer + * groups using the Network Peer Group as a base. + *

      + * A non-default configuration of The Network Peer Group may be + * set-up by the administrator in charge of the network domain inside which the + * peer is starting. The Network Peer Group may be discovered via the + * JXTA Discovery protocol. Many such groups may be configured by an + * administrator. + * + * @since JXTA JSE 2.4 + * + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.peergroup.WorldPeerGroupFactory + */ +public final class NetPeerGroupFactory { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(NetPeerGroupFactory.class.getName()); + + /** + * Our strong reference to the net peer group. + */ + private final PeerGroup net; + + /** + * Instantiates the Net Peer Group using the ConfigParams found in the + * directory specified by the {@code JXTA_HOME} system property or the + * "{@code .jxta/}" directory if {@code JXTA_HOME} is not defined. + *

      + * This constructor is provided primarily for backwards compatibility. + * Though not deprecated this method should be considered as sample code + * only and the other constructors should be used whenever possible. + * + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + public NetPeerGroupFactory() throws PeerGroupException { + WorldPeerGroupFactory world = new WorldPeerGroupFactory(); + PeerGroup worldGroup = world.getInterface(); + NetGroupTunables tunables; + + try { + ConfigParams cp = worldGroup.getConfigAdvertisement(); + PeerGroupConfigAdv netGroupConfig = (PeerGroupConfigAdv) cp.getSvcConfigAdvertisement(PeerGroup.peerGroupClassID); + + if (null == netGroupConfig) { + tunables = new NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config"), new NetGroupTunables()); + // load overides from "${JXTA_HOME}config.properties". + URI storeHome = worldGroup.getStoreHome(); + + if (null != storeHome) { + try { + File configProperties = new File(new File(storeHome), "config.properties"); + ResourceBundle rsrcs = new PropertyResourceBundle(new FileInputStream(configProperties)); + + tunables = new NetGroupTunables(rsrcs, tunables); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loaded defaults from " + rsrcs); + } + } catch (MissingResourceException ignored) { + // ingnored + } catch (IOException ignored) { + // ingnored + } + } + } else { + tunables = new NetGroupTunables(netGroupConfig.getPeerGroupID(), netGroupConfig.getName(), netGroupConfig.getDesc()); + } + + net = newNetPeerGroup(worldGroup, null, tunables.id, tunables.name, tunables.desc, null); + } finally { + worldGroup.unref(); + } + } + + /** + * Constructs a Net Peer Group using the specified parent peer group. This + * is the preferred constructor for constructing a Net Peer Group using the + * default configuration. The resulting Net Peer Group instance will use + * the default ID, Name and Description. + * + * @param parentGroup The Peer Group which will be the parent of the newly + * created net peer group. This should normally be the World Peer Group. + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + public NetPeerGroupFactory(PeerGroup parentGroup) throws PeerGroupException { + ConfigParams cp = parentGroup.getConfigAdvertisement(); + PeerGroupConfigAdv netGroupConfig = (PeerGroupConfigAdv) cp.getSvcConfigAdvertisement(PeerGroup.peerGroupClassID); + NetGroupTunables tunables; + + if (null == netGroupConfig) { + tunables = new NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config"), new NetGroupTunables()); + } else { + tunables = new NetGroupTunables(netGroupConfig.getPeerGroupID(), netGroupConfig.getName(), netGroupConfig.getDesc()); + } + + net = newNetPeerGroup(parentGroup, null, tunables.id, tunables.name, tunables.desc, null); + } + + /** + * Constructs a Net Peer Group and the World Peer Group using the + * configuration specified by the provided ConfigParams and using the + * specified storeHome location for persistence. The resulting Net Peer + * Group instance will use the default ID, Name and Description. + * + * @param config The configuration to use for the newly created World Peer + * Group and Net Peer Groups. + * @param storeHome The optional location that the World Peer Group, the + * Net Peer Group and its' services should use for storing persistent and + * transient information. May be {@code null} if the World Peer Group is + * not provided a persistent store (though this not currently supported). + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + public NetPeerGroupFactory(ConfigParams config, URI storeHome) throws PeerGroupException { + WorldPeerGroupFactory world = new WorldPeerGroupFactory(config, storeHome); + PeerGroup worldGroup = world.getInterface(); + + try { + PeerGroupConfigAdv netGroupConfig = (PeerGroupConfigAdv) config.getSvcConfigAdvertisement(PeerGroup.peerGroupClassID); + NetGroupTunables tunables; + + if (null == netGroupConfig) { + tunables = new NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config"), new NetGroupTunables()); + } else { + tunables = new NetGroupTunables(netGroupConfig.getPeerGroupID(), netGroupConfig.getName(), netGroupConfig.getDesc()); + } + + net = newNetPeerGroup(worldGroup, config, tunables.id, tunables.name, tunables.desc, null); + } finally { + worldGroup.unref(); + } + } + + /** + * Constructs a Net Peer Group and the World Peer Group using the + * configuration specified by the provided ConfigParams and using the + * specified storeHome location for persistence. The resulting Net Peer + * Group instance will use the group information provided in the + *

      + * This constructor is provided in anticipation of other improvements + * to the peer group instantiation process. Currently it has some + * unreasonable limitations which keep it from being very useful. In a + * future release it will be improved. + * + * @param config The configuration to use for the newly created World Peer + * Group and Net Peer Groups. + * @param storeHome The optional location that the World Peer Group, the + * Net Peer Group and its' services should use for storing persistent and + * transient information. May be {@code null} if the World Peer Group is + * not provided a persistent store (though this not currently supported). + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + * @param parentGroup the parent peer group + */ + public NetPeerGroupFactory(PeerGroup parentGroup, ConfigParams config, URI storeHome) throws PeerGroupException { + + if (config != parentGroup.getConfigAdvertisement()) { + throw new IllegalArgumentException("This constructor cannot currently accept group parameters different than the parent group"); + } + + if (null == storeHome) { + if (null != parentGroup.getStoreHome()) { + throw new IllegalArgumentException("This constructor cannot currently accept a different store location than the parent group"); + } + } else { + if (!storeHome.equals(parentGroup.getStoreHome())) { + throw new IllegalArgumentException("This constructor cannot currently accept a different store location than the parent group"); + } + } + + ConfigParams cp = parentGroup.getConfigAdvertisement(); + PeerGroupConfigAdv netGroupConfig = (PeerGroupConfigAdv) cp.getSvcConfigAdvertisement(PeerGroup.peerGroupClassID); + NetGroupTunables tunables; + + if (null == netGroupConfig) { + tunables = new NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config"), new NetGroupTunables()); + } else { + tunables = new NetGroupTunables(netGroupConfig.getPeerGroupID(), netGroupConfig.getName(), netGroupConfig.getDesc()); + } + + net = newNetPeerGroup(parentGroup, config, tunables.id, tunables.name, tunables.desc, null); + } + + /** + * Constructs a Net Peer Group and the World Peer Group using the + * configuration specified by the provided ConfigParams and using the + * specified storeHome location for persistence. + * + * @deprecated With the addition of support for {@code PeerGroupConfigAdv} + * this constructor is being deprecated as the precedence of settings is + * ambiguous. + * + * @param config The configuration to use for the newly created World Peer + * Group and Net Peer Groups. + * @param storeHome The optional location that the World Peer Group, the + * Net Peer Group and its' services should use for storing persistent and + * transient information. May be {@code null} if the World Peer Group is + * not provided a persistent store (though this not currently supported). + * @param id The PeerGroupID which will be used for the new Net Peer Group + * instance. + * @param name The name which will be used for the new Net Peer Group + * instance. + * @param desc The description which will be used for the new Net Peer Group + * instance. You can construct an {@code XMLDocument} from a {@code String} + * via : + *

      +     *     XMLDocument asDoc = StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, "desc", asString );
      +     * 
      + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + @Deprecated + public NetPeerGroupFactory(ConfigParams config, URI storeHome, ID id, String name, XMLElement desc) throws PeerGroupException { + WorldPeerGroupFactory world = new WorldPeerGroupFactory(config, storeHome); + PeerGroup worldGroup = world.getInterface(); + + try { + net = newNetPeerGroup(worldGroup, config, id, name, desc, null); + } finally { + worldGroup.unref(); + } + } + + /** + * Constructs a Net Peer Group instance using the specified parent peer + * group (normally the World Peer Group). This is the preferred constructor + * for constructing a private Net Peer Group. + * + * @deprecated With the addition of support for {@code PeerGroupConfigAdv} + * this constructor is being deprecated as the precedence of settings is + * ambiguous. + * + * @param parentGroup The Peer Group which will be the parent of the + * newly created net peer group. This should normally be the World Peer + * Group. + * @param id The PeerGroupID which will be used for the new Net Peer Group + * instance. + * @param name The name which will be used for the new Net Peer Group + * instance. + * @param desc The description which will be used for the new Net Peer Group + * instance. You can construct an {@code XMLDocument} from a {@code String} + * via : + *

      +     *     XMLDocument asDoc = StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, "desc", asString );
      +     * 
      + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + @Deprecated + public NetPeerGroupFactory(PeerGroup parentGroup, ID id, String name, XMLElement desc) throws PeerGroupException { + net = newNetPeerGroup(parentGroup, null, id, name, desc, null); + } + + /** + * Constructs a Net Peer Group instance using the specified parent peer + * group (normally the World Peer Group). This is the preferred constructor + * for constructing a private Net Peer Group with a specific implementation. + * + * @deprecated With the addition of support for {@code PeerGroupConfigAdv} + * this constructor is being deprecated as the precedence of settings is + * ambiguous. + * + * @param parentGroup The Peer Group which will be the parent of the newly + * created net peer group. This should normally be the World Peer + * + * @param id The PeerGroupID which will be used for the new Net Peer Group + * instance. + * @param name The name which will be used for the new Net Peer Group + * instance. + * @param desc The description which will be used for the new Net Peer Group + * instance. You can construct an {@code XMLDocument} from a {@code String} + * via : + *

      +     *     XMLDocument asDoc = StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, "desc", asString );
      +     * 
      + * @param moduleImplAdv The Module Impl Advertisement for the new Net Peer + * Group instance. + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + @Deprecated + public NetPeerGroupFactory(PeerGroup parentGroup, ID id, String name, XMLElement desc, ModuleImplAdvertisement moduleImplAdv) throws PeerGroupException { + net = newNetPeerGroup(parentGroup, null, id, name, desc, moduleImplAdv); + } + + /** + * Constructs a Net Peer Group instance using the specified parent peer + * group (normally the World Peer Group). This is the preferred constructor + * for constructing a Net Peer Group with a specific implementation. + * + * @param parentGroup The Peer Group which will be the parent of the + * newly created net peer group. This should normally be the World Peer + * Group. + * @param config The configuration parameters for the newly created Net Peer + * Group instance. + * @param moduleImplAdv The Module Impl Advertisement for the new Net Peer + * Group instance. + * @throws PeerGroupException Thrown for problems constructing the Net Peer + * Group. + */ + public NetPeerGroupFactory(PeerGroup parentGroup, ConfigParams config, ModuleImplAdvertisement moduleImplAdv) throws PeerGroupException { + PeerGroupConfigAdv netGroupConfig = (PeerGroupConfigAdv) config.getSvcConfigAdvertisement(PeerGroup.peerGroupClassID); + NetGroupTunables tunables; + + if (null == netGroupConfig) { + tunables = new NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config"), new NetGroupTunables()); + } else { + tunables = new NetGroupTunables(netGroupConfig.getPeerGroupID(), netGroupConfig.getName(), netGroupConfig.getDesc()); + } + + net = newNetPeerGroup(parentGroup, config, tunables.id, tunables.name, tunables.desc, moduleImplAdv); + } + + /** + * Returns a strong (reference counted) interface object for the Net Peer + * Group instance. This reference should be explicitly unreferenced when it + * is no longer needed. + * + * @return A strong (reference counted) interface object for the Net Peer Group. + * @see PeerGroup#unref() + */ + public PeerGroup getInterface() { + return (PeerGroup) net.getInterface(); + } + + /** + * Returns a weak (non-reference counted) interface object for the Net Peer Group. + * + * @return A weak (non-reference counted) interface object for the Net Peer Group. + * @see PeerGroup#getWeakInterface() + */ + public PeerGroup getWeakInterface() { + return net.getWeakInterface(); + } + + /** + * Construct the new Net Peer Group instance. + * + * @param parentGroup The parent group of the newly created net peer group. + * @param config Configuration parameters for the newly created net peer group. + * @param id The name to use for the newly created Net Peer Group. + * @param name The name to use for the newly created Net Peer Group. + * @param desc The description to use for the newly created Net Peer Group. + * @param implAdv The Module Impl Advertisement for the new Net Peer Group + * instance or {@code null} to use the advertisement returned by + * {@ link PeerGroup.getAllPurposePeerGroupImplAdvertisement()}. + * @return the PeerGroup + * @throws PeerGroupException Thrown for errors instantiating the new Net + * Peer Group instance. + */ + private PeerGroup newNetPeerGroup(PeerGroup parentGroup, ConfigParams config, ID id, String name, XMLElement desc, ModuleImplAdvertisement implAdv) throws PeerGroupException { + synchronized (PeerGroup.globalRegistry) { + PeerGroup result = PeerGroup.globalRegistry.lookupInstance((PeerGroupID) id); + + if (null != result) { + result.unref(); + throw new PeerGroupException("Only a single instance of a Peer Group may be instantiated at a single time."); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( "Instantiating net peer group : " + id + + "\n\tParent : " + parentGroup + + "\n\tID : " + id + + "\n\tName : " + name + + "\n\timpl : " + implAdv); + } + + try { + if (null == implAdv) { + // Use the default Peer Group Impl Advertisement + implAdv = parentGroup.getAllPurposePeerGroupImplAdvertisement(); + } + + // Build the group + GenericPeerGroup.setGroupConfigAdvertisement(id,config); + + result = (PeerGroup) parentGroup.loadModule(id, implAdv); + + // Set the name and description + // FIXME 20060217 bondolo How sad, we can't use our XML description. + if (null != desc) { + result.publishGroup(name, desc.getTextValue()); + } else { + result.publishGroup(name, null); + } + + return result; + } catch (PeerGroupException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", failed); + } + // rethrow + throw failed; + } catch (RuntimeException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", e); + } + // rethrow + throw e; + } catch (Exception e) { + // should be all other checked exceptions + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", e); + } + // Simplify exception scheme for caller: every sort of problem + // wrapped in a PeerGroupException. + throw new PeerGroupException("newNetPeerGroup failed", e); + } + } + } + + /** + * Holds the construction tunables for the Net Peer Group. This consists of + * the peer group id, the peer group name and the peer group description. + */ + static class NetGroupTunables { + + final ID id; + final String name; + final XMLElement desc; + + /** + * Constructor for loading the default Net Peer Group construction + * tunables. + */ + NetGroupTunables() { + id = PeerGroupID.defaultNetPeerGroupID; + name = "NetPeerGroup"; + desc = (XMLElement) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "desc", "default Net Peer Group"); + } + + /** + * Constructor for loading the default Net Peer Group construction + * tunables. + * + * @param pgid the PeerGroupID + * @param pgname the group name + * @param pgdesc the group description + */ + NetGroupTunables(ID pgid, String pgname, XMLElement pgdesc) { + id = pgid; + name = pgname; + desc = pgdesc; + } + + /** + * Constructor for loading the Net Peer Group construction + * tunables from the provided resource bundle. + * + * @param rsrcs The resource bundle from which resources will be loaded. + * @param defaults default values + */ + NetGroupTunables(ResourceBundle rsrcs, NetGroupTunables defaults) { + ID idTmp; + String nameTmp; + XMLElement descTmp; + + try { + String idTmpStr = rsrcs.getString("NetPeerGroupID").trim(); + + if (idTmpStr.startsWith(ID.URNNamespace + ":")) { + idTmpStr = idTmpStr.substring(5); + } + idTmp = IDFactory.fromURI(new URI(ID.URIEncodingName + ":" + ID.URNNamespace + ":" + idTmpStr)); + nameTmp = rsrcs.getString("NetPeerGroupName").trim(); + descTmp = (XMLElement) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "desc", + rsrcs.getString("NetPeerGroupDesc").trim()); + } catch (Exception failed) { + if (null != defaults) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "NetPeerGroup tunables not defined or could not be loaded. Using defaults.", failed); + } + + idTmp = defaults.id; + nameTmp = defaults.name; + descTmp = defaults.desc; + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "NetPeerGroup tunables not defined or could not be loaded.", failed); + } + + throw new IllegalStateException("NetPeerGroup tunables not defined or could not be loaded."); + } + } + + id = idTmp; + name = nameTmp; + desc = descTmp; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroup.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroup.java new file mode 100644 index 000000000..7e900561d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroup.java @@ -0,0 +1,1003 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peergroup; + + +import net.jxta.access.AccessService; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.Element; +import net.jxta.endpoint.EndpointService; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peer.PeerInfoService; +import net.jxta.pipe.PipeService; +import net.jxta.platform.JxtaLoader; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.resolver.ResolverService; +import net.jxta.service.Service; + +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.net.URI; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + + +/** + * Peer groups are formed as a collection of peers that have agreed upon a + * common set of services. Each peer group is assigned a unique peer group ID + * and a peer group advertisement. The peer group advertisement contains a + * ModuleSpecID which refers to a module specification for this peer group. + *

      + * The peer group specification mandates each of the group services (membership, + * discovery, resolver, etc). Implementations of that specification are + * described by ModuleImplAdvertisements which are identified by the group's + * ModuleSpecID. Implementations are responsible for providing the services mandated + * by the specification. + *

      + * The java reference implementation achieves this by loading additional Modules + * which ModuleSpecIDs are listed by the group implementation advertisement. + *

      + * In order to fully participate in a group, a peer may need to authenticate + * with the group using the peer group membership service. + * + * @see net.jxta.peergroup.PeerGroupID + * @see net.jxta.service.Service + * @see net.jxta.peergroup.PeerGroupFactory + * @see net.jxta.protocol.PeerGroupAdvertisement + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see net.jxta.platform.ModuleSpecID + * @see net.jxta.platform.ModuleClassID + */ +public interface PeerGroup extends Service { + + /** + * Look for needed ModuleImplAdvertisement in this group. + */ + public final static int Here = 0; + + /** + * Look for needed ModuleImplAdvertisement in the parent group of this group. + */ + public final static int FromParent = 1; + + /** + * Look for needed ModuleImplAdvertisement in both this group and its parent. + */ + public final static int Both = 2; + + /** + * Default life time for group advertisements in the publisher's cache. + * (a year) + */ + // without casting to long we lose precision + public final static long DEFAULT_LIFETIME = (long) 1000 * (long) 3600 * (long) 24 * 365L; + + /** + * Default expiration time for discovered group advertisements. (2 weeks) + */ + // without casting to long we lose precision + public final static long DEFAULT_EXPIRATION = (long) 1000 * (long) 3600 * (long) 24 * 14L; + + /** + * Global registry of instantiated peer groups. We allow only a single + * PeerGroup instance for a specific PeerGroupID within the context of the + * classloader JXTA is loaded into. + */ + static class GlobalRegistry { + + private final Map> registry = new HashMap>(8); + + /** + * Registers a new instance. + * + * @param gid the ID of the group of which an instance is being registered. + * @param pg the group instance being registered. + * @return false if the instance could not be registered because there + * was already such an instance registered. + */ + public synchronized boolean registerInstance(PeerGroupID gid, PeerGroup pg) { + + Reference ref = registry.get(gid); + + if ((ref != null) && (ref.get() != null)) { + return false; + } + + // If the ref is a dead instance, we can also replace it. + registry.put(gid, new WeakReference(pg)); + return true; + } + + /** + * Unregisters a group instance (normally because the group is being + * stopped. + * + * @param gid the ID of the group of which an instance is unregistered. + * @param pg the group instance itself (serves as a credential). + * @return false if the group could not be unregistered because no such + * registration (exact ID, exact object) was not found. + */ + public synchronized boolean unRegisterInstance(PeerGroupID gid, PeerGroup pg) { + + Reference ref = registry.get(gid); + + if (ref == null) { + return false; + } + + PeerGroup found = ref.get(); + + if (found == null) { + // Dead instance. Remove from table. + registry.remove(gid); + return false; + } + + // Note the use of "!=", not "!equals()" + if (pg != found) { + return false; + } + + registry.remove(gid); + return true; + } + + /** + * Returns a running instance of the peergroup with given ID if any + * exists. The instance should be {@link PeerGroup#unref()}ed when it is + * no longer needed. + * + * @param gid the id of the group of which an instance is wanted. + * @return the group, or {@code null} if no instance exists. + */ + public synchronized PeerGroup lookupInstance(PeerGroupID gid) { + + Reference ref = registry.get(gid); + + if (ref == null) { + return null; + } + + PeerGroup pg = ref.get(); + + if (pg == null) { + // Dead instance. remove from table. + registry.remove(gid); + return null; + } + + // Returns an interface object. Therefore a module that got the + // peergroup through lookup cannot unregister it if the group + // protects itself by returning an interface object different from + // the group object. In general only the group itself can + // unregister when being torn down. Unregistration will also be + // automatic if the grp object is GC'ed (the references are weak + // references). + return (PeerGroup) pg.getInterface(); + } + + /** + * Returns a running instance of the peergroup with given ID if any + * exists. + * + * @param gid The id of the group of which an instance is wanted. + * @return The group, or {@code null} if no instance exists. + */ + synchronized PeerGroup getInstance(PeerGroupID gid) { + + Reference ref = registry.get(gid); + + if (ref == null) { + return null; + } + + PeerGroup pg = ref.get(); + + if (pg == null) { + // Dead instance. remove from table. + registry.remove(gid); + return null; + } + + return pg; + } + + /** + * Returns {@code true} if there is a registered peergroup of the + * specified ID. + * + * @param gid the id of the group of which an instance is wanted. + * @return {@code} true if the peergroup is currently registered + * otherwise false; + */ + public synchronized boolean registeredInstance(PeerGroupID gid) { + + Reference ref = registry.get(gid); + + if (ref == null) { + return false; + } + + PeerGroup pg = ref.get(); + + if (pg == null) { + // Dead instance. remove from table. + registry.remove(gid); + return false; + } + + return true; + } + } + + /** + * Well known classes for the basic services. + * + *

      FIXME: we should make a "well-known ID" encoding implementation that + * has its own little name space of human readable names...later. + * To keep their string representation shorter, we put our small spec + * or role pseudo unique ID at the front of the second UUID string. + * Base classes do not need an explicit second UUID string because it is + * all 0. + * + *

      The type is always the last two characters, no-matter the total length. + */ + + /** + * Prefix string for all of the Well Known IDs declared in this interface. + */ + static final String WK_ID_PREFIX = ID.URIEncodingName + ":" + ID.URNNamespace + ":uuid-DeadBeefDeafBabaFeedBabe"; + + /** + * Well known module class identifier: peer group + */ + public final static ModuleClassID peerGroupClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000105")); + + /** + * Well known module class identifier: resolver service + */ + public final static ModuleClassID resolverClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000205")); + + /** + * Well known module class identifier: discovery service + */ + public final static ModuleClassID discoveryClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000305")); + + /** + * Well known module class identifier: pipe service + */ + public final static ModuleClassID pipeClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000405")); + + /** + * Well known module class identifier: membership service + */ + public final static ModuleClassID membershipClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000505")); + + /** + * Well known module class identifier: rendezvous service + */ + public final static ModuleClassID rendezvousClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000605")); + + /** + * Well known module class identifier: peerinfo service + */ + public final static ModuleClassID peerinfoClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000705")); + + /** + * Well known module class identifier: endpoint service + */ + public final static ModuleClassID endpointClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000805")); + + // FIXME: EndpointProtocols should probably all be of the same class + // and of different specs and roles... But we'll take a shortcut for now. + + /** + * Well known module class identifier: tcp protocol + */ + public final static ModuleClassID tcpProtoClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000905")); + + /** + * Well known module class identifier: http protocol + */ + public final static ModuleClassID httpProtoClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000A05")); + + /** + * Well known module class identifier: router protocol + */ + public final static ModuleClassID routerProtoClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000B05")); + + /** + * Well known module class identifier: application + */ + public final static ModuleClassID applicationClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000C05")); + + /** + * Well known module class identifier: tlsProtocol + */ + public final static ModuleClassID tlsProtoClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000D05")); + + /** + * Well known module class identifier: ProxyService + */ + public final static ModuleClassID proxyClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000E05")); + + /** + * Well known module class identifier: RelayProtocol + */ + public final static ModuleClassID relayProtoClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000000F05")); + + /** + * Well known module class identifier: AccessService + */ + public final static ModuleClassID accessClassID = + ModuleClassID.create(URI.create(WK_ID_PREFIX + "0000001005")); + + /** + * Well known group specification identifier: the platform + */ + public final static ModuleSpecID refPlatformSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000010106")); + + /** + * Well known group specification identifier: the Network Peer Group + */ + public final static ModuleSpecID refNetPeerGroupSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000010206")); + + /** + * Well known service specification identifier: the standard resolver + */ + public final static ModuleSpecID refResolverSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000020106")); + + /** + * Well known service specification identifier: the standard discovery + */ + public final static ModuleSpecID refDiscoverySpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000030106")); + + /** + * Well known service specification identifier: the standard pipe service + */ + public final static ModuleSpecID refPipeSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000040106")); + + /** + * Well known service specification identifier: the standard membership + */ + public final static ModuleSpecID refMembershipSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000050106")); + + /** + * Well known service specification identifier: the standard rendezvous + */ + public final static ModuleSpecID refRendezvousSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000060106")); + + /** + * Well known service specification identifier: the standard peerinfo + */ + public final static ModuleSpecID refPeerinfoSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000070106")); + + /** + * Well known service specification identifier: the standard endpoint + */ + public final static ModuleSpecID refEndpointSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000080106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * tcp endpoint protocol + */ + public final static ModuleSpecID refTcpProtoSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000090106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * http endpoint protocol + */ + public final static ModuleSpecID refHttpProtoSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "0000000A0106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * router + */ + public final static ModuleSpecID refRouterProtoSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "0000000B0106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * tls endpoint protocol + */ + public final static ModuleSpecID refTlsProtoSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "0000000D0106")); + + /** + * Well known group specification identifier: an all purpose peer group + * specification. The java reference implementation implements it with + * the StdPeerGroup class and all the standard platform services and no + * endpoint protocols. + */ + public final static ModuleSpecID allPurposePeerGroupSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000010306")); + + /** + * Well known application: the shell + */ + public final static ModuleSpecID refShellSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "0000000C0206")); + + /** + * Well known application: the Proxy + */ + public final static ModuleSpecID refProxySpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "0000000E0106")); + + /** + * Well known endpoint protocol specification identifier: the standard + * relay endpoint protocol + */ + public final static ModuleSpecID refRelayProtoSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "0000000F0106")); + + /** + * Well known access specification identifier: the standard + * access service + */ + public final static ModuleSpecID refAccessSpecID = + ModuleSpecID.create(URI.create(WK_ID_PREFIX + "000000100106")); + + /** + * The global registry of Peer Group instances. Operations involving the + * instantiation or orderly shutdown of Peer Groups should synchronize upon + * this object. + */ + final static GlobalRegistry globalRegistry = new GlobalRegistry(); + + /** + * Returns the Thread Group in which threads for this peer group will live. + * This is currently used only for debugging purposes so that the source of + * a thread can be determined. + * + * @return ThreadGroup + */ + public ThreadGroup getHomeThreadGroup(); + + /** + * Returns the class loader for this group. + * + * @return JxtaLoader The JXTA Class loader used by this group. + */ + public JxtaLoader getLoader(); + + /** + * Returns the whether the group member is a Rendezvous peer for the group. + * + * @return boolean true if the peer is a rendezvous for the group. + */ + public boolean isRendezvous(); + + /** + * Return the PeerGroupAdvertisement for this group. + * + * @return PeerGroupAdvertisement this Group's advertisement. + */ + public PeerGroupAdvertisement getPeerGroupAdvertisement(); + + /** + * Return the PeerAdvertisement of the local Peer within this Peer Group. + * + * @return the PeerAdvertisement of the local Peer within this Peer Group. + */ + public PeerAdvertisement getPeerAdvertisement(); + + /** + * Lookup for a service by name. + * + * @param name the service identifier. + * @return Service, the Service registered by that name + * @throws ServiceNotFoundException could not find the service requested + */ + public Service lookupService(ID name) throws ServiceNotFoundException; + + /** + * Lookup for a service by class ID and index in a map. + *

      + * More than one service in a group may be of a given ModuleClass. + * However each of them has a unique assigned ID which serves as the + * index in the map of services. In most cases, there is only one + * service of each given Module Class, and the ID of that Module Class + * is the assigned ID. Otherwise, the group may have a list of existing + * assigned ID per base class. This routine may be used to retrieve + * services of the given Module Class and index in that list. + * In the absence of a mapping, index 0 is still valid and + * corresponds to the service which assigned ID is exactly the + * given ID. + * Group objects with a map are normally wrappers tailored + * specially by the loader of a module (often the group itself) in order + * to provide a map appropriate for that module. Modules that do not use + * more than one service of a given base class normally never need to call + * this method; lookupService(ID) is equivalent to lookupService(ID, 0) + * and will transparently remap index 0 to whatever the group's + * structure defines as the default for the invoking service. + *

      + * Note: traditionally, the given ID is expected to be a base Module + * Class ID, and the assigned ID of a Module is a Class ID of the + * same base class with a role suffix to make it unique. If the given + * ID already contains a role suffix, there may exist an entry for + * it in the map anyway, if not (which is the expected use pattern), + * then only index 0 exists and the given ID is used whole and + * untranslated. + * + * @param name the service identifier + * @param roleIndex the index in the list of assigned IDs that match + * that identifier. + * @return Service, the corresponding Service + * @throws ServiceNotFoundException Could not find the service requested. + * @since JXTA 2.3.1 + */ + public Service lookupService(ID name, int roleIndex) throws ServiceNotFoundException; + + /** + * Returns the map of the assigned IDs currently associated with the given + * ModuleClassID by this PeerGroup object. The IDs are returned in the order + * of their index in the map. So the first ID returned will be identical to + * what would be returned by the lookup method for the given ID and index 0. + * If there is no explicit such map, this method will return a singleton + * containing the given ID as this is the default mapping. There is no + * guarantee that any of the returned IDs correspond to an actually + * registered service. This method only maps IDs. + * + * @param name The ModuleClassID for which the map is desired. + * @return Iterator An iterator on a collection of the IDs to which the given ID maps. + * @since JXTA 2.3.1 + */ + public Iterator getRoleMap(ID name); + + /** + * Return true if the provided compatibility statement is compatible with this group. + * + * @param compat compatibility element + * @return boolean True if the statement is compatible. + */ + public boolean compatible(Element compat); + + /** + * Load a Module from a ModuleImplAdv. + *

      + * Compatibility is checked and load is attempted. If compatible and + * loaded successfully, the resulting Module is initialized and returned. + * In most cases the other loadModule() method should be preferred, since + * unlike this one, it will seek many compatible implementation + * advertisements and try them all until one works. The home group of the new + * module (its' parent group if the new Module is a group) will be this group. + * + * @param assignedID Id to be assigned to that module (usually its ClassID). + * @param impl An implementation advertisement for that module. + * @return Module the module loaded and initialized. + * @throws ProtocolNotSupportedException The implementation described by the + * advertisement is incompatible with this peer. The module cannot be loaded. + * @throws PeerGroupException The module could not be loaded or initialized + */ + public Module loadModule(ID assignedID, Advertisement impl) throws ProtocolNotSupportedException, PeerGroupException; + + /** + * Load a module from a ModuleSpecID + *

      + * Advertisement is sought, compatibility is checked on all candidates + * and load is attempted. The first one that is compatible and loads + * successfully is initialized and returned. + * + * @param assignedID Id to be assigned to that module (usually its ClassID). + * @param specID The specID of this module. + * @param where May be one of: {@code Here}, {@code FromParent}, or + * {@code Both}, meaning that the implementation advertisement will be + * searched in this group, its parent or both. As a general guideline, the + * implementation advertisements of a group should be searched in its + * prospective parent (that is {@code Here}), the implementation + * advertisements of a group standard service should be searched in the same + * group than where this group's advertisement was found (that is, + * {@code FromParent}), while applications may be sought more freely + * ({@code Both}). + * @return Module the new module, or null if no usable implementation was + * found. + */ + public Module loadModule(ID assignedID, ModuleSpecID specID, int where); + + /** + * Publish this group's Peer Group Advertisement. The Advertisement will be + * published using the parent peer group's Discovery service. + *

      + * Calling this method is only useful if the group is being created + * from scratch and the PeerGroup advertisement has not been + * created beforehand. In such a case, the group has never been named or + * described. Therefore this information has to be supplied here. + * + * @param name The name of this group. + * @param description The description of this group. + * @throws IOException The publication could not be accomplished + * because of a network or storage failure. + */ + public void publishGroup(String name, String description) throws IOException; + + /* + * Valuable application helpers: Various methods to instantiate + * groups. + */ + + /** + * Instantiate a peer group from the provided advertisement. This peer + * group will be the parent of the newly instantiated peer group. + *

      + * The pgAdv itself may be all new and unpublished. Therefore, the two + * typical uses of this routine are: + *

      + *

        + *
      • Creating an all new group with a new ID while using an existing + * and published implementation. (Possibly a new one published for + * that purpose). The information should first be gathered in a new + * PeerGroupAdvertisement which is then passed to this method.
      • + *

        + *

      • Instantiating a group which advertisement has already been + * discovered (therefore there is no need to find it by groupID + * again).
      • + *
      + * + * @param pgAdv The advertisement for the group to be instantiated. + * @return PeerGroup the initialized (but not started) peergroup. + * @throws PeerGroupException For problems instantiating the peer group. + */ + public PeerGroup newGroup(Advertisement pgAdv) throws PeerGroupException; + + /** + * Instantiates a peer group from its elementary pieces + * and publishes the corresponding PeerGroupAdvertisement. + * The pieces are: the groups implementation adv, the group id, + * the name and description. + *

      + * The typical use of this routine is creating a whole new group based + * on a newly created and possibly unpublished implementation adv. + *

      + * This is a convenience method equivalent to either: + *

      + *

      +     * newGrp = thisGroup.loadModule(gid, impl);
      +     * newGrp.publishGroup(name, description);
      +     * 
      + * or, but only if the implementation advertisement has been published: + *

      + *

      +     * newPGAdv = AdvertisementFactory.newAdvertisement(
      +     *                 PeerGroupAdvertisement.getAdvertisementType());
      +     * newPGAdv.setPeerGroupID(gid);
      +     * newPGAdv.setModuleSpecID(impl.getModuleSpecID());
      +     * newPGAdv.setName(name);
      +     * newPGAdv.setDescription(description);
      +     * newGrp = thisGroup.newGroup(newPGAdv);
      +     * 
      + * + * @param gid The ID of that group. If null then a new group ID + * will be chosen. + * @param impl The advertisement of the implementation to be used. + * @param name The name of the group. + * @param description A description of this group. + * @return PeerGroup the initialized (but not started) peergroup. + * @throws PeerGroupException Thrown if the group could not be instantiated. + */ + public PeerGroup newGroup(PeerGroupID gid, Advertisement impl, String name, String description) throws PeerGroupException; + + /** + * Instantiate a group from its Peer Group ID only. Use this when using a + * group that has already been published and discovered. + *

      + * The typical uses of this routine are therefore: + *

      + *

        + *
      • Instantiating a peer group which is assumed to exist and whose Peer + * Group ID is already known.
      • + *

        + *

      • Creating a new peer group instance using an already published + * Group advertisement, typically published for that purpose. All other + * referenced advertisements must also be available.
      • + *
      + *

      + * To create a group from a known implAdv, just use + * {@link #loadModule(ID,Advertisement)} or even:

      + *

      + * + * grp = new GroupSubClass(); + * grp.init(parentGroup, gid, impladv); + * + *

      + * then, REMEMBER TO PUBLISH THE GROUP IF IT IS ALL NEW. + * + * @param gid the groupID. + * @return PeerGroup the initialized (but not started) peergroup. + * @throws PeerGroupException Thrown if the group could not be instantiated. + */ + public PeerGroup newGroup(PeerGroupID gid) throws PeerGroupException; + + /* + * Shortcuts to the well-known services, in order to avoid calls to + * {@link #lookupService(ID)}. + */ + + /** + * Return the Rendezvous Service for this Peer Group. This service is + * optional and may not be present in all groups. + * + * @return The Rendezvous Service for this Peer Group or null + * if there is no Rendezvous Service in this Peer Group. + */ + public RendezVousService getRendezVousService(); + + /** + * Return the Endpoint Service for this Peer Group. This service is + * present in every Peer Group. + * + * @return EndpointService The Endpoint Service for this Peer Group. + */ + public EndpointService getEndpointService(); + + /** + * Return the Resolver Service for this Peer Group. This service is + * present in every Peer Group. + * + * @return ResolverService The Resolver Service for this Peer Group. + */ + public ResolverService getResolverService(); + + /** + * Return the Discovery Service for this Peer Group. + * + * @return The Discovery Service for this Peer Group or null + * if there is no PeerInfo Service in this Peer Group. + */ + public DiscoveryService getDiscoveryService(); + + /** + * Return the PeerInfo Service for this Peer Group. + * + * @return The PeerInfo Service for this Peer Group or null + * if there is no PeerInfo Service in this Peer Group. + */ + public PeerInfoService getPeerInfoService(); + + /** + * Return the Membership Service for this Peer Group. This service is + * present in every Peer Group. + * + * @return MembershipService The Membership Service for this Peer Group. + */ + public MembershipService getMembershipService(); + + /** + * Return the Pipe Service for this Peer Group. + * + * @return The Pipe Service for this Peer Group or null if + * there is no Pipe Service in this Peer Group. + */ + public PipeService getPipeService(); + + /** + * Return the Access Service for this Peer Group. This service is + * present in every Peer Group. + * + * @return AccessService The Access Service for this Peer Group. + * @since JXTA 2.1 + */ + public AccessService getAccessService(); + + // A few convenience methods. This information is available from the peer and peergroup advertisement. + + /** + * Return the Peer Group ID of this Peer Group. + * + * @return PeerGroupId The Peer Group ID of this Peer Group. + */ + public PeerGroupID getPeerGroupID(); + + /** + * Return the Peer ID by which this Peer is known within this Peer Group. + * + * @return the Peer ID by which this Peer is known within this Peer Group. + */ + public PeerID getPeerID(); + + /** + * Return the Name of this group. This name is not canonical, meaning that + * there may be other groups with the same name. + * + * @return String This groups's name or null if no name was + * specified. + */ + public String getPeerGroupName(); + + /** + * Return the name of the local peer within this group. This name is not + * canonical, meaning that there may be other peers with the same name. + * + * @return String This peer's name or null if no name was + * specified. + */ + public String getPeerName(); + + /** + * Returns the config advertisement for this peer in this group (if any). + * + * @return The advertisement or null if none is available. + */ + public ConfigParams getConfigAdvertisement(); + + /** + * Get an all purpose peerGroup ModuleImplAdvertisement that is compatible + * with this group. This impl adv can be used to create any group that + * relies only on the standard services. Or to derive other impl advs, using + * this impl advertisement as a basis. + *

      + * This defines a peergroup implementation that can be used for + * many purposes, and from which one may derive slightly different + * peergroup implementations. + *

      + * This definition is always the same and has a well known ModuleSpecID. + * It includes the basic service, no protocols and the shell for main + * application. + *

      + * The user must remember to change the specID if the set of services + * protocols or applications is altered before use. + * + * @return ModuleImplAdvertisement The new peergroup impl adv. + * @throws Exception if an error occurs while creating the implementation advertisement + */ + public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() throws Exception; + + /** + * Explicitly notifies a group interface that it will no-longer be + * used (similar to dispose). Does nothing to a real group object, + * only has an effect on a group interface. + */ + public void unref(); + + /** + * Returns a weak interface object that represents this + * group. + *

      + * A weak interface object has no life-cycle privileges over + * the group that it represents and therefore its users have + * no accountability. A weak interface object is safe to + * give away but holds no promise of sustained validity. + *

      + * Whatever code gave away a weak interface object retains + * the power of terminating the group object from which it + * was obtained, thereby making the weak interface + * object invalid. + *

      + * A weak interface object is immutable; its unref and stopApp + * methods do nothing. Its validity is exactly that of the + * group or interface object from which it was obtained. + *

      + * A weak interface object can be obtained from an interface + * object, or from a real group object, or from a weak interface + * object. In the later case, the object returned may be + * the original weak interface object since such objects + * are immutable. + *

      + * Whatever code obtains a weak interface object from a group object + * or regular interface object, remains entirely liable for invoking unref + * on the initial object before discarding it. Giving away a weak interface + * object is not equivalent to transferring ownership of the original. + * + * @return PeerGroup A weak interface object that represents this + * PeerGroup object. + * @since JXTA 2.2 + */ + public PeerGroup getWeakInterface(); + + /** + * Returns the parent group of this group. Not all groups have parents and + * some implementations may not reveal their parents. + * + * @return PeerGroup the parent group or null if a parent group + * if not available. + * @since JXTA 2.3 + */ + public PeerGroup getParentGroup(); + + /** + * Returns the location of the parent of all items that this peer group is + * using for persistently storing its preferences, cache, persistent store, + * properties, etc. May be {@code null} if the peergroup has no defined + * location for storing persistent data. + * + * @return The location of the parent of all persistent items stored by + * this peer group. + * @since JXTA 2.3.7 + */ + public URI getStoreHome(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroupFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroupFactory.java new file mode 100644 index 000000000..bc182e5a6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroupFactory.java @@ -0,0 +1,577 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peergroup; + + +import net.jxta.document.Advertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.exception.ConfiguratorException; +import net.jxta.exception.JxtaError; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.protocol.ConfigParams; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URLConnection; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A factory for instantiating the JXTA core peer groups. + *

      + * JXTA comes with two peergroup implementations: + *

      + *

      + *
      Platform
      + *
      Implements the world peer group. Every peer starts by instantiating this + * peer group and then other peer groups are instantiated as needed. The World + * Peer Group's ID is invariant. + *

      + * The world peer group provides the minimum core services needed to find + * and instantiate other groups on a peer. The Platform + * implementation will assign a new ID to the peer, if it does not already have + * one.

      + *

      + *

      StdPeergroup
      + *
      This is currently used to implement all other kinds of peer groups. + * The first such peer group that it is instantiated after starting is known as + * The Net Peer Group. When the Platform starts it may + * optionally search for The Net Peer Group on the local network and, + * if found, instantiate it. Otherwise a default built-in configuration of + * The Net Peer Group is instantiated. + *

      + * A non-default configuration of The Net Peer Group may be set-up + * by the administrator in charge of the network domain inside which the peer + * is starting. The Net Peer Group is discovered via the Discovery + * protocol. Many such groups may be configured by an administrator.
      + *

      + * StdPeergroup may also be used to implement User-defined + * peer groups--Users can create new peer groups which use their own set of + * customized services.

      + *
      + * + * @see net.jxta.peergroup.PeerGroup + * @deprecated This factory has been deprecated in favour of {@link WorldPeerGroupFactory} + * and {@link NetPeerGroupFactory}. See the deprecations for the individual + * methods for the specific replacements/alternatives provided by the new + * factory classes. + */ +@Deprecated +public final class PeerGroupFactory { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(PeerGroupFactory.class.getName()); + + /** + * Constant for specifying no configurator. This configurator provides no + * configuration actions but does ensure that a valid configuration exists + * at the specified location. + */ + public final static Class NULL_CONFIGURATOR = net.jxta.impl.peergroup.NullConfigurator.class; + + /** + * Constant for specifying the default configurator. Currently this is the + * familiar AWT-based dialogue but in future is likely to become the + * UI-less automatic configurator. + */ + public final static Class DEFAULT_CONFIGURATOR = net.jxta.impl.peergroup.DefaultConfigurator.class; + + /** + * The class which will be instantiated as the World Peer Group. + */ + private static Class worldGroupClass = null; + + /** + * The ID of the network peer group. + */ + private static PeerGroupID netPGID = null; + + /** + * The name of the network peer group. + */ + private static String netPGName = null; + + /** + * The description of the network peer group. + */ + private static String netPGDesc = null; + + /** + * The class which will be instantiated to configure the World Peer + * Group. + */ + private static Class configurator = DEFAULT_CONFIGURATOR; + + /** + * the location which will serve as the parent for all stored items used + * by JXTA. + */ + private static URI storeHome = null; + + /** + * Static Method to initialize the world peer group class. + * + * @param c The Class which will be instantiated for the World Peer Group + * @deprecated Consider converting to use {@link WorldPeerGroupFactory#WorldPeerGroupFactory(Class,ConfigParams,URI)}. + */ + @Deprecated + public static void setPlatformClass(Class c) { + worldGroupClass = c; + } + + /** + * Static Method to initialize the std peer group class. + * + * @param c The Class which will be instantiated for most peer groups. + * @deprecated This method previously had no effect and has been removed with no alternatives. + */ + @Deprecated + public static void setStdPeerGroupClass(Class c) { + throw new UnsupportedOperationException("This feature has been removed. (sorry)"); + } + + /** + * Sets the description which will be used for new net peer group instances. + * + * @param desc The description which will be used for new net peer group instances. + * @deprecated Consider converting to use {@link NetPeerGroupFactory#NetPeerGroupFactory(ConfigParams,URI,ID,String,XMLElement)} + * or {@link NetPeerGroupFactory#NetPeerGroupFactory(PeerGroup,ID,String,XMLElement)}. + */ + @Deprecated + public static void setNetPGDesc(String desc) { + netPGDesc = desc; + } + + /** + * Sets the name which will be used for new net peer group instances. + * + * @param name The name which will be used for new net peer group instances. + * @deprecated Consider converting to use {@link NetPeerGroupFactory#NetPeerGroupFactory(ConfigParams,URI,ID,String,XMLElement)} + * or {@link NetPeerGroupFactory#NetPeerGroupFactory(PeerGroup,ID,String,XMLElement)}. + */ + @Deprecated + public static void setNetPGName(String name) { + netPGName = name; + } + + /** + * Sets the ID which will be used for new net peer group instances. + * + * @param id The ID which will be used for new net peer group instances. + * @deprecated Consider converting to use {@link NetPeerGroupFactory#NetPeerGroupFactory(ConfigParams,URI,ID,String,XMLElement)} + * or {@link NetPeerGroupFactory#NetPeerGroupFactory(PeerGroup,ID,String,XMLElement)}. + */ + @Deprecated + public static void setNetPGID(PeerGroupID id) { + netPGID = id; + } + + /** + * Get the optional configurator class for the world peer group. + * + * @return Class configurator class + * @deprecated Consider converting to use {@link NetPeerGroupFactory}. + */ + @Deprecated + public static Class getConfiguratorClass() { + return configurator; + } + + /** + * Set the optional configurator class for the World Peer Group. If present + * an instance of this class will be used to generate/update the + * configuration parameters for the World Peer Group whenever + * {@code newPlatform()} is invoked. + *

      + * All configuration actions for the World Peer Group may be completely + * disabled by specify {@code null} as the configurator class. The default + * configuration class is always initialized to {@code DEFAULT_CONFIGURATOR}. + * + * @param c The {@code Class} to use as a configurator for the World Peer + * Group. + * @deprecated Consider converting to use {@link NetPeerGroupFactory} and/or {@link WorldPeerGroupFactory}. + */ + @Deprecated + public static void setConfiguratorClass(Class c) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Setting configurator class to : " + c); + } + + configurator = c; + } + + /** + * Returns the location which will serve as the parent for all stored items + * used by JXTA. This method is intended for use by PeerGroup implementations + * and is not intended for use by applications. Applications and services + * should use the PeerGroup method with the same name. + * + * @return The location which will serve as the parent for all stored + * items used by JXTA. + * @see PeerGroup#getStoreHome() + * @deprecated Consider converting to use {@link NetPeerGroupFactory} and/or {@link WorldPeerGroupFactory}. + */ + @Deprecated + public static URI getStoreHome() { + if (null == storeHome) { + // Establish the default store location via long established hackery. + String jxta_path = System.getProperty("JXTA_HOME", ".jxta/"); + + File jxta_home = new File(jxta_path); + + jxta_home.mkdirs(); + URI defaultHome = jxta_home.toURI(); + + return defaultHome; + } + + return storeHome; + } + + /** + * Set the location which will serve as the parent for all stored items used by JXTA. + * + * @param newHome The absolute URI location which will serve as the parent + * for all stored items used by JXTA. Currently this must be a non-opaque URI. + * May also be {@code null} to restore the default value. + * @deprecated Consider converting to use {@link NetPeerGroupFactory} and/or {@link WorldPeerGroupFactory}. + */ + @Deprecated + public static void setStoreHome(URI newHome) { + + if (null != newHome) { + // Fail if the URI is not absolute. + if (!newHome.isAbsolute()) { + throw new IllegalArgumentException("Only absolute URIs accepted for store home location."); + } + + // Fail if the URI is Opaque. + if (newHome.isOpaque()) { + throw new IllegalArgumentException("Only hierarchical URIs accepted for store home location."); + } + + // Add a trailing slash if necessary. + if (!newHome.toString().endsWith("/")) { + newHome = URI.create(newHome.toString() + "/"); + } + } + + storeHome = newHome; + } + + /** + * Static Method to create a new peer group instance. + *

      + * After being created the init() method needs to be called, and + * the startApp() method may be called, at the invoker's discretion. + * + * @return PeerGroup instance of a new PeerGroup + * @deprecated This method was previously unused and has been removed with no alternatives. (it wasn't useful) + */ + @Deprecated + public static PeerGroup newPeerGroup() { + throw new UnsupportedOperationException("This feature has been removed. (sorry)"); + } + + /** + * Instantiates the World (Platform) Peer Group and can also optionally + * (re)configure the world peer group before instantiation using the + * configurator specified via {@link #setConfiguratorClass(Class)}. + *

      + * Only one instance of the World Peer Group may be created within the + * context of the {@code PeerGroupFactory}'s class loader. Invoking this + * method amounts to creating an instance of JXTA. + *

      + * The {@link PeerGroup#init(PeerGroup,ID,Advertisement)} method is + * called automatically. The {@link PeerGroup#startApp(String[])} method + * is left for the invoker to call if appropriate. + * + * @return PeerGroup The World Peer Group instance. + * @throws JxtaError Thrown for all checked Exceptions which occur during + * construction of the World Peer Group. + * @deprecated Consider converting to use {@link WorldPeerGroupFactory#WorldPeerGroupFactory()}. + */ + @Deprecated + public static PeerGroup newPlatform() { + + Class c = PeerGroupFactory.getConfiguratorClass(); + + if (null == c) { + c = NULL_CONFIGURATOR; + } + + Configurator configurator; + + try { + Constructor config_constructor = c.getConstructor(URI.class); + + configurator = (Configurator) config_constructor.newInstance(getStoreHome()); + } catch (InvocationTargetException ie) { + LOG.log(Level.SEVERE, "Uninstantiatable configurator: " + c, ie); + + throw new JxtaError("Uninstantiatable configurator: " + c, ie); + } catch (NoSuchMethodException ie) { + LOG.log(Level.SEVERE, "Uninstantiatable configurator: " + c, ie); + + throw new JxtaError("Uninstantiatable configurator: " + c, ie); + } catch (InstantiationException ie) { + LOG.log(Level.SEVERE, "Uninstantiatable configurator: " + c, ie); + + throw new JxtaError("Uninstantiatable configurator: " + c, ie); + } catch (IllegalAccessException iae) { + LOG.log(Level.SEVERE, "can\'t instantiate configurator: " + c, iae); + + throw new JxtaError("Can't instantiate configurator: " + c, iae); + } catch (ClassCastException cce) { + LOG.log(Level.SEVERE, "Not a Configurator :" + c, cce); + + throw new JxtaError("Not a Configurator :" + c, cce); + } + + ConfigParams pc; + + try { + pc = configurator.getConfigParams(); + } catch (ConfiguratorException cce) { + LOG.log(Level.SEVERE, "Could not retrieve configuration", cce); + + throw new JxtaError("Could not retrieve configuration", cce); + } + + try { + WorldPeerGroupFactory wpgf; + + if (null == worldGroupClass) { + wpgf = new WorldPeerGroupFactory(pc, getStoreHome()); + } else { + wpgf = new WorldPeerGroupFactory(worldGroupClass, pc, getStoreHome()); + } + + configurator.setConfigParams(pc); + configurator.save(); + + // Forget about the configurator + configurator = null; + + return wpgf.getInterface(); + } catch (RuntimeException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newPlatform failed", e); + } + // rethrow + throw e; + } catch (Exception e) { + // should be all other checked exceptions + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newPlatform failed", e); + } + + // Simplify exception scheme for caller: any sort of problem wrapped + // in a PeerGroupException. + throw new JxtaError("newPlatform failed", e); + } catch (Error e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newPlatform failed", e); + } + // rethrow + throw e; + } + } + + /** + * Instantiates the net peer group using the provided parent peer group. + * + * @param ppg The parent group. + * @return PeerGroup The default netPeerGroup + * @throws PeerGroupException For failures in constructing the Net Peer Group. + * @deprecated Consider converting to use {@link NetPeerGroupFactory#NetPeerGroupFactory(PeerGroup,ID,String,XMLElement)}. + */ + @Deprecated + public static PeerGroup newNetPeerGroup(PeerGroup ppg) throws PeerGroupException { + + try { + NetPeerGroupFactory npgf; + + NetPeerGroupFactory.NetGroupTunables tunables; + + if (null == netPGID) { + // Determine net peer group configuration parameters if they + // have not already been set. + tunables = new NetPeerGroupFactory.NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config") + , + new NetPeerGroupFactory.NetGroupTunables()); + + // load overides from "${JXTA_HOME}config.properties". + URI configPropertiesLocation = getStoreHome().resolve("config.properties"); + + try { + URLConnection configProperties = configPropertiesLocation.toURL().openConnection(); + + ResourceBundle rsrcs = new PropertyResourceBundle(configProperties.getInputStream()); + + tunables = new NetPeerGroupFactory.NetGroupTunables(rsrcs, tunables); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loaded defaults from " + rsrcs); + } + } catch (MissingResourceException ignored) { + ; + } catch (IOException ignored) { + ; + } catch (Exception ignored) { + ; + } + } else { + tunables = new NetPeerGroupFactory.NetGroupTunables(netPGID, netPGName + , + (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "desc", netPGDesc)); + } + + npgf = new NetPeerGroupFactory(ppg, tunables.id, tunables.name, tunables.desc); + + PeerGroup newPg = npgf.getInterface(); + + return newPg; + } catch (PeerGroupException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", failed); + } + // rethrow + throw failed; + } catch (RuntimeException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", e); + } + // rethrow + throw e; + } catch (Exception e) { + // should be all other checked exceptions + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", e); + } + // Simplify exception scheme for caller: any sort of problem wrapped + // in a PeerGroupException. + throw new PeerGroupException("newNetPeerGroup failed", e); + } catch (Error e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "newNetPeerGroup failed", e); + } + + // rethrow + throw e; + } + } + + /** + * Instantiates the World Peer Group and then instantiates the Net Peer + * Group. This simplifies the method by which applications can start JXTA. + * + * @return The newly instantiated Net Peer Group. + * @deprecated Consider converting to use {@link NetPeerGroupFactory#NetPeerGroupFactory()} + * or preferably one of the other {@code NetPeerGroupFactory} constructors. + */ + @Deprecated + public static PeerGroup newNetPeerGroup() throws PeerGroupException { + // get/create the World Peer Group. + PeerGroup wpg = getWorldPeerGroup(); + + try { + PeerGroup npg = newNetPeerGroup(wpg); + + return npg; + } finally { + wpg.unref(); + } + } + + /** + * Retrieves or constructs a new World Peer Group instance suitable for + * use as the parent for Net Peer Group instances. This implementation + * makes an important trade-off worth noting; it will use an existing + * world peer group instance if available and ignore any changes which have + * been made to the static configuration methods provided by this class. + * + * @return The World Peer Group. + * @throws PeerGroupException For failures in recovering the World Peer Group. + */ + private static PeerGroup getWorldPeerGroup() throws PeerGroupException { + synchronized (PeerGroup.globalRegistry) { + PeerGroup result = PeerGroup.globalRegistry.lookupInstance(PeerGroupID.worldPeerGroupID); + + if (null != result) { + return result; + } + + return newPlatform(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroupID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroupID.java new file mode 100644 index 000000000..5835fff90 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/PeerGroupID.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.peergroup; + + +import java.net.URI; + +import net.jxta.id.ID; +import net.jxta.id.IDFactory; + + +/** + * This class implements a PeerGroup ID. Each peer group is assigned a + * unique id. + * + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.peer.PeerID + * + * @since JXTA 1.0 + */ +public abstract class PeerGroupID extends ID { + + /** + * Creates an ID by parsing the given URI. + * + *

      This convenience factory method works as if by invoking the + * {@link net.jxta.id.IDFactory#fromURI(URI)} method; any + * {@link java.net.URISyntaxException} thrown is caught and wrapped in a + * new {@link IllegalArgumentException} object, which is then thrown. + * + *

      This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link net.jxta.id.IDFactory}, + * which throws {@link java.net.URISyntaxException} directly, should be used + * situations where a ID is being constructed from user input or from some + * other source that may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException If {@code fromURI} is {@code null}. + * @throws IllegalArgumentException If the given URI is not a valid ID. + */ + public static PeerGroupID create(URI fromURI) { + return (PeerGroupID) ID.create(fromURI); + } + + /** + * {@inheritDoc} + */ + public PeerGroupID intern() { + return (PeerGroupID) super.intern(); + } + + /** + * The well known Unique Identifier of the world peergroup. + * This is a singleton within the scope of a VM. + */ + public final static PeerGroupID worldPeerGroupID = (new WorldPeerGroupID()).intern(); + + /** + * The well known Unique Identifier of the net peergroup. + * This is a singleton within the scope of this VM. + */ + public final static PeerGroupID defaultNetPeerGroupID = (new NetPeerGroupID()).intern(); + + /** + * Returns the parent peer group id of this peer group id, if any. + * + * @return the id of the parent peergroup or null if this group has no + * parent group. + */ + public abstract PeerGroupID getParentPeerGroupID(); +} + + +final class WorldPeerGroupID extends PeerGroupID { + + /** + * The name associated with this ID Format. + */ + final static String JXTAFormat = "jxta"; + + private static final String UNIQUEVALUE = "WorldGroup"; + + /** + * WorldPeerGroupID is not intended to be constructed. You should use the + * {@link PeerGroupID.worldPeerGroupID} constant instead. + */ + WorldPeerGroupID() {} + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + return (this == target); // worldPeerGroupID is only itself. + } + + /** + * deserialization has to point back to the singleton in this VM + */ + private Object readResolve() { + return PeerGroupID.worldPeerGroupID; + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return JXTAFormat; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + UNIQUEVALUE; + } + + /** + * {@inheritDoc} + */ + @Override + public PeerGroupID getParentPeerGroupID() { + return null; + } +} + + +final class NetPeerGroupID extends PeerGroupID { + + /** + * The name associated with this ID Format. + */ + final static String JXTAFormat = "jxta"; + + private static final String UNIQUEVALUE = "NetGroup"; + + /** + * NetPeerGroupID is not intended to be constructed. You should use the + * {@link PeerGroupID.defaultNetPeerGroupID} constant instead. + */ + NetPeerGroupID() {} + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + return (this == target); // netPeerGroupID is only itself. + } + + /** + * deserialization has to point back to the singleton in this VM + */ + private Object readResolve() { + return PeerGroupID.defaultNetPeerGroupID; + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return JXTAFormat; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + UNIQUEVALUE; + } + + /** + * {@inheritDoc} + */ + @Override + public PeerGroupID getParentPeerGroupID() { + return PeerGroupID.worldPeerGroupID; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/WorldPeerGroupFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/WorldPeerGroupFactory.java new file mode 100644 index 000000000..a8cac02d7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/WorldPeerGroupFactory.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.peergroup; + + +import net.jxta.exception.ConfiguratorException; +import net.jxta.exception.PeerGroupException; +import net.jxta.logging.Logging; +import net.jxta.protocol.ConfigParams; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.platform.JxtaLoader; +import net.jxta.protocol.ModuleImplAdvertisement; + + +/** + * A factory for instantiating the World Peer Group. Every peer starts by + * instantiating the World Peer Group and then other Peer Groups are + * instantiated as needed. Most applications do not need to use + * {@code WorldPeerGroupFactory} but should instead prefer using + * {@code NetPeerGroupFactory} whenever possible. + *

      + * The World Peer Group provides the minimum core services needed to find + * and instantiate other Peer Groups on a peer. The World Peer Group is the + * primordial peer group upon which all other peer groups are instantiated. The + * World Peer Group is primarily responsible for management of physical network + * connections, physical network discovery (generally broadcast) and physical + * network topology management. + *

      + * Applications generally do not normally interact directly with the World Peer + * Group. The World Peer Group includes only limited endpoint, resolver, + * discovery and rendezvous services. + *

      + * When the World Peer Group starts it may optionally search + * for The Network Peer Group on the local network and, if found, + * instantiate it. Otherwise a default built-in configuration of The Net + * Peer Group is instantiated. + * + * @since JXTA JSE 2.4 + * + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.peergroup.NetPeerGroupFactory + */ +public final class WorldPeerGroupFactory { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(WorldPeerGroupFactory.class.getName()); + + /** + * Our strong reference to the World Peer Group. + */ + private final PeerGroup world; + + /** + * Provided for backwards compatibility, this constructor instantiates the + * World Peer Group using the PlatformConfig file found in the directory + * specified by the {@code JXTA_HOME} system property or the "{@code .jxta/}" + * directory if {@code JXTA_HOME} is not defined. + *

      + * Though not deprecated this method should be considered as sample + * code only and the other constructors should be used whenever possible. + * + * @throws PeerGroupException Thrown for problems construction the World + * Peer Group. + */ + public WorldPeerGroupFactory() throws PeerGroupException { + // Establish the default store location via long established hackery. + String jxta_home = System.getProperty("JXTA_HOME", ".jxta/"); + + // ensure that it ends in a seperator. + if (!jxta_home.endsWith(File.separator)) { + jxta_home += File.separator; + } + + File jxta_home_dir = new File(jxta_home); + + // Ensure the homedir exists. + if (!jxta_home_dir.exists()) { + jxta_home_dir.mkdirs(); + } + + URI storeHome = jxta_home_dir.toURI(); + + // Instantiate the default configurator. Do not do this in your own code! + try { + Configurator configurator = new net.jxta.impl.peergroup.DefaultConfigurator(storeHome); + // Get (and possibly generate) the platform configuration. + ConfigParams config = configurator.getConfigParams(); + + world = newWorldPeerGroup(getDefaultWorldPeerGroupClass(), config, storeHome); + + // persist any changes which were made to the platform config by + // service initialization. + configurator.setConfigParams(config); + configurator.save(); + } catch (ConfiguratorException configFailure) { + LOG.severe("Failure while managing World Peer Group configuration"); + + throw new PeerGroupException("Failure while managing World Peer Group configuration", configFailure); + } + } + + /** + * Constructs the World Peer Group using the specified configuration and + * using the specified storeHome location for persistence. + * + * @param config The configuration to use for the World Peer Group. + * @param storeHome The optional location that the World Peer Group and its' + * services should use for storing persistent and transient information. + * May be null if the World Peer Group is not provided a + * persistent store (though this not currently supported). + * @throws PeerGroupException Thrown for problems constructing the World + * Peer Group. + */ + public WorldPeerGroupFactory(ConfigParams config, URI storeHome) throws PeerGroupException { + + world = newWorldPeerGroup(getDefaultWorldPeerGroupClass(), config, storeHome); + } + + /** + * Constructs the World Peer Group using the specified configuration and + * using the specified storeHome location for persistence. + * + * @param worldPeerGroupClass The class which will be instantiated for the + * World Peer Group instance. + * @param config The configuration to use for the World Peer Group. + * @param storeHome The optional location that the World Peer Group and its' + * services should use for storing persistent and transient information. + * May be null if the World Peer Group is not provided a + * persistent store (though this not currently supported). + * @throws PeerGroupException Thrown for problems constructing the World + * Peer Group. + */ + public WorldPeerGroupFactory(Class worldPeerGroupClass, ConfigParams config, URI storeHome) throws PeerGroupException { + + world = newWorldPeerGroup(worldPeerGroupClass, config, storeHome); + } + + /** + * Returns a strong (reference counted) interface object for the World Peer + * Group. This reference should be explicitly unreferenced when it is no + * longer needed. + * + * @return A strong (reference counted) interface object for the World Peer + * Group. + * @see PeerGroup#unref() + */ + public PeerGroup getInterface() { + return (PeerGroup) world.getInterface(); + } + + /** + * Returns a weak (non-reference counted) interface object for the World + * Peer Group. + * + * @return A weak (non-reference counted) interface object for the World + * Peer Group. + * @see PeerGroup#getWeakInterface() + */ + public PeerGroup getWeakInterface() { + return world.getWeakInterface(); + } + + /** + * Determine the class to use for the World PeeerGroup. + * + * @return The Class which has been configured to be used for + * World Peer Group instances. + * @throws PeerGroupException Thrown for problems determining the class to + * be used for the World Peer Group. + */ + private static Class getDefaultWorldPeerGroupClass() throws PeerGroupException { + + try { + // XXX 20070713 bondolo Temporary hack to resolve class load order issue. StdPeerGroup is responsible for initializing standard modules. + String unused = net.jxta.impl.peergroup.StdPeerGroup.STD_COMPAT.toString(); + + JxtaLoader loader = net.jxta.impl.peergroup.GenericPeerGroup.getJxtaLoader(); + + ModuleImplAdvertisement worldGroupImplAdv = loader.findModuleImplAdvertisement(PeerGroup.refPlatformSpecID); + + if(null == worldGroupImplAdv) { + throw new PeerGroupException("Could not locate World PeerGroup Module Implementation."); + } + + return Class.forName(worldGroupImplAdv.getCode()); + } catch (RuntimeException failed) { + throw new PeerGroupException("Could not load World PeerGroup class.", failed); + } catch (ClassNotFoundException failed) { + throw new PeerGroupException("Could not load World PeerGroup class.", failed); + } + } + + /** + * Constructs the World Peer Group instance. + * + * @param worldPeerGroupClass The class which will be instantiated for the + * World Peer Group instance. + * @param config The configuration to use for the World Peer Group. + * @param storeHome The optional location the World Peer Group and its' + * services may use for storing persistent and transient information. + * May be {@code null} if the World Peer Group is not provided a + * persistent store (though this not currently supported). + * @throws PeerGroupException Thrown for problems constructing the World + * Peer Group. + * @return the WorldPeerGroup + */ + private PeerGroup newWorldPeerGroup(Class worldPeerGroupClass, ConfigParams config, URI storeHome) throws PeerGroupException { + if (!storeHome.isAbsolute()) { + LOG.severe("storeHome must be an absolute URI."); + throw new PeerGroupException("storeHome must be an absolute URI."); + } + + if (storeHome.isOpaque()) { + LOG.severe("Opaque storeHome is not currently supported."); + throw new PeerGroupException("Opaque storeHome is not currently supported."); + } + + synchronized (PeerGroup.globalRegistry) { + if (PeerGroup.globalRegistry.registeredInstance(PeerGroupID.worldPeerGroupID)) { + throw new PeerGroupException( "Only a single instance of the World Peer Group may be instantiated at a single time."); + } + + PeerGroup result = null; + + try { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Making a new World Peer Group instance using : " + worldPeerGroupClass.getName()); + } + + Constructor twoParams = (Constructor) worldPeerGroupClass.getConstructor(ConfigParams.class,URI.class); + + try { + result = twoParams.newInstance(config, storeHome); + } catch (InvocationTargetException failure) { + // unwrap the real exception. + Throwable cause = failure.getCause(); + + if (cause instanceof Exception) { + throw (Exception) cause; + } else if (cause instanceof Error) { + throw (Error) cause; + } else { + // just rethrow what we already had. sigh. + throw failure; + } + } + + result.init(null, PeerGroupID.worldPeerGroupID, null); + + return result; + } catch (RuntimeException e) { + // should be all other checked exceptions + LOG.log(Level.SEVERE, "World Peer Group could not be instantiated.", e); + + // cleanup broken instance + if (null != result) { + result.unref(); + } + + // just rethrow. + throw e; + } catch (Exception e) { + // should be all other checked exceptions + LOG.log(Level.SEVERE, "World Peer Group could not be instantiated.", e); + + // cleanup broken instance + if (null != result) { + result.unref(); + } + + // Simplify exception scheme for caller: any sort of problem wrapped + // in a PeerGroupException. + throw new PeerGroupException("World Peer Group could not be instantiated.", e); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/package.html new file mode 100644 index 000000000..155ccd1ff --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/peergroup/package.html @@ -0,0 +1,79 @@ + + + + + + + Peer groups are formed as a collection of peers that have agreed upon a + common set of services. The {@link net.jxta.peergroup.PeerGroup} interface presents the + API of those services and encapsulates the group's identity and the local + peer's identity in that group. + +

      A group is instantiated on a peer by instantiating the group class + specified by the group definition and initializing the resulting object + with the parameters specified by the group definition. + +

      A group may be, and often is, defined and instantiated within the + context of another group referred to as its parent group. In that case an + appropriate and initialized {@link net.jxta.peergroup.PeerGroup} object, + that represents that group may be obtained from the parent group by using + one of the parent's {@link net.jxta.peergroup.PeerGroup#newGroup newGroup} + methods. + +

      All peers start with instantiating one well known root group + (which has no parent) known as the World Peer Group. It is created + by calling {@link net.jxta.peergroup.PeerGroupFactory#newPlatform()}. + +

      The World Peer Group has a limited set of functionality. Most + peers chose to instantiate early on another well known group known as the + Net Peer Group and to use it as the root of the other groups they + create. + +

      An object representing the Net Peer Group may be obtained from + the {@link net.jxta.peergroup.PeerGroupFactory} by invoking the method + {@link net.jxta.peergroup.PeerGroupFactory#newNetPeerGroup()}. This method + invokes {@link net.jxta.peergroup.PeerGroupFactory#newPlatform()} + automatically, so if an application wants to use the Net Peer Group + as its root group, invoking + {@link net.jxta.peergroup.PeerGroupFactory#newNetPeerGroup()} is all that is + required. + +

      All other groups should be created or instantiated within the context of + already instantiated groups by using one of the + {@link net.jxta.peergroup.PeerGroup#newGroup newGroup} methods. + +

      It is possible to change the identity, name, and description of the + group that {@link net.jxta.peergroup.PeerGroupFactory#newNetPeerGroup()} + instantiates by setting the following properties in the file + config.properties (all three must be specified for the setting + to take effect): +

        +
      • NetPeerGroupID
      • +
      • NetPeerGroupName
      • +
      • NetPeerGroupDesc
      • +
      + The same result may be obtained by invoking the following + {@link net.jxta.peergroup.PeerGroupFactory} static methods: +
        +
      • {@link net.jxta.peergroup.PeerGroupFactory#setNetPGID}
      • +
      • {@link net.jxta.peergroup.PeerGroupFactory#setNetPGName}
      • +
      • {@link net.jxta.peergroup.PeerGroupFactory#setNetPGDesc}
      • +
      + +

      It is also possible to create arbitrary subgroups of the World Peer + Group programatically by first starting the World Peer Group + and applying one of the + {@link net.jxta.peergroup.PeerGroup#newGroup newGroup} methods of the + resulting PeerGroup object. An example of creating multiple + infrastructure peer groups. + {@link Dual Infrastructure Group Tutorial} + + + @see net.jxta.peergroup.PeerGroup + @see net.jxta.peergroup.PeerGroupFactory + @see net.jxta.protocol.PeerGroupAdvertisement + @see net.jxta.protocol.PeerAdvertisement + @see net.jxta.id.ID + @see JXTA Protocols Specification : Peer Groups + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/InputPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/InputPipe.java new file mode 100644 index 000000000..2e20ff4c7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/InputPipe.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import net.jxta.id.ID; +import net.jxta.endpoint.Message; +import net.jxta.protocol.PipeAdvertisement; + + +/** + * InputPipe defines the interface for receiving messages from a + * {@link net.jxta.pipe.PipeService}. + * + *

      An application that wants to receive messages from a Pipe will create + * an input pipe. + * + *

      An InputPipe is created and returned by the + * {@link net.jxta.pipe.PipeService} + * + * @see net.jxta.pipe.PipeService + * @see net.jxta.pipe.OutputPipe + * @see net.jxta.endpoint.Message + * @see net.jxta.endpoint.MessageElement + * @see net.jxta.protocol.PipeAdvertisement + */ +public interface InputPipe { + + /** + * Wait (block) for a message to be received. + * + * @return a message or null if the pipe has been closed. + * @exception InterruptedException If another thread interrupted while we + * were waiting for a message. + */ + public Message waitForMessage() throws InterruptedException; + + /** + * Poll for a message from the pipe. If there is no message immediately + * available then wait the specified amount of time for a message to arrive. + * + * @param timeout Maximum number of milliseconds to wait (block) for a + * message to be received. If zero then wait indefinitely for a message. + * @return Message received or null if the pipe has closed or the timeout + * expired without a message being received. + * @throws InterruptedException If another thread interrupted while we + * were waiting for a message. + */ + public Message poll(int timeout) throws InterruptedException; + + /** + * Close the pipe. No additional messages will be received on this pipe. + */ + public void close(); + + /** + * Gets the pipe type + * + * @return The type + */ + public String getType(); + + /** + * Gets the pipe id + * + * @return The type + */ + public ID getPipeID(); + + /** + * Gets the pipe name + * + * @return The name + */ + public String getName(); + + /** + * Gets the pipe advertisement + * + * @return The advertisement + */ + public PipeAdvertisement getAdvertisement(); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipe.java new file mode 100644 index 000000000..6a8b25f5b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipe.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import java.io.IOException; + +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.protocol.PipeAdvertisement; + + +/** + * OuputPipe defines the interface for sending messages from a + * {@link net.jxta.pipe.PipeService}. + * + *

      Application that want to send messages onto a Pipe must fist get + * an {@link net.jxta.pipe.OutputPipe} from the {@link net.jxta.pipe.PipeService}. + * + * @see net.jxta.pipe.PipeService + * @see net.jxta.pipe.InputPipe + * @see net.jxta.endpoint.Message + * @see net.jxta.protocol.PipeAdvertisement + */ + +public interface OutputPipe { + + /** + * Send a message through the pipe + * + *

      WARNING: The message object used when sending a pipe message + * should not be reused or modified after the {@link #send(Message)} call is + * made. Concurrent modification of messages will produce unexpected result. + * + * @param msg is the PipeMessage to be sent. + * @return boolean true if the message has been sent otherwise + * false. false. is commonly returned for + * non-error related congestion, meaning that you should be able to send + * the message after waiting some amount of time. + * @exception IOException output pipe error + * + */ + public boolean send(Message msg) throws IOException; + + /** + * close the pipe + * + */ + public void close(); + + /** + * Returns true if this pipe is closed and no longer + * accepting messages to be sent. The pipe should be discarded. + * + * @return true if this pipe is closed, otherwise + * false. + */ + boolean isClosed(); + + /** + * Gets the pipe type + * + * @return The type + */ + public String getType(); + + /** + * Gets the pipe id + * + * @return The type + */ + public ID getPipeID(); + + /** + * Gets the pipe name + * + * @return The name + */ + public String getName(); + + /** + * Gets the pipe advertisement + * + * @return The advertisement + */ + public PipeAdvertisement getAdvertisement(); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipeEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipeEvent.java new file mode 100644 index 000000000..7c5c1cd01 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipeEvent.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import java.util.EventObject; + + +/** + * Container for OutputPipeEvent events. + */ +public class OutputPipeEvent extends EventObject { + + private OutputPipe outputpipe; + + private String pipeID; + + private int queryID; + + /** + * Creates a new event + * + * @param source The PipeService which created this event. + * @param outputpipe the outputpipe object + * @param pipeID URI containing the Pipe unique identifier. + * @param queryID The query id associated with the response returned in this event + */ + public OutputPipeEvent(Object source, OutputPipe outputpipe, String pipeID, int queryID) { + + super(source); + + this.outputpipe = outputpipe; + this.pipeID = pipeID; + this.queryID = queryID; + } + + /** + * Returns the output associated with the event + * + * @return OutPutPipe + */ + public OutputPipe getOutputPipe() { + return outputpipe; + } + + /** + * Returns The pipe id associated with this output pipe event + * + * @return pipe id associated with this output pipe event + */ + public String getPipeID() { + return pipeID; + } + + /** + * Returns The query id associated with the response returned in this event + * + * @return query id associated with the response + */ + public int getQueryID() { + return queryID; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipeListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipeListener.java new file mode 100644 index 000000000..a5705c1c6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/OutputPipeListener.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving {@link net.jxta.pipe.OutputPipe} + * resolution events. + * + * The following example illustrates how to implement a + * {@link net.jxta.pipe.OutputPipeListener}: + * + *

      + *     public class MyService implements OutputPipeListener {
      + *        ..
      + *        ..
      + *        pipe.createOutputPipe(pipeAdv, this);
      + *        ..
      + *        ..
      + *        public void outputPipeEvent(OutputPipeEvent event) {
      + *
      + *        OutputPipe op = event.getOutputPipe();
      + *        }
      + *    }
      + * 
      + */ +public interface OutputPipeListener extends EventListener { + + /** + * Called when a input pipe has been located for a previously registered + * pipe. The event contains an {@link net.jxta.pipe.OutputPipe} which can + * be used to communicate with the remote peer. + * + * @param event the event + */ + void outputPipeEvent(OutputPipeEvent event); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeID.java new file mode 100644 index 000000000..579249f04 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeID.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import java.net.URI; +import net.jxta.id.ID; + + +/** + * This class implements a Pipe ID. Each pipe is assigned a unique id. + * + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.peergroup.PeerGroupID + * @see net.jxta.pipe.PipeService + * @see net.jxta.protocol.PipeAdvertisement + */ +public abstract class PipeID extends ID { + + /** + * Creates an ID by parsing the given URI. + * + *

      This convenience factory method works as if by invoking the + * {@link net.jxta.id.IDFactory#fromURI(URI)} method; any + * {@link java.net.URISyntaxException} thrown is caught and wrapped in a + * new {@link IllegalArgumentException} object, which is then thrown. + * + *

      This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link net.jxta.id.IDFactory}, + * which throws {@link java.net.URISyntaxException} directly, should be used + * situations where a ID is being constructed from user input or from some + * other source that may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException If {@code fromURI} is {@code null}. + * @throws IllegalArgumentException If the given URI is not a valid ID. + */ + public static PipeID create(URI fromURI) { + return (PipeID) ID.create(fromURI); + } + + /** + * {@inheritDoc} + */ + public PipeID intern() { + return (PipeID) super.intern(); + } + + /** + * Returns PeerGroupID of the Peer Group to which this Pipe ID belongs. + * + * @return The PeerGroupID of the Peer Group to which this Pipe ID belongs. + */ + public abstract ID getPeerGroupID(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeMsgEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeMsgEvent.java new file mode 100644 index 000000000..67eba550c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeMsgEvent.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import java.util.EventObject; +import net.jxta.endpoint.Message; + + +/** + * Container for Pipe Message events. + */ +public class PipeMsgEvent extends EventObject { + + /** + * The received Message + */ + private final Message message; + + /** + * Pipe ID of the pipe on which the message was received. + */ + private final PipeID pipeID; + + /** + * Creates a new event + * + * @param source The PipeObject on which the message was received. + * @param message the message object + * @param pipeID the pipe id of the pipe on which the message was received. + */ + public PipeMsgEvent(Object source, Message message, PipeID pipeID) { + super(source); + + this.message = message; + + this.pipeID = pipeID; + } + + /** + * Returns the message associated with the event + * + * @return message + */ + public Message getMessage() { + return message; + } + + /** + * Returns the pipeID associated with the event + * + * @return pipeID + */ + public PipeID getPipeID() { + return pipeID; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeMsgListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeMsgListener.java new file mode 100644 index 000000000..90b157e86 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeMsgListener.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.pipe; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving {@link net.jxta.pipe.PipeMsgEvent} + * events. + * + * The following example illustrates how to implement a {@link net.jxta.pipe.PipeMsgListener}: + *

      
      + * PipeMsgListener myListener = new PipeMsgListener() {
      + *
      + *   public void pipeMsgEvent(PipeMsgEvent event) {
      + *     Message msg=null;
      + *     try {
      + *       msg = event.getMessage();
      + *     } catch (Exception e) {
      + *       e.printStackTrace();
      + *       return;
      + *     }
      + *   }
      + * }
      + *
      + * InputPipe pipeIn = pipe.createInputPipe(pipeAdv, myListener);
      + * *
      + */ +public interface PipeMsgListener extends EventListener { + + /** + * Called for each pipe message event that occurs. + * + * @param event The event being received. + */ + void pipeMsgEvent(PipeMsgEvent event); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeService.java new file mode 100644 index 000000000..e4e1518cf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/PipeService.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.pipe; + + +import java.io.IOException; +import java.util.Set; + +import net.jxta.id.ID; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.service.Service; + + +/** + * Pipes are the core mechanism for exchanging messages between JXTA + * applications or services. + * + *

      Pipes are uniquely identified by a + * {@link net.jxta.protocol.PipeAdvertisement} which is associated with each + * pipe. + * + *

      Several types of Pipe can currently be used: + * + *

        + *
      • JxtaUnicast - unicast, unreliable and unsecured pipe + *
      • JxtaUnicastSecure - unicast and secure pipe + *
      • JxtaPropagate - propagated, unreliable and unsecured pipe + *
      + * + *

      The type of a Pipe is defined when creating its + * {@link net.jxta.protocol.PipeAdvertisement}. + * + * @see net.jxta.protocol.PipeAdvertisement + * @see net.jxta.pipe.InputPipe + * @see net.jxta.pipe.OutputPipe + * @see net.jxta.endpoint.Message + * @see JXTA Protocols Specification : Pipes + * @see JXTA Protocols Specification : Pipe Binding Protocol + */ +public interface PipeService extends Service { + + /** + * Unicast, unreliable and unsecured type of Pipe + */ + public final static String UnicastType = "JxtaUnicast"; + + /** + * Propagated, unsecured and unreliable type of Pipe + */ + public final static String PropagateType = "JxtaPropagate"; + + /** + * End-to-end secured unicast pipe of Pipe + */ + public final static String UnicastSecureType = "JxtaUnicastSecure"; + + /** + * Create an InputPipe from a pipe Advertisement + * + * @param adv The advertisement of the Pipe. + * @return The InputPipe created. + * @throws IOException error creating input pipe + */ + public InputPipe createInputPipe(PipeAdvertisement adv) throws IOException; + + /** + * Create an InputPipe from a pipe Advertisement + * + * @param adv is the advertisement of the Pipe. + * @param listener PipeMsgListener to receive msgs. + * @return InputPipe The InputPipe created. + * @throws IOException Error creating input pipe + */ + public InputPipe createInputPipe(PipeAdvertisement adv, PipeMsgListener listener) throws IOException; + + /** + * Attempt to create an OutputPipe using the specified Pipe Advertisement. + * The pipe will be be resolved within the provided timeout. + * + * @param pipeAdv The advertisement of the pipe being resolved. + * @param timeout Time duration in milliseconds to wait for a successful + * pipe resolution. 0 will wait indefinitely. + * @return OutputPipe the successfully resolved OutputPipe. + * @throws IOException If the pipe cannot be created or failed to resolve + * within the specified time. + */ + public OutputPipe createOutputPipe(PipeAdvertisement pipeAdv, long timeout) throws IOException; + + /** + * Attempt to create an OutputPipe using the specified Pipe Advertisement. + * The pipe will be be resolved to one of the peers in the set of peer ids + * provided within the provided timeout. + * + * @param pipeAdv The advertisement of the pipe being resolved. + * @param resolvablePeers The peers on which the pipe may be resolved. + * If the Set is empty then the pipe may be resolved to any + * destination peer. + * @param timeout Time duration in milliseconds to wait for a successful + * pipe resolution. 0 will wait indefinitely. + * @return The successfully resolved OutputPipe. + * @throws IOException If the pipe cannot be created or failed to resolve + * within the specified time. + */ + public OutputPipe createOutputPipe(PipeAdvertisement pipeAdv, Set resolvablePeers, long timeout) throws IOException; + + /** + * Attempt to create an OutputPipe using the specified Pipe Advertisement. + * The pipe may be resolved to any destination peer. When the pipe is + * resolved the listener will be called. + * + * @param pipeAdv The advertisement of the pipe being resolved. + * @param listener The listener to be called when the pipe is resolved. + * @throws IOException If the pipe cannot be created. + */ + public void createOutputPipe(PipeAdvertisement pipeAdv, OutputPipeListener listener) throws IOException; + + /** + * Attempt to create an OutputPipe using the specified Pipe Advertisement. + * When the pipe is resolved to one of the peers in the set of peer ids + * provided the listener will be called. + * + * @param pipeAdv The advertisement of the pipe being resolved. + * @param resolvablePeers The set of peers on which the pipe may be resolved. + * If the Set is empty then the pipe may be resolved to any + * destination peer. + * @param listener the listener to be called when the pipe is resolved. + * @throws IOException If the pipe cannot be created. + */ + public void createOutputPipe(PipeAdvertisement pipeAdv, Set resolvablePeers, OutputPipeListener listener) throws IOException; + + /** + * Remove an OutputPipeListener previously registered with + * createOuputputPipe. + * + * @deprecated This method is being replaced by {@link #removeOutputPipeListener(ID,OutputPipeListener)}. + * + * @param pipeID The pipe who's listener is to be removed. + * @param listener The listener to remove. + * @return The listener which was removed or null if the key did not have a mapping. + */ + @Deprecated + public OutputPipeListener removeOutputPipeListener(String pipeID, OutputPipeListener listener); + + /** + * Remove an OutputPipeListener previously registered with + * createOuputputPipe. + * + * @param pipeID The pipe who's listener is to be removed. + * @param listener The listener to remove. + * @return The listener which was removed or null if the key did not have a mapping. + */ + public OutputPipeListener removeOutputPipeListener(ID pipeID, OutputPipeListener listener); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/package.html new file mode 100644 index 000000000..6c508fb4a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/pipe/package.html @@ -0,0 +1,15 @@ + + + + + + + Pipes are the core mechanism for exchanging messages between JXTA + applications or services. + + @see net.jxta.protocol.PipeAdvertisement + @see net.jxta.pipe.PipeService + @see JXTA Protocols Specification : Pipes + @see JXTA Protocols Specification : Pipe Binding Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/Application.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/Application.java new file mode 100644 index 000000000..17d3ae2ce --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/Application.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +/** + * This interface defines a JXTA peer group application. + * That is a class of Module suitable for loading as the main application + * of a group, or which may be loaded by a group while not being a service. + * + * For now, it is a plain Module. + */ + +public interface Application extends Module {} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/JxtaLoader.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/JxtaLoader.java new file mode 100644 index 000000000..5d0379566 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/JxtaLoader.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +import java.net.URL; +import java.net.URLClassLoader; + +import net.jxta.protocol.ModuleImplAdvertisement; + + +/** + * A ClassLoader which provides additional JXTA functionality. You can load + * classes by ModuleSpecID. Classes are defined with ModuleImplAdvertisements + * and class loading will determine suitability using the provided + * compatibility statements. + */ +public abstract class JxtaLoader extends URLClassLoader { + + /** + * Construct a new loader with the specified parent loader and + * + * @param parent the parent class loader for delegation. + */ + public JxtaLoader(ClassLoader parent) { + this(new URL[0], parent); + } + + /** + * Construct a new loader for the specified URLS with the specified parent + * loader. + * + * @param urls the URLs from which to load classes and resources. + * @param parent the parent class loader for delegation. + */ + public JxtaLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + /** + * {@inheritDoc} + */ + @Override + public void addURL(URL url) { + super.addURL(url); + } + + /** + * Finds and loads the class with the specified spec ID from the URL search + * path. Any URLs referring to JAR files are loaded and opened as needed + * until the class is found. + * + * @param spec the specid of the class to load. + * @throws ClassNotFoundException if the class could not be found. + * @return the resulting class. + */ + public abstract Class findClass(ModuleSpecID spec) throws ClassNotFoundException; + + /** + * Loads the class with the specified spec ID from the URL search + * path. + * + * @param spec the specid of the class to load. + * @throws ClassNotFoundException if the class could not be found. + * @return the resulting class. + */ + public abstract Class loadClass(ModuleSpecID spec) throws ClassNotFoundException; + + /** + * Defines a new class from a Module Impl Advertisement. + * + * @param impl The moduleImplAdvertisement containing the class + * specification + * @return The Class object that was created from the specified class data. + */ + public abstract Class defineClass(ModuleImplAdvertisement impl); + + /** + * Finds the ModuleImplAdvertisement for the associated class in the + * context of this ClassLoader. + * + * @param clazz The class who's ModuleImplAdvertisement is desired. + * @return The matching {@code ModuleImplAdvertisement} otherwise + * {@code null} if there is no known association. + */ + public abstract ModuleImplAdvertisement findModuleImplAdvertisement(Class clazz); + + /** + * Finds the ModuleImplAdvertisement for the associated class in the + * context of this ClassLoader. + * + * @param msid The module spec id who's ModuleImplAdvertisement is desired. + * @return The matching {@code ModuleImplAdvertisement} otherwise + * {@code null} if there is no known association. + */ + public abstract ModuleImplAdvertisement findModuleImplAdvertisement(ModuleSpecID msid); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/Module.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/Module.java new file mode 100644 index 000000000..67ffaaff2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/Module.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +import net.jxta.peergroup.PeerGroup; +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.exception.PeerGroupException; + + +/** + * Defines the interface for modules loaded by PeerGroups. Message transports, + * services and applications need to implement this interface if they are + * to be loaded and started by a PeerGroup. Service and Application extend + * Module, PeerGroup implements Service and ShellApp implements Application, as + * a result both implement Module. + * + *

      Jxta Modules are given their initialization parameters via the init() + * method rather than a non-default constructor. + * + *

      Modules are passed the peer group within which they are created. + * From the peergroup object, Modules can access all the peer group + * services. The PeerGroup within which a PeerGroup runs is known as its + * parent. + * + *

      The initial root peer group is known as the World Peer Group and is + * implemented by an object of class Platform, a subclass of PeerGroup. + * The "parent" PeerGroup of the World Peer Group is null. + * + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.document.Advertisement + * @see net.jxta.id.ID + * @see net.jxta.platform.Application + * @see net.jxta.service.Service + **/ +public interface Module { + + /** + * startApp() completed successfully. This module claims to now + * be fully functional and no further invocation of startApp is required. + **/ + public static final int START_OK = 0; + + /** + * This is to be used mostly by co-dependent services when started as + * a set (such as {@link PeerGroup} services) so that their + * startApp() method may be invoked multiple times. + * + *

      This value indicates that startApp must be retried later in order for + * this module to become fully functional. However, some progress in + * functionality was accomplished. + * + *

      This is a strong indication that some other modules may be able + * to advance or complete their initialization if their + * startApp() method is invoked again. + * + *

      The distinction between START_AGAIN_STALLED and START_AGAIN_PROGRESS + * is only a hint. Each module makes an arbitrary judgment in this + * respect. It is up to the invoker of startApp to ensure that the + * starting of a set of modules eventually succeeds or fails. + **/ + public static final int START_AGAIN_PROGRESS = 1; + + /** + * This is to be used mostly by co-dependent services when started as + * a set (such as {@link PeerGroup} services) so that their startApp + * method may be invoked multiple times. + * + *

      This value indicates that startApp must be retried later in order for + * this module to become fully functional. However, some progress in + * functionality was accomplished. + * + *

      If all modules in a set return this value, it is a strong indication + * that the modules co-dependency is such that it prevents them + * collectively from starting. + * + *

      The distinction between START_AGAIN_STALLED and START_AGAIN_PROGRESS + * is only a hint. Each module makes an arbitrary judgment in this + * respect. It is up to the invoker of startApp to ensure that the + * starting of a set of modules eventually succeeds or fails. + **/ + public static final int START_AGAIN_STALLED = 2; + + /** + * This return result is used to indicate that the module refuses to start + * because it has been configured to be disabled or otherwise cannot run + * (missing hardware, missing system resources, etc.) The module will not be + * functional and should be discarded but the failure to load may be ignored + * by the loader at it's discretion. + */ + public static final int START_DISABLED = Integer.MIN_VALUE + 100; + + /** + * Initialize the module, passing it its peer group and advertisement. + * + *

      Note: when subclassing one of the existing PeerGroup implementations + * (which implement Module), it may not be recommended to overload the init + * method. See the documentation of the PeerGroup class being subclassed. + * + * @param group The PeerGroup from which this Module can obtain services. + * If this module is a Service, this is also the PeerGroup of which this + * module is a service. + * + * @param assignedID Identity of Module within group. + * modules can use it as a the root of their namespace to create + * names that are unique within the group but predictable by the + * same module on another peer. This is normally the ModuleClassID + * which is also the name under which the module is known by other + * modules. For a group it is the PeerGroupID itself. + * The parameters of a service, in the Peer configuration, are indexed + * by the assignedID of that service, and a Service must publish its + * run-time parameters in the Peer Advertisement under its assigned ID. + * + * @param implAdv The implementation advertisement for this + * Module. It is permissible to pass null if no implementation + * advertisement is available. This may happen if the + * implementation was selected by explicit class name rather than + * by following an implementation advertisement. Modules are not + * required to support that style of loading, but if they do, then + * their documentation should mention it. + * + * @exception PeerGroupException This module failed to initialize. + **/ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) throws PeerGroupException; + + /** + * Complete any remaining initialization of the module. The module should + * be fully functional after startApp() is completed. That is + * also the opportunity to supply arbitrary arguments (mostly to + * applications). + * + *

      If this module is a {@link PeerGroup} service, it may be invoked + * several times depending on its return value. + * + * @param args An array of Strings forming the parameters for this + * Module. + * + * @return int A status indication which may be one of + * {@link #START_OK}, {@link #START_AGAIN_PROGRESS}, + * {@link #START_AGAIN_STALLED}, which indicates partial or complete + * success, or any other value (negative values are + * recommended for future compatibility), which indicates failure. + **/ + public int startApp(String[] args); + + /** + * Stop a module. This may be called any time after init() + * completes and should not assume that startApp() has been + * called or completed. + * + *

      The Module cannot be forced to comply, but in the future + * we might be able to deny it access to anything after some timeout. + **/ + public void stopApp(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/ModuleClassID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/ModuleClassID.java new file mode 100644 index 000000000..97d3503d0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/ModuleClassID.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +import java.net.URI; +import net.jxta.id.ID; + + +/** + * A ModuleClassID uniquely identifies a particular local behaviour, that is, + * a specific API for each execution environment for which an implementation + * exists. + * + *

      A ModuleClassID has two components: A base class identifier, and a role identifier. + * The role identifier may be zero. By convention the API uses the ModuleClassID with + * a zero role identifier to designate the base class in contexts where only the base class + * is significant. Nonetheless, a ModuleClassID with a zero role identifier is a valid + * ModulesClassID wherever a full ModuleClassID is expected. In many cases, only one role + * in a given class is ever used. Using role zero in such cases is an optimization because + * it may make the string representation of the ModuleClassID shorter. + * + *

      Each service of a group, that is, the role it plays in the group, is uniquely identified + * per the group definition. + * This identifier may be used by other modules in the group to designate this one, or by the service + * itself to identify its parameters in a PeerAdvertisement. In addition, by combining its + * PeerGroupID with its own ModuleClassID, a service may create a predictible identifier unique + * on their peer, suitable for registering listeners with the EndpointService or other services + * with similar listener interfaces. + * + *

      The standard PeerGroup implementation of the java reference implementation + * assigns to each service its ModuleClassID as its unique service identifier. Most of the + * times this ModuleClassID is a base classID, but groups that use the same Module Class + * for more than one service (same behaviour but playing a different role in the group, such + * as, for example, a data base engine with a different data base), may define multiple roles + * identified by the same base class identifier but different role identifiers. The standard + * PeerGroup implementation of the java reference implementation has the notion of main + * application: a default application which may be started automatically upon instantiating + * the group. This application implements Module and, therefore, is assigned a ModuleClassID. + * However applications are not expected to play any specific role in the group. As a result, they + * are assigned a role identifier allocated at run-time as need to garantee local unicity. As + * a result main applications cannot expect a predictible ClassID. + * + *

      A ModuleClassID is optionaly described by a published ModuleClassAdvertisement. + * + *

      There may be any number of embodiements of a module class. These are module + * specifications. A module specification represent the network behaviour of a + * module while its class represents its local behaviour. Different groups + * may use a common subset of classes, for example, the basic set defined by the platform + * should always be part of it. Each group may use different and network-incompatible + * specifications for common classes, optimized for various purposes. The local API of a + * given class on a given JXTA implementation will be invariant per the spec being used. + * Therefore, the difference will be transparent to applications which do not depend + * on the possibly different quality of service. + * + *

      A ModuleSpecID embeds a base class identifier, which permits to verify that + * a given Module specification is suitable for its intended use. + * + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.platform.Module + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.protocol.PeerAdvertisement + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see net.jxta.protocol.ModuleClassAdvertisement + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.id.ID + * + */ +public abstract class ModuleClassID extends ID { + + /** + * Creates an ID by parsing the given URI. + * + *

      This convenience factory method works as if by invoking the + * {@link net.jxta.id.IDFactory#fromURI(URI)} method; any + * {@link java.net.URISyntaxException} thrown is caught and wrapped in a + * new {@link IllegalArgumentException} object, which is then thrown. + * + *

      This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link net.jxta.id.IDFactory}, + * which throws {@link java.net.URISyntaxException} directly, should be used + * situations where a ID is being constructed from user input or from some + * other source that may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException If {@code fromURI} is {@code null}. + * @throws IllegalArgumentException If the given URI is not a valid ID. + */ + public static ModuleClassID create(URI fromURI) { + return (ModuleClassID) ID.create(fromURI); + } + + /** + * {@inheritDoc} + */ + public ModuleClassID intern() { + return (ModuleClassID) super.intern(); + } + + /** + * Returns true if this ModuleClassID is of the same base class than the + * given class. + * Note: This method is NOT named "isOfClass" because a ModuleClassID + * may have two UUID; one that denotes a "base" class proper, + * and an optional second one that denotes a "Role", or subclass. + * Compatibility between ClassIDs is based on the "base" portion, hence the + * "isOfSame" naming. This routine can be used for comparison with a base class + * since a base class is just a class which role portion happens to be zero. + * + * @param id Module class id to compare with + * @return boolean true if equals + */ + + public abstract boolean isOfSameBaseClass(ModuleClassID id); + + /** + * Returns true if this ModuleClassID is of the same class than the + * the given ModuleSpecID. + * + * @param id Module spec id to compare with + * @return boolean true if equals + */ + + public abstract boolean isOfSameBaseClass(ModuleSpecID id); + + /** + * Return a ModuleClassID of the same base class but with the role portion + * set to zero. aka "the base class". + * + * @return ModuleClassID the base class. + */ + public abstract ModuleClassID getBaseClass(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/ModuleSpecID.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/ModuleSpecID.java new file mode 100644 index 000000000..bfca65585 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/ModuleSpecID.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +import java.net.URI; +import net.jxta.id.ID; + + +/** + * A ModuleSpecID uniquely identifies a particular network behaviour + * (wire protocol and choregraphy) that may be embodied by a Jxta Module. + * There may be any number of implementations of a given SpecID. All + * such implementations are assumed to be network compatible. + * + *

      + * The Specification that corresponds to a given ModuleSpecID may be published + * in a ModuleSpecAdvertisement. This advertisement is uniquely identified by + * the ModuleSpecID that it describes. + * + *

      + * The various implementations of a given SpecID may be published in + * ModuleImplAdvertisements. These advertisements are identified by the + * ModuleSpecID that they implement and a compatibility statement. + * ModuleImplAdvertisements baring the same SpecID and compatibility statement + * are theorethicaly interchangeable. However they may be subsequently discriminated + * by a Description element. + * + *

      + * A ModuleSpecID embeds a ModuleClassID which uniquely identifies a base Module + * class. A base module class defines a local behaviour and one API per compatible + * JXTA implementation. + * + *

      + * A ModuleSpecID therefore uniquely identifies an abstract module, of which an + * implementation compatible with the local JXTA implementation may be located and + * instantiated. + * + *

      + * In the standard PeerGroup implementation of the java reference implementation + * the various services are specified as a list of ModuleSpecID, for each of which + * the group locates and loads an implementation as part of the group's + * initialization. + * + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.platform.Module + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see net.jxta.id.ID + * @see net.jxta.document.Advertisement + * + */ + +public abstract class ModuleSpecID extends ID { + + /** + * Creates an ID by parsing the given URI. + * + *

      This convenience factory method works as if by invoking the + * {@link net.jxta.id.IDFactory#fromURI(URI)} method; any + * {@link java.net.URISyntaxException} thrown is caught and wrapped in a + * new {@link IllegalArgumentException} object, which is then thrown. + * + *

      This method is provided for use in situations where it is known that + * the given string is a legal ID, for example for ID constants declared + * within in a program, and so it would be considered a programming error + * for the URI not to parse as such. The {@link net.jxta.id.IDFactory}, + * which throws {@link java.net.URISyntaxException} directly, should be used + * situations where a ID is being constructed from user input or from some + * other source that may be prone to errors. + * + * @param fromURI The URI to be parsed into an ID + * @return The new ID + * + * @throws NullPointerException If {@code fromURI} is {@code null}. + * @throws IllegalArgumentException If the given URI is not a valid ID. + */ + public static ModuleSpecID create(URI fromURI) { + return (ModuleSpecID) ID.create(fromURI); + } + + /** + * {@inheritDoc} + */ + public ModuleSpecID intern() { + return (ModuleSpecID) super.intern(); + } + + /** + * Returns true if this ModuleSpecID is of the same base class than the + * given class. + * Note: This method is NOT named "isOfClass" because a ModuleClassID + * may have two portions; one that denotes a class proper, + * and an optional second one that denotes a "Role". For convenience, we refer + * the class stripped of its role portion as "the base class" although this is not + * a totally accurate term. + * A ModuleSpecID, is of a base class but is not related to any kind + * of role. So using "isOfClass" could be misleading. + * Base classes are represented by a class with the role ID set to zero, which + * happens to be a valid class. This routine may be used for comparison with + * such a class, of course. + * + * @param id Module class id to compare with + * @return boolean true if equals + * + */ + + public abstract boolean isOfSameBaseClass(ModuleClassID id); + + /** + * Returns true if this ModuleSpecID is of the same base class than the + * the given ModuleSpecID. + * + * @param id Module spec id to compare with + * @return boolean true if equals + * + */ + + public abstract boolean isOfSameBaseClass(ModuleSpecID id); + + /** + * Return a ModuleClassID of the same base class but with the role portion + * set to zero. aka "the base class". + * + * @return ModuleClassID the base class. + * + */ + + public abstract ModuleClassID getBaseClass(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/NetworkConfigurator.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/NetworkConfigurator.java new file mode 100644 index 000000000..3dc18b5c9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/NetworkConfigurator.java @@ -0,0 +1,1947 @@ +/* + * Copyright (c) 2006-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.membership.pse.PSEUtils; +import net.jxta.impl.membership.pse.PSEUtils.IssuerInfo; +import net.jxta.impl.protocol.HTTPAdv; +import net.jxta.impl.protocol.PSEConfigAdv; +import net.jxta.impl.protocol.PeerGroupConfigAdv; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.protocol.RdvConfigAdv.RendezVousConfiguration; +import net.jxta.impl.protocol.RelayConfigAdv; +import net.jxta.impl.protocol.TCPAdv; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.TransportAdvertisement; + +import javax.security.cert.CertificateException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.List; +import java.util.MissingResourceException; +import java.util.NoSuchElementException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * NetworkConfigurator provides a simple programmatic interface for JXTA configuration. + *

      + * By default, it defines an edge configuration with TCP in auto mode w/port + * range 9701-9799, multicast enabled on group "224.0.1.85", and port 1234, + * HTTP transport with only outgoing enabled. + *

      + * By default a new PeerID is always generated. This can be overridden via + * {@link NetworkConfigurator#setPeerID} method or loading a PlatformConfig via + * {@link NetworkConfigurator#load}. + *

      + * A facility is provided to initialize a configuration by loading from an + * existing configuration. This provides limited platform configuration lifecycle + * management as well as configuration change management. + *

      + * Also by default, this class sets the default platform configurator to + * {@link net.jxta.impl.peergroup.NullConfigurator}. NullConfigurator + * is a no operation configurator intended to prevent any other configurators from + * being invoked, including the AWT ConfigDialog. + *

      + * NetworkConfigurator makes use of classes from the {@code net.jxta.impl.*} + * packages. Applications are very strongly encouraged to avoid importing these + * classes as their interfaces may change without notice in future JXTA releases. + * The NetworkConfigurator API abstracts the configuration implementation details + * and will provide continuity and stability i.e. the NetworkConfigurator API + * won't change and it will automatically accommodate changes to service + * configuration. + *

      + * Configuration example : + *

      + *     NetworkConfigurator config = new NetworkConfigurator();
      + *     if (!config.exists()) {
      + *         // Create a new configuration with a new name, principal, and pass
      + *         config.setName("New Name");
      + *         config.setPrincipal("username");
      + *         config.setPassword("password");
      + *         try {
      + *             //persist it
      + *             config.save();
      + *         } catch (IOException io) {
      + *             // deal with the io error
      + *         }
      + *      } else {
      + *        // Load the pre-existing configuration
      + *        File pc = new File(config.getHome(), "PlatformConfig");
      + *        try {
      + *            config.load(pc.toURI());
      + *            // make changes if so desired
      + *             ..
      + *             ..
      + *            // store the PlatformConfig under the default home
      + *            config.save();
      + *        } catch (CertificateException ce) {
      + *            // In case the root cert is invalid, this creates a new one
      + *            try {
      + *                  //principal
      + *                  config.setPrincipal("principal");
      + *                  //password to encrypt private key with
      + *                  config.setPassword("password");
      + *                  config.save();
      + *              } catch (Exception e) {
      + *                  e.printStackTrace();
      + *              }
      + *        }
      + * 

      + *

      + * + * @since JXTA JSE 2.4 + */ +public class NetworkConfigurator { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(NetworkConfigurator.class.getName()); + + // begin configuration modes + + /** + * Relay off Mode + */ + public final static int RELAY_OFF = 1 << 2; + + /** + * Relay client Mode + */ + public final static int RELAY_CLIENT = 1 << 3; + + /** + * Relay Server Mode + */ + public final static int RELAY_SERVER = 1 << 4; + + /** + * Proxy Server Mode + */ + public final static int PROXY_SERVER = 1 << 5; + + /** + * TCP transport client Mode + */ + public final static int TCP_CLIENT = 1 << 6; + + /** + * TCP transport Server Mode + */ + public final static int TCP_SERVER = 1 << 7; + + /** + * HTTP transport client Mode + */ + public final static int HTTP_CLIENT = 1 << 8; + + /** + * HTTP transport server Mode + */ + public final static int HTTP_SERVER = 1 << 9; + + /** + * IP multicast transport Mode + */ + public final static int IP_MULTICAST = 1 << 10; + + /** + * RendezVousService Mode + */ + public final static int RDV_SERVER = 1 << 11; + + /** + * RendezVousService Client + */ + public final static int RDV_CLIENT = 1 << 12; + + /** + * RendezVousService Ad-Hoc mode + */ + public final static int RDV_AD_HOC = 1 << 13; + + /** + * Default AD-HOC configuration + */ + public final static int ADHOC_NODE = TCP_CLIENT | TCP_SERVER | IP_MULTICAST | RDV_AD_HOC | RELAY_OFF; + + /** + * Default Edge configuration + */ + public final static int EDGE_NODE = TCP_CLIENT | TCP_SERVER | HTTP_CLIENT | IP_MULTICAST | RDV_CLIENT | RELAY_CLIENT; + + /** + * Default Rendezvous configuration + */ + public final static int RDV_NODE = RDV_SERVER | TCP_CLIENT | TCP_SERVER | HTTP_SERVER; + + /** + * Default Relay configuration + */ + public final static int RELAY_NODE = RELAY_SERVER | TCP_CLIENT | TCP_SERVER | HTTP_SERVER; + + /** + * Default Proxy configuration + */ + public final static int PROXY_NODE = PROXY_SERVER | RELAY_NODE; + + /** + * Default Rendezvous/Relay/Proxy configuration + */ + public final static int RDV_RELAY_PROXY_NODE = RDV_NODE | PROXY_NODE; + + + // end configuration modes + + /** + * Default mode + */ + protected transient int mode = EDGE_NODE; + + /** + * Default PlatformConfig Peer Description + */ + protected transient String description = "Platform Config Advertisement created by : " + NetworkConfigurator.class.getName(); + + /** + * The location which will serve as the parent for all stored items used + * by JXTA. + */ + private transient URI storeHome = null; + + /** + * Default peer name + */ + protected transient String name = "unknown"; + + /** + * Password value used to generate root Certificate and to protect the + * Certificate's PrivateKey. + */ + protected transient String password = null; + + /** + * Default PeerID + */ + protected transient PeerID peerid = IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID); + + /** + * Principal value used to generate root certificate + */ + protected transient String principal = null; + + /** + * Public Certificate chain + */ + protected transient X509Certificate[] cert = null; + + /** + * Subject private key + */ + protected transient PrivateKey subjectPkey = null; + + /** + * Freestanding keystore location + */ + protected transient URI keyStoreLocation = null; + + /** + * Proxy Service Document + */ + protected transient XMLElement proxyConfig; + + /** + * Personal Security Environment Config Advertisement + * + * @see net.jxta.impl.membership.pse.PSEConfig + */ + protected transient PSEConfigAdv pseConf; + + /** + * Rendezvous Config Advertisement + */ + protected transient RdvConfigAdv rdvConfig; + + /** + * Default Rendezvous Seeding URI + */ + protected URI rdvSeedingURI = null; + + /** + * Relay Config Advertisement + */ + protected transient RelayConfigAdv relayConfig; + + /** + * Default Relay Seeding URI + */ + protected transient URI relaySeedingURI = null; + + /** + * TCP Config Advertisement + */ + protected transient TCPAdv tcpConfig; + + /** + * Default TCP transport state + */ + protected transient boolean tcpEnabled = true; + + /** + * HTTP Config Advertisement + */ + protected transient HTTPAdv httpConfig; + + /** + * Default HTTP transport state + */ + protected transient boolean httpEnabled = true; + + /** + * Infrastructure Peer Group Configuration + */ + protected transient PeerGroupConfigAdv infraPeerGroupConfig; + + /** + * Creates NetworkConfigurator instance with default AD-HOC configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with default AD-HOC configuration + */ + public static NetworkConfigurator newAdHocConfiguration(URI storeHome) { + return new NetworkConfigurator(ADHOC_NODE, storeHome); + } + + /** + * Creates NetworkConfigurator instance with default Edge configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with default AD-HOC configuration + */ + public static NetworkConfigurator newEdgeConfiguration(URI storeHome) { + return new NetworkConfigurator(EDGE_NODE, storeHome); + } + + /** + * Creates NetworkConfigurator instance with default Rendezvous configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with default Rendezvous configuration + */ + public static NetworkConfigurator newRdvConfiguration(URI storeHome) { + return new NetworkConfigurator(RDV_NODE, storeHome); + } + + /** + * Creates NetworkConfigurator instance with default Relay configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with default Relay configuration + */ + public static NetworkConfigurator newRelayConfiguration(URI storeHome) { + return new NetworkConfigurator(RELAY_NODE, storeHome); + } + + /** + * Creates NetworkConfigurator instance with default Rendezvous configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with default Rendezvous configuration + */ + public static NetworkConfigurator newRdvRelayConfiguration(URI storeHome) { + return new NetworkConfigurator(RDV_NODE | RELAY_SERVER, storeHome); + } + + /** + * Creates NetworkConfigurator instance with default Proxy configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with defaultProxy configuration + */ + public static NetworkConfigurator newProxyConfiguration(URI storeHome) { + return new NetworkConfigurator(PROXY_NODE, storeHome); + } + + /** + * Creates NetworkConfigurator instance with default Rendezvous, Relay, Proxy configuration + * + * @param storeHome the URI to persistent store + * @return NetworkConfigurator instance with default Rendezvous, Relay, Proxy configuration + */ + public static NetworkConfigurator newRdvRelayProxyConfiguration(URI storeHome) { + return new NetworkConfigurator(RDV_RELAY_PROXY_NODE, storeHome); + } + + /** + * Creates the default NetworkConfigurator. The configuration is stored with a default configuration mode of EDGE_NODE + */ + public NetworkConfigurator() { + this(EDGE_NODE, new File(".jxta").toURI()); + } + + /** + * Creates a NetworkConfigurator with the default configuration of the + * specified mode.

      Valid modes include ADHOC_NODE, EDGE_NODE, RDV_NODE + * PROXY_NODE, RELAY_NODE, RDV_RELAY_PROXY_NODE, or any combination of + * specific configuration.

      e.g. RDV_NODE | HTTP_CLIENT + * + * @param mode the new configuration mode + * @param storeHome the URI to persistent store + * @see #setMode + */ + public NetworkConfigurator(int mode, URI storeHome) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating a default configuration"); + } + + setStoreHome(storeHome); + + httpConfig = createHttpAdv(); + rdvConfig = createRdvConfigAdv(); + relayConfig = createRelayConfigAdv(); + proxyConfig = createProxyAdv(); + tcpConfig = createTcpAdv(); + infraPeerGroupConfig = createInfraConfigAdv(); + + setMode(mode); + } + + /** + * Sets PlaformConfig Peer Description element + * + * @param description the peer description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Set the current directory for configuration and cache persistent store + *

      (default is $CWD/.jxta) + *

      + *

      Simple example :
      + *
      +     *  
      +     *   //Create an application home
      +     *   File appHome = new File(System.getProperty("JXTA_HOME", ".cache"));
      +     *   //Create an instance home under the application home
      +     *   File instanceHome = new File(appHome, instanceName);
      +     *   jxtaConfig.setHome(instanceHome);
      +     *   
      +     * 
      + * + * @param home the new home value + * @see #getHome + */ + public void setHome(File home) { + this.storeHome = home.toURI(); + } + + /** + * Returns the current directory for configuration and cache persistent + * store. This is the same location as returned by {@link #getStoreHome()} + * which is more general than this method. + * + * @return Returns the current home directory + * @see #setHome + */ + public File getHome() { + if( "file".equalsIgnoreCase(storeHome.getScheme())) { + return new File(storeHome); + } else { + throw new UnsupportedOperationException("Home location is not a file:// URI : " + storeHome ); + } + } + + /** + * Returns the location which will serve as the parent for all stored items + * used by JXTA. + * + * @return The location which will serve as the parent for all stored + * items used by JXTA. + * @see net.jxta.peergroup.PeerGroup#getStoreHome() + */ + public URI getStoreHome() { + return storeHome; + } + + + /** + * Sets the location which will serve as the parent for all stored items + * used by JXTA. + * + * @see net.jxta.peergroup.PeerGroup#getStoreHome() + */ + public void setStoreHome(URI newHome) { + // Fail if the URI is not absolute. + if (!newHome.isAbsolute()) { + throw new IllegalArgumentException("Only absolute URIs accepted for store home location."); + } + + // Fail if the URI is Opaque. + if (newHome.isOpaque()) { + throw new IllegalArgumentException("Only hierarchical URIs accepted for store home location."); + } + + // FIXME this should be removed when 1488 is committed + if (!"file".equalsIgnoreCase(newHome.getScheme())) { + throw new IllegalArgumentException("Only file based URI currently supported"); + } + + // Adds a terminating / + if (!newHome.toString().endsWith("/")) { + newHome = URI.create(newHome.toString() + "/"); + } + + storeHome = newHome; + } + + /** + * Toggles HTTP transport state + * + * @param enabled if true, enables HTTP transport + */ + public void setHttpEnabled(boolean enabled) { + this.httpEnabled = enabled; + if (!httpEnabled) { + httpConfig.setClientEnabled(false); + httpConfig.setServerEnabled(false); + } + } + + /** + * Toggles the HTTP transport server (incoming) mode + * + * @param incoming toggles HTTP transport server mode + */ + public void setHttpIncoming(boolean incoming) { + httpConfig.setServerEnabled(incoming); + } + + /** + * Toggles the HTTP transport client (outgoing) mode + * + * @param outgoing toggles HTTP transport client mode + */ + public void setHttpOutgoing(boolean outgoing) { + httpConfig.setClientEnabled(outgoing); + } + + /** + * Sets the HTTP listening port (default 9901) + * + * @param port the new HTTP port value + */ + public void setHttpPort(int port) { + httpConfig.setPort(port); + } + + /** + * Sets the HTTP interface Address to bind the HTTP transport to + *

      e.g. "192.168.1.1" + * + * @param address the new address value + */ + public void setHttpInterfaceAddress(String address) { + httpConfig.setInterfaceAddress(address); + } + + /** + * Sets the HTTP JXTA Public Address + * e.g. "192.168.1.1:9700" + * + * @param address the HTTP transport public address + * @param exclusive determines whether an address is advertised exclusively + */ + public void setHttpPublicAddress(String address, boolean exclusive) { + httpConfig.setServer(address); + httpConfig.setPublicAddressOnly(exclusive); + } + + /** + * Sets the ID which will be used for new net peer group instances. + *

      + *

      By Setting an alternate infrastructure PeerGroup ID (aka NetPeerGroup), + * it prevents heterogeneous infrastructure PeerGroups from intersecting. + *

      This is highly recommended practice for application deployment + * + * @param id the new infrastructure PeerGroupID as a string + * @see net.jxta.peergroup.PeerGroupFactory#setNetPGID + */ + public void setInfrastructureID(ID id) { + if (id == null || id.equals(ID.nullID)) { + throw new IllegalArgumentException("PeerGroupID can not be null"); + } + infraPeerGroupConfig.setPeerGroupID(id); + } + + /** + * Sets the ID which will be used for new net peer group instances. + *

      + *

      By Setting an alternate infrastructure PeerGroup ID (aka NetPeerGroup), + * it prevents heterogeneous infrastructure PeerGroups from intersecting. + *

      This is highly recommended practice for application deployment + * + * @param idStr the new infrastructure PeerGroupID as a string + * @see net.jxta.peergroup.PeerGroupFactory#setNetPGID + */ + public void setInfrastructureID(String idStr) { + if (idStr == null || idStr.length() == 0) { + throw new IllegalArgumentException("PeerGroupID string can not be empty or null"); + } + + PeerGroupID pgid = (PeerGroupID) ID.create(URI.create(idStr)); + setInfrastructureID(pgid); + } + + /** + * Gets the ID which will be used for new net peer group instances. + *

      + * + * @return the infrastructure PeerGroupID as a string + */ + public String getInfrastructureIDStr() { + return infraPeerGroupConfig.getPeerGroupID().toString(); + } + + /** + * Sets the infrastructure PeerGroup name meta-data + * + * @param name the Infrastructure PeerGroup name + * @see net.jxta.peergroup.PeerGroupFactory#setNetPGName + */ + public void setInfrastructureName(String name) { + infraPeerGroupConfig.setName(name); + } + + /** + * Gets the infrastructure PeerGroup name meta-data + * + * @return the Infrastructure PeerGroup name + */ + public String getInfrastructureName() { + return infraPeerGroupConfig.getName(); + } + + /** + * Sets the infrastructure PeerGroup description meta-data + * + * @param description the infrastructure PeerGroup description + * @see net.jxta.peergroup.PeerGroupFactory#setNetPGDesc + */ + public void setInfrastructureDescriptionStr(String description) { + infraPeerGroupConfig.setDescription(description); + } + + /** + * Returns the infrastructure PeerGroup description meta-data + * + * @return the infrastructure PeerGroup description meta-data + */ + public String getInfrastructureDescriptionStr() { + return infraPeerGroupConfig.getDescription(); + } + + /** + * Sets the infrastructure PeerGroup description meta-data + * + * @param description the infrastructure PeerGroup description + * @see net.jxta.peergroup.PeerGroupFactory#setNetPGDesc + */ + public void setInfrastructureDesc(XMLElement description) { + infraPeerGroupConfig.setDesc(description); + } + + /** + * Sets the current node configuration mode. + *

      The default mode is EDGE, unless modified at construction time. + * A node configuration mode defined a preset configuration + * parameters based on a operating mode. i.e. an EDGE mode, enable + * client/server side tcp, multicast, client side http, RelayService + * client mode. + *

      Valid modes include EDGE, RDV_SERVER, + * RELAY_OFF, RELAY_CLIENT, RELAY_SERVER, PROXY_SERVER, or any combination + * of which.

      e.g. RDV_SERVER + RELAY_SERVER + * + * @param mode the new configuration mode + * @see #getMode + */ + public void setMode(int mode) { + this.mode = mode; + if ((mode & PROXY_SERVER) == PROXY_SERVER && ((mode & RELAY_SERVER) != RELAY_SERVER)) { + mode = mode | RELAY_SERVER; + } + + // RELAY config + relayConfig.setClientEnabled((mode & RELAY_CLIENT) == RELAY_CLIENT); + relayConfig.setServerEnabled((mode & RELAY_SERVER) == RELAY_SERVER); + + // RDV_SERVER + if ((mode & RDV_SERVER) == RDV_SERVER) { + rdvConfig.setConfiguration(RendezVousConfiguration.RENDEZVOUS); + } else if ((mode & RDV_CLIENT) == RDV_CLIENT) { + rdvConfig.setConfiguration(RendezVousConfiguration.EDGE); + } else if ((mode & RDV_AD_HOC) == RDV_AD_HOC) { + rdvConfig.setConfiguration(RendezVousConfiguration.AD_HOC); + } + + // TCP + tcpConfig.setClientEnabled((mode & TCP_CLIENT) == TCP_CLIENT); + tcpConfig.setServerEnabled((mode & TCP_SERVER) == TCP_SERVER); + + // HTTP + httpConfig.setClientEnabled((mode & HTTP_CLIENT) == HTTP_CLIENT); + httpConfig.setServerEnabled((mode & HTTP_SERVER) == HTTP_SERVER); + + // Multicast + tcpConfig.setMulticastState((mode & IP_MULTICAST) == IP_MULTICAST); + + // EDGE + if (mode == EDGE_NODE) { + rdvConfig.setConfiguration(RendezVousConfiguration.EDGE); + } + } + + /** + * Returns the current configuration mode + *

      The default mode is EDGE, unless modified at construction time or through + * Method {@link NetworkConfigurator#setMode}. A node configuration mode defined a preset configuration + * parameters based on a operating mode. i.e. an EDGE mode, enable + * client/server side tcp, multicast, client side http, RelayService + * client mode. + * + * @return mode the current mode value + * @see #setMode + */ + public int getMode() { + return mode; + } + + /** + * Sets the IP group multicast packet size + * + * @param size the new multicast packet + */ + public void setMulticastSize(int size) { + tcpConfig.setMulticastSize(size); + } + + /** + * Gets the IP group multicast packet size + * + * @return the multicast packet + */ + public int getMulticastSize() { + return tcpConfig.getMulticastSize(); + } + + /** + * Sets the IP group multicast address (default 224.0.1.85) + * + * @param mcastAddress the new multicast group address + * @see #setMulticastPort + */ + public void setMulticastAddress(String mcastAddress) { + tcpConfig.setMulticastAddr(mcastAddress); + } + + /** + * Sets the IP group multicast port (default 1234) + * + * @param port the new IP group multicast port + * @see #setMulticastAddress + */ + public void setMulticastPort(int port) { + tcpConfig.setMulticastPort(port); + } + + /** + * Sets the node name + * + * @param name node name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the node name + * + * @return node name + */ + public String getName() { + return this.name; + } + + /** + * Sets the Principal for the peer root certificate + * + * @param principal the new principal value + * @see #setPassword + * @see #getPrincipal + * @see #setPrincipal + */ + public void setPrincipal(String principal) { + this.principal = principal; + } + + /** + * Gets the Principal for the peer root certificate + * + * @return principal if a principal is set, null otherwise + * @see #setPassword + * @see #getPrincipal + * @see #setPrincipal + */ + public String getPrincipal() { + return principal; + } + + /** + * Sets the public Certificate for this configuration. + * + * @param cert the new cert value + */ + public void setCertificate(X509Certificate cert) { + this.cert = new X509Certificate[] { cert }; + } + + /** + * Returns the public Certificate for this configuration. + * + * @return X509Certificate + */ + public X509Certificate getCertificate() { + return (cert == null || cert.length == 0 ? null : cert[0]); + } + + /** + * Sets the public Certificate chain for this configuration. + * + * @param certificateChain the new Certificate chain value + */ + public void setCertificateChain(X509Certificate[] certificateChain) { + this.cert = certificateChain; + } + + /** + * Gets the public Certificate chain for this configuration. + * + * @return X509Certificate chain + */ + public X509Certificate[] getCertificateChain() { + return cert; + } + + /** + * Sets the Subject private key + * + * @param subjectPkey the subject private key + */ + public void setPrivateKey(PrivateKey subjectPkey) { + this.subjectPkey = subjectPkey; + } + + /** + * Gets the Subject private key + * + * @return the subject private key + */ + public PrivateKey getPrivateKey() { + return this.subjectPkey; + } + + /** + * Sets freestanding keystore location + * + * @param keyStoreLocation the absolute location of the freestanding keystore + */ + public void setKeyStoreLocation(URI keyStoreLocation) { + this.keyStoreLocation = keyStoreLocation; + } + + /** + * Gets the freestanding keystore location + * + * @return the location of the freestanding keystore + */ + public URI getKeyStoreLocation() { + return keyStoreLocation; + } + + /** + * Sets the password used to sign the private key of the root certificate + * + * @param password the new password value + * @see #setPassword + * @see #getPrincipal + * @see #setPrincipal + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Gets the password used to sign the private key of the root certificate + * + * @return password if a password is set, null otherwise + * @see #setPassword + * @see #getPrincipal + * @see #setPrincipal + */ + public String getPassword() { + return password; + } + + /** + * Sets the PeerID (by default, a new PeerID is generated). + *

      Note: Persist the PeerID generated, or use load() + * to avoid overridding a node's PeerID between restarts. + * + * @param peerid the new net.jxta.peer.PeerID + */ + public void setPeerID(PeerID peerid) { + this.peerid = peerid; + } + + /** + * Gets the PeerID + * + * @return peerid the net.jxta.peer.PeerID value + */ + public PeerID getPeerID() { + return this.peerid; + } + + /** + * Sets Rendezvous Seeding URI + *

      e.g. http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3 + * + * @param seedURI Rendezvous service seeding URI + */ + public void addRdvSeedingURI(URI seedURI) { + rdvConfig.addSeedingURI(seedURI); + } + + /** + * Sets Rendezvous Access Control URI + *

      e.g. http://rdv.jxtahosts.net/cgi-bin/rendezvousACL.cgi?3 + * + * @param aclURI Rendezvous Access Control URI + */ + public void setRdvACLURI(URI aclURI) { + rdvConfig.setAclUri(aclURI); + } + + /** + * Gets Rendezvous Access Control URI if set + *

      e.g. http://rdv.jxtahosts.net/cgi-bin/rendezvousACL.cgi?3 + * + * @return aclURI Rendezvous Access Control URI + */ + public URI getRdvACLURI() { + return rdvConfig.getAclUri(); + } + + /** + * Sets Relay Access Control URI + *

      e.g. http://rdv.jxtahosts.net/cgi-bin/relayACL.cgi?3 + * + * @param aclURI Relay Access Control URI + */ + public void setRelayACLURI(URI aclURI) { + relayConfig.setAclUri(aclURI); + } + + /** + * Gets Relay Access Control URI if set + *

      e.g. http://rdv.jxtahosts.net/cgi-bin/relayACL.cgi?3 + * + * @return aclURI Relay Access Control URI + */ + public URI getRelayACLURI() { + return relayConfig.getAclUri(); + } + + /** + * Sets the RelayService maximum number of simultaneous relay clients + * + * @param relayMaxClients the new relayMaxClients value + */ + public void setRelayMaxClients(int relayMaxClients) { + if ((relayMaxClients != -1) && (relayMaxClients <= 0)) { + throw new IllegalArgumentException("Relay Max Clients : " + relayMaxClients + " must be > 0"); + } + relayConfig.setMaxClients(relayMaxClients); + } + + /** + * Sets the RelayService Seeding URI + *

      e.g. http://rdv.jxtahosts.net/cgi-bin/relays.cgi?3 + *

      A seeding URI (when read) is expected to provide a list of + * physical endpoint addresse(s) to relay peers + * + * @param seedURI RelayService seeding URI + */ + public void addRelaySeedingURI(URI seedURI) { + relayConfig.addSeedingURI(seedURI); + } + + /** + * Sets the RendezVousService maximum number of simultaneous rendezvous clients + * + * @param rdvMaxClients the new rendezvousMaxClients value + */ + public void setRendezvousMaxClients(int rdvMaxClients) { + if ((rdvMaxClients != -1) && (rdvMaxClients <= 0)) { + throw new IllegalArgumentException("Rendezvous Max Clients : " + rdvMaxClients + " must be > 0"); + } + rdvConfig.setMaxClients(rdvMaxClients); + } + + /** + * Toggles TCP transport state + * + * @param enabled if true, enables TCP transport + */ + public void setTcpEnabled(boolean enabled) { + this.tcpEnabled = enabled; + if (!tcpEnabled) { + tcpConfig.setClientEnabled(false); + tcpConfig.setServerEnabled(false); + } + } + + /** + * Sets the TCP transport listening port (default 9701) + * + * @param port the new tcpPort value + */ + public void setTcpPort(int port) { + tcpConfig.setPort(port); + } + + /** + * Sets the lowest port on which the TCP Transport will listen if configured + * to do so. Valid values are -1, 0 and + * 1-65535. The -1 value is used to signify that + * the port range feature should be disabled. The 0 specifies + * that the Socket API dynamic port allocation should be used. For values + * 1-65535 the value must be equal to or less than the value + * used for end port. + * + * @param start the lowest port on which to listen. + */ + public void setTcpStartPort(int start) { + tcpConfig.setStartPort(start); + } + + /** + * Returns the highest port on which the TCP Transport will listen if + * configured to do so. Valid values are -1, 0 and + * 1-65535. The -1 value is used to signify that + * the port range feature should be disabled. The 0 specifies + * that the Socket API dynamic port allocation should be used. For values + * 1-65535 the value must be equal to or greater than the value + * used for start port. + * + * @param end the new TCP end port + */ + public void setTcpEndPort(int end) { + tcpConfig.setEndPort(end); + } + + /** + * Toggles TCP transport server (incoming) mode (default is on) + * + * @param incoming the new TCP server mode + */ + public void setTcpIncoming(boolean incoming) { + tcpConfig.setServerEnabled(incoming); + } + + /** + * Toggles TCP transport client (outgoing) mode (default is true) + * + * @param outgoing the new tcpOutgoing value + */ + public void setTcpOutgoing(boolean outgoing) { + tcpConfig.setClientEnabled(outgoing); + } + + /** + * Sets the TCP transport interface address + *

      e.g. "192.168.1.1" + * + * @param address the TCP transport interface address + */ + public void setTcpInterfaceAddress(String address) { + tcpConfig.setInterfaceAddress(address); + } + + /** + * Sets the node public address + *

      e.g. "192.168.1.1:9701" + *

      This address is the physical address defined in a node's + * AccessPointAdvertisement. This often required for NAT'd/FW nodes + * + * @param address the TCP transport public address + * @param exclusive public address advertised exclusively + */ + public void setTcpPublicAddress(String address, boolean exclusive) { + tcpConfig.setServer(address); + tcpConfig.setPublicAddressOnly(exclusive); + } + + /** + * Toggles whether to use IP group multicast (default is true) + * + * @param multicastOn the new useMulticast value + */ + public void setUseMulticast(boolean multicastOn) { + tcpConfig.setMulticastState(multicastOn); + } + + /** + * Determines whether to restrict RelayService leases to those defined in + * the seed list + * + * @param useOnlyRelaySeeds restrict RelayService lease to seed list + */ + public void setUseOnlyRelaySeeds(boolean useOnlyRelaySeeds) { + relayConfig.setUseOnlySeeds(useOnlyRelaySeeds); + } + + /** + * Determines whether to restrict RendezvousService leases to those defined in + * the seed list + * + * @param useOnlyRendezvouSeeds restrict RendezvousService lease to seed list + */ + public void setUseOnlyRendezvousSeeds(boolean useOnlyRendezvouSeeds) { + rdvConfig.setUseOnlySeeds(useOnlyRendezvouSeeds); + } + + /** + * Adds RelayService peer seed address + *

      A RelayService seed is defined as a physical endpoint address + *

      e.g. http://192.168.1.1:9700, or tcp://192.168.1.1:9701 + * + * @param seedURI the relay seed URI + */ + public void addSeedRelay(URI seedURI) { + relayConfig.addSeedRelay(seedURI.toString()); + } + + /** + * Adds Rendezvous peer seed, physical endpoint address + *

      A RendezVousService seed is defined as a physical endpoint address + *

      e.g. http://192.168.1.1:9700, or tcp://192.168.1.1:9701 + * + * @param seedURI the rendezvous seed URI + */ + public void addSeedRendezvous(URI seedURI) { + rdvConfig.addSeedRendezvous(seedURI); + } + + /** + * Returns true if a PlatformConfig file exist under store home + * + * @return true if a PlatformConfig file exist under store home + */ + public boolean exists() { + + URI platformConfig = storeHome.resolve("PlatformConfig"); + try { + return null != read(platformConfig); + } catch( IOException failed ) { + return false; + } + } + + /** + * Sets the PeerID for this Configuration + * + * @param peerIdStr the new PeerID as a string + */ + public void setPeerId(String peerIdStr) { + this.peerid = (PeerID) ID.create(URI.create(peerIdStr)); + } + + /** + * Sets the new RendezvousService seeding URI as a string. + *

      A seeding URI (when read) is expected to provide a list of + * physical endpoint address to rendezvous peers + * + * @param seedURIStr the new rendezvous seed URI as a string + */ + public void addRdvSeedingURI(String seedURIStr) { + rdvConfig.addSeedingURI(URI.create(seedURIStr)); + } + + /** + * Sets the new RelayService seeding URI as a string. + *

      A seeding URI (when read) is expected to provide a list of + * physical endpoint address to relay peers + * + * @param seedURIStr the new RelayService seed URI as a string + */ + public void addRelaySeedingURI(String seedURIStr) { + relayConfig.addSeedingURI(URI.create(seedURIStr)); + } + + /** + * Sets the List relaySeeds represented as Strings + *

      A RelayService seed is defined as a physical endpoint address + *

      e.g. http://192.168.1.1:9700, or tcp://192.168.1.1:9701 + * + * @param seeds the Set RelayService seed URIs as a string + */ + public void setRelaySeedURIs(List seeds) { + relayConfig.clearSeedRelays(); + for (String seedStr : seeds) { + relayConfig.addSeedRelay(new EndpointAddress(seedStr)); + } + } + + /** + * Sets the relaySeeds represented as Strings + *

      A seeding URI (when read) is expected to provide a list of + * physical endpoint address to relay peers + * + * @param seedURIs the List relaySeeds represented as Strings + */ + public void setRelaySeedingURIs(Set seedURIs) { + relayConfig.clearSeedingURIs(); + for (String seedStr : seedURIs) { + relayConfig.addSeedingURI(URI.create(seedStr)); + } + } + + /** + * Clears the List of RelayService seeds + */ + public void clearRelaySeeds() { + relayConfig.clearSeedRelays(); + } + + /** + * Clears the List of RelayService seeding URIs + */ + public void clearRelaySeedingURIs() { + relayConfig.clearSeedingURIs(); + } + + /** + * Sets the List of RendezVousService seeds represented as Strings + *

      A RendezvousService seed is defined as a physical endpoint address + *

      e.g. http://192.168.1.1:9700, or tcp://192.168.1.1:9701 + * + * @param seeds the Set of rendezvousSeeds represented as Strings + */ + public void setRendezvousSeeds(Set seeds) { + rdvConfig.clearSeedRendezvous(); + for (String seedStr : seeds) { + rdvConfig.addSeedRendezvous(URI.create(seedStr)); + } + } + + /** + * Sets the List of RendezVousService seeding URIs represented as Strings. + * A seeding URI (when read) is expected to provide a list of + * physical endpoint address to rendezvous peers. + * + * @deprecated The name of this method is inconsistent with it's function! + * It sets the seeding URIs and not the seed URIs. Use + * {@link #setRendezvousSeedingURIs()} instead. + * + * @param seedURIs the List rendezvousSeeds represented as Strings + */ + @Deprecated + public void setRendezvousSeedURIs(List seedingURIs) { + setRendezvousSeedingURIs(seedingURIs); + } + + /** + * Sets the List of RendezVousService seeding URIs represented as Strings. + * A seeding URI (when read) is expected to provide a list of + * physical endpoint address to rendezvous peers. + * + * @param seedURIs the List rendezvousSeeds represented as Strings. + */ + public void setRendezvousSeedingURIs(List seedingURIs) { + rdvConfig.clearSeedingURIs(); + for (String seedStr : seedingURIs) { + rdvConfig.addSeedingURI(URI.create(seedStr)); + } + } + + /** + * Clears the list of RendezVousService seeds + */ + public void clearRendezvousSeeds() { + rdvConfig.clearSeedRendezvous(); + } + + /** + * Clears the list of RendezVousService seeding URIs + * + * @deprecated The name of this method is inconsistent with it's function! + * It clears the seeding URIs and not the seed URIs. Use + * {@link #clearRendezvousSeedingURIs()} instead. + * + */ + @Deprecated + public void clearRendezvousSeedURIs() { + rdvConfig.clearSeedingURIs(); + } + + /** + * Clears the list of RendezVousService seeding URIs + */ + public void clearRendezvousSeedingURIs() { + rdvConfig.clearSeedingURIs(); + } + + /** + * Load a configuration from the specified store home uri + *

      + * e.g. file:/export/dist/EdgeConfig.xml, e.g. http://configserver.net/configservice?Edge + * + * @return The loaded configuration. + * @throws IOException if an i/o error occurs + * @throws CertificateException if the MembershipService is invalid + */ + public ConfigParams load() throws IOException, CertificateException { + return load(storeHome.resolve("PlatformConfig")); + } + + /** + * Loads a configuration from a specified uri + *

      + * e.g. file:/export/dist/EdgeConfig.xml, e.g. http://configserver.net/configservice?Edge + * + * @param uri the URI to PlatformConfig + * @return The loaded configuration. + * @throws IOException if an i/o error occurs + * @throws CertificateException if the MemebershipService is invalid + */ + public ConfigParams load(URI uri) throws IOException, CertificateException { + if (uri == null) { + throw new IllegalArgumentException("URI can not be null"); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loading configuration : " + uri); + } + + PlatformConfig platformConfig = read(uri); + + name = platformConfig.getName(); + peerid = platformConfig.getPeerID(); + description = platformConfig.getDescription(); + + // TCP + XMLElement param = (XMLElement) platformConfig.getServiceParam(PeerGroup.tcpProtoClassID); + tcpEnabled = platformConfig.isSvcEnabled(PeerGroup.tcpProtoClassID); + Enumeration tcpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv from either TransportAdv or tcpConfig + if (tcpChilds.hasMoreElements()) { + param = (XMLElement) tcpChilds.nextElement(); + } else { + throw new IllegalStateException("Missing TCP Advertisment"); + } + tcpConfig = (TCPAdv) AdvertisementFactory.newAdvertisement(param); + + // HTTP + try { + param = (XMLElement) platformConfig.getServiceParam(PeerGroup.httpProtoClassID); + httpEnabled = platformConfig.isSvcEnabled(PeerGroup.httpProtoClassID); + + Enumeration httpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv from either TransportAdv + if (httpChilds.hasMoreElements()) { + param = (XMLElement) httpChilds.nextElement(); + } else { + throw new IllegalStateException("Missing HTTP Advertisment"); + } + // Read-in the adv as it is now. + httpConfig = (HTTPAdv) AdvertisementFactory.newAdvertisement(param); + } catch (Exception failure) { + IOException ioe = new IOException("error processing the HTTP config advertisement"); + ioe.initCause(failure); + throw ioe; + } + + // ProxyService + try { + param = (XMLElement) platformConfig.getServiceParam(PeerGroup.proxyClassID); + if (param != null && !platformConfig.isSvcEnabled(PeerGroup.proxyClassID)) { + mode = mode | PROXY_SERVER; + } + } catch (Exception failure) { + IOException ioe = new IOException("error processing the pse config advertisement"); + ioe.initCause(failure); + throw ioe; + } + + // Rendezvous + try { + param = (XMLElement) platformConfig.getServiceParam(PeerGroup.rendezvousClassID); + // backwards compatibility + param.addAttribute("type", RdvConfigAdv.getAdvertisementType()); + rdvConfig = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(param); + if (rdvConfig.getConfiguration() == RendezVousConfiguration.AD_HOC) { + mode = mode | RDV_AD_HOC; + } else if (rdvConfig.getConfiguration() == RendezVousConfiguration.EDGE) { + mode = mode | RDV_CLIENT; + } else if (rdvConfig.getConfiguration() == RendezVousConfiguration.RENDEZVOUS) { + mode = mode | RDV_SERVER; + } + } catch (Exception failure) { + IOException ioe = new IOException("error processing the rendezvous config advertisement"); + ioe.initCause(failure); + throw ioe; + } + + // Relay + try { + param = (XMLElement) platformConfig.getServiceParam(PeerGroup.relayProtoClassID); + if (param != null && !platformConfig.isSvcEnabled(PeerGroup.relayProtoClassID)) { + mode = mode | RELAY_OFF; + } + // backwards compatibility + param.addAttribute("type", RelayConfigAdv.getAdvertisementType()); + relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(param); + } catch (Exception failure) { + IOException ioe = new IOException("error processing the relay config advertisement"); + ioe.initCause(failure); + throw ioe; + } + + // PSE + param = (XMLElement) platformConfig.getServiceParam(PeerGroup.membershipClassID); + if (param != null) { + + Advertisement adv = null; + try { + adv = AdvertisementFactory.newAdvertisement(param); + } catch (NoSuchElementException notAnAdv) { + CertificateException cnfe = new CertificateException("No membership advertisement found"); + cnfe.initCause(notAnAdv); + } catch (IllegalArgumentException invalidAdv) { + CertificateException cnfe = new CertificateException("Invalid membership advertisement"); + cnfe.initCause(invalidAdv); + } + + if (adv instanceof PSEConfigAdv) { + pseConf = (PSEConfigAdv) adv; + cert = pseConf.getCertificateChain(); + } else { + throw new CertificateException("Error processing the Membership config advertisement. Unexpected membership advertisement " + + adv.getAdvertisementType()); + } + } + + // Infra Group + infraPeerGroupConfig = (PeerGroupConfigAdv) platformConfig.getSvcConfigAdvertisement(PeerGroup.peerGroupClassID); + if (null == infraPeerGroupConfig) { + infraPeerGroupConfig = createInfraConfigAdv(); + try { + URI configPropsURI = storeHome.resolve("config.properties"); + InputStream configPropsIS = configPropsURI.toURL().openStream(); + ResourceBundle rsrcs = new PropertyResourceBundle(configPropsIS); + configPropsIS.close(); + + NetGroupTunables tunables = new NetGroupTunables(rsrcs, new NetGroupTunables()); + + infraPeerGroupConfig.setPeerGroupID(tunables.id); + infraPeerGroupConfig.setName(tunables.name); + infraPeerGroupConfig.setDesc(tunables.desc); + } catch (IOException ignored) { + //ignored + } catch (MissingResourceException ignored) { + //ignored + } + } + return platformConfig; + } + + /** + * Persists a PlatformConfig advertisement under getStoreHome()+"/PlaformConfig" + *

      + * Home may be overridden by a call to setHome() + * + * @see #load + * @throws IOException If there is a failure saving the PlatformConfig. + */ + public void save() throws IOException { + httpEnabled = (httpConfig.isClientEnabled() || httpConfig.isServerEnabled()); + tcpEnabled = (tcpConfig.isClientEnabled() || tcpConfig.isServerEnabled()); + ConfigParams advertisement = getPlatformConfig(); + OutputStream out = null; + + try { + if ("file".equalsIgnoreCase(storeHome.getScheme())) { + File saveDir = new File(storeHome); + saveDir.mkdirs(); + + // Sadly we can't use URL.openConnection() to create the + // OutputStream for file:// URLs. bogus. + out = new FileOutputStream(new File(saveDir, "PlatformConfig")); + } else { + out = storeHome.resolve("PlatformConfig").toURL().openConnection().getOutputStream(); + } + + XMLDocument aDoc = (XMLDocument) advertisement.getDocument(MimeMediaType.XMLUTF8); + OutputStreamWriter os = new OutputStreamWriter(out, "UTF-8"); + aDoc.sendToWriter(os); + os.flush(); + } finally { + if (null != out) { + out.close(); + } + } + } + + /** + * Returns a XMLDocument representation of an Advertisement + * + * @param enabled whether the param doc is enabled, adds a "isOff" + * element if disabled + * @param adv the Advertisement to retrieve the param doc from + * @return the parmDoc value + */ + protected XMLDocument getParmDoc(boolean enabled, Advertisement adv) { + XMLDocument parmDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + XMLDocument doc = (XMLDocument) adv.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(parmDoc, parmDoc, doc); + if (!enabled) { + parmDoc.appendChild(parmDoc.createElement("isOff")); + } + return parmDoc; + } + + /** + * Creates an HTTP transport advertisement + * + * @return an HTTP transport advertisement + */ + protected HTTPAdv createHttpAdv() { + httpConfig = (HTTPAdv) AdvertisementFactory.newAdvertisement(HTTPAdv.getAdvertisementType()); + httpConfig.setProtocol("http"); + httpConfig.setPort(9700); + httpConfig.setClientEnabled((mode & HTTP_CLIENT) == HTTP_CLIENT); + httpConfig.setServerEnabled((mode & HTTP_SERVER) == HTTP_SERVER); + return httpConfig; + } + + /** + * Creates Personal Security Environment Config Advertisement + *

      The configuration advertisement can include an optional seed certificate + * chain and encrypted private key. If this seed information is present the PSE + * Membership Service will require an initial authentication to unlock the + * encrypted private key before creating the PSE keystore. The newly created + * PSE keystore will be "seeded" with the certificate chain and the private key. + * + * @param principal principal + * @param password the password used to sign the private key of the root certificate + * @return PSEConfigAdv an PSE config advertisement + * @see net.jxta.impl.protocol.PSEConfigAdv + */ + protected PSEConfigAdv createPSEAdv(String principal, String password) { + pseConf = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); + if (principal != null && password != null) { + IssuerInfo info = PSEUtils.genCert(principal, null); + + pseConf.setCertificate(info.cert); + pseConf.setPrivateKey(info.subjectPkey, password.toCharArray()); + } + return pseConf; + } + + /** + * Creates Personal Security Environment Config Advertisement + *

      The configuration advertisement can include an optional seed certificate + * chain and encrypted private key. If this seed information is present the PSE + * Membership Service will require an initial authentication to unlock the + * encrypted private key before creating the PSE keystore. The newly created + * PSE keystore will be "seeded" with the certificate chain and the private key. + * + * @param cert X509Certificate + * @return PSEConfigAdv an PSE config advertisement + * @see net.jxta.impl.protocol.PSEConfigAdv + */ + protected PSEConfigAdv createPSEAdv(X509Certificate cert) { + pseConf = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); + if (subjectPkey != null && password != null) { + pseConf.setCertificate(cert); + pseConf.setPrivateKey(subjectPkey, password.toCharArray()); + } + return pseConf; + } + + /** + * Creates Personal Security Environment Config Advertisement + *

      The configuration advertisement can include an optional seed certificate + * chain and encrypted private key. If this seed information is present the PSE + * Membership Service will require an initial authentication to unlock the + * encrypted private key before creating the PSE keystore. The newly created + * PSE keystore will be "seeded" with the certificate chain and the private key. + * + * @param certificateChain X509Certificate[] + * @return PSEConfigAdv an PSE config advertisement + * @see net.jxta.impl.protocol.PSEConfigAdv + */ + protected PSEConfigAdv createPSEAdv(X509Certificate[] certificateChain) { + pseConf = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); + if (subjectPkey != null && password != null) { + pseConf.setCertificateChain(certificateChain); + pseConf.setPrivateKey(subjectPkey, password.toCharArray()); + } + return pseConf; + } + + /** + * Creates a ProxyService configuration advertisement + * + * @return ProxyService configuration advertisement + */ + protected XMLDocument createProxyAdv() { + return (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + } + + /** + * Creates a RendezVousService configuration advertisement with default values (EDGE) + * + * @return a RdvConfigAdv + */ + protected RdvConfigAdv createRdvConfigAdv() { + rdvConfig = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + if (mode == RDV_AD_HOC) { + rdvConfig.setConfiguration(RendezVousConfiguration.AD_HOC); + } else if ((mode & RDV_CLIENT) == RDV_CLIENT) { + rdvConfig.setConfiguration(RendezVousConfiguration.EDGE); + } else if ((mode & RDV_SERVER) == RDV_SERVER) { + rdvConfig.setConfiguration(RendezVousConfiguration.RENDEZVOUS); + } + // A better alternative is to reference rdv service defaults (currently private) + // rdvConfig.setMaxClients(200); + return rdvConfig; + } + + /** + * Creates a RelayService configuration advertisement with default values (EDGE) + * + * @return a RelayConfigAdv + */ + protected RelayConfigAdv createRelayConfigAdv() { + relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(RelayConfigAdv.getAdvertisementType()); + relayConfig.setUseOnlySeeds(false); + relayConfig.setClientEnabled((mode & RELAY_CLIENT) == RELAY_CLIENT || mode == EDGE_NODE); + relayConfig.setServerEnabled((mode & RELAY_SERVER) == RELAY_SERVER); + return relayConfig; + } + + /** + * Creates an TCP transport advertisement with the platform default values. + * multicast on, 224.0.1.85:1234, with a max packet size of 16K + * + * @return a TCP transport advertisement + */ + protected TCPAdv createTcpAdv() { + tcpConfig = (TCPAdv) AdvertisementFactory.newAdvertisement(TCPAdv.getAdvertisementType()); + tcpConfig.setProtocol("tcp"); + tcpConfig.setInterfaceAddress(null); + tcpConfig.setPort(9701); + tcpConfig.setStartPort(9701); + tcpConfig.setEndPort(9799); + tcpConfig.setMulticastAddr("224.0.1.85"); + tcpConfig.setMulticastPort(1234); + tcpConfig.setMulticastSize(16384); + tcpConfig.setMulticastState((mode & IP_MULTICAST) == IP_MULTICAST); + tcpConfig.setServer(null); + tcpConfig.setClientEnabled((mode & TCP_CLIENT) == TCP_CLIENT); + tcpConfig.setServerEnabled((mode & TCP_SERVER) == TCP_SERVER); + return tcpConfig; + } + + protected PeerGroupConfigAdv createInfraConfigAdv() { + infraPeerGroupConfig = (PeerGroupConfigAdv) AdvertisementFactory.newAdvertisement( + PeerGroupConfigAdv.getAdvertisementType()); + + NetGroupTunables tunables = new NetGroupTunables(ResourceBundle.getBundle("net.jxta.impl.config"), new NetGroupTunables()); + + infraPeerGroupConfig.setPeerGroupID(tunables.id); + infraPeerGroupConfig.setName(tunables.name); + infraPeerGroupConfig.setDesc(tunables.desc); + + return infraPeerGroupConfig; + } + + /** + * Returns a PlatformConfig which represents a platform configuration. + *

      Fine tuning is achieved through accessing each configured advertisement + * and achieved through accessing each configured advertisement and modifying + * each object directly. + * + * @return the PeerPlatformConfig Advertisement + */ + public ConfigParams getPlatformConfig() { + PlatformConfig advertisement = (PlatformConfig) AdvertisementFactory.newAdvertisement( + PlatformConfig.getAdvertisementType()); + + advertisement.setName(name); + advertisement.setDescription(description); + if (peerid != null) { + advertisement.setPeerID(peerid); + } + + if (tcpConfig != null) { + boolean enabled = tcpEnabled && (tcpConfig.isServerEnabled() || tcpConfig.isClientEnabled()); + advertisement.putServiceParam(PeerGroup.tcpProtoClassID, getParmDoc(enabled, tcpConfig)); + } + + if (httpConfig != null) { + boolean enabled = httpEnabled && (httpConfig.isServerEnabled() || httpConfig.isClientEnabled()); + advertisement.putServiceParam(PeerGroup.httpProtoClassID, getParmDoc(enabled, httpConfig)); + } + + if (relayConfig != null) { + boolean isOff = ((mode & RELAY_OFF) == RELAY_OFF) || (relayConfig.isServerEnabled() && relayConfig.isClientEnabled()); + XMLDocument relayDoc = (XMLDocument) relayConfig.getDocument(MimeMediaType.XMLUTF8); + + if (isOff) { + relayDoc.appendChild(relayDoc.createElement("isOff")); + } + advertisement.putServiceParam(PeerGroup.relayProtoClassID, relayDoc); + } + + if (rdvConfig != null) { + XMLDocument rdvDoc = (XMLDocument) rdvConfig.getDocument(MimeMediaType.XMLUTF8); + advertisement.putServiceParam(PeerGroup.rendezvousClassID, rdvDoc); + } + + if (cert != null) { + pseConf = createPSEAdv(cert); + } else { + pseConf = createPSEAdv(principal, password); + } + + if (pseConf != null) { + if (keyStoreLocation != null) { + if (keyStoreLocation.isAbsolute()) { + pseConf.setKeyStoreLocation(keyStoreLocation); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Keystore location set, but is not absolute: " + keyStoreLocation); + } + } + } + XMLDocument pseDoc = (XMLDocument) pseConf.getDocument(MimeMediaType.XMLUTF8); + advertisement.putServiceParam(PeerGroup.membershipClassID, pseDoc); + } + + if (proxyConfig != null && ((mode & PROXY_SERVER) == PROXY_SERVER)) { + advertisement.putServiceParam(PeerGroup.proxyClassID, proxyConfig); + } + + if ((null != infraPeerGroupConfig) && (null != infraPeerGroupConfig.getPeerGroupID()) + && (ID.nullID != infraPeerGroupConfig.getPeerGroupID()) + && (PeerGroupID.defaultNetPeerGroupID != infraPeerGroupConfig.getPeerGroupID())) { + advertisement.setSvcConfigAdvertisement(PeerGroup.peerGroupClassID, infraPeerGroupConfig); + } + return advertisement; + } + + /** + * @param location The location of the platform config. + * @return The platformConfig + * @throws IOException Thrown for failures reading the PlatformConfig. + */ + private PlatformConfig read(URI location) throws IOException { + URL url; + + try { + url = location.toURL(); + } catch (MalformedURLException mue) { + IllegalArgumentException failure = new IllegalArgumentException("Failed to convert URI to URL"); + failure.initCause(mue); + throw failure; + } + + InputStream input = url.openStream(); + try { + XMLDocument document = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, input); + PlatformConfig platformConfig = (PlatformConfig) AdvertisementFactory.newAdvertisement(document); + return platformConfig; + } finally { + input.close(); + } + } + + /** + * Holds the construction tunables for the Net Peer Group. This consists of + * the peer group id, the peer group name and the peer group description. + */ + static class NetGroupTunables { + + final ID id; + final String name; + final XMLElement desc; + + /** + * Constructor for loading the default Net Peer Group construction + * tunables. + */ + NetGroupTunables() { + id = PeerGroupID.defaultNetPeerGroupID; + name = "NetPeerGroup"; + desc = (XMLElement) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "desc", "default Net Peer Group"); + } + + /** + * Constructor for loading the default Net Peer Group construction + * tunables. + * + * @param pgid the PeerGroupID + * @param pgname the group name + * @param pgdesc the group description + */ + NetGroupTunables(ID pgid, String pgname, XMLElement pgdesc) { + id = pgid; + name = pgname; + desc = pgdesc; + } + + /** + * Constructor for loading the Net Peer Group construction + * tunables from the provided resource bundle. + * + * @param rsrcs The resource bundle from which resources will be loaded. + * @param defaults default values + */ + NetGroupTunables(ResourceBundle rsrcs, NetGroupTunables defaults) { + ID idTmp; + String nameTmp; + XMLElement descTmp; + + try { + String idTmpStr = rsrcs.getString("NetPeerGroupID").trim(); + + if (idTmpStr.startsWith(ID.URNNamespace + ":")) { + idTmpStr = idTmpStr.substring(5); + } + idTmp = IDFactory.fromURI(new URI(ID.URIEncodingName + ":" + ID.URNNamespace + ":" + idTmpStr)); + nameTmp = rsrcs.getString("NetPeerGroupName").trim(); + descTmp = (XMLElement) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "desc", rsrcs.getString("NetPeerGroupDesc").trim()); + } catch (Exception failed) { + if (null != defaults) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "NetPeerGroup tunables not defined or could not be loaded. Using defaults.", failed); + } + + idTmp = defaults.id; + nameTmp = defaults.name; + descTmp = defaults.desc; + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "NetPeerGroup tunables not defined or could not be loaded.", failed); + } + + throw new IllegalStateException("NetPeerGroup tunables not defined or could not be loaded."); + } + } + + id = idTmp; + name = nameTmp; + desc = descTmp; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/NetworkManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/NetworkManager.java new file mode 100644 index 000000000..b11b9e0f1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/NetworkManager.java @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2006-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.platform; + + +import javax.security.cert.CertificateException; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.credential.Credential; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.membership.InteractiveAuthenticator; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.NetPeerGroupFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezvousListener; + +import net.jxta.impl.membership.pse.StringAuthenticator; + + +/** + * NetworkManager provides a simplified JXTA platform configuration abstraction, and provides a JXTA platform life-cycle + * management. The node configuration is created during construction of this object and can be obtained for fine tuning + * or alteration. Note that all alterations must be done prior to calling #startNetwork(), otherwise the default + * configuration is used. Configuration persistence is on by default and maybe overridden by call to #setEnableConfigPersistence + *

      + * NetworkManager defines six abstractions of a node configurations as follows : + * ADHOC : A node which typically deployed in an ad-hoc network + * EDGE : In addition to supporting ADHOC function, an Edge node can attach to a infrastructure (a Rendezvous, Relay, or both) + * RENDEZVOUS: provides network bootstrapping services, such as discovery, pipe resolution, etc. + * RELAY: provides message relaying services, enabling cross firewall traversal + * PROXY: provide JXME JXTA for J2ME proxying services + * SUPER: provide the functionality of a Rendezvous, Relay, Proxy node. + */ +public class NetworkManager implements RendezvousListener { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(NetworkManager.class.getName()); + + protected final transient URI publicSeedingRdvURI = URI.create("http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3"); + protected final transient URI publicSeedingRelayURI = URI.create("http://rdv.jxtahosts.net/cgi-bin/relays.cgi?3"); + + /** + * Define node standard node operating modes + */ + public enum ConfigMode { + + /** + * A AD-HOC node + */ + ADHOC, + /** + * A Edge node + */ + EDGE, + /** + * A Rendezvous node + */ + RENDEZVOUS, + /** + * A Relay node + */ + RELAY, + /** + * Rendezvous and a Relay + */ + RENDEZVOUS_RELAY, + /** + * JXME Proxy node + */ + PROXY, + /** + * A Rendezvous, Relay, and JXME Proxy node + */ + SUPER + } + + private final Object networkConnectLock = new String("rendezvous connection lock"); + private PeerGroup netPeerGroup = null; + private volatile boolean started = false; + private volatile boolean connected = false; + private volatile boolean stopped = false; + private RendezVousService rendezvous; + private String instanceName = "NA"; + private ShutdownHook shutdownHook; + private ConfigMode mode; + private URI instanceHome; + private PeerGroupID infrastructureID = PeerGroupID.defaultNetPeerGroupID; + private PeerID peerID = IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID); + private NetworkConfigurator config; + private boolean configPersistent = true; + private boolean useDefaultSeeds; + + /** + * Creates NetworkManger instance with default instance home set to "$CWD"/.jxta" + * At this point, alternate Infrastructure PeerGroupID maybe specified, as well as a PeerID. if neither are + * specified, the default NetPeerGroupID will be used, and a new PeerID will be generated. Also note the default + * seeding URIs are the to development. Alternate values must be specified, if desired, prior to a call to {@link #startNetwork} + * + * @param mode Operating mode the node operating {@link ConfigMode} + * @param instanceName Node name + * @throws IOException if an io error occurs + */ + public NetworkManager(ConfigMode mode, String instanceName) throws IOException { + this(mode, instanceName, new File(".jxta/").toURI()); + } + + /** + * Creates NetworkManger instance. + * At this point, alternate Infrastructure PeerGroupID maybe specified, as well as a PeerID. if neither are + * specified, the default NetPeerGroupID will be used, and a new PeerID will be generated. Also note the default + * seeding URIs are the to development. Alternate values must be specified, if desired, prior to a call to {@link #startNetwork} + * + * @param mode Operating mode the node operating {@link ConfigMode} + * @param instanceName Node name + * @param instanceHome instance home is a uri to the instance persistent store (aka Cache Manager store home) + * @throws IOException if an io error occurs + */ + public NetworkManager(ConfigMode mode, String instanceName, URI instanceHome) throws IOException { + this.instanceName = instanceName; + this.mode = mode; + this.instanceHome = instanceHome; + } + + /** + * Returns the {@link NetworkConfigurator} for additional tuning + * + * @return the {@link NetworkConfigurator} for additional tuning + * @throws java.io.IOException if an io error occurs + */ + public synchronized NetworkConfigurator getConfigurator() throws IOException { + if (config == null) { + configure(mode); + } + return config; + } + + /** + * Getter for property 'infrastructureID'. + * + * @return Value for property 'infrastructureID'. + */ + public PeerGroupID getInfrastructureID() { + return infrastructureID; + } + + /** + * Setter for property 'infrastructureID'. + * + * @param infrastructureID Value to set for property 'infrastructureID'. + */ + public void setInfrastructureID(PeerGroupID infrastructureID) { + this.infrastructureID = infrastructureID; + if (config != null) { + config.setInfrastructureID(infrastructureID); + } + } + + /** + * Getter for property 'instanceName'. + * + * @return Value for property 'instanceName'. + */ + public String getInstanceName() { + return instanceName; + } + + /** + * Setter for property 'instanceName'. + * + * @param instanceName Value to set for property 'instanceName'. + */ + public void setInstanceName(String instanceName) { + this.instanceName = instanceName; + } + + /** + * Getter for property 'instanceHome'. + * + * @return Value for property 'instanceHome'. + */ + public URI getInstanceHome() { + return instanceHome; + } + + /** + * Setter for property 'instanceHome'. + * + * @param instanceHome Value to set for property 'instanceHome'. + */ + public void setInstanceHome(URI instanceHome) { + this.instanceHome = instanceHome; + } + + /** + * Getter for property node operating 'mode'. + * + * @return Value for property 'mode'. + */ + public ConfigMode getMode() { + return mode; + } + + /** + * Setter for property 'mode'. + * + * @param mode Value to set for property 'mode'. + * @throws IOException if an io error occurs + */ + public void setMode(ConfigMode mode) throws IOException { + this.mode = mode; + configure(mode); + } + + /** + * Getter for property 'peerID'. + * + * @return Value for property 'peerID'. + */ + public PeerID getPeerID() { + return peerID; + } + + /** + * Setter for property 'peerID'. + * + * @param peerID Value to set for property 'peerID'. + */ + public void setPeerID(PeerID peerID) { + this.peerID = peerID; + } + + /** + * Getter for property 'configPersistent'. + * + * @return Value for property 'configPersistent'. + */ + public boolean isConfigPersistent() { + return configPersistent; + } + + /** + * Setter for property 'configPersistent'. if disabled a PlatformConfig is not persisted. It assumed that + * the PeerID is will be set, or a new PeerID will always be generated. + * + * @param persisted Value to set for property 'configPersistent'. + */ + public void setConfigPersistent(boolean persisted) { + this.configPersistent = persisted; + } + + private void configure(ConfigMode mode) throws IOException { + switch (mode) { + case ADHOC: + config = NetworkConfigurator.newAdHocConfiguration(instanceHome); + break; + + case EDGE: + config = NetworkConfigurator.newEdgeConfiguration(instanceHome); + break; + + case RENDEZVOUS: + config = NetworkConfigurator.newRdvConfiguration(instanceHome); + break; + + case RELAY: + config = NetworkConfigurator.newRelayConfiguration(instanceHome); + break; + + case RENDEZVOUS_RELAY: + config = NetworkConfigurator.newRdvRelayConfiguration(instanceHome); + break; + + case PROXY: + config = NetworkConfigurator.newProxyConfiguration(instanceHome); + break; + + case SUPER: + config = NetworkConfigurator.newRdvRelayProxyConfiguration(instanceHome); + break; + + default: + config = NetworkConfigurator.newAdHocConfiguration(instanceHome); + } + if (!config.exists()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Created new configuration. mode = " + mode.toString()); + } + + config.setDescription("Created by NetworkManager"); + config.setPeerID(peerID); + config.setInfrastructureID(infrastructureID); + config.setName(instanceName); + if (useDefaultSeeds) { + config.addRdvSeedingURI(publicSeedingRdvURI); + config.addRelaySeedingURI(publicSeedingRelayURI); + } + } else { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Loading existing configuration. mode = " + mode.toString()); + } + + File pc = new File(config.getHome(), "PlatformConfig"); + + try { + config.load(pc.toURI()); + } catch (CertificateException pseFailed) { + IOException failure = new IOException("Failure reading membership service certificates."); + + failure.initCause(pseFailed); + throw failure; + } + + // XXX 20070524 bondolo Aren't we completely ignoring the mode? What if it changed? + // 20070614 hamada Good question, this feature is postponed due to the difficulty of comparing a stored/requested modes. + } + } + + /** + * Creates and starts the JXTA infrastructure peer group (aka NetPeerGroup) based on the specified mode + * template. This class also registers a listener for rendezvous events. + * + * @return The Net Peer Group + * @throws net.jxta.exception.PeerGroupException + * if the group fails to initialize + * @throws java.io.IOException if an io error occurs + */ + public synchronized PeerGroup startNetwork() throws PeerGroupException, IOException { + + if (started) { + return netPeerGroup; + } + + if (config == null) { + configure(mode); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Starting JXTA Network! MODE = " + mode.toString() + ", HOME = " + instanceHome); + } + + // create, and Start the default jxta NetPeerGroup + NetPeerGroupFactory factory = new NetPeerGroupFactory(config.getPlatformConfig(), instanceHome); + + netPeerGroup = factory.getInterface(); + + if (configPersistent) { + config.save(); + } + + rendezvous = netPeerGroup.getRendezVousService(); + rendezvous.addListener(this); + started = true; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Started JXTA Network!"); + } + + return netPeerGroup; + } + + /** + * Establishes group credential. This is a required step when planning to + * to utilize TLS messengers or secure pipes + * + * @param group peer group to establish credentials in + * @param keystore_password The passphrase for the keystore. This is a + * char[] rather than a String so that it can be blanked after use. + * @param principal_password The passphrase for the identity. This is a + * char[] rather than a String so that it can be blanked after use. + * @throws net.jxta.exception.PeerGroupException + * if group credentials were rejected + * @throws net.jxta.exception.ProtocolNotSupportedException + * if authenticator rejected the credential + */ + public static void login(PeerGroup group, char[] keystore_password, char[] principal_password) throws PeerGroupException, ProtocolNotSupportedException { + StringAuthenticator auth; + MembershipService membership = group.getMembershipService(); + Credential cred = membership.getDefaultCredential(); + + if (cred == null) { + AuthenticationCredential authCred = new AuthenticationCredential(group, "StringAuthentication", null); + + auth = (StringAuthenticator) membership.apply(authCred); + if (auth != null) { + auth.setAuth1_KeyStorePassword(keystore_password); + auth.setAuth2Identity(group.getPeerID()); + auth.setAuth3_IdentityPassword(principal_password); + if (auth.isReadyForJoin()) { + membership.join(auth); + } + } + } + + cred = membership.getDefaultCredential(); + if (null == cred) { + AuthenticationCredential authCred = new AuthenticationCredential(group, "InteractiveAuthentication", null); + InteractiveAuthenticator iAuth = (InteractiveAuthenticator) membership.apply(authCred); + + if (iAuth.interact() && iAuth.isReadyForJoin()) { + membership.join(iAuth); + } + } + } + + /** + * Stops and unreferences the NetPeerGroup + */ + public synchronized void stopNetwork() { + if (stopped || !started) { + return; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Stopping JXTA Network!"); + } + + stopped = true; + synchronized(networkConnectLock) { + connected = false; + networkConnectLock.notifyAll(); + } + + rendezvous.removeListener(this); + netPeerGroup.stopApp(); + netPeerGroup.unref(); + netPeerGroup = null; + // permit restart. + started = false; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Stopped JXTA Network!"); + } + } + + /** + * Gets the netPeerGroup object + * + * @return The netPeerGroup value + */ + public PeerGroup getNetPeerGroup() { + return netPeerGroup; + } + + /** + * Blocks only, if not connected to a rendezvous, or until a connection to rendezvous node occurs. + * + * @param timeout timeout in milliseconds, a zero timeout of waits forever + * @return true if connected to a rendezvous, false otherwise + */ + public boolean waitForRendezvousConnection(long timeout) { + if (0 == timeout) { + timeout = Long.MAX_VALUE; + } + + long timeoutAt = System.currentTimeMillis() + timeout; + + if (timeoutAt <= 0) { + // handle overflow. + timeoutAt = Long.MAX_VALUE; + } + + while (started && !stopped && !rendezvous.isConnectedToRendezVous() && !rendezvous.isRendezVous()) { + try { + long waitFor = timeoutAt - System.currentTimeMillis(); + + if (waitFor > 0) { + synchronized (networkConnectLock) { + networkConnectLock.wait(timeout); + } + } else { + // all done with waiting. + break; + } + } catch (InterruptedException e) { + Thread.interrupted(); + break; + } + } + + return rendezvous.isConnectedToRendezVous() || rendezvous.isRendezVous(); + } + + /** + * rendezvousEvent the rendezvous event + * + * @param event rendezvousEvent + */ + public void rendezvousEvent(RendezvousEvent event) { + if (event.getType() == RendezvousEvent.RDVCONNECT || event.getType() == RendezvousEvent.RDVRECONNECT + || event.getType() == RendezvousEvent.BECAMERDV) { + synchronized (networkConnectLock) { + connected = true; + networkConnectLock.notifyAll(); + } + } + } + + /** + * if true uses the public rendezvous seeding service + * + * @param useDefaultSeeds if true uses the default development seeding service + */ + public void setUseDefaultSeeds(boolean useDefaultSeeds) { + this.useDefaultSeeds = useDefaultSeeds; + } + + /** + * Returns true if useDefaultSeeds is set to true + * + * @return true if useDefaultSeeds is set to true + */ + public boolean getUseDefaultSeeds() { + return useDefaultSeeds; + } + + /** + * Registers a Runtime shutdown hook to cleanly shutdown the JXTA platform + */ + public synchronized void registerShutdownHook() { + if (shutdownHook != null) { + return; + } + shutdownHook = new NetworkManager.ShutdownHook(); + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + /** + * Unregisters a Runtime shutdown hook to cleanly shutdown the JXTA platform + */ + public synchronized void unregisterShutdownHook() { + + if (shutdownHook == null) { + return; + } + Runtime.getRuntime().removeShutdownHook(shutdownHook); + shutdownHook = null; + } + + private class ShutdownHook extends Thread { + + /** + * {@inheritDoc} + */ + @Override + public void run() { + stopNetwork(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/package.html new file mode 100644 index 000000000..c839dfd07 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/platform/package.html @@ -0,0 +1,14 @@ + + + + + + + Classes for defining code modules within JXTA. Modules are used for services + and applications within JXTA. Also provides utilities for configuring and + managing JXTA start-up and shutdown. + + @see net.jxta.id.ID + @see JXTA Protocols Specification : IDs + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/AccessPointAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/AccessPointAdvertisement.java new file mode 100644 index 000000000..6964fafbd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/AccessPointAdvertisement.java @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import java.util.Collection; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.peer.PeerID; + +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; + + +/** + * Provides a simple association of a {@code PeerID} to an ordered list of + * {@code EndpointAddress} entries. Each {@code EndpointAddress} defines one + * Message Transport address by which the peer may be reached. The addresses + * are sorted in the preferred order (which may refer to performance, cost, + * efficiency, etc.) which they should be used. + *

      + * The Access Point Advertisement is most commonly used as part of other + * Advertisements such as {@code RouteAdvertisement}. + * + * @see net.jxta.protocol.PeerAdvertisement + * @see net.jxta.protocol.RouteAdvertisement + */ +public abstract class AccessPointAdvertisement extends ExtendableAdvertisement implements Cloneable { + + /** + * The peer id of the peer with these endpoints. May be {@code null} + * if the APA is used as a sub-element of a structure in which the context + * peerid is already known. + */ + private PeerID pid = null; + + /** + * The EndpointAddresses associated with the specified peer in preferred + * order. + *

      + *

        + *
      • Values are, sadly, {@link java.lang.String} of + * {@link net.jxta.endpoint.EndpointAddress}.
      • + *
      + */ + private Vector endpointAddresses = new Vector(); + + /** + * {@inheritDoc} + *

      + *

      Make a deep copy. + */ + @Override + public AccessPointAdvertisement clone() { + try { + AccessPointAdvertisement a = (AccessPointAdvertisement) super.clone(); + + a.setPeerID(getPeerID()); + a.addEndpointAddresses(endpointAddresses); + + return a; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * {@inheritDoc} + *

      + * Equals means the same PID and the same endpoint addresses. + */ + @Override + public boolean equals(Object target) { + + if (this == target) { + return true; + } + + if (!(target instanceof AccessPointAdvertisement)) { + return false; + } + + AccessPointAdvertisement ap = (AccessPointAdvertisement) target; + + if ((null == getPeerID()) && (null != ap.getPeerID())) { + return false; + } + + if ((null != getPeerID())) { + if (!getPeerID().equals(ap.getPeerID())) { + return false; + } + } + if (endpointAddresses.size() != ap.endpointAddresses.size()) { + return false; + } + + // XXX 20061127 bondolo This eventually should be an ordered comparison. + + for (String anEA : endpointAddresses) { + if (!ap.endpointAddresses.contains(anEA)) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + if (null != pid) { + return pid.hashCode(); + } else { + // force all incomplete advertisements to hash to the same place. + return 1; + } + } + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:APA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * Gets the PeerID for this access point. + * + * @return PeerID The peer id associated with the endpoint addresses or + * {@code null} if no peer has been directly associated. + */ + public PeerID getPeerID() { + return pid; + } + + /** + * Sets the PeerID for this access point. + * + * @param pid The peer id associated with the endpoint addresses or + * {@code null} if no peer is directly associated. + */ + public void setPeerID(PeerID pid) { + this.pid = pid; + } + + /** + * Add all of the provided EndpointAddresses. + * + * @param addrs Add all of the specified endpoint addresses. + */ + public void addEndpointAddresses(List addrs) { + for (EndpointAddress addr : addrs) { + addEndpointAddress(addr); + } + } + + /** + * Clears all EndpointAddresses. + */ + public void clearEndpointAddresses() { + endpointAddresses.clear(); + } + + /** + * Remove the specified EndpointAddress. + * + * @param addr EndpointAddress to remove. + */ + public void removeEndpointAddress(EndpointAddress addr) { + endpointAddresses.remove(addr.toString()); + } + + /** + * Remove the specified EndpointAddresses. + * + * @param addrs EndpointAddresses to remove. + */ + public void removeEndpointAddresses(Collection addrs) { + for (EndpointAddress addr : addrs) { + endpointAddresses.remove(addr.toString()); + } + } + + /** + * Returns the endpoint addresses associated with this access point. + * + * @return The endpoint addresses associated with this access point + * represented as {@link java.lang.String}. + */ + public Enumeration getEndpointAddresses() { + return endpointAddresses.elements(); + } + + /** + * Returns the vector of endpoint addresses associated with this access + * point. The result is a vector of endpoint addresses represented as + * {@code String}. The Vector contains the "live" data of this + * advertisement. It should be modified only with great care. + * + * @return The endpoint addresses associated with this access point + * represented as {@link java.lang.String}. + * @deprecated Returning the Vector is dangerous and unwise. This feature + * will be removed. + */ + @Deprecated + public Vector getVectorEndpointAddresses() { + return endpointAddresses; + } + + /** + * Sets the list of endpoint addresses associated with this access point. + * + * @param addresses Vector of EndpointAddresses represented as + * {@link java.lang.String}. The Vector is not copied! + * @deprecated This method causes the AccessPointAdvertisement to reference + * the provided array. This means that subsequent changes to the array will + * alter the endpoint addresses which are part of the + * {@code AcccessPointAdvertisement}. + */ + @Deprecated + public void setEndpointAddresses(Vector addresses) { + endpointAddresses = addresses; + } + + /** + * Add a new list of EndpointAddresses to the access point. + * + * @param addresses List of EndpointAddresses represented as + * {@link java.lang.String}. + * + * @deprecated Use {@link #addEndpointAddresses(List)} instead. + */ + @Deprecated + public void addEndpointAddresses(Vector addresses) { + for (String toAdd : addresses) { + addEndpointAddress(toAdd); + } + } + + /** + * Add a new EndpointAddresses to the access point + * + * @param address An EndpointAddress + */ + public void addEndpointAddress(EndpointAddress address) { + String toAdd = address.toString(); + + if (!endpointAddresses.contains(toAdd)) { + endpointAddresses.add(toAdd); + } + } + + /** + * add a new EndpointAddresses to the access point + * + * @param address EndpointAddress represented as {@link java.lang.String}. + */ + public void addEndpointAddress(String address) { + if (!endpointAddresses.contains(address)) { + endpointAddresses.add(address); + } + } + + /** + * remove a list of EndpointAddresses from the access point + * + * @param addresses List of EndpointAddresses represented as + * {@link java.lang.String}. + */ + public void removeEndpointAddresses(List addresses) { + endpointAddresses.removeAll(addresses); + } + + /** + * return number of endpoint addresses + * + * @return size number of endpointAddress in the hop + */ + public int size() { + return endpointAddresses.size(); + } + + /** + * Check if the EndpointAddress is already associated with this access point + * + * @param addr endpoint address to check + * @return true if the EndpointAddress is already associated with this access point + */ + public boolean contains(EndpointAddress addr) { + return endpointAddresses.contains(addr.toString()); + } + + /** + * Generate a string that displays an access point + * information for logging or debugging purpose + * + * @return String return a string containing the access point advertisement + */ + public String display() { + StringBuilder routeBuf = new StringBuilder(); + + routeBuf.append("PID="); + + PeerID peerId = getPeerID(); + + if (peerId == null) { + routeBuf.append(""); + } else { + routeBuf.append(peerId.toString()); + } + + Enumeration e = getEndpointAddresses(); + + while (e.hasMoreElements()) { + routeBuf.append("\n Addr=").append(e.nextElement()); + } + return routeBuf.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ConfigParams.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ConfigParams.java new file mode 100644 index 000000000..05cea09c9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ConfigParams.java @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * A container for collections of configuration parameters. Configuration + * parameters are stored in a Map which is keyed by {@code JXTA ID}s and whose + * values are {@code Advertisement}s. + */ +public abstract class ConfigParams extends ExtendableAdvertisement implements Cloneable { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ConfigParams.class.getName()); + + private static final String SVC_TAG = "Svc"; + private static final String MCID_TAG = "MCID"; + private static final String PARAM_TAG = "Parm"; + + /** + * A table of structured documents to be interpreted by each service. + * For safe operation these elements should be immutable, but we're helpless + * if they are not. + */ + private final Map params = new HashMap(); + + /** + * A map of advertisements to be interpreted by each service. + * For safe operation we clone the advertisements when they are added to the + * map and only ever return clones of the advertisements. + */ + private final Map ads = new HashMap(); + + /** + * The ids of the advertisements and/or params which have been explicitly + * marked as disabled. + */ + private final Set disabled = new HashSet(); + + /** + * Counts the changes made to this object. The API increments it every time + * some change is not proven to be idempotent. We rely on implementations to + * increment modCount every time something is changed without going through + * the API. + */ + protected final transient AtomicInteger modCount = new AtomicInteger(0); + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:CP"; + } + + /** + * Default Constructor. We want all ConfigParams derived advertisements to + * pretty print. + */ + protected ConfigParams() { + super(true); + } + + /** + * {@inheritDoc} + */ + @Override + public ConfigParams clone() { + + try { + ConfigParams result = (ConfigParams) super.clone(); + + for (Map.Entry anEntry : params.entrySet()) { + result.params.put(anEntry.getKey(), StructuredDocumentUtils.copyAsDocument(anEntry.getValue())); + } + + for (Map.Entry anEntry : ads.entrySet()) { + result.ads.put(anEntry.getKey(), anEntry.getValue().clone()); + } + + result.disabled.addAll(disabled); + + return result; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + if(this == other) { + return true; + } + + if(other instanceof ConfigParams) { + ConfigParams likeMe = (ConfigParams) other; + + boolean ep = params.equals(likeMe.params); + boolean ea = ads.equals(likeMe.ads); + boolean ed = disabled.equals(likeMe.disabled); + + return ep && ea && ed; + } + + return false; + } + + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (SVC_TAG.equals(elem.getName())) { + Attribute disabledAttr = elem.getAttribute("disabled"); + boolean isDisabled = (null != disabledAttr) && Boolean.parseBoolean(disabledAttr.getValue()); + + Enumeration elems = elem.getChildren(); + + ID key = null; + XMLElement param = null; + + while (elems.hasMoreElements()) { + XMLElement e = elems.nextElement(); + + if (MCID_TAG.equals(e.getName())) { + try { + URI mcid = new URI(e.getTextValue()); + + key = IDFactory.fromURI(mcid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad ID in advertisement: " + e.getTextValue()); + } + } else if (PARAM_TAG.equals(e.getName())) { + param = e; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unrecognized tag : " + e.getName()); + } + } + } + + if (key != null && param != null) { + if(!isDisabled) { + // Backwards compatibility support. + Enumeration isOff = param.getChildren("isOff"); + + isDisabled = isOff.hasMoreElements(); + } + + putServiceParam(key, param); + if(isDisabled) { + disabled.add(key); + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Incomplete Service Param : id=" + key + " param=" + param); + } + + return false; + } + return true; + } + return false; + } + + /** + * Return the advertisement as a document. + * + * @param adv the document to add elements to. + * @return true if elements were added otherwise false. + */ + public boolean addDocumentElements(StructuredDocument adv) { + + for (Map.Entry anEntry : params.entrySet()) { + ID anID = anEntry.getKey(); + StructuredDocument aDoc = anEntry.getValue(); + + Element s = adv.createElement(SVC_TAG); + + adv.appendChild(s); + + if(disabled.contains(anID)) { + ((Attributable)s).addAttribute("disabled", "true"); + } + + Element e = adv.createElement(MCID_TAG, anID.toString()); + + s.appendChild(e); + + StructuredDocumentUtils.copyElements(adv, s, aDoc, PARAM_TAG); + } + + for (Map.Entry anEntry : ads.entrySet()) { + ID anID = anEntry.getKey(); + Advertisement anAdv = anEntry.getValue(); + + Element s = adv.createElement(SVC_TAG); + + adv.appendChild(s); + + if(disabled.contains(anID)) { + ((Attributable)s).addAttribute("disabled", "true"); + } + + Element e = adv.createElement(MCID_TAG, anID.toString()); + + s.appendChild(e); + + StructuredDocument asDoc = (StructuredDocument) anAdv.getDocument(adv.getMimeType()); + + StructuredDocumentUtils.copyElements(adv, s, asDoc, PARAM_TAG); + } + + return true; + } + + /** + * Returns the number of times this object has been modified since it was + * created. This permits the detection of local changes that require + * refreshing some other data. + * + * @return int the current modification count. + */ + public int getModCount() { + return modCount.get(); + } + + /** + * Increases the modification count of this instance. + * + * @return modification count + */ + protected synchronized int incModCount() { + return modCount.incrementAndGet(); + } + + /** + * Puts a service parameter in the service parameters table + * under the given key. The key is usually a ModuleClassID. This method + * makes a clone of the given element into an independent document. + * + * @param key The key. + * @param param The parameter document. + */ + public void putServiceParam(ID key, Element param) { + incModCount(); + + params.remove(key); + ads.remove(key); + + if (param == null) { + return; + } + + boolean isDisabled = false; + + if (param instanceof XMLElement) { + Enumeration isOff = param.getChildren("isOff"); + + isDisabled = isOff.hasMoreElements(); + + Advertisement adv = null; + + try { + adv = AdvertisementFactory.newAdvertisement((XMLElement) param); + } catch (RuntimeException ignored) { + // ignored + ; + } + + if (null != adv) { + setSvcConfigAdvertisement(key,adv, !isDisabled); + return; + } + } + + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param); + + if(isDisabled) { + disabled.add(key); + } else { + disabled.remove(key); + } + + params.put(key, newDoc); + } + + + /** + * Puts an advertisement into the service parameters table under the given + * key. The key is usually a {@code ModuleClassID}. This method makes a + * clone of the advertisement. + * + * @param key The key. + * @param adv The advertisement, a clone of which is stored or {@code null} + * to forget this key. + */ + public void setSvcConfigAdvertisement(ID key, Advertisement adv) { + setSvcConfigAdvertisement(key, adv, true); + } + + /** + * Puts an advertisement into the service parameters table under the given + * key. The key is usually a {@code ModuleClassID}. This method makes a + * clone of the advertisement. + * + * @param key The key. + * @param adv The advertisement, a clone of which is stored or {@code null} + * to forget this key. + * @param enabled If true then the service is enabled or disabled if false. + */ + public void setSvcConfigAdvertisement(ID key, Advertisement adv, boolean enabled) { + incModCount(); + + params.remove(key); + ads.remove(key); + + if(enabled) { + disabled.remove(key); + } else { + disabled.add(key); + } + + if (null == adv) { + return; + } + + try { + ads.put(key, adv.clone()); + } catch (CloneNotSupportedException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unclonable Advertisements may not be used : " + adv.getClass().getName(), failed); + } + + throw new IllegalArgumentException("Unclonable Advertisements may not be used : " + adv.getClass().getName()); + } + } + + /** + * Gets an advertisement from the service parameters table under the given + * key. The key is usually a {@code ModuleClassID}. This method makes a + * clone of the advertisement. + * + * @param key The key. + * @return If {@code true} then the service is enabled otherwise {@false} if + * the service is disabled. + */ + public boolean isSvcEnabled(ID key) { + return !disabled.contains(key); + } + + /** + * Gets an advertisement from the service parameters table under the given + * key. The key is usually a {@code ModuleClassID}. This method makes a + * clone of the advertisement. + * + * @param key The key. + * @return The advertisement for the specified key otherwise {@code null}. + */ + public Advertisement getSvcConfigAdvertisement(ID key) { + Advertisement adv = ads.get(key); + + if (null == adv) { + if (params.containsKey(key)) { + throw new IllegalStateException("Unable to return advertisement, params are not an advertisement."); + } + + return null; + } + + try { + return adv.clone(); + } catch (CloneNotSupportedException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unclonable Advertisements may not be used : " + adv.getClass().getName(), failed); + } + + throw new IllegalArgumentException("Unclonable Advertisements may not be used : " + adv.getClass().getName()); + } + } + + /** + * Returns the parameter element that matches the given key from the + * service parameters table. The key is of a subclass of ID; usually a + * ModuleClassID. + * + * @param key The key. + * @return StructuredDocument The matching parameter document or null if + * none matched. + */ + public StructuredDocument getServiceParam(ID key) { + StructuredDocument param = params.get(key); + + if (param == null) { + Advertisement ad = ads.get(key); + + if (null == ad) { + return null; + } + + return (XMLDocument) ad.getDocument(MimeMediaType.XMLUTF8); + } + + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param); + + if(disabled.contains(key)) { + Enumeration isOffAlready = newDoc.getChildren("isOff"); + + if(!isOffAlready.hasMoreElements()) { + newDoc.appendChild(newDoc.createElement("isOff", null)); + } + } + + return newDoc; + } + + /** + * Removes and returns the parameter element that matches the given key + * from the service parameters table. The key is of a subclass of ID; + * usually a ModuleClassID. + * + * @param key The key. + * + * @return The removed parameter element or {@code null} if not found. + */ + public StructuredDocument removeServiceParam(ID key) { + + StructuredDocument param = params.remove(key); + + if (param == null) { + Advertisement ad = ads.remove(key); + + if (null == ad) { + return null; + } + + return (XMLDocument) ad.getDocument(MimeMediaType.XMLUTF8); + } else { + ads.remove(key); + } + + incModCount(); + + // It sound silly to clone it, but remember that we could be sharing + // this element with a clone of ours, so we have the duty to still + // protect it. + + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param); + + if(disabled.contains(key)) { + newDoc.appendChild(newDoc.createElement("isOff", null)); + disabled.remove(key); + } + + return newDoc; + } + + /** + * Removes any parameters for the given key from the service parameters + * table. + * + * @param key The key. + */ + public void removeSvcConfigAdvertisement(ID key) { + incModCount(); + + params.remove(key); + ads.remove(key); + } + + /** + * Returns the set of params held by this object. The parameters are not + * copied and any changes to the Set are reflected in this object's version. + * incModCount should be called as appropriate. + * + * @deprecated This method exposes the internal data structures of the + * advertisement and will be removed in order to prevent unexpected + * behaviour. + */ + @Deprecated + public Set> getServiceParamsEntrySet() { + Map result = new HashMap(); + + result.putAll(params); + + for (Map.Entry anEntry : ads.entrySet()) { + XMLDocument entryDoc = (XMLDocument) anEntry.getValue().getDocument(MimeMediaType.XMLUTF8); + + if(disabled.contains(anEntry.getKey())) { + entryDoc.appendChild(entryDoc.createElement("isOff", null)); + } + + result.put(anEntry.getKey(), entryDoc); + } + + return Collections.unmodifiableSet(result.entrySet()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/DiscoveryQueryMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/DiscoveryQueryMsg.java new file mode 100644 index 000000000..6d5930c01 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/DiscoveryQueryMsg.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; + + +/** + * This class defines the Discovery Service message "Query". The default + * behavior of this abstract class is simply a place holder for the generic + * resolver query fields. + * + * @see net.jxta.discovery.DiscoveryService + * @see net.jxta.protocol.DiscoveryResponseMsg + */ + +public abstract class DiscoveryQueryMsg { + + private PeerAdvertisement peerAdvertisement = null; + + /** + * default threshold to limit the number of responses from one peer + */ + private int threshold = 10; + + /** + * FIXME 20030227 bondolo@jxta.org not a great default... + */ + private int type = DiscoveryService.PEER; + + private String attr = null; + private String value = null; + + /** + * returns the Attr value + * + * @return String value of Attribute + */ + public String getAttr() { + return attr; + } + + /** + * Get the response type + * + * @return int PEER, or GROUP discovery type response + */ + public int getDiscoveryType() { + return type; + } + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out, and "text/xml" which + * provides an XML representation. + * + * @param asMimeType mime-type format requested + * @return Document representation of the document as an + * advertisement + */ + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * returns the responding peer advertisement + * + * @return String handlername name + * @deprecated Peer Advertisement is available directly via + * {@link #getPeerAdvertisement()}. + */ + @Deprecated + public String getPeerAdv() { + if (null != peerAdvertisement) { + return peerAdvertisement.toString(); + } else { + return null; + } + } + + /** + * returns the querying peer's advertisement + * + * @return peer advertisement of querier. + */ + public PeerAdvertisement getPeerAdvertisement() { + return peerAdvertisement; + } + + /** + * returns the responding peer's advertisement + * + * @param newAdv peer advertisement of querier. + */ + public void setPeerAdvertisement(PeerAdvertisement newAdv) { + peerAdvertisement = newAdv; + } + + /** + * Get the Threshold for number of responses + * + * @return int threshold + */ + public int getThreshold() { + return threshold; + } + + /** + * returns the value of Attr + * + * @return String + */ + public String getValue() { + return value; + } + + /** + * set the attr + * + * @param attr attribute of the query + */ + public void setAttr(String attr) { + this.attr = attr; + } + + /** + * set the Response type whether it's peer, or group discovery + * + * @param type type of discovery + */ + public void setDiscoveryType(int type) { + // FIXME 20030227 bondolo@jxta.org This should be value checked. + this.type = type; + } + + /** + * set the threshold + * + * @param threshold value to be set + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * set the query + * + * @param value value of the attribute to query + */ + public void setValue(String value) { + this.value = value; + } + + /** + * All messages have a type (in xml this is !doctype) which + * identifies the message + * + * @return String "jxta:DiscoveryQuery" + */ + public static String getAdvertisementType() { + return "jxta:DiscoveryQuery"; + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/DiscoveryResponseMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/DiscoveryResponseMsg.java new file mode 100644 index 000000000..7e49fdc0f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/DiscoveryResponseMsg.java @@ -0,0 +1,379 @@ +/* + * Copyright(c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.util.*; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * This class defines the DiscoveryService message "Response".

      + * + * The default behavior of this abstract class is simply a place holder for the + * generic resolver query fields. This message is the response to the + * DiscoveryQueryMsg. + * + *@see net.jxta.discovery.DiscoveryService + *@see net.jxta.protocol.DiscoveryQueryMsg + */ +public abstract class DiscoveryResponseMsg { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(DiscoveryResponseMsg.class.getName()); + + /** + * attribute used by the query + */ + protected String attr = null; + + /** + * Responding peer's advertisement + */ + protected PeerAdvertisement peerAdvertisement = null; + + /** + * The advertisement responses serialized into strings. + */ + protected final List responses = new ArrayList(0); + + /** + * The advertisement responses deserialized. + */ + protected final List advertisements = new ArrayList(0); + + /** + * Expirations + */ + protected final List expirations = new ArrayList(0); + + /** + * Advertisement type used by the query + * + *

      FIXME 20040514 bondolo@jxta.org not a great default... + */ + protected int type = DiscoveryService.PEER; + + /** + * Value used by the query + */ + protected String value = null; + + /** + * All messages have a type(in xml this is !doctype) which identifies the + * message + * + * @return String "jxta:ResolverResponse" + */ + public static String getAdvertisementType() { + return "jxta:DiscoveryResponse"; + } + + /** + * Get the response type + * + * @return int type of discovery message PEER, GROUP or ADV discovery type + * response + */ + public int getDiscoveryType() { + return type; + } + + /** + * set the Response type whether it's peer, or group discovery + * + * @param type int representing the type + */ + public void setDiscoveryType(int type) { + this.type = type; + } + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out and "text/xml" which + * provides an XML format. + * + * @param asMimeType mime-type requested + * @return Document document that represents the advertisement + */ + + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * returns the responding peer's advertisement + * + * @return the Peer's advertisement + */ + public PeerAdvertisement getPeerAdvertisement() { + return peerAdvertisement; + } + + /** + * Sets the responding peer's advertisement + * + * @param newAdv the responding Peer's advertisement + */ + public void setPeerAdvertisement(PeerAdvertisement newAdv) { + peerAdvertisement = newAdv; + } + + /** + * returns the attributes used by the query + * + * @return String attribute of the query + */ + public String getQueryAttr() { + return attr; + } + + /** + * returns the value used by the query + * + *@return String value used by the query + */ + public String getQueryValue() { + return value; + } + + /** + * Get the response count + * + * @return int count + */ + public int getResponseCount() { + if (expirations.isEmpty() && (peerAdvertisement != null) && (type == DiscoveryService.PEER)) { + return 1; + } else { + return responses.size(); + } + } + + /** + * Gets the expirations attribute of the DiscoveryResponseMsg object + * + * @return The expirations value + */ + public Enumeration getExpirations() { + if (expirations.isEmpty() && (peerAdvertisement != null) && (type == DiscoveryService.PEER)) { + // this takes care of the case where the only response is the peerAdv + expirations.add(DiscoveryService.DEFAULT_EXPIRATION); + } + + return Collections.enumeration(expirations); + } + + /** + * set the expirations for this query + * + * @param expirations the expirations for this query + */ + public void setExpirations(List expirations) { + this.expirations.clear(); + this.expirations.addAll(expirations); + } + + /** + * returns the response(s) + * + * @return Enumeration of String responses + */ + public Enumeration getResponses() { + if (responses.isEmpty() && (peerAdvertisement != null) && (type == DiscoveryService.PEER)) { + // this takes care of the case where the only response is the peerAdv + responses.add(peerAdvertisement.toString()); + } + + return Collections.enumeration(responses); + } + + /** + * Set the responses to the query. The responses may be either + * {@code Advertisement}, {@code String} or {@code InputStream}. + * + * @param responses List of responses + */ + public void setResponses(List responses) { + this.responses.clear(); + + for (Object response : responses) { + if (response instanceof Advertisement) { + this.responses.add(((Advertisement) response).getDocument(MimeMediaType.XMLUTF8).toString()); + } else if (response instanceof String) { + this.responses.add((String) response); + } else if (response instanceof InputStream) { + String result = streamToString((InputStream) response); + + if (null != result) { + this.responses.add(result); + } + } else { + throw new IllegalArgumentException("Non-String or InputStream response recevied."); + } + } + } + + /** + * Reads in a stream into a string + * + * @param is inputstream + * @return string representation of a stream + */ + private String streamToString(InputStream is) { + Reader reader = null; + + try { + reader = new InputStreamReader(is, "UTF-8"); + } catch (UnsupportedEncodingException impossible) { + throw new Error("UTF-8 encoding not supported?!?"); + } + + StringBuilder stw = new StringBuilder(); + char[] buf = new char[512]; + + try { + do { + int c = reader.read(buf); + + if (c == -1) { + break; + } + stw.append(buf, 0, c); + } while (true); + } catch (IOException ie) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Got an Exception during stream conversion", ie); + } + return null; + } finally { + try { + is.close(); + } catch (IOException ignored) {} + } + + return stw.toString(); + } + + /** + * Set the attribute used by the query + * + * @param attr query attribute + */ + public void setQueryAttr(String attr) { + this.attr = attr; + } + + /** + * Set the value used by the query + * + * @param value Query value + */ + public void setQueryValue(String value) { + this.value = value; + } + + /** + * Get the responses to the query as advertisements. + * + * @return The response advertisements. + */ + public Enumeration getAdvertisements() { + if (responses.isEmpty() && (peerAdvertisement != null) && (type == DiscoveryService.PEER)) { + // this takes care of the case where the only response is the peerAdv + return Collections.enumeration(Collections.singletonList((Advertisement) peerAdvertisement)); + } + + if (advertisements.isEmpty() && !responses.isEmpty()) { + // Convert the responses. + for (String aResponse : responses) { + try { + XMLDocument anXMLDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8 + , + new StringReader(aResponse)); + Advertisement anAdv = AdvertisementFactory.newAdvertisement(anXMLDoc); + + advertisements.add(anAdv); + } catch (IOException badAdvertisement) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Invalid response in message : ", badAdvertisement); + } + } + } + } + + return Collections.enumeration(advertisements); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleClassAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleClassAdvertisement.java new file mode 100644 index 000000000..1934ecfed --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleClassAdvertisement.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.id.ID; +import net.jxta.platform.ModuleClassID; + + +/** + * Formally documents the existence of a module class (identified by the + * {@link net.jxta.platform.ModuleClassID} and may provide additional + * descriptive metadata about the Module Class. + * + * @see net.jxta.platform.ModuleClassID + */ +public abstract class ModuleClassAdvertisement extends ExtendableAdvertisement implements Cloneable { + + /** + * The module class id associated with the is advertisement. + */ + private ModuleClassID id = null; + + /** + * Informal, non-canonical name of module. + */ + private String name = null; + + /** + * Descriptive meta-data about this module. + */ + private Element description = null; + + /** + * Returns the identifying type of this Advertisement. + * + * @return The type of advertisement. + */ + public static String getAdvertisementType() { + return "jxta:MCA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ModuleClassAdvertisement clone() { + try { + ModuleClassAdvertisement clone = (ModuleClassAdvertisement) super.clone(); + + clone.setModuleClassID(getModuleClassID()); + clone.setName(getName()); + clone.setDesc(description); + + return clone; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + return id; + } + + /** + * returns the name of the class + * + * @return String name of the class + */ + public String getName() { + return name; + } + + /** + * sets the name of the class + * + * @param name name of the class to be set + * + */ + public void setName(String name) { + this.name = name; + } + + /** + * returns the description + * + * @return String the description + */ + public String getDescription() { + if (null != description) { + return (String) description.getValue(); + } else { + return null; + } + } + + /** + * sets the description + * + * @param description the description + */ + public void setDescription(String description) { + + if (null != description) { + StructuredDocument newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Desc", description); + + setDesc(newdoc); + } else { + this.description = null; + } + } + + /** + * returns the description + * + * @return the description + */ + public StructuredDocument getDesc() { + if (null != description) { + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(description); + + return newDoc; + } else { + return null; + } + } + + /** + * sets the description + * + * @param desc the description + */ + public void setDesc(Element desc) { + + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } + + /** + * returns the id of the class + * + * @return ModuleClassID the class id + */ + public ModuleClassID getModuleClassID() { + return id; + } + + /** + * sets the id of the class + * + * @param id The id of the class + */ + public void setModuleClassID(ModuleClassID id) { + this.id = id; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleImplAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleImplAdvertisement.java new file mode 100644 index 000000000..15f7e936c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleImplAdvertisement.java @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.id.ID; +import net.jxta.platform.ModuleSpecID; + + +/** + * A ModuleImplAdvertisement describes one of any number of published + * implementations for a given specification. + *

      + * Module specifications are referenced by their ModuleSpecID. Given a + * ModuleSpecID, a ModuleImplAdvertisement may be searched by means of JXTA + * Discovery, filtered according to the compatibility statement it contains, + * and if compatible, loaded and initialized. The {@code loadModule()} method of + * PeerGroup performs this task automatically, given a ModuleSpecID. + *

      + * One significant example of Modules referenced and loaded in that manner are + * the services and protocols that constitute a StdPeerGroup in the Java + * reference implementation. + * + * @see net.jxta.id.ID + * @see net.jxta.platform.ModuleSpecID + * @see net.jxta.document.Advertisement + * @see net.jxta.document.StructuredDocument + * @see net.jxta.document.Element + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see net.jxta.peergroup.PeerGroup + */ +public abstract class ModuleImplAdvertisement extends ExtendableAdvertisement implements Cloneable { + + private ModuleSpecID msid = null; + private StructuredDocument description = null; + private StructuredDocument compat = null; + private String code = null; + private String uri = null; + private String provider = null; + private StructuredDocument param = null; + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:MIA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * Clone this ModuleImplAdvertisement + */ + @Override + public ModuleImplAdvertisement clone() { + + try { + ModuleImplAdvertisement clone = (ModuleImplAdvertisement) super.clone(); + + clone.setModuleSpecID(getModuleSpecID()); + clone.setDesc(getDescPriv()); + clone.setCompat(getCompatPriv()); + clone.setCode(getCode()); + clone.setUri(getUri()); + clone.setProvider(getProvider()); + clone.setParam(getParamPriv()); + + return clone; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * Returns the unique ID of that advertisement for indexing purposes. + * In that case we do not have any particular one to offer. Let the indexer + * hash the document. + * + * @return ID the unique id + */ + @Override + public ID getID() { + return null; + } + + /** + * Returns the id of the spec that this implements. + * @return ID the spec id + * + */ + public ModuleSpecID getModuleSpecID() { + return msid; + } + + /** + * Sets the id of the spec that is implemented + * + * @param msid The id of the spec + */ + public void setModuleSpecID(ModuleSpecID msid) { + this.msid = msid; + } + + /** + * returns the description + * + * @return String the description + */ + public String getDescription() { + if (null != description) { + return (String) description.getValue(); + } else { + return null; + } + } + + /** + * sets the description + * + * @param description the description + */ + public void setDescription(String description) { + + if (null != description) { + StructuredDocument newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Desc", description); + + setDesc(newdoc); + } else { + this.description = null; + } + } + + /** + * returns the description + * + * @return the description + */ + public StructuredDocument getDesc() { + if (null != description) { + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(description); + + return newDoc; + } else { + return null; + } + } + + /** + * Privileged version of {@link #getDesc()} that does not clone the elements. + * + * @return the description + */ + public StructuredDocument getDescPriv() { + return description; + } + + /** + * sets the description + * + * @param desc the description + */ + public void setDesc(Element desc) { + + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } + + /** + * Returns the opaque compatibility statement for this advertisement. Each + * JXTA implementation has the ability to recognize and evaluate it's own + * compatibility statements (even though it may not be able to evaluate the + * compatibility statements of other implementations). + * + * @return The compatibility statement as a StructuredDocument of + * unspecified content. + */ + public StructuredDocument getCompat() { + return (compat == null ? null : StructuredDocumentUtils.copyAsDocument(compat)); + } + + /** + * Privileged version of {@link #getCompat()} that does not clone the elements. + * + * @return The compatibility statement as a StructuredDocument of + * unspecified content. + */ + protected StructuredDocument getCompatPriv() { + return compat; + } + + /** + * Sets the module impl. compatibility statement. + * + * @param compat Element of an unspecified content. + */ + public void setCompat(Element compat) { + this.compat = (compat == null ? null : StructuredDocumentUtils.copyAsDocument(compat)); + } + + /** + * returns the code; a reference to or representation of the executable code + * advertised by this advertisement. + *

      + * The appropriate interpretation of the code value is dependant upon the + * compatibility statement. Any compatible consumer of this advertisement + * will be able to correctly interpret code value. The standard group + * implementations of the JXSE reference implementation expect it to be a + * reference to a jar file. + * + * @return A reference to the executable code described by this + * advertisement. + */ + public String getCode() { + return code; + } + + /** + * Sets the reference for the executable code described by this + * advertisement. + * + * @param code A reference to the executable code described by this + * advertisement. + */ + public void setCode(String code) { + this.code = code; + } + + /** + * returns the uri; that is a reference to or representation of a package + * from which the executable code referenced by the getCode method may be + * loaded. + *

      + * The appropriate interpretation of the URI value is dependant upon the + * compatibility statement. Any compatible consumer of this advertisement + * will be able to correctly interpret the URI value. The standard group + * implementations of the JXSE reference implementation expect it to be a + * reference to a jar file. + * + * @return Location URI for the code described by this advertisement. + */ + public String getUri() { + return uri; + } + + /** + * Sets the uri + * + * @param uri Location URI for the code described by this advertisement. + */ + public void setUri(String uri) { + this.uri = uri; + } + + /** + * returns the provider + * + * @return String the provider + */ + public String getProvider() { + return provider; + } + + /** + * sets the provider + * + * @param provider the provider + */ + public void setProvider(String provider) { + this.provider = provider; + } + + /** + * returns the param element. + * + * The interpretation of the param element is entirely up to the code + * that this advertises. One valid use of it is to enable the code to + * be configured so that multiple specs or multiple implementations of + * one spec may use the same code. + * + * @return A standalone structured document of unspecified content. + */ + public StructuredDocument getParam() { + return (param == null ? null : StructuredDocumentUtils.copyAsDocument(param)); + } + + /** + * Privileged version of {@link #getParam()} that does not clone the elements. + * + * @return A standalone structured document of unspecified content. + */ + protected StructuredDocument getParamPriv() { + return param; + } + + /** + * Sets the module param + * + * @param param Element of an unspecified content. + */ + public void setParam(Element param) { + this.param = (param == null ? null : StructuredDocumentUtils.copyAsDocument(param)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleSpecAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleSpecAdvertisement.java new file mode 100644 index 000000000..5b9120841 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ModuleSpecAdvertisement.java @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.id.ID; +import net.jxta.platform.ModuleSpecID; + + +/** + * Provides the references that describe a module specification. Typically this + * includes references to the documentation needed in order to create conforming + * implementations of the specification. A secondary use is, optionally, to make + * running instances usable remotely, by publishing any or all of the following: + *

        + *
      • PipeAdvertisement + *
      • ModuleSpecID of a proxy module + *
      • ModuleSpecID of an authenticator module + *
      + *

      + * Not all modules are usable remotely, it is up to the specification creator to + * make that choice. However, if the specification dictates it, all + * implementations can be expected to support it. + *

      + * Note that the Standard PeerGroup implementation included with the JXSE + * reference implementation does not support replacing a group service + * with a pipe to a remote instance. However, nothing prevents a particular + * implementation of a group from using a proxy module in place of the fully + * version; provided that the API (and therefore the ClassIDs) of the proxy and + * local versions are identical. + *

      + * Note also that in the case of the local+proxy style, it is up to the + * implementation of both sides to figure-out which pipe to listen to or connect + * to. The safest method is probably for the full version to seek its own + * ModuleSpecAdvertisement, and for the proxy version to accept the full + * version's ModuleSpecAdvertisement as a parameter. Alternatively, if the proxy + * version is completely dedicated to the specification that it proxies, both + * sides may have the PipeID and type hard-coded. + * + * @see net.jxta.platform.ModuleSpecID + * @see net.jxta.protocol.PipeAdvertisement + * @see net.jxta.protocol.ModuleClassAdvertisement + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see net.jxta.document.Advertisement + */ +public abstract class ModuleSpecAdvertisement extends ExtendableAdvertisement implements Cloneable { + + private ModuleSpecID id = null; + private String name = null; + private Element description = null; + private String creator = null; + private String uri = null; + private String version = null; + private PipeAdvertisement pipeAdv = null; + private ModuleSpecID proxySpecID = null; + private ModuleSpecID authSpecID = null; + private StructuredDocument param = null; + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + **/ + public static String getAdvertisementType() { + return "jxta:MSA"; + } + + /** + * {@inheritDoc} + **/ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + **/ + @Override + public ModuleSpecAdvertisement clone() { + try { + ModuleSpecAdvertisement clone = (ModuleSpecAdvertisement) super.clone(); + + clone.setModuleSpecID(getModuleSpecID()); + clone.setName(getName()); + clone.setDesc(getDesc()); + clone.setCreator(getCreator()); + clone.setSpecURI(getSpecURI()); + clone.setVersion(getVersion()); + clone.setPipeAdvertisement(getPipeAdvertisement()); + clone.setProxySpecID(getProxySpecID()); + clone.setAuthSpecID(getAuthSpecID()); + clone.setParam(param); + + return clone; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * returns a unique id for that adv for the purpose of indexing. + * The spec id uniquely identifies this advertisement. + * + * @return ID the spec id as a basic ID. + * + */ + @Override + public ID getID() { + return id; + } + + /** + * returns the id of the spec + * + * @return ModuleSpecID the spec id + **/ + public ModuleSpecID getModuleSpecID() { + return id; + } + + /** + * sets the id of the spec + * + * @param id The id of the spec + **/ + public void setModuleSpecID(ModuleSpecID id) { + this.id = id; + } + + /** + * returns the name of the module spec + * + * @return String name of the module spec + **/ + public String getName() { + return name; + } + + /** + * sets the name of the module spec + * + * @param name name of the module spec to be set + **/ + public void setName(String name) { + this.name = name; + } + + /** + * returns the description + * + * @return String the description + **/ + public String getDescription() { + if (null != description) { + return (String) description.getValue(); + } else { + return null; + } + } + + /** + * sets the description + * + * @param description the description + **/ + public void setDescription(String description) { + + if (null != description) { + StructuredDocument newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Desc", description); + + setDesc(newdoc); + } else { + this.description = null; + } + } + + /** + * returns the description + * + * @return the description + **/ + public StructuredDocument getDesc() { + if (null != description) { + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(description); + + return newDoc; + } else { + return null; + } + } + + /** + * sets the description + * + * @param desc the description + **/ + public void setDesc(Element desc) { + + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } + + /** + * Returns the creator of the module spec, in case someone cares. + * + * @return String the creator. + **/ + public String getCreator() { + return creator; + } + + /** + * Sets the creator of this module spec. + * Note: the usefulness of this is unclear. + * + * @param creator name of the creator of the module + **/ + public void setCreator(String creator) { + this.creator = creator; + } + + /** + * returns the uri. This uri normally points at the actual specification + * that this advertises. + * + * @return String uri + **/ + public String getSpecURI() { + return uri; + } + + /** + * sets the uri + * + * @param uri string uri + **/ + public void setSpecURI(String uri) { + this.uri = uri; + } + + /** + * returns the specification version number + * + * @return String version number + **/ + public String getVersion() { + return version; + } + + /** + * sets the version of the module + * + * @param version version number + **/ + public void setVersion(String version) { + this.version = version; + } + + /** + * returns the param element. + * + * @return Element parameters as an Element of unspecified content. + **/ + public StructuredDocument getParam() { + return (param == null ? null : StructuredDocumentUtils.copyAsDocument(param)); + } + + /** + * Privileged version of {@link #getParam()} that does not clone the elements. + * + * @return StructuredDocument A stand-alone structured document of + * unspecified content. + **/ + protected StructuredDocument getParamPriv() { + return param; + } + + /** + * sets the param element. + * + * @param param Element of an unspecified content. + **/ + public void setParam(Element param) { + this.param = (param == null ? null : StructuredDocumentUtils.copyAsDocument(param)); + } + + /** + * returns the embedded pipe advertisement if any. + * + * @return PipeAdvertisement the Pipe Advertisement. null if none exists. + **/ + public PipeAdvertisement getPipeAdvertisement() { + return (pipeAdv == null ? null : pipeAdv.clone()); + } + + /** + * sets an embedded pipe advertisement. + * + * @param pipeAdv the Pipe Advertisement. null is authorized. + **/ + public void setPipeAdvertisement(PipeAdvertisement pipeAdv) { + this.pipeAdv = (pipeAdv == null ? null : pipeAdv.clone()); + } + + /** + * returns the specID of a proxy module. + * + * @return ModuleSpecID the spec id + **/ + public ModuleSpecID getProxySpecID() { + return proxySpecID; + } + + /** + * sets a proxy module specID + * + * @param proxySpecID The spec id + **/ + public void setProxySpecID(ModuleSpecID proxySpecID) { + this.proxySpecID = proxySpecID; + } + + /** + * returns the specID of an authenticator module. + * + * @return ModuleSpecID the spec id + **/ + public ModuleSpecID getAuthSpecID() { + return authSpecID; + } + + /** + * sets an authenticator module specID + * + * @param authSpecID The spec id + **/ + public void setAuthSpecID(ModuleSpecID authSpecID) { + this.authSpecID = authSpecID; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerAdvertisement.java new file mode 100644 index 000000000..9ffc16bcf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerAdvertisement.java @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import java.io.ByteArrayInputStream; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; + + +/** + * Generated when instantiating a group on a peer and contains all the + * parameters that services need to publish. It is then published within the + * group. + */ +public abstract class PeerAdvertisement extends ExtendableAdvertisement implements Cloneable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(PeerAdvertisement.class.getName()); + + /** + * The id of this peer. + */ + private PeerID pid = null; + + /** + * The group in which this peer is located. + */ + private PeerGroupID gid = null; + + /** + * The name of this peer. Not guaranteed to be unique in any way. May be empty or + * null. + */ + private String name = null; + + /** + * Descriptive meta-data about this peer. + */ + private Element description = null; + + /** + * A table of structured documents to be interpreted by each service. + */ + private final Map serviceParams = new HashMap(); + + /** + * Counts the changes made to this object. We rely on implementations to + * increment modCount every time something is changed without going through + * the API. + */ + private final transient AtomicInteger modCount = new AtomicInteger(0); + + /** + * Returns the number of times this object has been modified since + * it was created. This permits to detection of local changes that require + * refreshing of other data which depends upon the peer advertisement. + * + * @return int the current modification count. + */ + + public int getModCount() { + return modCount.get(); + } + + /** + * Increments the modification count for this peer advertisement. + */ + protected int incModCount() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + Throwable trace = new Throwable("Stack Trace"); + StackTraceElement elements[] = trace.getStackTrace(); + + LOG.finer("Modification #" + (getModCount() + 1) + " to PeerAdv@" + Integer.toHexString(System.identityHashCode(this)) + + " caused by : " + "\n\t" + elements[1] + "\n\t" + elements[2]); + } + + return modCount.incrementAndGet(); + } + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:PA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public PeerAdvertisement clone() { + + try { + PeerAdvertisement clone = (PeerAdvertisement) super.clone(); + + clone.setPeerID(getPeerID()); + clone.setPeerGroupID(getPeerGroupID()); + clone.setName(getName()); + clone.setDesc(getDesc()); + clone.setServiceParams(getServiceParams()); + + return clone; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * returns the name of the peer. + * + * @return String name of the peer. + */ + + public String getName() { + return name; + } + + /** + * sets the name of the peer. + * + * @param name name of the peer. + */ + + public void setName(String name) { + this.name = name; + incModCount(); + } + + /** + * Returns the id of the peer. + * + * @return PeerID the peer id + */ + + public PeerID getPeerID() { + return pid; + } + + /** + * Sets the id of the peer. + * + * @param pid the id of this peer. + */ + + public void setPeerID(PeerID pid) { + this.pid = pid; + incModCount(); + } + + /** + * Returns the id of the peergroup this peer advertisement is for. + * + * @return PeerGroupID the peergroup id + */ + + public PeerGroupID getPeerGroupID() { + return gid; + } + + /** + * Returns the id of the peergroup this peer advertisement is for. + * + * @param gid The id of the peer. + */ + + public void setPeerGroupID(PeerGroupID gid) { + this.gid = gid; + incModCount(); + } + + /** + * Returns a unique ID for that peer X group intersection. This is for + * indexing purposes only. + * + * @return ID the unique ID + */ + @Override + public ID getID() { + // If it is incomplete, there's no meaningful ID that we can return. + if (gid == null || pid == null) { + return null; + } + + try { + String hashValue = getAdvertisementType() + gid.getUniqueValue().toString() + pid.getUniqueValue().toString(); + byte[] seed = hashValue.getBytes("UTF-8"); + + return IDFactory.newCodatID(gid, seed, new ByteArrayInputStream(seed)); + } catch (Exception failed) { + return null; + } + } + + /** + * returns the description + * + * @return String the description + */ + public String getDescription() { + if (null != description) { + return (String) description.getValue(); + } else { + return null; + } + } + + /** + * sets the description + * + * @param description the description + * @since JXTA 1.0 + */ + public void setDescription(String description) { + + if (null != description) { + StructuredDocument newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Desc", description); + + setDesc(newdoc); + } else { + this.description = null; + } + + incModCount(); + } + + /** + * returns the description + * + * @return the description + */ + public StructuredDocument getDesc() { + if (null != description) { + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(description); + + return newDoc; + } else { + return null; + } + } + + /** + * sets the description + * + * @param desc the description + */ + public void setDesc(Element desc) { + + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + + incModCount(); + } + + /** + * sets the sets of parameters for all services. This method first makes a + * deep copy, in order to protect the active information from uncontrolled + * sharing. This quite an expensive operation. If only a few of the + * parameters need to be added, it is wise to use putServiceParam() + * instead. + * + * @param params The whole set of parameters. + */ + public void setServiceParams(Hashtable params) { + serviceParams.clear(); + + if (params == null) { + return; + } + + for (Map.Entry anEntry : params.entrySet()) { + Element e = anEntry.getValue(); + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(e); + + serviceParams.put(anEntry.getKey(), newDoc); + } + + incModCount(); + } + + /** + * Returns the sets of parameters for all services. + * + *

      This method returns a deep copy, in order to protect the real + * information from uncontrolled sharing while keeping it shared as long as + * it is safe. This quite an expensive operation. If only a few parameters + * need to be accessed, it is wise to use getServiceParam() instead. + * + * @return all of the parameters. + */ + public Hashtable getServiceParams() { + Hashtable copy = new Hashtable(); + + for (Map.Entry anEntry : serviceParams.entrySet()) { + Element e = anEntry.getValue(); + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(e); + + copy.put(anEntry.getKey(), newDoc); + } + + return copy; + } + + /** + * Puts a service parameter in the service parameters table under the given + * key. The key is of a subclass of ID; usually a ModuleClassID. This + * method makes a deep copy of the given element into an independent + * document. + * + * @param key The key. + * @param param The parameter, as an element. What is stored is a copy as a + * standalone StructuredDocument which type is the element's name. + */ + public void putServiceParam(ID key, Element param) { + if (param == null) { + serviceParams.remove(key); + incModCount(); + return; + } + + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param); + + serviceParams.put(key, newDoc); + + incModCount(); + } + + /** + * Returns the parameter element that matches the given key from the + * service parameters table. The key is of a subclass of ID; usually a + * ModuleClassID. + * + * @param key The key. + * @return StructuredDocument The matching parameter document or null if + * none matched. The document type id "Param". + */ + public StructuredDocument getServiceParam(ID key) { + StructuredDocument param = serviceParams.get(key); + + if (param == null) { + return null; + } + + return StructuredDocumentUtils.copyAsDocument(param); + } + + /** + * Removes and returns the parameter element that matches the given key + * from the service parameters table. The key is of a subclass of ID; + * usually a ModuleClassID. + * + * @param key The key. + * @return Element the removed parameter element or null if not found. + * This is actually a StructureDocument of type "Param". + */ + public StructuredDocument removeServiceParam(ID key) { + Element param = serviceParams.remove(key); + + if (param == null) { + return null; + } + + incModCount(); + + // It sound silly to clone it, but remember that we could be sharing + // this element with a clone of ours, so we have the duty to still + // protect it. + + return StructuredDocumentUtils.copyAsDocument(param); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerGroupAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerGroupAdvertisement.java new file mode 100644 index 000000000..7049b0a7c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerGroupAdvertisement.java @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import java.util.Hashtable; +import java.util.Map; +import java.util.HashMap; + +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.ModuleSpecID; + + +/** + * Describes a peer group and references additional information required for + * instantiating it. The PeerGroup method newGroup performs the task of + * instantiating a PeerGroup given its advertisement (provided the required + * subsequent documents can actually be found). This advertisement is indexed + * on "Name", "GID", and "Desc" + * + * @see net.jxta.platform.ModuleSpecID + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see net.jxta.peergroup.PeerGroup + */ + +public abstract class PeerGroupAdvertisement extends ExtendableAdvertisement implements Cloneable { + + private PeerGroupID gid = null; + private ModuleSpecID specId = null; + + /** + * Informal, non-canonical name of this peer group + */ + private String name = null; + + /** + * Descriptive meta-data about this peer group. + */ + private Element description = null; + + // A table of structured documents to be interpreted by each service. + private final Map serviceParams = new HashMap(); + + /** + * Returns the identifying type of this Advertisement. + * + *@return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:PGA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * Construct a new Peer Group Advertisement. + **/ + public PeerGroupAdvertisement() {} + + /** + * {@inheritDoc} + * + *@return An object of class PeerGroupAdvertisement that is a + * deep-enough copy of this one. + */ + @Override + public PeerGroupAdvertisement clone() { + + PeerGroupAdvertisement clone; + + try { + clone = (PeerGroupAdvertisement) super.clone(); + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + + clone.setPeerGroupID(getPeerGroupID()); + clone.setModuleSpecID(getModuleSpecID()); + clone.setName(getName()); + clone.setDesc(getDesc()); + clone.setServiceParams(getServiceParams()); + + return clone; + } + + /** + * Returns the name of the group or null if no name has been + * assigned. + * + *@return String name of the group. + */ + + public String getName() { + return name; + } + + /** + * sets the name of the group. + * + *@param name name of the group. + */ + + public void setName(String name) { + this.name = name; + } + + /** + * Returns the id of the group spec that this uses. + * + *@return ID the spec id + */ + + public ModuleSpecID getModuleSpecID() { + return specId; + } + + /** + * Sets the id of the group spec that this peer group uses. + * + *@param sid The id of the spec + */ + + public void setModuleSpecID(ModuleSpecID sid) { + this.specId = sid; + } + + /** + * Returns the id of the group. + * + *@return ID the group id + */ + + public PeerGroupID getPeerGroupID() { + return gid; + } + + /** + * Sets the id of the group. + * + *@param gid The id of this group. + */ + + public void setPeerGroupID(PeerGroupID gid) { + this.gid = gid; + } + + /** + * Returns a unique ID for indexing purposes. We use the id of the group as + * a plain ID. + * + *@return ID a unique id for that advertisement. + */ + + @Override + public ID getID() { + return gid; + } + + /** + * returns the description + * + * @return String the description + */ + public String getDescription() { + if (null != description) { + return (String) description.getValue(); + } else { + return null; + } + } + + /** + * sets the description + * + * @param description the description + */ + public void setDescription(String description) { + + if (null != description) { + StructuredDocument newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Desc", description); + + setDesc(newdoc); + } else { + this.description = null; + } + } + + /** + * returns the description + * + * @return the description + */ + public StructuredDocument getDesc() { + if (null != description) { + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(description); + + return newDoc; + } else { + return null; + } + } + + /** + * sets the description + * + * @since JXTA 1.0 + * + * @param desc the description + * + */ + public void setDesc(Element desc) { + + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } + + /** + * sets the sets of parameters for all services. This method first makes a + * deep copy, in order to protect the active information from uncontrolled + * sharing. This quite an expensive operation. If only a few of the + * parameters need to be added, it is wise to use putServiceParam() + * instead. + * + *@param params The whole set of parameters. + */ + public void setServiceParams(Hashtable params) { + serviceParams.clear(); + + if (params == null) { + return; + } + + for (Map.Entry anEntry : params.entrySet()) { + Element e = anEntry.getValue(); + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(e); + + serviceParams.put(anEntry.getKey(), newDoc); + } + + } + + /** + * Returns the sets of parameters for all services. + * + *

      This method returns a deep copy, in order to protect the real + * information from uncontrolled sharing while keeping it shared as long as + * it is safe. This quite an expensive operation. If only a few parameters + * need to be accessed, it is wise to use getServiceParam() instead. + * + *@return all of the parameters. + */ + public Hashtable getServiceParams() { + Hashtable copy = new Hashtable(); + + for (Map.Entry anEntry : serviceParams.entrySet()) { + Element e = anEntry.getValue(); + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(e); + + copy.put(anEntry.getKey(), newDoc); + } + + return copy; + } + + /** + * Puts a service parameter in the service parameters table under the given + * key. The key is of a subclass of ID; usually a ModuleClassID. This + * method makes a deep copy of the given element into an independent + * document. + * + *@param key The key. + *@param param The parameter, as an element. What is stored is a copy as a + * standalone StructuredDocument which type is the element's name. + */ + public void putServiceParam(ID key, Element param) { + if (param == null) { + serviceParams.remove(key); + return; + } + + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param); + + serviceParams.put(key, newDoc); + } + + /** + * Returns the parameter element that matches the given key from the + * service parameters table. The key is of a subclass of ID; usually a + * ModuleClassID. + * + *@param key The key. + *@return StructuredDocument The matching parameter document or null if + * none matched. The document type id "Param". + */ + public StructuredDocument getServiceParam(ID key) { + StructuredDocument param = serviceParams.get(key); + + if (param == null) { + return null; + } + + return StructuredDocumentUtils.copyAsDocument(param); + } + + /** + * Removes and returns the parameter element that matches the given key + * from the service parameters table. The key is of a subclass of ID; + * usually a ModuleClassID. + * + *@param key The key. + *@return Element the removed parameter element or null if not found. + * This is actually a StructureDocument of type "Param". + */ + public StructuredDocument removeServiceParam(ID key) { + Element param = serviceParams.remove(key); + + if (param == null) { + return null; + } + + // It sound silly to clone it, but remember that we could be sharing + // this element with a clone of ours, so we have the duty to still + // protect it. + + return StructuredDocumentUtils.copyAsDocument(param); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerInfoQueryMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerInfoQueryMessage.java new file mode 100644 index 000000000..3a94ce021 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerInfoQueryMessage.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.peer.PeerID; + + +/** + * This abstract class define the PeerInfoService Query message. + * + **/ +public abstract class PeerInfoQueryMessage { + + /** + * The Sender's (or Querying) Peer Id. + */ + private PeerID spid = null; + + /** + * Peer Id of the peer which published this advertisement. + */ + private PeerID tpid = null; + + /* representing request */ + private StructuredDocument request = null; + + public PeerInfoQueryMessage() { + super(); + } + + /** + * returns the Message type + * @return a string + * + * @since JXTA 1.0 + */ + public static String getMessageType() { + return "jxta:PeerInfoQueryMessage"; + } + + /** + * returns the sender's pid + * @return a string representing the peer's id + * + * @since JXTA 1.0 + */ + public PeerID getSourcePid() { + return spid; + } + + /** + * sets the sender's pid + * @param pid a string representing a peer's id + * + * @since JXTA 1.0 + */ + public void setSourcePid(PeerID pid) { + this.spid = pid; + } + + /** + * returns the target pid + * @return a string representing the peer's id + * + * @since JXTA 1.0 + */ + public PeerID getTargetPid() { + return tpid; + } + + /** + * sets the target's pid + * @param pid a string representing a peer's id + * + * @since JXTA 1.0 + */ + public void setTargetPid(PeerID pid) { + this.tpid = pid; + } + + /** + * returns the request + * @return a structured document representing request + * + * @since JXTA 1.0 + */ + public Element getRequest() { + if (null != request) { + return StructuredDocumentUtils.copyAsDocument(request); + } else { + return null; + } + } + + /** + * sets the request + * @param request a structured document representing a peerinfo request + * + * @since JXTA 1.0 + */ + public void setRequest(Element request) { + if (null != request) { + this.request = StructuredDocumentUtils.copyAsDocument(request); + } else { + this.request = null; + } + } + + public abstract Document getDocument(MimeMediaType encodeAs); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerInfoResponseMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerInfoResponseMessage.java new file mode 100644 index 000000000..5dfa38c59 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PeerInfoResponseMessage.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.peer.PeerID; + + +/** + * This abstract class define the PeerInfoService advertisement. + */ + +public abstract class PeerInfoResponseMessage { + + /** + * The Sender's (or Querying) Peer Id. + */ + private PeerID spid = null; + + /** + * Peer Id of the peer which published this advertisement. + */ + private PeerID tpid = null; + + /** String representing response */ + private StructuredDocument response = null; + + /** + * Time in seconds since this peer was started. + */ + private long uptime = 0; + + /** + * Time in milliseconds when this peer was last polled since + * "the epoch", namely January 1, 1970, 00:00:00 GMT. + */ + private long timestamp = 0; + + public PeerInfoResponseMessage() { + super(); + } + + /** + * returns the Message type + * @return a string + * + */ + public static String getMessageType() { + return "jxta:PeerInfoResponseMessage"; + } + + /** + * returns the sender's pid + * + * @return a string representing the peer's id + * + */ + public PeerID getSourcePid() { + return spid; + } + + /** + * sets the sender's pid + * + * @param pid a string representing a peer's id + * + */ + public void setSourcePid(PeerID pid) { + this.spid = pid; + } + + /** + * returns the target pid + * + * @return a string representing the peer's id + * + */ + public PeerID getTargetPid() { + return tpid; + } + + /** + * sets the target's pid + * + * @param pid a string representing a peer's id + * + */ + public void setTargetPid(PeerID pid) { + this.tpid = pid; + } + + /** + * returns the response + * + * @return a structured document representing request + * + */ + public Element getResponse() { + if (null != response) { + return StructuredDocumentUtils.copyAsDocument(response); + } else { + return null; + } + } + + /** + * sets the request + * + * @param response a structured document representing a peerinfo request + * + */ + public void setResponse(Element response) { + if (null != response) { + this.response = StructuredDocumentUtils.copyAsDocument(response); + } else { + this.response = null; + } + } + + /** + * returns the number of milliseconds since this peer was started + * @return the number of milliseconds + * + */ + public long getUptime() { + return uptime; + } + + /** + * sets the number of milliseconds since this peer was started + * @param milliseconds the number of milliseconds since this peer was started + * + */ + public void setUptime(long milliseconds) { + this.uptime = milliseconds; + } + + /** + * returns the time when this peer was last polled + * + * @return long time in milliseconds when this peer was last polled in + * milliseconds since "the epoch", namely January 1, 1970, 00:00:00 + * GMT. + * + */ + public long getTimestamp() { + return timestamp; + } + + /** + * sets the time when this peer was last polled + * + * @param milliseconds time in milliseconds when this peer was last polled + * in milliseconds since "the epoch", namely January 1, 1970, 00:00:00 + * GMT. + * + */ + public void setTimestamp(long milliseconds) { + this.timestamp = milliseconds; + } + + public abstract Document getDocument(MimeMediaType encodeAs); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PipeAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PipeAdvertisement.java new file mode 100644 index 000000000..a1db26916 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PipeAdvertisement.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.id.ID; + + +/** + * Describes a JXTA Pipe. A pipe is described by a pipe id and by a pipe type. + * A pipe can also optionally have a name and/or a description. + * + * @see net.jxta.pipe.PipeService + * @see JXTA Protocols Specification : Pipe Binding Protocol + */ +public abstract class PipeAdvertisement extends ExtendableAdvertisement implements Cloneable { + + /** + * XML tag to store the PipeID + */ + public static final String IdTag = "Id"; + + /** + * XML tag to store the Pipe Type + */ + public static final String TypeTag = "Type"; + + /** + * XML tag to store the name of the Pipe + */ + public static final String NameTag = "Name"; + + /** + * XML tag to store the name of the Pipe + */ + public static final String descTag = "Desc"; + + private transient ID pipeId = ID.nullID; + private String type = null; + private String name = null; + + /** + * Descriptive meta-data about this pipe. + */ + private Element description = null; + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:PipeAdvertisement"; + } + + /** + * {@inheritDoc} + */ + @Override + public PipeAdvertisement clone() { + try { + PipeAdvertisement likeMe = (PipeAdvertisement) super.clone(); + + likeMe.setPipeID(getPipeID()); + likeMe.setType(getType()); + likeMe.setName(getName()); + likeMe.setDesc(getDesc()); + + return likeMe; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj instanceof PipeAdvertisement) { + PipeAdvertisement likeMe = (PipeAdvertisement) obj; + + if (!getPipeID().equals(likeMe.getPipeID())) { + return false; + } + + if (!getType().equals(likeMe.getType())) { + return false; + } + + String pipeName = getName(); + + if (pipeName == null ? likeMe.getName() != null : !pipeName.equals(likeMe.getName())) { + return false; + } + + String pipeDescription = getDescription(); + + return !(pipeDescription == null ? likeMe.getDescription() != null : pipeDescription.equals(likeMe.getDescription())); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + + int result = 17; + + result = 37 * result + getPipeID().hashCode(); + result = 37 * result + getType().hashCode(); + String pipeName = getName(); + + if (pipeName != null) { + result = 37 * result + pipeName.hashCode(); + } + String pipeDescription = getDescription(); + + if (pipeDescription != null) { + result = 37 * result + pipeDescription.hashCode(); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + * + *

      The PipeID uniquely identifies this ADV. + */ + @Override + public ID getID() { + ID result = getPipeID(); + + if (null == result) { + result = ID.nullID; + } + return result; + } + + /** + * Return the pipe ID for the pipe described by this advertisement. + * + * @return The pipe ID for the pipe described by this advertisement. + */ + public ID getPipeID() { + return pipeId; + } + + /** + * Set the pipe ID for the pipe described by this advertisement. + * + * @param pipeId The pipe ID for the pipe described by this advertisement. + */ + public void setPipeID(ID pipeId) { + this.pipeId = pipeId; + } + + /** + * Return the pipe type for the pipe described by this advertisement. + * + * @return The pipe type for the pipe described by this advertisement. + */ + public String getType() { + return type; + } + + /** + * Set the pipe type for the pipe described by this advertisement. + * + * @param type The pipe type for the pipe described by this advertisement. + */ + public void setType(String type) { + this.type = type; + } + + /** + * Return the symbolic name for the pipe described by this advertisement. + * + * @return String The symbolic name for the pipe described by this advertisement. + */ + public String getName() { + return name; + } + + /** + * Set the symbolic name for the pipe described by this advertisement. + * + * @param name The symbolic name for the pipe described by this advertisement. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the description + * + * @return String the description + */ + public String getDescription() { + if (null != description) { + return (String) description.getValue(); + } + return null; + } + + /** + * Set the description meta-data for the pipe described by this advertisement. + * + * @param description The description meta-data for the pipe described by this advertisement. + */ + public void setDescription(String description) { + + if (null != description) { + StructuredDocument newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Desc", description); + + setDesc(newdoc); + } else { + this.description = null; + } + } + + /** + * Return the description meta-data for the pipe described by this advertisement. + * + * @return The description meta-data for the pipe described by this advertisement. + */ + public StructuredDocument getDesc() { + if (null != description) { + StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(description); + + return newDoc; + } + return null; + } + + /** + * Set the description meta-data for the pipe described by this advertisement. + * + * @param desc The description meta-data for the pipe described by this advertisement. + */ + public void setDesc(Element desc) { + + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PipeResolverMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PipeResolverMessage.java new file mode 100644 index 000000000..727af617d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/PipeResolverMessage.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.id.ID; +import net.jxta.peer.PeerID; +import net.jxta.pipe.PipeID; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + + +/** + * This abstract class defines the PipeResolver Message. + *

      + *

      This message is part of the Pipe Resolver Protocol. + * + * @see net.jxta.pipe.PipeService + * @see net.jxta.protocol.PipeAdvertisement + * @see JXTA Protocols Specification : Standard JXTA Protocols + */ +public abstract class PipeResolverMessage { + + /** + * The type of message this object is communicating. + */ + private MessageType msgType = null; + + /** + * The pipe which is the subject of this message. + */ + private ID pipeid = ID.nullID; + + /** + * The type of the pipe which is the subject of this message. + */ + private String pipeType = null; + + /** + *

        + *
      • For query : The peer ids which should respond to this query.
      • + *
      • For response : The peer id on which is responding.
      • + *
      + */ + private Set peerids = new HashSet(); + + /** + * For responses, if true then this message indicates the pipe is present + * otherwise the pipe is not present. + */ + private boolean found = true; + + /** + *
        + *
      • For query : The peer advertisement of the querying peer.
      • + *
      • For response : The peer advertisement of the responding peer.
      • + *
      + */ + private PeerAdvertisement inputPeerAdv = null; + + /** + * An enumeration class for message types. + */ + public enum MessageType { + + /** + * A query message + */ + QUERY, /** + * A response message + */ ANSWER + } + + /** + * Creates a new unintialized pipe resolver message + */ + public PipeResolverMessage() { + super(); + } + + /** + * returns the Message type. This will match the XML doctype declaration. + * + * @return a string + */ + public static String getMessageType() { + return "jxta:PipeResolver"; + } + + /** + * Write message into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/plain" encodes + * the document in "pretty-print" format for human viewing and "text/xml" + * which provides an XML format. + * + * @param asMimeType MimeMediaType format representation requested + * @return Document the document to be used in the construction + */ + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * Returns whether this message is a query or a response. + * + * @return the type of this message. + */ + public MessageType getMsgType() { + return msgType; + } + + /** + * Sets the message type of this message. + * + * @param type the type this message is to be. + */ + public void setMsgType(MessageType type) { + msgType = type; + } + + /** + * Return the id of the pipe which is the subject of this message. + * + * @return the id of the pipe which is the subject of this message. + */ + public ID getPipeID() { + return pipeid; + } + + /** + * Set the id of pipe which is to be subject of this message. + * + * @param id the pipe id which is the subject of this message. + */ + public void setPipeID(ID id) { + + if (!(id instanceof PipeID)) { + throw new IllegalArgumentException("can only set to pipe ids."); + } + + pipeid = id; + } + + /** + * Return the pipe type of the pipe which is the subject of this message. + * + * @return the pipe type of the pipe which is the subject of this message. + */ + public String getPipeType() { + return pipeType; + } + + /** + * Set the pipe type of the pipe which is the subject of this message. + * + * @param type The pipe type of the pipe which is to be the subject of this + * message. + */ + public void setPipeType(String type) { + pipeType = type; + } + + // Query + + /** + * Returns a {@link java.util.Set} (possibly empty) containing the peer ids + * which should respond to this query. + * + * @return set containing the peer ids to which this peer is directed. + */ + public Set getPeerIDs() { + + return Collections.unmodifiableSet(peerids); + } + + /** + * Add a peer to the set of peers to which this query is directed. + * + * @param id the peer id to add. + */ + public void addPeerID(ID id) { + + if (!(id instanceof PeerID)) { + throw new IllegalArgumentException("can only add peer ids"); + } + + peerids.add(id); + } + + // Answer + + /** + * If true then the pipe was found ont he + * + * @return true if found + */ + public boolean isFound() { + return found; + } + + public void setFound(boolean isFound) { + found = isFound; + } + + public PeerAdvertisement getInputPeerAdv() { + return inputPeerAdv; + } + + public void setInputPeerAdv(PeerAdvertisement peerAdv) { + inputPeerAdv = peerAdv; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RdvAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RdvAdvertisement.java new file mode 100644 index 000000000..8af488304 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RdvAdvertisement.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; + + +/** + * This class defines a Rendezvous Advertisement. This advertisement is indexed + * on "RdvGroupId", "RdvPeerId", and "RdvServiceName" + */ +public abstract class RdvAdvertisement extends ExtendableAdvertisement { + + /** + * GroupID tag + */ + public final static String GroupIDTag = "RdvGroupId"; + + /** + * Name tag + */ + public final static String NameTag = "Name"; + + /** + * Rendezvous ID tag + */ + public final static String PeerIDTag = "RdvPeerId"; + + /** + * Route tage + */ + public final static String RouteTag = "RdvRoute"; + + /** + * Rendezvous service name tag + */ + public final static String ServiceNameTag = "RdvServiceName"; + + private PeerGroupID groupId = null; + + private transient ID hashID = null; + private String name = null; + private PeerID peerId = null; + private RouteAdvertisement route = null; + private String serviceName = null; + + /** + * Returns the identifying type of this Advertisement. + * + *@return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:RdvAdvertisement"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * get the group id + * + *@return String PeerGroupID + */ + public PeerGroupID getGroupID() { + return groupId; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized ID getID() { + + if (groupId == null) { + throw new IllegalStateException("cannot build ID: no group id"); + } + + if (peerId == null) { + throw new IllegalStateException("cannot build ID: no peer id"); + } + + if (serviceName == null) { + throw new IllegalStateException("cannot build ID: no Service Name"); + } + + if (hashID == null) { + try { + // We have not yet built it. Do it now + String seed = getAdvertisementType() + groupId.toString() + serviceName + peerId.toString(); + + InputStream in = new ByteArrayInputStream(seed.getBytes()); + + hashID = IDFactory.newCodatID(groupId, seed.getBytes(), in); + } catch (Exception ez) { + IllegalStateException failure = new IllegalStateException("cannot build ID"); + + failure.initCause(ez); + throw failure; + } + } + return hashID; + } + + /** + * get the symbolic name associated with the rdv + * + *@return String the name field. null is returned if no name has been + * associated with the advertisement. + */ + public String getName() { + + return name; + } + + /** + * get the rdv peer id + * + *@return PeerID + */ + public PeerID getPeerID() { + return peerId; + } + + /** + * Get the Route Adv. + * + *@return RouteAdvertisement or null if no + */ + public RouteAdvertisement getRouteAdv() { + return route; + } + + /** + * get the rdv service name + * + *@return String name + */ + public String getServiceName() { + + return serviceName; + } + + /** + * set the group Id + * + *@param id The new groupID value + */ + public void setGroupID(PeerGroupID id) { + groupId = id; + } + + /** + * set the symbolic name associated with the rdv + * + *@param n the name this rdv adv should have. + */ + public void setName(String n) { + name = n; + } + + /** + * set the peer Id + * + *@param id The new peerID value + */ + public void setPeerID(PeerID id) { + peerId = id; + } + + /** + * set the RouteAdvertisement + * + *@param route RouteAdvertisement + */ + public void setRouteAdv(RouteAdvertisement route) { + this.route = route; + } + + /** + * set the service name + * + *@param n The new serviceName value + */ + + public void setServiceName(String n) { + serviceName = n; + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverQueryMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverQueryMsg.java new file mode 100644 index 000000000..1ad545aee --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverQueryMsg.java @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + +import java.net.URI; + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.id.ID; + +/** + * Generic Resolver Service message "Query". + * + * @see net.jxta.resolver.ResolverService + * @see net.jxta.protocol.ResolverResponseMsg + * @see JXTA Protocols Specification : Peer Resolver Protocol + */ +public abstract class ResolverQueryMsg { + + /** + * credential + */ + private StructuredDocument credential = null; + + /** + * Resolver query handler + */ + private String handlername = null; + + /** + * Number of times a message has been forwarded, not propagated or walked + */ + protected int hopcount = 0; + + /** + * Resolver query + */ + private String query = null; + + /** + * Query ID of this query. Unique to the originating node only, it can be + * utilized to match queries to responses. + */ + protected int queryid = 0; + + /** + * issuer of the query + */ + private ID srcPeerId = null; + + /** + * Optional route info about the issuer + */ + private RouteAdvertisement srcPeerRoute = null; + + /** + * returns the credential + * + * @return String credential + */ + public StructuredDocument getCredential() { + return credential; + } + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. 'text/text' encodes + * the document in a form nice for printing out and 'text/xml' which + * provides an XML format. + * + * @param asMimeType mime-type requested representation for the returned + * document + * @return Document document representing the advertisement + */ + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * returns the handlername + * + * @return String handlername name + */ + public String getHandlerName() { + return handlername; + } + + /** + * returns the hop count + * + * @return int hop count + */ + public int getHopCount() { + return hopcount; + } + + /** + * increment hop count + */ + public void incrementHopCount() { + hopcount++; + } + + /** + * Set hop count + * + * @param newCount hop count + */ + public void setHopCount(int newCount) { + hopcount = newCount; + } + + /** + * returns the query + * + * @return String value of the query + */ + public String getQuery() { + return query; + } + + /** + * returns queryid value + * + * @return int queryid value + */ + public int getQueryId() { + return queryid; + } + + /** + * Returns the source of the query + * + * @return String the peerid of the source of the query + * @deprecated Use {@link #getSrcPeer()} instead. + */ + @Deprecated + public String getSrc() { + return (null == srcPeerId) ? null : srcPeerId.toString(); + } + + /** + * Returns the source of the query + * + * @return The peerid of the source of the query + */ + public ID getSrcPeer() { + return (null == srcPeerId) ? null : srcPeerId; + } + + /** + * Returns the source route of the query + * + * @return RouteAdvertisement route to the issuer of the query + */ + + public RouteAdvertisement getSrcPeerRoute() { + if (srcPeerRoute == null) { + return null; + } else { + return srcPeerRoute.clone(); + } + } + + /** + * set the credential + * + * @param cred string representing credential + */ + public void setCredential(StructuredDocument cred) { + this.credential = cred; + } + + /** + * set the handlername + * + * @param name handler name + */ + public void setHandlerName(String name) { + this.handlername = name; + } + + /** + * set the Query string + * + * @param Query string representing the query + */ + public void setQuery(String Query) { + this.query = Query; + } + + /** + * set the query id. Each query has a unique id. + * + * @param id int id + */ + public void setQueryId(int id) { + queryid = id; + } + + /** + * set the source route of the query + * + * @param route route advertisement of the source peer + */ + public void setSrcPeerRoute(RouteAdvertisement route) { + srcPeerRoute = route; + } + + /** + * Set the source of the query + * + * @param src is a containing the peerid of the source + * @deprecated Use {@link #setSrcPeer(ID)} instead. + */ + @Deprecated + public void setSrc(String src) { + if (null == src) { + setSrcPeer(null); + } else { + setSrcPeer(ID.create(URI.create(src))); + } + } + + /** + * Set the source of the query + * + * @param srcPeer the peerid of the source + */ + public void setSrcPeer(ID srcPeer) { + srcPeerId = srcPeer; + } + + /** + * All messages have a type (in xml this is !doctype) which identifies the + * message + * + * @return String "jxta:ResolverQuery" + */ + public static String getAdvertisementType() { + return "jxta:ResolverQuery"; + } + + /** + * Create a ResolverResponse from a ResolverQuery message. This method + * takes advantage of any internal information available in an incoming + * Resolver query to build a resolver response for that query. For instance, + * optional route information which may be available in the query will + * be used to bypass the route resolution to send the response. + *

      + * WARNING: A side effect of this call is that the following fields are + * transfered from the query to the response: + * - HandlerName + * - QueryId + * + * @return ResolverResponseMsg resolverResponse built from the resolverQuery msg + */ + public abstract ResolverResponseMsg makeResponse(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverResponseMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverResponseMsg.java new file mode 100644 index 000000000..2eb7734fa --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverResponseMsg.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; + + +/** + * Generic Resolver Service message "Response". + * + * @see net.jxta.resolver.ResolverService + *@see net.jxta.protocol.ResolverQueryMsg + * @see JXTA Protocols Specification : Peer Resolver Protocol + **/ +public abstract class ResolverResponseMsg { + private StructuredDocument credential = null; + + private String handlername = null; + + /** + * Description of the Field + */ + public int queryid = 0; + + private String response = null; + + /** + * returns the credential + * + *@return StructuredDocument credential + */ + public StructuredDocument getCredential() { + return credential; + } + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out and "text/xml" which + * provides an XML format. + * + *@param asMimeType mime-type representation requested for that document + *@return Document document representing the advertisement + */ + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * Set optional route information as part of the response. This + * information is just attached to the response and is ONLY used by the + * resolver service. This information will not be sent as part of the + * response msg and is not part of the resolver response wire format + * protocol. + * + * @param route RouteAdvertisement to send the response + */ + public abstract void setSrcPeerRoute(RouteAdvertisement route); + + /** + * Get optional route information that may be attached to the + * response. This information is just attached to the response and + * is only used internally by the resolver service. This information will + * not be sent as part of the response msg and is not part of the + * resolver response wire format. + * + * @return RouteAdvertisement to send the response + */ + public abstract RouteAdvertisement getSrcPeerRoute(); + + /** + * returns the handlername + * + *@return String handlername name + */ + public String getHandlerName() { + return handlername; + } + + /** + * returns queryid value + * + *@return int queryid value + */ + public int getQueryId() { + return queryid; + } + + /** + * returns the response body for this message. + * + *@return the response body represented as a string. + */ + public String getResponse() { + return response; + } + + /** + * set the credential for this response. + * + *@param cred string credential + */ + + public void setCredential(StructuredDocument cred) { + this.credential = cred; + } + + /** + * set the handlername + * + *@param name string handlername + */ + public void setHandlerName(String name) { + this.handlername = name; + } + + /** + * set the query id to which this message is a response. + * + *@param id the query id for this response. + */ + public void setQueryId(int id) { + this.queryid = id; + } + + /** + * Set the response body for this message. + * + *@param response response body as a string. + */ + public void setResponse(String response) { + this.response = response; + } + + /** + * All messages have a type (in xml this is !doctype) which identifies the + * message + * + *@return String type of the advertisement + */ + public static String getAdvertisementType() { + return "jxta:ResolverResponse"; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverSrdiMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverSrdiMsg.java new file mode 100644 index 000000000..ea12ce67a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/ResolverSrdiMsg.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.credential.Credential; + + +/** + * ResolverSrdiMsg is generic resolver wrapper for Services that wish to + * implement their own distribution of indices. this message provides the + * scoping within the group, and service. In addition it also defines a credential + * which should be verified by the service. + */ + +public abstract class ResolverSrdiMsg { + + private String handlername = null; + private Credential credential = null; + private String payload = null; + + /** + * All messages have a type (in xml this is !doctype) + * which identifies the message + * + * @return String type of the advertisement + */ + + public static String getMessageType() { + return "jxta:ResolverSRDI"; + } + + /** + * returns the handlername + * + * @return String handlername name + * + */ + + public String getHandlerName() { + return handlername; + } + + /** + * returns the credential + * + * @return StructuredDocument credential + */ + + public Credential getCredential() { + return credential; + } + + /** + * returns the payload + * + * @return String value of query + */ + + public String getPayload() { + return payload; + } + + /** + * set the handlername + * + * @param name string handlername + */ + + public void setHandlerName(String name) { + this.handlername = name; + } + + /** + * set the credential object + * + * @param cred credential + */ + + public void setCredential(Credential cred) { + this.credential = cred; + } + + /** + * set the SRDI payload + * + * @param payload The new payload value + */ + + public void setPayload(String payload) { + this.payload = payload; + } + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out and "text/xml" which + * provides an XML format. + * + * @param asMimeType mime-type representation requested for that document + * @return Document document representing the advertisement + */ + + public abstract Document getDocument(MimeMediaType asMimeType); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteAdvertisement.java new file mode 100644 index 000000000..6748e78cd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteAdvertisement.java @@ -0,0 +1,859 @@ +/* +Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import java.util.Vector; + +/** + * Advertisement used to represent a route to a peer. Routes are represented in + * a generic manner as a sequence of hops to reach the destination. Each hop + * represent a potential relay peer in the route: + *

      + *

       Dest
      + *       hop 1
      + *       hop 2
      + *       hop 3
      + *       ....
      + *       hop n
      + * 
      + *

      + * A route can have as many hops as necessary. Hops are implicitly ordered + * starting from the hop with the shortest route to reach the destination. If a + * peer cannot reach directly the dest, it should try to reach in descending + * order one of the listed hops. Some hops may have the same physical distance + * to the destination. Some hops may define alternative routes. + *

      + * The destination and hops are defined using a AccessPointAdvertisements. + * + * @see net.jxta.protocol.PeerAdvertisement + * @see net.jxta.protocol.AccessPointAdvertisement + */ +public abstract class RouteAdvertisement extends ExtendableAdvertisement implements Cloneable { + + public static final String DEST_PID_TAG = "DstPID"; + + /** + * AccessPointAdvertisement of destination peer. + */ + private transient AccessPointAdvertisement dest = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + /** + * Semi-ordered list of alternative hops to the destination. + */ + private transient Vector hops = new Vector(); + + /** + * Cached value for {@link #getID()} + */ + private transient ID hashID = null; + + /** + * construct a new route + *

      + * WARNING hops may be MODIFIED. + * + * @param destPid destination + * @param firsthop first hop node ID + * @param hops routes + * @return the new route + */ + public static RouteAdvertisement newRoute(PeerID destPid, PeerID firsthop, Vector hops) { + + if (destPid == null) { + throw new IllegalArgumentException("Missing destination peer id."); + } + + for (AccessPointAdvertisement apa : hops) { + if (null == apa) { + throw new IllegalArgumentException("Bad route. null APA."); + } + + if (apa.getPeerID() == null) { + throw new IllegalArgumentException("Bad route. Incomplete APA."); + } + } + + RouteAdvertisement route = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + route.setDestPeerID(destPid); + + // set the route hops + route.setHops(hops); + + // check if the given first hop is already in the route if not add it + // (note: we do not expect it to be there, but it is acceptable). + if (firsthop != null) { + AccessPointAdvertisement ap = route.getFirstHop(); + + if (ap == null || !ap.getPeerID().equals(firsthop)) { + ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + ap.setPeerID(firsthop); + route.setFirstHop(ap); + } + } + + return route; + } + + /** + * {@inheritDoc} + */ + @Override + public RouteAdvertisement clone() { + try { + RouteAdvertisement a = (RouteAdvertisement) super.clone(); + + a.setDest(getDest()); + + // deep copy of the hops + Vector clonehops = getVectorHops(); + + ListIterator eachHop = clonehops.listIterator(); + + while (eachHop.hasNext()) { + eachHop.set(eachHop.next().clone()); + } + + a.setHops(clonehops); + + return a; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * makes a copy of a route advertisement + * that only contains PID not endpoint addresses + * + * @return object clone route advertisement + */ + public RouteAdvertisement cloneOnlyPIDs() { + RouteAdvertisement routeAdvertisement; + + try { + routeAdvertisement = (RouteAdvertisement) super.clone(); + routeAdvertisement.setDestEndpointAddresses(new Vector()); + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + + // deep copy of the hops + Vector clonehops = routeAdvertisement.getVectorHops(); + + ListIterator eachHop = clonehops.listIterator(); + + while (eachHop.hasNext()) { + AccessPointAdvertisement aHop = eachHop.next(); + + eachHop.set(aHop.clone()); + } + + routeAdvertisement.setHops(clonehops); + return routeAdvertisement; + } + + /** + * Compare if two routes are equals. Equals means same destination with the + * same endpoint addresses and thee same number of hops and the same + * endpoint addresses for each hop. + * + * @param target the route to compare against + * @return boolean true if the route is equal to this route otherwise false + */ + @Override + public boolean equals(Object target) { + + if (this == target) { + return true; + } + + if (!(target instanceof RouteAdvertisement)) { + return false; + } + + RouteAdvertisement route = (RouteAdvertisement) target; + + // check the destination + if (!dest.equals(route.getDest())) { + return false; + } + + // check each of the hops + + // routes need to have the same size + if (hops.size() != route.size()) { + return false; + } + + int index = 0; + + for (AccessPointAdvertisement hop : route.hops) { + if (!hop.equals(hops.get(index++))) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + if (null != dest.getPeerID()) { + return dest.getPeerID().hashCode(); + } else { + // force all incomplete advertisements to hash to the same place. + return 1; + } + } + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:RA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized ID getID() { + if (null == dest.getPeerID()) { + throw new IllegalStateException("Destination peerID not defined. Incomplete RouteAdvertisement"); + } + + if (hashID == null) { + try { + // We have not yet built it. Do it now + byte[] seed = getAdvertisementType().getBytes("UTF-8"); + InputStream in = new ByteArrayInputStream(dest.getPeerID().toString().getBytes("UTF-8")); + + hashID = IDFactory.newCodatID((PeerGroupID) dest.getPeerID().getPeerGroupID(), seed, in); + } catch (Exception ez) { + return ID.nullID; + } + } + return hashID; + } + + /** + * Returns the route destination Peer ID + * + * @return peerID of the destination of the route + */ + public PeerID getDestPeerID() { + return dest.getPeerID(); + } + + /** + * Sets the route destination peer id. + * + * @param pid route destination peerID + */ + public void setDestPeerID(PeerID pid) { + if ((null != pid) && (null != dest.getPeerID()) && (!pid.equals(dest.getPeerID()))) { + throw new IllegalStateException("Changing the peer id of the destination APA." + pid + " != " + dest.getPeerID()); + } + + dest.setPeerID(pid); + + // recalculate hash. + synchronized (this) { + hashID = null; + } + } + + /** + * Returns the destination access point. This does NOT copy + * the AccessPointAdvertisement. + * + * @return AccessPointAdvertisement of the destination peer. + * @deprecated Because this method unsafely exposes destination AccessPointAdvertisement it will be removed. + */ + @Deprecated + public AccessPointAdvertisement getDest() { + return dest; + } + + /** + * Sets the access point of the destination. This does NOT copy + * the AccessPointAdvertisement. + * + * @param ap AccessPointAdvertisement of the destination peer + */ + public void setDest(AccessPointAdvertisement ap) { + PeerID destPid = dest.getPeerID(); + + this.dest = ap.clone(); + + if ((null != destPid) && (null != dest.getPeerID()) && (!destPid.equals(dest.getPeerID()))) { + throw new IllegalStateException("Changed the peer id of the destination APA." + destPid + " != " + dest.getPeerID()); + } + + if (null != destPid) { + dest.setPeerID(destPid); + } + + // recalculate hash. + synchronized (this) { + hashID = null; + } + } + + /** + * Add a new list of EndpointAddresses to the Route Destination access + * point + * + * @param addresses vector of endpoint addresses to add to the + * destination access point. Warning: The vector of endpoint addresses + * is specified as a vector of String. Each string representing + * one endpoint address. + * @deprecated Use {@link #addDestEndpointAddresses(List)} instead. + */ + @Deprecated + public void addDestEndpointAddresses(Vector addresses) { + dest.addEndpointAddresses(addresses); + } + + /** + * Clears all endpoint addresses associated with the destination peer. + */ + public void clearDestEndpointAddresses() { + dest.clearEndpointAddresses(); + } + + /** + * Add the specified endpoint address to destination peer. + * + * @param addr EndpointAddress to add. + */ + public void addDestEndpointAddress(EndpointAddress addr) { + dest.addEndpointAddress(addr); + } + + /** + * Add all of the specified endpoint addresses to destination peer. + * + * @param addrs EndpointAddresses to add. + */ + public void addDestEndpointAddresses(List addrs) { + dest.addEndpointAddresses(addrs); + } + + /** + * Remove the specified endpoint address to destination peer. + * + * @param addr EndpointAddress to add. + */ + public void removeDestEndpointAddress(EndpointAddress addr) { + dest.removeEndpointAddress(addr); + } + + /** + * Remove the specified endpoint addresses from destination peer. + * + * @param addrs EndpointAddress to add. + */ + public void removeDestEndpointAddresses(Collection addrs) { + dest.removeEndpointAddresses(addrs); + } + + /** + * Remove a list of EndpointAddresses from the Route Destination + * access point + * + * @param addresses vector of endpoint addresses to remove from the + * destination access point. + * @deprecated Use {@link #removeDestEndpointAddresses(Collection)}. + */ + @Deprecated + public void removeDestEndpointAddresses(Vector addresses) { + dest.removeEndpointAddresses(addresses); + } + + /** + * Returns the endpoint addresses of the destination peer in their + * preferred order. + * + * @return The {@code EndpointAddress}es of the destination peer. + */ + public List getDestEndpointAddresses() { + List result = new ArrayList(); + + Enumeration eachEA = dest.getEndpointAddresses(); + + while (eachEA.hasMoreElements()) { + result.add(new EndpointAddress(eachEA.nextElement())); + } + + return result; + } + + /** + * Set the route destination endpoint addresses + * + * @param ea vector of endpoint addresses. Warning: The vector is not copied + * and is used directly. + * @deprecated Use {@link #addDestEndpointAddress(EndpointAddress)} instead. + */ + @Deprecated + public void setDestEndpointAddresses(Vector ea) { + dest.setEndpointAddresses(ea); + } + + /** + * returns the list of hops + * + * @return Enumeration list of hops as AccessPointAdvertisement + */ + public Enumeration getHops() { + return hops.elements(); + } + + /** + * returns the list of hops + * + * @return Vector list of hops as AccessPointAdvertisement + */ + public Vector getVectorHops() { + return hops; + } + + /** + * Sets the list of hops associated with this route. + * + * @param newHops AccessPointAdvertisements which form the hops. The + * Vector is NOT copied. + */ + public void setHops(Vector newHops) { + // It is legal to set it to null but it is automatically converted + // to an empty vector. The member hops is NEVER null. + if (null == newHops) { + hops = new Vector(); + } else { + for (AccessPointAdvertisement hop : newHops) { + if (null == hop.getPeerID()) { + throw new IllegalArgumentException("Bad hop"); + } + } + + hops = newHops; + } + } + + /** + * Check if the route contains the following hop + * + * @param pid peer id of the hop + * @return boolean true or false if the hop is found in the route + */ + public boolean containsHop(PeerID pid) { + for (AccessPointAdvertisement hop : hops) { + PeerID hid = hop.getPeerID(); + + if (pid.equals(hid)) { + return true; + } + } + return false; + } + + /** + * Returns the AccessPointAdvertisement of first hop. The + * AccessPointAdvertisement is not cloned. + * + * @return AccessPointAdvertisement of first hop. + */ + public AccessPointAdvertisement getFirstHop() { + return hops.isEmpty() ? null : hops.firstElement(); + } + + /** + * Sets the AccessPointAdvertisement for the first hop. The + * AccessPointAdvertisement is not cloned. + * + * @param ap AccessPointAdvertisement of the first hop. + */ + public void setFirstHop(AccessPointAdvertisement ap) { + if (null == ap.getPeerID()) { + throw new IllegalArgumentException("Bad hop"); + } + + hops.add(0, ap); + } + + /** + * Returns the access point for the last hop. The + * AccessPointAdvertisement is not cloned. + * + * @return AccessPointAdvertisement last hop. + */ + public AccessPointAdvertisement getLastHop() { + return hops.isEmpty() ? null : hops.lastElement(); + } + + /** + * Sets the AccessPointAdvertisement of the last hop. The + * AccessPointAdvertisement is not cloned. + * + * @param ap AccessPointAdvertisement of the last hop. + */ + public void setLastHop(AccessPointAdvertisement ap) { + if (null == ap.getPeerID()) { + throw new IllegalArgumentException("Bad hop"); + } + + hops.add(ap); + } + + /** + * check if the route has a loop + * + * @return boolean true or false if the route has a loop + */ + public boolean hasALoop() { + // Now check for any other potential loops. + + Set seenPeers = new HashSet(hops.size()); + + for (AccessPointAdvertisement anAPA : hops) { + PeerID pid = anAPA.getPeerID(); + + if (seenPeers.contains(pid)) { + return true; // There is a loop. + } + + seenPeers.add(pid); + } + return false; + } + + /** + * return the length of the route + * + * @return int size of the route + */ + public int size() { + return hops.size(); + } + + /** + * Return the hop that follows the specified currentHop. The + * AccessPointAdvertisement is not cloned. + * + * @param currentHop PeerID of the current hop + * @return ap AccessPointAdvertisement of the next Hop + */ + public AccessPointAdvertisement nextHop(PeerID currentHop) { + + // check if we have a real route + if (hops.isEmpty()) { + // Empty vector. + return null; + } + + // find the index of the route + int index = 0; + boolean found = false; + + for (AccessPointAdvertisement ap : hops) { + if (currentHop.equals(ap.getPeerID())) { + found = true; + break; + } + index++; + } + + AccessPointAdvertisement nextHop = null; + + if (!found) { + // The peer is not into the list. Since we have got that message, + // the best we can do is to send it to the first gateway in the + // forward path. + nextHop = hops.get(0); + } else { + // Found the peer within the vector of hops. Get the next hop. + if (index < hops.size()) { + nextHop = hops.get(index); + } + } + + return nextHop; + } + + /** + * Generate a string that displays the route + * information for logging or debugging purpose + * + * @return String return a string containing the route info + */ + public String display() { + StringBuilder routeBuf = new StringBuilder(); + + routeBuf.append("Dest APA : "); + AccessPointAdvertisement dest = getDest(); + + routeBuf.append(dest.display()); + routeBuf.append("\n"); + + int i = 1; + Enumeration e = getHops(); + + while (e.hasMoreElements()) { + AccessPointAdvertisement hop = e.nextElement(); + + if (i == 1) { + routeBuf.append("HOPS = "); + } + routeBuf.append("\n\t[").append(i++).append("] "); + + routeBuf.append(hop.display()); + } + return routeBuf.toString(); + } + + /** + * Remove a hop from the list of hops. + * + * @param pid peer id of the hop + * @return boolean true or false if the hop is found in the route + */ + public boolean removeHop(PeerID pid) { + Iterator eachHop = hops.iterator(); + + while (eachHop.hasNext()) { + AccessPointAdvertisement hop = eachHop.next(); + PeerID hid = hop.getPeerID(); + + if (pid.equals(hid)) { + eachHop.remove(); + return true; + } + } + + return false; + } + + /** + * Return a hop from the list of hops. + * + * @param pid peer id of the hop + * @return AccessPointAdvertisement of the corresponding hop + */ + public AccessPointAdvertisement getHop(PeerID pid) { + for (AccessPointAdvertisement hop : hops) { + PeerID hid = hop.getPeerID(); + + if (pid.equals(hid)) { + return hop.clone(); + } + } + return null; + } + + /** + * Alter the given newRoute (which does not start from here) by using firstLeg, a known route to whence + * it starts from. So that the complete route goes from here to the end-destination via firstLeg. + * public static boolean stichRoute(RouteAdvertisement newRoute, + * + * @param newRoute the new route + * @param firstLeg the first route + * @return true if successful + */ + public static boolean stichRoute(RouteAdvertisement newRoute, RouteAdvertisement firstLeg) { + return stichRoute(newRoute, firstLeg, null); + } + + /** + * Alter the given newRoute (which does not start from here) by using firstLeg, a known route to whence + * it starts from. So that the complete route goes from here to the end-destination via firstLeg + * also shortcut the route by removing the local peer. + * + * @param newRoute the new route + * @param firstLeg first hop + * @param localPeer local PeerID + * @return true if successful + */ + public static boolean stichRoute(RouteAdvertisement newRoute, RouteAdvertisement firstLeg, PeerID localPeer) { + + if (newRoute.hasALoop()) { + return false; + } + + Vector hops = newRoute.getVectorHops(); + + // Make room + hops.ensureCapacity(firstLeg.getVectorHops().size() + 1 + hops.size()); + + // prepend the routing peer unless the routing peer happens to be + // in the route already. That happens if the routing peer is the relay. + // or if the route does not have a first leg + PeerID routerPid = firstLeg.getDest().getPeerID(); + + if (newRoute.size() == 0 || (!newRoute.getFirstHop().getPeerID().equals(routerPid))) { + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + // prepend the route with the routing peer. + ap.setPeerID(routerPid); + hops.add(0, ap); + } + + // prepend the rest of the route + hops.addAll(0, firstLeg.getVectorHops()); + + // remove any loop from the root + cleanupLoop(newRoute, localPeer); + return true; + } + + /** + * Remove loops from the route advertisement + * by shortcutting cycle from the route + * + * @param route the route advertisement + * @param localPeer local PeerID + */ + public static void cleanupLoop(RouteAdvertisement route, PeerID localPeer) { + + // Note: we cleanup all enp addresses except for the last hop (which we + // use to shorten routes often enough). + // If we end-up removing the last hop, it means that it is the local + // peer and thus the route ends up with a size 0. + + Vector hops = route.getVectorHops(); + Vector newHops = new Vector(hops.size()); + AccessPointAdvertisement lastHop = null; + + // Replace all by PID-only entries, but keep the last hop on the side. + if (!hops.isEmpty()) { + lastHop = hops.get(hops.size() - 1); + } + hops = (route.cloneOnlyPIDs()).getVectorHops(); + + // remove cycle from the route + for (int i = 0; i < hops.size(); i++) { + int loopAt = newHops.indexOf(hops.elementAt(i)); + + if (loopAt != -1) { // we found a cycle + + // remove all entries after loopAt + for (int j = newHops.size(); --j > loopAt;) { + newHops.remove(j); + } + } else { // did not find it so we add it + newHops.add(hops.get(i)); + } + } + + // Remove the local peer in the route if we were given one + if (localPeer != null) { + for (int i = newHops.size(); --i >= 0;) { + if (localPeer.equals(newHops.elementAt(i).getPeerID())) { + // remove all the entries up to that point we + // need to keep the remaining of the route from that + // point + for (int j = 0; j <= i; j++) { + newHops.remove(0); + } + break; + } + } + } + + if (lastHop != null && newHops.size() > 0) { + newHops.setElementAt(lastHop, newHops.size() - 1); + } + + // update the new hops in the route + route.setHops(newHops); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteQueryMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteQueryMsg.java new file mode 100644 index 000000000..bde492659 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteQueryMsg.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.peer.PeerID; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + + +/** + * This class defines the EndpointRouter RouteQuery message "Query" + *

      + * This message is part of the Endpoint Routing Protocol. + * + * @deprecated This class will be removed from the public JXTA API. It is used + * only by the standard router message transport implementation and is of no use + * to applications. + * + * @see net.jxta.protocol.RouteResponseMsg + */ +@Deprecated +public abstract class RouteQueryMsg { + + private PeerID destPID = null; + private RouteAdvertisement srcRoute = null; + private final Set badHops = new HashSet(); + + /** + * All messages have a type (in xml this is !doctype) + * which identifies the message + * + * @return String "jxta:ERQ" + */ + public static String getAdvertisementType() { + return "jxta:ERQ"; + } + + /** + * set the destination PeerID we are searching a route for + * + * @param pid destination peerID + */ + public void setDestPeerID(PeerID pid) { + destPID = pid; + } + + /** + * returns the destination peer ID we are looking for + * + * @return pid PeerID of the route destination + */ + + public PeerID getDestPeerID() { + return destPID; + } + + /** + * set the Route advertisement of the source peer that is originating + * the query + * + * @param route RouteAdvertisement of the source + */ + public void setSrcRoute(RouteAdvertisement route) { + if(null == route.getDestPeerID()) { + throw new IllegalArgumentException("route lacks destination!"); + } + + srcRoute = route.clone(); + } + + /** + * returns the route of the src peer that issued the routequery + * + * @return route RouteAdvertisement of the source peer + */ + public RouteAdvertisement getSrcRoute() { + if(null == srcRoute) { + return null; + } else { + return srcRoute.clone(); + } + } + + /** + * Adds a bad hop to the list of those known to be bad for this route. + * + * @param badHop The known bad hop for the route. + */ + public void addBadHop(PeerID badHop) { + badHops.add(badHop); + } + + /** + * Set the bad hops known into that route + * + * @param hops RouteAdvertisement of the source + */ + public void setBadHops(Collection hops) { + badHops.clear(); + if (null != hops) { + badHops.addAll(hops); + } + } + + /** + * returns the bad hops know to the route + * + * @return The known bad hops for the route + */ + public Set getBadHops() { + return new HashSet(badHops); + } + + /** + * Write message into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out, and "text/xml" which + * provides an XML representation. + * + * @param asMimeType mime-type format requested + * @return Document representation of the document as an advertisement + */ + public abstract Document getDocument(MimeMediaType asMimeType); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteResponseMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteResponseMsg.java new file mode 100644 index 000000000..7bf0777f1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/RouteResponseMsg.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; + + +/** + * Sent by peers in response to Route Query Messages as part of the Endpoint + * Router Protocol (ERp). Contains a route advertisement for the destination + * peer. Route Response Messages are transmitted as responses within Resolver + * Response Message. + * + * @deprecated This message is private to the Endpoint Router implementation and + * not part of the JXTA public API. It will be moved from this package. + * + * @see net.jxta.protocol.RouteQueryMsg + * @see JXTA Protocols Specification : Endpoint Routing Protocol + **/ +@Deprecated +public abstract class RouteResponseMsg { + + private RouteAdvertisement dstRoute = null; + private RouteAdvertisement srcRoute = null; + + /** + * All messages have a type (in xml this is !doctype) + * which identifies the message + * @return String "jxta:ERR" + */ + + public static String getAdvertisementType() { + return "jxta:ERR"; + } + + /** + * set the destination route we were looking for + * + * @param dst destination route + */ + + public void setDestRoute(RouteAdvertisement dst) { + dstRoute = dst; + } + + /** + * returns the destination route we were looking for + * + * @return route destination route advertisement + */ + + public RouteAdvertisement getDestRoute() { + return dstRoute; + } + + /** + * Set the Route advertisement of the source peer that is originating + * the query + * + * @param route RouteAdvertisement of the source + */ + + public void setSrcRoute(RouteAdvertisement route) { + srcRoute = route; + } + + /** + * Returns the route of the src peer that responded + * + * @return route RouteAdvertisement of the source peer + * that responded to the query + */ + + public RouteAdvertisement getSrcRoute() { + return srcRoute; + } + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. "text/text" encodes + * the document in a form nice for printing out, and "text/xml" which + * provides an XML representation. + * + * @param asMimeType mime-type format requested + * @return Document representation of the document as an advertisement + */ + + public abstract Document getDocument(MimeMediaType asMimeType); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/SignedAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/SignedAdvertisement.java new file mode 100644 index 000000000..d76b330c0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/SignedAdvertisement.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.credential.Credential; +import net.jxta.document.Advertisement; +import net.jxta.document.ExtendableAdvertisement; + + +/** + * A container for signed Advertisements + */ +public abstract class SignedAdvertisement extends ExtendableAdvertisement { + + protected Credential signer = null; + + protected Advertisement adv = null; + + // todo implement clone + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:SA"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * Gets the Advertisement. + * + * @return a signed advertisement + */ + public Advertisement getAdvertisement() { + return adv; + } + + /** + * Sets the Advertisement to be signed. + * + * @param adv set the advertisment + */ + public void setAdvertisement(Advertisement adv) { + this.adv = adv; + } + + /** + * Returns the credential which signed the advertisement. + * + * @return the credential which signed the advertisement. + */ + public Credential getSigner() { + return signer; + } + + /** + * Sets the Credential which will sign the advertisement. + * + * @param cred the credential + */ + public void setSigner(Credential cred) { + signer = cred; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/SrdiMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/SrdiMessage.java new file mode 100644 index 000000000..297f5362a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/SrdiMessage.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.protocol; + + +import net.jxta.document.Document; +import net.jxta.document.MimeMediaType; +import net.jxta.peer.PeerID; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + + +/** + * A generic message that can be used by services to push shared resources to + * other peers on the network. + *

      + */ +public abstract class SrdiMessage { + + /** + * PERSIST Scope is persist only. i.e. A node receiving such message is expected to only persist + * the indexes contained within. + */ + public static final int PERSISTONLY = 0; + + /** + * REPLICATE Scope is persist and replicate. i.e. A node receiving such message is expected + * to pnly persist the indexes contained within. + */ + public static final int REPLICATE = 1; + private final Collection entries = new ArrayList(); + private PeerID peerid = null; + private String primaryKey = null; + + /** + * The scope of SrdiMesage (0, or 1) + */ + private int scope = 0; + + /** + * Write advertisement into a document. asMimeType is a mime media-type + * specification and provides the form of the document which is being + * requested. Two standard document forms are defined. 'text/text' encodes + * the document in a form nice for printing out and 'text/xml' which + * provides an XML format. + * + * @param asMimeType mime-type requested representation for the returned + * document + * @return Document document representing the advertisement + */ + public abstract Document getDocument(MimeMediaType asMimeType); + + /** + * returns the source peerid + * + * @return PeerID + */ + public PeerID getPeerID() { + return peerid; + } + + /** + * get the primary key + * + * @return primaryKey + */ + public String getPrimaryKey() { + return this.primaryKey; + } + + /** + * Returns the current TTL value. + * + * @return The current TTL value. + * @deprecated ttl is a misnomer, it is meant to be defined as scope. use #getScope() instead + */ + @Deprecated + public int getTTL() { + return scope; + } + + /** + * sets the ttl + * + * @param newTTL The new TTL value. + * @deprecated ttl is a misnomer, it is meant to be defined as scope. use #setScope() instead + */ + @Deprecated + public void setTTL(int newTTL) { + scope = newTTL; + } + + /** + * Returns the current scope of this message. + *

      + * Scope is either 0 (persist only), or 1 (persist and replicate) + * + * @return The current scope value. + */ + public int getScope() { + return scope; + } + + /** + * Sets the current scope of this message. + *

      + * Scope is either 0 (persist only), or 1 (persist and replicate) + * @see #PERSISTONLY + * @see #REPLICATE + * + * @param scope The new TTL value. + */ + public void setScope(int scope) { + this.scope = scope; + } + + /** + * Decrements TTL + */ + public void decrementTTL() { + + if (this.scope > 0) { + this.scope--; + } + } + + /** + * Returns the entries of this SrdiMessage + * + * @return the entries of this SrdiMessage + */ + public Collection getEntries() { + return new ArrayList(entries); + } + + /** + * Adds an index entry + * @param key key + * @param value the value + * @param expiration expiration in millisconds + */ + public void addEntry(String key, String value, long expiration) { + addEntry(new SrdiMessage.Entry(key, value, expiration)); + } + + public void addEntry(SrdiMessage.Entry entry) { + entries.add(entry); + } + + /** + * Set the Entries for this SrdiMessage. + * + * @param newEntries The entries to be included in this message. + */ + public void setEntries(Collection newEntries) { + entries.clear(); + entries.addAll(newEntries); + } + + /** + * Set the source peerid + * + * @param peerid the source PeerID + */ + public void setPeerID(PeerID peerid) { + this.peerid = peerid; + } + + /** + * Set the primary key + * + * @param pkey the primary key + */ + public void setPrimaryKey(String pkey) { + this.primaryKey = pkey; + } + + /** + * All messages have a type (in xml this is !doctype) which identifies the + * message, if no expiration is defined Default expiration infinite for + * entries. This is the amount of time which an entry will live in cache. + * After this time, the entry is garbage collected, it also worthy to note + * that it is up to the peer caching these entries to honor the lifetime of + * the entry, and peer may choose to garbage collect entries based on + * quotas, relationship with other peers, etc. * + * + * @return String "jxta:GenSRDI" + */ + public static String getMessageType() { + return "jxta:GenSRDI"; + } + + /** + * Entries object, which describes each entry described by this message + */ + public final static class Entry { + + /** + * Entry Expiration expressed in relative time in ms + */ + public long expiration; + + /** + * Entry key attribute + */ + public String key; + + /** + * Entry key value + */ + public String value; + + /** + * {@inheritDoc} + *

      + * Expiration time is not considered in calculation. + */ + @Override + public boolean equals(Object target) { + + if (this == target) { + return true; + } + + if (target instanceof Entry) { + Entry likeMe = (Entry) target; + + return key.equals(likeMe.key) && value.equals(likeMe.value); + } + + return false; + } + + /** + * {@inheritDoc} + *

      + * Expiration time is not considered in calculation. + */ + @Override + public int hashCode() { + int result = 0; + + if (null != key) { + result ^= key.hashCode(); + } + + if (null != value) { + result ^= value.hashCode(); + } + + return result; + } + + /** + * Creates a Entry with key, value, and expiration + * + * @param key key attribute + * @param value key value + * @param expiration expressed in relative time in ms + */ + public Entry(String key, String value, long expiration) { + this.key = key; + this.value = value; + this.expiration = expiration; + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/TransportAdvertisement.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/TransportAdvertisement.java new file mode 100644 index 000000000..391fd8fac --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/TransportAdvertisement.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.protocol; + + +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.id.ID; + + +/** + * This abstract class defines a Transport advertisement. Each peer endpoint + * protocol is associated with a transport advertisement that describes the + * protocol and network interface associated with the endpoint transport. For + * example for TCP endpoint. the following transport information needs to be + * maintained for this endpoint: + *

      + *

      Transport : + *

        + *
      • Protocol : TCP + *

      • Port : 6001 + *

      • MulticastAddr : 224.0.1.85 + *

      • MulticastPort : 1234 + *

      • MulticastSize : 8192 + *

      + *

      + *

      This class is an abstract class that needs to be extended by implementation + * to support the different types of transport advertisements (TCP, HTTP, etc) + *

      + *

      + * <?xml version="1.0"?>
      + *  <TransportAdvertisement type="HTTPAdvertisement">
      + *          ..........
      + *  </TransportAdvertisement>
      + * 
      + * + * @see net.jxta.protocol.AccessPointAdvertisement + */ + + +public abstract class TransportAdvertisement extends ExtendableAdvertisement { + + protected String protocol = null; + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:TransportAdvertisement"; + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * Return ID for indexing. We don't have one so return the nullID. + * + * @return jxta id associated with this advertisement. + */ + @Override + public ID getID() { + return ID.nullID; + } + + /** + * Sets the URI scheme to be used for EndpointAddresses of this Message Transport. + * + * @return The URI scheme used for EndpointAddresses of this Message Transport. + */ + public String getProtocol() { + return protocol; + } + + /** + * Returns the URI scheme to be used for EndpointAddresses of this Message Transport. + * + * @param protocol The URI scheme used for EndpointAddresses of this Message Transport. + */ + public void setProtocol(String protocol) { + this.protocol = protocol; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/package.html new file mode 100644 index 000000000..30c198219 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/protocol/package.html @@ -0,0 +1,17 @@ + + + + + + + Provides inteface objects for Advertisments and protocol messages for the JXTA + Core + and + Standard + Protocols. + + @see net.jxta.document.Advertisement + @see JXTA Protocols Specification - Overview : Advertisements + @see JXTA Protocols Specification - Advertisements + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezVousService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezVousService.java new file mode 100644 index 000000000..22f51f4f7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezVousService.java @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.rendezvous; + + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.service.Service; + + +/** + * The RendezVous Service provides propagation of messages within a JXTA + * PeerGroup. + * + *

      The JXTA RendezVous Service defines a subscription mechanism + * allowing JXTA peers to receive propagated messages (clients of the service) + * or become a repeater of the service (rendezvous peers). + * + *

      The Standard Reference Implementation requires that at least one peer in + * a PeerGroup to act as a Rendezvous. Rendezvous peers may dynamically join or + * leave the PeerGroup over time. + * + * @see JXTA Protocols Specification : Rendezvous + */ +public interface RendezVousService extends Service { + + /** + * Perform propagate() or walk() using the most + * appropriate TTL value for the implementation and configuration. The + * message will almost certainly be sent with a TTL value much less than + * this value. + */ + public final static int DEFAULT_TTL = Integer.MAX_VALUE; + + /** + * Attempt connection to the specified RendezVous peer. + * + * @deprecated Directly connecting to rendezvous peers is not recommended. + * Seed rendezvous should be specified using the RdvConfigAdv mechanisms. + * + * @param adv the advertisement of the RendezVousService peer + * @throws IOException When the specified peer is unreachable + */ + @Deprecated + public void connectToRendezVous(PeerAdvertisement adv) throws IOException; + + /** + * Attempt connection to the specified RendezVous peer. + * + * @deprecated Directly connecting to rendezvous peers is not recommended. + * Seed rendezvous should be specified using the RdvConfigAdv mechanisms. + * + * @param addr EndpointAddress of the rendezvous peer + * @throws IOException When the specified peer is unreachable + */ + @Deprecated + public void connectToRendezVous(EndpointAddress addr) throws IOException; + + /** + * Disconnect from the specified rendezvous. + * + * @param peerID the PeerId of the RendezVous to disconnect from. + */ + public void disconnectFromRendezVous(ID peerID); + + /** + * Returns an Enumeration of the PeerID all the RendezVous on which this + * Peer is currently connected. This returns the same result as + * {@link #getConnectedPeers()}. + * + * @return Enumeration enumeration of RendezVous. + */ + public Enumeration getConnectedRendezVous(); + + /** + * Returns an Enumeration of the PeerID all the RendezVous on which this + * Peer failed to connect to. + * + * @deprecated Due to design changes this no longer returns accurate nor + * complete results. It will eventually be removed. + * + * @return Enumeration of the PeerID all the RendezVous on which this + * Peer failed to connect to. + */ + @Deprecated + public Enumeration getDisconnectedRendezVous(); + + /** + * Start the local peer as a RendezVous peer. + */ + public void startRendezVous(); + + /** + * Stop the RendezVous function on the local Peer. All connected Peers are + * disconnected. + */ + public void stopRendezVous(); + + /** + * Returns an Enumeration of the PeerID of the peers that are currently + * connected to this peer. Depending upon the role of of this peer the + * result may be an enumeration of clients or an enumeration of rendezvous + * peers. + * + * @return Enumeration of {@link net.jxta.peer.PeerID} connected to this peer. + */ + public Enumeration getConnectedPeers(); + + /** + * Returns a Vector of the PeerID of the peers that are currently + * connected to this peer. Depending upon the role of of this peer the + * result may be an enumeration of clients or an enumeration of rendezvous + * peers. + * + * @return Vector of {@link net.jxta.peer.PeerID} connected to this peer. + */ + public Vector getConnectedPeerIDs(); + + /** + * Registers the provided listener under the given serviceName and + * serviceParam to receive messages propagated by the Rendezvous service. + * The listener will be added only if no other listener is already + * registered with these names. + * + * @deprecated This method just calls + * {@link net.jxta.endpoint.EndpointService#addIncomingMessageListener}. It's better to just + * register your listener with the Endpoint. This call may be + * eventually removed. + * + * @param serviceName The serviceName of the listener. + * @param serviceParam The serviceParam of the listener. + * @param listener An EndpointListener to process the message. + * @return true if listener was registered, otherwise false. + */ + @Deprecated + public boolean addPropagateListener(String serviceName, String serviceParam, EndpointListener listener); + + /** + * Removes a Listener previously added with addPropagateListener. + * If the given listener is not the one currently registered, nothing is removed. + * + * @deprecated This method just calls + * {@link net.jxta.endpoint.EndpointService#removeIncomingMessageListener}. + * It's better to just deregister your listener with the Endpoint. This call + * may be eventually removed. + * + * @param serviceName The serviceName of the listener. + * @param serviceParam The serviceParam of the listener. + * @param listener An EndpointListener to process the message. + * @return the listener removed, null if the listener was not registered. + */ + @Deprecated + public EndpointListener removePropagateListener(String serviceName, String serviceParam, EndpointListener listener); + + /** + * Add a listener for RendezVousEvents. + * + * @param listener An RendezvousListener to process the event. + */ + public void addListener(RendezvousListener listener); + + /** + * Removes a Rendezvous event listener previously added with addListener. + * + * @param listener the RendezvousListener listener remove + * @return true if successful + */ + public boolean removeListener(RendezvousListener listener); + + /** + * Propagates a message to the local network and to as many members of + * the peer group as possible. + * + *

      This method sends the message to all peers, rendezvous peers and + * edge peer. This method of propagation is very expensive and should + * be used very cautiously. When rendezvous peers are used in order to + * cache index of data, it is more efficient to use the walk() method. + * + *

      Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + * + *

      Loop and TTL control are performed automatically. + * + *

      Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + * + * @param msg is the message to propagate. + * @param serviceName is the name of the service. + * @param serviceParam is the parameter of the service. + * @param ttl The requested TTL for the message. + * @exception IOException if an io error occurs + */ + public void propagate(Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Propagates a message to the specified peers. + * + * @param destPeerIds An enumeration of PeerIDs of the peers that are the + * intended recipients of the propagated message. + * @param msg The message to propagate. + * @param serviceName The name of the service. + * @param serviceParam The parameter of the service. + * @param ttl The requested TTL for the message. + * @exception IOException if an io error occurs + */ + public void propagate(Enumeration destPeerIds, Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Propagates a message to members of the peer group reachable via the + * local network. Typically this is accomplished by broadcasting or + * multicasting. + * + *

      Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + * + *

      Loop and TTL control are performed automatically. + * + *

      Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + * + * @param msg is the message to propagate. + * @param serviceName is the name of the service. + * @param serviceParam is the parameter of the service. + * @param ttl The requested TTL for the message. + * @exception IOException if an io error occurs + */ + public void propagateToNeighbors(Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Propagates a message to as many members of the peer group as possible. + * + *

      Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + * + *

      Loop and TTL control are performed automatically. + * + *

      Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + * + * @param msg is the message to propagate. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param ttl The requested TTL for the message. + * @exception IOException if an io error occurs + */ + public void propagateInGroup(Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Return {@code true} if connected to a rendezvous. + * + * @return {@code true} if connected to a rendezvous otherwise {@code false}. + */ + public boolean isConnectedToRendezVous(); + + /** + * Returns {@code true} if this peer is acting as a rendezvous peer (per the + * implementation definition) within the peer group. {@code false} is + * returned for all other peer roles. + * + * @return {@code true} if this peer is acting as a rendezvous peer (per the + * implementation definition) within the peer group. {@code false} is + * returned for all other peer roles. + */ + public boolean isRendezVous(); + + /** + * Returns the current role of this peer within the peergroup. + * + * @return The current role of this peer within the peergroup. + */ + public RendezVousStatus getRendezVousStatus(); + + /** + * Enable or disable the automatic switching between an Edge Peer + * and a Rendezvous Peer. + * + * @param auto {@code true} will activate automatic role switching. + * @return The previous auto start value. + */ + public boolean setAutoStart(boolean auto); + + /** + * Enable or disable the automatic switching between an Edge Peer + * and a Rendezvous Peer. + * + * @param auto {@code true} will activate automatic role switching. + * @param period The interval in milliseconds at which the peer should + * reconsider it's role. + * @return The previous auto start value. + */ + public boolean setAutoStart(boolean auto, long period); + + /** + * Walk a message through the rendezvous peers of the network: only + * rendezvous peers will receive the message. + * + *

      Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + * + *

      Loop and TTL control are performed automatically. + * + *

      Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + * + *

      Note: The original msg is not modified and may be reused upon return. + * + * @param msg is the message to walk. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param ttl is the maximum TTL of the message. + * @throws IOException when walking the message is impossible (network failure) + */ + public void walk(Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + *

      Walk a message through the rendezvous peers of the network: only + * rendezvous peers will receive the message. + * + *

      Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + * + *

      Loop and TTL control are performed automatically. + * + *

      Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + * + *

      Note: The original msg is not modified and may be reused upon return. + * + * @param destPeerIDs is a Vector of PeerIDs of the peers which are receiving + * first the walker. Note that each entry in the Vector will create its own + * walker. + * @param msg is the message to walk. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param ttl is the maximum TTL of the message. + * @throws IOException when walking the message is impossible (network failure) + */ + public void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Returns a vector of RdvAdvertisement of the local view of rendezvous peers. + * + * @deprecated Due to design changes, the list of peers may be empty in + * configurations which previously returned a non-empty result. Future + * JXTA versions are likely to use a different API. + * + * @return The local view of RDV peers. + */ + @Deprecated + public Vector getLocalWalkView(); + + /** + * Set a new deadline for the rendezvous to be proven alive. + * As a result a lease response must be sought and obtained within the + * specified delay or the rdv is considered disconnected. + * + *

      A timeout of 0 or less triggers immediate disconnection. + * + * @param peer The peer to be challenged + * @param timeout The delay + */ + public void challengeRendezVous(ID peer, long timeout); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezVousStatus.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezVousStatus.java new file mode 100644 index 000000000..fb1486aa0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezVousStatus.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.rendezvous; + + +/** + * A static "enum" class for RendezVous Status. + */ +public enum RendezVousStatus { + + /** + * No RendezVous Service is configured. + */ + NONE, + + /** + * An unknown RendezVous Service is configured. + */ + UNKNOWN, + + /** + * An ad hoc (connectionless) RendezVous Service is configured. + */ + ADHOC, + + /** + * RendezVous Service is configured as an edge peer. + */ + EDGE, + + /** + * RendezVous Service is configured to automatically choose, but is + * currently running as an edge. + */ + AUTO_EDGE, + + /** + * RendezVous Service is configured to automatically choose, but is + * currently running as a Rendezvous. + */ + AUTO_RENDEZVOUS, + + /** + * RendezVous Service is configured as an rendezvous peer. + */ + RENDEZVOUS +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezvousEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezvousEvent.java new file mode 100644 index 000000000..ed6adf0e8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezvousEvent.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.rendezvous; + + +import java.util.EventObject; + +import net.jxta.id.ID; + + +/** + * Container for Rendezvous Service events. The source of the event is the + * rendezvous service generating the event + */ +public class RendezvousEvent extends EventObject { + + /** + * Rendezvous connection event + */ + public final static int RDVCONNECT = 0; + + /** + * Connection renewal event + */ + public final static int RDVRECONNECT = 1; + + /** + * Client connection event + */ + public final static int CLIENTCONNECT = 2; + + /** + * Client Connection renewal event + */ + public final static int CLIENTRECONNECT = 3; + + /** + * Rendezvous disconnection event + */ + public final static int RDVDISCONNECT = 4; + + /** + * Rendezvous connection failure + */ + public final static int RDVFAILED = 5; + + /** + * Client disconnection event + */ + public final static int CLIENTDISCONNECT = 6; + + /** + * Client connection failure + */ + public final static int CLIENTFAILED = 7; + + /** + * Node has become a rendezvous + */ + public final static int BECAMERDV = 8; + + /** + * Node has become a edge + */ + public final static int BECAMEEDGE = 9; + + private final static String EVENTNAMES[] = { + "RDVCONNECT", "RDVRECONNECT", "CLIENTCONNECT", "CLIENTRECONNECT", "RDVDISCONNECT", "RDVFAILED", "CLIENTDISCONNECT" + , + "CLIENTFAILED", "BECAMERDV", "BECAMEEDGE" + }; + + private int type; + private ID peer; + + /** + * Creates a new event + * + * @param source The rendezvous service which generated the event. + * @param type the event type. + * @param peer the peer associated with the event. + */ + public RendezvousEvent(Object source, int type, ID peer) { + super(source); + this.type = type; + this.peer = peer; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + String eventType; + + if ((type >= RDVCONNECT) && (type <= BECAMEEDGE)) { + eventType = EVENTNAMES[type]; + } else { + eventType = "UNKNOWN (" + type + ")"; + } + + return super.toString() + " : " + eventType + " for [" + peer + "]"; + } + + /** + * Returns the event type + * + * @return int type + */ + public int getType() { + return type; + } + + /** + * Returns peerid + * + * @return the peer associated with the event + */ + public String getPeer() { + return peer.toString(); + } + + /** + * Returns peerid + * + * @return the peer associated with the event + */ + public ID getPeerID() { + return peer; + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezvousListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezvousListener.java new file mode 100644 index 000000000..18c77425d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/RendezvousListener.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.rendezvous; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving RendezVousService events. + * + * The following example illustrate how to implement a + * RendezvousListener: + * + *

      
      + * public class MyApp implements RendezvousListener {
      + *           ..
      + *           rendezvous = mygroup.getRendezVousService();
      + *           rendezvous.addListener(this);
      + *           ..
      + *           ..
      + *           ..
      + *   public void rendezvousEvent (RendezvousEvent event) {
      + *       if (event.getType() == event.RDVCONNECT) {
      + *          ..
      + *       }
      + *   }
      + * }
      + * 
      + */ +public interface RendezvousListener extends EventListener { + + /** + * Called when an event occurs for the Rendezvous service + * + * @param event the rendezvous event + */ + void rendezvousEvent(RendezvousEvent event); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/package.html new file mode 100644 index 000000000..ce1e7e3a3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/rendezvous/package.html @@ -0,0 +1,14 @@ + + + + + + + The RendezVous Service is responsible for propagating messages within a JXTA + PeerGroup. + + @see net.jxta.protocol.RdvAdvertisement + @see net.jxta.rendezvous.RendezVousService + @see JXTA Protocols Specification : Rendezvous + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/GenericResolver.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/GenericResolver.java new file mode 100644 index 000000000..7d63e4788 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/GenericResolver.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.resolver; + + +/** + * @deprecated This interface has been subsumed into the + * {@link net.jxta.resolver.ResolverService}. + */ +@Deprecated +public interface GenericResolver {} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/QueryHandler.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/QueryHandler.java new file mode 100644 index 000000000..57ad88857 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/QueryHandler.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.resolver; + + +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.exception.*; +import java.io.*; + + +/** + * Services that wish to act as a resolver handler must implement this interface + * + * @see net.jxta.resolver.ResolverService + * @see net.jxta.protocol.ResolverQueryMsg + * @see net.jxta.protocol.ResolverResponseMsg + **/ +public interface QueryHandler { + + /** + * Process the resolver query, and generate response + * it is the responsibility of the handler to send the response + * + *

      +     * result = processIncomingQuery(query);
      +     * if (result != null) {
      +     *   resolver.sendResponse(query.getSrc(), response);
      +     *   return ResolverService.OK;
      +     *  } else return ResolverService.Repropagate;
      +     * 
      + * + * @param query ResolverQueryMsg query + * @return int status, {@link net.jxta.resolver.ResolverService#OK OK} + * success, {@link net.jxta.resolver.ResolverService#Repropagate Repropagate} + * to indicate a re-propagation is needed. + */ + + public int processQuery(ResolverQueryMsg query); + + /** + * Called when messages are received by the ResolverService + * it calls back this method to deal with received responses + * + * @param response ResolverQueryMsg response + **/ + public void processResponse(ResolverResponseMsg response); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/ResolverService.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/ResolverService.java new file mode 100644 index 000000000..bff38674a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/ResolverService.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.resolver; + + +import net.jxta.service.Service; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ResolverSrdiMsg; + + +/** + * Provides a generic mechanism for JXTA Services to send "Queries", and receive + * "Responses". It removes the burden for registered handlers in deal with : + * + *
        + *
      • Setting message tags, to ensure uniqueness of tags and + * ensures that messages are sent to the correct address, and group.

        + *
      • Authentication, and verification of credentials.

        + *
      • Query routing.

        + *
      • drop rogue messages.

        + *
      + * + *

      The ResolverService does not proccess the queries, nor does it not + * compose reponses. Processing of queries, and composition of responses is left + * up to the registered handlers. Services that wish to handle queries and + * generate reponses must implement {@link net.jxta.resolver.QueryHandler}. + * + * @see net.jxta.service.Service + * @see net.jxta.resolver.QueryHandler + * @see net.jxta.protocol.ResolverQueryMsg + * @see net.jxta.protocol.ResolverResponseMsg + */ +public interface ResolverService extends Service, GenericResolver { + + /** + * Returned by query handlers to indicate that the query should be + * forwarded to the rest of the network. + */ + public final static int Repropagate = -1; + + /** + * Returned by query handlers to indicate that the query has been resolved + * and a response has been sent. + */ + public final static int OK = 0; + + /** + * Registers a given QueryHandler, returns the previous handler registered + * under this name. + * + * @param name The name under which this handler is to be registered. + * @param handler The handler. + * @return The previous handler registered under this name. + */ + public QueryHandler registerHandler(String name, QueryHandler handler); + + /** + * Unregisters a given QueryHandler, returns the previous handler + * registered under this name. + * + * @param name The name of the handler to unregister. + * @return The previous handler registered under this name. + */ + public QueryHandler unregisterHandler(String name); + + /** + * Registers a given SrdiHandler, returns the previous handler registered + * under this name. + * + * @param name The name under which this handler is to be registered. + * @param handler The handler. + * @return The previous handler registered under this name. + * + */ + public SrdiHandler registerSrdiHandler(String name, SrdiHandler handler); + + /** + * Unregisters a given SrdiHandler, returns the previous handler registered + * under this name. + * + * @param name The name of the handler to unregister. + * @return The previous handler registered under this name + * + */ + public SrdiHandler unregisterSrdiHandler(String name); + + /** + * Sends a resolver query. If destPeer is null the + * message is propagated. + * + * @param destPeer The destination peer of the query or null if + * the query is to be propagated. + * @param query The query to match. + */ + public void sendQuery(String destPeer, ResolverQueryMsg query); + + /** + * Send a resolver response. If destPeer is null then the + * response is propagated. Propagated responses are generally announcements + * and not responses to active queries. + * + * @param destPeer The destination peer of the response or null if + * the response is to be propagated. + * @param response The response to be sent. + */ + public void sendResponse(String destPeer, ResolverResponseMsg response); + + /** + * Send an SRDI message. + * + *

      If destPeer is null the message is walked. + * + * @param destPeer is the destination of the SRDI message. + * @param srdi is the SRDI message to be sent. + */ + public void sendSrdi(String destPeer, ResolverSrdiMsg srdi); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/SrdiHandler.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/SrdiHandler.java new file mode 100644 index 000000000..321f0b58f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/SrdiHandler.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.resolver; + + +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.peer.PeerID; + + +/** + * Services that wish to receive shared resource indecies must implement this + * interface. + * + *@see net.jxta.protocol.SrdiMessage + */ + +public interface SrdiHandler { + + /** + * Process the SrdiMessage message, returns true if the message was + * processed properly + * + *@param message Description of the Parameter + *@return true if the message was processed properly + */ + + public boolean processSrdi(ResolverSrdiMsg message); + + /** + * Resolver calls this method when a failure to send a message to specified + * peer occurs + * + *@param peerid peerid failure occured on + */ + + public void messageSendFailed(PeerID peerid, OutgoingMessageEvent e); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/package.html new file mode 100644 index 000000000..791c05c05 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/resolver/package.html @@ -0,0 +1,12 @@ + + + + + + + The JXTA Resolver Services provides a generic mechanism for JXTA Services + to send "Queries", and receive "Responses". + + @see JXTA Protocols Specification : Peer Resolver Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/service/Service.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/service/Service.java new file mode 100644 index 000000000..fdb70fec4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/service/Service.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.service; + + +import net.jxta.platform.Module; +import net.jxta.document.Advertisement; + + +/** + * This interface implements the peer group service interface. Peer groups + * are formed as a collection of peers that have agreed upon a common set of + * services. The JXTA platform provides a predefined set of services to build + * peer groups + * + *

      Every service is defined by a + * {@link net.jxta.protocol.ModuleImplAdvertisement}. The Service + * advertisement provides the necessary information to uniquely identify + * the service and to contact its associated service(s). + * + *

      When a new peer is joining a peer group an instance of all the + * services associated with the new peer group is created on this peer + * dynamically. Not all services need to be resident on a peer. A peer can + * dynamically load a new service from the peer it contacted to join the + * new peer group (via the PeerGroupAdvertisement of this group). + * + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.platform.Application + * @see net.jxta.protocol.PeerGroupAdvertisement + * @see net.jxta.protocol.ModuleImplAdvertisement + **/ +public interface Service extends Module { + + /** + * Service objects are not manipulated directly to protect usage + * of the service. A Service interface is returned to access the service + * methods. + * + * @return Service public interface of the service + * + */ + public Service getInterface(); + + /** + * Returns the advertisement for this service. + * + * @return Advertisement the advertisement. This is always a + * {@code ModuleImplAdvertisement}. + * + **/ + public Advertisement getImplAdvertisement(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/service/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/service/package.html new file mode 100644 index 000000000..a248abb02 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/service/package.html @@ -0,0 +1,14 @@ + + + + + + + Every service is defined by a + {@link net.jxta.protocol.ModuleImplAdvertisement}. The Service + advertisement provides the necessary information to uniquely identify + the service and to contact its associated service(s). + + @see JXTA Protocols Specification : Services + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaMulticastSocket.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaMulticastSocket.java new file mode 100644 index 000000000..429e1c09e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaMulticastSocket.java @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.socket; + + +import net.jxta.credential.Credential; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.id.IDFactory; +import net.jxta.impl.util.ProducerBiasedQueue; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.util.Collections; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * The JxtaMulticastSocket class is useful for sending and receiving + * JXTA multicast packets. A JxtaMulticastSocket is a (UDP) DatagramSocket, + * with additional capabilities for joining "groups" of other multicast hosts + * on the internet. + * A multicast group is specified within the context of PeerGroup and a propagate + * pipe advertisement. + * One would join a multicast group by first creating a MulticastSocket + * with the desired peer group and pipe advertisement : + *

      + *

      + *  // join a Multicast group and send the group salutations
      + *  ...
      + *  String msg = "Hello";
      + *  MulticastSocket s = new JxtaMulticastSocket(peergroup, propPipeAdv);
      + *  //We are joined at this point
      + *  DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length());
      + *  s.send(hi);
      + *  // get their responses!
      + *  byte[] buf = new byte[1000];
      + *  DatagramPacket recv = new DatagramPacket(buf, buf.length);
      + *  s.receive(recv);
      + *  ...
      + *  // OK, I'm done talking - leave the group...
      + *  s.close();
      + * 
      + *

      + * One can also respond only to the sender of the datagram as follows : + *

      + *  DatagramPacket res = new DatagramPacket(response.getBytes(), response.length());
      + *  res.setAddress(recv.getAddress());
      + *  s.send(res);
      + * 
      + *

      + * When one sends a message to a multicast group, all subscribing recipients to + * that peergroup and pipe receive the message (including themselves) + * When a socket subscribes to a multicast group/port, it receives datagrams + * sent by other hosts to the group/pipe, as do all other members of the group + * and pipe. A socket relinquishes membership in a group by the + * close() method. Multiple MulticastSocket's may + * subscribe to a multicast group and pipe concurrently, and they will all receive + * group datagrams. + *

      + * When a datagram is sent it carries along with the peerid of the sender. + * The PeerID is represented as a InetAddress in the form of host/ipadress + * where host name is the peerid, and ip address is always represented as 0.0.0.0 + * since it is meaningless in the context of JXTA. + * e.g of InetAddress resembles the following: + *

      + *

      + * uuid-59616261646162614A787461503250339C6014B0F21A49DBBDF2ADBDDBCB314703/0.0.0.0
      + * 
      + */ + +public class JxtaMulticastSocket extends MulticastSocket implements PipeMsgListener { + private final static Logger LOG = Logger.getLogger(JxtaMulticastSocket.class.getName()); + public static final String NAMESPACE = "JXTAMCAST"; + public static final String DATATAG = "DATAGRAM"; + public static final String SRCIDTAG = "SRCID"; + protected PipeAdvertisement pipeAdv; + protected PipeService pipeSvc; + protected InputPipe in; + protected PeerGroup group; + protected SocketAddress socketAddress; + protected InetAddress localAddress; + protected OutputPipe outputPipe; + protected boolean closed = false; + protected boolean bound = false; + protected ProducerBiasedQueue queue = new ProducerBiasedQueue(); + protected Credential credential = null; + protected StructuredDocument credentialDoc = null; + private int timeout = 60000; + private byte[] fauxip = new byte[4]; + private boolean jxtamode = false; + private MessageElement srcElement = null; + + /** + * Create a multicast socket and bind it to a specific pipe within specified + * peer group + * + * @param group group context + * @param pipeAd PipeAdvertisement + * @throws IOException if an io error occurs + */ + public JxtaMulticastSocket(PeerGroup group, PipeAdvertisement pipeAd) throws IOException { + super(); + joinGroup(group, pipeAd); + } + + /** + * joins MutlicastSocket to specified pipe within the context of group + * + * @param group group context + * @param pipeAd PipeAdvertisement + * @throws IOException if an io error occurs + */ + public void joinGroup(PeerGroup group, PipeAdvertisement pipeAd) throws IOException { + + if (pipeAd.getType() != null && !pipeAd.getType().equals(PipeService.PropagateType)) { + throw new IOException("Only propagate pipe advertisements are supported"); + } + if (pipeAd.getPipeID() == null) { + throw new IOException("Invalid pipe advertisement"); + } + + this.group = group; + this.pipeAdv = pipeAd; + pipeSvc = group.getPipeService(); + this.in = pipeSvc.createInputPipe(pipeAd, this); + this.credentialDoc = getCredDoc(group); + outputPipe = pipeSvc.createOutputPipe(pipeAd, 1); + String id = group.getPeerID().toString(); + + srcElement = new StringMessageElement(SRCIDTAG, id, null); + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Starting JxtaMulticastSocket on pipe id :" + pipeAdv.getID()); + } + String pipeStr = pipeAd.getPipeID().getUniqueValue().toString(); + + localAddress = InetAddress.getByAddress(pipeStr, fauxip); + socketAddress = new InetSocketAddress(localAddress, 0); + bound = true; + } + + /** + * Obtain the credential doc from the group object + * + * @param group group context + * @return The credDoc value + */ + protected static StructuredDocument getCredDoc(PeerGroup group) { + try { + MembershipService membership = group.getMembershipService(); + Enumeration each = membership.getCurrentCredentials(); + + if (each.hasMoreElements()) { + // get the only credential "nobody" + Credential credential = (Credential) each.nextElement(); + + return credential.getDocument(MimeMediaType.XMLUTF8); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to get credential", e); + } + } + return null; + } + + /** + * Returns the binding state of the MutlicastSocket. + * + * @return true if the MutlicastSocket successfully bound to an address + */ + @Override + public boolean isBound() { + return bound; + } + + /** + * Closes this MutlicastSocket. + */ + @Override + public synchronized void close() { + if (closed) { + return; + } + bound = false; + closed = true; + in.close(); + outputPipe.close(); + queue.close(); + in = null; + } + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + + Message message = event.getMessage(); + + if (message == null) { + return; + } + + MessageElement element = null; + + // does the message contain any data + element = message.getMessageElement(NAMESPACE, DATATAG); + if (element == null) { + return; + } + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pushing a message onto queue"); + } + queue.push(message, -1); + } catch (InterruptedException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", e); + } + } + } + + /** + * Gets the Timeout attribute of the JxtaMulticastSocket + * + * @return The soTimeout value + */ + @Override + public synchronized int getSoTimeout() { + return timeout; + } + + /** + * Sets the Timeout attribute of the JxtaMulticastSocket + * a timeout of 0 blocks forever, by default this Socket's + * timeout is set to 0 + * + * @param timeout The new soTimeout value + */ + @Override + public synchronized void setSoTimeout(int timeout) throws SocketException { + checkState(); + this.timeout = timeout; + } + + /** + * Returns the closed state of the JxtaMulticastSocket. + * + * @return true if the socket has been closed + */ + @Override + public synchronized boolean isClosed() { + return closed; + } + + /** + * Throws a SocketException if closed or not bound + * + * @throws SocketException if closed + */ + private void checkState() throws SocketException { + if (isClosed()) { + throw new SocketException("MulticastSocket is closed"); + } else if (!isBound()) { + throw new SocketException("MulticastSocket not bound"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void send(DatagramPacket packet) throws IOException { + checkState(); + byte[] data = new byte[packet.getLength()]; + + System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength()); + + Message msg = new Message(); + + msg.addMessageElement(NAMESPACE, srcElement); + msg.addMessageElement(NAMESPACE, new ByteArrayMessageElement(DATATAG, MimeMediaType.AOS, data, null)); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a data packet"); + } + InetAddress address = packet.getAddress(); + PeerID pid = null; + + if (address != null) { + String pidStr = address.getHostName(); + + try { + pid = (PeerID) IDFactory.fromURI(new URI(pidStr)); + } catch (Exception ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Invalid source PeerID multicasting instead"); + } + } + } + if (pid != null) { + // Unicast datagram + // create a op pipe to the destination peer + OutputPipe op = pipeSvc.createOutputPipe(pipeAdv, Collections.singleton(pid), 1000); + + op.send(msg); + op.close(); + } else { + // multicast + outputPipe.send(msg); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void receive(DatagramPacket packet) throws IOException { + checkState(); + Message msg = null; + // data + MessageElement del = null; + // src + MessageElement sel = null; + + try { + msg = (Message) queue.pop(timeout); + if (msg == null) { + if (timeout > 0) { + throw new SocketTimeoutException("Socket timeout reached"); + } else { + return; + } + } + del = msg.getMessageElement(NAMESPACE, DATATAG); + sel = msg.getMessageElement(NAMESPACE, SRCIDTAG); + if (del == null || sel == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message contains no data element, returning"); + } + return; + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Popped a message off the queue"); + } + } + } catch (InterruptedException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Exception occured", e); + } + throw new IOException(e.toString()); + } + if (del.getByteLength() > packet.getLength()) { + throw new IOException("Datagram can not accomodate message of size :" + del.getByteLength()); + } + String addrStr = new String(sel.getBytes(false), 0, (int) sel.getByteLength(), "UTF8"); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Src Address :" + addrStr); + } + InetAddress address = InetAddress.getByAddress(addrStr, fauxip); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Setting Data, and Src Address :" + address); + } + packet.setAddress(address); + packet.setData(del.getBytes(false)); + } + + /** + * {@inheritDoc} + */ + @Override + public InetAddress getLocalAddress() { + if (isClosed()) { + return null; + } + return localAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public SocketAddress getLocalSocketAddress() { + if (isClosed()) { + return null; + } + return socketAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public void bind(SocketAddress addr) throws SocketException { + if (isBound()) { + throw new SocketException("Already bound"); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaServerSocket.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaServerSocket.java new file mode 100644 index 000000000..470065b77 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaServerSocket.java @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.socket; + +import net.jxta.credential.Credential; +import net.jxta.credential.CredentialValidator; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * JxtaServerSocket is a bi-directional Pipe that behaves very much like + * ServerSocket. It creates an inputpipe and listens for pipe connection + * requests. JxtaServerSocket also defines it own protocol. Requests arrive as + * a JXTA Message with the following elements: + *

      + * <Cred> Credentials which can be used to determine trust </Cred> + *

      + * <reqPipe> requestor's pipe advertisement </reqPipe> + *

      + * <remPipe> Remote pipe advertisement </remPipe> + *

      + * <reqPeer> Remote peer advertisement </reqPeer> + *

      + * <stream> determine whether the connection is reliable, or not </stream> + *

      + * <close> close request </close> + *

      + * <data> Data </data> + *

      + * JxtaServerSocket then creates a new private pipe, listens for messages on that pipe, + * resolves the requestor's pipe, and sends a <remPipe> private pipe created </remotePipe> + * advertisement back, where the remote side is resolved. + *

      + * The {@code accept()} backlog defaults to 50 requests. + *

      + * The timeout default to 60 seconds, i.e. blocking. + */ +public class JxtaServerSocket extends ServerSocket implements PipeMsgListener { + + private static final Logger LOG = Logger.getLogger(JxtaServerSocket.class.getName()); + + protected static final String MSG_ELEMENT_NAMESPACE = "JXTASOC"; + protected static final String credTag = "Cred"; + protected static final String reqPipeTag = "reqPipe"; + protected static final String remPeerTag = "remPeer"; + protected static final String remPipeTag = "remPipe"; + protected static final String dataTag = "data"; + protected static final String closeTag = "close"; + protected final static String closeReqValue = "close"; + protected final static String closeAckValue = "closeACK"; + protected static final String streamTag = "stream"; + + private final static int DEFAULT_BACKLOG = 50; + private final static long DEFAULT_TIMEOUT = 60 * 1000L; + + /** + * QUEUE_END_MESSAGE is used to signal that the queue has been closed. + */ + protected static final Message QUEUE_END_MESSAGE = new Message(); + + /** + * The PeerGroup + */ + protected PeerGroup group; + + /** + * The pipe advertisement we are serving. + */ + protected PipeAdvertisement pipeAdv; + + /** + * The input pipe on which we listen for connect requests. + */ + protected InputPipe serverPipe; + + /** + * The credential we will present to connect requests. + */ + protected Credential localCredential = null; + + /** + * The number of connect requests we will allow to become backlogged. + */ + protected int backlog = DEFAULT_BACKLOG; + + /** + * The timeout for accept operations. + */ + protected long timeout = DEFAULT_TIMEOUT; + + protected BlockingQueue queue = null; + protected volatile boolean bound = false; + protected volatile boolean closed = false; + private CredentialValidator credValidator = null; + + /** + * Default Constructor + *

      + * A call to {@code bind()} is needed to finish initializing this object. + * + * @throws IOException if an io error occurs + */ + public JxtaServerSocket() throws IOException {} + + /** + * Constructs and binds a JxtaServerSocket using a JxtaSocketAddress as + * the address. + * + * @param address an instance of JxtaSocketAddress + * @throws IOException if an io error occurs + * @see net.jxta.socket.JxtaSocketAddress + */ + public JxtaServerSocket(SocketAddress address) throws IOException { + this(address, DEFAULT_BACKLOG); + } + + /** + * Constructs and binds a JxtaServerSocket to the specified pipe. + * + * @param group JXTA PeerGroup + * @param pipeAdv PipeAdvertisement on which pipe requests are accepted + * @throws IOException if an I/O error occurs + */ + public JxtaServerSocket(PeerGroup group, PipeAdvertisement pipeAdv) throws IOException { + this(group, pipeAdv, DEFAULT_BACKLOG); + } + + /** + * Constructs and binds a JxtaServerSocket using a JxtaSocketAddress as + * the address. + * + * @param address an instance of JxtaSocketAddress + * @param backlog the size of the backlog queue + * @throws IOException if an I/O error occurs + * @see net.jxta.socket.JxtaSocketAddress + */ + public JxtaServerSocket(SocketAddress address, int backlog) throws IOException { + this(address, backlog, (int) DEFAULT_TIMEOUT); + } + + /** + * Constructor for the JxtaServerSocket object + * + * @param group JXTA PeerGroup + * @param pipeAdv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * @throws IOException if an I/O error occurs + */ + public JxtaServerSocket(PeerGroup group, PipeAdvertisement pipeAdv, int backlog) throws IOException { + this(group, pipeAdv, backlog, (int) DEFAULT_TIMEOUT); + } + + /** + * Constructs and binds a JxtaServerSocket using a JxtaSocketAddress as + * the address. + * + * @param address an instance of JxtaSocketAddress + * @param backlog the size of the backlog queue + * @param timeout connection timeout in milliseconds + * @throws IOException if an I/O error occurs + * @see net.jxta.socket.JxtaSocketAddress + */ + public JxtaServerSocket(SocketAddress address, int backlog, int timeout) throws IOException { + setSoTimeout(timeout); + bind(address, backlog); + } + + /** + * Constructor for the JxtaServerSocket object. + * + * @param group JXTA PeerGroup + * @param pipeAdv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * @param timeout the specified timeout, in milliseconds + * @throws IOException if an I/O error occurs + */ + public JxtaServerSocket(PeerGroup group, PipeAdvertisement pipeAdv, int backlog, int timeout) throws IOException { + this(group, pipeAdv, backlog, timeout, null); + } + + /** + * Constructor for the JxtaServerSocket object. + * + * @param group JXTA PeerGroup + * @param pipeAdv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * @param timeout the specified timeout, in milliseconds + * @param credValidator the CredentialValidator + * @throws IOException if an I/O error occurs + */ + public JxtaServerSocket(PeerGroup group, PipeAdvertisement pipeAdv, int backlog, int timeout, CredentialValidator credValidator) throws IOException { + setSoTimeout(timeout); + this.credValidator = credValidator; + bind(group, pipeAdv, backlog); + } + + /** + * {@inheritDoc} + *

      + * Closes the JxtaServerPipe. + */ + @Override + protected void finalize() throws Throwable { + super.finalize(); + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("JxtaServerSocket is being finalized without being previously closed. This is likely an application level bug."); + } + } + close(); + } + + /** + * {@inheritDoc} + */ + @Override + public Socket accept() throws IOException { + if (!isBound()) { + throw new SocketException("Socket is not bound yet"); + } + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting for a connection"); + } + + while (true) { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + Message msg = queue.poll(timeout, TimeUnit.MILLISECONDS); + + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + if (msg == null) { + throw new SocketTimeoutException("Timeout reached"); + } + + if (QUEUE_END_MESSAGE == msg) { + throw new SocketException("Socket is closed."); + } + + JxtaSocket socket = processMessage(msg); + + // make sure we have a socket returning + if (socket != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New socket connection " + socket); + } + return socket; + } else if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("No connection."); + } + } + } catch (InterruptedException ie) { + SocketException interrupted = new SocketException("interrupted"); + + interrupted.initCause(ie); + throw interrupted; + } + } + + /** + * Binds the JxtaServerSocket to a specific pipe advertisement + * + * @param group JXTA PeerGroup + * @param pipeAdv PipeAdvertisement on which pipe requests are accepted + * @throws IOException if an I/O error occurs + */ + public void bind(PeerGroup group, PipeAdvertisement pipeAdv) throws IOException { + bind(group, pipeAdv, DEFAULT_BACKLOG); + } + + /** + * Binds the JxtaServerSocket to a specific pipe advertisement + * + * @param group JXTA PeerGroup + * @param pipeadv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * @throws IOException if an I/O error occurs + */ + public void bind(PeerGroup group, PipeAdvertisement pipeadv, int backlog) throws IOException { + if (PipeService.PropagateType.equals(pipeadv.getType())) { + throw new IOException("Propagate pipe advertisements are not supported"); + } + + if (backlog <= 0) { + throw new IllegalArgumentException("backlog must be > 0"); + } + + this.backlog = backlog; + queue = new ArrayBlockingQueue(backlog); + this.group = group; + this.pipeAdv = pipeadv; + PipeService pipeSvc = group.getPipeService(); + + serverPipe = pipeSvc.createInputPipe(pipeadv, this); + setBound(true); + } + + /** + * {@inheritDoc} + *

      + * Used to bind a JxtaServerSocket created with the no-arg constructor. + */ + @Override + public void bind(SocketAddress endpoint) throws IOException { + bind(endpoint, backlog); + } + + /** + * {@inheritDoc} + *

      + * Used to bind a JxtaServerSocket created with the no-arg constructor. + */ + @Override + public void bind(SocketAddress endpoint, int backlog) throws IOException { + if (endpoint instanceof JxtaSocketAddress) { + JxtaSocketAddress socketAddress = (JxtaSocketAddress) endpoint; + PeerGroup pg = PeerGroup.globalRegistry.lookupInstance(socketAddress.getPeerGroupId()); + + if (pg == null) { + throw new IOException( + "Can't connect socket in PeerGroup with id " + socketAddress.getPeerGroupId() + + ". No running instance of the group is registered."); + } + bind(pg.getWeakInterface(), socketAddress.getPipeAdv(), backlog); + pg.unref(); + } else { + throw new IllegalArgumentException("Unsupported subclass of SocketAddress; " + "use JxtaSocketAddress instead."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + + if (closed) { + return; + } + closed = true; + + if (isBound()) { + // close all the pipe + serverPipe.close(); + setBound(false); + } + + queue.clear(); + while (true) { + try { + queue.put(QUEUE_END_MESSAGE); + // end queue message is now on the queue, we are done. + break; + } catch (InterruptedException woken) { + // We MUST put the terminal message onto the queue before + // finishing. We won't have a second chance. + Thread.interrupted(); + } + } + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closed : " + this); + } + } + + /** + * @return the server socket's JxtaSocketAddress + * @see java.net.ServerSocket#getLocalSocketAddress() + */ + @Override + public SocketAddress getLocalSocketAddress() { + return new JxtaSocketAddress(getGroup(), getPipeAdv()); + } + + /** + * {@inheritDoc} + */ + @Override + public int getSoTimeout() throws IOException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + + if (timeout > Integer.MAX_VALUE) { + return 0; + } else { + return (int) timeout; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setSoTimeout(int timeout) throws SocketException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + + if (timeout < 0) { + throw new IllegalArgumentException("timeout must be >= 0"); + } + + if (0 == timeout) { + this.timeout = Long.MAX_VALUE; + } else { + this.timeout = (long) timeout; + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isBound() { + return bound; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isClosed() { + return closed; + } + + /** + * Sets whether this socket is currently bound or not. A socket is + * considered bound if the local resources required in order to interact + * with a remote peer are allocated and open. + * + * @param boundState The new bound state. + */ + private synchronized void setBound(boolean boundState) { + this.bound = boundState; + } + + /** + * Gets the group associated with this JxtaServerSocket object + * + * @return The group value + */ + public PeerGroup getGroup() { + return group; + } + + /** + * Gets the PipeAdvertisement associated with this JxtaServerSocket object + * + * @return The pipeAdv value + */ + public PipeAdvertisement getPipeAdv() { + return pipeAdv; + } + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + + // deal with messages as they come in + Message message = event.getMessage(); + + if (message == null) { + return; + } + + boolean pushed = false; + try { + pushed = queue.offer(message, timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException woken) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", woken); + } + } + + if (!pushed && Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("backlog queue full, connect request dropped"); + } + } + + /** + * processMessage is the main mechanism in establishing bi-directional connections + *

      + * It accepts connection messages and constructs a JxtaSocket with a ephemeral + * InputPipe and a messenger. + * + * @param msg The client connection request (assumed not null) + * @return JxtaSocket Which may be null if an error occurs. + */ + private JxtaSocket processMessage(Message msg) { + + PipeAdvertisement remoteEphemeralPipeAdv = null; + PeerAdvertisement remotePeerAdv = null; + Credential credential = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Processing a connection message : " + msg); + } + + try { + MessageElement el = msg.getMessageElement(MSG_ELEMENT_NAMESPACE, reqPipeTag); + if (el != null) { + XMLDocument pipeAdvDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(el); + remoteEphemeralPipeAdv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(pipeAdvDoc); + } + + el = msg.getMessageElement(MSG_ELEMENT_NAMESPACE, remPeerTag); + if (el != null) { + XMLDocument peerAdvDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(el); + remotePeerAdv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(peerAdvDoc); + } + + el = msg.getMessageElement(MSG_ELEMENT_NAMESPACE, credTag); + if (el != null) { + try { + XMLDocument credDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(el); + credential = group.getMembershipService().makeCredential(credDoc); + if (!checkCred(credential)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Invalid credential"); + } + return null; + } + } catch (Exception ignored) { + // ignored + } + } + + boolean isReliable = false; + + el = msg.getMessageElement(MSG_ELEMENT_NAMESPACE, streamTag); + if (el != null) { + isReliable = Boolean.valueOf(el.toString()); + } + + if ((null != remoteEphemeralPipeAdv) && (null != remotePeerAdv)) { + return createEphemeralSocket(group, pipeAdv, remoteEphemeralPipeAdv, remotePeerAdv, localCredential, credential, isReliable); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Connection message did not contain valid connection information."); + } + return null; + } + } catch (IOException e) { + // deal with the error + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "IOException occured", e); + } + } catch (RuntimeException e) { + // deal with the error + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception occured", e); + } + } + return null; + } + + /** + * Invokes the specified CredentialValidator to very a credential + * @param cred the credential + * @return true if valid, or if no validator is specified + */ + private boolean checkCred(Credential cred) { + return credValidator == null || credValidator.checkCred(cred); + } + + /** + * Construct the emphemeral socket result from accept. This method exists + * primarily so that sub-classes can substitute a different JxtaSocket + * sub-class. + * + * @param group The peer group for the socket. + * @param pipeAdv The public pipe advertisement. + * @param remoteEphemeralPipeAdv The pipe advertisement of the remote peer's + * ephemeral pipe. + * @param remotePeerAdv The peer advertisement of the remote peer. + * @param localCredential Our credential. + * @param credential The credential of the remote peer. + * @param isReliable if true, uses the reliability library in non-direct mode + * @return The new JxtaSocket instance. + * @throws IOException if an io error occurs + */ + protected JxtaSocket createEphemeralSocket(PeerGroup group, PipeAdvertisement pipeAdv, PipeAdvertisement remoteEphemeralPipeAdv, PeerAdvertisement remotePeerAdv, Credential localCredential, Credential credential, boolean isReliable) throws IOException { + return new JxtaSocket(group, pipeAdv, remoteEphemeralPipeAdv, remotePeerAdv, localCredential, credential, isReliable); + } + + /** + * Sets the credential to be used by this socket connection. If no + * credentials are set, the default group credential will be used. + * + * @param localCredential The credential to be used for connection responses + * or null if the default credential is to be used. + */ + public void setCredential(Credential localCredential) { + this.localCredential = localCredential; + } + + /** + * {@inheritDoc} + *

      + * This output is suitable for debugging but should not be parsed. All + * of the information is available through other means. + */ + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + + result.append(getClass().getName()); + result.append('@'); + result.append(System.identityHashCode(this)); + + result.append('['); + result.append(pipeAdv.getPipeID()); + result.append(']'); + + result.append(isClosed() ? " CLOSED :" : " OPEN :"); + result.append(isBound() ? " BOUND " : " UNBOUND "); + return result.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocket.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocket.java new file mode 100644 index 000000000..0296f0148 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocket.java @@ -0,0 +1,1804 @@ +/* + * Copyright (c) 2006-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.socket; + +import net.jxta.credential.Credential; +import net.jxta.document.*; +import net.jxta.endpoint.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.util.pipe.reliable.FixedFlowControl; +import net.jxta.impl.util.pipe.reliable.Outgoing; +import net.jxta.impl.util.pipe.reliable.OutgoingMsgrAdaptor; +import net.jxta.impl.util.pipe.reliable.ReliableInputStream; +import net.jxta.impl.util.pipe.reliable.ReliableOutputStream; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.*; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * JxtaSocket is a sub-class of java.net.socket, and should be used like a java.net.Socket. + * Key differences to keep in mind are the following : + *

      + * - JxtaSocket does not implement Nagle's algorithm, therefore at end of a data frame a flush must invoked to enure all + * buffered data is packaged and transmitted. + * - JxtaSocket does not implement keep-alive, therefore it is possible the underlaying messengers to be closed due to + * lack of inactivity, which manifests in a short latency, while the messenger are recreated. This limitation should cease + * to exist as soon the inactivity logic is removed. + * + */ +public class JxtaSocket extends Socket implements PipeMsgListener, OutputPipeListener { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(JxtaSocket.class.getName()); + private final static int MAXRETRYTIMEOUT = 120 * 1000; + private final static int DEFAULT_TIMEOUT = 15 * 1000; + + /** + * Default size for output buffers. Only used when we do not know the MTU + * size for messengers sending to the remote peer and as an upper bounds + * should the MTU size be really huge. + */ + private final static int DEFAULT_OUTPUT_BUFFER_SIZE = 256 * 1024; + + /** + * If true then this peer initiated the connection. + */ + private boolean initiator = false; + + /** + * The PeerGroup + */ + protected PeerGroup group; + + /** + * Pipe Advertisement of the well known pipe. + */ + protected PipeAdvertisement pipeAdv; + + /** + * Pipe Advertisement of local ephemeral pipe. + */ + protected PipeAdvertisement localEphemeralPipeAdv; + + /** + * The input pipe for our ephemeral pipe. We will receive all messages on this pipe. + */ + protected InputPipe localEphemeralPipeIn; + + /** + * Pipe Advertisement of it's ephemeral pipe. + */ + protected PipeAdvertisement remoteEphemeralPipeAdv; + + /** + * The Messenger we use to + */ + protected Messenger remoteEphemeralPipeMsgr; + + protected PipeService pipeSvc; + + /** + * The peer id of the peer we are connecting to or {@code null} if we are + * willing to connect to any peer. + */ + protected PeerID remotePeerID; + + /** + * Used to negotiate connection parameters + */ + protected OutputPipe connectOutpipe; + + /** + * The timeout of the read() of this socket's input stream + */ + private int soTimeout = 0; + + /** + * timeout for connect and close + */ + protected long timeout = 60 * 1000; + + /** + * retry timeout in millisecods + */ + protected int retryTimeout = 60 * 1000; + + /** + * maximum retry timeout allowed + */ + protected int maxRetryTimeout = MAXRETRYTIMEOUT; + + /** + * retry window size + */ + protected int windowSize = 20; + + /** + * Lock for output pipe resolution. + */ + protected final Object pipeResolveLock = new Object(); + + /** + * Lock for ephemeral pipe connect states. + */ + protected final Object socketConnectLock = new Object(); + + /** + * Lock for closing states. + */ + protected final Object closeLock = new Object(); + + /* + *used to determine whether to wait for an ack + */ + private boolean closeAckReceived = false; + + /** + * If {@code true} then this socket has been closed and can no longer be used. + */ + protected volatile boolean closed = false; + + /** + * If {@code true} then we believer our end of the connection is open. + */ + protected boolean bound = false; + + /** + * If {@code true} then we believe the remote peer currently has this socket open. + */ + protected boolean connected = false; + + /** + * Credential of the remote peer. + */ + protected Credential remoteCredential = null; + + /** + * Our credential that we provide to the remote peer. + */ + protected Credential localCredential = null; + + /** + * The remote peer advertisement. + */ + private PeerAdvertisement remotePeerAdv = null; + + /** + * If {@code true} then the socket is a stream socket otherwise it is a datagram socket. + */ + protected boolean isReliable = true; + + /** + * If {@code true} then the output stream has been shutdown. All attempts + * to write to the socket will fail. This socket can no longer be used to + * send data though it may remain capable of receiving data. + */ + private boolean outputShutdown = false; + + /** + * If {@code true} then the input stream has been shutdown. All attempts + * to read from the socket will fail. This socket can no longer be used to + * receive data though it may remain capable of sending data. + */ + private boolean inputShutdown = false; + + /** + * Used for sending all messages by the reliable output and input streams. + */ + protected Outgoing outgoing = null; + + /** + * The reliable input stream we use for receiving data if + * {@link #isReliable} is {@code true}. + */ + protected ReliableInputStream ris = null; + + /** + * The reliable output stream we use for sending data if + * {@link #isReliable} is {@code true}. + */ + protected ReliableOutputStream ros = null; + + /** + * The unreliable input stream we use for receiving data if + * {@link #isReliable} is {@code false}. + */ + protected JxtaSocketInputStream nonReliableInputStream = null; + + /** + * The unreliable output stream we use for sending data if + * {@link #isReliable} is {@code false}. + */ + protected JxtaSocketOutputStream nonReliableOutputStream = null; + + /** + * The size of the output buffers to use. If not set this defaults to the + * MTU size of the messenger to the remote peer. + */ + private int outputBufferSize = -1; + + /** + * This constructor does not establish a connection. Use this constructor + * when altering the default parameters, and options of the socket. + *

      + * By default connections are reliable, and the default timeout is 60 + * seconds. To alter a connection a call to create(false) changes the + * connection to an unreliable one. + */ + public JxtaSocket() {} + + /** + * This constructor is used by JxtaServer socket for creating JxtaSocket + * instances in response to incoming connections. + * + * @param group group context + * @param pipeAdv The original PipeAdvertisement + * @param localCredential Our credential. + * @param remoteEphemeralPipeAdv the phemeral pipe advertisement + * @param remotePeerAdv remote peer advertisement + * @param remoteCredential The remote peer's credential. + * @param isReliable {@code true} for reliable stream connection or + * {@code false} for unreliable stream connection. + * @throws IOException if an io error occurs + */ + protected JxtaSocket(PeerGroup group, PipeAdvertisement pipeAdv, PipeAdvertisement remoteEphemeralPipeAdv, PeerAdvertisement remotePeerAdv, Credential localCredential, Credential remoteCredential, boolean isReliable) throws IOException { + + this.initiator = false; + this.group = group; + this.pipeAdv = pipeAdv; + this.remoteEphemeralPipeAdv = remoteEphemeralPipeAdv; + this.localEphemeralPipeAdv = newEphemeralPipeAdv(pipeAdv); + this.remotePeerAdv = remotePeerAdv; + this.remotePeerID = remotePeerAdv.getPeerID(); + this.localCredential = localCredential; + this.remoteCredential = remoteCredential; + this.isReliable = isReliable; + + pipeSvc = group.getPipeService(); + bind(); + connect(); + + Message connectResponse = createConnectMessage(group, localEphemeralPipeAdv, localCredential, isReliable, initiator); + + remoteEphemeralPipeMsgr.sendMessage(connectResponse); + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("New socket : " + this); + } + } + + /** + * Create a JxtaSocket connected to the give JxtaSocketAddress. + * + * @param address JxtaSocketAddress to connect to + * @throws IOException if an io error occurs + */ + public JxtaSocket(SocketAddress address) throws IOException { + connect(address, DEFAULT_TIMEOUT); + } + + /** + * Create a JxtaSocket to any node listening on pipeAdv + * + * @param group group context + * @param pipeAdv PipeAdvertisement + * @throws IOException if an io error occurs + */ + public JxtaSocket(PeerGroup group, PipeAdvertisement pipeAdv) throws IOException { + connect(group, pipeAdv); + } + + /** + * Create a JxtaSocket to the given JxtaSocketAddress, within the timeout + * specified in milliseconds. + * + * @param address JxtaSocket address to connect to + * @param timeout The number of milliseconds within which the socket must + * be successfully created. An exception will be thrown if the socket + * cannot be created in the allotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @throws IOException For failures in creating the socket. + * @throws SocketTimeoutException If the socket cannot be created before + * the timeout occurs. + */ + public JxtaSocket(SocketAddress address, int timeout) throws IOException { + connect(address, timeout); + } + + /** + * Create a JxtaSocket to any peer listening on pipeAdv this attempts + * establish a connection to specified pipe within the context of the + * specified group within timeout specified in milliseconds. + * + * @param group group context + * @param pipeAdv PipeAdvertisement + * @param timeout The number of milliseconds within which the socket must + * be successfully created. An exception will be thrown if the socket + * cannot be created in the allotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @throws IOException if an io error occurs + * @throws SocketTimeoutException If the socket cannot be created before + * the timeout occurs. + */ + public JxtaSocket(PeerGroup group, PipeAdvertisement pipeAdv, int timeout) throws IOException { + connect(group, pipeAdv, timeout); + } + + /** + * Create a JxtaSocket to any peer listening on pipeAdv + * this attempts establish a connection to specified + * pipe within a context of group and within the timeout specified in milliseconds + * + * @param group group context + * @param peerid node to connect to + * @param pipeAdv PipeAdvertisement + * @param timeout The number of milliseconds within which the socket must + * be successfully created. An exception will be thrown if the socket + * cannot be created in the allotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @throws IOException For failures in creating the socket. + * @throws SocketTimeoutException If the socket cannot be created before + * the timeout occurs. + */ + public JxtaSocket(PeerGroup group, PeerID peerid, PipeAdvertisement pipeAdv, int timeout) throws IOException { + connect(group, peerid, pipeAdv, timeout); + } + + /** + * Create a JxtaSocket to the given JxtaSocketAddress, within the timeout + * specified in milliseconds. The JxtaSocket can be reliable (stream) or + * not (datagram). If you want to use a SocketAddress in the constructor, + * this is the preferred method. Either that, or use JxtaSocket(), followed + * by create(boolean) to turn on reliability, followed by + * connect(SocketAddress, int) or connect(SocketAddress) to make the + * connection. + * + * @param address JxtaSocket address to connect to + * @param timeout The number of milliseconds within which the socket must + * be successfully created. An exception will be thrown if the socket + * cannot be created in the allotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @param reliable {@code true} for reliable stream connection or + * {@code false} for unreliable stream connection. + * @throws IOException For failures in creating the socket. + * @throws SocketTimeoutException If the socket cannot be created before + * the timeout occurs. + */ + public JxtaSocket(SocketAddress address, int timeout, boolean reliable) throws IOException { + this.isReliable = reliable; + connect(address, timeout); + } + + /** + * Create a JxtaSocket to any peer listening on pipeAdv + * this attempts establish a connection to specified + * pipe within a context of group and within the timeout specified in milliseconds + * + * @param group group context + * @param peerid node to connect to + * @param pipeAdv PipeAdvertisement + * @param timeout The number of milliseconds within which the socket must + * be successfully created. An exception will be thrown if the socket + * cannot be created in the allotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @param reliable {@code true} for reliable stream connection or + * {@code false} for unreliable stream connection. + * @throws IOException For failures in creating the socket. + * @throws SocketTimeoutException If the socket cannot be created before + * the timeout occurs. + */ + public JxtaSocket(PeerGroup group, PeerID peerid, PipeAdvertisement pipeAdv, int timeout, boolean reliable) throws IOException { + + this.isReliable = reliable; + connect(group, peerid, pipeAdv, timeout); + } + + /** + * {@inheritDoc} + */ + @Override + protected void finalize() throws Throwable { + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("JxtaSocket is being finalized without being previously closed. This is likely a users bug."); + } + } + close(); + super.finalize(); + } + + /** + * Creates either a stream or a datagram socket. + * + * @param reliable {@code true} for reliable stream connection or {@code false} for unreliable stream connection. + * @throws IOException if an I/O error occurs while creating the socket. + * @deprecated Unreliable mode is being removed. Use JxtaBiDiPipe instead. + */ + @Deprecated + public void create(boolean reliable) throws IOException { + if (isBound()) { + throw new IOException("Socket already bound, it is not possible to change connection type"); + } + this.isReliable = reliable; + } + + /** + * {@inheritDoc} + *

      + * Unsupported operation, an IOException will be thrown. + * + * @throws IOException Thrown in all cases as this operation is not supported. + */ + @Override + public void bind(SocketAddress address) throws IOException { + throw new IOException("Unsupported operation, use java.net.Socket instead"); + } + + /** + * {@inheritDoc} + *

      + * The default connect timeout of 60 seconds is used If SocketAddress is not an instance of JxtaSocketAddress, an + * IOException will be thrown. + */ + @Override + public void connect(SocketAddress address) throws IOException { + connect(address, DEFAULT_TIMEOUT); + } + + /** + * {@inheritDoc} + *

      + * If SocketAddress is not an instance of JxtaSocketAddress, an IOException will be thrown. + */ + @Override + public void connect(SocketAddress address, int timeout) throws IOException { + if (!(address instanceof JxtaSocketAddress)) { + throw new IOException("Subclass of SocketAddress not supported. Use JxtaSocketAddress instead."); + } + JxtaSocketAddress socketAddress = (JxtaSocketAddress) address; + PeerGroup pg = PeerGroup.globalRegistry.lookupInstance(socketAddress.getPeerGroupId()); + + if (pg == null) { + throw new IOException("Can't connect socket in PeerGroup with id " + socketAddress.getPeerGroupId() + + ". No running instance of the group is registered."); + } + connect(pg.getWeakInterface(), socketAddress.getPeerId(), socketAddress.getPipeAdv(), timeout); + pg.unref(); + } + + /** + * Connects to a JxtaServerSocket on any peer within the default timeout of 60 seconds + * + * @param group group context + * @param pipeAdv PipeAdvertisement + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PipeAdvertisement pipeAdv) throws IOException { + connect(group, pipeAdv, DEFAULT_TIMEOUT); + } + + /** + * Connects to a JxtaServerSocket on any peer within a timeout specified in milliseconds + * + * @param group group context + * @param pipeAdv PipeAdvertisement + * @param timeout in milliseconds + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PipeAdvertisement pipeAdv, int timeout) throws IOException { + connect(group, null, pipeAdv, timeout); + } + + /** + * Connects to a JxtaServerSocket on a specific peer within a timeout specified in milliseconds + * + * @param group group context + * @param peerid peer to connect to + * @param pipeAdv PipeAdvertisement + * @param timeout timeout in milliseconds + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PeerID peerid, PipeAdvertisement pipeAdv, int timeout) throws IOException { + if (PipeService.PropagateType.equals(pipeAdv.getType())) { + throw new IOException("Propagate pipe advertisements are not supported"); + } + + if (timeout < 0) { + throw new IllegalArgumentException("timeout may not be negative"); + } + + this.initiator = true; + this.group = group; + this.remotePeerID = peerid; + this.pipeAdv = pipeAdv; + this.localEphemeralPipeAdv = newEphemeralPipeAdv(pipeAdv); + this.timeout = (timeout == 0) ? Long.MAX_VALUE : timeout; + + pipeSvc = group.getPipeService(); + bind(); + Message openMsg = createConnectMessage(group, localEphemeralPipeAdv, localCredential, isReliable, initiator); + long connectTimeoutAt = System.currentTimeMillis() + timeout; + + if (connectTimeoutAt < timeout) { + // ensure no overflow + connectTimeoutAt = Long.MAX_VALUE; + } + + // Create the output pipe and send this message. Need to retry the call + // to createOutputPipe. If there is no rendezvous yet and the + // destination is not reachable by mcast, then createOutputPipe has no + // effect. We repeat it with exponential delays. + if (peerid == null) { + pipeSvc.createOutputPipe(pipeAdv, this); + } else { + pipeSvc.createOutputPipe(pipeAdv, Collections.singleton(peerid), this); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Beginning Output Pipe Resolution. " + this); + } + + // Wait for the pipe resolution. + synchronized (pipeResolveLock) { + while (connectOutpipe == null) { + try { + long waitFor = connectTimeoutAt - System.currentTimeMillis(); + + if (waitFor <= 0) { + // too late + break; + } + if (connectOutpipe == null) { + // in case the pipe is resolved + pipeResolveLock.wait(waitFor); + } + } catch (InterruptedException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", ie); + } + Thread.interrupted(); + SocketException exp = new SocketException("Connect Interrupted"); + exp.initCause(ie); + throw exp; + } + } + } + + if (connectOutpipe == null) { + throw new SocketTimeoutException("Connection (resolution) timeout"); + } + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Sending connect message. " + this); + } + + // send connect message + connectOutpipe.send(openMsg); + + // wait for the connect response. + synchronized (socketConnectLock) { + while (!isConnected()) { + try { + long waitFor = connectTimeoutAt - System.currentTimeMillis(); + if (waitFor <= 0) { + // too late + break; + } + socketConnectLock.wait(waitFor); + } catch (InterruptedException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", ie); + } + Thread.interrupted(); + SocketException exp = new SocketException("Connect Interrupted"); + exp.initCause(ie); + throw exp; + } + } + } + } finally { + connectOutpipe.close(); + connectOutpipe = null; + } + + if (!isConnected()) { + throw new SocketTimeoutException("Connection timeout (connect)"); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("New socket connection : " + this); + } + } + + /** + * obtain the cred doc from the group object + * + * @param group the group context + * @return The Credential value + */ + protected static Credential getDefaultCredential(PeerGroup group) { + try { + MembershipService membership = group.getMembershipService(); + return membership.getDefaultCredential(); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to get credential", e); + } + } + return null; + } + + /** + * get the remote credential doc + * + * @return Credential StructuredDocument + */ + public Credential getCredentialDoc() { + try { + return remoteCredential; + } catch (Exception failure) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to generate credential document ", failure); + } + return null; + } + } + + /** + * Sets our credential to be used by this socket connection. If no + * credentials are set, the default group credential will be used. + * + * @param localCredential The credential to be used for connection responses + * or null if the default credential is to be used. + */ + public void setCredential(Credential localCredential) { + if (localCredential == null) { + this.localCredential = localCredential; + } else { + try { + MembershipService membership = group.getMembershipService(); + this.localCredential = membership.getDefaultCredential(); + } catch (Exception failed) { + this.localCredential = null; + } + } + } + + /** + * Create a connection request/response message + * + * @param group The group in which the socket is being used. + * @param pipeAdv Advertisement for our ephemeral pipe. + * @param credential Our credential or null if default credential is to + * be used. + * @param isReliable The socket is to be reliable (stream). + * @param initiator indicates initiator + * @return The message. + * @throws IOException if an I/O error occurs + */ + protected Message createConnectMessage(PeerGroup group, PipeAdvertisement pipeAdv, Credential credential, boolean isReliable, boolean initiator) throws IOException { + + Message msg = new Message(); + + if (credential == null) { + credential = getDefaultCredential(group); + } + + if ((credential == null) && PipeService.UnicastSecureType.equals(pipeAdv.getType())) { + throw new IOException("Credentials must be established to initiate a secure connection."); + } + + if (credential != null) { + try { + XMLDocument credDoc = (XMLDocument) credential.getDocument(MimeMediaType.XMLUTF8); + + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + new TextDocumentMessageElement(JxtaServerSocket.credTag, credDoc, null)); + } catch (Exception failed) { + IOException failure = new IOException("Could not generate credential element."); + failure.initCause(failed); + throw failure; + } + } + + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + new TextDocumentMessageElement(initiator ? JxtaServerSocket.reqPipeTag : JxtaServerSocket.remPipeTag, + (XMLDocument) pipeAdv.getDocument(MimeMediaType.XMLUTF8), null)); + + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + new TextDocumentMessageElement(JxtaServerSocket.remPeerTag, + (XMLDocument) group.getPeerAdvertisement().getDocument(MimeMediaType.XMLUTF8), null)); + + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + new StringMessageElement(JxtaServerSocket.streamTag, Boolean.toString(isReliable), null)); + + return msg; + } + + /** + * Create a pipe advertisement for an ephemeral pipe (w/random pipe ID) from an existing pipe advertisement. + * The specified pipe adveritsement is only used for the name and type + * + * @param pipeAdv to get the basename and type from + * @return A new pipe advertisement for an ephemeral pipe. + */ + protected static PipeAdvertisement newEphemeralPipeAdv(PipeAdvertisement pipeAdv) { + PipeAdvertisement adv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + PeerGroupID gid = (PeerGroupID) ((PipeID) pipeAdv.getPipeID()).getPeerGroupID(); + adv.setPipeID(IDFactory.newPipeID(gid)); + adv.setName(pipeAdv.getName() + ".remote"); + adv.setType(pipeAdv.getType()); + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isBound() { + return bound; + } + + /** + * Sets whether this socket is currently bound or not. A socket is considered bound if the local resources required + * in order to interact with a remote peer are allocated and open. + * + * @param boundState The new bound state. + */ + private void setBound(boolean boundState) { + bound = boundState; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isConnected() { + return connected; + } + + /** + * Sets whether this socket is currently connected or not. A socket is + * considered connected if is believed that the Socket's remote peer has + * the resources required in order to interact with a local peer (us) + * allocated and open. + * + * @param connectedState The new connected state. + */ + private void setConnected(boolean connectedState) { + connected = connectedState; + } + + /** + * Opens our ephemeral input pipe enabling us to receive messages. + * + * @throws IOException Thrown for errors in creating the input pipe. + */ + private void bind() throws IOException { + this.localEphemeralPipeIn = pipeSvc.createInputPipe(localEphemeralPipeAdv, this); + // The socket is bound now. + setBound(true); + } + + /** + * Create an appropriate Outgoing Adaptor. This method exists primarily + * so that sub-classes can substitute a different Outgoing sub-class. + * + * @param msgr The messenger to be wrapped. + * @param timeout The timeout value; + * @return Outgoing The messenger wrapped in an appropriate adaptor. + */ + protected Outgoing makeOutgoing(Messenger msgr, long timeout) { + return new OutgoingMsgrAdaptor(msgr, (int) timeout); + } + + /** + * Opens the ephemeral output pipe for the remote peer. Also opens the + * input and output streams. (delaying adds complexity). + * + * @throws IOException Thrown for errors in opening resources. + */ + private void connect() throws IOException { + + remoteEphemeralPipeMsgr = lightweightOutputPipe(group, remoteEphemeralPipeAdv, remotePeerAdv); + + if (remoteEphemeralPipeMsgr == null) { + throw new IOException("Could not create messenger back to connecting peer"); + } + + // Force the buffer size smaller if user set it too high. + if (remoteEphemeralPipeMsgr.getMTU() < outputBufferSize) { + outputBufferSize = Math.min((int) remoteEphemeralPipeMsgr.getMTU(), DEFAULT_OUTPUT_BUFFER_SIZE); + } + + if (outputBufferSize == -1) { + outputBufferSize = Math.min((int) remoteEphemeralPipeMsgr.getMTU(), DEFAULT_OUTPUT_BUFFER_SIZE); + } + + // Force the creation of the inputStream now. Waiting until someone + // calls getInputStream() would likely cause us to drop messages. + if (isReliable) { + outgoing = makeOutgoing(remoteEphemeralPipeMsgr, retryTimeout); + ris = new ReliableInputStream(outgoing, soTimeout); + ros = new ReliableOutputStream(outgoing, new FixedFlowControl(windowSize)); + try { + ros.setSendBufferSize(outputBufferSize); + } catch (IOException ignored) {// it's only a preference... + } + } else { + nonReliableInputStream = new JxtaSocketInputStream(this, windowSize); + nonReliableOutputStream = new JxtaSocketOutputStream(this, outputBufferSize); + } + + // the socket is now connected! + setConnected(true); + } + + /** + * Returns the internal output stream buffer size + * + * @return the internal buffer size. + * @deprecated Use the standard {@link #getSendBufferSize()} method instead. + */ + @Deprecated + public int getOutputStreamBufferSize() { + return (outputBufferSize == -1) ? DEFAULT_OUTPUT_BUFFER_SIZE : outputBufferSize; + } + + /** + * Sets the internal output stream buffer size. + * + * @param size The internal buffer size. + * @throws IOException if an I/O error occurs + * @deprecated Use the standard {@link #setSendBufferSize(int)} method instead. + */ + @Deprecated + public void setOutputStreamBufferSize(int size) throws IOException { + setSendBufferSize(size); + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream getInputStream() throws IOException { + checkState(); + + if (isInputShutdown()) { + throw new SocketException("Input already shutdown."); + } + + if (isReliable) { + return ris; + } else { + return nonReliableInputStream; + } + } + + /** + * {@inheritDoc} + */ + @Override + public OutputStream getOutputStream() throws IOException { + checkState(); + if (isOutputShutdown()) { + throw new SocketException("Output already shutdown."); + } + return isReliable ? ros : nonReliableOutputStream; + } + + /** + * {@inheritDoc} + *

      + * We hard-close both the input and output streams. Nothing can be + * written or read to the socket after this method. Any queued incoming + * data is discarded. Any additional incoming messages will be ACKed but + * their content will be discarded. We will attempt to send any data which + * has already been written to the OutputStream. + *

      + * Once the output queue is empty we will send a close message to tell + * the remote side that no more data is coming. + *

      + * This is the only method in this class which is {@code synchronized}. + * All others use internal synchronization. + */ + @Override + public synchronized void close() throws IOException { + try { + synchronized (closeLock) { + long closeEndsAt = System.currentTimeMillis() + timeout; + + if (closeEndsAt < timeout) { + closeEndsAt = Long.MAX_VALUE; + } + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing " + this + " timeout=" + timeout + "ms."); + } + if (closed) { + return; + } + + closed = true; + shutdownOutput(); + shutdownInput(); + while (isConnected()) { + long closingFor = closeEndsAt - System.currentTimeMillis(); + + if (closingFor <= 0) { + break; + } + + if (isReliable) { + try { + if (ros.isQueueEmpty()) { + // Only send a close if the queue is empty. + sendClose(); + } else { + // Reliable Output Stream not empty. Don't send close yet. + ros.waitQueueEmpty(1000); + continue; + } + } catch (InterruptedException woken) { + Thread.interrupted(); + break; + } + } else { + sendClose(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent close, awaiting ACK for " + this); + } + + // Don't send our close too many times. + try { + long nextTry = Math.min(20000, closingFor); + + if (nextTry > 0 && isConnected()) { + closeLock.wait(nextTry); + } + } catch (InterruptedException woken) { + Thread.interrupted(); + break; + } + } + + if (isConnected()) { + // Last ditch close attempt + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Still connected at end of timeout. Forcing closed." + this); + } + sendClose(); + throw new SocketTimeoutException("Failed to receive close ack from remote connection."); + } + } + } finally { + // No matter what else happens at the end of close() we are no + // longer connected and no longer bound. + setConnected(false); + unbind(); + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Socket closed : " + this); + } + } + } + + /** + * This is called when closure is initiated on the remote side. By + * convention we receive the close message only after we have ACKed the last + * data segment. + *

      + * We soft-close the InputStream which allows us to read data already + * received. + *

      + * We hard-close our output stream and discard all queued, unACKed data + * as the remote side doesn't want to receive it (the remote side has + * already unbound themselves, they just want our close ACK in order to clean + * up.) + * + * @throws IOException if an I/O error occurs + */ + protected void closeFromRemote() throws IOException { + synchronized (closeLock) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.INFO)) { + LOG.info("Received a remote close request." + this); + } + + if (isConnected()) { + setConnected(false); + if (isReliable) { + ris.softClose(); + ros.hardClose(); + } else { + nonReliableInputStream.softClose(); + nonReliableOutputStream.hardClose(); + } + } + + // If we are still bound then send them a close ACK. + if (isBound() && (ros != null && ros.isQueueEmpty())) { + // do not ack until the queue is empty + sendCloseACK(); + } + if (closeAckReceived) { + closeLock.notifyAll(); + } + } + } + + /** + * Closes the input pipe which we use to receive messages and the messenger + * used for sending messages. + */ + protected synchronized void unbind() { + if (!isBound()) { + return; + } + + if (isReliable) { + try { + ris.close(); + } catch (IOException ignored) {// ignored + } + + ros.hardClose(); + } else { + nonReliableInputStream.close(); + nonReliableOutputStream.hardClose(); + } + + // We are no longer bound + setBound(false); + + // close pipe and messenger + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Closing ephemeral input pipe"); + } + + localEphemeralPipeIn.close(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Closing remote ephemeral pipe messenger"); + } + + if(null != outgoing) { + outgoing.close(); + } + remoteEphemeralPipeMsgr.close(); + } + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "Pipe Message Event for " + this + "\n\t" + event.getMessage() + " for " + event.getPipeID()); + } + + Message message = event.getMessage(); + if (message == null) { + return; + } + + // look for close request/ack + MessageElement element = message.getMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, JxtaServerSocket.closeTag); + + if (element != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Handling a close message " + this + " : " + element.toString()); + } + if (JxtaServerSocket.closeReqValue.equals(element.toString())) { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received a close request"); + } + closeFromRemote(); + } catch (IOException ie) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "failed during closeFromRemote", ie); + } + } + } else if (JxtaServerSocket.closeAckValue.equals(element.toString())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received a close acknowledgement"); + } + synchronized (closeLock) { + closeAckReceived = true; + setConnected(false); + closeLock.notifyAll(); + } + } + return; + } + + if (!isConnected()) { + // connect response + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Processing connect response : " + message); + } + + // look for a remote pipe answer + element = message.getMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, JxtaServerSocket.remPipeTag); + PipeAdvertisement incomingPipeAdv = null; + + if (element != null) { + try { + XMLDocument pipeAdvDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(element); + + incomingPipeAdv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(pipeAdvDoc); + } catch (IOException badPipeAdv) {// ignored + } + } + + element = message.getMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, JxtaServerSocket.remPeerTag); + PeerAdvertisement incomingRemotePeerAdv = null; + + if (element != null) { + try { + XMLDocument peerAdvDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(element); + incomingRemotePeerAdv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(peerAdvDoc); + } catch (IOException badPeerAdv) {// ignored + } + } + + element = message.getMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, JxtaServerSocket.credTag); + Credential incomingCredential = null; + + if (element != null) { + try { + StructuredDocument incomingCredentialDoc = StructuredDocumentFactory.newStructuredDocument(element); + incomingCredential = group.getMembershipService().makeCredential(incomingCredentialDoc); + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unable to generate credential for " + this, failed); + } + } + } + + element = message.getMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, JxtaServerSocket.streamTag); + boolean incomingIsReliable = isReliable; + + if (element != null) { + incomingIsReliable = Boolean.valueOf(element.toString()); + } + + if ((null != incomingPipeAdv) && (null != incomingRemotePeerAdv)) { + if ((null != remotePeerID) && (remotePeerID != incomingRemotePeerAdv.getPeerID())) { + // let the connection attempt timeout + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning( + "Connection response from wrong peer! " + remotePeerID + " != " + + incomingRemotePeerAdv.getPeerID()); + } + return; + } + + synchronized (socketConnectLock) { + if (!isConnected()) { + remoteCredential = incomingCredential; + remotePeerAdv = incomingRemotePeerAdv; + remotePeerID = incomingRemotePeerAdv.getPeerID(); + remoteEphemeralPipeAdv = incomingPipeAdv; + isReliable = incomingIsReliable; + + // Force the creation of the inputStream now. Waiting until someone + // calls getInputStream() would likely cause us to drop messages. + + // FIXME: it would be even better if we could create the + // input stream BEFORE having the output pipe resolved, but + // that would force us to have the MsrgAdaptor block + // until we can give it the real pipe or msgr... later. + try { + connect(); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Connection failed : " + this, failed); + } + return; + } + socketConnectLock.notify(); + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "New Socket Connection : " + this); + } + } + } + return; + } + } + + // Often we are called to handle data before the socket is connected. + synchronized (socketConnectLock) { + long timeoutAt = System.currentTimeMillis() + timeout; + if (timeoutAt < timeout) { + timeoutAt = Long.MAX_VALUE; + } + + while (!isClosed() && !isConnected()) { + long waitFor = timeoutAt - System.currentTimeMillis(); + + if (waitFor <= 0) { + break; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Holding " + message + " for " + timeout); + } + + try { + socketConnectLock.wait(timeout); + } catch (InterruptedException woken) { + return; + } + } + } + + if (!isReliable) { + // is there data ? + Iterator dataElements = message.getMessageElements(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + JxtaServerSocket.dataTag); + + while (dataElements.hasNext()) { + MessageElement anElement = dataElements.next(); + nonReliableInputStream.enqueue(anElement); + } + } else { + // Give ACKs to the Reliable Output Stream + if (ros != null) { + ros.recv(message); + } + // Give data blocks to the Reliable Input Stream + if (ris != null) { + ris.recv(message); + } + } + } + + /** + * {@inheritDoc} + */ + public void outputPipeEvent(OutputPipeEvent event) { + OutputPipe op = event.getOutputPipe(); + + if (op.getAdvertisement() == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("The output pipe has no internal pipe advertisement. discarding event"); + } + return; + } + // name can be different, therefore check the id + type + if (pipeAdv.getID().equals(op.getAdvertisement().getID()) && pipeAdv.getType().equals(op.getAdvertisement().getType())) { + synchronized (pipeResolveLock) { + // modify op within lock to prevent a race with the if. + if (connectOutpipe == null) { + connectOutpipe = op; + // if not null, will be closed. + op = null; + } + pipeResolveLock.notify(); + } + // Ooops one too many, we were too fast re-trying. + if (op != null) { + op.close(); + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unexpected OutputPipe :" + op); + } + } + } + + /** + * A lightweight output pipe constructor, note the return type + * Since all the info needed is available, there's no need for to use the pipe service + * to resolve the pipe we have all we need to construct a messenger. + * + * @param group group context + * @param pipeAdv Remote Pipe Advertisement + * @param peerAdv Remote Peer Advertisement + * @return Messenger + */ + protected static Messenger lightweightOutputPipe(PeerGroup group, PipeAdvertisement pipeAdv, PeerAdvertisement peerAdv) { + EndpointService endpoint = group.getEndpointService(); + ID opId = pipeAdv.getPipeID(); + String destPeer = peerAdv.getPeerID().getUniqueValue().toString(); + + // Get an endpoint messenger to that address + EndpointAddress addr; + RouteAdvertisement routeHint = net.jxta.impl.endpoint.EndpointUtils.extractRouteAdv(peerAdv); + if (pipeAdv.getType().equals(PipeService.UnicastType)) { + addr = new EndpointAddress("jxta", destPeer, "PipeService", opId.toString()); + } else if (pipeAdv.getType().equals(PipeService.UnicastSecureType)) { + addr = new EndpointAddress("jxtatls", destPeer, "PipeService", opId.toString()); + } else { + // not a supported type + throw new IllegalArgumentException(pipeAdv.getType() + " is not a supported pipe type"); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New pipe lightweight messenger for " + addr); + } + return endpoint.getMessenger(addr, routeHint); + } + + /** + * Sends a close message + * @throws IOException if an io error occurs + */ + private void sendClose() throws IOException { + Message msg = new Message(); + + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE + , + new StringMessageElement(JxtaServerSocket.closeTag, JxtaServerSocket.closeReqValue, null)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a close request " + this + " : " + msg); + } + remoteEphemeralPipeMsgr.sendMessageN(msg, null, null); + } + + /** + * Sends a close ack message + * @throws IOException if an io error occurs + */ + private void sendCloseACK() throws IOException { + Message msg = new Message(); + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + new StringMessageElement(JxtaServerSocket.closeTag, JxtaServerSocket.closeAckValue, null)); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a close ACK " + this + " : " + msg); + } + remoteEphemeralPipeMsgr.sendMessageN(msg, null, null); + } + + /** + * {@inheritDoc} + */ + @Override + public int getSoTimeout() throws SocketException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + if (timeout > Integer.MAX_VALUE) { + return 0; + } else { + return (int) timeout; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setSoTimeout(int soTimeout) throws SocketException { + if (soTimeout < 0) { + throw new IllegalArgumentException("Invalid Socket timeout :" + soTimeout); + } + + this.timeout = soTimeout; + if (!isBound()) { + return; + } + + // If we are bound then set the timeout on the streams. + // FIXME, ros does not define a timeout as it only relies on window saturation, it should take into account + // the socket timeout + if (isReliable) { + if (ris != null) { + ris.setTimeout(soTimeout); + } + } else { + nonReliableInputStream.setTimeout((long) soTimeout); + } + } + + /** + * Gets the Maximum Retry Timeout of the reliability layer + * + * @return The maximum retry Timeout value + * @deprecated The reliability layer manages it's own maximum. This value is not useful. + */ + @Deprecated + public int getMaxRetryTimeout() { + return maxRetryTimeout; + } + + /** + * Gets the Maximum Retry Timeout of the reliability layer + * + * @param maxRetryTimeout The new maximum retry timeout value + * @throws IllegalArgumentException if maxRetryTimeout exceeds jxta platform maximum retry timeout + * @deprecated The reliability layer manages it's own maximum. This value is not useful. + */ + @Deprecated + public void setMaxRetryTimeout(int maxRetryTimeout) { + if (maxRetryTimeout <= 0 || maxRetryTimeout > MAXRETRYTIMEOUT) { + throw new IllegalArgumentException("Invalid Maximum retry timeout :" + maxRetryTimeout + " Exceed Global maximum retry timeout :" + + MAXRETRYTIMEOUT); + } + this.maxRetryTimeout = maxRetryTimeout; + } + + /** + * Gets the Retry Timeout of the reliability layer + * + * @return The retry Timeout value + */ + public int getRetryTimeout() { + return retryTimeout; + } + + /** + * Sets the Retry Timeout of the underlying reliability layer. + * In reliable mode it is possible for this call to block + * trying to obtain a lock on reliable input stream + * + * @param retryTimeout The new retry timeout value + * @throws SocketException if an I/O error occurs + */ + public void setRetryTimeout(int retryTimeout) throws SocketException { + if (retryTimeout <= 0 || retryTimeout > maxRetryTimeout) { + throw new IllegalArgumentException("Invalid Retry Socket timeout :" + retryTimeout); + } + this.retryTimeout = retryTimeout; + if (outgoing != null) { + outgoing.setTimeout(retryTimeout); + } + } + + /** + * When in reliable mode, gets the Reliable library window size + * + * @return The windowSize value + */ + public int getWindowSize() { + return windowSize; + } + + /** + * When in reliable mode, sets the Reliable library window size + * + * @param windowSize The new window size value + * @throws SocketException if an I/O error occurs + */ + public void setWindowSize(int windowSize) throws SocketException { + if (isBound()) { + throw new SocketException("Socket bound. Can not change the window size"); + } + this.windowSize = windowSize; + } + + /** + * Returns the closed state of the JxtaSocket. + * + * @return true if the socket has been closed + */ + @Override + public boolean isClosed() { + return closed; + } + + /** + * Performs on behalf of JxtaSocketOutputStream. + * + * @param buf the data. + * @param offset the start offset in the data. + * @param length the number of bytes to write. + * @throws IOException if an I/O error occurs + * @see java.io.OutputStream#write + */ + protected void write(byte[] buf, int offset, int length) throws IOException { + checkState(); + if (isReliable) { + ros.write(buf, offset, length); + } else { + byte[] bufCopy = new byte[length]; + System.arraycopy(buf, offset, bufCopy, 0, length); + + Message msg = new Message(); + msg.addMessageElement(JxtaServerSocket.MSG_ELEMENT_NAMESPACE, + new ByteArrayMessageElement(JxtaServerSocket.dataTag, MimeMediaType.AOS, bufCopy, 0, length, null)); + remoteEphemeralPipeMsgr.sendMessageB(msg, null, null); + } + } + + /** + * @throws SocketException if closed, not bound or not connected. + */ + private void checkState() throws SocketException { + if (isClosed()) { + throw new SocketException("Socket is closed."); + } else if (!isBound()) { + throw new SocketException("Socket not bound."); + } else if (!isConnected()) { + throw new SocketException("Socket not connected."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getSendBufferSize() throws SocketException { + if (isOutputShutdown()) { + throw new SocketException("Socket is closed"); + } + return (outputBufferSize == -1) ? DEFAULT_OUTPUT_BUFFER_SIZE : outputBufferSize; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSendBufferSize(int size) throws SocketException { + if (isOutputShutdown()) { + throw new SocketException("Socket is closed"); + } + + if (size < 1) { + throw new IllegalArgumentException("negative/zero buffer size"); + } + + if ((null != remoteEphemeralPipeMsgr) && (size > remoteEphemeralPipeMsgr.getMTU())) { + throw new IllegalArgumentException("Buffer size larger than limit : " + remoteEphemeralPipeMsgr.getMTU()); + } + + outputBufferSize = size; + if (null != ros) { + try { + ros.setSendBufferSize(size); + } catch (SocketException failure) { + throw failure; + } catch (IOException failed) { + SocketException failure = new SocketException("Failed"); + + failure.initCause(failed); + throw failure; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getReceiveBufferSize() throws SocketException { + if (isInputShutdown()) { + throw new SocketException("Socket is closed"); + } + // this is just rough size + return outputBufferSize * windowSize; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean getKeepAlive() throws SocketException { + if (inputShutdown) { + throw new SocketException("Socket is closed"); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int getTrafficClass() throws SocketException { + throw new SocketException("TrafficClass not yet defined"); + } + + /** + * {@inheritDoc} + */ + @Override + public void setTrafficClass(int tc) throws SocketException { + // a place holder when and if we decide to add hints regarding + // flow info hints such as (IPTOS_LOWCOST (0x02), IPTOS_RELIABILITY (0x04), etc + throw new SocketException("TrafficClass not yet defined"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isInputShutdown() { + return inputShutdown; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOutputShutdown() { + return outputShutdown; + } + + /** + * {@inheritDoc} + */ + @Override + public void sendUrgentData(int data) throws IOException { + throw new SocketException("Urgent data not supported"); + } + + /** + * {@inheritDoc} + */ + @Override + public void setOOBInline(boolean state) throws SocketException { + throw new SocketException("Enable/disable OOBINLINE supported"); + } + + /** + * {@inheritDoc} + */ + @Override + public void setKeepAlive(boolean state) throws SocketException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + throw new SocketException("Operation not supported"); + } + + /** + * {@inheritDoc} + */ + @Override + public void shutdownInput() throws IOException { + inputShutdown = true; + if (isReliable) { + // hard close (EOF on next read) + ris.close(); + } else { + // hard close (EOF on next read) + nonReliableInputStream.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void shutdownOutput() throws IOException { + outputShutdown = true; + if (isReliable) { + ros.setLingerDelay(timeout); + // soft close (finish sending if you can) + ros.close(); + } else { + // soft close (finish sending if you can) + nonReliableOutputStream.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public SocketAddress getLocalSocketAddress() { + if (!isBound()) { + return null; + } + return new JxtaSocketAddress(group, localEphemeralPipeAdv, group.getPeerAdvertisement()); + } + + /** + * {@inheritDoc} + */ + @Override + public SocketAddress getRemoteSocketAddress() { + if (!isConnected()) { + return null; + } + return new JxtaSocketAddress(group, remoteEphemeralPipeAdv, remotePeerAdv); + } + + /** + * {@inheritDoc} + *

      + * This output is suitable for debugging but should not be parsed. All + * of the information is available through other means. + */ + @Override + public String toString() { + + StringBuilder result = new StringBuilder(); + + result.append(getClass().getName()); + result.append('@'); + result.append(System.identityHashCode(this)); + result.append('['); + + if (null != pipeAdv) { + result.append(pipeAdv.getPipeID().getUniqueValue()); + } + result.append('/'); + + if (null != localEphemeralPipeAdv) { + result.append(localEphemeralPipeAdv.getPipeID().getUniqueValue()); + } + result.append(']'); + result.append(isClosed() ? " CLOSED :" : " OPEN :"); + result.append(initiator ? " I " : " i "); + result.append(isReliable ? " R " : " r "); + result.append(isBound() ? " B " : " b "); + result.append(isConnected() ? " C " : " c "); + + return result.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketAddress.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketAddress.java new file mode 100644 index 000000000..749dd74ec --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketAddress.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.socket; + + +import net.jxta.document.MimeMediaType; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; + +import java.net.SocketAddress; + + +/** + * This class implements a JxtaSocket address (PeerGroup ID + Pipe Advertisement + * + (optional) Peer ID). + *

      + * It provides an immutable object used by sockets for binding, connecting, or as + * returned values. + * + * @author vwilliams + * @see net.jxta.socket.JxtaSocket + * @see net.jxta.socket.JxtaServerSocket + * @see java.net.SocketAddress + * @see java.net.Socket + * @see java.net.ServerSocket + */ +public class JxtaSocketAddress extends SocketAddress { + + private final PeerGroupID peerGroupId; + private final PipeAdvertisement pipeAdv; + private final PeerID peerId; + private final PeerAdvertisement peerAdv; + + private transient String pipeDoc; // convenience, see getPipeDocAsString() + + /** + * Creates a new instance of JxtaSocketAddress. + * + * @param peerGroup peer group within which this socket exists + * @param pipeAdv the advertisement of a pipe for the socket to listen on + */ + public JxtaSocketAddress(PeerGroup peerGroup, PipeAdvertisement pipeAdv) { + this(peerGroup.getPeerGroupID(), pipeAdv, null); + } + + /** + * Creates a new instance of JxtaSocketAddress. + * + * @param peerGroup peer group within which this socket exists + * @param pipeAdv the advertisement of a pipe for the socket to listen on + * @param peerId the ID of a specific peer to be contacted over this socket + * (may be null) + * @deprecated use the PeerAdvertisement variant instead + */ + @Deprecated + public JxtaSocketAddress(PeerGroup peerGroup, PipeAdvertisement pipeAdv, PeerID peerId) { + this(peerGroup.getPeerGroupID(), pipeAdv, peerId); + } + + /** + * Creates a new instance of JxtaSocketAddress. + * + * @param peerGroup peer group within which this socket exists + * @param pipeAdv the advertisement of a pipe for the socket to listen on + * @param peerAdv the PeerAdvertisement (may not be null) + */ + public JxtaSocketAddress(PeerGroup peerGroup, PipeAdvertisement pipeAdv, PeerAdvertisement peerAdv) { + if (peerGroup == null) { + throw new IllegalArgumentException("peerGroupId is required."); + } + if (pipeAdv == null) { + throw new IllegalArgumentException("pipeAdv is required."); + } + if (peerAdv == null) { + throw new IllegalArgumentException("pipeAdv is required."); + } + + this.pipeAdv = pipeAdv.clone(); + this.peerGroupId = peerGroup.getPeerGroupID(); + this.peerId = peerAdv.getPeerID(); + this.peerAdv = peerAdv.clone(); + } + + /** + * Creates a new instance of JxtaSocketAddress. + * + * @param peerGroupId ID of peer group within which this socket exists + * @param pipeAdv the advertisement of a pipe for the socket to listen on + * @deprecated use the PeerAdvertisement variant instead + */ + @Deprecated + public JxtaSocketAddress(PeerGroupID peerGroupId, PipeAdvertisement pipeAdv) { + this(peerGroupId, pipeAdv, null); + } + + /** + * Creates a new instance of JxtaSocketAddress. + * + * @param peerGroupId ID of peer group within which this socket exists + * @param pipeAdv the advertisement of a pipe for the socket to listen on + * @param peerId the ID of a specific peer to be contacted over this socket + * (may be null) + * @throws IllegalArgumentException if peerGroupId or pipeAdv are null + * @deprecated use the PeerAdvertisement variant instead + */ + @Deprecated + public JxtaSocketAddress(PeerGroupID peerGroupId, PipeAdvertisement pipeAdv, PeerID peerId) { + + if (peerGroupId == null) { + throw new IllegalArgumentException("peerGroupId is required."); + } + if (pipeAdv == null) { + throw new IllegalArgumentException("pipeAdv is required."); + } + + this.pipeAdv = pipeAdv.clone(); + this.peerGroupId = peerGroupId; + this.peerId = peerId; + this.peerAdv = null; + } + + /** + * Returns the PeerGroupID element of the address + * + * @return the PeerGroupID + */ + public PeerGroupID getPeerGroupId() { + return this.peerGroupId; + } + + /** + * Returns the PipeAdvertisement element of the address + * + * @return the PipeAdvertisement + */ + public PipeAdvertisement getPipeAdv() { + // preserve immutability + return pipeAdv.clone(); + } + + /** + * Returns the PeerID element of the address. May be null. + * + * @return the PeerID, if there is one, null otherwise + */ + public PeerID getPeerId() { + return this.peerId; + } + + /** + * Returns the PeerID element of the address. May be null. + * + * @return the PeerAdvertisement, if there is one, null otherwise + */ + public PeerAdvertisement getPeerAdvertisement() { + return this.peerAdv; + } + + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj instanceof JxtaSocketAddress) { + JxtaSocketAddress addr = (JxtaSocketAddress) obj; + + if (!peerGroupId.equals(addr.getPeerGroupId())) { + return false; + } + if (!pipeAdv.equals(addr.getPipeAdv())) { + return false; + } + if (peerId != null) { + if (!peerId.equals(addr.getPeerId())) { + return false; + } + } else if (addr.getPeerId() != null) { + return false; + } + + return true; + } + return false; + } + + @Override + public int hashCode() { + + int result = 17; + + result = 37 * result + peerGroupId.hashCode(); + result = 37 * result + pipeAdv.hashCode(); + if (peerId != null) { + result = 37 * result + peerId.hashCode(); + } + return result; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + String lineSep = System.getProperty("line.separator"); + + result.append(lineSep).append("JxtaSocketAdress:").append(lineSep); + result.append(" PeerGroupID: ").append(peerGroupId.toString()).append(lineSep); + if (peerId != null) { + result.append(lineSep).append(" PeerID: ").append(peerId.toString()).append(lineSep); + } + result.append(" Pipe Adv: ").append(lineSep).append(" ").append(getPipeDocAsString()); + return result.toString(); + } + + /* + * A convenience function to lazily-initialize a variable with the string + * representaiton of the pipe advertisement and return it as needed. + */ + private synchronized String getPipeDocAsString() { + if (pipeDoc == null) { + // Using plain text to avoid unpredictable white space + // nodes. [vwilliams] + pipeDoc = pipeAdv.getDocument(MimeMediaType.TEXTUTF8).toString(); + } + return pipeDoc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketInputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketInputStream.java new file mode 100644 index 000000000..bae578a31 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketInputStream.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.socket; + + +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.net.SocketTimeoutException; +import java.util.LinkedList; +import java.util.Queue; + + +/** + * Provides the stream data source for JxtaSocket. + * + * @author Athomas Goldberg + */ +class JxtaSocketInputStream extends InputStream { + + /** + * We push this "poison" value into the accept backlog queue in order to + * signal that the queue has been closed. + */ + protected static final MessageElement QUEUE_END = new StringMessageElement("Terminal", "Terminal", null); + + /** + * Our read timeout. + */ + private long timeout = 60 * 1000; + + /** + * The associated socket. + */ + private final JxtaSocket socket; + + /** + * Our queue of message elements waiting to be read. + */ + protected final Queue queue; + + /** + * The maximum number of message elements we will allow in the queue. + */ + protected final int queueSize; + + /** + * The current message element input stream we are processing. + */ + private InputStream currentMsgStream = null; + + /** + * Construct an InputStream for a specified JxtaSocket. + * + * @param socket the JxtaSocket + * @param queueSize the queue size + */ + JxtaSocketInputStream(JxtaSocket socket, int queueSize) { + this.socket = socket; + this.queueSize = queueSize; + queue = new LinkedList(); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized int available() throws IOException { + int result; + InputStream in = getCurrentStream(false); + + if (in != null) { + result = in.available(); + } else { + // We chose not to block, if we have no inputstream then + // that means there are no bytes available. + result = 0; + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized int read() throws IOException { + byte[] b = new byte[1]; + int result = 0; + + // The result of read() can be -1 (EOF), 0 (yes, its true) or 1. + while (0 == result) { + result = read(b, 0, 1); + } + + if (-1 != result) { + result = (int) b[0]; + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized int read(byte b[], int off, int len) throws IOException { + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } + + while (true) { + int result = -1; + InputStream in = getCurrentStream(true); + + if (null == in) { + return -1; + } + + result = in.read(b, off, len); + if (0 == result) { + // Some streams annoyingly return 0 result. We won't + // perpetuate this behaviour. + continue; + } + + if (result == -1) { + closeCurrentStream(); + continue; + } + return result; + } + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void close() { + queue.clear(); + closeCurrentStream(); + queue.offer(QUEUE_END); + notify(); + } + + /** + * Rather than force the InputStream closed we add the EOF at the end of + * any current data. + */ + synchronized void softClose() { + queue.offer(QUEUE_END); + notify(); + } + + /** + * Get the input stream for the current segment and optionally block until + * a segment is available. + * + * @param block If {@code true} then block until a segment is available. + * @return the InputStream + * @throws IOException if an io error occurs + */ + private InputStream getCurrentStream(boolean block) throws IOException { + + if (currentMsgStream == null) { + + if (QUEUE_END == queue.peek()) { + // We are at the end of the queue. + return null; + } + + MessageElement me = null; + long pollUntil = (Long.MAX_VALUE == timeout) ? Long.MAX_VALUE : System.currentTimeMillis() + timeout; + + while (pollUntil >= System.currentTimeMillis()) { + try { + me = queue.poll(); + + if (null == me) { + long sleepFor = pollUntil - System.currentTimeMillis(); + + if (sleepFor > 0) { + wait(sleepFor); + } + } else { + break; + } + } catch (InterruptedException woken) { + InterruptedIOException incomplete = new InterruptedIOException("Interrupted waiting for data."); + + incomplete.initCause(woken); + incomplete.bytesTransferred = 0; + throw incomplete; + } + } + + if (block && (null == me)) { + throw new SocketTimeoutException("Socket timeout during read."); + } + + if (me != null) { + currentMsgStream = me.getStream(); + } + } + return currentMsgStream; + } + + private void closeCurrentStream() { + if (currentMsgStream != null) { + try { + currentMsgStream.close(); + } catch (IOException ignored) {// ignored + } + currentMsgStream = null; + } + } + + synchronized void enqueue(MessageElement element) { + if (queue.contains(QUEUE_END)) { + // We have already marked the end of the queue. + return; + } + if (queue.size() < queueSize) { + queue.offer(element); + } + notify(); + } + + /** + * Returns the timeout value for this socket. This is the amount of time in + * relative milliseconds which we will wait for read() operations to + * complete. + * + * @return The timeout value in milliseconds or 0 (zero) for + * infinite timeout. + */ + long getTimeout() { + if (timeout < Long.MAX_VALUE) { + return timeout; + } else { + return 0; + } + } + + /** + * Returns the timeout value for this socket. This is the amount of time in + * relative milliseconds which we will wait for read() operations to + * operations to complete. + * + * @param timeout The timeout value in milliseconds or 0 (zero) for + * infinite timeout. + */ + void setTimeout(long timeout) { + if (timeout < 0) { + throw new IllegalArgumentException("Negative timeout not allowed."); + } + + if (0 == timeout) { + timeout = Long.MAX_VALUE; + } + this.timeout = timeout; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketOutputStream.java new file mode 100644 index 000000000..7ad728b8f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/JxtaSocketOutputStream.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.socket; + + +import java.io.IOException; +import java.io.OutputStream; +import java.net.SocketException; + + +/** + * This class implements a buffered output stream. By setting up such an output + * stream, an application can write bytes to the underlying output stream + * without necessarily causing a call to the underlying system for each byte + * written. Data buffer is flushed to the underlying stream, when it is full, + * or an explicit call to flush is made. + */ +class JxtaSocketOutputStream extends OutputStream { + + /** + * If {@code true} then this socket is closed. + */ + protected boolean closed = false; + + /** + * Data buffer + */ + protected byte buf[]; + + /** + * byte count in buffer + */ + protected int count; + + /** + * JxtaSocket associated with this stream + */ + protected JxtaSocket socket; + + /** + * Constructor for the JxtaSocketOutputStream object + * + * @param socket JxtaSocket associated with this stream + * @param size buffer size in bytes + */ + public JxtaSocketOutputStream(JxtaSocket socket, int size) { + if (size <= 0) { + throw new IllegalArgumentException("Buffer size <= 0"); + } + buf = new byte[size]; + this.socket = socket; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void close() throws IOException { + flushBuffer(); + closed = true; + } + + /** + * Similar to close except that any buffered data is discarded. + */ + synchronized void hardClose() { + count = 0; + closed = true; + } + + /** + * Flush the internal buffer + * + * @throws IOException if an i/o error occurs + */ + private void flushBuffer() throws IOException { + if (count > 0) { + // send the message + socket.write(buf, 0, count); + count = 0; + } + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void write(int b) throws IOException { + + if (closed) { + throw new SocketException("Socket Closed."); + } + + if (count >= buf.length) { + flushBuffer(); + } + buf[count++] = (byte) b; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void write(byte b[], int off, int len) throws IOException { + int left = buf.length - count; + + if (closed) { + throw new SocketException("Socket Closed."); + } + + if (len > left) { + System.arraycopy(b, off, buf, count, left); + len -= left; + off += left; + count += left; + flushBuffer(); + } + + // chunk data if larger than buf.length + while (len >= buf.length) { + socket.write(b, off, buf.length); + len -= buf.length; + off += buf.length; + } + System.arraycopy(b, off, buf, count, len); + count += len; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void flush() throws IOException { + flushBuffer(); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/package.html new file mode 100644 index 000000000..63f1fc276 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/socket/package.html @@ -0,0 +1,63 @@ + + + + + +

      The socket package provides interface ala {@link java.net.Socket} +over JXTA pipes. Since the PipeService provides uni-directional, and +unreliable communication channels, the JxtaSocket employs it's own +protocol over pipes to establish bi-directional connections for every +request. In addition the JxtaSocket also employs the reliability +library to ensure reliable delivery of data.  Another feature of +JxtaSockets is chunking, which relieves applications from having to +worry about mtu size, just remember to invoke flush at the end of data +transmission
      +

      +


      +

      +

      JxtaSocket defines the following message elements employed during +the life cycle of a JxtaSocket :
      +

      +
      <> +<Cred>Credentials to determine trust</Cred>
      +<><reqPipe>requestor's +pipe advertisement</reqPipe>
      +<remPipe>Remote +pipe advertisement</remPipe>
      +<reqPeer>Remote +peer advertisement</remPeer>
      +<stream>true|false +== reliable|or not</stream>
      +<close>close request</close>
      +
      <closeACK>ack +close request</closeACK>
      +<data>data</data>
      +
      +

      The socket package also provides interface ala {@link +java.net.MulticastSocket} over propagated pipes.  Keep in mind +JxtaMulticastSocket does not provide chunking nor reliability at this +time, therefore one must consider configuration parameters such as the +multicast datagram size defined for the TCP Message Transport :
      +

      +
      <MulticastSize>
      +    16384
      +</MulticastSize>
      +
      +

      As well as any other mtu size imposed by the JXTA Platform, or the +operating system.
      +

      +

      For examples on how to utilize the net.jxta.socket see the online +tutorials on JxtaSocket, +and JxtaMulticastSocket +available at http://www.jxta.org/Tutorials.html
      +

      +


      +

      + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/user.properties b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/user.properties new file mode 100644 index 000000000..66d16b784 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/user.properties @@ -0,0 +1,22 @@ +# Amount of time in minutes after which a connection is considered idle and may +# be scavenged expressed in minutes +impl.endpoint.tls.connection.idletimeout=5 + +# Amount of time in minutes a connection must be idle before a reconnection +# attempt will be considered expressed in minutes +impl.endpoint.tls.connection.minidlereconnect=1 + +# Amount if time in minutes which retries may remain queued for retrasmission. +# expressed in minutes +impl.endpoint.tls.connection.maxretryage=2 + +# Cache Manager Deffered checkpoint +# a setting of true deffers commit checkpoint to the Filer +# this setting increases performance, with a caveat of possible +# data corruption in unexpected process termination due to kernel +# crash, or power loss +impl.cm.defferedcheckpoint=true + +#Discovery provides the ability to disable discovery network traffic +#when defined, it renders discovery a local cache +impl.discovery.localonly=false diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AbstractSimpleSelectable.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AbstractSimpleSelectable.java new file mode 100644 index 000000000..0714118b9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AbstractSimpleSelectable.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.logging.Logging; +import net.jxta.util.SimpleSelectable.IdentityReference; + +/** + * This a tool to implement selectable objects. It may be composed or extended. + *

      + * {@code SimpleSelectable} objects that are not {@code SimpleSelector} objects + * only report changes to their listeners. + *

      + * The listeners of a {@code SimpleSelectable} may be {@code SimpleSelector} + * objects or other {@code SimpleSelectable} objects. However the method to + * register non-selectors is and must remain protected since it would allow the + * connection of arbitrary listeners. + * + * @see SimpleSelector + */ + +public abstract class AbstractSimpleSelectable implements SimpleSelectable { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(AbstractSimpleSelectable.class.getName()); + + /** + * The identity reference for this selectable. + * + * @see SimpleSelectable.IdentityReference + */ + public final IdentityReference identityReference = new IdentityReference(this); + + /** + * The object that is to reported to listeners as having changed. When this + * class is composed rather than extended, "this" is probably not the right + * choice. + */ + private final SimpleSelectable srcObject; + + /** + * Registered Change Listeners. + *

      + * We use a weakHashMap as a Set. The values are never used. + */ + private final Map myListeners = new WeakHashMap(2); + + /** + * Standard constructor for cases where the selectable object is this + * object. + */ + public AbstractSimpleSelectable() { + this.srcObject = this; + } + + /** + * Standard constructor for cases where the selectable object is some other + * object. + * + * @param srcObject the source object + */ + public AbstractSimpleSelectable(SimpleSelectable srcObject) { + this.srcObject = srcObject; + } + + /** + * {@inheritDoc} + */ + public IdentityReference getIdentityReference() { + return identityReference; + } + + /** + * Tells whether there are registered selectors right now, or not. A + * SimpleSelectable that also registers with something else may want to + * unregister (with the obvious consistency precautions) if it no longer has + * selectors of its own. + * + * @return true if there are listeners. + */ + protected boolean haveListeners() { + synchronized(myListeners) { + return !myListeners.isEmpty(); + } + } + + /** + * This method takes any listener, not just a SimpleSelector. + * + * @param selectable The SimpleSelectable to register + */ + protected void registerListener(SimpleSelectable selectable) { + synchronized(myListeners) { + myListeners.put(selectable, null); + } + } + + /** + * This method takes any listener, not just a SimpleSelector. + * + * @param selectable The SimpleSelectable to unregister + */ + protected void unregisterListener(SimpleSelectable selectable) { + synchronized(myListeners) { + myListeners.remove(selectable); + } + } + + /** + * {@inheritDoc} + */ + public void register(SimpleSelector simpleSelector) { + registerListener(simpleSelector); + simpleSelector.itemChanged(this); + } + + /** + * {@inheritDoc} + */ + public void unregister(SimpleSelector simpleSelector) { + unregisterListener(simpleSelector); + } + + /** + * This method tells us that something changed and so we need to notify our + * selectors by invoking their {@code itemChanged()} method. This is + * normally invoked internally by the implementation. One of the reasons for + * the implementation to invoke this method is that a SimpleSelectable + * object that this one is registered with has changed and so has invoked + * the itemChanged method. However, the correlation between the two is left + * up to the implementation. + *

      + * No external synchronization needed, nor desirable. + * + * @return false if there are no selectors left (that's a suggestion for the + * implementation to use haveListeners and possibly unregister itself). + */ + protected final boolean notifyChange() { + Collection listeners; + + synchronized(myListeners) { + listeners = new ArrayList(myListeners.keySet()); + } + + for (SimpleSelectable listener : listeners) { + try { + listener.itemChanged(srcObject); + } catch(Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in listener " + listener, all); + } + } + } + + return !listeners.isEmpty(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AdvertisementUtilities.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AdvertisementUtilities.java new file mode 100644 index 000000000..128c3e878 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AdvertisementUtilities.java @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; +import net.jxta.exception.JxtaException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.PipeID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleClassAdvertisement; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; + + +/** + * @deprecated Will be deprecated soon. Do not use these methods. They contain + * a number of incorrect assumption that cannot be corrected while maintaining + * backwards compatibility with programs which already use them. + * THIS CLASS IS SCHEDULED TO BE REMOVED AFTER 2.5 + */ +@Deprecated +public final class AdvertisementUtilities { + + /** + * Logger + */ + // private static final transient Logger LOG = Logger.getLogger(AdvertisementUtilities.class.getName()); + + public static final StructuredTextDocument STANDARD_COMPATABILITY = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument( + MimeMediaType.XMLUTF8, "Comp"); + public static final String STANDARD_URI = "http://www.jxta.org/download/jxta.jar"; + public static final String STANDARD_PROVIDER = "jxta.org"; + + static { + Element element = STANDARD_COMPATABILITY.createElement("Efmt", "JDK1.4.1"); + + STANDARD_COMPATABILITY.appendChild(element); + element = STANDARD_COMPATABILITY.createElement("Bind", "V2.0 Ref Impl"); + STANDARD_COMPATABILITY.appendChild(element); + } + + private AdvertisementUtilities() {} + + /** + * Read a JXTA Advertisement from a File + * + * @param fileName The file containing the Advertisement + * @return An polymorphic Advertisement object + * @throws JxtaException if Unable to parse the Advertisement + */ + public static Advertisement readAdvertisementFromFile(String fileName) throws JxtaException { + return readAdvertisementFromFile(new File(fileName)); + } + + /** + * Read a JXTA Advertisement from a File + * + * @param file The file containing the Advertisement + * @return An polymorphic Advertisement object + * @throws JxtaException if Unable to parse the Advertisement + */ + public static Advertisement readAdvertisementFromFile(File file) throws JxtaException { + FileInputStream in = null; + + try { + in = new FileInputStream(file); + + return AdvertisementFactory.newAdvertisement(MimeMediaType.XML_DEFAULTENCODING, in); + } catch (IOException e) { + throw new JxtaException("Advertisement Load Failed: " + file, e); + } catch (Exception e) { + throw new JxtaException("Advertisement Load Failed: " + file, e); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ignored) {// ignored + } + } + } + } + + /** + * Save a JXTA Advertisement as an XML Document to a File + * + * @param adv The Advertisement to be saved + * @param fileName The file to store the Advertisement + * @throws JxtaException if Unable to parse the Advertisement + */ + public static void saveAdvertisementToFile(Advertisement adv, String fileName) throws JxtaException { + saveAdvertisementToFile(adv, new File(fileName)); + } + + /** + * Save a JXTA Advertisement as an XML Document to a File + * + * @param adv The Advertisement to be saved + * @param file The file to store the Advertisement + * @throws JxtaException if Unable to parse the Advertisement + */ + public static void saveAdvertisementToFile(Advertisement adv, File file) throws JxtaException { + OutputStream out = null; + + try { + out = new FileOutputStream(file); + Document document = adv.getDocument(MimeMediaType.XML_DEFAULTENCODING); + + document.sendToStream(out); + } catch (IOException e) {} finally { + if (out != null) { + try { + out.close(); + } catch (IOException ignored) {// ignored + } + } + } + } + + /** + * Save a JXTA Advertisement as an XML Document to an array of bytes + * + * @param advertisement The Advertisement to be saved + * @throws JxtaException if Unable to parse the Advertisement + * @deprecated This method should not be used because it produces a result + * who's encoding is not predictable and may (will) differ from JVM to JVM. + */ + @Deprecated + public static byte[] advertisementToBytes(Advertisement advertisement) throws JxtaException { + try { + Document document = advertisement.getDocument(MimeMediaType.XML_DEFAULTENCODING); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + + document.sendToStream(bo); + + return bo.toByteArray(); + } catch (IOException e) { + throw new JxtaException("Error converting a document to bytes", e); + } + } + + /** + * Convert an array of bytes containing an XML encoded String to an JXTA Advertisement + * + * @param buf The source of the advertisement + * @return The Advertisement + * @deprecated This method should not be used because it interprets the + * input using the local default encoding which is not predictable and + * may (will) differ from JVM to JVM. + */ + @Deprecated + public static Advertisement bytesToAdvertisement(byte buf[]) { + try { + InputStream in = new ByteArrayInputStream(buf); + Advertisement advertisement = AdvertisementFactory.newAdvertisement(MimeMediaType.XML_DEFAULTENCODING, in); + + return advertisement; + } catch (IOException e) { + return null; + } // This will never be thrown + } + + /** + * Save a JXTA Advertisement to a String + * + * @param advertisement The Advertisement to be converted + * @param mimeType Type of document to be created + */ + public static String advertisementToText(Advertisement advertisement, String mimeType) { + try { + StructuredTextDocument doc = (StructuredTextDocument) advertisement.getDocument(new MimeMediaType(mimeType)); + StringWriter stringWriter = new StringWriter(); + + doc.sendToWriter(stringWriter); + + return stringWriter.toString(); + } catch (IOException e) { + return null; + } // This will never be thrown + } + + /** + * Save a JXTA Advertisement to a Plain Text String + * + * @param advertisement The Advertisement to be converted + */ + public static String advertisementToPlainText(Advertisement advertisement) { + return advertisementToText(advertisement, MimeMediaType.TEXT_DEFAULTENCODING.toString()); + } + + /** + * Save a JXTA Advertisement to an XML String + * + * @param advertisement The Advertisement to be converted + * @deprecated Equivalent to Advertisement.toString() + */ + @Deprecated + public static String advertisementToXmlText(Advertisement advertisement) { + return advertisementToText(advertisement, MimeMediaType.XMLUTF8.toString()); + } + + /** + * Convert an array of bytes containing an XML encoded String to an JXTA Advertisement + * + * @param xmlTextAsBytes The source of the advertisement + * @return The Advertisement + * @throws JxtaException if Unable to parse the Advertisement + * @deprecated This method should not be used because it produces a result + * who's encoding is not predictable and may (will) differ from JVM to JVM. + */ + @Deprecated + public static Advertisement newAdvertisementFromXml(byte xmlTextAsBytes[]) throws JxtaException { + try { + return AdvertisementFactory.newAdvertisement(MimeMediaType.XML_DEFAULTENCODING + , + new ByteArrayInputStream(xmlTextAsBytes)); + } catch (Exception e) { + throw new JxtaException("Unable to create Advertisement from the provided XML", e); + } + } + + /** + * Convert a String containing an XML encoded String to an JXTA Advertisement + * + * @param xmlText The source of the advertisement + * @return The Advertisement + * @throws JxtaException if Unable to parse the Advertisement + * @deprecated This method should not be used because it interprets the + * input using the local default encoding which is not precidcatable and + * may (will) differ from JVM to JVM. + */ + @Deprecated + public static Advertisement newAdvertisementFromXml(String xmlText) throws JxtaException { + try { + return AdvertisementFactory.newAdvertisement(MimeMediaType.XML_DEFAULTENCODING, new StringReader(xmlText)); + } catch (Exception e) { + throw new JxtaException("Unable to create Advertisement from the provided XML", e); + } + } + + /** + * Create a Pipe Advertisement + * + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement() { + return (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + } + + /** + * Create a Pipe Advertisement + * + * @param pipeId The pipe ID + * @param pipeType The type of the Pipe + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement(PipeID pipeId, String pipeType) { + PipeAdvertisement pipeAdvertisement = (PipeAdvertisement) AdvertisementFactory.newAdvertisement( + PipeAdvertisement.getAdvertisementType()); + + pipeAdvertisement.setPipeID(pipeId); + pipeAdvertisement.setType(pipeType); + return pipeAdvertisement; + } + + /** + * Create a Pipe Advertisement + * + * @param pipeIdText The pipe ID + * @param pipeType The type of the Pipe + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement(String pipeIdText, String pipeType) throws JxtaException { + PipeID pipeId; + + try { + pipeId = (PipeID) IDFactory.fromURI(new URI(pipeIdText)); + } catch (URISyntaxException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Bad pipe id"); + + failure.initCause(failed); + + throw failure; + } + PipeAdvertisement pipeAdvertisement = (PipeAdvertisement) AdvertisementFactory.newAdvertisement( + PipeAdvertisement.getAdvertisementType()); + + pipeAdvertisement.setPipeID(pipeId); + pipeAdvertisement.setType(pipeType); + return pipeAdvertisement; + } + + /** + * Create a Pipe Advertisement + * + * @param root Element containing a Pipe Advertisement + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement(Element root) { + TextElement pipeAdvElement = (TextElement) DocumentUtilities.getChild(root, PipeAdvertisement.getAdvertisementType()); + + if (pipeAdvElement == null) { + return null; + } + + return (PipeAdvertisement) AdvertisementFactory.newAdvertisement(pipeAdvElement); + } + + /** + * Create a Pipe Advertisement + * + * @param peerGroup The peerGroup + * @param pipeType The pipeType + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement(PeerGroup peerGroup, String pipeType) { + PipeID pipeID = IDFactory.newPipeID(peerGroup.getPeerGroupID()); + + return createPipeAdvertisement(pipeID, pipeType); + } + + /** + * Create a Pipe Advertisement + * + * @param pipeID The pipeID + * @param pipeType The pipeType + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement(ID pipeID, String pipeType) { + PipeAdvertisement pipeAdvertisement = createPipeAdvertisement(); + + pipeAdvertisement.setPipeID(pipeID); + pipeAdvertisement.setType(pipeType); + return pipeAdvertisement; + } + + /** + * Create a Pipe Advertisement + * + * @param peerGroup The peerGroup + * @param pipeType The pipeType + * @param name The Pime Name + * @return A new Pipe Advertisement + */ + public static PipeAdvertisement createPipeAdvertisement(PeerGroup peerGroup, String sPipeID, String pipeType, String name) throws JxtaException { + PipeAdvertisement pipeAdvertisement = createPipeAdvertisement(peerGroup, pipeType); + PipeID pipeId; + + try { + pipeId = (PipeID) IDFactory.fromURI(new URI(sPipeID)); + } catch (URISyntaxException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Bad pipe id"); + + failure.initCause(failed); + + throw failure; + } + pipeAdvertisement.setPipeID(pipeId); + if (name != null) { + pipeAdvertisement.setName(name); + } + + return pipeAdvertisement; + } + + /** + * Create a Pipe Advertisement + * + * @param root The Root element containing the Advertisement + * @return A new Pipe Advertisement + * @deprecated These utilities are too specialized for general use. + */ + @Deprecated + public static PipeAdvertisement getPipeAdvertisement(Element root) { + TextElement pipeAdvElement = (TextElement) DocumentUtilities.getChild(root, PipeAdvertisement.getAdvertisementType()); + + if (pipeAdvElement == null) { + return null; + } + + return (PipeAdvertisement) AdvertisementFactory.newAdvertisement(pipeAdvElement); + } + + /** + * Create a Peer Advertisement + * + * @param root The Root element containing the Advertisement + * @return A new Peer Advertisement + * @deprecated These utilities are too specialized for general use. + */ + @Deprecated + public static PeerAdvertisement getPeerAdvertisement(Element root) { + TextElement peerAdvElement = (TextElement) DocumentUtilities.getChild(root, PeerAdvertisement.getAdvertisementType()); + + if (peerAdvElement == null) { + return null; + } + + return (PeerAdvertisement) AdvertisementFactory.newAdvertisement(peerAdvElement); + } + + /** + * Create a ModuleClassAdvertisement + * + * @param name The name + * @param description The description + * @return An ModuleClassAdvertisement + */ + public static ModuleClassAdvertisement createModuleClassAdvertisement(String name, String description) { + String moduleClassAdvertisementType = ModuleClassAdvertisement.getAdvertisementType(); + ModuleClassAdvertisement moduleClassAdvertisement = (ModuleClassAdvertisement) AdvertisementFactory.newAdvertisement( + moduleClassAdvertisementType); + + moduleClassAdvertisement.setName(name); + moduleClassAdvertisement.setDescription(description); + + ModuleClassID mcID = IDFactory.newModuleClassID(); + + moduleClassAdvertisement.setModuleClassID(mcID); + return moduleClassAdvertisement; + } + + /** + * Create a ModuleSpecAdvertisement + * + * @param name The name + * @param param The param + * @return An ModuleSpecAdvertisement + * @deprecated This implementation incompletely initializes the module + * spec advertisement. Consider creating Module Spec Advertisements without + * this method. + */ + @Deprecated + public static ModuleSpecAdvertisement createModuleSpecAdvertisement(String name, StructuredDocument param) { + return createModuleSpecAdvertisement(name, null, param); + } + + /** + * Create a ModuleSpecAdvertisement + * + * @param name The name + * @param moduleClassAdvertisement The moduleClassAdvertisement + * @param param The param + * @return An ModuleSpecAdvertisement + * @deprecated This implementation incompletely initializes the module + * spec advertisement. Consider creating Module Spec Advertisements without + * this method. + */ + @Deprecated + public static ModuleSpecAdvertisement createModuleSpecAdvertisement(String name, ModuleClassAdvertisement moduleClassAdvertisement, StructuredDocument param) { + String moduleSpecAdvertisementType = ModuleSpecAdvertisement.getAdvertisementType(); + ModuleSpecAdvertisement moduleSpecAdvertisement = (ModuleSpecAdvertisement) AdvertisementFactory.newAdvertisement( + moduleSpecAdvertisementType); + + moduleSpecAdvertisement.setName(name); + moduleSpecAdvertisement.setVersion("Unknown"); + moduleSpecAdvertisement.setCreator("Unknown"); + + if (moduleClassAdvertisement != null) { + ModuleClassID moduleClassID = moduleClassAdvertisement.getModuleClassID(); + + moduleSpecAdvertisement.setModuleSpecID(IDFactory.newModuleSpecID(moduleClassID)); + } + + moduleSpecAdvertisement.setSpecURI("Unknown"); + + if (param != null) { + moduleSpecAdvertisement.setParam(param); + } + + return moduleSpecAdvertisement; + } + + /** + * Publish and advertisement to the Cache + * + * @param peerGroup The peerGroup + * @param peerAdvertisement The Advertisement + * @throws JxtaException if Unable to cache the Advertisement + */ + public static void cachePeerAdvertisement(PeerGroup peerGroup, PeerAdvertisement peerAdvertisement) throws JxtaException { + cachePeerAdvertisement(peerGroup, peerAdvertisement, DiscoveryService.DEFAULT_EXPIRATION + , + DiscoveryService.DEFAULT_EXPIRATION); + } + + private static void cachePeerAdvertisement(PeerGroup peerGroup, PeerAdvertisement peerAdvertisement, long lifetime, long lifetimeForOthers) throws JxtaException { + try { + DiscoveryService discoveryService = peerGroup.getDiscoveryService(); + + if (peerAdvertisement.getPeerID().equals(peerGroup.getPeerID())) { + return; + } // no reason to persist our own peer ID + + discoveryService.publish(peerAdvertisement, lifetime, lifetimeForOthers); + } catch (IOException e) { + throw new JxtaException("Unable to cache advertisement", e); + } + } + + /** + * Create a ModuleImplAdvertisement + * + * @param specID The specID + * @param code The code + * @param description the advertisement description + * @return An ModuleImplAdvertisement + * @deprecated This implementation initializes some fields of the + * resulting ModuleImplAdvertisement to constant values who's value may + * not be correct for all circumstances. Consider creating ModuleImpl + * Advertisements directly in your application. + */ + @Deprecated + public static ModuleImplAdvertisement createModuleImplAdvertisement(ModuleSpecID specID, String code, String description) { + + ModuleImplAdvertisement moduleImplAdvertisement = (ModuleImplAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType()); + + moduleImplAdvertisement.setModuleSpecID(specID); + moduleImplAdvertisement.setCompat(STANDARD_COMPATABILITY); + moduleImplAdvertisement.setCode(code); + moduleImplAdvertisement.setUri(STANDARD_URI); + moduleImplAdvertisement.setProvider(STANDARD_PROVIDER); + moduleImplAdvertisement.setDescription(description); + return moduleImplAdvertisement; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AwtUtils.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AwtUtils.java new file mode 100644 index 000000000..9d9171f96 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/AwtUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.awt.Frame; + + +public class AwtUtils { + + // It is recommended to invoke this method at least once before + // making any other references to awt. This will force awt threads + // to always be daemon threads, thereby preserving the JVM's automatic + // termination model. + + public static void initAsDaemon() { + (new Thread() { + + @Override + public void run() { + try { + Frame f = new Frame(); + + f.dispose(); + } catch (Throwable t) {} + } + + public void doit() { + setDaemon(true); + setName("awt daemon initializer"); + start(); + try { + join(); + } catch (InterruptedException ie) {} + } + } + ).doit(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/ClassFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/ClassFactory.java new file mode 100644 index 000000000..7d6057f6a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/ClassFactory.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; +import java.util.MissingResourceException; +import java.util.NoSuchElementException; + +import net.jxta.logging.Logging; + + +/** + * This util class provides methods needed by class construction factories. + * + * @see net.jxta.document.StructuredDocumentFactory + * @see net.jxta.document.AdvertisementFactory + * @see net.jxta.id.IDFactory + * @see net.jxta.endpoint.WireFormatMessageFactory + */ +public abstract class ClassFactory { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(ClassFactory.class.getName()); + + /** + * Standard constructor. + */ + protected ClassFactory() {} + + /** + * Used by ClassFactory methods to get the mapping of keys to constructors. + * + * @return the map containing the mappings. + */ + protected abstract Map getAssocTable(); + + /** + * Used by ClassFactory methods to ensure that all keys used with the + * mapping are of the correct type. + * + * @return Class object of the key type. + */ + protected abstract Class getClassForKey(); + + /** + * Return all of the available keys for this factory. + * + * @return Iterator of all the available keys for this factory. + */ + public Iterator getAvailableKeys() { + return Collections.unmodifiableSet(getAssocTable().keySet()).iterator(); + } + + /** + * Returns an unmodifiable Set containing all of the associations + * stored in this ClassFactory. + * + * @return Set containing all of the available entries for this factory. + */ + public Set> getEntrySet() { + return Collections.unmodifiableSet(getAssocTable().entrySet()); + } + + /** + * Used by ClassFactory methods to ensure that all of the instance classes + * which register with this factory have the correct base class + * + * @return Class object of the "Factory" type. + */ + protected abstract Class getClassOfInstantiators(); + + /** + * Given a resource bundle identifier and a property name register instance + * classes. The property must be a string containing class names which must + * be found on the current class path. The class names are separated by + * spaces. + * + * @param resourceName name of the resource bundle + * @param propertyName name of the property. + * @return boolean true if at least one instance class could be registered + * with this factory. + * @exception MissingResourceException if the resource bundle or + * property cannot be located. + */ + protected boolean registerFromResources(String resourceName, String propertyName) throws MissingResourceException { + ResourceBundle jxtaRsrcs = ResourceBundle.getBundle(resourceName); + String fromProps = jxtaRsrcs.getString(propertyName).trim(); + + return registerFromString(fromProps); + } + + /** + * Register instance classes given a string containing class names which + * must be found on the current class path. The class names are separated + * by spaces. + * + * @param classNamesString The class name list + * @return boolean true if at least one of the instance classes could be + * registered otherwise false. + */ + protected boolean registerFromString(String classNamesString) { + boolean registeredSomething = false; + + if ((null == classNamesString) || (0 == classNamesString.length())) { + return false; + } + + // make sure the static initialisers for each instance class are called. + List instanceClasses = Arrays.asList(classNamesString.split("\\s")); + + for (String eachInstanceClass : instanceClasses) { + try { + registeredSomething |= registerAssoc(eachInstanceClass); + } catch (Exception allElse) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to register \'" + eachInstanceClass + "\'", allElse); + } + } + } + + return registeredSomething; + } + + /** + * Given an provider interface name register instance classes. The class + * path is searched for service provider lists as described by the JAR File + * specification for service providers + * + * @param interfaceName name of the implemented interface. + * @return boolean true if at least one instance class could be registered + * with this factory. + */ + protected boolean registerProviders(String interfaceName) { + ClassLoader loader = getClass().getClassLoader(); + boolean registeredSomething = false; + + try { + Enumeration providerLists = loader.getResources("META-INF/services/" + interfaceName); + + while (providerLists.hasMoreElements()) { + try { + URI providerList = providerLists.nextElement().toURI(); + + registeredSomething |= registerFromFile(providerList); + } catch (URISyntaxException badURI) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to convert service URI", badURI); + } + } + } + } catch (IOException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to locate provider lists", ex); + } + } + + return registeredSomething; + } + + /** + * Register instance classes given a URI to a file containing class names + * which must be found on the current class path. The class names are listed + * on separate lines. Comments are marked with a '#', the pound sign and + * any following text on any line in the file are ignored. + * + * @param providerList the URI to a file containing a list of providers + * @return boolean true if at least one of the instance classes could be + * registered otherwise false. + */ + protected boolean registerFromFile(URI providerList) { + boolean registeredSomething = false; + InputStream urlStream = null; + + try { + urlStream = providerList.toURL().openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(urlStream, "UTF-8")); + + String provider; + + while ((provider = reader.readLine()) != null) { + int comment = provider.indexOf('#'); + + if (comment != -1) { + provider = provider.substring(0, comment); + } + + provider = provider.trim(); + + if (provider.length() > 0) { + try { + registeredSomething |= registerAssoc(provider); + } catch (Exception allElse) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to register \'" + provider + "\'", allElse); + } + } + } + } + } catch (IOException ex) { + LOG.log(Level.WARNING, "Failed to read provider list " + providerList, ex); + return false; + } finally { + if(null != urlStream) { + try { + urlStream.close(); + } catch(IOException ignored) { + + } + } + } + + return registeredSomething; + } + + /** + * Register a class with the factory from its class name. Since class name + * doesn't tell us much, we just load the class and hope that something + * happens as a result of the class loading. This class is often overridden + * in class factories to interogate the instance class before registering + * the instance class. + * + * @param className The class name which will be registered. + * @return boolean true if the class was registered otherwise false. + * @throws Exception when an error occurs. + */ + protected boolean registerAssoc(final String className) throws Exception { + + boolean registeredSomething = false; + + try { + /* + * This implementation skankily assumes that the class registers + * itself as part of class initialization. + */ + + Class ignored = Class.forName(className); + + registeredSomething = true; + } catch (ClassNotFoundException ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to locate \'" + className + "\'"); + } + } catch (NoClassDefFoundError ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to locate \'" + className + "\'"); + } + } + + return registeredSomething; + } + + /** + * Register a key and instance class with the factory. + * + * @param key The key to register. + * @param instantiator The instantiator object which will be registered for this key. + * @return boolean true if the key was successfully registered otherwise false. + */ + protected boolean registerAssoc(final K key, final I instantiator) { + + // Check the association table to make sure this key is not already present. + if (null != getAssocTable().get(key)) { + return false; + } + + getAssocTable().put(key, instantiator); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Factory : " + getClass().getName() + " Registered instantiator \'" + instantiator + "\' for \'" + key + "\'"); + } + + return true; + } + + /** + * Return the instantiator associated with the provided key. + * + * @param key The identifier for the Instantiator class to be returned. + * @return Instantiator Instantiator matching the provided key + * @throws NoSuchElementException if the key has not been registered. + */ + protected I getInstantiator(final K key) throws NoSuchElementException { + + // Get the constructors for this key. + I instantiator = getAssocTable().get(key); + + if (null == instantiator) { + throw new NoSuchElementException("key '" + key + "' not registered."); + } + + return instantiator; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingInputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingInputStream.java new file mode 100644 index 000000000..41ffcd2e4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingInputStream.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.*; + + +/** + * A filter input stream which counts the bytes read from the stream. A filter + * so that you don't have to count seperately from reading from the inoput + * + **/ +public class CountingInputStream extends FilterInputStream { + + /** + * For recursion detection to prevent overcounting. + **/ + private transient boolean alreadycounting; + + /** + * number of bytes which have been read on this stream + **/ + private long bytesRead = 0; + + /** + * Make a new Counting Input Stream + **/ + public CountingInputStream(InputStream in) { + super(in); + } + + /** + * {@inheritDoc} + * + *

      Debugging toString. + **/ + @Override + public String toString() { + if (null == in) { + return "closed/" + super.toString(); + } else { + return in.toString() + "/" + super.toString(); + } + } + + /** + * {@inheritDoc} + * + *

      Merely calls the super version. + **/ + @Override + public synchronized int read() throws IOException { + boolean wascounting = alreadycounting; + + alreadycounting = true; + int i = super.read(); + + alreadycounting = wascounting; + + if (!alreadycounting && (i != -1)) { + bytesRead++; + } + return i; + } + + /** + * {@inheritDoc} + * + *

      calls the super version of the same method. + **/ + @Override + public synchronized int read(byte[] b, int off, int len) throws IOException { + boolean wascounting = alreadycounting; + + alreadycounting = true; + + int i = super.read(b, off, len); + + alreadycounting = wascounting; + + if ((-1 != i) && !alreadycounting) { + bytesRead += i; + } + + return i; + } + + /** + * Returns the number of bytes read fromthe stream thus far. This and all + * the methods in this class are synchronized because bytesRead cannot be + * volatile. + * + * @return long containing the number of bytes read. + **/ + public synchronized long getBytesRead() { + return bytesRead; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingOutputStream.java new file mode 100644 index 000000000..f1b121d29 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingOutputStream.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.OutputStream; +import java.io.IOException; + + +/** + * A filter output stream which counts the bytes sent to the stream. A filter + * so that you don't have to count seperately from writing to the output + * + **/ +public class CountingOutputStream extends java.io.FilterOutputStream { + + /** + * For recursion detection to prevent overcounting. + **/ + private transient boolean alreadycounting; + + /** + * number of bytes which have been written on this stream + **/ + private long bytesWritten; + + /** + * Creates a new instance of CountingOutputStream + **/ + public CountingOutputStream(OutputStream out) { + super(out); + bytesWritten = 0; + alreadycounting = false; + } + + /** + * {@inheritDoc} + * + *

      Debugging toString. + **/ + @Override + public String toString() { + if (null == out) { + return "closed/" + super.toString(); + } else { + return out.toString() + "/" + super.toString(); + } + } + + /** + * {@inheritDoc} + * + *

      Merely calls the super version. + **/ + @Override + public synchronized void write(int b) throws IOException { + boolean wascounting = alreadycounting; + + alreadycounting = true; + super.write(b); + alreadycounting = wascounting; + if (!alreadycounting) { + bytesWritten++; + } + } + + /** + * {@inheritDoc} + * + *

      calls the super version of the same method. + **/ + @Override + public synchronized void write(byte[] b, int off, int len) throws IOException { + boolean wascounting = alreadycounting; + + alreadycounting = true; + super.write(b, off, len); + alreadycounting = wascounting; + if (!alreadycounting) { + bytesWritten += len; + } + } + + /** + * Returns the number of bytes written to the stream thus far. This and all + * the methods in this class are synchronized because bytesWritten cannot be + * volatile. + * + * @return long containing the number of bytes written. + **/ + public synchronized long getBytesWritten() { + return bytesWritten; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingWriter.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingWriter.java new file mode 100644 index 000000000..6321ff5ab --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/CountingWriter.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.Writer; +import java.io.FilterWriter; + +import java.io.IOException; + + +/** + * A filter writer which counts the characters sent to the writer. A filter + * so that you don't have to count seperately from writing to the output. + **/ +public class CountingWriter extends FilterWriter { + + /** + * For recursion detection to prevent overcounting. + **/ + private transient boolean alreadycounting; + + /** + * number of chars which have been written on this stream + **/ + private long charsWritten; + + /** + * Creates a new instance of CountingWriter + **/ + public CountingWriter(Writer out) { + super(out); + charsWritten = 0; + alreadycounting = false; + } + + /** + * {@inheritDoc} + * + *

      Debugging toString. + **/ + @Override + public String toString() { + if (null == out) { + return "closed/" + super.toString(); + } else { + return out.toString() + "/" + super.toString(); + } + } + + /** + * {@inheritDoc} + * + *

      Calls the super version of the same method. + **/ + @Override + public synchronized void write(int b) throws IOException { + boolean wascounting = alreadycounting; + + alreadycounting = true; + super.write(b); + alreadycounting = wascounting; + if (!alreadycounting) { + charsWritten++; + } + } + + /** + * {@inheritDoc} + * + *

      Calls the super version of the same method. + **/ + @Override + public synchronized void write(char[] b, int off, int len) throws IOException { + boolean wascounting = alreadycounting; + + alreadycounting = true; + super.write(b, off, len); + alreadycounting = wascounting; + if (!alreadycounting) { + charsWritten += len; + } + } + + /** + * Returns the number of chars written to the stream thus far. This and all + * the methods in this class are synchronized because bytesWritten cannot be + * volatile. + * + * @return long containing the number of bytes written. + **/ + public synchronized long getCharsWritten() { + return charsWritten; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DevNullOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DevNullOutputStream.java new file mode 100644 index 000000000..ca927c5c5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DevNullOutputStream.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.OutputStream; + + +/** + * An OutputStream which simply discards all data written to it. Useful when + * used with CountingOutputStream. + * + * This implementation just ignores everything you do it. + */ +public class DevNullOutputStream extends OutputStream { + + /** Creates a new instance of DevNullOutputStream */ + public DevNullOutputStream() {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void close() {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void flush() {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void write(byte b[]) {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void write(byte b[], int offset, int len) {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void write(int b) {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DevNullWriter.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DevNullWriter.java new file mode 100644 index 000000000..2f94f6393 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DevNullWriter.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.Writer; + + +/** + * An Writer which simply discards all data written to it. Useful when + * used with CountingWriter. + * + * This implementation just ignores everything you do it. + */ +public class DevNullWriter extends Writer { + + /** + * Creates a new instance of DevNullOutputStream + **/ + public DevNullWriter() { + ; + } + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void close() {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void flush() {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void write(char b[]) {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void write(char b[], int offset, int len) {} + + /** + * {@inheritDoc} + * + *

      Does nothing.... + **/ + @Override + public void write(String str, int offset, int len) {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DocumentUtilities.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DocumentUtilities.java new file mode 100644 index 000000000..effe1f6e7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/DocumentUtilities.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.exception.JxtaException; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.Enumeration; + + +/** + * @deprecated Will be removed soon. THIS CLASS IS SCHEDULED TO BE REMOVED AFTER 2.5 + */ +@Deprecated +public final class DocumentUtilities { + + private DocumentUtilities() {} + + public static StructuredTextDocument createStructuredXmlDocument(String rootTagName) throws JxtaException { + return (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, rootTagName); + } + + public static StructuredTextDocument getStructuredXmlDocument(String buf) throws JxtaException { + try { + return (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8 + , + new StringReader(buf)); + } catch (IOException e) { + throw new JxtaException("Error reading document", e); + } + } + + public static StructuredTextDocument getStructuredXmlDocument(byte buf[]) throws JxtaException { + return getStructuredXmlDocument(new ByteArrayInputStream(buf)); + } + + public static StructuredTextDocument getStructuredXmlDocument(InputStream in) throws JxtaException { + try { + return (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, in); + } catch (IOException e) { + throw new JxtaException("Error reading document", e); + } + } + + public static StructuredDocument createParamDocument() { + return StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + } + + public static Element getChild(Element root, Object key) { + Enumeration e = root.getChildren(key); + + if (e == null) { + return null; + } + + return (Element) e.nextElement(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/IgnoreFlushFilterOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/IgnoreFlushFilterOutputStream.java new file mode 100644 index 000000000..962ff3b3e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/IgnoreFlushFilterOutputStream.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.OutputStream; +import java.io.IOException; + + +/** + * A filter output stream which ignores flush requests. + * + **/ +public class IgnoreFlushFilterOutputStream extends java.io.FilterOutputStream { + + /** Creates a new instance of CountingOutputStream */ + public IgnoreFlushFilterOutputStream(OutputStream out) { + super(out); + } + + @Override + public void flush() throws IOException {// do nothing + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/JxtaBiDiPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/JxtaBiDiPipe.java new file mode 100644 index 000000000..c6e2d5840 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/JxtaBiDiPipe.java @@ -0,0 +1,1284 @@ +/* + * Copyright (c) 2006-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.util; + +import net.jxta.credential.Credential; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.impl.endpoint.tcp.TcpMessenger; +import net.jxta.impl.util.pipe.reliable.Defs; +import net.jxta.impl.util.pipe.reliable.FixedFlowControl; +import net.jxta.impl.util.pipe.reliable.OutgoingMsgrAdaptor; +import net.jxta.impl.util.pipe.reliable.ReliableInputStream; +import net.jxta.impl.util.pipe.reliable.ReliableOutputStream; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.OutputPipeEvent; +import net.jxta.pipe.OutputPipeListener; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketTimeoutException; +import java.util.Collections; +import java.util.Iterator; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * JxtaBiDiPipe is a pair of UnicastPipe channels that implements a bidirectional pipe. + * By default, JxtaBiDiPipe operates in reliable mode, unless otherwise specified, + * in addition, messages must not exceed the Endpoint MTU size of 64K, exceed the + * MTU will lead to unexpected behavior. + *

      + * It highly recommended that an application message listener is specified, not doing so, may + * lead to message loss in the event the internal queue is overflowed. + *

      + * Sending messages vis {@link #sendMessage(Message)} from within a + * {@code PipeMsgListener} may result in a deadlock due to contention + * between the sending and receiving portions of BiDi pipes. + *

      + * JxtaBiDiPipe, whenever possible, will attempt to utilize direct tcp messengers, + * which leads to improved performance. + */ +public class JxtaBiDiPipe implements PipeMsgListener, OutputPipeListener, ReliableInputStream.MsgListener { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(JxtaBiDiPipe.class.getName()); + + private final static int MAXRETRYTIMEOUT = 120 * 1000; + private PipeAdvertisement remotePipeAdv; + private PeerAdvertisement remotePeerAdv; + protected int timeout = 15 * 1000; + protected int retryTimeout = 60 * 1000; + protected int maxRetryTimeout = MAXRETRYTIMEOUT; + protected int windowSize = 50; + + private ArrayBlockingQueue queue = new ArrayBlockingQueue(windowSize); + protected PeerGroup group; + protected PipeAdvertisement pipeAdv; + protected PipeAdvertisement myPipeAdv; + protected PipeService pipeSvc; + protected InputPipe inputPipe; + protected OutputPipe connectOutpipe; + protected Messenger msgr; + protected InputStream stream; + protected final Object closeLock = new Object(); + protected final Object acceptLock = new Object(); + protected final Object finalLock = new Object(); + protected boolean closed = false; + protected boolean bound = false; + protected boolean dequeued = false; + protected PipeMsgListener msgListener; + protected PipeEventListener eventListener; + protected PipeStateListener stateListener; + protected Credential credential = null; + protected boolean waiting; + + /** + * If {@code true} then we are using the underlying end-to-end ACK reliable + * layer to ensure that messages are received by the remote peer. + */ + protected boolean isReliable = false; + + protected ReliableInputStream ris = null; + protected ReliableOutputStream ros = null; + + /** + * If {@code true} then we are using a reliable direct messenger to the + * remote peer. We will assume that messages which are sent successfully + * will be received successfully. + */ + protected volatile boolean direct = false; + protected OutgoingMsgrAdaptor outgoing = null; + protected StructuredDocument credentialDoc = null; + + /** + * Pipe close Event + */ + public static final int PIPE_CLOSED_EVENT = 1; + + /** + * Creates a bidirectional pipe + * + * @param group group context + * @param msgr lightweight output pipe + * @param pipe PipeAdvertisement + * @param isReliable Whether the connection is reliable or not + * @param credDoc Credential StructuredDocument + * @param direct indicates a direct messenger pipe + * @throws IOException if an io error occurs + */ + protected JxtaBiDiPipe(PeerGroup group, Messenger msgr, PipeAdvertisement pipe, StructuredDocument credDoc, boolean isReliable, boolean direct) throws IOException { + if (msgr == null) { + throw new IOException("Null Messenger"); + } + this.direct = direct; + this.group = group; + this.pipeAdv = pipe; + this.credentialDoc = credDoc != null ? credDoc : getCredDoc(group); + this.pipeSvc = group.getPipeService(); + this.inputPipe = pipeSvc.createInputPipe(pipe, this); + this.msgr = msgr; + this.isReliable = isReliable; + if (!direct) { + createRLib(); + } + setBound(); + } + + /** + * Creates a new object with a default timeout of #timeout, and no reliability. + * + */ + public JxtaBiDiPipe() { + } + + /** + * Creates a bidirectional pipe. + * + * Attempts to create a bidirectional connection to remote peer within default + * timeout of #timeout. + * + * @param group group context + * @param pipeAd PipeAdvertisement + * @param msgListener application PipeMsgListener + * @throws IOException if an io error occurs + */ + public JxtaBiDiPipe(PeerGroup group, PipeAdvertisement pipeAd, PipeMsgListener msgListener) throws IOException { + connect(group, null, pipeAd, timeout, msgListener); + } + + /** + * Creates a bidirectional pipe. + * + * Attempts to create a bidirectional connection to remote peer within specified + * timeout of #timeout. + * + * @param group group context + * @param timeout The number of milliseconds within which the JxtaBiDiPipe must + * be successfully created. An exception will be thrown if the pipe + * cannot be created in the alotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @param pipeAd PipeAdvertisement + * @param msgListener application PipeMsgListener + * @throws IOException if an io error occurs + */ + public JxtaBiDiPipe(PeerGroup group, PipeAdvertisement pipeAd, int timeout, PipeMsgListener msgListener) throws IOException { + connect(group, null, pipeAd, timeout, msgListener); + } + + /** + * attempts to create a bidirectional connection to remote peer + * + * @param group group context + * @param pipeAd PipeAdvertisement + * @param timeout The number of milliseconds within which the JxtaBiDiPipe must + * be successfully created. An exception will be thrown if the pipe + * cannot be created in the allotted time. A timeout value of {@code 0} + * (zero) specifies an infinite timeout. + * @param msgListener application PipeMsgListener + * @param reliable if true, the reliability is assumed + * @throws IOException if an io error occurs + */ + public JxtaBiDiPipe(PeerGroup group, PipeAdvertisement pipeAd, int timeout, PipeMsgListener msgListener, boolean reliable) throws IOException { + connect(group, null, pipeAd, timeout, msgListener, reliable); + } + + /** + * Connect to a JxtaServerPipe with default timeout + * + * @param group group context + * @param pipeAd PipeAdvertisement + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PipeAdvertisement pipeAd) throws IOException { + connect(group, pipeAd, timeout); + } + + /** + * Connects to a remote JxtaBiDiPipe + * + * @param group group context + * @param pipeAd PipeAdvertisement + * @param timeout timeout in ms, also reset object default timeout + * to that of timeout + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PipeAdvertisement pipeAd, int timeout) throws IOException { + connect(group, null, pipeAd, timeout, null); + } + + /** + * Connects to a remote JxtaServerPipe + * + * @param group group context + * @param peerid peer to connect to + * @param pipeAd PipeAdvertisement + * @param timeout timeout in ms, also reset object default timeout to that of timeout + * @param msgListener application PipeMsgListener + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PeerID peerid, PipeAdvertisement pipeAd, int timeout, PipeMsgListener msgListener) throws IOException { + connect(group, peerid, pipeAd, timeout, msgListener, isReliable); + } + + /** + * Connects to a remote JxtaServerPipe + * + * @param group group context + * @param peerid peer to connect to + * @param pipeAd PipeAdvertisement + * @param timeout timeout in ms, also reset object default timeout to that of timeout + * @param msgListener application PipeMsgListener + * @param reliable Reliable connection + * @throws IOException if an io error occurs + */ + public void connect(PeerGroup group, PeerID peerid, PipeAdvertisement pipeAd, int timeout, PipeMsgListener msgListener, boolean reliable) throws IOException { + if (isBound()) { + throw new IOException("Pipe already bound"); + } + if (timeout <= 0) { + throw new IllegalArgumentException("Invalid timeout :" + timeout); + } + + this.pipeAdv = pipeAd; + this.group = group; + this.msgListener = msgListener; + if (msgListener != null) { + dequeued = true; + } + this.isReliable = reliable; + pipeSvc = group.getPipeService(); + this.timeout = timeout; + myPipeAdv = JxtaServerPipe.newInputPipe(group, pipeAd); + this.inputPipe = pipeSvc.createInputPipe(myPipeAdv, this); + this.credentialDoc = credentialDoc != null ? credentialDoc : getCredDoc(group); + Message openMsg = createOpenMessage(group, myPipeAdv); + + // create the output pipe and send this message + if (peerid == null) { + pipeSvc.createOutputPipe(pipeAd, this); + } else { + pipeSvc.createOutputPipe(pipeAd, Collections.singleton(peerid), this); + } + try { + synchronized (acceptLock) { + // check connectOutpipe within lock to prevent a race with modification. + if (connectOutpipe == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting for " + timeout + " msec"); + } + acceptLock.wait(timeout); + } + } + } catch (InterruptedException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", ie); + } + Thread.interrupted(); + IOException exp = new IOException("Interrupted"); + exp.initCause(ie); + throw exp; + } + if (connectOutpipe == null) { + throw new IOException("connection timeout"); + } + // send connect message + waiting = true; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a backchannel message"); + } + connectOutpipe.send(openMsg); + // wait for the second op + try { + synchronized (finalLock) { + if (waiting) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting for " + timeout + " msec for back channel to be established"); + } + finalLock.wait(timeout); + // Need to check for creation + if (msgr == null) { + throw new IOException("connection timeout"); + } + } + } + } catch (InterruptedException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", ie); + } + Thread.interrupted(); + IOException exp = new IOException("Interrupted"); + exp.initCause(ie); + throw exp; + } + setBound(); + notifyListeners(PipeStateListener.PIPE_OPENED_EVENT); + } + + /** + * creates all the reliability objects + */ + private void createRLib() { + if (isReliable) { + if (outgoing == null) { + outgoing = new OutgoingMsgrAdaptor(msgr, retryTimeout); + } + if (ros == null) { + ros = new ReliableOutputStream(outgoing, new FixedFlowControl(windowSize)); + } + if (ris == null) { + ris = new ReliableInputStream(outgoing, retryTimeout, this); + } + } + } + + /** + * Toggles reliability + * + * @param reliable Toggles reliability to reliable + * @throws IOException if pipe is bound + */ + public void setReliable(boolean reliable) throws IOException { + if (isBound()) { + throw new IOException("Can not set reliability after pipe is bound"); + } + this.isReliable = reliable; + } + + /** + * Obtain the cred doc from the group object. + * + * @param group group context + * @return The credDoc value + */ + protected static StructuredDocument getCredDoc(PeerGroup group) { + try { + MembershipService membership = group.getMembershipService(); + Credential credential = membership.getDefaultCredential(); + + if (credential != null) { + return credential.getDocument(MimeMediaType.XMLUTF8); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to get credential", e); + } + } + return null; + } + + /** + * get the remote credential doc + * + * @return Credential StructuredDocument + */ + public StructuredDocument getCredentialDoc() { + return credentialDoc; + } + + /** + * Sets the connection credential doc. + * If no credentials are set, the default group credential are used. + * + * @param doc Credential StructuredDocument + */ + public void setCredentialDoc(StructuredDocument doc) { + this.credentialDoc = doc; + } + + /** + * Creates a connection request message + * + * @param group group context + * @param pipeAd pipe advertisement + * @return the Message object + * @throws IOException if an io error occurs + */ + protected Message createOpenMessage(PeerGroup group, PipeAdvertisement pipeAd) throws IOException { + Message msg = new Message(); + PeerAdvertisement peerAdv = group.getPeerAdvertisement(); + + if (credentialDoc == null) { + credentialDoc = getCredDoc(group); + } + if (credentialDoc == null && pipeAd.getType().equals(PipeService.UnicastSecureType)) { + throw new IOException("No credentials established to initiate a secure connection"); + } + try { + if (credentialDoc != null) { + msg.addMessageElement(JxtaServerPipe.nameSpace, + new TextDocumentMessageElement(JxtaServerPipe.credTag, (XMLDocument) credentialDoc, null)); + } + msg.addMessageElement(JxtaServerPipe.nameSpace, + new TextDocumentMessageElement(JxtaServerPipe.reqPipeTag, + (XMLDocument) pipeAd.getDocument(MimeMediaType.XMLUTF8), null)); + + msg.addMessageElement(JxtaServerPipe.nameSpace, + new StringMessageElement(JxtaServerPipe.reliableTag, Boolean.toString(isReliable), null)); + + msg.addMessageElement(JxtaServerPipe.nameSpace, + new StringMessageElement(JxtaServerPipe.directSupportedTag, Boolean.toString(true), null)); + + msg.addMessageElement(JxtaServerPipe.nameSpace, + new TextDocumentMessageElement(JxtaServerPipe.remPeerTag, + (XMLDocument) peerAdv.getDocument(MimeMediaType.XMLUTF8), null)); + return msg; + } catch (Throwable t) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "error getting element stream", t); + } + return null; + } + } + + /** + * Sets the bound attribute of the JxtaServerPipe object + */ + void setBound() { + bound = true; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pipe Bound :true"); + } + } + + /** + * Returns the binding state of the JxtaServerPipe. + * + * @return true if the ServerSocket successfully bound to an address + */ + public boolean isBound() { + return bound; + } + + /** + * Returns an input stream for this socket. + * + * @return a stream for reading from this socket. + * @throws IOException if an I/O error occurs when creating the + * input stream. + */ + public InputPipe getInputPipe() throws IOException { + return inputPipe; + } + + /** + * Returns remote PeerAdvertisement + * + * @return remote PeerAdvertisement + */ + public PeerAdvertisement getRemotePeerAdvertisement() { + return remotePeerAdv; + } + + /** + * Returns remote PipeAdvertisement + * + * @return remote PipeAdvertisement + */ + public PipeAdvertisement getRemotePipeAdvertisement() { + return remotePipeAdv; + } + + /** + * Sets the remote PeerAdvertisement + * + * @param peer Remote PeerAdvertisement + */ + protected void setRemotePeerAdvertisement(PeerAdvertisement peer) { + this.remotePeerAdv = peer; + } + + /** + * Sets the remote PipeAdvertisement + * + * @param pipe PipeAdvertisement + */ + protected void setRemotePipeAdvertisement(PipeAdvertisement pipe) { + this.remotePipeAdv = pipe; + } + + /** + * Closes this pipe. + * + * @throws IOException if an I/O error occurs when closing this + * socket. + */ + public void close() throws IOException { + sendClose(); + closePipe(false); + bound = false; + } + + protected void closePipe(boolean fastClose) throws IOException { + // close both pipes + synchronized (closeLock) { + if (closed) { + return; + } + closed = true; + bound = false; + } + + if (!fastClose && isReliable && !direct) { + /* + * This implements linger! + */ + long quitAt = System.currentTimeMillis() + timeout; + while (true) { + //FIXME hamada this does not loop + if (ros == null || ros.getMaxAck() == ros.getSeqNumber()) { + // Nothing to worry about. + break; + } + + // By default wait forever. + long left = 0; + + // If timeout is not zero. Then compute the waiting time + // left. + if (timeout != 0) { + left = quitAt - System.currentTimeMillis(); + if (left < 0) { + // Too late + sendClose(); + throw new IOException("Close timeout"); + } + } + + try { + if (!ros.isQueueEmpty()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting for Output stream queue event"); + } + ros.waitQueueEvent(left); + } + break; + } catch (InterruptedException ie) { + // give up, then. + throw new IOException("Close interrupted"); + } + } + + // We are initiating the close. We do not want to receive + // anything more. So we can close the ris right away. + ris.close(); + } + + if (isReliable && ros != null) { + ros.close(); + } + + // close the pipe + inputPipe.close(); + msgr.close(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pipe close complete"); + } + notifyListeners(PIPE_CLOSED_EVENT); + } + + private void notifyListeners(int event) { + try { + if (eventListener != null) { + eventListener.pipeEvent(event); + } else if (stateListener != null) { + stateListener.stateEvent(this, event); + } + } catch (Throwable th) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "error during pipe event callback", th); + } + } + } + + /** + * Sets the inputPipe attribute of the JxtaBiDiPipe object + * + * @param inputPipe The new inputPipe value + */ + protected void setInputPipe(InputPipe inputPipe) { + this.inputPipe = inputPipe; + } + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + Message message = event.getMessage(); + if (message == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Empty event"); + } + return; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pipe message arrived"); + } + + MessageElement element; + if (!bound) { + // look for a remote pipe answer + element = message.getMessageElement(JxtaServerPipe.nameSpace, JxtaServerPipe.remPipeTag); + if (element != null) { + // connect response + try { + XMLDocument CredDoc = null; + XMLDocument remotePipeDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(element); + + remotePipeAdv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(remotePipeDoc); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Recevied a pipe Advertisement :" + remotePipeAdv.getName()); + } + + element = message.getMessageElement(JxtaServerPipe.nameSpace, JxtaServerPipe.remPeerTag); + if (element != null) { + XMLDocument remotePeerDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(element); + + remotePeerAdv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(remotePeerDoc); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Recevied an Peer Advertisement :" + remotePeerAdv.getName()); + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(" BAD connect response"); + } + return; + } + + element = message.getMessageElement(JxtaServerPipe.nameSpace, JxtaServerPipe.credTag); + if (element != null) { + CredDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(element); + } + if (pipeAdv.getType().equals(PipeService.UnicastSecureType) && (CredDoc == null || !checkCred(CredDoc))) { + // we're done here + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Missing remote credential doc"); + } + return; + } + + element = message.getMessageElement(JxtaServerPipe.nameSpace, JxtaServerPipe.reliableTag); + if (element != null) { + isReliable = Boolean.valueOf(element.toString()); + } + + boolean directSupported = false; + element = message.getMessageElement(JxtaServerPipe.nameSpace, JxtaServerPipe.directSupportedTag); + if (element != null) { + directSupported = Boolean.valueOf(element.toString()); + } + + if (directSupported) { + msgr = getDirectMessenger(group, remotePipeAdv, remotePeerAdv); + if (msgr != null) { + this.direct = true; + } else { + msgr = lightweightOutputPipe(group, remotePipeAdv, remotePeerAdv); + } + } else { + msgr = lightweightOutputPipe(group, remotePipeAdv, remotePeerAdv); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reliability set to :" + isReliable); + } + if (isReliable && !direct) { + createRLib(); + } + synchronized (finalLock) { + waiting = false; + finalLock.notifyAll(); + } + } catch (IOException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "failed to process response message", e); + } + } + return; + } + } + + if (isReliable && !direct) { + // let reliabilty deal with the message + receiveMessage(message); + return; + } + if (!hasClose(message)) { + push(event); + } + } + + private boolean hasClose(Message message) { + // look for close request + MessageElement element = message.getMessageElement(JxtaServerPipe.nameSpace, JxtaServerPipe.closeTag); + if (element != null) { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Recevied a pipe close request, closing pipes"); + } + if (ros != null) { + ros.hardClose(); + } + closePipe(false); + } catch (IOException ie) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed during close", ie); + } + } + return true; + } + return false; + } + + private void receiveMessage(Message message) { + Iterator i = message.getMessageElements(Defs.NAMESPACE, Defs.MIME_TYPE_ACK); + + if (i.hasNext()) { + if (ros != null) { + ros.recv(message); + } + return; + } + + i = message.getMessageElements(Defs.NAMESPACE, Defs.MIME_TYPE_BLOCK); + if (i.hasNext()) { + + // It can happen that we receive messages for the input stream + // while we have not finished creating it. + try { + synchronized (finalLock) { + while (waiting) { + finalLock.wait(timeout); + } + } + } catch (InterruptedException ie) {// ignored + } + + if (ris != null) { + ris.recv(message); + } + } + } + + /** + * Gets the Maximum Retry Timeout of the reliability layer + * + * @return The maximum retry Timeout value + */ + public synchronized int getMaxRetryTimeout() { + return maxRetryTimeout; + } + + /** + * Gets the Maximum Retry Timeout of the reliability layer + * + * @param maxRetryTimeout The new maximum retry timeout value + * @throws IllegalArgumentException if maxRetryTimeout exceeds jxta platform maximum retry timeout + */ + public synchronized void setMaxRetryTimeout(int maxRetryTimeout) { + if (maxRetryTimeout <= 0 || maxRetryTimeout > MAXRETRYTIMEOUT) { + throw new IllegalArgumentException( + "Invalid Maximum retry timeout :" + maxRetryTimeout + " Exceed Global maximum retry timeout :" + + MAXRETRYTIMEOUT); + } + this.maxRetryTimeout = maxRetryTimeout; + } + + /** + * Gets the Retry Timeout of the reliability layer + * + * @return The retry Timeout value + */ + public synchronized int getRetryTimeout() { + return retryTimeout; + } + + /** + * Sets the Retry Timeout of the underlying reliability layer + * . + * In reliable mode it is possible for this call to block + * trying to obtain a lock on reliable input stream + * + * @param retryTimeout The new retry timeout value + * @throws IOException if an I/O error occurs + */ + public synchronized void setRetryTimeout(int retryTimeout) throws IOException { + if (timeout <= 0) { + throw new IllegalArgumentException("Invalid Socket timeout :" + retryTimeout); + } + this.retryTimeout = retryTimeout; + if (outgoing != null) { + outgoing.setTimeout(retryTimeout); + } + } + + /** + * When in reliable mode, gets the Reliable library window size + * + * @return The windowSize value + */ + public synchronized int getWindowSize() { + return windowSize; + } + + /** + * When in reliable mode, sets the Reliable library window size + * + * @param windowSize The new window size value + * @throws IOException if an I/O error occurs + */ + public synchronized void setWindowSize(int windowSize) throws IOException { + if (isBound()) { + throw new IOException("Socket bound. Can not change the window size"); + } + this.windowSize = windowSize; + } + + /** + * This method is invoked by the Reliablity library for each incoming data message + * + * @param message Incoming message + */ + public void processIncomingMessage(Message message) { + if (!hasClose(message)) { + PipeMsgEvent event = new PipeMsgEvent(this, message, (PipeID) inputPipe.getPipeID()); + push(event); + } + } + + private void push(PipeMsgEvent event) { + if (msgListener == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("push message onto queue"); + } + queue.offer(event); + } else { + dequeue(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("calling message listener"); + } + msgListener.pipeMsgEvent(event); + } + + } + + /** + * Send a message + *

      + * Messenger + * + * @param msg Message to send to the remote side + * @return true if message was successfully enqueued + * @throws IOException if the underlying messenger breaks, either due to + * a physical address change, reliability issue. + * @see net.jxta.endpoint.Message + */ + public boolean sendMessage(Message msg) throws IOException { + if (isReliable && !direct) { + int seqn = ros.send(msg); + return (seqn > 0); + } else { + try { + if (msgr instanceof TcpMessenger) { + ((TcpMessenger) msgr).sendMessageDirect(msg, null, null, true); + return true; + } else { + return msgr.sendMessage(msg, null, null); + } + } catch (SocketTimeoutException io) { + if (msgr instanceof TcpMessenger) { + ((TcpMessenger) msgr).sendMessageDirect(msg, null, null, true); + return true; + } else { + return msgr.sendMessage(msg, null, null); + } + } catch (IOException io) { + closePipe(true); + IOException exp = new IOException("IO error occured during sendMessage()"); + exp.initCause(io); + throw exp; + + } + } + } + + private void dequeue() { + if (!dequeued && (null != msgListener)) { + while (queue != null && !queue.isEmpty()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("dequeing messages onto message listener"); + } + try { + msgListener.pipeMsgEvent(queue.take()); + } catch (InterruptedException e) { + //ignored + } + } + dequeued = false; + } + } + + /** + * {@inheritDoc} + */ + public void outputPipeEvent(OutputPipeEvent event) { + OutputPipe op = event.getOutputPipe(); + + if (op.getAdvertisement() == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("The output pipe has no internal pipe advertisement. Continueing anyway."); + } + } + if (op.getAdvertisement() == null || pipeAdv.equals(op.getAdvertisement())) { + synchronized (acceptLock) { + // modify op within lock to prevent a race with the if. + if (connectOutpipe == null) { + connectOutpipe = op; + // set to null to avoid closure + op = null; + } + acceptLock.notifyAll(); + } + // Ooops one too many, we were too fast re-trying. + if (op != null) { + op.close(); + } + + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unexpected OutputPipe :" + op); + } + } + } + + /** + * A lightweight direct messenger output pipe constructor, note the return type + * Since all the info needed is available, there's no need for to + * use the pipe service to resolve the pipe we have all we need + * to construct a messenger. + * + * @param group group context + * @param pipeAdv Remote Pipe Advertisement + * @param peer Remote Peer advertisement + * @return Messenger + */ + protected static Messenger getDirectMessenger(PeerGroup group, PipeAdvertisement pipeAdv, PeerAdvertisement peer) { + // Get an endpoint messenger to that address + if (pipeAdv.getType().equals(PipeService.PropagateType)) { + throw new IllegalArgumentException("Invalid pipe type " + pipeAdv.getType()); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating a Direct Messenger"); + } + + if (pipeAdv.getType().equals(PipeService.UnicastType)) { + EndpointService endpoint = group.getEndpointService(); + EndpointAddress pipeEndpoint = new EndpointAddress("jxta", + (peer.getPeerID().getUniqueValue()).toString(), + "PipeService", + pipeAdv.getPipeID().toString()); + return endpoint.getDirectMessenger(pipeEndpoint, peer, true); + } + return null; + } + + /** + * A lightweight output pipe constructor, note the return type + * Since all the info needed is available, there's no need for to + * use the pipe service to resolve the pipe we have all we need + * to construct a messenger. + * + * @param group group context + * @param pipeAdv Remote Pipe Advertisement + * @param peer Remote Peer advertisement + * @return Messenger + */ + protected static Messenger lightweightOutputPipe(PeerGroup group, PipeAdvertisement pipeAdv, PeerAdvertisement peer) { + + EndpointService endpoint = group.getEndpointService(); + ID opId = pipeAdv.getPipeID(); + String destPeer = (peer.getPeerID().getUniqueValue()).toString(); + + // Get an endpoint messenger to that address + EndpointAddress addr; + if (pipeAdv.getType().equals(PipeService.UnicastType)) { + addr = new EndpointAddress("jxta", destPeer, "PipeService", opId.toString()); + } else if (pipeAdv.getType().equals(PipeService.UnicastSecureType)) { + addr = new EndpointAddress("jxtatls", destPeer, "PipeService", opId.toString()); + } else { + // not a supported type + return null; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating a lightweightOutputPipe()"); + } + return endpoint.getMessenger(addr); + } + + /** + * Not implemented yet + * + * @param cred the credential document + * @return always returns true + */ + protected boolean checkCred(StructuredDocument cred) { + // FIXME need to check credentials + return true; + } + + /** + * Send a close message to the remote side + */ + private void sendClose() { + if (!direct && isReliable && ros.isClosed()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("ReliableOutputStream is already closed. Skipping close message"); + } + return; + } + + Message msg = new Message(); + msg.addMessageElement(JxtaServerPipe.nameSpace, new StringMessageElement(JxtaServerPipe.closeTag, "close", null)); + try { + sendMessage(msg); + // ros will not take any new message, now. + if (!direct && ros != null) { + ros.close(); + } + } catch (IOException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.SEVERE, "failed during close", ie); + } + } + } + + /** + * Returns the message listener for this pipe + * + * @return PipeMsgListener + * @deprecated use getMessageListener instead + */ + @Deprecated + public PipeMsgListener getListener() { + return getMessageListener(); + } + + /** + * Returns the message listener for this pipe + * + * @return PipeMsgListener + */ + public PipeMsgListener getMessageListener() { + return msgListener; + } + + /** + * Sets message listener for a pipe spawned by the JxtaServerPipe. + * There is a window where a message could arrive prior to listener being + * registered therefore a message queue is created to queue messages, once + * a listener is registered these messages will be dequeued by calling the + * listener until the queue is empty + * + * @param msgListener New value of property listener. + * @deprecated use setMessageListener instead + */ + @Deprecated + public void setListener(PipeMsgListener msgListener) { + setMessageListener(msgListener); + } + + /** + * Sets message listener for a pipe spawned by the JxtaServerPipe. + * There is a window where a message could arrive prior to listener being + * registered therefore a message queue is created to queue messages, once + * a listener is registered these messages will be dequeued by calling the + * listener until the queue is empty. + *

      + * Sending messages vis {@link #sendMessage(Message)} from within a + * {@code PipeMsgListener} may result in a deadlock due to contention + * between the sending and receiving portions of BiDi pipes. + * + * @param msgListener New value of property listener. + */ + public void setMessageListener(PipeMsgListener msgListener) { + this.msgListener = msgListener; + // if there are messages enqueued then dequeue them onto the msgListener + dequeue(); + } + + /** + * Sets a Pipe event listener, set listener to null to unset the listener + * + * @param eventListener New value of property listener. + * @deprecated use setPipeEventListener instead + */ + @Deprecated + public void setListener(PipeEventListener eventListener) { + setPipeEventListener(eventListener); + } + + /** + * Sets a Pipe event listener, set listener to null to unset the listener + * + * @param eventListener New value of property listener. + */ + public void setPipeEventListener(PipeEventListener eventListener) { + this.eventListener = eventListener; + } + + /** + * Returns the Pipe event listener for this pipe + * + * @return PipeMsgListener + */ + public PipeEventListener getPipeEventListener() { + return eventListener; + } + + /** + * Sets a Pipe state listener, set listener to null to unset the listener + * + * @param stateListener New value of property listener. + */ + public void setPipeStateListener(PipeStateListener stateListener) { + this.stateListener = stateListener; + } + + /** + * Returns the Pipe state listener for this pipe + * + * @return PipeMsgListener + */ + public PipeStateListener getPipeStateListener() { + return stateListener; + } + + /** + * Gets a message from the queue. If no Object is immediately available, + * then wait the specified amount of time for a message to be inserted. + * + * @param timeout Amount of time to wait in milliseconds for an object to + * be available. Per Java convention, a timeout of zero (0) means wait an + * infinite amount of time. Negative values mean do not wait at all. + * @return The next message in the queue. if a listener is registered calls + * to this method will return null + * @throws InterruptedException if the operation is interrupted before + * the timeout interval is completed. + */ + public Message getMessage(int timeout) throws InterruptedException { + if (queue == null || msgListener != null) { + return null; + } else { + PipeMsgEvent ev = queue.poll(timeout, TimeUnit.MILLISECONDS); + if (ev != null) { + return ev.getMessage(); + } else { + return null; + } + } + } + + /** + * Returns the Assigned PipeAdvertisement + * + * @return the Assigned PipeAdvertisement + */ + public PipeAdvertisement getPipeAdvertisement() { + return pipeAdv; + } + + /** + * {@inheritDoc} + *

      + * Closes the JxtaBiDiPipe. + */ + @Override + protected synchronized void finalize() throws Throwable { + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("JxtaBiDiPipe is being finalized without being previously closed. This is likely a users bug."); + } + close(); + } + super.finalize(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/JxtaServerPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/JxtaServerPipe.java new file mode 100644 index 000000000..95c2ad775 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/JxtaServerPipe.java @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.util; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.IDFactory; +import net.jxta.impl.endpoint.tcp.TcpMessenger; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The server side of a JxtaBiDiPipe. The intent of this object is accept connection requests. + * JxtaServerPipe follows the same pattern as java.net.ServerSocket, without it no connection can be + * established. + * + */ +public class JxtaServerPipe implements PipeMsgListener { + + private static final Logger LOG = Logger.getLogger(JxtaServerPipe.class.getName()); + protected static final String nameSpace = "JXTABIP"; + protected static final String credTag = "Cred"; + protected static final String reqPipeTag = "reqPipe"; + protected static final String remPeerTag = "remPeer"; + protected static final String remPipeTag = "remPipe"; + protected static final String closeTag = "close"; + protected static final String reliableTag = "reliable"; + protected static final String directSupportedTag = "direct"; + private PeerGroup group; + private InputPipe serverPipe; + private PipeAdvertisement pipeadv; + private int backlog = 50; + private long timeout = 30 * 1000L; + private final Object closeLock = new Object(); + protected BlockingQueue connectionQueue = null; + private boolean bound = false; + private boolean closed = false; + protected StructuredDocument myCredentialDoc = null; + /** + * The exceutor service. + */ + private final ExecutorService executor; + + /** + * Default constructor for the JxtaServerPipe + *

      + * backlog default of 50 + *

      call to accept() for this ServerPipe will + * block for only this amount of time. If the timeout expires, + * a java.net.SocketTimeoutException is raised, though the ServerPipe is still valid. + *

      + * + * @param group JXTA PeerGroup + * @param pipeadv PipeAdvertisement on which pipe requests are accepted + * @throws IOException if an I/O error occurs + */ + public JxtaServerPipe(PeerGroup group, PipeAdvertisement pipeadv) throws IOException { + this(group, pipeadv, 50); + } + + /** + * Constructor for the JxtaServerPipe + * + * @param group JXTA PeerGroup + * @param pipeadv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * @param timeout call to accept() for this ServerPipe will + * block for only this amount of time. If the timeout expires, + * a java.net.SocketTimeoutException is raised, though the ServerPipe is still valid. + * @throws IOException if an I/O error occurs + */ + public JxtaServerPipe(PeerGroup group, PipeAdvertisement pipeadv, int backlog, int timeout) throws IOException { + this(group, pipeadv, backlog); + this.timeout = timeout; + } + + /** + * Constructor for the JxtaServerPipe object + * + * @param group JXTA PeerGroup + * @param pipeadv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs + */ + public JxtaServerPipe(PeerGroup group, PipeAdvertisement pipeadv, int backlog) throws IOException { + this.group = group; + this.executor = Executors.newFixedThreadPool(3); + this.pipeadv = pipeadv; + this.backlog = backlog; + connectionQueue = new ArrayBlockingQueue(backlog); + PipeService pipeSvc = group.getPipeService(); + serverPipe = pipeSvc.createInputPipe(pipeadv, this); + setBound(); + } + + /** + * Binds the JxtaServerPipe to a specific pipe advertisement + * + * @param group JXTA PeerGroup + * @param pipeadv PipeAdvertisement on which pipe requests are accepted + * @throws IOException if an I/O error occurs + */ + public void bind(PeerGroup group, PipeAdvertisement pipeadv) throws IOException { + bind(group, pipeadv, backlog); + } + + /** + * Binds the JxtaServerPipe to a specific pipe advertisement + * + * @param group JXTA PeerGroup + * @param pipeadv PipeAdvertisement on which pipe requests are accepted + * @param backlog the maximum length of the queue. + * @throws IOException if an I/O error occurs + */ + public void bind(PeerGroup group, PipeAdvertisement pipeadv, int backlog) throws IOException { + this.backlog = backlog; + connectionQueue = new ArrayBlockingQueue(backlog); + this.group = group; + this.pipeadv = pipeadv; + PipeService pipeSvc = group.getPipeService(); + serverPipe = pipeSvc.createInputPipe(pipeadv, this); + setBound(); + } + + /** + * Listens for a connection to be made to this socket and accepts + * it. The method blocks until a connection is made. + * + * @return the connection accepted, null otherwise + * @throws IOException if an I/O error occurs + */ + public JxtaBiDiPipe accept() throws IOException { + if (isClosed()) { + throw new SocketException("JxtaServerPipe is closed"); + } + if (!isBound()) { + throw new SocketException("JxtaServerPipe is not bound yet"); + } + try { + JxtaBiDiPipe bidi = connectionQueue.poll(timeout, TimeUnit.MILLISECONDS); + if (bidi == null) { + throw new SocketTimeoutException("Timeout reached"); + } + return bidi; + } catch (InterruptedException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Interrupted", ie); + } + throw new SocketException("interrupted"); + } + } + + /** + * Gets the group associated with this JxtaServerPipe + * + * @return The group value + */ + public PeerGroup getGroup() { + return group; + } + + /** + * Gets the PipeAdvertisement associated with this JxtaServerPipe + * + * @return The pipeAdv value + */ + public PipeAdvertisement getPipeAdv() { + return pipeadv; + } + + /** + * Closes this JxtaServerPipe (closes the underlying input pipe). + * + * @throws IOException if an I/O error occurs + */ + public void close() throws IOException { + synchronized (closeLock) { + if (isClosed()) { + return; + } + if (bound) { + // close all the pipe + serverPipe.close(); + connectionQueue.clear(); + executor.shutdownNow(); + bound = false; + } + closed = true; + } + } + + /** + * Sets the bound attribute of the JxtaServerPipe + */ + void setBound() { + bound = true; + } + + /** + * Gets the Timeout attribute of the JxtaServerPipe + * + * @return The soTimeout value + * @throws IOException if an I/O error occurs + */ + + public synchronized int getPipeTimeout() throws IOException { + if (isClosed()) { + throw new SocketException("Server Pipe is closed"); + } + if (timeout > Integer.MAX_VALUE) { + return 0; + } else { + return (int) timeout; + } + } + + /** + * Sets the Timeout attribute of the JxtaServerPipe a timeout of 0 blocks forever. + * + * @param timeout The new soTimeout value + * @throws SocketException if an I/O error occurs + */ + public synchronized void setPipeTimeout(int timeout) throws SocketException { + if (isClosed()) { + throw new SocketException("Server Pipe is closed"); + } + + if (timeout < 0) { + throw new IllegalArgumentException("Negative timeout values are not allowed."); + } + + if (0 == timeout) { + this.timeout = Long.MAX_VALUE; + } else { + this.timeout = (long) timeout; + } + } + + /** + * Returns the closed state of the JxtaServerPipe. + * + * @return true if the socket has been closed + */ + public boolean isClosed() { + synchronized (closeLock) { + return closed; + } + } + + /** + * Returns the binding state of the JxtaServerPipe. + * + * @return true if the ServerSocket successfully bound to an address + */ + public boolean isBound() { + return bound; + } + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + Message message = event.getMessage(); + if (message == null) { + return; + } + ConnectionProcessor processor = new ConnectionProcessor(message); + executor.execute(processor); + } + + /** + * Method processMessage is the heart of this class. + *

      + * This takes new incoming connect messages and constructs the JxtaBiDiPipe + * to talk to the new client. + *

      + * The ResponseMessage is created and sent. + * + * @param msg The client connection request (assumed not null) + * @return JxtaBiDiPipe Which may be null if an error occurs. + */ + private JxtaBiDiPipe processMessage(Message msg) { + + PipeAdvertisement outputPipeAdv = null; + PeerAdvertisement peerAdv = null; + StructuredDocument credDoc = null; + try { + MessageElement el = msg.getMessageElement(nameSpace, credTag); + + if (el != null) { + credDoc = StructuredDocumentFactory.newStructuredDocument(el); + } + + el = msg.getMessageElement(nameSpace, reqPipeTag); + if (el != null) { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(el); + outputPipeAdv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + } + + el = msg.getMessageElement(nameSpace, remPeerTag); + if (el != null) { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(el); + peerAdv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + } + + el = msg.getMessageElement(nameSpace, reliableTag); + boolean isReliable = false; + if (el != null) { + isReliable = Boolean.valueOf((el.toString())); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Connection request [isReliable] :" + isReliable); + } + } + + el = msg.getMessageElement(nameSpace, directSupportedTag); + boolean directSupported = false; + if (el != null) { + directSupported = Boolean.valueOf((el.toString())); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Connection request [directSupported] :" + directSupported); + } + } + + Messenger msgr; + boolean direct = false; + if (directSupported) { + msgr = JxtaBiDiPipe.getDirectMessenger(group, outputPipeAdv, peerAdv); + if (msgr == null) { + msgr = JxtaBiDiPipe.lightweightOutputPipe(group, outputPipeAdv, peerAdv); + } else { + direct = true; + } + } else { + msgr = JxtaBiDiPipe.lightweightOutputPipe(group, outputPipeAdv, peerAdv); + } + + if (msgr != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reliability set to :" + isReliable); + } + PipeAdvertisement newpipe = newInputPipe(group, outputPipeAdv); + JxtaBiDiPipe pipe = new JxtaBiDiPipe(group, msgr, newpipe, credDoc, isReliable, direct); + + pipe.setRemotePeerAdvertisement(peerAdv); + pipe.setRemotePipeAdvertisement(outputPipeAdv); + sendResponseMessage(group, msgr, newpipe); + return pipe; + } + } catch (IOException e) { + // deal with the error + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "IOException occured", e); + } + } + return null; + } + + /** + * Method sendResponseMessage get the createResponseMessage and sends it. + * + * @param group the peer group + * @param msgr the remote node messenger + * @param pipeAd the pipe advertisement + * @throws IOException for failures sending the response message. + */ + protected void sendResponseMessage(PeerGroup group, Messenger msgr, PipeAdvertisement pipeAd) throws IOException { + + Message msg = new Message(); + PeerAdvertisement peerAdv = group.getPeerAdvertisement(); + + if (myCredentialDoc == null) { + myCredentialDoc = JxtaBiDiPipe.getCredDoc(group); + } + + if (myCredentialDoc != null) { + msg.addMessageElement(JxtaServerPipe.nameSpace, + new TextDocumentMessageElement(credTag, (XMLDocument) myCredentialDoc, null)); + } + + msg.addMessageElement(JxtaServerPipe.nameSpace, + new StringMessageElement(JxtaServerPipe.directSupportedTag, Boolean.toString(true), null)); + + msg.addMessageElement(JxtaServerPipe.nameSpace, + new TextDocumentMessageElement(remPipeTag, (XMLDocument) pipeAd.getDocument(MimeMediaType.XMLUTF8), null)); + + msg.addMessageElement(nameSpace, + new TextDocumentMessageElement(remPeerTag, (XMLDocument) peerAdv.getDocument(MimeMediaType.XMLUTF8), null)); + if (msgr instanceof TcpMessenger) { + ((TcpMessenger) msgr).sendMessageDirect(msg, null, null, true); + } else { + msgr.sendMessage(msg); + } + } + + /** + * Utility method newInputPipe is used to get new pipe advertisement (w/random pipe ID) from old one. + *

      + * Called by JxtaSocket to make pipe (name -> name.remote) for open message + *

      + * Called by JxtaServerSocket to make pipe (name.remote -> name.remote.remote) for response message + * + * @param group the peer group + * @param pipeadv to get the basename and type from + * @return PipeAdvertisement a new pipe advertisement + */ + protected static PipeAdvertisement newInputPipe(PeerGroup group, PipeAdvertisement pipeadv) { + PipeAdvertisement adv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + adv.setPipeID(IDFactory.newPipeID(group.getPeerGroupID())); + adv.setName(pipeadv.getName()); + adv.setType(pipeadv.getType()); + return adv; + } + + /** + * get the credential doc + * + * @return Credential StructuredDocument + */ + public StructuredDocument getCredentialDoc() { + return myCredentialDoc; + } + + /** + * Sets the connection credential doc + * If no credentials are set, the default group credential will be used + * + * @param doc Credential StructuredDocument + */ + public void setCredentialDoc(StructuredDocument doc) { + this.myCredentialDoc = doc; + } + + /** + * {@inheritDoc} + *

      + * Closes the JxtaServerPipe. + */ + @Override + protected synchronized void finalize() throws Throwable { + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("JxtaServerPipe is being finalized without being previously closed. This is likely a user's bug."); + } + } + close(); + super.finalize(); + } + /** + * A small class for processing individual messages. + */ + private class ConnectionProcessor implements Runnable { + + private Message message; + ConnectionProcessor(Message message) { + this.message = message; + } + + public void run() { + JxtaBiDiPipe bidi = processMessage(message); + // make sure we have a socket returning + if (bidi != null) { + try { + connectionQueue.offer(bidi, timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Thread.interrupted(); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/LimitInputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/LimitInputStream.java new file mode 100644 index 000000000..8c738c756 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/LimitInputStream.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.InputStream; + +import java.io.IOException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * Implements a bounds on the number of bytes which may be read from an + * InputStream. {link LimitInputStream.close() close()} does not close the + * underlying stream. + **/ +public class LimitInputStream extends FilterInputStream { + + /* + * Log4J Catagory + */ + private static final Logger LOG = Logger.getLogger(LimitInputStream.class.getName()); + + private transient long limit; + + private transient long read; + + private transient long mark; + + private transient boolean fatalUnderflow; + + private transient boolean alreadycounting; + + /** + * Creates a new instance of LimitInputStream + * + * @param in the stream which will be limited. + * @param limit the number of bytes which can be read from the stream. + **/ + public LimitInputStream(InputStream in, long limit) { + this(in, limit, false); + } + + /** + * Creates a new instance of LimitInputStream + * + * @param in the stream which will be limited. + * @param limit the number of bytes which can be read from the stream. + * @param underflowThrows if the underlying stream EOFs before limit then + * an IOException will be thrown. + **/ + public LimitInputStream(InputStream in, long limit, boolean underflowThrows) { + super(in); + this.limit = limit; + this.mark = -1; + this.read = 0; + this.fatalUnderflow = underflowThrows; + this.alreadycounting = false; + } + + /** + * {@inheritDoc} + * + *

      Debugging toString. + **/ + @Override + public String toString() { + if (null == in) { + return "closed/" + super.toString(); + } else { + if (in instanceof ByteArrayInputStream) { + // ByteArrayInputStream.toString() prints the entire stream! + return in.getClass().getName() + "@" + System.identityHashCode(in) + "/" + super.toString() + ":" + read + "-" + + limit; + } else { + return in.toString() + "/" + super.toString() + ":" + read + "-" + limit; + } + } + } + + /** + * Closes this input stream and releases any system resources + * associated with the stream. + *

      + * This method simply forgets the underlying stream. + * + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public void close() throws IOException { + in = null; + } + + /** + * Returns the number of bytes that can be read from this input + * stream without blocking. + *

      + * This method + * simply performs in.available(n) and + * returns the result. + * + * @return the number of bytes that can be read from the input stream + * without blocking. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public int available() throws IOException { + if (null == in) { + throw new IOException("Stream has been closed."); + } + + return (int) Math.min(super.available(), (limit - read)); + } + + /** + * Marks the current position in this input stream. A subsequent + * call to the reset method repositions this stream at + * the last marked position so that subsequent reads re-read the same bytes. + *

      + * The readlimit argument tells this input stream to + * allow that many bytes to be read before the mark position gets + * invalidated. + *

      + * This method simply performs in.mark(readlimit). + * + * @param readlimit the maximum limit of bytes that can be read before + * the mark position becomes invalid. + * @see java.io.FilterInputStream#in + * @see java.io.FilterInputStream#reset() + */ + @Override + public void mark(int readlimit) { + if (null == in) { + return; + } // don't throw exception to be consistent with other impls. + + super.mark(readlimit); + mark = read; + } + + /** + * Repositions this stream to the position at the time the + * mark method was last called on this input stream. + *

      + * This method simply performs in.reset(). + *

      + * Stream marks are intended to be used in + * situations where you need to read ahead a little to see what's in + * the stream. Often this is most easily done by invoking some + * general parser. If the stream is of the type handled by the + * parse, it just chugs along happily. If the stream is not of + * that type, the parser should toss an exception when it fails. + * If this happens within readlimit bytes, it allows the outer + * code to reset the stream and try another parser. + * + * @exception IOException if the stream has not been marked or if the + * mark has been invalidated. + * @see java.io.FilterInputStream#in + * @see java.io.FilterInputStream#mark(int) + */ + @Override + public void reset() throws IOException { + if (null == in) { + throw new IOException("Stream has been closed."); + } + + if (-1 == mark) { + throw new IOException("reset() without mark(), or I dont know where mark is"); + } + + super.reset(); + + read = mark; + } + + /** + * Skips over and discards n bytes of data from the + * input stream. The skip method may, for a variety of + * reasons, end up skipping over some smaller number of bytes, + * possibly 0. The actual number of bytes skipped is + * returned. + *

      + * This method + * simply performs in.skip(n). + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException if an I/O error occurs. + */ + @Override + public synchronized long skip(long n) throws IOException { + if (null == in) { + throw new IOException("Stream has been closed."); + } + + long skipLen = Math.min(n, (limit - read)); + + boolean wascounting = alreadycounting; + + alreadycounting = true; + long result = super.skip(skipLen); + + alreadycounting = wascounting; + + if ((-1 != result) && !alreadycounting) { + read += result; + } + + return result; + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + *

      + * This method + * simply performs in.read() and returns the result. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public synchronized int read() throws IOException { + if (null == in) { + throw new IOException("Stream has been closed."); + } + + if (read >= limit) { + return -1; + } + + boolean wascounting = alreadycounting; + + alreadycounting = true; + int result = super.read(); + + alreadycounting = wascounting; + + if (!alreadycounting) { + if (-1 != result) { + read++; + } else { + if (fatalUnderflow && (read != limit)) { + IOException failed = new IOException( + "Underflow in read, stream EOFed at " + read + " before limit of " + limit); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failed.getMessage(), failed); + } + throw failed; + } + } + } + + return result; + } + + /** + * Reads up to len bytes of data from this input stream + * into an array of bytes. This method blocks until some input is + * available. + *

      + * This method simply performs in.read(b, off, len) + * and returns the result. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public synchronized int read(byte[] b, int off, int len) throws IOException { + if (null == in) { + throw new IOException("Stream has been closed."); + } + + if (read >= limit) { + return -1; + } + + int readLen = (int) Math.min(len, limit - read); + + boolean wascounting = alreadycounting; + + alreadycounting = true; + int result = super.read(b, off, readLen); + + alreadycounting = wascounting; + + if (!alreadycounting) { + if (-1 != result) { + read += result; + } else { + if (fatalUnderflow && (read != limit)) { + IOException failed = new IOException( + "Underflow while tring to read " + readLen + ", stream EOFed at " + read + " before limit of " + limit); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failed.getMessage(), failed); + } + throw failed; + + } + } + } + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/MarkProhibitedFilterStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/MarkProhibitedFilterStream.java new file mode 100644 index 000000000..ca73a2a0b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/MarkProhibitedFilterStream.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.FilterInputStream; +import java.io.InputStream; + +import java.io.IOException; + + +/** + * Implements a filter which disables the mark() feature of an input stream. + * Useful for when the stream is shared. + **/ +public class MarkProhibitedFilterStream extends FilterInputStream { + + /** + * Creates a new instance of MarkProhibitedFilterStream + * + * @param in the stream which will be limited. + */ + public MarkProhibitedFilterStream(InputStream in) { + super(in); + } + + /** + * {@inheritDoc} + * + *

      This method does nothing. + **/ + @Override + public void mark(int readlimit) {} + + /** + * {@inheritDoc} + * + *

      This implementation always throws IOException since mark is not + * supported. + */ + @Override + public void reset() throws IOException { + throw new IOException("reset() not supported"); + } + + /** + * {@inheritDoc} + * + *

      This method simply returns false. + **/ + @Override + public boolean markSupported() { + return false; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/MessageUtilities.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/MessageUtilities.java new file mode 100644 index 000000000..85a7bb00e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/MessageUtilities.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All right reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; + + +/** + * @deprecated These utilities are unsupported and known to have problems. They + * are not recommended for use and will be removed in a future JXTA release + * THIS CLASS IS SCHEDULED TO BE REMOVED AFTER 2.5. + */ +@Deprecated +public final class MessageUtilities { + + private MessageUtilities() {} + + // Fix-Me: I didn't implement byte, short or float + // Fix-Me: I didn't implement arrays, ie addInt(Message message, String tagName, int values[]), etc + // Fix-Me: I didn't implement add DocumentSerializable yet + + public static void addInt(Message message, String tagName, int value) { + StringMessageElement stringMessageElement = new StringMessageElement(tagName, Integer.toString(value), null); + + message.addMessageElement(stringMessageElement); + } + + public static int getInt(Message message, String tagName, int defaultValue) { + StringMessageElement stringMessageElement = (StringMessageElement) message.getMessageElement(tagName); + + if (stringMessageElement != null) { + return Integer.parseInt(stringMessageElement.toString()); + } else { + return defaultValue; + } + } + + public static void addLong(Message message, String tagName, long value) { + StringMessageElement stringMessageElement = new StringMessageElement(tagName, Long.toString(value), null); + + message.addMessageElement(stringMessageElement); + } + + public static long getLong(Message message, String tagName, long defaultValue) { + StringMessageElement stringMessageElement = (StringMessageElement) message.getMessageElement(tagName); + + if (stringMessageElement != null) { + return Long.parseLong(stringMessageElement.toString()); + } else { + return defaultValue; + } + } + + public static void addDouble(Message message, String tagName, double value) { + StringMessageElement stringMessageElement = new StringMessageElement(tagName, Double.toString(value), null); + + message.addMessageElement(stringMessageElement); + } + + public static double getDouble(Message message, String tagName, double defaultValue) { + StringMessageElement stringMessageElement = (StringMessageElement) message.getMessageElement(tagName); + + if (stringMessageElement != null) { + return Double.parseDouble(stringMessageElement.toString()); + } else { + return defaultValue; + } + } + + public static void addBoolean(Message message, String tagName, boolean value) { + StringMessageElement stringMessageElement = new StringMessageElement(tagName, value ? "true" : "false", null); + + message.addMessageElement(stringMessageElement); + } + + public static boolean getBoolean(Message message, String tagName, boolean defaultValue) { + StringMessageElement stringMessageElement = (StringMessageElement) message.getMessageElement(tagName); + + if (stringMessageElement != null) { + return "true".equals(stringMessageElement.toString()); + } else { + return defaultValue; + } + } + + public static void addString(Message message, String tagName, String value) { + StringMessageElement stringMessageElement = new StringMessageElement(tagName, value, null); + + message.addMessageElement(stringMessageElement); + } + + public static String getString(Message message, String tagName, String defaultValue) { + MessageElement stringMessageElement = message.getMessageElement(tagName); + + if (stringMessageElement != null) { + return stringMessageElement.toString(); + } else { + return defaultValue; + } + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeEventListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeEventListener.java new file mode 100644 index 000000000..7bbb041bd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeEventListener.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving JxtaBiDiPipe + * events. + * + * The following example illustrates how to implement a {@link net.jxta.util.PipeEventListener}: + *

      
      + * PipeEventListener myListener = new PipeEventListener() {
      + *
      + *   public void pipeEvent(int event) {
      + *        if (event == JxtaBiDiPipe.PIPE_CLOSED_EVENT) {
      + *          .....
      + *        }
      + *   }
      + * }
      + *
      + * InputPipe pipeIn = pipe.createInputPipe(pipeAdv, myListener);
      + * *
      + * + */ +public interface PipeEventListener extends EventListener { + + /** + * Called for each pipe message event that occurs. + * + * @param event The event being received. + */ + void pipeEvent(int event); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeStateListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeStateListener.java new file mode 100644 index 000000000..28740206b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeStateListener.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2006-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.util.EventListener; + + +/** + * The listener interface for receiving JxtaBiDiPipe + * events. + * + * The following example illustrates how to implement a {@link net.jxta.util.PipeStateListener}: + *
      
      + * PipeStateListener myListener = new PipeStateListener() {
      + *
      + *   public void pipeEvent(int event) {
      + *        if (event == PipeStateListener.PIPE_CLOSED_EVENT) {
      + *          .....
      + *        }
      + *   }
      + * }
      + *
      + * InputPipe pipeIn = pipe.createInputPipe(pipeAdv, myListener);
      + * 
      + * + */ +public interface PipeStateListener extends EventListener { + + /** + * Pipe close Event + */ + public static final int PIPE_CLOSED_EVENT = 1; + + /** + * Pipe opened Event + */ + public static final int PIPE_OPENED_EVENT = 2; + + /** + * Pipe failed Event + */ + public static final int PIPE_FAILED_EVENT = 4; + + /** + * Called for each pipe mode event that occurs. + * + * @param source the source of the event (JxtaBiDiPipe) + * @param event The event being received. + */ + void stateEvent(Object source, int event); + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeUtilities.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeUtilities.java new file mode 100644 index 000000000..f68676653 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/PipeUtilities.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.net.URI; +import net.jxta.pipe.*; +import net.jxta.id.*; +import net.jxta.peergroup.*; +import net.jxta.endpoint.*; +import net.jxta.document.*; +import net.jxta.protocol.*; +import net.jxta.exception.*; + + +public final class PipeUtilities { + + private PipeUtilities() {} + + public static PipeAdvertisement createPipeAdvertisement() { + return (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + } + + public static PipeAdvertisement createPipeAdvertisement(PipeID pipeId, String pipeType) { + PipeAdvertisement pipeAdvertisement = createPipeAdvertisement(); + + pipeAdvertisement.setPipeID(pipeId); + pipeAdvertisement.setType(pipeType); + return pipeAdvertisement; + } + + public static PipeAdvertisement createPipeAdvertisement(String pipeIdText, String pipeType) throws JxtaException { + PipeID pipeId = (PipeID) ID.create(URI.create(pipeIdText)); + PipeAdvertisement pipeAdvertisement = (PipeAdvertisement) AdvertisementFactory.newAdvertisement( + PipeAdvertisement.getAdvertisementType()); + + pipeAdvertisement.setPipeID(pipeId); + pipeAdvertisement.setType(pipeType); + return pipeAdvertisement; + } + + public static PipeAdvertisement createPipeAdvertisement(Element root) { + TextElement pipeAdvElement = (TextElement) DocumentUtilities.getChild(root, PipeAdvertisement.getAdvertisementType()); + + if (pipeAdvElement == null) { + return null; + } + + return (PipeAdvertisement) AdvertisementFactory.newAdvertisement(pipeAdvElement); + } + + public static PipeAdvertisement createNewPipeAdvertisement(PeerGroup peerGroup, String pipeType) { + PipeAdvertisement pipeAdvertisement = createPipeAdvertisement(); + + PipeID pipeID = IDFactory.newPipeID(peerGroup.getPeerGroupID()); + + pipeAdvertisement.setPipeID(pipeID); + pipeAdvertisement.setType(pipeType); + return pipeAdvertisement; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/SimpleSelectable.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/SimpleSelectable.java new file mode 100644 index 000000000..0fafb7980 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/SimpleSelectable.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.util; + +/** + * This the interface that all selectable objects expose. + * + *

      + * Applications programmers should treat this API as temporary, for now. + * + *

      + * A SimpleSelectable object can register SimpleSelector objects so that + * they are notified whenever this object chooses to report a change. + * + *

      + * SimpleSelectors are SimpleSelectable, therefore selectors can be selected. + * + *

      + * The change notification interface used to notify a selector is actually + * specified in SimpleSelectable. As a result, certain implementations may also + * allow to register SimpleSelectables that are not Selectors. Selectors themselves do not allow that. + * + * @see SimpleSelector + * @see AbstractSimpleSelectable + */ +public interface SimpleSelectable { + + /** + * A simple reference object that can be put in a map instead of the one it refers to. + * SimpleSelectable object often need to be put in maps where distinct objects are to be treated + * as such, even if they are identical at a semantical level. However, some + * SimpleSelectable objects may have semantically equals() and hashCode() + * methods rather than the identity ones. + * + *

      + * For that reason, whenever a SimpleSelectable needs to be used as a map or set key, its identity + * reference should be used instead. All SimpleSelectable can return an identity reference. A given + * SimpleSelectable always provides the same IdentityReference object. IdentityReference never overloads + * hashCode() and equals() in a way that could make different objects be equal or that could provide + * different results from invocation to invocation. + */ + public static class IdentityReference { + private final SimpleSelectable object; + + /** + * Creates a new IdentityReference object + * + * @param object the selectable + */ + public IdentityReference(SimpleSelectable object) { + this.object = object; + } + + /** + * @return The object that this one refers to. + */ + public SimpleSelectable getObject() { + return object; + } + } + + /** + * @return A canonical IdentityReference for this object. + * A given SimpleSelectable always provides the same IdentityReference + * object. An IdentityReference must never overload hashCode() or equals() + * in a way that could make different objects be equal or that could provide + * different results from invocation to invocation. + */ + public IdentityReference getIdentityReference(); + + /** + * Registers the given selector with this selectable object. This always + * causes one change event for this object to be reported through the + * selector. As a result, when selecting for a condition, it is not + * necessary to verify whether it has already happened or not; the next call + * to select will be able to detect it. + * + * @param s The SimpleSelector to register + */ + public void register(SimpleSelector s); + + /** + * Unregisters the given selector, so that it is no-longer notified when + * this object changes. + * + * @param s The SimpleSelector to unregister + */ + public void unregister(SimpleSelector s); + + /** + * This method is invoked when the given selectable object has changed. This + * permits to cascade selectable objects, so that one reports a change when + * the other changes, without having to select it. This also permits + * implementation of this interface by delegating its implementation to a + * utility class. + *

      + * An implementation may do what it wants about it. For example, a + * {@link SimpleSelector} will report the change to + * {@link SimpleSelector#select} and invoke + * {@link AbstractSimpleSelectable#notifyChange()} thereby reporting its own + * change to cascaded selectors. Other implementations may only invoke + * {@link AbstractSimpleSelectable#notifyChange()} or may perform more + * complex tasks. + * + * @see AbstractSimpleSelectable + * + * @param changedObject the object that has changed. + */ + public void itemChanged(SimpleSelectable changedObject); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/SimpleSelector.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/SimpleSelector.java new file mode 100644 index 000000000..22baaedf2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/SimpleSelector.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.util.Set; +import java.util.Collection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; + + +/** + * A very primitive version of NIO's select mechanism. Applications should not + * code to this API yet. This is subject to change and for use only by internal + * mechanisms. This is only good at implementing efficient polling. Users must + * wait for a batch of state changes and then figure out which item's state + * changed to something interesting. The batch returned by simpleSelect is a set + * of the items which state did change since the previous time select returned. + * Since a batch is returned as soon as there is at least one item in it, most + * batches are very small, they will contain the first item that was added, plus + * whatever few could sneak in between then and when select wakes-up and grabs + * that batch. + * + *

      A simpleSelector It is not very usable by multiple threads at once, + * unless they all do the same thing. Items are removed from the current batch + * when select returns it. As a result, any state change occurring in-between + * two calls to select() is guaranteed to be reported by the next call. However, + * the new state may be observed before the next select call to select returns + * the corresponding event, which may then be viewed as redundant. So events are + * reported too much rather than too little. + */ +public final class SimpleSelector extends AbstractSimpleSelectable { + + /** + * The small set of items that changed since the last batch was returned + * by select. + **/ + private final Set currentBatch = new HashSet(2); + + /** + * Let it be newed for now. We need to find a place for a factory. + */ + public SimpleSelector() {} + + /** + * {@inheritDoc} + * + *

      This is invoked by registered items when their state changes. Records + * changes for the benefit of {@link #select()}, and performs notifyChange(), + * which will cause notification of cascaded selectors, if any. It is thus + * possible to register selectors with a selector and come to a particular + * one only when it has something to report. + **/ + public final void itemChanged(SimpleSelectable item) { + synchronized (currentBatch) { + currentBatch.add(item.getIdentityReference()); + currentBatch.notifyAll(); + } + notifyChange(); + } + + /** + * This blocks unless and until at least one of the selected items reports + * that it changed. Then the list of such items is returned. More than one + * item may be added to the list by the time it is returned to the invoker. + * + *

      Note: the result cannot be a set, otherwise we would be + * prevented from returning objects that overload hashCode/equals. Every + * item returned will be a distinct object. + * + *

      The invoker should never assume that all items in the result + * have indeed changed in any expected manner or even changed at all. The + * simple action of registering a selector may, and usually does, cause the + * selectable object to report a change. In some cases a selectable object + * may just be unable to prove that it has not changed, and thus report a + * change. It is up to the invoker to inspect the relevant item's state + * every time. + **/ + public Collection select() throws InterruptedException { + + IdentityReference[] refs; + + synchronized (currentBatch) { + int resLen = 0; + + while ((resLen = currentBatch.size()) == 0) { + currentBatch.wait(); + } + + refs = currentBatch.toArray(new IdentityReference[resLen]); + currentBatch.clear(); + } + + // Now we have to retrieve the real objects behind the identity references. + // Costly, but unavoidable. + Collection result = new ArrayList(refs.length); + + for (IdentityReference aRef : Arrays.asList(refs)) { + result.add(aRef.getObject()); + } + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedInputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedInputStream.java new file mode 100644 index 000000000..df384c008 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedInputStream.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.*; +import java.util.Collection; + + +/** + * @deprecated This class is no longer used by the JXTA core and should not + * have been part of the public JXTA API. If you use it, copy it to your own + * source base. It will be deleted after June 2007 release. + */ +@Deprecated +public class WatchedInputStream extends FilterInputStream + implements WatchedStream { + + static final int DEFAULT_CHUNK_SIZE = 4096; + Collection watchList = null; + volatile boolean stalled = false; + volatile boolean idle = true; + boolean closed = false; + final int chunkSize; + InputStream in = null; + + public WatchedInputStream(InputStream in, int chunkSize) { + super(in); + this.in = in; + this.chunkSize = chunkSize; + } + + public WatchedInputStream(InputStream in) { + this(in, DEFAULT_CHUNK_SIZE); + } + + /** + * {@inheritDoc} + *

      + *

      Debugging toString. + */ + @Override + public String toString() { + if (null == in) { + return "closed/" + super.toString(); + } else { + if (in instanceof ByteArrayInputStream) { + // ByteArrayInputStream.toString() prints the entire stream! + return in.getClass().getName() + "@" + System.identityHashCode(in) + "/" + super.toString(); + } else { + return in.toString() + "/" + super.toString(); + } + } + } + + /** + * Sets the watcher list onto which this stream must register + * when it is not idle (so that it can be watched). + * This implementation may or may not remain registered while idle. + * This may affect performance but not functionality. + * It is assumed that that list is monitored by a watcher task that + * invokes the watch method as often as needed to monitor progress + * to its satisfaction. + * + * @param watchList The watchList to register with. Must be a + * Synchronized Collection. + */ + public synchronized void setWatchList(Collection watchList) { + if (this.watchList != null) { + this.watchList.remove(this); + } + this.watchList = watchList; + watchList.add(this); + } + + // This routine may be invoked as often as progress needs to be asserted. + // After at most two watch cycles stalling is detected. + public void watch() { + + if (idle) { + return; + } + + if (!stalled) { + stalled = true; // challenge a write method to clear that flag. + return; + } + + // It's stalled. The last time around it was not idle, so we set the + // stalled flag. Now, it is still not idle and the flag is still there. + // break the stream. + try { + close(); + } catch (IOException ioe) { + ; + } + } + + @Override + public void close() throws IOException { + idle = true; + synchronized (this) { + if (watchList != null) { + watchList.remove(this); + watchList = null; + } + + // Avoid calling close redundantly; some OSes seem to have + // deadlock capabilities when doing that. + + if (closed) { + return; + } + closed = true; + } + super.close(); + } + + @Override + public int read() throws IOException { + stalled = false; + idle = false; + try { + return in.read(); + } finally { + idle = true; + } + } + + // We overload it; not trusting that the base classes method does + // call read(byte[], int, int) in the future. + @Override + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + + // Apply the standard checks here; we will call in.read repeatedly + // which means that errors could be discovered too late per read's + // contract. + + if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + + throw new IndexOutOfBoundsException(); + + } + + stalled = false; + idle = false; + int left = len; + + try { + int i; + + while (left > chunkSize) { + i = in.read(b, off, chunkSize); + stalled = false; + if (i <= 0) { + if (left == len) { + return i; + } + return len - left; + } + off += i; + left -= i; + + // Must check available only after firt read. + // first read must wait for at least one byte. + + if (in.available() == 0) { + return len - left; + } + } + + // Read the left over now. If this is not the first read, + // available has been checked in the loop above. + i = in.read(b, off, left); + if (i <= 0) { + if (left == len) { + return i; + } + return len - left; + } + + return len - left + i; + + } finally { + idle = true; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedOutputStream.java new file mode 100644 index 000000000..c80de5efe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedOutputStream.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; + + +/** + * @deprecated This class is no longer used by the JXTA core and should not + * have been part of the public JXTA API. If you use it, copy it to your own + * source base. It will be deleted after June 2007 release. + */ +@Deprecated +public class WatchedOutputStream extends FilterOutputStream + implements WatchedStream { + + static final int DEFAULT_CHUNK_SIZE = 4096; + transient Collection watchList = null; + transient volatile boolean stalled = false; + transient volatile boolean idle = true; + transient boolean closed = false; + transient final int chunkSize; + transient OutputStream out = null; + + public WatchedOutputStream(OutputStream out, int chunkSize) { + super(out); + this.out = out; + this.chunkSize = chunkSize; + } + + public WatchedOutputStream(OutputStream out) { + this(out, DEFAULT_CHUNK_SIZE); + } + + /** + * {@inheritDoc} + *

      + *

      Debugging toString. + */ + @Override + public String toString() { + + if (null == out) { + return "closed/" + super.toString(); + } else { + if (out instanceof ByteArrayOutputStream) { + // ByteArrayInputStream.toString() prints the entire stream! + return out.getClass().getName() + "@" + System.identityHashCode(out) + "/" + super.toString(); + } else { + return out.toString() + "/" + super.toString(); + } + } + } + + /** + * Sets the watcher list onto which this stream must register + * when it is not idle (so that it can be watched). + * This implementation may or may not remain registered while idle. + * This may affect performance but not functionality. + * It is assumed that that list is monitored by a watcher task that + * invokes the watch method as often as needed to monitor progress + * to its satisfaction. + * + * @param watchList The watchList to register with. Must be a + * Synchronized Collection. + */ + public synchronized void setWatchList(Collection watchList) { + if (this.watchList != null) { + this.watchList.remove(this); + } + this.watchList = watchList; + watchList.add(this); + } + + // This routine may be invoked as often as progress needs to be asserted. + // After at most two watch cycles stalling is detected. + public void watch() { + + if (idle) { + return; + } + + if (!stalled) { + stalled = true; // challenge a write method to clear that flag. + return; + } + + // It's stalled. The last time around it was not idle, so we set the + // stalled flag. Now, it is still not idle and the flag is still there. + // break the stream. + try { + close(); + } catch (IOException ioe) { + ; + } + } + + @Override + public void close() throws IOException { + idle = true; + synchronized (this) { + if (watchList != null) { + watchList.remove(this); + watchList = null; + } + + // Avoid calling close redundantly; some OSes seem to have + // deadlock capabilities when doing that. + + if (closed) { + return; + } + closed = true; + } + super.close(); + } + + @Override + public void flush() throws IOException { + stalled = false; + idle = false; + try { + out.flush(); + } finally { + idle = true; + } + } + + @Override + public void write(int b) throws IOException { + stalled = false; + idle = false; + try { + out.write(b); + } finally { + idle = true; + } + } + + // We overload it; not trusting that the base classe's method does + // call write(byte[], int, int) in the future. + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + // We overload it; not wanting the base classe's method to + // call write(int). + @Override + public void write(byte[] b, int off, int len) throws IOException { + + // Do the standard checks here. Since we will be calling write + // repeatedly, errors could be discovered too late per write's + // contract. + + if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + + throw new IndexOutOfBoundsException(); + + } else if (len == 0) { + return; + } + + stalled = false; + idle = false; + try { + while (len > chunkSize) { + out.write(b, off, chunkSize); + stalled = false; + off += chunkSize; + len -= chunkSize; + } + if (len > 0) { + out.write(b, off, len); + } + } finally { + idle = true; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedStream.java new file mode 100644 index 000000000..7fb109e96 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/WatchedStream.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util; + + +import java.io.*; +import java.util.Collection; + + +/** + * @deprecated This class is no longer used by the JXTA core and should not + * have been part of the public JXTA API. If you use it, copy it to your own + * source base. It will be deleted after June 2007 release. + */ +@Deprecated +public interface WatchedStream { + + /** + * Sets the watcher list onto which this stream must register + * when it is not idle (so that it can be watched). + * This implementation may or may not remain registered while idle. + * This may affect performance but not functionality. + * It is assumed that that list is monitored by a watcher task that + * invokes the watch method as often as needed to monitor progress + * to its satisfaction. + * + * @param watchList The watchList to register with. Must be a + * Synchronized Collection. + */ + public void setWatchList(Collection watchList); + + /** + * This routine may be invoked as often as progress needs to be asserted. + * After at most two watch cycles stalling is detected. + */ + public void watch(); + + /** + * In case we want to close a watchStream regardless of its making + * progress. + * + * @throws java.io.IOException if an io error occurs + */ + public void close() throws IOException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/documentSerializable/DocumentSerializable.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/documentSerializable/DocumentSerializable.java new file mode 100644 index 000000000..f02363ffd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/documentSerializable/DocumentSerializable.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util.documentSerializable; + + +import net.jxta.document.*; + + +/** + **/ +public interface DocumentSerializable { + public void initializeFrom(Element element) throws DocumentSerializationException; + public void serializeTo(Element element) throws DocumentSerializationException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/documentSerializable/DocumentSerializableUtilities.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/documentSerializable/DocumentSerializableUtilities.java new file mode 100644 index 000000000..f32e88dd8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/documentSerializable/DocumentSerializableUtilities.java @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util.documentSerializable; + + +import net.jxta.document.*; +import net.jxta.exception.*; +import net.jxta.util.*; + +import java.util.*; +import java.io.*; + + +/** + **/ +public class DocumentSerializableUtilities { + // Fix-Me: I didn't implement byte, short or float + // Fix-Me: I didn't implement arrays, ie addInt(Element element, String tagName, int values[]), etc + + /** + * Creates a Structured XML Document containing the serialized object + * + * @return The created Document + * @throws DocumentSerializationException if Unable to parse the serialized object. + */ + public static XMLDocument createStructuredXmlDocument(String docType, DocumentSerializable documentSerializable) throws DocumentSerializationException { + XMLDocument xmlDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, docType); + + documentSerializable.serializeTo(xmlDoc); + return xmlDoc; + } + + /** + * Deeply copy an element into another element + * + * @param toElement The target Element + * @param fromElement The source Element + */ + public static void copyChildren(Element toElement, Element fromElement) { + // for now ... a quicky use of another utility + + StructuredDocument intoDoc = toElement.getRoot(); + + StructuredDocumentUtils.copyChildren(intoDoc, toElement, fromElement); + } + + /** + * Add an Element with the specified tagname and value (converted to a String) + * + * @param element Parent Element that the new child element will be added to + * @param tagName TagName to be used for the created Child Element + * @param documentSerializable This value will be serialized into the created child element + \ * @throws DocumentSerializationException if Unable to serialized object. + **/ + public static void addDocumentSerializable(Element element, String tagName, DocumentSerializable documentSerializable) throws DocumentSerializationException { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName); + + element.appendChild(childElement); + documentSerializable.serializeTo(childElement); + } + + /** + * Create an object from its Document Serialized components + * + * @param element The relative root element of a Document Serialized Object + * @param clazz The Class of the resurrected object (must implement DocumentSerializable and have a public no-arg constructor) + * @return An object of type 'clazz' + * @throws DocumentSerializationException if Unable to parse the serialized object. + **/ + public static DocumentSerializable getDocumentSerializable(Element element, Class clazz) throws DocumentSerializationException { + try { + return getDocumentSerializable(element, (DocumentSerializable) clazz.newInstance()); + } catch (DocumentSerializationException e) { + throw e; + } catch (Exception e) { + throw new DocumentSerializationException("Class must have a public no-arg constructor", e); + } + } + + /** + * Initialize an object from its Document Serialized components + * + * @param element The relative root element of a Document Serialized Object + * @param documentSerializable The object that will be populated from the Element + * @return The same parameter passed to it 'documentSerializable' + * @throws DocumentSerializationException if Unable to parse the serialized object. + **/ + public static DocumentSerializable getDocumentSerializable(Element element, DocumentSerializable documentSerializable) throws DocumentSerializationException { + documentSerializable.initializeFrom(element); + return documentSerializable; + } + + /** + * Create an object from its Document Serialized components + * + * @param element The Parent element which has a child Element with the serialized value + * @param tagName The tagname of the element that contains the relative root element of a Document Serialized Object + * @param clazz The Class of the resurrected object (must implement DocumentSerializable and have a public no-arg constructor) + * @return An object of type 'clazz' + * @throws DocumentSerializationException if Unable to parse the serialized object. + **/ + public static DocumentSerializable getDocumentSerializable(Element element, String tagName, Class clazz) throws DocumentSerializationException { + Element childElement = getChildElement(element, tagName); + + if (childElement != null) { + return getDocumentSerializable(childElement, clazz); + } else { + return null; + } + } + + /** + * Create a copy of any Document Serializable object. + * + * This is done by serializing and then deserializing the object (ie not very efficient) + * + * @param documentSerializable The Object to be copied + * @return An copy of the presented object + * @throws DocumentSerializationException if Unable to serialize or parse object. + **/ + public static DocumentSerializable copyDocumentSerializable(DocumentSerializable documentSerializable) throws DocumentSerializationException { + StructuredDocument structuredDocument = createStructuredXmlDocument("temp", documentSerializable); + + return getDocumentSerializable(structuredDocument, documentSerializable.getClass()); + } + + /** + * Create a child element of the specified tagName + * + * This is done by serializing and then deserializing the object (ie not very efficient) + * + * @param element The Parent Element + * @param tagName The Tag Name for the new Element + * @return The created Element + **/ + public static Element createChildElement(Element element, String tagName) { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName); + + element.appendChild(childElement); + return childElement; + } + + /** + * Get a child element of the specified tagName + * + * This is done by serializing and then deserializing the object (ie not very efficient) + * + * @param element The Parent Element + * @param tagName The Tag Name for the new Element + * @return The found Element + **/ + public static Element getChildElement(Element element, String tagName) { + Enumeration e = element.getChildren(tagName); + + if (e.hasMoreElements()) { + return (Element) e.nextElement(); + } else { + return null; + } + } + + /** + * Add an Element with the specified tagname and value (converted to a String) + * + * @param element Parent Element that the new element will be added to + * @param tagName TagName to be used for the created Child Element + * @param value The value that will be stored in the Element as a String + **/ + public static void addInt(Element element, String tagName, int value) { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName, Integer.toString(value)); + + element.appendChild(childElement); + } + + /** + * Get the value of an element converted from a String + * + * @param element Element that contains the value + * @return the value converted from a String + **/ + public static int getInt(Element element) { + return Integer.parseInt((String) element.getValue()); + } + + /** + * Get the value of a Child Element + * + * @param element The Parant Element + * @param tagName The Tag Name of the Child Element that will contain the value + * @param defaultValue The return value if there is no Child Element with that Tag Name + * @return the value converted from a String + **/ + public static int getInt(Element element, String tagName, int defaultValue) { + Element childElement = getChildElement(element, tagName); + + if (childElement != null) { + return getInt(childElement); + } else { + return defaultValue; + } + } + + /** + * Add an Element with the specified tagname and value (converted to a String) + * + * @param element Parent Element that the new element will be added to + * @param tagName TagName to be used for the created Child Element + * @param value The value that will be stored in the Element as a String + **/ + public static void addLong(Element element, String tagName, long value) { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName, Long.toString(value)); + + element.appendChild(childElement); + } + + /** + * Get the value of an element converted from a String + * + * @param element Element that contains the value + * @return the value converted from a String + **/ + public static long getLong(Element element) { + return Long.parseLong((String) element.getValue()); + } + + /** + * Get the value of a Child Element + * + * @param element The Parant Element + * @param tagName The Tag Name of the Child Element that will contain the value + * @param defaultValue The return value if there is no Child Element with that Tag Name + * @return the value converted from a String + **/ + public static long getLong(Element element, String tagName, long defaultValue) { + Element childElement = getChildElement(element, tagName); + + if (childElement != null) { + return getLong(childElement); + } else { + return defaultValue; + } + } + + /** + * Add an Element with the specified tagname and value (converted to a String) + * + * @param element Parent Element that the new element will be added to + * @param tagName TagName to be used for the created Child Element + * @param value The value that will be stored in the Element as a String + **/ + public static void addDouble(Element element, String tagName, double value) { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName, Double.toString(value)); + + element.appendChild(childElement); + } + + /** + * Get the value of an element converted from a String + * + * @param element Element that contains the value + * @return the value converted from a String + **/ + public static double getDouble(Element element) { + return Double.parseDouble((String) element.getValue()); + } + + /** + * Get the value of a Child Element + * + * @param element The Parant Element + * @param tagName The Tag Name of the Child Element that will contain the value + * @param defaultValue The return value if there is no Child Element with that Tag Name + * @return the value converted from a String + **/ + public static double getDouble(Element element, String tagName, double defaultValue) { + Element childElement = getChildElement(element, tagName); + + if (childElement != null) { + return getDouble(childElement); + } else { + return defaultValue; + } + } + + /** + * Add an Element with the specified tagname and value (converted to a String) + * + * @param element Parent Element that the new element will be added to + * @param tagName TagName to be used for the created Child Element + * @param value The value that will be stored in the Element as a String + **/ + public static void addBoolean(Element element, String tagName, boolean value) { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName, value ? "true" : "false"); + + element.appendChild(childElement); + } + + /** + * Get the value of an element converted from a String ("true" or "false") + * + * @param element Element that contains the value + * @return the value converted from a String + **/ + public static boolean getBoolean(Element element) { + return "true".equals((String) element.getValue()); + } + + /** + * Get the value of a Child Element + * + * @param element The Parant Element + * @param tagName The Tag Name of the Child Element that will contain the value + * @param defaultValue The return value if there is no Child Element with that Tag Name + * @return the value converted from a String + **/ + public static boolean getBoolean(Element element, String tagName, boolean defaultValue) { + Element childElement = getChildElement(element, tagName); + + if (childElement != null) { + return getBoolean(childElement); + } else { + return defaultValue; + } + } + + /** + * Add an Element with the specified tagname and value + * + * @param element Parent Element that the new element will be added to + * @param tagName TagName to be used for the created Child Element + * @param value The value that will be stored in the Element + **/ + public static void addString(Element element, String tagName, String value) { + StructuredDocument structuredDocument = element.getRoot(); + Element childElement = structuredDocument.createElement(tagName, value); + + element.appendChild(childElement); + } + + /** + * Get the value of an element as a String + * + * @param element Element that contains the value + * @return the value converted from a String + **/ + public static String getString(Element element) { + return (String) element.getValue(); + } + + /** + * Get the value of a Child Element + * + * @param element The Parant Element + * @param tagName The Tag Name of the Child Element that will contain the value + * @param defaultValue The return value if there is no Child Element with that Tag Name + * @return The value found in the Element + **/ + public static String getString(Element element, String tagName, String defaultValue) { + Element childElement = getChildElement(element, tagName); + + if (childElement != null) { + return getString(childElement); + } else { + return defaultValue; + } + } + + /** + * Convert a DocumentSerializable object to its XML representation as a String + * + * The Root TagName will be 'documentSerializable' by default + * + * @param documentSerializable The Object to be converted to an XML Document + * @return The String representation of an XML Document + * @throws DocumentSerializationException if Unable to serialize object. + **/ + public static String toXmlString(DocumentSerializable documentSerializable) throws DocumentSerializationException { + return toXmlString(documentSerializable, "documentSerializable"); + } + + /** + * Convert a DocumentSerializable object to its XML representation as a String + * + * The Root TagName will be 'documentSerializable' by default + * + * @param documentSerializable The Object to be converted to an XML Document + * @param rootTagName The Root tagName for the XML Document + * @return The String representation of an XML Document + * @throws DocumentSerializationException if Unable to serialize object. + **/ + public static String toXmlString(DocumentSerializable documentSerializable, String rootTagName) throws DocumentSerializationException { + try { + StringWriter bout = new StringWriter(); + XMLDocument document = DocumentSerializableUtilities.createStructuredXmlDocument(rootTagName, documentSerializable); + + document.sendToWriter(bout); + bout.close(); + + return bout.toString(); + } catch (IOException e) { + throw new DocumentSerializationException("Error converting to String", e); + } + } + + /** + * Write a DocumentSerializable object as an XML Document to a Stream + * + * The Root TagName will be 'documentSerializable' by default + * + * @param out The Stream to write the document to + * @param documentSerializable The Object to be converted to an XML Document + * @throws DocumentSerializationException if Unable to serialize object. + * @throws IOException if I/O error while writing + **/ + public static void writeAsXmlString(OutputStream out, DocumentSerializable documentSerializable) throws IOException, DocumentSerializationException { + writeAsXmlString(out, documentSerializable, "documentSerializable"); + } + + /** + * Write a DocumentSerializable object as an XML Document to a Stream + * + * The Root TagName will be 'documentSerializable' by default + * + * @param out The Stream to write the document to + * @param rootTagName The Root tagName for the XML Document + * @param documentSerializable The Object to be converted to an XML Document + * @throws DocumentSerializationException if Unable to serialize object. + * @throws IOException if I/O error while writing + **/ + public static void writeAsXmlString(OutputStream out, DocumentSerializable documentSerializable, String rootTagName) throws IOException, DocumentSerializationException { + StructuredDocument document = DocumentSerializableUtilities.createStructuredXmlDocument(rootTagName, documentSerializable); + + document.sendToStream(out); + } + + /** + * Write a DocumentSerializable object as an XML Document to StdErr + * + * The Root TagName will be 'documentSerializable' by default + * + * @param documentSerializable The DocumentSerializable to be printed. + **/ + public static void printAsXmlString(DocumentSerializable documentSerializable) { + try { + if (documentSerializable == null) { + System.err.println(""); + } else { + writeAsXmlString(System.err, documentSerializable); + } + } catch (Exception e) { + System.err.println(" for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.util.documentSerializable; + + +import net.jxta.exception.JxtaException; + + +/** + **/ +public class DocumentSerializationException extends JxtaException { + public DocumentSerializationException(String message) { + super(message); + } + + public DocumentSerializationException(String message, Exception exception) { + super(message, exception); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/package.html new file mode 100644 index 000000000..c4c1b99d2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/util/package.html @@ -0,0 +1,10 @@ + + + + + + + A collection of utility classes used by the JXTA implementation and/or + useful to users of the JXTA API. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/api/src/sun/net/www/protocol/urn/Handler.java b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/sun/net/www/protocol/urn/Handler.java new file mode 100644 index 000000000..d665d8055 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/api/src/sun/net/www/protocol/urn/Handler.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package sun.net.www.protocol.urn; + + +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import java.io.IOException; + + +/** + * Handler for URN + * + * @deprecated Use the URI interfaces for JXTA IDs instead of the URLs. + */ +@Deprecated +public final class Handler extends URLStreamHandler { + + public static Handler handler = new Handler(); + + /** + * Creates new Handler + **/ + public Handler() {} + + /** + * + **/ + @Override + public URLConnection openConnection(URL connect) throws + IOException { + return null; + } + + /** + * + * Private replacement for toHexString since we need the leading 0 digits. + * Returns a String containing byte value encoded as 2 hex characters. + * + * @param theByte a byte containing the value to be encoded. + * @return String containing byte value encoded as 2 hex characters. + */ + private static String toHexDigits(byte theByte) { + final char[] HEXDIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + StringBuilder result = new StringBuilder(2); + + result.append(HEXDIGITS[(theByte >>> 4) & 15]); + result.append(HEXDIGITS[theByte & 15]); + + return result.toString(); + } + + /** + * + * 2.4 of RFC2141 says we have to encode these chars. + * + **/ + static final String needsEncoding = "%/?#" + "\\\"&<>[]^`{|}~"; + + /** + * + * The byte values of the chars we have to encode. + * + **/ + static final byte[] encodesTo = new byte[] { + 0x25, 0x2F, 0x3F, 0x23, 0x5c, 0x22, 0x26, 0x3C, 0x3E, 0x5B, 0x5D, 0x5E, 0x60, 0x7B, 0x7C, 0x7D, 0x7E + }; + + /** + * Encode a string such that it is in a form acceptable for presentation + * as a URN. First the string is encoded as UTF8 so that any high byte + * unicode chars are ascii representable. Then any special characters in + * the string are escaped using the URN % syntax. + * + * @param source the string to encode + * @return String containing the URN acceptable presentation form. + **/ + public static String encodeURN(String source) { + String asISO8559_1 = null; + + try { + // first we get its bytes using UTF to encode its characters. + byte[] asBytes = source.getBytes("UTF8"); + + // then read it back in as ISO-8859-1. This allows us to see the + // bytes with no translation. This string will have chars in the + // range 0-255 only. + asISO8559_1 = new String(asBytes, "ISO-8859-1"); + } catch (java.io.UnsupportedEncodingException never) { + // these 2 encodings are required by all java implementations + // so this exception will never happen. + ; + } + + StringBuilder result = new StringBuilder(asISO8559_1.length()); + + // now do the % encoding for all chars which need it. + for (int eachChar = 0; eachChar < asISO8559_1.length(); eachChar++) { + char aChar = asISO8559_1.charAt(eachChar); + + // null char is bad + if (0 == aChar) { + throw new IllegalArgumentException("URN string cannot contain null char"); + } + + // in the excluded range + if ((aChar <= 32) || (aChar >= 127)) { + result.append('%'); + result.append(toHexDigits((byte) aChar)); + } else { + int inSpecials = needsEncoding.indexOf(aChar); + + // one of the special chars which must be encoded? + if (-1 != inSpecials) { + result.append('%'); + result.append(toHexDigits(encodesTo[inSpecials])); + } else { + result.append(aChar); + } // needed no encoding + } + } + + return result.toString(); + } + + /** + * Converts a string which was previously conveted to URN format back into + * the unencoded format. + * + * @param source the string to decode + * @return String containing the decoded form of the URN. + **/ + public static String decodeURN(String source) { + StringBuilder result = new StringBuilder(source.length()); + + // remove the % encoding for all chars which needed it. + for (int eachChar = 0; eachChar < source.length(); eachChar++) { + char aChar = source.charAt(eachChar); + + if ('%' != aChar) { + result.append(aChar); + } else { + String twoChars = source.substring(eachChar + 1, eachChar + 3); + + result.append((char) Integer.parseInt(twoChars, 16)); + eachChar += 2; + } + } + String fromUTF8 = null; + + try { + // first we get its bytes using ISO-8859-1 to encode its characters. + // ISO-8859-1 does no mapping. Each byte is the same as the character. + byte[] asBytes = result.toString().getBytes("ISO-8859-1"); + + // then read it back in as UTF8. This gets us any high byte chars back + fromUTF8 = new String(asBytes, "UTF8"); + } catch (java.io.UnsupportedEncodingException never) { + // these 2 encodings are required so this exception will never happen + ; + } + return fromUTF8; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.document.Advertisement b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.document.Advertisement new file mode 100644 index 000000000..1efce7a41 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.document.Advertisement @@ -0,0 +1,23 @@ +# The list of Advertisement Instance Classes included with this distribution. +# Used by AdvertisementFactory +net.jxta.impl.protocol.PeerAdv +net.jxta.impl.protocol.PlatformConfig +net.jxta.impl.protocol.PeerGroupAdv +net.jxta.impl.protocol.PeerGroupConfigAdv +net.jxta.impl.protocol.TCPAdv +net.jxta.impl.protocol.HTTPAdv +net.jxta.impl.protocol.PSEConfigAdv +net.jxta.impl.protocol.RdvConfigAdv +net.jxta.impl.protocol.DiscoveryConfigAdv +net.jxta.impl.protocol.PipeAdv +net.jxta.impl.protocol.RelayConfigAdv +net.jxta.impl.protocol.RdvAdv +net.jxta.impl.protocol.ModuleImplAdv +net.jxta.impl.protocol.ModuleSpecAdv +net.jxta.impl.protocol.ModuleClassAdv +net.jxta.impl.protocol.RouteAdv +net.jxta.impl.protocol.AccessPointAdv +net.jxta.impl.protocol.SignedAdv +net.jxta.impl.protocol.GroupConfig + +org.linphone.p2pproxy.core.P2pUserProfileAdvertisement \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.document.StructuredDocument b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.document.StructuredDocument new file mode 100644 index 000000000..443209e1c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.document.StructuredDocument @@ -0,0 +1,4 @@ +# The list of StructuredDocument Instance Classes included in this distribution. +# Used by StructuredDocumentFactory. +net.jxta.impl.document.PlainTextDocument +net.jxta.impl.document.LiteXMLDocument diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.endpoint.WireFormatMessage b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.endpoint.WireFormatMessage new file mode 100644 index 000000000..d056a1201 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.endpoint.WireFormatMessage @@ -0,0 +1,3 @@ +# The list of MessageWireFormat Instance Classes included in this distribution. +# Used by MessageWireFormatFactory. +net.jxta.impl.endpoint.WireFormatMessageBinary diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.id.ID b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.id.ID new file mode 100644 index 000000000..0b61d9452 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.id.ID @@ -0,0 +1,4 @@ +# List of ID types supported. +net.jxta.impl.id.UUID.IDFormat +net.jxta.impl.id.CBID.IDFormat +net.jxta.impl.id.binaryID.IDFormat diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.platform.Module b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.platform.Module new file mode 100644 index 000000000..1cd8292ed --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/META-INF/services/net.jxta.platform.Module @@ -0,0 +1,31 @@ +# The list of Builtin Module Implementation Classes included with this distribution. +# Used by PeerGroup Implementation. + +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000020106 net.jxta.impl.resolver.ResolverServiceImpl Reference Implementation of the Resolver service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000030106 net.jxta.impl.discovery.DiscoveryServiceImpl Reference Implementation of the Discovery service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000040106 net.jxta.impl.pipe.PipeServiceImpl Reference Implementation of the Pipe Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000050106 net.jxta.impl.membership.none.NoneMembershipService None Membership Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000050206 net.jxta.impl.membership.passwd.PasswdMembershipService Password Membership Service. +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000050306 net.jxta.impl.membership.pse.PSEMembershipService PSE Membership Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000060106 net.jxta.impl.rendezvous.RendezVousServiceImpl Reference Implementation of the Rendezvous Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000070106 net.jxta.impl.peer.PeerInfoServiceImpl Reference Implementation of the Peerinfo Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000080106 net.jxta.impl.endpoint.EndpointServiceImpl Reference Implementation of the Endpoint service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000090106 net.jxta.impl.endpoint.tcp.TcpTransport Reference Implementation of the TCP Message Transport +urn:jxta:uuid-deadbeefdeafbabafeedbabe0000000A0106 net.jxta.impl.endpoint.servlethttp.ServletHttpTransport Reference Implementation of the HTTP Message Transport +urn:jxta:uuid-deadbeefdeafbabafeedbabe0000000B0106 net.jxta.impl.endpoint.router.EndpointRouter Reference Implementation of the Router Message Transport +urn:jxta:uuid-deadbeefdeafbabafeedbabe0000000D0106 net.jxta.impl.endpoint.tls.TlsTransport Reference Implementation of the TLS Message Transport +urn:jxta:uuid-deadbeefdeafbabafeedbabe0000000E0106 net.jxta.impl.proxy.ProxyService Reference Implementation of the JXME Proxy Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe0000000F0106 net.jxta.impl.endpoint.relay.RelayTransport Reference Implementation of the Relay Message Transport +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000100106 net.jxta.impl.access.always.AlwaysAccessService Always Access Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000100206 net.jxta.impl.access.simpleACL.SimpleACLAccessService Simple ACL Access Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000100306 net.jxta.impl.access.pse.PSEAccessService PSE Access Service +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000110106 net.jxta.impl.endpoint.cbjx.CbJxTransport Reference Implementation of the Cryptobased-ID Message Transport +urn:jxta:uuid-0C801F65D38F421C9884D706B337B8110106 net.jxta.impl.endpoint.mcast.McastTransport Reference Implementation of the IP Multicast Message Transport + +# Since the peer groups refer to other modules in their ModuleImplAdvertisements it's necessary to load them last. + +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000010106 net.jxta.impl.peergroup.Platform Standard World PeerGroup Reference Implementation +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000010206 net.jxta.impl.peergroup.ShadowPeerGroup Default Network PeerGroup Reference Implementation +urn:jxta:uuid-deadbeefdeafbabafeedbabe000000010306 net.jxta.impl.peergroup.StdPeerGroup General Purpose Peer Group Implementation + + \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/Version.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/Version.java new file mode 100644 index 000000000..1762978f3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/Version.java @@ -0,0 +1,149 @@ +/* + * + * ==================================================================== + * + * Copyright (c) 2001 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl; + +import java.lang.Package; + +/** + * Provides easy access to Java Package information for the JXSE Implementation. + */ +public final class Version { + + /** + * Returns the package. + * + * @return The specification title. + */ + public static Package getPackage() { + return Version.class.getPackage(); + } + + /** + * Returns the specification title. + * + * @return The specification title. + */ + public static String getSpecTitle() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getSpecificationTitle(); + } + + /** + * Returns the specification vendor. + * + * @return The specification vendor. + */ + public static String getSpecVendor() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getSpecificationVendor(); + } + + /** + * Returns the specification version. + * + * @return The specification version. + */ + public static String getSpecVersion() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getSpecificationVersion(); + } + + /** + * Returns the specification title. + * + * @return The specification title. + */ + public static String getImplTitle() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getImplementationTitle(); + } + + /** + * Returns the specification vendor. + * + * @return The specification vendor. + */ + public static String getImplVendor() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getImplementationVendor(); + } + + /** + * Returns the specification version. + * + * @return The specification version. + */ + public static String getImplVersion() { + Package versionPackage = Version.class.getPackage(); + + return versionPackage.getImplementationVersion(); + } + + /** + * This class is a singleton. + */ + private Version() { + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/AccessList.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/AccessList.java new file mode 100644 index 000000000..2ffec1b64 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/AccessList.java @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.access; + + +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLElement; +import net.jxta.document.XMLDocument; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + + +/** + * Manages Access Permissions. + */ +public class AccessList { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(AccessList.class.getName()); + + private final static String PEER_TAG = "peer"; + private final static String NAME_TAG = "name"; + private final static String DESCRIPTION_TAG = "description"; + private final static String GRANTALL_TAG = "grantAll"; + private final static String ACCESS_TAG = "access"; + private final static String ACCESS_TAG_DENY_VALUE = "deny"; + private final static String ACCESS_TAG_GRANT_VALUE = "grant"; + + protected final Map accessMap = new HashMap(); + + String description = null; + boolean grantAll = false; + + /** + * Default Constructor + */ + public AccessList() {} + + /** + * Initialize access list from an InputStream + * + * @param stream the input stream + * @throws java.io.IOException if an io error occurs + */ + public AccessList(InputStream stream) throws IOException { + init(stream); + } + + /** + * Initialize access list from a URI + *

      + * e.g. file:/export/dist/acl.xml, e.g. http://configserver.net/edge.acl + * + * @param uri the URI to the access control list + * @throws IOException if an i/o error occurs + */ + public AccessList(URI uri) throws IOException { + init(uri); + } + + /** + * Initialize the access list from a URI + * + * @param uri the refresh URI + * @throws IOException if an io error occurs + */ + public void init(URI uri) throws IOException { + InputStream input = getInputStream(uri); + + init(input); + input.close(); + } + + /** + * Initialize access list from a file + * + * @param fromFile file to init from + * @throws IOException if an io error occurs + */ + public void init(File fromFile) throws IOException { + InputStream is = new FileInputStream(fromFile); + + init(is); + is.close(); + } + + /** + * Refresh access list from a file + * + * @param file file to refresh from + * @deprecated use URI variant + */ + @Deprecated + public void refresh(File file) { + if (file.exists()) { + try { + InputStream is = new FileInputStream(file); + + refresh(is); + is.close(); + } catch (IOException io) {// bad input + } + } + } + + /** + * refresh the access list from a stream + * + * @param stream the input stream + * @throws IOException if an io error occurs + */ + public void refresh(InputStream stream) throws IOException { + AccessList tmp = new AccessList(stream); + + refresh(tmp); + } + + /** + * refresh the access list from a URI + * + * @param uri the refresh URI + * @throws IOException if an io error occurs + */ + public void refresh(URI uri) throws IOException { + InputStream input = getInputStream(uri); + AccessList tmp = new AccessList(input); + + refresh(tmp); + input.close(); + } + + private InputStream getInputStream(URI uri) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loading ACL : " + uri.toString()); + } + + URL url = uri.toURL(); + + URLConnection connection = url.openConnection(); + + connection.setDoInput(true); + return connection.getInputStream(); + } + + private void init(InputStream stream) throws IOException { + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, stream); + + initialize(doc); + } + + /** + * @param map The map of addresses and permissions. + */ + public AccessList(Map map) { + this.accessMap.clear(); + this.accessMap.putAll(map); + } + + /** + * Construct from a StructuredDocument + * + * @param root root element + */ + public AccessList(Element root) { + if (!(root instanceof XMLElement)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + if (!getAdvertisementType().equals(doc.getName())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + initialize(doc); + } + + /** + * gets the description of this access control + * + * @return the document description + */ + public String getDescrption() { + return description; + } + + /** + * Determine if all access is granted. + * + * @return If {@code true} then all access requests will be granted. + */ + public boolean getGrantAll() { + return grantAll; + } + + /** + * Allows/denies all access + * + * @param grantAll If {@code true} then all access requests will be granted. + */ + public void setGrantAll(boolean grantAll) { + this.grantAll = grantAll; + } + + /** + * sets the ACL description + * + * @param description The new description + */ + public void setDescrption(String description) { + this.description = description; + } + + /** + * sets the entries list + * + * @param map The new access map + */ + protected void setEntries(Map map) { + accessMap.clear(); + accessMap.putAll(map); + } + + /** + * Refreshes the access list + * + * @param acl The access list to refresh from + */ + private void refresh(AccessList acl) { + grantAll = acl.grantAll; + description = acl.description; + accessMap.clear(); + accessMap.putAll(acl.accessMap); + } + + /** + * Adds an ACL entry + * + * @param entry the entry to add + */ + public void add(Entry entry) { + if (!accessMap.containsKey(entry.id)) { + accessMap.put(entry.id, entry); + } + } + + /** + * Removes an ACL entry + * + * @param entry the entry to remove + */ + public void remove(Entry entry) { + if (accessMap.containsKey(entry.id)) { + accessMap.remove(entry.id); + } + } + + /** + * Determines if an entry has access + * + * @param id the PeerID + * @return ture if access is allowed, always true if grantAll is set + */ + public boolean isAllowed(ID id) { + if (grantAll) { + return true; + } else if (accessMap.containsKey(id)) { + Entry entry = accessMap.get(id); + + return entry.access; + } else { + return false; + } + } + + /** + * gets the entries list + * + * @return List The List containing Entries + */ + public Map getAccessMap() { + return accessMap; + } + + /** + * Returns the Document + * + * @param asMimeType mime type encoding + * @return The document value + */ + public Document getDocument(MimeMediaType asMimeType) { + StructuredDocument adv = StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); + + if (adv instanceof XMLDocument) { + ((XMLDocument) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e; + + if (grantAll) { + e = adv.createElement(GRANTALL_TAG, Boolean.valueOf(grantAll).toString()); + adv.appendChild(e); + } + + if (description != null) { + e = adv.createElement(DESCRIPTION_TAG, description); + adv.appendChild(e); + } + + for (Object o : accessMap.values()) { + Entry entry = (Entry) o; + + if (entry.id == null && entry.name == null) { + // skip bad entries + continue; + } + e = adv.createElement(PEER_TAG, entry.id.toString()); + adv.appendChild(e); + ((Attributable) e).addAttribute(NAME_TAG, entry.name); + if (entry.access) { + ((Attributable) e).addAttribute(ACCESS_TAG, ACCESS_TAG_GRANT_VALUE); + } else { + ((Attributable) e).addAttribute(ACCESS_TAG, ACCESS_TAG_DENY_VALUE); + } + } + return adv; + } + + /** + * Process an individual element from the document. + * + * @param doc the element + */ + protected void initialize(XMLElement doc) { + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (GRANTALL_TAG.equals(elem.getName())) { + grantAll = Boolean.getBoolean(elem.getTextValue()); + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Grant all access = [ " + grantAll + " ]"); + } + + continue; + } + + if (DESCRIPTION_TAG.equals(elem.getName())) { + description = elem.getTextValue(); + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Loading [ " + description + " ] access list :"); + } + + continue; + } + + if (PEER_TAG.equals(elem.getName())) { + String name = "NA"; + Attribute nameAttr = elem.getAttribute(NAME_TAG); + + if (nameAttr != null) { + name = nameAttr.getValue(); + } + String access = ACCESS_TAG_GRANT_VALUE; + Attribute accessAttr = elem.getAttribute(ACCESS_TAG); + + if (accessAttr != null) { + access = accessAttr.getValue(); + } + boolean acl = ACCESS_TAG_GRANT_VALUE.equalsIgnoreCase(access); + + ID pid; + + try { + URI id = new URI(elem.getTextValue().trim()); + + pid = IDFactory.fromURI(id); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("unknown ID format in advertisement: " + elem.getTextValue()); + } + + Entry entry = new Entry(pid, name, acl); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Adding entry to access list :" + entry); + } + + accessMap.put(entry.id, entry); + + continue; + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unrecognized tag : " + elem.getName()); + } + } + } + + /** + * returns the document string representation of this object + * + * @return String representation of the of this message type + */ + @Override + public String toString() { + + try { + XMLDocument doc = (XMLDocument) getDocument(MimeMediaType.XMLUTF8); + + return doc.toString(); + } catch (Throwable e) { + if (e instanceof Error) { + throw (Error) e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new UndeclaredThrowableException(e); + } + } + } + + /** + * All messages have a type (in xml this is !doctype) which + * identifies the message + * + * @return String "jxta:XACL" + */ + public static String getAdvertisementType() { + return "jxta:XACL"; + } + + /** + * Entries class + */ + public final static class Entry { + + /** + * Entry ID entry id + */ + public final ID id; + + /** + * Entry name + */ + public final String name; + + /** + * Entry name + */ + public final boolean access; + + /** + * Creates a Entry with id and name + * + * @param id id + * @param name node name + * @param access access control + */ + + public Entry(ID id, String name, boolean access) { + this.id = id; + this.name = name; + this.access = access; + } + + @Override + public String toString() { + return "[" + name + " access = " + access + " : " + id.toString() + "]"; + } + + @Override + public boolean equals(Object obj) { + return this == obj || (obj != null && id.equals(((Entry) obj).id)); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/always/AlwaysAccessService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/always/AlwaysAccessService.java new file mode 100644 index 000000000..0f7e55fbb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/always/AlwaysAccessService.java @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.access.always; + + +import java.net.URI; +import java.util.Enumeration; + +import java.net.URISyntaxException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.access.AccessService; +import net.jxta.credential.Credential; +import net.jxta.credential.PrivilegedOperation; +import net.jxta.document.Advertisement; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.TextElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.service.Service; + + +/** + * A minimal {@link net.jxta.access.AccessService} implementation. + * + *

      doAccessCheck will return PERMITTED to all + * queries when provided any valid credential and operation. + * + *

      If the subject of the Credential or the operation is equivalent to the + * String "DENY" then the operation will be DISALLOWED. + * + * @see net.jxta.access.AccessService + **/ +public class AlwaysAccessService implements AccessService { + + /** + * log4J Logger + **/ + private final static Logger LOG = Logger.getLogger(AlwaysAccessService.class.getName()); + + /** + * Operation for the Always Access Service. + **/ + private static class AlwaysOperation implements PrivilegedOperation { + + AlwaysAccessService source; + + String op; + + Credential offerer; + + protected AlwaysOperation(AlwaysAccessService source, String op, Credential offerer) { + this.source = source; + this.op = op; + this.offerer = offerer; + } + + protected AlwaysOperation(AlwaysAccessService source, Element root) { + this.source = source; + initialize(root); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerGroupID() { + return source.getPeerGroup().getPeerGroupID(); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerID() { + return null; + } + + /** + * {@inheritDoc} + * + *

      AlwaysOperation are always valid. + **/ + public boolean isExpired() { + return false; + } + + /** + * {@inheritDoc} + * + *

      AlwaysOperation are always valid. + **/ + public boolean isValid() { + return true; + } + + /** + * {@inheritDoc} + **/ + public Object getSubject() { + return op; + } + + /** + * {@inheritDoc} + **/ + public Service getSourceService() { + return source; + } + + /** + * {@inheritDoc} + **/ + public StructuredDocument getDocument(MimeMediaType as) throws Exception { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + ((Attributable) doc).addAttribute("type", "jxta:AlwaysOp"); + } + + Element e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + + doc.appendChild(e); + + e = doc.createElement("Operation", op); + doc.appendChild(e); + + StructuredDocumentUtils.copyElements(doc, doc, offerer.getDocument(as), "Offerer"); + + return doc; + } + + /** + * {@inheritDoc} + **/ + public Credential getOfferer() { + return offerer; + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + **/ + protected boolean handleElement(TextElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + URI gID = new URI(elem.getTextValue().trim()); + ID pgid = IDFactory.fromURI(gID); + + if (!pgid.equals(getPeerGroupID())) { + throw new IllegalArgumentException( + "Operation is from a different group. " + pgid + " != " + getPeerGroupID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a group id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Operation")) { + op = elem.getTextValue(); + return true; + } + + if (elem.getName().equals("Offerer")) { + try { + offerer = source.getPeerGroup().getMembershipService().makeCredential(elem); + } catch (Throwable failed) { + throw new IllegalArgumentException("Offerer credential could not be constructed" + failed); + } + return true; + } + + // element was not handled + return false; + } + + /** + * Initialize from a portion of a structured document. + **/ + protected void initialize(Element root) { + + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + TextElement doc = (TextElement) root; + + String typedoctype = ""; + + if (root instanceof Attributable) { + Attribute itsType = ((Attributable) root).getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + } + + String doctype = doc.getName(); + + if (!doctype.equals("jxta:AlwaysOp") && !doctype.equals("jxta:Cred") || !"jxta:AlwaysOp".equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandleded element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + if (null == op) { + throw new IllegalArgumentException("operation was never initialized."); + } + + if (null == offerer) { + throw new IllegalArgumentException("offerer was never initialized."); + } + } + } + + PeerGroup group; + + ModuleImplAdvertisement implAdvertisement; + + /** + * Default Constructor + **/ + public AlwaysAccessService() {} + + /** + * {@inheritDoc} + **/ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) throws PeerGroupException { + implAdvertisement = (ModuleImplAdvertisement) implAdv; + this.group = group; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Always Access Service : " + assignedID); + + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tModule Spec ID: " + implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description: " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: " + group.getPeerID()); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + **/ + public int startApp(String[] args) { + return 0; + } + + /** + * {@inheritDoc} + **/ + public void stopApp() {} + + /** + * {@inheritDoc} + **/ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + **/ + public AlwaysAccessService getInterface() { + return this; + } + + /** + * {@inheritDoc} + **/ + PeerGroup getPeerGroup() { + return group; + } + + /** + * {@inheritDoc} + **/ + public AccessResult doAccessCheck(PrivilegedOperation op, Credential cred) { + if (null == cred) { + return (null == op) + ? AccessResult.PERMITTED + : ("DENY".equals(op.getSubject()) ? AccessResult.DISALLOWED : AccessResult.PERMITTED); + } + + if (!cred.isValid()) { + return AccessResult.DISALLOWED; + } + + if ("DENY".equals(cred.getSubject())) { + return AccessResult.DISALLOWED; + } + + if (null == op) { + return AccessResult.PERMITTED; + } + + if (!op.isValid()) { + return AccessResult.DISALLOWED; + } + + return "DENY".equals(op.getSubject()) ? AccessResult.DISALLOWED : AccessResult.PERMITTED; + } + + /** + * {@inheritDoc} + **/ + public PrivilegedOperation newPrivilegedOperation(Object subject, Credential offerer) { + if (!(subject instanceof String)) { + throw new IllegalArgumentException(getClass().getName() + " only supports String subjects."); + } + + if (!offerer.isValid()) { + throw new IllegalArgumentException("offerer is not a valid credential"); + } + + return new AlwaysOperation(this, (String) subject, offerer); + } + + /** + * {@inheritDoc} + **/ + public PrivilegedOperation newPrivilegedOperation(Element source) { + return new AlwaysOperation(this, source); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/always/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/always/package.html new file mode 100644 index 000000000..f66f65a2a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/always/package.html @@ -0,0 +1,14 @@ + + + + + + + A JXTA {@link net.jxta.access.AccessService} implementation which + provides minimal Access Service functionality. This implementation allows + all operations involving valid operations and credentials to succeed with + the exception of a single special value used for testing. + + @see net.jxta.access.AccessService + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/pse/PSEAccessService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/pse/PSEAccessService.java new file mode 100644 index 000000000..4140ad2a5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/pse/PSEAccessService.java @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.access.pse; + + +import java.net.URI; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import java.net.URISyntaxException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.access.AccessService; +import net.jxta.credential.Credential; +import net.jxta.credential.PrivilegedOperation; +import net.jxta.document.Advertisement; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.TextElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.JxtaError; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.membership.MembershipService; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.ModuleSpecID; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.service.Service; + +import net.jxta.impl.membership.pse.PSECredential; +import net.jxta.impl.membership.pse.PSEMembershipService; + + +/** + * Implements the {@link net.jxta.access.AccessService} using PKIX validation. + * + * FIXME 20060409 bondolo THIS IS AN EARLY DEVELOPMENT RELEASE FOR INVESTIGATING + * THE API. IT IS *NOT* SECURE! DO NOT SHIP THIS CODE (IN IT'S CURRENT FORM) IN + * A REAL PRODUCT. + * + * @see net.jxta.access.AccessService + * @see net.jxta.impl.membership.pse.PSEMembershipService + */ +public class PSEAccessService implements AccessService { + + /** + * Logger. + */ + private final static Logger LOG = Logger.getLogger(PSEAccessService.class.getName()); + + /** + * Well known access specification identifier: the pse access service + */ + public final static ModuleSpecID PSE_ACCESS_SPEC_ID = (ModuleSpecID) + ID.create(URI.create("urn:jxta:uuid-DeadBeefDeafBabaFeedBabe000000100306")); + + /** + * Operation for the PSE Access Service. + */ + private static class PSEOperation implements PrivilegedOperation { + + final PSEAccessService source; + + PSECredential op; + + protected PSEOperation(PSEAccessService source, PSECredential op) { + this.source = source; + this.op = op; + } + + protected PSEOperation(PSEAccessService source, Element root) { + this.source = source; + initialize(root); + } + + /** + * {@inheritDoc} + */ + public ID getPeerGroupID() { + return source.getPeerGroup().getPeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public ID getPeerID() { + return null; + } + + /** + * {@inheritDoc} + * + *

      AlwaysOperation are always valid. + */ + public boolean isExpired() { + return false; + } + + /** + * {@inheritDoc} + * + *

      AlwaysOperation are always valid. + */ + public boolean isValid() { + return true; + } + + /** + * {@inheritDoc} + */ + public PSECredential getSubject() { + return op; + } + + /** + * {@inheritDoc} + */ + public Service getSourceService() { + return source; + } + + /** + * {@inheritDoc} + * + * FIXME 20060317 bondolo This implementation is not secure. The + * operation should be signed by the offerer. + */ + public StructuredDocument getDocument(MimeMediaType as) throws Exception { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + ((Attributable) doc).addAttribute("type", "jxta:PSEOp"); + } + + Element e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + + doc.appendChild(e); + + e = doc.createElement("Operation", op); + doc.appendChild(e); + + return doc; + } + + /** + * {@inheritDoc} + */ + public PSECredential getOfferer() { + return null; + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + */ + protected boolean handleElement(TextElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + URI gID = new URI(elem.getTextValue().trim()); + ID pgid = IDFactory.fromURI(gID); + + if (!pgid.equals(getPeerGroupID())) { + throw new IllegalArgumentException( + "Operation is from a different group. " + pgid + " != " + getPeerGroupID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Unusable ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a group id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Operation")) { + op = (PSECredential) source.pseMembership.makeCredential(elem); + + return true; + } + + // element was not handled + return false; + } + + /** + * Intialize from a portion of a structured document. + */ + protected void initialize(Element root) { + + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + TextElement doc = (TextElement) root; + + String typedoctype = ""; + + if (root instanceof Attributable) { + Attribute itsType = ((Attributable) root).getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + } + + String doctype = doc.getName(); + + if (!doctype.equals("jxta:PSEOp") && !typedoctype.equals("jxta:PSEOp")) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + if (null == op) { + throw new IllegalArgumentException("operation was never initialized."); + } + } + } + + /** + * The Peer Group we are working for. + */ + PeerGroup group; + + /** + * Implementation advertisement for this instance. + */ + ModuleImplAdvertisement implAdvertisement; + + /** + * The PSE Membership service we are paired with. + */ + PSEMembershipService pseMembership; + + /** + * If {@code true} then a null credential will be allowed for the null op. + */ + final boolean allowNullCredentialForNullOperation = false; + + /** + * The default constructor + */ + public PSEAccessService() {} + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) throws PeerGroupException { + this.group = group; + implAdvertisement = (ModuleImplAdvertisement) implAdv; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring PSE Access Service : " + assignedID); + + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: " + implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID : " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID : " + group.getPeerID()); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] args) { + MembershipService membership = group.getMembershipService(); + + if (null == membership) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + + return Module.START_AGAIN_STALLED; + } + + ModuleImplAdvertisement membershipImplAdv = (ModuleImplAdvertisement) membership.getImplAdvertisement(); + + if ((null != membershipImplAdv) && PSEMembershipService.pseMembershipSpecID.equals(membershipImplAdv.getModuleSpecID()) + && (membership instanceof PSEMembershipService)) { + pseMembership = (PSEMembershipService) membership; + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("PSE Access Service requires a PSE Membership Service."); + } + + return -1; + } + + return 0; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + pseMembership = null; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + */ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public AccessResult doAccessCheck(PrivilegedOperation op, Credential cred) { + if ((null == op) && (null == cred)) { + return allowNullCredentialForNullOperation ? AccessResult.PERMITTED : AccessResult.DISALLOWED; + } + + if ((null == cred) || !(cred instanceof PSECredential)) { + return AccessResult.DISALLOWED; + } + + if (!cred.isValid()) { + return AccessResult.DISALLOWED; + } + + if (null == op) { + return AccessResult.PERMITTED; + } + + if (!(op instanceof PSEOperation)) { + return AccessResult.DISALLOWED; + } + + if (op.getSourceService() != this) { + return AccessResult.DISALLOWED; + } + + if (!op.isValid()) { + return AccessResult.DISALLOWED; + } + + PSECredential offerer = ((PSEOperation) op).getOfferer(); + + X509Certificate opCerts[] = offerer.getCertificateChain(); + + X509Certificate credCerts[] = ((PSECredential) cred).getCertificateChain(); + + // FIXME 20060409 bondolo THIS IS NOT A VALID TEST. It is a shortcut for + // PKIX validation and assumes that all presented certificates chains + // are valid and trustworthy. IT IS NOT SECURE. (It does not ensure that + // certficiates are really signed by their claimed issuer.) + for (X509Certificate credCert : Arrays.asList(credCerts)) { + for (X509Certificate opCert : Arrays.asList(opCerts)) { + if (credCert.getPublicKey().equals(opCert.getPublicKey())) { + return AccessResult.PERMITTED; + } + } + } + + return AccessResult.DISALLOWED; + } + + /** + * {@inheritDoc} + */ + public PrivilegedOperation newPrivilegedOperation(Object subject, Credential offerer) { + if (!(subject instanceof PSECredential)) { + throw new IllegalArgumentException(getClass().getName() + " only supports PSECredential subjects."); + } + + if (subject != offerer) { + throw new IllegalArgumentException("PSE Access Service requires operation and offerer to be the same object."); + } + + if (!offerer.isValid()) { + throw new IllegalArgumentException("offerer is not a valid credential"); + } + + return new PSEOperation((PSEAccessService) getInterface(), (PSECredential) offerer); + } + + /** + * {@inheritDoc} + */ + public PrivilegedOperation newPrivilegedOperation(Element source) { + return new PSEOperation((PSEAccessService) getInterface(), source); + } + + /** + * {@inheritDoc} + */ + PeerGroup getPeerGroup() { + return group; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/pse/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/pse/package.html new file mode 100644 index 000000000..90177d2a5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/pse/package.html @@ -0,0 +1,19 @@ + + + + + + + A JXTA {@link net.jxta.access.AccessService} implementation which + utilizes the PSE Membership service to make access control descisions. + +

      This Access Service is essentially an interface to PKIX Certificate + path validation. The trust anchor for the validation takes the place of the + The privledged operation for access determination. If the provided + credential cannot be validated against the provided trust anchor then the + operation will be disallowed. + + @see net.jxta.access.AccessService + @see net.jxta.impl.membership.pse.PSEMembershipService + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/simpleACL/SimpleACLAccessService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/simpleACL/SimpleACLAccessService.java new file mode 100644 index 000000000..dccb3f1a8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/simpleACL/SimpleACLAccessService.java @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.access.simpleACL; + + +import java.net.URI; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import java.net.URISyntaxException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.access.AccessService; +import net.jxta.credential.Credential; +import net.jxta.credential.PrivilegedOperation; +import net.jxta.document.Advertisement; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.TextElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.JxtaError; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.service.Service; + + +/** + * Implements the {@link net.jxta.access.AccessService} using a simple ACL + * scheme. + * + *

      The ACL table is read from the group advertisement. Each + * perm entry of the Access Service parameters in the group adv is + * assumed to be a permission in the following format: + * + *

      + *    <operation> ":" ( <identity> )* ( "," <identity> )*
      + * 
      + * + *

      A sample ACL table extracted from a PeerGroupAdvertisement: + * + *

      + * ...
      + * <Svc>
      + *   <MCID>urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE0000001005</MCID>
      + *   <Parm>
      + *     <perm>&lt;&lt;DEFAULT>>:nobody,permit</perm>
      + *     <perm>everyone:&lt;&lt;ALL>></perm>
      + *     <perm>permit:nobody,permit,allow</perm>
      + *     <perm>deny:notpermit,notallow</perm>
      + *   </Parm>
      + * </Svc>
      + * ...
      + * 
      + * + *

      If <<ALL>> is provided as an identity then the + * operation is permitted for all valid credentials. + * + *

      if <<DEFAULT>> is provided as an operation then the + * provided identities will be allowed for all operations which are not + * recognized. + * + *

      This implementation makes no effort to ensure that the + * permission table has not been altered. It is not appropriate for use + * in security sensitive deployments unless the integrity of the group + * advertisement is ensured. + * + * @see net.jxta.access.AccessService + **/ +public class SimpleACLAccessService implements AccessService { + + /** + * Logger. + **/ + private final static Logger LOG = Logger.getLogger(SimpleACLAccessService.class.getName()); + + /** + * Well known access specification identifier: the simple ACL access service + **/ + public static final ModuleSpecID simpleACLAccessSpecID = (ModuleSpecID) + ID.create(URI.create("urn:jxta:uuid-DeadBeefDeafBabaFeedBabe000000100206")); + + /** + * Operation for the Always Access Service. + **/ + private static class SimpleACLOperation implements PrivilegedOperation { + + SimpleACLAccessService source; + + String op; + + Credential offerer; + + protected SimpleACLOperation(SimpleACLAccessService source, String op, Credential offerer) { + this.source = source; + this.op = op; + this.offerer = offerer; + } + + protected SimpleACLOperation(SimpleACLAccessService source, Element root) { + this.source = source; + initialize(root); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerGroupID() { + return source.getPeerGroup().getPeerGroupID(); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerID() { + return null; + } + + /** + * {@inheritDoc} + * + *

      AlwaysOperation are always valid. + **/ + public boolean isExpired() { + return false; + } + + /** + * {@inheritDoc} + * + *

      AlwaysOperation are always valid. + **/ + public boolean isValid() { + return true; + } + + /** + * {@inheritDoc} + **/ + public String getSubject() { + return op; + } + + /** + * {@inheritDoc} + **/ + public Service getSourceService() { + return source; + } + + /** + * {@inheritDoc} + **/ + public StructuredDocument getDocument(MimeMediaType as) throws Exception { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + ((Attributable) doc).addAttribute("type", "jxta:SimpleACLOp"); + } + + Element e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + + doc.appendChild(e); + + e = doc.createElement("Operation", op); + doc.appendChild(e); + + StructuredDocumentUtils.copyElements(doc, doc, offerer.getDocument(as), "Offerer"); + + return doc; + } + + /** + * {@inheritDoc} + **/ + public Credential getOfferer() { + return offerer; + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + **/ + protected boolean handleElement(TextElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + URI gID = new URI(elem.getTextValue().trim()); + ID pgid = IDFactory.fromURI(gID); + + if (!pgid.equals(getPeerGroupID())) { + throw new IllegalArgumentException( + "Operation is from a different group. " + pgid + " != " + getPeerGroupID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Unusable ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a group id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Operation")) { + op = elem.getTextValue(); + return true; + } + + if (elem.getName().equals("Offerer")) { + try { + offerer = source.getPeerGroup().getMembershipService().makeCredential(elem); + } catch (Throwable failed) { + throw new IllegalArgumentException("Offerer credential could not be constructed" + failed); + } + return true; + } + + // element was not handled + return false; + } + + /** + * Initialize from a portion of a structured document. + **/ + protected void initialize(Element root) { + + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + TextElement doc = (TextElement) root; + + String typedoctype = ""; + + if (root instanceof Attributable) { + Attribute itsType = ((Attributable) root).getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + } + + String doctype = doc.getName(); + + if (!doctype.equals("jxta:SimpleACLOp") && !typedoctype.equals("jxta:SimpleACLOp")) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + if (null == op) { + throw new IllegalArgumentException("operation was never initialized."); + } + + if (null == offerer) { + throw new IllegalArgumentException("offerer was never initialized."); + } + } + } + + /** + * The peer group we are working for. + **/ + PeerGroup group; + + /** + * Implementation advertisement for this instance. + **/ + ModuleImplAdvertisement implAdvertisement; + + /** + * The ACLs we are supporting. + **/ + private final Map> ACLs = new HashMap>(); + + /** + * The default constructor + **/ + public SimpleACLAccessService() {} + + /** + * {@inheritDoc} + **/ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) throws PeerGroupException { + this.group = group; + implAdvertisement = (ModuleImplAdvertisement) implAdv; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Access Service : " + assignedID); + + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tImpl Description: " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: " + group.getPeerID()); + LOG.config(configInfo.toString()); + } + + PeerGroupAdvertisement configAdv = group.getPeerGroupAdvertisement(); + + TextElement myParam = (TextElement) configAdv.getServiceParam(assignedID); + + if (null == myParam) { + throw new PeerGroupException("parameters for group access controls missing."); + } + + Enumeration allACLS = myParam.getChildren(); + + while (allACLS.hasMoreElements()) { + TextElement anACL = (TextElement) allACLS.nextElement(); + + if (!anACL.getName().equals("perm")) { + continue; + } + + String etcPasswd = anACL.getTextValue(); + + int nextDelim = etcPasswd.indexOf(':'); + + if (-1 == nextDelim) { + continue; + } + + String operation = etcPasswd.substring(0, nextDelim).trim(); + + if ("<>".equals(operation)) { + operation = null; + } + + String identities = etcPasswd.substring(nextDelim + 1); + Set allowed = new HashSet(); + + StringTokenizer eachIdentity = new StringTokenizer(identities, ","); + + while (eachIdentity.hasMoreTokens()) { + String anIdentity = eachIdentity.nextToken().trim(); + + if ("<>".equals(anIdentity)) { + anIdentity = null; + } + + allowed.add(anIdentity); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Adding operation : \'" + ((null == operation) ? "<>" : operation) + "\' with " + allowed.size() + + " identities."); + } + + ACLs.put(operation, allowed); + } + } + + /** + * {@inheritDoc} + **/ + public int startApp(String[] args) { + return 0; + } + + /** + * {@inheritDoc} + **/ + public void stopApp() {} + + /** + * {@inheritDoc} + **/ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + **/ + public SimpleACLAccessService getInterface() { + return this; + } + + /** + * {@inheritDoc} + **/ + public AccessResult doAccessCheck(PrivilegedOperation op, Credential cred) { + if ((null != cred) && !cred.isValid()) { + return AccessResult.DISALLOWED; + } + + if ((null != op) && !op.isValid()) { + return AccessResult.DISALLOWED; + } + + Set allowed = ACLs.get((null != op) ? op.getSubject() : null); + + // do we know this operation? + if (null == allowed) { + // try the default permission + allowed = ACLs.get(null); + + if (null == allowed) { + return AccessResult.DISALLOWED; + } + } + + String credSubject = (null != cred) ? cred.getSubject().toString() : null; + + return (allowed.contains(credSubject) || allowed.contains(null)) ? AccessResult.PERMITTED : AccessResult.DISALLOWED; + } + + /** + * {@inheritDoc} + **/ + public PrivilegedOperation newPrivilegedOperation(Object subject, Credential offerer) { + if (!(subject instanceof String)) { + throw new IllegalArgumentException(getClass().getName() + " only supports String subjects."); + } + + if (!offerer.isValid()) { + throw new IllegalArgumentException("offerer is not a valid credential"); + } + + return new SimpleACLOperation(this, (String) subject, offerer); + } + + /** + * {@inheritDoc} + **/ + public PrivilegedOperation newPrivilegedOperation(Element source) { + return new SimpleACLOperation(this, source); + } + + /** + * {@inheritDoc} + **/ + PeerGroup getPeerGroup() { + return group; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/simpleACL/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/simpleACL/package.html new file mode 100644 index 000000000..724bf3b5e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/access/simpleACL/package.html @@ -0,0 +1,13 @@ + + + + + + + A JXTA {@link net.jxta.access.AccessService} implementation which + provides basic Access Control List (ACL) functionality. Supports a static + ACL loaded from the Peer Group Advertisement. + + @see net.jxta.access.AccessService + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Cm.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Cm.java new file mode 100644 index 000000000..241d8c71b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Cm.java @@ -0,0 +1,1209 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.cm; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.XMLDocument; +import net.jxta.impl.util.JxtaHash; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.core.filer.BTreeCallback; +import net.jxta.impl.xindice.core.filer.BTreeFiler; +import net.jxta.impl.xindice.core.indexer.IndexQuery; +import net.jxta.impl.xindice.core.indexer.NameIndexer; +import net.jxta.logging.Logging; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.protocol.SrdiMessage; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.lang.reflect.UndeclaredThrowableException; +import java.math.BigInteger; +import java.net.URI; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements a limited document caching mechanism + * intended to provide cache for services that have a need for cache + * to search and exchange jxta documents. + *

      + * Only Core Services are intended to use this mechanism. + */ +public final class Cm implements Runnable { + + /** + * Logger. + */ + private final static Logger LOG = Logger.getLogger(Cm.class.getName()); + + /** + * the name we will use for the base directory + */ + final File ROOTDIRBASE; + + /** + * adv types + */ + private static final String[] DIRNAME = {"Peers", "Groups", "Adv", "Raw"}; + + // garbage collect once an hour + public static final long DEFAULT_GC_MAX_INTERVAL = 1 * TimeUtils.ANHOUR; + + /* + * expiration db + */ + private BTreeFiler cacheDB = null; + private Indexer indexer = null; + private final static String databaseFileName = "advertisements"; + + private boolean stop = false; + + private boolean trackDeltas = false; + private final Map> deltaMap = new HashMap>(3); + + /** + * file descriptor for the root of the cm + */ + protected File rootDir; + + private Thread gcThread = null; + private long gcTime = 0; + private final long gcMinInterval = 1000L * 60L; + private long gcMaxInterval = DEFAULT_GC_MAX_INTERVAL; + + + private final int maxInconvenienceLevel = 1000; + private volatile int inconvenienceLevel = 0; + + /** + * Constructor for cm + * + * @param areaName the name of the cm sub-dir to create + *

      + * NOTE: Default garbage interval once an hour + * @param storeRoot store root dir + */ + public Cm(URI storeRoot, String areaName) { + // Default garbage collect once an hour + this(Thread.currentThread().getThreadGroup(), storeRoot, areaName, DEFAULT_GC_MAX_INTERVAL, false); + } + + /** + * Constructor for cm + * + * @param threadGroup the thread group + * @param storeRoot persistence location + * @param gcinterval garbage collect max interval + * @param trackDeltas when true deltas are tracked + * @param areaName storage area name + */ + public Cm(ThreadGroup threadGroup, URI storeRoot, String areaName, long gcinterval, boolean trackDeltas) { + this.trackDeltas = trackDeltas; + this.gcMaxInterval = gcinterval; + this.gcTime = System.currentTimeMillis() + gcMaxInterval; + + ROOTDIRBASE = new File(new File(storeRoot), "cm"); + + try { + rootDir = new File(ROOTDIRBASE, areaName); + rootDir = new File(rootDir.getAbsolutePath()); + if (!rootDir.exists()) { + // We need to create the directory + if (!rootDir.mkdirs()) { + throw new RuntimeException("Cm cannot create directory " + rootDir); + } + } + + /* + * to avoid inconsistent database state, it is highly recommended that + * checkpoint is true by default, which causes fd.sync() on every write + * operation. In transitory caches such as SrdiCache it makes perfect sense + */ + boolean chkPoint = true; + ResourceBundle jxtaRsrcs = ResourceBundle.getBundle("net.jxta.user"); + String checkpointStr = jxtaRsrcs.getString("impl.cm.defferedcheckpoint"); + + if (checkpointStr != null) { + chkPoint = !(checkpointStr.equalsIgnoreCase("true")); + } + + // Storage + cacheDB = new BTreeFiler(); + // no deffered checkpoint + cacheDB.setSync(chkPoint); + cacheDB.setLocation(rootDir.getAbsolutePath(), databaseFileName); + + if (!cacheDB.open()) { + cacheDB.create(); + // now open it + cacheDB.open(); + } + + // Index + indexer = new Indexer(chkPoint); + indexer.setLocation(rootDir.getAbsolutePath(), databaseFileName); + + if (!indexer.open()) { + indexer.create(); + // now open it + indexer.open(); + } + + if (System.getProperty("net.jxta.impl.cm.index.rebuild") != null) { + rebuildIndex(); + } + gcThread = new Thread(threadGroup, this, "CM GC Thread interval : " + gcMinInterval); + gcThread.setDaemon(true); + gcThread.start(); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Instantiated Cm for: " + rootDir.getAbsolutePath()); + } + } catch (DBException de) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unable to Initialize databases", de); + } + throw new UndeclaredThrowableException(de, "Unable to Initialize databases"); + } catch (Throwable e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unable to create Cm", e); + } + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else if (e instanceof Error) { + throw (Error) e; + } else { + throw new UndeclaredThrowableException(e, "Unable to create Cm"); + } + } + } + + @Override + public String toString() { + return "CM for " + rootDir.getAbsolutePath() + "[" + super.toString() + "]"; + } + + private static String getDirName(Advertisement adv) { + if (adv instanceof PeerAdvertisement) { + return DIRNAME[DiscoveryService.PEER]; + } else if (adv instanceof PeerGroupAdvertisement) { + return DIRNAME[DiscoveryService.GROUP]; + } + return DIRNAME[DiscoveryService.ADV]; + } + + /** + * Generates a random file name using doc hashcode + * + * @param doc to hash to generate a unique name + * @return String a random file name + */ + public static String createTmpName(StructuredTextDocument doc) { + try { + StringWriter out = new StringWriter(); + + doc.sendToWriter(out); + out.close(); + + JxtaHash digester = new JxtaHash(out.toString()); + BigInteger hash = digester.getDigestInteger(); + + if (hash.compareTo(BigInteger.ZERO) < 0) { + hash = hash.negate(); + } + return "cm" + hash.toString(16); + } catch (IOException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception creating tmp name: ", ex); + } + throw new IllegalStateException("Could not generate name from document"); + } + } + + /** + * Gets the list of all the files into the given folder + * + * @param dn contains the name of the folder + * @param threshold the max number of results + * @param expirations List to contain expirations + * @return List Strings containing the name of the + * files + */ + public List getRecords(String dn, int threshold, List expirations) { + return getRecords(dn, threshold, expirations, false); + } + + public synchronized List getRecords(String dn, int threshold, List expirations, boolean purge) { + List res = new ArrayList(); + + if (dn == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("null directory name"); + } + return res; + } else { + IndexQuery iq = new IndexQuery(IndexQuery.SW, new Value(dn)); + try { + cacheDB.query(iq, new SearchCallback(cacheDB, indexer, res, expirations, threshold, purge)); + } catch (DBException dbe) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Exception during getRecords(): ", dbe); + } + } catch (IOException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Exception during getRecords(): ", ie); + } + } + return res; + } + } + + public void garbageCollect() { + // calling getRecords is good enough since it removes + // expired entries + Map map = indexer.getIndexers(); + Iterator it = map.keySet().iterator(); + long t0; + + while (it != null && it.hasNext()) { + t0 = System.currentTimeMillis(); + String indexName = (String) it.next(); + getRecords(indexName, Integer.MAX_VALUE, null, true); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Cm garbageCollect :" + indexName + " in :" + (System.currentTimeMillis() - t0)); + } + } + } + + /** + * Returns the relative time in milliseconds at which the file + * will expire. + * + * @param dn contains the name of the folder + * @param fn contains the name of the file + * @return the absolute time in milliseconds at which this + * document will expire. -1 is returned if the file is not + * recognized or already expired. + */ + public synchronized long getLifetime(String dn, String fn) { + try { + Key key = new Key(dn + "/" + fn); + Record record = cacheDB.readRecord(key); + + if (record == null) { + return -1; + } + Long life = (Long) record.getMetaData(Record.LIFETIME); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Lifetime for :" + fn + " " + life.toString()); + } + if (life < System.currentTimeMillis()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing expired record :" + fn); + } + try { + remove(dn, fn); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to remove record", e); + } + } + } + return TimeUtils.toRelativeTimeMillis(life); + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to remove " + dn + "/" + fn, de); + } + return -1; + } + } + + /** + * Returns the maximum duration in milliseconds for which this + * document should cached by those other than the publisher. This + * value is either the cache lifetime or the remaining lifetime + * of the document, whichever is less. + * + * @param dn contains the name of the folder + * @param fn contains the name of the file + * @return number of milliseconds until the file expires or -1 if the + * file is not recognized or already expired. + */ + public synchronized long getExpirationtime(String dn, String fn) { + try { + Key key = new Key(dn + "/" + fn); + Record record = cacheDB.readRecord(key); + long expiration = calcExpiration(record); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Expiration for :" + fn + " " + expiration); + } + if (expiration < 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing expired record :" + fn); + } + try { + remove(dn, fn); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to remove record", e); + } + } + } + return expiration; + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to get " + dn + "/" + fn, de); + } + return -1; + } + } + + /** + * Figures out expiration + * + * @param record record + * @return expiration in ms + */ + private static long calcExpiration(Record record) { + if (record == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Record is null returning expiration of -1"); + } + return -1; + } + Long exp = (Long) record.getMetaData(Record.EXPIRATION); + Long life = (Long) record.getMetaData(Record.LIFETIME); + long expiresin = life - System.currentTimeMillis(); + + if (expiresin <= 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + MessageFormat.format("Record expired lifetime : {0} expiration: {1} expires in: {2}", life, exp + , + expiresin)); + LOG.fine(MessageFormat.format("Record expires on :{0}", new Date(life))); + } + return -1; + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Record lifetime: {0} expiration: {1} expires in: {2}", life, exp, expiresin)); + LOG.fine(MessageFormat.format("Record expires on :{0}", new Date(life))); + } + return Math.min(expiresin, exp.longValue()); + } + } + + /** + * Returns the inputStream of a specified file, in a specified dir + * + * @param dn directory name + * @param fn file name + * @return The inputStream value + * @throws IOException if an I/O error occurs + */ + public InputStream getInputStream(String dn, String fn) throws IOException { + Key key = new Key(dn + "/" + fn); + try { + Record record = cacheDB.readRecord(key); + if (record == null) { + return null; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Restored record for " + key); + } + Value val = record.getValue(); + + if (val != null) { + return val.getInputStream(); + } else { + return null; + } + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to restore record for " + key, de); + } + IOException failure = new IOException("Failed to restore record for " + key); + failure.initCause(de); + throw failure; + } + } + + /** + * Remove a file + * + * @param dn directory name + * @param fn file name + * @throws IOException if an I/O error occurs + */ + public synchronized void remove(String dn, String fn) throws IOException { + + try { + if (fn == null) { + return; + } + Key key = new Key(dn + "/" + fn); + Record record = cacheDB.readRecord(key); + long removePos = cacheDB.findValue(key); + + cacheDB.deleteRecord(key); + if (record != null) { + try { + if (calcExpiration(record) > 0) { + InputStream is = record.getValue().getInputStream(); + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, is); + Advertisement adv = AdvertisementFactory.newAdvertisement(asDoc); + Map indexables = getIndexfields(adv.getIndexFields(), asDoc); + + indexer.removeFromIndex(addKey(dn, indexables), removePos); + // add it to deltas to expire it in srdi + addDelta(dn, indexables, 0); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removed " + record); + } + } + } catch (Exception e) { + // bad bits we are done + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to remove " + dn + "/" + fn, e); + } + } + } + } catch (DBException de) { + // entry does not exist + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("failed to remove " + dn + "/" + fn); + } + } + } + + /** + * Restore a saved StructuredDocument. + * + * @param dn directory name + * @param fn file name + * @return StructuredDocument containing the file + * @throws IOException if an I/O error occurs + * was not possible. + */ + public StructuredDocument restore(String dn, String fn) throws IOException { + InputStream is = getInputStream(dn, fn); + return StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, is); + } + + /** + * Restore an advetisement into a byte array. + * + * @param dn directory name + * @param fn file name + * @return byte [] containing the file + * @throws IOException if an I/O error occurs + */ + public synchronized byte[] restoreBytes(String dn, String fn) throws IOException { + + try { + Key key = new Key(dn + "/" + fn); + Record record = cacheDB.readRecord(key); + + if (record == null) { + return null; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("restored " + record); + } + Value val = record.getValue(); + + if (val != null) { + return val.getData(); + } else { + return null; + } + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to restore " + dn + "/" + fn, de); + } + IOException failure = new IOException("failed to restore " + dn + "/" + fn); + failure.initCause(de); + throw failure; + } + } + + /** + * Stores a StructuredDocument in specified dir, and file name + * + * @param dn directory name + * @param fn file name + * @param adv Advertisement to store + * @throws IOException if an I/O error occurs + */ + public void save(String dn, String fn, Advertisement adv) throws IOException { + save(dn, fn, adv, DiscoveryService.INFINITE_LIFETIME, DiscoveryService.NO_EXPIRATION); + } + + /** + * Stores a StructuredDocument in specified dir, and file name, and + * associated doc timeouts + * + * @param dn directory name + * @param fn file name + * @param adv Advertisement to save + * @param lifetime Document (local) lifetime in relative ms + * @param expiration Document (global) expiration time in relative ms + * @throws IOException Thrown if there is a problem saving the document. + */ + public synchronized void save(String dn, String fn, Advertisement adv, long lifetime, long expiration) throws IOException { + + try { + if (expiration < 0 || lifetime <= 0) { + throw new IllegalArgumentException("Bad expiration or lifetime."); + } + XMLDocument doc; + + try { + doc = (XMLDocument) adv.getDocument(MimeMediaType.XMLUTF8); + } catch (RuntimeException e) { + IOException failure = new IOException("Advertisement couldn't be saved"); + failure.initCause(e); + throw failure; + } + + Key key = new Key(dn + "/" + fn); + // save the new version + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + doc.sendToStream(baos); + baos.close(); + Value value = new Value(baos.toByteArray()); + Long oldLife = null; + Record record = cacheDB.readRecord(key); + + if (record != null) { + // grab the old lifetime + oldLife = (Long) record.getMetaData(Record.LIFETIME); + } + + long absoluteLifetime = TimeUtils.toAbsoluteTimeMillis(lifetime); + + if (oldLife != null) { + if (absoluteLifetime < oldLife) { + // make sure we don't override the original value + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Overriding attempt to decrease adv lifetime from : {0} to :{1}", + new Date(oldLife), new Date(absoluteLifetime))); + } + absoluteLifetime = oldLife; + } + } + // make sure expiration does not exceed lifetime + if (expiration > lifetime) { + expiration = lifetime; + } + long pos = cacheDB.writeRecord(key, value, absoluteLifetime, expiration); + Map indexables = getIndexfields(adv.getIndexFields(), doc); + Map keyedIdx = addKey(dn, indexables); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Indexing " + keyedIdx + " at " + pos); + } + indexer.addToIndex(keyedIdx, pos); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + // too noisy + // LOG.debug("Wrote " + key + " = " + value); + LOG.fine("Stored " + indexables + " at " + pos); + } + + if (expiration > 0) { + // Update for SRDI with our caches lifetime only if we are prepared to share the advertisement with others. + addDelta(dn, indexables, TimeUtils.toRelativeTimeMillis(absoluteLifetime)); + } + + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, MessageFormat.format("Failed to write {0}/{1} {2} {3}", dn, fn, lifetime, expiration), de); + } + IOException failure = new IOException("Failed to write " + dn + "/" + fn + " " + lifetime + " " + expiration); + failure.initCause(de); + throw failure; + } + } + + /** + * Store some bytes in specified dir, and file name, and + * associated doc timeouts + * + * @param dn directory name + * @param fn file name + * @param data byte array to save + * @param lifetime Document (local) lifetime in relative ms + * @param expiration Document (global) expiration time in relative ms + * @throws IOException Thrown if there is a problem saving the document. + */ + public synchronized void save(String dn, String fn, byte[] data, long lifetime, long expiration) throws IOException { + + try { + if (expiration < 0 || lifetime <= 0) { + throw new IllegalArgumentException("Bad expiration or lifetime."); + } + + Key key = new Key(dn + "/" + fn); + Value value = new Value(data); + Long oldLife = null; + Record record = cacheDB.readRecord(key); + + if (record != null) { + // grab the old lifetime + oldLife = (Long) record.getMetaData(Record.LIFETIME); + } + + // save the new version + + long absoluteLifetime = TimeUtils.toAbsoluteTimeMillis(lifetime); + + if (oldLife != null) { + if (absoluteLifetime < oldLife) { + // make sure we don't override the original value + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Overriding attempt to decrease adv lifetime from : {0} to :{1}", + new Date(oldLife), new Date(absoluteLifetime))); + } + absoluteLifetime = oldLife; + } + } + + // make sure expiration does not exceed lifetime + if (expiration > lifetime) { + expiration = lifetime; + } + + cacheDB.writeRecord(key, value, absoluteLifetime, expiration); + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to write " + dn + "/" + fn + " " + lifetime + " " + expiration, de); + } + + IOException failure = new IOException("Failed to write " + dn + "/" + fn + " " + lifetime + " " + expiration); + failure.initCause(de); + throw failure; + } + } + + private static Map getIndexfields(String[] fields, StructuredDocument doc) { + Map map = new HashMap(); + + if (doc == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Null document"); + } + return map; + } + if (fields == null) { + return map; + } + for (String field : fields) { + Enumeration en = doc.getChildren(field); + while (en.hasMoreElements()) { + String val = (String) ((Element) en.nextElement()).getValue(); + if (val != null) { + map.put(field, val); + } + } + } + return map; + } + + /* adds a primary index 'dn' to indexables */ + private static Map addKey(String dn, Map map) { + if (map == null) { + return null; + } + + Map tmp = new HashMap(); + if (map.size() > 0) { + Iterator it = map.keySet().iterator(); + + while (it != null && it.hasNext()) { + String name = it.next(); + + tmp.put(dn + name, map.get(name)); + } + } + return tmp; + } + + private static final class EntriesCallback implements BTreeCallback { + + private BTreeFiler cacheDB = null; + private int threshold; + private List results; + private String key; + + EntriesCallback(BTreeFiler cacheDB, List results, String key, int threshold) { + this.cacheDB = cacheDB; + this.results = results; + this.key = key; + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public boolean indexInfo(Value val, long pos) { + if (results.size() >= threshold) { + return false; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found " + val.toString() + " at " + pos); + } + + Record record; + try { + record = cacheDB.readRecord(pos); + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ex); + } + return false; + } + if (record == null) { + return true; + } + long exp = calcExpiration(record); + + if (exp <= 0) { + // skip expired and private entries + return true; + } + Long life = (Long) record.getMetaData(Record.LIFETIME); + SrdiMessage.Entry entry = new SrdiMessage.Entry(key, val.toString(), life - System.currentTimeMillis()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(" key [" + entry.key + "] value [" + entry.value + "] exp [" + entry.expiration + "]"); + } + results.add(entry); + return true; + } + } + + + private final class SearchCallback implements BTreeCallback { + + private BTreeFiler cacheDB = null; + private Indexer indexer = null; + private int threshold; + private List results; + private List expirations; + private boolean purge; + + SearchCallback(BTreeFiler cacheDB, Indexer indexer, List results, List expirations, int threshold) { + this(cacheDB, indexer, results, expirations, threshold, false); + } + + SearchCallback(BTreeFiler cacheDB, Indexer indexer, List results, List expirations, int threshold, boolean purge) { + this.cacheDB = cacheDB; + this.indexer = indexer; + this.results = results; + this.threshold = threshold; + this.expirations = expirations; + this.purge = purge; + } + + /** + * {@inheritDoc} + */ + public boolean indexInfo(Value val, long pos) { + if (results.size() >= threshold) { + return false; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found " + val.toString() + " at " + pos); + } + + Record record; + try { + record = cacheDB.readRecord(pos); + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ex); + } + return false; + } + + if (record == null) { + return true; + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINEST)) { + LOG.finest("Search callback record " + record.toString()); + } + long exp = calcExpiration(record); + if (exp < 0) { + if (purge) { + try { + indexer.purge(pos); + cacheDB.deleteRecord(record.getKey()); + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ex); + } + } catch (IOException ie) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ie); + } + } + } else { + ++inconvenienceLevel; + } + return true; + } + + if (expirations != null) { + expirations.add(exp); + } + results.add(record.getValue().getInputStream()); + return true; + } + } + + protected static IndexQuery getIndexQuery(String value) { + + int operator; + + if (value == null) { + return null; + } else if (value.length() == 0 || "*".equals(value)) { + return null; + } else if (value.indexOf("*") < 0) { + operator = IndexQuery.EQ; + } else if (value.charAt(0) == '*' && value.charAt(value.length() - 1) != '*') { + operator = IndexQuery.EW; + value = value.substring(1, value.length()); + } else if (value.charAt(value.length() - 1) == '*' && value.charAt(0) != '*') { + operator = IndexQuery.SW; + value = value.substring(0, value.length() - 1); + } else { + operator = IndexQuery.BWX; + value = value.substring(1, value.length() - 1); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Index query operator :" + operator); + } + return new IndexQuery(operator, new Value(value)); + } + + /** + * Search and recovers documents that contains at least + * a macthing pair of tag/value. + * + * @param dn contains the name of the folder on which to + * perform the search + * @param value contains the value to search on. + * @param attribute attribute to search on + * @param threshold threshold + * @param expirations List to contain expirations + * @return Enumeration containing of all the documents names + */ + public synchronized List search(String dn, String attribute, String value, int threshold, List expirations) { + List res = new ArrayList(); + IndexQuery iq = getIndexQuery(value); + try { + indexer.search(iq, dn + attribute, new SearchCallback(cacheDB, indexer, res, expirations, threshold)); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while searching in index", ex); + } + } + return res; + } + + /** + * returns all entries that are cached + * + * @param dn the relative dir name + * @param clearDeltas if true clears the delta cache + * @return SrdiMessage.Entries + */ + public synchronized List getEntries(String dn, boolean clearDeltas) { + List res = new ArrayList(); + try { + Map map = indexer.getIndexers(); + BTreeFiler listDB = indexer.getListDB(); + Iterator it = map.keySet().iterator(); + + while (it != null && it.hasNext()) { + String indexName = (String) it.next(); + // seperate the index name from attribute + if (indexName.startsWith(dn)) { + String attr = indexName.substring((dn).length()); + NameIndexer idxr = (NameIndexer) map.get(indexName); + idxr.query(null, new Indexer.SearchCallback(listDB, new EntriesCallback(cacheDB, res, attr, Integer.MAX_VALUE))); + } + } + } catch (Exception ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Exception while searching in index", ex); + } + } + + if (clearDeltas) { + clearDeltas(dn); + } + return res; + } + + /** + * returns all entries that are added since this method was last called + * + * @param dn the relative dir name + * @return SrdiMessage.Entries + */ + public synchronized List getDeltas(String dn) { + List result = new ArrayList(); + List deltas = deltaMap.get(dn); + + if (deltas != null) { + result.addAll(deltas); + deltas.clear(); + } + return result; + } + + private synchronized void clearDeltas(String dn) { + + List deltas = deltaMap.get(dn); + + if (deltas == null) { + return; + } + deltas.clear(); + } + + private synchronized void addDelta(String dn, Map indexables, long exp) { + + if (trackDeltas) { + Iterator> eachIndex = indexables.entrySet().iterator(); + + if (eachIndex.hasNext()) { + List deltas = deltaMap.get(dn); + + if (deltas == null) { + deltas = new ArrayList(); + deltaMap.put(dn, deltas); + } + while (eachIndex.hasNext()) { + Map.Entry anEntry = eachIndex.next(); + String attr = anEntry.getKey(); + String value = anEntry.getValue(); + SrdiMessage.Entry entry = new SrdiMessage.Entry(attr, value, exp); + + deltas.add(entry); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Added entry :" + entry + " to deltas"); + } + } + } + } + } + + public synchronized void setTrackDeltas(boolean trackDeltas) { + this.trackDeltas = trackDeltas; + if (!trackDeltas) { + deltaMap.clear(); + } + } + + /** + * stop the cm + */ + public synchronized void stop() { + try { + cacheDB.close(); + indexer.close(); + stop = true; + notify(); + } catch (DBException ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unable to close advertisments.tbl", ex); + } + } + } + + /** + * {@inheritDoc} + */ + public synchronized void run() { + try { + while (!stop) { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("waiting " + gcMinInterval + "ms before garbage collection"); + } + wait(gcMinInterval); + } catch (InterruptedException woken) { + Thread.interrupted(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Thread interrupted", woken); + } + } + + if (stop) { + // if asked to stop, exit + break; + } + + if ((inconvenienceLevel > maxInconvenienceLevel) || (System.currentTimeMillis() > gcTime)) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Garbage collection started"); + } + garbageCollect(); + inconvenienceLevel = 0; + gcTime = System.currentTimeMillis() + gcMaxInterval; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Garbage collection completed"); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + gcThread = null; + } + } + + private synchronized void rebuildIndex() throws DBException, IOException { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Rebuilding indices"); + } + + String pattern = "*"; + IndexQuery any = new IndexQuery(IndexQuery.ANY, pattern); + + cacheDB.query(any, new RebuildIndexCallback(cacheDB, indexer)); + } + + private static final class RebuildIndexCallback implements BTreeCallback { + + private BTreeFiler database = null; + private Indexer index = null; + + RebuildIndexCallback(BTreeFiler database, Indexer index) { + this.database = database; + this.index = index; + } + + /** + * {@inheritDoc} + */ + public boolean indexInfo(Value val, long pos) { + try { + Record record = database.readRecord(pos); + + if (record == null) { + return true; + } + + InputStream is = record.getValue().getInputStream(); + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, is); + Advertisement adv = AdvertisementFactory.newAdvertisement(asDoc); + Map indexables = getIndexfields(adv.getIndexFields(), asDoc); + + String dn = getDirName(adv); + Map keyedIdx = addKey(dn, indexables); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Restoring index " + keyedIdx + " at " + pos); + } + index.addToIndex(keyedIdx, pos); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception rebuilding index at " + pos, ex); + } + return true; + } + return true; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Indexer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Indexer.java new file mode 100644 index 000000000..ef76db6ff --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Indexer.java @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.cm; + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.core.filer.BTreeCallback; +import net.jxta.impl.xindice.core.filer.BTreeException; +import net.jxta.impl.xindice.core.filer.BTreeFiler; +import net.jxta.impl.xindice.core.indexer.IndexQuery; +import net.jxta.impl.xindice.core.indexer.NameIndexer; +import net.jxta.logging.Logging; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +public final class Indexer { + + /** + * The logger + */ + private final static transient Logger LOG = Logger.getLogger(Indexer.class.getName()); + + private final static String listFileName = "offsets"; + + private String dir = null; + private String file = null; + private final Map indices = new HashMap(); + private BTreeFiler listDB = null; + private boolean sync = true; + + /* + * Indexer manages indexes to various advertisement types, + * and maintains a listDB which holds records that hold references + * to records in advertisments.tbl + * + * ------- ------- / ------- + * | index | ---->> | listDB | ------->> - | advDB | + * ------- ------- \ ------- + * + */ + public Indexer() {} + + /** + * Creates an indexer + * + * @param sync passed through to xindice to determine a lazy checkpoint or not + * false == lazy checkpoint + */ + public Indexer(boolean sync) { + this.sync = sync; + } + + public void setLocation(String dir, String file) { + this.dir = dir; + this.file = file; + + // upon restart, load existing indices + + File directory = new File(dir); + File[] indexFiles = directory.listFiles(new FilenameFilter() { + public boolean accept(File parentDir, String fileName) { + return fileName.endsWith(".idx"); + } + }); + + for (File indexFile : indexFiles) { + String indexFileName = indexFile.getName(); + int dash = indexFileName.lastIndexOf("-"); + int dot = indexFileName.lastIndexOf(".idx"); + + if (dot > 0 && dash > 0) { + String name = indexFileName.substring(dash + 1, dot).trim(); + + if (indices.get(name) == null) { + try { + NameIndexer indexer = new NameIndexer(); + + // location should be the same as in + // addToIndex below + indexer.setLocation(dir, file + "-" + name); + indexer.setSync(sync); + if (!indexer.open()) { + indexer.create(); + indexer.open(); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding :" + indexFileName + " under " + name); + } + indices.put(name, indexer); + } catch (DBException ignore) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to create Index " + name, ignore); + } + } + } + } + } + try { + // record pointers + listDB = new BTreeFiler(); + listDB.setSync(sync); + listDB.setLocation(directory.getCanonicalPath(), file + "-" + listFileName); + if (!listDB.open()) { + listDB.create(); + // now open it + listDB.open(); + } + } catch (DBException dbe) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed during listDB Creation", dbe); + } + } catch (IOException ie) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed during listDB Creation", ie); + } + } + } + + public boolean open() throws DBException { + return true; + } + + public boolean create() throws DBException { + return true; + } + + public synchronized boolean close() throws DBException { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing Indexer"); + } + + Iterator> eachIndex = indices.entrySet().iterator(); + while (eachIndex.hasNext()) { + Map.Entry anEntry = eachIndex.next(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Closing Index :" + anEntry.getKey()); + } + + try { + anEntry.getValue().close(); + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure closing index :" + anEntry.getKey(), failed); + } + } + + eachIndex.remove(); + } + + // clear just in case. + indices.clear(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Closing listDB"); + } + + listDB.close(); + return true; + } + + /** + * returns an iteration of index fields (attributes) + */ + public Map getIndexers() { + return Collections.unmodifiableMap(indices); + } + + /** + * returns listDB + */ + public BTreeFiler getListDB() { + return listDB; + } + + private static final class EndsWithCallback implements BTreeCallback { + + private int op = IndexQuery.ANY; + private BTreeCallback callback = null; + private Value pattern = null; + + EndsWithCallback(int op, BTreeCallback callback, Value pattern) { + this.op = op; + this.callback = callback; + this.pattern = pattern; + } + + /** + * {@inheritDoc} + */ + public boolean indexInfo(Value val, long pos) { + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("value :" + val + " pattern :" + pattern); + } + + switch (op) { + case IndexQuery.EW: + if (val.endsWith(pattern)) { + return callback.indexInfo(val, pos); + } + break; + + case IndexQuery.NEW: + if (!val.endsWith(pattern)) { + return callback.indexInfo(val, pos); + } + break; + + case IndexQuery.BWX: + if (val.contains(pattern)) { + return callback.indexInfo(val, pos); + } + break; + + default: + break; + + } + return true; + } + } + + public void search(IndexQuery query, String name, BTreeCallback callback) throws IOException, BTreeException { + + BTreeCallback cb = new SearchCallback(listDB, callback); + + if (query != null) { + int op = query.getOperator(); + if (op == IndexQuery.EW || op == IndexQuery.NEW || op == IndexQuery.BWX) { + query = new IndexQuery(IndexQuery.ANY, query.getValues()); + cb = new EndsWithCallback(op, new SearchCallback(listDB, callback), query.getValue(0)); + } + } + + if (name == null) { + if (indices != null) { + Iterator i = indices.values().iterator(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Searching all indexes"); + } + while (i.hasNext()) { + NameIndexer index = i.next(); + index.query(query, new SearchCallback(listDB, callback)); + } + } + } else { + NameIndexer indexer = indices.get(name); + if (indexer == null) { + return; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Searching Index : " + name); + } + indexer.query(query, cb); + } + } + + public void addToIndex(Map indexables, long pos) throws IOException, DBException { + + if (indexables == null) { + return; + } + // FIXME add indexer name to NameIndexer, to optimize this loop + for (String name : indexables.keySet()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("looking up NameIndexer : " + name); + } + NameIndexer indexer = indices.get(name); + + if (indexer == null) { + indexer = new NameIndexer(); + // location should be the same as in setLocation above + indexer.setLocation(dir, file + "-" + name); + indexer.setSync(sync); + if (!indexer.open()) { + indexer.create(); + indexer.open(); + } + indices.put(name, indexer); + } + + // we need to make sure that the db key is unique from the + // the index key to avoid value collision + Key dbKey = new Key(name + indexables.get(name)); + Key indexKey = new Key(indexables.get(name)); + long listPos = writeRecord(listDB, dbKey, pos); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + StringBuilder message = new StringBuilder().append("Adding a reference at position :").append(listPos).append(" to ").append(name).append(" index, Key: ").append( + indexables.get(name)); + LOG.finer(message.toString()); + } + indexer.add(indexKey, listPos); + } + } + + public void removeFromIndex(Map indexables, long pos) throws DBException { + + Collection names; + + if (indexables == null) { + names = indices.keySet(); + } else { + names = indexables.keySet(); + } + + Long lpos = pos; + + for (String name : names) { + NameIndexer indexer = indices.get(name); + + if (indexer != null) { + // we need to make sure that the db key is unique from the + // the index key to avoid value collision + Key dbKey = null; + + if (indexables != null) { + dbKey = new Key(name + indexables.get(name)); + } + Key indexKey = null; + + if (indexables != null) { + indexKey = new Key(indexables.get(name)); + } + synchronized (listDB) { + Record record = listDB.readRecord(dbKey); + Set offsets = readRecord(record); + + if (!offsets.isEmpty()) { + if (offsets.contains(lpos)) { + offsets.remove(lpos); + Value recordValue = new Value(toByteArray(offsets)); + + listDB.writeRecord(dbKey, recordValue); + } + if (offsets.isEmpty()) { + // only we can proceed to remove the entry from the index + listDB.deleteRecord(dbKey); + indexer.remove(indexKey); + } + } else { + // empty record purge it + listDB.deleteRecord(dbKey); + indexer.remove(indexKey); + } + } + } + } + } + + /** + * purge all index entries pointing to a certain record. + * + * @param list List of Long position(s) at which the record to be purged is + * located in the main database. + * @throws IOException if an io error occurs + * @throws BTreeException if an DB error occurs + */ + public void purge(List list) throws IOException, BTreeException { + IndexQuery iq = new IndexQuery(IndexQuery.ANY, ""); + Collection keys = new ArrayList(indices.keySet()); + + for (String objKey : keys) { + NameIndexer index = indices.get(objKey); + PurgeCallback pc = new PurgeCallback(listDB, index, objKey, list); + + index.query(iq, pc); + } + } + + /** + * purge all index entries pointing to a certain record. + * + * @param pos the position at which the record to be purged is + * located in the main database. + * @throws IOException if an io error occurs + * @throws BTreeException if an BTree error occurs + */ + public void purge(long pos) throws IOException, BTreeException { + purge(Collections.singletonList(pos)); + } + + private static final class PurgeCallback implements BTreeCallback { + + private final NameIndexer indexer; + private final List list; + private final BTreeFiler listDB; + private final String indexKey; + + PurgeCallback(BTreeFiler listDB, NameIndexer indexer, String indexKey, List list) { + this.listDB = listDB; + this.indexer = indexer; + this.indexKey = indexKey; + this.list = list; + } + + /** + * {@inheritDoc} + */ + public boolean indexInfo(Value val, long pos) { + // Read record to determine whether there's a refrence to pos + try { + synchronized (listDB) { + Record record = listDB.readRecord(pos); + Set offsets = readRecord(record); + + boolean changed = offsets.removeAll(list); + if (changed) { + if (!offsets.isEmpty()) { + Value recordValue = new Value(toByteArray(offsets)); + + listDB.writeRecord(pos, recordValue); + } else { + listDB.deleteRecord(new Key(indexKey + val)); + indexer.remove(new Key(val)); + } + } + } + } catch (DBException ignore) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "An exception occured", ignore); + } + } + return true; + } + } + + private static byte[] toByteArray(Set offsets) { + try { + int size = offsets.size(); + ByteArrayOutputStream bos = new ByteArrayOutputStream((size * 8) + 4); + DataOutputStream dos = new DataOutputStream(bos); + + dos.writeInt(size); + for (Long lpos : offsets) { + dos.writeLong(lpos.longValue()); + } + dos.close(); + return bos.toByteArray(); + } catch (IOException ie) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception during array to byte array conversion", ie); + } + } + return null; + } + + public static Set readRecord(Record record) { + Set result = new TreeSet(); + + if (record == null) { + return result; + } + + InputStream is = record.getValue().getInputStream(); + + try { + DataInputStream ois = new DataInputStream(is); + int size = ois.readInt(); + + for (int i = 0; i < size; i++) { + result.add(ois.readLong()); + } + ois.close(); + } catch (IOException ie) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading Entry", ie); + } + } + return result; + } + + private static long writeRecord(BTreeFiler listDB, Key key, long pos) throws DBException, IOException { + + synchronized (listDB) { + Long lpos = pos; + Record record = listDB.readRecord(key); + Set offsets = readRecord(record); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE) && offsets != null) { + LOG.finer("list.contains " + pos + " : " + offsets.contains(lpos)); + } + + if (offsets != null && !offsets.contains(lpos)) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Adding a reference to record at :" + lpos); + LOG.finer("Writing :" + offsets.size() + " references"); + } + offsets.add(lpos); + } + Value recordValue = new Value(toByteArray(offsets)); + + return listDB.writeRecord(key, recordValue); + } + } + + public static final class SearchCallback implements BTreeCallback { + + private BTreeCallback callback = null; + private BTreeFiler listDB = null; + + public SearchCallback(BTreeFiler listDB, BTreeCallback callback) { + this.listDB = listDB; + this.callback = callback; + } + + /** + * {@inheritDoc} + */ + public boolean indexInfo(Value val, long pos) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Found " + val.toString() + " at " + pos); + } + Record record = null; + Set offsets = null; + boolean result = true; + + try { + synchronized (listDB) { + record = listDB.readRecord(pos); + offsets = readRecord(record); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Found " + offsets.size() + " entries"); + } + } + + for (Long lpos : offsets) { + result &= callback.indexInfo(val, lpos); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Callback result : " + result); + } + } + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ex); + } + return false; + } + return result; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Srdi.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Srdi.java new file mode 100644 index 000000000..925ad7bb2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/Srdi.java @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.cm; + +import net.jxta.credential.Credential; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.protocol.ResolverSrdiMsgImpl; +import net.jxta.impl.protocol.SrdiMessageImpl; +import net.jxta.impl.util.JxtaHash; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.protocol.SrdiMessage; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezVousStatus; +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezvousListener; +import net.jxta.resolver.ResolverService; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Srdi is a service which provides SRDI functionalities such as : + *

      + *

        + *
      • pushing of SRDI messages to a another peer/propagate
      • + *
      • replication of an SRDI Message to other peers in a given peerview
      • + *
      • given an expression SRDI provides a independently calculated starting point
      • + *
      • Forwarding a ResolverQuery, and taking care of hopCount, random selection
      • + *
      • registers with the RendezvousService to determine when to share SrdSRDIi Entries
      • + * and whether to push deltas, or full a index + *
      • provides a SrdiInterface giving to provide a generic SRDI message definition
      • + *
      + *

      + * If Srdi is started as a thread it performs periodic SRDI pushes of + * indices and also has the ability to respond to rendezvous events. + *

      + * ResolverSrdiMessages define a ttl, to indicate to the receiving service + * whether to replicate such message or not. + *

      + * In addition A ResolverQuery defines a hopCount to indicate how many + * hops a query has been forwarded. This element could be used to detect/stop a + * query forward loopback hopCount is checked to make ensure a query is not + * forwarded more than twice. + * + * @see JXTA Protocols Specification : Peer Resolver Protocol + */ +public class Srdi implements Runnable, RendezvousListener { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(Srdi.class.getName()); + + private PeerGroup group = null; + private String handlername = null; + private SrdiInterface srdiService = null; + private SrdiIndex srdiIndex; + private long connectPollInterval = 0; + private long pushInterval = 0; + + private volatile boolean stop = false; + private AtomicBoolean republishSignal = new AtomicBoolean(false); + + private ResolverService resolver; + private MembershipService membership; + private final JxtaHash jxtaHash = new JxtaHash(); + private CredentialListener membershipCredListener = null; + private Credential credential = null; + private StructuredDocument credentialDoc = null; + private final String rdvEventLock; + + /** + * Random number generator used for random result selection + */ + private final static Random random = new Random(); + + // This ought be to configurable/based on a function applied to the rpv size + /** + * Replication threshold (minimum number of rdv's in peer view before replication) + */ + public final static int RPV_REPLICATION_THRESHOLD = 3; + + /** + * Listener we use for membership property events. + */ + private class CredentialListener implements PropertyChangeListener { + + /** + * {@inheritDoc} + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("defaultCredential".equals(evt.getPropertyName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New default credential event"); + } + + synchronized (Srdi.this) { + credential = (Credential) evt.getNewValue(); + credentialDoc = null; + if (null != credential) { + try { + credentialDoc = credential.getDocument(MimeMediaType.XMLUTF8); + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not generate credential document", all); + } + } + } + } + } + } + } + + + /** + * Interface for pushing entries. + */ + public interface SrdiInterface { + + /** + * Pushe SRDI entries. + * + * @param all if true then push all entries otherwise just push + * those which have changed since the last push. + */ + void pushEntries(boolean all); + } + + /** + * Starts the Srdi Service. wait for connectPollInterval prior to + * pushing the index if connected to a rdv, otherwise index is + * as soon as the Rendezvous connect occurs + * + * @param group group context to operate in + * @param handlername the SRDI handlername + * @param srdiService the service utilizing this Srdi, for purposes of + * callback push entries on events such as rdv connect/disconnect, etc. + * @param srdiIndex The index instance associated with this service + * @param connectPollInterval initial timeout before the very first push of entries in milliseconds + * @param pushInterval the Interval at which the deltas are pushed in milliseconds + */ + public Srdi(PeerGroup group, String handlername, SrdiInterface srdiService, SrdiIndex srdiIndex, long connectPollInterval, long pushInterval) { + + this.group = group; + this.handlername = handlername; + this.srdiService = srdiService; + this.srdiIndex = srdiIndex; + this.connectPollInterval = connectPollInterval; + this.pushInterval = pushInterval; + this.rdvEventLock = new String(handlername); + membership = group.getMembershipService(); + + resolver = group.getResolverService(); + + group.getRendezVousService().addListener(this); + + synchronized (this) { + membershipCredListener = new CredentialListener(); + membership.addPropertyChangeListener("defaultCredential", membershipCredListener); + + try { + credential = membership.getDefaultCredential(); + + if (null != credential) { + credentialDoc = credential.getDocument(MimeMediaType.XMLUTF8); + } else { + credentialDoc = null; + } + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not get credential", all); + } + } + } + } + + /** + * stop the current running thread + */ + public synchronized void stop() { + + if (stop) { + return; + } + + stop = true; + + RendezVousService rendezvous = group.getRendezVousService(); + + if (null != rendezvous) { + rendezvous.removeListener(this); + } + + membership.removePropertyChangeListener("defaultCredential", membershipCredListener); + membershipCredListener = null; + + // wakeup and die + synchronized (rdvEventLock) { + rdvEventLock.notify(); + } + } + + /** + * Replicates a SRDI message to other rendezvous' + * entries are replicated by breaking out entries out of the message + * and sorted out into rdv distribution bins. after which smaller messages + * are sent to other rdv's + * + * @param srdiMsg srdi message to replicate + */ + + public void replicateEntries(SrdiMessage srdiMsg) { + + List rpv = getGlobalPeerView(); + + if (srdiMsg.getScope() < SrdiMessage.REPLICATE || !group.isRendezvous() || rpv.size() < RPV_REPLICATION_THRESHOLD) { + return; + } + + Iterator allEntries = srdiMsg.getEntries().iterator(); + Map bins = new HashMap(rpv.size()); + + while (allEntries.hasNext()) { + SrdiMessage.Entry entry = (SrdiMessage.Entry) allEntries.next(); + PeerID destPeer = getReplicaPeer(srdiMsg.getPrimaryKey() + entry.key + entry.value); + + if (destPeer == null || destPeer.equals(group.getPeerID())) { + // don't replicate message back to ourselves + continue; + } + SrdiMessageImpl sm = bins.get(destPeer); + + if (sm == null) { + sm = new SrdiMessageImpl(); + sm.setPrimaryKey(srdiMsg.getPrimaryKey()); + sm.setPeerID(srdiMsg.getPeerID()); + bins.put(destPeer, sm); + } + sm.addEntry(entry); + } + + for (PeerID destPeer : bins.keySet()) { + SrdiMessageImpl msg = bins.get(destPeer); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupName() + " / " + handlername + "] Forwarding replica Srdi to " + destPeer); + } + pushSrdi(destPeer, msg); + } + } + + /** + * Push an SRDI message to a peer + * ttl is 1, and therefore services receiving this message could + * choose to replicate this message + * + * @param peer peer to push message to, if peer is null it is + * the message is propagated + * @param srdi SRDI message to send + */ + public void pushSrdi(ID peer, SrdiMessage srdi) { + try { + ResolverSrdiMsg resSrdi = new ResolverSrdiMsgImpl(handlername, credential, srdi.toString()); + + if (null == peer) { + resolver.sendSrdi(null, resSrdi); + } else { + resolver.sendSrdi(peer.toString(), resSrdi); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to send srdi message", e); + } + } + } + + /** + * Forwards a Query to a specific peer + * hopCount is incremented to indicate this query is forwarded + * + * @param peer peerid to forward query to + * @param query The query + */ + public void forwardQuery(PeerID peer, ResolverQueryMsg query) { + + query.incrementHopCount(); + if (query.getHopCount() > 2) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("hopCount exceeded. Not forwarding query " + query.getHopCount()); + } + // query has been forwarded too many times + return; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("[{0} / {1}] Forwarding Query to {2}", + group.getPeerGroupName(), handlername, peer)); + } + resolver.sendQuery(peer.toString(), query); + } + + /** + * Forwards a Query to a list of peers + * hopCount is incremented to indicate this query is forwarded + * + * @param peers The peerids to forward query to + * @param query The query + */ + public void forwardQuery(List peers, ResolverQueryMsg query) { + + query.incrementHopCount(); + if (query.getHopCount() > 2) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("hopCount exceeded not forwarding query {0}", query.getHopCount())); + } + // query has been forwarded too many times + return; + } + + for (PeerID destPeer : peers) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("[{0} / {1}] Forwarding Query to {2}", + group.getPeerGroupName(), handlername, destPeer)); + } + resolver.sendQuery(destPeer.toString(), query); + } + } + + /** + * Forwards a Query to a list of peers + * if the list of peers exceeds threshold, and random threshold is picked + * from peers + * hopCount is incremented to indicate this query is forwarded + * + * @param peers The peerids to forward query to + * @param query The query + * @param threshold number of peers to forward the query to + */ + public void forwardQuery(List peers, ResolverQueryMsg query, int threshold) { + + if (query.getHopCount() > 2) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("[{0} / {1}] hopCount exceeded ({2}) not forwarding query.", + group.getPeerGroupName(), handlername, query.getHopCount())); + } + // query has been forwarded too many times + return; + } + if (peers.size() <= threshold) { + forwardQuery(peers, query); + } else { + // pick some random entries out of the list + List newPeers = randomResult(peers, threshold); + forwardQuery(newPeers, query); + } + } + + /** + * returns a random List(threshold) from a given list + * + * @param result starting set + * @param threshold sub-set desired + * @return sub-list of result + */ + protected List randomResult(List result, int threshold) { + if (threshold < result.size()) { + List res = new ArrayList(threshold); + for (int i = 0; i < threshold; i++) { + int rand = random.nextInt(result.size()); + res.add(result.get(rand)); + result.remove(rand); + } + return res; + } + return result; + } + + /** + * Given an expression return a peer from the list peers in the peerview + * this function is used to to give a replication point, and entry point + * to query on a pipe + * + * @param expression expression to derive the mapping from + * @return The replicaPeer value + */ + public PeerID getReplicaPeer(String expression) { + PeerID pid; + List rpv = getGlobalPeerView(); + + if (rpv.size() >= RPV_REPLICATION_THRESHOLD) { + BigInteger digest; + + synchronized (jxtaHash) { + jxtaHash.update(expression); + digest = jxtaHash.getDigestInteger().abs(); + } + BigInteger sizeOfSpace = java.math.BigInteger.valueOf(rpv.size()); + BigInteger sizeOfHashSpace = BigInteger.ONE.shiftLeft(8 * digest.toByteArray().length); + int pos = (digest.multiply(sizeOfSpace)).divide(sizeOfHashSpace).intValue(); + + pid = rpv.get(pos); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("[{0} / {1}] Found a direct peer {2}", group.getPeerGroupName(), handlername, pid)); + } + return pid; + } else { + return null; + } + } + + /** + * forward srdi message to another peer + * + * @param peerid PeerID to forward query to + * @param srcPid The source originator + * @param primaryKey primary key + * @param secondarykey secondary key + * @param value value of the entry + * @param expiration expiration in ms + */ + public void forwardSrdiMessage(PeerID peerid, PeerID srcPid, String primaryKey, String secondarykey, String value, long expiration) { + + try { + SrdiMessageImpl srdi = new SrdiMessageImpl(srcPid, // ttl of 0, avoids additional replication + 0, primaryKey, secondarykey, value, expiration); + + ResolverSrdiMsgImpl resSrdi = new ResolverSrdiMsgImpl(handlername, credential, srdi.toString()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("[{0} / {1}] Forwarding a SRDI messsage of type {2} to {3}", group.getPeerGroupName(), + handlername, primaryKey, peerid)); + } + resolver.sendSrdi(peerid.toString(), resSrdi); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed forwarding SRDI Message", e); + } + } + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("fallthrough") + public void rendezvousEvent(RendezvousEvent event) { + + int theEventType = event.getType(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("[{0} / {1}] Processing {2}", group.getPeerGroupName(), handlername, event)); + } + + switch (theEventType) { + + case RendezvousEvent.RDVCONNECT: + synchronized (rdvEventLock) { + // wake up the publish thread now. + rdvEventLock.notify(); + } + + /* + * FALLSTHRU + */ + case RendezvousEvent.RDVRECONNECT: + // No need to wake up the publish thread; reconnect should not force indices to be published. + break; + + case RendezvousEvent.CLIENTCONNECT: + case RendezvousEvent.CLIENTRECONNECT: + case RendezvousEvent.BECAMERDV: + case RendezvousEvent.BECAMEEDGE: + // XXX 20031110 bondolo perhaps becoming edge one should cause it to wake up so that run() switch to + // don't do anything. + break; + + case RendezvousEvent.RDVFAILED: + case RendezvousEvent.RDVDISCONNECT: + republishSignal.set(true); + break; + + case RendezvousEvent.CLIENTFAILED: + case RendezvousEvent.CLIENTDISCONNECT: + // we should flush the cache for the peer + synchronized (rdvEventLock) { + if (group.isRendezvous() && (srdiIndex != null)) { + srdiIndex.remove((PeerID) event.getPeerID()); + } + } + break; + + default: + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning( + MessageFormat.format("[{0} / {1}] Unexpected RDV event {2}", group.getPeerGroupName(), handlername, event)); + } + break; + } + } + + /** + * {@inheritDoc} + *

      + * Main processing method for the SRDI Worker thread + * Send all entries, wait for pushInterval, then send deltas + */ + public void run() { + + boolean waitingForRdv; + boolean republish = true; + + try { + while (!stop) { + // upon connection we will have to republish + republish |= republishSignal.compareAndSet(true, false); + waitingForRdv = group.isRendezvous() || !group.getRendezVousService().isConnectedToRendezVous() || + group.getRendezVousService().getRendezVousStatus() == RendezVousStatus.ADHOC; + + if (!waitingForRdv) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupName() + " / " + handlername + "] Pushing " + + (republish ? "all entries" : "deltas")); + } + + srdiService.pushEntries(republish); + republish = false; + } + + synchronized (rdvEventLock) { + try { + rdvEventLock.wait(waitingForRdv ? connectPollInterval : pushInterval); + } catch (InterruptedException e) { + Thread.interrupted(); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + "Uncaught Throwable in " + Thread.currentThread().getName() + "[" + group.getPeerGroupName() + " / " + + handlername + "]",all); + } + } + } + + /** + * get the global peerview as the rendezvous service only returns + * the peerview without the local RDV peer. We need this + * consistent view for the SRDI index if not each RDV will have a + * different peerview, off setting the index even when the peerview + * is stable + * + * @return the sorted list + */ + public Vector getGlobalPeerView() { + + Vector global = new Vector(); + SortedSet set = new TreeSet(); + + try { + // get the local peerview + List rpv = group.getRendezVousService().getLocalWalkView(); + + for (RdvAdvertisement padv : rpv) { + set.add(padv.getPeerID().toString()); + } + + // add myself + set.add(group.getPeerID().toString()); + + // produce a vector of Peer IDs + for (String aSet : set) { + try { + PeerID peerID = (PeerID) IDFactory.fromURI(new URI(aSet)); + global.add(peerID); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("ID was not a peerID"); + } + } + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure generating the global view", ex); + } + } + return global; + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/SrdiIndex.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/SrdiIndex.java new file mode 100644 index 000000000..f4849d112 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/cm/SrdiIndex.java @@ -0,0 +1,987 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.cm; + +import net.jxta.id.IDFactory; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.core.filer.BTreeCallback; +import net.jxta.impl.xindice.core.filer.BTreeFiler; +import net.jxta.impl.xindice.core.indexer.IndexQuery; +import net.jxta.impl.xindice.core.indexer.NameIndexer; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * SrdiIndex + */ +public class SrdiIndex implements Runnable { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(SrdiIndex.class.getName()); + + private long interval = 1000 * 60 * 10; + private volatile boolean stop = false; + private final Indexer srdiIndexer; + private final BTreeFiler cacheDB; + private Thread gcThread = null; + private final Set gcPeerTBL = new HashSet(); + + private final String indexName; + + /** + * Constructor for the SrdiIndex + * + * @param group group + * @param indexName the index name + */ + public SrdiIndex(PeerGroup group, String indexName) { + this.indexName = indexName; + + try { + String pgdir = null; + File storeHome; + + if (group == null) { + pgdir = "srdi-index"; + storeHome = new File(".jxta"); + } else { + pgdir = group.getPeerGroupID().getUniqueValue().toString(); + storeHome = new File(group.getStoreHome()); + } + + File rootDir = new File(new File(storeHome, "cm"), pgdir); + + rootDir = new File(rootDir, "srdi"); + if (!rootDir.exists()) { + // We need to create the directory + if (!rootDir.mkdirs()) { + throw new RuntimeException("Cm cannot create directory " + rootDir); + } + } + // peerid database + // Storage + cacheDB = new BTreeFiler(); + // lazy checkpoint + cacheDB.setSync(false); + cacheDB.setLocation(rootDir.getCanonicalPath(), indexName); + + if (!cacheDB.open()) { + cacheDB.create(); + // now open it + cacheDB.open(); + } + + // index + srdiIndexer = new Indexer(false); + srdiIndexer.setLocation(rootDir.getCanonicalPath(), indexName); + if (!srdiIndexer.open()) { + srdiIndexer.create(); + // now open it + srdiIndexer.open(); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("[" + ((group == null) ? "none" : group.toString()) + "] : Initialized " + indexName); + } + } catch (DBException de) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unable to Initialize databases", de); + } + + throw new UndeclaredThrowableException(de, "Unable to Initialize databases"); + } catch (Throwable e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unable to create Cm", e); + } + + if (e instanceof Error) { + throw (Error) e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new UndeclaredThrowableException(e, "Unable to create Cm"); + } + } + } + + /** + * Construct a SrdiIndex and starts a GC thread which runs every "interval" + * milliseconds + * + * @param interval the interval at which the gc will run in milliseconds + * @param group group context + * @param indexName SrdiIndex name + */ + + public SrdiIndex(PeerGroup group, String indexName, long interval) { + this(group, indexName); + this.interval = interval; + startGC(group, indexName, interval); + } + + /** + * Start the GC thread + * + * @param group the PeerGroup + * @param indexName index name + * @param interval interval in milliseconds + */ + protected void startGC(PeerGroup group, String indexName, long interval) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("[" + ((group == null) ? "none" : group.toString()) + "] : Starting SRDI GC Thread for " + indexName); + } + + gcThread = new Thread(group.getHomeThreadGroup(), this, "SrdiIndex GC :" + indexName + " every " + interval + "ms"); + gcThread.setDaemon(true); + gcThread.start(); + } + + /** + * Returns the name of this srdi index. + * + * @return index name. + */ + public String getIndexName() { + return indexName; + } + + /** + * add an index entry + * + * @param primaryKey primary key + * @param attribute Attribute String to query on + * @param value value of the attribute string + * @param expiration expiration associated with this entry relative time in + * milliseconds + * @param pid peerid reference + */ + public synchronized void add(String primaryKey, String attribute, String value, PeerID pid, long expiration) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + indexName + "] Adding " + primaryKey + "/" + attribute + " = \'" + value + "\' for " + pid); + } + + try { + Key key = new Key(primaryKey + attribute + value); + long expiresin = TimeUtils.toAbsoluteTimeMillis(expiration); + + // update the record if it exists + synchronized (cacheDB) { + // FIXME hamada 10/14/04 it is possible a peer re-appears with + // a different set of indexes since it's been marked for garbage + // collection. will address this issue in a subsequent patch + gcPeerTBL.remove(pid); + + Record record = cacheDB.readRecord(key); + List old; + + if (record != null) { + old = readRecord(record).list; + } else { + old = new ArrayList(); + } + Entry entry = new Entry(pid, expiresin); + + if (!old.contains(entry)) { + old.add(entry); + } else { + // entry exists, replace it (effectively updating expiration) + old.remove(old.indexOf(entry)); + old.add(entry); + } + // no sense in keeping expired entries. + old = removeExpired(old); + long t0 = TimeUtils.timeNow(); + byte[] data = getData(key, old); + + // if (LOG.isLoggable(Level.FINE)) { + // LOG.fine("Serialized result in : " + (TimeUtils.timeNow() - t0) + "ms."); + // } + if (data == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Failed to serialize data"); + } + return; + } + Value recordValue = new Value(data); + long pos = cacheDB.writeRecord(key, recordValue); + Map indexables = getIndexMap(primaryKey + attribute, value); + + srdiIndexer.addToIndex(indexables, pos); + } + } catch (IOException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to add SRDI", de); + } + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to add SRDI", de); + } + } + } + + /** + * retrieves a record + * + * @param pkey primary key + * @param skey secondary key + * @param value value + * @return List of Entry objects + */ + public List getRecord(String pkey, String skey, String value) { + Record record = null; + + try { + Key key = new Key(pkey + skey + value); + + synchronized (cacheDB) { + record = cacheDB.readRecord(key); + } + } catch (DBException de) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to retrieve SrdiIndex record", de); + } + } + // if record is null, readRecord returns an empty list + return readRecord(record).list; + + } + + /** + * inserts a pkey into a map with a value of value + * + * @param primaryKey primary key + * @param value value + * @return The Map + */ + + private Map getIndexMap(String primaryKey, String value) { + if (primaryKey == null) { + return null; + } + if (value == null) { + value = ""; + } + Map map = new HashMap(1); + + map.put(primaryKey, value); + return map; + } + + /** + * remove entries pointing to peer id from cache + * + * @param pid peer id to remove + */ + public synchronized void remove(PeerID pid) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(" Adding " + pid + " to peer GC table"); + } + gcPeerTBL.add(pid); + } + + /** + * Query SrdiIndex + * + * @param attribute Attribute String to query on + * @param value value of the attribute string + * @return an enumeration of canonical paths + * @param primaryKey primary key + * @param threshold max number of results + */ + public synchronized List query(String primaryKey, String attribute, String value, int threshold) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + indexName + "] Querying for " + threshold + " " + primaryKey + "/" + attribute + " = \'" + value + "\'"); + } + + // return nothing + if (primaryKey == null) { + return Collections.emptyList(); + } + + List res; + + // a blind query + if (attribute == null) { + res = query(primaryKey); + } else { + res = new ArrayList(); + + IndexQuery iq = Cm.getIndexQuery(value); + + try { + srdiIndexer.search(iq, primaryKey + attribute, new SearchCallback(cacheDB, res, threshold, gcPeerTBL)); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while searching in index", ex); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( "[" + indexName + "] Returning " + res.size() + " results for " + primaryKey + "/" + attribute + " = \'" + + value + "\'"); + } + + return res; + } + + /** + * Query SrdiIndex + * + * @param primaryKey primary key + * @return A list of Peer IDs. + */ + public synchronized List query(String primaryKey) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + indexName + "] Querying for " + primaryKey); + } + + List res = new ArrayList(); + + try { + Map map = srdiIndexer.getIndexers(); + + for (Map.Entry index : map.entrySet()) { + String indexName = index.getKey(); + // seperate the index name from attribute + if (indexName.startsWith(primaryKey)) { + NameIndexer idxr = index.getValue(); + idxr.query(null, new SearchCallback(cacheDB, res, Integer.MAX_VALUE, gcPeerTBL)); + } + } + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while searching in index", ex); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + indexName + "] Returning " + res.size() + " results for " + primaryKey); + } + + return res; + } + + private static final class SearchCallback implements BTreeCallback { + private final BTreeFiler cacheDB; + private final int threshold; + private final List results; + private final Set excludeTable; + + SearchCallback(BTreeFiler cacheDB, List results, int threshold, Set excludeTable) { + this.cacheDB = cacheDB; + this.threshold = threshold; + this.results = results; + this.excludeTable = excludeTable; + } + + /** + * @inheritDoc + */ + public boolean indexInfo(Value val, long pos) { + + if (results.size() >= threshold) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SearchCallback.indexInfo reached Threshold :" + threshold); + } + return false; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found " + val); + } + Record record = null; + + try { + record = cacheDB.readRecord(pos); + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ex); + } + return false; + } + + if (record != null) { + long t0 = TimeUtils.timeNow(); + SrdiIndexRecord rec = readRecord(record); + + if (Logging.SHOW_FINEST && LOG.isLoggable(Level.FINEST)) { + LOG.finest("Got result back in : " + (TimeUtils.timeNow() - t0) + "ms."); + } + + copyIntoList(results, rec.list, excludeTable); + } + + return results.size() < threshold; + } + } + + + private static final class GcCallback implements BTreeCallback { + private final BTreeFiler cacheDB; + private final Indexer idxr; + private final List list; + private final Set table; + + GcCallback(BTreeFiler cacheDB, Indexer idxr, List list, Set table) { + this.cacheDB = cacheDB; + this.idxr = idxr; + this.list = list; + this.table = table; + } + + /** + * @inheritDoc + */ + public boolean indexInfo(Value val, long pos) { + + Record record = null; + synchronized (cacheDB) { + try { + record = cacheDB.readRecord(pos); + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading indexed", ex); + } + return false; + } + if (record == null) { + return true; + } + SrdiIndexRecord rec = readRecord(record); + List res = rec.list; + boolean changed = false; + + Iterator eachEntry = res.iterator(); + while(eachEntry.hasNext()) { + Entry entry = eachEntry.next(); + + if (entry.isExpired() || table.contains(entry.peerid)) { + changed = true; + eachEntry.remove(); + } + } + if (changed) { + if (res.isEmpty()) { + try { + cacheDB.deleteRecord(rec.key); + list.add(pos); + } catch (DBException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while deleting empty record", e); + } + } + } else { + // write it back + byte[] data = getData(rec.key, res); + Value recordValue = new Value(data); + + try { + cacheDB.writeRecord(pos, recordValue); + } catch (DBException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while writing back record", ex); + } + } + } + } + } + return true; + } + } + + /** + * copies the content of List into a list. Expired entries are not + * copied + * + * @param to list to copy into + * @param from list to copy from + * @param table table of PeerID's + */ + private static void copyIntoList(List to, List from, Set table) { + for (Entry entry : from) { + boolean expired = entry.isExpired(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Entry peerid : " + entry.peerid + (expired ? " EXPIRED " : (" Expires at : " + entry.expiration))); + } + + if (!to.contains(entry.peerid) && !expired) { + if (!table.contains(entry.peerid)) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("adding Entry :" + entry.peerid + " to list"); + } + to.add(entry.peerid); + } else { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Skipping gc marked entry :" + entry.peerid); + } + } + } else { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Skipping expired Entry :" + entry.peerid); + } + } + } + } + + /** + * Converts a List of {@link Entry} into a byte[] + * + * @param key record key + * @param list List to convert + * @return byte [] + */ + private static byte[] getData(Key key, List list) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(bos); + + dos.writeUTF(key.toString()); + dos.writeInt(list.size()); + for (Entry anEntry : list) { + dos.writeUTF(anEntry.peerid.toString()); + dos.writeLong(anEntry.expiration); + } + dos.close(); + return bos.toByteArray(); + } catch (IOException ie) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Exception while reading Entry", ie); + } + } + return null; + } + + /** + * Reads the content of a record into List + * + * @param record Btree Record + * @return List of entries + */ + public static SrdiIndexRecord readRecord(Record record) { + List result = new ArrayList(); + Key key = null; + + if (record == null) { + return new SrdiIndexRecord(null, result); + } + if (record.getValue().getLength() <= 0) { + return new SrdiIndexRecord(null, result); + } + InputStream is = record.getValue().getInputStream(); + + try { + DataInputStream ois = new DataInputStream(is); + + key = new Key(ois.readUTF()); + int size = ois.readInt(); + + for (int i = 0; i < size; i++) { + try { + String idstr = ois.readUTF(); + PeerID pid = (PeerID) IDFactory.fromURI(new URI(idstr)); + long exp = ois.readLong(); + Entry entry = new Entry(pid, exp); + + result.add(entry); + } catch (URISyntaxException badID) { + // ignored + } + } + ois.close(); + } catch (EOFException eofe) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Empty record", eofe); + } + } catch (IOException ie) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception while reading Entry", ie); + } + } + return new SrdiIndexRecord(key, result); + } + + /** + * Empties the index completely. + * The entries are abandoned to the GC. + */ + public synchronized void clear() { + // FIXME changing the behavior a bit + // instead of dropping all srdi entries, we let them expire + // if that is not a desired behavior the indexer could be dropped + // simply close it, and remove all index db created + try { + srdiIndexer.close(); + cacheDB.close(); + } catch (Exception e) { + // bad bits we are done + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to close index", e); + } + } + } + + /** + * Garbage Collect expired entries + */ + public void garbageCollect() { + try { + Map map = srdiIndexer.getIndexers(); + + for(NameIndexer idxr : map.values()) { + List list = new ArrayList(); + + if(stop) { + break; + } + + synchronized(this) { + idxr.query(null, new GcCallback(cacheDB, srdiIndexer, list, gcPeerTBL)); + srdiIndexer.purge(list); + } + } + gcPeerTBL.clear(); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure during SRDI Garbage Collect", ex); + } + } + } + + /** + * Remove expired entries from a List + * + * @param list A list of entries. + * @return The same list with the expired entries removed. + */ + private static List removeExpired(List list) { + Iterator eachEntry = list.iterator(); + + while(eachEntry.hasNext()) { + Entry entry = eachEntry.next(); + + if (entry.isExpired()) { + eachEntry.remove(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing expired Entry peerid :" + entry.peerid + " Expires at :" + entry.expiration); + } + } + } + return list; + } + + private static boolean isExpired(long expiration) { + return (TimeUtils.timeNow() > expiration); + } + + /** + * stop the current running thread + */ + public synchronized void stop() { + if(stop) { + return; + } + + stop = true; + + // wakeup and die + try { + Thread temp = gcThread; + if (temp != null) { + synchronized (temp) { + temp.notify(); + } + } + } catch (Exception ignored) { + // ignored + } + + // Stop the database + + try { + srdiIndexer.close(); + cacheDB.close(); + gcPeerTBL.clear(); + } catch (Exception ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Unable to stop the Srdi Indexer", ex); + } + } + } + + /** + * {@inheritDoc} + *

      + * Periodic thread for GC + */ + public void run() { + try { + while (!stop) { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting for " + interval + "ms before garbage collection"); + } + synchronized (gcThread) { + gcThread.wait(interval); + } + } catch (InterruptedException woken) { + // The only reason we are woken is to stop. + Thread.interrupted(); + continue; + } + + if (stop) { + break; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Garbage collection started"); + } + + garbageCollect(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Garbage collection completed"); + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + synchronized (this) { + gcThread = null; + } + } + } + + /** + * Flushes the Srdi directory for a specified group + * this method should only be called before initialization of a given group + * calling this method on a running group would have undefined results + * + * @param group group context + */ + public static void clearSrdi(PeerGroup group) { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Clearing SRDI for " + group.getPeerGroupName()); + } + + try { + String pgdir = null; + + if (group == null) { + pgdir = "srdi-index"; + } else { + pgdir = group.getPeerGroupID().getUniqueValue().toString(); + } + File rootDir = null; + + if (group != null) { + rootDir = new File(new File(new File(group.getStoreHome()), "cm"), pgdir); + } + + rootDir = new File(rootDir, "srdi"); + if (rootDir.exists()) { + // remove it along with it's content + String[] list = rootDir.list(); + + for (String aList : list) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing : " + aList); + } + File file = new File(rootDir, aList); + + if (!file.delete()) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unable to delete the file"); + } + } + } + rootDir.delete(); + } + } catch (Throwable t) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unable to clear Srdi", t); + } + } + } + + /** + * An entry in the index tables. + */ + public final static class Entry { + + public final PeerID peerid; + public final long expiration; + + /** + * Peer Pointer reference + * + * @param peerid PeerID for this entry + * @param expiration the expiration for this entry + */ + public Entry(PeerID peerid, long expiration) { + this.peerid = peerid; + this.expiration = expiration; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + return obj instanceof Entry && (peerid.equals(((Entry) obj).peerid)); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return peerid.hashCode(); + } + + /** + * Return the absolute time in milliseconds at which this entry will + * expire. + * + * @return The absolute time in milliseconds at which this entry will + * expire. + */ + public long getExpiration() { + return expiration; + } + + /** + * Return {@code true} if this entry is expired. + * + * @return {@code true} if this entry is expired otherwise {@code false}. + */ + public boolean isExpired() { + return TimeUtils.timeNow() > expiration; + } + } + + + /** + * an SrdiIndexRecord wrapper + */ + public final static class SrdiIndexRecord { + + public final Key key; + public final List list; + + /** + * SrdiIndex record + * + * @param key record key + * @param list record entries + */ + public SrdiIndexRecord(Key key,List list) { + this.key = key; + this.list = list; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + return obj instanceof SrdiIndexRecord && (key.equals(((SrdiIndexRecord) obj).key)); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return key.hashCode(); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/config.properties b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/config.properties new file mode 100644 index 000000000..f88f5ffb4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/config.properties @@ -0,0 +1,19 @@ +# JXTA Distribution Configuration Properties File +# +# This file contains properties which configure several basic defaults +# for JXTA distributions. Normally these values do not need to be changed +# by applications. (Most of the values have remained been unchanged since +# they were originally defined). +# + +# ID of the net peer group as a URI +#NetPeerGroupID=jxta-NetGroup +NetPeerGroupID=uuid-E6973087961042BC8412A6356F9FB70702 +# Name of the Net Peer Group +#NetPeerGroupName=NetPeerGroup +NetPeerGroupName=p2p.linphone.org-NetPeerGroup +# Description of the Net Peer Group +#NetPeerGroupDesc=default Net Peer Group +NetPeerGroupDesc=Net Peer Group for p2p.linphone.org +# Default type of ID to use when creating an ID +IDNewInstances=uuid diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/DiscoveryServiceImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/DiscoveryServiceImpl.java new file mode 100644 index 000000000..3dd7e6ef7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/DiscoveryServiceImpl.java @@ -0,0 +1,1718 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.discovery; + + +import net.jxta.credential.Credential; +import net.jxta.discovery.DiscoveryEvent; +import net.jxta.discovery.DiscoveryListener; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.impl.cm.Cm; +import net.jxta.impl.cm.Srdi; +import net.jxta.impl.cm.SrdiIndex; +import net.jxta.impl.peergroup.StdPeerGroup; +import net.jxta.impl.protocol.DiscoveryConfigAdv; +import net.jxta.impl.protocol.DiscoveryQuery; +import net.jxta.impl.protocol.DiscoveryResponse; +import net.jxta.impl.protocol.ResolverQuery; +import net.jxta.impl.protocol.ResolverResponse; +import net.jxta.impl.protocol.SrdiMessageImpl; +import net.jxta.impl.resolver.InternalQueryHandler; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.DiscoveryQueryMsg; +import net.jxta.protocol.DiscoveryResponseMsg; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.protocol.SrdiMessage; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezvousListener; +import net.jxta.resolver.ResolverService; +import net.jxta.resolver.SrdiHandler; +import net.jxta.service.Service; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.net.URI; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This Discovery Service implementation provides a mechanism to discover + * Advertisements using the Resolver service and SRDI. + *

      + *

      This implementation uses the standard JXTA Peer Discovery Protocol + * (PDP). + *

      + *

      The DiscoveryService service also provides a way to obtain information + * from a specified peer and request other peer advertisements, this method is + * particularly useful in the case of a portal where new relationships may be + * established starting from a predetermined peer (perhaps described in address + * book, or through an invitation). + * + * @see net.jxta.discovery.DiscoveryService + * @see net.jxta.protocol.DiscoveryQueryMsg + * @see net.jxta.impl.protocol.DiscoveryQuery + * @see net.jxta.protocol.DiscoveryResponseMsg + * @see net.jxta.impl.protocol.DiscoveryResponse + * @see net.jxta.resolver.ResolverService + * @see JXTA Protocols Specification : Peer Discovery Protocol + */ +public class DiscoveryServiceImpl implements DiscoveryService, InternalQueryHandler, RendezvousListener, SrdiHandler, Srdi.SrdiInterface { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(DiscoveryServiceImpl.class.getName()); + + /** + * adv types + */ + final static String[] dirname = {"Peers", "Groups", "Adv"}; + + /** + * The Query ID which will be associated with remote publish operations. + */ + private final static int REMOTE_PUBLISH_QUERYID = 0; + + private final static String srdiIndexerFileName = "discoverySrdi"; + + /** + * The current resolver query ID. static to make debugging easier. + */ + private final static AtomicInteger qid = new AtomicInteger(0); + + /** + * The maximum number of responses we will return for ANY query. + */ + private final static int MAX_RESPONSES = 50; + + /** + * The cache manager we're going to use to cache jxta advertisements + */ + protected Cm cm; + + /** + * assignedID as a String. + */ + private PeerGroup group = null; + private String handlerName = null; + private ModuleImplAdvertisement implAdvertisement = null; + + private ResolverService resolver = null; + private RendezVousService rendezvous = null; + private MembershipService membership = null; + + private PeerID localPeerId = null; + + private boolean localonly = false; + private boolean alwaysUseReplicaPeer = false; + + private boolean stopped = true; + + /** + * The table of discovery listeners. + */ + private Set listeners = new HashSet(); + + /** + * The table of discovery query listeners. + */ + private Hashtable listenerTable = new Hashtable(); + + private final String checkPeerAdvLock = new String("Check/Update PeerAdvertisement Lock"); + private PeerAdvertisement lastPeerAdv = null; + private int lastModCount = -1; + + private boolean isRdv = false; + + private SrdiIndex srdiIndex = null; + private Srdi srdi = null; + private Thread srdiThread = null; + + private CredentialListener membershipCredListener = null; + private Credential credential = null; + private StructuredDocument credentialDoc = null; + + private long initialDelay = 60 * TimeUtils.ASECOND; + private long runInterval = 30 * TimeUtils.ASECOND; + + /** + * the discovery interface object + */ + private DiscoveryService discoveryInterface = null; + + /** + * Listener we use for membership property events. + */ + private class CredentialListener implements PropertyChangeListener { + + /** + * {@inheritDoc} + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("defaultCredential".equals(evt.getPropertyName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New default credential event"); + } + + synchronized (DiscoveryServiceImpl.this) { + credential = (Credential) evt.getNewValue(); + credentialDoc = null; + + if (null != credential) { + try { + credentialDoc = credential.getDocument(MimeMediaType.XMLUTF8); + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not generate credential document", all); + } + } + } + } + } + } + } + + /** + * {@inheritDoc} + */ + public synchronized Service getInterface() { + if (discoveryInterface == null) { + discoveryInterface = new DiscoveryServiceInterface(this); + } + return discoveryInterface; + } + + /** + * {@inheritDoc} + */ + public Advertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + */ + public int getRemoteAdvertisements(String peer, int type, String attribute, String value, int threshold) { + + return getRemoteAdvertisements(peer, type, attribute, value, threshold, null); + } + + /** + * {@inheritDoc} + */ + public int getRemoteAdvertisements(String peer, int type, String attribute, String value, int threshold, DiscoveryListener listener) { + + int myQueryID = qid.incrementAndGet(); + + if (localonly || stopped) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("localonly, no network operations performed"); + } + return myQueryID; + } + + if (resolver == null) { + // warn about calling the service before it started + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("resolver has not started yet, query discarded."); + } + return myQueryID; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + StringBuilder query = new StringBuilder( + "Sending query#" + myQueryID + " for " + threshold + " " + dirname[type] + " advs"); + + if (attribute != null) { + query.append("\n\tattr = ").append(attribute); + if (value != null) { + query.append("\tvalue = ").append(value); + } + } + LOG.fine(query.toString()); + } + + long t0 = System.currentTimeMillis(); + + DiscoveryQueryMsg dquery = new DiscoveryQuery(); + + dquery.setDiscoveryType(type); + dquery.setAttr(attribute); + dquery.setValue(value); + dquery.setThreshold(threshold); + + if (listener != null) { + listenerTable.put(myQueryID, listener); + } + + ResolverQueryMsg query = new ResolverQuery(); + + query.setHandlerName(handlerName); + query.setCredential(credentialDoc); + query.setSrcPeer(localPeerId); + query.setQuery(dquery.toString()); + query.setQueryId(myQueryID); + + // check srdi + if (peer == null && srdiIndex != null) { + List res = srdiIndex.query(dirname[type], attribute, value, threshold); + + if (!res.isEmpty()) { + srdi.forwardQuery(res, query, threshold); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Srdi forward a query #" + myQueryID + " in " + (System.currentTimeMillis() - t0) + "ms."); + } + return myQueryID; + // nothing in srdi, get a starting point in rpv + } else if (group.isRendezvous() && attribute != null && value != null) { + PeerID destPeer = srdi.getReplicaPeer(dirname[type] + attribute + value); + + if (destPeer != null) { + if (!destPeer.equals(group.getPeerID())) { + // forward query increments the hopcount to indicate getReplica + // has been invoked once + srdi.forwardQuery(destPeer, query); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Srdi forward query #" + myQueryID + " to " + destPeer + " in " + + (System.currentTimeMillis() - t0) + "ms."); + } + return myQueryID; + } + } + } + } + + // no srdi, not a rendezvous, start the walk + resolver.sendQuery(peer, query); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (peer == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent a query #" + myQueryID + " in " + (System.currentTimeMillis() - t0) + "ms."); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent a query #" + myQueryID + " to " + peer + " in " + (System.currentTimeMillis() - t0) + "ms."); + } + } + } + + return myQueryID; + } + + /** + * {@inheritDoc} + */ + public Enumeration getLocalAdvertisements(int type, String attribute, String value) throws IOException { + + if ((type > 2) || (type < 0)) { + throw new IllegalArgumentException("Unknown Advertisement type"); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + StringBuilder query = new StringBuilder("Searching for " + dirname[type] + " advs"); + + if (attribute != null) { + query.append("\n\tattr = ").append(attribute); + } + if (value != null) { + query.append("\tvalue = ").append(value); + } + LOG.fine(query.toString()); + } + + return Collections.enumeration(search(type, attribute, value, Integer.MAX_VALUE, false, null)); + } + + /** + * {@inheritDoc} + */ + public void init(PeerGroup pg, ID assignedID, Advertisement impl) throws PeerGroupException { + + group = pg; + handlerName = assignedID.toString(); + implAdvertisement = (ModuleImplAdvertisement) impl; + localPeerId = group.getPeerID(); + + ConfigParams confAdv = pg.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + if (confAdv != null) { + Advertisement adv = null; + + try { + XMLDocument configDoc = (XMLDocument) confAdv.getServiceParam(assignedID); + + if (null != configDoc) { + adv = AdvertisementFactory.newAdvertisement(configDoc); + } + } catch (NoSuchElementException failed) {// ignored + } + + if (adv instanceof DiscoveryConfigAdv) { + DiscoveryConfigAdv discoConfigAdv = (DiscoveryConfigAdv) adv; + + alwaysUseReplicaPeer = discoConfigAdv.getForwardAlwaysReplica(); + + localonly |= discoConfigAdv.getLocalOnly(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (localonly) { + LOG.fine("localonly set to true via service parameters"); + } + if (alwaysUseReplicaPeer) { + LOG.fine("alwaysUseReplicaPeer set to true via service parameters"); + } + } + } + } + + cm = ((StdPeerGroup) group).getCacheManager(); + cm.setTrackDeltas(!localonly); + + // Initialize the peer adv tracking. + checkUpdatePeerAdv(); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Discovery Service : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID : ").append(group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tLocal Only : ").append(localonly); + configInfo.append("\n\t\tAlways Use ReplicaPeer : ").append(alwaysUseReplicaPeer); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + + // Now we know that the resolver is going to be there. + // The cm needs the resolver. The code is arranged so that + // until the resolver and the cm are created, we just pretend + // to be working. We have no requirement to be operational before + // startApp() is called, but we must tolerate our public methods + // being invoked. The reason for it is that services are registered + // upon return from init() so that other services startApp() methods + // can find them. (all startApp()s are called after all init()s - with + // a few exceptions). + + resolver = group.getResolverService(); + + if (null == resolver) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a resolver service"); + } + + return Module.START_AGAIN_STALLED; + } + + membership = group.getMembershipService(); + + if (null == membership) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + + return Module.START_AGAIN_STALLED; + } + + rendezvous = group.getRendezVousService(); + + if (null == rendezvous) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a rendezvous service"); + } + + return Module.START_AGAIN_STALLED; + } + + // local only discovery + if (!localonly) { + resolver.registerHandler(handlerName, this); + } + + // Get the initial credential doc + synchronized (this) { + membershipCredListener = new CredentialListener(); + membership.addPropertyChangeListener("defaultCredential", membershipCredListener); + + try { + membershipCredListener.propertyChange( + new PropertyChangeEvent(membership, "defaultCredential", null, membership.getDefaultCredential())); + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not get credential", all); + } + } + } + + if (rendezvous.isRendezVous()) { + beRendezvous(); + } else { + beEdge(); + } + + rendezvous.addListener(this); + + stopped = false; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Discovery service started"); + } + + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

      + *

      Detach from the resolver + */ + public void stopApp() { + + stopped = true; + boolean failed = false; + + membership.removePropertyChangeListener("defaultCredential", membershipCredListener); + membershipCredListener = null; + credential = null; + credentialDoc = null; + + rendezvous.removeListener(this); + + if (resolver.unregisterHandler(handlerName) == null) { + failed = true; + } + + if (rendezvous.isRendezVous()) { + if (resolver.unregisterSrdiHandler(handlerName) == null) { + failed = true; + } + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING) && failed) { + LOG.warning("failed to unregister discovery from resolver."); + } + + // stop the DiscoverySrdiThread + if (srdiThread != null) { + srdi.stop(); + srdi = null; + } + + // Reset values in order to avoid cross-reference problems with GC + resolver = null; + group = null; + membership = null; + srdiIndex = null; + srdiThread = null; + rendezvous = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Discovery service stopped."); + } + } + + /** + * {@inheritDoc} + */ + public void flushAdvertisements(String id, int type) throws IOException { + if (stopped) { + return; + } + if ((type >= PEER) && (type <= ADV)) { + if (null != id) { + ID advID = ID.create(URI.create(id)); + String advName = advID.getUniqueValue().toString(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("flushing adv " + advName + " of type " + dirname[type]); + } + cm.remove(dirname[type], advName); + } else { + // XXX bondolo 20050902 For historical purposes we ignore null + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Flush request by type IGNORED. You must delete advertisements individually."); + } + } + } else { + throw new IllegalArgumentException("Invalid Advertisement type."); + } + } + + /** + * {@inheritDoc} + */ + public void flushAdvertisement(Advertisement adv) throws IOException { + if (stopped) { + return; + } + + int type; + + if (adv instanceof PeerAdvertisement) { + type = PEER; + } else if (adv instanceof PeerGroupAdvertisement) { + type = GROUP; + } else { + type = ADV; + } + + ID id = adv.getID(); + String advName; + + if (id != null && !id.equals(ID.nullID)) { + advName = id.getUniqueValue().toString(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Flushing adv " + advName + " of type " + dirname[type]); + } + } else { + XMLDocument doc; + + try { + doc = (XMLDocument) adv.getDocument(MimeMediaType.XMLUTF8); + } catch (Exception everything) { + IOException failure = new IOException("Failure removing Advertisement"); + + failure.initCause(everything); + throw failure; + } + advName = Cm.createTmpName(doc); + } + + if (advName != null) { + cm.remove(dirname[type], advName); + } + } + + /** + * {@inheritDoc} + */ + public void publish(Advertisement adv) throws IOException { + publish(adv, DiscoveryService.DEFAULT_LIFETIME, DiscoveryService.DEFAULT_EXPIRATION); + } + + /** + * {@inheritDoc} + */ + public void publish(Advertisement adv, long lifetime, long expiration) throws IOException { + + if (stopped) { + return; + } + + ID advID; + String advName; + + int type; + + if (adv instanceof PeerAdvertisement) { + type = PEER; + } else if (adv instanceof PeerGroupAdvertisement) { + type = GROUP; + } else { + type = ADV; + } + + advID = adv.getID(); + + // if we dont have a unique id for the adv, use the hash method + if ((null == advID) || advID.equals(ID.nullID)) { + XMLDocument doc; + + try { + doc = (XMLDocument) adv.getDocument(MimeMediaType.XMLUTF8); + } catch (Exception everything) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to generated document from advertisement", everything); + } + IOException failure = new IOException("Failed to generate document from advertisement"); + + failure.initCause(everything); + throw failure; + } + + try { + advName = Cm.createTmpName(doc); + } catch (IllegalStateException ise) { + IOException failure = new IOException("Failed to generate tempname from advertisement"); + + failure.initCause(ise); + throw failure; + } + } else { + advName = advID.getUniqueValue().toString(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Publishing a " + adv.getAdvType() + " as " + dirname[type] + " / " + advName + "\n\texpiration : " + + expiration + "\tlifetime :" + lifetime); + } + + // save it + cm.save(dirname[type], advName, adv, lifetime, expiration); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(Advertisement adv) { + remotePublish(null, adv, DiscoveryService.DEFAULT_EXPIRATION); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(Advertisement adv, long expiration) { + remotePublish(null, adv, expiration); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(String peerid, Advertisement adv) { + remotePublish(peerid, adv, DiscoveryService.DEFAULT_EXPIRATION); + } + + /** + * {@inheritDoc} + */ + public void processResponse(ResolverResponseMsg response) { + processResponse(response, null); + } + + /** + * {@inheritDoc} + */ + public void processResponse(ResolverResponseMsg response, EndpointAddress srcAddress) { + if (stopped) { + return; + } + + long t0 = System.currentTimeMillis(); + DiscoveryResponse res; + + try { + XMLDocument asDoc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8 + , + new StringReader(response.getResponse())); + + res = new DiscoveryResponse(asDoc); + } catch (Exception e) { + // we don't understand this msg, let's skip it + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to Read Discovery Response", e); + } + return; + } + + /* + PeerAdvertisement padv = res.getPeerAdvertisement(); + if (padv == null) + return; + + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Got a " + dirname[res.getDiscoveryType()] + + " from "+padv.getName()+ " response : " + + res.getQueryAttr() + " = " + res.getQueryValue()); + } + + try { + // The sender does not put an expiration on that one, but + // we do not want to keep it around for more than the + // default duration. It may get updated or become invalid. + publish(padv, PEER, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + } catch (Exception e) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine(e, e); + } + return; + } + */ + Advertisement adv; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Processing responses for query #" + response.getQueryId()); + } + + Enumeration en = res.getAdvertisements(); + Enumeration exps = res.getExpirations(); + + while (en.hasMoreElements()) { + adv = en.nextElement(); + long exp = exps.nextElement(); + + if (exp > 0 && adv != null) { + try { + publish(adv, exp, exp); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error publishing Advertisement", e); + } + } + } + } + + DiscoveryEvent newevent = new DiscoveryEvent(srcAddress, res, response.getQueryId()); + + DiscoveryListener dl = listenerTable.get(new Integer(response.getQueryId())); + + if (dl != null) { + try { + dl.discoveryEvent(new DiscoveryEvent(srcAddress, res, response.getQueryId())); + } catch (Throwable all) { + LOG.log(Level.SEVERE, "Uncaught Throwable in listener :" + Thread.currentThread().getName(), all); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processed a response for query #" + response.getQueryId() + " in :" + (System.currentTimeMillis() - t0)); + } + + // are there any registered discovery listeners, + // generate the event and callback. + t0 = System.currentTimeMillis(); + + DiscoveryListener[] allListeners = listeners.toArray(new DiscoveryListener[0]); + + for (DiscoveryListener allListener : allListeners) { + try { + allListener.discoveryEvent(newevent); + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING + , + "Uncaught Throwable in listener (" + allListener.getClass().getName() + ") :" + + Thread.currentThread().getName() + , + all); + } + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Called all listenters to query #" + response.getQueryId() + " in :" + (System.currentTimeMillis() - t0)); + } + } + + /** + * {@inheritDoc} + */ + public int processQuery(ResolverQueryMsg query) { + + return processQuery(query, null); + } + + /** + * {@inheritDoc} + */ + public int processQuery(ResolverQueryMsg query, EndpointAddress srcAddress) { + if (stopped) { + return ResolverService.OK; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (srcAddress != null) { + LOG.fine("Processing query #" + query.getQueryId() + " from:" + srcAddress); + } else { + LOG.fine("Processing query #" + query.getQueryId() + " from: unknown"); + } + } + + List results; + List expirations = new ArrayList(); + DiscoveryQuery dq; + long t0 = System.currentTimeMillis(); + + try { + XMLDocument asDoc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(query.getQuery())); + + dq = new DiscoveryQuery(asDoc); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Malformed query : ", e); + } + return ResolverService.OK; + } + + if ((dq.getThreshold() < 0) || (dq.getDiscoveryType() < PEER) || (dq.getDiscoveryType() > ADV)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Malformed query"); + } + return ResolverService.OK; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Got a " + dirname[dq.getDiscoveryType()] + " query #" + query.getQueryId() + " query :" + dq.getAttr() + + " = " + dq.getValue()); + } + + /* + // Get the Peer Adv from the query and publish it. + PeerAdvertisement padv = dq.getPeerAdvertisement(); + try { + if (!(padv.getPeerID().toString()).equals(localPeerId)) { + // publish others only. Since this one comes from outside, + // we must not keep it beyond its expiration time. + // FIXME: [jice@jxta.org 20011112] In theory there should + // be an expiration time associated with it in the msg, like + // all other items. + publish(padv, PEER, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + } + } catch (Exception e) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Bad Peer Adv in Discovery Query", e); + } + } + */ + + /* + * threshold==0 and type==PEER is a special case. In this case we are + * responding for the purpose of providing our own adv only. + */ + int thresh = Math.min(dq.getThreshold(), MAX_RESPONSES); + + /* + * threshold==0 and type==PEER is a special case. In this case we are + * responding for the purpose of providing our own adv only. + */ + if ((dq.getDiscoveryType() == PEER) && (0 == dq.getThreshold())) { + respond(query, dq, Collections.singletonList(group.getPeerAdvertisement().toString()) + , + Collections.singletonList(DiscoveryService.DEFAULT_EXPIRATION)); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Responding to query #" + query.getQueryId() + " in :" + (System.currentTimeMillis() - t0)); + } + return ResolverService.OK; + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("start local search query" + dq.getAttr() + " " + dq.getValue()); + } + results = search(dq.getDiscoveryType(), dq.getAttr(), dq.getValue(), thresh, true, expirations); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("start local search pruned " + results.size()); + } + } + + // We only share the advs with > 0 expiration time. + Iterator eachExpiration = expirations.iterator(); + Iterator eachAdv = results.iterator(); + + while (eachExpiration.hasNext()) { + eachAdv.next(); + + if (eachExpiration.next() <= 0) { + eachAdv.remove(); + eachExpiration.remove(); + } + } + + if (!results.isEmpty()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Responding to " + dirname[dq.getDiscoveryType()] + " Query : " + dq.getAttr() + " = " + dq.getValue()); + } + respond(query, dq, results, expirations); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Responded to query #" + query.getQueryId() + " in :" + (System.currentTimeMillis() - t0)); + } + return ResolverService.OK; + } else { + // If this peer is a rendezvous, simply let the resolver + // re-propagate the query. + // If this peer is not a rendez, just discard the query. + if (!group.isRendezvous()) { + return ResolverService.OK; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Querying SrdiIndex query #" + query.getQueryId()); + } + List res = srdiIndex.query(dirname[dq.getDiscoveryType()], dq.getAttr(), dq.getValue(), thresh); + + if (!res.isEmpty()) { + srdi.forwardQuery(res, query, thresh); + return ResolverService.OK; + } else if (query.getHopCount() == 0) { + PeerID destPeer = srdi.getReplicaPeer(dirname[dq.getDiscoveryType()] + dq.getAttr() + dq.getValue()); + + // destPeer can be null in a small rpv (<3) + if (destPeer != null) { + if (!destPeer.equals(group.getPeerID())) { + srdi.forwardQuery(destPeer, query); + return ResolverService.OK; + } else { + // start the walk since this peer is this the starting peer + query.incrementHopCount(); + } + } + } + } + return ResolverService.Repropagate; + } + + private void respond(ResolverQueryMsg query, DiscoveryQuery dq, List results, List expirations) { + if (localonly || stopped) { + return; + } + + ResolverResponseMsg response; + DiscoveryResponse dresponse = new DiscoveryResponse(); + + // peer adv is optional, skip + dresponse.setDiscoveryType(dq.getDiscoveryType()); + dresponse.setQueryAttr(dq.getAttr()); + dresponse.setQueryValue(dq.getValue()); + dresponse.setResponses(results); + dresponse.setExpirations(expirations); + + // create a response from the query + response = query.makeResponse(); + response.setCredential(credentialDoc); + response.setResponse(dresponse.toString()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Responding to " + query.getSrcPeer()); + } + + resolver.sendResponse(query.getSrcPeer().toString(), response); + } + + /** + * {@inheritDoc} + */ + public synchronized void addDiscoveryListener(DiscoveryListener listener) { + + listeners.add(listener); + } + + /** + * {@inheritDoc} + */ + public synchronized boolean removeDiscoveryListener(DiscoveryListener listener) { + + Iterator> e = listenerTable.entrySet().iterator(); + + while (e.hasNext()) { + Map.Entry anEntry = e.next(); + + if (listener == anEntry.getValue()) { + e.remove(); + } + } + return (listeners.remove(listener)); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(String peerid, Advertisement adv, long timeout) { + + if (localonly || stopped) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("localonly, no network operations performed"); + } + return; + } + int type; + + if (adv instanceof PeerAdvertisement) { + type = PEER; + } else if (adv instanceof PeerGroupAdvertisement) { + type = GROUP; + } else { + type = ADV; + } + remotePublish(peerid, adv, type, timeout); + } + + /* + * remote publish the advertisement + */ + private void remotePublish(String peerid, Advertisement adv, int type, long expiration) { + + if (localonly || stopped) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("localonly, no network operations performed"); + } + return; + } + + // In case this is invoked before startApp(). + if (resolver == null) { + return; + } + + switch (type) { + case PEER: + if (adv instanceof PeerAdvertisement) { + break; + } + throw new IllegalArgumentException("Not a peer advertisement"); + + case GROUP: + if (adv instanceof PeerGroupAdvertisement) { + break; + } + throw new IllegalArgumentException("Not a peergroup advertisement"); + + case ADV: + break; + + default: + throw new IllegalArgumentException("Unknown advertisement type"); + } + + List advert = new ArrayList(1); + List expirations = new ArrayList(1); + + advert.add(adv.toString()); + expirations.add(expiration); + + DiscoveryResponseMsg dresponse = new DiscoveryResponse(); + + dresponse.setDiscoveryType(type); + dresponse.setResponses(advert); + dresponse.setExpirations(expirations); + + ResolverResponseMsg pushRes = new ResolverResponse(); + + pushRes.setHandlerName(handlerName); + pushRes.setCredential(credentialDoc); + pushRes.setQueryId(REMOTE_PUBLISH_QUERYID); + pushRes.setResponse(dresponse.toString()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Remote publishing "); + } + + resolver.sendResponse(peerid, pushRes); + } + + /** + * Search for a doc, that matches attr, and value + * bytes is set to true if the caller wants wire format of the + * advertisement, or set to false if caller wants Advertisement + * objects. + * + * @param type Discovery type PEER, GROUP, ADV + * @param threshold the upper limit of responses from one peer + * @param bytes flag to indicate how the results are returned-- advs, or streams + * @param expirations List containing the expirations associated with is returned + * @param attr attribute name to narrow discovery to Valid values for + * this parameter are null (don't care), or exact element name in the + * advertisement of interest (e.g. "Name") + * @param value Value + * @return list of results either as docs, or Strings + */ + private List search(int type, String attr, String value, int threshold, boolean bytes, List expirations) { + + if (stopped) { + return new ArrayList(); + } + + if (type == PEER) { + checkUpdatePeerAdv(); + } + + List results; + + if (threshold <= 0) { + throw new IllegalArgumentException("threshold must be greater than zero"); + } + + if (expirations != null) { + expirations.clear(); + } + + if (attr != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Searching for " + threshold + " entries of type : " + dirname[type]); + } + // a discovery query with a specific search criteria. + results = cm.search(dirname[type], attr, value, threshold, expirations); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting " + threshold + " entries of type : " + dirname[type]); + } + // Returning any entry that exists + results = cm.getRecords(dirname[type], threshold, expirations); + } + + if (results.isEmpty() || bytes) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Returning " + results.size() + " results"); + } + + // nothing more to do; + return results; + } + + // Convert the input streams returned by the cm into Advertisements. + + List advertisements = new ArrayList(); + + for (int i = 0; i < results.size(); i++) { + InputStream bis = null; + + try { + bis = (InputStream) results.get(i); + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, bis); + Advertisement adv = AdvertisementFactory.newAdvertisement(asDoc); + + advertisements.add(adv); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building advertisment", e); + } + + // we won't be including this advertisement so remove it's expiration. + if (null != expirations) { + expirations.remove(i); + } + + } finally { + if (null != bis) { + try { + bis.close(); + } catch (IOException ignored) { + // ignored + } + } + bis = null; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Returning " + advertisements.size() + " advertisements"); + } + + return advertisements; + } + + /** + * {@inheritDoc} + */ + public long getAdvExpirationTime(ID id, int type) { + if (stopped) { + return -1; + } + String advName; + + if (id != null && !id.equals(ID.nullID)) { + advName = id.getUniqueValue().toString(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting expiration time of " + advName + " of type " + dirname[type]); + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("invalid attempt to get advertisement expiration time of NullID"); + } + return -1; + } + + return cm.getExpirationtime(dirname[type], advName); + } + + /** + * {@inheritDoc} + */ + public long getAdvLifeTime(ID id, int type) { + if (id == null || id.equals(ID.nullID) || stopped) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("invalid attempt to get advertisement lifetime of a NullID"); + } + return -1; + } + + String advName = id.getUniqueValue().toString(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting lifetime of " + advName + " of type " + dirname[type]); + } + + return cm.getLifetime(dirname[type], advName); + } + + /** + * {@inheritDoc} + */ + public long getAdvExpirationTime(Advertisement adv) { + if (stopped) { + return -1; + } + int type; + + if (adv instanceof PeerAdvertisement) { + type = PEER; + } else if (adv instanceof PeerGroupAdvertisement) { + type = GROUP; + } else { + type = ADV; + } + + String advName; + ID id = adv.getID(); + + if (id != null && !id.equals(ID.nullID)) { + advName = id.getUniqueValue().toString(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("attempting to getAdvExpirationTime on " + advName + " of type " + dirname[type]); + } + } else { + XMLDocument doc; + + try { + doc = (XMLDocument) adv.getDocument(MimeMediaType.XMLUTF8); + } catch (Exception everything) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to get document", everything); + } + return -1; + } + advName = Cm.createTmpName(doc); + } + + return cm.getExpirationtime(dirname[type], advName); + } + + /** + * {@inheritDoc} + */ + public long getAdvLifeTime(Advertisement adv) { + if (stopped) { + return -1; + } + int type; + + if (adv instanceof PeerAdvertisement) { + type = PEER; + } else if (adv instanceof PeerGroupAdvertisement) { + type = GROUP; + } else { + type = ADV; + } + + ID id = adv.getID(); + String advName; + + if (id != null && !id.equals(ID.nullID)) { + advName = id.getUniqueValue().toString(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("attempting to getAdvLifeTime " + advName + " of type " + dirname[type]); + } + } else { + XMLDocument doc; + + try { + doc = (XMLDocument) adv.getDocument(MimeMediaType.XMLUTF8); + } catch (Exception everything) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to get document", everything); + } + return -1; + } + advName = Cm.createTmpName(doc); + } + return cm.getLifetime(dirname[type], advName); + } + + /** + * {@inheritDoc} + */ + public boolean processSrdi(ResolverSrdiMsg message) { + if (stopped) { + return true; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupID() + "] Received an SRDI messsage"); + } + + SrdiMessage srdiMsg; + + try { + XMLDocument asDoc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(message.getPayload())); + + srdiMsg = new SrdiMessageImpl(asDoc); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed parsing srdi message", e); + } + return false; + } + + PeerID pid = srdiMsg.getPeerID(); + + for (Object o : srdiMsg.getEntries()) { + SrdiMessage.Entry entry = (SrdiMessage.Entry) o; + + srdiIndex.add(srdiMsg.getPrimaryKey(), entry.key, entry.value, pid, entry.expiration); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Primary Key [" + srdiMsg.getPrimaryKey() + "] key [" + entry.key + "] value [" + entry.value + "] exp [" + + entry.expiration + "]"); + } + } + srdi.replicateEntries(srdiMsg); + return true; + } + + /** + * {@inheritDoc} + */ + public void messageSendFailed(PeerID peerid, OutgoingMessageEvent e) { + if (srdiIndex != null) { + srdiIndex.remove(peerid); + } + } + + /** + * {@inheritDoc} + */ + public void pushEntries(boolean all) { + + pushSrdi(null, PEER, all); + pushSrdi(null, GROUP, all); + pushSrdi(null, ADV, all); + } + + /** + * push srdi entries + * + * @param all if true push all entries, otherwise just deltas + * @param peer peer id + * @param type if true sends all entries + */ + protected void pushSrdi(ID peer, int type, boolean all) { + if (stopped) { + return; + } + + List entries; + + if (all) { + entries = cm.getEntries(dirname[type], true); + } else { + entries = cm.getDeltas(dirname[type]); + } + + if (!entries.isEmpty()) { + SrdiMessage srdiMsg; + + try { + srdiMsg = new SrdiMessageImpl(group.getPeerID(), 1, // ttl of 1, ensure it is replicated + dirname[type], entries); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Pushing " + entries.size() + (all ? " entries" : " deltas") + " of type " + dirname[type]); + } + srdi.pushSrdi(peer, srdiMsg); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception pushing SRDI Entries", e); + } + } + } else { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("No" + (all ? " entries" : " deltas") + " of type " + dirname[type] + " to push"); + } + } + } + + /** + * {@inheritDoc} + */ + public synchronized void rendezvousEvent(RendezvousEvent event) { + + int theEventType = event.getType(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupName() + "] Processing " + event); + } + + switch (theEventType) { + + case RendezvousEvent.RDVCONNECT: + case RendezvousEvent.RDVRECONNECT: + // start tracking deltas + cm.setTrackDeltas(true); + break; + + case RendezvousEvent.CLIENTCONNECT: + case RendezvousEvent.CLIENTRECONNECT: + break; + + case RendezvousEvent.RDVFAILED: + case RendezvousEvent.RDVDISCONNECT: + // stop tracking deltas until we connect again + cm.setTrackDeltas(false); + break; + + case RendezvousEvent.CLIENTFAILED: + case RendezvousEvent.CLIENTDISCONNECT: + break; + + case RendezvousEvent.BECAMERDV: + beRendezvous(); + break; + + case RendezvousEvent.BECAMEEDGE: + beEdge(); + break; + + default: + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(MessageFormat.format("[{0}] Unexpected RDV event : {1}", group.getPeerGroupName(), event)); + } + break; + } + } + + /** + * Checks to see if the local peer advertisement has been updated and if + * it has then republish it to the CM. + */ + private void checkUpdatePeerAdv() { + PeerAdvertisement newPadv = group.getPeerAdvertisement(); + int newModCount = newPadv.getModCount(); + + boolean updated = false; + + synchronized (checkPeerAdvLock) { + if ((lastPeerAdv != newPadv) || (lastModCount < newModCount)) { + lastPeerAdv = newPadv; + lastModCount = newModCount; + updated = true; + } + + if (updated) { + // Publish the local Peer Advertisement + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("publishing local advertisement"); + } + + // This is our own; we can publish it for a long time in our cache + publish(newPadv, INFINITE_LIFETIME, DEFAULT_EXPIRATION); + } catch (Exception ignoring) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish local peer advertisement: ", ignoring); + } + } + } + } + } + + /** + * Change the behavior to be an rendezvous Peer Discovery Service. + * If the Service was acting as an Edge peer, cleanup. + */ + private synchronized void beRendezvous() { + + if (isRdv && (srdi != null || srdiIndex != null)) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Already a rendezvous -- No Switch is needed"); + } + return; + } + + isRdv = true; + + // rdv peers do not need to track deltas + cm.setTrackDeltas(false); + + if (srdiIndex == null) { + srdiIndex = new SrdiIndex(group, srdiIndexerFileName); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("srdiIndex created"); + } + + } + + // Kill SRDI, create a new one. + if (srdi != null) { + srdi.stop(); + if (srdiThread != null) { + srdiThread = null; + } + srdi = null; + } + + if (!localonly) { + srdi = new Srdi(group, handlerName, this, srdiIndex, initialDelay, runInterval); + resolver.registerSrdiHandler(handlerName, this); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("srdi created, and registered as an srdi handler "); + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Switched to Rendezvous peer role."); + } + } + + /** + * Change the behavior to be an Edge Peer Discovery Service. + * If the Service was acting as a Rendezvous, cleanup. + */ + private synchronized void beEdge() { + + // make sure we have been here before + if (!isRdv && srdiThread != null) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Already an Edge peer -- No Switch is needed."); + } + return; + } + + isRdv = false; + if (!rendezvous.getConnectedPeerIDs().isEmpty()) { + // if we have a rendezvous connection track deltas, otherwise wait + // for a connect event to set this option + cm.setTrackDeltas(true); + } + if (srdiIndex != null) { + srdiIndex.stop(); + srdiIndex = null; + resolver.unregisterSrdiHandler(handlerName); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("stopped cache and unregistered from resolver"); + } + } + + // Kill SRDI + if (srdi != null) { + srdi.stop(); + if (srdiThread != null) { + srdiThread = null; + } + srdi = null; + } + + if (!localonly) { + // Create a new SRDI + srdi = new Srdi(group, handlerName, this, null, initialDelay, runInterval); + + // only edge peers distribute srdi + srdiThread = new Thread(group.getHomeThreadGroup(), srdi, "Discovery Srdi Thread"); + srdiThread.setDaemon(true); + srdiThread.start(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Started SRDIThread"); + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Switched to a Edge peer role."); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/DiscoveryServiceInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/DiscoveryServiceInterface.java new file mode 100644 index 000000000..4562ef6c8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/DiscoveryServiceInterface.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.discovery; + + +import java.util.Enumeration; +import java.io.IOException; + +import net.jxta.discovery.DiscoveryListener; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.service.Service; + + +/** + * Provides a pure interface object that permits interaction with the actual + * Discovery Service implementation without giving access to the real object. + */ +public final class DiscoveryServiceInterface implements DiscoveryService { + + private DiscoveryServiceImpl impl; + + /** + * Only authorized constructor + * + * @param theRealThing The actual discovery implementation + */ + protected DiscoveryServiceInterface(DiscoveryServiceImpl theRealThing) { + impl = theRealThing; + } + + /** + * {@inheritDoc} + */ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public Advertisement getImplAdvertisement() { + return impl.getImplAdvertisement(); + } + + /** + * {@inheritDoc} + * + *

      FIXME: This is meaningless for the interface object; + * it is there only to satisfy the requirements of the + * interface that we implement. Ultimately, the API should define + * two levels of interfaces: one for the real service implementation + * and one for the interface object. Right now it feels a bit heavy + * to so that since the only different between the two would be + * init() and may-be getName(). + */ + public void init(PeerGroup pg, ID assignedID, Advertisement impl) {} + + /** + * {@inheritDoc} + * + *

      This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + */ + public int startApp(String[] arg) { + return 0; + } + + /** + * {@inheritDoc} + * + *

      This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + * + *

      This request is currently ignored. + */ + public void stopApp() {} + + /** + * {@inheritDoc} + */ + public int getRemoteAdvertisements(String peer, int type, String attribute, String value, int threshold) { + + return impl.getRemoteAdvertisements(peer, type, attribute, value, threshold); + } + + /** + * {@inheritDoc} + */ + public int getRemoteAdvertisements(String peer, int type, String attribute, String value, int threshold, DiscoveryListener listener) { + return impl.getRemoteAdvertisements(peer, type, attribute, value, threshold, listener); + } + + /** + * {@inheritDoc} + */ + public Enumeration getLocalAdvertisements(int type, String attribute, String value) throws IOException { + return impl.getLocalAdvertisements(type, attribute, value); + } + + /** + * {@inheritDoc} + */ + public void flushAdvertisement(Advertisement adv) throws IOException { + + impl.flushAdvertisement(adv); + } + + /** + * {@inheritDoc} + */ + public void flushAdvertisements(String id, int type) throws IOException { + impl.flushAdvertisements(id, type); + } + + /** + * {@inheritDoc} + */ + public long getAdvExpirationTime(ID id, int type) { + return impl.getAdvExpirationTime(id, type); + } + + /** + * {@inheritDoc} + */ + public long getAdvLifeTime(ID id, int type) { + return impl.getAdvLifeTime(id, type); + } + + /** + * {@inheritDoc} + */ + public long getAdvExpirationTime(Advertisement adv) { + return impl.getAdvExpirationTime(adv); + } + + /** + * {@inheritDoc} + */ + public long getAdvLifeTime(Advertisement adv) { + return impl.getAdvLifeTime(adv); + } + + /** + * {@inheritDoc} + */ + public void publish(Advertisement adv) throws IOException { + impl.publish(adv); + } + + /** + * {@inheritDoc} + */ + public void publish(Advertisement adv, long lifetime, long expiration) throws IOException { + + impl.publish(adv, lifetime, expiration); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(Advertisement adv) { + impl.remotePublish(adv); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(Advertisement adv, long expiration) { + impl.remotePublish(adv, expiration); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(String peerid, Advertisement adv) { + impl.remotePublish(peerid, adv); + } + + /** + * {@inheritDoc} + */ + public void remotePublish(String peerid, Advertisement adv, long expiration) { + impl.remotePublish(peerid, adv, expiration); + } + + /** + * {@inheritDoc} + */ + public synchronized void addDiscoveryListener(DiscoveryListener listener) { + impl.addDiscoveryListener(listener); + } + + /** + * {@inheritDoc} + */ + public synchronized boolean removeDiscoveryListener(DiscoveryListener listener) { + return (impl.removeDiscoveryListener(listener)); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/package.html new file mode 100644 index 000000000..c225a79da --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/discovery/package.html @@ -0,0 +1,15 @@ + + + + + + + A JXTA {@link net.jxta.discovery.DiscoveryService} implementation which + implements the standard JXTA Peer Discovery Protocol (PDP). + + @see net.jxta.discovery.DiscoveryService + @see net.jxta.resolver.ResolverService + @see JXTA Protocols Specification : Peer Discovery Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/DOMXMLDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/DOMXMLDocument.java new file mode 100644 index 000000000..d10ca0876 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/DOMXMLDocument.java @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSSerializer; +import org.w3c.dom.ls.LSOutput; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentFactory.Instantiator.ExtensionMapping; +import net.jxta.document.XMLDocument; + +import net.jxta.impl.document.TextDocumentCommon.Utils; + + +/** + * This class is an implementation of the StructuredDocument interface using + * DOM + * + * @see W3C Document Object Model (DOM) + * @see DOM Java Language Binding + * @see Document Object Model (DOM) Level 3 Load and Save Specification + * @see Java API for XML Processing (JAXP) + * @see org.w3c.dom + */ +public class DOMXMLDocument extends DOMXMLElement implements XMLDocument { + + private static final class Instantiator implements StructuredDocumentFactory.TextInstantiator { + + /** + * The MIME Media Types which this StructuredDocument is + * capable of emitting. + */ + private static final MimeMediaType[] myTypes = { + MimeMediaType.XML_DEFAULTENCODING, + new MimeMediaType("Application", "Xml") + }; + + /** + * these are the file extensions which are likely to contain files of + * the type i like. + */ + private static final ExtensionMapping[] myExtensions = { + new ExtensionMapping("xml", myTypes[0]), + new ExtensionMapping("xml", null) + }; + + /** + * Creates new XMLDocumentInstantiator + */ + public Instantiator() {} + + /** + * {@inheritDoc} + */ + public MimeMediaType[] getSupportedMimeTypes() { + return (myTypes); + } + + /** + * {@inheritDoc} + */ + public ExtensionMapping[] getSupportedFileExtensions() { + return (myExtensions); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, String doctype) { + return new DOMXMLDocument(mimeType, doctype); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, String doctype, String value) { + return new DOMXMLDocument(mimeType, doctype, value); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, InputStream source) throws IOException { + return new DOMXMLDocument(mimeType, source); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, Reader source) throws IOException { + return new DOMXMLDocument(mimeType, source); + } + + } + + public static final StructuredDocumentFactory.TextInstantiator INSTANTIATOR = new Instantiator(); + + private MimeMediaType mimeType; + + /** + * Constructor for new instances of DOMXMLDocument + * with a value for the root element. + * + * @param mimeType This is the MIME Media Type being requested. In general + * it should be equivalent with the MIME Media Type returned by + * {@link #getMimeType()}. A StructuredDocument + * sub-class may, however, support more than one MIME Media type so this may be a + * true parameter. XMLDocument supports additional the MIME Media Type parameters, + * "charset". The charset parameter must be a value per IETF RFC 2279 or ISO-10646. + * @param docType Used as the root type of this document. {@link net.jxta.document.XMLDocument} uses this as the XML + * DOCTYPE. + * @param value String value to be associated with the root element. + * null if none is wanted. + * @throws RuntimeException Exceptions generated by the underlying implementation. + */ + private DOMXMLDocument(final MimeMediaType mimeType, final String docType, final String value) { + super(null, null); + this.root = this; + + this.mimeType = mimeType; + + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + + docBuilderFactory.setNamespaceAware(true); + docBuilderFactory.setValidating(false); + try { + DocumentBuilder dataDocBuilder = docBuilderFactory.newDocumentBuilder(); + DOMImplementation domImpl = dataDocBuilder.getDOMImplementation(); + DocumentType doctypeNode = domImpl.createDocumentType(docType, null, null); + + domNode = domImpl.createDocument("http://jxta.org", docType, doctypeNode); + } catch (ParserConfigurationException misconfig) { + throw new UndeclaredThrowableException(misconfig); + } + + if (value != null) { + Node text = ((Document) domNode).createTextNode(value); + + ((Document) domNode).getDocumentElement().appendChild(text); + } + } + + /** + * Constructor for new instances of DOMXMLDocument + * + * @param mimeType This is the MIME Media Type being requested. In general it should be equivalent with + * the MIME Media Type returned by {@link #getMimeType()}. A StructuredDocument + * sub-class may, however, support more than one MIME Media type so this may be a + * true parameter. XMLDocument supports additional the MIME Media Type parameters, + * "charset". The charset parameter must be a value per IETF RFC 2279 or ISO-10646. + * @param docType Used as the root type of this document. {@link net.jxta.document.XMLDocument} uses this as the XML + * DOCTYPE. + * @throws RuntimeException Exceptions generated by the underlying implementation. + */ + private DOMXMLDocument(final MimeMediaType mimeType, final String docType) { + this(mimeType, docType, null); + } + + /** + * Constructor for existing documents. + * + * @param mimeType This is the MIME Media Type being requested. In general + * it should be equivalent with the MIME Media Type returned by + * {@link #getMimeType()}. A StructuredDocument sub-class may, + * however, support more than one MIME Media type so this may be a + * true parameter. XMLDocument supports additional the MIME Media Type parameters, + * "charset". The charset parameter must be a value per IETF RFC 2279 or ISO-10646. + * @param stream Contains the input used to construct this object. This stream should be of a type + * conformant with the type specified by the MIME Media Type "charset" parameter. + * @throws RuntimeException Propagates exceptions from the underlying implementation. + * @throws java.io.IOException Thrown for failures processing the document. + */ + private DOMXMLDocument(final MimeMediaType mimeType, final InputStream stream) throws IOException { + super(null, null); + this.root = this; + + this.mimeType = mimeType; + + String charset = mimeType.getParameter("charset"); + + Reader source; + + if (charset == null) { + source = new InputStreamReader(stream); + } else { + source = new InputStreamReader(stream, charset); + } + + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + + docBuilderFactory.setNamespaceAware(true); + docBuilderFactory.setValidating(false); + try { + DocumentBuilder dataDocBuilder = docBuilderFactory.newDocumentBuilder(); + + domNode = dataDocBuilder.parse(new InputSource(source)); + } catch (ParserConfigurationException misconfig) { + throw new UndeclaredThrowableException(misconfig); + } catch (SAXException parseError) { + throw new IOException(parseError.toString()); + } + } + + /** + * Constructor for existing documents. + * + * @param mimeType This is the MIME Media Type being requested. In general + * it should be equivalent with the MIME Media Type returned by + * {@link #getMimeType()}. A StructuredDocument sub-class may, + * however, support more than one MIME Media type so this may be a + * true parameter. XMLDocument supports additional the MIME Media Type parameters, + * "charset". The charset parameter must be a value per IETF RFC 2279 or ISO-10646. + * @param source Contains the input used to construct this object. This reader + * should be of a type conformant with the type specified by the MIME Media Type + * "charset" parameter. + * @throws RuntimeException Propagates exceptions from the underlying implementation. + */ + private DOMXMLDocument(final MimeMediaType mimeType, final Reader source) throws IOException { + super(null, null); + this.root = this; + + this.mimeType = mimeType; + + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + + docBuilderFactory.setNamespaceAware(true); + docBuilderFactory.setValidating(false); + try { + DocumentBuilder dataDocBuilder = docBuilderFactory.newDocumentBuilder(); + + domNode = dataDocBuilder.parse(new InputSource(source)); + } catch (ParserConfigurationException misconfig) { + throw new UndeclaredThrowableException(misconfig); + } catch (SAXException parseError) { + throw new IOException(parseError.toString()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + try { + StringWriter stringOut = new StringWriter(); + + sendToWriter(stringOut); + stringOut.close(); + + return stringOut.toString(); + } catch (IOException ex) { + throw new UndeclaredThrowableException(ex); + } + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getMimeType() { + return mimeType; + } + + /** + * {@inheritDoc} + */ + public String getFileExtension() { + return Utils.getExtensionForMime(INSTANTIATOR.getSupportedFileExtensions(), getMimeType()); + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + String result = toString(); + + if (null == result) { + return null; + } + + String charset = mimeType.getParameter("charset"); + + if (charset == null) { + return new ByteArrayInputStream(result.getBytes()); + } else { + return new ByteArrayInputStream(result.getBytes(charset)); + } + } + + /** + * {@inheritDoc} + */ + public void sendToStream(OutputStream stream) throws IOException { + Writer osw; + String charset = mimeType.getParameter("charset"); + + if (charset == null) { + osw = new OutputStreamWriter(stream); + } else { + osw = new OutputStreamWriter(stream, charset); + } + + Writer out = new BufferedWriter(osw); + + sendToWriter(out); + out.flush(); + osw.flush(); + } + + /** + * {@inheritDoc} + */ + public Reader getReader() { + String result = toString(); + + if (null == result) { + return null; + } + + return new StringReader(result); + } + + /** + * {@inheritDoc} + */ + public void sendToWriter(Writer writer) throws IOException { + String charset = mimeType.getParameter("charset"); + + try { + DOMImplementationLS domImpl = (DOMImplementationLS) ((Document) domNode).getImplementation().getFeature("LS", "3.0"); + LSOutput output = domImpl.createLSOutput(); + + if (charset != null) { + output.setEncoding(charset); + } else { + output.setEncoding(java.nio.charset.Charset.defaultCharset().name()); + } + + output.setCharacterStream(writer); + + LSSerializer serial = domImpl.createLSSerializer(); + + serial.write(domNode, output); + } catch (Throwable ex) { + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } else if (ex instanceof Error) { + throw (Error) ex; + } else { + throw new UndeclaredThrowableException(ex); + } + } + } + + /** + * {@inheritDoc} + */ + public DOMXMLElement createElement(Object key) { + return createElement(key, null); + } + + /** + * {@inheritDoc} + */ + public DOMXMLElement createElement(Object key, Object val) { + if (!String.class.isAssignableFrom(key.getClass())) { + throw new ClassCastException(key.getClass().getName() + " not supported by createElement."); + } + + if ((null != val) && !String.class.isAssignableFrom(val.getClass())) { + throw new ClassCastException(val.getClass().getName() + " not supported by createElement."); + } + + return createElement((String) key, (String) val); + } + + // StructuredDocument Methods + + /** + * {@inheritDoc} + */ + public DOMXMLElement createElement(String name) { + return new DOMXMLElement(this, ((Document) domNode).createElement(name)); + } + + /** + * {@inheritDoc} + */ + public DOMXMLElement createElement(String name, String value) { + Element root; + + root = ((Document) domNode).createElement(name); + if (null != value) { + root.appendChild(((Document) domNode).createTextNode(value)); + } + return new DOMXMLElement(this, root); + } + + // Element Methods + + // Protected & Private Methods + + @Override + protected Node getAssocNode() { + return ((Document) domNode).getDocumentElement(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/DOMXMLElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/DOMXMLElement.java new file mode 100644 index 000000000..796eb0634 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/DOMXMLElement.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import net.jxta.document.Attribute; +import net.jxta.document.XMLElement; + +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + + +/** + * This class represent an element of an XML document. XML Documents are formed + * as a hierarchy of elements. Each element provides a proxy for DOM elements + * and the text nodes containing values. + */ +public class DOMXMLElement implements XMLElement { + + protected DOMXMLDocument root; + + /** + * The DOM node for which this element is a proxy. + */ + protected Node domNode; + + /** + * Constructor for associating a DOM node with a StructuredDocument Element. + * + * @param root the DOM not which is to be associated with this element. + * @param node the DOM node + */ + protected DOMXMLElement(DOMXMLDocument root, Node node) { + this.root = root; + domNode = node; + } + + /** + * Get the name associated with an element. + * + * @return A string containing the key of this element. + */ + public String getKey() { + return getName(); + } + + /** + * Get the value (if any) associated with an element. + * + * @return A string containing the value of this element, if any, otherwise null. + */ + public String getValue() { + return getTextValue(); + } + + /** + * Get the name associated with an element. + * + * @return A string containing the name of this element. + */ + public String getName() { + return getAssocNode().getNodeName(); + } + + /** + * Get the value (if any) associated with an element. + * + * @return A string containing the value of this element, if any, otherwise null. + */ + public String getTextValue() { + StringBuilder itsValue = new StringBuilder(); + + for (Node eachChild = getAssocNode().getFirstChild(); eachChild != null; eachChild = eachChild.getNextSibling()) { + if (Node.TEXT_NODE == eachChild.getNodeType()) { + itsValue.append(eachChild.getNodeValue()); + } + } + + if (0 == itsValue.length()) { + return null; + } else { + return itsValue.toString(); + } + } + + /** + * Get the root element of the hierarchy this element belongs to. + * + * @return StructuredDocument root of this element's hierarchy. + */ + public DOMXMLDocument getRoot() { + return root; + } + + /** + * Get the parent of this element. If the element has not been inserted into + * the Document then null is returned. If this element is the root of the + * Document then it returns itself. + */ + public DOMXMLElement getParent() { + Node node = getAssocNode(); + + if (node.getOwnerDocument().equals(node)) { + return new DOMXMLElement(root, node); + } else { + return new DOMXMLElement(root, node.getParentNode()); + } + } + + /** + * Add a child element to this element + * + * @param element the element to be added as a child + */ + public void appendChild(DOMXMLElement element) { + getAssocNode().appendChild(element.getAssocNode()); + } + + /** + * Returns an enumeration of the immediate children of this element + * + * @return An enumeration containing all of the children of this element. + */ + public Enumeration getChildren() { + List children = new ArrayList(); + + for (Node eachChild = getAssocNode().getFirstChild(); eachChild != null; eachChild = eachChild.getNextSibling()) { + if (Node.ELEMENT_NODE == eachChild.getNodeType()) { + children.add(new DOMXMLElement(root, eachChild)); + } + } + + return Collections.enumeration(children); + } + + /** + * Returns an enumeration of the immediate children of this element whose + * name match the specified string. + * + * @param key The key which will be matched against. + * @return enumeration containing all of the children of this element. + */ + public Enumeration getChildren(Object key) { + if (key instanceof String) + return getChildren((String) key); + else + throw new ClassCastException(key.getClass().getName() + " not supported by getChildren."); + } + + /** + * Returns an enumeration of the immediate children of this element whose + * name match the specified string. + * + * @param name The name which will be matched against. + * @return An enumeration containing all of the children of this element. + */ + public Enumeration getChildren(String name) { + List children = new ArrayList(); + + for (Node eachChild = getAssocNode().getFirstChild(); eachChild != null; eachChild = eachChild.getNextSibling()) { + if ((Node.ELEMENT_NODE == eachChild.getNodeType()) && (name.equals(eachChild.getNodeName()))) { + children.add(new DOMXMLElement(root, eachChild)); + } + } + + return Collections.enumeration(children); + } + + /** + * Tests two elements for equality. For the XML document the definition of + * equality is: + *

      + *

        + *
      • the item compared against must be an XML Element.
      • + *

        + *

      • The items must belong to the same document.
      • + *

        + *

      • The items must have the same name.
      • + *

        + *

      • The items must have the save textual value.
      • + *
      + * + * @param element the element to be compared against. + * @return true if the elements are equal + */ + @Override + public boolean equals(Object element) { + if (this == element) { + return true; + } + + if (!(element instanceof DOMXMLElement)) { + return false; + } + + DOMXMLElement xmlElement = (DOMXMLElement) element; + + Node me = getAssocNode(); + Node it = xmlElement.getAssocNode(); + + if (me == it) { + return true; + } + + if (me.getOwnerDocument() != it.getOwnerDocument()) { + return false; + } + + if (!getName().equals(xmlElement.getName())) { + return false; + } + + String val1 = getTextValue(); + String val2 = xmlElement.getTextValue(); + + return (null == val1) && (null == val2) || null != val1 && null != val2 && val1.equals(val2); + + } + + /** + * Returns the DOM Node associated with this StructuredDocument element. + * + * @return Node The DOM Node associated with this StructuredDocument element. + */ + protected Node getAssocNode() { + return domNode; + } + + // Attributable methods + + /** + * Adds an attribute with the given name and value. Some implementations + * may support only a single value for each distinct name. Others may + * support multiple values for each name. If the value being provided + * replaces some other value then that value is returned otherwise null + * is returned. + * + * @param name name of the attribute. + * @param value value for the attribute. + * @return String containing previous value for this name if the value + * is being replaced otherwise null. + */ + public String addAttribute(String name, String value) { + String oldAttrValue = ((Element) getAssocNode()).getAttribute(name); + + ((Element) getAssocNode()).setAttribute(name, value); + return (0 == oldAttrValue.length()) ? null : oldAttrValue; + } + + /** + * Adds an attribute with the given name and value. Some implementations + * may support only a single value for each distinct name. Others may + * support multiple values for each name. If the value being provided + * replaces some other value then that value is returned otherwise null + * is returned. + * + * @param newAttrib new attribute. + * @return String containing previous value for this name if the value + * is being replaced otherwise null. + */ + public String addAttribute(Attribute newAttrib) { + String oldAttrValue = ((Element) getAssocNode()).getAttribute(newAttrib.getName()); + + ((Element) getAssocNode()).setAttribute(newAttrib.getName(), newAttrib.getValue()); + return (0 == oldAttrValue.length()) ? null : oldAttrValue; + } + + /** + * Returns an enumerations of the attributes assosicated with this object. + * Each element is of type Attribute. + * + * @return Enumeration the attributes associated with this object. + */ + public Enumeration getAttributes() { + NamedNodeMap nmap = getAssocNode().getAttributes(); + + if (nmap == null) { + List noAttrs = Collections.emptyList(); + + return Collections.enumeration(noAttrs); + } + + List attrs = new ArrayList(); + + for (int i = 0; i < nmap.getLength(); i++) { + Node domAttr = nmap.item(i); + Attribute attr = new Attribute(this, domAttr.getNodeName(), domAttr.getNodeValue()); + + attrs.add(attr); + } + + return Collections.enumeration(attrs); + } + + /** + * returns a single attribute which matches the name provided. If no such + * named attribute exists then null is returned. For impelementations of + * this interface which support multiple values for each name only the + * first value will be returned. To access all values for a name you must + * use getAttributes. + * + * @return Attribute the attributes matching the given name. + */ + public Attribute getAttribute(String name) { + NamedNodeMap nmap = (getAssocNode()).getAttributes(); + + if (nmap == null) { + return null; + } + + for (int i = 0; i < nmap.getLength(); i++) { + Node domAttr = nmap.item(i); + + if (name.equals(domAttr.getNodeName())) { + Attribute attr = new Attribute(this, domAttr.getNodeName(), domAttr.getNodeValue()); + + return attr; + } + } + + return null; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/LiteXMLDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/LiteXMLDocument.java new file mode 100644 index 000000000..ba9116dc1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/LiteXMLDocument.java @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentFactory.Instantiator.ExtensionMapping; +import net.jxta.document.XMLDocument; +import net.jxta.impl.document.LiteXMLElement.charRange; +import net.jxta.impl.document.LiteXMLElement.tagRange; + + +/** + * This class is an implementation of the StructuredDocument interface using + * a simplified XML implementation. + */ +public class LiteXMLDocument extends LiteXMLElement implements XMLDocument { + + /** + * {@inheritDoc} + */ + private final static class Instantiator implements StructuredDocumentFactory.TextInstantiator { + + // "x-" is a mime-type convention for indicating partial or provisional + // compliance to a standard + private static final MimeMediaType[] myTypes = { + MimeMediaType.XML_DEFAULTENCODING, + MimeMediaType.valueOf("Text/x-Xml"), + MimeMediaType.valueOf("Application/Xml"), + MimeMediaType.valueOf("Application/x-Xml") + }; + + // these are the file extensions which are likely to contain files of + // the type I like. + private static final ExtensionMapping[] myExtensions = { + new ExtensionMapping("xml", myTypes[0]), + new ExtensionMapping("xml", (MimeMediaType) null) + }; + + /** + * Creates new LiteXMLDocumentInstantiator + */ + public Instantiator() {} + + /** + * {@inheritDoc} + */ + public MimeMediaType[] getSupportedMimeTypes() { + return (myTypes); + } + + /** + * {@inheritDoc} + */ + public ExtensionMapping[] getSupportedFileExtensions() { + return (myExtensions); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, String doctype) { + return new LiteXMLDocument(mimeType, doctype); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, String doctype, String value) { + return new LiteXMLDocument(mimeType, doctype, value); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, InputStream source) throws IOException { + return new LiteXMLDocument(mimeType, source); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, Reader source) throws IOException { + return new LiteXMLDocument(mimeType, source); + } + } + + /** + * The instantiator for instances of our documents. + */ + public static final StructuredDocumentFactory.TextInstantiator INSTANTIATOR = new Instantiator(); + + /** + * The actual document contents. + */ + final StringBuilder docContent; + + /** + * The mimetype of this document. + */ + private final MimeMediaType mimeType; + + /** + * Creates new LiteXMLDocument + */ + LiteXMLDocument(MimeMediaType mimeType, String type) { + this(mimeType, type, ""); + } + + /** + * Creates new LiteXMLDocument with a textValue in the root element + */ + LiteXMLDocument(MimeMediaType mimeType, String type, String textValue) { + super(null, (LiteXMLElement.tagRange) null); + + parent = this; + + this.mimeType = mimeType; + + docContent = new StringBuilder(); + + for (int eachChar = type.length() - 1; eachChar >= 0; eachChar--) { + if (Character.isWhitespace(type.charAt(eachChar))) { + throw new IllegalArgumentException("Root tag may not contain spaces"); + } + } + + if (null == textValue) { + textValue = ""; + } + + StringBuilder seedDoc = new StringBuilder(textValue.length() + 3 * type.length() + 128); + + seedDoc.append("\n"); + + seedDoc.append("\n"); + + seedDoc.append('<'); + seedDoc.append(type); + seedDoc.append('>'); + + seedDoc.append(textValue); + + seedDoc.append("'); + + try { + init(new StringReader(seedDoc.toString())); + } catch (IOException caught) { + throw new UndeclaredThrowableException(caught); + } + } + + /** + * Creates new LiteXMLDocument + */ + LiteXMLDocument(MimeMediaType mimeType, InputStream in) throws IOException { + super(null, (LiteXMLElement.tagRange) null); + + parent = this; + + this.mimeType = mimeType; + + docContent = new StringBuilder(); + + String charset = mimeType.getParameter("charset"); + + if (charset == null) { + init(new InputStreamReader(in)); + } else { + init(new InputStreamReader(in, charset)); + } + } + + /** + * Creates new LiteXMLDocument + */ + LiteXMLDocument(MimeMediaType mimeType, Reader in) throws IOException { + super(null, (LiteXMLElement.tagRange) null); + + parent = this; + + this.mimeType = mimeType; + + docContent = new StringBuilder(); + + init(in); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + + try { + StringWriter stringOut = new StringWriter(); + + sendToWriter(stringOut); + + stringOut.close(); + + return stringOut.toString(); + } catch (IOException caught) { + throw new UndeclaredThrowableException(caught); + } + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getMimeType() { + return mimeType; + } + + /** + * {@inheritDoc} + */ + public String getFileExtension() { + return TextDocumentCommon.Utils.getExtensionForMime(INSTANTIATOR.getSupportedFileExtensions(), getMimeType()); + } + + /** + * {@inheritDoc} + */ + public LiteXMLElement createElement(Object key) { + return createElement(key, null); + } + + /** + * {@inheritDoc} + */ + public LiteXMLElement createElement(Object key, Object val) { + if (!(key instanceof String)) { + throw new ClassCastException(key.getClass().getName() + " not supported by createElement as key."); + } + + if ((null != val) && !(val instanceof String)) { + throw new ClassCastException(val.getClass().getName() + " not supported by createElement as value."); + } + + return createElement((String) key, (String) val); + } + + /** + * {@inheritDoc} + */ + public LiteXMLElement createElement(String name) { + return createElement(name, (String) null); + } + + /** + * {@inheritDoc} + */ + public LiteXMLElement createElement(String name, String val) { + return new LiteXMLElement(this, name, val); + } + + /** + * Create a new text element as a sub-range of this document. + * + * @param loc The document range for the new element. + * @return The newly created element. + */ + protected LiteXMLElement createElement(tagRange loc) { + return new LiteXMLElement(this, loc); + } + + /** + * {@inheritDoc} + */ + public Reader getReader() { + return new StringReader(toString()); + } + + /** + * {@inheritDoc} + */ + @Override + public LiteXMLDocument getRoot() { + return this; + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + String charset = mimeType.getParameter("charset"); + + if (charset == null) { + return new ByteArrayInputStream(toString().getBytes()); + } else { + return new ByteArrayInputStream(toString().getBytes(charset)); + } + } + + /** + * {@inheritDoc} + */ + public void sendToWriter(Writer writer) throws IOException { + String charset = mimeType.getParameter("charset"); + + if (charset == null) { + writer.write("\n"); + } else { + writer.write("\n"); + } + + tagRange result = getDocType(docContent, true); + + if (result.isValid()) { + writer.write(docContent.substring(result.startTag.start, result.startTag.end + 1)); + writer.write('\n'); + } + + printNice(writer, 0, true); + } + + /** + * {@inheritDoc} + */ + public void sendToStream(OutputStream stream) throws IOException { + String charset = mimeType.getParameter("charset"); + + Writer osw; + + if (charset == null) { + osw = new OutputStreamWriter(stream); + } else { + osw = new OutputStreamWriter(stream, charset); + } + + Writer out = new BufferedWriter(osw); + + sendToWriter(out); + out.flush(); + } + + /** + * Initialises LiteXMLDocument. + */ + protected void init(Reader in) throws IOException { + loc = new tagRange(); + + char[] smallBuffer = new char[512]; + + do { + int readCount = in.read(smallBuffer); + + if (readCount < 0) { + break; + } + + if (readCount > 0) { + docContent.append(smallBuffer, 0, readCount); + } + + } while (true); + + // startTag will contain the xml declaration + loc.startTag.start = 0; + loc.startTag.end = docContent.indexOf(">"); + + // body is everything after the xml declaration + loc.body.start = loc.startTag.end + 1; + loc.body.end = docContent.length() - 1; + + // end is the end of the doc. + loc.endTag.start = loc.body.end; + loc.endTag.end = loc.body.end; + + tagRange docType = getDocType(getDocument().docContent, false); + + if (docType.isValid()) { + loc = getTagRanges(getDocument().docContent, docContent.substring(docType.body.start, docType.body.end + 1) + , + docType.endTag); + } else { + loc = getTagRanges(getDocument().docContent, null, loc.body); + } + + if (!loc.isValid()) { + throw new RuntimeException("Parsing error in source document."); + } + + if (!loc.startTag.equals(loc.endTag)) { + addChildTags(loc.body, this); // now add the subtags + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + } + + protected tagRange getDocType(final StringBuilder source, boolean wholeElement) { + final String xmldoctype = "!DOCTYPE"; + int start = 0; + int end = getDocument().docContent.length() - 1; + tagRange ranges = getTagRanges(source, xmldoctype, new charRange(start, end)); + + if (!ranges.startTag.isValid()) { + return ranges; + } + + // the rest of the document will be the "end" + ranges.endTag.start = ranges.body.start; + ranges.endTag.end = ranges.body.end; + + if (wholeElement) { + // this will be an empty element + ranges.body.start = ranges.startTag.end + 1; + ranges.body.end = ranges.endTag.start - 1; + } else { + ranges.body.start = ranges.startTag.start + 1 + xmldoctype.length() - 1 + 1; + ranges.startTag.end = ranges.body.start - 1; + + while ((ranges.body.start < end) && // immediately followed by a delimiter or the end of the tag + Character.isWhitespace(source.charAt(ranges.body.start))) { + ranges.body.start++; + } + + ranges.body.end = ranges.body.start; + + while ((ranges.body.end + 1) < end) { // immediately followed by a delimiter or the end of the tag + char possibleEnd = source.charAt(ranges.body.end + 1); + + if (Character.isWhitespace(possibleEnd) || ('/' == possibleEnd) || ('>' == possibleEnd)) { + break; + } + ranges.body.end++; + } + } + + return ranges; + } + + /** + * {@inheritDoc} + */ + @Override + LiteXMLDocument getDocument() { + return this; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/LiteXMLElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/LiteXMLElement.java new file mode 100644 index 000000000..01aa3c94f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/LiteXMLElement.java @@ -0,0 +1,1729 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import java.io.Writer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.IOException; + +import net.jxta.document.Attribute; +import net.jxta.document.XMLElement; +import net.jxta.logging.Logging; + + +/** + * An element of a StructuredDocument. StructuredDocuments + * are made up of hierarchies of elements. LiteXMLElement is part of an implementation + * while makes use of XML-style document conventions, but without the overhead of a + * full parser. + */ +public class LiteXMLElement implements XMLElement { + + /** + * Defines a range of characters, probably within a string. The range is + * deemed to be invalid if 'start' is -1. A zero length range is, by + * convention, described by an 'end' value of 'start' - 1. + */ + protected static class charRange implements Comparable { + + /** + * Contains the start position of this range. + */ + public int start; + + /** + * Contains the end position of this range. one weird thing: if end == start -1, + * then the item is of zero length beginning at start. + */ + public int end; + + /** + * Constructor for a null charRange. + */ + public charRange() { + start = -1; + end = -1; + } + + /** + * Constructor for which the bounds are specified. + */ + public charRange(int start, int end) { + this.start = start; + this.end = end; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object aRange) { + if (this == aRange) { + return true; + } + + if (!(aRange instanceof charRange)) { + return false; + } + + charRange someRange = (charRange) aRange; + + return (start == someRange.start) && (end == someRange.end); + } + + /** + * {@inheritDoc} + */ + public int compareTo(charRange someRange) { + if (this == someRange) { + return 0; + } + + if (start < someRange.start) { + return -1; + } + + if (start > someRange.start) { + return 1; + } + + if (end < someRange.end) { + return -1; + } + + if (end > someRange.end) { + return 1; + } + + return 0; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "[" + start + "," + end + "]"; + } + + /** + * Returns true if the charRange specified by someRange is + * contained within this range. + * + * @param someRange The range which must be contained within this range. + * @return true if the specified range is contained with this range otherwise false. + */ + public boolean contains(charRange someRange) { + return (isValid() && someRange.isValid() && (start <= someRange.start) && (end >= someRange.end)); + } + + /** + * Returns true if the tagRange specified by someRange is + * contained within this range. + * + * @param someRange The range which must be contained within this range. + * @return true if the specified range is contained with this range otherwise false. + */ + public boolean contains(tagRange someRange) { + return (isValid() && someRange.isValid() && (start <= someRange.startTag.start) && (end >= someRange.endTag.end)); + } + + /** + * Returns true if the location specified is contained in this range. + * + * @param someLoc the location which is to be tested. + * @return true if the location is in this range, otherwise false. + */ + public boolean contains(int someLoc) { + return (isValid() && (someLoc >= 0) && (start <= someLoc) && (end >= someLoc)); + } + + /** + * Returns true if the range is both non-null and has a length of greater + * than or equal to zero. + * + * @return true if the range is a valid one, otherwise false. + */ + public boolean isValid() { + return length() >= 0; + } + + /** + * Returns the length of this range. + * + * @return The length of the range or -1 if the range is null. + */ + public int length() { + if ((-1 == start) || (-1 == end)) { + return -1; + } + + return (end - start + 1); + } + } + + + /** + * A tagRange is a collection of char ranges useful for describing XML + * structures. + *

      + *

      + *
      startTag
      + *
      The range of the opening tag, ie. <tag>
      + *
      body
      + *
      Everything between startTag and endTag.
      + *
      endTag
      + *
      The range of the terminating tag, ie. </tag>.
      + *
      + *

      + *

      For empty-element tags the startTag, body + * and endTag will be equal. + */ + protected static class tagRange implements Comparable { + public charRange startTag; + public charRange body; + public charRange endTag; + + public tagRange() { + startTag = new charRange(); + body = new charRange(); + endTag = new charRange(); + } + + public tagRange(charRange startTag, charRange body, charRange endTag) { + this.startTag = startTag; + this.body = body; + this.endTag = endTag; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object aRange) { + if (this == aRange) { + return true; + } + + if (!(aRange instanceof tagRange)) { + return false; + } + + tagRange likeMe = (tagRange) aRange; + + return startTag.equals(likeMe.startTag) && body.equals(likeMe.body) && endTag.equals(likeMe.endTag); + } + + /** + * {@inheritDoc} + */ + public int compareTo(tagRange someRange) { + if (this == someRange) { + return 0; + } + + int compared = startTag.compareTo(someRange.startTag); + + if (0 != compared) { + return compared; + } + + return endTag.compareTo(someRange.endTag); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return startTag + ":" + body + ":" + endTag; + } + + /** + * Returns true if the tagRange specified by someRange is + * contained within the body portion of this range. + * + * @param someRange The range which must be contained within this range. + * @return true if the specified range is contained with this range + * otherwise false. + */ + public boolean contains(tagRange someRange) { + return (isValid() && someRange.isValid() && (body.start <= someRange.startTag.start) + && (body.end >= someRange.endTag.end)); + } + + /** + * Returns true if the charRange specified by someRange is + * contained within the body portion of this range. + * + * @param someRange The range which must be contained within this range. + * @return true if the specified range is contained with this range + * otherwise false. + */ + public boolean contains(charRange someRange) { + return (isValid() && someRange.isValid() && (body.start <= someRange.start) && (body.end >= someRange.end)); + } + + /** + * @return true if this tagRange represents and empty + * element. + */ + public boolean isEmptyElement() { + return isValid() && startTag.equals(body) && startTag.equals(endTag); + } + + /** + * @return true if valid + */ + public boolean isValid() { + return (null != startTag) && (null != body) && (null != endTag) && startTag.isValid() && body.isValid() + && endTag.isValid(); + } + } + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(LiteXMLElement.class.getName()); + + /** + * If true then every operation which modifies the state of the document will + * perform a consistency check. This is a deadly performance killer but + * helps a lot in isolating bugs. + */ + protected final static transient boolean paranoidConsistencyChecking = false; + + /** + * The document associated with this Element. + */ + protected final transient LiteXMLDocument doc; + + /** + * Identifies the element which is the parent of this element. If + * this.parent == this then this element is the root of the document. + * If null == parent then this element has not yet been + * inserted into the document. + */ + protected transient LiteXMLElement parent; + + /** + * The portion of the source XML associated with this node + */ + protected transient tagRange loc; + + /** + * If this node has yet to be inserted into the document then will contain + * the String value of this node, otherwise null. + */ + private transient StringBuilder uninserted = null; + + /** + * The child elements associated with this element + */ + private transient List children; + + /** + * Creates new LiteXMLElement + * + * @param loc The location of the element within the document. + * @param doc The {@link LiteXMLDocument} which is the root of the document. + */ + protected LiteXMLElement(LiteXMLDocument doc, tagRange loc) { + this.doc = doc; + this.loc = loc; + } + + /** + * Creates new LiteElement + * + * @param doc The {@link LiteXMLDocument} which is the root of the document. + * @param name The name of the element being created. + * @param val The value of the element being created or null if there is no + * content to the element. + */ + public LiteXMLElement(LiteXMLDocument doc, final String name, final String val) { + this(doc, new tagRange()); + + for (int eachChar = name.length() - 1; eachChar >= 0; eachChar--) { + if (Character.isWhitespace(name.charAt(eachChar))) { + throw new IllegalArgumentException("Element names may not contain spaces."); + } + } + + if ((null == val) || (0 == val.length())) { + uninserted = new StringBuilder("<" + name + "/>"); + } else { + uninserted = new StringBuilder(val); + encodeEscaped(uninserted); + uninserted.insert(0, "<" + name + ">"); + uninserted.append(""); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object element) { + if (this == element) { + return true; + } + + if (!(element instanceof LiteXMLElement)) { + return false; + } + + LiteXMLElement liteElement = (LiteXMLElement) element; + + if (getDocument() != liteElement.getDocument()) { + return false; + } + + if (!getName().equals(liteElement.getName())) { + return false; + } + + String val1; + + if (null != uninserted) { + val1 = uninserted.toString(); + } else { + val1 = getTextValue(); + } + + String val2 = liteElement.getTextValue(); + + if ((null == val1) && (null == val2)) { + return true; + } + + return null != val1 && null != val2 && val1.equals(val2); + + } + + /** + * {@inheritDoc} + *

      + *

      A toString implementation for debugging purposes. + */ + @Override + public String toString() { + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + String name = getName(); + + if (name == null) { + name = "<>"; + } + String value = getTextValue(); + + if (value == null) { + value = "<>"; + } + + if ((value.length() + name.length()) >= 60) { + int len = Math.max(20, 60 - name.length()); + + value = value.substring(0, Math.min(len, value.length())); + } + + // FIXME 20021125 bondolo@jxta.org should remove carriage control. + + return super.toString() + " / " + name + " = " + value; + } + + /** + * {@inheritDoc} + */ + public LiteXMLDocument getRoot() { + return getDocument(); + } + + /** + * {@inheritDoc} + */ + public LiteXMLElement getParent() { + return parent; + } + + /** + * {@inheritDoc} + */ + public Enumeration getChildren() { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (null == children) { + List empty = Collections.emptyList(); + + return Collections.enumeration(empty); + } else { + return Collections.enumeration(children); + } + } + + /** + * {@inheritDoc} + */ + public String getName() { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + int current = loc.startTag.start + 1; + + while (current <= loc.startTag.end) { + char inTagName = getDocument().docContent.charAt(current); + + if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { + break; + } + + current++; + } + + return getDocument().docContent.substring(loc.startTag.start + 1, current); + } + + /** + * Get the name associated with an element. + * + * @return A string containing the key of this element. + */ + public String getKey() { + return getName(); + } + + /** + * Get the value (if any) associated with an element. + * + * @return A string containing the value of this element, if any, otherwise null. + */ + public String getValue() { + return getTextValue(); + } + + /** + * {@inheritDoc} + */ + public void appendChild(LiteXMLElement element) { + if (element.getDocument() != getDocument()) { + throw new IllegalArgumentException("Wrong document"); + } + + if (null != element.parent) { + throw new IllegalArgumentException("New element is already in document"); + } + + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + // If uninserted then this new element contains content which needs to + // be added to the document. If uninserted is null then the child + // element's content is already in the document, but merely needs to + // be recognized as a child. + if (null != element.uninserted) { + if (loc.startTag.equals(loc.endTag)) { + getDocument().docContent.deleteCharAt(loc.endTag.end - 1); // delete the / + loc.startTag.end -= 1; + + // skip past the name portion + int current = loc.startTag.start + 1; + + while (current <= loc.startTag.end) { + char inTagName = getDocument().docContent.charAt(current); + + if (Character.isWhitespace(inTagName) || ('>' == inTagName)) { + break; + } + + current++; + } + + String tagName = getDocument().docContent.substring(loc.startTag.start + 1, current); + + getDocument().docContent.insert(loc.startTag.end + 1, ""); + getDocument().adjustLocations(loc.startTag.end + 1, tagName.length() + 2); + loc.endTag = new charRange(loc.startTag.end + 1, loc.startTag.end + 3 + tagName.length()); + loc.body = new charRange(loc.startTag.end + 1, loc.startTag.end); + } + + getDocument().docContent.insert(loc.endTag.start, element.uninserted); + + element.loc.startTag.start = loc.endTag.start; + element.loc.startTag.end = getDocument().docContent.indexOf(">", element.loc.startTag.start); + + if ('/' != element.uninserted.charAt(element.uninserted.length() - 2)) { + element.loc.body.start = element.loc.startTag.end + 1; + + element.loc.endTag.end = element.loc.startTag.start + element.uninserted.length() - 1; + element.loc.endTag.start = getDocument().docContent.lastIndexOf("<", element.loc.endTag.end); + + element.loc.body.end = element.loc.endTag.start - 1; + } else { + element.loc.body = new charRange(element.loc.startTag.start, element.loc.startTag.end); + element.loc.endTag = new charRange(element.loc.startTag.start, element.loc.startTag.end); + } + + if (0 != loc.body.length()) { + getDocument().adjustLocations(loc.endTag.start, element.uninserted.length()); + } else { + loc.body.start--; + getDocument().adjustLocations(loc.endTag.start, element.uninserted.length()); + loc.body.start++; + } + + loc.body.end += element.uninserted.length(); + + element.uninserted = null; + } + + element.parent = this; + + if (null == children) { + children = new ArrayList(); + } + + children.add(element); + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + } + + /** + * Returns an enumeration of the immediate children of this element whose + * name match the specified string. + * + * @param key The key which will be matched against. + * @return enumeration containing all of the children of this element. + */ + public Enumeration getChildren(Object key) { + if (key instanceof String) + return getChildren((String) key); + else + throw new ClassCastException(key.getClass().getName() + " not supported by getChildren."); + } + + /** + * {@inheritDoc} + */ + public Enumeration getChildren(String name) { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + if (null == children) { + List empty = Collections.emptyList(); + + return Collections.enumeration(empty); + } + + List result = new ArrayList(); + + for (LiteXMLElement aChild : children) { + if (name.equals(aChild.getName())) { + result.add(aChild); + } + } + + return Collections.enumeration(result); + } + + /** + * {@inheritDoc} + */ + public String getTextValue() { + return getTextValue(false, true); + } + + /** + * Get the value (if any) associated with an element. + * + * @param getEncoded if true then the contents will be encoded such that + * the contents will not be interpreted as XML. see + * {@link W3C XML 1.0 Specification} + * ie. < -> < & -> & + * @param trim if true trims prefix and suffix white space + * @return A string containing the value of this element, if any, otherwise null. + */ + protected String getTextValue(boolean getEncoded, boolean trim) { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + StringBuilder building = new StringBuilder(); + + List ranges = new ArrayList(); + + /* + * insert the ranges of the children in order. insertion method is ok + * because the number of children is usually less than 10 or so. + */ + for (Enumeration eachChild = getChildren(); eachChild.hasMoreElements();) { + LiteXMLElement aChild = eachChild.nextElement(); + charRange childsRange = new charRange(aChild.loc.startTag.start, aChild.loc.endTag.end); + + // find where to insert. + for (int eachRange = 0; eachRange < ranges.size(); eachRange++) { + charRange rangeChild = ranges.get(eachRange); + + if (1 == rangeChild.compareTo(childsRange)) { + ranges.set(eachRange, childsRange); + childsRange = rangeChild; + } + } + ranges.add(childsRange); + } + + int current = loc.body.start; + + // add all the text not part of some child + for (charRange aRange : ranges) { + building.append(getDocument().docContent.substring(current, aRange.start)); + + current = aRange.end + 1; + } + + // Add the last bit. + building.append(getDocument().docContent.substring(current, loc.endTag.start)); + + if (!getEncoded) { + building = decodeEscaped(building); + } + + // trim + int firstNonWhiteSpace = 0; + int lastNonWhiteSpace = building.length() - 1; + + if (trim) { + while (firstNonWhiteSpace < building.length()) { + char possibleSpace = building.charAt(firstNonWhiteSpace); + + if (!Character.isWhitespace(possibleSpace)) { + break; + } + + firstNonWhiteSpace++; + } + + // did we find no non-whitespace? + if (firstNonWhiteSpace >= building.length()) { + return null; + } + + while (lastNonWhiteSpace >= firstNonWhiteSpace) { + char possibleSpace = building.charAt(lastNonWhiteSpace); + + if (!Character.isWhitespace(possibleSpace)) { + break; + } + + lastNonWhiteSpace--; + } + } + + String result = building.substring(firstNonWhiteSpace, lastNonWhiteSpace + 1); + + return result; + } + + /** + * Write the contents of this element and optionally its children. The + * writing is done to a provided java.io.Writer. The writing + * can optionally be indented. + * + * @param into The java.io.Writer that the output will be sent to. + * @param indent the number of tabs which will be inserted before each + * line. + * @param recurse if true then also print the children of this element. + * @throws java.io.IOException if an io error occurs + */ + protected void printNice(Writer into, int indent, boolean recurse) throws IOException { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + // print start tag + StringBuilder start = new StringBuilder(); + + if (-1 != indent) { + // do indent + for (int eachTab = 0; eachTab < indent; eachTab++) { + start.append('\t'); + } + } + + start.append(getDocument().docContent.substring(loc.startTag.start, loc.startTag.end + 1)); + + if (-1 != indent) { + start.append('\n'); + } + + into.write(start.toString()); + + // print the rest if this was not an empty element. + if (!loc.startTag.equals(loc.endTag)) { + String itsValue = getTextValue(true, (-1 != indent)); + + // print node value + if (null != itsValue) { + if (-1 != indent) { + // do indent + for (int eachTab = 0; eachTab < indent + 1; eachTab++) { + into.write("\t"); + } + } + + into.write(itsValue); + + if (-1 != indent) { + into.write('\n'); + } + } + + // recurse as needed + if (recurse) { + int childIndent; + + Enumeration childrens = getChildren(); + + Attribute space = getAttribute("xml:space"); + + if (null != space) { + if ("preserve".equals(space.getValue())) { + childIndent = -1; + } else { + childIndent = indent + 1; + } + } else { + if (-1 != indent) { + childIndent = indent + 1; + } else { + childIndent = -1; + } + } + + while (childrens.hasMoreElements()) { + LiteXMLElement aChild = childrens.nextElement(); + + aChild.printNice(into, childIndent, recurse); + } + } + + // print end tag + StringBuilder end = new StringBuilder(); + + if (-1 != indent) { + // do indent + for (int eachTab = 0; eachTab < indent; eachTab++) { + end.append('\t'); + } + } + + end.append(getDocument().docContent.substring(loc.endTag.start, loc.endTag.end + 1)); + + if (-1 != indent) { + end.append('\n'); + } + + into.write(end.toString()); + } + } + + /** + * Given a source string, an optional tag and a range with in the source + * find either the tag specified or the next tag. + *

      + * The search consists of 4 phases : + * 0. If no tag was specified, determine if a tag can be found and + * learn its name. + * 1. Search for the start of the named tag. + * 2. Search for the end tag. Each time we think we have found a tag + * which might be the end tag we make sure it is not the end tag + * of another element with the same name as our tag. + * 3. Calculate the position of the body of the tag given the locations + * of the start and end. + * + * @param source the string to search + * @param tag the tag to search for in the source string. If this tag is + * empty or null then we will search for the next tag. + * @param range describes the range of character locations in the source + * string to which the search will be limited. + * @return tagRange containing the ranges of the found tag. + */ + + protected tagRange getTagRanges(final StringBuilder source, String tag, final charRange range) { + + // FIXME bondolo@jxta.org 20010327 Does not handle XML comments. ie. + if (null != uninserted) { + throw new IllegalStateException("This element has not been added to the document."); + } + + tagRange result = new tagRange(); + int start = range.start; + int end = source.length() - 1; + int current; + boolean foundStartTag = false; + boolean foundEndTag = false; + boolean emptyTag = (null == tag) || (0 == tag.length()); + + // check for bogosity + if ((-1 == start) || (start >= end)) { + throw new IllegalArgumentException("Illegal start value"); + } + + // adjust end of range + if ((-1 != range.end) && (end > range.end)) { + end = range.end; + } + + // check for empty tag and assign empty string + if (null == tag) { + tag = ""; + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Searching for \"" + tag + "\" in range [" + start + "," + end + "]"); + } + + current = start; + + // Begin Phase 0 : Search for any tag. + + if (emptyTag) { + int foundTagText = source.indexOf("<", current); + + // was it not found? if not then quit + if (-1 == foundTagText) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("No Tags Found"); + } + return result; + } + + // this part is about setting the tag if necessary + foundTagText++; + + int afterTagText = foundTagText; + + while (afterTagText <= end) { + char inTagName = source.charAt(afterTagText); + + if (!Character.isWhitespace(inTagName) && ('/' != inTagName) && ('>' != inTagName)) { + afterTagText++; + continue; + } + + tag = source.substring(foundTagText, afterTagText); + emptyTag = (null == tag) || (0 == tag.length()); + + break; + } + + // it better not be still empty + if (emptyTag) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("No tag found"); + } + return result; + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Search for \"" + tag + "\" [" + start + "," + end + "]"); + } + + // Begin Phase 1: Search for the Start Tag + + while (!foundStartTag && (current < end)) { + int foundTagText = source.indexOf(tag, current + 1); // first loc is one past current location + int foundTagTerminator; + int foundNextTagStart; + int afterTagText = foundTagText + tag.length(); + + // was it not found + if ((-1 == foundTagText) || (afterTagText > end)) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Tag \"" + tag + "\" Not Found(1)"); + } + return result; + } + + char checkChar = source.charAt(afterTagText); + + // check to see if it is the start tag + if (('<' != source.charAt(foundTagText - 1)) || // it has the open tag delimiter before it + (!Character.isWhitespace(checkChar) && ('/' != checkChar) && ('>' != checkChar))) { // is immediately followed by a delimiter + current = afterTagText; + continue; + } + + foundTagTerminator = source.indexOf(">", afterTagText); + foundNextTagStart = source.indexOf("<", afterTagText + 1); + + if ((-1 == foundTagTerminator) || // the tag has no terminator + (foundTagTerminator > end) || // it is past the valid range + ((-1 != foundNextTagStart) && // there is another tag start + (foundNextTagStart < foundTagTerminator))) { // and it is before the terminator we found. very bad + current = afterTagText; + continue; + } + + foundStartTag = true; + result.startTag.start = foundTagText - 1; + result.startTag.end = foundTagTerminator; + } + + if (!foundStartTag) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Tag \"" + tag + "\" Not Found(2)"); + } + return result; + } + + // is this an empty element declaration? + if ('/' == source.charAt(result.startTag.end - 1)) { + // end is the start and there is no body + result.body = new charRange(result.startTag.start, result.startTag.end); + result.endTag = new charRange(result.startTag.start, result.startTag.end); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Empty Element \"" + tag + "\" Start : " + result.startTag); + } + return result; + } + + current = result.startTag.end + 1; + + // if current is past the end then our end tag is not found. + if (current >= end) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("End not found \"" + tag + "\" Start : " + result.startTag); + } + return result; + } + + // Begin Phase 2 : Search for the end tag + + String endTag = ""; + int searchFrom = result.startTag.end + 1; + + while (!foundEndTag && (current < end) && (searchFrom < end)) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Searching for \"" + endTag + "\" in range [" + current + "," + end + "]"); + } + + int foundTagText = source.indexOf(endTag, current); + + // was it not found or not in bounds? + if ((-1 == foundTagText) || ((foundTagText + endTag.length() - 1) > end)) { + break; + } // it was not found + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Prospective tag pair for \"" + tag + "\" " + result.startTag + ":[" + foundTagText + "," + + (foundTagText + endTag.length() - 1) + "]"); + } + + // We recurse here in order to exclude the end tags of any sub elements with the same name + charRange subRange = new charRange(searchFrom, foundTagText - 1); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Recursing to search for \"" + tag + "\" in " + subRange); + } + + tagRange subElement = getTagRanges(source, tag, subRange); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Recursion result \"" + tag + "\" " + subElement); + } + + // if there was an incomplete sub-tag with the same name, skip past it + if (subElement.startTag.isValid()) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Found sub-tag \"" + tag + "\" at " + subElement + " within " + subRange); + } + + if (subElement.endTag.isValid()) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Complete sub-tag \"" + tag + "\" at " + subElement + " within " + subRange); + } + current = subElement.endTag.end + 1; + searchFrom = subElement.endTag.end + 1; + } else { + current = foundTagText + endTag.length(); + } + + continue; + } + + foundEndTag = true; + result.endTag.start = foundTagText; + result.endTag.end = foundTagText + endTag.length() - 1; + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Prospective tag \"" + tag + "\" " + result.endTag + " is confirmed."); + } + } + + // Begin Phase 3 : Calculate the location of the body. + + result.body.start = result.startTag.end + 1; + + if (foundEndTag) { + result.body.end = result.endTag.start - 1; + } else { + result.body.end = end; + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Found element : \"" + tag + "\" " + result); + } + + return result; + } + + /** + * Parse a charRange and add any tags found as content as children of a + * specified element. This process is repeated recursivly. + * + * @param scanRange the range to be parsed for sub-tags + * @param addTo the element to add any discovered children to. + */ + protected void addChildTags(final charRange scanRange, LiteXMLElement addTo) { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added to the document."); + } + + int current = scanRange.start; + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Scanning for children in range " + scanRange); + } + + do { + // scan for any tag. + tagRange aSubtag = getTagRanges(getDocument().docContent, null, new charRange(current, scanRange.end)); + + // did we find one? + if (aSubtag.isValid()) { + LiteXMLElement newChild = getDocument().createElement(aSubtag); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Adding child tag \"" + + getDocument().docContent.substring(aSubtag.endTag.start + 2, aSubtag.endTag.end) + "\" " + + aSubtag); + } + + addTo.appendChild(newChild); + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + if (!aSubtag.startTag.equals(aSubtag.endTag)) { + addChildTags(aSubtag.body, newChild); // recurse into the new tag + } + + // all done this tag, move on + current = aSubtag.endTag.end + 1; + } else { + current = -1; // all done! + } + } while ((-1 != current) && (current < scanRange.end)); + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + } + + /** + * For this element and all its children adjust the location of its ranges + * by the amount specified. + * + * @param beginningAt adjust all locations which are at or past this + * location. + * @param by amount to adjust all matching locations. + */ + protected void adjustLocations(final int beginningAt, final int by) { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + // Check that this element is not entirely to the left of the shift + // zone. NB: end can be < start if len is 0. + if (loc.endTag.end < beginningAt && loc.endTag.start < beginningAt) { + return; + } + + if ((loc.startTag.end >= beginningAt) + || ((loc.startTag.start >= beginningAt) && ((loc.startTag.end + 1) == loc.startTag.start))) { + loc.startTag.end += by; + } + + if (loc.startTag.start >= beginningAt) { + loc.startTag.start += by; + } + + if ((loc.body.end >= beginningAt) || ((loc.body.start >= beginningAt) && ((loc.body.end + 1) == loc.body.start))) { + loc.body.end += by; + } + + if (loc.body.start >= beginningAt) { + loc.body.start += by; + } + + if ((loc.endTag.end >= beginningAt) || ((loc.endTag.start >= beginningAt) && ((loc.endTag.end + 1) == loc.endTag.start))) { + loc.endTag.end += by; + } + + if (loc.endTag.start >= beginningAt) { + loc.endTag.start += by; + } + + for (Enumeration eachChild = getChildren(); eachChild.hasMoreElements();) { + LiteXMLElement aChild = eachChild.nextElement(); + + aChild.adjustLocations(beginningAt, by); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + } + + /** + * Given a StringBuilder find all occurrences of escaped characters which + * must be decoded and convert them back to their non-escaped equivalents. + *

      + *

      Also does end of line folding per: + * + * @param target The StringBuilder which will be decoded. + * @return The decoded version of the StringBuilder. + */ + protected StringBuilder decodeEscaped(StringBuilder target) { + + int current = 0; + + StringBuilder result = new StringBuilder(target.length()); + + while (current < target.length()) { + // FIXME bondolo@jxta.org 20010422 Should process xml comments out here. + + // fold 0x0D and 0x0D 0x0A to 0x0A + if ('\r' == target.charAt(current)) { + result.append('\n'); + current++; + if ((current < target.length()) && ('\n' == target.charAt(current))) { + current++; + } + continue; + } + + if ('&' != target.charAt(current)) { + result.append(target.charAt(current)); + current++; + continue; + } + + int terminusAt = current + 1; + + while ((terminusAt < target.length()) && // dont go past end + ((terminusAt - current) < 6) && // only look 6 chars away. + (';' != target.charAt(terminusAt))) { // must be a ; + terminusAt++; + } + + if ((terminusAt >= target.length()) || (';' != target.charAt(terminusAt))) { + // if we get here then we didnt find the terminal we needed + // so we just leave ampersand as it was, the document is + // ill-formed but why make things worse? + result.append(target.charAt(current)); + current++; + continue; + } + + char[] sub = new char[terminusAt - current + 1]; + + target.getChars(current, terminusAt + 1, sub, 0); + String escaped = new String(sub); + + if ("&".equals(escaped)) { + result.append('&'); + current += 4; + } else if ("<".equals(escaped)) { + result.append('<'); + current += 3; + } else if (">".equals(escaped)) { // for compatibility with SGML. We dont encode these + result.append('>'); + current += 3; + } else if (escaped.startsWith("&#")) { + String numericChar = escaped.substring(2, escaped.length() - 1); + + // is it &#; ? + if (numericChar.length() < 1) { + result.append(target.charAt(current)); + current++; + continue; + } + + // is it hex numeric + if (numericChar.charAt(0) == 'x') { + numericChar = numericChar.substring(1); + + // is it &#x; ? + if (numericChar.length() < 1) { + result.append(target.charAt(current)); + current++; + continue; + } + + try { + char asChar = (char) Integer.parseInt(numericChar.toLowerCase(), 16); + + result.append(asChar); + current += escaped.length(); + } catch (NumberFormatException badref) { + // it was bad, we will just skip it. + result.append(target.charAt(current)); + current++; + } + continue; + } + + // its base 10 + try { + char asChar = (char) Integer.parseInt(numericChar, 10); + + result.append(asChar); + current += escaped.length(); + } catch (NumberFormatException badref) { + // it was bad, we will just skip it. + result.append(target.charAt(current)); + current++; + } + continue; + } else { + // if we get here then we didn't know what to do with the + // entity. so we just send it unchanged. + result.append(target.charAt(current)); + current++; + continue; + } + + current++; + } + + return result; + } + + /** + * Given a StringBuilder find all occurrences of characters which must be + * escaped and convert them to their escaped equivalents. + * + * @param target The StringBuilder which will be encoded in place. + */ + protected void encodeEscaped(StringBuilder target) { + + int current = 0; + + while (current < target.length()) { + if ('&' == target.charAt(current)) { + target.insert(current + 1, "amp;"); + current += 5; + } else if ('<' == target.charAt(current)) { + target.setCharAt(current, '&'); + target.insert(current + 1, "lt;"); + current += 4; + } else { + current++; + } + } + } + + /** + * Returns an enumerations of the attributes associated with this object. + * Each element is of type Attribute. + * + * @return Enumeration the attributes associated with this object. + */ + public Enumeration getAttributes() { + List results = new ArrayList(); + + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + // find the start of the first attribute + int current = loc.startTag.start + 1; + + while (current <= loc.startTag.end) { + char inTagName = getDocument().docContent.charAt(current); + + if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { + break; + } + current++; + } + + // loop and add attributes to the vector + while (current < loc.startTag.end) { + tagRange nextAttr = getAttributeLoc(null, new charRange(current, loc.startTag.end)); + + if (!nextAttr.isValid()) { + break; + } + + results.add( + new Attribute(this, getDocument().docContent.substring(nextAttr.startTag.start, nextAttr.startTag.end + 1) + , + getDocument().docContent.substring(nextAttr.body.start, nextAttr.body.end + 1))); + + current = nextAttr.endTag.end + 1; + } + + return Collections.enumeration(results); + } + + /** + * Returns the tagRange of the next attribute contained in the range + * provided. The tag range returned consists of the startTag indicating + * the location of the name, body indicating the location of the value and + * endTag indicating the location of the final quote delimiter. + * + * @param name Name to match. null means match any name. + * @param inRange the limits of the locations to scan. + * @return tagRange containing the location of the next attribute + */ + protected tagRange getAttributeLoc(String name, charRange inRange) { + tagRange result = new tagRange(); + int current = inRange.start; + + do { + // skip the whitespace + + while (current <= inRange.end) { + char inTagName = getDocument().docContent.charAt(current); + + if (!Character.isWhitespace(inTagName) && ('/' != inTagName) && ('>' != inTagName)) { + break; + } + current++; + } + + int equalsAt = getDocument().docContent.indexOf("=", current); + + // make sure there is an equals + if ((-1 == equalsAt) || (equalsAt >= inRange.end)) { + return result; + } + + // get the name + result.startTag.start = current; + result.startTag.end = equalsAt - 1; + + // get the quote char we must match + String requiredQuote = getDocument().docContent.substring(equalsAt + 1, equalsAt + 2); + + // make sure its a valid quote + if (('\'' != requiredQuote.charAt(0)) && ('\"' != requiredQuote.charAt(0))) { + return result; + } + + // find the next occurance of this quote + int nextQuote = getDocument().docContent.indexOf(requiredQuote, equalsAt + 2); + + // make sure the quote is in a good spot. + if ((-1 == nextQuote) || (nextQuote >= inRange.end)) { + return result; + } + + result.body.start = equalsAt + 2; + result.body.end = nextQuote - 1; + + result.endTag.start = nextQuote; + result.endTag.end = nextQuote; + + // check if the name matches. + if ((null != name) && !name.equals(getDocument().docContent.substring(result.startTag.start, result.startTag.end + 1))) { + result.startTag.start = -1; + } + + current = nextQuote + 1; + } while ((current < inRange.end) && (!result.isValid())); + + return result; + } + + /** + * {@inheritDoc} + */ + public String addAttribute(String name, String value) { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (null == name) { + throw new IllegalArgumentException("name must not be null"); + } + + if (null == value) { + throw new IllegalArgumentException("value must not be null"); + } + + for (int eachChar = name.length() - 1; eachChar >= 0; eachChar--) { + if (Character.isWhitespace(name.charAt(eachChar))) { + throw new IllegalArgumentException("Attribute names may not contain spaces."); + } + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + // skip past the name portion + int current = loc.startTag.start + 1; + + while (current <= loc.startTag.end) { + char inTagName = getDocument().docContent.charAt(current); + + if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { + break; + } + + current++; + } + + // find out if there was a previous value for this name + String oldValue = null; + tagRange oldAttr = getAttributeLoc(name, new charRange(current, loc.startTag.end)); + + // choose which kind of quote to use + char usingQuote = (-1 != value.indexOf('"')) ? '\'' : '\"'; + + // make sure we can use it. + if (('\'' == usingQuote) && (-1 != value.indexOf('\''))) { + throw new IllegalArgumentException("Value contains both \" and \'"); + } + + // build the new attribute string + StringBuilder newStuff = new StringBuilder(" "); + + newStuff.append(name); + newStuff.append("="); + newStuff.append(usingQuote); + newStuff.append(value); + newStuff.append(usingQuote); + + // add it in. + if (!oldAttr.isValid()) { + // we aren't replacing an existing value + getDocument().docContent.insert(current, newStuff.toString()); + + // move all doc locations which follow this one based on how much we + // inserted. + getDocument().adjustLocations(current, newStuff.length()); + } else { + // we are replacing an existing value + oldValue = getDocument().docContent.substring(oldAttr.body.start, oldAttr.body.end + 1); + + getDocument().docContent.delete(oldAttr.body.start, oldAttr.body.end + 1); + getDocument().docContent.insert(oldAttr.body.start, value); + + int delta = value.length() - (oldAttr.body.end - oldAttr.body.start + 1); + + // move all doc locations which follow this one based on how much we + // inserted or deleted. + getDocument().adjustLocations(loc.startTag.start + 1, delta); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + return oldValue; + } + + /** + * {@inheritDoc} + */ + public String addAttribute(Attribute newAttrib) { + return addAttribute(newAttrib.getName(), newAttrib.getValue()); + } + + /** + * {@inheritDoc} + */ + public Attribute getAttribute(String name) { + if (null != uninserted) { + throw new IllegalStateException("This element has not been added."); + } + + if (paranoidConsistencyChecking) { + checkConsistency(); + } + + // skip past the name portion + int current = loc.startTag.start + 1; + + while (current <= loc.startTag.end) { + char inTagName = getDocument().docContent.charAt(current); + + if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { + break; + } + + current++; + } + + // find the attribute matching this name + tagRange attr = getAttributeLoc(name, new charRange(current, loc.startTag.end)); + + if (!attr.isValid()) { + return null; + } + + // build the object + return new Attribute(this, getDocument().docContent.substring(attr.startTag.start, attr.startTag.end + 1) + , + getDocument().docContent.substring(attr.body.start, attr.body.end + 1)); + } + + protected boolean checkConsistency() { + assert loc.isValid(); + + charRange elementRange = new charRange(loc.startTag.start, loc.endTag.end); + + assert elementRange.contains(loc.startTag); + assert elementRange.contains(loc.body); + assert elementRange.contains(loc.endTag); + + if (null != children) { + Iterator eachChild = children.iterator(); + Iterator nextChilds = children.iterator(); + + if (nextChilds.hasNext()) { + nextChilds.next(); + } + + while (eachChild.hasNext()) { + LiteXMLElement aChild = eachChild.next(); + + assert loc.contains(aChild.loc); + + if (nextChilds.hasNext()) { + LiteXMLElement nextChild = nextChilds.next(); + + assert aChild.loc.compareTo(nextChild.loc) < 0; + } else { + assert !eachChild.hasNext(); + } + + aChild.checkConsistency(); + } + } + return true; + } + + /** + * The document we are a part of. + * + * @return The document we are a part of. + */ + LiteXMLDocument getDocument() { + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/PlainTextDocument.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/PlainTextDocument.java new file mode 100644 index 000000000..4dc0f944b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/PlainTextDocument.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import java.io.IOException; +import java.security.ProviderException; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; +import net.jxta.document.TextDocument; + + +/** + * This class is an implementation of the StructuredDocument interface using + * simple text + */ +public class PlainTextDocument extends PlainTextElement implements StructuredTextDocument { + + private final static class Instantiator implements StructuredDocumentFactory.TextInstantiator { + + /** + * The MIME Media Types which this StructuredDocument is + * capable of emitting. + */ + private static final MimeMediaType[] myTypes = { + MimeMediaType.TEXT_DEFAULTENCODING + }; + + // these are the file extensions which are likely to contain files of + // the type i like. + private static final ExtensionMapping[] myExtensions = { + new ExtensionMapping("txt", myTypes[0]), new ExtensionMapping("text", myTypes[0]), new ExtensionMapping("txt", null) }; + + /** + * Creates new PlainTextDocument + */ + public Instantiator() {} + + /** + * {@inheritDoc} + */ + public MimeMediaType[] getSupportedMimeTypes() { + return (myTypes); + } + + /** + * {@inheritDoc} + */ + public ExtensionMapping[] getSupportedFileExtensions() { + return (myExtensions); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, String doctype) { + return new PlainTextDocument(mimeType, doctype); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, String doctype, String value) { + return new PlainTextDocument(mimeType, doctype, value); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, InputStream source) throws IOException { + throw new ProviderException("PlainTextDocument does not support input"); + } + + /** + * {@inheritDoc} + */ + public StructuredDocument newInstance(MimeMediaType mimeType, Reader source) throws IOException { + throw new ProviderException("PlainTextDocument does not support input"); + } + + } + + public static final StructuredDocumentFactory.TextInstantiator INSTANTIATOR = new Instantiator(); + + private MimeMediaType mimeType = null; + + /** + * Creates new PlainTextDocument + */ + public PlainTextDocument(final MimeMediaType mimeType, String type) { + super(null, type); + doc = this; + parent = this; + + this.mimeType = mimeType; + } + + /** + * Creates new PlainTextDocument with a value for the root element + */ + public PlainTextDocument(final MimeMediaType mimeType, final String type, final String value) { + super(null, type, value); + doc = this; + parent = this; + + this.mimeType = mimeType; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringWriter stringOut = new StringWriter(); + + try { + printNice(stringOut, 0, true); + stringOut.close(); + } catch (IOException caught) { + return null; + } + + return stringOut.toString(); + } + + /** + * get Type + */ + public MimeMediaType getMimeType() { + return mimeType; + } + + /** + * {@inheritDoc} + */ + public String getFileExtension() { + return TextDocumentCommon.Utils.getExtensionForMime(INSTANTIATOR.getSupportedFileExtensions(), getMimeType()); + } + + /** + * {@inheritDoc} + */ + public PlainTextElement createElement(Object key) { + return createElement(key, null); + } + + /** + * {@inheritDoc} + */ + public PlainTextElement createElement(Object key, Object val) { + if (!String.class.isAssignableFrom(key.getClass())) { + throw new ClassCastException(key.getClass().getName() + " not supported by createElement."); + } + + if ((null != val) && !String.class.isAssignableFrom(val.getClass())) { + throw new ClassCastException(val.getClass().getName() + " not supported by createElement."); + } + + return new PlainTextElement(this, (String) key, (String) val); + } + + /** + * {@inheritDoc} + */ + public PlainTextElement createElement(String name) { + return new PlainTextElement(this, name); + } + + /** + * {@inheritDoc} + */ + public PlainTextElement createElement(String name, String val) { + return new PlainTextElement(this, name, val); + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + // XXX bondolo@jxta.org 20010307 Should be using a pipe + String charset = mimeType.getParameter("charset"); + + if (charset == null) { + return new ByteArrayInputStream(toString().getBytes()); + } else { + return new ByteArrayInputStream(toString().getBytes(charset)); + } + } + + /** + * {@inheritDoc} + */ + public void sendToStream(OutputStream stream) throws IOException { + String charset = mimeType.getParameter("charset"); + + Writer osw; + + if (charset == null) { + osw = new OutputStreamWriter(stream); + } else { + osw = new OutputStreamWriter(stream, charset); + } + + Writer out = new BufferedWriter(osw); + + sendToWriter(out); + out.flush(); + } + + /** + * {@inheritDoc} + */ + public Reader getReader() { + // XXX bondolo@jxta.org 20010307 Should be using a pipe + + return new StringReader(toString()); + } + + /** + * {@inheritDoc} + */ + public void sendToWriter(Writer stream) throws IOException { + printNice(stream, 0, true); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/PlainTextElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/PlainTextElement.java new file mode 100644 index 000000000..af632e998 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/PlainTextElement.java @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import java.io.IOException; + +import net.jxta.document.Element; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; + +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; + + +/** + * This class is an implementation of the StructuredDocument interface using + * simple text + */ +public class PlainTextElement implements TextElement, Attributable { + protected PlainTextDocument doc; + + protected PlainTextElement parent; + + protected final String name; + + protected final String val; + + private List children = new Vector(); + + private Map attributes = new HashMap(); + + /** + * Creates new PlainTextElement + */ + protected PlainTextElement(PlainTextDocument doc, String name) { + this(doc, name, null); + } + + /** + * Creates new PlainTextElement + */ + protected PlainTextElement(PlainTextDocument doc, String name, String val) { + this.doc = doc; + this.name = name; + this.val = val; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object element) { + if (this == element) { + return true; + } + + if (!(element instanceof PlainTextElement)) { + return false; + } + + PlainTextElement textElement = (PlainTextElement) element; + + if (doc != textElement.doc) { + return false; + } + + if (!getName().equals(textElement.getName())) { + return false; + } + + String val1 = getTextValue(); + String val2 = textElement.getTextValue(); + + if ((null == val1) && (null == val2)) { + return true; + } + + if ((null == val1) || (null == val2)) { + return false; + } + + return val1.equals(val2); + } + + /** + * {@inheritDoc} + */ + public StructuredTextDocument getRoot() { + return (StructuredTextDocument) doc; + } + + /** + * Get the name associated with an element. + * + * @return A string containing the key of this element. + */ + public String getKey() { + return getName(); + } + + /** + * Get the value (if any) associated with an element. + * + * @return A string containing the value of this element, if any, otherwise null. + */ + public String getValue() { + return getTextValue(); + } + + /** + * {@inheritDoc} + */ + public PlainTextElement getParent() { + return parent; + } + + /** + * {@inheritDoc} + */ + public Enumeration getChildren() { + return Collections.enumeration(children); + } + + /** + * {@inheritDoc} + */ + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + public String getTextValue() { + return val; + } + + /** + * {@inheritDoc} + */ + public void appendChild(PlainTextElement element) { + if (element.doc != this.doc) { + throw new IllegalArgumentException("Wrong Document"); + } + + element.parent = this; + children.add(element); + } + + /** + * {@inheritDoc} + */ + public Enumeration getChildren(Object key) { + if (key instanceof String) + return getChildren((String) key); + else + throw new ClassCastException(key.getClass().getName() + " not supported by getChildren."); + } + + /** + * {@inheritDoc} + */ + public Enumeration getChildren(String name) { + List result = new ArrayList(); + + for (Iterator eachChild = children.iterator(); eachChild.hasNext();) { + TextElement aChild = (TextElement) eachChild.next(); + + if (name.equals(aChild.getName())) { + result.add(aChild); + } + } + + return Collections.enumeration(result); + } + + /** + * Write the contents of this element and optionally its children. The + * writing is done to a provided java.io.Writer. The writing can optionally + * be indented + * + * @param into The java.io.Writer that the output will be sent to. + * @param indent the number of tabs which will be inserted before each + * line. + * @param recurse if true then also print the children of this element. + */ + protected void printNice(Writer into, int indent, boolean recurse) throws IOException { + + // do indent + for (int eachTab = 0; eachTab < indent; eachTab++) { + into.write("\t"); + } + + // print node name + into.write(name); + + // print attributes + Enumeration attributes = getAttributes(); + + if (attributes.hasMoreElements()) { + into.write(" ( "); + + while (attributes.hasMoreElements()) { + Attribute anAttr = (Attribute) attributes.nextElement(); + + into.write(anAttr.getName() + "=\"" + anAttr.getValue() + "\" "); + } + into.write(")"); + } + + into.write(" : "); + // print node value + if (null != val) { + into.write(val + "\n"); + } else { + into.write("\n"); + } + + // recurse as needed + if (recurse) { + for (Enumeration childrens = getChildren(); childrens.hasMoreElements();) { + ((PlainTextElement) childrens.nextElement()).printNice(into, indent + 1, recurse); + } + } + } + + // Attributable methods + + /** + * {@inheritDoc} + */ + public String addAttribute(String name, String value) { + + String oldAttrValue = (String) attributes.remove(name); + + attributes.put(name, value); + + return oldAttrValue; + } + + /** + * Adds an attribute with the given name and value. Some implementations + * may support only a single value for each distinct name. Others may + * support multiple values for each name. If the value being provided + * replaces some other value then that value is returned otherwise null + * is returned. + * + * @param newAttrib new attribute. + * @return String containing previous value for this name if the value + * is being replaced otherwise null. + */ + public String addAttribute(Attribute newAttrib) { + return addAttribute(newAttrib.getName(), newAttrib.getValue()); + } + + /** + * {@inheritDoc} + */ + public Enumeration getAttributes() { + + Vector attrs = new Vector(); + + for (Iterator eachAttr = attributes.entrySet().iterator(); eachAttr.hasNext();) { + Map.Entry anAttr = (Map.Entry) eachAttr.next(); + + Attribute attr = new Attribute(this, (String) anAttr.getKey(), (String) anAttr.getValue()); + + attrs.addElement(attr); + } + + return attrs.elements(); + } + + /** + * {@inheritDoc} + */ + public Attribute getAttribute(String name) { + String value = (String) attributes.get(name); + + if (null == value) { + return null; + } + + // build the object + return new Attribute(this, name, value); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/TextDocumentCommon.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/TextDocumentCommon.java new file mode 100644 index 000000000..915de2e7e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/document/TextDocumentCommon.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.document; + + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; + + +/** + * Empty interface we use a container for utils + */ +interface TextDocumentCommon { + + /** + * static utility methods. + */ + static class Utils { + + static String getExtensionForMime(StructuredDocumentFactory.Instantiator.ExtensionMapping[] mappings, MimeMediaType mimeType) { + MimeMediaType cleanMime = new MimeMediaType(mimeType.getMimeMediaType()); + String result = "???"; + + for (int eachMapping = 0; eachMapping < mappings.length; eachMapping++) { + // assign the extension as the result if this is the default + if (null == mappings[eachMapping].getMimeMediaType()) { + result = mappings[eachMapping].getExtension(); + } + + if (mappings[eachMapping].getMimeMediaType().equals(cleanMime)) { + result = mappings[eachMapping].getExtension(); + break; + } + } + + return result; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/BlockingMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/BlockingMessenger.java new file mode 100644 index 000000000..a1daaf15d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/BlockingMessenger.java @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint; + +import java.util.Timer; +import java.util.TimerTask; + +import java.io.IOException; +import java.io.InterruptedIOException; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.endpoint.AbstractMessenger; +import net.jxta.endpoint.ChannelMessenger; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerState; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.util.SimpleSelectable; + +import net.jxta.impl.util.TimeUtils; + +/** + * This class is a near-drop-in replacement for the previous BlockingMessenger class. + * To subclassers (that is, currently, transports) the only difference is that some + * overloaded methods have a different name (class hierarchy reasons made it impossible + * to preserve the names without forcing an API change for applications). + * + * The other difference which is not API visible, is that it implements the + * standard MessengerState behaviour and semantics required by the changes in the endpoint framework. + * + * This the only base messenger class meant to be extended by outside code that is in the impl tree. The + * reason being that what it replaces was there already and that new code should not become dependant upon it. + */ +public abstract class BlockingMessenger extends AbstractMessenger { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(BlockingMessenger.class.getName()); + + /** + * The self destruct timer. + *

      + * When a messenger has become idle, it is closed. As a side effect, it + * makes the owning canonical messenger, if any, subject to removal if it is + * otherwise unreferenced. + */ + private final static transient Timer timer = new Timer("BlockingMessenger self destruct timer", true); + + /* + * Actions that we defer to after returning from event methods. In other + * words, they cannot be done with the lock held, or they require calling + * more event methods. Because this messenger can take only one message at + * a time (saturated while sending), actions do not cascade much. Start can + * lead to connect if the sending fails, but, because we always fail to + * connect, connect will not lead to start. As a result we can get away with + * performing deferred actions recursively. That simplifies the code. + */ + private enum DeferredAction { + /** + * No deferred action. + */ + ACTION_NONE, + + /** + * Must send message. + */ + ACTION_SEND, + + /** + * Must report failure to connect. + */ + ACTION_CONNECT + } + + /** + * The outstanding message. + */ + private Message currentMessage = null; + + /** + * The serviceName override for that message. + */ + private String currentService = null; + + /** + * The serviceParam override for that message. + */ + private String currentParam = null; + + /** + * The exception that caused that message to not be sent. + */ + private Throwable currentThrowable = null; + + /** + * true if we have deliberately closed our one message input queue. + */ + private boolean inputClosed = false; + + /** + * Need to know which group this transport lives in, so that we can suppress + * channel redirection when in the same group. This is currently the norm. + */ + private final PeerGroupID homeGroupID; + + /** + * The current deferred action. + */ + private DeferredAction deferredAction = DeferredAction.ACTION_NONE; + + /** + * Reference to owning object. This is there so that the owning object is not subject to garbage collection + * unless this object here becomes itself unreferenced. That happens when the self destruct timer closed it. + */ + private Object owner = null; + + /** + * The timer task watching over our self destruction requirement. + */ + private final TimerTask selfDestructTask; + + /** + * State lock and engine. + */ + private final BlockingMessengerState stateMachine = new BlockingMessengerState(); + + /** + * legacy artefact: transports need to believe the messenger is not yet closed in order to actually close it. + * So we lie to them just while we run their closeImpl method so that they do not see that the messenger is + * officially closed. + */ + private boolean lieToOldTransports = false; + + /** + * Our statemachine implementation; just connects the standard AbstractMessengerState action methods to + * this object. + */ + private class BlockingMessengerState extends MessengerState { + + protected BlockingMessengerState() { + super(true); + } + + /* + * The required action methods. + */ + + /** + * {@inheritDoc} + */ + @Override + protected void connectAction() { + deferredAction = DeferredAction.ACTION_CONNECT; + } + + /** + * {@inheritDoc} + */ + @Override + protected void startAction() { + deferredAction = DeferredAction.ACTION_SEND; + } + + /** + * {@inheritDoc} + */ + @Override + protected void closeInputAction() { + // we're synchonized here. (invoked from stateMachine). + inputClosed = true; + } + + /** + * {@inheritDoc} + */ + @Override + protected void closeOutputAction() { + // This will break the cnx; thereby causing a down event if we have a send in progress. + // If the cnx does not break before the current message is sent, then the message will be sent successfully, + // resulting in an idle event. Either of these events is enough to complete the shutdown process. + lieToOldTransports = true; + closeImpl(); + lieToOldTransports = false; + + // Disconnect from the timer. + if (selfDestructTask != null) { + selfDestructTask.cancel(); + } + } + + // This is a synchronous action. No synchronization needed: we're already synchronized, here. + // There's a subtlety here: we do not clear the current message. We let sendMessageB or sendMessageN + // deal with it, so that they can handle the status reporting each in their own way. So basically, all we + // do is to set a reason for that message to fail in case we are shutdown from the outside and that message + // is not sent yet. As long as there is a current message, it is guaranteed that there is a thread + // in charge of reporting its status. It is also guaranteed that when failAll is called, the input is + // already closed, and so, we have no obligation of making room for future messages immediately. + // All this aggravation is so that we do not have to create one context wrapper for each message just so + // that we can associate it with its result. Instead we use our single msg and single status model + // throughout. + @Override + protected void failAllAction() { + + if (currentMessage == null) { + return; + } + + if (currentThrowable == null) { + currentThrowable = new IOException("Messenger unexpectedly closed"); + } + } + } + + + /** + * The implementation of channel messenger that getChannelMessenger returns: + * All it does is address rewriting. Even close() is forwarded to the shared messenger. + * The reason is that BlockingMessengers are not really shared; they're transitional + * entities used directly by CanonicalMessenger. GetChannel is used only to provide address + * rewriting when we pass a blocking messenger directly to incoming messenger listeners...this + * practice is to be removed in the future, in favor of making incoming messengers full-featured + * async messengers that can be shared. + */ + private final class BlockingMessengerChannel extends ChannelMessenger { + + public BlockingMessengerChannel(EndpointAddress baseAddress, PeerGroupID redirection, String origService, String origServiceParam) { + + super(baseAddress, redirection, origService, origServiceParam); + + // We tell our super class that we synchronize on the stateMachine object. Althoug it is not obvious, our getState() + // method calls the shared messenger getState() method, which synchronizes on the shared messenger's state machine + // object. So, that's what we must specify. Logic would dictate that we pass it to super(), but it is not itself + // constructed until super() returns. No way around it. + + setStateLock(stateMachine); + } + + /** + * {@inheritDoc} + */ + public int getState() { + return BlockingMessenger.this.getState(); + } + + /** + * {@inheritDoc} + */ + public void resolve() { + BlockingMessenger.this.resolve(); + } + + /** + * {@inheritDoc} + */ + public void close() { + BlockingMessenger.this.close(); + } + + /** + * {@inheritDoc} + * + *

      + * Address rewriting done here. + */ + public boolean sendMessageN(Message msg, String service, String serviceParam) { + return BlockingMessenger.this.sendMessageN(msg, effectiveService(service), effectiveParam(service, serviceParam)); + } + + /** + * {@inheritDoc} + * + *

      + * Address rewriting done here. + */ + public void sendMessageB(Message msg, String service, String serviceParam) throws IOException { + BlockingMessenger.this.sendMessageB(msg, effectiveService(service), effectiveParam(service, serviceParam)); + } + + /** + * {@inheritDoc} + * + *

      + * We're supposed to return the complete destination, including + * service and param specific to that channel. It is not clear, whether + * this should include the cross-group mangling, though. For now, let's + * say it does not. + */ + public EndpointAddress getLogicalDestinationAddress() { + EndpointAddress rawLogical = getLogicalDestinationImpl(); + + if (rawLogical == null) { + return null; + } + return new EndpointAddress(rawLogical, origService, origServiceParam); + } + + // Check if it is worth staying registered + public void itemChanged(Object changedObject) { + + if (!notifyChange()) { + if (haveListeners()) { + return; + } + + BlockingMessenger.this.unregisterListener(this); + + if (!haveListeners()) { + return; + } + + // Ooops collision. We should not have unregistered. Next time, then. In case of collision, the end result + // is always to stay registered. There's no harm in staying registered. + BlockingMessenger.this.registerListener(this); + } + } + + /** + * {@inheritDoc} + *

      + * Always make sure we're registered with the shared messenger. + */ + @Override + protected void registerListener(SimpleSelectable l) { + BlockingMessenger.this.registerListener(this); + super.registerListener(l); + } + } + + private void storeCurrent(Message msg, String service, String param) { + currentMessage = msg; + currentService = service; + currentParam = param; + currentThrowable = null; + } + + /** + * Constructor. + *

      + * We start in the CONNECTED state, we pretend to have a queue of size 1, and we can never re-connect. Although this + * messenger fully respects the asynchronous semantics, it is saturated as soon as one msg is being send, and if not + * saturated, send is actually performed by the invoker thread. So return is not completely immediate. This is a barely + * acceptable implementation, but this is also a transition adapter that is bound to disappear one release from now. The main + * goal is to get things going until transports are adapted. + * + * @param homeGroupID the group that this messenger works for. This is the group of the endpoint service or transport + * that created this messenger. + * @param dest where messages should be addressed to + * @param selfDestruct true if this messenger must self close destruct when idle. Warning: If selfDestruct is used, + * this messenger will remained referenced for as long as isIdleImpl returns false. + */ + + public BlockingMessenger(PeerGroupID homeGroupID, EndpointAddress dest, boolean selfDestruct) { + + super(dest); + + this.homeGroupID = homeGroupID; + + // We tell our superclass that we synchronize our state on the stateMachine object. Logic would dictate that we pass it + // to super(), but it is not itself constructed until super() returns. No way around it. + + setStateLock(stateMachine); + + /* + * Sets up a timer task that will close this messenger if it says to have become idle. It will keep it referenced + * until then. + *

      + * As long as this timer task is scheduled, this messenger is not subject to GC. Therefore, its owner, if any, which is strongly + * referenced, is not subject to GC either. This avoids prematurely closing open connections just because a destination is + * not currently in use, which we would have to do if CanonicalMessengers could be GCed independantly (and which would + * force us to use finalizers, too).

      + * + * Such a mechanism is usefull only if this blocking messenger is expensive to make or holds system resources that require + * an explicit invocation of the close method. Else, it is better to let it be GC'ed along with any refering canonical + * messenger when memory is tight.

      + * + */ + + // + // FIXME 20040413 jice : we trust transports to implement isIdle reasonably, which may be a leap of faith. We + // should probably superimpose a time limit of our own. + // + if (selfDestruct) { + selfDestructTask = new TimerTask() { + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + if (isIdleImpl()) { + close(); + } else { + return; + } + } catch (Throwable uncaught) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in selfDescructTask. ", uncaught); + } + } + cancel(); + } + }; + + timer.schedule(selfDestructTask, TimeUtils.AMINUTE, TimeUtils.AMINUTE); + } else { + selfDestructTask = null; + } + } + + /** + * Sets an owner for this blocking messenger. Owners are normally canonical messengers. The goal of registering the owner is + * to keep that owner reachable as long as this blocking messenger is. Canonical messengers are otherwise softly referenced, + * and so, may be deleted whenever memory is tight. + *

      + * We do not want to use finalizers or the equivalent reference queue mechanism; so we have no idea when a blocking messenger + * is no-longer referenced by any canonical. In addition it may be expensive to make and so we want to keep it for a while + * anyway. As a result, instead of keeping a blocking messenger open as long as there is a canonical, we do the opposite: we + * keep the canonical (owner, here) as long as the blocking messenger is open (and usually beyond, memory allowing). How long + * a blocking messenger will stay around depends upon that messenger's implementation. That may even be left up to the GC, in + * the end (if close is not needed AND the messenger is cheap to make). In that case, the owner is likely the only referrer, + * and so both will have the same lifetime. + * + * @param owner The object that should be kept referenced at least as long as this one. + */ + public void setOwner(Object owner) { + this.owner = owner; + } + + /** + * Assemble a destination address for a message based upon the messenger + * default destination address and the optional provided overrides. + * + * @param service The destination service or {@code null} to use default. + * @param serviceParam The destination service parameter or {@code null} to + * use default. + */ + protected EndpointAddress getDestAddressToUse(String service, String serviceParam) { + EndpointAddress defaultAddress = getDestinationAddress(); + EndpointAddress result; + + if(null == service) { + if(null == serviceParam) { + // Use default service name and service params + result = defaultAddress; + } else { + // use default service name, override service params + result = new EndpointAddress(defaultAddress, defaultAddress.getServiceName(), serviceParam); + } + } else { + if(null == serviceParam) { + // override service name, use default service params (this one is pretty weird and probably not useful) + result = new EndpointAddress(defaultAddress, service, defaultAddress.getServiceParameter()); + } else { + // override service name, override service params + result = new EndpointAddress(defaultAddress, service, serviceParam); + } + } + + return result; + } + + /** + * A transport may call this to cause an orderly closure of its messengers. + */ + protected final void shutdown() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.shutdownEvent(); + action = eventCalled(); + } + + // We called an event. State may have changed. + notifyChange(); + + performDeferredAction(action); + } + + /** + * {@inheritDoc} + *

      + * We overload isClosed because many messengers still use super.isClosed() + * as part of their own implementation or don't override it at all. They + * expect it to be true only when all is shutdown; not while we're closing + * gently. + * + * FIXME - jice@jxta.org 20040413: transports should get a deeper retrofit eventually. + */ + @Override + public boolean isClosed() { + return (!lieToOldTransports) && super.isClosed(); + } + + /** + * {@inheritDoc} + *

      + * getLogicalDestinationAddress() requires resolution (it's the address advertised by the other end). + * For a blocking messenger it's easy. We're born resolved. So, just ask the implementor what it is. + */ + public final EndpointAddress getLogicalDestinationAddress() { + return getLogicalDestinationImpl(); + } + + /** + * {@inheritDoc} + * + *

      Some transports historically overload the close method of BlockingMessenger. + * The final is there to make sure we know about it. However, there should be no + * harm done if the unchanged code is renamed to closeImpl; even if it calls super.close(). + * The real problem, however, is transports calling close (was their own, but now it means this one), when + * they want to break. It will make things look like someone just called close, but it will not + * actually break anything. However, that will cause the state machine to go through the close process. + * this will end up calling closeImpl(). That will do. + */ + public final void close() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.closeEvent(); + + action = eventCalled(); + } + + // We called an event. State may have changed. + notifyChange(); + + performDeferredAction(action); + } + + /** + * {@inheritDoc} + */ + public void sendMessageB(Message msg, String service, String serviceParam) throws IOException { + + DeferredAction action; + + synchronized (stateMachine) { + try { + while ((currentMessage != null) && !inputClosed) { + stateMachine.wait(); + } + } catch (InterruptedException ie) { + throw new InterruptedIOException(); + } + + if (inputClosed) { + throw new IOException("Messenger is closed. It cannot be used to send messages"); + } + + // We store the four elements of a pending msg separately. We do not want to pour millions of tmp objects on the GC for + // nothing. + + storeCurrent(msg, service, serviceParam); + stateMachine.saturatedEvent(); + action = eventCalled(); + } + + notifyChange(); // We called an event. State may have changed. + performDeferredAction(action); // We called an event. There may be an action. (start, normally). + + // After deferred action, the message was either sent or failed. (done by this thread). + // We can tell because, if failed, the currentMessage is still our msg. + Throwable failure = null; + + synchronized (stateMachine) { + if (currentMessage == msg) { + failure = currentThrowable; + if (failure == null) { + failure = new IOException("Unknown error"); + } + // Ok, let it go, now. + storeCurrent(null, null, null); + } // Else, don't touch currentMsg; it's not our msg. + } + + if (failure == null) { + // No failure. Report ultimate succes. + msg.setMessageProperty(Messenger.class, OutgoingMessageEvent.SUCCESS); + return; + } + + // Failure. See how we can manage to throw it. + if (failure instanceof IOException) { + throw (IOException) failure; + } + if (failure instanceof RuntimeException) { + throw (RuntimeException) failure; + } + if (failure instanceof Error) { + throw (Error) failure; + } + + IOException failed = new IOException("Failure sending message"); + failed.initCause(failure); + throw failed; + } + + /** + * {@inheritDoc} + */ + public final boolean sendMessageN(Message msg, String service, String serviceParam) { + + boolean queued = false; + DeferredAction action = DeferredAction.ACTION_NONE; + boolean closed; + + synchronized (stateMachine) { + closed = inputClosed; + if ((!closed) && (currentMessage == null)) { + // We copy the four elements of a pending msg right here. We do not want to pour millions of tmp objects on the GC. + storeCurrent(msg, service, serviceParam); + stateMachine.saturatedEvent(); + action = eventCalled(); + queued = true; + } + } + + if (queued) { + notifyChange(); // We called an event. State may have changed. + performDeferredAction(action); // We called an event. There may be an action. (start, normally). + + // After deferred action, the message was either sent or failed. (done by this thread). + // We can tell because, if failed, the currentMessage is still our msg. + synchronized (stateMachine) { + if (currentMessage == msg) { + if (currentThrowable == null) { + currentThrowable = new IOException("Unknown error"); + } + msg.setMessageProperty(Message.class, currentThrowable); + // Ok, let it go, now. + storeCurrent(null, null, null); + } else { + msg.setMessageProperty(Message.class, OutgoingMessageEvent.SUCCESS); + // Don't touch the current msg; it's not our msg. + } + } + // Yes, we return true in either case. sendMessageN is supposed to be async. If a message fails + // after it was successfuly queued, the error is not reported by the return value, but only by + // the message property (and select). Just making sure the behaviour is as normal as can be + // even it means suppressing some information. + + return true; + } + + // Not queued. Either closed, or currently sending. If inputClosed, that's what we report. + msg.setMessageProperty(Messenger.class, + closed ? + new OutgoingMessageEvent(msg, new IOException("This messenger is closed. " + "It cannot be used to send messages.")) : + OutgoingMessageEvent.OVERFLOW); + return false; + } + + /** + * {@inheritDoc} + */ + public final void resolve() {// We're born resolved. Don't bother calling the event. + } + + /** + * {@inheritDoc} + */ + public final int getState() { + return stateMachine.getState(); + } + + /** + * {@inheritDoc} + */ + public final Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam) { + + // Our transport is always in the same group. If the channel's target group is the same, no group + // redirection is ever needed. + + return new BlockingMessengerChannel(getDestinationAddress(), + homeGroupID.equals(redirection) ? null : redirection, service, + serviceParam); + } + + /** + * Three exposed methods may need to inject new events in the system: sendMessageN, close, and shutdown. Since they can both + * cause actions, and since connectAction and startAction are deferred, it seems possible that one of the + * actions caused by send, close, or shutdown be called while connectAction or startAction are in progress. + * + * However, the state machine gives us a few guarantees: connectAction and startAction can never nest. We will not be + * asked to perform one while still performing the other. Only the synchronous actions closeInput, closeOutput, or + * failAll can possibly be requested in the interval. We could make more assumptions and simplify the code, but rather + * keep at least some flexibility. + */ + + private void performDeferredAction(DeferredAction action) { + switch (action) { + case ACTION_SEND: + sendIt(); + break; + + case ACTION_CONNECT: + cantConnect(); + break; + } + } + + /** + * A shortHand for a frequently used sequence. MUST be called while synchronized on stateMachine. + * + * @return the deferred action. + */ + private DeferredAction eventCalled() { + DeferredAction action = deferredAction; + + deferredAction = DeferredAction.ACTION_NONE; + stateMachine.notifyAll(); + return action; + } + + /** + * Performs the ACTION_SEND deferred action: sends the one msg in our one msg queue. + * This method *never* sets the outcome message property. This is left to sendMessageN and sendMessageB, because + * sendMessageB does not want to set it in any other case than success, while sendMessageN does it in all cases. + * The problem with that is: how do we communicate the outcome to sendMessage{NB} without having to keep + * the 1 msg queue locked until then (which would be in contradiction with how we interact with the state machine). + * To make it really inexpensive, here's the trick: when a message fails currentMessage and currentFailure remain. + * So the sendMessageRoutine can check them and known that it is its message and not another one that caused the + * failure. If all is well, currentMessage and currentFailure are nulled and if another message is send immediately + * sendMessage is able to see that its own message was processed fully. (this is a small cheat regarding the + * state of saturation after failall, but that's not actually detectable from the outside: input is closed + * before failall anyway. See failall for that part. + */ + private void sendIt() { + + if (currentMessage == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Internal error. Asked to send with no message."); + } + return; + } + + DeferredAction action; + + try { + sendMessageBImpl(currentMessage, currentService, currentParam); + } catch (Throwable any) { + // Did not work. We report the link down and let the state machine tell us when to fail the msg. It is assumed that + // when this happens, the cnx is already down. FIXME - jice@jxta.org 20040413: check with the various kind of funky + // exception. Some may not mean the link is down + synchronized (stateMachine) { + currentThrowable = any; + stateMachine.downEvent(); + action = eventCalled(); + } + notifyChange(); + performDeferredAction(action); // we expect connect but let the state machine decide. + return; + } + + // Worked. + + synchronized (stateMachine) { + storeCurrent(null, null, null); + stateMachine.idleEvent(); + action = eventCalled(); + } + + // We did go from non-idle to idle. Report it. + notifyChange(); + + performDeferredAction(action); // should be none but let the state machine decide. + } + + /** + * Performs the ACTION_CONNECT deferred action: generate a downEvent since we cannot reconnect. + */ + private void cantConnect() { + DeferredAction action; + + synchronized (stateMachine) { + stateMachine.downEvent(); + action = eventCalled(); + } + notifyChange(); + performDeferredAction(action); // should be none but let the state machine decide. + } + + /* + * Abstract methods to be provided by implementer (a transport for example). + * To adapt legacy transport, keep extending BlockingMessenger and just rename your close, isIdle, sendMessage and + * getLogicalDestinationAddress methods to closeImpl, isIdleImpl, sendMessageBImpl, and getLogicalDestinationImpl, respectively. + */ + + /** + * Close connection. May fail current send. + */ + protected abstract void closeImpl(); + + /** + * Send a message blocking as needed until the message is sent. + * + * @param message The message to send. + * @param service The destination service. + * @param param The destination serivce param. + * @throws IOException Thrown for errors encountered while sending the message. + */ + protected abstract void sendMessageBImpl(Message message, String service, String param) throws IOException; + + /** + * return true if this messenger has not been used for a long time. The definition of long time is: "sufficient such that closing it + * is worth the cost of having to re-open". A messenger should self close if it thinks it meets the definition of + * idle. BlockingMessenger leaves the evaluation to the transport but does the work automatically. Important: if + * self destruction is used, this method must work; not just return false. See the constructor. In general, if closeImpl does + * not need to do anything, then self destruction is not needed. + * + * @return {@code true} if theis messenger is, by it's own definition, idle. + */ + protected abstract boolean isIdleImpl(); + + /** + * Obtain the logical destination address from the implementer (a transport for example). + */ + protected abstract EndpointAddress getLogicalDestinationImpl(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointServiceImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointServiceImpl.java new file mode 100644 index 000000000..d3db1125a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointServiceImpl.java @@ -0,0 +1,1961 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.ChannelMessenger; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessageFilterListener; +import net.jxta.endpoint.MessagePropagater; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.MessageTransport; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerEvent; +import net.jxta.endpoint.MessengerEventListener; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.ThreadedMessenger; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.impl.endpoint.endpointMeter.EndpointMeter; +import net.jxta.impl.endpoint.endpointMeter.EndpointMeterBuildSettings; +import net.jxta.impl.endpoint.endpointMeter.EndpointServiceMonitor; +import net.jxta.impl.endpoint.endpointMeter.InboundMeter; +import net.jxta.impl.endpoint.endpointMeter.OutboundMeter; +import net.jxta.impl.endpoint.endpointMeter.PropagationMeter; +import net.jxta.impl.endpoint.relay.RelayClient; +import net.jxta.impl.endpoint.router.EndpointRouter; +import net.jxta.impl.endpoint.tcp.TcpTransport; +import net.jxta.impl.meter.MonitorManager; +import net.jxta.impl.util.SequenceIterator; +import net.jxta.logging.Logging; +import net.jxta.meter.MonitorResources; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements the frontend for all the JXTA endpoint protocols, as + * well as the API for the implementation of the core protocols that use + * directly the EndpointService. It theory it only needs to implement core methods. + * legacy or convenience methods should stay out. However, that would require + * a two-level interface for the service (internal and public). May be later. + */ +public class EndpointServiceImpl implements EndpointService, MessengerEventListener { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(EndpointServiceImpl.class.getName()); + + // // constants //// + + /** + * The Wire Message Format we will use by default. + */ + public static final MimeMediaType DEFAULT_MESSAGE_TYPE = new MimeMediaType("application/x-jxta-msg").intern(); + + /** + * The name of this service. + */ + public static final String ENDPOINTSERVICE_NAME = "EndpointService"; + + /** + * The Message empty namespace. This namespace is reserved for use by + * applications. It will not be used by core protocols. + */ + public static final String MESSAGE_EMPTY_NS = ""; + + /** + * The Message "jxta" namespace. This namespace is reserved for use by + * core protocols. It will not be used by applications. + */ + public static final String MESSAGE_JXTA_NS = "jxta"; + + /** + * Namespace in which the message source address will be placed. + */ + public static final String MESSAGE_SOURCE_NS = MESSAGE_JXTA_NS; + + /** + * Element name in which the message source address will be placed. + */ + public static final String MESSAGE_SOURCE_NAME = "EndpointSourceAddress"; + + /** + * Namespace in which the message destination address will be placed. + */ + public static final String MESSAGE_DESTINATION_NS = MESSAGE_JXTA_NS; + + /** + * Element name in which the message destination address will be placed. + * This element is used for loopback detection during propagate. Only + * propagate messages currently contain this element. + */ + public static final String MESSAGE_DESTINATION_NAME = "EndpointDestinationAddress"; + + /** + * Namespace in which the message source peer address will be placed. + */ + public static final String MESSAGE_SRCPEERHDR_NS = MESSAGE_JXTA_NS; + + /** + * Element name in which the message source peer address will be placed. + * This element is used for loopback detection during propagate. Only + * propagated messages currently contain this element. + */ + public static final String MESSAGE_SRCPEERHDR_NAME = "EndpointHeaderSrcPeer"; + + /** + * Size of the message queue provided by virtual messengers. + */ + private final static int DEFAULT_MESSAGE_QUEUE_SIZE = 20; + + /** + * If {@code true} then the parent endpoint may be used for acquiring + * messengers and for registering listeners. + */ + private final static boolean DEFAULT_USE_PARENT_ENDPOINT = true; + + EndpointServiceMonitor endpointServiceMonitor; + + /** + * the EndpointMeter + */ + private EndpointMeter endpointMeter; + private PropagationMeter propagationMeter; + + /** + * If {@code true} then this service has been initialized. + */ + private boolean initialized = false; + + /** + * tunable: the virtual messenger queue size + */ + private int vmQueueSize = DEFAULT_MESSAGE_QUEUE_SIZE; + + private PeerGroup group = null; + private ID assignedID = null; + private ModuleImplAdvertisement implAdvertisement = null; + + private String localPeerId = null; + private boolean useParentEndpoint = DEFAULT_USE_PARENT_ENDPOINT; + private EndpointService parentEndpoint = null; + private String myServiceName = null; + + /** + * The Message Transports which are registered for this endpoint. This is + * only the message transport registered locally, it does not include + * transports which are used from other groups. + */ + private final Collection messageTransports = new HashSet(); + + /** + * Passive listeners for messengers. Three priorities, so far. + */ + private final Collection[] passiveMessengerListeners = { + Collections.synchronizedList(new ArrayList()), + Collections.synchronizedList(new ArrayList()), + Collections.synchronizedList(new ArrayList()) + }; + + /** + * The set of listener managed by this instance of the endpoint svc. + */ + private final Map incomingMessageListeners = new HashMap(16); + + /** + * The set of shared transport messengers currently ready for use. + */ + private final Map> messengerMap = new WeakHashMap>(32); + /** + * The set of shared transport messengers currently ready for use. + */ + private final Map> directMessengerMap = new WeakHashMap>(32); + + /** + * The filter listeners. + *

      + * We rarely add/remove, never remove without iterating + * and insert objects that are always unique. So using a set + * does not make sense. An array list is the best. + */ + private final Collection incomingFilterListeners = new ArrayList(); + private final Collection outgoingFilterListeners = new ArrayList(); + + /** + * Holder for a filter listener and its conditions + */ + private static class FilterListenerAndMask { + final String namespace; + final String name; + final MessageFilterListener listener; + + public FilterListenerAndMask(MessageFilterListener listener, String namespace, String name) { + this.namespace = namespace; + this.name = name; + this.listener = listener; + } + + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof FilterListenerAndMask) { + FilterListenerAndMask likeMe = (FilterListenerAndMask) target; + + boolean result = (null != namespace) ? (namespace.equals(likeMe.namespace)) : (null == likeMe.namespace); + + result &= (null != name) ? (name.equals(likeMe.name)) : (null == likeMe.name); + result &= (listener == likeMe.listener); + + return result; + } + + return false; + } + + /** + * {@inheritDoc} + *

      + * Added to make PMD shut up.... + */ + @Override + public int hashCode() { + return System.identityHashCode(this); + } + } + + + /** + * A non blocking messenger that obtains a backing (possibly blocking) + * messenger on-demand. + */ + private class CanonicalMessenger extends ThreadedMessenger { + + /** + * If the hint was not used because there already was a transport + * messenger available, then it is saved here for the next time we are + * forced to create a new transport messenger by the breakage of the one + * that's here. + *

      + * The management of hints is a bit inconsistent for now: the hint + * used may be different dependent upon which invocation created the + * current canonical messenger and, although we try to use the hint only + * once (to avoid carrying an invalid hint forever) it may happen that a + * hint is used long after it was suggested. + */ + Object hint; + + /** + * The transport messenger that this canonical messenger currently uses. + */ + Messenger cachedMessenger = null; + + /** + * Create a new CanonicalMessenger. + * + * @param vmQueueSize queue size + * @param destination destination who messages should be addressed to + * @param logicalDestination logical destination + * @param hint route hint + * @param messengerMeter the metering object if any + */ + public CanonicalMessenger(int vmQueueSize, EndpointAddress destination, EndpointAddress logicalDestination, Object hint, OutboundMeter messengerMeter) { + super(group.getPeerGroupID(), destination, logicalDestination, vmQueueSize); + this.hint = hint; + } + + /** + * close this canonical messenger. + */ + @Override + public void close() { + // No way. Not form the outside. + } + + /** + * Drop the current messenger. + */ + @Override + protected void closeImpl() { + if (cachedMessenger != null) { + cachedMessenger.close(); + cachedMessenger = null; + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Internal messenger error: close requested while not connected."); + } + } + } + + /** + * Get a transport messenger to the destination. + *

      + * FIXME 20040413 jice : Do better hint management. + */ + @Override + protected boolean connectImpl() { + if (cachedMessenger != null) { + if ((cachedMessenger.getState() & Messenger.TERMINAL) != 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.SEVERE)) { + LOG.fine("Closing TERMINAL internal messenger : attempting requested connect."); + } + cachedMessenger.close(); + cachedMessenger = null; + } else { + return true; + } + } + + // Consume the hint, if any. + Object theHint = hint; + + hint = null; + cachedMessenger = getLocalTransportMessenger(getDestinationAddress(), theHint); + + if (cachedMessenger == null) { + return false; + } + + // FIXME 20040413 jice : it's not too clean: we assume + // that all transports use BlockingMessenger as the base class for + // their messengers. If they don't we can't force them to hold the + // strong reference to the canonical messenger. + try { + ((BlockingMessenger) cachedMessenger).setOwner(this); + } catch (ClassCastException cce) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport messengers must all extend BlockingMessenger for now. " + + cachedMessenger + " may remain open beyond its use."); + } + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + protected EndpointAddress getLogicalDestinationImpl() { + if (cachedMessenger == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Internal messenger error: logical destination requested while not connected."); + } + return null; + } + return cachedMessenger.getLogicalDestinationAddress(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void sendMessageBImpl(Message msg, String service, String param) throws IOException { + if (cachedMessenger == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Internal messenger error: send requested while not connected."); + } + throw new IOException("Internal messenger error."); + } + + try { + cachedMessenger.sendMessageB(msg, service, param); + } catch (IOException any) { + cachedMessenger = null; + throw any; + } catch (RuntimeException any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure sending " + msg, any); + } + + throw any; + } + } + } + + /** + * Create a new EndpointService. + */ + public EndpointServiceImpl() { + } + + /** + * {@inheritDoc} + */ + public synchronized void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + if (initialized) { + throw new PeerGroupException("Cannot initialize service more than once"); + } + + this.group = group; + // The selector for the element of the peer adv params that we have to update. + this.assignedID = assignedID; + this.implAdvertisement = (ModuleImplAdvertisement) impl; + + this.localPeerId = group.getPeerID().toString(); + + this.myServiceName = ChannelMessenger.InsertedServicePrefix + group.getPeerGroupID().getUniqueValue().toString(); + + ConfigParams confAdv = group.getConfigAdvertisement(); + XMLElement paramBlock = null; + + if (confAdv != null) { + paramBlock = (XMLElement) confAdv.getServiceParam(assignedID); + } + + if (paramBlock != null) { + // get our two tunables: virtual messenger queue size, and whether to use the parent endpoint + Enumeration param; + + param = paramBlock.getChildren("MessengerQueueSize"); + if (param.hasMoreElements()) { + String textQSz = ((XMLElement) param.nextElement()).getTextValue(); + + try { + Integer requestedSize = Integer.parseInt(textQSz.trim()); + + if (requestedSize > 0) { + vmQueueSize = requestedSize; + } else { + LOG.warning("Illegal MessengerQueueSize : " + textQSz); + } + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not parse MessengerQueueSize string", e); + } + } + } + + param = paramBlock.getChildren("UseParentEndpoint"); + if (param.hasMoreElements()) { + String textUPE = ((XMLElement) param.nextElement()).getTextValue(); + + useParentEndpoint = textUPE.trim().equalsIgnoreCase("true"); + } + + } + + PeerGroup parentGroup = group.getParentGroup(); + + if (useParentEndpoint && parentGroup != null) { + parentEndpoint = parentGroup.getEndpointService(); + parentEndpoint.addMessengerEventListener(this, EndpointService.LowPrecedence); + } + + initialized = true; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Endpoint Service : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: "); + configInfo.append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + if (null == parentGroup) { + configInfo.append("\n\t\tHome Group : (none)"); + } else { + configInfo.append("\n\t\tHome Group : ").append(parentGroup.getPeerGroupName()).append(" / ").append( + parentGroup.getPeerGroupID()); + } + configInfo.append("\n\t\tUsing home group endpoint : ").append(parentEndpoint); + configInfo.append("\n\t\tVirtual Messenger Queue Size : ").append(vmQueueSize); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] args) { + if (!initialized) { + return -1; + } + + // FIXME when Load order Issue is resolved this should fail + // until it is able to get a non-failing service Monitor (or + // null = not monitoring) + // FIXME it is ok because of the hack in StdPeerGroup that starts + // endpoint service first + if (EndpointMeterBuildSettings.ENDPOINT_METERING) { // Fix-Me: Move to startApp() when load order issue is resolved + endpointServiceMonitor = (EndpointServiceMonitor) MonitorManager.getServiceMonitor(group, MonitorResources.endpointServiceMonitorClassID); + + if (endpointServiceMonitor != null) { + endpointMeter = endpointServiceMonitor.getEndpointMeter(); + } + } + + if (parentEndpoint != null) { + Iterator parentMTs = parentEndpoint.getAllMessageTransports(); + + synchronized (this) { + while (parentMTs.hasNext()) { + addProtoToAdv(parentMTs.next()); + } + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Endpoint Service started."); + } + + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

      + * The transports and services are going to be stopped as well. When + * they are, they will dereference us and we'll go into oblivion. + */ + public void stopApp() { + if (parentEndpoint != null) { + parentEndpoint.removeMessengerEventListener(this, EndpointService.LowPrecedence); + } + + // Clear up the passiveMessengersListeners + int prec = EndpointService.HighPrecedence; + while (prec >= EndpointService.LowPrecedence) { + passiveMessengerListeners[prec--].clear(); + } + + // Clear up any messengers. + messengerMap.clear(); + directMessengerMap.clear(); + + // Clear up the listeners + incomingMessageListeners.clear(); + + // Forget about any message filters. + incomingFilterListeners.clear(); + outgoingFilterListeners.clear(); + + // Forget any message transports + messageTransports.clear(); + + // Avoid cross-reference problems with the GC + + // group = null; + // parentEndpoint = null; + // parentGroup = null; + + // The above is not really needed and until we have a very orderly + // shutdown, it causes NPEs that are hard to prevent. + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Endpoint Service stopped."); + } + } + + /** + * {@inheritDoc} + */ + public PeerGroup getGroup() { + return group; + } + + /** + * {@inheritDoc} + *

      + * We create a new instance each time because our interface actually + * has state (channel messengers and listener callback adaptor). + */ + public EndpointService getInterface() { + return new EndpointServiceInterface(this); + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + // A vector for statistics between propagateThroughAll and its invoker. + private static class Metrics { + int numFilteredOut = 0; + int numPropagatedTo = 0; + int numErrorsPropagated = 0; + } + + private void propagateThroughAll(Iterator eachProto, Message myMsg, String serviceName, String serviceParam, int initialTTL, Metrics metrics) { + + Message filtered = null; + + while (eachProto.hasNext()) { + MessageTransport aTransport = eachProto.next(); + + try { + if (!(aTransport instanceof MessagePropagater)) { + continue; + } + + MessagePropagater propagater = (MessagePropagater) aTransport; + + if (null == filtered) { + // run process filters only once + filtered = processFilters(myMsg, + propagater.getPublicAddress(), + new EndpointAddress(group.getPeerGroupID(), serviceName, serviceParam), + false); + } + + if (null == filtered) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(" message " + myMsg + " discarded upon filter decision"); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING) { + metrics.numFilteredOut++; + } + break; + } + + propagater.propagate(filtered.clone(), serviceName, serviceParam, initialTTL); + + if (EndpointMeterBuildSettings.ENDPOINT_METERING) { + metrics.numPropagatedTo++; + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed propagating message " + filtered + " on message transport " + aTransport, e); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING) { + metrics.numErrorsPropagated++; + } + } + } + } + + /** + * {@inheritDoc} + */ + public void propagate(Message msg, String serviceName, String serviceParam) { + propagate(msg, serviceName, serviceParam, Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + public void propagate(Message msg, String serviceName, String serviceParam, int initialTTL) { + long startPropagationTime = 0; + + if (null == serviceName) { + throw new IllegalArgumentException("serviceName may not be null"); + } + + Metrics metrics = null; + + if (EndpointMeterBuildSettings.ENDPOINT_METERING) { + metrics = new Metrics(); + } + + // Keep the orig unchanged for metering reference and caller's benefit, but + // we are forced to clone it here, because we add a header. + msg = msg.clone(); + + if (EndpointMeterBuildSettings.ENDPOINT_METERING) { + startPropagationTime = System.currentTimeMillis(); + } + + // Add our header. + MessageElement srcHdrElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SRCPEERHDR_NAME, localPeerId, null); + + msg.replaceMessageElement(EndpointServiceImpl.MESSAGE_SRCPEERHDR_NS, srcHdrElement); + + // Do the local transports with the plain address. + Iterator eachProto = getAllLocalTransports(); + + propagateThroughAll(eachProto, msg.clone(), serviceName, serviceParam, initialTTL, metrics); + + // Do the parent transports with a mangled address. + if (parentEndpoint != null) { + eachProto = parentEndpoint.getAllMessageTransports(); + + StringBuilder mangled = new StringBuilder(serviceName); + if (null != serviceParam) { + mangled.append('/'); + mangled.append(serviceParam); + } + + propagateThroughAll(eachProto, msg.clone(), myServiceName, mangled.toString(), initialTTL, metrics); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointServiceMonitor != null)) { + PropagationMeter propagationMeter = endpointServiceMonitor.getPropagationMeter(serviceName, serviceParam); + + propagationMeter.registerPropagateMessageStats(metrics.numPropagatedTo, metrics.numFilteredOut, metrics.numErrorsPropagated, + System.currentTimeMillis() - startPropagationTime); + } + } + + /** + * Process the filters for this message. + */ + private Message processFilters(Message message, EndpointAddress srcAddress, EndpointAddress dstAddress, boolean incoming) { + + Iterator eachFilter = incoming + ? incomingFilterListeners.iterator() + : outgoingFilterListeners.iterator(); + + while (eachFilter.hasNext()) { + FilterListenerAndMask aFilter = eachFilter.next(); + + Message.ElementIterator eachElement = message.getMessageElements(); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + + if ((null != aFilter.namespace) && (!aFilter.namespace.equals(eachElement.getNamespace()))) { + continue; + } + + if ((null != aFilter.name) && (!aFilter.name.equals(anElement.getElementName()))) { + continue; + } + + message = aFilter.listener.filterMessage(message, srcAddress, dstAddress); + + if (null == message) { + return null; + } + } + } + + // If we got here, no filter has rejected the message. Keep processing it. + return message; + } + + private static EndpointAddress demangleAddress(EndpointAddress mangled) { + String serviceName = mangled.getServiceName(); + + if (null == serviceName) { + // not a mangled address + return mangled; + } + + if (!serviceName.startsWith(ChannelMessenger.InsertedServicePrefix)) { + // not a mangled address + return mangled; + } + + String serviceParam = mangled.getServiceParameter(); + + if (null == serviceParam) { + // it has no param, its a null destination. + // XXX bondolo 20050907 I'm not sure this is correct. + return new EndpointAddress(mangled, null, null); + } + + int slashAt = serviceParam.indexOf('/'); + + if (-1 == slashAt) { + // param has no param portion. + return new EndpointAddress(mangled, serviceParam, null); + } + + return new EndpointAddress(mangled, serviceParam.substring(0, slashAt), serviceParam.substring(slashAt + 1)); + } + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddress, EndpointAddress dstAddress) { + + // check for propagate loopback. + MessageElement srcPeerElement = msg.getMessageElement(EndpointServiceImpl.MESSAGE_SRCPEERHDR_NS, EndpointServiceImpl.MESSAGE_SRCPEERHDR_NAME); + + if (null != srcPeerElement) { + msg.removeMessageElement(srcPeerElement); + String srcPeer = srcPeerElement.toString(); + + if (localPeerId.equals(srcPeer)) { + // This is a loopback. Discard. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(msg + " is a propagate loopback. Discarded"); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.discardedLoopbackDemuxMessage(); + } + + return; + } + } + + if (null == srcAddress) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("null src address, discarding message " + msg); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.invalidIncomingMessage(); + } + + return; + } + + if (null == dstAddress) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("null destination address, discarding message " + msg); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.invalidIncomingMessage(); + } + + return; + } + + // Decode the destination address. + // We want: + // 1 - a version of the address that does not have the grp redirection. + // 2 - a version of the serviceName that includes BOTH the group redirection and the original service name. + // 3 - the original service param; without the original service name stuck to it. + // So, basically we want the original serviceName part stuck to the group mangling, not stuck to the original + // serviceParam. We do that by cut/pasting from both the mangled and demangled versions of the address. + + EndpointAddress demangledAddress = demangleAddress(dstAddress); + String decodedServiceName = demangledAddress.getServiceName(); + String decodedServiceParam = demangledAddress.getServiceParameter(); + + if ((null == decodedServiceName) || (0 == decodedServiceName.length())) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("dest serviceName must not be null, discarding message " + msg); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.invalidIncomingMessage(); + } + + return; + } + + // Do filters for this message: + // FIXME - jice 20040417 : filters are likely broken, now. They do not see messages + // from xports in parent groups. For those messages that are seen, demangled address seems to be the useful one. + msg = processFilters(msg, srcAddress, demangledAddress, true); + + // If processFilters retuns null, the message is to be discarded. + if (msg == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message discarded during filter processing"); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.incomingMessageFilteredOut(); + } + + return; + } + + // Now that we know the original service name is valid, finish building the decoded version. + if (demangledAddress != dstAddress) { + decodedServiceName = dstAddress.getServiceName() + "/" + decodedServiceName; + } + + // Look up the listener + EndpointListener listener = getIncomingMessageListener(decodedServiceName, decodedServiceParam); + + // No listener? oh well. + + if (listener == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("No listener for \'" + dstAddress + "\' in group " + + group + "\n\tdecodedServiceName :" + + decodedServiceName + "\tdecodedServiceParam :" + + decodedServiceParam); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.noListenerForIncomingMessage(); + } + + return; // noone cares for this message + } + + // call the listener + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (null != decodedServiceParam) { + LOG.fine("Calling listener for \'" + decodedServiceName + "/" + decodedServiceParam + "\' with " + msg); + } else { + LOG.fine("Calling listener for \'" + decodedServiceName + "\' with " + msg); + } + } + + listener.processIncomingMessage(msg, srcAddress, demangledAddress); + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.incomingMessageSentToEndpointListener(); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.demuxMessageProcessed(); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught throwable from listener for " + dstAddress, all); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.errorProcessingIncomingMessage(); + } + } + } + + /** + * {@inheritDoc} + */ + public void demux(Message msg) { + + // Get the message destination + MessageElement dstAddressElement = msg.getMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, + EndpointServiceImpl.MESSAGE_DESTINATION_NAME); + + if (null == dstAddressElement) { + // No destination address... Just discard + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(msg + " has no destination address. Discarded"); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.noDestinationAddressForDemuxMessage(); + } + + return; + } + + msg.removeMessageElement(dstAddressElement); + EndpointAddress dstAddress = new EndpointAddress(dstAddressElement.toString()); + + // Get the message source + MessageElement srcAddressElement = msg.getMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, EndpointServiceImpl.MESSAGE_SOURCE_NAME); + + if (null == srcAddressElement) { + // No src address... Just discard + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(msg + " has no source address. Discarded"); + } + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointMeter != null)) { + endpointMeter.noSourceAddressForDemuxMessage(); + } + + return; + } + + msg.removeMessageElement(srcAddressElement); + EndpointAddress msgScrAddress = new EndpointAddress(srcAddressElement.toString()); + + processIncomingMessage(msg, msgScrAddress, dstAddress); + } + + /** + * {@inheritDoc} + */ + public MessengerEventListener addMessageTransport(MessageTransport transpt) { + + synchronized (messageTransports) { + // check if it is already installed. + if (!messageTransports.contains(transpt)) { + + clearProtoFromAdv(transpt); // just to be safe + messageTransports.add(transpt); + addProtoToAdv(transpt); + + // FIXME: For now, we return this. Later we might return something else, so that we can take + // advantage of the fact that we know that the event is from a local transport. + // That will help cleaning up the incoming messenger mess. + return this; + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + public boolean removeMessageTransport(MessageTransport transpt) { + + boolean removed; + + synchronized (messageTransports) { + removed = messageTransports.remove(transpt); + } + + if (removed) { + clearProtoFromAdv(transpt); + } + + return removed; + } + + /** + * {@inheritDoc} + */ + public Iterator getAllMessageTransports() { + if (null != parentEndpoint) { + return new SequenceIterator(getAllLocalTransports(), parentEndpoint.getAllMessageTransports()); + } else { + return getAllLocalTransports(); + } + } + + /** + * {@inheritDoc} + */ + public MessageTransport getMessageTransport(String name) { + Iterator allTransports = getAllMessageTransports(); + + while (allTransports.hasNext()) { + MessageTransport transpt = allTransports.next(); + + if (transpt.getProtocolName().equals(name)) { + return transpt; + } + } + + return null; + } + + private void addProtoToAdv(MessageTransport proto) { + + boolean relay = false; + + try { + if (!(proto instanceof MessageReceiver)) { + return; + } + + // no value to publish for the router endpoint address + if (proto instanceof EndpointRouter) { + // register the corresponding group to relay connection events + addActiveRelayListener(group); + return; + } + + // register this group to Relay connection events + if (proto instanceof RelayClient) { + relay = true; + ((RelayClient) proto).addActiveRelayListener(group); + } + + // get the list of addresses + Iterator allAddresses = ((MessageReceiver) proto).getPublicAddresses(); + Vector ea = new Vector(); + + while (allAddresses.hasNext()) { + EndpointAddress anEndpointAddress = allAddresses.next(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding endpoint address to route advertisement : " + anEndpointAddress); + } + + ea.add(anEndpointAddress.toString()); + } + + PeerAdvertisement padv = group.getPeerAdvertisement(); + StructuredDocument myParam = padv.getServiceParam(assignedID); + + RouteAdvertisement route = null; + + if (myParam != null) { + Enumeration paramChilds = myParam.getChildren(RouteAdvertisement.getAdvertisementType()); + + if (paramChilds.hasMoreElements()) { + // we have an advertisement just add the new access points + XMLElement param = (XMLElement) paramChilds.nextElement(); + + route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(param); + route.addDestEndpointAddresses(ea); + if (relay) { + // need to add the relay info if we have some + Vector hops = ((RelayClient) proto).getActiveRelays(group); + + if (!hops.isEmpty()) { + route.setHops(hops); + } + } + } + } + + if (null == route) { + // None yet, so create a new Route Advertisement + // create the RouteAdvertisement that will contain the route to + // the peer. At this point we only know the peer endpoint addresses + // no hops are known + + // create the destination access point + AccessPointAdvertisement destAP = (AccessPointAdvertisement) AdvertisementFactory.newAdvertisement( + AccessPointAdvertisement.getAdvertisementType()); + + destAP.setPeerID(group.getPeerID()); + destAP.setEndpointAddresses(ea); + + // create the route advertisement + route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + route.setDest(destAP); + + if (relay) { + // need to add the relay info if we have some + Vector hops = ((RelayClient) proto).getActiveRelays(group); + + if (!hops.isEmpty()) { + route.setHops(hops); + } + } + } + + // create the param route + XMLDocument newParam = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + XMLDocument xptDoc = (XMLDocument) route.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(newParam, newParam, xptDoc); + + padv.putServiceParam(assignedID, newParam); + + // publish the new advertisement + DiscoveryService discovery = group.getDiscoveryService(); + + if (discovery != null) { + discovery.publish(padv, DiscoveryService.INFINITE_LIFETIME, DiscoveryService.DEFAULT_EXPIRATION); + } + } catch (Exception ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Exception adding message transport ", ex); + } + } + } + + private void clearProtoFromAdv(MessageTransport transpt) { + + try { + if (!(transpt instanceof MessageReceiver)) { + return; + } + + // no value to publish the router endpoint address + if (transpt instanceof EndpointRouter) { + // register the corresponding group in the relay + removeActiveRelayListener(group); + return; + } + + // register this group to Relay connection events + if (transpt instanceof RelayClient) { + ((RelayClient) transpt).removeActiveRelayListener(group); + } + + Iterator allAddresses = ((MessageReceiver) transpt).getPublicAddresses(); + Vector ea = new Vector(); + + while (allAddresses.hasNext()) { + EndpointAddress anEndpointAddress = allAddresses.next(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing endpoint address from route advertisement : " + anEndpointAddress); + } + + ea.add(anEndpointAddress.toString()); + } + + PeerAdvertisement padv = group.getPeerAdvertisement(); + XMLDocument myParam = (XMLDocument) padv.getServiceParam(assignedID); + + if (myParam == null) { + return; + } + + Enumeration paramChilds = myParam.getChildren(RouteAdvertisement.getAdvertisementType()); + + if (!paramChilds.hasMoreElements()) { + return; + } + + XMLElement param = (XMLElement) paramChilds.nextElement(); + + RouteAdvertisement route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(param); + + route.removeDestEndpointAddresses(ea); + + // update the new route to a new parm structure. + XMLDocument newParam = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + + XMLDocument xptDoc = (XMLDocument) route.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(newParam, newParam, xptDoc); + + // put the parms back. + padv.putServiceParam(assignedID, newParam); + + // publish the new advertisement + DiscoveryService discovery = group.getDiscoveryService(); + + if (discovery != null) { + discovery.publish(padv, DiscoveryService.INFINITE_LIFETIME, DiscoveryService.DEFAULT_EXPIRATION); + } + } catch (Exception ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Exception removing messsage transport ", ex); + } + } + } + + /** + * {@inheritDoc} + */ + public boolean addMessengerEventListener(MessengerEventListener listener, int prio) { + int priority = prio; + + if (priority > EndpointService.HighPrecedence) { + priority = EndpointService.HighPrecedence; + } + + if (priority < EndpointService.LowPrecedence) { + priority = EndpointService.LowPrecedence; + } + + return passiveMessengerListeners[priority].add(listener); + } + + /** + * {@inheritDoc} + */ + public boolean removeMessengerEventListener(MessengerEventListener listener, int prio) { + int priority = prio; + + if (priority > EndpointService.HighPrecedence) { + priority = EndpointService.HighPrecedence; + } + if (priority < EndpointService.LowPrecedence) { + priority = EndpointService.LowPrecedence; + } + + return passiveMessengerListeners[priority].remove(listener); + } + + /** + * {@inheritDoc} + */ + public boolean addIncomingMessageListener(EndpointListener listener, String serviceName, String serviceParam) { + + if (null == listener) { + throw new IllegalArgumentException("EndpointListener must be non-null"); + } + + if (null == serviceName) { + throw new IllegalArgumentException("serviceName must not be null"); + } + + if (-1 != serviceName.indexOf('/')) { + throw new IllegalArgumentException("serviceName may not contain '/' characters"); + } + + String address = serviceName; + + if (null != serviceParam) { + address += "/" + serviceParam; + } + + synchronized (incomingMessageListeners) { + if (incomingMessageListeners.containsKey(address)) { + return false; + } + + InboundMeter incomingMessageListenerMeter = null; + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointServiceMonitor != null)) { + incomingMessageListenerMeter = endpointServiceMonitor.getInboundMeter(serviceName, serviceParam); + } + + incomingMessageListeners.put(address, listener); + } + + if (parentEndpoint != null) { + if (serviceName.startsWith(ChannelMessenger.InsertedServicePrefix)) { + // The listener name is already re-written. + // The listener is already a quota listener; we made extra sure of that before tucking it into our local map. + parentEndpoint.addIncomingMessageListener(listener, serviceName, serviceParam); + } else { + parentEndpoint.addIncomingMessageListener(listener, myServiceName, address); + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + public EndpointListener getIncomingMessageListener(String serviceName, String serviceParam) { + + if (null == serviceName) { + throw new IllegalArgumentException("serviceName must not be null"); + } + + EndpointListener listener = null; + + if (null != serviceParam) { + listener = incomingMessageListeners.get(serviceName + "/" + serviceParam); + } + + // Didn't find it with param, maybe there is a generic listener for the service + if (listener == null) { + listener = incomingMessageListeners.get(serviceName); + } + + // Didn't find it still, try the compatibility name. + if (listener == null) { + listener = incomingMessageListeners.get(serviceName + serviceParam); + + if ((null != listener) && Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Found handler only via compatibility listener : " + serviceName + serviceParam); + } + } + + return listener; + } + + /** + * {@inheritDoc} + */ + public EndpointListener removeIncomingMessageListener(String serviceName, String serviceParam) { + if (null == serviceName) { + throw new IllegalArgumentException("serviceName must not be null"); + } + + if (-1 != serviceName.indexOf('/')) { + throw new IllegalArgumentException("serviceName may not contain '/' characters"); + } + + String address = serviceName; + + if (null != serviceParam) { + address += "/" + serviceParam; + } + + EndpointListener removedListener; + synchronized (incomingMessageListeners) { + removedListener = incomingMessageListeners.remove(address); + } + + if (parentEndpoint != null) { + if (serviceName.startsWith(ChannelMessenger.InsertedServicePrefix)) { + parentEndpoint.removeIncomingMessageListener(serviceName, serviceParam); + } else { + parentEndpoint.removeIncomingMessageListener(myServiceName, address); + } + } + return removedListener; + } + + /** + * Returns a local transport that can send to the given address. For now + * this is based only on the protocol name. + * + * @param addr the endpoint address + * @return the transport if the address protocol is supported by this transport + */ + private MessageSender getLocalSenderForAddress(EndpointAddress addr) { + + Iterator localTransports = getAllLocalTransports(); + + while (localTransports.hasNext()) { + MessageTransport transpt = localTransports.next(); + if (!transpt.getProtocolName().equals(addr.getProtocolName())) { + continue; + } + + if (!(transpt instanceof MessageSender)) { + continue; + } + + return (MessageSender) transpt; + } + return null; + } + + /** + * {@inheritDoc} + *

      + * Note: canonical messenger itself does not do any address rewriting. + * Any address rewriting must be specified when getting a channel. However, + * canonical knows the default group redirection for its owning endpoint and + * will automatically skip redirection if it is the same. + */ + + public Messenger getCanonicalMessenger(EndpointAddress addr, Object hint) { + if (addr == null) { + throw new IllegalArgumentException("null endpoint address not allowed."); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + Throwable trace = new Throwable("Stack Trace"); + StackTraceElement elements[] = trace.getStackTrace(); + + int position = 1; + + while (elements[position].getClassName().startsWith("net.jxta.impl.endpoint.EndpointService")) { + position++; + } + + if ((elements.length - 1) == position) { + position--; + } + + LOG.fine("Get Messenger for " + addr + " by " + elements[position]); + } + + // Check the canonical map. + synchronized (messengerMap) { + Reference ref = messengerMap.get(addr); + + if (ref != null) { + Messenger found = ref.get(); + + // If it is USABLE, return it. + if ((found != null) && ((found.getState() & Messenger.USABLE) != 0)) { + return found; + } + + // It has been GCed or is no longer USABLE. Make room for a new one. + messengerMap.remove(addr); + } + + if (getLocalSenderForAddress(addr) != null) { + OutboundMeter messengerMeter = null; + + if (EndpointMeterBuildSettings.ENDPOINT_METERING && (endpointServiceMonitor != null)) { + messengerMeter = endpointServiceMonitor.getOutboundMeter(addr); + } + + // The hint is saved in the canonical messenger and will be used + // when that virtual messenger first faces the need to create a + // transport messenger. As of now, the logical dest is unknown. + Messenger m = new CanonicalMessenger(vmQueueSize, addr, null, hint, messengerMeter); + + messengerMap.put(m.getDestinationAddress(), new SoftReference(m)); + return m; + } + } + + // If we're here, we do not have any such transport. + // Try our ancestors enpoints, if any. + + if (parentEndpoint == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Could not create messenger for : " + addr); + } + return null; + } + + return parentEndpoint.getCanonicalMessenger(addr, hint); + } + + /** + * Return only the message transport registered locally. + */ + protected Iterator getAllLocalTransports() { + List transportList; + + synchronized (messageTransports) { + transportList = new ArrayList(messageTransports); + } + + return transportList.iterator(); + } + + /** + * Returns a messenger for the specified address from one of the Message + * Transports registered with this very endpoint service. Message + * Transports inherited from parent groups will not be used. + * + * @param addr The destination address of the desired Messenger. + * @param hint A hint provided to the Message Transport which may assist it + * in creating the messenger. + * @return A Messenger for the specified destination address or {@code null} + * if no Messenger could be created. + */ + private Messenger getLocalTransportMessenger(EndpointAddress addr, Object hint) { + MessageSender sender = getLocalSenderForAddress(addr); + Messenger messenger = null; + + if (sender != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Trying address \'" + addr + "\' with : " + sender); + } + messenger = sender.getMessenger(addr, hint); + } + + if (messenger == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Couldn\'t create messenger for : " + addr); + } + } + return messenger; + } + + /** + * {@inheritDoc} + */ + public synchronized void addIncomingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + if (null == listener) { + throw new IllegalArgumentException("listener must be non-null"); + } + + FilterListenerAndMask aFilter = new FilterListenerAndMask(listener, namespace, name); + + incomingFilterListeners.add(aFilter); + } + + /** + * {@inheritDoc} + */ + public synchronized void addOutgoingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + if (null == listener) { + throw new IllegalArgumentException("listener must be non-null"); + } + + FilterListenerAndMask aFilter = new FilterListenerAndMask(listener, namespace, name); + + outgoingFilterListeners.add(aFilter); + } + + /** + * {@inheritDoc} + */ + public synchronized MessageFilterListener removeIncomingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + Iterator eachListener = incomingFilterListeners.iterator(); + + while (eachListener.hasNext()) { + FilterListenerAndMask aFilter = eachListener.next(); + + if (listener == aFilter.listener) { + eachListener.remove(); + return listener; + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + public synchronized MessageFilterListener removeOutgoingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + Iterator eachListener = outgoingFilterListeners.iterator(); + + while (eachListener.hasNext()) { + FilterListenerAndMask aFilter = eachListener.next(); + + if ((listener == aFilter.listener) + && ((null != namespace) ? namespace.equals(aFilter.namespace) : (null == aFilter.namespace)) + && ((null != name) ? name.equals(aFilter.name) : (null == aFilter.name))) { + eachListener.remove(); + return listener; + } + } + + return null; + } + + /** + * {@inheritDoc} + * + *

      Redistribute the event to those interested. + */ + public boolean messengerReady(MessengerEvent event) { + + // FIXME - jice@jxta.org 20040413: now that we share messengers, we + // should be able to get rid of most of this mess, and in the router, + // and the relay too. + + Messenger messenger = event.getMessenger(); + Messenger messengerForHere; + EndpointAddress connAddr = event.getConnectionAddress(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New " + messenger + " for : " + + messenger.getDestinationAddress() + " (" + + messenger.getLogicalDestinationAddress() + ")"); + } + + int highestPrec = EndpointService.HighPrecedence; + int lowestPrec = EndpointService.LowPrecedence; + + // If there's no connection address we just pass the messenger around + // everywhere; it is unspecified which group it is for. + // Else, we must figure out if it is for this group, or must be + // passed upStack (if any). + if (connAddr != null) { + String cgServiceName = connAddr.getServiceName(); + + // See if there is a mangling. If not, this means this was sent + // within this group through a local xport, so it is for here. Else + // it may be for here (from below) or for upstack. + + if (cgServiceName == null || !cgServiceName.startsWith(ChannelMessenger.InsertedServicePrefix)) { + // FIXME: jice@jxta.org - 20030512 If we restrict use to "here" + // we make most backchannels useless. So, the statement below is + // commented out. Ideally we should not have to worry about the + // group targetting of connections, only messages. However the + // way the relay and the router have to split messengers makes + // it necessary. This may only be fixed by re-organizing + // globally the management of incoming messengers in the + // endpoint, so that router and relay no-longer need to claim + // exclusive use of messengers. Since relay clients set the + // group properly, their messengers are not affected by this + // branch of the code. + // lowestPrec = EndpointService.LowPrecedence + 1; + } else if (!myServiceName.equals(cgServiceName)) { + // This is for upstack only + highestPrec = EndpointService.LowPrecedence; + } else { + // Mangling present and this is for here (and therefore this is + // from below). We must demangle. Wrapping is figured later, + // since we may also have to wrap if there the + lowestPrec = EndpointService.LowPrecedence + 1; + + String serviceParam = connAddr.getServiceParameter(); + String realService = null; + String realParam = null; + + if (null != serviceParam) { + int slashAt = serviceParam.indexOf('/'); + + if (-1 == slashAt) { + realService = serviceParam; + } else { + realService = serviceParam.substring(0, slashAt); + realParam = serviceParam.substring(slashAt + 1); + } + } + + connAddr = new EndpointAddress(connAddr, realService, realParam); + } + } + + // We make a channel in all cases, the channel will decide if the desired grp redirection + // requires address rewriting or not. + + // As for a MessageWatcher for implementing sendMessage-with-listener, we do not provide one + // mostly because it is difficult to get a hold on the only appropriate one: that of the endpoint + // service interface of the listener's owner. So, incoming messengers will not support the listener-based send API. + // Unless someone adds a watcher by hand. + messengerForHere = event.getMessenger().getChannelMessenger(group.getPeerGroupID(), null, null); + + // Call the listener highest precedence first. The first one that claims + // the messenger wins. + for (int prec = highestPrec + 1; prec-- > lowestPrec;) { + MessengerEvent newMessenger = new MessengerEvent(event.getSource(), + prec == EndpointService.LowPrecedence ? messenger : messengerForHere, connAddr); + + // We need to grab the listeners and release the lock. Otherwise the + // sometimes too long operations performed by the listener creates + // an unnecessary contention. + // The side effect is that a listener can in theory be called after + // remove returned. It is unlikely to be a problem for messenger + // events, but if it is, then we'll have to add reader-writer synch. + Collection allML = new ArrayList(passiveMessengerListeners[prec]); + for (MessengerEventListener listener : allML) { + try { + if (listener.messengerReady(newMessenger)) { + // A listener has taken the messenger. we're done. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(newMessenger + " claimed by " + listener); + } + return true; + } + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable in listener " + listener, all); + } + } + } + } + + // Note that the messenger was not wanted. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Nobody cared about " + event); + } + return false; + } + + // public MessengerEventListener getMessengerEventListener() { + // return this; + // } + + // try to find the relay service in our + // hierachy of endpoints to register our listener group + // since the group has to register into the relay service. This is not + // very pretty, but the other way was even worth to register the relay + // into the endpoint! + + private void addActiveRelayListener(PeerGroup listeningGroup) { + PeerGroup parentGroup = group.getParentGroup(); + while (parentGroup != null) { + EndpointService parentEndpoint = parentGroup.getEndpointService(); + + for (Iterator it = parentEndpoint.getAllMessageTransports(); it.hasNext();) { + MessageTransport mt = it.next(); + + if ((mt instanceof RelayClient)) { + ((RelayClient) mt).addActiveRelayListener(listeningGroup); + break; + } + } + parentGroup = parentGroup.getParentGroup(); + } + } + + // try to find the relay service in our + // hierachy of endpoints to unregister our listener group + private void removeActiveRelayListener(PeerGroup listeningGroup) { + PeerGroup parentGroup = group.getParentGroup(); + + while (parentGroup != null) { + EndpointService parentEndpoint = parentGroup.getEndpointService(); + + for (Iterator it = parentEndpoint.getAllMessageTransports(); it.hasNext();) { + MessageTransport mt = it.next(); + + if ((mt instanceof RelayClient)) { + ((RelayClient) mt).removeActiveRelayListener(listeningGroup); + break; + } + } + parentGroup = parentGroup.getParentGroup(); + } + } + + /* + * Convenience legacy methods. They are here to reduce the complexity of the class hierarchy but are not supposed to be used. + */ + + /** + * {@inheritDoc} + * + * @deprecated legacy method. + */ + @Deprecated + public boolean ping(EndpointAddress addr) { + throw new UnsupportedOperationException("Legacy method not implemented. Use an interface object."); + } + + /** + * {@inheritDoc} + * + * @deprecated legacy method. + */ + @Deprecated + public boolean getMessenger(MessengerEventListener listener, EndpointAddress addr, Object hint) { + throw new UnsupportedOperationException("Legacy method not implemented. Use an interface object."); + } + + /** + * {@inheritDoc} + *

      + * convenience method not supported here. + */ + public Messenger getMessenger(EndpointAddress addr) { + throw new UnsupportedOperationException("Convenience method not implemented. Use an interface object."); + } + + /** + * {@inheritDoc} + *

      + * convenience method not supported here. + */ + public Messenger getMessengerImmediate(EndpointAddress addr, Object hint) { + throw new UnsupportedOperationException("Convenience method not implemented. Use an interface object."); + } + + /** + * {@inheritDoc} + *

      + * convenience method not supported here. + */ + public Messenger getMessenger(EndpointAddress addr, Object hint) { + throw new UnsupportedOperationException("Convenience method not implemented. Use an interface object."); + } + + /** + * Returns a Direct Messenger that may be used to send messages via this endpoint + * to the specified destination. + * + * @param address the destination address. + * @param hint the messenger hint, if any, otherwise null. + * @param exclusive if true avoids caching the messenger + * @return The messenger or {@code null} is returned if the destination address is not reachable. + * @throws IllegalArgumentException if hint is not of RouteAdvertisement, or PeerAdvertisement type. + */ + public Messenger getDirectMessenger(EndpointAddress address, Object hint, boolean exclusive) { + + if (!exclusive) { + Reference reference = directMessengerMap.get(address); + if (reference != null) { + Messenger messenger = reference.get(); + if (messenger != null && !messenger.isClosed()) { + return messenger; + } + } + } + + // We must have access to a TCP transport to create a direct messenger. + TcpTransport tcpTransport = (TcpTransport) getMessageTransport("tcp"); + + if ((tcpTransport != null) && (hint != null)) { + RouteAdvertisement route; + EndpointAddress direct; + Messenger messenger; + if (hint instanceof RouteAdvertisement) { + route = (RouteAdvertisement) hint; + } else if (hint instanceof PeerAdvertisement) { + route = EndpointUtils.extractRouteAdv((PeerAdvertisement) hint); + } else { + throw new IllegalArgumentException("Unknown route hint object type" + hint); + } + + for (EndpointAddress transportAddr : route.getDestEndpointAddresses()) { + if (transportAddr.getProtocolName().equals("tcp")) { + direct = createDirectAddress(transportAddr, address); + // direct messengers are non self destructive + messenger = tcpTransport.getMessenger(direct, route, false); + if (messenger != null) { + if (!exclusive) { + directMessengerMap.put(address, new WeakReference(messenger)); + } + return messenger; + } + } + } + } + + return null; + } + + /** + * Given a transport address and service address, create a mangled endpoint address + * + * @param transportAddr the transport messenger address + * @param serviceEndpoint the service endpoint + * @return an composite endpoint address + */ + private EndpointAddress createDirectAddress(EndpointAddress transportAddr, EndpointAddress serviceEndpoint) { + //physical transport address + StringBuilder destStr = new StringBuilder(transportAddr.toString()).append("/"); + // EndpointService + destStr.append(ENDPOINTSERVICE_NAME); + //Dest peergroup + destStr.append(":").append(group.getPeerGroupID().getUniqueValue().toString()).append("/"); + //Service endpoint + destStr.append(serviceEndpoint.getServiceName()).append("/").append(serviceEndpoint.getServiceParameter()); + + //return new EndpointAddress(transportAddr, serviceEndpoint.getServiceName(), serviceEndpoint.getServiceParameter()); + return new EndpointAddress(destStr.toString()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointServiceInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointServiceInterface.java new file mode 100644 index 000000000..8cc33d7f2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointServiceInterface.java @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint; + +import net.jxta.document.Advertisement; +import net.jxta.endpoint.ChannelMessenger; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.ListenerAdaptor; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageFilterListener; +import net.jxta.endpoint.MessageTransport; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerEventListener; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.peergroup.StdPeerGroup; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.ModuleImplAdvertisement; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +import net.jxta.platform.Module; + +/** + * Provides an interface object appropriate for applications using the endpoint + * service. The interface provides a number of convenience features and + * implementation necessary for legacy features. + */ +class EndpointServiceInterface implements EndpointService { + + /** + * The service interface that we will be fronting. + */ + private final EndpointServiceImpl theRealThing; + + /** + * The number of active instances of this class. We use this for deciding + * when to instantiate and shutdown the listener adaptor. + */ + private static int activeInstanceCount = 0; + + /** + * Provides emulation of the legacy send-message-with-listener and get-messenger-with-listener APIs. + */ + private static ListenerAdaptor listenerAdaptor; + + /** + * The cache of channels. If a given owner of this EndpointService interface + * object requests channels for the same exact destination multiple times, + * we will return the same channel object as much as possible. We keep + * channels in a weak map, so that when channels are discarded, they + * eventually disappear. Channels that have messages in them are always + * referenced. Therefore, this prevents the creation of more than one + * channel with messages in it for the same destination in the same context + * (owner of interface object - typically one module). This is required to + * properly support the common (and convenient) pattern: + *

      + * m = endpointServiceInterface.getMessenger(); messenger.sendMessage(); m = null; + *

      + * If that was not kept in check, it would be possible to inadvertently + * create an infinite number of channels with pending messages, thus an + * infinite number of messages too. + */ + private final Map> channelCache = new WeakHashMap>(); + + /** + * Builds a new interface object. + * + * @param endpointService the endpoint service that we will front. + */ + public EndpointServiceInterface(EndpointServiceImpl endpointService) { + theRealThing = endpointService; + synchronized (this.getClass()) { + activeInstanceCount++; + if (1 == activeInstanceCount) { + listenerAdaptor = new ListenerAdaptor(Thread.currentThread().getThreadGroup(), ((StdPeerGroup) endpointService.getGroup()).getExecutor()); + } + } + } + + /** + * {@inheritDoc} + *

      + * This is rather heavy-weight if instances are frequently created and + * discarded since finalization significantly delays GC. + */ + @Override + protected void finalize() throws Throwable { + synchronized (this.getClass()) { + activeInstanceCount--; + if (0 == activeInstanceCount) { + listenerAdaptor.shutdown(); + listenerAdaptor = null; + } + } + super.finalize(); + } + + /** + * {@inheritDoc} + *

      + * it is there only to satisfy the requirements of the interface that we + * implement. Ultimately, the API should define two levels of interfaces : + * one for the real service implementation and one for the interface object. + * Right now it feels a bit heavy to so that since the only different + * between the two would be init() and may-be getName(). + */ + public void init(PeerGroup peerGroup, ID id, Advertisement implAdv) { + } + + /** + * {@inheritDoc} + *

      + * This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + */ + public int startApp(String[] arg) { + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

      + * This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + *

      + * This request is currently ignored. + */ + public void stopApp() { + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return theRealThing.getImplAdvertisement(); + } + + /** + * {@inheritDoc} + *

      + * Sort of absurd but this is part of the API we're implementing. + * We would not do a two-level API just for that. + */ + public EndpointService getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public PeerGroup getGroup() { + return theRealThing.getGroup(); + } + + /** + * {@inheritDoc} + */ + public Messenger getCanonicalMessenger(EndpointAddress addr, Object hint) { + // XXX: maybe we should enforce the stripping of the address here. + // That would prevent application from making canonical messengers with a variety of service names and + // service params. On the other hand that would cost useless cloning of endp addrs and prevent future + // flexibility regarding QOS params, possibly. Be liberal for now. + return theRealThing.getCanonicalMessenger(addr, hint); + } + + /** + * {@inheritDoc} + */ + public Messenger getMessengerImmediate(EndpointAddress addr, Object hint) { + // Note: for now, the hint is not used for canonicalization (hint != QOS). + synchronized (channelCache) { + Reference existing = channelCache.get(addr); + + if (existing != null) { + Messenger messenger = existing.get(); + if ((messenger != null) && ((messenger.getState() & Messenger.USABLE) != 0)) { + return messenger; + } + } + } + + // We do not have a good one at hand. Make a new one. + + // Use the stripped address to get a canonical msngr; not doing so + // would reduce the sharing to almost nothing. + EndpointAddress plainAddr = new EndpointAddress(addr, null, null); + + Messenger found = theRealThing.getCanonicalMessenger(plainAddr, hint); + + // Address must not be a supported one. + if (found == null) { + return null; + } + + // Get a channel for that servicename and serviceparam. redirect to this group. + + // NOTE: This assumes that theRealThing.getGroup() is really the group where the application that obtained + // this interface object lives. This is the case today because all groups have their own endpoint service. + // In the future, interface objects may refer to a group context that is not necessarily the group where + // "therealThing" lives. When that happens, this interface object will have to know which group it works + // for without asking "theRealThing". + + ChannelMessenger res = (ChannelMessenger) found.getChannelMessenger(theRealThing.getGroup().getPeerGroupID(), + addr.getServiceName(), addr.getServiceParameter()); + + synchronized (channelCache) { + // We have to check again. May be we did all that in parallel with some other thread and it beat + // us to the finish line. In which case, substitute the existing one and throw ours away. + Reference existing = channelCache.get(addr); + + if (existing != null) { + Messenger messenger = existing.get(); + if ((messenger != null) && ((messenger.getState() & Messenger.USABLE) != 0)) { + return messenger; + } + } + // The listenerAdaptor of this interface obj is used to support the sendMessage-with-listener API. + res.setMessageWatcher(listenerAdaptor); + channelCache.put(res.getDestinationAddress(), new WeakReference(res)); + } + return res; + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress addr) { + return getMessenger(addr, null); + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress addr, Object hint) { + + // Get an unresolved messenger (that's immediate). + Messenger messenger = getMessengerImmediate(addr, hint); + + if (messenger == null) { + return null; + } + + // Now ask the messenger to resolve: this legacy blocking API ensures + // that only successfully resolved messengers are ever returned. + messenger.resolve(); + try { + messenger.waitState(Messenger.RESOLVED | Messenger.TERMINAL, TimeUtils.AMINUTE); + } catch (InterruptedException ie) { + Thread.interrupted(); + } + + // check the state + int state = messenger.getState(); + + if ((state & Messenger.TERMINAL) != 0) { + return null; + } + if ((state & Messenger.RESOLVED) == 0) { + // Not failed yet. But too late for us. + return null; + } + return messenger; + } + + /** + * {@inheritDoc} + */ + public void propagate(Message msg, String serviceName, String serviceParam) { + theRealThing.propagate(msg, serviceName, serviceParam, Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + public void propagate(Message msg, String serviceName, String serviceParam, int initialTTL) { + theRealThing.propagate(msg, serviceName, serviceParam, initialTTL); + } + + /** + * {@inheritDoc} + */ + public void demux(Message msg) { + theRealThing.demux(msg); + } + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message message, EndpointAddress source, EndpointAddress destination) { + theRealThing.processIncomingMessage(message, source, destination); + } + + /** + * {@inheritDoc} + */ + @Deprecated + public boolean ping(EndpointAddress addr) { + return null != getMessengerImmediate(addr, null); + } + + /** + * {@inheritDoc} + */ + public MessengerEventListener addMessageTransport(MessageTransport transpt) { + // FIXME TOO: We should probably make the interface refuse to do it. + // But that will have to wait until we have criteria to decide who + // gets an interface object and who gets the real thing. In the + // meantime just do it. + return theRealThing.addMessageTransport(transpt); + } + + /** + * {@inheritDoc} + */ + public boolean removeMessageTransport(MessageTransport transpt) { + // FIXME TOO: We should probably make the interface refuse to do it. + // But that will have to wait until we have criteria to decide who + // gets an interface object and who gets the real thing. In the + // meantime just do it. + return theRealThing.removeMessageTransport(transpt); + } + + /** + * {@inheritDoc} + */ + public Iterator getAllMessageTransports() { + return theRealThing.getAllMessageTransports(); + } + + /** + * {@inheritDoc} + */ + public MessageTransport getMessageTransport(String name) { + return theRealThing.getMessageTransport(name); + } + + /** + * {@inheritDoc} + */ + public boolean addIncomingMessageListener(EndpointListener listener, String serviceName, String serviceParam) { + return theRealThing.addIncomingMessageListener(listener, serviceName, serviceParam); + } + + /** + * {@inheritDoc} + */ + public EndpointListener getIncomingMessageListener(String serviceName, String serviceParam) { + return theRealThing.getIncomingMessageListener(serviceName, serviceParam); + } + + /** + * {@inheritDoc} + */ + public void addIncomingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + theRealThing.addIncomingMessageFilterListener(listener, namespace, name); + } + + /** + * {@inheritDoc} + */ + public void addOutgoingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + theRealThing.addOutgoingMessageFilterListener(listener, namespace, name); + } + + /** + * {@inheritDoc} + */ + public MessageFilterListener removeIncomingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + return theRealThing.removeIncomingMessageFilterListener(listener, namespace, name); + } + + /** + * {@inheritDoc} + */ + public MessageFilterListener removeOutgoingMessageFilterListener(MessageFilterListener listener, String namespace, String name) { + return theRealThing.removeOutgoingMessageFilterListener(listener, namespace, name); + } + + /** + * {@inheritDoc} + */ + public EndpointListener removeIncomingMessageListener(String serviceName, String serviceParam) { + return theRealThing.removeIncomingMessageListener(serviceName, serviceParam); + } + + /** + * {@inheritDoc} + */ + public boolean addMessengerEventListener(MessengerEventListener listener, int prio) { + return theRealThing.addMessengerEventListener(listener, prio); + } + + /** + * {@inheritDoc} + */ + public boolean removeMessengerEventListener(MessengerEventListener listener, int prio) { + return theRealThing.removeMessengerEventListener(listener, prio); + } + + /** + * {@inheritDoc} + * + * @deprecated legacy support + */ + @Deprecated + public boolean getMessenger(MessengerEventListener listener, EndpointAddress addr, Object hint) { + Messenger messenger = getMessengerImmediate(addr, hint); + if (messenger == null) { + return false; + } + + if (!listenerAdaptor.watchMessenger(listener, messenger)) { + return false; + } + + // Make sure that resolution is being attempted if not already in progress. + messenger.resolve(); + return true; + } + + /** + * Returns a Direct Messenger that may be used to send messages via this endpoint to the specified destination. + * + * @param addr the destination address. + * @param hint the messenger hint, if any, otherwise null. + * @param exclusive if true avoids caching the messenger + * @return The messenger or {@code null} is returned if the destination address is not reachable. + */ + public Messenger getDirectMessenger(EndpointAddress addr, Object hint, boolean exclusive) { + return theRealThing.getDirectMessenger(addr, hint, exclusive); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointUtils.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointUtils.java new file mode 100644 index 000000000..2a5c25fbe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/EndpointUtils.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2001-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint; + + +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLElement; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + + +/** + * Utility functions related to the Endpoint Service. + */ +public final class EndpointUtils { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(EndpointUtils.class.getName()); + + /** + * Extracts a route advertisement from a peer advertisement. + * + * @param adv The peer advertisement believed to contain a route advertisement. + * @return The extracted route advertisement or {@code null} if a route + * advertisement could not be extracted. + */ + public static RouteAdvertisement extractRouteAdv(PeerAdvertisement adv) { + + try { + // Get its EndpointService advertisement + XMLElement endpParam = (XMLElement) adv.getServiceParam(PeerGroup.endpointClassID); + + if (endpParam == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No Endpoint Params"); + } + return null; + } + + // get the Route Advertisement element + Enumeration paramChilds = endpParam.getChildren(RouteAdvertisement.getAdvertisementType()); + XMLElement param; + + if (paramChilds.hasMoreElements()) { + param = (XMLElement) paramChilds.nextElement(); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No Route Adv in Peer Adv"); + } + return null; + } + + // build the new route + RouteAdvertisement route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(param); + + // Embedded routes often don't contain the peer id. + route.setDestPeerID(adv.getPeerID()); + + return route; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to extract radv", e); + } + } + + return null; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/IPUtils.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/IPUtils.java new file mode 100644 index 000000000..60aafbf66 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/IPUtils.java @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint; + + +import java.io.IOException; +import java.net.BindException; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import javax.net.ServerSocketFactory; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * Utility methods for use by IP based transports. + */ +public final class IPUtils { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(IPUtils.class.getName()); + + final static Random random = new Random(); + + final static String IPV4ANYADDRESS = "0.0.0.0"; + final static String IPV6ANYADDRESS = "::"; + + final static String IPV4LOOPBACK = "127.0.0.1"; + final static String IPV6LOOPBACK = "::1"; + + /** + * Constant which works as the IP "Any Address" value + */ + public final static InetAddress ANYADDRESS; + public final static InetAddress ANYADDRESSV4; + public final static InetAddress ANYADDRESSV6; + + /** + * Constant which works as the IP "Local Loopback" value; + */ + public final static InetAddress LOOPBACK; + public final static InetAddress LOOPBACKV4; + public final static InetAddress LOOPBACKV6; + + /** + * Socket factory to allow changing the way Sockets are created + * and connected. A null value is ok and results in the regular + * connectToFromNoFactory being used. + * + *

      Plugin in a different implementation via setSocketFactory(). + */ + private static SocketFactory socketFactory; + + /** + * Socket factory to allow changing the way Sockets are created + * and connected. A null value is ok and results in the regular + * connectToFromNoFactory being used. + * + *

      Plugin in a different implementation via setSocketFactory(). + */ + private static ServerSocketFactory serverSocketFactory; + + static { + InetAddress GET_ADDRESS = null; + + try { + GET_ADDRESS = InetAddress.getByName(IPV4ANYADDRESS); + } catch (Exception ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("failed to intialize ANYADDRESSV4. Not fatal"); + } + } + + ANYADDRESSV4 = GET_ADDRESS; + + InetAddress GET_ANYADDRESSV6 = null; + + GET_ADDRESS = null; + try { + GET_ADDRESS = InetAddress.getByName(IPV6ANYADDRESS); + } catch (Exception ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("failed to intialize IPV6ANYADDRESS. Not fatal"); + } + } + + ANYADDRESSV6 = GET_ADDRESS; + + ANYADDRESS = (ANYADDRESSV4 == null) ? ANYADDRESSV6 : ANYADDRESSV4; + + GET_ADDRESS = null; + try { + GET_ADDRESS = InetAddress.getByName(IPV4LOOPBACK); + } catch (Exception ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("failed to intialize IPV4LOOPBACK. Not fatal"); + } + } + + LOOPBACKV4 = GET_ADDRESS; + + GET_ADDRESS = null; + try { + GET_ADDRESS = InetAddress.getByName(IPV6LOOPBACK); + } catch (Exception ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("failed to intialize ANYADDRESSV4. Not fatal"); + } + } + + LOOPBACKV6 = GET_ADDRESS; + + LOOPBACK = (LOOPBACKV4 == null) ? LOOPBACKV6 : LOOPBACKV4; + + if (LOOPBACK == null || ANYADDRESS == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("failure initializing statics. Neither IPV4 nor IPV6 seem to work."); + } + + throw new IllegalStateException("failure initializing statics. Neither IPV4 nor IPV6 seem to work."); + } + } + + /** + * This is a static utility class, you don't make instances. + */ + private IPUtils() {} + + /** + * Provide an iterator which returns all of the local InetAddresses for this + * host. + * + * @return iterator of InetAddress which is all of the InetAddress for all + * local interfaces. + */ + public static Iterator getAllLocalAddresses() { + List allAddr = new ArrayList(); + + Enumeration allInterfaces = null; + + try { + allInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException caught) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not get local interfaces list", caught); + } + } + + if (null == allInterfaces) { + allInterfaces = Collections.enumeration(Collections.emptyList()); + } + + while (allInterfaces.hasMoreElements()) { + NetworkInterface anInterface = allInterfaces.nextElement(); + + try { + Enumeration allIntfAddr = anInterface.getInetAddresses(); + + while (allIntfAddr.hasMoreElements()) { + InetAddress anAddr = allIntfAddr.nextElement(); + + if (anAddr.isLoopbackAddress() || anAddr.isAnyLocalAddress()) { + continue; + } + + if (!allAddr.contains(anAddr)) { + allAddr.add(anAddr); + } + } + } catch (Throwable caught) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not get addresses for " + anInterface, caught); + } + } + } + + // if nothing suitable was found then return loopback address. + if (allAddr.isEmpty() || Boolean.getBoolean("net.jxta.impl.IPUtils.localOnly")) { + if (null != LOOPBACKV4) { + allAddr.add(LOOPBACKV4); + } + + if (null != LOOPBACKV6) { + allAddr.add(LOOPBACKV6); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding loopback interfaces"); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Returning " + allAddr.size() + " addresses."); + } + + return allAddr.iterator(); + } + + /** + * Normalized version of {@link java.net.InetAddress#getHostAddress()} that + * handles IPv6 addresss formatting using the style of IETF RFC 2732 and + * also handles removal of IPv6 scoping identifiers. + * + * @see IETF RFC 2732 MIME : IPv6 Literal Addresses in URL's + * @param anAddress The address to format as a String. + * @return The addresss formatted as a String. + */ + public static String getHostAddress(InetAddress anAddress) { + String hostAddress; + + if (anAddress instanceof Inet6Address) { + hostAddress = anAddress.getHostAddress(); + int percentAt = hostAddress.indexOf('%'); + + if (-1 == percentAt) { + // no scoping identifier. Just add the brackets. + hostAddress = "[" + hostAddress + "]"; + } else { + // Remove scoping identifier. They aren't relevant when published. + hostAddress = "[" + hostAddress.substring(0, percentAt) + "]"; + } + } else { + hostAddress = anAddress.getHostAddress(); + } + + return hostAddress; + } + + /** + * Parses a String containing a SokectAddress formatted as either: + *

      + *

      +     *     <host> ":" <port>
      +     *
      +     *     "[" <numeric_host> "]:" <port>
      +     *  
      + *

      + * @param anAddress The address string to be parsed. + * @return The parsed address. + */ + public static InetSocketAddress parseSocketAddress(String anAddress) { + String hostAddress; + String port; + + if (anAddress.startsWith("[")) { + int endBracketAt = anAddress.indexOf(']'); + int portSeparatorAt = anAddress.lastIndexOf(':'); + + if (-1 == endBracketAt) { + throw new IllegalArgumentException("missing final ]"); + } + + if (-1 == portSeparatorAt) { + throw new IllegalArgumentException("missing port separator"); + } + + if (portSeparatorAt < endBracketAt) { + throw new IllegalArgumentException("missing port"); + } + + hostAddress = anAddress.substring(1, endBracketAt); + port = anAddress.substring(portSeparatorAt); + } else { + int portSeparatorAt = anAddress.lastIndexOf(':'); + + if (-1 == portSeparatorAt) { + throw new IllegalArgumentException("missing port separator"); + } + + hostAddress = anAddress.substring(0, portSeparatorAt); + port = anAddress.substring(portSeparatorAt + 1); + } + + int portNum = Integer.parseInt(port); + + return InetSocketAddress.createUnresolved(hostAddress, portNum); + } + + /** + * Create a client socket using the configured socketFactory or + * connectToFromNoFactory if none is available. + * + * @param inetAddress Destination address + * @param port Destination port + * @param usingInterface Interface to use + * @param localPort local port + * @param timeout timeout in millis + * @return a client socket with the JDK1.4 method connect(). + * @throws IOException if an io error occurs + */ + public static Socket connectToFrom(InetAddress inetAddress, int port, InetAddress usingInterface, int localPort, int timeout) throws IOException { + if (socketFactory != null) { + return socketFactory.createConnection(inetAddress, port, usingInterface, localPort, timeout); + } else { + return connectToFromNoFactory(inetAddress, port, usingInterface, localPort, timeout); + } + } + + /** + * Create a client socket with the JDK1.4 method connect(). + * + * @param inetAddress Destination address + * @param port Destination port + * @param usingInterface Interface to use + * @param localPort local port + * @param timeout timeout in millis + * @return a client socket with the JDK1.4 method connect(). + * @throws IOException if an io error occurs + */ + public static Socket connectToFromNoFactory(InetAddress inetAddress, int port, InetAddress usingInterface, int localPort, int timeout) throws IOException { + + Socket socket = new Socket(); + InetSocketAddress src = new InetSocketAddress(usingInterface, localPort); + InetSocketAddress dst = new InetSocketAddress(inetAddress, port); + + socket.bind(src); + socket.connect(dst, timeout); + + return socket; + } + + /** + * makes connectToFrom create sockets with this factory. + * + * @param sf is the socket factory to use or null if you want the + * default behaviour provided by connectToFromNoFactory(). + */ + public static void setSocketFactory(SocketFactory sf) { + socketFactory = sf; + } + + /** + * returns the socketFactory used by connectToFrom() to create sockets, or + * null if connectToFromNoFactory() is being used. + * + * @return the socket factory used by connectToFrom() or null if + * the connectToFromNoFactory() method is used to create Sockets. + */ + public static SocketFactory getSocketFactory() { + return socketFactory; + } + + /** + * makes connectToFrom create sockets with this factory. + * + * @param sf is the socket factory to use or null if you want the + * default behaviour provided by new SeverSocket(). + */ + public static void setServerSocketFactory(ServerSocketFactory sf) { + serverSocketFactory = sf; + } + + /** + * returns the ServerSocketFactory to create server sockets, or + * null if new SeverSocket() is being used. + * + * @return the socket factory used or null if + * the new SeverSocket() method is used to create ServerSockets. + */ + public static ServerSocketFactory getServerSocketFactory() { + return serverSocketFactory; + } + + /** + * Size of port groups we will probe. + */ + final static int rangesize = 200; + + /** + * Open a ServerSocket in the specified range. + * + *

      + * The method used is done so that the entire range is examined if + * needed while ensuring that the process eventually terminates if no port + * is available. + * + * @param start The lowest numbered port to try. + * @param end The highest numbered port to try. + * @param backlog the allowed backlog of unaccepted connections. + * @param bindAddress the InetAddress to which to bind. + * @return a ServerSocket in the specified range. + * @throws IOException when the socket cannot be opened. (Lame, but that's what ServerSocket says). + */ + public static ServerSocket openServerSocketInRange(int start, int end, int backlog, InetAddress bindAddress) throws IOException { + ServerSocketFactory factory = getServerSocketFactory(); + + if ((start < 1) || (start > 65535)) { + throw new IllegalArgumentException("Invalid start port"); + } + + if ((end < 1) || (end > 65535) || (end < start)) { + throw new IllegalArgumentException("Invalid end port"); + } + + // fill the inRange array. + List inRange = new ArrayList(rangesize); + + for (int eachInRange = 0; eachInRange < rangesize; eachInRange++) { + inRange.add(eachInRange, eachInRange); + } + + // fill the ranges array. + List ranges = new ArrayList(); + int starts = start; + + while (starts <= end) { + ranges.add(starts); + starts += rangesize; + } + + // shuffle the ranges + Collections.shuffle(ranges); + while (!ranges.isEmpty()) { + int range = ranges.remove(0); + + // reshuffle the inRange + Collections.shuffle(inRange); + + for (int eachInRange = 0; eachInRange < rangesize; eachInRange++) { + int tryPort = range + inRange.get(eachInRange); + + if (tryPort > end) { + continue; + } + + try { + ServerSocket result; + + if (null == factory) { + result = new ServerSocket(tryPort, backlog, bindAddress); + } else { + result = factory.createServerSocket(tryPort, backlog, bindAddress); + } + + return result; + } catch (BindException failed) {// this one is busy. try another. + } + } + } + throw new BindException("All ports in range are in use."); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/JxtaMessageMessageElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/JxtaMessageMessageElement.java new file mode 100644 index 000000000..6084fd323 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/JxtaMessageMessageElement.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint; + + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.WireFormatMessageFactory; + + +/** + * A Message Element using a JXTA Message as the element data + * + * @see net.jxta.endpoint.Message + * @see net.jxta.endpoint.MessageElement + **/ +public class JxtaMessageMessageElement extends MessageElement { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(JxtaMessageMessageElement.class.getName()); + + /** + * The Message which is the data for this message element. + **/ + protected final Message msg; + + /** + * A serialized form of the message. + **/ + protected transient net.jxta.endpoint.WireFormatMessage serial; + + /** + * Create a new Message Element. The contents of the provided message are + * not copied during construction. + * + * @param name Name of the MessageElement. May be the empty string ("") if + * the MessageElement is not named. + * @param type Type of the MessageElement. null is the same as specifying + * the type "Application/Octet-stream". + * @param msg A message which will be used as the element content for this + * message. + * @param sig optional message digest/digital signature element or null if + * no signature is desired. + **/ + public JxtaMessageMessageElement(String name, MimeMediaType type, Message msg, MessageElement sig) { + super(name, type, sig); + + this.msg = msg; + } + + /** + * {@inheritDoc} + **/ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof MessageElement) { + if (!super.equals(target)) { + return false; + } + + if (target instanceof JxtaMessageMessageElement) { + JxtaMessageMessageElement likeMe = (JxtaMessageMessageElement) target; + + return super.equals(likeMe) && msg.equals(likeMe.msg); + } else { + // have to do a slow stream comparison. + // XXX 20020615 bondolo@jxta.org the performance of this could be much improved. + try { + MessageElement likeMe = (MessageElement) target; + + InputStream myStream = getStream(); + InputStream itsStream = likeMe.getStream(); + + int mine; + int its; + + do { + mine = myStream.read(); + its = itsStream.read(); + + if (mine != its) { + return false; + } // content didn't match (includes EOF check). + + } while (-1 != mine); + + return true; + } catch (IOException fatal) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "MessageElements could not be compared.", fatal); + } + + IllegalStateException failure = new IllegalStateException("MessageElements could not be compared."); + + failure.initCause(fatal); + + throw failure; + } + } + } + + return false; // not a message element + } + + /** + * {@inheritDoc} + **/ + @Override + public int hashCode() { + int result = super.hashCode() * 6037 + // a prime + msg.hashCode(); + + return (0 != result) ? result : 1; + } + + /** + * {@inheritDoc} + **/ + @Override + public String toString() { + throw new UnsupportedOperationException("Cannot Generate String for this message element type."); + } + + /** + * {@inheritDoc} + **/ + @Override + public long getByteLength() { + initSerial(); + + return serial.getByteLength(); + } + + /** + * {@inheritDoc} + **/ + @Override + public byte[] getBytes(boolean copy) { + initSerial(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream((int) serial.getByteLength()); + + try { + sendToStream(baos); + + baos.close(); + } catch (IOException failed) { + throw new IllegalStateException("failed to generate byte stream"); + } + + return baos.toByteArray(); + } + + /** + * {@inheritDoc} + **/ + public InputStream getStream() throws IOException { + initSerial(); + + return serial.getStream(); + } + + /** + * {@inheritDoc} + **/ + @Override + public void sendToStream(OutputStream sendTo) throws IOException { + initSerial(); + + serial.sendToStream(sendTo); + } + + /** + * Returns a copy of the message which backs this element. + * + * @return Returns a copy of the message which backs this element. + **/ + public Message getMessage() { + return msg.clone(); + } + + /** + * Generates the serialized representation of the message. + **/ + private synchronized void initSerial() { + if (null == serial) { + serial = WireFormatMessageFactory.toWire(msg, type, null); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/LoopbackMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/LoopbackMessenger.java new file mode 100644 index 000000000..37d0748db --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/LoopbackMessenger.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import net.jxta.impl.peergroup.GenericPeerGroup; +import net.jxta.peergroup.PeerGroup; + + +/** + * This class implements local delivery of messages (for example when the + * InputPipe and the OutputPipe are located on the same peer) + *

      + * The reason this class is useful is that it may not always be possible to + * connect to oneself without actually through the relay. i.e. A peer with outgoing + * only http transport, can not possibly connect to self through the transport. + *

      + * Since transports cannot be relied on to perform a loopback, some layer + * above has to figure out that a message is looping back. + * Since peerid loopback does not explicitly request to go through a real + * transport, and since peerid addressing is the job of the router, it is + * the router that performs loopback. + *

      + * The router could probably perform the loopback by delivering the message + * to its own input queue, that would take a special transport instead of a + * special messenger, which is the same kind of deal but would imply some + * incoming message processing by the router for every message. In + * contrast, the loopback messenger is setup once and the router will never + * sees the messages. That's a good optimization. + *

      + * Alternatively, the endpoint service itself could figure out the + * loopback, but since the API wants to give a messenger to the requestor + * rather than just sending a message, the endpoint would have to setup a + * loopback messenger anyway. So it is pretty much the same. + */ +public class LoopbackMessenger extends BlockingMessenger { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(LoopbackMessenger.class.getName()); + + /** + * The peergroup we are working for, ie. that we will loop back to. + */ + private final PeerGroup group; + + /** + * The endpoint we are working for, ie. that we will loop back to. + */ + private final EndpointService endpoint; + + /** + * The source address of messages sent on this messenger. + */ + private final EndpointAddress srcAddress; + + /** + * The location destination of this messenger. + */ + private final EndpointAddress logicalDestination; + + /** + * Used to ensure that only a single message is demuxed at a time. + */ + private final Lock orderingLock = new ReentrantLock(true); + + /** + * Create a new loopback messenger. + * + * @param group The group context. + * @param ep where messages go + * @param src who messages should be addressed from + * @param dest who messages should be addressed to + * @param logicalDest The logical destination address. + */ + public LoopbackMessenger(PeerGroup group, EndpointService ep, EndpointAddress src, EndpointAddress dest, EndpointAddress logicalDest) { + super(group.getPeerGroupID(), dest, false); + + this.group = group; + endpoint = ep; + srcAddress = src; + logicalDestination = logicalDest; + } + + /** + * {@inheritDoc} + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + return logicalDestination; + } + + /** + * {@inheritDoc} + */ + @Override + public long getMTU() { + return Long.MAX_VALUE; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdleImpl() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void closeImpl() {} + + /** + * {@inheritDoc} + */ + @Override + public void sendMessageBImpl(final Message message, final String service, final String serviceParam) throws IOException { + + if (isClosed()) { + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failure.getMessage(), failure); + } + throw failure; + } + + orderingLock.lock(); + try { + // Process the message with the appropriate src and dest address + ((GenericPeerGroup)group).getExecutor().execute( new Runnable() { + public void run() { + try { + endpoint.processIncomingMessage(message, srcAddress, getDestAddressToUse(service, serviceParam)); + } catch(Throwable uncaught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable in Loopback Messenger ", uncaught); + } + } + } + }); + } finally { + orderingLock.unlock(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/SocketFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/SocketFactory.java new file mode 100644 index 000000000..a11949487 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/SocketFactory.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint; + + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; + + +/** + * Provides pluggable socket creation for JXTA TCP connection (not + * those for HTTP since those are from URLConnection). + * + *

      The motivation for this class was to provide the ability to + * tunnel JXTA TCP through a web proxy but it could be used for other + * things as well. Call IPUtils.setSocketFactory() to configure JXTA + * to use a particular socket factory

      + * + * @author Mike Sample + */ +public interface SocketFactory { + + /** + * creates and returns a connected Socket. + * + * @param inetAddress the destination IP address used to create an + * InetSocketAddress that will be used with the connect() call on + * the created socket. + * + * @param port the destination TCP port used to create an + * InetSocketAddress that will be used with the connect() call on + * the created socket. + * + * @param usingInterface the src (local) IP address used to create + * an InetSocketAddress to which the created socket will be bound + * via bind(). + * + * @param localPort the src (local) TCP port used to create an + * InetSocketAddress to which the created socket will be bound via + * bind(). + * + * @param timeout the time in milliseconds to be used with the + * socket.connect() call. A value of zero means infinite timeout. + * + */ + public Socket createConnection(InetAddress inetAddress, int port, InetAddress usingInterface, int localPort, int timeout) throws IOException; + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/WireFormatMessageBinary.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/WireFormatMessageBinary.java new file mode 100644 index 000000000..92e358763 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/WireFormatMessageBinary.java @@ -0,0 +1,1280 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint; + + +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.util.LimitInputStream; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.SequenceInputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.nio.ByteBuffer; +import java.text.MessageFormat; +import java.util.Arrays; + + +/** + * A Wire Format Message which encodes the message into MIME Type + * "application/x-jxta-msg". + *

      + *

      This implementation does nothing with encodings. + *

      + *

      This implementation does not use any MIME parameters attached to the + * requesting mime type. + * + * @see net.jxta.endpoint.WireFormatMessageFactory + * @see JXTA Protocols Specification : Binary Message Format + */ +public class WireFormatMessageBinary implements WireFormatMessage { + + /* + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(WireFormatMessageBinary.class.getName()); + + // Flag bits + protected static final byte HAS_TYPE = 0x01; + protected static final byte HAS_ENCODING = 0x02; + protected static final byte HAS_SIGNATURE = 0x04; + + protected static final int MESSAGE_VERSION = 0; + + /** + * Our Mime Media Type(s) + */ + private static final MimeMediaType[] myTypes = { + MimeMediaType.valueOf("application/x-jxta-msg") }; + + /** + * These are the content encodings we support. + */ + private static final MimeMediaType[] myContentEncodings = { + + // we support raw binary! + null + }; + + /** + * Our instantiator for the factory. + */ + public static final WireFormatMessageFactory.Instantiator INSTANTIATOR = new Instantiator(); + + /** + * Our instantiator. + */ + static class Instantiator implements WireFormatMessageFactory.Instantiator { + + /** + * Creates new WireFormatMessageBinary Instantiator + */ + public Instantiator() {} + + /** + * {@inheritDoc} + */ + public MimeMediaType[] getSupportedMimeTypes() { + return myTypes; + } + + /** + * {@inheritDoc} + */ + public MimeMediaType[] getSupportedContentEncodings() { + return myContentEncodings; + } + + /** + * {@inheritDoc} + */ + public Message fromWire(InputStream is, MimeMediaType type, MimeMediaType contentEncoding) throws IOException { + // FIXME 20020504 bondolo@jxta.org Ignores type and contentEncoding completely. + Message msg = new Message(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reading " + msg + " from " + is); + } + + DataInputStream dis = new DataInputStream(is); + + HashMap idToNamespace = readHeader(dis); + + int elementCnt = dis.readShort(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Message element count " + elementCnt + " from " + is); + } + + int eachElement = 0; + + do { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Read element " + eachElement + " of " + elementCnt + " from " + is + " for " + msg); + } + + Object[] anElement; + + try { + anElement = readMessageElement(dis, is); + } catch (IOException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE + , + "Failure reading element " + eachElement + " of " + elementCnt + " from " + is + " for " + msg + , + failed); + } + + throw failed; + } + + if (null == anElement) { + break; + } + + String namespace = (String) idToNamespace.get(anElement[0]); + + if (null == namespace) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Element identified a namespace which was not defined for this message."); + } + + throw new IOException("Element identified a namespace which was not defined for this message."); + } + + msg.addMessageElement(namespace, (MessageElement) anElement[1]); + eachElement++; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Add element (name=\'" + ((MessageElement) anElement[1]).getElementName() + "\') #" + eachElement + + " of #" + elementCnt + " elements from " + dis.toString()); + } + } while (((0 == elementCnt) || (eachElement < elementCnt))); + + if ((elementCnt != 0) && (eachElement != elementCnt)) { + throw new IOException("Found wrong number of elements in message."); + } + + return msg; + } + + public Message fromBuffer(ByteBuffer buffer, MimeMediaType type, MimeMediaType contentEncoding) throws IOException { + // FIXME 20020504 bondolo@jxta.org Ignores type and contentEncoding completely. + Message msg = new Message(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reading " + msg + " from " + buffer); + } + + HashMap idToNamespace = readHeader(buffer); + + int elementCnt = buffer.getShort(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Message element count " + elementCnt + " from " + buffer); + } + + int eachElement = 0; + + do { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Read element " + eachElement + " of " + elementCnt + " from " + buffer + " for " + msg); + } + + Object[] anElement; + + try { + anElement = readMessageElement(buffer); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + MessageFormat.format("Read element of size {0}, [{1}] {2}", anElement.length, anElement.toString() + , + buffer.toString())); + } + } catch (IOException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE + , + "Failure reading element " + eachElement + " of " + elementCnt + " from " + buffer + " for " + msg + , + failed); + } + throw failed; + } + + if (null == anElement) { + break; + } + + String namespace = (String) idToNamespace.get(anElement[0]); + + if (null == namespace) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Element identified a namespace which was not defined for this message."); + } + throw new IOException("Element identified a namespace which was not defined for this message."); + } + + msg.addMessageElement(namespace, (MessageElement) anElement[1]); + eachElement++; + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Add element (name=\'" + ((MessageElement) anElement[1]).getElementName() + "\') #" + eachElement + + " of #" + elementCnt + " elements from " + buffer.toString()); + } + } while (((0 == elementCnt) || (eachElement < elementCnt))); + + if ((elementCnt != 0) && (eachElement != elementCnt)) { + throw new IOException("Found wrong number of elements in message."); + } + + return msg; + } + + /** + * {@inheritDoc} + */ + public WireFormatMessage toWire(Message msg, MimeMediaType type, MimeMediaType[] preferedContentEncoding) { + try { + return new WireFormatMessageBinary(msg, type, preferedContentEncoding); + } catch (IOException caught) { + throw new IllegalStateException("Could not build wire format for message due to " + caught.getMessage()); + } + } + + /** + * Read in a message header from the provided data stream. + * + * @param dis the data stream to read from + * @return hashmap containing the namespace id to namespace values + * @throws IOException if EOF or other IOException is encountered + * during the reading of the header. + */ + private static HashMap readHeader(DataInputStream dis) throws IOException { + // Read message signature + char[] msgsig = new char[4]; + + try { + msgsig[0] = (char) dis.readByte(); + } catch (EOFException failed) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "EOF reading message at first byte of header.", failed); + } + + throw failed; + } + msgsig[1] = (char) dis.readByte(); + msgsig[2] = (char) dis.readByte(); + msgsig[3] = (char) dis.readByte(); + + if (msgsig[0] != 'j' || msgsig[1] != 'x' || msgsig[2] != 'm' || msgsig[3] != 'g') { + IOException failure = new IOException( + "Not a message (incorrect signature '" + msgsig[0] + msgsig[1] + msgsig[2] + msgsig[3] + "') "); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe(failure.toString()); + } + + throw failure; + } + + // Message version + if (dis.readByte() != MESSAGE_VERSION) { + IOException failure = new IOException("Message not version " + MESSAGE_VERSION); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + + throw failure; + } + + int namespaceCnt = dis.readShort(); + + if (namespaceCnt > 253) { + IOException failure = new IOException("Message contains too many namespaces (>253)"); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + + throw failure; + } + + HashMap id2namespace = new HashMap(2 + namespaceCnt); + + id2namespace.put(0, ""); + id2namespace.put(1, "jxta"); + + int id = 2; + + for (int i = 0; i < namespaceCnt; ++i) { + try { + String namespace = readString(dis); + + id2namespace.put(id++, namespace); + } catch (IOException caught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error Processing namespace", caught); + } + throw caught; + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Read Message Header with " + (namespaceCnt + 2) + " namespaces from " + dis.toString()); + } + + return id2namespace; + } + + /** + * Read in a message header from the provided data stream. + * + * @param buffer the data buffer to read from + * @return hashmap containing the namespace id to namespace values + * @throws IOException if EOF or other IOException is encountered + * during the reading of the header. + */ + private static HashMap readHeader(ByteBuffer buffer) throws IOException { + // Read message signature + char[] msgsig = new char[4]; + + msgsig[0] = (char) buffer.get(); + msgsig[1] = (char) buffer.get(); + msgsig[2] = (char) buffer.get(); + msgsig[3] = (char) buffer.get(); + + if (msgsig[0] != 'j' || msgsig[1] != 'x' || msgsig[2] != 'm' || msgsig[3] != 'g') { + IOException failure = new IOException( + "Not a message (incorrect signature '" + msgsig[0] + msgsig[1] + msgsig[2] + msgsig[3] + "') "); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe(failure.toString()); + } + throw failure; + } + + // Message version + if (buffer.get() != MESSAGE_VERSION) { + IOException failure = new IOException("Message not version " + MESSAGE_VERSION); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + throw failure; + } + + int namespaceCnt = buffer.getShort(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("Message defines {0} namespaces buffer stats{1}", namespaceCnt, buffer.toString())); + } + + if (namespaceCnt > 253) { + IOException failure = new IOException( + MessageFormat.format("Message contains too many namespaces ({0} >253)", namespaceCnt)); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + + throw failure; + } + + HashMap id2namespace = new HashMap(2 + namespaceCnt); + + id2namespace.put(0, ""); + id2namespace.put(1, "jxta"); + + int id = 2; + + for (int i = 0; i < namespaceCnt; ++i) { + try { + String namespace = readString(buffer); + + id2namespace.put(id++, namespace); + } catch (IOException caught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error Processing namespace", caught); + } + throw caught; + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Read Message Header with " + (namespaceCnt + 2) + " namespaces from " + buffer.toString()); + } + + return id2namespace; + } + + /** + * Read in a message element from the provided data stream. + * + * @param dis the data stream to read from + * @param is todo + * @return object array containing two objects, index[0] contains an + * Integer which identifies the namespace to which this element belongs + * and index[1] contains a MessageElement. If null is returned then + * the DataInputStream reached EOF before reading the first byte of the + * element. + * @throws IOException if EOF or other IOException is encountered + * during the reading of the element. + */ + private Object[] readMessageElement(DataInputStream dis, InputStream is) throws IOException { + // Read message signature + char[] elsig = new char[4]; + + // if we EOF before the first byte, return null. EOF anywhere else + // and its an error. + try { + elsig[0] = (char) dis.readByte(); + } catch (EOFException allDone) { + return null; + } + + elsig[1] = (char) dis.readByte(); + elsig[2] = (char) dis.readByte(); + elsig[3] = (char) dis.readByte(); + + if (elsig[0] != 'j' || elsig[1] != 'x' || elsig[2] != 'e' || elsig[3] != 'l') { + IOException failure = new IOException( + "Not a message element (incorrect signature '" + elsig[0] + elsig[1] + elsig[2] + elsig[3] + "') "); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + + throw failure; + } + + // Namespace id + int nsid = dis.readByte(); + + // flags + byte flags = dis.readByte(); + + // Name + String name = readString(dis); + + // Mime type + MimeMediaType type; + + if ((flags & HAS_TYPE) != 0) { + String typeString = readString(dis); + + try { + type = new MimeMediaType(typeString); + } catch (IllegalArgumentException uhoh) { + throw new IOException("Bad MIME type in message element header : " + uhoh.getMessage()); + } + } else { + type = MimeMediaType.AOS; + } + + int dataLen = dis.readInt(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "element : nsid = " + nsid + " name = \'" + name + "\' type = \'" + type + "\' flags = " + + Integer.toBinaryString(flags) + " datalen = " + dataLen); + } + + Object[] res = new Object[2]; + + res[0] = nsid & 0x000000FF; + + byte[] value = null; + Message submsg = null; + + // Value + if (type.equalsIngoringParams(myTypes[0])) { + InputStream subis = new LimitInputStream(is, dataLen); + + submsg = WireFormatMessageFactory.fromWire(subis, type, null); + } else { + if (dataLen > Integer.MAX_VALUE) { + // FIXME hamada dataLen is an int, the above expression can never be true + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("WireFormatMessageBinary does not support elements longer than 2GB"); + } + throw new IllegalStateException("WireFormatMessageBinary does not support elements longer than 2GB"); + } + + value = new byte[dataLen]; + + String mayFail = null; + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + mayFail = is.toString(); + } + + try { + dis.readFully(value); + } catch (EOFException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("had tried to read " + dataLen + " from " + mayFail + " which is now " + is); + } + throw failed; + } + } + + MessageElement sig = null; + + if ((flags & HAS_SIGNATURE) != 0) { + Object[] sigRes = readMessageElement(dis, is); + + sig = (MessageElement) sigRes[1]; + } + + if (null != value) { + res[1] = new ByteArrayMessageElement(name, type, value, sig); + } else { + res[1] = new JxtaMessageMessageElement(name, type, submsg, sig); + } + + return res; + } + + /** + * Read in a message element from the provided data stream. + * + * @param buffer the data buffer to read from + * @return object array containing two objects, index[0] contains an + * Integer which identifies the namespace to which this element belongs + * and index[1] contains a MessageElement. If null is returned then + * the DataInputStream reached EOF before reading the first byte of the + * element. + * @throws IOException if EOF or other IOException is encountered + * during the reading of the element. + */ + private Object[] readMessageElement(ByteBuffer buffer) throws IOException { + // Read message signature + char[] elsig = new char[4]; + + // if we EOF before the first byte, return null. EOF anywhere else + // and its an error. + elsig[0] = (char) buffer.get(); + elsig[1] = (char) buffer.get(); + elsig[2] = (char) buffer.get(); + elsig[3] = (char) buffer.get(); + + if (elsig[0] != 'j' || elsig[1] != 'x' || elsig[2] != 'e' || elsig[3] != 'l') { + IOException failure = new IOException( + "Not a message element (incorrect signature '" + elsig[0] + elsig[1] + elsig[2] + elsig[3] + "') "); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failure.getMessage(), failure); + } + + throw failure; + } + + // Namespace id + int nsid = buffer.get(); + + // flags + byte flags = buffer.get(); + + // Name + String name = readString(buffer); + + // Mime type + MimeMediaType type; + + if ((flags & HAS_TYPE) != 0) { + String typeString = readString(buffer); + + try { + type = new MimeMediaType(typeString); + } catch (IllegalArgumentException uhoh) { + throw new IOException("Bad MIME type in message element header : " + uhoh.getMessage()); + } + } else { + type = MimeMediaType.AOS; + } + + int dataLen = buffer.getInt(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "element : nsid = " + nsid + " name = \'" + name + "\' type = \'" + type + "\' flags = " + + Integer.toBinaryString(flags) + " datalen = " + dataLen); + } + + Object[] res = new Object[2]; + + res[0] = nsid & 0x000000FF; + + byte[] value = null; + Message submsg = null; + + // Value + if (type.equalsIngoringParams(myTypes[0])) { + InputStream subis = new ByteArrayInputStream(buffer.array(), buffer.position(), dataLen); + + submsg = WireFormatMessageFactory.fromWire(subis, type, null); + // buffer.position(buffer.position() + dataLen); + } else { + if (dataLen > Integer.MAX_VALUE) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("WireFormatMessageBinary does not support elements longer than 2GB"); + } + throw new IllegalStateException("WireFormatMessageBinary does not support elements longer than 2GB"); + } + + value = new byte[dataLen]; + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("expecting {0} bytes, Buffer stats {1}", dataLen, buffer.toString())); + } + buffer.get(value); + } + + MessageElement sig = null; + + if ((flags & HAS_SIGNATURE) != 0) { + Object[] sigRes = readMessageElement(buffer); + + sig = (MessageElement) sigRes[1]; + } + + if (null != value) { + res[1] = new ByteArrayMessageElement(name, type, value, sig); + } else { + res[1] = new JxtaMessageMessageElement(name, type, submsg, sig); + } + + return res; + } + + /** + * Read and construct a string from the data stream. + * + * @param dis the stream to read from + * @return the String which was read. + * @throws IOException if EOF or other IOException is encountered + * during the reading of the string. + */ + private static String readString(DataInputStream dis) throws IOException { + int len = dis.readShort(); + + if (len < 0) { + throw new IOException("Bad string length in message"); + } + + byte[] bytes = new byte[len]; + + dis.readFully(bytes); + return new String(bytes, "UTF8"); + } + + /** + * Read and construct a string from the data stream. + * + * @param buffer the ByteBuffer to read from + * @return the String which was read. + * @throws IOException if EOF or other IOException is encountered + * during the reading of the string. + */ + private static String readString(ByteBuffer buffer) throws IOException { + int len = buffer.getShort(); + + if (len < 0) { + throw new IOException("Bad string length in message"); + } + + byte[] bytes = new byte[len]; + + buffer.get(bytes); + return new String(bytes, "UTF8"); + } + } + + + /** + * Internal representation for a binary format wire message. Implemented + * as an inner class to allow content encodings to be easily mapped on + * top of the streams this class produces. + */ + static class binaryMessageProxy implements WireFormatMessage { + final Message message; + + final MimeMediaType type; + + final List elements = new ArrayList(); + + final Map namespaceIDs = new HashMap(); + + final List namespaces = new ArrayList(); + + byte[] header; + + binaryMessageProxy(Message msg, MimeMediaType type) throws IOException { + message = msg; + + this.type = type; // we may generate different content based upon the type. + + assignNamespaceIds(); + + // build the element proxies + Message.ElementIterator eachElement = message.getMessageElements(); + + while (eachElement.hasNext()) { + MessageElement anElement = eachElement.next(); + byte namespaceid = namespaceIDs.get(eachElement.getNamespace()).byteValue(); + + elements.add(new binaryElementProxy(namespaceid, anElement)); + } + + buildHeader(); + } + + /** + * {@inheritDoc} + */ + public String getFileExtension() { + return "???"; + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getMimeType() { + return type; + } + + /** + * {@inheritDoc} + */ + public ByteBuffer[] getByteBuffers() { + List partBuffers = new ArrayList(); + + partBuffers.add(ByteBuffer.wrap(header)); + + for (binaryElementProxy anElement : elements) { + partBuffers.addAll(Arrays.asList(anElement.getByteBuffers())); + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("Returning {0} buffers for {1}", partBuffers.size(), message)); + } + + return partBuffers.toArray(new ByteBuffer[partBuffers.size()]); + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting stream for " + message); + } + + List streamParts = new ArrayList(); + + streamParts.add(new ByteArrayInputStream(header)); + + for (binaryElementProxy anElement : elements) { + streamParts.add(anElement.getStream()); + } + + InputStream theStream = new SequenceInputStream(Collections.enumeration(streamParts)); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + MessageFormat.format("Returning {0}@{1} for {2}", theStream.getClass().getName() + , + System.identityHashCode(theStream), message)); + } + + return theStream; + } + + /** + * {@inheritDoc} + */ + public void sendToStream(OutputStream sendTo) throws IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + message + " to " + sendTo.getClass().getName() + "@" + System.identityHashCode(sendTo)); + } + + sendTo.write(header); + + Iterator eachElement = elements.listIterator(); + + while (eachElement.hasNext()) { + binaryElementProxy anElement = (binaryElementProxy) eachElement.next(); + + anElement.sendToStream(sendTo); + } + } + + /** + * {@inheritDoc} + */ + public long getByteLength() { + long size = 0; + + size += header.length; + for (binaryElementProxy element : elements) { + binaryElementProxy anElement = element; + + size += anElement.getByteLength(); + } + return size; + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getContentEncoding() { + return null; + } + + /** + * Scans the source message to build a HashMap of the namespaces used + * in the message and assign and id to each namespace. + */ + private void assignNamespaceIds() { + int id = 0; + Iterator namespaces = message.getMessageNamespaces(); + + // insert the predefined namespaces. + namespaceIDs.put("", id++); + this.namespaces.add(""); + namespaceIDs.put("jxta", id++); + this.namespaces.add("jxta"); + + // insert items in the vector if they are not found in the map + while (namespaces.hasNext()) { + String namespace = (String) namespaces.next(); + + if (namespaceIDs.get(namespace) == null) { + namespaceIDs.put(namespace, id++); + this.namespaces.add(namespace); + } + } + + if (id >= 256) { + throw new IllegalStateException("WireFormatMessageBinary does not support more than 255 namespaces"); + } + } + + /** + * Builds the wire format header for the message. + * + * @throws IOException if for some reason the header cannot be built. + */ + private void buildHeader() throws IOException { + ByteArrayOutputStream headerBytes = new ByteArrayOutputStream(256); + DataOutputStream header = new DataOutputStream(headerBytes); + + header.writeBytes("jxmg"); + + header.writeByte(MESSAGE_VERSION); + header.writeShort(namespaces.size() - 2); + + for (int eachNamespace = 2; eachNamespace < namespaces.size(); eachNamespace++) { + byte[] elementName = namespaces.get(eachNamespace).getBytes("UTF8"); + + header.writeShort(elementName.length); + header.write(elementName, 0, elementName.length); + } + + header.writeShort(elements.size()); + + header.flush(); + header.close(); + headerBytes.flush(); + headerBytes.close(); + + this.header = headerBytes.toByteArray(); + } + } + + + /** + * Proxy for a message element. Handles the serialization of the element + * meta information. + */ + static class binaryElementProxy { + final byte namespaceid; + + binaryElementProxy sig; + + MessageElement element; + + byte[] header; + + binaryElementProxy(byte namespaceid, MessageElement element) throws IOException { + this.namespaceid = namespaceid; + + this.element = element; + + MessageElement sig = element.getSignature(); + + if (null != sig) { + this.sig = new binaryElementProxy(namespaceid, sig); + } + + buildHeader(); + } + + void buildHeader() throws IOException { + byte[] elementName = element.getElementName().getBytes("UTF8"); + byte[] elementType = null; + + if (!MimeMediaType.AOS.equals(element.getMimeType())) { + elementType = element.getMimeType().toString().getBytes("UTF8"); + } + + // FIXME 20020504 bondolo@jxta.org Do something with encodings. + ByteArrayOutputStream headerBytes = new ByteArrayOutputStream(256); + DataOutputStream header = new DataOutputStream(headerBytes); + + header.writeBytes("jxel"); + + header.writeByte(namespaceid); + header.writeByte(((null != elementType) ? HAS_TYPE : 0) | ((null != sig) ? HAS_SIGNATURE : 0)); + + header.writeShort(elementName.length); + header.write(elementName, 0, elementName.length); + + if (null != elementType) { + header.writeShort(elementType.length); + header.write(elementType, 0, elementType.length); + } + + // FIXME content encoding should go here + + long dataLen = element.getByteLength(); + + if (dataLen > Integer.MAX_VALUE) { + throw new IllegalStateException("WireFormatMessageBinary does not support elements longer than 4GB"); + } + + header.writeInt((int) dataLen); + + header.flush(); + header.close(); + headerBytes.flush(); + headerBytes.close(); + + this.header = headerBytes.toByteArray(); + } + + public long getByteLength() { + long size = 0; + + size += header.length; + size += element.getByteLength(); + if (null != sig) { + size += sig.getByteLength(); + } + + return size; + } + + public ByteBuffer[] getByteBuffers() { + List partBuffers = new ArrayList(); + + partBuffers.add(ByteBuffer.wrap(header)); + + partBuffers.add(ByteBuffer.wrap(element.getBytes(false))); + + if (null != sig) { + partBuffers.addAll(Arrays.asList(sig.getByteBuffers())); + } + + return partBuffers.toArray(new ByteBuffer[partBuffers.size()]); + } + + public InputStream getStream() throws IOException { + List streamParts = new ArrayList(); + + streamParts.add(new ByteArrayInputStream(header)); + + streamParts.add(element.getStream()); + + if (null != sig) { + streamParts.add(sig.getStream()); + } + + return new SequenceInputStream(Collections.enumeration(streamParts)); + } + + public void sendToStream(OutputStream sendTo) throws IOException { + + sendTo.write(header); + element.sendToStream(sendTo); + if (null != sig) { + sig.sendToStream(sendTo); + } + } + } + + /** + * The message we are serializing. + */ + private final Message msg; + + /** + * The mod count of the message when we started. Used for detecting + * (illegal) modifications. + */ + private final int msgModCount; + + /** + * The mime type of the encoded message. + */ + private final MimeMediaType type; + + /** + * The mime type of the content encoding for this message. + */ + private final MimeMediaType contentEncoding; + + /** + * The serialization peer to the Message. + */ + private final binaryMessageProxy msgProxy; + + /** + * Creates a new instance of WireFormatMessageBinary. Called only by the + * Instantiator. + * + * @param msg the message being serialized + * @param type the mime mediatype being requested. + * @param preferedContentEncodings The ranked content encodings preferred by + * the recipient. + * @throws java.io.IOException if an io error occurs + */ + WireFormatMessageBinary(Message msg, MimeMediaType type, MimeMediaType[] preferedContentEncodings) throws IOException { + if (null == msg) { + throw new IllegalArgumentException("Null message!"); + } + + this.msg = msg; + + this.msgModCount = msg.getMessageModCount(); + + if (null == type) { + throw new IllegalArgumentException("Null mime type!"); + } + + int matchedIdx = -1; + + for (int eachType = 0; eachType < myTypes.length; eachType++) { + if (type.equalsIngoringParams(myTypes[eachType])) { + matchedIdx = eachType; + break; + } + } + + if (-1 == matchedIdx) { + throw new IllegalArgumentException("Unsupported mime type!"); + } + + // FIXME 20020504 bondolo@jxta.org Check the mimetype params to make + // sure we can support them. + this.type = type; + + // FIXME 20020504 bondolo@jxta.org Do something with encodings. + this.contentEncoding = myContentEncodings[0]; + + msgProxy = new binaryMessageProxy(msg, type); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + throw new UnsupportedOperationException("don't do this"); + } + + /* + * The cost of just having a finalize routine is high. The finalizer is + * a bottleneck and can delay garbage collection all the way to heap + * exhaustion. Leave this comment as a reminder to future maintainers. + * Below is the reason why finalize is not needed here. + * + * No critical non-memory resource held. + protected void finalize( ) { + } + + */ + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + throw new UnsupportedOperationException("don't do this"); + } + + /** + * {@inheritDoc} + */ + public String getFileExtension() { + return "???"; + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getMimeType() { + return type; + } + + /** + * {@inheritDoc} + */ + public InputStream getStream() throws IOException { + if (msg.getMessageModCount() != msgModCount) { + throw new IllegalStateException("message was unexpectedly modified!"); + } + + msg.modifiable = false; + try { + InputStream result = msgProxy.getStream(); + + return result; + } finally { + msg.modifiable = true; + } + } + + /** + * {@inheritDoc} + */ + public ByteBuffer[] getByteBuffers() { + if (msg.getMessageModCount() != msgModCount) { + throw new IllegalStateException("message was unexpectedly modified!"); + } + + msg.modifiable = false; + try { + ByteBuffer[] result = msgProxy.getByteBuffers(); + + return result; + } finally { + msg.modifiable = true; + } + } + + /** + * {@inheritDoc} + */ + public void sendToStream(OutputStream sendTo) throws IOException { + if (msg.getMessageModCount() != msgModCount) { + throw new IllegalStateException("message was unexpectedly modified!"); + } + + msg.modifiable = false; + try { + msgProxy.sendToStream(sendTo); + } finally { + msg.modifiable = true; + } + } + + /** + * {@inheritDoc} + */ + public long getByteLength() { + if (msg.getMessageModCount() != msgModCount) { + throw new IllegalStateException("message was unexpectedly modified!"); + } + + return msgProxy.getByteLength(); + } + + /** + * {@inheritDoc} + */ + public MimeMediaType getContentEncoding() { + return contentEncoding; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxDefs.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxDefs.java new file mode 100644 index 000000000..135c07d0d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxDefs.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.cbjx; + + +import net.jxta.id.ID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; + +import java.net.URI; + + +/** + * the value of the constants used with cbid + */ +public final class CbJxDefs { + + /** + * the name of the algo to compute signature + */ + public static final String signAlgoName = "SHA1WITHRSA"; + + /** + * the name of the algo to digest of message + */ + public static final String hashAlgoName = "SHA-1"; + + /** + * Well known module class identifier: msg transport + */ + public static final ModuleClassID msgtptClassID = (ModuleClassID) + ID.create(URI.create("urn:jxta:uuid-DeadBeefDeafBabaFeedBabe0000001105")); + + /** + * Well known service specification identifier: cbjx Msg Transport + */ + public static final ModuleSpecID cbjxMsgTransportSpecID = (ModuleSpecID) + ID.create(URI.create("urn:jxta:uuid-DeadBeefDeafBabaFeedBabe000000110106")); + + /** + * static utility factory + */ + private CbJxDefs() {} +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxMessageInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxMessageInfo.java new file mode 100644 index 000000000..7ca0bd15a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxMessageInfo.java @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.cbjx; + + +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.membership.pse.PSEUtils; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * this class defines the xml document used to store message information + * that is useful for the cbjx endpoint + */ +public class CbJxMessageInfo { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(CbJxMessageInfo.class.getName()); + + /** + * the root element for the information's XML document + */ + private static final String DOCTYPE = "CbJxMessageInfo"; + + /** + * the element name for the peer certificate + */ + private static final String tagPeerCert = "PeerCert"; + + /** + * the element name of the destination address + */ + private static final String tagDestination = "DestinationAddress"; + + /** + * the element name of the source address + */ + private static final String tagSource = "SourceAddress"; + + /** + * the element name for the sourceID of the message + */ + private static final String tagSourceID = "SourceID"; + + /** + * the peer root cert + */ + private Certificate rootCert = null; + + /** + * the destination address of the message + */ + private EndpointAddress destinationAddress = null; + + /** + * the source address of the message + */ + private EndpointAddress sourceAddress = null; + + /** + * the source ID of the sender + */ + private ID sourceID = null; + + /** + * creates a new information object + */ + public CbJxMessageInfo() { + super(); + } + + /** + * creates a new Message information by parsing the given stream + * + * @param stream the InputStream source of the info data + * @throws IOException if the info can't be parsed from the stream + */ + public CbJxMessageInfo(InputStream stream, MimeMediaType type) throws IOException { + super(); + + XMLDocument document = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(type, stream); + + initialize(document); + } + + /** + * retrieve the peer certificate + * + * @return Certificate the peer certificate + */ + public Certificate getPeerCert() { + return rootCert; + } + + /** + * set the peer certificate + * + * @param cert the peer certificate + */ + public void setPeerCert(Certificate cert) { + rootCert = cert; + } + + /** + * retrieve the destination address of the message + * + * @return String the original destination address of the message + */ + public EndpointAddress getDestinationAddress() { + return destinationAddress; + } + + /** + * set the destination address of the message + * + * @param addr the destination address + */ + public void setDestinationAddress(EndpointAddress addr) { + destinationAddress = addr; + } + + /** + * retrieve the original source address of the message + * + * @return String the original source address of the message + */ + public EndpointAddress getSourceAddress() { + return sourceAddress; + } + + /** + * set the source address of the messsage + * + * @param addr the source address + */ + public void setSourceAddress(EndpointAddress addr) { + sourceAddress = addr; + } + + /** + * retrieve the source id of the message + * + * @return String the source id of the sender + */ + public ID getSourceID() { + return sourceID; + } + + /** + * set the source id of the message + * + * @param src the ID of the sender + */ + public void setSourceID(ID src) { + sourceID = src; + } + + /** + * returns a Document containing the information's document tree + * + * @param asMimeType the desired MIME type for the information rendering + * @return Document the Document containing the information's document tree + */ + public Document getDocument(MimeMediaType asMimeType) { + StructuredDocument document = StructuredDocumentFactory.newStructuredDocument(asMimeType, DOCTYPE); + + Element element; + + if (getPeerCert() == null) { + throw new IllegalStateException("Missing Peer Root Certificate"); + } + + try { + String base64cert = PSEUtils.base64Encode(getPeerCert().getEncoded()); + + element = document.createElement(tagPeerCert, base64cert); + document.appendChild(element); + } catch (Exception e) { + throw new IllegalStateException("Bad root cert! " + e); + } + + if (getSourceID() == null) { + throw new IllegalStateException("Missing Source ID"); + } + + element = document.createElement(tagSourceID, getSourceID().toString()); + document.appendChild(element); + + if (getDestinationAddress() == null) { + throw new IllegalStateException("Missing Destination Address"); + } + + element = document.createElement(tagDestination, getDestinationAddress().toString()); + document.appendChild(element); + + if (getSourceAddress() == null) { + throw new IllegalStateException("Missing Source Address"); + } + + element = document.createElement(tagSource, getSourceAddress().toString()); + document.appendChild(element); + + return document; + } + + /** + * Called to handle elements during parsing. + * + * @param elem Element to parse + * @return true if element was handled, otherwise false. + */ + protected boolean handleElement(XMLElement elem) { + if (elem.getName().equals(tagPeerCert)) { + try { + byte[] cert_der = PSEUtils.base64Decode(new StringReader(elem.getTextValue())); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + Certificate cert = cf.generateCertificate(new ByteArrayInputStream(cert_der)); + + setPeerCert(cert); + } catch (Exception e) { + throw new IllegalArgumentException("Bad X509 Cert!"); + } + return true; + } + + if (elem.getName().equals(tagDestination)) { + EndpointAddress destination = new EndpointAddress(elem.getTextValue()); + + setDestinationAddress(destination); + return true; + } + + if (elem.getName().equals(tagSource)) { + EndpointAddress source = new EndpointAddress(elem.getTextValue()); + + setSourceAddress(source); + return true; + } + + if (elem.getName().equals(tagSourceID)) { + + try { + URI sourcePeerURL = new URI(elem.getTextValue().trim()); + PeerID sourcePeerID = (PeerID) IDFactory.fromURI(sourcePeerURL); + + setSourceID(sourcePeerID); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerGroupID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a peer id: " + elem.getTextValue()); + } + return true; + } + + return false; + } + + /** + * internal method to process a document into an advertisement. + * + * @param root where to start. + */ + protected void initialize(Element root) { + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + if (!doctype.equals(DOCTYPE)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.getName()); + } + } + } + + // sanity checking time. + + if (null == rootCert) { + throw new IllegalArgumentException("Document did not contain a root cert element"); + } + + if (null == destinationAddress) { + throw new IllegalArgumentException("Document did not contain a destination address element"); + } + + if (null == sourceAddress) { + throw new IllegalArgumentException("Document did not contain a source address element"); + } + + if (null == sourceID) { + throw new IllegalArgumentException("Document did not contain a source ID element"); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxMessenger.java new file mode 100644 index 000000000..5d132c0ec --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxMessenger.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.cbjx; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.impl.endpoint.BlockingMessenger; +import net.jxta.logging.Logging; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class is the Messenger used to send CbJx Messages + */ +public class CbJxMessenger extends BlockingMessenger { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(CbJxMessenger.class.getName()); + + /** + * the new destination address computed by the CbJx Endpoint + * this address is of the form jxta:///CbJxService/ + */ + private final EndpointAddress newDestAddr; + + /** + * A string which we can lock on while acquiring new messengers. We don't + * want to lock the whole object. + */ + private final Object acquireMessengerLock = new String("Messenger Acquire Lock"); + + /** + * Cached messenger for sending to {@link #newDestAddr} + */ + private Messenger outBoundMessenger = null; + + /** + * The transport we are working for. + */ + private final CbJxTransport transport; + + /** + * constructor + * + * @param dest the destination address + */ + public CbJxMessenger(CbJxTransport transport, EndpointAddress dest, Object hintIgnored) throws IOException { + this(transport, dest); + } + + /** + * constructor + * + * @param dest the destination address + */ + public CbJxMessenger(CbJxTransport transport, EndpointAddress dest) throws IOException { + + // Do not use self destruction. There's nothing we have that can't just let be GC'ed + super(transport.group.getPeerGroupID(), dest, false); + + this.transport = transport; + + newDestAddr = new EndpointAddress("jxta", dest.getProtocolAddress(), CbJxTransport.cbjxServiceName, null); + + outBoundMessenger = transport.endpoint.getMessengerImmediate(newDestAddr, null); + + if (null == outBoundMessenger) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Could not get messenger for " + newDestAddr); + } + + throw new IOException("Could not get messenger for " + newDestAddr); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void closeImpl() { + synchronized (acquireMessengerLock) { + outBoundMessenger.close(); + outBoundMessenger = null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + return newDestAddr; + } + + /** + * {@inheritDoc} + *

      + * Since CbJx is a virtual transport and consumes very few resources there + * is no point to doing idle teardown. + */ + @Override + public boolean isIdleImpl() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void sendMessageBImpl(Message msg, String service, String serviceParam) throws IOException { + msg = msg.clone(); + + EndpointAddress destAddressToUse = getDestAddressToUse(service, serviceParam); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Messenger: sending out " + msg + " to: " + destAddressToUse); + } + + // add the cbjx info to the message + msg = transport.addCryptoInfo(msg, destAddressToUse); + + if (isClosed()) { + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info(failure.toString()); + } + + throw failure; + } + + // and sends out the message + sendTo( msg ); + } + + /** + * Send a message via the underlying messenger. + * + * @param msg The message to send to the remote peer. + * @throws IOException if there was a problem sending the message. + **/ + void sendTo( Message msg ) throws IOException { + + synchronized (acquireMessengerLock) { + if ((null == outBoundMessenger) || outBoundMessenger.isClosed()) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting messenger for " + newDestAddr); + } + + outBoundMessenger = transport.endpoint.getMessengerImmediate(newDestAddr, null); + + if (outBoundMessenger == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Could not get messenger for " + newDestAddr); + } + + throw new IOException("Underlying messenger could not be repaired"); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " to endpoint " + newDestAddr); + } + + // Good we have a messenger. Send the message. + outBoundMessenger.sendMessageB(msg, null, null); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxTransport.java new file mode 100644 index 000000000..142d33af3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxTransport.java @@ -0,0 +1,692 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.cbjx; + + +import net.jxta.document.Advertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.TextDocument; +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessageFilterListener; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.endpoint.JxtaMessageMessageElement; +import net.jxta.impl.membership.pse.PSECredential; +import net.jxta.impl.membership.pse.PSEMembershipService; +import net.jxta.impl.membership.pse.PSEUtils; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; + +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.interfaces.RSAPublicKey; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which + * which provides message verification by examining message signatures. A + * virtual transport, the messages are transfered between peers using some + * other message transport. + */ +public class CbJxTransport implements Module, MessageSender, MessageReceiver, EndpointListener { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(CbJxTransport.class.getName()); + + /** + * the name of the cbjx valid element + */ + public static final String CBJX_MSG_NS = "cbjx"; + + /** + * the name of the cbjx crypto element + */ + static final String CBJX_MSG_INFO = "CryptoInfo"; + + /** + * the name of the cbjx body element + */ + static final String CBJX_MSG_BODY = "Body"; + + /** + * the name of the cbjx body element + */ + static final String CBJX_MSG_SIG = "Signature"; + + /** + * the cbjx protocol name + */ + static final String cbjxProtocolName = "cbjx"; + + /** + * the cbjx service name + */ + static final String cbjxServiceName = "CbJxTransport"; + + /** + * the local peer ID + */ + static PeerID localPeerID = null; + + /** + * the endpoint address of this peer + */ + static EndpointAddress localPeerAddr = null; + + /** + * the peer group to which this module belongs + */ + PeerGroup group = null; + + /** + * the endpoint service in my group + */ + EndpointService endpoint = null; + + /** + * the membership service in my group + */ + PSEMembershipService membership = null; + + /** + * Default constructor + */ + public CbJxTransport() {} + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + this.group = group; + + ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) impl; + + localPeerID = group.getPeerID(); + + CbJxTransport.localPeerAddr = new EndpointAddress(cbjxProtocolName, group.getPeerID().getUniqueValue().toString(), null + , + null); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring CBJX Message Transport : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tPublic Address : ").append(CbJxTransport.localPeerAddr); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return START_AGAIN_STALLED; + } + + MembershipService groupMembership = group.getMembershipService(); + + if (null == groupMembership) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + return START_AGAIN_STALLED; + } + + if (!(groupMembership instanceof PSEMembershipService)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("CBJX Transport requires PSE Membership Service"); + } + return -1; + } + + membership = (PSEMembershipService) groupMembership; + + if (endpoint.addMessageTransport(this) == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + return -1; + } + + // XXX bondolo@jxta.org 20030526 check for errors + + endpoint.addIncomingMessageListener(this, cbjxServiceName, null); + + endpoint.addIncomingMessageFilterListener(new CbJxInputFilter(), null, null); + // endpoint.addOutgoingMessageFilterListener( new CbJxOutputFilter(), null, null ); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("CbJxTransport started"); + } + + return 0; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + + if (endpoint != null) { + // FIXME 20030516 bondolo@jxta.org remove filters and listener + + endpoint.removeMessageTransport(this); + endpoint = null; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("CbJxTransport stopped"); + } + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return CbJxTransport.localPeerAddr; + } + + /** + * {@inheritDoc} + */ + public boolean isConnectionOriented() { + // since we rely on other endpoint protocol we are not connection oriented + return false; + } + + /** + * {@inheritDoc} + */ + public boolean allowsRouting() { + // since we are using the endpoint router + // the endpoint router cannot use our endpoint to send messages + return false; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return (EndpointService) endpoint.getInterface(); + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object value) { + return null; + } + + /** + * {@inheritDoc} + */ + public Iterator getPublicAddresses() { + return Collections.singletonList(getPublicAddress()).iterator(); + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return cbjxProtocolName; + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress dest, Object hintIgnored) { + try { + return new CbJxMessenger(this, dest, hintIgnored); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to create cbjx messenger", failed); + } + return null; + } + } + + /** + * {@inheritDoc} + */ + @Deprecated + public boolean ping(EndpointAddress addr) { + Messenger messenger = getMessenger(addr, null); + + boolean reachable = (null != messenger); + + if (messenger != null) { + messenger.close(); + } + + return reachable; + } + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processIncomingMessage : Received message from: " + srcAddr); + } + + // extract the Crypto info from the message + MessageElement cryptoElement = message.getMessageElement(CBJX_MSG_NS, CBJX_MSG_INFO); + + if (cryptoElement == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processIncomingMessage : No \'" + CBJX_MSG_INFO + "\' in the message"); + } + return; + } + message.removeMessageElement(cryptoElement); + + // the cbjx message info + CbJxMessageInfo cryptoInfo = null; + + try { + cryptoInfo = new CbJxMessageInfo(cryptoElement.getStream(), cryptoElement.getMimeType()); + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING + , + "processIncomingMessage : Couldn\'t retrieve CbJxMessageInfo from \'" + CBJX_MSG_INFO + "\' element", e); + } + return; + } + + Message submessage = checkCryptoInfo(message, cryptoElement, cryptoInfo); + + if (null == submessage) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("processIncomingMessage : discarding message from " + srcAddr); + } + return; + } + + // give back the message to the endpoint + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processIncomingMessage: delivering " + submessage + " to: " + cryptoInfo.getDestinationAddress()); + } + + endpoint.processIncomingMessage(submessage, cryptoInfo.getSourceAddress(), cryptoInfo.getDestinationAddress()); + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "processIncomingMessage: endpoint failed to demux message", all); + } + } + } + + /** + * add the CryptoInfo into the message + * + * @param submessage the message + * @param destAddress the destination + * @return Message the message with the CbJxMessageInfo added + */ + public Message addCryptoInfo(Message submessage, EndpointAddress destAddress) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Building CBJX wrapper for " + submessage); + } + + // Remove all existing CbJx Elements from source + Iterator eachCbJxElement = submessage.getMessageElementsOfNamespace(CbJxTransport.CBJX_MSG_NS); + + while (eachCbJxElement.hasNext()) { + MessageElement aMessageElement = (MessageElement) eachCbJxElement.next(); + + eachCbJxElement.remove(); + } + + Message message = new Message(); + + CbJxMessageInfo cryptoInfo = new CbJxMessageInfo(); + + // set the source Id of the message + cryptoInfo.setSourceID(localPeerID); + cryptoInfo.setSourceAddress(localPeerAddr); + cryptoInfo.setDestinationAddress(destAddress); + + // add the root cert into the message info + PSECredential cred = (PSECredential) membership.getDefaultCredential(); + + if (null == cred) { + throw new IOException("No authentication available for message signing."); + } + + Certificate cert = cred.getCertificate(); + + cryptoInfo.setPeerCert(cert); + + // compute the signature of the message body + TextDocument infoDoc = (TextDocument) cryptoInfo.getDocument(MimeMediaType.XMLUTF8); + byte[] infoSignature = null; + + try { + infoSignature = PSEUtils.computeSignature(CbJxDefs.signAlgoName, cred.getPrivateKey(), infoDoc.getStream()); + } catch (Throwable e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "failed to sign " + submessage, e); + } + return null; + } + + // add the cbjx:CryptoInfo into the message + MessageElement infoSigElement = new ByteArrayMessageElement(CBJX_MSG_SIG, MimeMediaType.AOS, infoSignature, null); + + // add the cbjx:CryptoInfo into the message + MessageElement cryptoInfoElement = new TextDocumentMessageElement(CBJX_MSG_INFO, infoDoc, infoSigElement); + + message.addMessageElement(CBJX_MSG_NS, cryptoInfoElement); + + // Compute the signature of the encapsulated message and append it to + // the container. + + // serialize the container + WireFormatMessage subserial = WireFormatMessageFactory.toWire(submessage, WireFormatMessageFactory.DEFAULT_WIRE_MIME, null); + + // calculate the signature + byte[] bodySignature = null; + + try { + bodySignature = PSEUtils.computeSignature(CbJxDefs.signAlgoName, cred.getPrivateKey(), subserial.getStream()); + } catch (Throwable e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "failed to sign" + submessage, e); + } + return null; + } + + subserial = null; + + // Make the signature into an element + MessageElement bodySigElement = new ByteArrayMessageElement(CBJX_MSG_SIG, MimeMediaType.AOS, bodySignature, null); + + // Add the encapsulated body into the container message. + message.addMessageElement(CBJX_MSG_NS + , + new JxtaMessageMessageElement(CBJX_MSG_BODY, new MimeMediaType("application/x-jxta-msg"), submessage + , + bodySigElement)); + + return message; + } + + public Message checkCryptoInfo(Message message, MessageElement cryptoElement, CbJxMessageInfo cryptoInfo) { + + // extract the body element from the message + JxtaMessageMessageElement bodyElement = (JxtaMessageMessageElement) message.getMessageElement(CBJX_MSG_NS, CBJX_MSG_BODY); + + if (null == bodyElement) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("No \'" + CBJX_MSG_BODY + "\' in " + message); + } + return null; + } + message.removeMessageElement(bodyElement); + + // extract the peer certificate + Certificate peerCert = cryptoInfo.getPeerCert(); + + // and from it the public key + // the public key from the message + RSAPublicKey publicKey = (RSAPublicKey) peerCert.getPublicKey(); + + // check the cert validity + try { + peerCert.verify(publicKey); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Invalid peer cert", e); + } + return null; + } + + // check the cbid + try { + net.jxta.impl.id.CBID.PeerID srcPeerID = (net.jxta.impl.id.CBID.PeerID) cryptoInfo.getSourceID(); + + byte[] pub_der = peerCert.getPublicKey().getEncoded(); + net.jxta.impl.id.CBID.PeerID genID = (net.jxta.impl.id.CBID.PeerID) IDFactory.newPeerID(group.getPeerGroupID() + , + pub_der); + + if (!srcPeerID.getUUID().equals(genID.getUUID())) { + // the cbid is not valid. Discard the message + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("CBID of " + message + " is not valid : " + srcPeerID + " != " + genID); + } + return null; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("CBID of the message is valid"); + } + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to verify cbid", e); + } + return null; + } + + // verify the signature of the cryptinfo message + try { + boolean valid = PSEUtils.verifySignature(CbJxDefs.signAlgoName, peerCert, cryptoElement.getSignature().getBytes(false) + , + cryptoElement.getStream()); + + if (!valid) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to verify the signature of cryptinfo for " + message); + } + return null; + } + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to verify the signature of cryptinfo for " + message, e); + } + return null; + } + + // then verify the signature + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("verifying signature"); + } + + // verify the signature of the message + try { + boolean valid = PSEUtils.verifySignature(CbJxDefs.signAlgoName, peerCert, bodyElement.getSignature().getBytes(false) + , + bodyElement.getStream()); + + if (!valid) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("failed to verify the signature of " + message); + } + return null; + } + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failed to verify the signature of " + message, e); + } + return null; + } + + // the message is valid + return bodyElement.getMessage(); + } + + /** + * this class filters incoming messages. + * it checks if messages are valid and if not discard them + */ + public class CbJxInputFilter implements MessageFilterListener { + public CbJxInputFilter() { + super(); + } + + /** + * {@inheritDoc} + */ + public Message filterMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (dstAddr.getProtocolAddress().equals(getProtocolName())) { + // extract the Crypto info from the message + MessageElement cryptoElement = message.getMessageElement(CBJX_MSG_NS, CBJX_MSG_INFO); + + if (cryptoElement == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No \'" + CBJX_MSG_INFO + "\' in the message"); + } + return null; + } + message.removeMessageElement(cryptoElement); + + // the cbjx message info + CbJxMessageInfo cryptoInfo = null; + + try { + cryptoInfo = new CbJxMessageInfo(cryptoElement.getStream(), cryptoElement.getMimeType()); + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Couldn\'t retrieve CbJxMessageInfo from \'" + CBJX_MSG_INFO + "\' element", e); + } + return null; + } + + return checkCryptoInfo(message, cryptoElement, cryptoInfo); + } + + return message; + } + } + + + /** + * this class filters all outgoing messages that are not sent with + * messengers. (that is propagate messages). It adds CbJxInformation + * into to messages. + */ + public class CbJxOutputFilter implements MessageFilterListener { + + /** + * Default constructor + */ + public CbJxOutputFilter() { + super(); + } + + /** + * {@inheritDoc} + */ + public Message filterMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + Message msg = message.clone(); + + if (null == msg.getMessageElement(CBJX_MSG_NS, CBJX_MSG_INFO)) { + try { + msg = addCryptoInfo(msg, dstAddr); + } catch (IOException failed) { + return null; + } + } + + return msg; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/package.html new file mode 100644 index 000000000..4d04e184c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/package.html @@ -0,0 +1,12 @@ + + + + + + + A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which + which provides message verification by examining message signatures. A + virtual transport, the messages are transfered between peers using some + other message transport. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/ConditionalEndpointMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/ConditionalEndpointMeterBuildSettings.java new file mode 100644 index 000000000..c502900fc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/ConditionalEndpointMeterBuildSettings.java @@ -0,0 +1,80 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.endpoint.endpointMeter; + +import java.util.ResourceBundle; +import net.jxta.impl.meter.*; + +public class ConditionalEndpointMeterBuildSettings { + public static boolean isRuntimeMetering() { + boolean runtimeMetering = false; + + try { + ResourceBundle userResourceBundle = ResourceBundle.getBundle( "net.jxta.user" ); + String meteringProperty = "net.jxta.meter.conditionalEndpointMetering"; + String meteringValue = userResourceBundle.getString( meteringProperty ); + runtimeMetering = "on".equalsIgnoreCase( meteringValue ); + } catch (Exception ignored) { + } + + return runtimeMetering; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMeter.java new file mode 100644 index 000000000..b3f4614a5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMeter.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.peer.*; +import net.jxta.peergroup.*; +import net.jxta.endpoint.*; +import net.jxta.impl.endpoint.*; + +import java.net.*; +import java.util.*; + + +/** + * Aggregate Meter for Endpoint Monitoring + **/ +public class EndpointMeter { + + private EndpointMetric total; + private EndpointMetric delta; + + public EndpointMeter() { + total = new EndpointMetric(); + } + + public EndpointMetric getCumulativeMetrics() { + total.setEndpointUpTime(System.currentTimeMillis() - total.getEndpointStartTime()); + return total; + } + + public synchronized EndpointMetric collectMetrics() { + if (delta != null) { + delta.setEndpointUpTime(System.currentTimeMillis() - total.getEndpointStartTime()); + } + + EndpointMetric oldDelta = delta; + + delta = null; + + return oldDelta; + } + + public void invalidIncomingMessage() { + if (delta == null) { + createDeltaMetric(); + } + + delta.invalidIncomingMessage(); + total.invalidIncomingMessage(); + } + + public void noListenerForIncomingMessage() { + if (delta == null) { + createDeltaMetric(); + } + + delta.noListenerForIncomingMessage(); + total.noListenerForIncomingMessage(); + } + + public void errorProcessingIncomingMessage() { + if (delta == null) { + createDeltaMetric(); + } + + delta.errorProcessingIncomingMessage(); + total.errorProcessingIncomingMessage(); + } + + public void noDestinationAddressForDemuxMessage() { + if (delta == null) { + createDeltaMetric(); + } + + delta.noDestinationAddressForDemuxMessage(); + total.noDestinationAddressForDemuxMessage(); + } + + public void noSourceAddressForDemuxMessage() { + if (delta == null) { + createDeltaMetric(); + } + + delta.noSourceAddressForDemuxMessage(); + total.noSourceAddressForDemuxMessage(); + } + + public void discardedLoopbackDemuxMessage() { + if (delta == null) { + createDeltaMetric(); + } + + delta.discardedLoopbackDemuxMessage(); + total.discardedLoopbackDemuxMessage(); + } + + public void incomingMessageFilteredOut() { + if (delta == null) { + createDeltaMetric(); + } + + delta.incomingMessageFilteredOut(); + total.incomingMessageFilteredOut(); + } + + public void incomingMessageSentToEndpointListener() { + if (delta == null) { + createDeltaMetric(); + } + + delta.incomingMessageSentToEndpointListener(); + total.incomingMessageSentToEndpointListener(); + } + + public void demuxMessageProcessed() { + if (delta == null) { + createDeltaMetric(); + } + + delta.demuxMessageProcessed(); + total.demuxMessageProcessed(); + } + + private void createDeltaMetric() { + delta = new EndpointMetric(total); + } + + @Override + public String toString() { + return "EndpointMeter()"; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMeterBuildSettings.java new file mode 100644 index 000000000..dc6809b40 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMeterBuildSettings.java @@ -0,0 +1,67 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.endpoint.endpointMeter; + +import net.jxta.impl.meter.*; + +public interface EndpointMeterBuildSettings extends MeterBuildSettings { + public static final boolean ENDPOINT_METERING = ConditionalEndpointMeterBuildSettings.isRuntimeMetering(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMetric.java new file mode 100644 index 000000000..ee7456a52 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointMetric.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; + +import java.util.*; + + +/** + * Aggregate Metric for Endpoint Monitoring + **/ +public class EndpointMetric implements DocumentSerializable { + private long endpointStartTime; + private long endpointUpTime; + private int invalidIncomingMessage; + private int noListenerForIncomingMessage; + private int errorProcessingIncomingMessage; + private int noDestinationAddressForDemuxMessage; + private int noSourceAddressForDemuxMessage; + private int discardedLoopbackDemuxMessage; + private int incomingMessageFilteredOut; + private int incomingMessageSentToEndpointListener; + private int demuxMessageProcessed; + + public EndpointMetric() { + endpointStartTime = System.currentTimeMillis(); + } + + public EndpointMetric(EndpointMetric prototype) { + endpointStartTime = prototype.endpointStartTime; + } + + void invalidIncomingMessage() { + invalidIncomingMessage++; + } + + void noListenerForIncomingMessage() { + noListenerForIncomingMessage++; + } + + void errorProcessingIncomingMessage() { + errorProcessingIncomingMessage++; + } + + void noDestinationAddressForDemuxMessage() { + noDestinationAddressForDemuxMessage++; + } + + void noSourceAddressForDemuxMessage() { + noSourceAddressForDemuxMessage++; + } + + void discardedLoopbackDemuxMessage() { + discardedLoopbackDemuxMessage++; + } + + void incomingMessageFilteredOut() { + incomingMessageFilteredOut++; + } + + void incomingMessageSentToEndpointListener() { + incomingMessageSentToEndpointListener++; + } + + void demuxMessageProcessed() { + demuxMessageProcessed++; + } + + void setEndpointUpTime(long endpointUpTime) { + this.endpointUpTime = endpointUpTime; + } + + /** Get the time this Endpoint was created, essentially the boot time of the PeerGroup **/ + public long getEndpointStartTime() { + return endpointStartTime; + } + + /** Get the time this Endpoint has been up **/ + public long getEndpointUpTime() { + return endpointUpTime; + } + + /** The number of messages received that had invalid formats **/ + public int getInvalidIncomingMessage() { + return invalidIncomingMessage; + } + + /** The number of messages received that had no listeners **/ + public int getNoListenerForIncomingMessage() { + return noListenerForIncomingMessage; + } + + /** The number of messages whose local listeners threw exceptions **/ + public int getErrorProcessingIncomingMessage() { + return errorProcessingIncomingMessage; + } + + /** The number of messages that couldn't be demuxed because there was no destination address **/ + public int getNoDestinationAddressForDemuxMessage() { + return noDestinationAddressForDemuxMessage; + } + + /** The number of messages that couldn't be demuxed because there was no source address **/ + public int getNoSourceAddressForDemuxMessage() { + return noSourceAddressForDemuxMessage; + } + + /** The number of messages that were discarded because of loopback detection **/ + public int getDiscardedLoopbackDemuxMessage() { + return discardedLoopbackDemuxMessage; + } + + /** The number of messages that were discarded because of filtering **/ + public int getIncomingMessageFilteredOut() { + return incomingMessageFilteredOut; + } + + /** The number of messages that sent to registered listeners **/ + public int getIncomingMessageSentToEndpointListener() { + return incomingMessageSentToEndpointListener; + } + + /** The number of messages that were processed through demux **/ + public int getDemuxMessageProcessed() { + return demuxMessageProcessed; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (endpointStartTime != 0) { + DocumentSerializableUtilities.addLong(element, "endpointStartTime", endpointStartTime); + } + if (endpointUpTime != 0) { + DocumentSerializableUtilities.addLong(element, "endpointUpTime", endpointUpTime); + } + if (invalidIncomingMessage != 0) { + DocumentSerializableUtilities.addInt(element, "invalidIncomingMessage", invalidIncomingMessage); + } + if (noListenerForIncomingMessage != 0) { + DocumentSerializableUtilities.addInt(element, "noListenerForIncomingMessage", noListenerForIncomingMessage); + } + if (errorProcessingIncomingMessage != 0) { + DocumentSerializableUtilities.addInt(element, "errorProcessingIncomingMessage", errorProcessingIncomingMessage); + } + if (noDestinationAddressForDemuxMessage != 0) { + DocumentSerializableUtilities.addInt(element, "noDestinationAddressForDemuxMessage" + , + noDestinationAddressForDemuxMessage); + } + if (noSourceAddressForDemuxMessage != 0) { + DocumentSerializableUtilities.addInt(element, "noSourceAddressForDemuxMessage", noSourceAddressForDemuxMessage); + } + if (discardedLoopbackDemuxMessage != 0) { + DocumentSerializableUtilities.addInt(element, "discardedLoopbackDemuxMessage", discardedLoopbackDemuxMessage); + } + if (incomingMessageFilteredOut != 0) { + DocumentSerializableUtilities.addInt(element, "incomingMessageFilteredOut", incomingMessageFilteredOut); + } + if (incomingMessageSentToEndpointListener != 0) { + DocumentSerializableUtilities.addInt(element, "incomingMessageSentToEndpointListener" + , + incomingMessageSentToEndpointListener); + } + if (demuxMessageProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "demuxMessageProcessed", demuxMessageProcessed); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("endpointStartTime")) { + endpointStartTime = DocumentSerializableUtilities.getLong(childElement); + } + if (tagName.equals("endpointUpTime")) { + endpointUpTime = DocumentSerializableUtilities.getLong(childElement); + } + if (tagName.equals("invalidIncomingMessage")) { + invalidIncomingMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("noListenerForIncomingMessage")) { + noListenerForIncomingMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("errorProcessingIncomingMessage")) { + errorProcessingIncomingMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("noDestinationAddressForDemuxMessage")) { + noDestinationAddressForDemuxMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("noSourceAddressForDemuxMessage")) { + noSourceAddressForDemuxMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("invalidIncomingMessage")) { + invalidIncomingMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("discardedLoopbackDemuxMessage")) { + discardedLoopbackDemuxMessage = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("incomingMessageFilteredOut")) { + incomingMessageFilteredOut = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("incomingMessageSentToEndpointListener")) { + incomingMessageSentToEndpointListener = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("demuxMessageProcessed")) { + demuxMessageProcessed = DocumentSerializableUtilities.getInt(childElement); + } + } + + } + + public void mergeMetrics(EndpointMetric other) { + if (other == null) { + return; + } + + endpointStartTime = other.endpointStartTime; + + if (other.endpointUpTime != 0) { + endpointUpTime = other.endpointUpTime; + } + + invalidIncomingMessage += other.invalidIncomingMessage; + noListenerForIncomingMessage += other.noListenerForIncomingMessage; + errorProcessingIncomingMessage += other.errorProcessingIncomingMessage; + noDestinationAddressForDemuxMessage += other.noDestinationAddressForDemuxMessage; + noSourceAddressForDemuxMessage += other.noSourceAddressForDemuxMessage; + discardedLoopbackDemuxMessage += other.discardedLoopbackDemuxMessage; + incomingMessageSentToEndpointListener += other.incomingMessageSentToEndpointListener; + demuxMessageProcessed += other.demuxMessageProcessed; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMetric.java new file mode 100644 index 000000000..720eb008e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMetric.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.document.Element; +import net.jxta.document.TextElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.IDFactory; +import net.jxta.meter.MonitorResources; +import net.jxta.meter.ServiceMetric; +import net.jxta.platform.ModuleClassID; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; + + +/** + * Basic Service Metric EndpointService Monitoring + */ +public class EndpointServiceMetric implements ServiceMetric { + private LinkedList inboundMetrics = new LinkedList(); + private LinkedList outboundMetrics = new LinkedList(); + private LinkedList propagationMetrics = new LinkedList(); + private EndpointMetric endpointMetric; + private ModuleClassID moduleClassID = MonitorResources.endpointServiceMonitorClassID; + + public EndpointServiceMetric() {} + + public EndpointServiceMetric(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + void addInboundMetric(InboundMetric inboundMetric) { + inboundMetrics.add(inboundMetric); + } + + public Iterator getInboundMetrics() { + return inboundMetrics.iterator(); + } + + public InboundMetric getInboundMetric(String serviceName, String serviceParam) { + for (InboundMetric inboundMetric : inboundMetrics) { + if (inboundMetric.matches(serviceName, serviceParam)) { + return inboundMetric; + } + } + + return null; + } + + public Iterator getPropagationMetrics() { + return propagationMetrics.iterator(); + } + + public PropagationMetric getPropagationMetric(String serviceName, String serviceParam) { + for (PropagationMetric propagationMetric : propagationMetrics) { + if (propagationMetric.matches(serviceName, serviceParam)) { + return propagationMetric; + } + } + + return null; + } + + void addPropagationMetric(PropagationMetric propagationMetric) { + propagationMetrics.add(propagationMetric); + } + + void addOutboundMetric(OutboundMetric outboundMetric) { + outboundMetrics.add(outboundMetric); + } + + public Iterator getOutboundMetrics() { + return outboundMetrics.iterator(); + } + + public OutboundMetric getOutboundMetric(EndpointAddress endpointAddress) { + for (OutboundMetric outboundMetric : outboundMetrics) { + if (outboundMetric.matches(endpointAddress)) { + return outboundMetric; + } + } + + return null; + } + + public EndpointMetric getEndpointMetric() { + return endpointMetric; + } + + void setEndpointMetric(EndpointMetric endpointMetric) { + this.endpointMetric = endpointMetric; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + for (Object outboundMetric1 : outboundMetrics) { + OutboundMetric outboundMetric = (OutboundMetric) outboundMetric1; + + DocumentSerializableUtilities.addDocumentSerializable(element, "outboundMetric", outboundMetric); + } + for (Object inboundMetric1 : inboundMetrics) { + InboundMetric inboundMetric = (InboundMetric) inboundMetric1; + + DocumentSerializableUtilities.addDocumentSerializable(element, "inboundMetric", inboundMetric); + } + for (Object propagationMetric1 : propagationMetrics) { + PropagationMetric propagationMetric = (PropagationMetric) propagationMetric1; + + DocumentSerializableUtilities.addDocumentSerializable(element, "propagationMetric", propagationMetric); + } + if (endpointMetric != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "endpointMetric", endpointMetric); + } + + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("inboundMetric")) { + InboundMetric inboundMetric = (InboundMetric) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + InboundMetric.class); + + inboundMetrics.add(inboundMetric); + } + if (tagName.equals("outboundMetric")) { + OutboundMetric outboundMetric = (OutboundMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, OutboundMetric.class); + + outboundMetrics.add(outboundMetric); + } + if (tagName.equals("propagationMetric")) { + PropagationMetric propagationMetric = (PropagationMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, PropagationMetric.class); + + propagationMetrics.add(propagationMetric); + } + if (tagName.equals("endpointMetric")) { + endpointMetric = (EndpointMetric) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + EndpointMetric.class); + } + try { + if (tagName.equals("moduleClassID")) { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't decipher ModuleClassID", jex); + } + } + } + + public void mergeMetrics(ServiceMetric otherOne) { + mergeMetrics(otherOne, true, true, true, true); + } + + /** + * Make a deep copy of this metric only including the portions designated in the Filter + * The resulting metric is Safe to modify without danger to the underlying Monitor Metrics + * + * @param endpointServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + */ + public EndpointServiceMetric deepCopy(EndpointServiceMonitorFilter endpointServiceMonitorFilter) { + EndpointServiceMetric serviceMetric = new EndpointServiceMetric(); + + serviceMetric.moduleClassID = moduleClassID; + + serviceMetric.mergeMetrics(this, true, endpointServiceMonitorFilter.isIncludeInboundMetrics() + , + endpointServiceMonitorFilter.isIncludeOutboundMetrics(), endpointServiceMonitorFilter.isIncludePropagateMetrics()); + return serviceMetric; + } + + public void mergeMetrics(ServiceMetric otherOne, boolean includeEndpointMetrics, boolean includeInboundMetrics, boolean includeOutboundEndpointMetrics, boolean includePropagationMetrics) { + EndpointServiceMetric otherEndpointServiceMetric = (EndpointServiceMetric) otherOne; + + if (includeEndpointMetrics) { + EndpointMetric otherEndpointMetric = otherEndpointServiceMetric.getEndpointMetric(); + + if ((endpointMetric == null) && (otherEndpointMetric != null)) { + endpointMetric = new EndpointMetric(otherEndpointMetric); + } + + if (otherEndpointMetric != null) { + endpointMetric.mergeMetrics(otherEndpointMetric); + } + } + + if (includeInboundMetrics) { + for (Iterator i = otherEndpointServiceMetric.getInboundMetrics(); i.hasNext();) { + InboundMetric otherInboundMetric = i.next(); + InboundMetric inboundMetric = getInboundMetric(otherInboundMetric.getServiceName() + , + otherInboundMetric.getServiceParameter()); + + if (inboundMetric == null) { + inboundMetric = new InboundMetric(otherInboundMetric); + addInboundMetric(inboundMetric); + } + + inboundMetric.mergeMetrics(otherInboundMetric); + } + } + + if (includeOutboundEndpointMetrics) { + for (Iterator i = otherEndpointServiceMetric.getOutboundMetrics(); i.hasNext();) { + OutboundMetric otherOutboundMetric = i.next(); + OutboundMetric outboundMetric = getOutboundMetric(otherOutboundMetric.getEndpointAddress()); + + if (outboundMetric == null) { + outboundMetric = new OutboundMetric(otherOutboundMetric); + addOutboundMetric(outboundMetric); + } + + outboundMetric.mergeMetrics(otherOutboundMetric); + } + } + + if (includeOutboundEndpointMetrics) { + for (Iterator i = otherEndpointServiceMetric.getPropagationMetrics(); i.hasNext();) { + PropagationMetric otherPropagationMetric = i.next(); + PropagationMetric propagationMetric = getPropagationMetric(otherPropagationMetric.getServiceName() + , + otherPropagationMetric.getServiceParameter()); + + if (propagationMetric == null) { + propagationMetric = new PropagationMetric(otherPropagationMetric); + addPropagationMetric(propagationMetric); + } + + propagationMetric.mergeMetrics(otherPropagationMetric); + } + } + } + + /** + * Make a shallow copy of this metric only including the portions designated in the Filter + *

      Note: since this is a shallow copy it is dangerous to modify the submetrics + * + * @param endpointServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + */ + public EndpointServiceMetric shallowCopy(EndpointServiceMonitorFilter endpointServiceMonitorFilter) { + EndpointServiceMetric endpointServiceMetric = new EndpointServiceMetric(moduleClassID); + + endpointServiceMetric.endpointMetric = endpointMetric; + + if (endpointServiceMonitorFilter.isIncludeInboundMetrics()) { + for (Iterator i = getInboundMetrics(); i.hasNext();) { + InboundMetric inboundMetric = i.next(); + + endpointServiceMetric.addInboundMetric(inboundMetric); + } + } + + if (endpointServiceMonitorFilter.isIncludeOutboundMetrics()) { + for (Iterator i = getOutboundMetrics(); i.hasNext();) { + OutboundMetric outboundMetric = i.next(); + + endpointServiceMetric.addOutboundMetric(outboundMetric); + } + } + + if (endpointServiceMonitorFilter.isIncludePropagateMetrics()) { + for (Iterator i = getPropagationMetrics(); i.hasNext();) { + PropagationMetric propagationMetric = i.next(); + + endpointServiceMetric.addPropagationMetric(propagationMetric); + } + } + + return endpointServiceMetric; + } + + public void diffMetrics(ServiceMetric otherOne) { + throw new RuntimeException("Not Supported"); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMonitor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMonitor.java new file mode 100644 index 000000000..fac60ea89 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMonitor.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import java.util.Hashtable; +import java.util.Map; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.impl.meter.GenericServiceMonitor; +import net.jxta.meter.ServiceMetric; +import net.jxta.meter.ServiceMonitorFilter; + + +/** + * Standard EndpointService Monitor + **/ +public class EndpointServiceMonitor extends GenericServiceMonitor { + private EndpointServiceMetric cumulativeEndpointServiceMetric; + private final Map inboundMeters = new Hashtable(); + private final Map outboundMeters = new Hashtable(); + private final Map propagationMeters = new Hashtable(); + private final EndpointMeter endpointMeter = new EndpointMeter(); + + public EndpointServiceMonitor() {} + + /** + * {@inheritDoc} + */ + @Override + protected void init() { + cumulativeEndpointServiceMetric = (EndpointServiceMetric) getCumulativeServiceMetric(); + cumulativeEndpointServiceMetric.setEndpointMetric(endpointMeter.getCumulativeMetrics()); + } + + public EndpointMeter getEndpointMeter() { + return endpointMeter; + } + + public synchronized InboundMeter getInboundMeter(String serviceName, String serviceParam) { + String address = serviceName; + + if (null != serviceParam) { + address += "/" + serviceParam; + } + + InboundMeter inboundMeter = inboundMeters.get(address); + + if (inboundMeter == null) { + inboundMeter = new InboundMeter(serviceName, serviceParam); + inboundMeters.put(address, inboundMeter); + cumulativeEndpointServiceMetric.addInboundMetric(inboundMeter.getCumulativeMetrics()); + } + + return inboundMeter; + } + + public synchronized PropagationMeter getPropagationMeter(String serviceName, String serviceParam) { + String address = serviceName; + + if (null != serviceParam) { + address += "/" + serviceParam; + } + + PropagationMeter propagationMeter = propagationMeters.get(address); + + if (propagationMeter == null) { + propagationMeter = new PropagationMeter(serviceName, serviceParam); + propagationMeters.put(address, propagationMeter); + cumulativeEndpointServiceMetric.addPropagationMetric(propagationMeter.getCumulativeMetrics()); + } + + return propagationMeter; + } + + public synchronized OutboundMeter getOutboundMeter(EndpointAddress endpointAddress) { + OutboundMeter outboundMeter = outboundMeters.get(endpointAddress); + + if (outboundMeter == null) { + outboundMeter = new OutboundMeter(endpointAddress); + cumulativeEndpointServiceMetric.addOutboundMetric(outboundMeter.getCumulativeMetrics()); + outboundMeters.put(endpointAddress, outboundMeter); + } + + return outboundMeter; + } + + /** + * {@inheritDoc} + */ + @Override + public ServiceMetric getServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime, int pulseIndex, long reportRate) { + int deltaReportRateIndex = monitorManager.getReportRateIndex(reportRate); + EndpointServiceMetric origEndpointServiceMetric = (EndpointServiceMetric) deltaServiceMetrics[deltaReportRateIndex]; + + if (origEndpointServiceMetric == null) { + return null; + } + + EndpointServiceMonitorFilter endpointServiceMonitorFilter = (EndpointServiceMonitorFilter) serviceMonitorFilter; + + return origEndpointServiceMetric.shallowCopy(endpointServiceMonitorFilter); + } + + /** + * {@inheritDoc} + */ + @Override + public ServiceMetric getCumulativeServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime) { + EndpointServiceMetric origEndpointServiceMetric = (EndpointServiceMetric) cumulativeServiceMetric; + EndpointServiceMonitorFilter endpointServiceMonitorFilter = (EndpointServiceMonitorFilter) serviceMonitorFilter; + + return origEndpointServiceMetric.deepCopy(endpointServiceMonitorFilter); + } + + /** + * {@inheritDoc} + */ + @Override + protected ServiceMetric collectServiceMetrics() { + EndpointServiceMetric endpointServiceMetric = (EndpointServiceMetric) createServiceMetric(); + + boolean anyData = false; + + for (InboundMeter inboundMeter : inboundMeters.values()) { + InboundMetric inboundMetric = inboundMeter.collectMetrics(); // clears delta from meter + + if (inboundMetric != null) { + endpointServiceMetric.addInboundMetric(inboundMetric); + anyData = true; + } + } + + for (OutboundMeter outboundMeter : outboundMeters.values()) { + OutboundMetric outboundMetric = outboundMeter.collectMetrics(); // clears delta from meter + + if (outboundMetric != null) { + endpointServiceMetric.addOutboundMetric(outboundMetric); + anyData = true; + } + } + + for (PropagationMeter propagationMeter : propagationMeters.values()) { + PropagationMetric propagationMetric = propagationMeter.collectMetrics(); // clears delta from meter + + if (propagationMetric != null) { + endpointServiceMetric.addPropagationMetric(propagationMetric); + anyData = true; + } + } + + EndpointMetric endpointMetric = endpointMeter.collectMetrics(); + + if (endpointMetric != null) { + endpointServiceMetric.setEndpointMetric(endpointMetric); + anyData = true; + } + + if (anyData) { + return endpointServiceMetric; + } else { + return null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMonitorFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMonitorFilter.java new file mode 100644 index 000000000..109dbca68 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/EndpointServiceMonitorFilter.java @@ -0,0 +1,158 @@ + + +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import java.net.*; +import java.util.*; + +import net.jxta.meter.*; +import net.jxta.platform.*; +import net.jxta.document.*; +import net.jxta.id.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.platform.*; +import net.jxta.util.*; + + +public class EndpointServiceMonitorFilter implements ServiceMonitorFilter { + // private boolean reportAllEndpoints = true; + private ModuleClassID moduleClassID = MonitorResources.endpointServiceMonitorClassID; + + private boolean includeOutboundMetrics = true; + private boolean includeInboundMetrics = true; + private boolean includePropagateMetrics = true; + + public EndpointServiceMonitorFilter() {} + + public EndpointServiceMonitorFilter(boolean includeInboundMetrics, boolean includeOutboundMetrics, boolean includePropagateMetrics) { + this.includeInboundMetrics = includeInboundMetrics; + this.includeOutboundMetrics = includeOutboundMetrics; + this.includePropagateMetrics = includePropagateMetrics; + } + + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public void setIncludeInboundMetrics(boolean metrics) { + includeInboundMetrics = metrics; + } + + public void setIncludeOutboundMetrics(boolean metrics) { + includeOutboundMetrics = metrics; + } + + public void setIncludePropagateMetrics(boolean metrics) { + includePropagateMetrics = metrics; + } + + public boolean isIncludeOutboundMetrics() { + return includeOutboundMetrics; + } + + public boolean isIncludeInboundMetrics() { + return includeInboundMetrics; + } + + public boolean isIncludePropagateMetrics() { + return includePropagateMetrics; + } + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addBoolean(element, "includeOutboundMetrics", includeOutboundMetrics); + DocumentSerializableUtilities.addBoolean(element, "includeInboundMetrics", includeInboundMetrics); + DocumentSerializableUtilities.addBoolean(element, "includePropagateMetrics", includePropagateMetrics); + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("includeOutboundMetrics")) { + includeOutboundMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } + if (tagName.equals("includeInboundMetrics")) { + includeInboundMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } + if (tagName.equals("includePropagateMetrics")) { + includePropagateMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } + + if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Couldn't uderstand ModuleClassID", jex); + } + } + } + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/InboundMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/InboundMeter.java new file mode 100644 index 000000000..48dffd201 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/InboundMeter.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.Message; + + +/** + * Meter corresponding to a registered EndpointListener + **/ +public class InboundMeter { + private String serviceName; + private String serviceParameter; + + private InboundMetric totals; + private InboundMetric delta; + + public InboundMeter(String serviceName, String serviceParameter) { + this.serviceName = serviceName; + this.serviceParameter = serviceParameter; + this.totals = new InboundMetric(this); + } + + private void createDeltaMetric() { + delta = new InboundMetric(this); + } + + public void inboundMessageQueued(Message message) { + if (delta == null) { + createDeltaMetric(); + } + + delta.inboundMessageQueued(message); + totals.inboundMessageQueued(message); + } + + public void inboundMessageDropped(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.inboundMessageDropped(message, time); + totals.inboundMessageDropped(message, time); + } + + public void inboundMessageDeQueued(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.inboundMessageDeQueued(message, time); + totals.inboundMessageDeQueued(message, time); + } + + public void inboundMessageProcessed(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.inboundMessageProcessed(message, time); + totals.inboundMessageProcessed(message, time); + } + + String getServiceName() { + return serviceName; + } + + String getServiceParameter() { + return serviceParameter; + } + + @Override + public String toString() { + return "InboundMeter(" + serviceName + "//" + serviceParameter + ")"; + } + + public InboundMetric getCumulativeMetrics() { + return totals; + } + + public synchronized InboundMetric collectMetrics() { + InboundMetric prevDelta = delta; + + delta = null; + return prevDelta; + } + + /* Fix-Me: delete after next build.. unused + public synchronized InboundMetric addDeltaToTotals(long reportingDelta) { // returns delta + if (delta != null) { + totals.mergeMetrics(delta); + InboundMetric oldDelta = delta; + delta = null; + return oldDelta; + } else + return null; + } + */ +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/InboundMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/InboundMetric.java new file mode 100644 index 000000000..754a0ced8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/InboundMetric.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.*; +import net.jxta.impl.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; + +import java.util.*; + + +/** + * Meter corresponding to inbound queue for registered EndpointListeners ServiceName/ServiceParam pair + **/ +public class InboundMetric implements DocumentSerializable { + private String serviceName; + private String serviceParameter; + + private String serviceIdString; // internally used to speed up Hashing + + private int numInboundQueued; + private int numInboundDropped; + private long timeToDropInbound; + private int numInboundDeQueued; + private long timeInInboundQueue; + private int numInboundProcessed; + private long timeToProcessInbound; + + public InboundMetric(InboundMeter inboundMeter) { + this.serviceName = inboundMeter.getServiceName(); + this.serviceParameter = inboundMeter.getServiceParameter(); + + serviceIdString = serviceName + serviceParameter; + } + + public InboundMetric(InboundMetric prototype) { + this.serviceName = prototype.getServiceName(); + this.serviceParameter = prototype.getServiceParameter(); + + serviceIdString = serviceName + serviceParameter; + } + + public InboundMetric() {} + + /** The Service Name for this Metric **/ + public String getServiceName() { + return serviceName; + } + + /** The Service Parameter for this Metric **/ + public String getServiceParameter() { + return serviceParameter; + } + + /** The Number of Inbound Messages Queued **/ + public int getNumInboundQueued() { + return numInboundQueued; + } + + /** The Number of Inbound Messages Dropped **/ + public int getNumInboundDropped() { + return numInboundDropped; + } + + /** The Sum of time for all dropped messages from queue **/ + public long getTimeToDropInbound() { + return timeToDropInbound; + } + + /** The Number of Inbound Messages Dequeued **/ + public int getNumInboundDeQueued() { + return numInboundDeQueued; + } + + /** The Sum of time in queue for messages in queue **/ + public long getTimeInInboundQueue() { + return timeInInboundQueue; + } + + public int getNumInboundProcessed() { + return numInboundProcessed; + } + + /** The Sum of time for local listeners to process messages **/ + public long getTimeToProcessInbound() { + return timeToProcessInbound; + } + + /** The Average of time in queue for messages **/ + public long getAverageTimeInInboundQueue() { + return (numInboundDeQueued == 0) ? 0 : (timeInInboundQueue / numInboundDeQueued); + } + + /** The Average of time in queue for dropped messages **/ + public long getAverageInboundDropTime() { + return (numInboundDropped == 0) ? 0 : (timeToDropInbound / numInboundDropped); + } + + /** The Average clock time for local listeners to process messages **/ + public long getAverageInboundProcessTime() { + return (numInboundProcessed == 0) ? 0 : (timeToProcessInbound / numInboundProcessed); + } + + @Override + public boolean equals(Object obj) { + + if (obj instanceof InboundMetric) { + InboundMetric other = (InboundMetric) obj; + + return serviceIdString.equals(other.serviceIdString); + } else { + return false; + } + } + + public boolean matches(String serviceName, String serviceParam) { + if (serviceName.equals(getServiceName())) { + if (serviceParam == null && getServiceParameter() == null) { + return true; + } else if (serviceParam != null && getServiceParameter() != null) { + return serviceParam.equals(getServiceParameter()); + } + } + return false; + } + + @Override + public int hashCode() { + return serviceIdString.hashCode(); + } + + void inboundMessageQueued(Message message) { + numInboundQueued++; + } + + void inboundMessageDropped(Message message, long time) { + numInboundDropped++; + timeToDropInbound += time; + } + + void inboundMessageDeQueued(Message message, long time) { + numInboundDeQueued++; + timeInInboundQueue += time; + } + + void inboundMessageProcessed(Message message, long time) { + numInboundProcessed++; + timeToProcessInbound += time; + } + + public void mergeMetrics(InboundMetric other) { + numInboundQueued += other.numInboundQueued; + numInboundDropped += other.numInboundDropped; + timeToDropInbound += other.timeToDropInbound; + numInboundDeQueued += other.numInboundDeQueued; + timeInInboundQueue += other.timeInInboundQueue; + numInboundProcessed += other.numInboundProcessed; + timeToProcessInbound += other.timeToProcessInbound; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + + DocumentSerializableUtilities.addString(element, "serviceName", serviceName); + DocumentSerializableUtilities.addString(element, "serviceParam", serviceParameter); + + if (numInboundQueued != 0) { + DocumentSerializableUtilities.addInt(element, "numInboundQueued", numInboundQueued); + } + + if (numInboundDropped != 0) { + DocumentSerializableUtilities.addInt(element, "numInboundDropped", numInboundDropped); + } + + if (timeToDropInbound != 0) { + DocumentSerializableUtilities.addLong(element, "timeToDropInbound", timeToDropInbound); + } + + if (numInboundDeQueued != 0) { + DocumentSerializableUtilities.addInt(element, "numInboundDeQueued", numInboundDeQueued); + } + + if (timeInInboundQueue != 0) { + DocumentSerializableUtilities.addLong(element, "timeInInboundQueue", timeInInboundQueue); + } + + if (numInboundProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "numInboundProcessed", numInboundProcessed); + } + + if (timeToProcessInbound != 0) { + DocumentSerializableUtilities.addLong(element, "timeToProcessInbound", timeToProcessInbound); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("serviceName")) { + serviceName = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("serviceParam")) { + serviceParameter = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("numInboundQueued")) { + numInboundQueued = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numInboundDropped")) { + numInboundDropped = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeToDropInbound")) { + timeToDropInbound = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numInboundDeQueued")) { + numInboundDeQueued = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeInInboundQueue")) { + timeInInboundQueue = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numInboundProcessed")) { + numInboundProcessed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeToProcessInbound")) { + timeToProcessInbound = DocumentSerializableUtilities.getLong(childElement); + } + } + + serviceIdString = serviceName + serviceParameter; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/IncomingMessageListenerMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/IncomingMessageListenerMeter.java new file mode 100644 index 000000000..4c08d2221 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/IncomingMessageListenerMeter.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.Message; + + +public interface IncomingMessageListenerMeter { + public void inboundMessageQueued(Message message); + public void inboundMessageDropped(Message message, long time); + public void inboundMessageDeQueued(Message message, long time); + public void inboundMessageProcessed(Message message, long time); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/MessengerMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/MessengerMeter.java new file mode 100644 index 000000000..28dccf3bb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/MessengerMeter.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.*; + + +public interface MessengerMeter { + public void outboundMessageQueued(Message message); + public void outboundMessageDropped(Message message, long time); + public void outboundMessageFailed(Message message, long time); + public void outboundMessageDeQueued(Message message, long time); + public void outboundMessageProcessed(Message message, long time); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/OutboundMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/OutboundMeter.java new file mode 100644 index 000000000..6ee9e4ec2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/OutboundMeter.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.*; + + +/** + * Meter corresponding to a messages demuxed to registered listeners + **/ +public class OutboundMeter { + private EndpointAddress endpointAddress; + + private OutboundMetric totals; + private OutboundMetric delta; + + public OutboundMeter(EndpointAddress endpointAddress) { + this.endpointAddress = endpointAddress; + totals = new OutboundMetric(this); + } + + private void createDeltaMetric() { + delta = new OutboundMetric(this); + } + + public void outboundMessageQueued(Message message) { + if (delta == null) { + createDeltaMetric(); + } + + delta.outboundMessageQueued(message); + totals.outboundMessageQueued(message); + } + + public void outboundMessageDropped(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.outboundMessageDropped(message, time); + totals.outboundMessageDropped(message, time); + } + + public void outboundMessageFailed(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.outboundMessageFailed(message, time); + totals.outboundMessageFailed(message, time); + } + + public void outboundMessageDeQueued(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.outboundMessageDeQueued(message, time); + totals.outboundMessageDeQueued(message, time); + } + + public void outboundMessageProcessed(Message message, long time) { + if (delta == null) { + createDeltaMetric(); + } + + delta.outboundMessageProcessed(message, time); + totals.outboundMessageProcessed(message, time); + } + + EndpointAddress getEndpointAddress() { + return endpointAddress; + } + + @Override + public String toString() { + return "OutboundMeter(" + endpointAddress + ")"; + } + + public OutboundMetric getCumulativeMetrics() { + return totals; + } + + public synchronized OutboundMetric collectMetrics() { + OutboundMetric prevDelta = delta; + + delta = null; + return prevDelta; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/OutboundMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/OutboundMetric.java new file mode 100644 index 000000000..250398abe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/OutboundMetric.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.*; +import net.jxta.impl.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; + +import java.util.*; + + +/** + * Metric corresponding to a message queue to for outbound messengers based upon an endpoint address + **/ +public class OutboundMetric implements DocumentSerializable { + private EndpointAddress endpointAddress; + + private int numOutboundQueued; + private int numOutboundDropped; + private long timeToDropOutbound; + private int numOutboundDeQueued; + private long timeInOutboundQueue; + private int numOutboundProcessed; + private long timeToProcessOutbound; + private int numOutboundFailed; + private long timeOutboundToFail; + + public OutboundMetric(OutboundMeter outboundMeter) { + this.endpointAddress = outboundMeter.getEndpointAddress(); + } + + public OutboundMetric(OutboundMetric prototype) { + this.endpointAddress = prototype.getEndpointAddress(); + } + + public OutboundMetric() {} + + /** The Endpoint address for this outbound message queue **/ + public EndpointAddress getEndpointAddress() { + return endpointAddress; + } + + /** The Number of Outbound Messages Queued **/ + public int getNumOutboundQueued() { + return numOutboundQueued; + } + + /** The Number of Outbound Messages Dropped from Queue **/ + public int getNumOutboundDropped() { + return numOutboundDropped; + } + + /** The Sum of the times in queue for all dropped messages **/ + public long getTimeToDropOutbound() { + return timeToDropOutbound; + } + + /** The Number of Outbound Messages DeQueued **/ + public int getNumOutboundDeQueued() { + return numOutboundDeQueued; + } + + /** The Sum of the times in queue for all messages **/ + public long getTimeInOutboundQueue() { + return timeInOutboundQueue; + } + + /** The Number of Outbound Messages Processed Successfully **/ + public int getNumOutboundProcessed() { + return numOutboundProcessed; + } + + /** The Sum of the times from sending to handling by messenger **/ + public long getTimeToProcessOutbound() { + return timeToProcessOutbound; + } + + /** The Number of Outbound Messages Failed in sending **/ + public int getNumOutboundFailed() { + return numOutboundFailed; + } + + /** The Sum of the times in queue for all failed messages **/ + public long getTimeOutboundToFail() { + return timeOutboundToFail; + } + + /** The Average of the times in queue for all messages **/ + public long getAverageTimeInOutboundQueue() { + return (numOutboundDeQueued == 0) ? 0 : (timeInOutboundQueue / numOutboundDeQueued); + } + + /** The Average of the times in queue for all dropped messages **/ + public long getAverageOutboundDropTime() { + return (numOutboundDropped == 0) ? 0 : (timeToDropOutbound / numOutboundDropped); + } + + /** The Average of the times from sending to handling by messenger **/ + public long getAverageOutboundProcessTime() { + return (numOutboundProcessed == 0) ? 0 : (timeToProcessOutbound / numOutboundProcessed); + } + + @Override + public boolean equals(Object obj) { + + if (obj instanceof OutboundMetric) { + OutboundMetric other = (OutboundMetric) obj; + + return endpointAddress.equals(other.endpointAddress); + } else { + return false; + } + } + + public boolean matches(EndpointAddress otherAddress) { + return getEndpointAddress().equals(otherAddress); + } + + @Override + public int hashCode() { + return endpointAddress.hashCode(); + } + + void outboundMessageQueued(Message message) { + numOutboundQueued++; + } + + void outboundMessageDropped(Message message, long time) { + numOutboundDropped++; + timeToDropOutbound += time; + } + + void outboundMessageFailed(Message message, long time) { + numOutboundFailed++; + timeOutboundToFail += time; + } + + void outboundMessageDeQueued(Message message, long time) { + numOutboundDeQueued++; + timeInOutboundQueue += time; + } + + void outboundMessageProcessed(Message message, long time) { + numOutboundProcessed++; + timeToProcessOutbound += time; + } + + public void mergeMetrics(OutboundMetric other) { + + numOutboundQueued += other.numOutboundQueued; + numOutboundDropped += other.numOutboundDropped; + timeToDropOutbound += other.timeToDropOutbound; + numOutboundDeQueued += other.numOutboundDeQueued; + timeInOutboundQueue += other.timeInOutboundQueue; + numOutboundProcessed += other.numOutboundProcessed; + timeToProcessOutbound += other.timeToProcessOutbound; + numOutboundFailed += other.numOutboundFailed; + timeOutboundToFail += other.timeOutboundToFail; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + + DocumentSerializableUtilities.addString(element, "endpointAddress", endpointAddress.toString()); + + if (numOutboundQueued != 0) { + DocumentSerializableUtilities.addInt(element, "numOutboundQueued", numOutboundQueued); + } + + if (numOutboundDropped != 0) { + DocumentSerializableUtilities.addInt(element, "numOutboundDropped", numOutboundDropped); + } + + if (timeToDropOutbound != 0) { + DocumentSerializableUtilities.addLong(element, "timeToDropOutbound", timeToDropOutbound); + } + + if (numOutboundDeQueued != 0) { + DocumentSerializableUtilities.addInt(element, "numOutboundDeQueued", numOutboundDeQueued); + } + + if (timeInOutboundQueue != 0) { + DocumentSerializableUtilities.addLong(element, "timeInOutboundQueue", timeInOutboundQueue); + } + + if (numOutboundProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "numOutboundProcessed", numOutboundProcessed); + } + + if (timeToProcessOutbound != 0) { + DocumentSerializableUtilities.addLong(element, "timeToProcessOutbound", timeToProcessOutbound); + } + + if (numOutboundFailed != 0) { + DocumentSerializableUtilities.addInt(element, "numOutboundFailed", numOutboundFailed); + } + + if (timeOutboundToFail != 0) { + DocumentSerializableUtilities.addLong(element, "timeOutboundToFail", timeOutboundToFail); + } + + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("endpointAddress")) { + String endpointAddressString = DocumentSerializableUtilities.getString(childElement); + + endpointAddress = new EndpointAddress(endpointAddressString); + } else if (tagName.equals("numOutboundQueued")) { + numOutboundQueued = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numOutboundDropped")) { + numOutboundDropped = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeToDropOutbound")) { + timeToDropOutbound = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numOutboundDeQueued")) { + numOutboundDeQueued = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeInOutboundQueue")) { + timeInOutboundQueue = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numOutboundProcessed")) { + numOutboundProcessed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeToProcessOutbound")) { + timeToProcessOutbound = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numOutboundFailed")) { + numOutboundFailed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("timeOutboundToFail")) { + timeOutboundToFail = DocumentSerializableUtilities.getLong(childElement); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/PropagationMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/PropagationMeter.java new file mode 100644 index 000000000..5a2153c7f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/PropagationMeter.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +/** + * Meter corresponding to a propagated messages + **/ +public class PropagationMeter { + private String serviceName; + private String serviceParameter; + + private PropagationMetric totals; + private PropagationMetric delta; + + public PropagationMeter(String serviceName, String serviceParameter) { + this.serviceName = serviceName; + this.serviceParameter = serviceParameter; + this.totals = new PropagationMetric(this); + } + + private void createDeltaMetric() { + delta = new PropagationMetric(this); + } + + public void registerPropagateMessageStats(int numPropagatedTo, int numFilteredOut, int numErrorsPropagated, long propagationTime) { + if (delta == null) { + createDeltaMetric(); + } + + delta.registerPropagateMessageStats(numPropagatedTo, numFilteredOut, numErrorsPropagated, propagationTime); + totals.registerPropagateMessageStats(numPropagatedTo, numFilteredOut, numErrorsPropagated, propagationTime); + } + + String getServiceName() { + return serviceName; + } + + String getServiceParameter() { + return serviceParameter; + } + + @Override + public String toString() { + return "PropagationMeter(" + serviceName + "//" + serviceParameter + ")"; + } + + public PropagationMetric getCumulativeMetrics() { + return totals; + } + + public synchronized PropagationMetric collectMetrics() { + PropagationMetric prevDelta = delta; + + delta = null; + return prevDelta; + } + + /* Fix-Me: delete after next build.. unused + public synchronized PropagationMetric addDeltaToTotals(long reportingDelta) { // returns delta + if (delta != null) { + totals.mergeMetrics(delta); + PropagationMetric oldDelta = delta; + delta = null; + return oldDelta; + } else + return null; + } + */ +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/PropagationMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/PropagationMetric.java new file mode 100644 index 000000000..8bf71be1e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/endpointMeter/PropagationMetric.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.endpointMeter; + + +import net.jxta.endpoint.*; +import net.jxta.impl.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; + +import java.util.*; + + +/** + * Metric corresponding to a propagated messages + * Meter corresponding to propagated to a ServiceName/ServiceParam pair + **/ +public class PropagationMetric implements DocumentSerializable { + private String serviceName; + private String serviceParameter; + + private String serviceIdString; // for Hashing + int numPropagations; + int numPropagatedTo; + int numFilteredOut; + int numErrorsPropagated; + long propagationTime; + + public PropagationMetric() { + serviceIdString = serviceName + serviceParameter; + } + + public PropagationMetric(PropagationMeter propagationMeter) { + this.serviceName = propagationMeter.getServiceName(); + this.serviceParameter = propagationMeter.getServiceParameter(); + + serviceIdString = serviceName + serviceParameter; + } + + public PropagationMetric(PropagationMetric prototype) { + this.serviceName = prototype.getServiceName(); + this.serviceParameter = prototype.getServiceParameter(); + + serviceIdString = serviceName + serviceParameter; + } + + void registerPropagateMessageStats(int numPropagatedTo, int numFilteredOut, int numErrorsPropagated, long propagationTime) { + this.numPropagations++; + this.numPropagatedTo += numPropagatedTo; + this.numFilteredOut += numFilteredOut; + this.numErrorsPropagated += numErrorsPropagated; + this.propagationTime += propagationTime; + } + + /** The Endpoint address for this outbound message queue **/ + public String getServiceName() { + return serviceName; + } + + /** The Endpoint address for this outbound message queue **/ + public String getServiceParameter() { + return serviceParameter; + } + + /** The Number of Propagated Messages **/ + public int getNumPropagations() { + return numPropagations; + } + + /** Total number of transports messagess were propagated to **/ + public int getNumPropagatedTo() { + return numPropagatedTo; + } + + /** The Number of Filtered out Messages **/ + + /** The Average of number of Transports propagated To from propagation to transport **/ + public int getAverageNumTransports() { + return (numPropagatedTo == 0) ? 0 : (numPropagations / numPropagatedTo); + } + + public int getNumFilteredOut() { + return numFilteredOut; + } + + /** The Number of Errors propagating Messages **/ + public int getNumErrorsPropagated() { + return numErrorsPropagated; + } + + /** The Sum of (clock) times from propagation to transport **/ + public long getPropagationTime() { + return propagationTime; + } + + /** The Average of (clock) times from propagation to transport **/ + public long getAveragePropagationTime() { + return (numPropagatedTo == 0) ? 0 : (propagationTime / numPropagatedTo); + } + + @Override + public boolean equals(Object obj) { + + if (obj instanceof PropagationMetric) { + PropagationMetric other = (PropagationMetric) obj; + + return serviceIdString.equals(other.serviceIdString); + } else { + return false; + } + } + + public boolean matches(String serviceName, String serviceParam) { + if (serviceName.equals(getServiceName())) { + if (serviceParam == null && getServiceParameter() == null) { + return true; + } else if (serviceParam != null && getServiceParameter() != null) { + return serviceParam.equals(getServiceParameter()); + } + } + return false; + } + + @Override + public int hashCode() { + return serviceIdString.hashCode(); + } + + String getServiceIdString() { + return serviceIdString; + } + + public void mergeMetrics(PropagationMetric other) { + numPropagatedTo += other.numPropagatedTo; + numFilteredOut += other.numFilteredOut; + numErrorsPropagated += other.numErrorsPropagated; + propagationTime += other.propagationTime; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + + DocumentSerializableUtilities.addString(element, "serviceName", serviceName); + DocumentSerializableUtilities.addString(element, "serviceParam", serviceParameter); + + if (numPropagations != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagations", numPropagatedTo); + } + + if (numPropagatedTo != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagatedTo", numPropagatedTo); + } + + if (numFilteredOut != 0) { + DocumentSerializableUtilities.addInt(element, "numFilteredOut", numFilteredOut); + } + + if (numErrorsPropagated != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsPropagated", numErrorsPropagated); + } + + if (propagationTime != 0) { + DocumentSerializableUtilities.addLong(element, "propagationTime", propagationTime); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("serviceName")) { + serviceName = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("serviceParam")) { + serviceParameter = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("numPropagations")) { + numPropagations = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagatedTo")) { + numPropagatedTo = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFilteredOut")) { + numFilteredOut = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("propagationTime")) { + propagationTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numErrorsPropagated")) { + numErrorsPropagated = DocumentSerializableUtilities.getInt(childElement); + } + } + + serviceIdString = serviceName + serviceParameter; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/mcast/McastTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/mcast/McastTransport.java new file mode 100644 index 000000000..8a0dfd9ae --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/mcast/McastTransport.java @@ -0,0 +1,887 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.mcast; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; +import java.net.SocketException; +import java.net.URI; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessagePropagater; +import net.jxta.endpoint.MessengerEventListener; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.meter.MonitorResources; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.TransportAdvertisement; + +import net.jxta.impl.endpoint.EndpointServiceImpl; +import net.jxta.impl.endpoint.IPUtils; +import net.jxta.impl.endpoint.msgframing.MessagePackageHeader; +import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings; +import net.jxta.impl.endpoint.transportMeter.TransportServiceMonitor; +import net.jxta.impl.meter.MonitorManager; +import net.jxta.impl.peergroup.StdPeerGroup; +import net.jxta.impl.protocol.TCPAdv; + +/** + * This class implements the IP Multicast Message Transport. + *

      + * Important Note: This implementation was formerly a portion of the TCP + * Message Transport and currently uses the TCP Transport's configuration + * advertisement. + * + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.MessagePropagater + * @see net.jxta.endpoint.EndpointService + * @see JXTA Protocols Specification : Standard JXTA Transport Bindings + */ +public class McastTransport implements Runnable, Module, MessagePropagater { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(McastTransport.class.getName()); + + /** + * Well known service class identifier: mcast message transport + */ + public final static ModuleClassID MCAST_TRANSPORT_CLASSID = + ModuleClassID.create(URI.create("urn:jxta:uuid-0C801F65D38F421C9884D706B337B81105")); + + /** + * Well known service spec identifier: mcast message transport + */ + public final static ModuleSpecID MCAST_TRANSPORT_SPECID = + ModuleSpecID.create(URI.create("urn:jxta:uuid-0C801F65D38F421C9884D706B337B8110106")); + + /** + * The Protocol name we will use for our endpoint addresses. + */ + private String protocolName = "mcast"; + + /** + * Our Source Addres. + */ + private EndpointAddress ourSrcAddr = null; + + /** + * The Source Address Element we attach to all of the messages we send. + */ + private MessageElement msgSrcAddrElement = null; + + /** + * The name of the local interface that we bind to. + */ + private String interfaceAddressStr; + + /** + * The address of the local interface address that be bind to. + */ + private InetAddress usingInterface; + + /** + * If {@code true} then we are closed otherwise {@code false} + */ + private boolean isClosed = false; + + /** + * The name of multicast address we will send/receive upon. + */ + private String multicastAddress = "224.0.1.85"; + + /** + * The multicast address we will send/receive upon. + */ + private InetAddress multicastInetAddress; + + /** + * The port number will send/receive upon. + */ + private int multicastPort = 1234; + + /** + * The "return address" we will advertise. + */ + private EndpointAddress publicAddress = new EndpointAddress(protocolName, multicastAddress + ":" + Integer.toString(multicastPort), null, null); + + /** + * The maximum size of multicast messages we will send and the size of the + * {@code DatagramPacket}s we will allocate. + */ + private int multicastPacketSize = 16384; + + /** + * The socket we use to send and receive. + */ + private MulticastSocket multicastSocket = null; + + /** + * Daemon thread which services the multicast socket and receives datagrams. + */ + private Thread multicastThread = null; + + /** + * Thread pooling/queing multicast datagram processor. + */ + private DatagramProcessor multicastProcessor; + + /** + * The peer group we are working for. + */ + private PeerGroup group = null; + + /** + * The Module Class ID we were assigned in init(). + */ + private ID assignedID = null; + + /** + * The impl advertisement we were provided in init(). + */ + private ModuleImplAdvertisement implAdvertisement = null; + + /** + * The endpoint service we are working for. + */ + private EndpointService endpoint = null; + + private TransportMeter multicastTransportMeter; + private TransportBindingMeter multicastTransportBindingMeter; + private transient boolean disabled = false; + + /** + * Construct a new McastTransport instance + */ + public McastTransport() { + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof McastTransport) { + McastTransport likeMe = (McastTransport) target; + return getProtocolName().equals(likeMe.getProtocolName()) && getPublicAddress().equals(likeMe.getPublicAddress()); + } + return false; + } + + /** + * {@inheritDoc} + */ + public int hashCode() { + return getPublicAddress().hashCode(); + } + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + this.group = group; + this.assignedID = assignedID; + this.implAdvertisement = (ModuleImplAdvertisement) impl; + + ConfigParams configAdv = group.getConfigAdvertisement(); + + // Get out invariable parameters from the implAdv + XMLElement param = (XMLElement) implAdvertisement.getParam(); + + if (param != null) { + Enumeration list = param.getChildren("Proto"); + if (list.hasMoreElements()) { + XMLElement pname = list.nextElement(); + protocolName = pname.getTextValue(); + } + } + + // Get our peer-defined parameters in the configAdv + param = (XMLElement) configAdv.getServiceParam(PeerGroup.tcpProtoClassID); + if (null == param) { + throw new IllegalArgumentException(TransportAdvertisement.getAdvertisementType() + " could not be located."); + } + + Enumeration tcpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv + if (tcpChilds.hasMoreElements()) { + param = tcpChilds.nextElement(); + Attribute typeAttr = param.getAttribute("type"); + + if (!TCPAdv.getAdvertisementType().equals(typeAttr.getValue())) { + throw new IllegalArgumentException("transport adv is not a " + TCPAdv.getAdvertisementType()); + } + + if (tcpChilds.hasMoreElements()) { + throw new IllegalArgumentException("Multiple transport advs detected for " + assignedID); + } + } else { + throw new IllegalArgumentException(TransportAdvertisement.getAdvertisementType() + " could not be located."); + } + + Advertisement paramsAdv = null; + try { + paramsAdv = AdvertisementFactory.newAdvertisement(param); + } catch (NoSuchElementException notThere) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not find parameter document", notThere); + } + } + + if (!(paramsAdv instanceof TCPAdv)) { + throw new IllegalArgumentException("Provided Advertisement was not a " + TCPAdv.getAdvertisementType()); + } + + TCPAdv adv = (TCPAdv) paramsAdv; + + // Check if we are disabled. If so, don't bother with the rest of config. + if (!adv.getMulticastState()) { + disabled = true; + return; + } + + // Determine the local interface to use. If the user specifies one, use + // that. Otherwise, use the all the available interfaces. + interfaceAddressStr = adv.getInterfaceAddress(); + if (interfaceAddressStr != null) { + try { + usingInterface = InetAddress.getByName(interfaceAddressStr); + } catch (UnknownHostException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid address for local interface address, using default"); + } + usingInterface = IPUtils.ANYADDRESS; + } + } else { + usingInterface = IPUtils.ANYADDRESS; + } + + // Start the servers + + // Only the outgoing interface matters. + // Verify that ANY interface does not in fact mean LOOPBACK only. + // If that's the case, we want to make that explicit, so that + // consistency checks regarding the allowed use of that interface work + // properly. + if (usingInterface.equals(IPUtils.ANYADDRESS)) { + boolean localOnly = true; + Iterator eachLocal = IPUtils.getAllLocalAddresses(); + while (eachLocal.hasNext()) { + InetAddress anAddress = eachLocal.next(); + if (!anAddress.isLoopbackAddress()) { + localOnly = false; + break; + } + } + + if (localOnly) { + usingInterface = IPUtils.LOOPBACK; + } + } + + ourSrcAddr = new EndpointAddress(group.getPeerID(), null, null); + msgSrcAddrElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, ourSrcAddr.toString(), null); + + // Get the multicast configuration. + multicastAddress = adv.getMulticastAddr(); + multicastPort = adv.getMulticastPort(); + + // XXX 20070711 bondolo We resolve the address only once. Perhaps we should do this dynamically? + try { + multicastInetAddress = InetAddress.getByName(multicastAddress); + } catch (UnknownHostException notValid) { + IllegalArgumentException failed = new IllegalArgumentException("Invalid or unknown host name :" + multicastAddress); + failed.initCause(notValid); + throw failed; + } + + assert multicastInetAddress.isMulticastAddress(); + publicAddress = new EndpointAddress(protocolName, multicastAddress + ":" + Integer.toString(multicastPort), null, null); + multicastPacketSize = adv.getMulticastSize(); + + // Create the multicast input socket + try { + multicastSocket = new MulticastSocket(new InetSocketAddress(usingInterface, multicastPort)); + } catch (IOException failed) { + throw new PeerGroupException("Could not open multicast socket", failed); + } + + try { + // Surprisingly, "true" means disable.... + multicastSocket.setLoopbackMode(false); + } catch (SocketException ignored) { + // We may not be able to set loopback mode. It is inconsistent + // whether an error will occur if the set fails. + } + + // Tell tell the world about our configuration. + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring IP Multicast Message Transport : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID: ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration:"); + configInfo.append("\n\t\tProtocol: ").append(protocolName); + configInfo.append("\n\t\tInterface address: ").append(interfaceAddressStr == null ? "(unspecified)" : interfaceAddressStr); + configInfo.append("\n\t\tMulticast Addr: ").append(multicastAddress); + configInfo.append("\n\t\tMulticast Port: ").append(multicastPort); + configInfo.append("\n\t\tMulticast Packet Size: ").append(multicastPacketSize); + + configInfo.append("\n\tBound To :"); + configInfo.append("\n\t\tUsing Interface: ").append(usingInterface.getHostAddress()); + + configInfo.append("\n\t\tMulticast Server Bind Addr: ").append(multicastSocket.getLocalSocketAddress()); + configInfo.append("\n\t\tPublic Address: ").append(publicAddress); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized int startApp(String[] arg) { + if (disabled) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("IP Multicast Message Transport disabled."); + } + return Module.START_DISABLED; + } + + endpoint = group.getEndpointService(); + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return Module.START_AGAIN_STALLED; + } + + isClosed = false; + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + TransportServiceMonitor transportServiceMonitor = (TransportServiceMonitor) MonitorManager.getServiceMonitor(group, + MonitorResources.transportServiceMonitorClassID); + + if (transportServiceMonitor != null) { + multicastTransportMeter = transportServiceMonitor.createTransportMeter("Multicast", publicAddress); + multicastTransportBindingMeter = getMulticastTransportBindingMeter(publicAddress); + // Since multicast is connectionless, force it to appear outbound connected + multicastTransportBindingMeter.connectionEstablished(true, 0); + // Since multicast is connectionless, force it to appear inbound connected + multicastTransportBindingMeter.connectionEstablished(false, 0); + } + } + + // We're fully ready to function. + MessengerEventListener messengerEventListener = endpoint.addMessageTransport(this); + if (messengerEventListener == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + return -1; + } + + // Cannot start before registration + multicastProcessor = new DatagramProcessor(((StdPeerGroup) group).getExecutor()); + multicastThread = new Thread(group.getHomeThreadGroup(), this, "IP Multicast Listener for " + publicAddress); + multicastThread.setDaemon(true); + multicastThread.start(); + + try { + multicastSocket.joinGroup(multicastInetAddress); + } catch (IOException soe) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Could not join multicast group, setting Multicast off"); + } + return -1; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("IP Multicast Message Transport started."); + } + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public synchronized void stopApp() { + if (isClosed || disabled) { + return; + } + + isClosed = true; + + if (multicastSocket != null) { + multicastSocket.close(); + multicastSocket = null; + } + + if (null != multicastProcessor) { + multicastProcessor.stop(); + multicastProcessor = null; + } + + endpoint.removeMessageTransport(this); + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (multicastTransportBindingMeter != null)) { + // Since multicast is connectionless, force it to appear outbound disconnected + multicastTransportBindingMeter.connectionClosed(true, 0); + // Since multicast is connectionless, force it to appear inbound disconnected + multicastTransportBindingMeter.connectionClosed(false, 0); + } + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return protocolName; + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return publicAddress; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return (EndpointService) endpoint.getInterface(); + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + /** + * {@inheritDoc} + *

      + * Handles incoming multicasts and enqueues them with the datagram processor. + */ + public void run() { + + try { + while (!isClosed) { + byte[] buffer = new byte[multicastPacketSize]; + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + + try { + multicastSocket.receive(packet); + + if (isClosed) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("multicast message received from :" + packet.getAddress().getHostAddress()); + } + + // This operation is blocking and may take a long time to + // return. As a result we may lose datagram packets because + // we are not calling + // {@link MulticastSocket#receive(DatagramPacket)} often + // enough. + multicastProcessor.put(packet); + } catch (InterruptedException woken) { + Thread.interrupted(); + } catch (InterruptedIOException woken) { + Thread.interrupted(); + } catch (Exception e) { + if (isClosed) { + return; + } + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE) && (!isClosed)) { + LOG.log(Level.SEVERE, "failure during multicast receive", e); + } + break; + } + } + } catch (Throwable all) { + if (isClosed) { + return; + } + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + multicastThread = null; + } + } + + /** + * {@inheritDoc} + *

      + * Synchronized to not allow concurrent IP multicast: this naturally bounds + * the usage of ip-multicast boolean be linear and not exponential. + */ + public synchronized boolean propagate(Message message, String pName, String pParams, int initalTTL) { + long sendStartTime = System.currentTimeMillis(); + int numBytesInPacket = 0; + + try { + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, msgSrcAddrElement); + + // First build the destination and source addresses + EndpointAddress destAddr = new EndpointAddress(publicAddress, pName, pParams); + MessageElement dstAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NAME, destAddr.toString(), null); + + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, dstAddressElement); + + WireFormatMessage serialed = WireFormatMessageFactory.toWire(message, WireFormatMessageFactory.DEFAULT_WIRE_MIME, null); + MessagePackageHeader header = new MessagePackageHeader(); + + header.setContentTypeHeader(serialed.getMimeType()); + header.setContentLengthHeader(serialed.getByteLength()); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(multicastPacketSize); + + buffer.write('J'); + buffer.write('X'); + buffer.write('T'); + buffer.write('A'); + header.sendToStream(buffer); + serialed.sendToStream(buffer); + buffer.flush(); + buffer.close(); + numBytesInPacket = buffer.size(); + + if ((buffer.size() > multicastPacketSize) && Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Multicast datagram exceeds multicast size."); + } + + DatagramPacket packet = new DatagramPacket(buffer.toByteArray(), numBytesInPacket, multicastInetAddress, multicastPort); + + multicastSocket.send(packet); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent Multicast message to :" + pName + "/" + pParams); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (multicastTransportBindingMeter != null)) { + multicastTransportBindingMeter.messageSent(true, message, System.currentTimeMillis() - sendStartTime, numBytesInPacket); + } + return true; + } catch (IOException e) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (multicastTransportBindingMeter != null)) { + multicastTransportBindingMeter.sendFailure(true, message, System.currentTimeMillis() - sendStartTime, numBytesInPacket); + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Multicast socket send failed", e); + } + return false; + } + } + + /** + * Handle a byte buffer from a multi-cast. + * + * @param packet the message packet. + */ + void processMulticast(DatagramPacket packet) { + int size = packet.getLength(); + byte[] buffer = packet.getData(); + + long messageReceiveBeginTime = System.currentTimeMillis(); + + try { + if (size < 4) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("damaged multicast discarded"); + } + throw new IOException("damaged multicast discarded : too short"); + } + + if (('J' != buffer[0]) || ('X' != buffer[1]) || ('T' != buffer[2]) || ('A' != buffer[3])) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("damaged multicast discarded"); + } + throw new IOException("damaged multicast discarded : incorrect signature"); + } + + ByteBuffer bbuffer = ByteBuffer.wrap(buffer, 4, size - 4); + MessagePackageHeader header = new MessagePackageHeader(); + + if (!header.readHeader(bbuffer)) { + throw new IOException("Failed to read framing header"); + } + + MimeMediaType msgMime = header.getContentTypeHeader(); + // TODO 20020730 bondolo@jxta.org Do something with content-coding here. + + // read the message! + Message msg = WireFormatMessageFactory.fromBuffer(bbuffer, msgMime, null); + + // Extract the source and destination + MessageElement srcAddrElem = msg.getMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, EndpointServiceImpl.MESSAGE_SOURCE_NAME); + if (null == srcAddrElem) { + throw new IOException("No Source Address in " + msg); + } + + msg.removeMessageElement(srcAddrElem); + + EndpointAddress srcAddr = new EndpointAddress(srcAddrElem.toString()); + + if (srcAddr.equals(ourSrcAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Discard loopback multicast message"); + } + return; + } + + MessageElement dstAddrElem = msg.getMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, EndpointServiceImpl.MESSAGE_DESTINATION_NAME); + if (null == dstAddrElem) { + throw new IOException("No Destination Address in " + msg); + } + + msg.removeMessageElement(dstAddrElem); + + EndpointAddress dstAddr = new EndpointAddress(dstAddrElem.toString()); + + // Handoff the message to the EndpointService Manager + endpoint.processIncomingMessage(msg, srcAddr, dstAddr); + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (multicastTransportBindingMeter != null)) { + multicastTransportBindingMeter.messageReceived(false, msg, messageReceiveBeginTime - System.currentTimeMillis(), size); + } + } catch (Exception e) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (multicastTransportBindingMeter != null)) { + multicastTransportBindingMeter.receiveFailure(false, messageReceiveBeginTime - System.currentTimeMillis(), size); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Discard incoming multicast message", e); + } + } + } + + TransportBindingMeter getMulticastTransportBindingMeter(EndpointAddress destinationAddress) { + if (multicastTransportMeter != null) { + return multicastTransportMeter.getTransportBindingMeter(group.getPeerID(), destinationAddress); + } else { + return null; + } + } + + /** + * Handles incoming datagram packets. This implementation uses the peer + * group Executor service to process the datagram packets, but limits the + * number of concurrent tasks. + */ + private class DatagramProcessor implements Runnable { + + /** + * The maximum number of datagrams we will simultaneously process. + */ + private static final int MAX_SIMULTANEOUS_PROCESSING = 5; + + /** + * The executor to which we will issue tasks. + */ + final Executor executor; + + /** + * Queue of datagrams waiting to be executed. The queue is quite small. + * The goal is not to cache datagrams in memory. If we can't keep up it + * is better that we drop messages. + */ + final BlockingQueue queue = new ArrayBlockingQueue(MAX_SIMULTANEOUS_PROCESSING + 1); + + /** + * The number of executor tasks we are currently using. + */ + int currentTasks = 0; + + /** + * If {@code true} then this processor has been stopped. + */ + volatile boolean stopped = false; + + /** + * Default constructor + * @param executor the threadpool + */ + DatagramProcessor(Executor executor) { + this.executor = executor; + } + + /** + * Stops this thread + */ + void stop() { + queue.clear(); + stopped = true; + } + + /** + * Puts a datagram on the queue. The enqueue operation is blocking and + * may take a significant amount of time. + * + * @param packet the datagram + * @throws InterruptedException if interrupted + */ + void put(DatagramPacket packet) throws InterruptedException { + boolean execute = false; + + if (stopped) { + return; + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "Queuing incoming datagram packet : " + packet); + } + + // push the datagram + queue.put(packet); + + // See if we can start a new executor. + synchronized (this) { + if (!stopped && (currentTasks < MAX_SIMULTANEOUS_PROCESSING)) { + currentTasks++; + execute = true; + } + } + + // If it's ok, start a new executor outside of the synchronization. + if (execute) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINER, "Starting new executor datagram processing task"); + } + executor.execute(this); + } + } + + /** + * {@inheritDoc} + */ + public void run() { + try { + DatagramPacket packet; + while (!stopped && (null != (packet = queue.poll()))) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "Processing incoming datagram packet : " + packet); + } + processMulticast(packet); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable", all); + } + } finally { + synchronized (this) { + currentTasks--; + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/mcast/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/mcast/package.html new file mode 100644 index 000000000..0fc088141 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/mcast/package.html @@ -0,0 +1,17 @@ + + + + + + +A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which uses raw +IP multicast datagrams. + +@see net.jxta.endpoint.EndpointService +@see net.jxta.endpoint.MessageTransport +@see net.jxta.endpoint.MessagePropagater +@see net.jxta.endpoint.Message +@see JXTA Protocols + Specification : Standard JXTA Transport Bindings + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/msgframing/MessagePackageHeader.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/msgframing/MessagePackageHeader.java new file mode 100644 index 000000000..c679feaae --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/msgframing/MessagePackageHeader.java @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.msgframing; + + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.text.MessageFormat; +import java.util.ListIterator; + +import net.jxta.document.MimeMediaType; + + +/** + * Header Package for Messages. Analogous to HTTP Headers. + */ +public class MessagePackageHeader { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(MessagePackageHeader.class.getName()); + + /** + * Standard header name for content-length + */ + private final static String CONTENT_LENGTH = "content-length"; + + /** + * Standard header name for content-type + */ + private final static String CONTENT_TYPE = "content-type"; + + /** + * The maximum size of Header data buffers we will emit. + */ + private final static int MAX_HEADER_LEN = 1024; + + /** + * Used for storing individual header elements. + */ + public static class Header { + + final String name; + final byte[] value; + + public Header(String name, byte[] value) { + this.name = name; + + assert value.length <= 65535; + + this.value = value; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return MessageFormat.format("{0} := {1}", name, value); + } + + public String getName() { + return name; + } + + public byte[] getValue() { + return value; + } + + public String getValueString() { + try { + return new String(value, "UTF-8"); + } catch (UnsupportedEncodingException never) { + // utf-8 is a required encoding. + throw new Error("UTF-8 encoding support missing!"); + } + } + } + + /** + * The individual header elements in the order they were read. + */ + private final List

      headers = new ArrayList
      (); + + /** + * Creates a new instance of MessagePackageHeader. Used for outgoing messages. + */ + public MessagePackageHeader() {} + + /** + * Creates a new instance of MessagePackageHeader. Used for incoming messages. + * + * @param in The stream from which the headers will be read. + * @throws java.io.IOException if an io error occurs. + */ + public MessagePackageHeader(InputStream in) throws IOException { + boolean sawEmpty = false; + boolean sawLength = false; + boolean sawType = false; + DataInput di = new DataInputStream(in); + + // todo 20021014 bondolo@jxta.org A framing signature would help here. + + do { + byte headerNameLength = di.readByte(); + + if (0 == headerNameLength) { + sawEmpty = true; + } else { + byte[] headerNameBytes = new byte[headerNameLength]; + + di.readFully(headerNameBytes); + + String headerNameString = new String(headerNameBytes, "UTF-8"); + + if (headerNameString.equalsIgnoreCase(CONTENT_LENGTH)) { + if (sawLength) { + throw new IOException("Duplicate content-length header"); + } + sawLength = true; + } + + if (headerNameString.equalsIgnoreCase(CONTENT_TYPE)) { + if (sawType) { + throw new IOException("Duplicate content-type header"); + } + sawType = true; + } + + int headerValueLength = di.readUnsignedShort(); + + byte[] headerValueBytes = new byte[headerValueLength]; + + di.readFully(headerValueBytes); + + headers.add(new Header(headerNameString, headerValueBytes)); + + } + } while (!sawEmpty); + + if (!sawLength) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Content Length header was missing"); + } + throw new IOException("Content Length header was missing"); + } + + if (!sawType) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Content Type header was missing"); + } + throw new IOException("Content Type header was missing"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + + result.append('['); + + Iterator
      eachHeader = getHeaders(); + + while (eachHeader.hasNext()) { + Header aHeader = eachHeader.next(); + + result.append(" {"); + result.append(aHeader); + result.append('}'); + + if (eachHeader.hasNext()) { + result.append(','); + } + } + + result.append(']'); + + return result.toString(); + } + + /** + * Returns number of header elements otherwise -1 + * + * @param buffer the byte buffer + * @return number of header elements + */ + private int getHeaderCount(ByteBuffer buffer) { + int pos = buffer.position(); + int limit = buffer.limit(); + int headerCount = 0; + boolean sawZero = false; + + while (pos < limit) { + // get header name length + int len = buffer.get(pos) & 0xFF; + + pos += 1; + + if (0 == len) { + sawZero = true; + break; + } + + // advance past name + pos += len; + + if ((pos + 2) >= limit) { + // not enough data + break; + } + + // get value length + len = buffer.getShort(pos) & 0xFFFF; + pos += 2; + + // advance past value + pos += len; + + headerCount++; + } + + return sawZero ? headerCount : -1; + } + + /** + * Reads a Header from a ByteBuffer + * + * @param buffer the input buffer + * @return {@code true} If the header block was completely read. + * @throws IOException if an io error is encountered + */ + public boolean readHeader(ByteBuffer buffer) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Parsing Package Header from byte buffer :{0}", buffer.toString())); + } + + int count = getHeaderCount(buffer); + + if (count < 0) { + return false; + } + for (int i = 1; i <= count; i++) { + byte headerNameLength = buffer.get(); + byte[] headerNameBytes = new byte[headerNameLength]; + + buffer.get(headerNameBytes); + String headerNameString = new String(headerNameBytes, "UTF-8"); + int headerValueLength = buffer.getShort() & 0x0FFFF; // unsigned + byte[] headerValueBytes = new byte[headerValueLength]; + + buffer.get(headerValueBytes); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("Adding Name {0}: {1}", headerNameString, headerValueBytes)); + } + headers.add(new Header(headerNameString, headerValueBytes)); + } + + // get the end-of-pkg + buffer.get(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("Parsed {0} header elements, buffer stats :{1}", count, buffer.toString())); + } + return true; + } + + /** + * Add a header. + * + * @param name The header name. The UTF-8 encoded representation of this + * name may not be longer than 255 bytes. + * @param value The value for the header. May not exceed 65535 bytes in + * length. + */ + public void addHeader(String name, byte[] value) { + if (name.length() > 255) { + throw new IllegalArgumentException("name may not exceed 255 bytes in length."); + } + + if (value.length > 65535) { + throw new IllegalArgumentException("value may not exceed 65535 bytes in length."); + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Add header :" + name + "(" + name.length() + ") with " + value.length + " bytes of value"); + } + + headers.add(new Header(name, value)); + } + + /** + * Add a header. + * + * @param name The header name. The UTF-8 encoded representation of this + * name may not be longer than 255 bytes. + * @param value The value for the header. May not exceed 65535 bytes in + * length. + */ + public void addHeader(String name, String value) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Add header :" + name + "(" + name.length() + ") with " + value.length() + " chars of value"); + } + + try { + addHeader(name, value.getBytes("UTF-8")); + } catch (UnsupportedEncodingException never) { + // utf-8 is a required encoding. + throw new IllegalStateException("UTF-8 encoding support missing!"); + } + } + + /** + * Replace a header. Replaces all existing headers with the same name. + * + * @param name The header name. The UTF-8 encoded representation of this + * name may not be longer than 255 bytes. + * @param value The value for the header. May not exceed 65535 bytes in + * length. + */ + public void replaceHeader(String name, byte[] value) { + if (name.length() > 255) { + throw new IllegalArgumentException("name may not exceed 255 bytes in length."); + } + + if (value.length > 65535) { + throw new IllegalArgumentException("value may not exceed 65535 bytes in length."); + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Replace header :" + name + "(" + name.length() + ") with " + value.length + " bytes of value"); + } + + Header newHeader = new Header(name, value); + ListIterator
      eachHeader = getHeaders(); + boolean replaced = false; + + while (eachHeader.hasNext()) { + Header aHeader = eachHeader.next(); + + if (aHeader.getName().equalsIgnoreCase(name)) { + eachHeader.set(newHeader); + replaced = true; + } + } + + if(!replaced) { + headers.add(newHeader); + } + } + + /** + * Replace a header. Replaces all existing headers with the same name + * + * @param name The header name. The UTF-8 encoded representation of this + * name may not be longer than 255 bytes. + * @param value The value for the header. May not exceed 65535 bytes in + * length. + */ + public void replaceHeader(String name, String value) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Replace header :" + name + "(" + name.length() + ") with " + value.length() + " chars of value"); + } + + try { + replaceHeader(name, value.getBytes("UTF-8")); + } catch (UnsupportedEncodingException never) { + // utf-8 is a required encoding. + throw new IllegalStateException("UTF-8 encoding support missing!"); + } + } + + /** + * Gets all of the headers. This iterator provides access to the live + * data of this instance. Modifying the headers using {@code add()}, + * {@code set()}, {@code remove()} is permitted. + * + * @return all of the headers + */ + public ListIterator
      getHeaders() { + return headers.listIterator(); + } + + /** + * Gets all of the headers matching the specified name + * + * @param name the name of the header we are seeking. + */ + public Iterator
      getHeader(String name) { + List
      matchingHeaders = new ArrayList
      (); + + for (Header aHeader : headers) { + if (name.equals(aHeader.getName())) { + matchingHeaders.add(aHeader); + } + } + return matchingHeaders.iterator(); + } + + /** + * Write this group of header elements to a stream. + * + * @param out the stream to send the headers to. + * @throws java.io.IOException if an io error occurs + */ + public void sendToStream(OutputStream out) throws IOException { + Iterator
      eachHeader = getHeaders(); + DataOutput dos = new DataOutputStream(out); + + // todo 20021014 bondolo@jxta.org A framing signature would help here + + while (eachHeader.hasNext()) { + Header aHeader = eachHeader.next(); + + byte[] nameBytes = aHeader.getName().getBytes("UTF-8"); + byte[] value = aHeader.getValue(); + + assert nameBytes.length <= 255; + assert value.length <= 65535; + + dos.write(nameBytes.length); + dos.write(nameBytes); + dos.writeShort(value.length); + dos.write(value); + } + + // write empty header + dos.write(0); + } + + /** + * Return a ByteBuffer representing this group of header elements. + * + * @return ByteBuffer representing this Header + */ + public ByteBuffer getByteBuffer() { + // note: according to the spec this may exceed MAX_HEADER_LEN, + // but since there are practically only 3 header elements used + // it's safe to assume this implemention detail. + ByteBuffer buffer = ByteBuffer.allocate(MAX_HEADER_LEN); + + for (Header header : headers) { + byte[] name; + + try { + name = header.getName().getBytes("UTF-8"); + } catch (UnsupportedEncodingException never) { + throw new Error("Required UTF-8 encoding not available."); + } + + byte[] value = header.getValue(); + + assert name.length <= 255; + assert value.length <= 65535; + + buffer.put((byte) name.length); + buffer.put(name); + buffer.putShort((short) value.length); + buffer.put(value); + } + + // write empty header + buffer.put((byte) 0); + buffer.flip(); + + return buffer; + } + + /** + * Convenience method setting the "{@code content-length}" header. + * + * @param length length of the message. + */ + public void setContentLengthHeader(long length) { + byte[] lengthAsBytes = new byte[8]; + + for (int eachByte = 0; eachByte < 8; eachByte++) { + lengthAsBytes[eachByte] = (byte) (length >> ((7 - eachByte) * 8L)); + } + + replaceHeader(CONTENT_LENGTH, lengthAsBytes); + } + + /** + * Convenience method for getting the "{@code content-length}" header. + * + * @return length from the header or -1 if there was no + * {@code content-length} header element. + */ + public long getContentLengthHeader() { + Iterator
      it = getHeader(CONTENT_LENGTH); + + if (!it.hasNext()) { + return -1L; + } + Header header = it.next(); + byte[] lengthAsBytes = header.getValue(); + + long lengthAsLong = 0L; + + for (int eachByte = 0; eachByte < 8; eachByte++) { + lengthAsLong |= ((long) (lengthAsBytes[eachByte] & 0xff)) << ((7 - eachByte) * 8L); + } + + return lengthAsLong; + } + + /** + * Convenience method for setting the "{@code content-type}" header. + * + * @param type type of the message. + */ + public void setContentTypeHeader(MimeMediaType type) { + replaceHeader(CONTENT_TYPE, type.toString()); + } + + /** + * Convenience method for getting the "{@code content-type}" header. + * + * @return type from the header or "{@code application/octet-stream}" if + * there was no {@code content-type} header. + */ + public MimeMediaType getContentTypeHeader() { + Iterator
      it = getHeader(CONTENT_TYPE); + + if (!it.hasNext()) { + // return the generic type. Better than returning "null". + return MimeMediaType.AOS; + } + Header header = it.next(); + + return MimeMediaType.valueOf(header.getValueString()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/msgframing/WelcomeMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/msgframing/WelcomeMessage.java new file mode 100644 index 000000000..6bce09d21 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/msgframing/WelcomeMessage.java @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.msgframing; + + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.util.Arrays; +import java.util.List; +import java.text.MessageFormat; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * Contains a JXTA connection Welcome Message. The Welcome Message is sent by + * both participant peers as the first interchange on newly opened connections. + *

      + *

      The Welcome Message contains the following information: + *

        + *
      • The address to which the local peer believes it is connected.
      • + *
      • The local peer's return address, the source address.
      • + *
      • The local peer's peer id.
      • + *
      • A flag which controls propagation behaviour for this conneciton.
      • + *
      + * + * @see JXTA Protocols Specification : TCP/IP Message Transport + */ +public class WelcomeMessage { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(WelcomeMessage.class.getName()); + + /** + * The Welcome Message Signature/Preamble + */ + private final static String GREETING = "JXTAHELLO"; + + /** + * A space for separating elements of the welcome message. + */ + private final static String SPACE = " "; + + /** + * Version string for Welcome Message Version 1.1 + */ + private final static String WELCOME_VERSION_1_1 = "1.1"; + + /** + * Version string for Welcome Message Version 3.0 + */ + private final static String WELCOME_VERSION_3_0 = "3.0"; + + /** + * The current welcome message version. This is the only version we will emit. + */ + private final static String CURRENTVERSION = WELCOME_VERSION_1_1; + + /** + * The destination address that we believe we are connecting to. + */ + private EndpointAddress destinationAddress; + + /** + * Our return address, the purported source address of this connection. + */ + private EndpointAddress publicAddress; + + /** + * Our peerid, the logical return address. + */ + private ID peerID; + + /** + * This connection does not wish to receive any propagation/broadcast/notifications. + */ + private boolean noPropagate; + + /** + * The preferred binary wire message format version. + */ + private int preferredMessageVersion; + + /** + * The welcome message version we are supporting + */ + private String versionString; + + /** + * The welcome message as a text string. + */ + private String welcomeString; + + /** + * The welcome message as UTF-8 byte stream. + */ + private byte[] welcomeBytes; + private final int MAX_LEN = 4096; + + /** + * Default constructor + */ + public WelcomeMessage() {} + + /** + * Creates a new instance of WelcomeMessage for our Welcome Message. + * + * @param destAddr The destination address that we believe we are connecting to. + * @param publicaddress Our return address, the purported source address of this connection. + * @param peerid Our peerid, the logical return address. + * @param dontPropagate If true this connection does not wish to receive any propagation/broadcast/notifications. + */ + public WelcomeMessage(EndpointAddress destAddr, EndpointAddress publicaddress, ID peerid, boolean dontPropagate) { + this(destAddr, publicaddress, peerid, dontPropagate, 0); + } + + /** + * Creates a new instance of WelcomeMessage for our Welcome Message. + * + * @param destAddr The destination address that we believe we are connecting to. + * @param publicaddress Our return address, the purported source address of this connection. + * @param peerid Our peerid, the logical return address. + * @param dontPropagate If true this connection does not wish to receive any propagation/broadcast/notifications. + * @param preferredMsgVersion Binary Wire Messsage format we prefer. + */ + public WelcomeMessage(EndpointAddress destAddr, EndpointAddress publicaddress, ID peerid, boolean dontPropagate, int preferredMsgVersion) { + destinationAddress = destAddr; + publicAddress = publicaddress; + peerID = peerid; + noPropagate = dontPropagate; + versionString = CURRENTVERSION; + preferredMessageVersion = preferredMsgVersion; + + welcomeString = GREETING + SPACE + destAddr.toString() + SPACE + publicAddress.toString() + SPACE + peerID.toString() + + SPACE + (noPropagate ? "1" : "0") + SPACE + versionString; + + try { + welcomeBytes = welcomeString.getBytes("UTF-8"); + } catch (UnsupportedEncodingException never) {// all implementations must support utf-8 + } + } + + /** + * Creates a new instance of WelcomeMessage for another peer's Welcome Message + * + * @param in The InputStream to read the welcome message from. + * @throws IOException If there is a problem reading the welcome header. + */ + public WelcomeMessage(InputStream in) throws IOException { + welcomeBytes = new byte[MAX_LEN]; + int readAt = 0; + boolean sawCR = false; + boolean sawCRLF = false; + + // read the welcome message + do { + int c = in.read(); + + switch (c) { + case -1: + throw new EOFException("Stream terminated before end of welcome message"); + + case '\r': + if (sawCR) { + welcomeBytes[readAt++] = (byte) 0x0D; + } + sawCR = true; + break; + + case '\n': + if (sawCR) { + sawCRLF = true; + } else { + welcomeBytes[readAt++] = (byte) 0x0A; + } + break; + + default: + welcomeBytes[readAt++] = (byte) c; + sawCR = false; + } + + if (readAt == welcomeBytes.length) { + throw new IOException("Invalid welcome message, too long"); + } + + } while (!sawCRLF); + + byte[] truncatedBytes = new byte[readAt]; + + System.arraycopy(welcomeBytes, 0, truncatedBytes, 0, readAt); + welcomeBytes = truncatedBytes; + welcomeString = new String(welcomeBytes, "UTF-8"); + parseWelcome(welcomeString); + } + + /** + * Attempts to init a welcome object from a socketChannel + * + * @param buffer the data buffer + * @return null if incomplete welcome was received + * @throws IOException if an io error occurs + */ + public boolean read(ByteBuffer buffer) throws IOException { + int limit = buffer.limit(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Reading a buffer of size :{0}", limit)); + } + if (limit == 0) { + throw new IOException(MessageFormat.format("Invalid welcome message. Invalid length {0}", limit)); + } + int eomPos = findEom(buffer, 0, limit); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Buffer size :{0} Welcome End-Of-Message pos :{1}", limit, eomPos)); + } + if (eomPos < 0) { + return false; + } + welcomeBytes = new byte[eomPos]; + try { + buffer.get(welcomeBytes, 0, eomPos); + // skip + buffer.position(eomPos + 2); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("buffer stats :{0}", buffer.toString())); + } + } catch (BufferUnderflowException buf) { + // not enough data, signal for another read + return false; + } + welcomeString = new String(welcomeBytes, "UTF-8"); + parseWelcome(welcomeString); + return true; + } + + /** + * returns position of position in buffer, otherwise -1 + * + * @param buffer the byte buffer + * @param offset The offset within the buffer array + * @param length the length + * @return terminating position, or -1 if none found + */ + private int findEom(ByteBuffer buffer, int offset, int length) { + + int lastOffset = length - 2; // we are looking for 2 chars. + + for (int j = offset; j <= lastOffset; j++) { + byte c = buffer.get(j); + + if (c == '\r') { + c = buffer.get(j + 1); + + if (c == '\n') { + return j; + } + } + } + + return -1; + } + + private void parseWelcome(String welcomeString) throws IOException { + List thePieces = Arrays.asList(welcomeString.split("\\s")); + + if (0 == thePieces.size()) { + throw new IOException("Invalid welcome message, did not contain any tokens."); + } + + if (thePieces.size() < 5) { + throw new IOException("Invalid welcome message, did not contain enough tokens."); + } + + if (!GREETING.equals(thePieces.get(0))) { + throw new IOException("Invalid welcome message, did not start with greeting"); + } + + try { + destinationAddress = new EndpointAddress(thePieces.get(1)); + } catch (IllegalArgumentException badAddress) { + IOException failed = new IOException("Invalid welcome message, bad destination address"); + + failed.initCause(badAddress); + throw failed; + } + + try { + publicAddress = new EndpointAddress(thePieces.get(2)); + } catch (IllegalArgumentException badAddress) { + IOException failed = new IOException("Invalid welcome message, bad publicAddress address"); + + failed.initCause(badAddress); + throw failed; + } + + try { + URI peerURI = new URI(thePieces.get(3)); + + peerID = IDFactory.fromURI(peerURI); + } catch (URISyntaxException badURI) { + IOException failed = new IOException("Invalid welcome message, bad peer id"); + + failed.initCause(badURI); + throw failed; + } + + versionString = thePieces.get(thePieces.size() - 1); + + if (WELCOME_VERSION_1_1.equals(versionString)) { + if (6 != thePieces.size()) { + throw new IOException("Invalid welcome message, incorrect number of tokens."); + } + + String noPropagateStr = thePieces.get(4); + + if (noPropagateStr.equals("1")) { + noPropagate = true; + } else if (noPropagateStr.equals("0")) { + noPropagate = false; + } else { + throw new IOException("Invalid welcome message, illegal value for propagate flag"); + } + + // preferred message version is not set in + preferredMessageVersion = 0; + } else if (WELCOME_VERSION_3_0.equals(versionString)) { + if (7 != thePieces.size()) { + throw new IOException("Invalid welcome message, incorrect number of tokens."); + } + + String noPropagateStr = thePieces.get(4); + + if (noPropagateStr.equals("1")) { + noPropagate = true; + } else if (noPropagateStr.equals("0")) { + noPropagate = false; + } else { + throw new IOException("Invalid welcome message, illegal value for propagate flag"); + } + + String preferredVersionStr = thePieces.get(5); + + try { + preferredMessageVersion = Integer.valueOf(preferredVersionStr); + } catch (IllegalArgumentException failed) { + IOException failure = new IOException("Invalid welcome message, illegal value for preferred message version"); + + failure.initCause(failed); + + throw failure; + } + } else { + // Unrecognized Welcome message version. Use default values. + noPropagate = false; + preferredMessageVersion = 0; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Successfuly parsed a welcome message :" + getWelcomeString()); + } + } + + /** + * Write the welcome message to the provided stream. + * + * @param theStream The OutputStream to which to write the welcome message. + * @throws IOException If there is a problem writing the welcome message. + */ + public void sendToStream(OutputStream theStream) throws IOException { + theStream.write(welcomeBytes); + theStream.write('\r'); + theStream.write('\n'); + } + + /** + * Write the welcome to a socket channel + * + * @return A ByteBuffer of the welcome message + * @throws java.io.IOException if an io error occurs + */ + public ByteBuffer getByteBuffer() throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Sending welcome message of size:{0}", welcomeBytes.length + 2)); + } + ByteBuffer buffer = ByteBuffer.allocate(welcomeBytes.length + 2); + + buffer.put(welcomeBytes); + buffer.put((byte) '\r'); + buffer.put((byte) '\n'); + buffer.flip(); + return buffer; + } + + /** + * Return the peerid associated with the Welcome Message. + * + * @return The peer ID from the Welcome Message. + */ + public ID getPeerID() { + return peerID; + } + + /** + * Return the source address associated with the Welcome Message. + * + * @return The source address from the Welcome Message. + */ + public EndpointAddress getPublicAddress() { + return publicAddress; + } + + /** + * Return the destination address associated with the Welcome Message. + * + * @return The destination address from the Welcome Message. + */ + public EndpointAddress getDestinationAddress() { + return destinationAddress; + } + + /** + * Return the propagation preference from the Welcome Message. + * + * @return true if no propagation is desired + * otherwise false + */ + public boolean dontPropagate() { + return noPropagate; + } + + /** + * Return the preferred message version from the Welcome Message. + * + * @return The preferred Message Version. + */ + public int getPreferredMessageVersion() { + return preferredMessageVersion; + } + + /** + * Return the version associated with the Welcome Message. + * + * @return The version from the Welcome Message. + */ + public String getWelcomeVersion() { + return versionString; + } + + /** + * Return a String containing the Welcome Message. + * + * @return a String containing the Welcome Message. + */ + public String getWelcomeString() { + return welcomeString; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/package.html new file mode 100644 index 000000000..acd637cf9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/package.html @@ -0,0 +1,13 @@ + + + + + + + A JXTA {@link net.jxta.endpoint.EndpointService} implementation which + implements the standard JXTA Endpoint Service. + + @see JXTA Protocols Specification : Endpoint Service + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayClient.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayClient.java new file mode 100644 index 000000000..ab5ac489b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayClient.java @@ -0,0 +1,1351 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.relay; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.MessageTransport; +import net.jxta.endpoint.Messenger; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.protocol.RelayConfigAdv; +import net.jxta.impl.util.SeedingManager; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.URISeedingManager; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * RelayClient manages the relationship with the RelayServer(s) + * + */ +public class RelayClient implements MessageReceiver, Runnable { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RelayClient.class.getName()); + + private final static long DEFAULT_EXPIRATION = 20L * TimeUtils.AMINUTE; + + private final PeerGroup group; + private final String serviceName; + private EndpointService endpoint; + private final EndpointAddress publicAddress; + private final String groupName; + private final String peerId; + + private final int maxServers; + private final long leaseLengthToRequest; + private final long messengerPollInterval; + + private Thread thread = null; + + private volatile boolean closed = false; + + /** + *
        + *
      • Values are {@link net.jxta.peergroup.PeerGroup}.
      • + *
      + */ + private final List activeRelayListeners = new ArrayList(); + + /** + *
        + *
      • Keys are {@link net.jxta.endpoint.EndpointAddress}.
      • + *
      • Values are {@link net.jxta.protocol.RouteAdvertisement}.
      • + *
      + */ + private final Map activeRelays = new Hashtable(); + + /** + * Our source for relay servers. + */ + private final SeedingManager seedingManager; + + RelayServerConnection currentServer = null; + + public RelayClient(PeerGroup group, String serviceName, RelayConfigAdv relayConfig) { + this.group = group; + this.groupName = group.getPeerGroupID().getUniqueValue().toString(); + + this.serviceName = serviceName; + + maxServers = (-1 != relayConfig.getMaxRelays()) ? relayConfig.getMaxRelays() : RelayTransport.DEFAULT_MAX_SERVERS; + leaseLengthToRequest = (-1 != relayConfig.getClientLeaseDuration()) + ? relayConfig.getClientLeaseDuration() + : RelayTransport.DEFAULT_LEASE; + messengerPollInterval = (-1 != relayConfig.getMessengerPollInterval()) + ? relayConfig.getMessengerPollInterval() + : RelayTransport.DEFAULT_POLL_INTERVAL; + + URISeedingManager uriSeedingManager = new URISeedingManager(relayConfig.getAclUri(), relayConfig.getUseOnlySeeds(), group, serviceName); + + for (EndpointAddress aSeeder : Arrays.asList(relayConfig.getSeedRelays())) { + uriSeedingManager.addSeed(aSeeder.toURI()); + } + + for (URI aSeed : Arrays.asList(relayConfig.getSeedingURIs())) { + uriSeedingManager.addSeedingURI(aSeed); + } + + this.seedingManager = uriSeedingManager; + + // sanity check + + peerId = group.getPeerID().getUniqueValue().toString(); + publicAddress = new EndpointAddress(RelayTransport.protocolName, peerId, null, null); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Relay Client"); + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID : ").append(group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tService Name : ").append(serviceName); + configInfo.append("\n\t\tPublic Address : ").append(publicAddress); + configInfo.append("\n\t\tMax Relay Servers : ").append(maxServers); + configInfo.append("\n\t\tMax Lease Length : ").append(leaseLengthToRequest).append("ms."); + configInfo.append("\n\t\tMessenger Poll Interval : ").append(messengerPollInterval).append("ms."); + LOG.config(configInfo.toString()); + } + } + + public synchronized boolean startClient() { + endpoint = group.getEndpointService(); + + if (endpoint.addMessageTransport(this) == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + return false; + } + + // start the client thread + thread = new Thread(group.getHomeThreadGroup(), this, "Relay Client Worker Thread for " + publicAddress); + thread.setDaemon(true); + thread.start(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Started client : " + publicAddress.toString()); + } + + return true; + } + + public synchronized void stopClient() { + if (closed) { + return; + } + + closed = true; + + endpoint.removeMessageTransport(this); + + // make sure the thread is not running + Thread tempThread = thread; + + thread = null; + if (tempThread != null) { + tempThread.interrupt(); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Stopped client : " + publicAddress.toString()); + } + + } + + /** + * {@inheritDoc} + */ + public Iterator getPublicAddresses() { + + return Collections.singletonList(publicAddress).iterator(); + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return RelayTransport.protocolName; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return endpoint; + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + /** + * Logic for the relay client + * + *
        + *
      1. Pick a relay server to try
      2. + *
      3. try getting a messenger to relay server, if can not get messenger, start over
      4. + *
      5. use the messenger to send a connect message
      6. + *
      7. wait for a response, if there is no response or a disconnect response, start over
      8. + *
      9. while still connected + *
          + *
        1. renew the lease as needed and keep the messenger connected
        2. + *
            + *
          + * + *

          FIXME 20041102 bondolo The approach used here is really, really + * stupid. The calls to connectToRelay() will not return if a + * connection to a relay is achieved. This makes continued iteration over + * seeds after return incredibly silly. connectToRelay() only + * returns when it can NO LONGER CONNECT to the relay. The only + * hack I can think of to subvert this is to stop iteration of advs/seeds + * if connectToRelay() takes a long time. bizarre. + */ + public void run() { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Start relay client thread"); + } + + try { + long nextConnectAttemptAt = 0; + + RdvAdvertisement referral = null; + List allSeeds = null; + long gotLastSeedsAt = 0; + + // run until the service is stopped + while (!closed) { + // Attempt to use any referral immediately. + if (null != referral) { + RouteAdvertisement relayRoute = referral.getRouteAdv(); + + relayRoute.setDestPeerID(referral.getPeerID()); + + referral = connectToRelay(new RelayServerConnection(this, relayRoute)); + + continue; + } + + // Sleep until it is time for the next connection attempt. + long untilNextConnectAttempt = TimeUtils.toRelativeTimeMillis(nextConnectAttemptAt); + + if (untilNextConnectAttempt > 0) { + try { + Thread.sleep(untilNextConnectAttempt); + } catch (InterruptedException e) { + // ignore interrupted exception + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Thread Interrupted ", e); + } + + continue; + } + } + + // Don't allow next connection attempt to start any sooner than this. + nextConnectAttemptAt = TimeUtils.toAbsoluteTimeMillis(30 * TimeUtils.ASECOND); + + // Get seeds if we need them or the ones we have are old. + if ((TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), gotLastSeedsAt) > (5 * TimeUtils.AMINUTE)) + || allSeeds.isEmpty()) { + allSeeds = new ArrayList(Arrays.asList(seedingManager.getActiveSeedRoutes())); + gotLastSeedsAt = TimeUtils.timeNow(); + } + + // Try seeds until we get a connection, a referral or are closed. + while ((null == referral) && !allSeeds.isEmpty() && !closed) { + RouteAdvertisement aSeed = allSeeds.remove(0); + + if (null == aSeed.getDestPeerID()) { + // It is an incomplete route advertisement. We are going to assume that it is only a wrapper for a single ea. + Vector seed_eas = aSeed.getDest().getVectorEndpointAddresses(); + + if (!seed_eas.isEmpty()) { + EndpointAddress aSeedHost = new EndpointAddress(seed_eas.get(0)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Attempting relay connect to : " + aSeedHost); + } + + referral = connectToRelay(new RelayServerConnection(this, aSeedHost)); + } + } else { + // We have a full route, send it to the virtual address of the route! + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Attempting relay connect to : " + aSeed.getDestPeerID()); + } + + referral = connectToRelay(new RelayServerConnection(this, aSeed)); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + thread = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("stop client thread"); + } + } + } + + protected boolean isRelayConnectDone() { + return (thread == null || Thread.currentThread() != thread); + } + + /** + * @param server The relay server to connect to + * @return The advertisement of an alternate relay server to try. + */ + RdvAdvertisement connectToRelay(RelayServerConnection server) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Connecting to " + server); + } + + RdvAdvertisement referral = null; + + // make this the current server + currentServer = server; + + // try getting a messenger to the relay peer + if (!server.createMessenger(leaseLengthToRequest)) { + return referral; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("got messenger " + server); + } + + // check the peerId of the relay peer + if (server.logicalAddress != null && "jxta".equals(server.logicalAddress.getProtocolName())) { + server.peerId = server.logicalAddress.getProtocolAddress(); + } + + // make sure that the peerId was found. + if (server.peerId == null) { + if (server.messenger != null) { + server.sendDisconnectMessage(); + server.messenger.close(); + } + return referral; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("got peerId " + server); + } + + synchronized (this) { + // wait for a response from the server + // There is no real damage other than bandwidth usage in sending + // a message on top of the connection request, so we realy do not + // wait very long before doing it. + long requestTimeoutAt = TimeUtils.toAbsoluteTimeMillis(5 * TimeUtils.ASECOND); + + while (currentServer != null && currentServer.leaseLength == 0 && !isRelayConnectDone()) { + long waitTimeout = requestTimeoutAt - System.currentTimeMillis(); + + if (waitTimeout <= 0) { + // did not receive the response in time ? + break; + } + + try { + wait(waitTimeout); + } catch (InterruptedException e) { + // ignore interrupt + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "wait got interrupted early ", e); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("wait done"); + } + } + } + + if (currentServer == null) { + return server.alternateRelayAdv; + } + + if (isRelayConnectDone()) { + if (currentServer.messenger != null) { + currentServer.messenger.close(); + } + currentServer = null; + return server.alternateRelayAdv; + } + + // If we did not get a lease in the first 5 secs, maybe it is because + // the server knows us from a previous session. Then it will wait for + // a lease renewal message before responding, not just the connection. + // Send one and wait another 15. + if (currentServer.leaseLength == 0) { + + currentServer.sendConnectMessage(leaseLengthToRequest); + + synchronized (this) { + + // wait for a response from the server + long requestTimeoutAt = TimeUtils.toAbsoluteTimeMillis(15 * TimeUtils.ASECOND); + + while (currentServer != null && currentServer.leaseLength == 0 && !isRelayConnectDone()) { + long waitTimeout = requestTimeoutAt - System.currentTimeMillis(); + + if (waitTimeout <= 0) { + // did not receive the response in time ? + break; + } + + try { + wait(waitTimeout); + } catch (InterruptedException e) { + // ignore interrupt + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "wait got interrupted early ", e); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("wait done"); + } + } + } + } + + // If we had a messenger but are going to give up that relay server because it is + // not responsive or rejected us. Make sure that the messenger is closed. + if (currentServer == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("did not get connect from " + server); + } + // return any alternate relay advertisements + return server.alternateRelayAdv; + } + + if (currentServer.relayAdv == null || currentServer.leaseLength == 0 || isRelayConnectDone()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("did not get connect from " + server); + } + if (currentServer.messenger != null) { + currentServer.sendDisconnectMessage(); + currentServer.messenger.close(); + } + currentServer = null; + + // return any alternate relay advertisements + return server.alternateRelayAdv; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Connected to " + server); + } + + RouteAdvertisement holdAdv = server.relayAdv; + EndpointAddress holdDest = server.logicalAddress; + + // register this relay server + addActiveRelay(holdDest, holdAdv); + + // maintain the relay server connection + referral = maintainRelayConnection(server); + + // unregister this relay server + removeActiveRelay(holdDest, holdAdv); + + return referral; + } + + // FIXME: jice@jxta.org 20030212. This is junk code: that should be a + // method of RelayServerConnection and at least not refer to currentServer + // other than to assign the reference. + protected RdvAdvertisement maintainRelayConnection(RelayServerConnection server) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("maintainRelayConnection() start " + currentServer); + } + + if (server == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RelayConnection() failed at start " + currentServer); + } + return null; + } + + synchronized (this) { + long currentTime = System.currentTimeMillis(); + long renewLeaseAt = currentServer.leaseObtainedAt + currentServer.leaseLength / 3; + long waitTimeout = 0; + + // This will be true if we need to do the first lease renewal early + // (that is at the time of the next connection check). + // We'll do that if we did not know the relay server's adv (seed). + // In that case we told the relay server to send us its own + // adv, else we told it to send us some alternate adv (we have to + // chose). In the former case, we want to do a lease connect + // request soon so that the server has an opportunity to send us + // the alternate adv that we did not get during initial connection. + + boolean earlyRenew = currentServer.seeded; + + while (currentServer != null && !isRelayConnectDone()) { + // calculate how long to wait + waitTimeout = renewLeaseAt - currentTime; + + // check that the waitTimeout is not greater than the messengerPollInterval + // We want to make sure that we poll. Most of the time it cost nothing. + // Also, if we urgently need to renew our lease we may wait + // less, but if we fail to get our lease renewed in time, the + // delay may become negative. In that case we do not want + // to start spinning madly. The only thing we can do is just + // wait some arbitrary length of time for the lease to be + // renewed. (If that gets badly overdue, we should probably + // give up on that relay server, though). + if (waitTimeout > messengerPollInterval || waitTimeout <= 0) { + waitTimeout = messengerPollInterval; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("waitTimeout=" + waitTimeout + " server=" + currentServer); + } + + try { + wait(waitTimeout); + } catch (InterruptedException e) { + Thread.interrupted(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("wait done, server=" + currentServer); + } + + // make sure the server did not disconnect while waiting + if (currentServer == null) { + break; + } + + // get the current time + currentTime = System.currentTimeMillis(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("check messenger " + currentServer); + } + + // check if the messenger is still open + if (currentServer.messenger.isClosed()) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Server connection broken"); + } + + // See if we can re-open, that happens often. + // That's a reason to renew the connection, + // Not a reason to give up on the server yet. + // Note we do not renew the lease. This is a transient + // and if the server forgot about us, it will respond + // to the connection alone. Otherwise, we'd rather avoid + // getting a response, since in some cases http connections + // close after each received message. + if (!currentServer.createMessenger(currentServer.leaseLength)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Server connection NOT re-established"); + } + // lost connection to relay server + currentServer = null; + break; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Server connection re-established"); + } + + // getMessenger asks for a new lease. + // In the meantime, we'll just assume our old lease is + // still current and that the messenger breakage was just + // a transient. + if (!isRelayConnectDone()) { + continue; + } + } + + // We've been asked to leave. Be nice and tell the + // server about it. + if (isRelayConnectDone()) { + break; + } + + // check if the lease needs to be renewed + renewLeaseAt = currentServer.leaseObtainedAt + currentServer.leaseLength / 3; + if (currentTime >= renewLeaseAt || earlyRenew) { + + earlyRenew = false; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("renew lease " + currentServer); + } + + // If we do not receive any response to our lease renewals + // (that is the response is overdue badly), then we give + // up and try another relayServer. We give up after 4 minutes + // because if we go as far as 5 we start overshooting other + // timeouts such as the local peer becoming a rdv in a sub-group. + // This later timeout is usually set to 5 minutes or more. + + if ((currentTime > currentServer.leaseObtainedAt + currentServer.leaseLength / 3 + 4 * TimeUtils.AMINUTE) + || (!currentServer.sendConnectMessage(leaseLengthToRequest))) { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("renew lease failed" + currentServer); + } + if (currentServer.messenger != null) { + currentServer.messenger.close(); + } + currentServer.messenger = null; + currentServer.peerId = null; + currentServer.leaseLength = 0; + currentServer.leaseObtainedAt = 0; + currentServer.relayAdv = null; + currentServer = null; + break; + } + } + } + } + + if (isRelayConnectDone() && currentServer != null) { + currentServer.sendDisconnectMessage(); + if (currentServer.messenger != null) { + currentServer.messenger.close(); + } + currentServer.messenger = null; + currentServer.peerId = null; + currentServer.leaseLength = 0; + currentServer.leaseObtainedAt = 0; + currentServer.relayAdv = null; + // Make sure that we will not suggest an alternate + // since we're asked to terminate. + currentServer.alternateRelayAdv = null; + + currentServer = null; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("maintainRelayConnection() terminated " + currentServer); + } + + return server.alternateRelayAdv; + } + + protected synchronized void handleResponse(Message message, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleResponse " + currentServer); + } + + // ignore all responses if there is not a current server + if (currentServer == null) { + return; + } + + // get the request, make it lowercase so that case is ignored + String response = RelayTransport.getString(message, RelayTransport.RESPONSE_ELEMENT); + + if (response == null) { + return; + } + response = response.toLowerCase(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("response = " + response); + } + + // check if a relay advertisement was included + RdvAdvertisement relayAdv = null; + + MessageElement advElement = message.getMessageElement(RelayTransport.RELAY_NS, RelayTransport.RELAY_ADV_ELEMENT); + + if (null != advElement) { + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(advElement); + Advertisement adv = AdvertisementFactory.newAdvertisement(asDoc); + + if (adv instanceof RdvAdvertisement) { + relayAdv = (RdvAdvertisement) adv; + } + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not read Relay RdvAdvertisement", e); + } + } + } + + // WATCHOUT: this is not a pid, just the unique string portion. + String serverPeerId = dstAddr.getServiceParameter(); + + // only process the request if a client peer id was sent + if (serverPeerId == null) { + return; + } + + // ignore all responses that are not from the current server + if (!serverPeerId.equals(currentServer.peerId)) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("serverPeerId = " + serverPeerId); + } + + // Figure out which response it is + if (RelayTransport.CONNECTED_RESPONSE.equals(response)) { + // Connect Response + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("connected response for " + currentServer); + } + + String responseLeaseString = RelayTransport.getString(message, RelayTransport.LEASE_ELEMENT); + + long responseLease = 0; + + if (responseLeaseString != null) { + try { + responseLease = Long.parseLong(responseLeaseString); + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not parse response lease string", e); + } + } + } + + // make sure the lease is valid + if (responseLease <= 0) { + // invalid lease value + return; + } + + // update the lease values + currentServer.leaseLength = responseLease; + currentServer.leaseObtainedAt = System.currentTimeMillis(); + + // Since we got the lease, if we requested a queue flush, it's + // now done. We never send it with a new messenger creation, but + // when the server already has us as a client it does not respond + // to connections through messenger creation, so we're sure we + // will have to send an explicit connect message before we get + // a response. So, we're sure it's done if it was needed. + currentServer.flushNeeded = false; + + if (relayAdv != null) { + // Set it only if it is the server's own. Else it got + // published. Still set alternateRelayAdv so that we + // can return something that could be usefull when this + // connection breaks. + PeerID pidOfAdv = relayAdv.getPeerID(); + String pidOfAdvUnique = pidOfAdv.getUniqueValue().toString(); + + if (currentServer.peerId.equals(pidOfAdvUnique)) { + currentServer.relayAdv = relayAdv.getRouteAdv(); + // Fix the embedded route adv ! + currentServer.relayAdv.setDestPeerID(pidOfAdv); + } else { + currentServer.alternateRelayAdv = relayAdv; + } + } + + notifyAll(); + + } else if (RelayTransport.DISCONNECTED_RESPONSE.equals(response)) { + // Disconnect Response + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("disconnected from " + currentServer); + } + + // If our request was denied, the adv that came back is + // always an alternate one. + currentServer.alternateRelayAdv = relayAdv; + + if (currentServer.messenger != null) { + currentServer.messenger.close(); + } + currentServer.messenger = null; + currentServer.peerId = null; + currentServer.leaseLength = 0; + currentServer.leaseObtainedAt = 0; + currentServer.relayAdv = null; + currentServer = null; + notifyAll(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("response handled for " + currentServer); + } + } + + static class RelayServerConnection { + final RelayClient client; + + Messenger messenger = null; + EndpointAddress logicalAddress = null; + String peerId = null; + long leaseLength = 0; + long leaseObtainedAt = 0; + + // If seeded out of a raw address, we have relayAddress. + // relayAdv comes only later. + public RouteAdvertisement relayAdv = null; + EndpointAddress relayAddress = null; + + RdvAdvertisement alternateRelayAdv = null; + boolean seeded = false; + boolean flushNeeded = true; // true until we know it's been done + + protected RelayServerConnection(RelayClient client, EndpointAddress addr) { + this.client = client; + relayAddress = new EndpointAddress(addr, null, null); + seeded = true; + } + + protected RelayServerConnection(RelayClient client, RouteAdvertisement relayAdv) { + this.client = client; + this.relayAdv = relayAdv; + } + + protected boolean createMessenger(long leaseLengthToRequest) { + + // make sure the old messenger is closed + if (messenger != null) { + messenger.close(); + messenger = null; + } + + List endpointAddresses = null; + + // check for a relay advertisement + if (relayAdv != null) { + AccessPointAdvertisement accessPointAdv = relayAdv.getDest(); + + if (accessPointAdv != null) { + endpointAddresses = accessPointAdv.getVectorEndpointAddresses(); + } + } else { + // silly but if we use getVetorEndpointAddresses, we get + // strings. It's realy simpler to have only one kind of obj + // inthere. + endpointAddresses = new ArrayList(1); + endpointAddresses.add(relayAddress.toString()); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("createMessenger to " + endpointAddresses); + } + + // make sure we found some endpoint addresses to try + if (endpointAddresses == null) { + return false; + } + + // try each endpoint address until one is successful + for (String s : endpointAddresses) { + if (s == null) { + continue; + } + EndpointAddress addr = new EndpointAddress(s); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("find transport for " + addr); + } + // get the list of messengers on this endpoint + Iterator transports = client.endpoint.getAllMessageTransports(); + + while (transports.hasNext() && messenger == null) { + MessageTransport transport = (MessageTransport) transports.next(); + + // only try transports that are senders and allow routing + if (transport instanceof MessageSender && ((MessageSender) transport).allowsRouting()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("try transport " + transport); + } + if (addr.getProtocolName().equals(transport.getProtocolName())) { + // NOTE: here we're creating a messenger. + // For risk management reason, we refrain from + // including the flush request at this time in + // this. There is the possibility that the + // connection will be repeatedly established + // by the transport in our bakck, and would keep + // including the flush request ! Normaly this + // does not matter because the server should + // disregard it when it come in that way, but + // still, let's be defensive. We will still send + // the flush in a subsequent explicit message. + String reqStr = RelayTransport.createConnectString(leaseLengthToRequest, relayAdv == null, false); + // NOTE: this is simulating address mangling by CrossgroupMessenger. + // The real service param is after the "/" in the below serviceParam arg. + EndpointAddress addrToUse = new EndpointAddress(addr, "EndpointService:" + client.groupName + , + client.serviceName + "/" + reqStr); + + messenger = ((MessageSender) transport).getMessenger(addrToUse, null); + if (messenger != null && messenger.isClosed()) { + messenger = null; + } + if (messenger != null) { + logicalAddress = messenger.getLogicalDestinationAddress(); + // We're using a known adv, which means that + // we did not ask to get the adv back. + // Make sure that we do not keep going with + // an adv for the wrong peer. That can happen. + if (relayAdv != null && !addr2pid(logicalAddress).equals(relayAdv.getDestPeerID())) { + // oops, wrong guy ! + messenger.close(); + messenger = null; + logicalAddress = null; + } + // In case it was not given, set relayAddress + // for toString purposes. + relayAddress = addr; + } + } + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messenger=" + messenger); + } + + return (messenger != null); + } + + protected boolean sendConnectMessage(long leaseLengthToRequest) { + if (messenger == null || messenger.isClosed()) { + return false; + } + + Message message = RelayTransport.createConnectMessage(leaseLengthToRequest, (relayAdv == null), flushNeeded); + + try { + messenger.sendMessage(message, "EndpointService:" + client.groupName, client.serviceName + "/" + client.peerId); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not send connect message", e); + } + + // connection attempt failed + return false; + } + + return true; + } + + protected boolean sendDisconnectMessage() { + if (messenger == null || messenger.isClosed()) { + return false; + } + + Message message = RelayTransport.createDisconnectMessage(); + + try { + messenger.sendMessage(message, "EndpointService:" + client.groupName, client.serviceName + "/" + client.peerId); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not send disconnect message", e); + } + + // connection attempt failed + return false; + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + + return + ((relayAddress == null) ? "(adv to " + relayAdv.getDestPeerID() + ")" : relayAddress.toString()) + " [" + + leaseLength + ", " + leaseObtainedAt + "] "; + } + } + + /** + * Register an active Relay to the endpoint. This is done + * so the Route Advertisement of the PeerAdvertisement is + * updated + */ + public synchronized boolean addActiveRelayListener(Object service) { + + boolean added = false; + + if (!activeRelayListeners.contains(service)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Register group to relay connection " + ((PeerGroup) service).getPeerGroupName()); + } + + activeRelayListeners.add(service); + + added = true; + } + + return added; + } + + /** + * Unregister an active Relay to the endpoint. This is done + * so the Route Advertisement of the PeerAdvertisement is + * updated + */ + public synchronized boolean removeActiveRelayListener(Object service) { + activeRelayListeners.remove(service); + + return true; + } + + /** + * Notify of a new relay connection + * + */ + public synchronized boolean addActiveRelay(EndpointAddress address, RouteAdvertisement relayRoute) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("notify add relay connection for " + address); + } + + // need to notify all our listeners + + for (Object activeRelayListener : activeRelayListeners) { + PeerGroup pg = (PeerGroup) activeRelayListener; + addRelay(pg, relayRoute); + } + + // maintain the list of active relays + activeRelays.put(address, relayRoute); + return true; + } + + /** + * Notify of a relay connection removal + * + */ + public synchronized boolean removeActiveRelay(EndpointAddress address, RouteAdvertisement relayRoute) { + + // need to notify all our listeners + + for (Object activeRelayListener : activeRelayListeners) { + PeerGroup pg = (PeerGroup) activeRelayListener; + removeRelay(pg, relayRoute); + } + + activeRelays.remove(address); + + return true; + } + + /** + * Register an active Relay to the endpoint. This is done + * so the Route Advertisement of the PeerAdvertisement is + * updated + * + * @param relayRoute address of the relay to add + */ + private void addRelay(PeerGroup pg, RouteAdvertisement relayRoute) { + + ID assignedID = PeerGroup.endpointClassID; + + try { + // get the advertisement of the associated endpoint address as we + // need to get the peer Id and available route + + // update our own peer advertisement + PeerAdvertisement padv = pg.getPeerAdvertisement(); + XMLDocument myParam = (XMLDocument) padv.getServiceParam(assignedID); + + RouteAdvertisement route; + + if (myParam == null) { + // we should have found a route here. This is not good + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("no route found in peer adv"); + } + return; + } else { + Enumeration paramChilds = myParam.getChildren(RouteAdvertisement.getAdvertisementType()); + XMLElement param = null; + + if (paramChilds.hasMoreElements()) { + param = paramChilds.nextElement(); + } + + route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(param); + } + + if (route == null) { // we should have a route here + return; + } + + // ready to stich the Relay route in our route advertisement + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("found route info for local peer \n" + route.display()); + } + + // update the new hops info + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("OLD route info to local peer \n" + route.display()); + } + + // If we already have the relay in our list of hops, remove it. + // The new version can only be more accurate. + route.removeHop(relayRoute.getDestPeerID()); + + // Get a hold of the hops list AFTER removing: removeHop + // rebuilds the vector ! + Vector hops = route.getVectorHops(); + + // Create the new relay Hop + hops.add(relayRoute.getDest()); + + // update the new hops info + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("NEW route info to local peer" + route.display()); + } + + // create the new param route + myParam = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + StructuredTextDocument xptDoc = (StructuredTextDocument) + route.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(myParam, myParam, xptDoc); + + padv.putServiceParam(assignedID, myParam); + + // publish the new peer advertisement + DiscoveryService discovery = pg.getDiscoveryService(); + + if (discovery != null) { + discovery.publish(padv, DiscoveryService.DEFAULT_LIFETIME, DiscoveryService.DEFAULT_EXPIRATION); + } + } catch (Exception ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "exception adding relay route ", ex); + } + } + } + + /** + * remove relay hop from the peer advertisement + * + * @param group which peer advertisement needs to be updated + * @param relayRoute address of the relay to be removed + */ + private void removeRelay(PeerGroup group, RouteAdvertisement relayRoute) { + + // we can keep the advertisement for now (should remove it) + // remove the relay from its active list + ID assignedID = PeerGroup.endpointClassID; + PeerID relayPid = relayRoute.getDestPeerID(); + + try { + // get the advertisement of the associated endpoint address as we + // need to get the peer Id and available route + + PeerAdvertisement padv; + + // update our peer advertisement + padv = group.getPeerAdvertisement(); + XMLDocument myParam = (XMLDocument) padv.getServiceParam(assignedID); + + RouteAdvertisement route = null; + + if (myParam == null) { + // no route found we should really have one + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("no route found in peer adv"); + return; + } + } else { + Enumeration paramChilds = myParam.getChildren(RouteAdvertisement.getAdvertisementType()); + XMLElement param = null; + + if (paramChilds.hasMoreElements()) { + param = paramChilds.nextElement(); + } + + route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement( param); + } + + if (route == null) { + return; + } // we should have a route here + + // update the new hops info + route.removeHop(relayPid); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("new route info to the peer" + route.display()); + } + + // create the new param route + myParam = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + XMLDocument xptDoc = (XMLDocument) route.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(myParam, myParam, xptDoc); + + padv.putServiceParam(assignedID, myParam); + + // publish the new advertisement + DiscoveryService discovery = group.getDiscoveryService(); + + if (discovery != null) { + discovery.publish(padv, DiscoveryService.DEFAULT_LIFETIME, DiscoveryService.DEFAULT_EXPIRATION); + } + } catch (Throwable theMatter) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed adding relay route", theMatter); + } + } + } + + /** + * return the list of connected relays + */ + public Vector getActiveRelays(PeerGroup pg) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("get active Relays list"); + } + + Vector hops = new Vector(); + + for (RouteAdvertisement route : activeRelays.values()) { + try { + // publish our route if pg is not null + if (pg != null) { + DiscoveryService discovery = pg.getDiscoveryService(); + + if (discovery != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("publishing route to active relay " + route.display()); + } + discovery.publish(route, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + } + } + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "error publishing active relay", ex); + } + continue; + } + + hops.add(route.getDest()); + } + + return hops; + } + + // convert an endpointRouterAddress into a PeerID + private static PeerID addr2pid(EndpointAddress addr) { + try { + URI asURI = new URI(ID.URIEncodingName, ID.URNNamespace + ":" + addr.getProtocolAddress(), null); + + return (PeerID) IDFactory.fromURI(asURI); + } catch (Exception ex) { + return null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayReferralSeedingManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayReferralSeedingManager.java new file mode 100644 index 000000000..3c3b3e261 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayReferralSeedingManager.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2002-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.relay; + +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.MessageTransport; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.RouteAdvertisement; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.impl.util.URISeedingManager; + +/** + * Extends the URI Seeding Manager by supplementing the list of active seeds + * with the active relay peers. + */ +public class RelayReferralSeedingManager extends URISeedingManager { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(RelayReferralSeedingManager.class.getName()); + + private final PeerGroup group; + + /** + * Get an instance of RelayReferralSeedingManager. + * + * @param aclLocation acl URI + * @param allowOnlySeeds if true allow only seeds + * @param group the peer group + * @param serviceName Service name + */ + public RelayReferralSeedingManager(URI aclLocation, boolean allowOnlySeeds, PeerGroup group, String serviceName) { + super(aclLocation, allowOnlySeeds, group, serviceName); + this.group = group; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized URI[] getActiveSeedURIs() { + Collection result = new ArrayList(); + Collection relays = getRelayPeers(); + + int eaIndex = 0; + boolean addedEA; + + do { + addedEA = false; + + for (RouteAdvertisement aRA : relays) { + List raEAs = aRA.getDestEndpointAddresses(); + if (eaIndex < raEAs.size()) { + URI seedURI = raEAs.get(eaIndex).toURI(); + if(!result.contains(seedURI)) { + result.add(seedURI); + } + addedEA = true; + } + } + + // Next loop we use the next most preferred address. + eaIndex++; + } while (addedEA); + + // Add the non-relay seeds afterwards. + for(URI eachURI : Arrays.asList(super.getActiveSeedURIs())) { + if(!result.contains(eachURI)) { + result.add(eachURI); + } + } + + return result.toArray(new URI[result.size()]); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized RouteAdvertisement[] getActiveSeedRoutes() { + List result = new ArrayList(getRelayPeers()); + + for(RouteAdvertisement eachRoute : Arrays.asList(super.getActiveSeedRoutes())) { + if(!result.contains(eachRoute)) { + result.add(eachRoute); + } + } + return result.toArray(new RouteAdvertisement[result.size()]); + } + + /** + * @return List of RouteAdvertisement + */ + private Collection getRelayPeers() { + Collection result = new ArrayList(); + + try { + EndpointService ep = group.getEndpointService(); + + Iterator it = ep.getAllMessageTransports(); + + while (it.hasNext()) { + MessageTransport mt = (MessageTransport) it.next(); + + if (!mt.getEndpointService().getGroup().getPeerGroupID().equals(group.getPeerGroupID())) { + // We only want relay services in this peer group. + continue; + } + + if (mt instanceof RelayClient) { + RelayClient er = (RelayClient) mt; + + RelayClient.RelayServerConnection current = er.currentServer; + + if (null == current) { + continue; + } + + RouteAdvertisement rdvAdv = current.relayAdv; + + if (null == rdvAdv) { + continue; + } + + result.add(rdvAdv.clone()); + } + } + } catch (Exception ez1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unexpected error getting relays", ez1); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found " + result.size() + " relay seeds."); + } + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayServer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayServer.java new file mode 100644 index 000000000..c62b150c8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayServer.java @@ -0,0 +1,1498 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.relay; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Random; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerEvent; +import net.jxta.endpoint.MessengerEventListener; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.access.AccessList; +import net.jxta.impl.protocol.RelayConfigAdv; +import net.jxta.impl.util.TimeUtils; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; +import net.jxta.impl.endpoint.EndpointUtils; + +/** + * Relay server that maintains outgoing message queues, leases, etc. + */ +public class RelayServer implements MessageSender, MessengerEventListener, Runnable { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RelayServer.class.getName()); + + private final static int MAX_CACHED_SERVERS = 20; + + /** + * The EndpointService for the RelayService + */ + private EndpointService endpointService; + + /** + * The DiscoveryService for the RelayService + */ + private DiscoveryService discoveryService; + + /** + * The public address is of the form relay://peerId + */ + private final EndpointAddress publicAddress; + + /** + * Map of the current clients + */ + private final Map relayedClients = new HashMap(); + + protected final PeerGroup group; + protected final String serviceName; + private final int maxClients; + private final long maxLeaseDuration; + private final long stallTimeout; + private final int clientQueueSize; + private final long minBroadcastInterval; + + protected final String peerId; + + protected final AccessList acl; + protected File aclFile; + protected long refreshTime = 0; + + protected long aclFileLastModified = 0; + private static final long ACL_REFRESH_PERIOD = 30 * TimeUtils.AMINUTE; + + protected RelayServerCache relayServerCache; + + private Thread gcThread = null; + + private MessengerEventListener messengerEventListener = null; + + /** + * constructor + */ + public RelayServer(PeerGroup group, String serviceName, RelayConfigAdv relayConfigAdv) { + + this.group = group; + peerId = group.getPeerID().getUniqueValue().toString(); + publicAddress = new EndpointAddress(RelayTransport.protocolName, peerId, null, null); + + this.serviceName = serviceName; + + this.maxClients = (-1 != relayConfigAdv.getMaxClients()) + ? relayConfigAdv.getMaxClients() + : RelayTransport.DEFAULT_MAX_CLIENTS; + this.clientQueueSize = (-1 != relayConfigAdv.getClientMessageQueueSize()) + ? relayConfigAdv.getClientMessageQueueSize() + : RelayTransport.DEFAULT_CLIENT_QUEUE_SIZE; + this.maxLeaseDuration = (-1 != relayConfigAdv.getServerLeaseDuration()) + ? relayConfigAdv.getServerLeaseDuration() + : RelayTransport.DEFAULT_LEASE; + this.minBroadcastInterval = (-1 != relayConfigAdv.getAnnounceInterval()) + ? relayConfigAdv.getAnnounceInterval() + : RelayTransport.DEFAULT_BROADCAST_INTERVAL; + this.stallTimeout = (-1 != relayConfigAdv.getStallTimeout()) + ? relayConfigAdv.getStallTimeout() + : RelayTransport.DEFAULT_STALL_TIMEOUT; + + aclFile = new File(new File(group.getStoreHome()), "relayACL.xml"); + aclFileLastModified = aclFile.lastModified(); + this.acl = new AccessList(); + try { + acl.init(aclFile); + this.refreshTime = System.currentTimeMillis() + ACL_REFRESH_PERIOD; + } catch (IOException io) { + acl.setGrantAll(true); + this.refreshTime = Long.MAX_VALUE; + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RelayServer Access Control granting all permissions"); + } + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Relay Server"); + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tService Name : ").append(serviceName); + configInfo.append("\n\t\tMax Relay Clients : ").append(maxClients); + configInfo.append("\n\t\tMax Lease Length : ").append(maxLeaseDuration).append("ms."); + configInfo.append("\n\t\tBroadcast Interval : ").append(minBroadcastInterval).append("ms."); + configInfo.append("\n\t\tStall Timeout : ").append(stallTimeout).append("ms."); + + LOG.config(configInfo.toString()); + } + } + + /** + * Debug routine: returns the list of relayedClients with details. + */ + public List getRelayedClients() { + List res = new ArrayList(); + + for (Object o : Arrays.asList(relayedClients.values().toArray())) { + String client = o.toString(); + + res.add(client); + } + + return res; + } + + public boolean startServer() { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Starting " + publicAddress.toString()); + } + + endpointService = group.getEndpointService(); + discoveryService = group.getDiscoveryService(); + + if ((messengerEventListener = endpointService.addMessageTransport(this)) == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + return false; + } + + try { + discoveryService.publish(createRdvAdvertisement(group.getPeerAdvertisement(), serviceName)); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish Relay RdvAdvertisement", e); + } + } + + relayServerCache = new RelayServerCache(this); + + // start cache relay servers + relayServerCache.startCache(); + + endpointService.addMessengerEventListener(this, EndpointService.HighPrecedence); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Relay Server started"); + } + return true; + } + + public void stopServer() { + // stop cache relay servers + relayServerCache.stopCache(); + relayServerCache = null; + + // remove messenger events listener since we do not have any clients + endpointService.removeMessengerEventListener(this, EndpointService.HighPrecedence); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Messenger Event Listener removed " + serviceName); + } + + // Close all clients. + // Get a list of the clients but leave them in the map; + // they remove themselves by calling removeClient(this). + // That's why we do not iterate through the real map to close them. + + RelayServerClient[] oldClients; + + synchronized (relayedClients) { + oldClients = relayedClients.values().toArray(new RelayServerClient[0]); + } + + int i = oldClients.length; + + while (i-- > 0) { + oldClients[i].closeClient(); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Stopped " + publicAddress); + } + } + + /* + * Methods inherited from MessageSender + */ + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return publicAddress; + } + + /** + * {@inheritDoc} + */ + public boolean isConnectionOriented() { + return true; + } + + /** + * {@inheritDoc} + */ + public boolean allowsRouting() { + return true; + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress destAddr, Object hintIgnored) { + Messenger messenger = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("getMessenger for dest " + destAddr); + } + + if (!RelayTransport.protocolName.equals(destAddr.getProtocolName())) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("could not make messenger for protocol :" + destAddr.getProtocolName()); + } + + return null; + } + + // check if we have a queue for this client + RelayServerClient handler = getClient(destAddr.getProtocolAddress()); + + if (handler != null) { + messenger = handler.getMessenger(publicAddress, destAddr, false); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messenger for " + destAddr.getProtocolAddress() + " is " + messenger); + } + + return messenger; + } + + /** + * {@inheritDoc} + */ + @Deprecated + public boolean ping(EndpointAddress addr) { + + synchronized (relayedClients) { + return (null != relayedClients.get(addr.getProtocolAddress())); + } + } + + /* + * Methods inherited from MessageTransport + */ + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return RelayTransport.protocolName; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return endpointService; + } + + /** + * {@inheritDoc} + */ + public boolean messengerReady(MessengerEvent event) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messengerReady"); + } + + Messenger newMessenger = event.getMessenger(); + Object source = event.getSource(); + EndpointAddress connectionAddress = event.getConnectionAddress(); + + // Sanity check, this should not happen + if (newMessenger == null || source == null || connectionAddress == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("there was not a messenger or not enough information"); + } + + return false; + } + + // We do not grab just any messenger; that would replace the + // existing one and then we could have a fight between the + // front channel and the back channel from the same peer. + // We only grab back-channel messengers that where explicitly + // directed to the relay. + if (!serviceName.equals(connectionAddress.getServiceName())) { + return false; + } + + // make sure that it is not a higher level messenger + if (source instanceof MessageSender && !((MessageSender) source).allowsRouting()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("this is a higher level messenger"); + } + + return false; + } + + // make sure that this is not one of our own. + if (source == this || newMessenger instanceof RelayServerClient.RelayMessenger) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("this is a relay messenger"); + } + + return false; + } + + // make sure that the messenger matches a possible client address + EndpointAddress destAddr = newMessenger.getLogicalDestinationAddress(); + + if (destAddr == null || !"jxta".equals(destAddr.getProtocolName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("LogicalDestinationAddress is not a \"jxta\" protocol"); + } + + return false; + } + + // check if we have a queue for this client + // In that case, we just give it the handler and be done. + // We must not process the lease request that comes with a messenger + // for an existing client. If we did, we would reply with a lease + // response. Some connections can carry only one message and then + // close. In that case, the client has to re-establish the connection + // every time we respond. So, if we repond to all incoming connections + // we're going nowhere. In some cases, the client realy wants a + // response because it believes it is an initial connection while + // we still have it from a previous session. In that case, the client + // must try to send an explicit lease renewal message. (To which + // we do respond). + + String clientPeerId = destAddr.getProtocolAddress(); + RelayServerClient handler = getClient(clientPeerId); + + if (handler != null) { + return handler.addMessenger(newMessenger); + } + + // Non-existent client. We want to process the + // connection request and respond. + // handleRequest may do whatever, but we always keep the + // messenger. It was meant for us anyway. + handleRequest(newMessenger, connectionAddress); + return true; + } + + protected void handleRequest(Messenger messenger, EndpointAddress connectionAddress) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleRequest from messenger"); + } + + // In this case, the request comes within the messenger's destination. + String request = connectionAddress.getServiceParameter(); + + // make sure that the messenger shows a client logical address + EndpointAddress clientAddr = messenger.getLogicalDestinationAddress(); + + if (clientAddr == null || !"jxta".equals(clientAddr.getProtocolName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("LogicalDestinationAddress is not a \"jxta\" protocol"); + } + + return; + } + + String clientPeerId = clientAddr.getProtocolAddress(); + + handleRequest(request, clientPeerId, messenger); + } + + protected void handleRequest(Message message, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleRequest from message"); + } + + String request = RelayTransport.getString(message, RelayTransport.REQUEST_ELEMENT); + String clientPeerId = dstAddr.getServiceParameter(); + + handleRequest(request, clientPeerId, null); + } + + void handleRequest(String request, String clientPeerId, Messenger messenger) { + // This request may come along with a messenger (if it is a renewal + // post-disconnection or an initial lease request). + + if (request == null) { + return; + } + + request = request.toLowerCase(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("request = " + request); + } + + // only process the request if a client peer id was sent + if (clientPeerId == null) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("clientPeerId = " + clientPeerId); + } + + // The only valid anonymous request is a request to obtain a real pid. + if ((clientPeerId.equals("unknown-unknown")) && (!request.startsWith(RelayTransport.PID_REQUEST))) { + return; + } + + Message responseMessage = null; + + RelayServerClient closingHandler = null; + boolean rawMessenger = false; + boolean closeMessenger = false; + + // Figure out which request it is + if (request.startsWith(RelayTransport.CONNECT_REQUEST)) { + // Connect Request + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("connect clientPeerId = " + clientPeerId); + } + + long requestedLease = maxLeaseDuration; + boolean returnRelayAdv = false; + boolean returnOtherRelayAdv = false; + boolean flushQueue = false; + + String requestedLeaseString = null; + + // check if a lease value was specified + int startIdx = request.indexOf(','); + + if (startIdx != -1) { + // find the end of the lease value + int endIdx = request.indexOf(',', startIdx + 1); + + if (endIdx == -1) { + requestedLeaseString = request.substring(startIdx + 1); + } else { + requestedLeaseString = request.substring(startIdx + 1, endIdx); + String flags = request.substring(endIdx + 1); + + if (flags.endsWith("true")) { + returnRelayAdv = true; + } else if (flags.endsWith("other")) { + // This is an addition to the protocol. Newer + // clients will always set that in connection requests + // when not setting true. Only older clients use to + // set nothing at all. + returnOtherRelayAdv = true; + } + // Only two flag positions for now + // The inserted first position is another extention. + // Only newer clients use it. Older servers will not + // notice it because they only check how the request ends. + // So, new clients are also compatible with old servers. + if (flags.startsWith("flush")) { + flushQueue = true; + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "request lease string = " + requestedLeaseString + "\treturn relay adv = " + returnRelayAdv + + "\n\treturn other relay adv = " + returnOtherRelayAdv + "\tflush queue = " + flushQueue); + } + + if (requestedLeaseString != null) { + try { + requestedLease = Long.parseLong(requestedLeaseString); + } catch (NumberFormatException e) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("could not parse requested lease string"); + } + } + + if (requestedLease > maxLeaseDuration) { + requestedLease = maxLeaseDuration; + } + } + + // process the connect request + EndpointAddress clientAddr = new EndpointAddress("jxta", clientPeerId, serviceName, peerId); + + // If we have a messenger, the clientHandler gets it. + // If the client handler did not already exist, it will be + // created only if we pass a messenger. We can no-longer create + // new clients without an incoming messenger. We used to get one + // from the router but no-longer. Now initial lease requests must + // come as part of the messenger creation. + + RelayServerClient handler = addClient(clientPeerId, requestedLease, messenger, flushQueue); + + if (handler != null) { + + // the client was added, send a connected response + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("added client " + clientPeerId); + } + + // Now get a messenger that goes through the handler and + // sends messages out-of-band (and internal perk). + // jice@jxta.org - 20021227 all this code is getting ridiculous + // it has to be re-organized. Addind the outOfBand feature + // to all RelayMessengers just for that is overkill. This + // just a temporary patch. The real fix would be to respond + // straight with the messenger we have. Unfortunately, sometimes + // we have to respond without a messenger in our hands because + // sending a message over an explicit connection is the only + // way for existing clients to ask for a response when they + // reconnect. We would need to change the protocol and add an + // "initial connection" request type to fix that. + + messenger = handler.getMessenger(publicAddress, clientAddr, true); + responseMessage = RelayTransport.createConnectedMessage(handler.getLeaseRemaining()); + // For protocol compatibility reasons, returnRelayAdv realy + // means "return your own because I do not know it". + // If returnOtherRelayAdv is true, then, we will return one + // selected among those we know, for the enlightenment of the + // other party. + // If neither is true, we'll return no adv at all in order not + // to confuse existing clients. + + RdvAdvertisement relayAdv = null; + + if (returnRelayAdv) { + relayAdv = createRdvAdvertisement(group.getPeerAdvertisement(), serviceName); + } else if (returnOtherRelayAdv) { + relayAdv = relayServerCache.getRandomCacheAdv(); + } + if (relayAdv != null) { + XMLDocument asDoc = (XMLDocument) relayAdv.getDocument(MimeMediaType.XMLUTF8); + + MessageElement relayAdvElement = new TextDocumentMessageElement(RelayTransport.RELAY_ADV_ELEMENT, asDoc, null); + + responseMessage.addMessageElement(RelayTransport.RELAY_NS, relayAdvElement); + } + } else { + // We can't keep the messenger. + // the client was not added, send a disconnected response + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("could not add client " + clientPeerId); + } + + // We do not get a messenger for ourselves here, so + // just get one from the router ourselves, if we have to. + // and can. + if (messenger == null) { + // If we did not get one and manage to obtain one + // from the endpoint, we can use it in-line, but + // we must close it. (The only case). + messenger = endpointService.getMessenger(clientAddr); + if (messenger != null) { + closeMessenger = true; + } + + } else { + + // This is the incoming messenger. We cannot use it + // synchronously. See, the use of BGSend, below. + + rawMessenger = true; + } + + responseMessage = RelayTransport.createDisconnectedMessage(); + + // add the relay advertisement of another know relay for the client to try + RdvAdvertisement relayAdv = relayServerCache.getRandomCacheAdv(); + + if (relayAdv != null) { + XMLDocument asDoc = (XMLDocument) relayAdv.getDocument(MimeMediaType.XMLUTF8); + + MessageElement relayAdvElement = new TextDocumentMessageElement(RelayTransport.RELAY_ADV_ELEMENT, asDoc, null); + + responseMessage.addMessageElement(RelayTransport.RELAY_NS, relayAdvElement); + } + } + } else if (RelayTransport.DISCONNECT_REQUEST.equals(request)) { + // Disconnect Request, don't send a response + if (clientPeerId != null) { + closingHandler = removeClient(clientPeerId); + if (closingHandler != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removed client " + clientPeerId); + } + } + } + } else if (RelayTransport.PID_REQUEST.equals(request)) { + + // Generate a PeerID in the same group as our PeerID. + // The group which my peerID stems from is not necessarily + // the group where I am running (more likely it is the net peer + // group). Rather than guessing, get the group from our own PID. + + PeerGroupID groupOfMyPid = (PeerGroupID) group.getPeerID().getPeerGroupID(); + + String pidStr = IDFactory.newPeerID(groupOfMyPid).toString(); + + responseMessage = RelayTransport.createPIDResponseMessage(pidStr); + + // If there is a raw incoming messenger, that's what we + // use. Else, we won't respond. + rawMessenger = true; + } + + // if there is a messenger and a response, send it + if (messenger != null && responseMessage != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("sending response to client " + clientPeerId); + } + + // If rawMessenger, then this is the incoming + // messenger brought in by messengerReady. In that case, + // be carefull. It is synchronous and it could block this + // here thread until the message can be sent. Which could + // possibly imply that this here method returns...dead lock. + // See HttpMessageServlet: messengerReady is called by + // the same thread that subsequently picks up messages from + // the BCMessenger. So, spawn a thread to reply. + // FIXME: eventualy we should start replacing some listener + // based code with state machines and event queues. + + if (rawMessenger) { + + // BGSend will *not* close the messenger after use + // Because incoming messengers do not need to be closed. + new BGSend(messenger, responseMessage, serviceName, peerId); + } else { + try { + messenger.sendMessage(responseMessage, serviceName, peerId); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not send response message to " + clientPeerId, e); + } + } + } + } + + if (closeMessenger) { + messenger.close(); + } + + if (closingHandler != null) { + closingHandler.closeClient(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("relayedClients.size()=" + relayedClients.size()); + } + } + + private RelayServerClient getClient(String clientPeerId) { + RelayServerClient handler; + + synchronized (relayedClients) { + handler = relayedClients.get(clientPeerId); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("getClient(" + clientPeerId + ") = " + handler); + } + + return handler; + } + + // Add client is idempotent. It can be called for a client that already + // exists. The flushqueue option instructs to clear the queue if the client + // exists. + private RelayServerClient addClient(String clientPeerId, long requestedLease, Messenger messenger, boolean flushQueue) { + RelayServerClient handler; + boolean isNewClient = false; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("addClient(" + clientPeerId + ")"); + } + + synchronized (relayedClients) { + // check if this client is already registered + handler = relayedClients.get(clientPeerId); + if (handler == null) { + // make sure the maximum number of clients has not been reached + // and make sure that we have a messenger to give to the new + // clientHandler. + if ((relayedClients.size() < maxClients) && (messenger != null) && !messenger.isClosed()) { + + // create a new handler + handler = new RelayServerClient(this, clientPeerId, requestedLease, stallTimeout, clientQueueSize); + + // add the handler to the list + relayedClients.put(clientPeerId, handler); + isNewClient = true; + + // check if this is the first client added + if (relayedClients.size() == 1) { + // start the gcThread if it is not already started + if (gcThread == null) { + gcThread = new Thread(group.getHomeThreadGroup(), this, "GC Thread for Relay at " + publicAddress); + gcThread.setDaemon(true); + gcThread.start(); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "new client denied. nb clients: " + relayedClients.size() + "/" + maxClients + ", messenger: " + + messenger); + } + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("added = " + (handler != null)); + } + + if (handler == null) { + return null; + } + + // renew the lease on the old handler + // Watchout. The handler might have expired since we got it from the + // map. RenewLease will tell us. In that case, tough luck. We don't + // make a new one. FIXME: it's not nice to the client, but in no way + // a disaster (and very rare). + + if (!handler.renewLease()) { + return null; + } + + if (flushQueue) { + handler.flushQueue(); + } + + if (messenger != null) { + handler.addMessenger(messenger); + + // We must force the router to learn the new relay connection as + // a direct route, so that it replies to route queries even if we + // never start talking to the client otherwise. + // Here we do something rather acrobatic. We invoke messengerReady + // recursively with a new relay messenger that the router will + // catch as if it where an incoming messenger (which it is, sort + // of). The cleaner alternative: call getMessenger with a hint + // causes too much commotion: sometimes an unreachable tcp address + // is tried before the hint, which blocks getMessenger for long. + + if (isNewClient) { + EndpointAddress ear = new EndpointAddress(RelayTransport.protocolName, clientPeerId, null, null); + + MessengerEvent me = new MessengerEvent(this, handler.getMessenger(publicAddress, ear, false), null); + + messengerEventListener.messengerReady(me); + } + } + + return handler; + } + + private RelayServerClient removeClient(String clientPeerId) { + RelayServerClient handler; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeClient(" + clientPeerId + ")"); + } + + synchronized (relayedClients) { + handler = relayedClients.remove(clientPeerId); + + // check if there are any clients + if (relayedClients.size() == 0) { + // stop the gcThread + if (gcThread != null) { + try { + gcThread.interrupt(); + } catch (SecurityException e) { + // ignore this exception + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + } + } + + return handler; + } + + // this is only used by the RelayServerClient when it is closing and needs to remove itself + protected void removeClient(String clientPeerId, RelayServerClient handler) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeClient(" + clientPeerId + "," + handler + ")"); + } + + synchronized (relayedClients) { + RelayServerClient currentHandler = relayedClients.get(clientPeerId); + + // only remove the client if the current handler matches the passed one + if (currentHandler == handler) { + relayedClients.remove(clientPeerId); + } + + // check if there are any clients + if (relayedClients.size() == 0) { + // stop the gcThread + Thread temp = gcThread; + + if (temp != null) { + try { + temp.interrupt(); + } catch (SecurityException e) { + // ignore this exception + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + } + } + } + + /** + * {@inheritDoc} + */ + public void run() { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Starting lease gc thread"); + } + + try { + while (true) { + // check if there are any client handlers left + synchronized (relayedClients) { + if (relayedClients.size() == 0) { + break; + } + } + + // do the lease gc + doClientGC(); + + // check if there are any client handlers left + synchronized (relayedClients) { + if (relayedClients.size() == 0) { + break; + } + } + + // sleep for a while. + try { + Thread.sleep(stallTimeout); + } catch (InterruptedException e) { + Thread.interrupted(); + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + gcThread = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("stopping lease gc thread"); + } + } + } + + // checks for expired client handlers + private void doClientGC() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("start: check for expired client handler. # clients = " + relayedClients.size()); + } + + // get a snapshot of the client handlers + RelayServerClient[] handlers; + + synchronized (relayedClients) { + handlers = relayedClients.values().toArray(new RelayServerClient[0]); + } + + // run through the client handlers + int i = handlers.length; + + while (i-- > 0) { + try { + // simply calling isExpired will cause the handler to check + // if it is expired and remove itself if expired + handlers[i].isExpired(); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception during client gc", e); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("stop: check for expired client handler. # clients = " + relayedClients.size()); + } + } + + private static class RelayServerCache implements PipeMsgListener, Runnable { + final static ID pipeID = ID.create( + URI.create("urn:jxta:uuid-59616261646162614E50472050325033DEADBEEFDEAFBABAFEEDBABE0000000F04")); + + final RelayServer server; + final PipeAdvertisement pipeAdv; + InputPipe inputPipe = null; + + volatile boolean doRun = false; + Thread cacheThread = null; + + final Map relayAdvCache = new HashMap(); + + final Random rand = new Random(); + + protected RelayServerCache(RelayServer server) { + this.server = server; + + pipeAdv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + pipeAdv.setPipeID(pipeID); + pipeAdv.setType(PipeService.PropagateType); + } + + private int relayAdvCacheSize() { + synchronized (relayAdvCache) { + return relayAdvCache.size(); + } + } + + protected RdvAdvertisement getRandomCacheAdv() { + synchronized (relayAdvCache) { + RdvAdvertisement[] items = relayAdvCache.values().toArray(new RdvAdvertisement[0]); + + if (items.length == 0) { + return null; + } + + return items[rand.nextInt(items.length)]; + } + } + + private boolean putCacheAdv(String peerId, RdvAdvertisement adv) { + if (!server.acl.isAllowed(adv.getPeerID())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Rejected cache entry for : " + peerId); + } + return false; + } + synchronized (relayAdvCache) { + boolean replaced = (null != relayAdvCache.put(peerId, adv)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine((replaced ? "Updated" : "Created") + " cache entry for : " + peerId); + } + + if (relayAdvCache.size() >= MAX_CACHED_SERVERS) { + // New entry and map full. Remove one at random. + String[] keys = relayAdvCache.keySet().toArray(new String[0]); + + relayAdvCache.remove(keys[rand.nextInt(keys.length)]); + } + + return replaced; + } + } + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + Message message = event.getMessage(); + + if (message == null) { + return; + } + + boolean isResponse = (RelayTransport.getString(message, RelayTransport.RESPONSE_ELEMENT) != null); + String peerId = RelayTransport.getString(message, RelayTransport.PEERID_ELEMENT); + + if (peerId == null || peerId.equals(server.peerId)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("pipeMsgEvent() discarding message no response PID defined, or loopback "); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("pipeMsgEvent() from " + peerId); + } + + MessageElement me = message.getMessageElement(RelayTransport.RELAY_NS, RelayTransport.RELAY_ADV_ELEMENT); + + if (null == me) { + return; + } + + Advertisement adv; + try { + // XXX bondolo 20041207 Force parsing of MessageElement as + // XMLUTF8 rather than the actual mime type associated with the + // MessageElement since the advertisement is often incorrectly + // stored as a String by older JXTA implementations. + adv = AdvertisementFactory.newAdvertisement(MimeMediaType.XMLUTF8, me.getStream()); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building relay advertisement", failed); + } + return; + } catch (NoSuchElementException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not build relay advertisement", failed); + } + return; + } + + if (!(adv instanceof RdvAdvertisement)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Response does not contain relay advertisement (" + adv.getAdvType() + ")"); + } + return; + } + + RdvAdvertisement radv = (RdvAdvertisement) adv; + + if (putCacheAdv(peerId, radv)) { + + // New entry, we might want to respond. + // "someone" should respond; on average, one response + // is all we want. And that response obviously should be + // unicast. + // We achieve an approximation of that by making a computation + // that will result in "true" on average on only one peer + // of the set, based on our idea of what the set is. + // If we know very few other relays compared to what other + // relays know, we are more likely to respond than they are. + // So this is very approximate. We want to keep it simple + // until we have time replace this lazy junk with something + // sensible. + + // If it's a response already, the story stops here ! + if (isResponse) { + return; + } + + // Here we go: + int i = relayAdvCacheSize(); + long magic = server.peerId.hashCode() % i; + + if (rand.nextInt(i) == magic) { + + // Our number came out. Respond. + + // See if we have amunition to respond anyway. + // Very defensive. I care a lot more not to break anything + // at this stage, than to have optimal functionality. + + RdvAdvertisement myAdv = RelayServer.createRdvAdvertisement(server.group.getPeerAdvertisement(), server.serviceName); + + // Need to convert the other party's string pid into + // a real pid. + PeerID otherPid = null; + try { + otherPid = (PeerID) IDFactory.fromURI(new URI(ID.URIEncodingName, ID.URNNamespace + ":" + peerId, null)); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Bad peerid : " + peerId, ex); + } + + } + + PipeService pipeService = server.group.getPipeService(); + if (pipeService == null) { + return; // Funny. We're receiving messages, after all. + } + + // FIXME: jice@jxta.org 20030131 - We're making a rather + // unorthodox use of the peer-subset feature of propagate + // pipes. Basically what this does is to send the message + // in unicast so that it is received on the propagate + // input pipe of the specified peer. + // The correct API, if it existed, would be respond(). + + OutputPipe retPipe = null; + try { + retPipe = pipeService.createOutputPipe(pipeAdv, Collections.singleton(otherPid), 2 * TimeUtils.ASECOND); + if (retPipe == null) { + return; + } + + // create a new cache message + message = new Message(); + + // String version of unique portion only. Per the protocol. + RelayTransport.setString(message, RelayTransport.PEERID_ELEMENT, server.peerId); + // Our own adv. + RelayTransport.setString(message, RelayTransport.RELAY_ADV_ELEMENT, myAdv.toString()); + + // This is a response. New servers: do not respond! Old + // servers won't respond anyway. + RelayTransport.setString(message, RelayTransport.RESPONSE_ELEMENT, "t"); + + retPipe.send(message); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Responded"); + } + + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not send reply on pipe ", e); + } + } + + if (retPipe != null) { + retPipe.close(); + } + } + } + } + + /** + * {@inheritDoc} + */ + public void run() { + try { + OutputPipe outputPipe = null; + PipeService pipeService = server.group.getPipeService(); + + while (doRun && inputPipe == null) { + try { + inputPipe = pipeService.createInputPipe(pipeAdv, this); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Could not create input pipe, try again"); + } + } catch (IllegalStateException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pipe Service not ready yet, try again"); + } + } + + try { + Thread.sleep(TimeUtils.ASECOND); + } catch (InterruptedException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("wait interrupted"); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Created input pipe"); + } + + while (doRun && outputPipe == null) { + try { + outputPipe = pipeService.createOutputPipe(pipeAdv, 5 * TimeUtils.ASECOND); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Could not create output pipe, try again"); + } + } catch (IllegalStateException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pipe Service not ready yet, try again"); + } + } + + try { + Thread.sleep(TimeUtils.ASECOND); + } catch (InterruptedException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("wait interrupted "); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Created output pipe"); + } + + // Wait a little before mcasting our hello. + // We depend on the rendezvous infrastructure for it to + // work. It's pretty important to get the first one out + // so that we may get a response from others. After that + // the interval is very long (and its computation an total + // nonsense) and so others do not talk much + // either. We want to learn at least one other relay early on. + // FIXME: jice@jxta.org 20030131 - We realy need to switch to + // using peerview. It does all of that correctly. + + try { + Thread.sleep(10 * TimeUtils.ASECOND); + } catch (InterruptedException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("wait interrupted"); + } + } + + while (doRun) { + RdvAdvertisement adv = RelayServer.createRdvAdvertisement(server.group.getPeerAdvertisement(), server.serviceName); + + // Make sure that the version that can be discovered + // is consistent. + try { + server.discoveryService.publish(adv); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not publish Relay RdvAdvertisement", e); + } + } + + if (adv != null) { + // create a new cache message + Message message = new Message(); + + RelayTransport.setString(message, RelayTransport.PEERID_ELEMENT, server.peerId); + RelayTransport.setString(message, RelayTransport.RELAY_ADV_ELEMENT, adv.toString()); + + try { + outputPipe.send(message); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not send message on pipe ", e); + } + } + } + + long sleepTime = server.minBroadcastInterval + + ((server.relayedClients.size() + 1) * 100 / (server.maxClients + 1)) * server.minBroadcastInterval; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("sleepTime=" + sleepTime); + } + + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.interrupted(); + } + } + outputPipe.close(); + if (System.currentTimeMillis() > server.refreshTime) { + server.refreshTime = System.currentTimeMillis() + ACL_REFRESH_PERIOD; + if (server.aclFile.lastModified() > server.aclFileLastModified) { + server.aclFileLastModified = server.aclFile.lastModified(); + server.acl.refresh(server.aclFile); + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + cacheThread = null; + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Cache thread quitting."); + } + } + } + + protected void startCache() { + doRun = true; + cacheThread = new Thread(server.group.getHomeThreadGroup(), this, "RelayCache Worker Thread for " + server.publicAddress); + cacheThread.setDaemon(true); + cacheThread.start(); + } + + protected void stopCache() { + doRun = false; + + if (inputPipe != null) { + inputPipe.close(); + inputPipe = null; + } + cacheThread.interrupt(); + } + } + + + /** + * Sends a message on an synchronous messenger. + */ + static class BGSend extends Thread { + + Messenger mr; + Message ms; + String sn; + String ps; + + BGSend(Messenger mr, Message ms, String sn, String ps) { + super("Relay Background Sender"); + this.mr = mr; + this.ms = ms; + this.sn = sn; + this.ps = ps; + setDaemon(true); + start(); + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + mr.sendMessage(ms, sn, ps); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed sending response " + ms + " to " + ps, e); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } + + } + } + + private static RdvAdvertisement createRdvAdvertisement(PeerAdvertisement padv, String name) { + try { + // FIX ME: 10/19/2002 lomax@jxta.org. We need to properly set up the service ID. Unfortunately + // this current implementation of the PeerView takes a String as a service name and not its ID. + // Since currently, there is only PeerView per group (all peerviews share the same "service", this + // is not a problem, but that will have to be fixed eventually. + + // create a new RdvAdvertisement + RdvAdvertisement rdv = (RdvAdvertisement) AdvertisementFactory.newAdvertisement( + RdvAdvertisement.getAdvertisementType()); + + rdv.setPeerID(padv.getPeerID()); + rdv.setGroupID(padv.getPeerGroupID()); + rdv.setServiceName(name); + rdv.setName(padv.getName()); + + RouteAdvertisement ra = EndpointUtils.extractRouteAdv(padv); + + if (null == ra) { + // No route available + return null; + } + + // Insert it into the RdvAdvertisement. + rdv.setRouteAdv(ra); + + return rdv; + } catch (Exception ez) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Cannot create Local RdvAdvertisement: ", ez); + } + return null; + } + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayServerClient.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayServerClient.java new file mode 100644 index 000000000..a89eee42d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayServerClient.java @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.relay; + +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import java.util.logging.Level; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.logging.Logging; + +import net.jxta.impl.endpoint.BlockingMessenger; +import net.jxta.impl.endpoint.EndpointServiceImpl; +import net.jxta.impl.util.TimeUtils; + +/** + * This class abstracts a client of the Relay Server + */ +class RelayServerClient implements Runnable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(RelayServerClient.class.getName()); + + /** + * The lease length when there are messages pending and we can't send them. + */ + private static long stallTimeout = 0; + + /** + * the Relay Server of this client + */ + private final RelayServer server; + + /** + * the peerId of this client + */ + private final String clientPeerId; + + /** + * The length of the lease in milliseconds + */ + private long leaseLength = 0; + + /** + * the Endpoint Address of the client of the queue expressed as jxta://'peerid' + */ + private final EndpointAddress clientAddr; + + /** + * the time at which the message queue expires + */ + private volatile long expireTime = 0; + + /** + * indicates whether this client handler is valid or expired + */ + private boolean isClosed = false; + + /** + * a queue of message for this client + */ + private final BlockingQueue messageList; + + /** + * endpoint service for this client + */ + private final EndpointService endpoint; + + private Messenger messenger = null; + private Thread thread = null; + private boolean thread_idle = false; + + private Message outOfBandMessage = null; + + protected RelayServerClient(RelayServer server, String clientPeerId, long leaseLength, long stallTimeout, int clientQueueSize) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("new Client peerId=" + clientPeerId + " lease=" + leaseLength); + } + + this.server = server; + this.clientPeerId = clientPeerId; + this.leaseLength = leaseLength; + RelayServerClient.stallTimeout = stallTimeout; + + clientAddr = new EndpointAddress("jxta", clientPeerId, null, null); + endpoint = server.getEndpointService(); + messageList = new ArrayBlockingQueue(clientQueueSize); + + // initialize the lease + renewLease(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void finalize() throws Throwable { + closeClient(); + super.finalize(); + } + + /** + * {@inheritDoc} + * + *

          Send all of the queued messages to the client. + */ + public void run() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("send queued messages to " + clientAddr); + } + + try { + Message message; + int failedInARow = 0; + + while (true) { + message = null; + Messenger holdIt; + synchronized (this) { + // Messenger + message is the condition to continue running + // We do not want to dequeue messages for sending before knowing if + // we have a messenger because re-queing is clumsy, so we + // check the messenger first. However, if we fail to get + // a messenger, we are forced to check the queue so that we + // can update the lease accordingly. It is possible to be here + // with neither messenger nor messages and then we must let + // the lease be long. + + if (messenger == null || messenger.isClosed()) { + messenger = null; + if (outOfBandMessage != null || !messageList.isEmpty()) { + + // If we cannot send a message by lack of messenger. + // The client is suspect of being dead. The clock starts + // ticking faster until we manage to send again. + // In two minutes we declare it dead. + + long newExpireTime = TimeUtils.toAbsoluteTimeMillis(stallTimeout); + + // If we're closed, we won't touch expireTime since it is 0. + if (expireTime > newExpireTime) { + expireTime = newExpireTime; + } + + } + thread = null; // Make sure a thread will be created if + break; // it is needed after we release the synch. + } + + if (outOfBandMessage != null) { + message = outOfBandMessage; + outOfBandMessage = null; + } else { + message = messageList.poll(0, TimeUnit.MILLISECONDS); + if (message == null) { + try { + thread_idle = true; + wait(4 * TimeUtils.ASECOND); + if (outOfBandMessage != null) { + message = outOfBandMessage; + outOfBandMessage = null; + } else { + message = messageList.poll(0, TimeUnit.MILLISECONDS); + } + } catch (InterruptedException ie) { + //ignored + } + if (message == null) { + thread = null; // Make sure a thread will be created if + break; // it is needed after we release the synch. + } + } + } + + holdIt = messenger; // Avoid NPE once out of synch. + thread_idle = false; + } + + // get the final service name and parameter that was loaded before queueing + MessageElement dstAddressElement = message.getMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, + EndpointServiceImpl.MESSAGE_DESTINATION_NAME); + + if (null == dstAddressElement) { + // No destination address... Just discard + // this should really not happen + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("message destination was not set"); + } + + continue; + } + EndpointAddress destAddr = new EndpointAddress(dstAddressElement.toString()); + + // send the message + try { + holdIt.sendMessageB(message, destAddr.getServiceName(), destAddr.getServiceParameter()); + + // The client is off the hook for now. One message was sent. + // Lease will stay long until the next messenger failure. + synchronized (this) { + failedInARow = 0; + + // Do not touch expireTime if we've been closed. + if (!isClosed) { + expireTime = TimeUtils.toAbsoluteTimeMillis(leaseLength); + } + } + } catch (Exception e) { + // Check that the exception is not due to the message + // rather than the messenger, and then drop the message. In that case + // we give the messenger the benefit of the doubt and keep + // it open, renewing the lease as above. (this could be the last + // message). For now the transports do not tell the difference, so we + // count the nb of times we failed in a row. After three times, + // kill the message rather than the messenger. + + // put the message back + synchronized (this) { + if (++failedInARow >= 3) { + failedInARow = 0; + if (!isClosed) { + expireTime = TimeUtils.toAbsoluteTimeMillis(leaseLength); + } + continue; + } + + // Ok, if we cannot push back the message, below, we + // should reset failedInARow, since we won't be retrying + // the same message. But it does not realy matter so + // let's keep things simple. + + if (outOfBandMessage == null) { + outOfBandMessage = message; + } + } + + // If we're here, we decided to close the messenger. We do that + // out of sync. + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "closing messenger after exception :" + clientAddr, e); + } + holdIt.close(); // Next loop deal with it. + // (including shortening the lease if needed.) + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + thread = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("stopped sending queued messages for " + clientAddr); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return clientPeerId + "," + messageList.size() + "," + + (messenger == null ? "-m" : "+m") + "," + TimeUtils.toRelativeTimeMillis(expireTime, TimeUtils.timeNow()); + } + + protected int getQueueSize() { + return messageList.size(); + } + + public long getLeaseRemaining() { + // May be shorter than lease length. Compute real value from expire + // time. + return TimeUtils.toRelativeTimeMillis(expireTime, TimeUtils.timeNow()); + } + + public void closeClient() { + + Messenger messengerToClose; + + synchronized (this) { + if (isClosed) { + return; + } + + isClosed = true; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( "Terminating client:" + "\n\tclient=" + clientAddr + "\tnbMessages=" + messageList.size() + + "\tmessenger=" + messenger + (messenger == null ? "" : "(c:" + messenger.isClosed() + ")") + + "\tlease-left=" + TimeUtils.toRelativeTimeMillis(expireTime, TimeUtils.timeNow()) + "\tt=" + (thread != null)); + } + + messengerToClose = messenger; + + expireTime = 0; + messenger = null; + + // remove all queued messages if expired + messageList.clear(); + } + + // We can do that out of sync. It avoids nesting locks. + server.removeClient(clientPeerId, this); + if (messengerToClose != null) { + messengerToClose.close(); + } + } + + /** + * remove all queued messages. + */ + synchronized void flushQueue() { + messageList.clear(); + } + + public boolean addMessenger(Messenger newMessenger) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("addMessenger() " + newMessenger); + } + + // make sure we are being passed a valid messenger + if (newMessenger == null || newMessenger.isClosed()) { + return false; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messenger (" + messenger + ") thread=" + thread); + } + + // Unless we change our mind, we'll close the new messenger. + // If we do not keep it, we must close it. Otherwise + // the client on the other end will never know what happened. + // Its connection will be left hanging for a long time. + + Messenger messengerToClose = newMessenger; + + synchronized (this) { + // Do not use isExpired() here. IsExpired is not supposed to be called + // synchronized. Also isClosed() is good enough. The handler being + // expired is not a problem; we'll figure it out soon enough and do the + // right thing. + + if (!isClosed) { + // use this messenger instead of the old one. + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + if (messenger != null) { + LOG.info("closing messenger replaced by a new one : " + clientAddr); + } + } + + // Swap messengers; we'll close the old one if there was one. + + messengerToClose = messenger; + messenger = newMessenger; + + if ((thread == null || thread_idle) && ((!messageList.isEmpty()) || (outOfBandMessage != null))) { + + // if we do not already have a thread, start one + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messageList.size() = " + messageList.size() + " client=" + clientAddr); + } + + if (thread != null) { + notify(); + } else { + thread = new Thread(server.group.getHomeThreadGroup(), this, "Draining queue to " + clientAddr); + thread.setDaemon(true); + thread.start(); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messenger (" + messenger + ") thread=" + thread); + } + } + } + + // Close whichever messenger out of sync. + // In either case, we claim that we kept the new one. + + if (messengerToClose != null) { + messengerToClose.close(); + } + + return true; + } + + public boolean isExpired() { + boolean isExpired = TimeUtils.timeNow() > expireTime; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("isExpired() = " + isExpired + " client=" + clientAddr); + } + + if (isExpired) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing expired client : " + clientAddr); + } + closeClient(); + } + + return isExpired; + } + + public synchronized boolean renewLease() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("renewLease() old expireTime = " + expireTime); + } + + // It is ok to renew a lease past the expiration time, as long + // as the handler has not been closed yet. So, we do not use + // isExpired(). + + if (isClosed) { + return false; + } + + // As long as there are messages to send, the lease is controlled + // by our ability to send them, not by client renewal. + + if (!messageList.isEmpty()) { + return true; + } + + expireTime = TimeUtils.toAbsoluteTimeMillis(leaseLength); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("renewLease() new expireTime = " + expireTime); + } + return true; + } + + /** + * add a message to the tail of the list + * + * @param message the message + * @param outOfBand if true, indicates outbound + * @throws IOException if an io error occurs + */ + private void queueMessage(Message message, boolean outOfBand) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("queueMessage (" + messageList.size() + ") client=" + clientAddr); + } + + synchronized (this) { + if (isClosed) { + throw new IOException("Client has been disconnected"); + } + + if (outOfBand) { + // We have a single oob message pending. + outOfBandMessage = message; + } else { + // We will simply discard the latest msg when the queue is full + // to avoid penalty of dropping earlier reliable message + if (!messageList.offer(message)) { + if (Logging.SHOW_WARNING) { + LOG.warning("Dropping relayed message " + message.toString() + " for peer " + clientPeerId); + } + } + } + + // check if a new thread needs to be started. + if ((thread == null) || thread_idle) { + // Normally, if messenger is null we knew it already: + // it becomes null only when we detect that it breaks while + // trying to send. However, let's imagine it's possible that + // we never had one so far. Be carefull that this is not a + // one-time event; we must not keep renewing the short lease; + // that would ruin it's purpose. + + if (messenger == null) { + long newExpireTime = TimeUtils.toAbsoluteTimeMillis(stallTimeout); + + if (expireTime > newExpireTime) { + expireTime = newExpireTime; + } + + } else { + // Messenger good. + // if we do not already have a thread, start one + if (thread != null) { + notify(); + } else { + thread = new Thread(server.group.getHomeThreadGroup(), this, "Draining queue to " + clientAddr); + thread.setDaemon(true); + thread.start(); + } + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("done queueMessage (" + messageList.size() + ") client=" + clientAddr); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messenger (" + messenger + ") thread=" + thread); + } + } + + protected EndpointAddress getClientAddress() { + return clientAddr; + } + + protected Messenger getMessenger(EndpointAddress srcAddr, EndpointAddress destAddr, boolean outOfBand) { + return new RelayMessenger(srcAddr, destAddr, this, outOfBand); + } + + protected static class RelayMessenger extends BlockingMessenger { + private final MessageElement srcAddressElement; + private final RelayServerClient handler; + private boolean outOfBand = false; + + // Since we send messages through other messengers that do not necessarily have the + // same destination service and param (usually none), we have to pass these along explicitly + // in all cases. If we just build a destination element for the message it will be overwritten + // by messengers below. + private final String defaultServiceName; + private final String defaultServiceParam; + + public RelayMessenger(EndpointAddress srcAddress, EndpointAddress destAddress, RelayServerClient handler, boolean outOfBand) { + + // We do not use self destruction + super(handler.server.group.getPeerGroupID(), destAddress, false); + + this.defaultServiceName = destAddress.getServiceName(); + this.defaultServiceParam = destAddress.getServiceParameter(); + this.handler = handler; + this.outOfBand = outOfBand; + + this.srcAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, srcAddress.toString(), null); + } + + /* + * The cost of just having a finalize routine is high. The finalizer is + * a bottleneck and can delay garbage collection all the way to heap + * exhaustion. Leave this comment as a reminder to future maintainers. + * Below is the reason why finalize is not needed here. + * + * This is never given to application layers directly. No need + * to close-on-finalize. + * + + protected void finalize() { + } + + */ + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdleImpl() { + // We do not use self destruction + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void closeImpl() { + // Nothing to do. The underlying connection is not affected. + // The messenger will be marked closed by the state machine once completely down; that's it. + } + + /** + * {@inheritDoc} + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + // getClientAddress returns a clone of the client's jxta: address. + return handler.getClientAddress(); + } + + /* + * {@inheritDoc} + * + *

          Send messages. Messages are queued and then processed when there is a transport messenger. + */ + @Override + public void sendMessageBImpl(Message message, String serviceName, String serviceParam) throws IOException { + + // Set the message with the appropriate src address + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, srcAddressElement); + + // load the final destination into the message + EndpointAddress destAddressToUse = getDestAddressToUse(serviceName, serviceParam); + + MessageElement dstAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NAME, + destAddressToUse.toString(), null); + + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, dstAddressElement); + + // simply enqueue the message. + // We clone it, since we pretend it's been sent synchronously. + handler.queueMessage(message.clone(), outOfBand); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayTransport.java new file mode 100644 index 000000000..51188fe80 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/RelayTransport.java @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.relay; + +import java.util.NoSuchElementException; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.platform.Module; + +import net.jxta.exception.PeerGroupException; + +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.protocol.RelayConfigAdv; +import net.jxta.pipe.PipeService; + +/** + * The Relay Server supports the following commands: + * + * CONNECT - message contains PEERID, optional LEASE + * DISCONNECT - message contains PEERID. + * GETSERVER - message contains PEERID. + */ + +public final class RelayTransport implements EndpointListener, Module { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(RelayTransport.class.getName()); + + // // constants //// + static final String protocolName = "relay"; + + static final String RELAY_NS = "relay"; + static final String REQUEST_ELEMENT = "request"; + static final String RESPONSE_ELEMENT = "response"; + static final String PEERID_ELEMENT = "peerid"; + static final String LEASE_ELEMENT = "lease"; + static final String RELAY_ADV_ELEMENT = "relayAdv"; + + static final String CONNECT_REQUEST = "connect"; + static final MessageElement CONNECT_REQUEST_ELEMENT = new StringMessageElement(REQUEST_ELEMENT, CONNECT_REQUEST, null); + static final String DISCONNECT_REQUEST = "disconnect"; + static final MessageElement DISCONNECT_REQUEST_ELEMENT = new StringMessageElement(REQUEST_ELEMENT, DISCONNECT_REQUEST, null); + static final String PID_REQUEST = "pid"; + static final MessageElement PID_REQUEST_ELEMENT = new StringMessageElement(REQUEST_ELEMENT, PID_REQUEST, null); + + static final String CONNECTED_RESPONSE = "connected"; + static final MessageElement CONNECTED_RESPONSE_ELEMENT = new StringMessageElement(RESPONSE_ELEMENT, CONNECTED_RESPONSE, null); + static final String DISCONNECTED_RESPONSE = "disconnected"; + static final MessageElement DISCONNECTED_RESPONSE_ELEMENT = new StringMessageElement(RESPONSE_ELEMENT, DISCONNECTED_RESPONSE + , + null); + static final String PID_RESPONSE = "pid"; + static final MessageElement PID_RESPONSE_ELEMENT = new StringMessageElement(RESPONSE_ELEMENT, PID_RESPONSE, null); + + static final int DEFAULT_MAX_CLIENTS = 150; + + static final int DEFAULT_MAX_SERVERS = 1; + + // Note the weird time below can be decreased but should not be increased + // otherwise there will not be enough traffic for the other side to + // keep the connection open. + static final long DEFAULT_LEASE = TimeUtils.ANHOUR; + static final long DEFAULT_STALL_TIMEOUT = 15 * TimeUtils.ASECOND; + + static final long DEFAULT_POLL_INTERVAL = 15 * TimeUtils.ASECOND; // (the poll costs very little) + + static final long DEFAULT_BROADCAST_INTERVAL = 10 * TimeUtils.AMINUTE; + + static final int DEFAULT_CLIENT_QUEUE_SIZE = 20; + + private PeerGroup group = null; + + private String serviceName = null; + + private RelayClient relayClient = null; + private RelayServer relayServer = null; + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) throws PeerGroupException { + this.group = group; + ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) implAdv; + + this.serviceName = assignedID.getUniqueValue().toString(); + + ConfigParams confAdv = group.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + RelayConfigAdv relayConfigAdv = null; + + if (confAdv != null) { + Advertisement adv = null; + + try { + XMLDocument configDoc = (XMLDocument) confAdv.getServiceParam(assignedID); + + if (null != configDoc) { + adv = AdvertisementFactory.newAdvertisement(configDoc); + } + } catch (NoSuchElementException failed) { + //ignored + } catch (IllegalArgumentException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Error in relay advertisement", failed); + } + + throw failed; + } + + if (adv instanceof RelayConfigAdv) { + relayConfigAdv = (RelayConfigAdv) adv; + } else { + relayConfigAdv = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(RelayConfigAdv.getAdvertisementType()); + } + } + + // XXX bondolo 20041030 I'd like to move these to startApp so that we + // can pass endpointService and share the instance. + if (relayConfigAdv.isServerEnabled()) { + relayServer = new RelayServer(group, serviceName, relayConfigAdv); + } + + if (relayConfigAdv.isClientEnabled()) { + relayClient = new RelayClient(group, serviceName, relayConfigAdv); + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Relay Message Transport : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tService Name : ").append(serviceName); + configInfo.append("\n\t\tisServer : ").append(relayConfigAdv.isServerEnabled()); + configInfo.append("\n\t\tisClient : ").append(relayConfigAdv.isClientEnabled()); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] args) { + EndpointService endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + + return START_AGAIN_STALLED; + } + + // XXX bondolo 20041025 Server depends upon discovery and its non-optional. + DiscoveryService discovery = group.getDiscoveryService(); + + if (null == discovery) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a discovery service"); + } + + return START_AGAIN_STALLED; + } + + // XXX bondolo 20041025 Server depends upon pipes and its non-optional. + PipeService pipeService = group.getPipeService(); + + if (null == pipeService) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a pipe service"); + } + + return START_AGAIN_STALLED; + } + + endpoint.addIncomingMessageListener(this, serviceName, null); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message Listener added " + serviceName); + } + + if (relayServer != null) { + if (!relayServer.startServer()) { + return -1; // cannot start + } + } + + if (relayClient != null) { + if (!relayClient.startClient()) { + return -1; // cannot start + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Relay Message Transport started"); + } + + return 0; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + // remove listener + EndpointService endpoint = group.getEndpointService(); + + if (endpoint == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("could not get EndpointService"); + } + } else { + endpoint.removeIncomingMessageListener(serviceName, null); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message Listener removed " + serviceName); + } + } + + if (relayServer != null) { + relayServer.stopServer(); + } + + if (relayClient != null) { + relayClient.stopClient(); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Relay Message Transport stopped"); + } + } + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Started for " + message + "\tsrc=" + srcAddr); + } + + MessageElement element; + + // check if it is a request + element = message.getMessageElement(RelayTransport.RELAY_NS, REQUEST_ELEMENT); + + if (element != null) { + // this is a request, pass it to the relayServer + if (relayServer != null) { + relayServer.handleRequest(message, dstAddr); + } + } else { + // check if it is a response + element = message.getMessageElement(RelayTransport.RELAY_NS, RESPONSE_ELEMENT); + + if (element != null) { + // this is a response, pass it to the relayClient + if (relayClient != null) { + relayClient.handleResponse(message, dstAddr); + } + } + } + } + + protected PeerGroup getGroup() { + return group; + } + + protected String getServiceName() { + return serviceName; + } + + // This is for reference only, the Desktop client implementation does not + // use that server feature + static Message createPIDRequestMessage() { + Message message = new Message(); + message.addMessageElement(RELAY_NS, PID_REQUEST_ELEMENT); + return message; + } + + static Message createPIDResponseMessage(String pidStr) { + Message message = new Message(); + message.addMessageElement(RELAY_NS, PID_RESPONSE_ELEMENT); + setString(message, PEERID_ELEMENT, pidStr); + + return message; + } + + static Message createConnectMessage(long lease, boolean doReturnAdv, boolean doFlushQueue) { + Message message = new Message(); + String request = createConnectString(lease, doReturnAdv, doFlushQueue); + setString(message, REQUEST_ELEMENT, request); + return message; + } + + static String createConnectString(long lease, boolean doReturnAdv, boolean doFlushQueue) { + + String request = CONNECT_REQUEST; + + if (lease > 0) { + request += "," + Long.toString(lease); + } else { + request += ","; + } + + if (doFlushQueue) { + request += ",flush"; + } else { + request += ",keep"; + } + + if (doReturnAdv) { + request += ",true"; + } else { + request += ",other"; + } + + return request; + } + + static Message createConnectedMessage(long lease) { + Message message = new Message(); + + message.addMessageElement(RELAY_NS, CONNECTED_RESPONSE_ELEMENT); + + if (lease > 0) { + setString(message, LEASE_ELEMENT, Long.toString(lease)); + } + + return message; + } + + static Message createDisconnectMessage() { + Message message = new Message(); + message.addMessageElement(RELAY_NS, DISCONNECT_REQUEST_ELEMENT); + return message; + } + + static Message createDisconnectedMessage() { + Message message = new Message(); + message.addMessageElement(RELAY_NS, DISCONNECTED_RESPONSE_ELEMENT); + return message; + } + + /** + * Convinence function for setting a string element with the relay namespace + * + * @param message the message + * @param elementName message element name + * @param value the value of the string + */ + static void setString(Message message, String elementName, String value) { + // create a new String Element with the given value + StringMessageElement sme = new StringMessageElement(elementName, value, null); + + // add the new element to the message + message.addMessageElement(RELAY_NS, sme); + } + + /** + * Convinence function for getting a String from the element with the given + * tag and relay namespace + * + * @param message the message + * @param elementName the value of the string + * @return the string value, null if the element does not exist + */ + static String getString(Message message, String elementName) { + // get the requested element + MessageElement element = message.getMessageElement(RelayTransport.RELAY_NS, elementName); + + // if the element is not present, return null + if (element == null) { + return null; + } + return element.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/package.html new file mode 100644 index 000000000..8c7ed3403 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/relay/package.html @@ -0,0 +1,20 @@ + + + + + + + A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which + which provides client polling and server store-and forward functionality for + peers incapable of receiving incoming connections. A virtual transport, the + messages are transfered between peers using client initiated connections of + some other message transport. + + @see net.jxta.endpoint.EndpointService + @see net.jxta.endpoint.MessageTransport + @see net.jxta.endpoint.MessageSender + @see net.jxta.endpoint.MessageReceiver + @see net.jxta.endpoint.Message + @see JXTA Protocols Specification : Standard JXTA Transport Bindings + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/BadRoute.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/BadRoute.java new file mode 100644 index 000000000..e731a7b6b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/BadRoute.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.router; + + +import net.jxta.peer.PeerID; +import net.jxta.protocol.RouteAdvertisement; + +import java.util.HashSet; +import java.util.Set; + + +/** + * This class is used to cache negative route information. Bad routes are + * represented by three fields: + * + *

            + *
          • Route advertisement,
          • + *
          • Lists of hops that are known bad for that route.
          • + *
          • Expiration time of the negative cache.
          • + *
          + */ +class BadRoute { + + /** + * The RouteAdvertisement with known bad hops. + */ + private final RouteAdvertisement badRoute; + + /** + * The PeerID of the known bad hops in the route. + */ + private final Set badHops = new HashSet(); + + /** + * The absolute time at which this information becomes obsolete. + */ + private long expiration; + + BadRoute(RouteAdvertisement route, long exp, Set hops) { + this.badRoute = route; + this.expiration = exp; + this.badHops.addAll(hops); + } + + /** + * Return the bad route info + * + * @return bad route advertisement + */ + public RouteAdvertisement getRoute() { + if (badRoute != null) { + return badRoute.clone(); + } else { + return null; + } + } + + /** + * Return the absolute time at which the this entry expires. + * + * @return The absolute time at which the this entry expires. + */ + public long getExpiration() { + return expiration; + } + + /** + * set the bad route expiration time + * + * @param exp bad route expiration time + */ + public void setExpiration(long exp) { + this.expiration = exp; + } + + /** + * return the known bad hops in the route + * + * @return bad route hops + */ + public Set getBadHops() { + Set hops = new HashSet(badHops); + + return hops; + } + + /** + * set bad hops into the bad route + * + * @param hops bad route hops + */ + public void setBadHops(Set hops) { + + badHops.clear(); + addBadHops(hops); + } + + /** + * add bad hops into the bad route + * + * @param hops bad route hops + */ + public void addBadHops(Set hops) { + badHops.addAll(hops); + } + + /** + * add a bad hop into the bad route + * + * @param hop The bad route hop. + */ + public void addBadHop(PeerID hop) { + badHops.add(hop); + } + + /** + * {@inheritDoc} + * + *

          Implementation useful for debugging. Don't depend on the format + */ + @Override + public String toString() { + StringBuilder routeBuf = new StringBuilder(); + + routeBuf.append("Bad ").append(getRoute().display()); + routeBuf.append("\tExp: ").append(getExpiration()); + routeBuf.append("\tHops: "); + + for (PeerID eachBadHop : getBadHops()) { + routeBuf.append("\t\t").append(eachBadHop); + } + + return routeBuf.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/Destinations.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/Destinations.java new file mode 100644 index 000000000..27af78225 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/Destinations.java @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.router; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Messenger; +import net.jxta.impl.util.TimeUtils; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.*; + + +/** + * This class is a repository of wisdom regarding destinations. It also provides + * a messenger if there is one. Currently, the wisdom is very limited and is + * only about direct destinations (for which a messenger once existed). The + * wisdom that can be obtained is: + * + *

            + *
          • is there a messenger at hand (incoming or otherwise).
          • + * + *
          • is it likely that one can be made from this end, should the one we + * have break. (the last attempt succeeded, not only incoming, and that was + * not long ago).
          • + * + *
          • is either of the above true, (are we confident we can get a + * messenger as of right now one way or the other).
          • + * + *
          • are we supposed to send a welcome to that destination (we can't + * remember having done it).
          • + *
          + * + *

          This could be extended to manage more of the life cycle, such as knowing + * about messengers being resolved or having failed to. This primitive interface + * is temporary; it is only meant to replace messengerPool without having to + * change the router too much. + */ + +class Destinations { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(Destinations.class.getName()); + + /** + * Shared Timer which handles cleanup of expired Wisdom. + */ + private final static transient Timer cleanup = new Timer("Endpoint Destinations GC", true); + + private final Map wisdoms = new HashMap(64); + + /** + * If {@code true} then we are shutting down. + */ + private volatile boolean stopped = false; + + /** + * The endpoint service we are working for. + */ + private final EndpointService endpoint; + + /** + * The wisdom GC task for this instance. + */ + private final WisdomGCTask wisdomGC; + + /** + * Stores knowledge about one particular destination. + * + *

          It does not provide any synchronization. This is provided by the Destinations class. + */ + final class Wisdom { + + /** + * How long we consider that a past outgoingMessenger is an indication + * that one is possible in the future. + */ + static final long EXPIRATION = 10 * TimeUtils.AMINUTE; + + /** + * The channel we last used, if any. They disappear faster than the + * canonical, but, as long as the canonical is around, they can be + * obtained at a near-zero cost. + */ + private Reference outgoingMessenger; + + /** + * The channel we last used if it happens to be an incoming messenger. We keep + * a strong reference to it. + */ + private Messenger incomingMessenger; + + /** + * The transport destination address of the messenger we're caching (if + * not incoming). + */ + private EndpointAddress xportDest; + + /** + * This tells when the outgoing messenger information expires. Incoming + * messengers have no expiration per se. We draw no conclusion from + * their past presence; only current presence. A wisdom is totally + * expired (and may thus be removed) when its outgoing messenger + * information is expired AND it has no incoming messenger. + */ + private long expiresAt = 0; + + /** + * When a new destination is added, we're supposed to send our welcome + * along with the first message. This tells whether isWelcomeNeeded was + * once invoked or not. + */ + private boolean welcomeNeeded = true; + + /** + * @param messenger The messenger to cache information about. + * @param incoming If true, this is an incoming messenger, which means + * that if the channel is lost it cannot be re-obtained. It must + * strongly referenced until it closes for disuse, or breaks. + */ + Wisdom(Messenger messenger, boolean incoming) { + if (incoming) { + addIncomingMessenger(messenger); + } else { + addOutgoingMessenger(messenger); + } + } + + /** + * Reports whether a welcome message is needed. The first time we're + * asked we say "true". Subsequently, always "false". + * + *

          This assumes that the welcome was sent following the first test. + * (so, ask only if you'll send the welcome when told to). + * + * @return {@code true} if this is the first time this method is invoked. + */ + synchronized boolean isWelcomeNeeded() { + boolean res = welcomeNeeded; + + welcomeNeeded = false; + return res; + } + + boolean addIncomingMessenger(Messenger m) { + + // If we have no other incoming, we take it. No questions asked. + Messenger currentIncoming = getIncoming(); + + if (currentIncoming == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Accepted new incoming messenger for " + m.getDestinationAddress()); + } + + incomingMessenger = m; + return true; + } + + // Now, check reachability (0 port number means no incoming connections). + // If the old one looks better, prefer it. + + // Compute reachability of the new one. + String originAddr = m.getDestinationAddress().getProtocolAddress(); + + int index = originAddr.lastIndexOf(':'); + int srcPort = (index != -1) ? Integer.parseInt(originAddr.substring(index + 1)) : 0; + boolean reachable = (srcPort != 0); + + // Compute reachability of the old one. + originAddr = currentIncoming.getDestinationAddress().getProtocolAddress(); + + index = originAddr.lastIndexOf(':'); + srcPort = (index != -1) ? Integer.parseInt(originAddr.substring(index + 1)) : 0; + boolean currentReachable = (srcPort != 0); + + // The new one is less reachable than the old one. Keep the old one. + if (currentReachable && !reachable) { + return false; + } + + incomingMessenger = m; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Accepted new incoming messenger for " + m.getDestinationAddress()); + } + + return true; + } + + boolean addOutgoingMessenger(Messenger m) { + if (getOutgoing() != null) { + return false; + } + this.outgoingMessenger = new SoftReference(m); + xportDest = m.getDestinationAddress(); + expiresAt = TimeUtils.toAbsoluteTimeMillis(EXPIRATION); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Accepted new outgoing messenger for " + xportDest); + } + return true; + } + + void noOutgoingMessenger() { + outgoingMessenger = null; + xportDest = null; + expiresAt = 0; + } + + /** + * Returns an incoming messenger is there is a working one available. + * + * @return an incoming messenger, null if there's none + */ + private Messenger getIncoming() { + if (incomingMessenger != null) { + if ((incomingMessenger.getState() & Messenger.USABLE) != 0) { + return incomingMessenger; + } + + // forget about this broken messenger. + incomingMessenger = null; + } + return null; + } + + /** + * Returns an outgoingMessenger if there is one or one can be made without delay. + * Renews a broken one if it can be. Refreshes expiration time if a messenger is returned. + * + * @return an outgoing messenger, null if there's none + */ + private Messenger getOutgoing() { + + if (outgoingMessenger == null) { + return null; + } + + // (If messenger is not null, it means that we also have a xportDest). + + Messenger messenger = outgoingMessenger.get(); + + // If it is gone or broken, try and get a new one. + if ((messenger == null) || ((messenger.getState() & Messenger.USABLE) == 0)) { + + messenger = endpoint.getMessengerImmediate(xportDest, null); + + // If this fails, it is hopeless: the address is bad or something like that. Make ourselves expired right away. + if (messenger == null) { + outgoingMessenger = null; + xportDest = null; + expiresAt = 0; + return null; + } + + // Renew the ref. The xportDest is the same. + outgoingMessenger = new SoftReference(messenger); + } + + // So we had one or could renew. But, does it work ? + if ((messenger.getState() & (Messenger.USABLE & Messenger.RESOLVED)) == 0) { + // We no-longer have the underlying connection. Let ourselves expire. Do not renew the expiration time. + outgoingMessenger = null; + xportDest = null; + return null; + } + + // Ok, we do have an outgoing messenger at the ready after all. + expiresAt = TimeUtils.toAbsoluteTimeMillis(EXPIRATION); + return messenger; + } + + /** + * Returns a channel for this destination if one is there or can be obtained + * readily and works. + *

          + *

          We prefer the incoming connection to the outgoing for two + * reasons: + *

            + *
          • The remote peer was able to reach us. We cannot be sure that + * we can reach the remote peer.
          • + *
          • The remote peer initiated the connection. It has a better + * sense of when the connection should be closed or reopened than + * we do.
          • + * + * @return a channel for this destination + */ + Messenger getCurrentMessenger() { + Messenger res = getIncoming(); + + if (res != null) { + return res; + } + + return getOutgoing(); + } + + /** + * @return true if we do have an outgoing messenger or, failing that, we had one not too long ago. + */ + boolean isNormallyReachable() { + return ((getOutgoing() != null) || (TimeUtils.toRelativeTimeMillis(expiresAt) >= 0)); + } + + /** + * We think the destination is reachable somehow. Not sure how long. + * + * @return true if we have any kind of messenger or, failing that, we had an outgoing one not too long ago. + */ + boolean isCurrentlyReachable() { + return ((getIncoming() != null) || (getOutgoing() != null) || (TimeUtils.toRelativeTimeMillis(expiresAt) >= 0)); + } + + /** + * @return true if this wisdom carries no positive information whatsoever. + */ + boolean isExpired() { + return !isCurrentlyReachable(); + } + } + + /* + * Internal mechanisms + */ + + /** + * Return any Wisdom for the specified destination. The address will + * be normalized to the base form. + * + * @param destination The address of the wisdom that is sought. + * @return The Wisdom for this address or {@code null} if no Wisdom found. + */ + private Wisdom getWisdom(EndpointAddress destination) { + if (destination.getServiceName() != null) { + destination = new EndpointAddress(destination, null, null); + } + return wisdoms.get(destination); + } + + /** + * Add a Wisdom for the specified destination. The address will + * be normalized to the base form. + * + * @param destination The address of the Wisdom that is being added. + * @param wisdom The Wisdom for this address to be added to the map. + */ + private void addWisdom(EndpointAddress destination, Wisdom wisdom) { + destination = new EndpointAddress(destination, null, null); + wisdoms.put(destination, wisdom); + } + + /* + * General house keeping. + */ + + public Destinations(EndpointService endpoint) { + + this.endpoint = endpoint; + + wisdomGC = new WisdomGCTask(); + + cleanup.schedule(wisdomGC, TimeUtils.AMINUTE, TimeUtils.AMINUTE); + } + + /** + * Shutdown this cache. (stop the gc) + */ + public synchronized void close() { + stopped = true; + + // forget everything. + wisdoms.clear(); + + wisdomGC.cancel(); + } + + /** + * Handles cleanup of expired wisdoms + */ + class WisdomGCTask extends TimerTask { + + /** + * {@inheritDoc} + * + *

            garbage collector. We use soft references to messengers, but we use + * a strong hashmap to keep the wisdom around in a more predictable + * manner. Entries are simply removed when they no-longer carry + * relevant information; so there's no change in the total meaning of + * the map when an entry is removed. + */ + @Override + public void run() { + try { + synchronized (Destinations.this) { + Iterator eachWisdom = wisdoms.values().iterator(); + + while (eachWisdom.hasNext()) { + Wisdom w = eachWisdom.next(); + + if (w.isExpired()) { + eachWisdom.remove(); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && Destinations.LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in TimerTask :" + Thread.currentThread().getName(), all); + } + } + } + } + + public synchronized Collection allDestinations() { + + Set allKeys = wisdoms.keySet(); + List res = new ArrayList(allKeys); + + return res; + } + + /* + * information output + */ + + /** + * If there is a messenger at hand (incoming or otherwise), return it. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + * @return A messenger to that destination if a resolved and usable one is available or can be made instantly. null otherwise. + */ + public synchronized Messenger getCurrentMessenger(EndpointAddress destination) { + Wisdom wisdom = getWisdom(destination); + + if (wisdom == null) { + return null; + } + return wisdom.getCurrentMessenger(); + } + + /** + * Is it likely that one can be made from this end. (the last attempt succeeded, not only incoming, and that was not long ago) ? + * This is a conservative test. It means that declaring that we can route to that destination is a very safe bet, as opposed + * to isNormallyReachable and getCurrentMessenger, which could be misleading if the only messenger we can ever get is incoming. + * Not currently used. Should likely be. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + * @return true if it is likely that we can get a messenger to that destination in the future. + */ + public synchronized boolean isNormallyReachable(EndpointAddress destination) { + Wisdom wisdom = getWisdom(destination); + + return ((wisdom != null) && wisdom.isNormallyReachable()); + } + + /** + * Do we already have a messenger or is it likely that we can make one? + * We is will return {@code true} more often than + * {@code isNormallyReachable()} since it can be true even when all we have + * is an incoming messenger. + * + *

            Just testing that there is an entry is no-longer the same because we + * may keep the entries beyond the point where we would keep them before, so + * that we can add some longer-lived information in the future, and do not + * interfere as much with the gc thread. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + * @return true is we are confident that we can obtain a messenger, either because we can get one instantly, or because + * this destination is normally reachable. (So, it is ok to try and route to that destination, now). + */ + public synchronized boolean isCurrentlyReachable(EndpointAddress destination) { + Wisdom wisdom = getWisdom(destination); + + return ((wisdom != null) && wisdom.isCurrentlyReachable()); + } + + /** + * Are we supposed to send a welcome to that destination (we can't remember having done it). + * It is assumed that once true was returned, it will be acted upon. So, true is not returned a second time. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + * @return true if this a destination to whish we can't remember sending a welcome message. + */ + public synchronized boolean isWelcomeNeeded(EndpointAddress destination) { + Wisdom wisdom = getWisdom(destination); + + return ((wisdom != null) && wisdom.isWelcomeNeeded()); + } + + /* + * information input. + */ + + /** + * Here is a messenger that we were able to obtain. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + * @param messenger The incoming messenger for that destination. + * @return true if this messenger was added (keep it open). false otherwise (do what you want with it). + */ + public synchronized boolean addOutgoingMessenger(EndpointAddress destination, Messenger messenger) { + Wisdom wisdom = getWisdom(destination); + + if (wisdom != null) { + return wisdom.addOutgoingMessenger(messenger); + } + addWisdom(destination, new Wisdom(messenger, false)); + return true; + } + + /** + * Here is an incoming messenger that just popped out. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + * @param messenger The incoming messenger for that destination. + * @return true if this messenger was added (keep it open). false otherwise (do what you want with it). + */ + public synchronized boolean addIncomingMessenger(EndpointAddress destination, Messenger messenger) { + Wisdom wisdom = getWisdom(destination); + + if (wisdom != null) { + return wisdom.addIncomingMessenger(messenger); + } + addWisdom(destination, new Wisdom(messenger, true)); + return true; + } + + /** + * We tried to get a messenger but could not. We know that we do not have connectivity from our end, for now. we may still + * have an incoming. However, if we had to try and make a messenger, there probably isn't an incoming, but that's not our + * business here. isNormallyReachable becomes false; but we can still try when solicited. + * + * @param destination The destination as an endpoint address (is automatically normalized to protocol and address only). + */ + public synchronized void noOutgoingMessenger(EndpointAddress destination) { + Wisdom wisdom = getWisdom(destination); + + if (wisdom != null) { + wisdom.noOutgoingMessenger(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/EndpointRouter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/EndpointRouter.java new file mode 100644 index 000000000..1db223848 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/EndpointRouter.java @@ -0,0 +1,2715 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.router; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.MessageTransport; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerEvent; +import net.jxta.endpoint.MessengerEventListener; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.endpoint.LoopbackMessenger; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.TimerThreadNamer; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.service.Service; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class EndpointRouter implements EndpointListener, MessageReceiver, MessageSender, MessengerEventListener, Module { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(EndpointRouter.class.getName()); + + /** + * Until we decide otherwise, the router is *by definition* handling + * virtually addressed messages. + */ + private final static String ROUTER_PROTOCOL_NAME = "jxta"; + + /** + * Router Service Name + */ + private final static String ROUTER_SERVICE_NAME = "EndpointRouter"; + + /** + * how long we are willing to wait for a response from an async + * getMessenger. We do not wait long at all because it is non-critical + * that we get the answer synchronously. The goal is to avoid starting + * a route discovery if there's a chance to get a direct connection. + * However, we will still take advantage of the direct route if it is + * found while we wait for the route discovery result. If that happens, + * the only wrong is that we used some bandwidth doing a route discovery + * that wasn't needed after all. + */ + public final static long ASYNC_MESSENGER_WAIT = 3L * TimeUtils.ASECOND; + + /** + * MessageTransport Control operation + */ + public final static Integer GET_ROUTE_CONTROL = 0; // Return RouteControl Object + public final static int RouteControlOp = 0; // Return RouteControl Object + + /** + * MAX timeout (seconds) for route discovery after that timeout + * the peer will bail out from finding a route + */ + private final static long MAX_FINDROUTE_TIMEOUT = 60L * TimeUtils.ASECOND; + + /** + * How long do we wait (seconds) before retrying to make a connection + * to an endpoint destination + */ + private final static long MAX_ASYNC_GETMESSENGER_RETRY = 30L * TimeUtils.ASECOND; + + /** + * These are peers which we know multi-hop routes for. + */ + private final Map routedRoutes = new HashMap(16); + + /** + * A record of failures. + *

            + * Values are the time of failure as {@link java.lang.Long}. If + * {@code Long.MAX_VALUE} then a connect attempt is current in progress. + */ + private final Map triedAndFailed = new HashMap(); + + /** + * local peer ID as an endpointAddress. + */ + private EndpointAddress localPeerAddr = null; + + /** + * local Peer ID + */ + private PeerID localPeerId = null; + + /** + * The Endpoint Service we are routing for. + */ + private EndpointService endpoint = null; + + /** + * PeerGroup handle + */ + private PeerGroup group = null; + + private ID assignedID = null; + + /** + * If {@code true} this service has been closed. + */ + private boolean stopped = false; + + /** + * Whenever we initiate connectivity to a peer (creating a direct route). + * we remember that we need to send our route adv to that peer. So that + * it has a chance to re-establish the connection from its side, if need + * be. The route adv is actually sent piggy-backed on the first message + * that goes there. + */ + private final Set newDestinations = Collections.synchronizedSet(new HashSet()); + + /** + * A pool of messengers categorized by logical address. + * This actually is the direct routes map. + */ + private Destinations destinations; + + /** + * A record of expiration time of known bad routes we received a NACK route + */ + private final Map badRoutes = new HashMap(); + + /** + * We record queries when first started and keep them pending for + * a while. Threads coming in the meanwhile wait for a result without + * initiating a query. Thus threads may wait passed the point where + * the query is no-longer pending, and, although they could initiate + * a new one, they do not. + *

            + * However, other threads coming later may initiate a new query. So a + * query is not re-initiated systematically on a fixed schedule. This + * mechanism also serves to avoid infinite recursions if we're looking + * for the route to a rendezvous (route queries will try to go there + * themselves). + *

            + * FIXME: jice@jxta.org 20020903 this is approximate. We can do + * cleaner/better than this, but it's already an inexpensive improvement + * over what used before. + *

            + * FIXME: tra@jxta.org 20030818 the pending hashmap should be moved + * in the routeResolver class. + */ + private final Map pendingQueries = + Collections.synchronizedMap(new HashMap()); + + /** + * Timer by which we schedule the clearing of pending queries. + */ + private final Timer timer = new Timer("EndpointRouter Timer", true); + + /** + * PeerAdv tracking. + * The peer adv is modified every time a new public address is + * enabled/disabled. One of such cases is the connection/disconnection + * from a relay. Since these changes are to the embedded route adv + * and since we may embed our route adv in messages, we must keep it + * up-to-date. + */ + private PeerAdvertisement lastPeerAdv = null; + private int lastModCount = -1; + + /** + * Route info for the local peer (updated along with lastPeerAdv). + */ + private RouteAdvertisement localRoute = null; + + /** + * Route CM persistent cache + */ + private RouteCM routeCM = null; + + /** + * Route Resolver + */ + private RouteResolver routeResolver; + + class ClearPendingQuery extends TimerTask { + final PeerID peerID; + volatile boolean failed = false; + long nextRouteResolveAt = 0; + + ClearPendingQuery(PeerID peerID) { + this.peerID = peerID; + // We schedule for one tick at one minute and another at 5 minutes + // after the second, we cancel ourselves. + timer.schedule(this, TimeUtils.AMINUTE, 5L * TimeUtils.AMINUTE); + nextRouteResolveAt = TimeUtils.toAbsoluteTimeMillis(20L * TimeUtils.ASECOND); + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + if (failed) { + // Second tick. + // This negative cache info is expired. + pendingQueries.remove(peerID); + + this.cancel(); + } else { + // First timer tick. We're done trying. This is now a negative + // cache info. For the next 5 minutes that destination fails + // immediately unless it unexpectedly gets finaly resolved. + failed = true; + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in timer task " + Thread.currentThread().getName() + " for " + peerID, all); + } + } + } + + public synchronized boolean isTimeToResolveRoute() { + if (TimeUtils.toRelativeTimeMillis(nextRouteResolveAt) > 0) { + return false; + } + // nextRouteResolveAt is passed. Set the next time to retry from now. + nextRouteResolveAt = TimeUtils.toAbsoluteTimeMillis(20L * TimeUtils.ASECOND); + return true; + } + + public boolean isFailed() { + return failed; + } + } + + RouteAdvertisement getMyLocalRoute() { + + // Update our idea of the local peer adv. If it has change, + // update our idea of the local route adv. + // If nothing has changed, do not do any work. + // In either case, return the local route adv as it is after this + // refresh. + + // Race condition possible but tolerable: if two threads discover + // the change in the same time, lastPeerAdv and lastModCount + // could become inconsistent. That'll be straightened out the + // next time someone looks. The inconsistency can only trigger + // an extraneous update. + + PeerAdvertisement newPadv = group.getPeerAdvertisement(); + int newModCount = newPadv.getModCount(); + + if ((lastPeerAdv != newPadv) || (lastModCount != newModCount) || (null == localRoute)) { + lastPeerAdv = newPadv; + lastModCount = newModCount; + } else { + // The current version is good. + return localRoute; + } + + // Get its EndpointService advertisement + XMLElement endpParam = (XMLElement) + newPadv.getServiceParam(PeerGroup.endpointClassID); + + if (endpParam == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("no Endpoint SVC Params"); + } + + // Return whatever we had so far. + return localRoute; + } + + // get the Route Advertisement element + Enumeration paramChilds = endpParam.getChildren(RouteAdvertisement.getAdvertisementType()); + XMLElement param; + + if (paramChilds.hasMoreElements()) { + param = (XMLElement) paramChilds.nextElement(); + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("no Endpoint Route Adv"); + } + + // Return whatever we had so far. + return localRoute; + } + + // build the new route + try { + // Stick the localPeerID in-there, since that was what + // every single caller of getMyLocalRoute did so far. + + RouteAdvertisement route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(param); + + route.setDestPeerID(localPeerId); + localRoute = route; + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure extracting route", ex); + } + } + + return localRoute; + } + + /** + * listener object to synchronize on asynchronous getMessenger + */ + private static class EndpointGetMessengerAsyncListener implements MessengerEventListener { + + private final EndpointRouter router; + private final EndpointAddress logDest; + + volatile boolean hasResponse = false; + volatile boolean isGone = false; + private Messenger messenger = null; + + /** + * Constructor + * + * @param router the router + * @param dest logical destination + */ + EndpointGetMessengerAsyncListener(EndpointRouter router, EndpointAddress dest) { + this.router = router; + this.logDest = dest; + } + + /** + * {@inheritDoc} + */ + public boolean messengerReady(MessengerEvent event) { + + Messenger toClose = null; + + synchronized (this) { + hasResponse = true; + if (event != null) { + messenger = event.getMessenger(); + if (null != messenger) { + if(!logDest.equals(messenger.getLogicalDestinationAddress())) { + // Ooops, wrong number ! + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Incorrect Messenger logical destination : " + logDest + "!=" + messenger.getLogicalDestinationAddress()); + } + + toClose = messenger; + messenger = null; + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("null messenger for dest :" + logDest); + } + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("null messenger event for dest :" + logDest); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (messenger == null) { + LOG.fine("error creating messenger for dest :" + logDest); + } else { + LOG.fine("got a new messenger for dest :" + logDest); + } + } + + // We had to release the lock on THIS before we can get the lock on + // the router. (Or face a dead lock - we treat this as a lower level + // lock) + + if (messenger == null) { + if (toClose != null) { + toClose.close(); + } + + // we failed to get a messenger, we need to update the try and + // failed as it currently holds an infinite timeout to permit + // another thread to retry that destination. We only retry + // every MAX_ASYNC_GETMESSENGER_RETRY seconds + + router.noMessenger(logDest); + + synchronized (this) { + // Only thing that can happen is that we notify for nothing + // We took the lock when updating hasResult, so, the event + // will not be missed. + // FIXME It would be more logical to let the waiter do the + // above if (!isGone) as in the case of success below. + // However, we'll minimize changes for risk management + // reasons. + notify(); + } + return false; + } + + // It worked. Update router cache entry if we have to. + + synchronized (this) { + if (!isGone) { + notify(); // Waiter will do the rest. + return true; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("async caller gone add the messenger " + logDest); + } + return router.newMessenger(event); + } + + /** + * Wait on the async call for ASYNC_MESSENGER_WAIT + * then bailout. The messenger will be added whenever + * the async getMessenger will return + * + * @param quick if true return a messenger immediately if available, + * otherwise wait the Messenger resolution to be completed + * @return the Messenger if one available + */ + public synchronized Messenger waitForMessenger(boolean quick) { + if (!quick) { + long quitAt = TimeUtils.toAbsoluteTimeMillis(ASYNC_MESSENGER_WAIT); + + while (TimeUtils.toRelativeTimeMillis(quitAt) > 0) { + try { + // check if we got a response already + if (hasResponse) { // ok, we got a response + break; + } + wait(ASYNC_MESSENGER_WAIT); + } catch (InterruptedException woken) { + Thread.interrupted(); + break; + } + } + } + + // mark the fact that the caller is bailing out + isGone = true; + return messenger; + } + } + + /** + * isLocalRoute is a shallow test. It tells you that there used to be a + * local route that worked the last time it was tried. + * + * @param peerAddress Address of the destination who's route is desired. + * @return {@code true} if we know a direct route to the specified address + * otherwise {@code false}. + */ + boolean isLocalRoute(EndpointAddress peerAddress) { + return destinations.isCurrentlyReachable(peerAddress); + } + + /** + * Get a Messenger for the specified destination if a direct route is known. + * + * @param peerAddress The peer who's messenger is desired. + * @param hint A route hint to use if a new Messenger must be created. + * @return Messenger for direct route or {@code null} if none could be + * found or created. + */ + Messenger ensureLocalRoute(EndpointAddress peerAddress, RouteAdvertisement hint) { + + // We need to make sure that there is a possible connection to that peer + // If we have a decent (not closed, busy or available) transport + // messenger in the pool, then we're done. Else we activly try to make + // one. + + // See if we already have a messenger. + Messenger messenger = destinations.getCurrentMessenger(peerAddress); + + if (messenger != null) { + return messenger; + } + + // Ok, try and make one. Pass the route hint info + messenger = findReachableEndpoint(peerAddress, false, hint); + if (messenger == null) { + // We must also zap it from our positive cache: if we remembered it + // working, we should think again. + destinations.noOutgoingMessenger(peerAddress); + return null; // No way. + } + + destinations.addOutgoingMessenger(peerAddress, messenger); + + // We realy did bring something new. Give relief to those that have been + // waiting for it. + synchronized (this) { + notifyAll(); + } + + // NOTE to maintainers: Do not remove any negative cache info + // or route here. It is being managed by lower-level routines. + // The presence of a messenger in the pool has many origins, + // each case is different and taken care of by lower level + // routines. + return messenger; + } + + /** + * Send a message to a given logical destination if it maps to some + * messenger in our messenger pool or if such a mapping can be found and + * added. + * + * @param destination peer-based address to send the message to. + * @param message the message to be sent. + * @throws java.io.IOException if an io error occurs + */ + void sendOnLocalRoute(EndpointAddress destination, Message message) throws IOException { + + IOException lastIoe = null; + Messenger sendVia; + + // Try sending the message as long as we get have transport messengers + // to try with. They close when they fail, which puts them out of cache + // or pool if any, so we will not see a broken one a second time. We'll + // try the next one until we run out of options. + + while ((sendVia = ensureLocalRoute(destination, null)) != null) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + message + " to " + destination + " via " + sendVia); + } + + try { + // FIXME 20040413 jice Maybe we should use the non-blocking mode + // and let excess messages be dropped given the threading issue + // still existing in the input circuit (while routing messages + // through). + + sendVia.sendMessageB(message, EndpointRouter.ROUTER_SERVICE_NAME, null); + + // If we reached that point, we're done. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent " + message + " to " + destination); + } + return; + + } catch (IOException ioe) { + // Can try again, with another messenger (most likely). + lastIoe = ioe; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Trying next messenger to " + destination); + } + // try the next messenger if there is one. + } + + // Now see why we're here. + // If we're here for no other reason than failing to get a messenger + // say so. Otherwise, report the failure from the last time we tried. + if (lastIoe == null) { + lastIoe = new IOException("No reachable endpoints for " + destination); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not send to " + destination, lastIoe); + } + + throw lastIoe; + } + + /** + * Default constructor + */ + public EndpointRouter() { + } + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + timer.schedule(new TimerThreadNamer("EndpointRouter Timer for " + group.getPeerGroupID()), 0); + + this.group = group; + this.assignedID = assignedID; + ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) impl; + + localPeerId = group.getPeerID(); + localPeerAddr = pid2addr(group.getPeerID()); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Router Transport : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tProtocol : ").append(getProtocolName()); + configInfo.append("\n\t\tPublic Address : ").append(localPeerAddr); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized int startApp(String[] arg) { + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return START_AGAIN_STALLED; + } + + Service needed = group.getResolverService(); + + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Endpoint Router start stalled until resolver service available"); + } + return Module.START_AGAIN_STALLED; + } + + needed = group.getMembershipService(); + + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Endpoint Router start stalled until membership service available"); + } + return Module.START_AGAIN_STALLED; + } + + needed = group.getRendezVousService(); + + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Endpoint Router start stalled until rendezvous service available"); + } + return Module.START_AGAIN_STALLED; + } + + destinations = new Destinations(endpoint); + + try { + // FIXME tra 20030818 Should be loaded as a service + // when we have service dependency. When loaded as a true service should + // not have to pass the EnpointRouter object. The issue is we need an + // api to obtain the real object from the PeerGroup API. + routeCM = new RouteCM(); + + // FIXME tra 20030818 Should be loaded as a service + // when we have service dependency. When loaded as a true service should + // not have to pass the EnpointRouter object. The issue is we need an + // api to obtain the real object from the PeerGroup API. + routeResolver = new RouteResolver(this); + + // initialize persistent CM route Cache + // FIXME tra 20030818 Should be loaded as service when complete + // refactoring is done. + routeCM.init(group, assignedID, null); + + // initialize the route resolver + // FIXME tra 20030818 Should be loaded as service when complete + // refactoring is done. + routeResolver.init(group, assignedID, null); + } catch (PeerGroupException failure) { + return -1; + } + + int status; + + // FIXME tra 20031015 Should be started as a service when refactored work + // completed + status = routeCM.startApp(arg); + if (status != 0) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Route CM failed to start : " + status); + } + + return status; + } + + // FIXME tra 20031015 Should be started as a service when refactored work + // completed + status = routeResolver.startApp(arg); + if (status != 0) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Route Resolver failed to start : " + status); + } + return status; + } + // publish my local route adv + routeCM.publishRoute(getMyLocalRoute()); + + // FIXME tra 20031015 is there a risk for double registration when + // startApp() is recalled due to failure to get the discovery service + // by the Route Resolver service. + + // NOTE: Endpoint needs to be registered before we register the endpoint + // resolver. This is bringing a more complex issue of service loading + // dependencies. + endpoint.addMessengerEventListener(this, EndpointService.MediumPrecedence); + + endpoint.addIncomingMessageListener(this, ROUTER_SERVICE_NAME, null); + + if (endpoint.addMessageTransport(this) == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + + return -1; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info(group + " : Router Message Transport started."); + } + return status; + } + + /** + * {@inheritDoc} + *

            + * Careful that stopApp() could in theory be called before startApp(). + */ + public synchronized void stopApp() { + stopped = true; + + if (endpoint != null) { + endpoint.removeIncomingMessageListener(ROUTER_SERVICE_NAME, null); + endpoint.removeMessengerEventListener(this, EndpointService.MediumPrecedence); + endpoint.removeMessageTransport(this); + } + + // FIXME tra 20030818 should be unloaded as a service + routeCM.stopApp(); + + // FIXME tra 20030818 should be unloaded as a service + routeResolver.stopApp(); + + destinations.close(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info(group + " : Router Message Transport stopped."); + } + } + + /** + * {@inheritDoc} + */ + public boolean isConnectionOriented() { + return false; + } + + /** + * {@inheritDoc} + */ + public boolean allowsRouting() { + // Yes, this is the router, and it does not allow routing. + // Otherwise we would have a chicken and egg problem. + return false; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return endpoint; + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return localPeerAddr; + } + + /** + * {@inheritDoc} + */ + public Iterator getPublicAddresses() { + return Collections.singletonList(getPublicAddress()).iterator(); + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return ROUTER_PROTOCOL_NAME; + } + + /** + * Given a peer id, return an address to reach that peer. + * The address may be for a directly reachable peer, or + * for the first gateway along a route to reach the peer. + * If we do not have a route to the peer, we will use the + * Peer Routing Protocol to try to discover one. We will + * wait up to 30 seconds for a route to be discovered. + * + * @param peerAddress the peer we are trying to reach. + * @param seekRoute whether to go as far as issuing a route query, or just fish in our cache. + * when forwarding a message we allow ourselves to mend a broken source-issued route but we + * won't go as far as seeking one from other peers. When originating a message, on the other end + * we will aggressively try to find route. + * @param hint whether we are passed a route hint to be used, in that case that route + * hint should be used + * @return an EndpointAddress at which that peer should be reachable. + */ + EndpointAddress getGatewayAddress(EndpointAddress peerAddress, boolean seekRoute, RouteAdvertisement hint) { + PeerID peerID = addr2pid(peerAddress); + + try { + // FIXME 20021215 jice Replace this junk with a background task; + // separate the timings of route disco from the timeouts of + // the requesting threads. EndpointAddress result = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Searching local" + (seekRoute ? " & remote" : "") + " for route for " + peerAddress); + } + + // If we can't get a route within the timeout, give up for now. + long quitAt = TimeUtils.toAbsoluteTimeMillis(MAX_FINDROUTE_TIMEOUT); + + // Time we need to wait before we can start issue a find route request + // to give a chance for the async messenger to respond (success or failure) + long findRouteAt = TimeUtils.toAbsoluteTimeMillis(ASYNC_MESSENGER_WAIT); + + EndpointAddress addr; + + while (TimeUtils.toRelativeTimeMillis(quitAt) > 0) { + // Then check if by any chance we can talk to it directly. + Messenger directMessenger = ensureLocalRoute(peerAddress, hint); + + if (null != directMessenger) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found direct route for " + peerAddress + " via " + directMessenger.getDestinationAddress()); + } + return peerAddress; + } + + // Otherwise, look for a long route. + // check if we got a hint. If that's the case use it + RouteAdvertisement route; + + if (hint != null) { + route = hint; + } else { + route = getRoute(peerAddress, seekRoute); + } + + if (route != null && route.size() > 0) { + addr = pid2addr(route.getLastHop().getPeerID()); + if (ensureLocalRoute(addr, null) != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found last hop remote address: " + peerAddress + " -> " + route.getLastHop().getPeerID()); + } + + // Ensure local route removes negative cache info about + // addr. We also need to remove that about peerAddress. + return addr; + } else { // need to try the first hop + addr = pid2addr(route.getFirstHop().getPeerID()); + + if (ensureLocalRoute(addr, null) != null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found first hop remote address first hop: " + peerAddress + " -> " + + route.getFirstHop().getPeerID()); + } + + // Ensure local route removes negative cache info about addr. + return addr; + } else { + removeRoute(peerID); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found no reachable route to " + peerAddress); + } + } + } + } + + // For messages we didn't originate we don't seek routes. + if (!seekRoute) { + break; + } + + // Check that route resolution is enabled if + // not then bail out, there is nothing more + // that we can do. + if (!routeResolver.useRouteResolver()) { + break; + } + + // due to the asynchronous nature of getting our messenger we + // need to handle the multi-entrance of issueing a route + // discovery. A route discovery needs to be generated only + // either if we have no pending request (it completed or we had + // no information so we did not created one), or we tried and + // we failed, or we waited at least ASYNC_MESSENGER_WAIT to get + // a chance for the async request to respond before we can + // issue the route discovery + Long nextTry = triedAndFailed.get(peerID); + + if ((nextTry == null) || (nextTry < TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)) + || (TimeUtils.toRelativeTimeMillis(findRouteAt) <= 0)) { + + // If it is already hopeless (negative cache), just give up. + // Otherwise, try and recover the route. If a query is not + // already pending, we may trigger a route discovery before we + // wait. Else, just wait. The main problem we have here is that + // the same may re-enter because the resolver query sent by + // findRoute ends up with the rendezvous service trying to + // resolve the same destiation if the destination happens to be + // the start of the walk. In that situation we will re-enter + // at every findRoute attempt until the query becomes "failed". + // However, we do want to do more than one findRoute because + // just one attempt can fail for totaly fortuitous or temporary + // reasons. A tradeoff is to do a very limitted number of attempts + // but still more than one. Over the minute for which the query + // is not failed, isTimeToRety will return true at most twice + // so that'll be a total of three attempts: once every 20 seconds. + boolean doFind = false; + ClearPendingQuery t; + + synchronized (pendingQueries) { + t = pendingQueries.get(peerID); + + if (t == null) { + doFind = true; + t = new ClearPendingQuery(peerID); + pendingQueries.put(peerID, t); + } else { + if (t.isFailed()) { + break; + } + if (t.isTimeToResolveRoute()) { + doFind = true; + } + } + } + + // protect against the async messenger request. We only + // look for a route after the first iteration by + // that time we will have bailed out from the async call + if (doFind) { + routeResolver.findRoute(peerAddress); + // we do not need to check the CM, route table will + // be updated when the route response arrive. This reduces + // CM activities when we wait for the route response + seekRoute = false; + } + } + + // Now, wait. Responses to our query may occur asynchronously. + // threads. + synchronized (this) { + // We can't possibly do everything above while synchronized, + // so we could miss an event of interrest. But some changes + // are not readily noticeable anyway, so we must wake up + // every so often to retry. + try { + // we only need to wait if we haven't got a messenger + // yet. + if (destinations.getCurrentMessenger(peerAddress) == null) { + wait(ASYNC_MESSENGER_WAIT); + } + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No route to " + peerAddress); + } + return null; + + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "getGatewayAddress exception", ex); + } + return null; + } + } + + /** + * {@inheritDoc} + */ + @Deprecated + public boolean ping(EndpointAddress addr) { + + EndpointAddress plainAddr = new EndpointAddress(addr, null, null); + + try { + return (getGatewayAddress(plainAddr, true, null) != null); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.FINE, "Ping failure (exception) for : " + plainAddr, e); + } + return false; + } + } + + /** + * Receives notifications of new messengers being generated by the + * underlying network transports. + *

            + * IMPORTANT: Incoming messengers only. If/when this is used for + * outgoing, some things have to change: + *

            + * For example we do not need to send the welcome msg, but for + * outgoing messengers, we would need to. + *

            + * Currently, newMessenger handles the outgoing side. + * + * @param event the new messenger event. + */ + public boolean messengerReady(MessengerEvent event) { + + Messenger messenger = event.getMessenger(); + Object source = event.getSource(); + EndpointAddress logDest = messenger.getLogicalDestinationAddress(); + + if (source instanceof MessageSender && !((MessageSender) source).allowsRouting()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring messenger to :" + logDest); + } + return false; + } + + // We learned that a transport messenger has just been announced. + // Nobody else took it, so far, so we'll take it. Incoming messengers + // are not pooled by the endpoint service. We do pool them for our + // exclusive use. + + boolean taken = destinations.addIncomingMessenger(logDest, messenger); + + // Note to maintainers: Do not remove any route or negative cache info + // here. Here is why: The messenger we just obtained was made out of an + // incoming connection. It brings no proof whatsoever that the peer is + // reachable at our initiative. In general, there is nothing to gain in + // removing our knowlege of a long route, or a pending route query, or a + // triedAndFailed record, other than to force trying a newly obtained + // set of addresses. They will not stop us from using this messenger as + // long as it works. The only good thing we can do here, is waking up + // those that may be waiting for a connection. + + synchronized (this) { + notifyAll(); + } + return taken; + } + + /** + * Call when an asynchronous new messenger could not be obtained. + * + * @param logDest the failed logical destination + */ + void noMessenger(EndpointAddress logDest) { + + // Switch to short timeout if there was an infinite one. + // Note if there's one, it is either short or inifinite. So we + // look at the value only in the hope it is less expensive + // than doing a redundant put. + + PeerID peerID = addr2pid(logDest); + + synchronized (this) { + Long curr = triedAndFailed.get(peerID); + + if (curr != null && curr > TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)) { + triedAndFailed.put(peerID, TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)); + } + } + } + + /** + * Call when an asynchronous new messenger is ready. + * (name is not great). + * + * @param event the new messenger event. + * @return always returns true + */ + boolean newMessenger(MessengerEvent event) { + + Messenger messenger = event.getMessenger(); + EndpointAddress logDest = messenger.getLogicalDestinationAddress(); + + // We learned that a new transport messenger has just been announced. + // We pool it for our exclusive use. + destinations.addOutgoingMessenger(logDest, messenger); + + // Here's a new connection. Wakeup those that may be waiting for that. + synchronized (this) { + notifyAll(); + } + return true; + } + + /** + * Get the routed route, if any, for a given peer id. + * + * @param peerAddress the peer who's route is desired. + * @param seekRoute boolean to indicate if we should search for a route + * if we don't have one + * @return a route advertisement describing the direct route to the peer. + */ + RouteAdvertisement getRoute(EndpointAddress peerAddress, boolean seekRoute) { + + ID peerID = addr2pid(peerAddress); + + // check if we have a valid route + RouteAdvertisement route; + + synchronized (this) { + route = routedRoutes.get(peerID); + } + if (route != null || !seekRoute) { // done + return route; + } + + // No known route and we're allowed to search for one + + // check if there is route advertisement available + Iterator allRadvs = routeCM.getRouteAdv(peerID); + + while (allRadvs.hasNext()) { + route = allRadvs.next(); + Vector hops = route.getVectorHops(); + + // no hops, uninterresting: this needs to be a route + if (hops.isEmpty()) { + continue; + } + + // let's check if we can speak to any of the hops in the route + // we try them in reverse order so we shortcut the route + // in the process + RouteAdvertisement newRoute = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + newRoute.setDest(route.getDest().clone()); + Vector newHops = new Vector(); + + // build the route from the available hops + for (int i = hops.size() - 1; i >= 0; i--) { + ID hopID = hops.elementAt(i).getPeerID(); + + // If the local peer is one of the first reachable + // hop in the route, that route is worthless to us. + if (localPeerId.equals(hopID)) { + break; + } + + EndpointAddress addr = pid2addr(hopID); + + if (ensureLocalRoute(addr, null) != null) { + // we found a valid hop return the corresponding + // route from that point + for (int j = i; j <= hops.size() - 1; j++) { + newHops.add(hops.elementAt(j).clone()); + } + // make sure we have a real route at the end + if (newHops.isEmpty()) { + break; + } + + newRoute.setHops(newHops); + // try to set the route + if (setRoute(newRoute, false)) { + // We got one; we're done. + return newRoute; + } else { + // For some reason the route table does not + // want that route. Move on to the next adv; it + // unlikely that a longer version of the same would + // be found good. + break; + } + } + } + } + + // no route found + return null; + } + + /** + * Check if a route is valid. + * Currently, only loops are detected. + * + * @param routeAdvertisement The route to check. + * @return {@code true} if the route is valid otherwise {@code false}. + */ + private boolean checkRoute(RouteAdvertisement routeAdvertisement) { + + if (0 == routeAdvertisement.size()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("route is empty"); + } + return false; + } + + if (routeAdvertisement.containsHop(localPeerId)) { + // The route does contain this local peer. Using this route + // would create a loop. Discard. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("route contains this peer - loopback"); + } + return false; + } + + PeerID destPid = routeAdvertisement.getDest().getPeerID(); + + if (routeAdvertisement.containsHop(destPid)) { + // May be it is fixable, may be not. See to it. + Vector hops = routeAdvertisement.getVectorHops(); + + // It better be the last hop. Else this is a broken route. + hops.remove(hops.lastElement()); + if (routeAdvertisement.containsHop(destPid)) { + // There was one other than last: broken route. + return false; + } + } + + if (routeAdvertisement.hasALoop()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("route has a loop "); + } + return false; + } else { + // Seems to be a potential good route. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("route is ok"); + } + return true; + } + } + + // Adds a new long route provided there not a direct one already. + // Replaces any longer route. return true if the route was truely new. + // The whole deal must be synch. We do not want to add a long route + // while a direct one is being added in parallell or other stupid things like that. + + /** + * set new route info + * + * @param route new route to learn + * @param force true if the route was obtained by receiving + * a message + * @return true if route was truly new + */ + boolean setRoute(RouteAdvertisement route, boolean force) { + PeerID peerID; + EndpointAddress peerAddress; + boolean pushNeeded = false; + boolean status; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("setRoute:"); + } + + if (route == null) { + return false; + } + + synchronized (this) { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(route.display()); + } + peerID = route.getDest().getPeerID(); + peerAddress = pid2addr(peerID); + + // Check if we are in the case where we are + // setting a new route as we received a message + // always force the new route setup when we received a + // a message + if (!force) { + // check if we have some bad NACK route info for + // this destination + BadRoute badRoute = badRoutes.get(peerAddress); + + if (badRoute != null) { + Long nextTry = badRoute.getExpiration(); + + if (nextTry > System.currentTimeMillis()) { + // check if the route we have in the NACK cache match the + // new one. Need to make sure that we clean the route + // from any endpoint addresses as the badRoute cache only + // contains PeerIDs + RouteAdvertisement routeClean = route.cloneOnlyPIDs(); + + if (routeClean.equals(badRoute.getRoute())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("try to use a known bad route"); + } + return false; + } + } else { + // expired info, just flush NACK route cache + badRoutes.remove(peerAddress); + } + } + } else { + // we get a new route + badRoutes.remove(peerAddress); + } + + // Check if the route makes senses (loop detection) + if (!checkRoute(route)) { + // Route is invalid. Drop it. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Route is invalid"); + } + return false; + } + + // check if we can reach the first hop in the route + // We only do a shallow test of the first hop. Whether more effort + // is worth doing or not is decided (and done) by the invoker. + if (!isLocalRoute(pid2addr(route.getFirstHop().getPeerID()))) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unreachable route - ignore"); + } + return false; + } + + } catch (Exception ez1) { + // The vector must be empty, which is not supposed to happen. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Got an empty route - discard" + route.display()); + } + return false; + } + + // add the new route + try { + // push the route to SRDI only if it is a new route. the intent is + // to minimize SRDI traffic. The SRDIinformation is more of the order + // this peer has a route to this destination, it does not need to be + // updated verey time the route is updated. Information about knowing + // that this peer has a route is more important that the precise + // route information + + // SRDI is run only if the peer is acting as a rendezvous + if (group.isRendezvous()) { + if (!routedRoutes.containsKey(peerID)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("push new SRDI route " + peerID); + } + pushNeeded = true; + } + } + + // new route so publish the known route in our cache + if (!routedRoutes.containsKey(peerID)) { + routeCM.createRoute(route); + newDestinations.add(peerAddress); + } + + // Remove any endpoint addresses from the route + // as part of the cloning. We just keep track + // of PIDs in our route table + RouteAdvertisement newRoute = route.cloneOnlyPIDs(); + + routedRoutes.put(peerID, newRoute); + + // We can get rid of any negative info we had. We have + // a new and different route. + badRoutes.remove(peerAddress); + notifyAll(); // Wakeup those waiting for a route. + status = true; + } catch (Exception e2) { + // We failed, leave things as they are. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(" failed setting route with " + e2); + } + status = false; + } + } + // due to the potential high latency of making the + // srdi revolver push we don't want to hold the lock + // on the EndpointRouter object as we may have to + // discover a new route to a rendezvous + if (pushNeeded && status) { + // we are pushing the SRDI entry to a replica peer + routeResolver.pushSrdi(null, peerID); + } + return status; + } + + /** + * This method is used to remove a route + * + * @param peerID route to peerid to be removed + */ + void removeRoute(PeerID peerID) { + boolean needRemove; + + synchronized (this) { + needRemove = false; + if (routedRoutes.containsKey(peerID)) { + if (group.isRendezvous()) { + // Remove the SRDI cache entry from the SRDI cache + needRemove = true; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("remove SRDI route " + peerID); + } + } + routedRoutes.remove(peerID); + } + } + + // due to the potential high latency of pushing + // the SRDI message we don't want to hold the EndpointRouter + // object lock + if (needRemove) { + // We are trying to flush it from the replica peer + // Note: this is not guarantee to work if the peerview + // is out of sync. The SRDI index will be locally + // repaired as the peerview converge + routeResolver.removeSrdi(null, peerID); + } + } + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + EndpointAddress srcPeerAddress; + EndpointAddress destPeer; + EndpointAddress lastHop = null; + boolean connectLastHop = false; + EndpointAddress origSrcAddr; + EndpointAddress origDstAddr; + Vector origHops = null; // original route of the message + EndpointRouterMessage routerMsg; + EndpointAddress nextHop = null; + RouteAdvertisement radv; + + // We do not want the existing header to be ignored of course. + routerMsg = new EndpointRouterMessage(msg, false); + if (!routerMsg.msgExists()) { + // The sender did not use this router + if (Logging.SHOW_FINE && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Discarding " + msg + ". No routing info."); + } + return; + } + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(routerMsg.display()); + } + origSrcAddr = routerMsg.getSrcAddress(); + origDstAddr = routerMsg.getDestAddress(); + + // convert the src and dest addresses into canonical + // form stripping service info + srcPeerAddress = new EndpointAddress(origSrcAddr, null, null); + destPeer = new EndpointAddress(origDstAddr, null, null); + + lastHop = routerMsg.getLastHop(); + + // See if there's an originator full route adv inthere. + // That's a good thing to keep. + radv = routerMsg.getRouteAdv(); + if (radv != null) { + + // publish the full route adv. Also, leave it the + // message. It turns out to be extremely usefull to + // peers downstream, specially the destination. If + // this here peer wants to embed his own radv, it will + // have to wait; the one in the message may not come + // again. + + // FIXME - jice@jxta.org 20040413 : all this could wait (couldn't it ?) + // until we know it's needed, therefore parsing could wait as well. + + // Looks like a safe bet to try and ensure a + // connection in the opposite direction if there + // isn't one already. + + if (pid2addr(radv.getDestPeerID()).equals(lastHop)) { + connectLastHop = true; + } + + // Make the most of that new adv. + setRoute(radv, true); + updateRouteAdv(radv); + } + } catch (Exception badHdr) { + // Drop it, we do not even know the destination + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Bad routing header or bad message. Dropping " + msg); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Exception: ", badHdr); + } + return; + } + + // Is this a loopback ? + if ((srcPeerAddress != null) && srcPeerAddress.equals(localPeerAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("dropped loopback"); + } + return; + } + + // Are we already sending to ourself. This may occur + // if some old advertisements for our EA is still + // floating around + if ((lastHop != null) && lastHop.equals(localPeerAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("dropped loopback from impersonating Peer"); + } + return; + } + + // We have to try and reciprocate the connection, so that we + // have chance to learn reverse routes early enough. If we do + // not already have a messenger, then we must know a route adv + // for that peer in order to be able to connect. Otherwise, + // the attempt will fail and we'll be left with a negative + // entry without having realy tried anything. To prevent that + // we rely on the presence of a radv in the router message. If + // there's no radv, two possibilities: + // + // - It is not the first contact from that peer and we already + // have tried (with or without success) to reciprocate. + // + // - It is the first contact from that peer but it has not + // embedded its radv. In the most likely case (an edge peer + // connecting to a rdv), the edge peer will have no difficulty + // finding the reverse route, provided that we do not make a + // failed attempt right now. + // + // Conclusion: if there's no embedded radv in the message, do + // nothing. + + if (connectLastHop) { + ensureLocalRoute(lastHop, radv); + } + + try { + + // Normalize the reverseHops vector from the message and, if it + // looks well formed and usefull, learn from it. Do we have a + // direct route to the origin ? If yes, we'll zap the revers + // route in the message: we're a much better router. else, + // learn from it. As a principle we regard given routes to be + // better than existing ones. + Vector reverseHops = routerMsg.getReverseHops(); + + if (reverseHops == null) { + reverseHops = new Vector(); + } + + // check if we do not have a direct route + // in that case we don't care to learn thelong route + if (!isLocalRoute(srcPeerAddress)) { + // Check if the reverseRoute info looks correct. + if (lastHop != null) { + // since we are putting the lasthop in the + // reverse route to indicate the validity of + // lastop to reach the previous hop, we have + // the complete route, just clone it. (newRoute + // owns the given vector) + + if ((reverseHops.size() > 0) && reverseHops.firstElement().getPeerID().equals(addr2pid(lastHop))) { + + // Looks like a good route to learn + setRoute(RouteAdvertisement.newRoute(addr2pid(srcPeerAddress), null, (Vector) reverseHops.clone()), true); + + } + + } + } + + // If this peer is the final destination, then we're done. Just let + // it be pushed up the stack. We must not leave our header; + // it is now meaningless and none of the upper layers business. + // All we have to do is to supply the end-2-end src and dest + // so that the endpoint demux routine can do its job. + if (destPeer.equals(localPeerAddr)) { + // Removing the header. + routerMsg.clearAll(); + routerMsg.updateMessage(); + // receive locally + endpoint.processIncomingMessage(msg, origSrcAddr, origDstAddr); + return; + } + + // WATCHOUT: if this peer is part of the reverse route + // it means that we've seen that message already: there's + // a loop between routers ! If that happens drop that + // message as if it was burning our fingers + + // First build the ap that we might add to the reverse route. + // We need it to look for ourselves in reverseHops. (contains + // uses equals(). equals will work because we always include + // in reversehops aps that have only a peerAddress. + + AccessPointAdvertisement selfAp = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + selfAp.setPeerID(localPeerId); + + if (reverseHops.contains(selfAp)) { + + // Danger, bail out ! + // Better not to try to NACK for now, but get rid of our own + // route. If we're sollicited again, there won't be a loop + // and we may NACK. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Routing loop detected. Message dropped"); + } + removeRoute(addr2pid(destPeer)); + return; + } + + // Update reverseHops. That is, add ourselves to the list. + + // We will only add the current hop to the reverse + // route if we know how to talk back to the previous hop + // it is important to point the difference between the lastHop + // and the reverse route entry. The lastHop indicates where the + // message came from but does not specify whether it is able to + // route messages in the other direction. The reverse route, if + // present, provides that information. + + // FIXME - jice@jxta.org 20040413 : HERE comes the use of connectLastHop. Could have waited till here. + + if (isLocalRoute(lastHop)) { // ok we have direct route back, at least we hope :-) + reverseHops.add(0, selfAp); // Update our vector + routerMsg.prependReverseHop(selfAp); // Update the message, this preserves the cache. + } else { + + // We cannot talk to our previous hop, well + // check if we have route to the src and use it as + // our reverse route. We could do more. But let's keep + // it to the minimum at this point. + RouteAdvertisement newReverseRoute = routedRoutes.get(addr2pid(srcPeerAddress)); + + if (newReverseRoute != null) { + // we found a new route back from our cache so let's use it + reverseHops = (Vector) newReverseRoute.getVectorHops().clone(); + // ok add ourselve to the reverse route + reverseHops.add(0, selfAp); + } else { + // no new route found, sorry. In the worst + // case it is better to not have reverse route + reverseHops = null; + } + + // In both cases above, we replace the hops completely. + // The cache is of no use and is lost. + routerMsg.setReverseHops(reverseHops); + } + + // Get the next peer into the forward route + origHops = routerMsg.getForwardHops(); + if (origHops != null) { + nextHop = getNextHop(origHops); + } + + // see if we can shortcut to the destination with no effort. + // If that works it's all very easy. + if (isLocalRoute(destPeer)) { + + // There is a local route - use it + // Clear the forward path which is probably wrong + routerMsg.setForwardHops(null); + nextHop = destPeer; + } else { + if (nextHop == null) { + + // No next hop. Use the destPeer instead. (but, unlike when + // we shortcut it deliberately, don't know if we can have a direct route + // yet). This is perfectly normal if we're just the last + // hop before the destination and we have closed the direct connection + // with it since we declared to be a router to it. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No next hop in forward route - Using destination as next hop"); + } + nextHop = destPeer; + + // That forward path is exhausted. It will not be usefull anymore. + // either we reach the destination directly and there will be + // no need for a NACK further down, or we will need to find an alternate + // route. + routerMsg.setForwardHops(null); + } + + // We must be do better than look passively for a direct + // route. The negative cache will take care of reducing the + // implied load. If we do not, then we never re-establish + // a broken local route until the originating peer seeks a + // new route. Then the result is roughly the same plus + // the overhead of route seeking...worse, if we're in the + // path from the originator to it's only rdv, then the + // originator does not stand a chance until it re-seeds ! + + if (ensureLocalRoute(nextHop, null) == null) { + + // need to look for a long route. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Forward route element broken - trying alternate route"); + } + + // While we're at it, we might as well get rid of our own + // route to the destination if it goes through the same hop + // by any chance. + // FIXME: idealy, each time we get a broken local route + // we'd want to get rid of all routes that start from there + // but that's one more map to maintain. + + RouteAdvertisement route = getRoute(destPeer, false); + + if (route == null) { + cantRoute("No new route to repair the route - drop message", null, origSrcAddr, destPeer, origHops); + return; + } + + if (pid2addr(route.getFirstHop().getPeerID()).equals(nextHop)) { + // Our own route is just as rotten as the sender's. Get rid + // of it. + removeRoute(addr2pid(destPeer)); + cantRoute("No better route to repair the route - drop message", null, origSrcAddr, destPeer, origHops); + return; + } + + // optimization to see if we can reach + // directly the last hop of that route + EndpointAddress addr = pid2addr(route.getLastHop().getPeerID()); + + if (isLocalRoute(addr)) { + // FIXME - jice@jxta.org 20030723. Should update our route table to reflect the shortcut. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found new remote route via : " + addr); + } + + // set the forward path to null no next hop + // FIXME: Not true. the last hop is not the destination. + // There could be a need for us receiving a NACK and that won't be + // possible. We should leave the next hop in the fw path. Just like + // we do when forwarding along the existing route. + + routerMsg.setForwardHops(null); + } else { // need to check the first hop + Vector newHops = (Vector) route.getVectorHops().clone(); + + // FIXME: remove(0) seems wrong + // There could be a need for us receiving a NACK and that won't be + // possible. We should leave the next hop in the fw path. Just like + // we do when forwarding along the existing route. + addr = pid2addr(newHops.remove(0).getPeerID()); + if (!isLocalRoute(addr)) { + // Our own route is provably rotten + // as well. Get rid of it. + removeRoute(addr2pid(destPeer)); + cantRoute("No usable route to repair the route - drop message", null, origSrcAddr, destPeer, origHops); + return; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Found new remote route via : " + addr); + } + + // NB: setForwardHops does not clone. + routerMsg.setForwardHops(newHops); + } + // If we're here. addr is our new nextHop. + nextHop = addr; + } + } + + // The first time we talk to a peer to which we have + // initiated a connection, we must include our local + // route adv in the routerMsg. However, we give priority to + // a route adv that's already in the message and which we pass along. + // In that case, our own will go next time. Note: we care only for + // nextHop, not for the final destination. We give our radv to a far + // destination only if we originate a message to it; not when forwarding. + // JC: give priority to our own radv instead. It can be critical. + + // 20040301 tra: May be the case we haven't yet initialize our + // own local route. For example still waiting for our relay connection + RouteAdvertisement myRoute = getMyLocalRoute(); + + if ((myRoute != null) && destinations.isWelcomeNeeded(nextHop)) { + routerMsg.setRouteAdv(myRoute); + } + + // We always modify the router message within the message + routerMsg.setLastHop(localPeerAddr); + routerMsg.updateMessage(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Trying to forward to " + nextHop); + } + + sendOnLocalRoute(nextHop, msg); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Successfully forwarded to " + nextHop); + } + } catch (Exception e) { + cantRoute("Failed to deliver or forward message for " + destPeer, e, origSrcAddr, destPeer, origHops); + } + } + + private void cantRoute(String logMsg, Exception exception, EndpointAddress origSrcAddr, EndpointAddress destPeer, Vector origHops) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + if (exception == null) { + LOG.warning(logMsg); + } else { + LOG.log(Level.WARNING, logMsg, exception); + } + } + routeResolver.generateNACKRoute(addr2pid(origSrcAddr), addr2pid(destPeer), origHops); + } + + /** + * Return the address of the next hop in this vector + * + * @param hops of forward hops in the route + * @return next hop to be used + */ + private EndpointAddress getNextHop(Vector hops) { + // check if we have a real route + if ((hops == null) || (hops.size() == 0)) { + return null; + } + + // find the next hop. + for (Enumeration e = hops.elements(); e.hasMoreElements();) { + AccessPointAdvertisement ap = (AccessPointAdvertisement) e.nextElement(); + + if (localPeerId.equals(ap.getPeerID())) { + + // If found at the end, no next hop + if (!e.hasMoreElements()) { + return null; + } + return pid2addr(((AccessPointAdvertisement) e.nextElement()).getPeerID()); + } + } + + // The peer is not into the vector. Since we have got that + // message, the best we can do is to send it to the first gateway + // in the forward path. + return pid2addr(((AccessPointAdvertisement) hops.elementAt(0)).getPeerID()); + } + + /** + * lame hard-coding + * + * @param p message transport + * @return true if fast + */ + private boolean isFast(MessageTransport p) { + String name = p.getProtocolName(); + + return name.equals("tcp") || name.equals("beep"); + } + + private boolean isRelay(MessageTransport p) { + String name = p.getProtocolName(); + + return name.equals("relay"); + } + + /** + * Given a list of addresses, find the best reachable endpoint. + *

            + *

              + *
            • The address returned must be reachable.
            • + *
            • We prefer an address whose protocol is, in order:
            • + *
                + *
              1. connected and fast.
              2. + *
              3. connected and slow.
              4. + *
              5. unconnected and fast.
              6. + *
              7. unconnected and slow
              8. + *
              + *
            + * + * @param dest destination address. + * @param mightWork A list of addresses to evaluate reachability. + * @param exist true if there already are existing messengers for + * the given destinations but we want one more. It may lead us to reject + * certain addresses that we would otherwise accept. + * @return The endpoint address for which we found a local route otherwise + * null + */ + Messenger findBestReachableEndpoint(EndpointAddress dest, List mightWork, boolean exist) { + + List rankings = new ArrayList(mightWork.size()); + List worthTrying = new ArrayList(mightWork.size()); + + // First rank the available addresses by type rejecting those which + // cant be used. + + for (Object aMightWork : mightWork) { + EndpointAddress addr = (EndpointAddress) aMightWork; + + // skip our own type + if (getProtocolName().equals(addr.getProtocolName())) { + continue; + } + int rank = -1; + Iterator eachTransport = endpoint.getAllMessageTransports(); + + while (eachTransport.hasNext()) { + MessageTransport transpt = eachTransport.next(); + + if (!transpt.getProtocolName().equals(addr.getProtocolName())) { + continue; + } + + // must be a sender + if (!(transpt instanceof MessageSender)) { + continue; + } + + MessageSender sender = (MessageSender) transpt; + + // must allow routing + if (!sender.allowsRouting()) { + // This protocol should not be used for routing. + continue; + } + rank += 1; + if (sender.isConnectionOriented()) { + rank += 2; + } + + if (isRelay(transpt)) { + // That should prevent the relay for ever being used + // when the relay may be sending through the router. + if (exist) { + rank -= 1000; + } + } + if (isFast(transpt)) { + rank += 4; + } + } + + // if its worth trying then insert it into the rankings. + if (rank >= 0) { + for (int eachCurrent = 0; eachCurrent <= rankings.size(); eachCurrent++) { + if (rankings.size() == eachCurrent) { + rankings.add(rank); + worthTrying.add(addr); + break; + } + if (rank > rankings.get(eachCurrent)) { + rankings.add(eachCurrent, rank); + worthTrying.add(eachCurrent, addr); + break; + } + } + } + } + + // now that we have them ranked, go through them until we get a + // successful messenger. + rankings = null; + + for (EndpointAddress addr : worthTrying) { + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Trying : " + addr); + } + // We use an async getMessenger as we do not + // want to wait too long to obtain our messenger + // We will still wait ASYNCMESSENGER_WAIT to see + // if we can get the messenger before bailing out + + // Create the listener object for that request + EndpointGetMessengerAsyncListener getMessengerListener = new EndpointGetMessengerAsyncListener(this, dest); + boolean stat = endpoint.getMessenger(getMessengerListener, new EndpointAddress(addr, ROUTER_SERVICE_NAME, null) + , + null); + + if (!stat) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Failed to create async messenger to : " + addr); + } + // we failed to get a messenger, we need to update the try and + // failed as it currently holds an infinite timeout to permit + // another thread to retry that destination. We only retry + // every MAX_ASYNC_GETMESSENGER_RETRY seconds + synchronized (this) { + triedAndFailed.put(addr2pid(dest), TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)); + } + continue; + } + + // wait to see if we can get the Async messenger + // If there is a long route to that destination, do not + // wait on the direct route. + // It may happen that we are actually + // trying to reach a different peer and this is just part of + // shortcuting the route via the one of the hops. In that case + // this test is not entirely accurate. We might still decide + // to wait when we shouldn't (we're no worse than before, then) + // But, in most cases, this is going to help. + boolean quick = (getRoute(dest, false) != null); + Messenger messenger = getMessengerListener.waitForMessenger(quick); + + if (messenger == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("did not get our async messenger. continue"); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("we got our async messenger, proceed"); + } + // Success we got a messenger synchronously. Remove + // the negative cache entry. + synchronized (this) { + triedAndFailed.remove(addr2pid(dest)); + notifyAll(); + } + return messenger; + } + } catch (RuntimeException e) { + // That address is somehow broken. + // Cache that result for a while. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "failed checking route", e); + } + } + } + return null; + } + + /** + * Read the route advertisement for a peer and find a suitable transport + * endpoint for sending to that peer either directly or via one of + * the advertised peer router + * + * @param destPeerAddress dest address + * @param exist use existing messengers, avoid creating a new one + * @param hint route hint + * @return a reachable messenger + */ + Messenger findReachableEndpoint(EndpointAddress destPeerAddress, boolean exist, RouteAdvertisement hint) { + + PeerID destPeerID = addr2pid(destPeerAddress); + + // findReachableEndpoint is really lazy because what it does is expensive. + // When needed, the negative info that prevents its from working + // too much is removed. (see calls to ensureLocalRoute). + synchronized (this) { + Long nextTry = triedAndFailed.get(destPeerID); + + if (nextTry != null) { + if (nextTry > TimeUtils.timeNow()) { + return null; + } + } + + // We are the first thread trying this destination. Let's preclude + // any other threads from attempting to do anything while we are + // trying that destination. Other threads will have a chance if they + // are still waiting when this thread is done. We will update + // triedAndFailed when we get the async notification that we got or + // we failed to get a messenger. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Temporarly adding " + destPeerAddress.toString() + " to triedAndFailed, while attempting connection"); + } + triedAndFailed.put(destPeerID, TimeUtils.toAbsoluteTimeMillis(Long.MAX_VALUE)); + } + + // Never tried or it was a long time ago. + // Get (locally) the advertisements of this peer + Iterator advs; + + try { + // try to use the hint that was given to us + if (hint != null) { + advs = Collections.singletonList(hint).iterator(); + } else { + // Ok extract from the CM + advs = routeCM.getRouteAdv(destPeerID); + } + + // Check if we got any advertisements + List addrs = new ArrayList(); + + while (advs.hasNext()) { + RouteAdvertisement adv = advs.next(); + + String saddr = null; + + // add the destination endpoint + for (Enumeration e = adv.getDest().getEndpointAddresses(); e.hasMoreElements();) { + try { + saddr = e.nextElement(); + addrs.add(new EndpointAddress(saddr)); + } catch (Throwable ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(" bad address in route adv : " + saddr); + } + } + } + } + + // ok let's go and try all these addresses + if (!addrs.isEmpty()) { + Messenger bestMessenger = findBestReachableEndpoint(destPeerAddress, addrs, exist); + + if (bestMessenger != null) { + // Found a direct route. Return it. + // Tried+failed has been cleaned. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("found direct route"); + } + return bestMessenger; + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("findReachableEndpoint : Failed due to empty address list"); + } + } + } catch (RuntimeException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure looking for an address ", e); + } + } + + // We're done trying. Since we did not find anything at all (or failed, + // during the atempt) the triedFailed record is still set to infinite + // value. Reset it to finite. + // There is a small chance that another thread did find + // something in parallel, but that's very unlikely and + // if it is rare enough then the damage is small. + synchronized (this) { + triedAndFailed.put(destPeerID, TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("did not find a direct route to :" + destPeerAddress); + } + return null; + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress addr, Object hint) { + RouteAdvertisement routeHint = null; + EndpointAddress plainAddr = new EndpointAddress(addr, null, null); + + // If the dest is the local peer, just loop it back without going + // through the router. + if (plainAddr.equals(localPeerAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("return LoopbackMessenger"); + } + return new LoopbackMessenger(group, endpoint, localPeerAddr, addr, addr); + } + + try { + // try and add that hint to our cache of routes (that may be our only route). + if (hint != null && hint instanceof RouteAdvertisement) { + routeHint = ((RouteAdvertisement) hint).clone(); + AccessPointAdvertisement firstHop = routeHint.getFirstHop(); + PeerID firstHopPid; + EndpointAddress firstHopAddr = null; + + // If the firstHop is equal to the destination, clean that up, + // that's a direct route. If the first hop is the local peer + // leave it there but treat it as a local route. That's what + // it is from the local peer point of view. + if (firstHop != null) { + + firstHopPid = firstHop.getPeerID(); + firstHopAddr = pid2addr(firstHopPid); + + if (firstHopAddr.equals(addr)) { + routeHint.removeHop(firstHopPid); + firstHop = null; + } else if (firstHopPid.equals(localPeerId)) { + firstHop = null; + } + + } + + if (firstHop == null) { + // The hint is a direct route. Make sure that we have the + // route adv so that we can actually connect. + + // we only need to publish this route if we don't know about + // it yet. + EndpointAddress da = pid2addr(routeHint.getDestPeerID()); + + if (!isLocalRoute(da) && !routedRoutes.containsKey(routeHint.getDestPeerID())) { + routeCM.publishRoute(routeHint); + } + + } else { + // For the hint to be useful, we must actively try the first + // hop. It is possible that we do not know it yet and that's + // not a reason to ignore the hint (would ruin the purpose + // in most cases). + RouteAdvertisement routeFirstHop = null; + + // Manufacture a RA just that as just the routerPeer as a + // destination. We only need to publish this route if we + // don't know about it yet. + if (!isLocalRoute(firstHopAddr) && !routedRoutes.containsKey(firstHop.getPeerID())) { + + routeFirstHop = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + routeFirstHop.setDest(firstHop.clone()); + + // Here we used to pass a second argument with value + // true which forced updateRouteAdv to ignore a + // pre-existing identical adv and remove negative cache + // information anyway. The reason for doing that was + // that sometimes the new route adv does already exist + // but has not yet been tried. We cannot do that; it + // exposes us too much to retrying incessantly the same + // address. A hint cannot be trusted to such an extent. + // The correct remedy is to be able to tell accurately + // if there really is an untried address in that radv, + // which requires a sizeable refactoring. in the + // meantime just let the negative cache play its role. + updateRouteAdv(routeFirstHop); + } + + // if we constructed the route hint then passes it in the + // past we were just relying on the CM now that the CM can + // be disabled, we have to pass the argument. + if (ensureLocalRoute(firstHopAddr, routeFirstHop) != null) { + setRoute(routeHint.clone(), false); + } + } + } + + } catch (Throwable ioe) { + // Enforce a stronger semantic to hint. If the application passes + // a hint that is rotten then this is an application problem + // we should not try to fix what was given to us. + return null; + } + + try { + // Build a persistent RouterMessenger around it that will add our + // header. If a hint was passed to us we just use it as it. Too bad + // if it is not the the right one. In that mode it is the + // responsibility of the application to make sure that a correct + // hint was passed. + return new RouterMessenger(addr, this, routeHint); + } catch (IOException caught) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Can\'t generate messenger for addr " + addr, caught); + } + return null; + } + } + + /** + * Updates the router element of a message and returns the peerAddress address of + * the next hop (where to send the message). + *

            + * Currently, address message is only called for messages that we + * originate. As a result we will always aggressively seek a route if needed. + * + * @param message the message for which to compute/update a route. + * @param dstAddress the final destination of the route which the message be set to follow. + * @return EndpointAddress The address (logical) where to send the message next. Null if there + * is nowhere to send it to. + */ + EndpointAddress addressMessage(Message message, EndpointAddress dstAddress) { + if (endpoint == null) { + return null; + } + + // We need to create a RouterMessage + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Create a new EndpointRouterMessage " + dstAddress); + } + + // Specify that we do not want an existing msg parsed. + EndpointRouterMessage routerMsg = new EndpointRouterMessage(message, true); + + if (routerMsg.isDirty()) { + // Oops there was one in the message already. This must be a + // low-level protocol looping back through the router. The relay can + // be led to do that in some corner cases. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Probable transport recursion"); + } + throw new IllegalStateException("RouterMessage element already present"); + } + + routerMsg.setSrcAddress(localPeerAddr); + routerMsg.setDestAddress(dstAddress); + + EndpointAddress theGatewayAddress; + EndpointAddress dstAddressPlain = new EndpointAddress(dstAddress, null, null); + + try { + RouteAdvertisement route = null; + + theGatewayAddress = getGatewayAddress(dstAddressPlain, true, null); + + if (theGatewayAddress == null) { + // Cleanup the message, so that the invoker + // may retry (with a different hint, for example). + routerMsg.clearAll(); + routerMsg.updateMessage(); + return null; + } + + // Check that we're actually going through a route; we could have one + // but not be using it, because we know of a volatile shortcut. + + // FIXME: jice@jxta.org - 20030512: This is not very clean: + // getGatewayAddress should be giving us the route that it's using, if any. + // By doing the fetch ourselves, not only do we waste CPU hashing + // twice, but we could also get a different route ! + + if (!theGatewayAddress.equals(dstAddressPlain)) { + route = getRoute(dstAddressPlain, false); + } + + // If we're going through a route for that, stuff it in the + // message. NB: setForwardHops does not clone. + if (route != null) { + routerMsg.setForwardHops((Vector) route.getVectorHops().clone()); + } + + // set the last hop info to point to the local peer info + // The recipient takes last hop to be the last peer that the message has traversed + // before arriving. + routerMsg.setLastHop(localPeerAddr); + + // The first time we talk to a peer to which we have + // initiated a connection, we must include our local + // route adv in the routerMsg. + RouteAdvertisement myRoute = getMyLocalRoute(); + + if (myRoute != null) { + // FIXME - jice@jxta.org 20040430 : use destinations instead of newDestinations, even for routed ones. + boolean newDest = newDestinations.remove(dstAddressPlain); + boolean newGatw = destinations.isWelcomeNeeded(theGatewayAddress); + + if (newDest || newGatw) { + routerMsg.setRouteAdv(myRoute); + } + } + + // Push the router header onto the message. + // That's all we have to do for now. + + routerMsg.updateMessage(); + } catch (Exception ez1) { + // Not much we can do + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not fully address message", ez1); + } + return null; + } + + return theGatewayAddress; + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object value) { + if (!(operation instanceof Integer)) { + return null; + } + + int op = (Integer) operation; + + switch (op) { + case RouteControlOp: // Get a Router Control Object + return new RouteControl(this, localPeerId); + + default: + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid Transport Control operation argument"); + } + + return null; + } + } + + /** + * Convert a Router EndpointAddress into a PeerID + * + * @param addr the address to extract peerAddress from + * @return the PeerID + */ + static PeerID addr2pid(EndpointAddress addr) { + URI asURI = null; + + try { + asURI = new URI(ID.URIEncodingName, ID.URNNamespace + ":" + addr.getProtocolAddress(), null); + return (PeerID) IDFactory.fromURI(asURI); + } catch (URISyntaxException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error converting a source address into a virtual address : " + addr, ex); + } + } catch (ClassCastException cce) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error converting a source address into a virtual address: " + addr, cce); + } + } + + return null; + } + + /** + * Convert an ID into a Router Endpoint Address + * + * @param pid The ID who's equivalent Endpoint Address is desired. + * @return The ID as an EndpointAddress. + */ + static EndpointAddress pid2addr(ID pid) { + return new EndpointAddress(ROUTER_PROTOCOL_NAME, pid.getUniqueValue().toString(), null, null); + } + + /** + * check if it is a new route adv + * + * @param route route advertisement + */ + void updateRouteAdv(RouteAdvertisement route) { + updateRouteAdv(route, false); + } + + /** + * check if it is a new route adv + * + * @param route route advertisement + * @param force enforce the route + */ + void updateRouteAdv(RouteAdvertisement route, boolean force) { + try { + PeerID pID = route.getDestPeerID(); + + // check if we updated the route + if (routeCM.updateRoute(route)) { + // We just dumped an adv for that dest, so we want to do a real check + // on its new addresses. Remove the entry from the negative cache. + synchronized (this) { + Long nextTry = triedAndFailed.get(pID); + + if (nextTry != null) { + // only remove if we do not have a pending request (infinite retry) + // we take the conservative approach to avoid creating multiple + // async thread blocked on the same destination + if (nextTry <= TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)) { + triedAndFailed.remove(pID); + notifyAll(); + } + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Route for " + pID + " is same as existing route, not publishing it"); + } + + if (force) { + synchronized (this) { + Long nextTry = triedAndFailed.get(pID); + + if (nextTry != null) { + // only remove if we do not have a pending request (infinite retry) + // we take the conservative approach to avoid creating multiple + // async thread blocked on the same destination + if (nextTry <= TimeUtils.toAbsoluteTimeMillis(MAX_ASYNC_GETMESSENGER_RETRY)) { + triedAndFailed.remove(pID); + notifyAll(); + } + } + } + } + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to publish route advertisement", e); + } + } + } + + /** + * is there a pending route query for that destination + * + * @param peerID destination address + * @return true or false + */ + boolean isPendingRouteQuery(PeerID peerID) { + return pendingQueries.containsKey(peerID); + } + + /** + * get a pending route query info + * + * @param peerID destination address + * @return pending route query info + */ + ClearPendingQuery getPendingRouteQuery(PeerID peerID) { + return pendingQueries.get(peerID); + } + + /** + * Do we have a long route for that destination + * + * @param peerID destination address + * @return true or false + */ + boolean isRoutedRoute(PeerID peerID) { + return peerID != null && routedRoutes.containsKey(peerID); + } + + /** + * Snoop if we have a messenger + * + * @param addr destination address + * @return Messenger + */ + Messenger getCachedMessenger(EndpointAddress addr) { + return destinations.getCurrentMessenger(addr); + } + + /** + * Get all direct route destinations + * + * @return Iterator iterations of all endpoint destinations + */ + Iterator getAllCachedMessengerDestinations() { + return destinations.allDestinations().iterator(); + } + + /** + * Get all long route destinations + * + * @return Iterator iterations of all routed route destinations + */ + Iterator> getRoutedRouteAllDestinations() { + return routedRoutes.entrySet().iterator(); + } + + /** + * Get all long route destination addresses + * + * @return Iterator iterations of all routed route addresses + */ + Iterator getAllRoutedRouteAddresses() { + return routedRoutes.keySet().iterator(); + } + + /** + * Get all pendingRouteQuery destinations + * + * @return All pending route query destinations + */ + Collection> getPendingQueriesAllDestinations() { + List> copy = new ArrayList>( + pendingQueries.size()); + + synchronized (pendingQueries) { + copy.addAll(pendingQueries.entrySet()); + } + + return copy; + } + + /** + * Get the route CM cache Manager + * + * @return the route CM cache Manager + */ + RouteCM getRouteCM() { + return routeCM; + } + + /** + * Get the route resolver manager + * + * @return the route resolver Manager + */ + RouteResolver getRouteResolver() { + return routeResolver; + } + + /** + * set bad route entry + * + * @param addr of the bad route + * @param badRoute bad route info + */ + synchronized void setBadRoute(EndpointAddress addr, BadRoute badRoute) { + badRoutes.put(addr, badRoute); + } + + /** + * get bad route entry + * + * @param addr of the bad route + * @return BadRoute bad route info + */ + synchronized BadRoute getBadRoute(EndpointAddress addr) { + return badRoutes.get(addr); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/EndpointRouterMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/EndpointRouterMessage.java new file mode 100644 index 000000000..febf54e41 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/EndpointRouterMessage.java @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.router; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.logging.Logging; + +import java.util.Enumeration; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Router Message element. This element is added to every message to carry route + * information for the EndpointRouter service. + */ +public class EndpointRouterMessage { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(EndpointRouterMessage.class.getName()); + + public static final String MESSAGE_NS = "jxta"; + public static final String MESSAGE_NAME = "EndpointRouterMsg"; + public static final String Name = "jxta:ERM"; + + public static final String SrcTag = "Src"; + public static final String DestTag = "Dest"; + public static final String LastHopTag = "Last"; + public static final String GatewayForwardTag = "Fwd"; + public static final String GatewayReverseTag = "Rvs"; + + private EndpointAddress srcAddress = null; // PeerID-based EndpointAddress + private EndpointAddress destAddress = null; // PeerID-based EndpointAddress + private EndpointAddress lastHop = null; // Plain PeerID + + private transient Vector forwardGateways = null; + private transient Vector forwardCache = null; + private transient Vector reverseGateways = null; + private transient Vector reverseCache = null; + private transient RouteAdvertisement radv = null; + + // A flag that represents the existence of data. Which is + // different from all fields being empty. + private transient boolean rmExists = false; + + // A flag that tells us that the message is not uptodate compared to + // This object. + private transient boolean rmDirty = false; + + // Keep tied to one and only one message. + private final transient Message message; + + // Cache the element. At the minimum it simplifies removal. + private transient MessageElement rmElem = null; + + public boolean msgExists() { + return rmExists; + } + + public boolean isDirty() { + return rmDirty; + } + + public EndpointRouterMessage(Message message, boolean removeMsg) { + + this.message = message; + + try { + rmElem = message.getMessageElement(MESSAGE_NS, MESSAGE_NAME); + if (rmElem == null) { + return; + } + + // We have an element, but until we read it, no data to + // match (rmExists == false). If the data cannot be read + // from the element, the element is scheduled for removal. + rmDirty = true; + + // If we have been instructed so, do not parse any existing + // element, and leave it marked for removal from the message + // as if it were invalid. + if (removeMsg) { + return; + } + + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(rmElem); + + Enumeration each; + XMLElement e; + + each = doc.getChildren(); + if (!each.hasMoreElements()) { + // results in rmExists being false. + return; + } + + while (each.hasMoreElements()) { + try { + e = each.nextElement(); + + if (e.getName().equals(SrcTag)) { + srcAddress = new EndpointAddress(e.getTextValue()); + continue; + } + + if (e.getName().equals(DestTag)) { + destAddress = new EndpointAddress(e.getTextValue()); + continue; + } + + if (e.getName().equals(LastHopTag)) { + lastHop = new EndpointAddress(e.getTextValue()); + continue; + } + + if (e.getName().equals(GatewayForwardTag)) { + for (Enumeration eachXpt = e.getChildren(); eachXpt.hasMoreElements();) { + + if (forwardGateways == null) { + forwardGateways = new Vector(); + } + if (forwardCache == null) { + forwardCache = new Vector(); + } + XMLElement aXpt = eachXpt.nextElement(); + AccessPointAdvertisement xptAdv = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(aXpt); + + forwardGateways.addElement(xptAdv); + // Save the original element + forwardCache.addElement(aXpt); + } + continue; + } + + if (e.getName().equals(GatewayReverseTag)) { + for (Enumeration eachXpt = e.getChildren(); eachXpt.hasMoreElements();) { + if (reverseGateways == null) { + reverseGateways = new Vector(); + } + if (reverseCache == null) { + reverseCache = new Vector(); + } + XMLElement aXpt = eachXpt.nextElement(); + AccessPointAdvertisement xptAdv = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(aXpt); + + reverseGateways.addElement(xptAdv); + // Save the original element + reverseCache.addElement(aXpt); + } + continue; + } + + if (e.getName().equals(RouteAdvertisement.getAdvertisementType())) { + radv = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(e); + } + } catch (Exception ee) { + // keep going + } + } + + // XXX 20040929 bondolo Should be doing validation here. + + // All parsed ok, we're in sync. + rmExists = true; + rmDirty = false; + } catch (Exception eee) { + // give up. The dirty flag will get the element removed + // from the message (if there was one) and we'll report + // there was none. + } + } + + public void updateMessage() { + + if (!rmDirty) { + return; + } + + if (!rmExists) { + + // The change was to remove it. + // If there was an rmElem, remove it and make sure to remove + // all of them. We may have found one initialy but there may be + // several. (just a sanity check for outgoing messages). + + while (rmElem != null) { + message.removeMessageElement(MESSAGE_NS, rmElem); + rmElem = message.getMessageElement(MESSAGE_NS, MESSAGE_NAME); + } + + rmDirty = false; + return; + } + + // The element was either created or changed. Replace whatever + // if anything was in the message + + XMLDocument doc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, Name); + + doc.addAttribute("xmlns:jxta", "http://jxta.org"); + doc.addAttribute("xml:space", "preserve"); + + XMLElement e; + + if (srcAddress != null) { + e = doc.createElement(SrcTag, srcAddress.toString()); + doc.appendChild(e); + } + + if (destAddress != null) { + e = doc.createElement(DestTag, destAddress.toString()); + doc.appendChild(e); + } + + if (lastHop != null) { + e = doc.createElement(LastHopTag, lastHop.toString()); + doc.appendChild(e); + } + + e = doc.createElement(GatewayForwardTag); + doc.appendChild(e); + if ((forwardGateways != null) && (!forwardGateways.isEmpty())) { + if (forwardCache != null) { + for (XMLElement xptDoc : forwardCache) { + try { + StructuredDocumentUtils.copyElements(doc, e, xptDoc); + } catch (Exception e1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Forward cache failed"); + } + forwardCache = null; + break; + } + } + } else { + for (AccessPointAdvertisement gateway : forwardGateways) { + try { + XMLDocument xptDoc = (XMLDocument) gateway.getDocument(MimeMediaType.XMLUTF8); + StructuredDocumentUtils.copyElements(doc, e, xptDoc); + } catch (Exception ignored) { + //ignored + } + } + } + } + + e = doc.createElement(GatewayReverseTag); + doc.appendChild(e); + if ((reverseGateways != null) && (!reverseGateways.isEmpty())) { + if (reverseCache != null) { + for (XMLElement xptDoc : reverseCache) { + try { + StructuredDocumentUtils.copyElements(doc, e, xptDoc); + } catch (Exception e1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Reverse cache failed"); + } + reverseCache = null; + break; + } + } + } else { + for (AccessPointAdvertisement gateway : reverseGateways) { + try { + XMLDocument xptDoc = (XMLDocument) gateway.getDocument(MimeMediaType.XMLUTF8); + StructuredDocumentUtils.copyElements(doc, e, xptDoc); + } catch (Exception e1) { + // ignored + } + } + } + } + + if (radv != null) { + try { + XMLDocument radvDoc = (XMLDocument) radv.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(doc, doc, radvDoc); + } catch (Exception e1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Cannot add route advertisement"); + } + } + } + + rmElem = new TextDocumentMessageElement(MESSAGE_NAME, doc, null); + message.replaceMessageElement(MESSAGE_NS, rmElem); + + rmDirty = false; + } + + public void setSrcAddress(EndpointAddress address) { + rmExists = true; + rmDirty = true; + srcAddress = address; + } + + public EndpointAddress getSrcAddress() { + return srcAddress; + } + + public void setDestAddress(EndpointAddress address) { + rmExists = true; + rmDirty = true; + destAddress = address; + } + + public EndpointAddress getDestAddress() { + return destAddress; + } + + public void setLastHop(EndpointAddress lhop) { + rmExists = true; + rmDirty = true; + lastHop = lhop; + } + + public EndpointAddress getLastHop() { + return lastHop; + } + + public void setForwardHops(Vector fhops) { + rmExists = true; + rmDirty = true; + forwardGateways = fhops; + forwardCache = null; + } + + public Vector getForwardHops() { + return forwardGateways; + } + + public void prependReverseHop(AccessPointAdvertisement apa) { + rmExists = true; + rmDirty = true; + if (reverseGateways == null) { + reverseGateways = new Vector(); + reverseCache = new Vector(); + } + + reverseGateways.add(0, apa); + + if (reverseCache == null) { + return; + } + + // if we still have a cache (we where able to keep it conistent, update it + XMLDocument apDoc = (XMLDocument) apa.getDocument(MimeMediaType.XMLUTF8); + + reverseCache.add(0, apDoc); + } + + // Do not call this routine lightly: it blasts the cache. + public void setReverseHops(Vector rhops) { + rmExists = true; + rmDirty = true; + + // No inplace changes allowed, we need to keep the cache + // consistent: clone + + if (rhops == null) { + reverseGateways = null; + } else { + reverseGateways = (Vector) rhops.clone(); + } + + // Not worth updating the cache. Blast it. + reverseCache = null; + } + + public Vector getReverseHops() { + + if (reverseGateways == null) { + return null; + } + + return (Vector) reverseGateways.clone(); + } + + public RouteAdvertisement getRouteAdv() { + return radv; + } + + public void setRouteAdv(RouteAdvertisement radv) { + rmExists = true; + rmDirty = true; + this.radv = radv; + } + + // Used only for debugging + public String display() { + StringBuilder msgInfo = new StringBuilder("Endpoint Router Message : "); + + msgInfo.append("\n\tsrc="); + msgInfo.append((srcAddress != null) ? srcAddress : "none"); + msgInfo.append("\n\tdest== "); + msgInfo.append((destAddress != null) ? destAddress : "none"); + msgInfo.append("\n\tlastHop= "); + msgInfo.append((lastHop != null) ? lastHop : "none"); + msgInfo.append("\n\tembedded radv= "); + msgInfo.append(radv != null ? radv.display() : "none"); + if (forwardGateways != null) { + msgInfo.append("\n\tForward Hops:"); + for (int i = 0; i < forwardGateways.size(); ++i) { + try { + msgInfo.append(" [").append(i).append("] "); + msgInfo.append(forwardGateways.elementAt(i).getPeerID()); + } + catch (Exception ez1) { + break; + } + } + } + if (reverseGateways != null) { + msgInfo.append("\n\tReverse Hops:"); + for (int i = 0; i < reverseGateways.size(); ++i) { + msgInfo.append(" [").append(i).append("] "); + msgInfo.append(reverseGateways.elementAt(i).getPeerID()); + } + } + return msgInfo.toString(); + } + + // This will ensure that all older elements will be removed from + // the message in case they do not get replaced by new ones before + // updateMsg is called. + + public void clearAll() { + + if (rmExists) { + rmDirty = true; + + srcAddress = null; + destAddress = null; + lastHop = null; + forwardGateways = null; + reverseGateways = null; + radv = null; + rmExists = false; + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteCM.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteCM.java new file mode 100644 index 000000000..012e8fbe1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteCM.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +/** + * This class is used to manage a persistent CM cache of route + * for the router + */ +package net.jxta.impl.endpoint.router; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.LRUCache; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import net.jxta.impl.endpoint.EndpointUtils; + +class RouteCM implements Module { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RouteCM.class.getName()); + + /** + * Default expiration time for Route advertisements. This is the amount + * of time which advertisements will live in caches. After this time, the + * advertisement should be refreshed from the source. + */ + public final static long DEFAULT_EXPIRATION = 20L * TimeUtils.AMINUTE; + + /** + * If {@code true} then the CM is used to persistently store route + * advertisements. If {@code false} then only the in-memory route table is + * used. + */ + public final static boolean USE_CM_DEFAULT = true; + + /** + * If {@code true} then the CM is used to persistently store route + * advertisements. If {@code false} then only the in-memory route table is + * used. + *

            + * We start out {@code false} until the module is started. + */ + private boolean useCM = false; + + /** + * If {@code true} then the CM is used to persistently store route + * advertisements. If {@code false} then only the in-memory route table is + * used. + */ + private boolean useCMConfig = USE_CM_DEFAULT; + + /** + * PeerGroup Service Handle + */ + private PeerGroup group = null; + private LRUCache lruCache = new LRUCache(100); + + /** + * EndpointRouter pointer + */ + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) impl; + + // extract Router service configuration properties + + ConfigParams confAdv = group.getConfigAdvertisement(); + XMLElement paramBlock = null; + + if (confAdv != null) { + paramBlock = (XMLElement) confAdv.getServiceParam(assignedID); + } + + if (paramBlock != null) { + // get our tunable router parameter + Enumeration param; + + param = paramBlock.getChildren("useCM"); + if (param.hasMoreElements()) { + useCMConfig = Boolean.getBoolean(((XMLElement) param.nextElement()).getTextValue()); + } + } + + this.group = group; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Router Transport Resolver : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID : ").append(group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tUse Route CM : ").append(useCMConfig); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + // ok, we are initialized, go ahead and enable CM usage desired + useCM = useCMConfig; + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + useCM = false; + } + + /** + * return routeCM usage + * + * @return true if enabled + */ + boolean useRouteCM() { + return useCM; + } + + /** + * toggles whether to use the RouteCM + * @param enable if true it enables use of persistent store + */ + void enableRouteCM(boolean enable) { + useCM = enable; + } + + /** + * Get route advertisements from the local discovery cache. + * We collect straight RouteAdvertisements as well as what can be + * found in PeerAdvertisements. + * + *

            We can find both, and there's no way to know which is most relevant, + * so we have to return all and let the invoker try its luck with each. + * + * @param peerID the target peer's ID. + * @return Route Advertisements for the specified peer. + */ + protected Iterator getRouteAdv(ID peerID) { + DiscoveryService discovery; + + // check if we use the CM, if not then nothing + // to retrieve + if (!useCM) { + return Collections.emptyList().iterator(); + } else { + discovery = group.getDiscoveryService(); + if (null == discovery) { + return Collections.emptyList().iterator(); + } + } + + String peerIDStr = peerID.toString(); + List result = new ArrayList(2); + if (lruCache.contains(peerID)) { + result.add(lruCache.get(peerID)); + return result.iterator(); + } + // check first if we have a route advertisement + Enumeration advs = null; + + try { + advs = discovery.getLocalAdvertisements(DiscoveryService.ADV, RouteAdvertisement.DEST_PID_TAG, peerIDStr); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed discovering routes for " + peerIDStr, failed); + } + } + + while ((null != advs) && advs.hasMoreElements()) { + Advertisement adv = advs.nextElement(); + + if (!(adv instanceof RouteAdvertisement)) { + continue; + } + + RouteAdvertisement route = (RouteAdvertisement) adv; + + if (!result.contains(route)) { + result.add(route); + } + } + + // get the local peer advertisements for the peer. + advs = null; + try { + advs = discovery.getLocalAdvertisements(DiscoveryService.PEER, "PID", peerIDStr); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed discovering peer advertisements for " + peerIDStr, failed); + } + } + + while ((null != advs) && advs.hasMoreElements()) { + Advertisement adv = advs.nextElement(); + + if (!(adv instanceof PeerAdvertisement)) { + continue; + } + + PeerAdvertisement padv = (PeerAdvertisement) adv; + + RouteAdvertisement route = EndpointUtils.extractRouteAdv(padv); + + // Publish the route if it was previously unknown. + if (!result.contains(route)) { + // We found a new route just publish it locally + try { + // XXX 20060106 bondolo These publication values won't be obeyed if + // the route had been previously published. + + //FIXME by hamada: This operation may lead to overwriting an existing and valid rout adv, no? + discovery.publish(route, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed publishing route", failed); + } + } + result.add(route); + } + } + return result.iterator(); + } + + /** + * Create a new persistent route to the cache only if we can find set of + * endpoint addresses + * + * @param route to be published + */ + protected void createRoute(RouteAdvertisement route) { + DiscoveryService discovery; + + // check if CM is used + if (!useCM) { + return; + } else { + discovery = group.getDiscoveryService(); + + if (null == discovery) { + return; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("try to publish route "); + } + // we need to retrieve the current adv to get all the known + // endpoint addresses + try { + RouteAdvertisement newRoute = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + PeerID pId = route.getDestPeerID(); + + String realPeerID = pId.toString(); + + // check first if we have a route advertisement + Enumeration advs = discovery.getLocalAdvertisements(DiscoveryService.ADV, RouteAdvertisement.DEST_PID_TAG, realPeerID); + + if (!advs.hasMoreElements()) { + // No route, sorry + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("could not find a route advertisement " + realPeerID); + } + return; + } + + // make sure we are returning the longest route we know either + // from the peer or route advertisement + Advertisement adv = advs.nextElement(); + + if (adv instanceof RouteAdvertisement) { + RouteAdvertisement dest = (RouteAdvertisement) adv; + + newRoute.setDest(dest.getDest()); + } + + // let's get the endpoint addresses for each hops + Vector newHops = new Vector(); + + Enumeration e = route.getHops(); + + while (e.hasMoreElements()) { + AccessPointAdvertisement ap = e.nextElement(); + + realPeerID = ap.getPeerID().toString(); + + // check first if we have a route advertisement + advs = discovery.getLocalAdvertisements(DiscoveryService.ADV, RouteAdvertisement.DEST_PID_TAG, realPeerID); + if (!advs.hasMoreElements()) { + // No route, sorry + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("could not find a route advertisement for hop " + realPeerID); + } + return; + } + adv = advs.nextElement(); + // ensure it is a RouteAdvertisement + if (adv instanceof RouteAdvertisement) { + newHops.add(((RouteAdvertisement) adv).getDest()); + } + } + + // last check to see that we have a route + if (newHops.isEmpty()) { + return; + } + + newRoute.setHops(newHops); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("publishing new route \n" + newRoute.display()); + } + lruCache.put(route.getDestPeerID(), route); + // XXX 20060106 bondolo These publication values won't be obeyed if + // the route had been previously published. + discovery.publish(newRoute, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "error publishing route" + route.display(), ex); + } + } + } + + /** + * Publish a route advertisement to the CM + * + * @param route advertisement to be published + */ + protected void publishRoute(RouteAdvertisement route) { + DiscoveryService discovery; + + // check if CM is in used, if not nothing to do + if (!useCM) { + return; + } else { + discovery = group.getDiscoveryService(); + if (null == discovery) { + return; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Publishing route for " + route.getDestPeerID()); + } + + // publish route adv + if (!lruCache.contains(route.getDestPeerID())) { + try { + // XXX 20060106 bondolo These publication values won't be obeyed if + // the route had been previously published. + discovery.publish(route, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + } catch (Exception ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "error publishing route adv \n" + route, ex); + } + } + } + lruCache.put(route.getDestPeerID(), route); + } + + /** + * flush route adv from CM + * + * @param peerID the PeerID + */ + protected void flushRoute(ID peerID) { + DiscoveryService discovery; + + // check if CM is in used, if not nothing to do + if (!useCM) { + return; + } else { + discovery = group.getDiscoveryService(); + if (null == discovery) { + return; + } + } + + // leqt's remove any advertisements (route, peer) related to this peer + // this should force a route query to try to find a new route + // check first if we have a route advertisement + String peerIDStr = peerID.toString(); + + Enumeration advs = null; + + // Flush the local route advertisements for the peer. + try { + advs = discovery.getLocalAdvertisements(DiscoveryService.ADV, RouteAdvertisement.DEST_PID_TAG, peerIDStr); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure recovering route advertisements.", failed); + } + } + + while ((null != advs) && advs.hasMoreElements()) { + Advertisement adv = advs.nextElement(); + + if (!(adv instanceof RouteAdvertisement)) { + continue; + } + + // ok so let's delete the advertisement + try { + discovery.flushAdvertisement(adv); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removed RouteAdvertisement for " + peerIDStr); + } + } catch (IOException ex) {// protect against flush IOException when the entry is not there + } + } + + // Flush the local peer advertisements for the peer. + advs = null; + try { + advs = discovery.getLocalAdvertisements(DiscoveryService.PEER, "PID", peerIDStr); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed discovering peer advertisements for " + peerIDStr, failed); + } + } + + while ((null != advs) && advs.hasMoreElements()) { + Advertisement adv = advs.nextElement(); + + if (!(adv instanceof PeerAdvertisement)) { + continue; + } + + // ok so let's delete the advertisement + try { + discovery.flushAdvertisement(adv); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removed PeerAdvertisement for " + peerIDStr); + } + } catch (IOException ex) {// protect against flush IOException when the entry is not there + } + } + // remove it from the cache as well + lruCache.remove(peerID); + } + + /** + * publish or update new route from the advertisement cache + * + * @param route to be published or updated + * @return boolean true or false if adv cache was updated + */ + protected boolean updateRoute(RouteAdvertisement route) { + DiscoveryService discovery; + + // check if CM is in used + if (!useCM) { + return false; + } else { + discovery = group.getDiscoveryService(); + if (null == discovery) { + return true; + } + } + + try { + String realPeerID = route.getDestPeerID().toString(); + + // check first if we have a route advertisement + Enumeration advs = discovery.getLocalAdvertisements(DiscoveryService.ADV, RouteAdvertisement.DEST_PID_TAG, realPeerID); + + if (advs.hasMoreElements()) { + Advertisement adv = advs.nextElement(); + + if (adv instanceof RouteAdvertisement) { + RouteAdvertisement oldRouteAdv = (RouteAdvertisement) adv; + + // check if the old route is equal to the new route + if (!route.equals(oldRouteAdv)) { + // publish the new route + // XXX 20060106 bondolo These publication values won't be obeyed if + // the route had been previously published. + discovery.publish(route, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + lruCache.put(route.getDestPeerID(), route); + return true; + } + } + } else { + // publish the new route + discovery.publish(route, DEFAULT_EXPIRATION, DEFAULT_EXPIRATION); + lruCache.put(route.getDestPeerID(), route); + return true; + } + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, " failure to publish route advertisement response", e); + } + } + return false; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteControl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteControl.java new file mode 100644 index 000000000..ccf0ec267 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteControl.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +/** + * This class is used to control the Router route options + * + */ +package net.jxta.impl.endpoint.router; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerEvent; +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.io.IOException; + +/** + * Provides an "IOCTL" style interface to the JXTA router transport + */ +public class RouteControl { + + /** + * Logger + */ + private static transient final Logger LOG = Logger.getLogger(RouteControl.class.getName()); + + /** + * return value for operation + */ + public final static int OK = 0; // operation succeeded + public final static int ALREADY_EXIST = 1; // failed route already exists + public final static int FAILED = -1; // failed operation + public final static int DIRECT_ROUTE = 2; // failed direct route + public final static int INVALID_ROUTE = 3; // invalid route + + /** + * Endpoint Router pointer + */ + private final EndpointRouter router; + + /** + * Router CM cache + */ + private final RouteCM routeCM; + + /** + * local Peer Id + */ + private final ID localPeerId; + + /** + * initialize RouteControl + * + * @param router the router + * @param pid the PeerID + */ + public RouteControl(EndpointRouter router, ID pid) { + this.router = router; + this.routeCM = router.getRouteCM(); + this.localPeerId = pid; + } + + /** + * get my local route + * + * @return RoutAdvertisement of the local route + */ + public RouteAdvertisement getMyLocalRoute() { + return router.getMyLocalRoute(); + } + + /** + * add a new route. For the route to be useful, we actively verify + * the route by trying it + * + * @param newRoute route to add + * @return Integer status (OK, FAILED, INVALID_ROUTE or ALREADY_EXIST) + */ + public int addRoute(RouteAdvertisement newRoute) { + + RouteAdvertisement route = newRoute.clone(); + + // check if the destination is not ourself + if (route.getDestPeerID().equals(localPeerId)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Skipping Local peer addRoute"); + } + return ALREADY_EXIST; + } + + AccessPointAdvertisement firstHop = route.getFirstHop(); + PeerID firstHopPid; + EndpointAddress firstHopAddr; + + // The route is not necessarily a direct route + if (firstHop != null) { + firstHopPid = firstHop.getPeerID(); + + // The first hop is ourselves. Remove it a move to the new first hop if any + if (localPeerId.equals(firstHopPid)) { + route.removeHop(firstHopPid); + firstHop = route.getFirstHop(); + } + } + + if (firstHop == null) { + // It really is a direct route. + EndpointAddress destAddress = EndpointRouter.pid2addr(route.getDestPeerID()); + + if (router.ensureLocalRoute(destAddress, route) != null) { + routeCM.publishRoute(newRoute); + return OK; + } + + if (router.isLocalRoute(destAddress) || router.isRoutedRoute(route.getDestPeerID())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Skipping add Route " + destAddress + " already exists"); + LOG.fine("isLocalRoute() " + router.isLocalRoute(destAddress) + " isRoutedRoute() : " + + router.isRoutedRoute(route.getDestPeerID())); + } + return ALREADY_EXIST; + } + + // ok go ahead try to connect to the destination using the route info + if (router.ensureLocalRoute(destAddress, route) == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to connect to address :" + destAddress); + } + return FAILED; + } + + // Use the original route for publication as we may later supply the advertisement to othe peers + // which may make good use of ourselves as a first and only hop. (Normally routes are discovered + // via route discovery, which automatically stiches routes to the respondant ahead of the + // discovered route. But a discovered route adv is sometimes used as well). + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Publishing route :" + newRoute); + } + routeCM.publishRoute(newRoute); + return OK; + } + + // we have a long route + + // Manufacture a RA just that as just the routerPeer as a destination. + // We only need to publish this route if we don't know about it yet. + + RouteAdvertisement firstHopRoute = null; + + firstHopPid = firstHop.getPeerID(); + firstHopAddr = EndpointRouter.pid2addr(firstHopPid); + + if (!router.isLocalRoute(firstHopAddr) && !router.isRoutedRoute(firstHopPid)) { + firstHopRoute = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + firstHopRoute.setDest(firstHop.clone()); + router.updateRouteAdv(firstHopRoute); + } + if (router.ensureLocalRoute(firstHopAddr, firstHopRoute) == null) { + // could not find a route to the first hop, discard the route + return FAILED; + } + + router.setRoute(route.clone(), false); + return OK; + } + + /** + * Get a current route info + * + * @param pId destination of the route + * @return RouteAdvertisement current route info + */ + public RouteAdvertisement getRouteInfo(PeerID pId) { + + RouteAdvertisement route; + EndpointRouter.ClearPendingQuery entry; + EndpointAddress addr = EndpointRouter.pid2addr(pId); + + // check if we have a direct route + Messenger oneOfThem = router.getCachedMessenger(addr); + EndpointAddress pcaddr = (oneOfThem == null) ? null : oneOfThem.getDestinationAddress(); + + if (pcaddr != null) { + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(pId); + Vector eas = new Vector(); + + eas.add(pcaddr.getProtocolName() + "://" + pcaddr.getProtocolAddress()); + ap.setEndpointAddresses(eas); + route = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + route.setDest(ap); + return route; + + } else { // check if we have a long route + route = router.getRoute(addr, false); + if (route != null) { + return route; + } else { // check if we have a pending query + entry = router.getPendingRouteQuery(pId); + if (entry != null) { // ok we have a pending query + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(pId); + Vector eas = new Vector(); + + eas.add("pending " + (entry.isFailed() ? "(failed)" : "(new)")); + ap.setEndpointAddresses(eas); + route = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + route.setDest(ap); + return route; + } else { // sorry no route found + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(pId); + route = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + route.setDest(ap); + return route; + } + } + } + } + + /** + * Delete route info + * + * @param pId destination route to be removed + * @return Integer status + */ + public int deleteRoute(PeerID pId) { + + // check if the route Id is not ourself + if (pId.equals(localPeerId)) { + return INVALID_ROUTE; + } + + EndpointAddress addr = EndpointRouter.pid2addr(pId); + + // FIXME tra 20030820 We are only allowing to remove long routes. + // Since direct routes can be used as the first hop for multiple + // valid routes, we don't want to close the associate messenger. At some + // point we should introduce a way to disassociate direct routes and + // their corresponding messengers, so we can have a generic table of routes + // and a separated table of messengers that can be manipulated + // independently. + + // Check if we have a direct route + if (router.isLocalRoute(addr)) { + return DIRECT_ROUTE; + } + + // remove routing table info + router.removeRoute(pId); + + // flush the CM. We need to flush the CM + // so the route will not be regenarated + routeCM.flushRoute(pId); + + return OK; + } + + /** + * get all the know routes by the router. Return a vector of all + * the routes known. + *

            + * This method which is meant for informational purposes, does not lock the maps that + * it browses. As a result, it could in some cases generate a concurrent modification + * exception. + * + * @return vector of known routes + */ + public Vector getAllRoutesInfo() { + + Vector routes = new Vector(); + EndpointAddress ea; + + try { + // get the direct routes + for (Iterator it = router.getAllCachedMessengerDestinations(); it.hasNext();) { + ea = (EndpointAddress) it.next(); + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(EndpointRouter.addr2pid(ea)); + Vector eas = new Vector(); + Messenger oneOfThem = router.getCachedMessenger(ea); + EndpointAddress pcaddr = (oneOfThem == null) ? null : oneOfThem.getDestinationAddress(); + + if (pcaddr == null) { // incomplete route + eas.add("unknown"); + } else { + eas.add(pcaddr.getProtocolName() + "://" + pcaddr.getProtocolAddress()); + } + ap.setEndpointAddresses(eas); + RouteAdvertisement r = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + r.setDest(ap); + routes.add(r); + } + + // now get the long routes + // Use entrySet, there's no point in doing redundant lookups + // in the map. + for (Iterator> i = router.getRoutedRouteAllDestinations(); i.hasNext();) { + Map.Entry entry = i.next(); + + routes.add(entry.getValue()); + } + + for (Map.Entry entry : router.getPendingQueriesAllDestinations()) { + PeerID pid = entry.getKey(); + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(pid); + Vector eas = new Vector(); + + eas.add("pending " + (entry.getValue().isFailed() ? "(failed)" : "(new)")); + ap.setEndpointAddresses(eas); + RouteAdvertisement r = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + r.setDest(ap); + routes.add(r); + } + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "getAllRoutesInfo error : ", ex); + } + } + return routes; + } + + /** + * get RouteCM usage + * + * @return true if use route CM is set + */ + public boolean useRouteCM() { + return router.getRouteCM().useRouteCM(); + } + + /** + * get RouteResolver usage + * + * @return true of use route resolver + */ + public boolean useRouteResolver() { + return router.getRouteResolver().useRouteResolver(); + } + + /** + * enable usage of Route CM cache + */ + public void enableRouteCM() { + router.getRouteCM().enableRouteCM(true); + } + + /** + * disable usage of Route CM cache + */ + public void disableRouteCM() { + router.getRouteCM().enableRouteCM(false); + } + + /** + * enable usage of Route Resolver + */ + public void enableRouteResolver() { + router.getRouteResolver().enableRouteResolver(true); + } + + /** + * disable usage of Route resolver + */ + public void disableRouteResolver() { + router.getRouteResolver().enableRouteResolver(false); + } + + /** + * Get the low level messenger for a destination. + * + * @param source the source endpoint address + * @param destination the destination endpoint address + * @param messenger the messenger to add + * @return true if successful + */ + public boolean addMessengerFor(Object source, EndpointAddress destination, Messenger messenger) { + return router.newMessenger(new MessengerEvent(source, messenger, destination)); + } + + /** + * Get the low level messenger for a destination. + * + * @param destination the destination endpoint address + * @param hint route hint + * @return the messenger for the destination + */ + public Messenger getMessengerFor(EndpointAddress destination, Object hint) { + if (!(hint instanceof RouteAdvertisement)) { + hint = null; + } + + return router.ensureLocalRoute(destination, (RouteAdvertisement) hint); + } + /** + * Determines whether a connection to a specific node exists, or if one can be created. + * This method can block to ensure a usable connection exists, it does so by sending an empty + * message. + * + * @param pid Node ID + * @return true, if a connection already exists, or a new was sucessfully created + */ + public boolean isConnected(PeerID pid) { + Messenger messenger = getMessengerFor(new EndpointAddress("jxta", pid.getUniqueValue().toString(), null, null), null); + if (messenger == null) { + return false; + } + if ((messenger.getState() & Messenger.USABLE) != 0) { + try { + //ensure it can be used + messenger.sendMessageB(new Message(), null, null); + } catch (IOException io) { + // determine whether it is usable + return (messenger.getState() & Messenger.USABLE) != 0; + } + } + return (messenger.getState() & Messenger.CLOSED) != Messenger.CLOSED; + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteResolver.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteResolver.java new file mode 100644 index 000000000..6f3cfd173 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouteResolver.java @@ -0,0 +1,1432 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.router; + +import net.jxta.credential.Credential; +import net.jxta.document.*; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.impl.cm.Srdi; +import net.jxta.impl.cm.Srdi.SrdiInterface; +import net.jxta.impl.cm.SrdiIndex; +import net.jxta.impl.protocol.*; +import net.jxta.impl.util.TimeUtils; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.*; +import net.jxta.resolver.QueryHandler; +import net.jxta.resolver.ResolverService; +import net.jxta.resolver.SrdiHandler; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Handles dynamic route resolution. + */ +class RouteResolver implements Module, QueryHandler, SrdiHandler, SrdiInterface { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RouteResolver.class.getName()); + + /** + * Router Service Name + */ + public final static String routerSName = "EndpointRouter"; + + private final static String srdiIndexerFileName = "routerSrdi"; + + /** + * Negative Route query acknowledgment + */ + private final static int NACKROUTE_QUERYID = -1; + + /** + * Bad route expiration. Amount of time we consider a route bad + */ + private final static long BADROUTE_EXPIRATION = 2L * TimeUtils.AMINUTE; + + /** + * Default dynamic route resolution configuration preference. + */ + private final static boolean USE_ROUTE_RESOLVER_DEFAULT = true; + + /** + * Configuration property that disables the usage + * of dynamic route resolution. Dynamic routes + * will not be discovered. set to true by default + * can be overwritten via ConfigParams + */ + private boolean useRouteResolver = USE_ROUTE_RESOLVER_DEFAULT; + + /** + * PeerGroup Service Handle + */ + private PeerGroup group = null; + + /** + * Resolver service handle + */ + private ResolverService resolver = null; + + /** + * membership service + */ + private MembershipService membership = null; + + /** + * EndpointRouter pointer + */ + private EndpointRouter router = null; + + /** + * local peer ID as a endpointAddress. + */ + private EndpointAddress localPeerAddr = null; + + /** + * local Peer ID + */ + private ID localPeerId = null; + + /** + * Route CM Persistent cache + */ + private RouteCM routeCM = null; + + /** + * The current resolver query ID. static to make debugging easier. + */ + private final static AtomicInteger qid = new AtomicInteger(0); + + /** + * SRDI route index + */ + private SrdiIndex srdiIndex = null; + + /** + * SRDI Index + */ + private Srdi srdi = null; + + /** + * Encapsulates current Membership Service credential. + */ + final static class CurrentCredential { + + /** + * The current default credential + */ + final Credential credential; + + /** + * The current default credential in serialized XML form. + */ + final XMLDocument credentialDoc; + + CurrentCredential(Credential credential, XMLDocument credentialDoc) { + this.credential = credential; + this.credentialDoc = credentialDoc; + } + } + + /** + * The current Membership service default credential. + */ + CurrentCredential currentCredential; + + /** + * Listener we use for membership property events. + */ + private class CredentialListener implements PropertyChangeListener { + + /** + * Standard Constructor + */ + CredentialListener() {} + + /** + * {@inheritDoc} + */ + public void propertyChange(PropertyChangeEvent evt) { + if (MembershipService.DEFAULT_CREDENTIAL_PROPERTY.equals(evt.getPropertyName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New default credential event"); + } + + synchronized (RouteResolver.this) { + Credential cred = (Credential) evt.getNewValue(); + XMLDocument credentialDoc; + if (null != cred) { + try { + credentialDoc = (XMLDocument) cred.getDocument(MimeMediaType.XMLUTF8); + currentCredential = new CurrentCredential(cred, credentialDoc); + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not generate credential document", all); + } + currentCredential = null; + } + } else { + currentCredential = null; + } + } + } + } + } + + final CredentialListener membershipCredListener = new CredentialListener(); + + /** + * @param router the router + */ + RouteResolver(EndpointRouter router) { + this.router = router; + } + + /** + * initialize routeResolver + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) impl; + + // extract Router service configuration properties + ConfigParams confAdv = group.getConfigAdvertisement(); + XMLElement paramBlock = null; + + if (confAdv != null) { + paramBlock = (XMLElement) confAdv.getServiceParam(assignedID); + } + + if (paramBlock != null) { + // get our tunable router parameter + Enumeration param; + + param = paramBlock.getChildren("useRouteResolver"); + if (param.hasMoreElements()) { + useRouteResolver = Boolean.getBoolean(((XMLElement) param.nextElement()).getTextValue()); + } + } + + this.group = group; + + localPeerId = group.getPeerID(); + + localPeerAddr = EndpointRouter.pid2addr(group.getPeerID()); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Router Transport Resolver : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration:"); + configInfo.append("\n\t\tUse Route Resolver : ").append(useRouteResolver()); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + + resolver = group.getResolverService(); + + if (null == resolver) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Endpoint Router start stalled until resolver service available"); + } + return Module.START_AGAIN_STALLED; + } + + membership = group.getMembershipService(); + + if (null == membership) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Endpoint Router start stalled until membership service available"); + } + return Module.START_AGAIN_STALLED; + } + + resolver.registerHandler(routerSName, this); + // create and register the srdi service + srdiIndex = new SrdiIndex(group, srdiIndexerFileName); + // Srdi is a thread but we are not going to start, + // since the service is reactive. + srdi = new Srdi(group, routerSName, this, srdiIndex, 0, 0); + resolver.registerSrdiHandler(routerSName, this); + + synchronized (this) { + // register our credential listener. + membership.addPropertyChangeListener(MembershipService.DEFAULT_CREDENTIAL_PROPERTY, membershipCredListener); + + try { + // set the initial version of the default credential. + currentCredential = null; + Credential credential = membership.getDefaultCredential(); + XMLDocument credentialDoc; + + if (null != credential) { + credentialDoc = (XMLDocument) credential.getDocument(MimeMediaType.XMLUTF8); + currentCredential = new CurrentCredential(credential, credentialDoc); + } + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not get default credential", all); + } + } + } + + // get the RouteCM cache service + routeCM = router.getRouteCM(); + + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

            + * Careful that stopApp() could in theory be called before startApp(). + */ + public void stopApp() { + + resolver.unregisterHandler(routerSName); + + // unregister SRDI + resolver.unregisterSrdiHandler(routerSName); + srdiIndex.stop(); + + membership.removePropertyChangeListener("defaultCredential", membershipCredListener); + currentCredential = null; + + resolver = null; + srdi = null; + membership = null; + } + + /** + * return routeResolver usage + * + * @return routeResolver usage + */ + boolean useRouteResolver() { + return useRouteResolver; + } + + /** + * enable routeResolver usage + * @param enable if true, enables route resolver + */ + void enableRouteResolver(boolean enable) { + useRouteResolver = enable; + } + + /** + * issue a new route discovery resolver request + * + * @param peer the destination as a logical endpoint address + */ + protected void findRoute(EndpointAddress peer) { + + RouteAdvertisement myRoute = router.getMyLocalRoute(); + + // No need to pursue further if we haven't initialized our own route as + // responding peers are not going to be able to respond to us. + if (myRoute == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Cannot issue a find route if we don\'t know our own route"); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Find route for peer = " + peer); + } + + try { + // create a new RouteQuery message + RouteQuery doc; + + // check if we have some bad route information + // for that peer, in that case pass the bad hop count + BadRoute badRoute; + + badRoute = router.getBadRoute(peer); + + if (badRoute != null) { + // ok we have a bad route + // pass the bad hops info as part of the query + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("findRoute sends query: known bad Hops" + badRoute); + } + doc = new RouteQuery(EndpointRouter.addr2pid(peer), myRoute, badRoute.getBadHops()); + } else { + doc = new RouteQuery(EndpointRouter.addr2pid(peer), myRoute, null); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending query for peer : " + peer); + } + + XMLDocument credentialDoc; + CurrentCredential current = currentCredential; + + if (null != current) { + credentialDoc = current.credentialDoc; + } else { + credentialDoc = null; + } + + ResolverQuery query = new ResolverQuery(routerSName, credentialDoc, localPeerId.toString(), doc.toString(), qid.incrementAndGet()); + + // only run SRDI if we are a rendezvous + // FIXME 20060106 bondolo This is not dynamic enough. The route + // resolver needs to respond to changes in rendezvous configuration + // at runtime. + if (group.isRendezvous()) { + + // check where to send the query via SRDI + List results; + + if (srdiIndex != null) { + // try to find a least 10 entries, will pick up one + // randomly. This will protect against retry. It is + // likely that a number of RDV will know about a route + results = srdiIndex.query("route", RouteAdvertisement.DEST_PID_TAG, EndpointRouter.addr2pid(peer).toString(), 10); + + if (results != null && !results.isEmpty()) { + // use SRDI to send the query + // remove any non rdv peers from the candidate list + // and garbage collect the index in the process + List clean = cleanupAnyEdges(query.getSrcPeer(), results); + + if (!clean.isEmpty()) { + // The purpose of incrementing the hopcount + // when an SRDI index match is found (we got a + // pointer to a rdv that should have the route) is to + // restrict any further forwarding. The increment + // count is only done when a matching SRDI index is + // found. Not when the replica is selected as we + // still need to forward the query. This restriction + // is purposelly done to avoid too many longjumps + // within a walk. + query.incrementHopCount(); + + srdi.forwardQuery(clean, query, 1); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("found an srdi entry forwarding query to SRDI peer"); + } + return; + } + } else { + // it is not in our cache, look for the replica peer + // we need to send the query + PeerID destPeer = srdi.getReplicaPeer(EndpointRouter.addr2pid(peer).toString()); + + if (destPeer != null && !destPeer.equals(localPeerId)) { + // don't push anywhere if we do not have a replica + // or we are trying to push to ourself + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processQuery srdiIndex DHT forward :" + destPeer); + } + + srdi.forwardQuery(destPeer, query); + return; + } else { + LOG.fine("processQuery srdiIndex DHT forward resulted in no op"); + } + } + } + } + + // if we reach that point then we just use the resolver walk + resolver = group.getResolverService(); + if (resolver != null) { + resolver.sendQuery(null, query); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("find route query sent"); + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("cannot get the resolver service"); + } + } + } catch (Exception ee) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception in findRoute", ee); + } + } + } + + /** + * {@inheritDoc} + *

            + * This is called by the Generic ResolverServiceImpl when processing a + * response to a query. + */ + public void processResponse(ResolverResponseMsg response) { + + if (!useRouteResolver) { // Route resolver disabled + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processResponse got a response"); + } + + // convert the response into a RouteResponse + RouteResponse doc = null; + + try { + Reader ip = new StringReader(response.getResponse()); + + XMLDocument asDoc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, ip); + + doc = new RouteResponse(asDoc); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "malformed response - discard", e); + } + return; + } + + RouteAdvertisement dstRoute = doc.getDestRoute(); + RouteAdvertisement srcRoute = doc.getSrcRoute(); + int queryId = response.getQueryId(); + + EndpointAddress routingPeer = EndpointRouter.pid2addr(srcRoute.getDestPeerID()); + EndpointAddress destPeer = EndpointRouter.pid2addr(dstRoute.getDestPeerID()); + + // check if we have a negative route response + if (queryId == NACKROUTE_QUERYID) { + AccessPointAdvertisement badHop = dstRoute.nextHop(EndpointRouter.addr2pid(routingPeer)); + + PeerID badPeer; + + if (badHop != null) { + badPeer = badHop.getPeerID(); + } else { // the bad hop is the final destination + badPeer = dstRoute.getDestPeerID(); + } + + processBadRoute(badPeer, dstRoute); + return; + } + + // This is not our own peer adv, so we must not keep it + // for more than its expiration time. + // we only need to publish this route if + // we don't know about it yet + // XXX: here is where we could be more conservative and use isNormallyReachable() instead, thus excluding + // incoming messengers. + if ((!router.isLocalRoute(EndpointRouter.pid2addr(srcRoute.getDestPeerID()))) + && (!router.isRoutedRoute(srcRoute.getDestPeerID()))) { + router.updateRouteAdv(srcRoute); + } + + if (destPeer.equals(routingPeer)) { + // The dest peer itself managed to respond to us. That means we + // learned the route from the reverseRoute in the message + // itself. So, there's nothing we need to do. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("learn route directly from the destination"); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("learn route:" + routingPeer); + } + + try { + // build the candidate route using the + // route response from the respondant peer + RouteAdvertisement candidateRoute = RouteAdvertisement.newRoute(EndpointRouter.addr2pid(destPeer), + EndpointRouter.addr2pid(routingPeer),(Vector) dstRoute.getVectorHops().clone()); + + // cleanup the candidate route from any loop and remove the local peer extra + // cycle + RouteAdvertisement.cleanupLoop(candidateRoute, (PeerID) localPeerId); + + // Is there anything left in that route (or did the respondant + // believe that we are the last hop on the route - which + // obviously we are not. + if (candidateRoute.size() == 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Route response outdated: NACK responder"); + } + generateNACKRoute(EndpointRouter.addr2pid(routingPeer), EndpointRouter.addr2pid(destPeer), dstRoute.getVectorHops()); + return; + } + + // get the address of the first hop in the route to verify that + // we have a route (direct or long) to the first hop, so the route + // is valid + EndpointAddress candidateRouter = EndpointRouter.pid2addr(candidateRoute.getFirstHop().getPeerID()); + + // check that we have a direct connection to the first hop + if (router.ensureLocalRoute(candidateRouter, null) == null) { + // If we do not have a direct route to the candidate router check + // for a long route in that case stich the route + RouteAdvertisement routeToRouter = router.getRoute(candidateRouter, false); + + if (routeToRouter == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Route response useless: no route to next router hop"); + } + return; + } + + // stich the route removing any loops and localPeer cycle + if (RouteAdvertisement.stichRoute(candidateRoute, routeToRouter, (PeerID) localPeerId)) { + router.setRoute(candidateRoute, false); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Route response error stiching route response"); + } + return; + } + } else { + // we have a direct connection with the first hop of the candidate route + // set the new route, which starts with the peer that replied to us. + router.setRoute(candidateRoute, false); + } + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure building response route", ex); + LOG.warning(" bad dstRoute: " + dstRoute.display()); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("finish process route response successfully"); + } + } + } + + /** + * bad route, so let's remove everything we have so + * we can start from scratch. We are maintaining a + * bad route up to DEFAULT_ROUTE expiration after + * that we consider it to be ok to retry the same route + * We are removing both the route and peer advertisement + * to force a new route query + * + * @param badHop source PeerID of NACK route info + * @param dest original route information + */ + private void processBadRoute(PeerID badHop, RouteAdvertisement dest) { + + EndpointAddress addr = EndpointRouter.pid2addr(dest.getDestPeerID()); + + if (addr == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("remove bad route has a bad route info - discard"); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("remove bad route info for dest " + dest.display()); + if (badHop != null) { + LOG.fine("remove bad route bad hop " + badHop); + } + } + + try { + + // check first that we still have the same route, we may already + // using a new route + RouteAdvertisement currentRoute = router.getRoute(addr, false); + + if (currentRoute == null) { // we already cleanup the route info + return; + } + + // check if we still have the old bad route, we may have + // already updated the route + if (!currentRoute.equals(dest)) { + + // check if the bad hop is not the destination + // if it is then we still have a bad route + if (badHop == null) { + // we could get the bad hop, so consider the route ok + return; + } + if (badHop.equals(EndpointRouter.addr2pid(addr))) { + // check if the new route may still contain the bad hop + // the known bad hop is the hop after the src peer that + // responded with a NACK route + // In this case we also consider the route bad + if (!currentRoute.containsHop(badHop)) { + return; // we are ok + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("current route is bad because it contains known bad hop" + badHop); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("current route is bad because it contains known bad destination" + badHop); + } + } + + } + + // keep the bad one in a cache table so we don't retry them + // right away. We use the default route timeout + BadRoute badRoute = (router.getBadRoute(addr)); + + if (badRoute != null) { + if (badRoute.getExpiration() > TimeUtils.timeNow()) {// nothing to do. the information is still valid + } else { + // It is ancient knowlege update it + badRoute.setExpiration(TimeUtils.toAbsoluteTimeMillis(BADROUTE_EXPIRATION)); + } + + // check if we have to add a new bad hop + // to our bad route + if (badHop != null) { + badRoute.addBadHop(badHop); + badRoute.setExpiration(TimeUtils.toAbsoluteTimeMillis(BADROUTE_EXPIRATION)); + } + + router.setBadRoute(addr, badRoute); + return; + } else { + // create a new NACK route entry + Set badHops; + + if (badHop != null) { + badHops = Collections.singleton(badHop); + } else { + badHops = Collections.emptySet(); + } + + badRoute = new BadRoute(dest, TimeUtils.toAbsoluteTimeMillis(BADROUTE_EXPIRATION), badHops); + router.setBadRoute(addr, badRoute); + } + + // remove route from route CM + routeCM.flushRoute(EndpointRouter.addr2pid(addr)); + + // let's remove the remote route info from the routing table + // we do this after we removed the entries from the CM + // to avoid that another thread is putting back the entry + router.removeRoute(EndpointRouter.addr2pid(addr)); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "exception during bad route removal", ex); + } + } + } + + /** + * Process the Query, and generate response + * + * @param query the query to process + */ + public int processQuery(ResolverQueryMsg query) { + + if (!useRouteResolver) { // Route resolver disabled + return ResolverService.OK; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processQuery starts"); + } + + RouteQuery routeQuery; + try { + Reader ip = new StringReader(query.getQuery()); + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, ip); + routeQuery = new RouteQuery(asDoc); + } catch (RuntimeException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Malformed Route query ", e); + } + return ResolverService.OK; + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Malformed Route query ", e); + } + return ResolverService.OK; + } + + PeerID pId = routeQuery.getDestPeerID(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Looking for route to " + pId); + } + + RouteAdvertisement srcRoute = routeQuery.getSrcRoute(); + Collection badHops = routeQuery.getBadHops(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + StringBuilder badHopsDump = new StringBuilder("bad Hops :\n"); + + for (ID aBadHop : badHops) { + badHopsDump.append('\t').append(aBadHop); + } + + LOG.finer(badHopsDump.toString()); + } + + // if our source route is not null, then publish it + if (srcRoute != null) { + if (!(srcRoute.getDestPeerID()).equals(localPeerId)) { + // This is not our own peer adv so we must not keep it + // longer than its expiration time. + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Publishing sender route info " + srcRoute.getDestPeerID()); + } + + // we only need to publish this route if + // we don't know about it yet + // XXX: here is where we could be more conservative and use isNormallyReachable() instead, thus excluding + // incoming messengers. + if ((!router.isLocalRoute(EndpointRouter.pid2addr(srcRoute.getDestPeerID()))) + && (!router.isRoutedRoute(srcRoute.getDestPeerID()))) { + routeCM.publishRoute(srcRoute); + } + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not publish Route Adv from query - discard", e); + } + return ResolverService.OK; + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No src Route in route query - discard "); + } + return ResolverService.OK; + } + + if (pId == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Malformed route query request, no PeerId - discard"); + } + return ResolverService.OK; + } + + // We have more luck with that one because, since it is part of OUR + // message, and not part of the resolver protocol, it is in OUR + // format. + EndpointAddress qReqAddr = EndpointRouter.pid2addr(pId); + + RouteAdvertisement route; + + // check if this peer has a route to the destination + // requested + boolean found = false; + + if (qReqAddr.equals(localPeerAddr)) { + found = true; + // return the route that is my local route + route = router.getMyLocalRoute(); + } else { + // only rendezvous can respond to route requests + // if not we are generating too much traffic + // XXX: here is where we could be more conservative and use isNormallyReachable() instead, thus excluding + // incoming messengers. + if (router.isLocalRoute(qReqAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Peer has direct route to destination "); + } + // we should set the route to something :-) + + found = true; + + // this peer has a direct route to the destination + // return the short route advertisement we know for this peer + // (For us it is zero hop, and we advertise ourself as the routing + // peer in the response. The stiching is done by whoever gets that + // response). May be there are more than one hop advertised in-there... + // alternate routing peers...should we leave them ? + // For now, we keep the full dest, but wack the hops. + + route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(pId); + route.setDest(ap); + } else { + route = router.getRoute(qReqAddr, false); + if (route != null) { + found = true; + // check if we were given some bad hops info + // and see if the found route contains + // any of these bad hops. In that case, we need + // to mark this route as bad + for (PeerID aBadHop : badHops) { + // destination is known to be bad + if (EndpointRouter.addr2pid(qReqAddr).equals(aBadHop)) { + processBadRoute(aBadHop, route); + found = false; + break; + } + + if (route.containsHop(aBadHop)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Peer has bad route due to " + aBadHop); + } + processBadRoute(aBadHop, route); + found = false; + break; + } + } + } + } + } + + if (!found) { + // discard the request if we are not a rendezvous + // else forward to the next peers + if (!group.isRendezvous()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("discard query forwarding as not a rendezvous"); + } + return ResolverService.OK; + } + + // did not find a route, check our srdi cache + // make sure we protect against out of sync + // SRDI index + + // srdi forwarding is only involved once the Index entry has + // been found and we forwarded the resolver query. Afterward a + // normal walk proceeds from the initial SRDI index pointing + // rdv. This is done to protect against potential loopback + // entries in the SRDI cache index due to out of sync peerview + // and index. + if (query.getHopCount() < 2) { + + // check local SRDI cache to see if we have the entry + // we look for 10 entries, will pickup one randomly + List results = srdiIndex.query("route", RouteAdvertisement.DEST_PID_TAG, pId.toString(), 10); + + if (results.size() > 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processQuery srdiIndex lookup match :" + results.size()); + } + + // remove any non-rdv peers to avoid sending + // to a non-rdv peers and garbage collect the SRDI + // index in the process + List clean = cleanupAnyEdges(query.getSrcPeer(), results); + + if (clean.size() > 0) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("found an srdi entry forwarding query to SRDI peer"); + } + + // The purpose of incrementing the hopcount + // when an SRDI index match is found (we got a + // pointer to a rdv that should have the route) is to + // restrict any further forwarding. The increment + // count is only done when a matching SRDI index is + // found. Not when the replica is selected as we + // still need to forward the query. This restriction + // is purposelly done to avoid too many longjumps + // within a walk. + query.incrementHopCount(); + + // Note: this forwards the query to 1 peer randomly + // selected from the result + srdi.forwardQuery(clean, query, 1); + + // tell the resolver no further action is needed. + return ResolverService.OK; + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("did not find a route or SRDI index"); + } + + // force a walk + return ResolverService.Repropagate; + } + + // we found a route send the response + try { + if (route == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("we should have had a route at this point"); + } + return ResolverService.OK; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("we have a route build route response" + route.display()); + } + + RouteAdvertisement myRoute = router.getMyLocalRoute(); + + // make sure we initialized our local + // route info as we will need it to respond. We may + // not have our route if we are still + // waiting for a relay connection. + if (myRoute == null) { + return ResolverService.OK; + } + + RouteResponse routeResponse = new RouteResponse(); + + routeResponse.setDestRoute(route); + routeResponse.setSrcRoute(myRoute); + + if (routeResponse == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("error creating route response"); + } + return ResolverService.OK; + } + + // construct a response from the query + ResolverResponseMsg res = query.makeResponse(); + + CurrentCredential current = currentCredential; + + if (null != current) { + res.setCredential(current.credentialDoc); + } + res.setResponse(routeResponse.toString()); + + resolver.sendResponse(query.getSrcPeer().toString(), res); + return ResolverService.OK; + + } catch (Exception ee) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "processQuery: error while processing query ", ee); + } + return ResolverService.OK; + } + } + + /** + * Return a route error in case a route was found to be invalid + * as the current hop cannot find a way to forward the message to the + * destination or any other hops in the forward part of the route. + * In that case a negative route response is forwarded + * to the original source of the message. Now of course we + * do not have any way to guarantee that the NACK message will be + * received by the sender, but the best we can do is to try :-) + *

            + * we send a query ID to NACKROUTE_QUERYID to indicate + * this is a bad Route + * + * @param src original source of the message + * @param dest original destination of the message + * @param origHops original hops + */ + protected void generateNACKRoute(PeerID src, PeerID dest, Vector origHops) { + + // As long as the group is partially initialized, do not bother + // trying to send NACKS. We can't: it just causes NPEs. + if (resolver == null) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("generate NACK Route response " + src); + } + + // check first, if we are not already in process of looking for a + // route to the destination peer of the NACK. We should not try to + // send a NACK to that destination at that point as this will block + // our incoming processing thread while it is looking for a route to + // that destination. If there a no pending route requests to that + // destination then we can go ahead an attempt to send the NACK. At + // the maximum we should have only one thread block while looking for + // a specific destination. When we find a route to the destination, + // the next NACK processing will be sent. + + if (router.isPendingRouteQuery(src)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("drop NACK due to pending route discovery " + src); + } + return; + } + + // Generate a route response + RouteAdvertisement route = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + AccessPointAdvertisement ap = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ap.setPeerID(dest); + route.setDest(ap); + route.setHops(origHops); + + // set the the route of the peer that + // detected the bad route + RouteAdvertisement routeSrc = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + + AccessPointAdvertisement apSrc = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + apSrc.setPeerID((PeerID) localPeerId); + routeSrc.setDest(apSrc); + + RouteResponse routeResponse = new RouteResponse(); + + routeResponse.setDestRoute(route); + routeResponse.setSrcRoute(routeSrc); + + ResolverResponse res = new ResolverResponse(); + + res.setHandlerName(routerSName); + + CurrentCredential current = currentCredential; + + if (null != current) { + res.setCredential(current.credentialDoc); + } + + res.setQueryId(NACKROUTE_QUERYID); + res.setResponse(routeResponse.toString()); + + // send the NACK response back to the originator + resolver.sendResponse(src.toString(), res); + } + + /** + * process an SRDI message request + * + * @param message SRDI resolver message + */ + public boolean processSrdi(ResolverSrdiMsg message) { + if(!group.isRendezvous()) { + return true; + } + + String value; + SrdiMessage srdiMsg; + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received a SRDI messsage in group" + group.getPeerGroupName()); + } + + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(message.getPayload())); + srdiMsg = new SrdiMessageImpl(asDoc); + } catch (Exception e) { + // we don't understand this msg, let's skip it + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "corrupted SRDI message", e); + } + return false; + } + + PeerID pid = srdiMsg.getPeerID(); + + // filter messages that contain messages + // about the local peer, so we don't enter + // self-reference + if (pid.equals(localPeerId)) { + return false; + } + + for (SrdiMessage.Entry entry : srdiMsg.getEntries()) { + // drop any information about ourself + if (entry.key.equals(localPeerId.toString())) { + continue; + } + value = entry.value; + if (value == null) { + value = ""; + } + + // Expiration of entries is taken care of by SrdiIdex, so we always add + // FIXME hamada 20030314 + // All routes are added under the secondary key 'DstPID', it would be more correct to + // Specify it in the message, but since versioning is not yet supported the following is + // acceptable, since it is localized + srdiIndex.add(srdiMsg.getPrimaryKey(), RouteAdvertisement.DEST_PID_TAG, entry.key, pid, entry.expiration); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Primary Key [" + srdiMsg.getPrimaryKey() + "] key [RouteAdvertisement.DEST_PID_TAG]" + " value [" + entry.key + "] exp [" + entry.expiration + "]"); + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + public void pushEntries(boolean all) { + // only send to the replica + pushSrdi(null, all); + } + + /* + * push all srdi entries to the rednezvous SRDI cache (new connection) + * + *@param all if true push all entries, otherwise just deltas + */ + protected void pushSrdi(String peer, boolean all) { + + SrdiMessage srdiMsg; + Vector routeIx = new Vector(); + + // 20021018 tra:Route info don't expire unless the peer disappears + // This approach is used to limit the SRDI traffic. The key + // point here is that SRDI is used to tell a peer that another + // has a route to the destination it is looking for. The information + // that SRDI cache is not so much the specific route info but rather + // the fact that a peer has knowledge of a route to another peer + // We don't want to update the SRDI cache on every route update. + // The SRDI cache will be flushed when the peer disconnect from + // the rendezvous. + + // We cannot support concurrent modification of the map while we + // do that: we must synchronize... + for (Iterator each = router.getAllRoutedRouteAddresses(); each.hasNext();) { + ID pid = each.next(); + SrdiMessage.Entry entry = new SrdiMessage.Entry(pid.toString(), "", Long.MAX_VALUE); + routeIx.addElement(entry); + } + + try { + // check if we have anything to send + if (routeIx.size() == 0) { + return; + } + + srdiMsg = new SrdiMessageImpl(group.getPeerID(), + // one hop + 1, + "route", routeIx); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a SRDI messsage of [All=" + all + "] routes"); + } + // this will replicate entry to the SRDI replica peers + srdi.replicateEntries(srdiMsg); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "SRDI Push failed", e); + } + } + } + + /* + * push srdi entries to the SRDI rendezvous cache + * @param all if true push all entries, otherwise just deltas + */ + protected void pushSrdi(ID peer, PeerID id) { + + SrdiMessage srdiMsg; + + try { + srdiMsg = new SrdiMessageImpl(group.getPeerID(), 1, // only one hop + "route", id.toString(), null, Long.MAX_VALUE); // maximum expiration + // 20021018 tra:Route info don't expire unless the peer disappears + // This approach is used to limit the SRDI traffic. The key + // point here is that SRDI is used to tell a peer that another + // has a route to the destination it is looking for. The information + // that SRDI cache is not so much the specific route info but rather + // the fact that a peer has knowledge of a route to another peer + // We don't want to update the SRDI cache on every route update. + // The SRDI cache will be flushed when the peer disconnect from + // the rendezvous. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("sending a router SRDI message add route " + id); + } + if (peer == null) { + PeerID destPeer = srdi.getReplicaPeer(id.toString()); + peer = destPeer; + } + // don't push anywhere if we do not have a replica + // or we are trying to send the query to ourself + if (!localPeerId.equals(peer)) { + srdi.pushSrdi(peer, srdiMsg); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "SRDI push failed", e); + } + } + } + + /** + * remove a SRDI cache entry + * + * @param peer peer id we send the request, null for sending to all + * @param id peer id of the SRDI route that we want to remove + * from the cache + */ + protected void removeSrdi(String peer, PeerID id) { + + SrdiMessage srdiMsg; + + try { + srdiMsg = new SrdiMessageImpl(group.getPeerID(), 1, // only one hop + "route", id.toString(), null, // 0 means remove + 0); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("sending a router SRDI message delete route " + id); + } + + if (peer == null) { + PeerID destPeer = srdi.getReplicaPeer(id.toString()); + + // don't push anywhere if we do not have replica + // or we are trying to push to ouself + if (destPeer != null && (!destPeer.equals(localPeerId))) { + srdi.pushSrdi(destPeer, srdiMsg); + } + } + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Removing srdi entry failed", e); + } + } + } + + /** + * {@inheritDoc} + */ + public void messageSendFailed(PeerID peerid, OutgoingMessageEvent e) { + // when the resolver failed to send, we get a notification and + // flush the SRDI cache entries for that destination + removeSrdiIndex(peerid); + } + + /** + * cleanup any edge peers when trying to forward an SRDI query so we are + * guaranteed to the best of our knowledge that the peer is a rendezvous. + * This is not perfect, as it may take time for the peerview to converge but + * at least we can remove any peers that is not a rendezvous. + * + * @param src source + * @param results vector of PeerIDs + * @return cleaned up vector of PeerIDs + */ + protected List cleanupAnyEdges(ID src, List results) { + List clean = new ArrayList(results.size()); + + // put the peerview as a vector of PIDs + List rpvId = srdi.getGlobalPeerView(); + + // remove any peers not in the current peerview + // these peers may be gone or have become edges + for (PeerID pid : results) { + // eliminate the src of the query so we don't resend + // the query to whom send it to us + if (src.equals(pid)) { + continue; + } + // remove the local also, so we don't send to ourself + if (localPeerId.equals(pid)) { + continue; + } + if (rpvId.contains(pid)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("valid rdv for SRDI forward " + pid); + } + clean.add(pid); + } else { + // cleanup our SRDI cache for that peer + srdiIndex.remove(pid); + } + } + return clean; + } + + /** + * remove SRDI index + * + * @param pid of the index to be removed + */ + protected void removeSrdiIndex(PeerID pid) { + srdiIndex.remove(pid); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouterMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouterMessenger.java new file mode 100644 index 000000000..7b9245f58 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/RouterMessenger.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.router; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.impl.endpoint.BlockingMessenger; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import net.jxta.protocol.RouteAdvertisement; + + +/** + * Messenger for destinations which are logical peers. This messenger is used + * only at the origin of routes. Incoming messages that are being forwarded to + * another peer do not use this form of messenger. + */ +class RouterMessenger extends BlockingMessenger { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RouterMessenger.class.getName()); + + /** + * The router we are working for. Also who we make route queries to. + */ + private final EndpointRouter router; + + /** + * Constructor for a RouterMessenger. + * + * @param dstAddress the peer which is the final destination of the message. + * @param r the router which this messenger is servicing. + * @param hint potential hint information that we passed + * @throws IOException Thrown if the messenger cannot be constructed for this destination. + */ + public RouterMessenger(EndpointAddress dstAddress, EndpointRouter r, Object hint) throws IOException { + + // Make sure that we do not ask for self destruction. + super(r.getEndpointService().getGroup().getPeerGroupID(), dstAddress, false); + + this.router = r; + + // Probably redundant. getGatewayAddress does it. + EndpointAddress plainAddr = new EndpointAddress(dstAddress, null, null); + + // Discard the hint if it is not a route advertisement. + if (!(hint instanceof RouteAdvertisement)) { + hint = null; + } + + // We aggressively look for a route upfront. If it fails, we must refuse to create the messenger. + EndpointAddress gate = router.getGatewayAddress(plainAddr, true, (RouteAdvertisement) hint); + + if (gate == null) { + throw new IOException("Could not construct RouterMessenger, no route for " + plainAddr); + } + } + + /** + * {@inheritDoc} + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + return getDestinationAddress(); + } + + /** + * {@inheritDoc} + */ + @Override + public void closeImpl() {// Nothing to do. The underlying connection is not affected. + // The messenger will be marked closed by the state machine once completely down; that's it. + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdleImpl() { + // We do not need self destruction. + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void sendMessageBImpl(Message message, String service, String serviceParam) throws IOException { + + if (isClosed()) { + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failure.getMessage(), failure); + } + + throw failure; + } + + EndpointAddress dest = getDestAddressToUse(service, serviceParam); + + // Loop trying to send message until we run out of routes. + Throwable lastFailure = null; + + while (true) { + EndpointAddress sendTo = null; + + try { + sendTo = router.addressMessage(message, dest); + if (null == sendTo) { + break; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + message + " to " + sendTo); + } + + router.sendOnLocalRoute(sendTo, message); + + // it worked! We are done. + return; + } catch (RuntimeException rte) { + // Either the message is invalid, or there is + // a transport loop and the upper layer should close. + // Either way, we must not retry. The loop could be + // unbounded. + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure while routing " + message, rte); + } + + lastFailure = rte; + break; + } catch (Throwable theMatter) { + if (sendTo == null) { + // This is bad: address message was not able to + // do anything. Stop the loop. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unknown failure while routing " + message, theMatter); + } + break; + } + + // Everything else is treated like a bad route. + lastFailure = theMatter; + } + + // Currently we have only one long route per destination. + // If the first hop is broken, then that long route is broken + // as well. We must dump it, under penalty of trying it over and over again. + + EndpointAddress destPeer = new EndpointAddress(getDestinationAddress(), null, null); + + router.removeRoute(EndpointRouter.addr2pid(destPeer)); + + // reset the router message for the next attempt. + message.removeMessageElement(message.getMessageElement(EndpointRouterMessage.MESSAGE_NS, EndpointRouterMessage.MESSAGE_NAME)); + } + + if (lastFailure == null) { + lastFailure = new IOException("Could not find a route for : " + dest); + } + + // Except if we hit an illegal transport loop, we've exhausted all + // the options we had, or there was a RuntimeException. + // In both cases we must close. In the latter case it is a + // precaution: we're not 100% sure that the message is at fault; + // it could be this messenger as well. For illegal transport loops + // the invoking messenger should close, not this one. + + if (!(lastFailure instanceof IllegalStateException)) { + // FIXME - jice@jxta.org 20040413: as for all the transports. This used to be how this messenger broke itself. Now, + // all it does is too pretend that someone called for a nice close...just before the exception we throw causes the + // BlockingMessenger state machine to go into breackage mode. Ultimately transports should get a deeper retrofit. + close(); + } + + // Kind of stupid. Have to convert the runtime exceptions so that we + // can re-throw them. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Messenger failed:", lastFailure); + } + + if (lastFailure instanceof IOException) { + throw (IOException) lastFailure; + } else if (lastFailure instanceof RuntimeException) { + throw (RuntimeException) lastFailure; + } else if (lastFailure instanceof Error) { + throw (Error) lastFailure; + } else { + IOException failure = new IOException("Failed sending " + message); + failure.initCause(lastFailure); + throw failure; + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/package.html new file mode 100644 index 000000000..a20925afd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/router/package.html @@ -0,0 +1,19 @@ + + + + + + +A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which +simply translates addresses in messages from peer ids to physical Endpoint +Addresses. + +@see net.jxta.endpoint.EndpointService +@see net.jxta.endpoint.MessageTransport +@see net.jxta.endpoint.MessageSender +@see net.jxta.endpoint.MessageReceiver +@see net.jxta.endpoint.Message +@see JXTA Protocols + Specification : Standard JXTA Transport Bindings + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpClientMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpClientMessenger.java new file mode 100644 index 000000000..62dba7060 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpClientMessenger.java @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.servlethttp; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.SocketTimeoutException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; + +import net.jxta.impl.endpoint.BlockingMessenger; +import net.jxta.impl.endpoint.EndpointServiceImpl; +import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings; +import net.jxta.impl.util.TimeUtils; + +/** + * Simple messenger that simply posts a message to a URL. + * + *

            URL/HttpURLConnection is used, so (depending on your JDK) you will get + * reasonably good persistent connection management. + */ +final class HttpClientMessenger extends BlockingMessenger { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(HttpClientMessenger.class.getName()); + + /** + * Minimum amount of time between poll + */ + private final static int MIMIMUM_POLL_INTERVAL = (int) (5 * TimeUtils.ASECOND); + + /** + * Amount of time to wait for connections to open. + */ + private final static int CONNECT_TIMEOUT = (int) (15 * TimeUtils.ASECOND); + + /** + * Amount of time we are willing to wait for responses. This is the amount + * of time between our finishing sending a message or beginning a poll and + * the beginning of receipt of a response. + */ + private final static int RESPONSE_TIMEOUT = (int) (2 * TimeUtils.AMINUTE); + + /** + * Amount of time we are willing to accept for additional responses. This + * is the total amount of time we are willing to wait after receiving an + * initial response message whether additional responses are sent or not. + * This setting governs the latency with which we switch back and forth + * between sending and receiving messages. + */ + private final static int EXTRA_RESPONSE_TIMEOUT = (int) (2 * TimeUtils.AMINUTE); + + /** + * Messenger idle timeout. + */ + private final static long MESSENGER_IDLE_TIMEOUT = 15 * TimeUtils.AMINUTE; + + /** + * Number of attempts we will attempt to make connections. + */ + private final static int CONNECT_RETRIES = 2; + + /** + * Warn only once about obsolete proxies. + */ + private static boolean neverWarned = true; + + /** + * The URL we send messages to. + */ + private final URL senderURL; + + /** + * The ServletHttpTransport that created this object. + */ + private final ServletHttpTransport servletHttpTransport; + + /** + * The Return Address element we will add to all messages we send. + */ + private final MessageElement srcAddressElement; + + /** + * The logical destination address of this messenger. + */ + private final EndpointAddress logicalDest; + + private TransportBindingMeter transportBindingMeter; + + /** + * The last time at which we successfully received or sent a message. + */ + private transient long lastUsed = TimeUtils.timeNow(); + + /** + * Poller that we use to get our messages. + */ + private MessagePoller poller = null; + + /** + * Constructs the messenger. + * + * @param servletHttpTransport The transport this messenger will work for. + * @param srcAddr The source address. + * @param destAddr The destination address. + */ + HttpClientMessenger(ServletHttpTransport servletHttpTransport, EndpointAddress srcAddr, EndpointAddress destAddr) throws IOException { + + // We do use self destruction. + super(servletHttpTransport.getEndpointService().getGroup().getPeerGroupID(), destAddr, true); + + this.servletHttpTransport = servletHttpTransport; + + EndpointAddress srcAddress = srcAddr; + this.srcAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, srcAddr.toString(), null); + + String protoAddr = destAddr.getProtocolAddress(); + + String host; + int port; + int lastColon = protoAddr.lastIndexOf(':'); + + if ((-1 == lastColon) || (lastColon < protoAddr.lastIndexOf(']')) || ((lastColon + 1) == protoAddr.length())) { + // There's no port or it's an IPv6 addr with no port or the colon is the last character. + host = protoAddr; + port = 80; + } else { + host = protoAddr.substring(0, lastColon); + port = Integer.parseInt(protoAddr.substring(lastColon + 1)); + } + + senderURL = new URL("http", host, port, "/"); + + logicalDest = retreiveLogicalDestinationAddress(); + + // Start receiving messages from the other peer + poller = new MessagePoller(srcAddr.getProtocolAddress(), destAddr); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("New messenger : " + this ); + } + } + + /* + * The cost of just having a finalize routine is high. The finalizer is + * a bottleneck and can delay garbage collection all the way to heap + * exhaustion. Leave this comment as a reminder to future maintainers. + * Below is the reason why finalize is not needed here. + * + * These messengers (normally) never go to the application layer. Endpoint + * code does call close when necessary. + + protected void finalize() { + } + + */ + + /** + * {@inheritDoc} + *

            + * A simple implementation for debugging. Do not parse the String + * returned. All of the information is available in other (simpler) ways. + */ + public String toString() { + StringBuilder result = new StringBuilder(super.toString()); + result.append(" {"); + result.append(getDestinationAddress()); + result.append(" / "); + result.append(getLogicalDestinationAddress()); + result.append("}"); + + return result.toString(); + } + + /** + * {@inheritDoc} + */ + void doShutdown() { + super.shutdown(); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void closeImpl() { + + if (isClosed()) { + return; + } + + super.close(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Close messenger to " + senderURL); + } + + MessagePoller stopPoller = poller; + + poller = null; + + if (null != stopPoller) { + stopPoller.stop(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void sendMessageBImpl(Message message, String service, String serviceParam) throws IOException { + + if (isClosed()) { + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Messenger was closed, it cannot be used to send messages.", failure); + } + + throw failure; + } + + // clone the message before modifying it. + message = message.clone(); + + // Set the message with the appropriate src and dest address + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, srcAddressElement); + + EndpointAddress destAddressToUse = getDestAddressToUse(service, serviceParam); + + MessageElement dstAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NAME, + destAddressToUse.toString(), null); + + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, dstAddressElement); + + try { + doSend(message); + } catch (IOException e) { + // close this messenger + close(); + // rethrow the exception + throw e; + } + } + + /** + * {@inheritDoc} + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + return logicalDest; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdleImpl() { + return isClosed() || (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), lastUsed) > MESSENGER_IDLE_TIMEOUT); + } + + /** + * Connects to the http server and retrieves the Logical Destination Address + */ + private EndpointAddress retreiveLogicalDestinationAddress() throws IOException { + long beginConnectTime = 0; + long connectTime = 0; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ping (" + senderURL + ")"); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + beginConnectTime = TimeUtils.timeNow(); + } + + // open a connection to the other end + HttpURLConnection urlConn = (HttpURLConnection) senderURL.openConnection(); + + urlConn.setRequestMethod("GET"); + urlConn.setDoOutput(true); + urlConn.setDoInput(true); + urlConn.setAllowUserInteraction(false); + urlConn.setUseCaches(false); + urlConn.setConnectTimeout(CONNECT_TIMEOUT); + urlConn.setReadTimeout(CONNECT_TIMEOUT); + + try { + // this is where the connection is actually made, if not already + // connected. If we can't connect, assume it is dead + int code = urlConn.getResponseCode(); + + if (code != HttpURLConnection.HTTP_OK) { + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + transportBindingMeter = servletHttpTransport.getTransportBindingMeter(null, getDestinationAddress()); + if (transportBindingMeter != null) { + transportBindingMeter.connectionFailed(true, TimeUtils.timeNow() - beginConnectTime); + } + } + + throw new IOException("Message not accepted: HTTP status " + "code=" + code + " reason=" + urlConn.getResponseMessage()); + } + + // check for a returned peerId + int msglength = urlConn.getContentLength(); + + if (msglength <= 0) { + throw new IOException("Ping response was empty."); + } + + InputStream inputStream = urlConn.getInputStream(); + + // read the peerId + byte[] uniqueIdBytes = new byte[msglength]; + int bytesRead = 0; + + while (bytesRead < msglength) { + int thisRead = inputStream.read(uniqueIdBytes, bytesRead, msglength - bytesRead); + + if (thisRead < 0) { + break; + } + + bytesRead += thisRead; + } + + if (bytesRead < msglength) { + throw new IOException("Content ended before promised Content length"); + } + + String uniqueIdString; + + try { + uniqueIdString = new String(uniqueIdBytes, "UTF-8"); + } catch (UnsupportedEncodingException never) { + // utf-8 is always available, but we handle it anyway. + uniqueIdString = new String(uniqueIdBytes); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + connectTime = TimeUtils.timeNow(); + transportBindingMeter = servletHttpTransport.getTransportBindingMeter(uniqueIdString, getDestinationAddress()); + if (transportBindingMeter != null) { + transportBindingMeter.connectionEstablished(true, connectTime - beginConnectTime); + transportBindingMeter.ping(connectTime); + transportBindingMeter.connectionClosed(true, connectTime - beginConnectTime); + } + } + + EndpointAddress remoteAddress = new EndpointAddress("jxta", uniqueIdString.trim(), null, null); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ping (" + senderURL + ") -> " + remoteAddress); + } + + return remoteAddress; + } catch (IOException failure) { + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + connectTime = TimeUtils.timeNow(); + transportBindingMeter = servletHttpTransport.getTransportBindingMeter(null, getDestinationAddress()); + if (transportBindingMeter != null) { + transportBindingMeter.connectionFailed(true, connectTime - beginConnectTime); + } + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Ping (" + senderURL + ") -> failed"); + } + + throw failure; + } + } + + /** + * Connects to the http server and POSTs the message + */ + private void doSend(Message msg) throws IOException { + long beginConnectTime = 0; + long connectTime = 0; + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + beginConnectTime = TimeUtils.timeNow(); + } + + WireFormatMessage serialed = WireFormatMessageFactory.toWire(msg, EndpointServiceImpl.DEFAULT_MESSAGE_TYPE, null); + + for (int connectAttempt = 1; connectAttempt <= CONNECT_RETRIES; connectAttempt++) { + if (connectAttempt > 1) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Retrying connection to " + senderURL); + } + } + // open a connection to the other end + HttpURLConnection urlConn = (HttpURLConnection) senderURL.openConnection(); + + try { + urlConn.setRequestMethod("POST"); + urlConn.setDoOutput(true); + urlConn.setDoInput(true); + urlConn.setAllowUserInteraction(false); + urlConn.setUseCaches(false); + urlConn.setConnectTimeout(CONNECT_TIMEOUT); + urlConn.setReadTimeout(CONNECT_TIMEOUT); + // FIXME 20040907 bondolo Should set message encoding http header. + urlConn.setRequestProperty("content-length", Long.toString(serialed.getByteLength())); + urlConn.setRequestProperty("content-type", serialed.getMimeType().toString()); + // send the message + OutputStream out = urlConn.getOutputStream(); + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + connectTime = TimeUtils.timeNow(); + transportBindingMeter.connectionEstablished(true, connectTime - beginConnectTime); + } + serialed.sendToStream(out); + out.flush(); + int responseCode; + + try { + responseCode = urlConn.getResponseCode(); + } catch (SocketTimeoutException expired) { + // maybe a retry will help. + continue; + } catch (IOException ioe) { + // Could not connect. This seems to happen a lot with a loaded HTTP 1.0 + // proxy. Apparently, HttpUrlConnection can be fooled by the proxy + // in believing that the connection is still open and thus breaks + // when attempting to make a second transaction. We should not have to but it + // seems that it befalls us to retry. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("HTTP 1.0 proxy seems in use"); + } + // maybe a retry will help. + continue; + } + + // NOTE: If the proxy closed the connection 1.0 style without returning + // a status line, we do not get an exception: we get a -1 response code. + // Apparently, proxies no-longer do that anymore. Just in case, we issue a + // warning and treat it as OK.71 + if (responseCode == -1) { + if (neverWarned && Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Obsolete HTTP proxy does not issue HTTP_OK response. Assuming OK"); + neverWarned = false; + } + responseCode = HttpURLConnection.HTTP_OK; + } + + if (responseCode != HttpURLConnection.HTTP_OK) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.dataSent(true, serialed.getByteLength()); + transportBindingMeter.connectionDropped(true, TimeUtils.timeNow() - beginConnectTime); + } + throw new IOException( "Message not accepted: HTTP status " + "code=" + responseCode + + " reason=" + urlConn.getResponseMessage()); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + long messageSentTime = TimeUtils.timeNow(); + + transportBindingMeter.messageSent(true, msg, messageSentTime - connectTime, serialed.getByteLength()); + transportBindingMeter.connectionClosed(true, messageSentTime - beginConnectTime); + } + + // note that we successfully sent a message + lastUsed = TimeUtils.timeNow(); + + return; + } finally { + // This does prevent the creation of an infinite number of connections + // if we happen to be going through a 1.0-only proxy or connect to a server + // that still does not set content length to zero for the response. With this, at + // least we close them (they eventualy close anyway because the other side closes + // them but it takes too much time). If content-length is set, then jdk ignores + // the disconnect AND reuses the connection, which is what we want. + urlConn.disconnect(); + } + } + + throw new IOException("Failed sending " + msg + " to " + senderURL); + } + + /** + * Polls for messages sent to us. + */ + private class MessagePoller implements Runnable { + + /** + * If true then this poller is stopped or stopping. + */ + private volatile boolean stopped = false; + + /** + * The thread that does the work. + */ + private Thread pollerThread; + + /** + * The URL we poll for messages. + */ + private final URL pollingURL; + + MessagePoller(String pollAddress, EndpointAddress destAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("new MessagePoller for " + senderURL); + } + + /* + * query string is of the format ?{response timeout},{extra response timeout},{dest address} + * + * The timeout's are expressed in milliseconds. -1 means do not wait + * at all, 0 means wait forever. + */ + try { + pollingURL = new URL(senderURL, + "/" + pollAddress + + "?" + Integer.toString(RESPONSE_TIMEOUT) + "," + + Integer.toString(EXTRA_RESPONSE_TIMEOUT) + "," + + destAddr); + } catch (MalformedURLException badAddr) { + IllegalArgumentException failure = new IllegalArgumentException("Could not construct polling URL"); + + failure.initCause(badAddr); + + throw failure; + } + + pollerThread = new Thread(this, "HttpClientMessenger poller for " + senderURL); + pollerThread.setDaemon(true); + pollerThread.start(); + } + + protected void stop() { + if (stopped) { + return; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Stop polling for " + senderURL); + } + + stopped = true; + + // Here, we are forced to abandon this object open. Because we could + // get blocked forever trying to close it. It will rot away after + // the current read returns. The best we can do is interrupt the + // thread; unlikely to have an effect per the current. + // HttpURLConnection implementation. + + Thread stopPoller = pollerThread; + + if (null != stopPoller) { + stopPoller.interrupt(); + } + } + + /** + * Returns {@code true} if this messenger is stopped otherwise + * {@code false}. + * + * @return returns {@code true} if this messenger is stopped otherwise + * {@code false}. + */ + protected boolean isStopped() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(this + " " + senderURL + " --> " + (stopped ? "stopped" : "running")); + } + + return stopped; + } + + /** + * {@inheritDoc} + * + *

            Connects to the http server and waits for messages to be received and processes them. + */ + public void run() { + try { + long beginConnectTime = 0; + long connectTime = 0; + long noReconnectBefore = 0; + HttpURLConnection conn = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Message polling beings for " + pollingURL); + } + + int connectAttempt = 1; + + // get messages until the messenger is closed + while (!isStopped()) { + if (conn == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Opening new connection to " + pollingURL); + } + + conn = (HttpURLConnection) pollingURL.openConnection(); // Incomming data channel + + conn.setRequestMethod("GET"); + conn.setDoOutput(false); + conn.setDoInput(true); + conn.setAllowUserInteraction(false); + conn.setUseCaches(false); + conn.setConnectTimeout(CONNECT_TIMEOUT); + conn.setReadTimeout(RESPONSE_TIMEOUT); + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + beginConnectTime = TimeUtils.timeNow(); + } + + // Loop back and try again to connect + continue; + } + + long untilNextConnect = TimeUtils.toRelativeTimeMillis(noReconnectBefore); + + try { + if (untilNextConnect > 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Delaying for " + untilNextConnect + "ms before reconnect to " + senderURL); + } + Thread.sleep(untilNextConnect); + } + } catch (InterruptedException woken) { + Thread.interrupted(); + continue; + } + + InputStream inputStream; + MimeMediaType messageType; + + try { + if (connectAttempt > 1) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reconnect attempt for " + senderURL); + } + } + + // Always connect (no cost if connected). + conn.connect(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting for response code from " + senderURL); + } + + int responseCode = conn.getResponseCode(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "Response " + responseCode + " for Connection : " + senderURL + "\n\tContent-Type : " + + conn.getHeaderField("Content-Type") + "\tContent-Length : " + + conn.getHeaderField("Content-Length") + "\tTransfer-Encoding : " + + conn.getHeaderField("Transfer-Encoding")); + } + + connectTime = TimeUtils.timeNow(); + noReconnectBefore = TimeUtils.toAbsoluteTimeMillis(MIMIMUM_POLL_INTERVAL, connectTime); + + if (0 == conn.getContentLength()) { + continue; + } + + if (HttpURLConnection.HTTP_NO_CONTENT == responseCode) { + // the connection timed out. + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionClosed(true, TimeUtils.toRelativeTimeMillis(beginConnectTime, connectTime)); + } + + conn = null; + continue; + } + + if (responseCode != HttpURLConnection.HTTP_OK) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionClosed(true, TimeUtils.timeNow() - beginConnectTime); + } + + throw new IOException("HTTP Failure: " + conn.getResponseCode() + " : " + conn.getResponseMessage()); + } + + String contentType = conn.getHeaderField("Content-Type"); + + if (null == contentType) { + // XXX 20051219 bondolo Figure out why the mime type is not always set. + messageType = EndpointServiceImpl.DEFAULT_MESSAGE_TYPE; + } else { + messageType = MimeMediaType.valueOf(contentType); + } + + // FIXME 20040907 bondolo Should get message content-encoding from http header. + + inputStream = conn.getInputStream(); + + // reset connection attempt. + connectAttempt = 1; + } catch (InterruptedIOException broken) { + // We don't know where it was interrupted. Restart connection. + Thread.interrupted(); + + if (connectAttempt > CONNECT_RETRIES) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unable to connect to " + senderURL); + } + + stop(); + break; + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Failed connecting to " + senderURL); + } + + if (null != conn) { + conn.disconnect(); + } + conn = null; + connectAttempt++; + continue; + } + } catch (IOException ioe) { + if (connectAttempt > CONNECT_RETRIES) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unable to connect to " + senderURL, ioe); + } + + stop(); + break; + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Failed connecting to " + senderURL); + } + + if (null != conn) { + conn.disconnect(); + } + conn = null; + connectAttempt++; + continue; + } + } + + // start receiving messages + try { + while (!isStopped() + && (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), connectTime) < RESPONSE_TIMEOUT)) { + // read a message! + long messageReceiveStart = TimeUtils.timeNow(); + Message incomingMsg; + + incomingMsg = WireFormatMessageFactory.fromWire(inputStream, messageType, null); + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.messageReceived(true, incomingMsg, incomingMsg.getByteLength(), + TimeUtils.timeNow() - messageReceiveStart); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + incomingMsg + " from " + senderURL); + } + + servletHttpTransport.executor.execute(new MessageProcessor(incomingMsg)); + + // note that we received a message + lastUsed = TimeUtils.timeNow(); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionClosed(true, TimeUtils.timeNow() - beginConnectTime); + } + } catch (EOFException e) { + // Connection ran out of messages. let it go. + conn = null; + } catch (InterruptedIOException broken) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionDropped(true, TimeUtils.timeNow() - beginConnectTime); + } + + // We don't know where it was interrupted. Restart connection. + Thread.interrupted(); + if (null != conn) { + conn.disconnect(); + } + conn = null; + } catch (IOException e) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionDropped(true, TimeUtils.timeNow() - beginConnectTime); + } + + // If we managed to get down here, it is really an error. + // However, being disconnected from the server, for + // whatever reason, is a common place event. No need to + // clutter the screen with scary messages. When the + // message layer believes it's serious, it prints the + // scary message already. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to read message from " + senderURL, e); + } + // Time to call this connection dead. + stop(); + break; + } finally { + try { + inputStream.close(); + } catch (IOException ignored) { + //ignored + } + } + } + } catch (Throwable argh) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Poller exiting because of uncaught exception", argh); + } + stop(); + } finally { + pollerThread = null; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Message polling stopped for " + senderURL); + } + } + } + + /** + * A small class for processing individual messages. + */ + private class MessageProcessor implements Runnable { + + private Message msg; + + MessageProcessor(Message msg) { + this.msg = msg; + } + + public void run() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Demuxing " + msg + " from " + senderURL); + } + + servletHttpTransport.getEndpointService().demux(msg); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageReceiver.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageReceiver.java new file mode 100644 index 000000000..ad8ab55d1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageReceiver.java @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.servlethttp; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.InetAddress; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import java.io.IOException; +import java.io.FileNotFoundException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import org.mortbay.http.HttpContext; +import org.mortbay.http.HttpServer; +import org.mortbay.http.SocketListener; +import org.mortbay.http.handler.ResourceHandler; +import org.mortbay.jetty.servlet.ServletHandler; +import org.mortbay.util.InetAddrPort; +import org.mortbay.util.Log; +import org.mortbay.util.LoggerLogSink; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessengerEvent; +import net.jxta.endpoint.MessengerEventListener; + +import net.jxta.exception.PeerGroupException; + +import net.jxta.impl.util.TimeUtils; + +/** + * Simple Message Receiver for server side. + */ +class HttpMessageReceiver implements MessageReceiver { + + /** + * logger + */ + private final static transient Logger LOG = Logger.getLogger(HttpMessageReceiver.class.getName()); + + /** + * the relative URI of where the message receiver servlet will be mounted. + */ + private final static String MSG_RECEIVER_RELATIVE_URI = "/*"; + + /** + * The ServletHttpTransport that created this MessageReceiver. + */ + final ServletHttpTransport servletHttpTransport; + + /** + * The public addresses for the this transport. + */ + private final List publicAddresses; + + /** + * The min threads that the HTTP server will use for handling requests. + */ + private static int MIN_LISTENER_THREADS = 10; + + /** + * The max threads that the HTTP server will use for handling requests. + */ + private static int MAX_LISTENER_THREADS = 200; + + /** + * How long a thread can remain idle until the worker thread is let go. + */ + private static long MAX_THREAD_IDLE_DURATION = 30 * TimeUtils.ASECOND; + + /** + * The Jetty HTTP Server instance. + */ + private final HttpServer server; + private final ServletHandler handler; + private final SocketListener listener; + + /** + * The listener to invoke when making an incoming messenger. + */ + private MessengerEventListener messengerEventListener; + + public HttpMessageReceiver(ServletHttpTransport servletHttpTransport, List publicAddresses, InetAddress useInterface, int port) throws PeerGroupException { + this.servletHttpTransport = servletHttpTransport; + this.publicAddresses = publicAddresses; + + // read settings from the properties file + Properties prop = getJxtaProperties( + new File(new File(servletHttpTransport.getEndpointService().getGroup().getStoreHome()), "jxta.properties")); + initFromProperties(prop); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring HTTP Servlet Message Transport : " + servletHttpTransport.assignedID); + + configInfo.append("\n\tMin threads=").append(MIN_LISTENER_THREADS); + configInfo.append("\n\tMax threads=").append(MAX_LISTENER_THREADS); + configInfo.append("\n\tMax thread idle time=").append(MAX_THREAD_IDLE_DURATION).append("ms"); + + LOG.config(configInfo.toString()); + } + + // Configure Jetty Logging + if (!(Logging.SHOW_FINER && LOG.isLoggable(Level.FINER))) { + Log.instance().disableLog(); + } + + org.mortbay.util.Code.setDebug(Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)); + org.mortbay.util.Code.setSuppressWarnings(!(Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING))); + org.mortbay.util.Code.setSuppressStack(!(Logging.SHOW_FINER && LOG.isLoggable(Level.FINER))); + + // Setup the logger to match the rest of JXTA unless explicitly configured. + // "LOG_CLASSES" is a Jetty thing. + if (System.getProperty("LOG_CLASSES") == null) { + LoggerLogSink logSink = new LoggerLogSink(); + Logger jettyLogger = Logger.getLogger(org.mortbay.http.HttpServer.class.getName()); + + logSink.setLogger(jettyLogger); + try { + logSink.start(); + Log.instance().add(logSink); + } catch (Exception ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not configure LoggerLogSink"); + } + } + } + + // Initialize the Jetty HttpServer + server = new HttpServer(); + + // Create the listener and attach it to server. + InetAddrPort addrPort = new InetAddrPort(useInterface, port); + + listener = new SocketListener(addrPort); + + listener.setMinThreads(MIN_LISTENER_THREADS); + listener.setMaxThreads(MAX_LISTENER_THREADS); + listener.setMaxIdleTimeMs((int) MAX_THREAD_IDLE_DURATION); + + server.addListener(listener); + + // Create a context for the handlers at the root, then add servlet + // handler for the specified servlet class and add it to the context + HttpContext handlerContext = server.getContext("/"); + + handler = new ServletHandler(); + + handler.setUsingCookies(false); + handler.initialize(handlerContext); + + // Use peer group class loader (useful for HttpMessageServlet) + handlerContext.setClassLoader(servletHttpTransport.getEndpointService().getGroup().getLoader()); + handlerContext.addHandler(handler); + + // Set up support for downloading midlets. + if (System.getProperty("net.jxta.http.allowdownload") != null) { + HttpContext context = server.addContext("/midlets/*"); + + context.setResourceBase("./midlets/"); + // context.setDirAllowed(false); + // context.setServingResources(true); + + // String methods[] = {"GET"}; + ResourceHandler resHandler = new ResourceHandler(); + + // resHandler.setAllowedMethods(methods); + context.addHandler(resHandler); + } + + handler.addServlet(MSG_RECEIVER_RELATIVE_URI, HttpMessageServlet.class.getName()); + } + + synchronized void start() throws PeerGroupException { + try { + server.start(); + handler.getServletContext().setAttribute("HttpMessageReceiver", this); + } catch (Exception e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not start server", e); + } + PeerGroupException failure = new PeerGroupException("Could not start server"); + failure.initCause(e); + throw failure; + } + + messengerEventListener = servletHttpTransport.getEndpointService().addMessageTransport(this); + if (messengerEventListener == null) { + throw new PeerGroupException("Transport registration refused"); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("HTTP Servlet Transport started."); + } + } + + synchronized void stop() { + servletHttpTransport.getEndpointService().removeMessageTransport(this); + messengerEventListener = null; + + try { + server.stop(); + } catch (InterruptedException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Interrupted during stop()", e); + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("HTTP Servlet Transport stopped."); + } + } + + /** + * {@inheritDoc} + */ + boolean messengerReadyEvent(HttpServletMessenger newMessenger, EndpointAddress connAddr) { + MessengerEventListener temp = messengerEventListener; + + return null != temp && temp.messengerReady(new MessengerEvent(this, newMessenger, connAddr)); + } + + /** + * {@inheritDoc} + */ + public Iterator getPublicAddresses() { + return Collections.unmodifiableList(publicAddresses).iterator(); + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return servletHttpTransport.HTTP_PROTOCOL_NAME; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return servletHttpTransport.getEndpointService(); + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + ServletHttpTransport getServletHttpTransport() { + return servletHttpTransport; + } + + /** + * Returns a Properties instance for jxta.properties if the file exists; + * otherwise, returns null. + * + * @param fromFile properties file + * @return the properties object or null if properties file was not found + */ + private static Properties getJxtaProperties(File fromFile) { + Properties prop = new Properties(); + InputStream in = null; + + try { + in = new FileInputStream(fromFile); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Read properties from " + fromFile.getPath()); + } + } catch (FileNotFoundException e) { + return null; + } + + try { + prop.load(in); + } catch (IOException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Error reading " + fromFile.getPath(), e); + } + } finally { + try { + in.close(); + } catch (IOException ignored) { + //ignored + } + in = null; + } + return prop; + } + + /** + * Reads the properties from the jxta.properties file + * + * @param prop properties to init from + */ + private void initFromProperties(Properties prop) { + + if (prop == null) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.fine("jxta.properties not found: using default values"); + } + } else { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Using jxta.properties to configure HTTP server"); + } + + String minThreadsStr = prop.getProperty("HttpServer.MinThreads"); + String maxThreadsStr = prop.getProperty("HttpServer.MaxThreads"); + String maxThreadIdleTimeStr = prop.getProperty("HttpServer.MaxThreadIdleTime"); + + try { + if (minThreadsStr != null) { + MIN_LISTENER_THREADS = Integer.parseInt(minThreadsStr); + } + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid HttpServer.MinThreads value; using default"); + } + } + + try { + if (maxThreadsStr != null) { + MAX_LISTENER_THREADS = Integer.parseInt(maxThreadsStr); + } + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid HttpServer.MaxThreads value; using default"); + } + } + + try { + if (maxThreadIdleTimeStr != null) { + MAX_THREAD_IDLE_DURATION = Integer.parseInt(maxThreadIdleTimeStr); + } + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid HttpServer.MaxThreadIdleTime value; using default"); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageSender.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageSender.java new file mode 100644 index 000000000..72b07d075 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageSender.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.servlethttp; + +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +import java.net.SocketTimeoutException; +import java.net.ConnectException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.Messenger; + +import net.jxta.exception.PeerGroupException; + +/** + * Simple Client MessageSender + */ +class HttpMessageSender implements MessageSender { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(HttpMessageSender.class.getName()); + + /** + * The ServletHttpTransport that created this object + */ + private final ServletHttpTransport servletHttpTransport; + + /** + * The public address for this message sender + */ + private final EndpointAddress publicAddress; + + /** + * The Set of active messengers. We keep track so that we can aggressively + * close the Messengers when the transport is shut down. + */ + private final Map messengers = new WeakHashMap(); + + /** + * constructor + */ + public HttpMessageSender(ServletHttpTransport servletHttpTransport, EndpointAddress publicAddress) throws PeerGroupException { + + this.servletHttpTransport = servletHttpTransport; + this.publicAddress = publicAddress; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder( "Configuring HTTP Client Message Transport : " + servletHttpTransport.assignedID); + + configInfo.append("\n\tPublic Address = ").append(publicAddress); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return publicAddress; + } + + /** + * {@inheritDoc} + */ + public boolean isConnectionOriented() { + return true; + } + + /** + * {@inheritDoc} + */ + public boolean allowsRouting() { + return true; + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + /** + * shut down all client connections. + */ + public synchronized void start() throws PeerGroupException { + if (servletHttpTransport.getEndpointService().addMessageTransport(this) == null) { + throw new PeerGroupException("Transport registration refused"); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("HTTP Client Transport started."); + } + } + + /** + * shut down all client connections. + */ + public synchronized void stop() { + synchronized (messengers) { + Iterator eachMessenger = messengers.keySet().iterator(); + + while (eachMessenger.hasNext()) { + HttpClientMessenger aMessenger = eachMessenger.next(); + + eachMessenger.remove(); + + aMessenger.doShutdown(); + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("HTTP Client Transport stopped."); + } + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress destAddr, Object hintIgnored) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("getMessenger for : " + destAddr); + } + + if (!getProtocolName().equals(destAddr.getProtocolName())) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Cannot make messenger for protocol :" + destAddr.getProtocolName()); + } + + return null; + } + + try { + // Right now we do not want to "announce" outgoing messengers + // because they get pooled and so must not be grabbed by a listener. + // If "announcing" is to be done, that should be by the endpoint + // and probably with a subtly different interface. + + HttpClientMessenger result = new HttpClientMessenger(servletHttpTransport, publicAddress, destAddr); + + synchronized (messengers) { + messengers.put(result, null); + } + + return result; + } catch (SocketTimeoutException noConnect) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not connect to " + destAddr + " : " + noConnect.getMessage()); + } + } catch (ConnectException noConnect) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to connect to " + destAddr + " : " + noConnect.getMessage()); + } + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not make messenger for " + destAddr, e); + } + } + + // If we got here, we failed. + return null; + } + + /** + * {@inheritDoc} + */ + public boolean ping(EndpointAddress addr) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Using http client sender to ping " + addr); + } + + Messenger messenger = getMessenger(addr, null); + + // XXX pool this messenger. + // Ping obsolete. And do not announce an outgoing messenger + + boolean pong = 0 != (Messenger.USABLE & messenger.getState()); + + messenger.close(); + + return pong; + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return servletHttpTransport.HTTP_PROTOCOL_NAME; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return servletHttpTransport.getEndpointService(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageServlet.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageServlet.java new file mode 100644 index 000000000..8a1a7093e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpMessageServlet.java @@ -0,0 +1,908 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.servlethttp; + +import java.io.InputStream; +import java.io.OutputStream; +// import java.util.Enumeration; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +// import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.linphone.p2pproxy.core.jxtaext.EndpointRegistry; + +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; + +import net.jxta.impl.endpoint.EndpointServiceImpl; +import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings; +import net.jxta.impl.util.TimeUtils; + +/** + * This is a simple servlet that accepts JXTA Messages from clients using HTTP + * via {@code POST}. In addition to receiving messages via {@code POST} + * responses clients can also poll for messages using {@code GET}. + * + *

            It also supports a ping operation. When the URI is / the + * response consists of the unique value portion of the local peer id. + */ +public class HttpMessageServlet extends HttpServlet { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(HttpMessageServlet.class.getName()); + + /** + * The maximum duration in milliseconds we will keep a connection alive + * while generating a response. + */ + private final static long MAXIMUM_RESPONSE_DURATION = 2 * TimeUtils.AMINUTE; + + /** + * Owner of this servlet. + */ + private HttpMessageReceiver owner = null; + + /** + * The endpoint that the owner message transport is registered with. + */ + private EndpointService endpoint = null; + + /** + * Our address. + */ + private EndpointAddress localAddress = null; + private byte[] pingResponseBytes; + + private ServletHttpTransport servletHttpTransport = null; + + /** + * If {@code true} then this servlet has been (or is being) destroyed. + */ + private volatile boolean destroyed = false; + + /** + * Recovers the Message Transport which owns this servlet from the context + * information. + */ + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + + try { + owner = (HttpMessageReceiver) getServletContext().getAttribute("HttpMessageReceiver"); + if (owner == null) { + throw new ServletException("Servlet Context did not contain 'HttpMessageReceiver'"); + } + } catch (ClassCastException e) { + throw new ServletException("'HttpMessageReceiver' attribute was not of the proper type in the Servlet Context"); + } + + servletHttpTransport = owner.servletHttpTransport; + endpoint = owner.getEndpointService(); + + String peerId = endpoint.getGroup().getPeerID().getUniqueValue().toString(); + + localAddress = new EndpointAddress("jxta", peerId, null, null); + + try { + pingResponseBytes = peerId.getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException never) { + // UTF-8 is always available. + } + } + + /** + * {@inheritDoc} + */ + @Override + public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("GET " + req.getRequestURI() + " thread = " + Thread.currentThread()); + } + + processRequest(req, res); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("GET done for thread = " + Thread.currentThread()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("POST " + req.getRequestURI() + " thread = " + Thread.currentThread()); + } + + processRequest(req, res); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("POST done for thread = " + Thread.currentThread()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void destroy() { + // All we need to do is wakeup the threads that are waiting. (In truth + // we'll miss those that are waiting on a messenger, but that'll do for + // now, because we do that only when shutting down the group and then + // the relay will be shutdown as well, which will take care of the + // messengers. + destroyed = true; + notifyAll(); + } + + /** + * Handle a request and optionally generate a response. + * + * @param req The request we are being asked to process. + * @param res The response we should use for any response. + * @throws IOException For failures in IO processing. + */ + private void processRequest(HttpServletRequest req, HttpServletResponse res) throws IOException { + + long lastReadWriteTime; + int requestSize = 0; + TransportBindingMeter transportBindingMeter = null; + + if (Logging.SHOW_FINEST && LOG.isLoggable(Level.FINEST)) { + printRequest(req); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + int contentLength = req.getContentLength(); + + requestSize += (contentLength != -1) ? contentLength : 0; + } + + JxtaRequest currentRequest = new JxtaRequest(req); + + /* + * We accept three request formats: + * + * o PING : no Message and no Requestor defined. + * o POLL : Requestor defined, positive response timeout and destination address. + * o SEND : Requestor defined, positive response timeout or no destination address. + */ + + // check if this is a ping request, no requestor peerId or incoming message + if (null == currentRequest.requestorAddr && !currentRequest.messageContent) { + // this is only a ping request + pingResponse(res); + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + long connectionTime = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime); + EndpointAddress sourceAddress = new EndpointAddress("http", req.getRemoteHost(), null, null); // + + transportBindingMeter = servletHttpTransport.getTransportBindingMeter(null, sourceAddress); + if (transportBindingMeter != null) { + transportBindingMeter.connectionEstablished(false, currentRequest.requestStartTime); + transportBindingMeter.dataReceived(false, requestSize); + transportBindingMeter.dataSent(false, 0); + transportBindingMeter.pingReceived(); + transportBindingMeter.connectionClosed(false, connectionTime); + } + } + + return; + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + lastReadWriteTime = TimeUtils.timeNow(); + long connectTime = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime); + EndpointAddress sourceAddress = new EndpointAddress("http", req.getRemoteHost(), null, null); // + + if (null != currentRequest.requestorAddr) { + transportBindingMeter = servletHttpTransport.getTransportBindingMeter(currentRequest.requestorAddr.toString(), + sourceAddress); + } else { + transportBindingMeter = servletHttpTransport.getTransportBindingMeter(req.getRemoteHost(), sourceAddress); + } + if (transportBindingMeter != null) { + transportBindingMeter.connectionEstablished(false, connectTime); + transportBindingMeter.dataReceived(false, requestSize); + } + } + + // check if the request included polling (valid requestor peerId and timeout not -1) + HttpServletMessenger messenger = null; + + if ((null != currentRequest.requestorAddr) && (currentRequest.responseTimeout >= 0) && (null != currentRequest.destAddr)) { + // create the back channel messenger + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( "Creating back channel messenger for " + currentRequest.requestorAddr + " (" + currentRequest.destAddr + ")"); + } + + long messengerAliveFor; + + if (0 == currentRequest.responseTimeout) { + messengerAliveFor = 0; + } else { + messengerAliveFor = Math.max(currentRequest.responseTimeout, currentRequest.extraResponsesTimeout); + } + + messenger = new HttpServletMessenger(owner.servletHttpTransport.group.getPeerGroupID(), localAddress, + currentRequest.requestorAddr, messengerAliveFor); + boolean taken = owner.messengerReadyEvent(messenger, currentRequest.destAddr); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Incoming messenger to: " + currentRequest.requestorAddr + " taken=" + taken); + } + + if (!taken) { + // nobody cares. Just destroy it. + messenger.close(); + messenger = null; + } + } + + // We may later decide that contentLength should not be set after all + // if we use chunking. Otherwise we must set it; specially to zero, so + // that jetty does not forcefully close the connection after each + // message in order to complete the transaction http-1.0-style. + + boolean mustSetContentLength = true; + + try { + // get the incoming message is there is one + if (currentRequest.messageContent) { + Message incomingMessage; + + // read the stream + InputStream in = req.getInputStream(); + + // construct the message. Send BAD_REQUEST if the message construction + // fails + try { + String contentType = req.getContentType(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reading message from request : " + contentType); + } + + MimeMediaType contentMimeType = EndpointServiceImpl.DEFAULT_MESSAGE_TYPE; + + if (null != contentType) { + contentMimeType = MimeMediaType.valueOf(contentType); + } + + // FIXME 20040927 bondolo Should get message encoding from http header. + try { + incomingMessage = WireFormatMessageFactory.fromWire(in, contentMimeType, null); + } catch (NoSuchElementException noValidWireFormat) { + IOException failure = new IOException("Unrecognized content type MIME type : " + contentType); + + failure.initCause(noValidWireFormat); + throw failure; + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + lastReadWriteTime = TimeUtils.timeNow(); + long receiveTime = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime); + + transportBindingMeter.messageReceived(false, incomingMessage, receiveTime, 0); // size=0 since it was already incorporated in the request size + } + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Malformed JXTA message, responding with BAD_REQUEST", e); + } + + res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Message was not a valid JXTA message"); + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionDropped(false, + TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime)); + } + return; + } + + // post the incoming message to the endpoint demux + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Handing " + incomingMessage + " to the endpoint."); + } + + try { + endpoint.demux(incomingMessage); + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure demuxing an incoming message", e); + } + } + } + + boolean beganResponse = false; + + // Check if the back channel is to be used for sending messages. + if ((currentRequest.responseTimeout >= 0) && (null != messenger)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Wait for message from the messenger. timeout = " + currentRequest.responseTimeout); + } + + long quitAt = (currentRequest.responseTimeout == 0) + ? Long.MAX_VALUE + : TimeUtils.toAbsoluteTimeMillis(currentRequest.requestStartTime, currentRequest.responseTimeout); + + while ((0 != (messenger.getState() & Messenger.USABLE)) && !destroyed) { + long remaining = TimeUtils.toRelativeTimeMillis(quitAt); + + if ((remaining <= 0)) { + // done processing the request + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Terminating expired request."); + } + + // We know we did not respond anything. + // In general it's better if jetty closes the connection + // here, because it could have been an unused + // back-channel and the client has to open a new one + // next time, thus making sure we get to see a different + // URL (if applicable). JDK should do that anyway, + // but ...). + break; + } + + Message outMsg; + + // Send a message if there is one + try { + outMsg = messenger.waitForMessage(remaining); + } catch (InterruptedException ie) { + // Ok. Leave early, then. + Thread.interrupted(); + continue; + } + + if (outMsg == null) { + // done processing the request + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Terminating request with no message to send."); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionClosed(false, + TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime)); + } + + // We know we did not respond anything. Do not set + // content-length In general it's better if jetty closes + // the connection here, because it could have been an + // unused back-channel and the client has to open a new + // one next time, thus making sure we get to see a + // different URL (if applicable). JDK should do that + // anyway, but ...). + break; + } + + long startMessageSend = TimeUtils.timeNow(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + outMsg + " on back channel to " + req.getRemoteHost()); + } + + if (!beganResponse) { + // valid request, send back OK response + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending OK in response to request"); + } + + beganResponse = true; + res.setStatus(HttpServletResponse.SC_OK); + res.setContentType(EndpointServiceImpl.DEFAULT_MESSAGE_TYPE.toString()); + } + + // send the message + WireFormatMessage serialed = WireFormatMessageFactory.toWire(outMsg, EndpointServiceImpl.DEFAULT_MESSAGE_TYPE, null); + + // if only one message is being returned, set the content + // length, otherwise try to use chunked encoding. + if (currentRequest.extraResponsesTimeout < 0) { + res.setContentLength((int) serialed.getByteLength()); + } + + // Either way, we've done what had to be done. + mustSetContentLength = false; + + // get the output stream for the response + OutputStream out = res.getOutputStream(); + + // send the message + try { + serialed.sendToStream(out); + out.flush(); + + messenger.messageSent(true); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Successfully sent " + outMsg + " on back channel to " + req.getRemoteHost()); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + lastReadWriteTime = TimeUtils.timeNow(); + long sendTime = TimeUtils.toRelativeTimeMillis(lastReadWriteTime, startMessageSend); + long bytesSent = serialed.getByteLength(); + + transportBindingMeter.messageSent(false, outMsg, sendTime, bytesSent); + } + } catch (IOException ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Failed sending Message on back channel to " + req.getRemoteHost()); + } + + messenger.messageSent(false); + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionDropped(false, + TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime)); + } + + throw ex; + } finally { + // make sure the response is pushed out + res.flushBuffer(); + } + + // Adjust the quit time based upon the extra response time available. + if (0 == currentRequest.extraResponsesTimeout) { + quitAt = Long.MAX_VALUE; + } else { + quitAt = TimeUtils.toAbsoluteTimeMillis(currentRequest.requestStartTime, currentRequest.extraResponsesTimeout); + } + + // If we never generated a response then make it clear we gave up waiting. + if (!beganResponse) { + res.setStatus(HttpServletResponse.SC_NO_CONTENT); + } + } + } else { + // No response was desired. + res.setStatus(HttpServletResponse.SC_OK); + } + } finally { + // close the messenger + if (null != messenger) { + messenger.close(); + } + } + + // If contentLength was never set and we have not decided *not* to set + // it, then we must set it to 0 (that's the truth in that case). This + // allows Jetty to keep to keep the connection open unless what's on the + // other side is a 1.0 proxy. + if (mustSetContentLength) { + res.setContentLength(0); + } + + // make sure the response is pushed out + res.flushBuffer(); + + // done processing the request + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Finished processing the request from " + req.getRemoteHost()); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.connectionClosed(false, + TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), currentRequest.requestStartTime)); + } + } + + /** + * Returns a response to a ping request. The response is the PeerID of + * this peer. + * + * @param res The response to which the ping result should be sent. + */ + private void pingResponse(HttpServletResponse res) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Responding to \'ping\' request with 200 and peerID"); + } + + res.setStatus(HttpServletResponse.SC_OK); + + res.setContentLength(pingResponseBytes.length); + res.setContentType(MimeMediaType.TEXTUTF8.toString()); + + OutputStream out = res.getOutputStream(); + + out.write(pingResponseBytes); + out.flush(); + out.close(); + } + + /** + * Debugging output. + */ + private static void printRequest(HttpServletRequest req) { + final char nl = '\n'; + StringBuilder builder = new StringBuilder(); + + builder.append("HTTP request:" + nl); + builder.append(" AUTH_TYPE: ").append(req.getAuthType()).append(nl); + builder.append(" CONTEXT_PATH: ").append(req.getContextPath()).append(nl); + + Cookie[] cookies = req.getCookies(); + + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + builder.append(" COOKIE[").append(i).append("]:" + nl); + builder.append(" comment: ").append(cookies[i].getComment()).append(nl); + builder.append(" domain: ").append(cookies[i].getDomain()).append(nl); + builder.append(" max age: ").append(cookies[i].getMaxAge()).append(nl); + builder.append(" name: ").append(cookies[i].getName()).append(nl); + builder.append(" path: ").append(cookies[i].getPath()).append(nl); + builder.append(" secure: ").append(cookies[i].getSecure()).append(nl); + builder.append(" value: ").append(cookies[i].getValue()).append(nl); + builder.append(" version: ").append(cookies[i].getVersion()).append(nl); + } + } + + for (Enumeration headers = req.getHeaderNames(); headers.hasMoreElements();) { + String header = (String) headers.nextElement(); + builder.append(" HEADER[").append(header).append("]: ").append(req.getHeader(header)).append(nl); + } + + builder.append(" METHOD: ").append(req.getMethod()).append(nl); + builder.append(" PATH_INFO: ").append(req.getPathInfo()).append(nl); + builder.append(" PATH_TRANSLATED: ").append(req.getPathTranslated()).append(nl); + builder.append(" QUERY_STRING: ").append(req.getQueryString()).append(nl); + builder.append(" REMOTE_USER: ").append(req.getRemoteUser()).append(nl); + builder.append(" REQUESTED_SESSION_ID: ").append(req.getRequestedSessionId()).append(nl); + builder.append(" REQUEST_URI: ").append(req.getRequestURI()).append(nl); + builder.append(" SERVLET_PATH: ").append(req.getServletPath()).append(nl); + builder.append(" REMOTE_USER: ").append(req.getRemoteUser()).append(nl); + builder.append(" isSessionIdFromCookie: ").append(req.isRequestedSessionIdFromCookie()).append(nl); + builder.append(" isSessionIdFromURL: ").append(req.isRequestedSessionIdFromURL()).append(nl); + builder.append(" isSessionIdValid: ").append(req.isRequestedSessionIdValid()).append(nl); + + for (Enumeration attributes = req.getAttributeNames(); attributes.hasMoreElements();) { + String attribute = (String) attributes.nextElement(); + builder.append(" ATTRIBUTE[").append(attribute).append("]: ").append(req.getAttribute(attribute)).append(nl); + } + + builder.append(" ENCODING: ").append(req.getCharacterEncoding()).append(nl); + builder.append(" CONTENT_LENGTH: ").append(req.getContentLength()).append(nl); + builder.append(" CONTENT_TYPE: ").append(req.getContentType()).append(nl); + builder.append(" LOCALE: ").append(req.getLocale().toString()).append(nl); + + for (Enumeration parameters = req.getParameterNames(); parameters.hasMoreElements();) { + String parameter = (String) parameters.nextElement(); + builder.append(" PARAMETER[").append(parameter).append("]: ").append(req.getParameter(parameter)).append(nl); + } + + builder.append(" PROTOCOL: ").append(req.getProtocol()).append(nl); + builder.append(" REMOTE_ADDR: ").append(req.getRemoteAddr()).append(nl); + builder.append(" REMOTE_HOST: ").append(req.getRemoteHost()).append(nl); + builder.append(" SCHEME: ").append(req.getScheme()).append(nl); + builder.append(" SERVER_NAME: ").append(req.getServerName()).append(nl); + builder.append(" SERVER_PORT: ").append(req.getServerPort()).append(nl); + builder.append(" isSecure: ").append(req.isSecure()); + + LOG.finest(builder.toString()); + } + + /** + * A servlet request. + * + * @see JXTA Protocols Specification : Standard JXTA Transport Bindings : HTTP Bindings + */ + private static class JxtaRequest { + + /** + * Absolute time in milliseconds at which this request began processing. + */ + final long requestStartTime; + + /** + * Endpoint address of the requestor. + */ + final EndpointAddress requestorAddr; + + /** + * Duration of time to wait for the initial response message. + * + *

              + *
            • <0 : No response message wanted.
            • + *
            • 0 : Wait indefinitely for response message.
            • + *
            • >0 : Wait specified amount of time for response message.
            • + *
            + */ + final long responseTimeout; + + /** + * Duration of time to wait for additional response messages. + * + *

              + *
            • <0 : No additional response messages wanted.
            • + *
            • 0 : Wait indefinitely for additional response messages.
            • + *
            • >0 : Wait specified amount of time for additional response messages.
            • + *
            + */ + final long extraResponsesTimeout; + + /** + * Destination address for messages sent in this connection. + */ + final EndpointAddress destAddr; + + /** + * If true then the requestor is providing a Message. + */ + final boolean messageContent; + + /** + * Construct a request. + */ + JxtaRequest(HttpServletRequest req) { + + requestStartTime = TimeUtils.timeNow(); + + // check if a peerId was given + String requestorPeerId = getRequestorPeerId(req); + + if (null != requestorPeerId) { + requestorAddr = new EndpointAddress("jxta", requestorPeerId, null, null); + try { + EndpointRegistry.getInstance().add("urn:jxta:"+requestorPeerId, InetAddress.getByName(req.getRemoteHost())); + } catch (UnknownHostException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING,"cannot register ["+requestorPeerId+"]", e); + } + } + } else { + requestorAddr = null; + } + + // get the query string + String queryString = req.getQueryString(); + + if (queryString != null) { + // the query string is of the format responseTimeout,extraResponsesTimeout,destAdd + // the times given are in milliseconds + int commaIndex = queryString.indexOf(','); + + if (commaIndex == -1) { + // there is no extra responses timeout + responseTimeout = getResponseTimeout(queryString); + extraResponsesTimeout = -1; + destAddr = null; + } else { + responseTimeout = getResponseTimeout(queryString.substring(0, commaIndex)); + + String moreQueryParams = queryString.substring(commaIndex + 1); + + commaIndex = moreQueryParams.indexOf(','); + if (commaIndex == -1) { + extraResponsesTimeout = getExtraResponsesTimeout(moreQueryParams); + destAddr = null; + } else { + extraResponsesTimeout = getExtraResponsesTimeout(moreQueryParams.substring(0, commaIndex)); + destAddr = new EndpointAddress(moreQueryParams.substring(commaIndex + 1)); + } + } + } else { + responseTimeout = 0; + extraResponsesTimeout = -1; + destAddr = null; + } + + // check for incoming message + messageContent = hasMessageContent(req); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer( + "New JXTA Request for Requestor=" + requestorAddr + "\n\tResponse Timeout=" + responseTimeout + + "\tAdditional Response Timeout=" + extraResponsesTimeout + "\tRequest Destination Address=" + destAddr + + "\tHas Message Content=" + Boolean.toString(messageContent)); + } + } + + /** + * Returns the peerId of the peer making the request, if given + */ + private static String getRequestorPeerId(HttpServletRequest req) { + // get the potential PeerId from the PathInfo + String requestorPeerId = req.getPathInfo(); + + if (null != requestorPeerId) { + int begin = 0; + int end = requestorPeerId.length(); + + // check for all leading "/" + while (begin < end && requestorPeerId.charAt(begin) == '/') { + begin++; + } + + // check for all trailing "/" + while (end - begin > 0 && requestorPeerId.charAt(end - 1) == '/') { + end--; + } + + if (begin == end) { + // nothing left of the string + requestorPeerId = null; + } else { + // get the new substring + requestorPeerId = requestorPeerId.substring(begin, end); + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("requestorPeerId = " + requestorPeerId); + } + + return requestorPeerId; + } + + /** + * Returns the request timeout or -1 if a request timeout is not given + */ + private static long getResponseTimeout(String requestTimeoutString) { + // the default timeout is -1, which means do not return a message + long timeout = -1; + + try { + timeout = Long.parseLong(requestTimeoutString); + + // Protect agains clients that will try top have us keep + // connections for ever. If they re-establish all the time it's + // fine, but until we have a more sophisticated mechanism, we + // want to make sure we quit timely if the client's gone. + if (timeout > MAXIMUM_RESPONSE_DURATION || timeout == 0) { + timeout = MAXIMUM_RESPONSE_DURATION; + } + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("The requestTimeout does not contain a decimal number " + requestTimeoutString); + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("requestTimeout = " + timeout); + } + + return timeout; + } + + /** + * Returns the lazy close timeout or -1 if a lazy close timeout is not given + */ + private static long getExtraResponsesTimeout(String extraResponseTimeoutString) { + // the default timeout is -1, which means do not wait for additional messages + long timeout = -1; + + try { + timeout = Long.parseLong(extraResponseTimeoutString); + + // Protect agains clients that will try top have us keep + // connections for ever. If they re-establish all the time it's + // fine, but until we have a more sophisticated mechanism, we + // want to make sure we quit timely if the client's gone. + if (timeout > (2 * TimeUtils.AMINUTE) || timeout == 0) { + timeout = (2 * TimeUtils.AMINUTE); + } + } catch (NumberFormatException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("The extraResponseTimeoutString does not contain a decimal number " + extraResponseTimeoutString); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("extraResponseTimeout = " + timeout); + } + + return timeout; + } + + /** + * Checks if the request includes a message as content. + * + * @param req The request to be inspected. + * @return true if there is content to be read from this request. + */ + private static boolean hasMessageContent(HttpServletRequest req) { + boolean hasContent = false; + + int contentLength = req.getContentLength(); + + // if the content length is not zero, there is an incoming message + // Either the message length is given or it is a chunked message + if (contentLength > 0) { + hasContent = true; + } else if (contentLength == -1) { + // check if the transfer encoding is chunked + String transferEncoding = req.getHeader("Transfer-Encoding"); + + hasContent = "chunked".equals(transferEncoding); + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("hasMessageContent = " + hasContent); + } + + return hasContent; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpServletMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpServletMessenger.java new file mode 100644 index 000000000..3d72bf21d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/HttpServletMessenger.java @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.servlethttp; + +import java.util.Timer; +import java.util.TimerTask; + +import java.io.IOException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.peergroup.PeerGroupID; + +import net.jxta.impl.endpoint.BlockingMessenger; +import net.jxta.impl.endpoint.EndpointServiceImpl; +import net.jxta.impl.util.TimeUtils; + +/** + * Simple messenger that waits for a message to give back to the requesting client + * + *

            This messenger is not entirely thread-safe. You should not use any + * of the sendMessage methods from more than one thread. + * + */ +final class HttpServletMessenger extends BlockingMessenger { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(HttpServletMessenger.class.getName()); + + // We need an explicit idle state. outgoingMessage being null is not enough + // because there is an intermediate state where the http servlet must know + // that there is nothing new to be sent but the relay side must also know + // that status has not been collected yet (the messenger is not ready to be + // reused). We use outgoingMessage == null to know that the message + // has already been picked-up by the servlet thread, and + // sendResult != IDLE to know that the result has not yet been collected + // by the relay sender thread. + + private final static int SEND_IDLE = 0; + private final static int SEND_INPROGRESS = 1; + private final static int SEND_SUCCESS = 2; + private final static int SEND_FAIL = 3; + private final static int SEND_TOOLONG = 4; + + private final static long MAX_SENDING_BLOCK = 2 * TimeUtils.AMINUTE; + private final static long MAX_SENDING_WAIT = 3 * TimeUtils.ASECOND; + + private final static EndpointAddress nullEndpointAddr = new EndpointAddress("http", "0.0.0.0:0", null, null); + + private final static Timer closeMessengerTimer = new Timer("HttpServletMessenger Expiration timer", true); + + private final EndpointAddress logicalAddress; + private final MessageElement srcAddressElement; + private ScheduledExipry expirationTask; + + /** + * The message "queue" + */ + private Message outgoingMessage = null; + + private int sendResult = SEND_IDLE; + private long sendingSince = 0; + + /** + * Allows us to schedule the closing of a messenger. + */ + private static class ScheduledExipry extends TimerTask { + + /** + * The messenger we will be expiring. + */ + HttpServletMessenger messenger; + + ScheduledExipry(HttpServletMessenger toExpire) { + messenger = toExpire; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean cancel() { + // It is important we clear the messenger because Timer doesn't + // remove cancelled TimerTasks from it's queue until they fire. This + // means that the Messenger would not be GCed until the TimerTask + // fired. + messenger = null; + boolean result = super.cancel(); + + // take the opportunity to also purge canceled tasks + closeMessengerTimer.purge(); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + HttpServletMessenger temp = messenger; + + messenger = null; + + if (null != temp) { + temp.close(); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in timer task :" + Thread.currentThread().getName(), all); + } + } + } + } + + /** + * Standard constructor. + * + * @param peerGroupID the peer group id + * @param srcAddress source address + * @param logicalAddress logical address + * @param validFor validity in milliseconds + */ + HttpServletMessenger(PeerGroupID peerGroupID, EndpointAddress srcAddress, EndpointAddress logicalAddress, long validFor) { + + // We do not use self destruction. + super(peerGroupID, nullEndpointAddr, false); + + this.logicalAddress = logicalAddress; + + this.srcAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, srcAddress.toString(), null); + + if ((0 != validFor) && (validFor < Long.MAX_VALUE)) { + expirationTask = new ScheduledExipry(this); + + closeMessengerTimer.schedule(expirationTask, validFor); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("HttpServletMessenger\n\t" + toString()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void closeImpl() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("close\n\t" + toString()); + } + + ScheduledExipry cancelExpire = expirationTask; + + expirationTask = null; + if (null != cancelExpire) { + cancelExpire.cancel(); + } + + super.close(); + + notifyAll(); + } + + /** + * {@inheritDoc} + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + return logicalAddress; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdleImpl() { + // We do not use self destruction. + return false; + } + + /** + * Send messages. Messages are queued and processed by a thread + * running HttpClientConnection. + */ + @Override + public synchronized void sendMessageBImpl(Message message, String service, String serviceParam) throws IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Send " + message + " to " + dstAddress.toString() + "\n\t" + toString()); + } + + if (isClosed()) { + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, failure.getMessage(), failure); + } + + throw failure; + } + + // Set the message with the appropriate src and dest address + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, srcAddressElement); + + EndpointAddress destAddressToUse = getDestAddressToUse(service, serviceParam); + + MessageElement dstAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NAME, + destAddressToUse.toString(), null); + + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, dstAddressElement); + + // doSend returns false only when this messenger is closed. + if (!doSend(message)) { + // send message failed + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "sendMessage failed (messenger closed).\n\t" + toString(), failure); + } + + throw failure; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("sendMessage successful for " + message + "\n\t" + toString()); + } + } + + // Must be called from synchronized context only. + private boolean doSend(Message message) { + + // No need to wait for the messenger to be free. Transport + // messengers have no obligation to behave nicely if they're + // used by mltiple threads. If a thread comes here while + // we're already busy sending, then that's a congestion. Just + // drop the new message (pretend it went out). + // This is not even so nasty, because jetty has a sizeable + // output buffer. As long as that buffer is not full, sending + // is instantaneou. If sending starts blocking, then we can honestly + // drop messages. + + if (isClosed()) { + return false; + } + + long now = TimeUtils.timeNow(); + + if (sendResult != SEND_IDLE) { + // check if that connection is a lemon + if ((sendResult == SEND_TOOLONG) && (now > (sendingSince + MAX_SENDING_BLOCK))) { + close(); + } + return true; + } + + // put the message on the outgoing "queue" of size 1 + outgoingMessage = message; + sendResult = SEND_INPROGRESS; + sendingSince = now; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Queued " + message); + } + + // notify the servlet if it was waiting for a message + notifyAll(); + + // wait for the result of the send Since there is ample + // buffering underneath, we're not supposed to wait for long; + // unless we outdo the connection, in which case, we might as + // well start dropping. No point in blocking. + // FIXME: jice@jxta.org - this is a rudimentary fix. We need + // something like watchedOutputStream instead. Being forced + // to do a two-way handshake with a servlet thread is pretty + // ridiculous too. We need a simpler http transport. + + long absoluteTimeOut = TimeUtils.toAbsoluteTimeMillis(MAX_SENDING_WAIT); + + while (!isClosed()) { + if (sendResult != SEND_INPROGRESS) { + break; + } + + long waitfor = TimeUtils.toRelativeTimeMillis(absoluteTimeOut); + + if (waitfor <= 0) { + break; + } + + try { + wait(waitfor); + } catch (InterruptedException e) { + Thread.interrupted(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "InterruptedException timeout = " + MAX_SENDING_WAIT + "\n\t" + toString(), e); + } + break; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Got result\n\t" + toString()); + } + + if (isClosed() && (SEND_INPROGRESS == sendResult)) { + return false; + } + + // If the operation completed just confirm that we're done + // reading the result too. Else mark that we don't care. + // When it completes the result will be discarded. By default, + // the we return ok. If the operation did not complete fast + // enough, that's what we return. + + boolean result = (sendResult != SEND_FAIL); + + if (sendResult == SEND_INPROGRESS) { + sendResult = SEND_TOOLONG; + outgoingMessage = null; + } else { + sendResult = SEND_IDLE; + } + + // Let another contending thread use this messenger. + notifyAll(); + + return result; + } + + /** + * Retrieve a message from the "queue" of messages for the servlet. + * + * @param timeout Number of milliseconds to wait for a message. Per Java + * convention 0 (zero) means wait forever. + * @return the message or null if no message was available + * before the timeout was reached. + * @throws InterruptedException If the thread is interrupted while waiting. + */ + protected synchronized Message waitForMessage(long timeout) throws InterruptedException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting (" + (0 == timeout ? "forever" : Long.toString(timeout)) + ") for message\n\t" + toString()); + } + + if (0 == timeout) { + // it's forever + timeout = Long.MAX_VALUE; + } + + long absoluteTimeOut = TimeUtils.toAbsoluteTimeMillis(timeout); + + while (!isClosed() && (null == outgoingMessage)) { + long waitfor = TimeUtils.toRelativeTimeMillis(absoluteTimeOut); + + if (waitfor <= 0) { + break; + } + + wait(waitfor); + } + + // get the message + Message result = outgoingMessage; + + outgoingMessage = null; // Msg can only be picked-up once. + + if (!isClosed() && (result == null)) { + // ABSURD, but seems to happen: the message sent was NULL + // and the sender thread is waiting for the completion event. + // There would be no such thing, but we can make sure it stops + // waiting and still leave the messenger in a sane state if there + // was no such absurdity going on. + + sendResult = SEND_IDLE; + notifyAll(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Returning " + result + "\n\t" + toString()); + } + + return result; + } + + protected synchronized void messageSent(boolean wasSuccessful) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("messageSent(" + wasSuccessful + ")\n\t" + toString()); + } + + if (SEND_TOOLONG == sendResult) { + // No-one cares for the result any more. Let the next send go. + sendResult = SEND_IDLE; + } else { + sendResult = wasSuccessful ? SEND_SUCCESS : SEND_FAIL; + } + + notifyAll(); + } + + /** + * {@inheritDoc} + * + *

            An implementation for debugging. Do not depend on the format. + */ + @Override + public String toString() { + return "[" + super.toString() + "] isClosed=" + isClosed() + " sendResult=" + sendResult + " outmsg=" + outgoingMessage; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/ServletHttpTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/ServletHttpTransport.java new file mode 100644 index 000000000..fa19f8544 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/ServletHttpTransport.java @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.servlethttp; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import java.net.UnknownHostException; +import java.util.concurrent.Executor; + +import java.util.logging.Logger; +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.id.ID; +import net.jxta.meter.MonitorResources; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.TransportAdvertisement; +import net.jxta.platform.Module; + +import net.jxta.exception.PeerGroupException; + +import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings; +import net.jxta.impl.endpoint.transportMeter.TransportServiceMonitor; +import net.jxta.impl.endpoint.IPUtils; +import net.jxta.impl.protocol.HTTPAdv; + +import net.jxta.impl.meter.*; +import net.jxta.impl.peergroup.StdPeerGroup; + +/** + * A JXTA Message Transport + * + *

            This class is really a facade for the following:

              + *
            • An HTTP client message sender
            • + *
            • An HTTP-server-based message receiver
            • + *
            + */ +public final class ServletHttpTransport implements Module { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ServletHttpTransport.class.getName()); + + /** + * The name of the protocol + */ + private final static String DEFAULT_HTTP_PROTOCOL_NAME = "http"; + + String HTTP_PROTOCOL_NAME = DEFAULT_HTTP_PROTOCOL_NAME; + + /** + * PeerGroup we are working for + */ + PeerGroup group; + ID assignedID; + ModuleImplAdvertisement implAdvertisement; + + /** + * The executor used by HttpClientMessenger + */ + Executor executor; + + /** + * The endpoint we attach to. + */ + private EndpointService endpoint = null; + + /** + * If {@code true} then we are configured to act as an HTTP client. This + * means we will poll for messages. + */ + private boolean configClient = false; + + /** + * If {@code true} then we are configured to act as an HTTP server. This + * means we will accept connections from polling clients. + */ + private boolean configServer = false; + + /** + * The HttpMessageSender instance + */ + private HttpMessageSender sender = null; + + /** + * The HttpMessageReceiver instance + */ + private HttpMessageReceiver receiver = null; + + /** + * The TransportMeter for this httpTransport + */ + private TransportMeter transportMeter; + + /** + * The TransportBindingMeter for unknown connections (pings/errors) + */ + private TransportBindingMeter unknownTransportBindingMeter; + + /** + * The InetAddress of the network interface we are bound to otherwise the + * ALL/ANY address. + */ + InetAddress usingInterface = null; + + /** + * Port number to which we are bound. + */ + int usingPort = 0; + + /** + * The addresses which we will advertise and by which we may be reached. + */ + private List publicAddresses = null; + + /** + * Our preferred return address which we will use as the "source" for + * messages we send. + */ + private EndpointAddress publicAddress; + + /** + * {@inheritDoc} + */ + public synchronized void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + this.group = group; + this.assignedID = assignedID; + implAdvertisement = (ModuleImplAdvertisement) impl; + + this.executor = ((StdPeerGroup) group).getExecutor(); + + // Get out invariable parameters from the implAdv + XMLElement param = (XMLElement) implAdvertisement.getParam(); + + if (param != null) { + Enumeration list = param.getChildren("Proto"); + + if (list.hasMoreElements()) { + XMLElement pname = (XMLElement) list.nextElement(); + String configProtoName = pname.getTextValue(); + if (null != configProtoName) { + HTTP_PROTOCOL_NAME = configProtoName.trim(); + } + } + } + + ConfigParams peerAdv = group.getConfigAdvertisement(); + + param = (XMLElement) peerAdv.getServiceParam(assignedID); + + Enumeration httpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv + if (httpChilds.hasMoreElements()) { + param = (XMLElement) httpChilds.nextElement(); + Attribute typeAttr = param.getAttribute("type"); + + if (!HTTPAdv.getAdvertisementType().equals(typeAttr.getValue())) { + throw new IllegalArgumentException("Transport adv is not an http adv"); + } + + if (httpChilds.hasMoreElements()) { + throw new IllegalArgumentException("Configuration contained multiple http advertisements"); + } + } else { + throw new IllegalArgumentException("Configuration did not contain http advertisement"); + } + + Advertisement paramsAdv = AdvertisementFactory.newAdvertisement(param); + + if (!(paramsAdv instanceof HTTPAdv)) { + throw new IllegalArgumentException("Provided advertisement was not a " + HTTPAdv.getAdvertisementType()); + } + + HTTPAdv httpAdv = (HTTPAdv) paramsAdv; + + // determine the local interface to use. If the user specifies + // one, use that. Otherwise, use the all the available interfaces. + String interfaceAddressStr = httpAdv.getInterfaceAddress(); + boolean publicAddressOnly = httpAdv.getPublicAddressOnly(); + + if (interfaceAddressStr != null) { + try { + usingInterface = InetAddress.getByName(interfaceAddressStr); + } catch (UnknownHostException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid address for local interface address, using default"); + } + usingInterface = IPUtils.ANYADDRESS; + } + } else { + usingInterface = IPUtils.ANYADDRESS; + } + + usingPort = httpAdv.getPort(); + + configClient = httpAdv.isClientEnabled(); + + configServer = httpAdv.isServerEnabled(); + + publicAddresses = getPublicAddresses(configServer, httpAdv.getServer(), usingInterface, usingPort, publicAddressOnly); + + if (!configClient && !configServer) { + throw new IllegalArgumentException("Neither incoming nor outgoing connections configured."); + } + + publicAddress = publicAddresses.get(0); + + // Tell tell the world about our configuration. + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring HTTP Message Transport : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description: ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI: ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code: ").append(implAdvertisement.getCode()); + } + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: ").append(group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: ").append(group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: ").append(group.getPeerID()); + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tProtocol: ").append(httpAdv.getProtocol()); + configInfo.append("\n\t\tClient Enabled: ").append(configClient); + configInfo.append("\n\t\tServer Enabled: ").append(configServer); + configInfo.append("\n\t\tPublic address: ").append(httpAdv.getServer() == null ? "(unspecified)" : httpAdv.getServer()); + configInfo.append("\n\t\tInterface address: ").append(interfaceAddressStr == null ? "(unspecified)" : interfaceAddressStr); + configInfo.append("\n\t\tUnicast Server Bind Addr: ").append(IPUtils.getHostAddress(usingInterface)).append(":").append(usingPort); + configInfo.append("\n\t\tPublic Addresses: "); + configInfo.append("\n\t\t\tDefault Endpoint Addr : ").append(publicAddress); + for (EndpointAddress anAddr : publicAddresses) { + configInfo.append("\n\t\t\tEndpoint Addr : ").append(anAddr); + } + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized int startApp(String[] args) { + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + + return START_AGAIN_STALLED; + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + TransportServiceMonitor transportServiceMonitor = (TransportServiceMonitor) MonitorManager.getServiceMonitor(group, + MonitorResources.transportServiceMonitorClassID); + + if (transportServiceMonitor != null) { + transportMeter = transportServiceMonitor.createTransportMeter("HTTP", publicAddress); + unknownTransportBindingMeter = transportMeter.getTransportBindingMeter(TransportMeter.UNKNOWN_PEER, + TransportMeter.UNKNOWN_ADDRESS); + } + } + + if (configServer) { + // Start the http server that runs the receiver. + + try { + receiver = new HttpMessageReceiver(this, publicAddresses, usingInterface, usingPort); + receiver.start(); + } catch (PeerGroupException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not start http message receiver", e); + } + return -1; // Can't go on; if we were configured to be a server we must make the failure obvious. + } + } + + if (configClient) { + // create the MessageSender + + try { + sender = new HttpMessageSender(this, + new EndpointAddress("jxta", group.getPeerID().getUniqueValue().toString(), null, null)); + sender.start(); + } catch (PeerGroupException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not start http message sender", e); + } + return -1; // Can't go on; if we were configured to be a server we must make the failure obvious. + } + } + + return 0; + } + + /** + * {@inheritDoc} + */ + public synchronized void stopApp() { + if (receiver != null) { + receiver.stop(); + } + + if (sender != null) { + sender.stop(); + } + + endpoint = null; + } + + /** + * {@inheritDoc} + */ + EndpointService getEndpointService() { + return endpoint; + } + + private List getPublicAddresses(boolean serverEnabled, String serverName, InetAddress usingInterface, int serverSocketPort, boolean publicAddressOnly) { + List publicAddresses = new ArrayList(); + + if (serverEnabled) { + // Build the publicAddresses + + // first in the list is the "public server name". We don't try to + // resolve this since it might not be resolvable in the context + // we are running in, we just assume it's good. + if (serverName != null) { + // use speced server name. + EndpointAddress newAddr = new EndpointAddress(HTTP_PROTOCOL_NAME, serverName, null, null); + + publicAddresses.add(newAddr); + if (publicAddressOnly) { + return publicAddresses; + } + } + } + + // then add the rest of the local interfaces as appropriate + if (usingInterface.equals(IPUtils.ANYADDRESS)) { + // its wildcarded + Iterator eachLocal = IPUtils.getAllLocalAddresses(); + List wildAddrs = new ArrayList(); + + while (eachLocal.hasNext()) { + InetAddress anAddress = eachLocal.next(); + + String hostAddress = IPUtils.getHostAddress(anAddress); + + EndpointAddress newAddr = new EndpointAddress(HTTP_PROTOCOL_NAME, + hostAddress + ":" + Integer.toString(serverSocketPort), null, null); + + // don't add it if its already in the list + if (!publicAddresses.contains(newAddr)) { + wildAddrs.add(newAddr); + } + } + + // we sort them so that later equals() will be deterministic. + // the result of IPUtils.getAllLocalAddresses() is not known + // to be sorted. + Collections.sort(wildAddrs, new Comparator() { + public int compare(EndpointAddress one, EndpointAddress two) { + return one.toString().compareTo(two.toString()); + } + + @Override + public boolean equals(Object that) { + return this == that; + } + }); + + publicAddresses.addAll(wildAddrs); + } else { + // use specified interface + String hostAddress = IPUtils.getHostAddress(usingInterface); + + EndpointAddress newAddr = new EndpointAddress(HTTP_PROTOCOL_NAME, + hostAddress + ":" + Integer.toString(serverSocketPort), null, null); + + // don't add it if its already in the list + if (!publicAddresses.contains(newAddr)) { + publicAddresses.add(newAddr); + } + } + + return publicAddresses; + } + + TransportBindingMeter getTransportBindingMeter(String peerIDString, EndpointAddress destinationAddress) { + if (transportMeter != null) { + return transportMeter.getTransportBindingMeter((peerIDString != null) ? peerIDString : TransportMeter.UNKNOWN_PEER, + destinationAddress); + } else { + return null; + } + } + + TransportBindingMeter getUnknownTransportBindingMeter() { + return unknownTransportBindingMeter; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/package.html new file mode 100644 index 000000000..7a5ac9cce --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/package.html @@ -0,0 +1,19 @@ + + + + + + + A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which + uses the HTTP protocol. + + @see net.jxta.endpoint.EndpointService + @see net.jxta.endpoint.MessageTransport + @see net.jxta.endpoint.MessageSender + @see net.jxta.endpoint.MessageReceiver + @see net.jxta.endpoint.Message + + @see IETF 2068 : Hypertext Transfer Protocol -- HTTP/1.1 + @see JXTA Protocols Specification : Standard JXTA Transport Bindings + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/IncomingUnicastServer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/IncomingUnicastServer.java new file mode 100644 index 000000000..496d9f078 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/IncomingUnicastServer.java @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tcp; + +import net.jxta.logging.Logging; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.*; +import java.nio.channels.*; +import java.nio.channels.spi.SelectorProvider; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.RejectedExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This server handles incoming unicast TCP connections + */ +public class IncomingUnicastServer implements Runnable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(IncomingUnicastServer.class.getName()); + + /** + * The transport which owns this server. + */ + private final TcpTransport transport; + + /** + * The interface address the serverSocket will try to bind to. + */ + private final InetAddress serverBindLocalInterface; + + /** + * The beginning of the port range the serverSocket will try to bind to. + */ + private final int serverBindStartLocalPort; + + /** + * The port the serverSocket will try to bind to. + */ + private int serverBindPreferedLocalPort; + + /** + * The end of the port range the serverSocket will try to bind to. + */ + private final int serverBindEndLocalPort; + + /** + * The socket we listen for connections on. + */ + private ServerSocket serverSocket; + + /** + * If true then the we are closed or closing. + */ + private volatile boolean closed = false; + + /** + * The thread on which connection accepts will take place. + */ + private Thread acceptThread = null; + + /** + * Channel Selector + */ + private Selector acceptSelector = null; + + /** + * ServerSocket Channel + */ + private ServerSocketChannel serverSocChannel = null; + + /** + * Constructor for the TCP server + * + * @param owner the TCP transport we are working for + * @param serverInterface the network interface to use. + * @param preferedPort the port we will be listening on. + * @param startPort starting port + * @param endPort the endport in port range + * @throws IOException if an io severe occurs + * @throws SecurityException if a security exception occurs + */ + public IncomingUnicastServer(TcpTransport owner, InetAddress serverInterface, int preferedPort, int startPort, int endPort) throws IOException, SecurityException { + this.transport = owner; + serverBindLocalInterface = serverInterface; + serverBindPreferedLocalPort = preferedPort; + serverBindStartLocalPort = startPort; + serverBindEndLocalPort = endPort; + + openServerSocket(); + } + + /** + * Start this server. + * + * @return true if successfully started + */ + public synchronized boolean start() { + + if (acceptThread != null) { + return false; + } + + // Start daemon thread + acceptThread = new Thread(transport.group.getHomeThreadGroup(), this, "TCP Transport ServerSocket accept for " + transport.getPublicAddress()); + acceptThread.setDaemon(true); + acceptThread.start(); + return true; + } + + /** + * Stop this server. + */ + public synchronized void stop() { + closed = true; + + Thread temp = acceptThread; + + if (null != temp) { + // interrupt does not seem to have an effect on threads blocked in accept. + temp.interrupt(); + } + + // Closing the socket works though. + try { + serverSocket.close(); + } catch (IOException ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "IO error occured while closing server socket", ignored); + } + } + + try { + acceptSelector.close(); + } catch (IOException io) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "IO error occured while closing Selectors", io); + } + } + } + + /** + * Get the address of the network interface being used. + * + * @return the local socket address + */ + synchronized InetSocketAddress getLocalSocketAddress() { + ServerSocket localSocket = serverSocket; + + if (null != localSocket) { + return (InetSocketAddress) localSocket.getLocalSocketAddress(); + } else { + return null; + } + } + + /** + * Get the start port range we are using + * + * @return starting port range + */ + int getStartPort() { + return serverBindStartLocalPort; + } + + /** + * Get the end port range we are using + * + * @return the ending port range + */ + int getEndPort() { + return serverBindEndLocalPort; + } + + /** + * Daemon where we wait for incoming connections. + */ + public void run() { + try { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Server is ready to accept connections"); + } + + while (!closed) { + try { + if ((null == serverSocChannel) || !serverSocChannel.isOpen()) { + openServerSocket(); + if (null == serverSocChannel) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to open Server Channel"); + } + break; + } + } + acceptSelector.select(); + Iterator it = acceptSelector.selectedKeys().iterator(); + + while (it.hasNext()) { + SelectionKey key = it.next(); + + // remove it + it.remove(); + if (key.isAcceptable()) { + ServerSocketChannel nextReady = (ServerSocketChannel) key.channel(); + SocketChannel inputSocket = nextReady.accept(); + + if ((inputSocket == null) || (inputSocket.socket() == null)) { + continue; + } + + MessengerBuilder builder = new MessengerBuilder(inputSocket, transport); + + try { + transport.executor.execute(builder); + transport.incrementConnectionsAccepted(); + } catch (RejectedExecutionException re) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, MessageFormat.format("Executor rejected task : {0}", builder.toString()), re); + } + } + } + } + } catch (ClosedSelectorException cse) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Accept Selector closed"); + } + if (closed) { + break; + } + } catch (InterruptedIOException woken) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Accept Thread woken"); + } + } catch (IOException e1) { + if (closed) { + break; + } + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, + "[1] ServerSocket.accept() failed on " + serverSocket.getInetAddress() + ":"+ serverSocket.getLocalPort(), e1); + } + } catch (SecurityException e2) { + if (closed) { + break; + } + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "[2] ServerSocket.accept() failed on " + serverSocket.getInetAddress() + ":" + serverSocket.getLocalPort(), e2); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + synchronized (this) { + closed = true; + ServerSocket temp = serverSocket; + + serverSocket = null; + if (null != temp) { + try { + temp.close(); + } catch (IOException ignored) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Exception occurred while closing server socket", ignored); + } + } + } + acceptThread = null; + } + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Server has been shut down."); + } + } + } + + public List rangeCheckShuffle(int start, int end) { + if ((start < 1) || (start > 65535)) { + throw new IllegalArgumentException("Invalid start port"); + } + + if ((end < 1) || (end > 65535) || (end < start)) { + throw new IllegalArgumentException("Invalid end port"); + } + + // fill the inRange array. + List inRange = new ArrayList(); + + for (int eachInRange = start; eachInRange < end; eachInRange++) { + inRange.add(eachInRange); + } + Collections.shuffle(inRange); + return inRange; + } + + private synchronized void openServerSocket() throws IOException, SecurityException { + serverSocket = null; + while (true) { + try { + synchronized (this) { + acceptSelector = SelectorProvider.provider().openSelector(); + serverSocChannel = ServerSocketChannel.open(); + InetSocketAddress bindAddress; + + if (-1 != serverBindPreferedLocalPort) { + bindAddress = new InetSocketAddress(serverBindLocalInterface, serverBindPreferedLocalPort); + serverSocket = serverSocChannel.socket(); + int useBufferSize = Math.max(TcpTransport.RecvBufferSize, serverSocket.getReceiveBufferSize()); + + serverSocket.setReceiveBufferSize(useBufferSize); + serverSocket.bind(bindAddress, TcpTransport.MaxAcceptCnxBacklog); + } else { + List rangeList = rangeCheckShuffle(serverBindStartLocalPort, serverBindEndLocalPort); + + while (!rangeList.isEmpty()) { + int tryPort = rangeList.remove(0); + + if (tryPort > serverBindEndLocalPort) { + continue; + } + + try { + bindAddress = new InetSocketAddress(serverBindLocalInterface, tryPort); + serverSocket = serverSocChannel.socket(); + int useBufferSize = Math.max(TcpTransport.RecvBufferSize, serverSocket.getReceiveBufferSize()); + + serverSocket.setReceiveBufferSize(useBufferSize); + serverSocket.bind(bindAddress, TcpTransport.MaxAcceptCnxBacklog); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("ServerSocketChannel bound to " + bindAddress + ":" + tryPort); + } + } catch (SocketException failed) { + // this one is busy. try another. + } catch (Error err) { + // this can occur on some platforms where 2 instances are listenting on the same port + } + } + } + } + try { + // set the new channel non-blocking + serverSocChannel.configureBlocking(false); + serverSocChannel.register(acceptSelector, SelectionKey.OP_ACCEPT); + } catch (ClosedChannelException cce) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "Channel closed.", cce); + } + } + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Server will accept connections at " + serverSocket.getLocalSocketAddress()); + } + return; + } catch (BindException e0) { + if (-1 != serverBindStartLocalPort) { + serverBindPreferedLocalPort = (0 == serverBindStartLocalPort) ? 0 : -1; + continue; + } + closed = true; + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Cannot bind ServerSocket on " + serverBindLocalInterface + ":" + serverBindPreferedLocalPort, e0); + } + return; + } + } + } + + /** + * An Executor task that creates a messenger from an incoming SocketChannel + * object. + */ + private static class MessengerBuilder implements Runnable { + + private SocketChannel inputSocket; + private TcpTransport transport; + TcpMessenger newMessenger; + + MessengerBuilder(SocketChannel inputSocket, TcpTransport transport) { + assert inputSocket.socket() != null; + this.inputSocket = inputSocket; + this.transport = transport; + } + + /** + * {@inheritDoc} + */ + public void run() { + try { + if (inputSocket != null && inputSocket.isConnected()) { + newMessenger = new TcpMessenger(inputSocket, transport); + } + } catch (IOException io) { + // protect against invalid connections + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Messenger creation failure", io); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.SEVERE, "Uncaught Throwable", all); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/TcpMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/TcpMessenger.java new file mode 100644 index 000000000..da61b40a8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/TcpMessenger.java @@ -0,0 +1,1128 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.tcp; + +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.id.ID; +import net.jxta.impl.endpoint.BlockingMessenger; +import net.jxta.impl.endpoint.EndpointServiceImpl; +import net.jxta.impl.endpoint.msgframing.MessagePackageHeader; +import net.jxta.impl.endpoint.msgframing.WelcomeMessage; +import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.linphone.p2pproxy.core.jxtaext.EndpointRegistry; + +/** + * Implements a messenger which sends messages via raw TCP sockets. + */ +public class TcpMessenger extends BlockingMessenger implements Runnable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(TcpMessenger.class.getName()); + + /** + * The number of times we allow our write selector to be selected with no + * progress before we give up. + */ + private static final int MAX_WRITE_ATTEMPTS = 3; + + /** + * Description of our current location within the stream. + */ + private enum readState { + /** + * Reading the initial welcome + */ + WELCOME, + /** + * Reading a message header + */ + HEADER, + /** + * Reading a message + */ + BODY + } + + /** + * The source address of messages sent on this messenger. + */ + private final EndpointAddress srcAddress; + + private final MessageElement srcAddressElement; + + /** + * Cache of the logical destination of this messenger. (It helps if it works even after close) + */ + private EndpointAddress logicalDestAddress; + + /** + * The message tcpTransport we are working for. + */ + private final TcpTransport tcpTransport; + + private EndpointAddress dstAddress = null; + private EndpointAddress origAddress = null; + private EndpointAddress fullDstAddress = null; + private InetAddress inetAddress = null; + private int port = 0; + + private volatile boolean closed = false; + private boolean closingDueToFailure = false; + + private WelcomeMessage itsWelcome = null; + + private final long createdAt = TimeUtils.timeNow(); + private long lastUsed = TimeUtils.timeNow(); + + private SocketChannel socketChannel = null; + + private TransportBindingMeter transportBindingMeter; + + /** + * If this is an incoming connection we must not close it when the messenger + * disappears. It has many reasons to disappear while the connection must + * keep receiving messages. This is causing some problems for incoming + * messengers that are managed by some entity, such as the router or the + * relay. These two do call close explicitly when they discard a messenger, + * and their intent is truly to close the underlying connection. So + * basically we need to distinguish between incoming messengers that are + * abandoned without closing (for these we must protect the input side + * because that's the only reason for the connection being there) and + * incoming messengers that are explicitly closed (in which case we must let + * the entire connection be closed). + */ + private boolean initiator; + + private AtomicReference state = new AtomicReference(readState.WELCOME); + + private final static int MAX_LEN = 4096; + private ByteBuffer buffer = ByteBuffer.allocate(MAX_LEN); + + /** + * Header from the current incoming message (if any). + */ + private MessagePackageHeader header = null; + + /** + * Time at which we began receiving the current incoming message. + */ + long receiveBeginTime = 0; + + /** + * Enforces single writer on message write in case the messenger is being + * used on multiple threads. + */ + private final ReentrantLock writeLock = new ReentrantLock(); + + /** + * Create a new TcpMessenger for the specified address. + * + * @param socketChannel the SocketChannel for the messenger + * @param transport the tcp MessageSender we are working for. + * @throws java.io.IOException if an io error occurs + */ + TcpMessenger(SocketChannel socketChannel, TcpTransport transport) throws IOException { + super(transport.group.getPeerGroupID(), + new EndpointAddress(transport.getProtocolName(), + socketChannel.socket().getInetAddress().getHostAddress() + ":" + socketChannel.socket().getPort(), null, null), true); + + initiator = false; + this.socketChannel = socketChannel; + this.tcpTransport = transport; + this.srcAddress = transport.getPublicAddress(); + this.srcAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, srcAddress.toString(), null); + + try { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Connection from " + socketChannel.socket().getInetAddress().getHostAddress() + ":" + socketChannel.socket().getPort()); + } + + // Set the socket options. + Socket socket = socketChannel.socket(); + + int useBufferSize = Math.max(TcpTransport.SendBufferSize, socket.getSendBufferSize()); + + socket.setSendBufferSize(useBufferSize); + + inetAddress = socketChannel.socket().getInetAddress(); + port = socketChannel.socket().getPort(); + + socket.setKeepAlive(true); + socket.setSoTimeout(TcpTransport.connectionTimeOut); + socket.setSoLinger(true, TcpTransport.LingerDelay); + + // Disable Nagle's algorithm (We do this to reduce latency) + socket.setTcpNoDelay(true); + + // Temporarily, our address for inclusion in the welcome message response. + dstAddress = new EndpointAddress(this.tcpTransport.getProtocolName(), inetAddress.getHostAddress() + ":" + port, null, null); + fullDstAddress = dstAddress; + + startMessenger(); + } catch (IOException io) { + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + transportBindingMeter = this.tcpTransport.getUnicastTransportBindingMeter(null, dstAddress); + if (transportBindingMeter != null) { + transportBindingMeter.connectionFailed(initiator, TimeUtils.timeNow() - createdAt); + } + } + // If we failed for any reason, make sure the socket is closed. + // We're the only one to know about it. + if (socketChannel != null) { + socketChannel.close(); + } + throw io; + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + transportBindingMeter = this.tcpTransport.getUnicastTransportBindingMeter((PeerID) getDestinationPeerID(), dstAddress); + if (transportBindingMeter != null) { + transportBindingMeter.connectionEstablished(initiator, TimeUtils.timeNow() - createdAt); + } + } + if (!isConnected()) { + throw new IOException("Failed to establish connection to " + dstAddress); + } + } + + + /** + * Create a new TcpMessenger for the specified address. + * + * @param destaddr the destination of the messenger + * @param tcpTransport the tcp MessageSender we are working for. + * @throws java.io.IOException if an io error occurs + */ + TcpMessenger(EndpointAddress destaddr, TcpTransport tcpTransport) throws IOException { + this(destaddr, tcpTransport, true); + } + + /** + * Create a new TcpMessenger for the specified address. + * + * @param destaddr the destination of the messenger + * @param tcpTransport the tcp MessageSender we are working for. + * @param selfDestruct indicates whether the messenger created will self destruct when idle + * @throws java.io.IOException if an io error occurs + */ + TcpMessenger(EndpointAddress destaddr, TcpTransport tcpTransport, boolean selfDestruct) throws IOException { + // We need self destruction: tcp messengers are expensive to make and they refer to + // a connection that must eventually be closed. + super(tcpTransport.group.getPeerGroupID(), destaddr, selfDestruct); + this.origAddress = destaddr; + + initiator = true; + this.tcpTransport = tcpTransport; + + this.fullDstAddress = destaddr; + this.dstAddress = new EndpointAddress(destaddr, null, null); + + this.srcAddress = tcpTransport.getPublicAddress(); + + srcAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, srcAddress.toString(), null); + + String protoAddr = destaddr.getProtocolAddress(); + int portIndex = protoAddr.lastIndexOf(":"); + + if (portIndex == -1) { + throw new IllegalArgumentException("Invalid Protocol Address (port # missing) "); + } + + String portString = protoAddr.substring(portIndex + 1); + try { + port = Integer.valueOf(portString); + } catch (NumberFormatException caught) { + throw new IllegalArgumentException("Invalid Protocol Address (port # invalid): " + portString); + } + + // Check for bad port number. + if ((port <= 0) || (port > 65535)) { + throw new IllegalArgumentException("Invalid port number in Protocol Address : " + port); + } + + String hostString = protoAddr.substring(0, portIndex); + + inetAddress = InetAddress.getByName(hostString); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Creating new TCP Connection to : " + dstAddress + " / " + inetAddress.getHostAddress() + ":" + port); + } + + // See if we're attempting to use the loopback address. + // And if so, is the peer configured for the loopback network only? + // (otherwise the connection is not permitted). Btw, the otherway around + // is just as wrong, so we check both at once and pretend it cannot work, + // even if it might have. + // FIXME 20041130 This is not an appropriate check if the other peer is + // running on the same machine and the InetAddress.getByName returns the + // loopback address. + // if (inetAddress.isLoopbackAddress() != tcpTransport.usingInterface.isLoopbackAddress()) { + // throw new IOException("Network unreachable--connect to loopback attempted."); + // } + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Connecting to " + inetAddress.getHostAddress() + ":" + port + " via " + + this.tcpTransport.usingInterface.getHostAddress() + ":0"); + } + + socketChannel = SocketChannel.open(); + Socket socket = socketChannel.socket(); + + // Bind it to our outbound interface. + SocketAddress bindAddress = new InetSocketAddress(this.tcpTransport.usingInterface, 0); + + socket.bind(bindAddress); + // Set Socket options. + int useBufferSize = Math.max(TcpTransport.SendBufferSize, socket.getSendBufferSize()); + socket.setSendBufferSize(useBufferSize); + + useBufferSize = Math.max(TcpTransport.RecvBufferSize, socket.getReceiveBufferSize()); + socket.setReceiveBufferSize(useBufferSize); + + socket.setKeepAlive(true); + socket.setSoTimeout(TcpTransport.connectionTimeOut); + socket.setSoLinger(true, TcpTransport.LingerDelay); + // Disable Nagle's algorithm (We do this to reduce latency) + socket.setTcpNoDelay(true); + + SocketAddress connectAddress = new InetSocketAddress(inetAddress, port); + socketChannel.connect(connectAddress); + + startMessenger(); + } catch (IOException io) { + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + transportBindingMeter = this.tcpTransport.getUnicastTransportBindingMeter(null, dstAddress); + + if (transportBindingMeter != null) { + transportBindingMeter.connectionFailed(initiator, TimeUtils.timeNow() - createdAt); + } + } + // If we failed for any reason, make sure the socket is closed. This is the only place it is known. + if (socketChannel != null) { + socketChannel.close(); + } + throw io; + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + transportBindingMeter = this.tcpTransport.getUnicastTransportBindingMeter((PeerID) getDestinationPeerID(), dstAddress); + if (transportBindingMeter != null) { + transportBindingMeter.connectionEstablished(initiator, TimeUtils.timeNow() - createdAt); + } + // TODO: We need to add the bytes from the Welcome Messages to the transportBindingMeter, iam@jxta.org + } + + if (!isConnected()) { + throw new IOException("Failed to establish connection to " + dstAddress); + } + } + + /** + * The cost of just having a finalize routine is high. The finalizer is + * a bottleneck and can delay garbage collection all the way to heap + * exhaustion. Leave this comment as a reminder to future maintainers. + * Below is the reason why finalize is not needed here. + *

            + * These messengers are never given to application layers. Endpoint code + * always calls close when needed. + *

            + * There used to be an incoming special case in order to *prevent* + * closure because the inherited finalize used to call close. This is + * no-longer the case. For the outgoing case, we do not need to call close + * for the reason explained above. + */ + protected void finalize() throws Throwable { + closeImpl(); + super.finalize(); + } + + /** + * {@inheritDoc} + *

            + * Now everyone knows its closed and the connection can no-longer be + * obtained. So, we can go about our business of closing it. + * It can happen that a redundant close() is done but it does not matter. + * close() is idempotent. + */ + public synchronized void closeImpl() { + super.close(); + + if (closed) { + return; + } + + closed = true; + + // we are idle now. Way idle. + setLastUsed(0); + if (socketChannel != null) { + // unregister from selector. + tcpTransport.unregister(socketChannel); + try { + socketChannel.close(); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to close messenger " + toString(), e); + } + } + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info((closingDueToFailure ? "Failure" : "Normal") + " close (open " + + TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), createdAt) + "ms) of socket to : " + dstAddress + " / " + + inetAddress.getHostAddress() + ":" + port); + if (closingDueToFailure && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "stack trace", new Throwable("stack trace")); + } + } + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + if (closingDueToFailure) { + transportBindingMeter.connectionDropped(initiator, TimeUtils.timeNow() - createdAt); + } else { + transportBindingMeter.connectionClosed(initiator, TimeUtils.timeNow() - createdAt); + } + } + } + + /** + * {@inheritDoc} + */ + public boolean isClosed() { + // FIXME - jice 20040413: Warning. this is overloading the standard + // isClosed(). Things were arranged so that it + // should still work, but it's a stretch. Transports should get a deeper + // retrofit eventually. + if (isConnected()) { + return false; + } + + // Ah, this connection is broken. So, we weren't closed, but now + // we are. That could happen redundantly since two threads could + // find that holdIt.isConnected() is false before one of them + // first zeroes conn. But it does not matter. super.close() is + // idempotent (and does pretty much nothing in our case, anyway). + super.close(); + return true; + } + + /** + * {@inheritDoc} + *

            + * Since we probe the connection status, we'll keep a messenger as long + * as the connection is active, even if only on the incoming side. + * So we're being a bit nice to the other side. Anyway, incoming + * connections do not go away when the messenger does. There's a receive + * timeout for that. + */ + public boolean isIdleImpl() { + return (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), getLastUsed()) > 15 * TimeUtils.AMINUTE); + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getLogicalDestinationImpl() { + // FIXME 20070127 bondolo THIS IS BEING CALLED BEFORE IT IS INITED. + return logicalDestAddress; + } + + /** + * {@inheritDoc} + */ + public void sendMessageBImpl(Message message, String service, String serviceParam) throws IOException { + sendMessageDirect(message, service, serviceParam, false); + } + + public void sendMessageDirect(Message message, String service, String serviceParam, boolean direct) throws IOException { + if (isClosed()) { + IOException failure = new IOException("Messenger was closed, it cannot be used to send messages."); + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failure.getMessage(), failure); + } + throw failure; + } + + // Set the message with the appropriate src and dest address + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, srcAddressElement); + EndpointAddress destAddressToUse; + if (direct) { + destAddressToUse = origAddress; + } else { + destAddressToUse = getDestAddressToUse(service, serviceParam); + } + + MessageElement dstAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NAME, destAddressToUse.toString(), null); + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, dstAddressElement); + + // send it + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + message + " to " + destAddressToUse + " on connection " + getDestinationAddress()); + } + xmitMessage(message); + } catch (IOException caught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Message send failed for " + message, caught); + } + closeImpl(); + throw caught; + } + } + + private void startMessenger() throws IOException { + socketChannel.configureBlocking(true); + + // Send the welcome message + WelcomeMessage myWelcome = new WelcomeMessage(fullDstAddress, + tcpTransport.getPublicAddress(), + tcpTransport.group.getPeerID(), false); + long written = write(new ByteBuffer[]{myWelcome.getByteBuffer()}); + tcpTransport.incrementBytesSent(written); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("welcome message sent"); + } + while (state.get() == readState.WELCOME) { + if (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), this.createdAt) > (TcpTransport.connectionTimeOut)) { + throw new SocketTimeoutException("Failed to receive remote welcome message before timeout."); + } + read(); + processBuffer(); + } + if (!closed) { + socketChannel.configureBlocking(false); + tcpTransport.register(socketChannel, this); + } + } + + /** + * Send message to the remote peer. + * + * @param msg the message to send. + * @throws java.io.IOException For errors sending the message. + */ + private void xmitMessage(Message msg) throws IOException { + + if (closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Connection was closed to : " + dstAddress); + } + throw new IOException("Connection was closed to : " + dstAddress); + } + + long sendBeginTime = TimeUtils.timeNow(); + long size = 0; + + try { + // todo 20020730 bondolo@jxta.org Do something with content-coding here + // serialize the message. + WireFormatMessage serialed = WireFormatMessageFactory.toWire(msg, WireFormatMessageFactory.DEFAULT_WIRE_MIME, null); + + // Build the package header + MessagePackageHeader header = new MessagePackageHeader(); + + header.setContentTypeHeader(serialed.getMimeType()); + size = serialed.getByteLength(); + header.setContentLengthHeader(size); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " (" + size + ") to " + dstAddress + " via " + inetAddress.getHostAddress() + ":"+ port); + } + + List partBuffers = new ArrayList(); + + partBuffers.add(header.getByteBuffer()); + partBuffers.addAll(Arrays.asList(serialed.getByteBuffers())); + + long written; + writeLock.lock(); + try { + written = write(partBuffers.toArray(new ByteBuffer[partBuffers.size()])); + } finally { + writeLock.unlock(); + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.messageSent(initiator, msg, TimeUtils.timeNow() - sendBeginTime, written); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Sent {0} bytes {1} successfully via {2}:{3}", written, msg, + inetAddress.getHostAddress(), port)); + } + + tcpTransport.incrementBytesSent(written); + tcpTransport.incrementMessagesSent(); + setLastUsed(TimeUtils.timeNow()); + } catch (SocketTimeoutException failed) { + SocketTimeoutException failure = new SocketTimeoutException("Failed sending " + msg + " to : " + inetAddress.getHostAddress() + ":" + port); + failure.initCause(failed); + throw failure; + } catch (IOException failed) { + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.sendFailure(initiator, msg, TimeUtils.timeNow() - sendBeginTime, size); + } + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Message send failed for " + inetAddress.getHostAddress() + ":" + port, failed); + } + closingDueToFailure = true; + close(); + IOException failure = new IOException("Failed sending " + msg + " to : " + inetAddress.getHostAddress() + ":" + port); + + failure.initCause(failed); + throw failure; + } + } + + /** + * Blocking write of byte buffers to the socket channel. + * + * @param byteBuffers The bytes to write. + * @return The number of bytes written. + * @throws IOException Thrown for errors while writing message. + */ + private long write(final ByteBuffer[] byteBuffers) throws IOException { + + // Determine how many bytes there are to be written in the buffers. + long bytesToWrite = 0; + for (ByteBuffer byteBuffer : byteBuffers) { + bytesToWrite += byteBuffer.remaining(); + } + + if (bytesToWrite == 0L) { + return 0L; + } + + long bytesWritten = 0; + Selector writeSelector = null; + SelectionKey wKey = null; + int attempts = 1; + try { + do { + long wroteBytes; + // Write from the buffers until we write nothing. + do { + wroteBytes = socketChannel.write(byteBuffers); + bytesWritten += wroteBytes; + if (wroteBytes < 0) { + throw new EOFException(); + } + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("Wrote {0} bytes", wroteBytes)); + } + } while (wroteBytes != 0); + + // Are we done? + if (bytesWritten == bytesToWrite) { + break; + } + // This attempt failed, we may try again. + attempts++; + if (attempts > MAX_WRITE_ATTEMPTS) { + throw new IOException(MessageFormat.format("Max write attempts ({0}) exceeded ({1})", attempts, MAX_WRITE_ATTEMPTS)); + } + + // Get a write selector, we're going to do some waiting. + if (writeSelector == null) { + try { + writeSelector = tcpTransport.getSelector(); + } catch (InterruptedException woken) { + InterruptedIOException incompleteIO = new InterruptedIOException("Interrupted while acquiring write selector."); + incompleteIO.initCause(woken); + incompleteIO.bytesTransferred = (int) Math.min(bytesWritten, Integer.MAX_VALUE); + throw incompleteIO; + } + if (writeSelector == null) { + continue; + } + wKey = socketChannel.register(writeSelector, SelectionKey.OP_WRITE); + } + + // Wait until we are told we can write again. + int ready = writeSelector.select(TcpTransport.connectionTimeOut); + + if (ready == 0) { + throw new SocketTimeoutException("Timeout during socket write"); + } else { + attempts--; + } + } while (attempts <= MAX_WRITE_ATTEMPTS); + } finally { + // cancel the key before returning selector to the pool. + if (wKey != null) { + wKey.cancel(); + wKey = null; + } + + // put the selector back in the pool + if (writeSelector != null) { + // clean up the selector + writeSelector.selectNow(); + tcpTransport.returnSelector(writeSelector); + } + } + return bytesWritten; + } + + /** + * parses a welcome from a buffer + * + * @param buffer the buffer to parse, if successful the state is set to HEADER + * @return true if successfully parsed + */ + private boolean processWelcome(ByteBuffer buffer) { + try { + if (itsWelcome == null) { + itsWelcome = new WelcomeMessage(); + } + + if (!itsWelcome.read(buffer)) { + return false; + } + + // The correct value for dstAddr: that of the other party. + dstAddress = itsWelcome.getPublicAddress(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating a logical address from : " + itsWelcome.getWelcomeString()); + } + EndpointRegistry.getInstance().add(itsWelcome.getPeerID().toString(), socketChannel.socket().getInetAddress()); + fullDstAddress = dstAddress; + logicalDestAddress = new EndpointAddress("jxta", itsWelcome.getPeerID().getUniqueValue().toString(), null, null); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Hello from " + itsWelcome.getPublicAddress() + " [" + itsWelcome.getPeerID() + "] "); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Registering Messenger from " + socketChannel.socket().getInetAddress().getHostAddress() + ":"+ socketChannel.socket().getPort()); + } + + try { + // announce this messenger by connection address + tcpTransport.messengerReadyEvent(this, getConnectionAddress()); + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + IOException failure = new IOException("Failure announcing messenger."); + + failure.initCause(all); + throw failure; + } + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Error while parsing the welcome message", e); + } + closeImpl(); + return false; + } + return true; + } + + /** + * parses a header from a buffer + * + * @param buffer the buffer to parse, if successful the state is set to BODY + * @return true if successfully parsed + */ + private boolean processHeader(ByteBuffer buffer) { + + if (null == header) { + header = new MessagePackageHeader(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} Processing message package header, buffer stats:{1}", Thread.currentThread(), buffer.toString())); + } + try { + if (!header.readHeader(buffer)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} maintaining current state at header, buffer stats :{1}", Thread.currentThread(), buffer.toString())); + } + return false; + } + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Error while parsing the message header", e); + } + if (!socketChannel.isConnected()) { + // defunct connection close the messenger + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SocketChannel closed. Closing the messenger"); + } + closeImpl(); + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} setting current state to body, Buffer stats :{1}, remaining elements {2}:", + Thread.currentThread(), buffer.toString(), buffer.remaining())); + } + return true; + } + + private Message processMessage(ByteBuffer buffer, MessagePackageHeader header) throws IOException { + // TODO 20020730 bondolo@jxta.org Do something with content-coding here. + MimeMediaType msgMime = header.getContentTypeHeader(); + + return WireFormatMessageFactory.fromBuffer(buffer, msgMime, null); + } + + /** + * {@inheritDoc} + *

            + * This is what gets run by the Executor. It reads whatever is available, + * processes it and then goes back to the selector waiting for more IO + */ + public void run() { + try { + while (read()) { + List msgs = processBuffer(); + for (Message msg : msgs) { + // Use the group's threadpool to process the message + tcpTransport.executor.execute(new MessageProcessor(msg)); + } + } + + // resets the interestOPS and wakeup the selector + if (socketChannel != null) { + tcpTransport.register(socketChannel, this); + } + + } catch (Throwable all) { + if (Logging.SHOW_SEVERE) { + LOG.log(Level.SEVERE, "Uncaught Throwable", all); + } + } + } + + /** + * @return true to indicate read maybe required + */ + private boolean read() { + if (closed || socketChannel == null) { + return false; + } + if (!socketChannel.isConnected()) { + closeImpl(); + return false; + } + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} State before read(): {1}, buffer stats : {2}, remaining :{3}", + Thread.currentThread(), state.get(), buffer.toString(), buffer.remaining())); + } + + int read = socketChannel.read(buffer); + if (read < 0) { + if (!socketChannel.isConnected() || read < 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} Closing due to EOF", Thread.currentThread())); + } + closeImpl(); + } + return false; + } else if (read == 0) { + return false; + } + + tcpTransport.incrementBytesReceived(read); + // prepare the buffer for reading + buffer.flip(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} SocketChannel.read() == {1} bytes. Buffer stats:{2}, remaining {3}", + Thread.currentThread(), read, buffer.toString(), buffer.remaining())); + } + return true; + } catch (ClosedChannelException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Channel closed while reading data", e); + } + closeImpl(); + return false; + } catch (InterruptedIOException woken) { + // Framing is maintained within this object, therefore a read maybe interrupted then resumed + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(MessageFormat.format("tcp receive - interrupted : read() {0} {1}:{2}", woken.bytesTransferred, + inetAddress.getHostAddress(), port)); + } + } catch (IOException ioe) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "IOException occured while reading data", ioe); + } + closeImpl(); + return false; + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, MessageFormat.format("tcp receive - Error on connection {0}:{1}", inetAddress.getHostAddress(), port), e); + } + closingDueToFailure = true; + closeImpl(); + return false; + } + // if the channel has a valid read ops return true, otherwise false + return (socketChannel.validOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ; + } + + /** + * processes the input byte buffer + * @return the list of messages present in the buffer + */ + @SuppressWarnings("fallthrough") + public List processBuffer() { + + List msgs = new ArrayList(); + boolean done = false; + + while (!done) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} processBuffer({1}). Buffer stats:{2}, elements remaining {3}", + Thread.currentThread(), state.getClass(), buffer.toString(), buffer.remaining())); + } + + switch (state.get()) { + case WELCOME: + // Parse Welcome message + boolean wseen = processWelcome(buffer); + + if (wseen) { + state.set(readState.HEADER); + } + done = true; + break; + + case HEADER: + // process the message header + boolean hseen = processHeader(buffer); + + if (!hseen) { + done = true; + break; + } + + receiveBeginTime = TimeUtils.timeNow(); + // todo add a check for MTU size + if (header.getContentLengthHeader() > buffer.capacity()) { + ByteBuffer src = buffer; + + // create an array backed buffer + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} Reallocating a new buffer of size {1} to replace :{2}", + Thread.currentThread(), header.getContentLengthHeader(), buffer.toString())); + } + + // This implementation limits the message size to the MTU which is always < 2GB + buffer = ByteBuffer.allocate((int) header.getContentLengthHeader()); + buffer.put(src); + buffer.flip(); + } + state.set(readState.BODY); + /* FALLSTHROUGH */ + + case BODY: + // process the message body + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format(" {0} Proccessing Message Body. expecting {1}, {2} elements remaining {3}", + Thread.currentThread(), header.getContentLengthHeader(), buffer.toString(), buffer.remaining())); + } + if (buffer.remaining() >= (int) header.getContentLengthHeader()) { + Message msg; + try { + msg = processMessage(buffer, header); + } catch (IOException io) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to parse a message from buffer. closing connection", io); + } + closeImpl(); + done = true; + break; + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING && (transportBindingMeter != null)) { + transportBindingMeter.messageReceived(initiator, msg, TimeUtils.timeNow() - receiveBeginTime, + header.getContentLengthHeader()); + } + + tcpTransport.incrementMessagesReceived(); + setLastUsed(TimeUtils.timeNow()); + state.set(readState.HEADER); + header = null; + + msgs.add(msg); + } else { + done = true; + break; + } + } + } // while loop + + // prepare the buffer for more data + buffer.compact(); + return msgs; + } + + /** + * A small class for processing individual messages. + */ + private class MessageProcessor implements Runnable { + + private Message msg; + MessageProcessor(Message msg) { + this.msg = msg; + } + public void run() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("{0} calling EndpointService.demux({1})", + Thread.currentThread(), + msg, inetAddress.getHostAddress(), port)); + } + tcpTransport.endpoint.demux(msg); + } + } + + /** + * return the current connection status. + * + * @return true if there is an active connection to the remote peer, otherwise false. + */ + private boolean isConnected() { + return !closed; + } + + /** + * Return the absolute time in milliseconds at which this Connection was last used. + * + * @return absolute time in milliseconds. + */ + private long getLastUsed() { + return lastUsed; + } + + /** + * Set the last used time for this connection in absolute milliseconds. + * + * @param time absolute time in milliseconds. + */ + private void setLastUsed(long time) { + lastUsed = time; + } + + /** + * Returns the metering object for this tcpTransport + * + * @return the metering object for this tcpTransport + */ + TransportBindingMeter getTransportBindingMeter() { + return transportBindingMeter; + } + + /** + * Returns the remote address + * + * @return the remote address + */ + private EndpointAddress getConnectionAddress() { + // Somewhat confusing but destinationAddress is the name of that thing + // for the welcome message. + return itsWelcome.getDestinationAddress(); + } + + /** + * Returns Remote PeerID + * + * @return Remote PeerID + */ + private ID getDestinationPeerID() { + return itsWelcome.getPeerID(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/TcpTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/TcpTransport.java new file mode 100644 index 000000000..ead443f6f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/TcpTransport.java @@ -0,0 +1,1236 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.endpoint.tcp; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.SelectorProvider; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessengerEvent; +import net.jxta.endpoint.MessengerEventListener; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.meter.MonitorResources; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.TransportAdvertisement; + +import net.jxta.impl.endpoint.IPUtils; +import net.jxta.impl.endpoint.LoopbackMessenger; +import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeter; +import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings; +import net.jxta.impl.endpoint.transportMeter.TransportServiceMonitor; +import net.jxta.impl.meter.MonitorManager; +import net.jxta.impl.peergroup.StdPeerGroup; +import net.jxta.impl.protocol.TCPAdv; +import net.jxta.impl.util.TimeUtils; + + +/** + * This class implements the TCP Message Transport. + * + * @see net.jxta.endpoint.MessageTransport + * @see net.jxta.endpoint.MessagePropagater + * @see net.jxta.endpoint.MessageReceiver + * @see net.jxta.endpoint.MessageSender + * @see net.jxta.endpoint.EndpointService + * @see JXTA Protocols Specification : Standard JXTA Transport Bindings + */ +public class TcpTransport implements Module, MessageSender, MessageReceiver { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(TcpTransport.class.getName()); + + /** + * The TCP send buffer size. + * The size of the buffer used to store outgoing messages + * This should be set to the maximum message size (smaller is allowed). + */ + static final int SendBufferSize = 64 * 1024; // 64 KBytes + + /** + * The TCP receive buffer size + */ + static final int RecvBufferSize = 64 * 1024; // 64 KBytes + + /** + * The amount of time the socket "lingers" after we close it locally. + * Linger enables the remote socket to finish receiving any pending data + * at its own rate. + * Note: LingerDelay time unit is seconds + */ + static final int LingerDelay = 2 * 60; + + /** + * Connection timeout + * use the same system property defined by URLconnection, otherwise default to 10 seconds. + */ + static int connectionTimeOut = 10 * (int) TimeUtils.ASECOND; + + // Java's default is 50 + static final int MaxAcceptCnxBacklog = 50; + + private String serverName = null; + private final List publicAddresses = new ArrayList(); + private EndpointAddress publicAddress = null; + + private String interfaceAddressStr; + InetAddress usingInterface; + private int serverSocketPort; + private int restrictionPort = -1; + private IncomingUnicastServer unicastServer = null; + + private boolean isClosed = false; + + private long messagesSent = 0; + private long messagesReceived = 0; + private long bytesSent = 0; + private long bytesReceived = 0; + private long connectionsAccepted = 0; + + PeerGroup group = null; + EndpointService endpoint = null; + Executor executor; + + private String protocolName = "tcp"; + private TransportMeter unicastTransportMeter; + private TransportMeter multicastTransportMeter; + + private boolean publicAddressOnly = false; + + private MessengerEventListener messengerEventListener = null; + + private Thread messengerSelectorThread; + Selector messengerSelector = null; + + private final Map regisMap = new ConcurrentHashMap(); + private final Set unregisMap = Collections.synchronizedSet(new HashSet()); + + /** + * This is the thread group into which we will place all of the threads + * we create. THIS HAS NO EFFECT ON SCHEDULING. Java thread groups are + * only for organization and naming. + */ + ThreadGroup myThreadGroup = null; + + /** + * The maximum number of write selectors we will maintain in our cache per + * transport instance. + */ + protected final static int MAX_WRITE_SELECTORS = 50; + + /** + * A cache we maintain for selectors writing messages to the socket. + */ + private final static Stack writeSelectorCache = new Stack(); + + /** + * The number of excess write selectors believed to be in the pool. + */ + private int extraWriteSelectors = 0; + + /** + * Construct a new TcpTransport instance + */ + public TcpTransport() { + // Add some selectors to the pool. + try { + for (int i = 0; i < MAX_WRITE_SELECTORS; i++) { + writeSelectorCache.add(Selector.open()); + } + } catch (IOException ex) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Failed adding selector to write selector pool"); + } + } + + try { + String connectTOStr = System.getProperty("sun.net.client.defaultConnectTimeout"); + + if (connectTOStr != null) { + connectionTimeOut = Integer.parseInt(connectTOStr); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not parse system property: sun.net.client.defaultConnectTimeout"); + } + } + } + + /** + * Gets the number of 'connectionsAccepted'. + * + * @return the number of 'connectionsAccepted'. + */ + public long getConnectionsAccepted() { + return connectionsAccepted; + } + + /** + * increment the number of connectionsAccepted sent by 1 + */ + public void incrementConnectionsAccepted() { + connectionsAccepted++; + } + + /** + * increment the number of messages sent by 1 + */ + public void incrementMessagesSent() { + messagesSent++; + } + + /** + * increment the number of messages received by 1 + */ + public void incrementMessagesReceived() { + messagesReceived++; + } + + /** + * increment the number of bytes sent + * + * @param bytes the number of bytes to be added + */ + public void incrementBytesSent(long bytes) { + bytesSent += bytes; + } + + /** + * increment the number of bytes received + * + * @param bytes the number of bytes to be added + */ + public void incrementBytesReceived(long bytes) { + bytesReceived += bytes; + } + + /** + * Gets the number of 'messagesSent'. + * + * @return the number of 'messagesSent'. + */ + public long getMessagesSent() { + return messagesSent; + } + + /** + * Gets the number of 'messagesReceived'. + * + * @return the number of 'messagesReceived'. + */ + public long getMessagesReceived() { + return messagesReceived; + } + + /** + * Gets the number of 'bytesSent'. + * + * @return the number of 'bytesSent'. + */ + public long getBytesSent() { + return bytesSent; + } + + /** + * Gets the number of 'bytesReceived'. + * + * @return the number of 'bytesReceived'. + */ + public long getBytesReceived() { + return bytesReceived; + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (null == target) { + return false; + } + + if (target instanceof TcpTransport) { + TcpTransport likeMe = (TcpTransport) target; + + if (!getProtocolName().equals(likeMe.getProtocolName())) { + return false; + } + + Iterator itsAddrs = likeMe.publicAddresses.iterator(); + + for (EndpointAddress publicAddress1 : publicAddresses) { + if (!itsAddrs.hasNext()) { + return false; + } // it has fewer than i do. + + EndpointAddress mine = publicAddress1; + EndpointAddress its = itsAddrs.next(); + + if (!mine.equals(its)) { + // content didnt match + return false; + } + } + // ran out at the same time? + return (!itsAddrs.hasNext()); + } + return false; + } + + /** + * {@inheritDoc} + */ + public int hashCode() { + return getPublicAddress().hashCode(); + } + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + this.group = group; + ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) impl; + + this.executor = ((StdPeerGroup) group).getExecutor(); + + ConfigParams configAdv = group.getConfigAdvertisement(); + + // Get out invariable parameters from the implAdv + XMLElement param = (XMLElement) implAdvertisement.getParam(); + + if (param != null) { + Enumeration list = param.getChildren("Proto"); + + if (list.hasMoreElements()) { + XMLElement pname = list.nextElement(); + protocolName = pname.getTextValue(); + } + } + + // Get our peer-defined parameters in the configAdv + param = (XMLElement) configAdv.getServiceParam(assignedID); + if (null == param) { + throw new IllegalArgumentException(TransportAdvertisement.getAdvertisementType() + " could not be located."); + } + + Enumeration tcpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv + if (tcpChilds.hasMoreElements()) { + param = tcpChilds.nextElement(); + Attribute typeAttr = param.getAttribute("type"); + + if (!TCPAdv.getAdvertisementType().equals(typeAttr.getValue())) { + throw new IllegalArgumentException("transport adv is not a " + TCPAdv.getAdvertisementType()); + } + + if (tcpChilds.hasMoreElements()) { + throw new IllegalArgumentException("Multiple transport advs detected for " + assignedID); + } + } else { + throw new IllegalArgumentException(TransportAdvertisement.getAdvertisementType() + " could not be located."); + } + + Advertisement paramsAdv = null; + + try { + paramsAdv = AdvertisementFactory.newAdvertisement(param); + } catch (NoSuchElementException notThere) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Could not find parameter document", notThere); + } + } + + if (!(paramsAdv instanceof TCPAdv)) { + throw new IllegalArgumentException("Provided Advertisement was not a " + TCPAdv.getAdvertisementType()); + } + + TCPAdv adv = (TCPAdv) paramsAdv; + + // determine the local interface to use. If the user specifies + // one, use that. Otherwise, use the all the available interfaces. + interfaceAddressStr = adv.getInterfaceAddress(); + if (interfaceAddressStr != null) { + try { + usingInterface = InetAddress.getByName(interfaceAddressStr); + } catch (UnknownHostException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Invalid address for local interface address, using default"); + } + usingInterface = IPUtils.ANYADDRESS; + } + } else { + usingInterface = IPUtils.ANYADDRESS; + } + + serverName = adv.getServer(); + + // Even when server is not enabled, we use the serverSocketPort as a + // discriminant for the simulated network partitioning, human readable + // messages, and a few things of that sort. + serverSocketPort = adv.getPort(); + + // should we expose other than a public address if one was specified? + publicAddressOnly = adv.getPublicAddressOnly(); + + // Start the servers + if (adv.isServerEnabled()) { + try { + unicastServer = new IncomingUnicastServer(this, usingInterface, serverSocketPort, adv.getStartPort(), adv.getEndPort()); + } catch (IOException failed) { + throw new PeerGroupException("Failed to open server socket.", failed); + } + + InetSocketAddress boundAddress = unicastServer.getLocalSocketAddress(); + + // TODO bondolo 20040628 Save the port back as a preference to TCPAdv + /* + if(-1 != adv.getStartPort()) { + adv.setPort(boundAddress.getPort()); + } + */ + + // Build the publicAddresses : + // first in the list is the "public server name". We don't try to + // resolve this since it might not be resolvable in the context we + // are running in, we just assume it's good. + if (serverName != null) { + // use speced server name. + EndpointAddress newAddr = new EndpointAddress(protocolName, serverName, null, null); + publicAddresses.add(newAddr); + } + + // then add the rest of the local interfaces as appropriate. Unless + // we find an non-loopback interface, we're in local only mode. + boolean localOnly = true; + + if (usingInterface.equals(IPUtils.ANYADDRESS)) { + // its wildcarded + Iterator eachLocal = IPUtils.getAllLocalAddresses(); + List wildAddrs = new ArrayList(); + + while (eachLocal.hasNext()) { + InetAddress anAddress = (InetAddress) eachLocal.next(); + String hostAddress = IPUtils.getHostAddress(anAddress); + EndpointAddress newAddr = new EndpointAddress(protocolName, + hostAddress + ":" + Integer.toString(boundAddress.getPort()), null, null); + + // don't add it if its already in the list + if (!anAddress.isLoopbackAddress()) { + localOnly = false; + } + + if (!publicAddresses.contains(newAddr)) { + wildAddrs.add(newAddr); + } + } + + // we sort them so that later equals() will be deterministic. + // the result of IPUtils.getAllLocalAddresses() is not known to + // be sorted. + Collections.sort(wildAddrs, new Comparator() { + public int compare(EndpointAddress one, EndpointAddress two) { + return one.toString().compareTo(two.toString()); + } + + public boolean equals(Object that) { + return (this == that); + } + }); + + // Add public addresses: + // don't add them if we have a hand-set public address and the + // publicAddressOnly property is set. + if (!(serverName != null && publicAddressOnly)) { + publicAddresses.addAll(wildAddrs); + } + } else { + // use specified interface + if (!usingInterface.isLoopbackAddress()) { + localOnly = false; + } + + String hostAddress = IPUtils.getHostAddress(usingInterface); + EndpointAddress newAddr = new EndpointAddress(protocolName, + hostAddress + ":" + Integer.toString(boundAddress.getPort()), null, null); + + // Add public address: + // don't add it if its already in the list + // don't add it if specified as public address and publicAddressOnly + if (!(serverName != null && publicAddressOnly)) { + if (!publicAddresses.contains(newAddr)) { + publicAddresses.add(newAddr); + } + } + } + + // If the only available interface is LOOPBACK, then make sure we + // use only that (that includes resetting the outgoing/listening + // interface from ANYADDRESS to LOOPBACK). + + if (localOnly) { + usingInterface = IPUtils.LOOPBACK; + publicAddresses.clear(); + String hostAddress = IPUtils.getHostAddress(usingInterface); + EndpointAddress pubAddr = new EndpointAddress(protocolName, + hostAddress + ":" + Integer.toString(boundAddress.getPort()), null, null); + + publicAddresses.add(pubAddr); + } + + // Set the "preferred" public address. This is the address we will + // use for identifying outgoing requests. + publicAddress = publicAddresses.get(0); + } else { + // Only the outgoing interface matters. + // Verify that ANY interface does not in fact mean LOOPBACK only. If + // that's the case, we want to make that explicit, so that + // consistency checks regarding the allowed use of that interface + // work properly. + if (usingInterface.equals(IPUtils.ANYADDRESS)) { + boolean localOnly = true; + Iterator eachLocal = IPUtils.getAllLocalAddresses(); + + while (eachLocal.hasNext()) { + InetAddress anAddress = (InetAddress) eachLocal.next(); + + if (!anAddress.isLoopbackAddress()) { + localOnly = false; + break; + } + } + + if (localOnly) { + usingInterface = IPUtils.LOOPBACK; + } + } + + // The "public" address is just an internal label + // it is not usefull to anyone outside. + // IMPORTANT: we set the port to zero, to signify that this address + // is not realy usable. + String hostAddress = IPUtils.getHostAddress(usingInterface); + + publicAddress = new EndpointAddress(protocolName, hostAddress + ":0", null, null); + } + + // Tell tell the world about our configuration. + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring TCP Message Transport : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID: ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration:"); + configInfo.append("\n\t\tProtocol: ").append(protocolName); + configInfo.append("\n\t\tPublic address: ").append(serverName == null ? "(unspecified)" : serverName); + configInfo.append("\n\t\tInterface address: ").append( + interfaceAddressStr == null ? "(unspecified)" : interfaceAddressStr); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tUsing Interface: ").append(usingInterface.getHostAddress()); + + if (null != unicastServer) { + if (-1 == unicastServer.getStartPort()) { + configInfo.append("\n\t\tUnicast Server Bind Addr: ").append(usingInterface.getHostAddress()).append(":").append( + serverSocketPort); + } else { + configInfo.append("\n\t\tUnicast Server Bind Addr: ").append(usingInterface.getHostAddress()).append(":").append(serverSocketPort).append(" [").append(unicastServer.getStartPort()).append("-").append(unicastServer.getEndPort()).append( + "]"); + } + configInfo.append("\n\t\tUnicast Server Bound Addr: ").append(unicastServer.getLocalSocketAddress()); + } else { + configInfo.append("\n\t\tUnicast Server : disabled"); + } + + configInfo.append("\n\t\tPublic Addresses: "); + configInfo.append("\n\t\t\tDefault Endpoint Addr : ").append(publicAddress); + + for (EndpointAddress anAddr : publicAddresses) { + configInfo.append("\n\t\t\tEndpoint Addr : ").append(anAddr); + } + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized int startApp(String[] arg) { + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return Module.START_AGAIN_STALLED; + } + + try { + messengerSelector = SelectorProvider.provider().openSelector(); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not create a messenger selector", e); + } + } + + messengerSelectorThread = new Thread(group.getHomeThreadGroup(), new MessengerSelectorThread(), "TCP Transport MessengerSelectorThread for " + this); + messengerSelectorThread.setDaemon(true); + messengerSelectorThread.start(); + + // We're fully ready to function. + messengerEventListener = endpoint.addMessageTransport(this); + + if (messengerEventListener == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + return -1; + } + + // Cannot start before registration, we could be announcing new messengers while we + // do not exist yet ! (And get an NPE because we do not have the messenger listener set). + + if (unicastServer != null) { + if (!unicastServer.start()) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Unable to start TCP Unicast Server"); + } + return -1; + } + } + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + TransportServiceMonitor transportServiceMonitor = (TransportServiceMonitor) MonitorManager.getServiceMonitor(group, + MonitorResources.transportServiceMonitorClassID); + + if (transportServiceMonitor != null) { + unicastTransportMeter = transportServiceMonitor.createTransportMeter("TCP", publicAddress); + } + } + + isClosed = false; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("TCP Message Transport started."); + } + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public synchronized void stopApp() { + if (isClosed) { + return; + } + + isClosed = true; + + if (unicastServer != null) { + unicastServer.stop(); + unicastServer = null; + } + + Thread temp = messengerSelectorThread; + + if (null != temp) { + temp.interrupt(); + try { + messengerSelector.close(); + } catch (IOException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "IO error occured while closing server socket", failed); + } + } + } + + // Inform the pool that we don't need as many write selectors. + synchronized (writeSelectorCache) { + extraWriteSelectors += MAX_WRITE_SELECTORS; + } + + endpoint.removeMessageTransport(this); + + endpoint = null; + group = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info(MessageFormat.format("Total bytes sent : {0}", getBytesSent())); + LOG.info(MessageFormat.format("Total Messages sent : {0}", getMessagesSent())); + LOG.info(MessageFormat.format("Total bytes received : {0}", getBytesReceived())); + LOG.info(MessageFormat.format("Total Messages received : {0}", getMessagesReceived())); + LOG.info(MessageFormat.format("Total connections accepted : {0}", getConnectionsAccepted())); + + LOG.info("TCP Message Transport shut down."); + } + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return protocolName; + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return publicAddress; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return (EndpointService) endpoint.getInterface(); + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + /** + * {@inheritDoc} + */ + public Iterator getPublicAddresses() { + return Collections.unmodifiableList(publicAddresses).iterator(); + } + + /** + * {@inheritDoc} + */ + public boolean isConnectionOriented() { + return true; + } + + /** + * {@inheritDoc} + */ + public boolean allowsRouting() { + return true; + } + + public Messenger getMessenger(EndpointAddress dst, Object hintIgnored) { + return getMessenger(dst, hintIgnored, true); + } + + /** + * {@inheritDoc} + */ + public Messenger getMessenger(EndpointAddress dst, Object hintIgnored, boolean selfDestruct) { + + if (!dst.getProtocolName().equalsIgnoreCase(getProtocolName())) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Cannot make messenger for protocol: " + dst.getProtocolName()); + } + return null; + } + + EndpointAddress plainAddr = new EndpointAddress(dst, null, null); + + // If the destination is one of our addresses including loopback, we + // return a loopback messenger. + if (publicAddresses.contains(plainAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("return LoopbackMessenger for addr : " + dst); + } + return new LoopbackMessenger(group, endpoint, getPublicAddress(), dst, + new EndpointAddress("jxta", group.getPeerID().getUniqueValue().toString(), null, null)); + } + + try { + // Right now we do not want to "announce" outgoing messengers because they get pooled and so must + // not be grabbed by a listener. If "announcing" is to be done, that should be by the endpoint + // and probably with a subtely different interface. + return new TcpMessenger(dst, this, selfDestruct); + } catch (Exception caught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "Could not get messenger for " + dst, caught); + } else { + LOG.warning("Could not get messenger for " + dst + " : " + caught.getMessage()); + } + } + if (caught instanceof RuntimeException) { + throw (RuntimeException) caught; + } + return null; + } + } + + /** + * {@inheritDoc} + *

            + * This implementation tries to open a connection, and after tests the + * result. + */ + public boolean ping(EndpointAddress addr) { + boolean result = false; + EndpointAddress endpointAddress; + long pingStartTime = 0; + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + pingStartTime = System.currentTimeMillis(); + } + + endpointAddress = new EndpointAddress(addr, null, null); + + try { + // Too bad that this one will not get pooled. On the other hand ping is + // not here too stay. + TcpMessenger tcpMessenger = new TcpMessenger(endpointAddress, this); + + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + TransportBindingMeter transportBindingMeter = tcpMessenger.getTransportBindingMeter(); + + if (transportBindingMeter != null) { + transportBindingMeter.ping(System.currentTimeMillis() - pingStartTime); + } + } + result = true; + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failure pinging " + addr.toString(), e); + } + if (TransportMeterBuildSettings.TRANSPORT_METERING) { + TransportBindingMeter transportBindingMeter = getUnicastTransportBindingMeter(null, endpointAddress); + + if (transportBindingMeter != null) { + transportBindingMeter.pingFailed(System.currentTimeMillis() - pingStartTime); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("ping to " + addr.toString() + " == " + result); + } + return result; + } + + /** + * Getter for property 'restrictionPort'. + * + * @return Value for property 'restrictionPort'. + */ + int getRestrictionPort() { + return restrictionPort; + } + + TransportBindingMeter getUnicastTransportBindingMeter(PeerID peerID, EndpointAddress destinationAddress) { + if (unicastTransportMeter != null) { + return unicastTransportMeter.getTransportBindingMeter( + (peerID != null) ? peerID.toString() : TransportMeter.UNKNOWN_PEER, destinationAddress); + } else { + return null; + } + } + + void messengerReadyEvent(Messenger newMessenger, EndpointAddress connAddr) { + messengerEventListener.messengerReady(new MessengerEvent(this, newMessenger, connAddr)); + } + + /** + * Getter for property 'server'. + * + * @return Value for property 'server'. + */ + IncomingUnicastServer getServer() { + return unicastServer; + + } + + /** + * Get a write selector from the cache. + * + * @return A write selector. + * @throws InterruptedException If interrupted while waiting for a selector + * to become available. + */ + Selector getSelector() throws InterruptedException { + synchronized (writeSelectorCache) { + Selector selector = null; + try { + if (!writeSelectorCache.isEmpty()) { + selector = writeSelectorCache.pop(); + } + } catch (EmptyStackException ese) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No write selector available, waiting for one"); + } + } + + int attempts = 0; + while (selector == null && attempts < 2) { + writeSelectorCache.wait(connectionTimeOut); + try { + if (!writeSelectorCache.isEmpty()) { + selector = writeSelectorCache.pop(); + } + } catch (EmptyStackException ese) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to get a write selector available, waiting for one", ese); + } + } + attempts++; + } + + return selector; + } + } + + /** + * Return the Selector to the cache + * + * @param selector the selector to put back into the pool + */ + void returnSelector(Selector selector) { + synchronized (writeSelectorCache) { + if (extraWriteSelectors > 0) { + // Allow the selector to be discarded. + extraWriteSelectors--; + } else { + writeSelectorCache.push(selector); + // it does not hurt to notify, even if there are no waiters + writeSelectorCache.notify(); + } + } + } + + /** + * Waits for incoming data on channels and sends it to the appropriate + * messenger object. + */ + private class MessengerSelectorThread implements Runnable { + + /** + * {@inheritDoc} + */ + public void run() { + try { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("MessengerSelectorThread polling started"); + } + + while (!isClosed) { + try { + int selectedKeys = 0; + + // Update channel registerations. + updateChannelRegisterations(); + + try { + // this can be interrupted through wakeup + selectedKeys = messengerSelector.select(); + } catch (CancelledKeyException cke) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Key was cancelled", cke); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("MessengerSelector has {0} selected keys", selectedKeys)); + } + + if (selectedKeys == 0 && messengerSelector.selectNow() == 0) { + // We were probably just woken. + continue; + } + + Set keySet = messengerSelector.selectedKeys(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("KeySet has {0} selected keys", keySet.size())); + } + + Iterator it = keySet.iterator(); + + while (it.hasNext()) { + SelectionKey key = it.next(); + + // remove it from the SelectedKeys Set + it.remove(); + + if (key.isValid()) { + try { + if (key.isReadable() && key.channel().isOpen()) { + // ensure this channel is not selected again until the thread is done with it + // TcpMessenger is expected to reset the interestOps back to OP_READ + // Without this, expect multiple threads to execute on the same event, until + // the first thread completes reading all data available + key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); + + // get the messenger + TcpMessenger msgr = (TcpMessenger) key.attachment(); + + // process the data + try { + executor.execute(msgr); + } catch (RejectedExecutionException re) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, + MessageFormat.format("Executor rejected task for messenger :{0}", msgr.toString()), re); + } + } + } + } catch (CancelledKeyException cce) { + //in case the key was canceled after the selection + } + } else { + // unregister it, no need to keep invalid/closed channels around + try { + key.channel().close(); + } catch (IOException io) { + // avoids breaking out of the selector loop + } + key.cancel(); + key = null; + } + } + } catch (ClosedSelectorException cse) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("IO Selector closed"); + } + } catch (InterruptedIOException woken) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Thread inturrupted", woken); + } + } catch (IOException e1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "An exception occurred while selecting keys", e1); + } + } catch (SecurityException e2) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "A security exception occurred while selecting keys", e2); + } + } + } + + // XXX 20070205 bondolo What should we do about the channels + // that are still registered with the selector and any pending + // updates? + + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && Logging.SHOW_SEVERE) { + LOG.log(Level.SEVERE, "Uncaught Throwable", all); + } + } finally { + messengerSelectorThread = null; + } + } + } + + /** + * Registers the channel with the Read selector and attaches the messenger to the channel + * + * @param channel the socket channel. + * @param messenger the messenger to attach to the channel. + */ + void register(SocketChannel channel, TcpMessenger messenger) { + regisMap.put(messenger, channel); + messengerSelector.wakeup(); + } + + /** + * Unregisters the channel with the Read selector + * + * @param channel the socket channel. + */ + void unregister(SocketChannel channel) { + unregisMap.add(channel); + messengerSelector.wakeup(); + } + + /** + * Registers all newly accepted and returned (by TcpMessenger) channels. + * Removes all closing TcpMessengers. + */ + private synchronized void updateChannelRegisterations() { + + if (!regisMap.isEmpty() && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Registering {0} channels with MessengerSelectorThread", regisMap.size())); + } + + if (!regisMap.isEmpty()) { + Iterator> eachMsgr = regisMap.entrySet().iterator(); + + while (eachMsgr.hasNext()) { + Map.Entry anEntry = eachMsgr.next(); + TcpMessenger msgr = anEntry.getKey(); + SocketChannel channel = anEntry.getValue(); + SelectionKey key = channel.keyFor(messengerSelector); + + try { + if (key == null) { + key = channel.register(messengerSelector, SelectionKey.OP_READ, msgr); + } + key.interestOps(key.interestOps() | SelectionKey.OP_READ); + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(MessageFormat.format("Key interestOps on channel {0}, bit set :{1}", channel, key.interestOps())); + } + } catch (ClosedChannelException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Failed to register Channel with messenger selector", e); + } + // it's best a new messenger is created when a new messenger is requested + msgr.close(); + } catch (CancelledKeyException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Key is already cancelled, removing key from registeration map", e); + } + } catch (IllegalBlockingModeException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Invalid blocking channel mode, closing messenger", e); + } + // messenger state is unknown + msgr.close(); + } + // remove it from the table + eachMsgr.remove(); + } + } + + // Unregister and close channels. + if (!unregisMap.isEmpty() && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Unregistering {0} channels with MessengerSelectorThread", unregisMap.size())); + } + if (!unregisMap.isEmpty()) { + Iterator eachChannel; + + synchronized (unregisMap) { + List allChannels = new ArrayList(unregisMap); + unregisMap.clear(); + eachChannel = allChannels.iterator(); + } + + while (eachChannel.hasNext()) { + SocketChannel aChannel = eachChannel.next(); + SelectionKey key = aChannel.keyFor(messengerSelector); + if (null != key) { + try { + key.cancel(); + } catch (CancelledKeyException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Key is already cancelled, removing key from registeration map", e); + } + } + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/package.html new file mode 100644 index 000000000..c31034974 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tcp/package.html @@ -0,0 +1,17 @@ + + + + + + +A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which uses raw TCP/IP sockets. + +@see net.jxta.endpoint.EndpointService +@see net.jxta.endpoint.MessageTransport +@see net.jxta.endpoint.MessageSender +@see net.jxta.endpoint.MessageReceiver +@see net.jxta.endpoint.Message +@see JXTA Protocols + Specification : Standard JXTA Transport Bindings + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsDefs.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsDefs.java new file mode 100644 index 000000000..5215f08f1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsDefs.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import net.jxta.document.MimeMediaType; + + +public class JTlsDefs { + // Until we decide otherwise, the tls is *by definition* handling + // peerID addressed messages. + static String tlsPName = "jxtatls"; + + static final String TLSNameSpace = "jxtatls"; // our name space + + static final String ServiceName = "TlsTransport"; + + static final int FAKEPORT = 1376911; // for TLS hashing only + + static final String ACKKEY = "TLSACK"; + static final String RETR = "MARKRetr"; + + static final MimeMediaType MTYPE = new MimeMediaType("application/x-jxta-msg"); + static final MimeMediaType BLOCKS = new MimeMediaType("application/x-jxta-tls-block"); + static final MimeMediaType ACKS = new MimeMediaType("application/x-jxta-tls-ack"); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsInputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsInputStream.java new file mode 100644 index 000000000..cbebd9f43 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsInputStream.java @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.io.InterruptedIOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.impl.util.TimeUtils; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * Acts as the input for TLS. Accepts ciphertext which arrives in messages + * and orders it before passing it to TLS for decryption. + * + * TLS will do its raw reads off of this InputStream + * Here, we will have queued up the payload of TLS message + * elements to be passed to TLS code as TLS Records. + * + */ +class JTlsInputStream extends InputStream { + private static final Logger LOG = Logger.getLogger(JTlsInputStream.class.getName()); + + private static final boolean DEBUGIO = false; + + static private int MAXQUEUESIZE = 25; + + /** + * Connection we are working for. + */ + private TlsConn conn; + + private volatile boolean closed = false; + private boolean closing = false; + + private long timeout = 2 * TimeUtils.AMINUTE; + private JTlsRecord jtrec = null; + private volatile int sequenceNumber = 0; + private final Vector inputQueue = new Vector(MAXQUEUESIZE); // For incoming messages. + + /** + * Input TLS record Object + **/ + private static class JTlsRecord { + // This dummy message elt + public InputStream tlsRecord; // TLS Record + public long nextByte; // next inbuff byte + public long size; // size of TLS Record + + public JTlsRecord() { + tlsRecord = null; // allocated by caller + nextByte = 0; // We read here (set by caller) + size = 0; // TLS Record size(set by caller) + } + + // reset the jxta tls record element + + public void resetRecord() { + if (null != tlsRecord) { + try { + tlsRecord.close(); + } catch (IOException ignored) {// ignored + } + } + tlsRecord = null; + size = nextByte = 0; + } + } + + + // An input queue element which breaks out a + // received message in enqueueMessage(). + private static class IQElt { + int seqnum; + MessageElement elt; + boolean ackd; + } + + public JTlsInputStream(TlsConn conn, long timeout) { + this.timeout = timeout; + this.conn = conn; + jtrec = new JTlsRecord(); + // 1 <= seq# <= maxint, monotonically increasing + // Incremented before compare. + sequenceNumber = 0; + + } + + /** + * {@inheritDoc} + **/ + @Override + public void close() throws IOException { + super.close(); + + closed = true; + synchronized (inputQueue) { + inputQueue.clear(); + inputQueue.notifyAll(); + } + } + + /** + * prepare this input stream to being closed. It will still + * deliver the packets that have been received, but nothing + * more. This is meant to be called in response to the other side + * having initiated closure. We assume that when the other side does it + * it means that it is satified with what we have acknoleged so far. + */ + public void setClosing() throws IOException { + synchronized (inputQueue) { + closing = true; + inputQueue.notifyAll(); + } + } + + // Here we read the TLS Record data from the incoming JXTA message. + // (We will really have a full jxta message available.) + // + // TLS Record input only calls the following methods. + // They are called from SSLRecord.decode(SSLConn, Inputstream); + // + + /** + * {@inheritDoc} + */ + @Override + public int read() throws IOException { + if (closed) { + return -1; + } + + byte[] a = new byte[1]; + + while (true) { + int len = local_read(a, 0, 1); + + if (len < 0) { + break; + } + + if (len > 0) { + if (DEBUGIO && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Read() : " + (a[0] & 255)); + } + + return (a[0] & 0xFF); // The byte + } + } + // If we've reached EOF, there's nothing to do but close(). + + close(); + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] a, int offset, int length) throws IOException { + if (closed) { + return -1; + } + + if (0 == length) { + return 0; + } + + int i = local_read(a, offset, length); + + if (DEBUGIO && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Read(byte[], int, " + length + "), bytes read = " + i); + } + + // If we've reached EOF; there's nothing to do but close(). + if (i == -1) { + close(); + } + return i; + } + + // protected accessor for sequence number + int getSequenceNumber() { + return sequenceNumber; + } + + // Our input queue max size + int getMaxIQSize() { + return MAXQUEUESIZE; + } + + /** + * Send a sequential ACK and selective ACKs for all of the queued messages. + * + * @param seqnAck the sequence number being sequential ACKed + **/ + private void sendACK(int seqnAck) { + List selectedAckList = new ArrayList(); + + synchronized (inputQueue) { + Iterator eachInQueue = inputQueue.iterator(); + + while (eachInQueue.hasNext() && (selectedAckList.size() < MAXQUEUESIZE)) { + IQElt anIQElt = eachInQueue.next(); + + if (anIQElt.seqnum > seqnAck) { + selectedAckList.add(new Integer(anIQElt.seqnum)); + } + } + } + + // PERMIT DUPLICATE ACKS. Just a list and one small message. + sendACK(seqnAck, selectedAckList); + } + + /** + * Build an ACK message. The message provides a sequential ACK count and + * an optional list of selective ACKs. + * + * @param seqnAck the sequence number being sequential ACKed + * @param sackList a list of selective ACKs. Must be sorted in increasing + * order. + */ + private void sendACK(int seqnAck, List sackList) { + ByteArrayOutputStream bos = new ByteArrayOutputStream((1 + sackList.size()) * 4); + DataOutputStream dos = new DataOutputStream(bos); + + try { + dos.writeInt(seqnAck); + + Iterator eachSACK = sackList.iterator(); + + while (eachSACK.hasNext()) { + int aSack = (eachSACK.next()).intValue(); + + dos.writeInt(aSack); + } + dos.close(); + bos.close(); + + Message ACKMsg = new Message(); + MessageElement elt = new ByteArrayMessageElement(JTlsDefs.ACKKEY, JTlsDefs.ACKS, bos.toByteArray(), null); + + ACKMsg.addMessageElement(JTlsDefs.TLSNameSpace, elt); + + conn.sendToRemoteTls(ACKMsg); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SENT ACK, seqn#" + seqnAck + " and " + sackList.size() + " SACKs "); + } + } catch (IOException e) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "sendACK caught IOException:", e); + } + } + } + + /** + * queue messages by sequence number. + */ + public void queueIncomingMessage(Message msg) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Queue Incoming Message begins for " + msg); + } + + long startEnqueue = TimeUtils.timeNow(); + + Message.ElementIterator e = msg.getMessageElements(JTlsDefs.TLSNameSpace, JTlsDefs.BLOCKS); + + // OK look for jxta message + while (!closed && !closing && e.hasNext()) { + MessageElement elt = e.next(); + + e.remove(); + + int msgSeqn = 0; + + try { + msgSeqn = Integer.parseInt(elt.getElementName()); + } catch (NumberFormatException n) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Discarding element (" + elt.getElementName() + ") Not one of ours."); + } + continue; + } + + IQElt newElt = new IQElt(); + + newElt.seqnum = msgSeqn; + newElt.elt = elt; + newElt.ackd = false; + + // OK we must inqueue: + // Wait until someone dequeues if we are at the size limit + // see if this is a duplicate + if (newElt.seqnum <= sequenceNumber) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RCVD OLD MESSAGE : Discard seqn#" + newElt.seqnum + " now at seqn#" + sequenceNumber); + } + break; + } + synchronized (inputQueue) { + // dbl check with the lock held. + if (closing || closed) { + return; + } + + // Insert this message into the input queue. + // 1. Do not add duplicate messages + // 2. Store in increasing sequence nos. + int insertIndex = inputQueue.size(); + boolean duplicate = false; + + for (int j = 0; j < inputQueue.size(); j++) { + IQElt iq = inputQueue.elementAt(j); + + if (newElt.seqnum < iq.seqnum) { + insertIndex = j; + break; + } else if (newElt.seqnum == iq.seqnum) { + duplicate = true; + break; + } + } + + if (duplicate) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RCVD OLD MESSAGE : Discard duplicate msg, seqn#" + newElt.seqnum); + } + newElt = null; + break; + } + + inputQueue.add(insertIndex, newElt); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Enqueued msg with seqn#" + newElt.seqnum + " at index " + insertIndex); + } + + inputQueue.notifyAll(); + newElt = null; + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + long waited = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), startEnqueue); + + LOG.fine("Queue Incoming Message for " + msg + " completed in " + waited + " msec."); + } + } + + /** + * Dequeue the message with the desired sequence number waiting as needed + * until the message is available. + * + * @param desiredSeqn the sequence number to be dequeued. + * @return the Message Element with the desired sequence number or null if + * the queue has been closed. + **/ + private MessageElement dequeueMessage(int desiredSeqn) throws IOException { + IQElt iQ = null; + + // Wait for incoming message here + long startDequeue = TimeUtils.timeNow(); + long whenToTimeout = startDequeue + timeout; + int wct = 0; + + long nextRetransRequest = TimeUtils.toAbsoluteTimeMillis(TimeUtils.ASECOND); + + synchronized (inputQueue) { + while (!closed) { + if (inputQueue.size() == 0) { + if (closing) { + return null; + } + try { + wct++; + inputQueue.wait(TimeUtils.ASECOND); + if (whenToTimeout < TimeUtils.timeNow()) { + throw new SocketTimeoutException("Read timeout reached"); + } + } catch (InterruptedException e) { + Thread.interrupted(); // just continue + } + // we reset the retrans request timer since we don't want to + // immediately request retry after a long wait for out of + // order messages. + + nextRetransRequest = TimeUtils.toAbsoluteTimeMillis(TimeUtils.ASECOND); + continue; + } + + iQ = inputQueue.elementAt(0); // FIFO + + if (iQ.seqnum < desiredSeqn) { + // Ooops a DUPE slipped in the head of the queue undetected + // (seqnum consistency issue). + // Just drop it. + inputQueue.remove(0); + // if such is the case then notify the other end so that + // the message does not remain in the retry queue eventually + // triggering a broken pipe exception + sendACK(iQ.seqnum); + continue; + } else if (iQ.seqnum != desiredSeqn) { + if (TimeUtils.toRelativeTimeMillis(nextRetransRequest) < 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Trigger retransmission. Wanted seqn#" + desiredSeqn + " found seqn#" + iQ.seqnum); + } + sendACK(desiredSeqn - 1); + nextRetransRequest = TimeUtils.toAbsoluteTimeMillis(TimeUtils.ASECOND); + } + + try { + wct++; + inputQueue.wait(TimeUtils.ASECOND); + if (whenToTimeout < TimeUtils.timeNow()) { + throw new SocketTimeoutException("Read timeout reached"); + } + } catch (InterruptedException e) { + throw new InterruptedIOException("IO interrupted "); + } + continue; + } + + inputQueue.remove(0); + break; + } + } + + nextRetransRequest = 0; + sendACK(desiredSeqn); + // if we are closed then we return null + if (null == iQ) { + return null; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + long waited = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), startDequeue); + + LOG.info("DEQUEUED seqn#" + iQ.seqnum + " in " + waited + " msec on input queue"); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (wct > 0) { + LOG.fine("DEQUEUE waited " + wct + " times on input queue"); + } + } + } + + return iQ.elt; + } + + /** + * + */ + private int local_read(byte[] a, int offset, int length) throws IOException { + + synchronized (jtrec) { + if ((jtrec.size == 0) || (jtrec.nextByte == jtrec.size)) { + + // reset the record + jtrec.resetRecord(); // GC as necessary(tlsRecord byte[]) + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("local_read: getting next data block at seqn#" + (sequenceNumber + 1)); + } + + MessageElement elt = null; + + try { + elt = dequeueMessage(sequenceNumber + 1); + } catch (SocketTimeoutException ste) { + // timed out with no data + // SSLSocket expects a 0 data in this case + return 0; + } + + if (null == elt) { + return -1; + } + + sequenceNumber += 1; // next msg sequence number + + // Get the length of the TLS Record + jtrec.size = elt.getByteLength(); + jtrec.tlsRecord = elt.getStream(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("local_read: new seqn#" + sequenceNumber + ", bytes = " + jtrec.size); + } + } + + // return the requested TLS Record data + // These calls should NEVER ask for more data than is in the + // received TLS Record. + + long left = jtrec.size - jtrec.nextByte; + int copyLen = (int) Math.min(length, left); + int copied = 0; + + do { + int res = jtrec.tlsRecord.read(a, offset + copied, copyLen - copied); + + if (res < 0) { + break; + } + + copied += res; + } while (copied < copyLen); + + jtrec.nextByte += copied; + + if (DEBUGIO) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("local_read: Requested " + length + ", Read " + copied + " bytes"); + } + } + + return copied; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsOutputStream.java new file mode 100644 index 000000000..ab11a5b08 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/JTlsOutputStream.java @@ -0,0 +1,964 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import java.io.OutputStream; +import java.io.IOException; +import java.net.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; + +import net.jxta.impl.endpoint.tls.TlsConn.HandshakeState; +import net.jxta.impl.util.TimeUtils; + + +/** + * Acts as the output for TLS. Accepts ciphertext from TLS and packages it into + * messages for sending to the remote. The messages are kept in a retry queue + * until the remote peer acknowledges receipt of the message. + **/ +class JTlsOutputStream extends OutputStream { + + /** + * Log4J Logger + **/ + private static final Logger LOG = Logger.getLogger(JTlsOutputStream.class.getName()); + + // constants + + /** + * This maximum is only enforced if we have not heard + * from the remote for RETRMAXAGE. + **/ + private static final int MAXRETRQSIZE = 100; + + /** + * Initial estimated Round Trip Time + **/ + private static final long initRTT = 1 * TimeUtils.ASECOND; + + private static final MessageElement RETELT = new StringMessageElement(JTlsDefs.RETR, "TLSRET", null); + + /** + * Retrans window. When reached, we up the RTO. + **/ + private static final int RWINDOW = 5; + + /** + * If true then the stream has been closed. + **/ + private volatile boolean closed = false; + + /** + * If true then the stream is being closed. + * It means that it still works completely for all messages already + * queued, but no new message may be enqueued. + **/ + private volatile boolean closing = false; + + /** + * Sequence number of the message we most recently sent out. + **/ + private volatile int sequenceNumber = 0; + + /** + * Sequence number of highest sequential ACK. + **/ + private volatile int maxACK = 0; + + /** + * Transport we are working for + **/ + private TlsTransport tp = null; + + /** + * connection we are working for + **/ + private TlsConn conn = null; + + private Retransmitter retransmitter = null; + + // for retransmission + + /** + * Average round trip time in milliseconds. + **/ + private volatile long aveRTT = initRTT; + + /** + * Number of ACK message received. + **/ + private int nACKS = 0; + + /** + * Retry Time Out measured in milliseconds. + **/ + private volatile long RTO = 0; + + /** + * Minimum Retry Timeout measured in milliseconds. + **/ + private volatile long minRTO = initRTT; + + /** + * Maximum Retry Timeout measured in milliseconds. + **/ + private volatile long maxRTO = initRTT * 5; + + /** + * absolute time in milliseconds of last sequential ACK. + **/ + private volatile long lastACKTime = 0; + + /** + * absolute time in milliseconds of last SACK based retransmit. + **/ + private volatile long sackRetransTime = 0; + + /** + * The collection of messages available for re-transmission. + */ + final List retrQ = new Vector(25, 5); + + // running average of receipients Input Queue + private int nIQTests = 0; + private int aveIQSize = 0; + + /** + * Our estimation of the current free space in the remote input queue. + **/ + private volatile int mrrIQFreeSpace = 0; + + /** + * Our estimation of the maximum sise of the remote input queue. + **/ + private int rmaxQSize = 0; + + /** + * retrans queue element + **/ + private static class RetrQElt { + int seqnum; // sequence number of this message. + long enqueuedAt; // absolute time of original enqueing. + volatile Message msg; // the message + int marked; // has been marked as retransmission + long sentAt; // when this msg was last transmitted + + public RetrQElt(int seqnum, Message msg) { + this.seqnum = seqnum; + this.msg = msg; + this.enqueuedAt = TimeUtils.timeNow(); + this.sentAt = this.enqueuedAt; + this.marked = 0; + } + } + + JTlsOutputStream(TlsTransport tp, TlsConn conn) { + this.conn = conn; // TlsConnection. + this.tp = tp; // our transport + + this.RTO = minRTO; // initial RTO + + // input free queue size + this.rmaxQSize = 20; + this.mrrIQFreeSpace = rmaxQSize; + + // Init last ACK Time to now + this.lastACKTime = TimeUtils.timeNow(); + this.sackRetransTime = TimeUtils.timeNow(); + + // Start retransmission thread + this.retransmitter = new Retransmitter(); + } + + /** + * {@inheritDoc} + * + *

            We don't current support linger. + **/ + @Override + public void close() throws IOException { + synchronized (this) { + super.close(); + closed = true; + } + synchronized (retrQ) { + retrQ.notifyAll(); + retrQ.clear(); + } + } + + /** + * indicate that we're in the process of closing. To respect the semantics + * of close()/isClosed(), we do not set the closed flag, yet. Instead, we + * set the flag "closing", which simply garantees that no new message + * will be queued. + * This, in combination with getSequenceNumber and getMaxAck, and + * waitQevent, enables fine grain control of the tear down process. + **/ + public void setClosing() { + synchronized (retrQ) { + closing = true; + retrQ.clear(); + retrQ.notifyAll(); + } + } + + /** + * {@inheritDoc} + **/ + @Override + public void write(int c) throws IOException { + byte[] a = new byte[1]; + + a[0] = (byte) (c & 0xFF); + write(a, 0, 1); + } + + /** + * {@inheritDoc} + * + *

            We override the write(byte[], offset, length); + * method which is called by SSLRecord.send(SSLConn conn) + * via tos.writeTo(conn.sock_out), tos a ByteArrayOutputStream + * which has buffered the TLS output record in the byte array. + * The actual call is write(byte[] b, 0, length); + * + *

            We put this TLS record into a msssage element for the output + * pipe to send along. + * + *

            This is reasonable since in fact, if more than 16K bytes of + * application data are sent, then the max TLS Record is a little + * larger than 16K bytes including the TLS overhead. + * + *

            Therefore, an app. message is N+r TLS Records, + * Message length = Nx16K + r, N >= 0, r >= 0, + * N > 0 || r > 0 true. + **/ + @Override + public void write(byte[] b, int off, int len) throws IOException { + // flag to allow connection closure in finally block + // Connection can not be closed when holding a lock on this + boolean closeStale = false; + // allocate new message + Message jmsg = new Message(); + + try { + if (closed) { + throw new IOException("stream is closed"); + } + if (closing) { + throw new IOException("stream is being closed"); + } + if (b == null) { + throw new IllegalArgumentException("buffer is null"); + } + + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } + + if (len == 0) { + return; + } + + // Copy the data since it will be queued, and caller may + // overwrite the same byte[] buffer. + byte[] data = new byte[len]; + + System.arraycopy(b, off, data, 0, len); + + // sync so that writes don't get out of order. + synchronized (retrQ) { + // add TLS record as element + MessageElement ciphertext = new ByteArrayMessageElement(Integer.toString(++sequenceNumber), JTlsDefs.BLOCKS, data + , + null); + + jmsg.addMessageElement(JTlsDefs.TLSNameSpace, ciphertext); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS CT WRITE : seqn#" + sequenceNumber + " length=" + len); + } + + // (1) See if the most recent remote input queue size is close to + // it's maximum input queue size + // Send only if at least 20% or more of the queue is free. + // (2) Also, if our retransQ is larger than the remotes inputQ, + // wait until we've received an ack. + // We assume some msgs are in transit or the remote system buffers + // We do not want to overrun the receiver. + // (3) We need to release from the loop because of possible deadlocks + // EG: retrQ.size() == 0 and mrrIQFreeSpace forces looping + // forever because the most recent SACK cleared it, and the receiver + // is waiting for more data. + + // max of 200ms wait + int maxwait = Math.min((int) aveRTT, 200); + // iterations to wait (max 3, min 1) + int waitCt = Math.max(maxwait / 60, 1); + + // check if the queue has gone dead. + if (retrQ.size() > 0) { + long inQueue = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), retrQ.get(0).enqueuedAt); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("write : Retry queue idle for " + inQueue); + } + + if (inQueue > tp.RETRMAXAGE) { + if (inQueue > (2 * tp.RETRMAXAGE)) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing stale connection " + conn); + } + // SPT - set flag for connection close in finally block + closeStale = true; + throw new IOException("Stale connection closure in progress"); + } else if (retrQ.size() >= MAXRETRQSIZE) { + // if the the queue is "full" and we are long idle, delay new writes forever. + waitCt = Integer.MAX_VALUE; + } + } + } + + int i = 0; + + while (!closed && ((mrrIQFreeSpace < rmaxQSize / 5) || (retrQ.size() > rmaxQSize))) { + + // see if max. wait has arrived. + if (i++ == waitCt) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("write() wait for ACK, maxwait timer expired while enqueuing seqn#" + sequenceNumber); + } + break; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("write() wait 60ms for ACK while enqueuing seqn#" + sequenceNumber + "\n\tremote IQ free space = " + + mrrIQFreeSpace + "\n\tMIN free space to continue = " + (rmaxQSize / 5) + "" + "\n\tretQ.size()=" + + retrQ.size()); + } + + // Less than 20% free queue space is left. Wait. + try { + retrQ.wait(60); + } catch (InterruptedException ignored) { + Thread.interrupted(); + } + } + + // place copy on retransmission queue + RetrQElt r = new RetrQElt(sequenceNumber, jmsg.clone()); + + retrQ.add(r); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Retrans Enqueue added seqn#" + sequenceNumber + " retQ.size()=" + retrQ.size()); + } + } + + // Here we will send the message to the transport + conn.sendToRemoteTls(jmsg); + // assume we have now taken a slot + mrrIQFreeSpace--; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS CT SENT : seqn#" + sequenceNumber + " length=" + len); + } + } finally { + if (closeStale) { + // The retry queue has really gone stale. + try { + setClosing(); + // in this we close ourself + conn.close(HandshakeState.CONNECTIONDEAD); + } catch (IOException ignored) { + ; + } + } + } + } + + private void calcRTT(long enqueuedAt) { + long dt = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), enqueuedAt); + + if (dt == 0) { + dt += 1; + } + + int n = nACKS; + + nACKS += 1; + + aveRTT = ((n * aveRTT) + dt) / (nACKS); + + // Set retransmission time out: 2.5 x RTT + RTO = (aveRTT << 1) + (aveRTT >> 1); + + // Enforce a min/max + + RTO = Math.max(RTO, minRTO); + RTO = Math.min(RTO, maxRTO); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS!! RTT = " + dt + "ms aveRTT = " + aveRTT + "ms" + " RTO = " + RTO + "ms"); + } + } + + private int calcAVEIQ(int iq) { + int n = nIQTests; + + nIQTests += 1; + + aveIQSize = ((n * aveIQSize) + iq) / nIQTests; + + return aveIQSize; + } + + /** + * Process an ACK Message. We remove ACKed messages from the retry queue. + * We only acknowledge messages received in sequence. + * + * The seqnum is for the largest unacknowledged seqnum + * the receipient has received. + * + * The sackList is a sequence of all of the received + * messages in the sender's input Q. All will be sequence numbers higher + * than the sequential ACK seqnum. + * + * Recepients are passive and only ack upon the receipt + * of an in sequence message. + * + * They depend on our RTO to fill holes in message + * sequences. + **/ + void ackReceived(int seqnum, int[] sackList) { + lastACKTime = TimeUtils.timeNow(); + int numberACKed = 0; + + // remove acknowledged messages from retrans Q. + + synchronized (retrQ) { + maxACK = Math.max(maxACK, seqnum); + + // dump the current Retry queue and the SACK list + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + StringBuilder dumpRETRQ = new StringBuilder("ACK RECEIVE : " + Integer.toString(seqnum)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append('\n'); + } + dumpRETRQ.append("\tRETRQ (size=" + retrQ.size() + ")"); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append(" : "); + for (int y = 0; y < retrQ.size(); y++) { + if (0 != y) { + dumpRETRQ.append(", "); + } + RetrQElt r = retrQ.get(y); + + dumpRETRQ.append(r.seqnum); + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append('\n'); + } + dumpRETRQ.append("\tSACKLIST (size=" + sackList.length + ")"); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append(" : "); + for (int y = 0; y < sackList.length; y++) { + if (0 != y) { + dumpRETRQ.append(", "); + } + dumpRETRQ.append(sackList[y]); + } + } + LOG.fine(dumpRETRQ.toString()); + } + + Iterator eachRetryQueueEntry = retrQ.iterator(); + + // First remove monotonically increasing seq#s in retrans vector + while (eachRetryQueueEntry.hasNext()) { + RetrQElt r = (RetrQElt) eachRetryQueueEntry.next(); + + if (r.seqnum > seqnum) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("r.seqnum :" + r.seqnum + " > seqnum :" + seqnum); + } + break; + } + + // Acknowledged + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("seqnum :" + seqnum); + LOG.fine("Removing :" + r.seqnum + " from retransmit queue"); + } + eachRetryQueueEntry.remove(); + + // Update RTT, RTO + if (0 != r.enqueuedAt) { + calcRTT(r.enqueuedAt); + } + + r.msg.clear(); + r.msg = null; + r = null; + numberACKed++; + } + + // Update last accessed time in response to getting seq acks. + if (numberACKed > 0) { + conn.lastAccessed = TimeUtils.timeNow(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS!! SEQUENTIALLY ACKD SEQN = " + seqnum + ", (" + numberACKed + " acked)"); + } + + // most recent remote IQ free space + rmaxQSize = Math.max(rmaxQSize, sackList.length); + mrrIQFreeSpace = rmaxQSize - sackList.length; + + // let's look at average sacs.size(). If it is big, then this + // probably means we must back off because the system is slow. + // Our retrans Queue can be large and we can overwhelm the + // receiver with retransmissions. + // We will keep the rwin <= ave real input queue size. + int aveIQ = calcAVEIQ(sackList.length); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("remote IQ free space = " + mrrIQFreeSpace + " remote avg IQ occupancy = " + aveIQ); + } + + int retrans = 0; + + if (sackList.length > 0) { + Iterator eachRetrQElement = retrQ.iterator(); + + int currentSACK = 0; + + while (eachRetrQElement.hasNext()) { + RetrQElt r = (RetrQElt) eachRetrQElement.next(); + + while (sackList[currentSACK] < r.seqnum) { + currentSACK++; + if (currentSACK == sackList.length) { + break; + } + } + + if (currentSACK == sackList.length) { + break; + } + + if (sackList[currentSACK] == r.seqnum) { + eachRetrQElement.remove(); + + // ack counter + numberACKed++; + + // for aveRTT calculation + long enqueuetime = r.enqueuedAt; + + // Update RTT, RTO + if (enqueuetime != 0) { + calcRTT(enqueuetime); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS!! SACKD SEQN = " + r.seqnum); + } + + // GC this stuff + r.msg.clear(); + r.msg = null; + r = null; + + } else { + // Retransmit? Only if there is a hole in the selected + // acknowledgement list. Otherwise let RTO deal. + // Given that this SACK acknowledged messages still + // in the retrQ: + // seqnum is the max consectively SACKD message. + // seqnum < r.seqnum means a message has not reached + // receiver. EG: sacklist == 10,11,13 seqnum == 11 + // We retransmit 12. + if (seqnum < r.seqnum) { + retrans++; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETR: Fill hole, SACK, seqn#" + r.seqnum + ", Window =" + retrans); + } + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS!! SELECTIVE ACKD (" + numberACKed + ") " + retrans + " retrans wanted"); + } + + // retransmit 1 retq mem. only + if (retrans > 0) { + retransmit(Math.min(RWINDOW, retrans), lastACKTime); + sackRetransTime = TimeUtils.timeNow(); + } + } + + retrQ.notify(); + } + } + + /** + * retransmit unacknowledged messages + * + * @param rwin max number of messages to retransmit + * @return number of messages retransmitted. + **/ + private int retransmit(int rwin, long triggerTime) { + List retransMsgs = new ArrayList(); + + int numberToRetrans; + + // build a list of retries. + synchronized (retrQ) { + numberToRetrans = Math.min(retrQ.size(), rwin); + + if (numberToRetrans > 0 && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANSMITING [rwindow = " + numberToRetrans + "]"); + } + + for (int j = 0; j < numberToRetrans; j++) { + RetrQElt r = retrQ.get(j); + + // Mark message as retransmission + // need to know if a msg was retr or not for RTT eval + + if (r.marked == 0) { + + // First time: we're here because this message has not arrived, but + // the next one has. It may be an out of order message. + // Experience shows that such a message rarely arrives older than + // 1.2 * aveRTT. Beyond that, it's lost. It is also rare that we + // detect a hole within that delay. So, often enough, as soon as + // a hole is detected, it's time to resend...but not always. + + if (TimeUtils.toRelativeTimeMillis(triggerTime, r.sentAt) < (6 * aveRTT) / 5) { + + // Nothing to worry about, yet. + continue; + } + + } else { + + // That one has been retransmitted at least once already. + // So, we don't have much of a clue other than the age of the + // last transmission. It is unlikely that it arrives before aveRTT/2 + // but we have to anticipate its loss at the risk of making dupes. + // Otherwise the receiver will reach the hole, and that's really + // expensive. (Think that we've been trying for a while already.) + + if (TimeUtils.toRelativeTimeMillis(triggerTime, r.sentAt) < aveRTT) { + + // Nothing to worry about, yet. + continue; + } + } + + r.marked++; + // Make a copy to for sending + retransMsgs.add(r); + } + } + + // send the retries. + int retransmitted = 0; + + Iterator eachRetrans = retransMsgs.iterator(); + + while (eachRetrans.hasNext()) { + RetrQElt r = (RetrQElt) eachRetrans.next(); + + eachRetrans.remove(); + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TLS!! RETRANSMIT seqn#" + r.seqnum); + } + + Message sending = r.msg; + + // its possible that the message was acked while we were working + // in this case r.msg will have been nulled. + if (null != sending) { + sending = sending.clone(); + sending.replaceMessageElement(JTlsDefs.TLSNameSpace, RETELT); + if (conn.sendToRemoteTls(sending)) { + mrrIQFreeSpace--; // assume we have now taken a slot + retransmitted++; + } else { + break; + } // don't bother continuing. + } + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "FAILED RETRANS seqn#" + r.seqnum, e); + } + break; // don't bother continuing. + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANSMITED " + retransmitted + " of " + numberToRetrans); + } + + return retransmitted; + } + + /** + * Retransmission daemon thread + **/ + private class Retransmitter implements Runnable { + + Thread retransmitterThread; + volatile int nretransmitted = 0; + int nAtThisRTO = 0; + + public Retransmitter() { + + this.retransmitterThread = new Thread(tp.myThreadGroup, this, "JXTA TLS Retransmiter for " + conn.destAddr); + retransmitterThread.setDaemon(true); + retransmitterThread.start(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("STARTED TLS Retransmit thread, RTO = " + RTO); + } + } + + public int getRetransCount() { + return nretransmitted; + } + + /** + * {@inheritDoc] + **/ + public void run() { + + try { + int idleCounter = 0; + + while (!closed) { + long conn_idle = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), conn.lastAccessed); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANS : " + conn + " idle for " + conn_idle); + } + + // check to see if we have not idled out. + if (tp.CONNECTION_IDLE_TIMEOUT < conn_idle) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RETRANS : Shutting down idle connection: " + conn); + } + try { + setClosing(); + // the following call eventually closes this stream + conn.close(HandshakeState.CONNECTIONDEAD); + // Leave. Otherwise we'll be spinning forever + return; + } catch (IOException ignored) { + ; + } + continue; + } + + synchronized (retrQ) { + try { + retrQ.wait(RTO); + } catch (InterruptedException e) { + Thread.interrupted(); + } + } + if (closed) { + break; + } + + // see if we recently did a retransmit triggered by a SACK + long sinceLastSACKRetr = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), sackRetransTime); + + if (sinceLastSACKRetr < RTO) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANS : SACK retrans " + sinceLastSACKRetr + "ms ago"); + } + + continue; + } + + // See how long we've waited since RTO was set + long sinceLastACK = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), lastACKTime); + long oldestInQueueWait; + + synchronized (retrQ) { + if (retrQ.size() > 0) { + oldestInQueueWait = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), retrQ.get(0).enqueuedAt); + } else { + oldestInQueueWait = 0; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANS : Last ACK " + sinceLastACK + "ms ago. Age of oldest in Queue " + oldestInQueueWait + "ms"); + } + + // see if the queue has gone dead + if (oldestInQueueWait > (tp.RETRMAXAGE * 2)) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RETRANS : Shutting down stale connection: " + conn); + } + try { + setClosing(); + conn.close(HandshakeState.CONNECTIONDEAD); + // Leave. Otherwise we'll be spinning forever. + return; + } catch (IOException ignored) { + ; + } + continue; + } + + // get real wait as max of age of oldest in retrQ and + // lastAck time + long realWait = Math.max(oldestInQueueWait, sinceLastACK); + + // Retransmit only if RTO has expired. + // a. real wait time is longer than RTO + // b. oldest message on Q has been there longer + // than RTO. This is necessary because we may + // have just sent a message, and we do not + // want to overrun the receiver. Also, we + // do not want to restransmit a message that + // has not been idle for the RTO. + if ((realWait >= RTO) && (oldestInQueueWait >= RTO)) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANS : RTO RETRANSMISSION [" + RWINDOW + "]"); + } + + // retrasmit + int retransed = retransmit(RWINDOW, TimeUtils.timeNow()); + + // Total + nretransmitted += retransed; + + // number at this RTO + nAtThisRTO += retransed; + + // See if real wait is too long and queue is non-empty + // Remote may be dead - double until max. + // Double after window restransmitted msgs at this RTO + // exceeds the RWINDOW, and we've had no response for + // twice the current RTO. + if ((retransed > 0) && (realWait >= 2 * RTO) && (nAtThisRTO >= 2 * RWINDOW)) { + RTO = (realWait > maxRTO ? maxRTO : 2 * RTO); + nAtThisRTO = 0; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANS : RETRANSMISSION " + retransed + " retrans " + nAtThisRTO + " at this RTO (" + RTO + + ") " + nretransmitted + " total retrans"); + } + } else { + idleCounter += 1; + + // reset RTO to min if we are idle + if (idleCounter == 2) { + RTO = minRTO; + idleCounter = 0; + nAtThisRTO = 0; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANS : IDLE : RTO=" + RTO + " WAIT=" + realWait); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("STOPPED TLS Retransmit thread"); + } + + retransmitterThread = null; + retransmitter = null; + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsConn.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsConn.java new file mode 100644 index 000000000..a3e80dd58 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsConn.java @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.cert.X509Certificate; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Provider; +import java.security.Security; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.util.IgnoreFlushFilterOutputStream; +import net.jxta.impl.membership.pse.PSECredential; +import net.jxta.impl.util.TimeUtils; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * This class implements the TLS connection between two peers. + * + * + *

            Properties: + * + *

            net.jxta.impl.endpoint.tls.TMFAlgorithm - if defined provides the name of + * the trust manager factory algorithm to use. + */ +class TlsConn { + + /** + * Logger + **/ + private static final transient Logger LOG = Logger.getLogger(TlsConn.class.getName()); + static final int BOSIZE = 16000; + /** + * TLS transport this connection is working for. + **/ + final TlsTransport transport; + /** + * The address of the peer to which we will be forwarding ciphertext + * messages. + **/ + final EndpointAddress destAddr; + /** + * Are we client or server? + **/ + private boolean client; + /** + * State of the connection + **/ + private volatile HandshakeState currentState; + /** + * Are we currently closing? To prevent recursion in {@link close()} + **/ + private boolean closing = false; + /** + * Time that something "good" last happened on the connection + **/ + long lastAccessed; + final String lastAccessedLock = new String("lastAccessedLock"); + final String closeLock = new String("closeLock"); + /** + * Number of retransmissions we have received. + **/ + int retrans; + /** + * Our synthetic socket which sends and receives the ciphertext. + **/ + final TlsSocket tlsSocket; + private final SSLContext context; + /** + * For interfacing with TLS + **/ + private SSLSocket ssls; + /** + * We write our plaintext to this stream + **/ + private OutputStream plaintext_out = null; + /** + * Reads plaintext from the + **/ + private PlaintextMessageReader readerThread = null; + /** + * A string which we can lock on while acquiring new messengers. We don't + * want to lock the whole connection object. + **/ + private String acquireMessengerLock = new String("Messenger Acquire Lock"); + /** + * Cached messenger for sending to {@link destAddr} + **/ + private Messenger outBoundMessenger = null; + +/** + * Tracks the state of our TLS connection with a remote peer. + **/ + enum HandshakeState { + + /** + * Handshake is ready to begin. We will be the client side. + */ + CLIENTSTART + + , /** + * Handshake is ready to begin. We will be the server side. + */ + SERVERSTART + + , /** + * Handshake is in progress. + */ + HANDSHAKESTARTED + + , /** + * Handshake failed to complete. + */ + HANDSHAKEFAILED + + , /** + * Handshake completed successfully. + */ + HANDSHAKEFINISHED + + , /** + * Connection is closing. + */ + CONNECTIONCLOSING + + , /** + * Connection has died. + */ + CONNECTIONDEAD + } + + /** + * Create a new connection + **/ + TlsConn(TlsTransport tp, EndpointAddress destAddr, boolean client) throws Exception { + this.transport = tp; + this.destAddr = destAddr; + this.client = client; + this.currentState = client ? HandshakeState.CLIENTSTART : HandshakeState.SERVERSTART; + this.lastAccessed = TimeUtils.timeNow(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info((client ? "Initiating" : "Accepting") + " new connection for : " + destAddr.getProtocolAddress()); + } + + boolean choseTMF = false; + javax.net.ssl.TrustManagerFactory tmf = null; + String overrideTMF = System.getProperty("net.jxta.impl.endpoint.tls.TMFAlgorithm"); + + if ((!choseTMF) && (null != overrideTMF)) { + tmf = javax.net.ssl.TrustManagerFactory.getInstance(overrideTMF); + choseTMF = true; + } + + Collection providers = Arrays.asList(Security.getProviders()); + + Set providerNames = new HashSet(); + + Iterator eachProvider = providers.iterator(); + + while (eachProvider.hasNext()) { + providerNames.add(((Provider) eachProvider.next()).getName()); + } + + if ((!choseTMF) && providerNames.contains("SunJSSE")) { + tmf = javax.net.ssl.TrustManagerFactory.getInstance("SunX509", "SunJSSE"); + choseTMF = true; + } + + if ((!choseTMF) && providerNames.contains("IBMJSSE")) { + tmf = javax.net.ssl.TrustManagerFactory.getInstance("IbmX509", "IBMJSSE"); + choseTMF = true; + } + + // XXX 20040830 bondolo Other solutions go here! + if (!choseTMF) { + tmf = javax.net.ssl.TrustManagerFactory.getInstance(javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm()); + LOG.warning("Using defeualt Trust Manager Factory algorithm. This may not work as expected."); + } + + KeyStore trusted = transport.membership.getPSEConfig().getKeyStore(); + + tmf.init(trusted); + + javax.net.ssl.TrustManager[] tms = tmf.getTrustManagers(); + + javax.net.ssl.KeyManager[] kms = new javax.net.ssl.KeyManager[]{new PSECredentialKeyManager(transport.credential, trusted)}; + + context = SSLContext.getInstance("TLS"); + context.init(kms, tms, null); + + javax.net.ssl.SSLSocketFactory factory = context.getSocketFactory(); + + // endpoint interface + TlsSocket newConnect = new TlsSocket(new JTlsInputStream(this, tp.MIN_IDLE_RECONNECT), new JTlsOutputStream(transport, this)); + + // open SSL socket and do the handshake + ssls = (SSLSocket) factory.createSocket(newConnect, destAddr.getProtocolAddress(), JTlsDefs.FAKEPORT, true); + ssls.setEnabledProtocols(new String[]{"TLSv1"}); + ssls.setUseClientMode(client); + if (!client) { + ssls.setNeedClientAuth(true); + } + + // We have to delay initialization of this until we have set the + // handshake mode. + tlsSocket = newConnect; + } + + /** + * @inheritDoc + * + *

            An implementation which is useful for debugging. + **/ + @Override + public String toString() { + return super.toString() + "/" + getHandshakeState() + ":" + (client ? "Client" : "Server") + " for " + destAddr; + } + + /** + * Returns the current state of the connection + * + * @return the current state of the connection. + **/ + HandshakeState getHandshakeState() { + return currentState; + } + + /** + * Changes the state of the connection. Calls + * {@link java.lang.Object#notifyAll()} to wake any threads waiting on + * connection state changes. + * + * @param newstate the new connection state. + * @return the previous state of the connection. + **/ + synchronized HandshakeState setHandshakeState(HandshakeState newstate) { + + HandshakeState oldstate = currentState; + + currentState = newstate; + notifyAll(); + return oldstate; + } + + /** + * Open the connection with the remote peer. + **/ + void finishHandshake() throws IOException { + + long startTime = 0; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + startTime = TimeUtils.timeNow(); + LOG.info((client ? "Client:" : "Server:") + " Handshake START"); + } + + setHandshakeState(HandshakeState.HANDSHAKESTARTED); + + // this starts a handshake + SSLSession newSession = ssls.getSession(); + + if ("SSL_NULL_WITH_NULL_NULL".equals(newSession.getCipherSuite())) { + setHandshakeState(HandshakeState.HANDSHAKEFAILED); + throw new IOException("Handshake failed"); + } + + setHandshakeState(HandshakeState.HANDSHAKEFINISHED); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + long hsTime = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), startTime) / TimeUtils.ASECOND; + + LOG.info((client ? "Client:" : "Server:") + "Handshake DONE in " + hsTime + " secs"); + } + + // set up plain text i/o + // writes to be encrypted + plaintext_out = new BufferedOutputStream(ssls.getOutputStream(), BOSIZE); + + // Start reader thread + readerThread = new PlaintextMessageReader(ssls.getInputStream()); + } + + /** + * Close this connection. + * + * @param finalstate state that the connection will be in after close. + **/ + void close(HandshakeState finalstate) throws IOException { + synchronized (lastAccessedLock) { + lastAccessed = Long.MIN_VALUE; + } + synchronized (closeLock) { + closing = true; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Shutting down " + this); + } + + setHandshakeState(HandshakeState.CONNECTIONCLOSING); + + try { + if (null != tlsSocket) { + try { + tlsSocket.close(); + } catch (IOException ignored) { + ; + } + } + + if (null != ssls) { + try { + ssls.close(); + } catch (IOException ignored) { + ; + } + ssls = null; + } + + if (null != outBoundMessenger) { + outBoundMessenger.close(); + outBoundMessenger = null; + } + } catch (Throwable failed) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Throwable during close " + this, failed); + } + + IOException failure = new IOException("Throwable during close()"); + + failure.initCause(failed); + } finally { + closeLock.notifyAll(); + closing = false; + setHandshakeState(finalstate); + } + } + } + + /** + * Used by the TlsManager and the TlsConn in order to send a message, + * either a TLS connection establishment, or TLS fragments to the remote TLS. + * + * @param msg message to send to the remote TLS peer. + * @return if true then message was sent, otherwise false. + * @throws IOException if there was a problem sending the message. + **/ + boolean sendToRemoteTls(Message msg) throws IOException { + + synchronized (acquireMessengerLock) { + if ((null == outBoundMessenger) || outBoundMessenger.isClosed()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting messenger for " + destAddr); + } + + EndpointAddress realAddr = new EndpointAddress(destAddr, JTlsDefs.ServiceName, null); + + // Get a messenger. + outBoundMessenger = transport.endpoint.getMessenger(realAddr); + + if (outBoundMessenger == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Could not get messenger for " + realAddr); + } + return false; + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " to " + destAddr); + } + + // Good we have a messenger. Send the message. + return outBoundMessenger.sendMessage(msg); + } + + /** + * sendMessage is called by the TlsMessenger each time a service or + * an application sends a new message over a TLS connection. + * IOException is thrown when something goes wrong. + * + *

            The message is encrypted by TLS ultimately calling + * JTlsOutputStream.write(byte[], int, int); with the resulting TLS + * Record(s). + * + * @param msg The plaintext message to be sent via this connection. + * @throws IOException for errors in sending the message. + **/ + void sendMessage(Message msg) throws IOException { + + try { + WireFormatMessage serialed = WireFormatMessageFactory.toWire(msg, JTlsDefs.MTYPE, (MimeMediaType[]) null); + + serialed.sendToStream(new IgnoreFlushFilterOutputStream(plaintext_out)); + + plaintext_out.flush(); + } catch (IOException failed) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Closing " + this + " due to exception ", failed); + } + + close(HandshakeState.CONNECTIONDEAD); + throw failed; + } + } + +/** + * This is our message reader thread. This reads from the plaintext input + * stream and dispatches messages received to the endpoint. + **/ + private class PlaintextMessageReader implements Runnable { + + InputStream ptin = null; + Thread workerThread = null; + + public PlaintextMessageReader(InputStream ptin) { + this.ptin = ptin; + + // start our thread + workerThread = new Thread(TlsConn.this.transport.myThreadGroup, this, "JXTA TLS Plaintext Reader for " + TlsConn.this.destAddr); + workerThread.setDaemon(true); + workerThread.start(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Started ReadPlaintextMessage thread for " + TlsConn.this.destAddr); + } + } + + /** + * @inheritDoc + **/ + public void run() { + try { + while (true) { + try { + Message msg = WireFormatMessageFactory.fromWire(ptin, JTlsDefs.MTYPE, null); + + if (null == msg) { + break; + } + + // dispatch it to TlsTransport for demuxing + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Dispatching " + msg + " to TlsTransport"); + } + + TlsConn.this.transport.processReceivedMessage(msg); + + synchronized (TlsConn.this.lastAccessedLock) { + TlsConn.this.lastAccessed = TimeUtils.timeNow(); // update idle timer + } + } catch (IOException iox) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "I/O error while reading decrypted Message", iox); + } + + break; + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + workerThread = null; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Finishing ReadPlaintextMessage thread"); + } + } + } + +/** + * A private key manager which selects based on the key and cert chain found + * in a PSE Credential. + * + *

            TODO Promote this class to a full featured interface for all of the + * active PSECredentials. Currently the alias "theone" is used to refer to + * the + **/ + private static class PSECredentialKeyManager implements javax.net.ssl.X509KeyManager { + + PSECredential cred; + KeyStore trusted; + + public PSECredentialKeyManager(PSECredential useCred, KeyStore trusted) { + this.cred = useCred; + this.trusted = trusted; + } + + /** + * {@inheritDoc} + **/ + public String chooseClientAlias(String[] keyType, java.security.Principal[] issuers, java.net.Socket socket) { + for (String aKeyType : Arrays.asList(keyType)) { + String result = checkTheOne(aKeyType, Arrays.asList(issuers)); + + if (null != result) { + return result; + } + } + + return null; + } + + /** + * Checks to see if a peer that trusts the given issuers would trust the + * special alias THE_ONE, returning it if so, and null otherwise. + * + * @param keyType the type of key a Certificate must use to be considered + * @param issuers the issuers trusted by the other peer + * @return "theone" if one of the Certificates in this peer's PSECredential's + * Certificate chain matches the given keyType and one of the issuers, + * or null + */ + private String checkTheOne(String keyType, Collection allIssuers) { + List certificates = Arrays.asList(cred.getCertificateChain()); + + for (X509Certificate certificate : certificates) { + if (!certificate.getPublicKey().getAlgorithm().equals(keyType)) { + continue; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("CHECKING: " + certificate.getIssuerX500Principal() + " in " + allIssuers); + } + + if (allIssuers.contains(certificate.getIssuerX500Principal())) { + return "theone"; + } + } + return null; + } + + /** + * {@inheritDoc} + **/ + public String chooseServerAlias(String keyType, java.security.Principal[] issuers, java.net.Socket socket) { + String[] available = getServerAliases(keyType, issuers); + + if (null != available) { + return available[0]; + } else { + return null; + } + } + + /** + * {@inheritDoc} + **/ + public X509Certificate[] getCertificateChain(String alias) { + if (alias.equals("theone")) { + return cred.getCertificateChain(); + } else { + try { + return (X509Certificate[]) trusted.getCertificateChain(alias); + } catch (KeyStoreException ignored) { + return null; + } + } + } + + /** + * {@inheritDoc} + **/ + public String[] getClientAliases(String keyType, java.security.Principal[] issuers) { + List clientAliases = new ArrayList(); + + try { + Enumeration eachAlias = trusted.aliases(); + + Collection allIssuers = null; + + if (null != issuers) { + allIssuers = Arrays.asList(issuers); + } + + while (eachAlias.hasMoreElements()) { + String anAlias = (String) eachAlias.nextElement(); + + if (trusted.isCertificateEntry(anAlias)) { + try { + X509Certificate aCert = (X509Certificate) trusted.getCertificate(anAlias); + + if (null == aCert) { + // strange... it should have been there... + continue; + } + + if (!aCert.getPublicKey().getAlgorithm().equals(keyType)) { + continue; + } + + if (null != allIssuers) { + if (allIssuers.contains(aCert.getIssuerX500Principal())) { + clientAliases.add(anAlias); + } + } else { + clientAliases.add(anAlias); + } + } catch (KeyStoreException ignored) { + ; + } + } + } + } catch (KeyStoreException ignored) { + ; + } + + return (String[]) clientAliases.toArray(new String[clientAliases.size()]); + } + + /** + * {@inheritDoc} + **/ + public java.security.PrivateKey getPrivateKey(String alias) { + if (alias.equals("theone")) { + return cred.getPrivateKey(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + **/ + public String[] getServerAliases(String keyType, java.security.Principal[] issuers) { + if (keyType.equals(cred.getCertificate().getPublicKey().getAlgorithm())) { + if (null == issuers) { + return new String[]{"theone"}; + } else { + Collection allIssuers = Arrays.asList(issuers); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Looking for : " + cred.getCertificate().getIssuerX500Principal()); + LOG.fine("Issuers : " + allIssuers); + java.security.Principal prin = cred.getCertificate().getIssuerX500Principal(); + + LOG.fine(" Principal Type :" + prin.getClass().getName()); + Iterator it = allIssuers.iterator(); + + while (it.hasNext()) { + java.security.Principal tmp = (java.security.Principal) it.next(); + + LOG.fine("Issuer Type : " + tmp.getClass().getName()); + LOG.fine("Issuer value : " + tmp); + LOG.fine("tmp.equals(prin) : " + tmp.equals(prin)); + } + } + + X509Certificate[] chain = cred.getCertificateChain(); + for (X509Certificate aCert : Arrays.asList(chain)) { + if (allIssuers.contains(aCert.getIssuerX500Principal())) { + return new String[]{"theone"}; + } + } + } + } + return null; + } + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsManager.java new file mode 100644 index 000000000..2cfd15733 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsManager.java @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import java.io.DataInputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import java.io.IOException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; + +import net.jxta.impl.util.TimeUtils; + +import net.jxta.impl.endpoint.tls.TlsConn.HandshakeState; + + +/** + * Manages the connection pool between peers. + **/ +class TlsManager implements EndpointListener { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(TlsManager.class.getName()); + + /** + * Transport we are working for. + **/ + private TlsTransport transport = null; + + /** + * Hash table for known connections + * + *

              + *
            • keys are {@link String } containing {@link net.jxta.peer.PeerID#getUniqueValue() PeerID.getUniqueValue()}
            • + *
            • values are {@link TlsConn}
            • + *
            + **/ + private Map connections = new HashMap(); + + /** + * The last time at which we printed a warning about discarding messages + * due to no authentication. + **/ + private long lastNonAuthenticatedWarning = 0; + + /** + * Standard Constructor for TLS Manager + **/ + TlsManager(TlsTransport tp) { + this.transport = tp; + } + + /** + * Close this manager. This involves closing all registered connections. + * + **/ + void close() { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Shutting down all connections"); + } + + synchronized (connections) { + Iterator eachConnection = connections.values().iterator(); + + while (eachConnection.hasNext()) { + TlsConn aConnection = (TlsConn) eachConnection.next(); + + try { + aConnection.close(HandshakeState.CONNECTIONDEAD); + } catch (IOException ignored) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Non-fatal problem shutting down connection to " + aConnection); + } + } + + eachConnection.remove(); + } + } + } + + /** + * Returns or creates a TLS Connection to the specified peer. If an + * existing connection exists, it will be returned. + * + * @param dstAddr the EndpointAddress of the remote peer. + * @return A TLS Connection or null if the connection could not be opened. + **/ + TlsConn getTlsConn(EndpointAddress dstAddr) { + + if (null == transport.credential) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Not authenticated. Cannot open connections."); + } + + return null; + } + + boolean startHandshake = false; + + // see if we have an existing conn, and if so, then reuse it + // if it has not timed out. + String paddr = dstAddr.getProtocolAddress(); + + TlsConn conn = null; + + synchronized (connections) { + conn = (TlsConn) connections.get(paddr); + + // remove it if it is dead + if (null != conn) { + if ((HandshakeState.CONNECTIONDEAD == conn.getHandshakeState()) + || (HandshakeState.HANDSHAKEFAILED == conn.getHandshakeState())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing connection for: " + paddr); + } + connections.remove(paddr); + conn = null; + } + } + + // create the connection info entry as needed + if (null == conn) { + try { + conn = new TlsConn(transport, dstAddr, true); // true means client + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed making connection to " + paddr, failed); + } + + return null; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding connection for: " + paddr); + } + connections.put(paddr, conn); + startHandshake = true; + } + } + + // if we got to be the first one to start the handshake then do it here. + // We do this outside of the synchro block so that others can enter the + // state machine. + if (startHandshake) { + try { + // OK. We are originating the connection: + // Open the connection (returns when handshake is completed) + // or throws an IOException if a TLS internal error occurs. + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Start of client handshake for " + paddr); + } + + conn.finishHandshake(); + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed making connection to " + paddr, e); + } + + synchronized (connections) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing connection for: " + paddr); + } + connections.remove(paddr); + } + try { + conn.close(HandshakeState.HANDSHAKEFAILED); + } catch (IOException ignored) { + ; + } + + return null; + } + } + + do { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("getting " + conn); + } + + synchronized (conn) { + HandshakeState currentState = conn.getHandshakeState(); + + if ((HandshakeState.SERVERSTART == currentState) || (HandshakeState.CLIENTSTART == currentState)) { + // wait for the handshake to get going on another thread. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sleeping until handshake starts for " + paddr); + } + + try { + conn.wait(TimeUtils.ASECOND); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + continue; + } else if (HandshakeState.HANDSHAKESTARTED == currentState) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Handshake in progress for " + paddr); + } + + try { + // sleep forever waiting for the state to change. + conn.wait(200); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + continue; + } else if (HandshakeState.HANDSHAKEFINISHED == currentState) { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Returning active connection to " + paddr); + } + + conn.lastAccessed = TimeUtils.timeNow(); // update idle timer + + return conn; + } else if (HandshakeState.HANDSHAKEFAILED == currentState) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Handshake failed. " + paddr + " unreachable"); + } + + return null; + } else if (HandshakeState.CONNECTIONDEAD == currentState) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Connection dead for " + paddr); + } + + return null; + } else if (HandshakeState.CONNECTIONCLOSING == currentState) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Connection closing for " + paddr); + } + + return null; + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Unhandled Handshake state: " + currentState); + } + } + } + } while (true); + } + + /** + * Handle an incoming message from the endpoint. This method demultiplexes + * incoming messages to the connection objects by their source address. + * + *

            Several types of messages may be received for a connection: + * + *

              + *
            • TLS Elements
            • + *
            • Element Acknowledgements
            • + *
            + * + * @param msg is the incoming message + * @param srcAddr is the address of the source of the message + * @param dstAddr is the address of the destination of the message + **/ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Starts for " + msg); + } + + if (null == transport.credential) { + // ignore ALL messages until we are authenticated. + if (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), lastNonAuthenticatedWarning) > TimeUtils.AMINUTE) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("NOT AUTHENTICATED--Discarding all incoming messages"); + } + + lastNonAuthenticatedWarning = TimeUtils.timeNow(); + } + + return; + } + + // determine if its a retry. + MessageElement retryElement = msg.getMessageElement(JTlsDefs.TLSNameSpace, JTlsDefs.RETR); + boolean retrans = (null != retryElement); + + if (retrans) { + msg.removeMessageElement(retryElement); + retryElement = null; + } + + int seqN = getMsgSequenceNumber(msg); + + // Extract unique part of source address + String paddr = srcAddr.getProtocolAddress(); + + TlsConn conn = null; + + boolean serverStart = false; + + synchronized (connections) { + // Will be in our hash table unless this is for a first time + // incoming connection request + conn = (TlsConn) connections.get(paddr); + + if (null != conn) { + // check if the connection has idled out and remote is asking for a restart. + if (TlsTransport.ACT_AS_SERVER && (1 == seqN)) { + synchronized (conn) { + long idle = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), conn.lastAccessed); + + if (idle > transport.MIN_IDLE_RECONNECT) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Restarting : " + conn + " which has been idle for " + idle + " millis"); + } + try { + conn.close(HandshakeState.CONNECTIONDEAD); + } catch (IOException ignored) { + ; + } + } + } + } + + // remove it if it is dead + if ((HandshakeState.CONNECTIONDEAD == conn.getHandshakeState()) + || (HandshakeState.HANDSHAKEFAILED == conn.getHandshakeState())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing connection for: " + paddr); + } + connections.remove(paddr); + conn = null; + } + } + + // we don't have a connection to this destination, make a new connection if seqn#1 + if (null == conn) { + if (TlsTransport.ACT_AS_SERVER && (1 == seqN)) { + try { + conn = new TlsConn(transport, srcAddr, false); // false means Server + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed making connection for" + paddr, failed); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding connection for: " + paddr); + } + connections.put(paddr, conn); + serverStart = true; + } else { + // Garbage from an old connection. discard it + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(msg + " is not start of handshake (seqn#" + seqN + ") for " + paddr); + } + + msg.clear(); + return; + } + } + } + + // if this is a new connection, get it started. + if (serverStart) { + try { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Start of SERVER handshake for " + paddr); + } + + // Queue message up for TlsInputStream on that connection + conn.tlsSocket.input.queueIncomingMessage(msg); + + // Start the TLS Server and complete the handshake + conn.finishHandshake(); // open the TLS connection + + conn.lastAccessed = TimeUtils.timeNow(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Handshake complete for SERVER TLS for: " + paddr); + } + + return; + } catch (Throwable e) { + // Handshake failure or IOException + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "TLS Handshake failure for connection: " + paddr, e); + } + + synchronized (connections) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing connection for: " + paddr); + } + connections.remove(paddr); + } + try { + conn.close(HandshakeState.HANDSHAKEFAILED); + } catch (IOException ignored) { + ; + } + + return; + } + } + + // handle an ongoing connection. + do { + HandshakeState currentState; + + synchronized (conn) { + if (retrans) { + conn.retrans++; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("retrans received, " + conn.retrans + " total."); + } + retrans = false; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Process incoming message for " + conn); + } + + currentState = conn.getHandshakeState(); + + if ((HandshakeState.HANDSHAKESTARTED == currentState) || (HandshakeState.HANDSHAKEFINISHED == currentState) + || (HandshakeState.CONNECTIONCLOSING == currentState)) {// we will process the message once we get out of sync. + } else if (HandshakeState.CONNECTIONDEAD == currentState) { + // wait for the handshake to get going on another thread. + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Connection failed, discarding msg with seqn#" + seqN + " for " + paddr); + } + + return; + } else if ((HandshakeState.SERVERSTART == currentState) || (HandshakeState.CLIENTSTART == currentState)) { + // wait for the handshake to get going on another thread. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sleeping msg with seqn#" + seqN + " until handshake starts for " + paddr); + } + + try { + conn.wait(TimeUtils.AMINUTE); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + continue; + } else if (HandshakeState.HANDSHAKEFAILED == currentState) { + // wait for the handshake to get going on another thread. + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Handshake failed, discarding msg with seqn#" + seqN + " for " + paddr); + } + + return; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unexpected state : " + currentState); + } + } + } + + // Process any message outside of the sync on the connection. + if ((HandshakeState.HANDSHAKESTARTED == currentState) || (HandshakeState.HANDSHAKEFINISHED == currentState) + || (HandshakeState.CONNECTIONCLOSING == currentState)) { + // process any ACK messages. + Iterator eachACK = msg.getMessageElements(JTlsDefs.TLSNameSpace, JTlsDefs.ACKS); + + while (eachACK.hasNext()) { + MessageElement elt = (MessageElement) eachACK.next(); + + eachACK.remove(); + + int sackCount = ((int) elt.getByteLength() / 4) - 1; + + try { + DataInputStream dis = new DataInputStream(elt.getStream()); + + int seqack = dis.readInt(); + + int[] sacs = new int[sackCount]; + + for (int eachSac = 0; eachSac < sackCount; eachSac++) { + sacs[eachSac] = dis.readInt(); + } + + Arrays.sort(sacs); + + // take care of the ACK here; + conn.tlsSocket.output.ackReceived(seqack, sacs); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure processing ACK", failed); + } + } + } + + if (0 == seqN) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Queue " + msg + " seqn#" + seqN + " for " + conn); + } + + // Queue message up for TlsInputStream on that connection + TlsSocket bound = conn.tlsSocket; + + if (null != bound) { + bound.input.queueIncomingMessage(msg); + } + + return; + } + } while (true); + } + + /** + * getMsgSequenceNumber + * + * @param msg Input message + * @return int sequence number or 0 (zero) if no tls records in message. + **/ + private static int getMsgSequenceNumber(Message msg) { + + int seqN = 0; + + Iterator eachElement = msg.getMessageElements(JTlsDefs.TLSNameSpace, JTlsDefs.BLOCKS); + + while (eachElement.hasNext()) { + MessageElement elt = (MessageElement) eachElement.next(); + + try { + seqN = Integer.parseInt(elt.getElementName()); + } catch (NumberFormatException e) { + // This element was not a TLS element. Get the next one + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Bad tls record name=" + elt.getElementName()); + } + + eachElement.remove(); + continue; + } + + break; + } + + return seqN; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsMessenger.java new file mode 100644 index 000000000..4e80d913d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsMessenger.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import java.io.*; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.endpoint.*; +import net.jxta.impl.endpoint.*; +import net.jxta.impl.endpoint.tls.TlsConn.HandshakeState; + + +/** + * This class implements sending messages through a TLS connection. + */ +public class TlsMessenger extends BlockingMessenger { + + private static final Logger LOG = Logger.getLogger(TlsMessenger.class.getName()); + + private TlsTransport transport = null; + private TlsConn conn = null; + + /** + * The source address of messages sent on this messenger. + */ + private final EndpointAddress srcAddress; + + private final MessageElement srcAddressElement; + + TlsMessenger(EndpointAddress destAddress, TlsConn conn, TlsTransport tp) { + + // No need for self destruction. + super(tp.getPeerGroup().getPeerGroupID(), destAddress, false); + + if (conn == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("null TLS connection!"); + } + throw new IllegalArgumentException("null TLS connection!"); + } + + this.conn = conn; + this.transport = tp; + + this.srcAddress = transport.getPublicAddress(); + + srcAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NAME, srcAddress.toString() + , + (MessageElement) null); + } + + /* + * The cost of just having a finalize routine is high. The finalizer is + * a bottleneck and can delay garbage collection all the way to heap + * exhaustion. Leave this comment as a reminder to future maintainers. + * Below is the reason why finalize is not needed here. + * + * These messengers never go to the application layer. The endpoint code + * always invokes close when needed. + + protected void finalize() { + } + + */ + + /** + * {@inheritDoc} + */ + @Override + public synchronized void closeImpl() { + super.close(); + conn = null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdleImpl() { + // No need for self destruction. + return false; + } + + /** + * {@inheritDoc} + * + *

            The peer that is the destination is the logical address + */ + @Override + public EndpointAddress getLogicalDestinationImpl() { + return new EndpointAddress("jxta", dstAddress.getProtocolAddress(), null, null); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void sendMessageBImpl(Message message, String service, String serviceParam) throws IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Starting send for " + message); + } + + // check if the connection has died. + if (HandshakeState.CONNECTIONDEAD == conn.getHandshakeState()) { + + // FIXME - jice@jxta.org 20040413: This will do but it causes the below exception to be shown as the cause of the + // failure, which is not true: nobody realy closed the messenger before it failed. It failed first. Also, it used to + // shutdown this messenger, now it does not. What does is the call to closeImpl() that follows our IOException...(and + // that's how it should be). Transports should get a deeper retrofit eventually. + + close(); + } + + if (isClosed()) { + IOException failure = new IOException("Messenger is closed, it cannot be used to send messages."); + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failure.getMessage(), failure); + } + + throw failure; + } + + // Set the message with the appropriate src and dest address + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_SOURCE_NS, srcAddressElement); + + MessageElement dstAddressElement = new StringMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NAME + , + getDestAddressToUse(service, serviceParam).toString(), (MessageElement) null); + + message.replaceMessageElement(EndpointServiceImpl.MESSAGE_DESTINATION_NS, dstAddressElement); + + // Give the message to the TLS connection + try { + conn.sendMessage(message); + } catch (IOException caught) { + close(); + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Message send to \'" + dstAddress + "\' failed for " + message, caught); + } + throw caught; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message send to \'" + dstAddress + "\' succeeded for " + message); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsSocket.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsSocket.java new file mode 100644 index 000000000..a38e1b814 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsSocket.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.channels.SocketChannel; +import net.jxta.impl.endpoint.IPUtils; + + +/** + * A "shim" socket which we provide to the TLS layer. + */ +public class TlsSocket extends Socket { + + final JTlsInputStream input; + final JTlsOutputStream output; + + boolean connected = true; + + /** + * Creates a new instance of TlsSocket + */ + public TlsSocket(JTlsInputStream useInput, JTlsOutputStream useOutput) { + input = useInput; + output = useOutput; + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + input.close(); + output.close(); + connected = false; + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream getInputStream() throws IOException { + return input; + } + + /** + * {@inheritDoc} + */ + @Override + public OutputStream getOutputStream() throws IOException { + return output; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isBound() { + return connected; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isConnected() { + return connected; + } + + /** + * {@inheritDoc} + */ + @Override + public InetAddress getInetAddress() { + return IPUtils.LOOPBACK; + } + + /** + * {@inheritDoc} + */ + @Override + public InetAddress getLocalAddress() { + return IPUtils.ANYADDRESS; + } + + /** + * {@inheritDoc} + */ + @Override + public SocketAddress getRemoteSocketAddress() { + return new InetSocketAddress(IPUtils.LOOPBACK, 0); + } + + /** + * {@inheritDoc} + */ + @Override + public SocketAddress getLocalSocketAddress() { + return new InetSocketAddress(IPUtils.ANYADDRESS, 0); + } + + /** + * {@inheritDoc} + */ + @Override + public SocketChannel getChannel() { + return null; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsTransport.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsTransport.java new file mode 100644 index 000000000..b1fc8cf4f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/TlsTransport.java @@ -0,0 +1,772 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.tls; + + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.net.URI; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.ResourceBundle; +import javax.security.auth.x500.X500Principal; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.KeyStoreException; +import java.security.SignatureException; +import java.util.MissingResourceException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageReceiver; +import net.jxta.endpoint.MessageSender; +import net.jxta.endpoint.Messenger; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; + +import net.jxta.exception.PeerGroupException; + +import net.jxta.impl.endpoint.LoopbackMessenger; +import net.jxta.impl.membership.pse.PSECredential; +import net.jxta.impl.membership.pse.PSEMembershipService; +import net.jxta.impl.peergroup.GenericPeerGroup; +import net.jxta.impl.util.TimeUtils; + + +/** + * A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which + * uses TLS sockets. + */ +public class TlsTransport implements Module, MessageSender, MessageReceiver { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(TlsTransport.class.getName()); + + /** + * If true then we can accept incoming connections. Eventually this should + * be coming out of the transport advertisement. + */ + static final boolean ACT_AS_SERVER = true; + + private PeerGroup group = null; + ID assignedID = null; + ModuleImplAdvertisement implAdvertisement = null; + + EndpointService endpoint = null; + PSEMembershipService membership = null; + private membershipPCL membershipListener = null; + + X509Certificate[] serviceCert = null; + + PSECredential credential = null; + private credentialPCL credentialListener = null; + + EndpointAddress localPeerAddr = null; + EndpointAddress localTlsPeerAddr = null; + + /** + * local peerID + */ + PeerID localPeerId = null; + + /** + * Amount of a connection must be idle before a reconnection attempt will + * be considered. + */ + long MIN_IDLE_RECONNECT = 1 * TimeUtils.AMINUTE; + + /** + * Amount of time after which a connection is considered idle and may be + * scavenged. + */ + long CONNECTION_IDLE_TIMEOUT = 5 * TimeUtils.AMINUTE; + + /** + * Amount if time which retries may remain queued for retransmission. If + * still unACKed after this amount of time then the connection is + * considered dead. + */ + long RETRMAXAGE = 2 * TimeUtils.AMINUTE; + + /** + * Will manage connections to remote peers. + */ + private TlsManager manager = null; + + /** + * This is the thread group into which we will place all of the threads + * we create. THIS HAS NO EFFECT ON SCHEDULING. Java thread groups are + * only for organization and naming. + */ + ThreadGroup myThreadGroup = null; + + /** + * Extends LoopbackMessenger to add a message property to passed messages + * so that TLS pipes and other users can be sure that the message + * originate with the local TLS transport. + */ + class TlsLoopbackMessenger extends LoopbackMessenger { + TlsLoopbackMessenger(EndpointService ep, EndpointAddress src, EndpointAddress dest, EndpointAddress logicalDest) { + super(group, ep, src, dest, logicalDest); + } + + /** + * {@inheritDoc} + **/ + @Override + public void sendMessageBImpl(Message message, String service, String serviceParam) throws IOException { + + // add a property to the message to indicate it came from us. + message.setMessageProperty(TlsTransport.class, TlsTransport.this); + + super.sendMessageBImpl(message, service, serviceParam); + } + } + + /** + * Default constructor + **/ + public TlsTransport() { + + // initialize connection timeout + try { + ResourceBundle jxtaRsrcs = ResourceBundle.getBundle("net.jxta.user"); + + try { + String override_str = jxtaRsrcs.getString("impl.endpoint.tls.connection.idletimeout"); + + if (null != override_str) { + long override_long = Long.parseLong(override_str.trim()); + + if (override_long >= 1) { + CONNECTION_IDLE_TIMEOUT = override_long * TimeUtils.AMINUTE; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Adjusting TLS connection idle timeout to " + CONNECTION_IDLE_TIMEOUT + " millis."); + } + } + } + } catch (NumberFormatException badvalue) { + ; + } + + try { + String override_str = jxtaRsrcs.getString("impl.endpoint.tls.connection.minidlereconnect"); + + if (null != override_str) { + long override_long = Long.parseLong(override_str.trim()); + + if (override_long >= 1) { + MIN_IDLE_RECONNECT = override_long * TimeUtils.AMINUTE; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Adjusting TLS min reconnection idle to " + MIN_IDLE_RECONNECT + " millis."); + } + } + } + } catch (NumberFormatException badvalue) { + ; + } + + try { + String override_str = jxtaRsrcs.getString("impl.endpoint.tls.connection.maxretryage"); + + if (null != override_str) { + long override_long = Long.parseLong(override_str.trim()); + + if (override_long >= 1) { + RETRMAXAGE = override_long * TimeUtils.AMINUTE; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Adjusting TLS maximum retry queue age to " + RETRMAXAGE + " millis."); + } + } + } + } catch (NumberFormatException badvalue) { + ; + } + + // reconnect must be less the idle interval. + + MIN_IDLE_RECONNECT = Math.min(MIN_IDLE_RECONNECT, CONNECTION_IDLE_TIMEOUT); + + // max retry queue age must be less the idle interval. + RETRMAXAGE = Math.min(RETRMAXAGE, CONNECTION_IDLE_TIMEOUT); + + } catch (MissingResourceException notthere) { + ; + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (null == target) { + return false; + } + + if (target instanceof TlsTransport) { + TlsTransport likeMe = (TlsTransport) target; + + if (!getProtocolName().equals(likeMe.getProtocolName())) { + return false; + } + + return localTlsPeerAddr.equals(likeMe.localTlsPeerAddr); + } + + return false; + } + + /** + * {@inheritDoc} + */ + PeerGroup getPeerGroup() { + return group; + } + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + this.group = group; + this.assignedID = assignedID; + this.implAdvertisement = (ModuleImplAdvertisement) impl; + + localPeerId = group.getPeerID(); + + localPeerAddr = mkAddress(group.getPeerID(), null, null); + + localTlsPeerAddr = new EndpointAddress(JTlsDefs.tlsPName, localPeerId.getUniqueValue().toString(), null, null); + + myThreadGroup = new ThreadGroup(group.getHomeThreadGroup(), "TLSTransport " + localTlsPeerAddr); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring TLS Transport : " + assignedID); + + if (null != implAdvertisement) { + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tModule Spec ID: " + implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + } + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: " + group.getPeerID()); + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tProtocol: " + JTlsDefs.tlsPName); + configInfo.append("\n\t\tOutgoing Connections Enabled: " + Boolean.TRUE); + configInfo.append("\n\t\tIncoming Connections Enabled: " + ACT_AS_SERVER); + configInfo.append("\n\t\tMinimum idle for reconnect : " + MIN_IDLE_RECONNECT + "ms"); + configInfo.append("\n\t\tConnection idle timeout : " + CONNECTION_IDLE_TIMEOUT + "ms"); + configInfo.append("\n\t\tRetry queue maximum age : " + RETRMAXAGE + "ms"); + configInfo.append("\n\t\tPeerID : " + localPeerId); + configInfo.append("\n\t\tRoute through : " + localPeerAddr); + configInfo.append("\n\t\tPublic Address : " + localTlsPeerAddr); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized int startApp(String[] args) { + + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + + return START_AGAIN_STALLED; + } + + MembershipService groupMembership = group.getMembershipService(); + + if (null == groupMembership) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + + return START_AGAIN_STALLED; + } + + if (!(groupMembership instanceof PSEMembershipService)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("TLS Transport requires PSE Membership Service"); + } + return -1; + } + + if (endpoint.addMessageTransport(this) == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Transport registration refused"); + } + return -1; + } + + membership = (PSEMembershipService) groupMembership; + + PropertyChangeListener mpcl = new membershipPCL(); + + membership.addPropertyChangeListener(mpcl); + + try { + serviceCert = membership.getPSEConfig().getTrustedCertificateChain(assignedID); + + Enumeration eachCred = membership.getCurrentCredentials(); + + while (eachCred.hasMoreElements()) { + PSECredential aCred = (PSECredential) eachCred.nextElement(); + + // send a fake property change event. + mpcl.propertyChange(new PropertyChangeEvent(membership, "addCredential", null, aCred)); + } + } catch (IOException failed) { + serviceCert = null; + } catch (KeyStoreException failed) { + serviceCert = null; + } + + // Create the TLS Manager + manager = new TlsManager(this); + + // Connect ourself to the EndpointService + try { + endpoint.addIncomingMessageListener(manager, JTlsDefs.ServiceName, null); + } catch (Throwable e2) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "TLS could not register listener...as good as dead", e2); + } + return -1; + } + + return 0; + } + + /** + * {@inheritDoc} + */ + public synchronized void stopApp() { + if (null != endpoint) { + endpoint.removeIncomingMessageListener(JTlsDefs.ServiceName, null); + endpoint.removeMessageTransport(this); + endpoint = null; + } + + if (null != manager) { + manager.close(); + manager = null; + } + + if (null != membership) { + membership.removePropertyChangeListener(membershipListener); + membershipListener = null; + membership = null; + } + + PSECredential temp = credential; + + if (null != temp) { + temp.removePropertyChangeListener(credentialListener); + credentialListener = null; + credential = null; + } + } + + /** + * {@inheritDoc} + **/ + public boolean isConnectionOriented() { + + return true; + } + + /** + * {@inheritDoc} + */ + public boolean allowsRouting() { + // The TLS connection should not be used for default routing + return false; + } + + /** + * {@inheritDoc} + */ + public Object transportControl(Object operation, Object Value) { + return null; + } + + /** + * {@inheritDoc} + */ + public EndpointAddress getPublicAddress() { + return localTlsPeerAddr; + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return endpoint; + } + + /** + * {@inheritDoc} + */ + public Iterator getPublicAddresses() { + return Collections.singletonList(getPublicAddress()).iterator(); + } + + /** + * {@inheritDoc} + */ + public String getProtocolName() { + return JTlsDefs.tlsPName; + } + + /** + * {@inheritDoc} + */ + public boolean ping(EndpointAddress addr) { + + return null != getMessenger(addr, null); + } + + /** + * {@inheritDoc} + * + * XXX bondolo 20040522 The hint could be used in request for the + * underlying messenger. + */ + public Messenger getMessenger(EndpointAddress addr, Object hintIgnored) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("getMessenger for " + addr); + } + + EndpointAddress plainAddress = new EndpointAddress(addr, null, null); + + // If the dest is the local peer, just loop it back without going + // through the TLS. Local communication do not use TLS. + if (plainAddress.equals(localTlsPeerAddr)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("returning LoopbackMessenger"); + } + return new TlsLoopbackMessenger(endpoint, plainAddress, addr, localPeerAddr); + } + + // Create a Peer EndpointAddress + EndpointAddress dstPAddr = mkAddress(ID.URIEncodingName + ":" + ID.URNNamespace + ":" + addr.getProtocolAddress(), null + , + null); + + TlsConn conn = manager.getTlsConn(dstPAddr); + + if (conn == null) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Cannot get a TLS connection for " + dstPAddr); + } + // No connection was either available or created. Cannot do TLS + // with the destination address. + return null; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TlsMessanger with TlsConn DONE"); + } + + // Build a TlsMessenger around it that will add our header. + // Right now we do not want to "announce" outgoing messengers because they get pooled and so must + // not be grabbed by a listener. If "announcing" is to be done, that should be by the endpoint + // and probably with a subtely different interface. + return new TlsMessenger(addr, conn, this); + } + + /** + * processReceivedMessage is invoked by the TLS Manager when a message has been + * completely received and is ready to be delivered to the service/application + */ + void processReceivedMessage(final Message msg) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("processReceivedMessage starts"); + } + + // add a property to the message to indicate it came from us. + msg.setMessageProperty(TlsTransport.class, this); + + // let the message continue to its final destination. + try { + ((GenericPeerGroup)group).getExecutor().execute( new Runnable() { + public void run() { + try { + endpoint.demux(msg); + } catch(Throwable uncaught) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure demuxing an incoming message", uncaught); + } + } + } + }); + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure demuxing an incoming message", e); + } + } + } + + /** + * Convenience method for constructing an endpoint address from an id + * + * @param destPeer peer id + * @param serv the service name (if any) + * @param parm the service param (if any) + * @param endpointAddress for this peer id. + */ + private final static EndpointAddress mkAddress(String destPeer, String serv, String parm) { + + ID asID = null; + + try { + asID = IDFactory.fromURI(new URI(destPeer)); + } catch (URISyntaxException caught) { + throw new IllegalArgumentException(caught.getMessage()); + } + + return mkAddress(asID, serv, parm); + } + + /** + * Convenience method for constructing an endpoint address from an id + * + * @param destPeer peer id + * @param serv the service name (if any) + * @param parm the service param (if any) + * @param endpointAddress for this peer id. + */ + private final static EndpointAddress mkAddress(ID destPeer, String serv, String parm) { + + EndpointAddress addr = new EndpointAddress("jxta", destPeer.getUniqueValue().toString(), serv, parm); + + return addr; + } + + /** + * Listener for Property Changed Events on our credential + **/ + class credentialPCL implements PropertyChangeListener { + + /** + * {@inheritDoc} + * + *

            Handle events on our active credential. + **/ + public synchronized void propertyChange(PropertyChangeEvent evt) { + + if (credential == evt.getSource()) { + if (!credential.isValid()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Clearing credential/certfile "); + } + + credential.removePropertyChangeListener(this); + credential = null; + } + } + } + } + + + /** + * Listener for Property Changed Events on membership service + **/ + class membershipPCL implements PropertyChangeListener { + + /** + * {@inheritDoc} + **/ + public synchronized void propertyChange(PropertyChangeEvent evt) { + + String evtProp = evt.getPropertyName(); + PSECredential cred = (PSECredential) evt.getNewValue(); + + boolean validCertificate = true; + + if (null != serviceCert) { + try { + serviceCert[0].checkValidity(); + } catch (Exception notValidException) { + validCertificate = false; + } + } + + if ("addCredential".equals(evtProp) && ((null == serviceCert) || !validCertificate)) { + // no service Cert or Non-valid Cert? Make one. + Exception failure = null; + + try { + X509Certificate peerCert = membership.getPSEConfig().getTrustedCertificate(group.getPeerID()); + + X500Principal credSubjectDN = cred.getCertificate().getSubjectX500Principal(); + X500Principal peerCertSubjectDN = peerCert.getSubjectX500Principal(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Checking credential cert for match to peer cert" + "\n\tcred subject=" + credSubjectDN + + "\n\tpeer subject=" + peerCertSubjectDN); + } + + if (peerCertSubjectDN.equals(credSubjectDN)) { + + serviceCert = cred.generateServiceCertificate(assignedID); + + } + } catch (IOException failed) { + failure = failed; + } catch (KeyStoreException failed) { + failure = failed; + } catch (InvalidKeyException failed) { + failure = failed; + } catch (SignatureException failed) { + failure = failed; + } + + if (null != failure) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failure building service certificate", failure); + } + + return; + } + } + + if ("addCredential".equals(evtProp)) { + Exception failure = null; + + try { + X509Certificate credCert = cred.getCertificate(); + + X500Principal credSubjectDN = credCert.getSubjectX500Principal(); + X500Principal serviceIssuerDN = serviceCert[0].getIssuerX500Principal(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Checking credential cert for match to service issuer cert" + "\n\tcred subject=" + credSubjectDN + + "\n\t svc issuer=" + serviceIssuerDN); + } + + if (credSubjectDN.equals(serviceIssuerDN)) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Setting credential/certfile "); + } + + credential = cred.getServiceCredential(assignedID); + + if (null != credential) { + credentialListener = new credentialPCL(); + credential.addPropertyChangeListener(credentialListener); + } + } + } catch (IOException failed) { + failure = failed; + } catch (PeerGroupException failed) { + failure = failed; + } catch (InvalidKeyException failed) { + failure = failed; + } catch (SignatureException failed) { + failure = failed; + } + + if (null != failure) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failure building service credential", failure); + } + + return; + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/package.html new file mode 100644 index 000000000..4190d5a73 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/tls/package.html @@ -0,0 +1,15 @@ + + + + + + + A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which + which provides secure, private message transmission using TLS sockets. A + virtual transport, the messages are transfered between peers using some + other message transport. + + @see JXTA Protocols Specification : Standard JXTA Transport Bindings + @see IETF RFC 2246: The TLS Protocol-Version 1.0 + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/ConditionalTransportMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/ConditionalTransportMeterBuildSettings.java new file mode 100644 index 000000000..3f2e70ca7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/ConditionalTransportMeterBuildSettings.java @@ -0,0 +1,80 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.endpoint.transportMeter; + +import java.util.ResourceBundle; +import net.jxta.impl.meter.*; + +public class ConditionalTransportMeterBuildSettings { + public static boolean isRuntimeMetering() { + boolean runtimeMetering = false; + + try { + ResourceBundle userResourceBundle = ResourceBundle.getBundle( "net.jxta.user" ); + String meteringProperty = "net.jxta.meter.conditionalTransportMetering"; + String meteringValue = userResourceBundle.getString( meteringProperty ); + runtimeMetering = "on".equalsIgnoreCase( meteringValue ); + } catch (Exception ignored) { + } + + return runtimeMetering; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportBindingMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportBindingMeter.java new file mode 100644 index 000000000..2fc3bb68f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportBindingMeter.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.peer.PeerID; +import net.jxta.endpoint.*; + + +public class TransportBindingMeter { + private PeerID peerID; + private EndpointAddress endpointAddress; + + private TransportBindingMetric cumulativeMetrics; + private TransportBindingMetric deltaMetrics; + + public TransportBindingMeter(PeerID peerID, EndpointAddress endpointAddress) { + this(peerID, endpointAddress, false, false); + } + + public TransportBindingMeter(PeerID peerID, EndpointAddress endpointAddress, boolean initiatorConnected, boolean acceptorConnected) { + this.peerID = peerID; + this.endpointAddress = endpointAddress; + cumulativeMetrics = new TransportBindingMetric(this, initiatorConnected, acceptorConnected); + } + + @Override + public String toString() { + return "TransportBindingMeter(" + endpointAddress + ";" + peerID + ")"; + } + + public synchronized TransportBindingMetric collectMetrics() { + TransportBindingMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + return prevDelta; + } + + private void createDeltaMetric() { + deltaMetrics = new TransportBindingMetric(cumulativeMetrics); + } + + public TransportBindingMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public PeerID getPeerID() { + return peerID; + } + + public EndpointAddress getEndpointAddress() { + return endpointAddress; + } + + public void setPeerID(PeerID peerID) { + this.peerID = peerID; + cumulativeMetrics.setPeerID(peerID); + + if (deltaMetrics != null) { + deltaMetrics.setPeerID(peerID); + } + } + + public synchronized void connectionEstablished(boolean initator, long timeToConnect) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + long now = System.currentTimeMillis(); + + deltaMetrics.connectionEstablished(initator, timeToConnect, now); + cumulativeMetrics.connectionEstablished(initator, timeToConnect, now); + } + + public synchronized void connectionFailed(boolean initator, long timeToConnect) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + long now = System.currentTimeMillis(); + + deltaMetrics.connectionFailed(initator, timeToConnect, now); + cumulativeMetrics.connectionFailed(initator, timeToConnect, now); + } + + public synchronized void connectionClosed(boolean initator, long connectionLife) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + long now = System.currentTimeMillis(); + + deltaMetrics.connectionClosed(initator, now); + cumulativeMetrics.connectionClosed(initator, now); + } + + public synchronized void connectionDropped(boolean initator, long connectionLife) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + long now = System.currentTimeMillis(); + + deltaMetrics.connectionDropped(initator, now); + cumulativeMetrics.connectionDropped(initator, now); + } + + public synchronized void pingReceived() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.pingReceived(); + cumulativeMetrics.pingReceived(); + } + + public synchronized void ping(long time) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.ping(time); + cumulativeMetrics.ping(time); + } + + public synchronized void pingFailed(long time) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.pingFailed(time); + cumulativeMetrics.pingFailed(time); + } + + public synchronized void dataReceived(boolean initator, int size) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.dataReceived(initator, size); + cumulativeMetrics.dataReceived(initator, size); + } + + public synchronized void messageReceived(boolean initator, Message message, long time, long size) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageReceived(initator, message, time, size); + cumulativeMetrics.messageReceived(initator, message, time, size); + } + + public synchronized void receiveFailure(boolean initator, long time, long size) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.receiveFailure(initator, time, size); + cumulativeMetrics.receiveFailure(initator, time, size); + } + + public synchronized void dataSent(boolean initator, long size) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.dataSent(initator, size); + cumulativeMetrics.dataSent(initator, size); + } + + public synchronized void sendFailure(boolean initator, Message message, long time, long size) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.sendFailure(initator, message, time, size); + cumulativeMetrics.sendFailure(initator, message, time, size); + } + + public synchronized void messageSent(boolean initator, Message message, long time, long size) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageSent(initator, message, time, size); + cumulativeMetrics.messageSent(initator, message, time, size); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportBindingMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportBindingMetric.java new file mode 100644 index 000000000..1af8e6afb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportBindingMetric.java @@ -0,0 +1,1135 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.document.Element; +import net.jxta.document.TextElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.impl.meter.MetricUtilities; +import net.jxta.peer.PeerID; +import net.jxta.util.documentSerializable.DocumentSerializable; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; + +import java.util.Enumeration; + + +public class TransportBindingMetric implements DocumentSerializable { + public static final String CONNECTED = "connected"; + public static final String CLOSED = "closed"; + public static final String DROPPED = "dropped"; + public static final String FAILED = "failed"; + + private PeerID peerID; + private EndpointAddress endpointAddress; + + private String initiatorState = null; + private String acceptorState = null; + private long initiatorTransitionTime; + private long acceptorTransitionTime; + + private int acceptorBytesReceived; + private int acceptorBytesSent; + private int acceptorConnections; + private int acceptorConnectionsClosed; + private int acceptorConnectionsDropped; + private int acceptorConnectionsFailed; + private int acceptorMessagesReceived; + private int acceptorMessagesSent; + private long acceptorReceiveFailureProcessingTime; + private int acceptorReceiveFailures; + private long acceptorReceiveProcessingTime; + private long acceptorSendFailureProcessingTime; + private int acceptorSendFailures; + private long acceptorSendProcessingTime; + private long acceptorTotalTimeConnected; + private long acceptorTimeToConnect; + private long acceptorTimeToFail; + private int initiatorBytesReceived; + private int initiatorBytesSent; + private long initiatorTotalTimeConnected; + private int initiatorConnections; + private int initiatorConnectionsClosed; + private int initiatorConnectionsDropped; + private int initiatorConnectionsFailed; + private int initiatorMessagesReceived; + private int initiatorMessagesSent; + private long initiatorReceiveFailureProcessingTime; + private int initiatorReceiveFailures; + private long initiatorReceiveProcessingTime; + private long initiatorSendFailureProcessingTime; + private int initiatorSendFailures; + private long initiatorSendProcessingTime; + private long initiatorTimeToConnect; + private long initiatorTimeToFail; + + private int numPings; + private int numFailedPings; + private long pingTime; + private long pingFailedTime; + private int numPingsReceived; + + public TransportBindingMetric(TransportBindingMeter transportBindingMeter, boolean initiatorConnected, boolean acceptorConnected) { + this.peerID = transportBindingMeter.getPeerID(); + this.endpointAddress = transportBindingMeter.getEndpointAddress(); + this.initiatorState = initiatorConnected ? CONNECTED : CLOSED; + this.acceptorState = acceptorConnected ? CONNECTED : CLOSED; + } + + public TransportBindingMetric() {} + + public TransportBindingMetric(TransportBindingMetric prototype) { + this.peerID = prototype.peerID; + this.endpointAddress = prototype.endpointAddress; + this.initiatorState = prototype.initiatorState; + this.acceptorState = prototype.acceptorState; + this.initiatorTransitionTime = prototype.initiatorTransitionTime; + this.acceptorTransitionTime = prototype.acceptorTransitionTime; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TransportBindingMetric) { + TransportBindingMetric other = (TransportBindingMetric) obj; + + return endpointAddress.equals(other.endpointAddress); + } else { + return false; + } + } + + @Override + public int hashCode() { + return peerID.hashCode() + endpointAddress.hashCode(); + } + + public PeerID getPeerID() { + return peerID; + } + + public void setPeerID(PeerID peerID) { + this.peerID = peerID; + } + + public EndpointAddress getEndpointAddress() { + return endpointAddress; + } + + /** + * State of this Initiator Binding + * + * @return TransportBindingMetric.CONNECTED, TransportBindingMetric.DISCONNECTED or TransportBindingMetric.FAILED + */ + public String getInitiatorState() { + return initiatorState; + } + + /** + * State of this Acceptor Binding + * + * @return TransportBindingMetric.CONNECTED, TransportBindingMetric.DISCONNECTED or TransportBindingMetric.FAILED + */ + public String getAcceptorState() { + return acceptorState; + } + + /** + * Get the time that it entered the current state + * + * @return transition time in ms since January 1, 1970, 00:00:00 GMT + */ + public long getInitiatorTransitionTime() { + return initiatorTransitionTime; + } + + /** + * Get the time that it entered the current state + * + * @return transition time in ms since January 1, 1970, 00:00:00 GMT + */ + public long getAcceptorTransitionTime() { + return acceptorTransitionTime; + } + + public boolean isAcceptorConnected() { + return (acceptorState != null) && acceptorState.equals(CONNECTED); + } + + public boolean isInitiatorConnected() { + return (initiatorState != null) && initiatorState.equals(CONNECTED); + } + + public long getTimeAcceptorConnectionEstablished() { + return isAcceptorConnected() ? acceptorTransitionTime : 0; + } + + public long getTimeInitiatorConnectionEstablished() { + return isInitiatorConnected() ? initiatorTransitionTime : 0; + } + + public int getAcceptorBytesReceived() { + return acceptorBytesReceived; + } + + public int getAcceptorBytesSent() { + return acceptorBytesSent; + } + + public int getAcceptorConnections() { + return acceptorConnections; + } + + public int getAcceptorConnectionsClosed() { + return acceptorConnectionsClosed; + } + + public int getAcceptorConnectionsDropped() { + return acceptorConnectionsDropped; + } + + public int getAcceptorConnectionsFailed() { + return acceptorConnectionsFailed; + } + + public int getAcceptorMessagesReceived() { + return acceptorMessagesReceived; + } + + public int getAcceptorMessagesSent() { + return acceptorMessagesSent; + } + + public long getAcceptorReceiveFailureProcessingTime() { + return acceptorReceiveFailureProcessingTime; + } + + public int getAcceptorReceiveFailures() { + return acceptorReceiveFailures; + } + + public long getAcceptorReceiveProcessingTime() { + return acceptorReceiveProcessingTime; + } + + public long getAcceptorSendFailureProcessingTime() { + return acceptorSendFailureProcessingTime; + } + + public int getAcceptorSendFailures() { + return acceptorSendFailures; + } + + public long getAcceptorSendProcessingTime() { + return acceptorSendProcessingTime; + } + + public long getAcceptorTimeToConnect() { + return acceptorTimeToConnect; + } + + public long getAcceptorTimeToFail() { + return acceptorTimeToFail; + } + + public int getInitiatorBytesReceived() { + return initiatorBytesReceived; + } + + public int getInitiatorBytesSent() { + return initiatorBytesSent; + } + + public int getInitiatorConnections() { + return initiatorConnections; + } + + public int getInitiatorConnectionsClosed() { + return initiatorConnectionsClosed; + } + + public int getInitiatorConnectionsDropped() { + return initiatorConnectionsDropped; + } + + public int getInitiatorConnectionsFailed() { + return initiatorConnectionsFailed; + } + + public int getInitiatorMessagesReceived() { + return initiatorMessagesReceived; + } + + public int getInitiatorMessagesSent() { + return initiatorMessagesSent; + } + + public long getInitiatorReceiveFailureProcessingTime() { + return initiatorReceiveFailureProcessingTime; + } + + public int getInitiatorReceiveFailures() { + return initiatorReceiveFailures; + } + + public long getInitiatorReceiveProcessingTime() { + return initiatorReceiveProcessingTime; + } + + public long getInitiatorSendFailureProcessingTime() { + return initiatorSendFailureProcessingTime; + } + + public int getInitiatorSendFailures() { + return initiatorSendFailures; + } + + public long getInitiatorSendProcessingTime() { + return initiatorSendProcessingTime; + } + + public long getInitiatorTimeToConnect() { + return initiatorTimeToConnect; + } + + public long getInitiatorTimeToFail() { + return initiatorTimeToFail; + } + + public int getNumPings() { + return numPings; + } + + public int getNumFailedPings() { + return numFailedPings; + } + + public long getPingTime() { + return pingTime; + } + + public long getPingFailedTime() { + return pingFailedTime; + } + + public int getNumPingsReceived() { + return numPingsReceived; + } + + public int getBytesReceived() { + return acceptorBytesReceived + initiatorBytesReceived; + } + + public int getBytesSent() { + return acceptorBytesSent + initiatorBytesSent; + } + + public int getConnections() { + return acceptorConnections + initiatorConnections; + } + + public int getConnectionsClosed() { + return acceptorConnectionsClosed + initiatorConnectionsClosed; + } + + public int getConnectionsDropped() { + return acceptorConnectionsDropped + initiatorConnectionsDropped; + } + + public int getConnectionsFailed() { + return acceptorConnectionsFailed + initiatorConnectionsFailed; + } + + public int getMessagesReceived() { + return acceptorMessagesReceived + initiatorMessagesReceived; + } + + public int getMessagesSent() { + return acceptorMessagesSent + initiatorMessagesSent; + } + + public long getReceiveFailureProcessingTime() { + return acceptorReceiveFailureProcessingTime + initiatorReceiveFailureProcessingTime; + } + + public int getReceiveFailures() { + return acceptorReceiveFailures + initiatorReceiveFailures; + } + + public long getReceiveProcessingTime() { + return acceptorReceiveProcessingTime + initiatorReceiveProcessingTime; + } + + public long getSendFailureProcessingTime() { + return acceptorSendFailureProcessingTime + initiatorSendFailureProcessingTime; + } + + public int getSendFailures() { + return acceptorSendFailures + initiatorSendFailures; + } + + public long getSendProcessingTime() { + return acceptorSendProcessingTime + initiatorSendProcessingTime; + } + + public long getTotalTimeConnected() { + return acceptorTotalTimeConnected + initiatorTotalTimeConnected; + } + + public long getTimeToConnect() { + return acceptorTimeToConnect + initiatorTimeToConnect; + } + + public long getTimeToFail() { + return acceptorTimeToFail + initiatorTimeToFail; + } + + public int getAveragePingTime() { + return (int) ((numPings != 0) ? (pingTime / numPings) : 0); + } + + public int getAveragePingFailedTime() { + return (int) ((numFailedPings != 0) ? (pingFailedTime / numFailedPings) : 0); + } + + public int getAverageAcceptorReceiveFailureProcessingTime() { + return (int) ((acceptorReceiveFailures != 0) ? (acceptorReceiveFailureProcessingTime / acceptorReceiveFailures) : 0); + } + + public int getAverageAcceptorReceiveProcessingTime() { + return (int) ((acceptorMessagesReceived != 0) ? (acceptorReceiveProcessingTime / acceptorMessagesReceived) : 0); + } + + public int getAverageAcceptorSendFailureProcessingTime() { + return (int) ((acceptorSendFailures != 0) ? (acceptorSendFailureProcessingTime / acceptorSendFailures) : 0); + } + + public int getAverageAcceptorSendProcessingTime() { + return (int) ((acceptorMessagesSent != 0) ? (acceptorSendProcessingTime / acceptorMessagesSent) : 0); + } + + public int getAverageAcceptorTimeToConnect() { + return (int) ((acceptorConnections != 0) ? (acceptorTimeToConnect / acceptorConnections) : 0); + } + + public int getAverageAcceptorTimeToFail() { + return (int) ((acceptorConnectionsFailed != 0) ? (acceptorTimeToFail / acceptorConnectionsFailed) : 0); + } + + public int getAverageInitiatorReceiveFailureProcessingTime() { + return (int) ((initiatorReceiveFailures != 0) ? (initiatorReceiveFailureProcessingTime / initiatorReceiveFailures) : 0); + } + + public int getAverageInitiatorReceiveProcessingTime() { + return (int) ((initiatorMessagesReceived != 0) ? (initiatorReceiveProcessingTime / initiatorMessagesReceived) : 0); + } + + public int getAverageInitiatorSendFailureProcessingTime() { + return (int) ((initiatorSendFailures != 0) ? (initiatorSendFailureProcessingTime / initiatorSendFailures) : 0); + } + + public int getAverageInitiatorSendProcessingTime() { + return (int) ((initiatorMessagesSent != 0) ? (initiatorSendProcessingTime / initiatorMessagesSent) : 0); + } + + public int getAverageInitiatorTimeToConnect() { + return (int) ((initiatorConnections != 0) ? (initiatorTimeToConnect / initiatorConnections) : 0); + } + + public int getAverageInitiatorTimeToFail() { + return (int) ((initiatorConnectionsFailed != 0) ? (initiatorTimeToFail / initiatorConnectionsFailed) : 0); + } + + public int getAverageReceiveFailureProcessingTime() { + return (int) (((initiatorReceiveFailures + acceptorReceiveFailures) != 0) + ? ((initiatorReceiveFailureProcessingTime + acceptorReceiveFailureProcessingTime) + / (initiatorReceiveFailures + acceptorReceiveFailures)) + : 0); + } + + public int getAverageReceiveProcessingTime() { + return (int) (((initiatorMessagesReceived + acceptorMessagesReceived) != 0) + ? ((initiatorReceiveProcessingTime + acceptorReceiveProcessingTime) + / (initiatorMessagesReceived + acceptorMessagesReceived)) + : 0); + } + + public int getAverageSendFailureProcessingTime() { + return (int) (((initiatorSendFailures + acceptorSendFailures) != 0) + ? ((initiatorSendFailureProcessingTime + acceptorSendFailureProcessingTime) + / (initiatorSendFailures + acceptorSendFailures)) + : 0); + } + + public int getAverageSendProcessingTime() { + return (int) (((initiatorMessagesSent + acceptorMessagesSent) != 0) + ? ((initiatorSendProcessingTime + acceptorSendProcessingTime) / (initiatorMessagesSent + acceptorMessagesSent)) + : 0); + } + + public int getAverageTimeToConnect() { + return (int) (((initiatorConnections + acceptorConnections) != 0) + ? ((initiatorTimeToConnect + acceptorTimeToConnect) / (initiatorConnections + acceptorConnections)) + : 0); + } + + public int getAverageTimeToFail() { + return (int) (((initiatorConnectionsFailed + acceptorConnectionsFailed) != 0) + ? ((initiatorTimeToFail + acceptorTimeToFail) / (initiatorConnectionsFailed + acceptorConnectionsFailed)) + : 0); + } + + /** + * Get the total time this intiated connection has been connected. + *

            + * Note: This does not include the current time connected (if it is currently connected) + * + * @return time in ms (see note above) + * @see #getTotalTimeConnected() + */ + public long getInitiatorTotalTimeConnected() { + return initiatorTotalTimeConnected; + } + + /** + * Get the total time this initiating connection has been connected. If it is currently + * connected, then the total time is adjusted to include the time since the transition time + * to become connected until the provided time + * + * @param adjustmentTime The time of this metric will be adjusted to + * @return time in ms (see note above) + * @see #getTotalTimeConnected() + */ + public long getInitiatorTotalTimeConnected(long adjustmentTime) { + long result = initiatorTotalTimeConnected; + + if (isInitiatorConnected()) { + result += (adjustmentTime - this.initiatorTransitionTime); + } + + return result; + } + + /** + * Get the duration of current connection relative to local clock (from transition time) + *

            + * Note: This assumes the clocks are in sync with the reporting peer + * + * @return time in ms (see note above) or 0 if not connected + * @see #getTotalTimeConnected() + */ + public long getInitiatorTimeConnected() { + return getInitiatorTimeConnected(System.currentTimeMillis()); + } + + /** + * Get the duration of current connection until the specified time + * + * @param adjustmentTime The time of this metric will be computed until + * @return time in ms (see note above) or 0 if not connected + */ + public long getInitiatorTimeConnected(long adjustmentTime) { + + if (isInitiatorConnected()) { + return (adjustmentTime - this.initiatorTransitionTime); + } else { + return 0; + } + } + + /** + * Get the total time this intiated connection has been connected. + *

            + * Note: This does not include the current time connected (if it is currently connected) + * + * @return time in ms (see note above) + * @see #getTotalTimeConnected() + */ + public long getAcceptorTotalTimeConnected() { + return acceptorTotalTimeConnected; + } + + /** + * Get the total time this initiating connection has been connected. If it is currently + * connected, then the total time is adjusted to include the time since the transition time + * to become connected until the provided time + * + * @param adjustmentTime The time of this metric will be adjusted to + * @return time in ms (see note above) + * @see #getTotalTimeConnected() + */ + public long getAcceptorTotalTimeConnected(long adjustmentTime) { + long result = acceptorTotalTimeConnected; + + if (isAcceptorConnected()) { + result += (adjustmentTime - this.acceptorTransitionTime); + } + + return result; + } + + /** + * Get the duration of current connection relative to local clock (from transition time) + *

            + * Note: This assumes the clocks are in sync with the reporting peer + * + * @return time in ms (see note above) or 0 if not connected + * @see #getTotalTimeConnected() + */ + public long getAcceptorTimeConnected() { + return getAcceptorTimeConnected(System.currentTimeMillis()); + } + + /** + * Get the duration of current connection until the specified time + * + * @param adjustmentTime The time of this metric will be computed until + * @return time in ms (see note above) or 0 if not connected + */ + public long getAcceptorTimeConnected(long adjustmentTime) { + + if (isAcceptorConnected()) { + return (adjustmentTime - this.acceptorTransitionTime); + } else { + return 0; + } + } + + void resetInitiatorState(String state, long transitionTime) { + if (isInitiatorConnected()) { + acceptorTotalTimeConnected += (System.currentTimeMillis() - this.initiatorTransitionTime); + } + + this.initiatorState = state; + this.initiatorTransitionTime = transitionTime; + // System.out.println("initiatorState: " + initiatorState + " " + endpointAddress); + } + + void resetAcceptorState(String state, long transitionTime) { + if (isAcceptorConnected()) { + initiatorTotalTimeConnected += (System.currentTimeMillis() - this.acceptorTransitionTime); + } + + this.acceptorState = state; + this.acceptorTransitionTime = transitionTime; + // System.out.println("acceptorState: " + acceptorState + " " + endpointAddress); + } + + void connectionEstablished(boolean initiator, long timeToConnect, long transitionTime) { + if (initiator) { + resetInitiatorState(CONNECTED, transitionTime); + initiatorConnections++; + initiatorTimeToConnect += timeToConnect; + } else { + resetAcceptorState(CONNECTED, transitionTime); + acceptorConnections++; + acceptorTimeToConnect += timeToConnect; + } + + } + + void connectionFailed(boolean initiator, long timeToConnect, long transitionTime) { + if (initiator) { + resetInitiatorState(FAILED, transitionTime); + initiatorConnectionsFailed++; + initiatorTimeToFail += timeToConnect; + } else { + resetAcceptorState(FAILED, transitionTime); + acceptorConnectionsFailed++; + acceptorTimeToFail += timeToConnect; + } + } + + void connectionClosed(boolean initiator, long transitionTime) { + if (initiator) { + resetInitiatorState(CLOSED, transitionTime); + initiatorConnectionsClosed++; + } else { + resetAcceptorState(CLOSED, transitionTime); + acceptorConnectionsClosed++; + } + } + + void connectionDropped(boolean initiator, long transitionTime) { + if (initiator) { + resetInitiatorState(DROPPED, transitionTime); + initiatorConnectionsDropped++; + } else { + resetAcceptorState(DROPPED, transitionTime); + acceptorConnectionsDropped++; + } + } + + void pingReceived() { + numPingsReceived++; + } + + void ping(long time) { + numPings++; + pingTime += time; + } + + void pingFailed(long time) { + numFailedPings++; + pingFailedTime += time; + } + + void dataReceived(boolean initiator, int size) { + if (initiator) { + initiatorBytesReceived += size; + } else { + acceptorBytesReceived += size; + } + } + + void messageReceived(boolean initiator, Message message, long time, long size) { + if (initiator) { + initiatorMessagesReceived++; + initiatorReceiveProcessingTime += time; + initiatorBytesReceived += size; + } else { + acceptorMessagesReceived++; + acceptorReceiveProcessingTime += time; + acceptorBytesReceived += size; + } + } + + void receiveFailure(boolean initiator, long time, long size) { + if (initiator) { + initiatorReceiveFailures++; + initiatorReceiveFailureProcessingTime += time; + initiatorBytesReceived += size; + } else { + acceptorReceiveFailures++; + acceptorReceiveFailureProcessingTime += time; + acceptorBytesReceived += size; + } + } + + void dataSent(boolean initiator, long size) { + if (initiator) { + initiatorBytesSent += size; + } else { + acceptorBytesSent += size; + } + } + + void sendFailure(boolean initiator, Message message, long time, long size) { + if (initiator) { + initiatorSendFailures++; + initiatorSendFailureProcessingTime += time; + initiatorBytesSent += size; + } else { + acceptorSendFailures++; + acceptorSendFailureProcessingTime += time; + acceptorBytesSent += size; + } + } + + void messageSent(boolean initiator, Message message, long time, long size) { + if (initiator) { + initiatorMessagesSent++; + initiatorSendProcessingTime += time; + initiatorBytesSent += size; + } else { + acceptorMessagesSent++; + acceptorSendProcessingTime += time; + acceptorBytesSent += size; + } + } + + public void mergeMetrics(TransportBindingMetric other) { + peerID = other.peerID; + + if (other.initiatorState != null) { + initiatorState = other.initiatorState; + } + + if (other.initiatorTransitionTime != 0) { + initiatorTransitionTime = other.initiatorTransitionTime; + } + + if (other.acceptorState != null) { + acceptorState = other.acceptorState; + } + + if (other.initiatorTransitionTime != 0) { + acceptorTransitionTime = other.acceptorTransitionTime; + } + + acceptorBytesReceived += other.acceptorBytesReceived; + acceptorBytesSent += other.acceptorBytesSent; + acceptorConnections += other.acceptorConnections; + acceptorConnectionsClosed += other.acceptorConnectionsClosed; + acceptorConnectionsDropped += other.acceptorConnectionsDropped; + acceptorConnectionsFailed += other.acceptorConnectionsFailed; + acceptorMessagesReceived += other.acceptorMessagesReceived; + acceptorMessagesSent += other.acceptorMessagesSent; + acceptorReceiveFailureProcessingTime += other.acceptorReceiveFailureProcessingTime; + acceptorReceiveFailures += other.acceptorReceiveFailures; + acceptorReceiveProcessingTime += other.acceptorReceiveProcessingTime; + acceptorSendFailureProcessingTime += other.acceptorSendFailureProcessingTime; + acceptorSendFailures += other.acceptorSendFailures; + acceptorSendProcessingTime += other.acceptorSendProcessingTime; + acceptorTotalTimeConnected += other.acceptorTotalTimeConnected; + acceptorTimeToConnect += other.acceptorTimeToConnect; + acceptorTimeToFail += other.acceptorTimeToFail; + initiatorBytesReceived += other.initiatorBytesReceived; + initiatorBytesSent += other.initiatorBytesSent; + initiatorTotalTimeConnected += other.initiatorTotalTimeConnected; + initiatorConnections += other.initiatorConnections; + initiatorConnectionsClosed += other.initiatorConnectionsClosed; + initiatorConnectionsDropped += other.initiatorConnectionsDropped; + initiatorConnectionsFailed += other.initiatorConnectionsFailed; + initiatorMessagesReceived += other.initiatorMessagesReceived; + initiatorMessagesSent += other.initiatorMessagesSent; + initiatorReceiveFailureProcessingTime += other.initiatorReceiveFailureProcessingTime; + initiatorReceiveFailures += other.initiatorReceiveFailures; + initiatorReceiveProcessingTime += other.initiatorReceiveProcessingTime; + initiatorSendFailureProcessingTime += other.initiatorSendFailureProcessingTime; + initiatorSendFailures += other.initiatorSendFailures; + initiatorSendProcessingTime += other.initiatorSendProcessingTime; + initiatorTimeToConnect += other.initiatorTimeToConnect; + initiatorTimeToFail += other.initiatorTimeToFail; + numPings += other.numPings; + numFailedPings += other.numFailedPings; + pingTime += other.pingTime; + pingFailedTime += other.pingFailedTime; + numPingsReceived += other.numPingsReceived; + + } + + public void serializeTo(Element element) throws DocumentSerializationException { + + DocumentSerializableUtilities.addString(element, "peerID", peerID.toString()); + DocumentSerializableUtilities.addString(element, "endpointAddress", endpointAddress.toString()); + + if (initiatorState != null) { + DocumentSerializableUtilities.addString(element, "initiatorState", initiatorState); + } + if (initiatorTransitionTime != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorTransitionTime", initiatorTransitionTime); + } + + if (acceptorState != null) { + DocumentSerializableUtilities.addString(element, "acceptorState", acceptorState); + } + if (acceptorTransitionTime != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorTransitionTime", acceptorTransitionTime); + } + + if (acceptorBytesReceived != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorBytesReceived", acceptorBytesReceived); + } + + if (acceptorBytesSent != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorBytesSent", acceptorBytesSent); + } + + if (acceptorConnections != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorConnections", acceptorConnections); + } + + if (acceptorConnectionsClosed != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorConnectionsClosed", acceptorConnectionsClosed); + } + + if (acceptorConnectionsDropped != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorConnectionsDropped", acceptorConnectionsDropped); + } + + if (acceptorConnectionsFailed != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorConnectionsFailed", acceptorConnectionsFailed); + } + + if (acceptorMessagesReceived != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorMessagesReceived", acceptorMessagesReceived); + } + + if (acceptorMessagesSent != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorMessagesSent", acceptorMessagesSent); + } + + if (acceptorReceiveFailureProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorReceiveFailureProcessingTime" + , + acceptorReceiveFailureProcessingTime); + } + + if (acceptorReceiveFailures != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorReceiveFailures", acceptorReceiveFailures); + } + + if (acceptorReceiveProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorReceiveProcessingTime", acceptorReceiveProcessingTime); + } + + if (acceptorSendFailureProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorSendFailureProcessingTime", acceptorSendFailureProcessingTime); + } + + if (acceptorSendFailures != 0) { + DocumentSerializableUtilities.addInt(element, "acceptorSendFailures", acceptorSendFailures); + } + + if (acceptorSendProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorSendProcessingTime", acceptorSendProcessingTime); + } + + if (acceptorTotalTimeConnected != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorTotalTimeConnected", acceptorTotalTimeConnected); + } + + if (acceptorTimeToConnect != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorTimeToConnect", acceptorTimeToConnect); + } + + if (acceptorTimeToFail != 0) { + DocumentSerializableUtilities.addLong(element, "acceptorTimeToFail", acceptorTimeToFail); + } + + if (initiatorBytesReceived != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorBytesReceived", initiatorBytesReceived); + } + + if (initiatorBytesSent != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorBytesSent", initiatorBytesSent); + } + + if (initiatorTotalTimeConnected != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorTotalTimeConnected", initiatorTotalTimeConnected); + } + + if (initiatorConnections != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorConnections", initiatorConnections); + } + + if (initiatorConnectionsClosed != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorConnectionsClosed", initiatorConnectionsClosed); + } + + if (initiatorConnectionsDropped != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorConnectionsDropped", initiatorConnectionsDropped); + } + + if (initiatorConnectionsFailed != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorConnectionsFailed", initiatorConnectionsFailed); + } + + if (initiatorMessagesReceived != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorMessagesReceived", initiatorMessagesReceived); + } + + if (initiatorMessagesSent != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorMessagesSent", initiatorMessagesSent); + } + + if (initiatorReceiveFailureProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorReceiveFailureProcessingTime" + , + initiatorReceiveFailureProcessingTime); + } + + if (initiatorReceiveFailures != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorReceiveFailures", initiatorReceiveFailures); + } + + if (initiatorReceiveProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorReceiveProcessingTime", initiatorReceiveProcessingTime); + } + + if (initiatorSendFailureProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorSendFailureProcessingTime" + , + initiatorSendFailureProcessingTime); + } + + if (initiatorSendFailures != 0) { + DocumentSerializableUtilities.addInt(element, "initiatorSendFailures", initiatorSendFailures); + } + + if (initiatorSendProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorSendProcessingTime", initiatorSendProcessingTime); + } + + if (initiatorTimeToConnect != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorTimeToConnect", initiatorTimeToConnect); + } + + if (initiatorTimeToFail != 0) { + DocumentSerializableUtilities.addLong(element, "initiatorTimeToFail", initiatorTimeToFail); + } + + if (numPings != 0) { + DocumentSerializableUtilities.addInt(element, "numPings", numPings); + } + + if (numFailedPings != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedPings", numFailedPings); + } + + if (pingTime != 0) { + DocumentSerializableUtilities.addLong(element, "pingTime", pingTime); + } + + if (pingFailedTime != 0) { + DocumentSerializableUtilities.addLong(element, "pingFailedTime", pingFailedTime); + } + + if (initiatorTimeToFail != 0) { + DocumentSerializableUtilities.addInt(element, "numPingsReceived", numPingsReceived); + } + + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("peerID")) { + String peerIdString = DocumentSerializableUtilities.getString(childElement); + + peerID = MetricUtilities.getPeerIdFromString(peerIdString); + } + if (tagName.equals("endpointAddress")) { + String endpointAddressString = DocumentSerializableUtilities.getString(childElement); + + endpointAddress = new EndpointAddress(endpointAddressString); + } else if (tagName.equals("acceptorBytesReceived")) { + acceptorBytesReceived = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorBytesSent")) { + acceptorBytesSent = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorConnections")) { + acceptorConnections = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorConnectionsClosed")) { + acceptorConnectionsClosed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorConnectionsDropped")) { + acceptorConnectionsDropped = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorConnectionsFailed")) { + acceptorConnectionsFailed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorMessagesReceived")) { + acceptorMessagesReceived = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorMessagesSent")) { + acceptorMessagesSent = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorReceiveFailureProcessingTime")) { + acceptorReceiveFailureProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("acceptorReceiveFailures")) { + acceptorReceiveFailures = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorReceiveProcessingTime")) { + acceptorReceiveProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("acceptorSendFailureProcessingTime")) { + acceptorSendFailureProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("acceptorSendFailures")) { + acceptorSendFailures = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("acceptorSendProcessingTime")) { + acceptorSendProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("acceptorTotalTimeConnected")) { + acceptorTotalTimeConnected = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("acceptorTimeToConnect")) { + acceptorTimeToConnect = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("acceptorTimeToFail")) { + acceptorTimeToFail = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorBytesReceived")) { + initiatorBytesReceived = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorBytesSent")) { + initiatorBytesSent = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorTotalTimeConnected")) { + initiatorTotalTimeConnected = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorConnections")) { + initiatorConnections = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorConnectionsClosed")) { + initiatorConnectionsClosed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorConnectionsDropped")) { + initiatorConnectionsDropped = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorConnectionsFailed")) { + initiatorConnectionsFailed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorMessagesReceived")) { + initiatorMessagesReceived = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorMessagesSent")) { + initiatorMessagesSent = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorReceiveFailureProcessingTime")) { + initiatorReceiveFailureProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorReceiveFailures")) { + initiatorReceiveFailures = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorReceiveProcessingTime")) { + initiatorReceiveProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorSendFailureProcessingTime")) { + initiatorSendFailureProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorSendFailures")) { + initiatorSendFailures = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("initiatorSendProcessingTime")) { + initiatorSendProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorTimeToConnect")) { + initiatorTimeToConnect = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("initiatorTimeToFail")) { + initiatorTimeToFail = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numPingsReceived")) { + numPingsReceived = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPings")) { + numPings = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedPings")) { + numFailedPings = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("pingTime")) { + pingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("pingFailedTime")) { + pingFailedTime = DocumentSerializableUtilities.getLong(childElement); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMeter.java new file mode 100644 index 000000000..ca544b60e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMeter.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.impl.meter.MetricUtilities; +import net.jxta.peer.PeerID; + +import java.util.Enumeration; +import java.util.Hashtable; + + +/** + * Transport Meter for a specific registered Transport + */ +public class TransportMeter { + public static final EndpointAddress UNKNOWN_ADDRESS = new EndpointAddress("", "", null, null); + public static final String UNKNOWN_PEER = MetricUtilities.UNKNOWN_PEERID.toString(); + private String protocol; + private EndpointAddress endpointAddress; + + private Hashtable transportBindingMeters = new Hashtable(); + private TransportMetric cumulativeMetrics; + + public TransportMeter(String protocol, EndpointAddress endpointAddress) { + this.endpointAddress = endpointAddress; + this.protocol = protocol; + cumulativeMetrics = new TransportMetric(this); + } + + public TransportMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public TransportMetric collectMetrics() { + TransportMetric transportMetric = new TransportMetric(this); + boolean anyData = false; + + for (Enumeration e = transportBindingMeters.elements(); e.hasMoreElements();) { + TransportBindingMeter transportBindingMeter = e.nextElement(); + TransportBindingMetric transportBindingMetric = transportBindingMeter.collectMetrics(); + + if (transportBindingMetric != null) { + transportMetric.addTransportBindingMetric(transportBindingMetric); + anyData = true; + } + } + + if (anyData) { + return transportMetric; + } else { + return null; + } + } + + /** + * Get a specific Binding Meter corresponding to a connection for this transport + * + * @param peerIdString PeerID of destination + * @param destinationAddress Destination Address of connected peer transport + * @return The Binding Meter for tracking this connection + */ + public synchronized TransportBindingMeter getTransportBindingMeter(String peerIdString, EndpointAddress destinationAddress) { + PeerID peerID = MetricUtilities.getPeerIdFromString(peerIdString); + + return getTransportBindingMeter(peerID, destinationAddress); + } + + /** + * Get a specific Binding Meter corresponding to a connection for this transport + * + * @param peerID destination PeerID + * @param destinationAddress Destination Address of connected peer transport + * @return The Binding Meter for tracking this connection + */ + public synchronized TransportBindingMeter getTransportBindingMeter(PeerID peerID, EndpointAddress destinationAddress) { + destinationAddress = new EndpointAddress(destinationAddress, null, null); + + TransportBindingMeter transportBindingMeter = transportBindingMeters.get(destinationAddress); + + if (transportBindingMeter == null) { + transportBindingMeter = new TransportBindingMeter(peerID, destinationAddress); + transportBindingMeters.put(destinationAddress, transportBindingMeter); + cumulativeMetrics.addTransportBindingMetric(transportBindingMeter.getCumulativeMetrics()); + } else { + transportBindingMeter.setPeerID(peerID); + } + + return transportBindingMeter; + } + + public Enumeration getTransportBindingMeters() { + return transportBindingMeters.elements(); + } + + public int getTransportBindingCount() { + return transportBindingMeters.size(); + } + + public String getProtocol() { + return protocol; + } + + public EndpointAddress getEndpointAddress() { + return endpointAddress; + } + + @Override + public String toString() { + return "TransportMeter(" + endpointAddress + ")"; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMeterBuildSettings.java new file mode 100644 index 000000000..1d09ff673 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMeterBuildSettings.java @@ -0,0 +1,67 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.endpoint.transportMeter; + +import net.jxta.impl.meter.*; + +public interface TransportMeterBuildSettings extends MeterBuildSettings { + public static final boolean TRANSPORT_METERING = ConditionalTransportMeterBuildSettings.isRuntimeMetering(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMetric.java new file mode 100644 index 000000000..3e8b02752 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportMetric.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.endpoint.EndpointAddress; + +import net.jxta.util.documentSerializable.DocumentSerializable; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; +import net.jxta.document.Element; +import net.jxta.document.TextElement; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; + + +/** + * The Metric for a single Transport + **/ +public class TransportMetric implements DocumentSerializable { + private String protocol; + private EndpointAddress endpointAddress; + private HashMap transportBindingMetrics = new HashMap(); + + public TransportMetric(TransportMeter transportMeter) { + this.endpointAddress = transportMeter.getEndpointAddress(); + this.protocol = transportMeter.getProtocol(); + } + + public TransportMetric() {} + + public TransportMetric(TransportMetric prototype) { + this.endpointAddress = prototype.endpointAddress; + this.protocol = prototype.protocol; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TransportMetric) { + TransportMetric other = (TransportMetric) obj; + + return protocol.equals(other.protocol) && endpointAddress.equals(other.endpointAddress); + } else { + return false; + } + } + + @Override + public int hashCode() { + return endpointAddress.hashCode(); + } + + public EndpointAddress getEndpointAddress() { + return endpointAddress; + } + + public String getProtocol() { + return protocol; + } + + public synchronized void addTransportBindingMetric(TransportBindingMetric transportBindingMetric) { + transportBindingMetrics.put(transportBindingMetric.getEndpointAddress(), transportBindingMetric); + } + + public TransportBindingMetric getTransportBindingMetric(EndpointAddress endpointAddress) { + return transportBindingMetrics.get(endpointAddress); + } + + public TransportBindingMetric getTransportBindingMetric(TransportBindingMetric prototype) { + return getTransportBindingMetric(prototype.getEndpointAddress()); + } + + public Iterator getTransportBindingMetrics() { + return transportBindingMetrics.values().iterator(); + } + + public int getTransportBindingMetricsCount() { + return transportBindingMetrics.size(); + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addString(element, "endpointAddress", endpointAddress.toString()); + DocumentSerializableUtilities.addString(element, "protocol", protocol); + + for (Iterator i = getTransportBindingMetrics(); i.hasNext();) { + TransportBindingMetric transportBindingMetric = i.next(); + + DocumentSerializableUtilities.addDocumentSerializable(element, "binding", transportBindingMetric); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("endpointAddress")) { + String endpointAddressString = DocumentSerializableUtilities.getString(childElement); + + endpointAddress = new EndpointAddress(endpointAddressString); + } else if (tagName.equals("protocol")) { + protocol = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("binding")) { + TransportBindingMetric transportBindingMetric = (TransportBindingMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, TransportBindingMetric.class); + + transportBindingMetrics.put(transportBindingMetric.getEndpointAddress(), transportBindingMetric); + } + } + } + + void mergeMetrics(TransportMetric otherTransportMetric) { + for (Iterator i = otherTransportMetric.getTransportBindingMetrics(); i.hasNext();) { + TransportBindingMetric otherTransportBindingMetric = i.next(); + TransportBindingMetric transportBindingMetric = getTransportBindingMetric( + otherTransportBindingMetric.getEndpointAddress()); + + if (transportBindingMetric == null) { + transportBindingMetric = new TransportBindingMetric(otherTransportBindingMetric); + addTransportBindingMetric(transportBindingMetric); + } + + transportBindingMetric.mergeMetrics(otherTransportBindingMetric); + } + + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMetric.java new file mode 100644 index 000000000..0cb944182 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMetric.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.document.Element; +import net.jxta.document.TextElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.IDFactory; +import net.jxta.meter.MonitorResources; +import net.jxta.meter.ServiceMetric; +import net.jxta.platform.ModuleClassID; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; + + +/** + * The Service Monitor Metric for the Transport Services + */ +public class TransportServiceMetric implements ServiceMetric { + private LinkedList transportMetrics = new LinkedList(); + private ModuleClassID moduleClassID = MonitorResources.transportServiceMonitorClassID; + + public TransportServiceMetric() {} + + /** + * {@inheritDoc} + */ + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + /** + * {@inheritDoc} + */ + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + /** + * Append a Transport Metric + * @param transportMetric metric to add + */ + public void addTransportMetric(TransportMetric transportMetric) { + transportMetrics.add(transportMetric); + } + + /** + * Get all Transport Metrics + * @return iterator of all transport metrics + */ + public Iterator getTransportMetrics() { + return transportMetrics.iterator(); + } + + /** + * Get the Transport Metric for a specific Transport Type + * @param protocol protocol name + * @param endpointAddress address + * @return a Transport Metric for a specific Transport Type + */ + public TransportMetric getTransportMetric(String protocol, EndpointAddress endpointAddress) { + for (TransportMetric transportMetric : transportMetrics) { + if (protocol.equals(transportMetric.getProtocol()) && endpointAddress.equals(transportMetric.getEndpointAddress())) { + return transportMetric; + } + } + + return null; + } + + /** + * Get the Transport Metric for a specific Transport Type + * + * @param prototype a similar Transport metric object (ie same protocol/endpointAddress) + * @see #getTransportMetric(String, EndpointAddress) + * @return a Transport Metric for a specific Transport Type + */ + public TransportMetric getTransportMetric(TransportMetric prototype) { + return getTransportMetric(prototype.getProtocol(), prototype.getEndpointAddress()); + } + + /** + * {@inheritDoc} + */ + public void serializeTo(Element element) throws DocumentSerializationException { + for (TransportMetric transportMetric : transportMetrics) { + DocumentSerializableUtilities.addDocumentSerializable(element, "transportMetric", transportMetric); + } + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + } + + /** + * {@inheritDoc} + */ + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("transportMetric")) { + TransportMetric transportMetric = (TransportMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, TransportMetric.class); + + transportMetrics.add(transportMetric); + } + if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't read moduleClassID", jex); + } + } + } + } + + /** + * Make a shallow copy of this metric only including the portions designated in the Filter + *

            Note: since this is a shallow copy it is dangerous to modify the submetrics + * + * @param transportServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + */ + public TransportServiceMetric shallowCopy(TransportServiceMonitorFilter transportServiceMonitorFilter) { + TransportServiceMetric serviceMetric = new TransportServiceMetric(); + + serviceMetric.moduleClassID = moduleClassID; + + for (Iterator i = getTransportMetrics(); i.hasNext();) { + TransportMetric transportMetric = i.next(); + String protocol = transportMetric.getProtocol(); + + if (transportServiceMonitorFilter.hasTransport(protocol)) { + serviceMetric.addTransportMetric(transportMetric); + } + } + + return serviceMetric; + } + + /** + * {@inheritDoc} + */ + public void mergeMetrics(ServiceMetric serviceMetric) { + mergeMetrics(serviceMetric, null); + } + + /** + * + * @param serviceMetric + * @param transportServiceMonitorFilter + */ + public void mergeMetrics(ServiceMetric serviceMetric, TransportServiceMonitorFilter transportServiceMonitorFilter) { + TransportServiceMetric otherTransportServiceMetric = (TransportServiceMetric) serviceMetric; + + for (Iterator i = otherTransportServiceMetric.getTransportMetrics(); i.hasNext();) { + TransportMetric otherTransportMetric = i.next(); + String protocol = otherTransportMetric.getProtocol(); + + if ((transportServiceMonitorFilter == null) || transportServiceMonitorFilter.hasTransport(protocol)) { + TransportMetric transportMetric = getTransportMetric(otherTransportMetric.getProtocol() + , + otherTransportMetric.getEndpointAddress()); + + if (transportMetric == null) { + transportMetric = new TransportMetric(otherTransportMetric); + addTransportMetric(transportMetric); + } + + transportMetric.mergeMetrics(otherTransportMetric); + } + } + } + + /** + * Make a deep copy of this metric only including the portions designated in the Filter + * The resulting metric is Safe to modify without danger to the underlying Monitor Metrics + * + * @param transportServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + */ + public TransportServiceMetric deepCopy(TransportServiceMonitorFilter transportServiceMonitorFilter) { + TransportServiceMetric serviceMetric = new TransportServiceMetric(); + + serviceMetric.moduleClassID = moduleClassID; + + serviceMetric.mergeMetrics(this, transportServiceMonitorFilter); + return serviceMetric; + } + + /** + * {@inheritDoc} + */ + public void diffMetrics(ServiceMetric otherOne) { + throw new RuntimeException("Not Supported"); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMonitor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMonitor.java new file mode 100644 index 000000000..4c790c2ad --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMonitor.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.impl.meter.GenericServiceMonitor; +import net.jxta.meter.ServiceMetric; +import net.jxta.meter.ServiceMonitorFilter; + +import java.util.LinkedList; + + +/** + * The Service Monitor Metric for the Transport Services + *

            Each Transport will register with this to create their own TransportMeter + */ +public class TransportServiceMonitor extends GenericServiceMonitor { + private LinkedList transportMeters = new LinkedList(); + private TransportServiceMetric cumulativeTransportServiceMetric; + + public TransportServiceMonitor() {} + + /** + * {@inheritDoc} + */ + @Override + protected void init() { + cumulativeTransportServiceMetric = (TransportServiceMetric) getCumulativeServiceMetric(); + } + + /** + * Create a service TransportMeter for a registerd Transport Type + * + * @param protocol protocol identifier + * @param sourceAddressString source address string + * @return a TransportMeter + * @deprecated use #createTransportMeter(String, EndpointAddress) + */ + @Deprecated + public synchronized TransportMeter createTransportMeter(String protocol, String sourceAddressString) { + EndpointAddress endpointAddress = new EndpointAddress(sourceAddressString); + + return createTransportMeter(protocol, endpointAddress); + } + + /** + * Create a service TransportMeter for a registerd Transport Type + * + * @param protocol Descriptive name of protocol + * @param endpointAddress The common public address for this transport + * @return Transport Meter for this transport + */ + public synchronized TransportMeter createTransportMeter(String protocol, EndpointAddress endpointAddress) { + endpointAddress = new EndpointAddress(endpointAddress, null, null); + + for (TransportMeter transportMeter : transportMeters) { + if (transportMeter.getProtocol().equals(protocol) && transportMeter.getEndpointAddress().equals(endpointAddress)) { + return transportMeter; + } + } + + TransportMeter transportMeter = new TransportMeter(protocol, endpointAddress); + + transportMeters.add(transportMeter); + cumulativeTransportServiceMetric.addTransportMetric(transportMeter.getCumulativeMetrics()); + return transportMeter; + } + + /** + * {@inheritDoc} + */ + @Override + protected ServiceMetric collectServiceMetrics() { + TransportServiceMetric transportServiceMetric = (TransportServiceMetric) createServiceMetric(); + + boolean anyData = false; + + for (TransportMeter transportMeter : transportMeters) { + TransportMetric transportMetric = transportMeter.collectMetrics(); + + if (transportMetric != null) { + transportServiceMetric.addTransportMetric(transportMetric); + anyData = true; + } + } + + if (anyData) { + return transportServiceMetric; + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public ServiceMetric getServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime, int pulseIndex, long reportRate) { + int deltaReportRateIndex = monitorManager.getReportRateIndex(reportRate); + TransportServiceMetric origServiceMetric = (TransportServiceMetric) deltaServiceMetrics[deltaReportRateIndex]; + + if (origServiceMetric == null) { + return null; + } + + TransportServiceMonitorFilter transportServiceMonitorFilter = (TransportServiceMonitorFilter) serviceMonitorFilter; + + return origServiceMetric.shallowCopy(transportServiceMonitorFilter); + } + + /** + * {@inheritDoc} + */ + @Override + public ServiceMetric getCumulativeServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime) { + TransportServiceMetric origServiceMetric = (TransportServiceMetric) cumulativeServiceMetric; + + TransportServiceMonitorFilter transportServiceMonitorFilter = (TransportServiceMonitorFilter) serviceMonitorFilter; + + return origServiceMetric.deepCopy(transportServiceMonitorFilter); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMonitorFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMonitorFilter.java new file mode 100644 index 000000000..ed5f0f4f5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/transportMeter/TransportServiceMonitorFilter.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.endpoint.transportMeter; + + +import net.jxta.document.Element; +import net.jxta.document.TextElement; +import net.jxta.id.IDFactory; +import net.jxta.meter.MonitorResources; +import net.jxta.meter.ServiceMonitorFilter; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.LinkedList; + + +public class TransportServiceMonitorFilter implements ServiceMonitorFilter { + private ModuleClassID moduleClassID = MonitorResources.transportServiceMonitorClassID; + private LinkedList includedTransports = new LinkedList(); + private boolean includeAllTransports = true; + + public TransportServiceMonitorFilter() {} + + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + public void removeAllTransports() { + includedTransports.clear(); + includeAllTransports = false; + } + + public void includeAllTransports(boolean includeAllTransports) { + this.includeAllTransports = includeAllTransports; + } + + public void includeTransport(String protocol) { + includedTransports.add(protocol); + } + + public boolean hasTransport(String protocol) { + if (includeAllTransports) { + return true; + } + + for (String includedTransport : includedTransports) { + if (includedTransport.equals(protocol)) { + return true; + } + } + return false; + } + + public void includeTransport(ModuleSpecID transportModuleClassID, String subProtocol) {// todo: how is this used??? + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + + DocumentSerializableUtilities.addBoolean(element, "includeAllTransports", includeAllTransports); + + for (String includedTransport : includedTransports) { + DocumentSerializableUtilities.addString(element, "includedTransport", includedTransport); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't read moduleClassID", jex); + } + } + if (tagName.equals("includedTransport")) { + String includedTransport = DocumentSerializableUtilities.getString(childElement); + + includedTransports.add(includedTransport); + } + if (tagName.equals("includeAllTransports")) { + includeAllTransports = DocumentSerializableUtilities.getBoolean(childElement); + } + } + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/CodatID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/CodatID.java new file mode 100644 index 000000000..d1d0ceb54 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/CodatID.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.util.logging.Logger; + + +/** + * An implementation of the {@link net.jxta.codat.CodatID} ID Type. + */ +public class CodatID extends net.jxta.impl.id.UUID.CodatID { + + /** + * Log4J Logger + */ + private static final transient Logger LOG = Logger.getLogger(CodatID.class.getName()); + + /** + * Internal constructor + */ + protected CodatID() { + super(); + } + + /** + * Intializes contents from provided bytes. + * + * @param id the ID data + */ + protected CodatID(IDBytes id) { + super(id); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID)}. + * + * @param groupID the GroupID + */ + public CodatID(PeerGroupID groupID) { + super(groupID.getUUID(), UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID,byte[])}. + * + * @param groupID the GroupID + * @param seed the seed + */ + public CodatID(PeerGroupID groupID, byte[] seed) { + this(); + + UUID groupCBID = groupID.getUUID(); + + id.longIntoBytes(CodatID.groupIdOffset, groupCBID.getMostSignificantBits()); + id.longIntoBytes(CodatID.groupIdOffset + 8, groupCBID.getLeastSignificantBits()); + + MessageDigest digester = null; + + try { + digester = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException caught) { + digester = null; + } + + if (digester == null) { + throw new ProviderException("SHA1 digest algorithm not found"); + } + + byte[] digest = digester.digest(seed); + + // we keep only the 128 most significant bits + byte[] buf16 = new byte[16]; + + System.arraycopy(digest, 0, buf16, 0, 16); + + UUID peerCBID = UUIDFactory.newUUID(buf16); + + id.longIntoBytes(CodatID.idOffset, peerCBID.getMostSignificantBits()); + id.longIntoBytes(CodatID.idOffset + 8, peerCBID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID,InputStream)}. + * + * @param groupID the GroupID + * @param in the input stream + * @throws IOException if an io error occurs + */ + public CodatID(PeerGroupID groupID, InputStream in) throws IOException { + super(groupID, in); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID,InputStream)}. + * + * @param groupID the GroupID + * @param seed the seed + * @param in the input stream + * @throws IOException if an io error occurs + */ + public CodatID(PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + this(groupID, seed); + + setHash(in); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + UUID groupCBID = new UUID(id.bytesIntoLong(CodatID.groupIdOffset), id.bytesIntoLong(CodatID.groupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupCBID); + + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(groupID); + } + + /** + * Returns the UUID associated with this CodatID. + * + * @return The UUID associated with this CodatID. + */ + public UUID getUUID() { + return new UUID(id.bytesIntoLong(CodatID.idOffset), id.bytesIntoLong(CodatID.idOffset + 8)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/IDFormat.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/IDFormat.java new file mode 100644 index 000000000..a87ef04d7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/IDFormat.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.id.CBID; + + +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.id.UUID.UUID; + +import java.util.logging.Logger; + + +/** + * A general purpose JXTA ID Format implementing all of the six standard ID + * Types. It was originally created for the Java 2 SE reference implementation. + * The 'cbid' format uses values generated from secure hash functions as the + * mechanism for generating canonical values for the ids it provides. + * + * @see net.jxta.id.ID + * @see JXTA Protocols Specification : IDs + */ +public class IDFormat extends net.jxta.impl.id.UUID.IDFormat { + + /** + * Log4J Logger + */ + private static final transient Logger LOG = Logger.getLogger(IDFormat.class.getName()); + + /** + * Our local version of the world Peer Group ID. We need this for cases + * where we have to make ids which are in the world peer group. We only + * use this ID for those cases and never return this ID. + */ + static final PeerGroupID worldPeerGroupID = new PeerGroupID(new UUID(0x5961626164616261L, 0x4A78746150325033L)); // YabadabaJXTAP2P! + + /** + * Our local version of the net Peer Group ID. We need this for cases + * where we have to make ids which are in the net peer group. We only + * use this ID for those cases and never return this ID. + */ + static final PeerGroupID defaultNetPeerGroupID = new PeerGroupID(new UUID(0x5961626164616261L, 0x4E50472050325033L)); // YabadabaNPG P2P! + + /** + * This table maps our local private versions of the well known ids to the + * globally known version. + */ + private final static Object[][] wellKnownIDs = { + { net.jxta.peergroup.PeerGroupID.worldPeerGroupID, worldPeerGroupID} + , + { net.jxta.peergroup.PeerGroupID.defaultNetPeerGroupID, defaultNetPeerGroupID} + }; + + /** + * The instantiator for this ID Format which is used by the IDFactory. + */ + public static final IDFactory.URIInstantiator INSTANTIATOR = new Instantiator(); + + /** + * This class cannot be instantiated. + */ + protected IDFormat() {} + + /** + * Translate from well known ID to our locally encoded versions. + * + * @param input the id to be translated. + * @return the translated ID or the input ID if no translation was needed. + */ + static ID translateFromWellKnown(ID input) { + for (Object[] wellKnownID : wellKnownIDs) { + ID aWellKnown = (ID) wellKnownID[0]; + + if (aWellKnown.equals(input)) { + return (ID) wellKnownID[1]; + } + } + + return input; + } + + /** + * Translate from locally encoded versions to the well known versions. + * + * @param input the id to be translated. + * @return the translated ID or the input ID if no translation was needed. + */ + static ID translateToWellKnown(ID input) { + for (Object[] wellKnownID : wellKnownIDs) { + ID aLocalEncoding = (ID) wellKnownID[1]; + + if (aLocalEncoding.equals(input)) { + return (ID) wellKnownID[0]; + } + } + + return input; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/Instantiator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/Instantiator.java new file mode 100644 index 000000000..a1603cc94 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/Instantiator.java @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.UnknownServiceException; + + +/** + * The instantiator for the CBID ID Format. + *

            + *

            For "seed" variant constructors, the "seed" must be a certificate. + */ +public class Instantiator implements net.jxta.id.IDFactory.URIInstantiator { + + /** + * Our ID Format + */ + final static String CBIDEncoded = "cbid"; + + /** + * {@inheritDoc} + */ + public String getSupportedIDFormat() { + return CBIDEncoded; + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURL(URL source) throws MalformedURLException, UnknownServiceException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getProtocol())) { + throw new UnknownServiceException("URI protocol type was not as expected."); + } + + String encoded = source.getFile(); + + int colonAt = encoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new UnknownServiceException("URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(encoded.substring(0, colonAt))) { + throw new UnknownServiceException("URN namespace was not as expected."); + } + + // skip the namespace portion and the colon + encoded = encoded.substring(colonAt + 1); + + int dashAt = encoded.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new UnknownServiceException("URN Encodingtype was missing."); + } + + if (!encoded.substring(0, dashAt).equals(getSupportedIDFormat())) { + throw new UnknownServiceException("JXTA ID Format was not as expected."); + } + + // skip the dash + encoded = encoded.substring(dashAt + 1); + + // check that the length is even + if (0 != (encoded.length() % 2)) { + throw new MalformedURLException("URN contains an odd number of chars"); + } + + // check that the length is long enough + if (encoded.length() < 2) { + throw new MalformedURLException("URN does not contain enough chars"); + } + + // check that id is short enough + if (IDFormat.IdByteArraySize < (encoded.length() % 2)) { + throw new MalformedURLException("URN contains too many chars"); + } + + net.jxta.id.ID result = null; + IDBytes id = new IDBytes(); + + try { + // do the primary portion. + for (int eachByte = 0; eachByte < ((encoded.length() / 2) - IDFormat.flagsSize); eachByte++) { + int index = eachByte * 2; + String twoChars = encoded.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + + // do the flags + for (int eachByte = IDFormat.flagsOffset; eachByte < IDFormat.IdByteArraySize; eachByte++) { + int index = encoded.length() - (IDFormat.IdByteArraySize - eachByte) * 2; + String twoChars = encoded.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + } catch (NumberFormatException caught) { + throw new MalformedURLException("Invalid Character in JXTA URI"); + } + + switch (id.bytes[IDFormat.flagsOffset + IDFormat.flagsIdTypeOffset]) { + case IDFormat.flagCodatID: + result = new CodatID(id); + break; + + case IDFormat.flagPeerGroupID: + result = new PeerGroupID(id); + result = (PeerGroupID) IDFormat.translateToWellKnown(result); + break; + + case IDFormat.flagPeerID: + result = new PeerID(id); + break; + + case IDFormat.flagPipeID: + result = new PipeID(id); + break; + + case IDFormat.flagModuleClassID: + result = new ModuleClassID(id); + break; + + case IDFormat.flagModuleSpecID: + result = new ModuleSpecID(id); + break; + + default: + throw new MalformedURLException("JXTA ID Type not recognized"); + } + + return result; + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, InputStream in) throws IOException { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID, in); + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID, seed, in); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID() { + return new PeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(byte[] seed) { + return new PeerGroupID(seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent) { + return new PeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent, byte[] seed) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(parent); + + return new PeerGroupID(parentGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peer.PeerID newPeerID(net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + throw new UnsupportedOperationException("Must provide a cert as seed to generate a peer id."); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peer.PeerID newPeerID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PeerID(peerGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.pipe.PipeID newPipeID(net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PipeID(peerGroupID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.pipe.PipeID newPipeID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PipeID(peerGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.platform.ModuleClassID newModuleClassID() { + return new ModuleClassID(); + } + + /** + * {@inheritDoc} + */ + public net.jxta.platform.ModuleClassID newModuleClassID(net.jxta.platform.ModuleClassID classID) { + return new ModuleClassID((ModuleClassID) classID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.platform.ModuleSpecID newModuleSpecID(net.jxta.platform.ModuleClassID classID) { + return new ModuleSpecID((ModuleClassID) classID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURI(URI source) throws URISyntaxException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getScheme())) { + throw new URISyntaxException(source.toString(), "URI scheme was not as expected."); + } + + String decoded = source.getSchemeSpecificPart(); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new URISyntaxException(source.toString(), "URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new URISyntaxException(source.toString() + , + "URN namespace was not as expected. (" + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + return fromURNNamespaceSpecificPart(decoded); + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURNNamespaceSpecificPart(String source) throws URISyntaxException { + int dashAt = source.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new URISyntaxException(source, "URN Encodingtype was missing."); + } + + if (!source.substring(0, dashAt).equals(getSupportedIDFormat())) { + throw new URISyntaxException(source, "JXTA ID Format was not as expected."); + } + + // skip the dash + source = source.substring(dashAt + 1); + + // check that the length is even + if (0 != (source.length() % 2)) { + throw new URISyntaxException(source, "URN contains an odd number of chars"); + } + + // check that the length is long enough + if (source.length() < 2) { + throw new URISyntaxException(source, "URN does not contain enough chars"); + } + + // check that id is short enough + if (IDFormat.IdByteArraySize < (source.length() % 2)) { + throw new URISyntaxException(source, "URN contains too many chars"); + } + + net.jxta.id.ID result = null; + IDBytes id = new IDBytes(); + + try { + // do the primary portion. + for (int eachByte = 0; eachByte < ((source.length() / 2) - IDFormat.flagsSize); eachByte++) { + int index = eachByte * 2; + String twoChars = source.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + + // do the flags + for (int eachByte = IDFormat.flagsOffset; eachByte < IDFormat.IdByteArraySize; eachByte++) { + int index = source.length() - (IDFormat.IdByteArraySize - eachByte) * 2; + String twoChars = source.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + } catch (NumberFormatException caught) { + throw new URISyntaxException(source, "Invalid Character in JXTA URI"); + } + + switch (id.bytes[IDFormat.flagsOffset + IDFormat.flagsIdTypeOffset]) { + case IDFormat.flagCodatID: + result = new CodatID(id); + break; + + case IDFormat.flagPeerGroupID: + result = new PeerGroupID(id); + result = (PeerGroupID) IDFormat.translateToWellKnown(result); + break; + + case IDFormat.flagPeerID: + result = new PeerID(id); + break; + + case IDFormat.flagPipeID: + result = new PipeID(id); + break; + + case IDFormat.flagModuleClassID: + result = new ModuleClassID(id); + break; + + case IDFormat.flagModuleSpecID: + result = new ModuleSpecID(id); + break; + + default: + throw new URISyntaxException(source, "JXTA ID Type not recognized"); + } + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/ModuleClassID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/ModuleClassID.java new file mode 100644 index 000000000..bd11b932e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/ModuleClassID.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +import java.util.logging.Logger; + + +/** + * An implementation of the {@link net.jxta.platform.ModuleClassID} ID Type. + */ +public final class ModuleClassID extends net.jxta.impl.id.UUID.ModuleClassID { + + /** + * Log4J categorgy + */ + private static final transient Logger LOG = Logger.getLogger(ModuleClassID.class.getName()); + + /** + * Constructor. + * Intializes contents from provided ID. + * + * @param id the ID data + */ + protected ModuleClassID(IDBytes id) { + super(id); + } + + /** + * Constructor. + * Creates a ModuleClassID in a given class, with a given class unique id. + * A UUID of a class and another UUID are provided. + * + * @param classUUID the class to which this will belong. + * @param roleUUID the unique id of this role in that class. + */ + protected ModuleClassID(UUID classUUID, UUID roleUUID) { + super(classUUID, roleUUID); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newModuleClassID()}. + *

            + * A new class UUID is created. The role ID is left null. This is the + * only way to create a new class without supplying a new UUID explicitly. + *

            + * Note that a null role is just as valid as any other, it just has a + * shorter string representation. So it is not mandatory to create a new + * role in a new class. + */ + public ModuleClassID() { + this(UUIDFactory.newUUID(), new UUID(0L, 0L)); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newModuleClassID(net.jxta.platform.ModuleClassID)}. + * @param classID the ModuleClassID + */ + public ModuleClassID(ModuleClassID classID) { + this(classID.getClassUUID(), UUIDFactory.newUUID()); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.platform.ModuleClassID getBaseClass() { + return new ModuleClassID(getClassUUID(), new UUID(0L, 0L)); + } + + /** + * get the class' unique id + * + * @return UUID module class' unique id + */ + @Override + protected UUID getClassUUID() { + return super.getClassUUID(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/ModuleSpecID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/ModuleSpecID.java new file mode 100644 index 000000000..480d2dc35 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/ModuleSpecID.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +import java.util.logging.Logger; + + +/** + * An implementation of the {@link net.jxta.platform.ModuleSpecID} ID Type. + */ +public final class ModuleSpecID extends net.jxta.impl.id.UUID.ModuleSpecID { + + /** + * Log4J categorgy + */ + private static final transient Logger LOG = Logger.getLogger(ModuleSpecID.class.getName()); + + /** + * Constructor. Used only internally. + */ + protected ModuleSpecID() { + super(); + } + + /** + * Intializes contents from provided ID. + * + * @param id the ID data + */ + protected ModuleSpecID(IDBytes id) { + super(id); + } + + /** + * Creates a ModuleSpecID in a given class, with a given class unique id. + * A UUID of a class and another UUID are provided. + * + * @param classUUID the class to which this will belong. + * @param specUUID the unique id of this spec in that class. + * @since JXTA 1.0 + */ + protected ModuleSpecID(UUID classUUID, UUID specUUID) { + super(classUUID, classUUID); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newModuleSpecID(net.jxta.platform.ModuleClassID)}. + * @param classID the ModuleClassID + */ + public ModuleSpecID(ModuleClassID classID) { + this(classID.getClassUUID(), UUIDFactory.newUUID()); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.platform.ModuleClassID getBaseClass() { + return new ModuleClassID(getClassUUID(), new UUID(0L, 0L)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PeerGroupID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PeerGroupID.java new file mode 100644 index 000000000..d655ee7e6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PeerGroupID.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.util.logging.Logger; + + +/** + * An implementation of the {@link net.jxta.peergroup.PeerGroupID} ID Type. + */ +public class PeerGroupID extends net.jxta.impl.id.UUID.PeerGroupID { + + /** + * Log4J categorgy + */ + private static final transient Logger LOG = Logger.getLogger(PeerGroupID.class.getName()); + + /** + * Intializes contents from provided ID. + * + * @param id the ID data + */ + protected PeerGroupID(IDBytes id) { + super(id); + } + + /** + * Creates a PeerGroupID. A PeerGroupID is provided + * + * @param groupUUID the PeerGroupID to use to construct the new PeerGroupID + */ + protected PeerGroupID(UUID groupUUID) { + super(groupUUID); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID()}. + */ + public PeerGroupID() { + this(UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID(byte[])}. + * @param seed the seed + */ + public PeerGroupID(byte[] seed) { + super(); + + MessageDigest digester = null; + + try { + digester = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException caught) { + digester = null; + } + + if (digester == null) { + throw new ProviderException("SHA1 digest algorithm not found"); + } + + byte[] digest = digester.digest(seed); + + // we keep only the 128 most significant bits + byte[] buf16 = new byte[16]; + + System.arraycopy(digest, 0, buf16, 0, 16); + + UUID groupUUID = UUIDFactory.newUUID(buf16); + + id.longIntoBytes(PeerGroupID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PeerGroupID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID(net.jxta.peergroup.PeerGroupID,byte[])}. + * + * @param parent Parent PeerGroupID + * @param seed the seed + */ + public PeerGroupID(PeerGroupID parent, byte[] seed) { + this(seed); + + UUID parentUUID = parent.getUUID(); + + id.longIntoBytes(PeerGroupID.parentgroupIdOffset, parentUUID.getMostSignificantBits()); + id.longIntoBytes(PeerGroupID.parentgroupIdOffset + 8, parentUUID.getLeastSignificantBits()); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.peergroup.PeerGroupID getParentPeerGroupID() { + + UUID parentUUID = new UUID(id.bytesIntoLong(PeerGroupID.parentgroupIdOffset) + , + id.bytesIntoLong(PeerGroupID.parentgroupIdOffset + 8)); + + // if zero, then there is no parent. + if ((0 == parentUUID.getMostSignificantBits()) && (0 == parentUUID.getLeastSignificantBits())) { + return null; + } + + PeerGroupID groupID = new PeerGroupID(parentUUID); + + // convert to the generic world PGID as necessary + return (net.jxta.peergroup.PeerGroupID) IDFormat.translateToWellKnown(groupID); + } + + /** + * Returns the UUID associated with this PeerGroupID. + * + * @return The UUID associated with this PeerGroupID. + */ + @Override + public UUID getUUID() { + return super.getUUID(); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PeerID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PeerID.java new file mode 100644 index 000000000..5fdeda5be --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PeerID.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.util.logging.Logger; + + +/** + * An implementation of the {@link net.jxta.peer.PeerID} ID Type. + */ +public class PeerID extends net.jxta.impl.id.UUID.PeerID { + + /** + * Log4J Logger + */ + private static final transient Logger LOG = Logger.getLogger(PeerID.class.getName()); + + /** + * Used only internally. + */ + protected PeerID() { + super(); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerID(net.jxta.peergroup.PeerGroupID)}. + * + * @param groupID the PeerGroupID + */ + public PeerID(PeerGroupID groupID) { + this(groupID.getUUID(), UUIDFactory.newUUID()); + } + + /** + * Intializes contents from provided ID. + * + * @param id the ID data + */ + protected PeerID(IDBytes id) { + super(id); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerID(net.jxta.peergroup.PeerGroupID,byte[])}. + * + * @param groupID the PeerGroupID + * @param seed the seed + */ + public PeerID(PeerGroupID groupID, byte[] seed) { + this(); + + UUID groupUUID = groupID.getUUID(); + + id.longIntoBytes(PeerID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PeerID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + MessageDigest digester = null; + + try { + digester = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException caught) { + digester = null; + } + + if (digester == null) { + throw new ProviderException("SHA1 digest algorithm not found"); + } + + byte[] digest = digester.digest(seed); + + // we keep only the 128 most significant bits + byte[] buf16 = new byte[16]; + + System.arraycopy(digest, 0, buf16, 0, 16); + + UUID peerCBID = new UUID(buf16); + + id.longIntoBytes(PeerID.idOffset, peerCBID.getMostSignificantBits()); + id.longIntoBytes(PeerID.idOffset + 8, peerCBID.getLeastSignificantBits()); + } + + /** + * Creates a PeerID. A PeerGroupID is provided + * + * @param groupUUID the group to which this will belong. + * @param peerUUID id of this peer + */ + protected PeerID(UUID groupUUID, UUID peerUUID) { + super(groupUUID, peerUUID); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + UUID groupCBID = new UUID(id.bytesIntoLong(PeerID.groupIdOffset), id.bytesIntoLong(PeerID.groupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupCBID); + + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(groupID); + } + + /** + * Returns the UUID associated with this PeerID. + * + * @return The UUID associated with this PeerID. + */ + public UUID getUUID() { + return new UUID(id.bytesIntoLong(PeerID.idOffset), id.bytesIntoLong(PeerID.idOffset + 8)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PipeID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PipeID.java new file mode 100644 index 000000000..c61fca925 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/PipeID.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.id.CBID; + + +import net.jxta.impl.id.UUID.IDBytes; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.util.logging.Logger; + + +/** + * An implementation of the {@link net.jxta.pipe.PipeID} ID Type. + */ +public class PipeID extends net.jxta.impl.id.UUID.PipeID { + + /** + * Log4J categorgy + */ + private static final transient Logger LOG = Logger.getLogger(PipeID.class.getName()); + + /** + * Used only internally + */ + protected PipeID() { + super(); + } + + /** + * Constructor. + * Intializes contents from provided ID. + * + * @param id the ID data + */ + protected PipeID(IDBytes id) { + super(id); + } + + /** + * Creates a PipeID. A PeerGroupID is provided + * + * @param groupUUID the UUID of the group to which this will belong. + * @param idUUID the UUID which will be used for this pipe. + */ + protected PipeID(UUID groupUUID, UUID idUUID) { + super(groupUUID, idUUID); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPipeID(net.jxta.peergroup.PeerGroupID)}. + * @param groupID the PeerGroupID + */ + public PipeID(PeerGroupID groupID) { + this(groupID.getUUID(), UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPipeID(net.jxta.peergroup.PeerGroupID,byte[])}. + * @param groupID the PeerGroupID + * @param seed the seed + */ + public PipeID(PeerGroupID groupID, byte[] seed) { + this(); + + UUID groupCBID = groupID.getUUID(); + + id.longIntoBytes(PipeID.groupIdOffset, groupCBID.getMostSignificantBits()); + id.longIntoBytes(PipeID.groupIdOffset + 8, groupCBID.getLeastSignificantBits()); + + MessageDigest digester = null; + + try { + digester = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException caught) { + digester = null; + } + + if (digester == null) { + throw new ProviderException("SHA1 digest algorithm not found"); + } + + byte[] digest = digester.digest(seed); + + // we keep only the 128 most significant bits + byte[] buf16 = new byte[16]; + + System.arraycopy(digest, 0, buf16, 0, 16); + + UUID pipeCBID = UUIDFactory.newUUID(buf16); + + id.longIntoBytes(PipeID.idOffset, pipeCBID.getMostSignificantBits()); + id.longIntoBytes(PipeID.idOffset + 8, pipeCBID.getLeastSignificantBits()); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + UUID groupCBID = new UUID(id.bytesIntoLong(PipeID.groupIdOffset), id.bytesIntoLong(PipeID.groupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupCBID); + + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(groupID); + } + + /** + * Returns the UUID associated with this PipeID. + * + * @return The UUID associated with this PipeID. + */ + public UUID getUUID() { + return new UUID(id.bytesIntoLong(PipeID.idOffset), id.bytesIntoLong(PipeID.idOffset + 8)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/package.html new file mode 100644 index 000000000..ca7cc2c25 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/CBID/package.html @@ -0,0 +1,17 @@ + + + + + + + The 'cbid' format is a general purpose JXTA ID Format. It implements all of + the six standard ID types. It was originally created for the Jave 2 SE + reference implementation. The 'cbid' format uses values generated from + secure hash functions as the mechanism for generating canonical values for + the ids it provides. + + @see JXTA Protocols Specification +: IDs + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/CodatID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/CodatID.java new file mode 100644 index 000000000..c51c8bf94 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/CodatID.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.io.InputStream; +import java.security.MessageDigest; + +import java.io.IOException; +import java.security.ProviderException; +import java.security.NoSuchAlgorithmException; + + +/** + * An implementation of the {@link net.jxta.codat.CodatID} ID Type. + */ +public class CodatID extends net.jxta.codat.CodatID { + + /** + * size of a SHA1 hash. I would use MessageDigest.getDigestLength, but + * possible exceptions make it difficult to do. + */ + protected final static int hashSize = 20; + + /** + * Location of the group id in the byte array. + */ + protected final static int groupIdOffset = 0; + + /** + * Location of the randomly chosen portion of the id within the byte array. + */ + protected final static int idOffset = CodatID.groupIdOffset + IDFormat.uuidSize; + + /** + * Location of the hash value portion of the id within the byte array. + */ + protected final static int codatHashOffset = CodatID.idOffset + IDFormat.uuidSize; + + /** + * Location of the beginning of pad (unused space) within the byte array. + */ + protected final static int padOffset = CodatID.codatHashOffset + CodatID.hashSize; + + /** + * Size of the pad. + */ + protected final static int padSize = IDFormat.flagsOffset - CodatID.padOffset; + + /** + * The id data + */ + protected IDBytes id; + + /** + * Internal constructor + */ + protected CodatID() { + super(); + id = new IDBytes(IDFormat.flagCodatID); + } + + /** + * Initializes contents from provided bytes. + * + * @param id the ID data + */ + protected CodatID(IDBytes id) { + super(); + this.id = id; + } + + protected CodatID(UUID groupUUID, UUID idUUID) { + this(); + + id.longIntoBytes(CodatID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(CodatID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + id.longIntoBytes(CodatID.idOffset, idUUID.getMostSignificantBits()); + id.longIntoBytes(CodatID.idOffset + 8, idUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID)}. + */ + public CodatID(PeerGroupID groupID) { + this(groupID.getUUID(), UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID,byte[])}. + */ + public CodatID(PeerGroupID groupID, byte[] seed) { + this(); + + UUID groupUUID = groupID.getUUID(); + + id.longIntoBytes(CodatID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(CodatID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + System.arraycopy(seed, 0, id.bytes, CodatID.idOffset, Math.min(IDFormat.uuidSize, seed.length)); + + // make it a valid UUID + id.bytes[CodatID.idOffset + 6] &= 0x0f; + id.bytes[CodatID.idOffset + 6] |= 0x40; /* version 4 */ + id.bytes[CodatID.idOffset + 8] &= 0x3f; + id.bytes[CodatID.idOffset + 8] |= 0x80; /* IETF variant */ + id.bytes[CodatID.idOffset + 10] &= 0x3f; + id.bytes[CodatID.idOffset + 10] |= 0x80; /* multicast bit */ + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID,InputStream)}. + */ + public CodatID(PeerGroupID groupID, InputStream in) throws IOException { + this(groupID); + + setHash(in); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newCodatID(net.jxta.peergroup.PeerGroupID,InputStream)}. + */ + public CodatID(PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + this(groupID, seed); + + setHash(in); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof CodatID) { + CodatID codatTarget = (CodatID) target; + + return id.equals(codatTarget.id); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + (String) id.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + UUID groupUUID = new UUID(id.bytesIntoLong(CodatID.groupIdOffset), id.bytesIntoLong(CodatID.groupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupUUID); + + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(groupID); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isStatic() { + for (int eachHashByte = CodatID.codatHashOffset; eachHashByte < (CodatID.padOffset); eachHashByte++) { + if (0 != id.bytes[eachHashByte]) { + return true; + } + } + + return false; + } + + /** + * Calculates the SHA-1 hash of a stream. + * + * @param in The InputStream. + */ + protected void setHash(InputStream in) throws IOException { + MessageDigest dig = null; + + try { + dig = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException caught) { + dig = null; + } + + if (dig == null) { + throw new ProviderException("SHA-1 digest algorithm not found"); + } + + dig.reset(); + + byte[] chunk = new byte[1024]; + + try { + do { + int read = in.read(chunk); + + if (read == -1) { + break; + } + + dig.update(chunk, 0, read); + } while (true); + } finally { + in.close(); + } + + byte[] result = dig.digest(); + + System.arraycopy(result, 0, id.bytes, CodatID.codatHashOffset, CodatID.hashSize); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/IDBytes.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/IDBytes.java new file mode 100644 index 000000000..0a9a647cc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/IDBytes.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.io.Serializable; +import java.util.Arrays; +import java.util.zip.Checksum; +import java.util.zip.CRC32; + + +/** + * Maintains the internal representation of a 'uuid' JXTA ID. + * + * @see net.jxta.id.IDFactory + * @see net.jxta.impl.id.UUID.IDFormat + * @see JXTA Protocols Specification : UUID ID Format + */ +public final class IDBytes implements Serializable { + + /** + * The bytes. + */ + public final byte[] bytes; + + /** + * The cached hash value for this object + */ + protected transient int cachedHash = 0; + + /** + * Constructs a new byte representation. This constructor initializes only + * the flag fields of the ID. + * + */ + public IDBytes() { + this.bytes = new byte[ IDFormat.IdByteArraySize ]; + } + + /** + * Constructs a new byte representation. This constructor initializes only + * the flag fields of the ID. + */ + public IDBytes(byte type) { + this(); + this.bytes[IDFormat.flagsOffset + IDFormat.flagsIdTypeOffset] = type; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof IDBytes) { + IDBytes asIDBytes = (IDBytes) target; + + return Arrays.equals(bytes, asIDBytes.bytes); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = cachedHash; + + if (0 == result) { + // There is a very small chance that this + Checksum crc = new CRC32(); + + crc.update(bytes, 0, bytes.length); + + cachedHash = (int) crc.getValue(); + cachedHash = (0 == cachedHash) ? 1 : cachedHash; + + result = cachedHash; + } + + return result; + } + + /** + * Returns a string representation of the ID bytes. The bytes are encoded + * in hex ASCII format with two characters per byte. The pad bytes between + * the primary id portion and the flags field are omitted. + * + * @return String containing the unique value of this ID. + */ + @Override + public String toString() { + return getUniqueValue().toString(); + } + + /** + * Private replacement for toHexString since we need the leading 0 digits. + * Returns a char array containing byte value encoded as 2 hex chars. + * + * @param theByte a byte containing the value to be encoded. + * @return char[] containing byte value encoded as 2 hex characters. + */ + private static char[] toHexDigits(byte theByte) { + final char[] HEXDIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + char result[] = new char[2]; + + result[0] = HEXDIGITS[(theByte >>> 4) & 15]; + result[1] = HEXDIGITS[theByte & 15]; + + return result; + } + + /** + * Return an object containing the unique value of the ID. This object must + * provide implementations of toString() and hashCode() that are canonical + * and consistent from run-to-run given the same input values. Beyond + * this nothing should be assumed about the nature of this object. For some + * implementations the object returned may be the same as provided. + * + * @return Object which can provide canonical representations of the ID. + */ + public Object getUniqueValue() { + StringBuilder encoded = new StringBuilder(144); + int lastIndex; + + // find the last non-zero index. + for (lastIndex = IDFormat.flagsOffset - 1; lastIndex > 0; lastIndex--) { + if (0 != bytes[lastIndex]) { + break; + } + } + + // build the string. + for (int eachByte = 0; eachByte <= lastIndex; eachByte++) { + char[] asHex = toHexDigits(bytes[eachByte]); + + encoded.append(asHex); + } + + // append the flags field + for (int eachFlagByte = IDFormat.flagsOffset; eachFlagByte < IDFormat.IdByteArraySize; eachFlagByte++) { + char asHex[] = toHexDigits(bytes[eachFlagByte]); + + encoded.append(asHex); + } + + return encoded.toString(); + } + + /** + * Insert a long value into the byte array. The long is stored in + * big-endian order into the byte array beginning at the specified index. + * + * @param offset location within the byte array to insert. + * @param value value to be inserted. + */ + public void longIntoBytes(int offset, long value) { + if ((offset < 0) || ((offset + 8) > IDFormat.IdByteArraySize)) { + throw new IndexOutOfBoundsException("Bad offset"); + } + + for (int eachByte = 0; eachByte < 8; eachByte++) { + bytes[eachByte + offset] = (byte) (value >> ((7 - eachByte) * 8L)); + } + + cachedHash = 0; + } + + /** + * Return the long value of a portion of the byte array. The long is + * retrieved in big-endian order from the byte array at the specified + * offset. + * + * @param offset location within the byte array to extract. + * @return long value extracted from the byte array. + */ + public long bytesIntoLong(int offset) { + if ((offset < 0) || ((offset + 8) > IDFormat.IdByteArraySize)) { + throw new IndexOutOfBoundsException("Bad offset"); + } + + long result = 0L; + + for (int eachByte = 0; eachByte < 8; eachByte++) { + result |= ((long) (bytes[eachByte + offset] & 0xff)) << ((7 - eachByte) * 8L); + } + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/IDFormat.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/IDFormat.java new file mode 100644 index 000000000..ad3b42191 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/IDFormat.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.id.ID; +import net.jxta.id.IDFactory; + + +/** + * A general purpose JXTA ID Format implementing all of the six standard ID + * Types. It was originally created for the Java 2 SE reference implementation. + * The 'uuid' format uses (IETF version 4) randomly generated UUIDs as the + * mechanism for generating canonical values for the ids it provides. + * + *

            For IDs constructed using "seed" variant constructors, the first 16 + * bytes of the seed are used literally as the UUID value. The value is masked + * to make it a valid version 4 IETF variant UUID. + * + * @see net.jxta.id.ID + * @see JXTA Protocols Specification : IDs + * @see JXTA Protocols Specification : UUID ID Format + */ +public class IDFormat { + + /** + * Log4J Logger + */ + private static final transient Logger LOG = Logger.getLogger(IDFormat.class.getName()); + + /** + * number of bytes in the byte array + */ + public final static int IdByteArraySize = 64; + + /** + * The size of a UUID in bytes + */ + public final static int uuidSize = 16; + + /** + * The size of the flags field + */ + public final static int flagsSize = 1; + + /** + * Location of the type field within the flags field + */ + public final static int flagsIdTypeOffset = IDFormat.flagsSize - 1; + + /** + * Type value for Codat + */ + public final static byte flagCodatID = 0x01; + + /** + * Type value for PeerGroup + */ + public final static byte flagPeerGroupID = 0x02; + + /** + * Type value for Peer + */ + public final static byte flagPeerID = 0x03; + + /** + * Type value for Pipe + */ + public final static byte flagPipeID = 0x04; + + /** + * Type value for ModuleClass + */ + public final static byte flagModuleClassID = 0x05; + + /** + * Type value for ModuleSpec + */ + public final static byte flagModuleSpecID = 0x06; + + /** + * Type value for CodatID + */ + public final static byte flagCodatID7 = 0x07; + + /** + * Location of ID flags within byte array. + */ + public final static int flagsOffset = IDFormat.IdByteArraySize - IDFormat.flagsSize; + + /** + * Our local version of the world Peer Group ID. We need this for cases + * where we have to make ids which are in the world peer group. We only + * use this ID for those cases and never return this ID. + */ + public static final PeerGroupID worldPeerGroupID = new PeerGroupID(new UUID(0x5961626164616261L, 0x4A78746150325033L)); // YabadabaJXTAP2P! + + /** + * Our local version of the net Peer Group ID. We need this for cases + * where we have to make ids which are in the net peer group. We only + * use this ID for those cases and never return this ID. + */ + public static final PeerGroupID defaultNetPeerGroupID = new PeerGroupID(new UUID(0x5961626164616261L, 0x4E50472050325033L)); // YabadabaNPG P2P! + + /** + * This table maps our local private versions of the well known ids to the + * globally known version. + */ + private final static Object[][] wellKnownIDs = { + { net.jxta.peergroup.PeerGroupID.worldPeerGroupID, worldPeerGroupID } + , + { net.jxta.peergroup.PeerGroupID.defaultNetPeerGroupID, defaultNetPeerGroupID } + }; + + /** + * The instantiator for this ID Format which is used by the IDFactory. + */ + public static final IDFactory.Instantiator INSTANTIATOR = new Instantiator(); + + /** + * This class cannot be instantiated. + */ + protected IDFormat() {} + + /** + * Translate from well known ID to our locally encoded versions. + * + * @param input the id to be translated. + * @return the translated ID or the input ID if no translation was needed. + */ + static ID translateFromWellKnown(ID input) { + for (int eachWellKnown = 0; eachWellKnown < wellKnownIDs.length; eachWellKnown++) { + ID aWellKnown = (ID) wellKnownIDs[eachWellKnown][0]; + + if (aWellKnown.equals(input)) { + return (ID) wellKnownIDs[eachWellKnown][1]; + } + } + + return input; + } + + /** + * Translate from locally encoded versions to the well known versions. + * + * @param input the id to be translated. + * @return the translated ID or the input ID if no translation was needed. + */ + static ID translateToWellKnown(ID input) { + for (int eachWellKnown = 0; eachWellKnown < wellKnownIDs.length; eachWellKnown++) { + ID aLocalEncoding = (ID) wellKnownIDs[eachWellKnown][1]; + + if (aLocalEncoding.equals(input)) { + return (ID) wellKnownIDs[eachWellKnown][0]; + } + } + + return input; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/Instantiator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/Instantiator.java new file mode 100644 index 000000000..57d2bdf33 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/Instantiator.java @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.UnknownServiceException; +import java.net.URISyntaxException; + +import net.jxta.id.IDFactory; + + +/** + * The instantiator for the UUID ID Format. + * + *

            For "seed" variant constructors, the first 16 bytes of the seed are used + * literally as the UUID value. The value is masked to make it a valid version 4 + * IETF varient UUID. + */ +public class Instantiator implements IDFactory.URIInstantiator { + + /** + * Our ID Format + */ + final static String UUIDEncoded = "uuid"; + + /** + * {@inheritDoc} + */ + public String getSupportedIDFormat() { + return UUIDEncoded; + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURL(URL source) throws MalformedURLException, UnknownServiceException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getProtocol())) { + throw new UnknownServiceException("URI protocol type was not as expected."); + } + + String encoded = source.getFile(); + + int colonAt = encoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new UnknownServiceException("URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(encoded.substring(0, colonAt))) { + throw new UnknownServiceException("URN namespace was not as expected."); + } + + // skip the namespace portion and the colon + encoded = encoded.substring(colonAt + 1); + + int dashAt = encoded.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new UnknownServiceException("URN Encodingtype was missing."); + } + + if (!encoded.substring(0, dashAt).equals(getSupportedIDFormat())) { + throw new UnknownServiceException("JXTA ID Format was not as expected."); + } + + // skip the dash + encoded = encoded.substring(dashAt + 1); + + // check that the length is even + if (0 != (encoded.length() % 2)) { + throw new MalformedURLException("URN contains an odd number of chars"); + } + + // check that the length is long enough + if (encoded.length() < 2) { + throw new MalformedURLException("URN does not contain enough chars"); + } + + // check that id is short enough + if (IDFormat.IdByteArraySize < (encoded.length() % 2)) { + throw new MalformedURLException("URN contains too many chars"); + } + + net.jxta.id.ID result = null; + IDBytes id = new IDBytes(); + + try { + // do the primary portion. + for (int eachByte = 0; eachByte < ((encoded.length() / 2) - IDFormat.flagsSize); eachByte++) { + int index = eachByte * 2; + String twoChars = encoded.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + + // do the flags + for (int eachByte = IDFormat.flagsOffset; eachByte < IDFormat.IdByteArraySize; eachByte++) { + int index = encoded.length() - (IDFormat.IdByteArraySize - eachByte) * 2; + String twoChars = encoded.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + } catch (NumberFormatException caught) { + throw new MalformedURLException("Invalid Character in JXTA URI"); + } + + switch (id.bytes[IDFormat.flagsOffset + IDFormat.flagsIdTypeOffset]) { + case IDFormat.flagCodatID: + result = new CodatID(id); + break; + + case IDFormat.flagPeerGroupID: + result = new PeerGroupID(id); + result = (PeerGroupID) IDFormat.translateToWellKnown(result); + break; + + case IDFormat.flagPeerID: + result = new PeerID(id); + break; + + case IDFormat.flagPipeID: + result = new PipeID(id); + break; + + case IDFormat.flagModuleClassID: + result = new ModuleClassID(id); + break; + + case IDFormat.flagModuleSpecID: + result = new ModuleSpecID(id); + break; + + default: + throw new MalformedURLException("JXTA ID Type not recognized"); + } + + return result; + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, InputStream in) throws IOException { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID, in); + } + + /** + * {@inheritDoc} + */ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new CodatID(peerGroupID, seed, in); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID() { + return new PeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(byte[] seed) { + return new PeerGroupID(seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(parent); + + return new PeerGroupID(parentGroupID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent, byte[] seed) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(parent); + + return new PeerGroupID(parentGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peer.PeerID newPeerID(net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PeerID(peerGroupID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peer.PeerID newPeerID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PeerID(peerGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.pipe.PipeID newPipeID(net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PipeID(peerGroupID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.pipe.PipeID newPipeID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PipeID(peerGroupID, seed); + } + + /** + * {@inheritDoc} + */ + public net.jxta.platform.ModuleClassID newModuleClassID() { + return new ModuleClassID(); + } + + /** + * {@inheritDoc} + */ + public net.jxta.platform.ModuleClassID newModuleClassID(net.jxta.platform.ModuleClassID classID) { + return new ModuleClassID((ModuleClassID) classID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.platform.ModuleSpecID newModuleSpecID(net.jxta.platform.ModuleClassID classID) { + return new ModuleSpecID((ModuleClassID) classID); + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURI(URI source) throws URISyntaxException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getScheme())) { + throw new URISyntaxException(source.toString(), "URI scheme was not as expected."); + } + + String decoded = source.getSchemeSpecificPart(); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new URISyntaxException(source.toString(), "URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new URISyntaxException(source.toString() + , + "URN namespace was not as expected. (" + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + return fromURNNamespaceSpecificPart(decoded); + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURNNamespaceSpecificPart(String source) throws URISyntaxException { + int dashAt = source.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new URISyntaxException(source, "URN Encodingtype was missing."); + } + + if (!source.substring(0, dashAt).equals(getSupportedIDFormat())) { + throw new URISyntaxException(source, "JXTA ID Format was not as expected."); + } + + // skip the dash + source = source.substring(dashAt + 1); + + // check that the length is even + if (0 != (source.length() % 2)) { + throw new URISyntaxException(source, "URN contains an odd number of chars"); + } + + // check that the length is long enough + if (source.length() < 2) { + throw new URISyntaxException(source, "URN does not contain enough chars"); + } + + // check that id is short enough + if (IDFormat.IdByteArraySize < (source.length() / 2)) { + throw new URISyntaxException(source, "URN contains too many chars"); + } + + net.jxta.id.ID result = null; + IDBytes id = new IDBytes(); + + try { + // do the primary portion. + for (int eachByte = 0; eachByte < ((source.length() / 2) - IDFormat.flagsSize); eachByte++) { + int index = eachByte * 2; + String twoChars = source.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + + // do the flags + for (int eachByte = IDFormat.flagsOffset; eachByte < IDFormat.IdByteArraySize; eachByte++) { + int index = source.length() - (IDFormat.IdByteArraySize - eachByte) * 2; + String twoChars = source.substring(index, index + 2); + + id.bytes[eachByte] = (byte) Integer.parseInt(twoChars, 16); + } + } catch (NumberFormatException caught) { + throw new URISyntaxException(source, "Invalid Character in JXTA URI"); + } + + switch (id.bytes[IDFormat.flagsOffset + IDFormat.flagsIdTypeOffset]) { + case IDFormat.flagCodatID: + result = new CodatID(id); + break; + + case IDFormat.flagPeerGroupID: + result = new PeerGroupID(id); + result = IDFormat.translateToWellKnown(result); + break; + + case IDFormat.flagPeerID: + result = new PeerID(id); + break; + + case IDFormat.flagPipeID: + result = new PipeID(id); + break; + + case IDFormat.flagModuleClassID: + result = new ModuleClassID(id); + break; + + case IDFormat.flagModuleSpecID: + result = new ModuleSpecID(id); + break; + + default: + throw new URISyntaxException(source, "JXTA ID Type not recognized"); + } + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/ModuleClassID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/ModuleClassID.java new file mode 100644 index 000000000..2f56ff626 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/ModuleClassID.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * An implementation of the {@link net.jxta.platform.ModuleClassID} ID Type. + */ +public class ModuleClassID extends net.jxta.platform.ModuleClassID { + + /** + * Location of the class id + */ + private final static int moduleClassIdOffset = 0; + + /** + * Location of the role id + */ + private final static int moduleRoleIdOffset = moduleClassIdOffset + IDFormat.uuidSize; + + /** + * location of the start of the pad space + */ + private final static int padOffset = ModuleClassID.moduleRoleIdOffset + IDFormat.uuidSize; + + /** + * size of the unused space + */ + private final static int padSize = IDFormat.flagsOffset - ModuleClassID.padOffset; + + /** + * The id data + */ + protected IDBytes id; + + /** + * Constructor. + * Initializes contents from provided ID. + * + * @param id the ID data + */ + protected ModuleClassID(IDBytes id) { + super(); + this.id = id; + } + + /** + * Constructor. + * Creates a ModuleClassID in a given class, with a given class unique id. + * A UUID of a class and another UUID are provided. + * + * @param classUUID the class to which this will belong. + * @param roleUUID the unique id of this role in that class. + */ + protected ModuleClassID(UUID classUUID, UUID roleUUID) { + super(); + id = new IDBytes(IDFormat.flagModuleClassID); + + id.longIntoBytes(ModuleClassID.moduleClassIdOffset, classUUID.getMostSignificantBits()); + id.longIntoBytes(ModuleClassID.moduleClassIdOffset + 8, classUUID.getLeastSignificantBits()); + + id.longIntoBytes(ModuleClassID.moduleRoleIdOffset, roleUUID.getMostSignificantBits()); + id.longIntoBytes(ModuleClassID.moduleRoleIdOffset + 8, roleUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newModuleClassID()}. + * + *

            A new class UUID is created. The role ID is left null. This is the + * only way to create a new class without supplying a new UUID explicitly. + * + *

            Note that a null role is just as valid as any other, it just has a + * shorter string representation. So it is not mandatory to create a new + * role in a new class. + */ + public ModuleClassID() { + this(UUIDFactory.newUUID(), new UUID(0L, 0L)); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newModuleClassID(net.jxta.platform.ModuleClassID)}. + */ + public ModuleClassID(ModuleClassID classID) { + this(classID.getClassUUID(), UUIDFactory.newUUID()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof ModuleClassID) { + ModuleClassID mcidTarget = (ModuleClassID) target; + + return id.equals(mcidTarget.id); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + (String) id.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.platform.ModuleClassID getBaseClass() { + return new ModuleClassID(getClassUUID(), new UUID(0L, 0L)); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleClassID classId) { + return getClassUUID().equals(((ModuleClassID) classId).getClassUUID()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleSpecID specId) { + return getClassUUID().equals(((ModuleSpecID) specId).getClassUUID()); + } + + /** + * get the class' unique id + * + * @return UUID module class' unique id + */ + protected UUID getClassUUID() { + UUID result = new UUID(id.bytesIntoLong(ModuleClassID.moduleClassIdOffset) + , + id.bytesIntoLong(ModuleClassID.moduleClassIdOffset + 8)); + + return result; + } + + /** + * get the role unique id + * + * @return UUID module role unique id + */ + protected UUID getRoleUUID() { + UUID result = new UUID(id.bytesIntoLong(ModuleClassID.moduleRoleIdOffset) + , + id.bytesIntoLong(ModuleClassID.moduleRoleIdOffset + 8)); + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/ModuleSpecID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/ModuleSpecID.java new file mode 100644 index 000000000..eed81a107 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/ModuleSpecID.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * An implementation of the {@link net.jxta.platform.ModuleSpecID} ID Type. + */ +public class ModuleSpecID extends net.jxta.platform.ModuleSpecID { + private final static int moduleClassIdOffset = 0; + private final static int moduleSpecIdOffset = IDFormat.uuidSize; + private final static int padOffset = ModuleSpecID.moduleSpecIdOffset + IDFormat.uuidSize; + private final static int padSize = IDFormat.flagsOffset - ModuleSpecID.padOffset; + + /** + * The id data + */ + protected IDBytes id; + + /** + * Constructor. Used only internally. + */ + protected ModuleSpecID() { + super(); + id = new IDBytes(IDFormat.flagModuleSpecID); + } + + /** + * Initializes contents from provided ID. + * + * @param id the ID data + */ + protected ModuleSpecID(IDBytes id) { + super(); + this.id = id; + } + + /** + * Creates a ModuleSpecID in a given class, with a given class unique id. + * A UUID of a class and another UUID are provided. + * + * @param classUUID the class to which this will belong. + * @param specUUID the unique id of this spec in that class. + */ + protected ModuleSpecID(UUID classUUID, UUID specUUID) { + + this(); + id.longIntoBytes(ModuleSpecID.moduleClassIdOffset, classUUID.getMostSignificantBits()); + id.longIntoBytes(ModuleSpecID.moduleClassIdOffset + 8, classUUID.getLeastSignificantBits()); + + id.longIntoBytes(ModuleSpecID.moduleSpecIdOffset, specUUID.getMostSignificantBits()); + id.longIntoBytes(ModuleSpecID.moduleSpecIdOffset + 8, specUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newModuleSpecID(net.jxta.platform.ModuleClassID)}. + */ + public ModuleSpecID(ModuleClassID classID) { + this(classID.getClassUUID(), UUIDFactory.newUUID()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof ModuleSpecID) { + ModuleSpecID msidTarget = (ModuleSpecID) target; + + return id.equals(msidTarget.id); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + (String) id.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.platform.ModuleClassID getBaseClass() { + return new ModuleClassID(getClassUUID(), new UUID(0L, 0L)); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleClassID classId) { + return getClassUUID().equals(((ModuleClassID) classId).getClassUUID()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleSpecID specId) { + return getClassUUID().equals(((ModuleSpecID) specId).getClassUUID()); + } + + /** + * get the class' unique id + * + * @since JXTA 1.0 + * + * @return UUID module class' unique id + */ + protected UUID getClassUUID() { + UUID result = new UUID(id.bytesIntoLong(ModuleSpecID.moduleClassIdOffset) + , + id.bytesIntoLong(ModuleSpecID.moduleClassIdOffset + 8)); + + return result; + } + + /** + * get the spec unique id + * + * @since JXTA 1.0 + * + * @return UUID module spec unique id + */ + protected UUID getSpecUUID() { + UUID result = new UUID(id.bytesIntoLong(ModuleSpecID.moduleSpecIdOffset) + , + id.bytesIntoLong(ModuleSpecID.moduleSpecIdOffset + 8)); + + return result; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PeerGroupID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PeerGroupID.java new file mode 100644 index 000000000..616345c9d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PeerGroupID.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * An implementation of the {@link net.jxta.peergroup.PeerGroupID} ID Type. + */ +public class PeerGroupID extends net.jxta.peergroup.PeerGroupID { + + /** + * Location of the group id UUID within the id bytes. + */ + protected final static int groupIdOffset = 0; + + /** + * Location of the parent group id UUID within the id bytes. + */ + protected final static int parentgroupIdOffset = PeerGroupID.groupIdOffset + IDFormat.uuidSize; + + /** + * Location of the begining of the pad space. + */ + protected final static int padOffset = PeerGroupID.parentgroupIdOffset + IDFormat.uuidSize; + + /** + * size of the pad space. + */ + protected final static int padSize = IDFormat.flagsOffset - PeerGroupID.padOffset; + + /** + * The id data + */ + protected IDBytes id; + + /** + * Initializes contents from provided ID. + * + * @param id the ID data + */ + protected PeerGroupID(IDBytes id) { + super(); + this.id = id; + } + + /** + * Creates a PeerGroupID. A PeerGroupID is provided + * + * @param groupUUID the PeerGroupID to use to construct the new PeerGroupID + */ + protected PeerGroupID(UUID groupUUID) { + super(); + id = new IDBytes(IDFormat.flagPeerGroupID); + + id.longIntoBytes(PeerGroupID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PeerGroupID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID()}. + */ + public PeerGroupID() { + this(UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID(net.jxta.peergroup.PeerGroupID)}. + */ + public PeerGroupID(PeerGroupID parent) { + this(UUIDFactory.newUUID()); + + System.arraycopy(parent.id.bytes, 0, id.bytes, 16, IDFormat.uuidSize); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID(byte[])}. + */ + public PeerGroupID(byte[] seed) { + super(); + id = new IDBytes(IDFormat.flagPeerGroupID); + + for (int copySeed = Math.min(IDFormat.uuidSize, seed.length) - 1; copySeed >= 0; copySeed--) { + id.bytes[copySeed + PeerGroupID.groupIdOffset] = seed[copySeed]; + } + + // make it a valid UUID + id.bytes[PeerGroupID.groupIdOffset + 6] &= 0x0f; + id.bytes[PeerGroupID.groupIdOffset + 6] |= 0x40; /* version 4 */ + id.bytes[PeerGroupID.groupIdOffset + 8] &= 0x3f; + id.bytes[PeerGroupID.groupIdOffset + 8] |= 0x80; /* IETF variant */ + id.bytes[PeerGroupID.groupIdOffset + 10] &= 0x3f; + id.bytes[PeerGroupID.groupIdOffset + 10] |= 0x80; /* multicast bit */ + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerGroupID(net.jxta.peergroup.PeerGroupID,byte[])}. + */ + public PeerGroupID(PeerGroupID parent, byte[] seed) { + this(seed); + + System.arraycopy(parent.id.bytes, 0, id.bytes, 16, IDFormat.uuidSize); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof PeerGroupID) { + PeerGroupID peergroupTarget = (PeerGroupID) target; + + return id.equals(peergroupTarget.id); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + (String) id.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.peergroup.PeerGroupID getParentPeerGroupID() { + boolean zero = true; + + for (int eachByte = 0; eachByte < IDFormat.uuidSize; eachByte++) { + if (id.bytes[eachByte + PeerGroupID.parentgroupIdOffset] != 0) { + zero = false; + break; + } + } + + // if zero, then there is no parent. + if (zero) { + return null; + } + + UUID groupUUID = new UUID(id.bytesIntoLong(PeerGroupID.parentgroupIdOffset) + , + id.bytesIntoLong(PeerGroupID.parentgroupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupUUID); + + // convert to the generic world PGID as necessary + return (net.jxta.peergroup.PeerGroupID) IDFormat.translateToWellKnown(groupID); + } + + /** + * Returns the UUID associated with this PeerGroupID. + * + * @return The UUID associated with this PeerGroupID. + */ + protected UUID getUUID() { + return new UUID(id.bytesIntoLong(PeerGroupID.groupIdOffset), id.bytesIntoLong(PeerGroupID.groupIdOffset + 8)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PeerID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PeerID.java new file mode 100644 index 000000000..4ba50ed3e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PeerID.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +/** + * An implementation of the {@link net.jxta.peer.PeerID} ID Type. + */ +public class PeerID extends net.jxta.peer.PeerID { + + protected final static int groupIdOffset = 0; + protected final static int idOffset = PeerID.groupIdOffset + IDFormat.uuidSize; + protected final static int padOffset = PeerID.idOffset + IDFormat.uuidSize; + + protected final static int padSize = IDFormat.flagsOffset - PeerID.padOffset; + + /** + * The id data + */ + protected IDBytes id; + + /** + * Used only internally. + */ + protected PeerID() { + super(); + id = new IDBytes(IDFormat.flagPeerID); + } + + /** + * Initializes contents from provided ID. + * + * @param id the ID data + */ + protected PeerID(IDBytes id) { + super(); + this.id = id; + } + + /** + * Creates a PeerID. A PeerGroupID is provided + * + * @param groupUUID the UUID of the group to which this will belong. + * @param idUUID the UUID which will be used for this pipe. + */ + protected PeerID(UUID groupUUID, UUID idUUID) { + this(); + + id.longIntoBytes(PipeID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + id.longIntoBytes(PipeID.idOffset, idUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.idOffset + 8, idUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerID(net.jxta.peergroup.PeerGroupID)}. + */ + public PeerID(PeerGroupID groupID) { + this(groupID.getUUID(), UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPeerID(net.jxta.peergroup.PeerGroupID,byte[])}. + */ + public PeerID(PeerGroupID groupID, byte[] seed) { + this(); + + UUID groupUUID = new UUID(groupID.id.bytesIntoLong(PeerGroupID.groupIdOffset) + , + groupID.id.bytesIntoLong(PeerGroupID.groupIdOffset + 8)); + + byte[] idUUIDbytes = new byte[IDFormat.uuidSize]; + + System.arraycopy(seed, 0, idUUIDbytes, 0, Math.min(IDFormat.uuidSize, seed.length)); + + UUID idUUID = UUIDFactory.newUUID(idUUIDbytes); + + id.longIntoBytes(PipeID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + id.longIntoBytes(PipeID.idOffset, idUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.idOffset + 8, idUUID.getLeastSignificantBits()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof PeerID) { + PeerID peerTarget = (PeerID) target; + + return id.equals(peerTarget.id); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + (String) id.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + UUID groupUUID = new UUID(id.bytesIntoLong(PeerID.groupIdOffset), id.bytesIntoLong(PeerID.groupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupUUID); + + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(groupID); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PipeID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PipeID.java new file mode 100644 index 000000000..92d25b20c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/PipeID.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * An implementation of the {@link net.jxta.pipe.PipeID} ID Type. + */ +public class PipeID extends net.jxta.pipe.PipeID { + protected final static int groupIdOffset = 0; + protected final static int idOffset = PipeID.groupIdOffset + IDFormat.uuidSize; + protected final static int padOffset = PipeID.idOffset + IDFormat.uuidSize; + protected final static int padSize = IDFormat.flagsOffset - PipeID.padOffset; + + /** + * The id data + */ + protected IDBytes id; + + /** + * Used only internally + * + */ + protected PipeID() { + super(); + id = new IDBytes(IDFormat.flagPipeID); + } + + /** + * Constructor. + * Initializes contents from provided ID. + * + * + * @param id the ID data + */ + protected PipeID(IDBytes id) { + super(); + this.id = id; + } + + /** + * Creates a PipeID. A PeerGroupID is provided + * + * @param groupUUID the UUID of the group to which this will belong. + * @param idUUID the UUID which will be used for this pipe. + */ + protected PipeID(UUID groupUUID, UUID idUUID) { + this(); + + id.longIntoBytes(PipeID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + id.longIntoBytes(PipeID.idOffset, idUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.idOffset + 8, idUUID.getLeastSignificantBits()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPipeID(net.jxta.peergroup.PeerGroupID)}. + */ + public PipeID(PeerGroupID groupID) { + this(groupID.getUUID(), UUIDFactory.newUUID()); + } + + /** + * See {@link net.jxta.id.IDFactory.Instantiator#newPipeID(net.jxta.peergroup.PeerGroupID,byte[])}. + */ + public PipeID(PeerGroupID groupID, byte[] seed) { + this(); + + UUID groupUUID = groupID.getUUID(); + + id.longIntoBytes(PipeID.groupIdOffset, groupUUID.getMostSignificantBits()); + id.longIntoBytes(PipeID.groupIdOffset + 8, groupUUID.getLeastSignificantBits()); + + for (int copySeed = Math.min(IDFormat.uuidSize, seed.length) - 1; copySeed >= 0; copySeed--) { + id.bytes[copySeed + PipeID.idOffset] = seed[copySeed]; + } + + // make it a valid UUID + id.bytes[PipeID.idOffset + 6] &= 0x0f; + id.bytes[PipeID.idOffset + 6] |= 0x40; /* version 4 */ + id.bytes[PipeID.idOffset + 8] &= 0x3f; + id.bytes[PipeID.idOffset + 8] |= 0x80; /* IETF variant */ + id.bytes[PipeID.idOffset + 10] &= 0x3f; + id.bytes[PipeID.idOffset + 10] |= 0x80; /* multicast bit */ + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof PipeID) { + PipeID pipeTarget = (PipeID) target; + + return id.equals(pipeTarget.id); + } else { + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + (String) id.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + UUID groupUUID = new UUID(id.bytesIntoLong(PipeID.groupIdOffset), id.bytesIntoLong(PipeID.groupIdOffset + 8)); + + PeerGroupID groupID = new PeerGroupID(groupUUID); + + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(groupID); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/UUID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/UUID.java new file mode 100644 index 000000000..f7ea4da13 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/UUID.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.io.Serializable; + + +/** + * A UUID is a 128-bit universally unique identifier. + * The most significant long can be decomposed into the following + * unsigned fields: + *

            + * 0xFFFFFFFF00000000 time_low
            + * 0x00000000FFFF0000 time_mid
            + * 0x000000000000F000 version
            + * 0x0000000000000FFF time_hi
            + * 
            + *

            The least significant long can be decomposed into the following + * unsigned fields: + *

            + * 0xC000000000000000 variant
            + * 0x3FFF000000000000 clock_seq
            + * 0x0000FFFFFFFFFFFF node
            + * 
            + *

            The variant field must be 0x2. The version field must be either 0x1 or 0x4. + * + *

            If the version field is 0x4, then the most significant bit of the node + * field must be set to 1, and the remaining fields are set to values + * produced by a cryptographically strong pseudo-random number generator. + * + *

            If the version field is 0x1, then the node field is set to an IEEE 802 + * address (MAC), the clock_seq field is set to a 14-bit random number, and the + * time_low, time_mid, and time_hi fields are set to the least, middle and + * most significant bits (respectively) of a 60-bit timestamp measured in + * 100-nanosecond units since midnight, October 15, 1582 UTC. + * + * @see net.jxta.impl.id.UUID.IDFormat + * @see net.jxta.impl.id.UUID.UUIDFactory + * @see "Information Technology - Open Systems Interconnection - Remote Procedure Call (RPC), ISO 11578:1996" + * @see The Open Group - DCE 1.1 Remote Procedure Call (RPC) : Appendix A - Universal Unique Identifier + * + */ +public final class UUID implements Serializable { + + /** + * The null UUID. Useful for comparisons. + */ + public static final UUID nullUUID = new UUID(0L, 0L); + + /** + * The most significant 64 bits. + */ + private long mostSig; + + /** + * The least significant 64 bits. + */ + private long leastSig; + + /** + * Simple constructor. This constructor does not check to ensure that the + * values provided produce a valid UUID. + * + * @param mostSig the most significant 64 bits + * @param leastSig the least significant 64 bits + */ + public UUID(long mostSig, long leastSig) { + this.mostSig = mostSig; + this.leastSig = leastSig; + } + + /** + * Simple constructor. This constructor does not check to ensure that the + * values provided produce a valid UUID. + * + * @param bytes the 128 bits of + */ + public UUID(byte[] bytes) { + if (bytes.length != 16) { + throw new IllegalArgumentException("bytes must be 16 bytes in length"); + } + + long mostSig = 0; + + for (int i = 0; i < 8; i++) { + mostSig = (mostSig << 8) | (bytes[i] & 0xff); + } + + long leastSig = 0; + + for (int i = 8; i < 16; i++) { + leastSig = (leastSig << 8) | (bytes[i] & 0xff); + } + + this.mostSig = mostSig; + this.leastSig = leastSig; + } + + public UUID(String uuid) { + if (36 != uuid.length()) { + throw new IllegalArgumentException("uuid must be 36 characters in length"); + } + + byte bytes[] = new byte[16]; + + boolean hi = true; + + for (int eachChar = 0, offset = 0; eachChar < 36; eachChar++) { + char aChar = uuid.charAt(eachChar); + + switch (eachChar) { + case 8: + case 13: + case 18: + case 23: + if ('-' != uuid.charAt(eachChar)) { + throw new IllegalArgumentException("uuid has an illegal character at position " + eachChar); + } + break; + + default: + aChar = Character.toLowerCase(aChar); + + int aNibble; + + if (('0' <= aChar) && ('9' >= aChar)) { + aNibble = aChar - '0'; + } else if (('a' <= aChar) && ('f' >= aChar)) { + aNibble = aChar - 'a' + 10; + } else { + throw new IllegalArgumentException("uuid has an illegal character at position " + eachChar); + } + + if (hi) { + aNibble <<= 4; + } + + bytes[offset] |= aNibble; + + if (!hi) { + offset++; + } + + hi = !hi; + } + } + + mostSig = 0; + for (int i = 0; i < 8; i++) { + mostSig = (mostSig << 8) | (bytes[i] & 0xff); + } + + leastSig = 0; + for (int i = 8; i < 16; i++) { + leastSig = (leastSig << 8) | (bytes[i] & 0xff); + } + } + + /** + * Returns the most significant 64 bits of the UUID. + * + * @return long return most significant bits + */ + public long getMostSignificantBits() { + return mostSig; + } + + /** + * Returns the least significant 64 bits of the UUID. + * + * @return long least significant bits + */ + public long getLeastSignificantBits() { + return leastSig; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return (int) ((mostSig >> 32) ^ mostSig ^ (leastSig >> 32) ^ leastSig); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof UUID) { + return equals((UUID) target); + } else { + return false; + } + } + + /** + * UUIDs are equal if they represent the same 128-bit value. + * + * @param sid UUID seed + * @return boolean true if equals + */ + public boolean equals(UUID sid) { + if (null == sid) { + return false; + } + + return (mostSig == sid.mostSig && leastSig == sid.leastSig); + } + + /** + * Returns a 36-character string of six fields separated by hyphens, + * with each field represented in lowercase hexadecimal with the same + * number of digits as in the field. The order of fields is: time_low, + * time_mid, version and time_hi treated as a single field, variant and + * clock_seq treated as a single field, and node. + * + * ie. XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + * + * @return String return value + */ + @Override + public String toString() { + return (digits(mostSig >> 32, 8) + "-" + digits(mostSig >> 16, 4) + "-" + digits(mostSig, 4) + "-" + + digits(leastSig >> 48, 4) + "-" + digits(leastSig, 12)); + } + + /** + * Returns val represented by the specified number of hex digits + * + * @param val value + * @param digits + * @return String return value + */ + private static String digits(long val, int digits) { + long hi = 1L << (digits * 4); + + return Long.toHexString(hi | (val & (hi - 1))).substring(1); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/UUIDFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/UUIDFactory.java new file mode 100644 index 000000000..689dedee1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/UUIDFactory.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.UUID; + + +import java.security.SecureRandom; +import java.util.GregorianCalendar; +import java.util.Random; +import java.util.Calendar; +import java.util.TimeZone; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * A Factory for generating random UUIDs. + * + * @see net.jxta.impl.id.UUID.UUID + */ +public final class UUIDFactory { + + /** + * Log4J Logger + */ + private static final transient Logger LOG = Logger.getLogger(UUIDFactory.class.getName()); + + /** + * The point at which the Gregorian calendar rules are used, measured in + * milliseconds from the standard epoch. Default is October 15, 1582 + * (Gregorian) 00:00:00 UTC or -12219292800000L. + */ + static final long GREGORIAN_MILLIS_OFFSET = 12219292800000L; + + /** + * offset of this computer relative to utc + */ + private long utc_offset = 0L; + + /** + * Time at which we last generated a version 1 UUID in relative + * milliseconds from 00:00:00.00, 15 October 1582 UTC. + */ + private long lastTimeSequence = 0L; + + /** + * Count of how many version 1 UUIDs we have generated at this time + * sequence value. + */ + private long inSequenceCounter = 0L; + + /** + * pseudo random value to prevent clock collisions on the same computer. + */ + private long clock_seq = 0L; + + /** + * pseudo random value. If available, this should be seeded with the MAC + * address of a local network interface. + */ + private long node = 0L; + + /** + * Random number generator for UUID generation. + */ + private Random randNum = null; + + /** + * We have to catch exceptions from construct of JRandom so we + * have to init it inline. + */ + private static UUIDFactory factory = new UUIDFactory(); + + /** + * Generate a new random UUID value. The UUID returned is a version 4 IETF + * variant random UUID. + * + *

            This member must be synchronized because it makes use of shared + * internal state. + * + * @return UUID returns a version 4 IETF variant random UUID. + */ + public synchronized static UUID newUUID() { + + return newUUID(factory.randNum.nextLong(), factory.randNum.nextLong()); + } + + /** + * Returns a formatted time sequence field containing the elapsed time in + * 100 nano units since 00:00:00.00, 15 October 1582. Since the normal + * clock resolution is coarser than 100 nano than this value, the lower + * bits are generated in sequence for each call within the same milli. + * + * @return time sequence value + */ + private synchronized long getTimeSequence() { + long now = (System.currentTimeMillis() - GREGORIAN_MILLIS_OFFSET + utc_offset) * 10000L; // convert to 100 nano units; + + if (now > lastTimeSequence) { + lastTimeSequence = now; + // XXX bondolo@jxta.org It might be better to set this to a random + // value and just watch for rollover. The reason is that there may + // be more than one instance running on the same computer which is + // generating UUIDs, but is not excluded by our synchronization. + // A random value would reduce collisions. + inSequenceCounter = 0; + } else { + inSequenceCounter++; + if (inSequenceCounter >= 10000L) { + // we allow the clock to skew forward rather than wait. It's + // really unlikely that anyone will be continuously generating + // more than 10k UUIDs per milli for very long. + lastTimeSequence += 10000L; + inSequenceCounter = 0; + } + } + + return (lastTimeSequence + inSequenceCounter); + } + + /** + * Generate a new UUID value. The UUID returned is a version 1 IETF + * variant UUID. + * + *

            The node value used is currently a random value rather than the + * normal ethernet MAC address because the MAC address is not directly + * accessible in to java. + * + * @return UUID returns a version 1 IETF variant UUID. + */ + public static UUID newSeqUUID() { + long mostSig = 0L, leastSig = 0L; + + long timeSeq = factory.getTimeSequence(); + + mostSig |= (timeSeq & 0x0FFFFFFFFL) << 32; + mostSig |= ((timeSeq >> 32) & 0x0FFFFL) << 16; + mostSig |= (0x01L) << 12; // version 1; + mostSig |= ((timeSeq >> 48) & 0x00FFFL); + + leastSig |= (0x02L) << 62; // ietf variant + leastSig |= ((factory.clock_seq >> 8) & 0x03FL) << 56; + leastSig |= (factory.clock_seq & 0x0FFL) << 48; + leastSig |= factory.node & 0x0FFFFFFFFFFFFL; + + return new UUID(mostSig, leastSig); + } + + /** + * Generate a new UUID value. The values provided are masked to produce a + * version 4 IETF variant random UUID. + * + * @param bytes the 128 bits of the UUID + * @return UUID returns a version 4 IETF variant random UUID. + */ + public static UUID newUUID(byte[] bytes) { + if (bytes.length != 16) { + throw new IllegalArgumentException("bytes must be 16 bytes in length"); + } + + long mostSig = 0; + + for (int i = 0; i < 8; i++) { + mostSig = (mostSig << 8) | (bytes[i] & 0xff); + } + + long leastSig = 0; + + for (int i = 8; i < 16; i++) { + leastSig = (leastSig << 8) | (bytes[i] & 0xff); + } + + return newUUID(mostSig, leastSig); + } + + /** + * Generate a new UUID value. The values provided are masked to produce a + * version 3 IETF variant UUID. + * + * @param mostSig High-long of UUID value. + * @param leastSig Low-long of UUID value. + * @return UUID returns a version 3 IETF variant random UUID. + */ + public static UUID newHashUUID(long mostSig, long leastSig) { + + mostSig &= 0xFFFFFFFFFFFF0FFFL; + mostSig |= 0x0000000000003000L; // version 3 + leastSig &= 0x3FFFFFFFFFFFFFFFL; + leastSig |= 0x8000000000000000L; // IETF variant + + return new UUID(mostSig, leastSig); + } + + /** + * Generate a new UUID value. The values provided are masked to produce a + * version 4 IETF variant random UUID. + * + * @param mostSig High-long of UUID value. + * @param leastSig Low-long of UUID value. + * @return UUID returns a version 4 IETF variant random UUID. + */ + public static UUID newUUID(long mostSig, long leastSig) { + + mostSig &= 0xFFFFFFFFFFFF0FFFL; + mostSig |= 0x0000000000004000L; // version 4 + leastSig &= 0x3FFFFFFFFFFFFFFFL; + leastSig |= 0x8000000000000000L; // IETF variant + + leastSig &= 0xFFFF7FFFFFFFFFFFL; + leastSig |= 0x0000800000000000L; // multicast bit + + return new UUID(mostSig, leastSig); + } + + /** + * Singleton class + */ + private UUIDFactory() { + + randNum = new SecureRandom(); + + String[] tz_ids = TimeZone.getAvailableIDs(0); + Calendar gregorianCalendar = new GregorianCalendar(); + + // FIXME 20031024 bondolo@jxta.org In theory we should be doing this + // EVERY time we generate a UUID. In practice because of we use a random + // clock_seq we don't have to. + utc_offset = gregorianCalendar.get(Calendar.ZONE_OFFSET) + gregorianCalendar.get(Calendar.DST_OFFSET); + + // Generate a random clock seq + clock_seq = randNum.nextInt() & 0x03FFL; + + // Generate a random node ID since we can't get the MAC Address + node = (randNum.nextLong() & 0x0000FFFFFFFFFFFFL); + node |= 0x0000800000000000L; // mask in the multicast bit since we don't know if its unique. + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/package.html new file mode 100644 index 000000000..dc0f6b23e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/UUID/package.html @@ -0,0 +1,16 @@ + + + + + + + The 'uuid' format is a general purpose JXTA ID Format. It implements all of + the six standard ID types. It was originally created for the Jave 2 SE + reference implementation. The 'uuid' format uses randomly generated UUIDs + as the mechanism for generating canonical values for the ids it provides. + + @see JXTA Protocols Specification : IDs + @see JXTA Protocols Specification +: UUID ID Format + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/BinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/BinaryID.java new file mode 100644 index 000000000..fd45a2f14 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/BinaryID.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.Serializable; + + +/** + * A BinaryID is a 256-byte, identifier. + * This class should be immutable so that it is thread safe. + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + */ + +public class BinaryID implements Serializable { + + private final static transient Logger LOG = Logger.getLogger(BinaryID.class.getName()); + public static String UUIDEncoded = "uuid"; + public final static int flagsSize = 1; + + public final static byte flagPeerGroupID = 'a'; + public final static byte flagPeerID = 'b'; + public final static byte flagPipeID = 'c'; + + public final static byte flagModuleClassID = 'd'; + public final static byte flagModuleClassRoleID = 'e'; + + public final static byte flagModuleSpecID = 'f'; + public final static byte flagCodatID = 'g'; + public final static byte flagGenericID = 'z'; + + /** + * location of the byte designating its type. + */ + public final static int flagsOffset = 0; + + /** + * location of the byte where the data starts. + */ + public final static int dataOffset = 1; + + /** + * Null id contents. + */ + private static final byte[] nullID = { 0}; + public static final BinaryID nullBinaryID = new BinaryID(flagGenericID, nullID, true); + + /** + * Array that holds the length and the value of the id in base64 format. This is the default format + * rather than binary byte because it saves time converting. Odds of returning the actual binary are + * low so it is done on demand only. Callers of the toByteArray() method should consider the cost of + * decoding if it is to be called often. + */ + protected String encodedValue = null; + + /** + * Creates a null value ID. + */ + public BinaryID() { + this.encodedValue = nullBinaryID.encodedValue; // (flagGenericID, nullID, true); + } + + /** + * Creates zero content ID of a specific type. + */ + public BinaryID(byte id) { + this(id, nullID, true); + } + + /** + * Creates a ID from a string. Note that the ID is not currently validated. + * + * @param encodedValue Value to convert ID. + */ + protected BinaryID(String encodedValue) { + this.encodedValue = encodedValue; + } + + /** + * Simple constructor that takes a binary array to signify the contents of the array. + * + * @param type The Type of ID. Valid values: flagPeerGroupID,flagPeerID,flagPipeID,flagGenericID + * @param data the array of up to 256 bytes. Max is 256 if lengthIncluded is true or 255 if the first byte is the length-1. + * @param lengthIncluded Boolean that signifies if the first byte is the length of the bytes to follow. + * @throws RuntimeException Runtime exception trhown if array is not correct or if included, the array length does not match actual size. + */ + + public BinaryID(byte type, byte data[], boolean lengthIncluded) { + if (lengthIncluded && data.length < 256 && data.length > 1) { + if (data[0] == data.length - 1) { + try { + java.io.StringWriter base64 = new java.io.StringWriter(); + net.jxta.impl.util.BASE64OutputStream encoder = new net.jxta.impl.util.BASE64OutputStream(base64); + + encoder.write(data); + encoder.close(); + + encodedValue = ((char) type) + base64.toString(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Unable to encode binary value.", e); + throw new RuntimeException("Unable to encode binary value."); + } + } else { + throw new RuntimeException( + "Length of data section is " + (data.length - 1) + " but byte zero says length is:" + data[0] + "."); + } + } else if (!lengthIncluded && data.length > 0) { + byte temp[] = new byte[data.length + 1]; + + temp[0] = (byte) data.length; + System.arraycopy(data, 0, temp, 1, data.length); + try { + java.io.StringWriter base64 = new java.io.StringWriter(); + net.jxta.impl.util.BASE64OutputStream encoder = new net.jxta.impl.util.BASE64OutputStream(base64); + + encoder.write(temp); + encoder.close(); + + encodedValue = ((char) type) + base64.toString(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Unable to encode binary value.", e); + throw new RuntimeException("Unable to encode binary value."); + } + } else if (lengthIncluded && (data.length > 256 || data.length == 0)) { + throw new RuntimeException("Length of 'data' is " + data.length + " must be >0 and less or equal to 256."); + } else if (!lengthIncluded && data.length > 255) { + throw new RuntimeException("Length of 'data' is " + data.length + " must be less than 256. "); + } + } + + /** + * Returns the value of the ID as a binary array. This is always decoded from the base64 + * string rather than caching of the binary array. Callers of the toByteArray() method + * should consider the cost of decoding if the method is called often. + * + * @return returns the data part of the array. + */ + public byte[] toByteArray() { + try { + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); + net.jxta.impl.util.BASE64InputStream decoder = new net.jxta.impl.util.BASE64InputStream( + new java.io.StringReader(encodedValue.substring(1))); + + while (true) { + int c = decoder.read(); + + if (-1 == c) { + break; + } + + bos.write(c); + } + + return bos.toByteArray(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Unable to decode binary value.", e); + throw new RuntimeException("Unable to encode binary value."); + } + + } + + /** + * Returns the value of the ID as a binary array without the size in byte zero. This is always decoded from the base64 + * string rather than caching of the binary array. Callers of the toByteArray() method + * should consider the cost of decoding if the method is called often.

            + *

            + * Note that we assume the array size-1 equals the contents of byte zero. + * + * @return returns the array with the first byte as the length of the remaining bytes. + */ + public byte[] toSizeIncludedByteArray() { + byte[] data = toByteArray(); + + byte temp[] = new byte[data.length - 1]; + + System.arraycopy(data, 1, temp, 0, temp.length); + + return temp; + } + + /** + * @return The ID which consists of a character designating type, followed by the base64 encoded value of the size and array of bytes. + */ + public String encodedValue() { + return encodedValue; + } + + /** + * Returns the hash code of the BinaryID

            + *

            + * WARNING: Do not use this hash as a network ID. Use a stronger digest hash like SHA-1 to get the hash of the contents. + * + * @return int hashcode + */ + + @Override + public int hashCode() { + return encodedValue.hashCode(); + } + + /** + * Compares two BinaryIDs for equality.

            + * true: taget == this

            + * false: target == null

            + * true: taget.encodedValue == this.encodedValue

            + * true: target instance of ID && ID==ID.nullID && nullBinaryID.encodedValue().equals( encodedValue())

            + * false: all other posibilities

            + * + * @param target the BidaryID to be compared against. + * @return boolean true if IDs are equal, false otherwise. + */ + @Override + public boolean equals(Object target) { + boolean result = false; + + if (target == this) { + result = true; + } else if (target == null) { + result = false; + } else if (target instanceof BinaryID) { + result = encodedValue().equals(((BinaryID) target).encodedValue()); + LOG.fine("((BinaryID)target).encodedValue():" + ((BinaryID) target).encodedValue()); + } else if (target instanceof net.jxta.id.ID && ((net.jxta.id.ID) target) == net.jxta.id.ID.nullID + && nullBinaryID.encodedValue().equals(encodedValue())) { + result = true; + } + // LOG.error("this:"+encodedValue()+" type:"+target.getClass().getName()+" target:"+target+" equals:"+result,new RuntimeException("test exception")); + return result; + } + + /** + * Return the type of ID. + * + * @return byte value designating type. + */ + + public byte type() { + return (byte) encodedValue.charAt(0); + } + + /** + * Returns base 64 encoded value. + * + * @return String return value + */ + + @Override + public String toString() { + return encodedValue; + } + + /** + * returns the raw encoded value. Not cloned because it is a string. + */ + public String getID() { + return encodedValue; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/BinaryIDFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/BinaryIDFactory.java new file mode 100644 index 000000000..f1266d38b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/BinaryIDFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +/** + * A BinaryIDFactory generates a BinaryID id. BinaryIDs are used to uniquely + * identify objects such as peers, peer groups and pipes. + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.id.ID + */ + +public class BinaryIDFactory { + + /** + * Returns a new BinaryID value. + * + * @return BinaryID returns a BinaryID. + */ + + public static BinaryID newBinaryID(byte type, byte data[], boolean lengthIncluded) { + return new BinaryID(type, data, lengthIncluded); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/CodatBinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/CodatBinaryID.java new file mode 100644 index 000000000..a06006720 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/CodatBinaryID.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.id.binaryID; + + +import net.jxta.peergroup.PeerGroupID; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.InputStream; +import java.net.URI; +import net.jxta.id.ID; + + +/** + * This class implements a Pipe ID. Each pipe is assigned a unique id. + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.peergroup.PeerGroupID + */ +public final class CodatBinaryID extends net.jxta.codat.CodatID { + + /** + * LOG object for this class. + */ + private final static transient Logger LOG = Logger.getLogger(CodatBinaryID.class.getName()); + + /** + * The id data + */ + protected String id; + + /** + * Used only internally + */ + protected CodatBinaryID() { + super(); + } + + /** + * Creates a ID from a string. Note that the ID is not currently validated. + * + * @param id Value of ID. + */ + + public CodatBinaryID(String id) { + super(); + this.id = id; + + } + + /** + * Constructor. Intializes contents from provided ID. + * + * @param id the ID data + */ + public CodatBinaryID(BinaryID id) { + super(); + this.id = id.getID(); + } + + /** + * Constructor. Creates a PipeID. A PeerGroupID is provided. Note that only + * the peer group's primary node is used to build this node. We don't want + * to be appending great grand parents. + * + * @param parent the group to which this will belong. + * @param data DOCUMENT ME! + * @param lengthIncluded DOCUMENT ME! + */ + public CodatBinaryID(net.jxta.peergroup.PeerGroupID parent, byte[] data, boolean lengthIncluded) { + this(); + + String parentStr = IDFormat.childGroup(parent); + + id = BinaryIDFactory.newBinaryID(BinaryID.flagPipeID, data, lengthIncluded).getID() + "." + parentStr.replace('-', '.'); + } + + public CodatBinaryID(PeerGroupID groupID, InputStream in) { + // this( groupID ); + net.jxta.id.IDFactory.newCodatID(groupID); + // setHash( in ); + } + + public CodatBinaryID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed, InputStream in) { + this(groupID, seed, false); + + // setHash( in ); + } + + /* + private void setHash( InputStream in ) throws IOException { + MessageDigest dig = null; + try { + dig = MessageDigest.getInstance( "SHA" ); + } catch( NoSuchAlgorithmException caught ) { + dig = null; + } + + if (dig == null) { + throw new ProviderException("SHA1 digest algorithm found"); + } + + dig.reset(); + + do { + int nextByte = in.read(); + if( nextByte == -1 ) + break; + + dig.update( (byte) nextByte); + } + while( true ); + + in.close(); + + try { + byte [] result = dig.digest( ); + for( int eachByte = 0; eachByte < CodatID.hashSize; eachByte++ ) + id.bytes[eachByte + CodatID.codatHashOffset] = result[eachByte]; + } catch( Throwable e ) { + // we convert this to an IO Exception to keep the number of + // down. + throw new IOException( "Digest algorithm could not complete : " + e.getMessage() ); + } + } + */ + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + return target instanceof CodatBinaryID && getUniqueValue().equals(((CodatBinaryID) target).getUniqueValue()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + if (null == id) { + return ID.nullID.getUniqueValue(); + } + + return getIDFormat() + "-" + id; + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + try { + if (id == null) { + return net.jxta.id.ID.nullID; + } + String idd = id; + int parentStart = idd.indexOf('.'); + + if (parentStart != -1) { + idd = idd.substring(parentStart + 1); + } else { + return null; + } + + URI url = new URI("urn:jxta:" + idd.replace('.', '-')); + net.jxta.peergroup.PeerGroupID peerGroupID = (net.jxta.peergroup.PeerGroupID) net.jxta.id.IDFactory.fromURI(url); + + return peerGroupID; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("cannot convert sub group. ID value = " + id); + } + return null; + + } + } + + /** + * returns the coded ID without the binaryid tag. + * + * @return Returns the raw string used to create the urn! + */ + protected String getID() { + return id; + } + + /** + * {@inheritDoc} + * Binary ID only supports static + */ + @Override + public boolean isStatic() { + return true; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/DigestTool.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/DigestTool.java new file mode 100644 index 000000000..101def961 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/DigestTool.java @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.security.MessageDigest; + + +/** + * This is a utility class used to create pipe advertisement named and BinaryID for the pipeID to create + * a private address space that can be hosted in the public discovery system or sent over unencrypted + * channeds without revealing their intent or purpose.

            + *

            + * We use a one-way hashing algorythum to create an ID from private information like + * a user's social security number or a user's email address. + * We search for the pipe by with this private information securly by creating the + * matching hash using the same methods.

            + *

            + * The purpose of this system is to create a way to search + * for a pipe (or other BinaryID based system) without exposing the + * pipe owner's clearTextID while allowing for people that + * know what they are looking for to find the right pipe. The + * system also has the ability to create pipes that have a specific purpose. + * For example, the email address is appended with a function name. Say you + * have a pipe for messages and one for administrative purposes. You would + * supply the email and a string for the function. The same combination can be + * created by another peer to search for either of these pipes.

            + *

            + * This implementation uses the "SHA-1" algorythum. This was selected for relitive + * speed. It is used as a one-way conversion that cannot be reversed engineered to + * create the original string. This allows you to publish the hash without the + * possibility of the contents being decoded. This allows for public indexing of + * data that is only known by the parties involved.

            + *

            + * Note that this can also be used to generate safe password verification hash codes. + * Sample useage: + * + * String clearTextID = "turbogeek@cluck.com"; + * String function = "eventPipe"; + * System.out.println("clear text ID: "+clearTextID); + * System.out.println("function text: "+function); + * String digest1 = DigestID.generateHashString(clearTextID, function); + * String digest2 = DigestID.generateHashString(clearTextID); + * System.out.println("Digest1: '"+digest1+"'"); + * System.out.println("Digest2: '"+digest2+"'"); + * System.out.println("test1: "+DigestID.test(clearTextID, function,digest1)); + * System.out.println("test2: "+DigestID.test(clearTextID, digest2)); + * System.out.println("Digest1 != Digest2: "+DigestID.test(clearTextID, function,digest2)); + *

            + *

            + * To use an algorythum other than SHA-1, you will need stronger encyption. + * The BouncyCastle that comes with JXTA is just a minimum implimentation so + * a good choice is the normal bouncy castle (it is much larger, nearing a meg, + * which is why it is not a part of the normal JXTA distribution. The full version + * of bouncy includes SHA-128, SHA-256, SHA-384, and SHA-512.

            + *

            + * Here is how you create a provider from the full version of Bouncy. Once you do this, you can access the extended + * Digest ecryption levels. + * + * provider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); + * System.out.println("provider:"+provider.getName()); + * Security.addProvider(provider); + *

            + * Security Note

            + *

            + * This class should have all of its fields and properties marked as 'final' to prevent overriding the default behavior. + * Failure to do so could allow a less scrupulous person to cause the BinaryID or hash codes to contain the original information. + * Note that the class itself is not final to allow for additional convienience methods to be added. There + * a no methods for creating ModuleClassBinaryID, ModuleSpecBinaryID, or CodatID because this is meant for general' + * use, not for extending platform (you can write your own using similar code).

            + * + * @author Daniel Brookshier turbogeek@cluck.com + * @version $Revision$ + */ +public class DigestTool { + private final static transient Logger LOG = Logger.getLogger(DigestTool.class.getName()); + + /** + * varaible used for conditional compile of debug printing. + */ + public static final boolean debug = true; + + /** + * Defualt SHA-1 digest algorithm type. This is a 20 byte hash function (note: that MD5 is only 16 so we don't use it). + */ + public static final String SHAOne = "SHA-1"; + + /** + * SHA-128 digest algorithm type. This is a 128 bit hash function (note: must have another provider registered to use). + */ + public static final String SHA128 = "SHA-128"; + + /** + * SHA-256 digest algorithm type. This is a 256 bit hash function (note: must have another provider registered to use). + */ + public static final String SHA256 = "SHA-256"; + + /** + * SHA-384 digest algorithm type. This is a 384 bit hash function (note: must have another provider registered to use). + */ + public static final String SHA384 = "SHA-384"; + + /** + * SHA-512 digest algorithm type. This is a 512 bit hash function (note: must have another provider registered to use). + */ + public static final String SHA512 = "SHA-512"; + + /** + * Tilde character used to seperate candidate strings from a function. + */ + public final String functionSeperator = "~"; + String algorithmType; + + public DigestTool() { + algorithmType = SHAOne; + } + + public DigestTool(String algorithmType) { + this.algorithmType = algorithmType; + } + + /** + * Create a PipeID based on the BinaryID type with a digest of the clearTextID and function. + * + * @param peerGroupID Parent peer group ID. + * @param clearTextID String used as the significant part of the address + * @param function String used to diferentiate different clearTextID addresses (can be null). + * @return PipeBinaryID with the digest hash of the string: clearTextID+"~"+function. + */ + public final PipeBinaryID createPipeID(net.jxta.peergroup.PeerGroupID peerGroupID, String clearTextID, String function) { + byte[] digest = generateHash(clearTextID, function); + PipeBinaryID pipe = new PipeBinaryID(peerGroupID, digest, false); + + return pipe; + } + + /** + * Create a PeerGroupID based on the BinaryID type with a digest of the clearTextID and function. + * + * @param parentPeerGroupID Parent peer group ID. + * @param clearTextID String used as the significant part of the address + * @param function String used to diferentiate different clearTextID addresses (can be null). + * @return PeerGroupBinaryID with the digest hash of the string: clearTextID+"~"+function. + */ + public final PeerGroupBinaryID createPeerGroupID(net.jxta.peergroup.PeerGroupID parentPeerGroupID, String clearTextID, String function) { + byte[] digest = generateHash(clearTextID, function); + PeerGroupBinaryID peerGroupID = new PeerGroupBinaryID(parentPeerGroupID, digest, false); + + return peerGroupID; + } + + /** + * Create a PeerID based on the BinaryID type with a digest of the clearTextID and function. + * + * @param peerGroupID Parent peer group ID. + * @param clearTextID String used as the significant part of the address + * @param function String used to diferentiate different clearTextID addresses (can be null). + * @return PeerBinaryID with the digest hash of the string: clearTextID+"~"+function. + */ + public final PeerBinaryID createPeerID(net.jxta.peergroup.PeerGroupID peerGroupID, String clearTextID, String function) { + byte[] digest = generateHash(clearTextID, function); + PeerBinaryID peerID = new PeerBinaryID(peerGroupID, digest, false); + + return peerID; + } + + /** + * Creates a new instance of DigestPipe. Because this is a utility, + * this is private to prevent construction. + */ + + /** + * Generates a Base64 encoded string of an SHA-1 digest hash of the string: clearTextID.

            + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @return Base64 encoded string containing the hash of the string: clearTextID. + */ + public final String generateHashString(String clearTextID) { + try { + java.io.StringWriter base64 = new java.io.StringWriter(); + net.jxta.impl.util.BASE64OutputStream encode = new net.jxta.impl.util.BASE64OutputStream(base64); + + encode.write(generateHash(clearTextID)); + encode.close(); + + return base64.toString(); + } catch (Exception failed) { + LOG.log(Level.SEVERE, "Unable to encode hash value.", failed); + throw new RuntimeException("Unable to encode hash value."); + } + } + + /** + * Generates a Base64 encoded string of an SHA-1 digest hash of the string: clearTextID+"-"+function or: clearTextID if function was blank.

            + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @param function A function related to the clearTextID string. This is used to create a hash associated with clearTextID so that it is a uique code. + * @return Base64 encoded string containing the hash of the string: clearTextID+"-"+function or clearTextID if function was blank. + */ + public final String generateHashString(String clearTextID, String function) { + try { + java.io.StringWriter base64 = new java.io.StringWriter(); + net.jxta.impl.util.BASE64OutputStream encode = new net.jxta.impl.util.BASE64OutputStream(base64); + + encode.write(generateHash(clearTextID, function)); + encode.close(); + + return base64.toString(); + } catch (Exception failed) { + LOG.log(Level.SEVERE, "Unable to encode hash value.", failed); + throw new RuntimeException("Unable to encode hash value."); + } + } + + /** + * Generates a SHA-1 digest hash of the string: clearTextID.

            + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @return String containing the hash of the string: clearTextID. + */ + public final byte[] generateHash(String clearTextID) { + return generateHash(clearTextID, null); + } + + /** + * Generates an SHA-1 digest hash of the string: clearTextID+"-"+function or: clearTextID if function was blank.

            + *

            + * Note that the SHA-1 used only creates a 20 byte hash.

            + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @param function A function related to the clearTextID string. This is used to create a hash associated with clearTextID so that it is a uique code. + * @return array of bytes containing the hash of the string: clearTextID+"-"+function or clearTextID if function was blank. Can return null if SHA-1 does not exist on platform. + */ + public final byte[] generateHash(String clearTextID, String function) { + String id; + + if (function == null) { + id = clearTextID; + } else { + id = clearTextID + functionSeperator + function; + } + byte[] buffer = id.getBytes(); + + MessageDigest algorithm; + + try { + algorithm = MessageDigest.getInstance(algorithmType); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Cannot load selected Digest Hash implementation", e); + return null; + } + + // Generate the digest. + algorithm.reset(); + algorithm.update(buffer); + + try { + byte[] digest1 = algorithm.digest(); + + return digest1; + } catch (Exception de) { + LOG.log(Level.SEVERE, "Failed to creat a digest.", de); + return null; + } + } + + /** + * Generates an SHA-1 digest hash of the string: clearTextID.

            + * + * @param function the function + * @param testHash test hash + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @return String containing the hash of the string: clearTextID. + */ + public final boolean test(String clearTextID, String function, String testHash) { + String id = clearTextID + functionSeperator + function; + + return test(id, testHash); + + } + + /** + * Compares a clear text code or ID with a candidate hash code. + * This is used to confirm that the clearTextID can be successfully converted to the hash. + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @param testHash A string of hashed string. + * @return true if the hash created from clearTextID is equal to the testHash string.Can return false if SHA-1 does not exist on platform. + */ + public final boolean test(String clearTextID, String testHash) { + + byte[] digest1 = generateHash(clearTextID); + byte[] digest2; + + try { + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); + net.jxta.impl.util.BASE64InputStream decoder = new net.jxta.impl.util.BASE64InputStream( + new java.io.StringReader(testHash)); + + while (true) { + int c = decoder.read(); + + if (-1 == c) { + break; + } + + bos.write(c); + } + + digest2 = bos.toByteArray(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Failed to create a digest.", e); + return false; + } + + if (digest1.length != digest2.length) { + // Not a match! because of length. + return false; + } + + for (int i = 0; i < digest1.length; i++) { + if (digest1[i] != digest2[i]) { + // Not a match because of byte:"+i+" did not match + return false; + } + } + + // Match was ok + return true; + } + + /** + * Compares a clear text code or ID with a candidate hash code. + * This is used to confirm that the clearTextID can be successfully converted to the hash. + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @param testHash A string of hashed string. + * @return true if the hash created from clearTextID is equal to the testHash string.Can return false if SHA-1 does not exist on platform. + */ + public final boolean test(String clearTextID, byte[] testHash) { + + byte[] digest1 = generateHash(clearTextID); + + if (digest1.length != testHash.length) { + // Not a match! because of length. + return false; + } + + for (int i = 0; i < testHash.length; i++) { + if (digest1[i] != testHash[i]) { + // Not a match because of byte:"+i+" did not match + return false; + } + } + + // Match was ok + return true; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/IDFormat.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/IDFormat.java new file mode 100644 index 000000000..480115dab --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/IDFormat.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +import java.util.logging.Logger; + + +/** + * The 'BinaryID' format is a general purpose JXTA ID Format. It implements all of + * the six standard ID types. It was originally created for the Java 2 SE + * reference implementation. The 'BinaryID' format uses randomly generated BinaryIDs + * as the mechanism for generating canonical values for the ids it provides. + * + * @author Daniel Brookshier turbogeek@cluck.com + */ +public class IDFormat { + + /** + * LOG4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(IDFormat.class.getName()); + + /** + * This table maps our local private versions of the well known ids to the + * globally known version. + */ + + final static Object[][] wellKnownIDs = { + { net.jxta.peergroup.PeerGroupID.worldPeerGroupID, net.jxta.impl.id.UUID.IDFormat.worldPeerGroupID} + , + { net.jxta.peergroup.PeerGroupID.defaultNetPeerGroupID, net.jxta.impl.id.UUID.IDFormat.defaultNetPeerGroupID} + }; + + /** + * The instantiator for this ID Format which is used by the IDFactory. + */ + public static final net.jxta.impl.id.binaryID.Instantiator INSTANTIATOR = new net.jxta.impl.id.binaryID.Instantiator(); + + /** + * Private Constructor. This class cannot be instantiated. + */ + private IDFormat() {} + + /** + * Translate from well known ID to our locally encoded versions. + * + * @param input the id to be translated. + * @return the translated ID or the input ID if no translation was needed. + */ + + static net.jxta.id.ID translateFromWellKnown(net.jxta.id.ID input) { + for (int eachWellKnown = 0; eachWellKnown < wellKnownIDs.length; eachWellKnown++) { + net.jxta.id.ID aWellKnown = (net.jxta.id.ID) wellKnownIDs[eachWellKnown][0]; + + if (aWellKnown.equals(input)) { + return (net.jxta.id.ID) wellKnownIDs[eachWellKnown][1]; + } + } + + return input; + } + + /** + * Translate from locally encoded versions to the well known versions. + * + * @param input the id to be translated. + * @return the translated ID or the input ID if no translation was needed. + */ + + static net.jxta.id.ID translateToWellKnown(net.jxta.id.ID input) { + for (int eachWellKnown = 0; eachWellKnown < wellKnownIDs.length; eachWellKnown++) { + net.jxta.id.ID aLocalEncoding = (net.jxta.id.ID) wellKnownIDs[eachWellKnown][1]; + + if (aLocalEncoding.equals(input)) { + return (net.jxta.id.ID) wellKnownIDs[eachWellKnown][0]; + } + } + + return input; + } + + /** + * Utility method used to strip only the most significant peer group ID. + * This prevents us from continiously appending grandparents to each child. + *

            + *

            + * This method is used in PipeID and PeerID. + *

            + * + * @param peerGroupID Peer group ID to pull the child from. + * @return Child of the peer group. + */ + public static String childGroup(net.jxta.peergroup.PeerGroupID peerGroupID) { + String parentStr = (String) peerGroupID.getUniqueValue(); + // Child is the first ID + int first = parentStr.indexOf('.'); + String child = null; + + if (first != -1) { + child = parentStr.substring(0, first); + + } else { + child = parentStr; + } + return child; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/Instantiator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/Instantiator.java new file mode 100644 index 000000000..f49346740 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/Instantiator.java @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.security.SecureRandom; +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.UnknownServiceException; + +import net.jxta.peergroup.PeerGroupID; + + +/** + * ID Factory for the binary ID type. All identifiers in this type are prefixed by "binaryid". + * + * @author Daniel Brookshier turbogeek@cluck.com + */ + +public final class Instantiator implements net.jxta.id.IDFactory.URIInstantiator { + + /** + * LOG object for this class. + */ + private final static transient Logger LOG = Logger.getLogger(Instantiator.class.getName()); + + /** + * Our ID Format + */ + final static String BinaryIDEncoded = "binaryid"; + + /** + * Random generator used for ID creation where a seed (idValue) is not provided. + */ + private static final Random randNumGenerator = new SecureRandom(); + + /** + * {@inheritDoc} + */ + public String getSupportedIDFormat() { + return BinaryIDEncoded; + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURL(URL source) throws MalformedURLException, UnknownServiceException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getProtocol())) { + throw new UnknownServiceException("URI protocol type was not as expected."); + } + + String encoded = source.getFile(); + + int colonAt = encoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new UnknownServiceException("URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(encoded.substring(0, colonAt))) { + throw new UnknownServiceException("URN namespace was not as expected."); + } + + // skip the namespace portion and the colon + encoded = encoded.substring(colonAt + 1); + + try { + return fromURNNamespaceSpecificPart(encoded); + } catch (URISyntaxException failed) { + MalformedURLException failure = new MalformedURLException("Failure parsing URL"); + + failure.initCause(failed); + + throw failure; + } + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURI(URI source) throws URISyntaxException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getScheme())) { + throw new URISyntaxException(source.toString(), "URI scheme was not as expected."); + } + + String decoded = source.getSchemeSpecificPart(); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new URISyntaxException(source.toString(), "URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new URISyntaxException(source.toString() + , + "URN namespace was not as expected. (" + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + return fromURNNamespaceSpecificPart(decoded); + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID fromURNNamespaceSpecificPart(String encoded) throws URISyntaxException { + int dashAt = encoded.indexOf('-'); + + // there's a dash, right? + if (-1 == dashAt) { + throw new URISyntaxException(encoded, "URN Encodingtype was missing."); + } + + if (!encoded.substring(0, dashAt).equals(BinaryIDEncoded)) { + throw new URISyntaxException(encoded + , + "JXTA id format was not as expected. Should have been BinaryIDEncoded found:" + encoded.substring(0, dashAt)); + } + + // skip the dash + encoded = encoded.substring(dashAt + 1); + // check that the length is long enough + if (encoded.length() < 1) { + throw new URISyntaxException(encoded, "URN does not contain enough chars. Must have at least one byte"); + } + BinaryID id = new BinaryID(encoded); + net.jxta.id.ID result = null; + + switch (id.type()) { + + case BinaryID.flagCodatID: + result = new CodatBinaryID(encoded); + break; + + case BinaryID.flagPeerGroupID: + result = new PeerGroupBinaryID(encoded); + if (PeerGroupID.worldPeerGroupID.equals(result)) { + result = net.jxta.peergroup.PeerGroupID.worldPeerGroupID; + } + break; + + case BinaryID.flagPeerID: + result = new PeerBinaryID(encoded); + break; + + case BinaryID.flagPipeID: + result = new PipeBinaryID(encoded); + break; + + case BinaryID.flagModuleClassID: + result = new ModuleClassBinaryID(encoded); + break; + + case BinaryID.flagModuleSpecID: + result = new ModuleSpecBinaryID(encoded); + break; + + default: + throw new URISyntaxException(encoded, "jxta ID type not recognized"); + } + + return result; + } + + /** + * Utility to create a random array of bits to be used when a random value is required. + */ + private byte[] randomID() { + byte[] randBuf16 = new byte[16]; + + randNumGenerator.nextBytes(randBuf16); + + return randBuf16; + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported. Use CODAT from UUID package instead. + */ + public net.jxta.codat.CodatID newCodatID(final net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new net.jxta.impl.id.binaryID.CodatBinaryID(parentGroupID, randomID(), false); + // throw new UnsupportedOperationException("This form is not supported. Use CODAT from UUID package instead."); + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported. Use CODAT from UUID package instead. + */ + public net.jxta.codat.CodatID newCodatID(final net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new net.jxta.impl.id.binaryID.CodatBinaryID(parentGroupID, seed, false); + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported. Use CODAT from UUID package instead. + */ + public net.jxta.codat.CodatID newCodatID(final net.jxta.peergroup.PeerGroupID groupID, InputStream in) throws IOException { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new net.jxta.impl.id.binaryID.CodatBinaryID(parentGroupID, randomID(), false); + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported. Use CODAT from UUID package instead. + */ + public net.jxta.codat.CodatID newCodatID(final net.jxta.peergroup.PeerGroupID groupID, byte[] idValue, InputStream in) throws IOException { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new net.jxta.impl.id.binaryID.CodatBinaryID(parentGroupID, idValue, false); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peer.PeerID newPeerID(final net.jxta.peergroup.PeerGroupID groupID) { + LOG.log(Level.SEVERE, "random peer created", new RuntimeException()); + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new net.jxta.impl.id.binaryID.PeerBinaryID(parentGroupID, randomID(), false); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peer.PeerID newPeerID(final net.jxta.peergroup.PeerGroupID groupID, byte[] idValue) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new net.jxta.impl.id.binaryID.PeerBinaryID(parentGroupID, idValue, false); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID() { + return net.jxta.id.IDFactory.newPeerGroupID(randomID()); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(byte[] idValue) { + return new PeerGroupBinaryID(idValue, false); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent) { + LOG.log(Level.SEVERE, "random peergroup created", new RuntimeException()); + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(parent); + + return net.jxta.id.IDFactory.newPeerGroupID(parentGroupID, randomID()); + } + + /** + * {@inheritDoc} + */ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent, byte[] idValue) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(parent); + + return new PeerGroupBinaryID(parentGroupID, idValue, false); + } + + /** + * {@inheritDoc} + */ + public net.jxta.pipe.PipeID newPipeID(final net.jxta.peergroup.PeerGroupID groupID) { + PeerGroupID parentGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return net.jxta.id.IDFactory.newPipeID(parentGroupID, randomID()); + } + + /** + * {@inheritDoc} + */ + public net.jxta.pipe.PipeID newPipeID(final net.jxta.peergroup.PeerGroupID groupID, byte[] idValue) { + PeerGroupID peerGroupID = (PeerGroupID) IDFormat.translateFromWellKnown(groupID); + + return new PipeBinaryID(peerGroupID, idValue, false); + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported because a binary ID is meant to be created with a random ID. + */ + public net.jxta.platform.ModuleClassID newModuleClassID() { + throw new UnsupportedOperationException( + "This form is not supported because a binary ID is meant to be created with a random ID. Use UUID package instead."); + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported because a binary ID is meant to be created with a random ID. + */ + public net.jxta.platform.ModuleClassID newModuleClassID(final net.jxta.platform.ModuleClassID classID) { + throw new UnsupportedOperationException( + "This form is not supported because a binary ID is meant to be created with a random ID. Use UUID package instead."); + } + + /** + * {@inheritDoc} + * + * @throws UnsupportedOperationException This form is not supported because a binary ID is meant to be created with a random ID. Use UUID instead. + */ + public net.jxta.platform.ModuleSpecID newModuleSpecID(final net.jxta.platform.ModuleClassID classID) { + throw new UnsupportedOperationException( + "This form is not supported because a binary ID is meant to be created with a random ID. Use UUID package instead."); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/ModuleClassBinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/ModuleClassBinaryID.java new file mode 100644 index 000000000..596e83d2f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/ModuleClassBinaryID.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +import net.jxta.peergroup.PeerGroupID; +import java.util.logging.Logger; +import net.jxta.id.ID; + + +/** + * This interface defines a Module Class Identifier. + * A ModuleClassID uniquely identifies a particular local behaviour, that is, + * a specific API for each execution environment for which an implementation + * exists. + *

            + *

            + * A ModuleClassID has two components: A base class identifier, and a role identifier. + * The role identifier may be zero. By convention the API uses the ModuleClassID with + * a zero role identifier to designate the base class in contexts where only the base class + * is significant. Nonetheless, a ModuleClassID with a zero role identifier is a valid + * ModulesClassID wherever a full ModuleClassID is expected. In many cases, only one role + * in a given class is ever used. Using role zero in such cases is an optimization because + * it may make the string representation of the ModuleClassID shorter. + *

            + *

            + * Each service of a group, that is, the role it plays in the group, is uniquely identified + * per the group definition. + * This identifier may be used by other modules in the group to designate this one, or by the service + * itself to identify its parameters in a PeerAdvertisement. In addition, by combining its + * PeerGroupID with its own ModuleClassID, a service may create a predictible identifier unique + * on their peer, suitable for registering listeners with the EndpointService or other services + * with similar listener interfaces. + *

            + *

            + * The standard PeerGroup implementation of the java reference implementation + * assigns to each service its ModuleClassID as its unique service identifier. Most of the + * times this ModuleClassID is a base classID, but groups that use the same Module Class + * for more than one service (same behaviour but playing a different role in the group, such + * as, for example, a data base engine with a different data base), may define multiple roles + * identified by the same base class identifier but different role identifiers. The standard + * PeerGroup implementation of the java reference implementation has the notion of main + * application: a default application which may be started automatically upon instantiating + * the group. This application implements Module and, therefore, is assigned a ModuleClassID. + * However applications are not expected to play any specific role in the group. As a result, they + * are assigned a role identifier allocated at run-time as need to garantee local unicity. As + * a result main applications cannot expect a predictible ClassID. + *

            + *

            + * A ModuleClassID is optionaly described by a published ModuleClassAdvertisement. + *

            + *

            + * There may be any number of embodiements of a module class. These are module + * specifications. A module specification represent the network behaviour of a + * module while its class represents its local behaviour. Different groups + * may use a common subset of classes, for example, the basic set defined by the platform + * should always be part of it. Each group may use different and network-incompatible + * specifications for common classes, optimized for various purposes. The local API of a + * given class on a given JXTA implementation will be invariant per the spec being used. + * Therefore, the difference will be transparent to applications which do not depend + * on the possibly different quality of service. + *

            + *

            + * A ModuleSpecID embeds a base class identifier, which permits to verify that + * a given Module specification is suitable for its intended use. + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.platform.Module + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.protocol.PeerAdvertisement + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see net.jxta.protocol.ModuleClassAdvertisement + * @see net.jxta.endpoint.EndpointService + * @see net.jxta.id.ID + */ + +public final class ModuleClassBinaryID extends net.jxta.platform.ModuleClassID { + + /** + * Log4J categorgy + */ + private final static transient Logger LOG = Logger.getLogger(ModuleClassBinaryID.class.getName()); + + /** + * The id data + */ + protected BinaryID classID; + protected BinaryID parentClassID; + protected BinaryID roleID; + protected PeerGroupID peerGroupID; + + /** + * Constructor. + * Intializes contents from provided ID. + * + * @param id the ID data + * @since JXTA 1.0 + */ + protected ModuleClassBinaryID(String id) { + super(); + int start = id.indexOf('-'); + int parent = id.indexOf(start + 1, '-'); + int role = id.indexOf(id.indexOf(parent + 1, '-') + 1, '-'); + int group = id.indexOf(id.indexOf(role + 1, '-') + 1, '-'); + + classID = new BinaryID(id.substring(group + 1, parent)); + parentClassID = new BinaryID(id.substring(parent + 1, role)); + roleID = new BinaryID(id.substring(role + 1, group)); + peerGroupID = new PeerGroupBinaryID(new BinaryID(id.substring(group + 1))); + } + + /** + * Constructor. + * Creates a ModuleClassID in a given class, with a given class unique id. + * A BinaryID of a class and another BinaryID are provided. + * + * @param parentClassID the class to which this will belong. + * @param roleID the unique id of this role in that class. + * @param peerGroupID the peer group ID + * @param classID the class ID + */ + protected ModuleClassBinaryID(BinaryID classID, BinaryID parentClassID, BinaryID roleID, PeerGroupID peerGroupID) { + super(); + this.classID = classID; + this.parentClassID = parentClassID; + this.roleID = roleID; + this.peerGroupID = peerGroupID; + } + + protected ModuleClassBinaryID(BinaryID classID, BinaryID parentClassID, BinaryID roleID, BinaryID peerGroupID) { + super(); + this.classID = classID; + this.parentClassID = parentClassID; + this.roleID = roleID; + this.peerGroupID = new PeerGroupBinaryID(peerGroupID); + } + + /** + * Constructor for creating a new ModuleClassID. A new class BinaryID is + * created. The role ID is left null. This is the only way to create + * a new class without supplying a new BinaryID explicitly. + * To create a new role in an existing class, one must use one of + * the other constructors. + * Note that a null role is just as valid as any other, it just has a + * shorter string representation. So it is not mandatory to create a new + * role in a new class. + * + * @since JXTA 1.0 + */ + public ModuleClassBinaryID() { + this(new BinaryID(BinaryID.flagModuleClassID), new BinaryID(BinaryID.flagModuleClassID) + , + new BinaryID(BinaryID.flagModuleClassRoleID), new BinaryID(BinaryID.flagPeerGroupID)); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (!(target instanceof ModuleClassBinaryID)) { + return false; + } + + ModuleClassBinaryID targetObj = (ModuleClassBinaryID) target; + + return this.classID.equals(targetObj.getClassID()) && this.parentClassID.equals(targetObj.getBaseClass()) + && this.roleID.equals(targetObj.getRoleID()) && this.peerGroupID.equals(targetObj.getPeerGroupID()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + classID.getID() + "-" + parentClassID.getID() + "-" + roleID.getID() + "-" + + peerGroupID.getUniqueValue(); + } + + /** + * Returns the peer group ID + * + * @return the peer group ID + */ + public net.jxta.id.ID getPeerGroupID() { + return peerGroupID; + } + + /** + * returns the coded ID without the binaryid tag. + * + * @return string of the contents + */ + protected String getID() { + return classID.getID() + "*" + parentClassID.getID() + "*" + roleID.getID() + "*" + peerGroupID.getUniqueValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.platform.ModuleClassID getBaseClass() { + return new ModuleClassBinaryID(parentClassID, new BinaryID(), new BinaryID(), new BinaryID()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleClassID classId) { + return getClass().equals(((ModuleClassBinaryID) classId).getClass()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleSpecID specId) { + return getBaseClassID().equals(((ModuleSpecBinaryID) specId).getBaseClassID()); + } + + /** + * get the class' unique id + * + * @return BinaryID module class' unique id + * @since JXTA 1.0 + */ + public BinaryID getClassID() { + return classID; + } + + /** + * get the role unique id + * + * @return Module role unique id. + * @since JXTA 1.0 + */ + public BinaryID getRoleID() { + return roleID; + } + + /** + * Getter for property parentClassID. + * + * @return Value of property parentClassID. + */ + public BinaryID getBaseClassID() { + return parentClassID; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/ModuleSpecBinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/ModuleSpecBinaryID.java new file mode 100644 index 000000000..ca1f2108e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/ModuleSpecBinaryID.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.binaryID; + + +import java.util.logging.Logger; + + +/** + * A ModuleSpecID uniquely identifies a particular network behaviour + * (wire protocol and choregraphy) that may be embodied by a Jxta Module. + * There may be any number of implementations of a given SpecID. All + * such implementations are assumed to be network compatible. + *

            + *

            + * The Specification that corresponds to a given ModuleSpecID may be published + * in a ModuleSpecAdvertisement. This advertisement is uniquely identified by + * the ModuleSpecID that it describes. + *

            + *

            + * The various implementations of a given SpecID may be published in + * ModuleImplAdvertisements. These advertisements are identified by the + * ModuleSpecID that they implement and a compatibility statement. + * ModuleImplAdvertisements baring the same SpecID and compatibility statement + * are theorethicaly interchangeable. However they may be subsequently discriminated + * by a Description element. + *

            + *

            + * A ModuleSpecID embeds a ModuleClassID which uniquely identifies a base Module + * class. A base module class defines a local behaviour and one API per compatible + * JXTA implementation. + *

            + *

            + * A ModuleSpecID therefore uniquely identifies an abstract module, of which an + * implementation compatible with the local JXTA implementation may be located and + * instantiated. + *

            + *

            + * In the standard PeerGroup implementation of the java reference implementation + * the various services are specified as a list of ModuleSpecID, for each of which + * the group locates and loads an implementation as part of the group's + * initialization. + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.peergroup.PeerGroup + * @see net.jxta.platform.Module + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see net.jxta.id.ID + * @see net.jxta.document.Advertisement + */ + +public final class ModuleSpecBinaryID extends net.jxta.platform.ModuleSpecID { + + /** + * Log4J categorgy + */ + private final static transient Logger LOG = Logger.getLogger(ModuleSpecBinaryID.class.getName()); + + protected BinaryID classID; + protected BinaryID baseClassID; + protected BinaryID specID; + + /** + * Constructor. Used only internally. + * + * @since JXTA 1.0 + */ + protected ModuleSpecBinaryID() { + super(); + specID = new BinaryID(BinaryID.flagModuleSpecID); + classID = new BinaryID(BinaryID.flagModuleClassID); + baseClassID = new BinaryID(BinaryID.flagModuleClassID); + } + + ; + + /** + * Constructor. + * Intializes contents from provided ID. + * + * @param id the ID data + * @since JXTA 1.0 + */ + protected ModuleSpecBinaryID(String id) { + super(); + int start = id.indexOf('-'); + int parent = id.indexOf(start + 1, '-'); + int spec = id.indexOf(id.indexOf(parent + 1, '-') + 1, '-'); + + classID = new BinaryID(id.substring(start + 1, parent)); + baseClassID = new BinaryID(id.substring(parent + 1, spec)); + specID = new BinaryID(id.substring(parent + 1)); + } + + /** + * Constructor. + * Creates a ModuleSpecID in a given class, with a given class unique id. + * A BinaryID of a class and another BinaryID are provided. + * + * @param classID the class to which this will belong. + * @param baseClassID the unique id of this spec in that class. + * @param specID the spec ID + */ + protected ModuleSpecBinaryID(BinaryID classID, BinaryID baseClassID, BinaryID specID) { + this.classID = classID; + this.baseClassID = baseClassID; + this.specID = specID; + } + + /* + * Official constructors. No mention of BinaryID. + */ + + /** + * Creates a new ModuleSpecID in a given class. A ModuleClassID is + * provided. A new SpecID in that class is created. + * + * @since JXTA 1.0 + * + * @param classID the class to which this will belong. + */ + + /* + public ModuleSpecID( net.jxta.platform.ModuleClassID moduleClassID ) { + this.classID = moduleClassID.getClassID(); + this.baseClassID = getBaseClassID(); + this.specID = getSpecID(); + } + */ + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (!(target instanceof ModuleSpecBinaryID)) { + return false; + } + + ModuleSpecBinaryID targetObj = (ModuleSpecBinaryID) target; + + return classID.equals(targetObj.getClassID()) && baseClassID.equals(targetObj.getBaseClassID()) + && specID.equals(targetObj.getSpecID()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + return getIDFormat() + "-" + classID + "-" + baseClassID + "_" + specID; + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.platform.ModuleClassID getBaseClass() { + return new ModuleClassBinaryID(baseClassID, new BinaryID(BinaryID.flagModuleClassID) + , + new BinaryID(BinaryID.flagModuleSpecID), new BinaryID(BinaryID.flagModuleSpecID)); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleClassID classId) { + return baseClassID.equals(classId.getBaseClass()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOfSameBaseClass(net.jxta.platform.ModuleSpecID specId) { + return getClassID().equals(((ModuleSpecBinaryID) specId).getClassID()); + } + + /** + * Getter for property classID. + * + * @return Value of property classID. + */ + public net.jxta.impl.id.binaryID.BinaryID getClassID() { + return classID; + } + + /** + * Getter for property baseClassID. + * + * @return Value of property baseClassID. + */ + public net.jxta.impl.id.binaryID.BinaryID getBaseClassID() { + return baseClassID; + } + + /** + * Getter for property specID. + * + * @return Value of property specID. + */ + public net.jxta.impl.id.binaryID.BinaryID getSpecID() { + return specID; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PeerBinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PeerBinaryID.java new file mode 100644 index 000000000..39dcc8c7a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PeerBinaryID.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.id.binaryID; + + +import java.net.URI; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; +import net.jxta.id.ID; + + +/** + * This class implements a PeerID. Each peer is assigned a unique peer id.UUID + * id are used to implement peer id. + * + * @see net.jxta.impl.id.UUID.UUID + * @see net.jxta.impl.id.UUID.UUIDFactory + */ +public final class PeerBinaryID extends net.jxta.peer.PeerID { + + /** + * LOG object form this class + */ + private final static transient Logger LOG = Logger.getLogger(PeerBinaryID.class.getName()); + + /** + * This is the id string used in the XML of the id. The format is TX0..Xn where T is the type and X0 through Xn are the base64 encoded id. + */ + private String id; + + /** + * Constructor. Used only internally. + */ + private PeerBinaryID() { + super(); + } + + /** + * Creates a ID from a string. Note that the ID is not currently validated. + * + * @param id Value of ID. + */ + + protected PeerBinaryID(String id) { + super(); + this.id = id; + + } + + /** + * Creates a new PeerID object. + * + * @param binaryID binary id to build the peerID from. + */ + public PeerBinaryID(BinaryID binaryID) { + id = binaryID.getID(); + } + + /** + * Constructor. Creates a PeerID. A PeerGroupID and BinaryID is provided. If + * the binary ID is not a pipe ID, the construcion will throw a runtime + * exception.

            + *

            + * Note that only the ID for the parent is obtained and not the + * parent and the grandparent. + * + * @param parent the group to which this will belong. + * @param data data byte array to be used as the id. + * @param lengthIncluded If true, the first byte in the data array is the length of the remaining bytes. + */ + public PeerBinaryID(net.jxta.peergroup.PeerGroupID parent, byte[] data, boolean lengthIncluded) { + this(); + + String parentStr = IDFormat.childGroup(parent); + + id = BinaryIDFactory.newBinaryID(BinaryID.flagPeerID, data, lengthIncluded).getID() + "." + parentStr.replace('-', '.'); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + return target instanceof PeerBinaryID && getUniqueValue().equals(((PeerBinaryID) target).getUniqueValue()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + if (null == id) { + return ID.nullID.getUniqueValue(); + } + + return new StringBuilder().append(getIDFormat()).append("-").append(id).toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + try { + if (id == null) { + return net.jxta.id.ID.nullID; + } + String idd = id; + int parentStart = idd.indexOf('.'); + + if (parentStart != -1) { + idd = idd.substring(parentStart + 1); + } else { + return null; + } + + URI url = new URI("urn:jxta:" + idd.replace('.', '-')); + net.jxta.peergroup.PeerGroupID peerGroupID = (net.jxta.peergroup.PeerGroupID) net.jxta.id.IDFactory.fromURI(url); + + return peerGroupID; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("cannot convert sub group. ID value = " + id); + } + return null; + + } + } + + /** + * returns the coded ID without the binaryid tag. + * + * @return The raw ID. + */ + protected String getID() { + return id; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PeerGroupBinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PeerGroupBinaryID.java new file mode 100644 index 000000000..59477bd5a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PeerGroupBinaryID.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.id.binaryID; + + +import java.net.URI; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; +import net.jxta.id.ID; + + +/** + * This class implements a PeerGroup ID. Each peer group is assigned a unique + * peer id.BinaryID id are used to implement peer group id. Because this id is + * built with BinaryID, pulling the parent group requires a little work. The + * parent group is the first id, with the second following, separated by a + * dash '-' character.

            + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.peergroup.PeerGroupID + */ +public final class PeerGroupBinaryID extends net.jxta.peergroup.PeerGroupID { + + /** + * LOG object for this class. + */ + private final static transient Logger LOG = Logger.getLogger(PeerGroupBinaryID.class.getName()); + + /** + * This is the id string used in the XML of the id. The format is TX0..Xn where T is the type and X0 through Xn are the base64 encoded id. + */ + protected String id; + + /** + * Constructor for creating a new PeerGroupID with a unique ID and a parent.

            + *

            + * Note that only the ID for the parent is obtained and not the + * parent and the grandparent. + * + * @param parent Parent peer group. + * @param data data byte array to be used as the id. + * @param lengthIncluded If true, the first byte in the data array is the length of the remaining bytes. + */ + public PeerGroupBinaryID(net.jxta.peergroup.PeerGroupID parent, byte[] data, boolean lengthIncluded) { + this(); + + String parentStr = IDFormat.childGroup(parent); + + if (parentStr != null) { + id = BinaryIDFactory.newBinaryID(BinaryID.flagPeerGroupID, data, lengthIncluded).getID() + "." + + parentStr.replace('-', '.'); + } else { + id = BinaryIDFactory.newBinaryID(BinaryID.flagPeerGroupID, data, lengthIncluded).getID(); + } + } + + /** + * Creates a ID from a string. Note that the ID is not currently validated. + * + * @param id Value of ID. + */ + + protected PeerGroupBinaryID(String id) { + super(); + this.id = id; + } + + /** + * Constructor for creating a new PeerGroupID with a unique ID and a parent. + * + * @param data DOCUMENT ME! + * @param lengthIncluded DOCUMENT ME! + */ + public PeerGroupBinaryID(byte[] data, boolean lengthIncluded) { + this(); + id = BinaryIDFactory.newBinaryID(BinaryID.flagPeerGroupID, data, lengthIncluded).getID(); + } + + /** + * Constructor for creating a new PeerGroupID. Note that this creates an + * invalid ID but is required for serialization. + */ + public PeerGroupBinaryID() { + super(); + } + + /** + * Constructor. Intializes contents from provided ID. This PeerGroupID has + * no parent. + * + * @param id the ID data + */ + public PeerGroupBinaryID(BinaryID id) { + super(); + this.id = id.getID(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + return target instanceof PeerGroupBinaryID && getUniqueValue().equals(((PeerGroupBinaryID) target).getUniqueValue()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + if (null == id) { + return ID.nullID.getUniqueValue(); + } + + return getIDFormat() + "-" + id; + } + + /** + * {@inheritDoc} + */ + public net.jxta.id.ID getPeerGroupID() { + // convert to the generic world PGID as necessary + return IDFormat.translateToWellKnown(this); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.peergroup.PeerGroupID getParentPeerGroupID() { + net.jxta.peergroup.PeerGroupID result = null; + + try { + if (id == null) { + result = (net.jxta.peergroup.PeerGroupID) net.jxta.id.ID.nullID; + } + String idd = id; + int parentStart = idd.indexOf('.'); + + if (parentStart != -1) { + idd = idd.substring(parentStart + 1); + } else { + result = null; + } + URI url = new URI("urn:jxta:" + idd.replace('.', '-')); + net.jxta.peergroup.PeerGroupID peerGroupID = (net.jxta.peergroup.PeerGroupID) net.jxta.id.IDFactory.fromURI(url); + + result = (net.jxta.peergroup.PeerGroupID) IDFormat.translateToWellKnown(peerGroupID); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("cannot convert sub group. ID value = " + id); + } + result = null; + + } + // LOG.error("getParentPeerGroupID():"+result); + return result; + } + + /** + * returns the coded ID without the binaryid tag. + * + * @return The coded ID without the binaryid tag. + */ + protected String getID() { + return id; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PipeBinaryID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PipeBinaryID.java new file mode 100644 index 000000000..0ffe37efe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/PipeBinaryID.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.id.binaryID; + + +import java.net.URI; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; +import net.jxta.id.ID; + + +/** + * This class implements a Pipe ID. Each pipe is assigned a unique id. + * + * @author Daniel Brookshier turbogeek@cluck.com + * @see net.jxta.id.ID + * @see net.jxta.id.IDFactory + * @see net.jxta.peergroup.PeerGroupID + */ +public final class PipeBinaryID extends net.jxta.pipe.PipeID { + + /** + * LOG object for this class. + */ + private final static transient Logger LOG = Logger.getLogger(PipeBinaryID.class.getName()); + + /** + * The id data + */ + protected String id; + + /** + * Used only internally + */ + protected PipeBinaryID() { + super(); + } + + /** + * Creates a ID from a string. Note that the ID is not currently validated. + * + * @param id Value of ID. + */ + + protected PipeBinaryID(String id) { + super(); + this.id = id; + + } + + /** + * Constructor. Intializes contents from provided ID. + * + * @param id the ID data + */ + PipeBinaryID(BinaryID id) { + super(); + this.id = id.getID(); + } + + /** + * Constructor. Creates a PipeID. A PeerGroupID is provided. Note that only + * the peer group's primary node is used to build this node. We don't want + * to be appending great grand parents. + * + * @param parent the group to which this will belong. + * @param data DOCUMENT ME! + * @param lengthIncluded DOCUMENT ME! + */ + public PipeBinaryID(net.jxta.peergroup.PeerGroupID parent, byte[] data, boolean lengthIncluded) { + this(); + + String parentStr = IDFormat.childGroup(parent); + + id = BinaryIDFactory.newBinaryID(BinaryID.flagPipeID, data, lengthIncluded).getID() + "." + parentStr.replace('-', '.'); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + return target instanceof PipeBinaryID && getUniqueValue().equals(((PipeBinaryID) target).getUniqueValue()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getIDFormat() { + return IDFormat.INSTANTIATOR.getSupportedIDFormat(); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUniqueValue() { + if (null == id) { + return ID.nullID.getUniqueValue(); + } + + return new StringBuilder().append(getIDFormat()).append("-").append(id).toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getPeerGroupID() { + try { + if (id == null) { + return net.jxta.id.ID.nullID; + } + String idd = id; + int parentStart = idd.indexOf('.'); + + if (parentStart != -1) { + idd = idd.substring(parentStart + 1); + } else { + return null; + } + + URI url = new URI("urn:jxta:" + idd.replace('.', '-')); + net.jxta.peergroup.PeerGroupID peerGroupID = (net.jxta.peergroup.PeerGroupID) net.jxta.id.IDFactory.fromURI(url); + + return peerGroupID; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "cannot convert sub group. ID value = " + id, e); + } + return null; + } + } + + /** + * returns the coded ID without the binaryid tag. + * + * @return Returns the raw string used to create the urn! + */ + protected String getID() { + return id; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/package.html new file mode 100644 index 000000000..7556f18c0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/binaryID/package.html @@ -0,0 +1,49 @@ + + + + + + +The 'binary' format is a general purpose JXTA ID Format. It implements Peer, +group, and pipe ID types. The remaining types are supported, but not +guarenteed (CODAT not supported at all yet).

            + + The DigestTool class is probably the main entry point for most developers. + The class creates various BinaryID types with an SHA digest hashing. The + intent is to make secure but non-random possible for ID pipes, peers, + and peer groups. When using the utility, it is recomended tha you use + a hash size apropriate to your address space. + + @see net.jxta.impl.id.binaryID.DigestTool + + This package supports the creation of an identifier given a binary value + that is 0 to 255 bytes long that is encoded as Base64. The value needs to + be a unique value so that it can be used for addressing peers, pipes, and + groups. + +

            + + The implementation also includes the creation of a digest hash given an + arbirary length string. This allows you to encode any type of data into + a secure digest. The digest hash is recomended unless you are sure that + your binary id is truely unique. Using a digest hash is also preferrable + for situatins when you have an id that could be comprimized if known (like + a socal security number). The digest tools also have convenience methods + for mixing an id with a function name and a way to create a time + limited ID. + +

            + + Note that this ID currently only allows parent peer group ID to be of + type UUID. + +

            + + @author Daniel Brookshier turbogeek@cluck.com + + + @see JXTA + Protocols Specification : IDs + + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/ID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/ID.java new file mode 100644 index 000000000..66295ebdf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/ID.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.unknown; + + +import net.jxta.id.IDFactory; +import java.net.URI; +import java.net.URL; + +import java.net.MalformedURLException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * IDs are used to uniquely identify peers, peer groups, pipes and other + * types of objects manipulated by the JXTA APIs. + * + * @see net.jxta.id.IDFactory + * @see net.jxta.codat.CodatID + * @see net.jxta.peer.PeerID + * @see net.jxta.peergroup.PeerGroupID + * @see net.jxta.pipe.PipeID + * @see net.jxta.platform.ModuleClassID + * @see net.jxta.platform.ModuleSpecID + * + **/ +public final class ID extends net.jxta.id.ID { + + /** + * Log4J Logger + **/ + private static final transient Logger LOG = Logger.getLogger(ID.class.getName()); + + String unqiueValue; + + /** + * Constructor for IDs. + **/ + ID(String value) { + unqiueValue = value; + } + + /** + * {@inheritDoc} + **/ + @Override + public boolean equals(Object target) { + if (this == target) { + return true; + } + + if (target instanceof ID) { + return getUniqueValue().toString().equals(((ID) target).getUniqueValue().toString()); + } else { + return false; + } + } + ; + + /** + * {@inheritDoc} + **/ + @Override + public int hashCode() { + return getUniqueValue().hashCode(); + } + ; + + /** + * {@inheritDoc} + **/ + @Override + public String getIDFormat() { + return unqiueValue.substring(0, unqiueValue.indexOf('-')); + } + + /** + * {@inheritDoc} + **/ + @Override + public Object getUniqueValue() { + return unqiueValue; + } + + /** + * {@inheritDoc} + **/ + @Override + public URL getURL() { + return getURL((String) getUniqueValue()); + } + + /** + * Public member which returns a URI (URL in Java nomenclature) of the ID. + * + * @param uniqueValue the unique portion of the ID + * @return URL Object containing the URI + **/ + static URL getURL(String uniqueValue) { + URL result = null; + + // Encode the unique value so that the resulting URN is valid. + String encoded = sun.net.www.protocol.urn.Handler.encodeURN(uniqueValue); + + try { + result = IDFactory.jxtaURL(ID.URIEncodingName, "", ID.URNNamespace + ":" + encoded); + } catch (MalformedURLException failed) { + LOG.log(Level.SEVERE, "Failed to construct URL", failed); + } + + return result; + } + + /** + * {@inheritDoc} + **/ + @Override + public URI toURI() { + return URI.create(ID.URIEncodingName + ":" + ID.URNNamespace + ":" + getUniqueValue()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/IDFormat.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/IDFormat.java new file mode 100644 index 000000000..a2f133062 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/IDFormat.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.unknown; + + +import net.jxta.id.IDFactory; + + +/** + * The 'unknown' format is not a regular JXTA ID format. It is a special ID + * format used by the J2SE implementation to manage ids of formats which are + * not recognized. No ids of format 'unknown' are ever emitted nor can any new + * ids be created. + **/ +public final class IDFormat { + + /** + * The instantiator for this ID Format which is used by the IDFactory. + * + **/ + public static final IDFactory.URIInstantiator INSTANTIATOR = new Instantiator(); + + /** + * Private Constructor. This class cannot be instantiated. + **/ + private IDFormat() {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/Instantiator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/Instantiator.java new file mode 100644 index 000000000..f06ea65e2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/Instantiator.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.id.unknown; + + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.UnknownServiceException; +import java.net.URISyntaxException; +import java.security.ProviderException; + +import net.jxta.id.IDFactory; + + +final class Instantiator implements IDFactory.URIInstantiator { + + /** + * Our ID Format + **/ + final static String unknownFormat = "unknown"; + + /** + * {@inheritDoc} + **/ + public String getSupportedIDFormat() { + return unknownFormat; + } + + /** + * {@inheritDoc} + **/ + public net.jxta.id.ID fromURL(URL source) throws MalformedURLException, UnknownServiceException { + + net.jxta.id.ID result = null; + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getProtocol())) { + throw new UnknownServiceException("URI protocol type was not as expected."); + } + + String encoded = source.getFile(); + + // Decode the URN to convert any % encodings and convert it from UTF8. + String decoded = sun.net.www.protocol.urn.Handler.decodeURN(encoded); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new UnknownServiceException("URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new UnknownServiceException("URN namespace was not as expected."); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + result = new ID(decoded); + + return result; + } + ; + + /** + * {@inheritDoc} + **/ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, InputStream in) throws IOException { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.codat.CodatID newCodatID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed, InputStream in) throws IOException { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.peer.PeerID newPeerID(net.jxta.peergroup.PeerGroupID groupID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.peer.PeerID newPeerID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.peergroup.PeerGroupID newPeerGroupID() { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.peergroup.PeerGroupID newPeerGroupID(net.jxta.peergroup.PeerGroupID parent, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.pipe.PipeID newPipeID(net.jxta.peergroup.PeerGroupID groupID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.pipe.PipeID newPipeID(net.jxta.peergroup.PeerGroupID groupID, byte[] seed) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.platform.ModuleClassID newModuleClassID() { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.platform.ModuleClassID newModuleClassID(final net.jxta.platform.ModuleClassID classID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.platform.ModuleSpecID newModuleSpecID(final net.jxta.platform.ModuleClassID classID) { + throw new ProviderException("unsupported id type"); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.id.ID fromURI(URI source) throws URISyntaxException { + + // check the protocol + if (!net.jxta.id.ID.URIEncodingName.equalsIgnoreCase(source.getScheme())) { + throw new URISyntaxException(source.toString(), "URI scheme was not as expected."); + } + + String decoded = source.getSchemeSpecificPart(); + + int colonAt = decoded.indexOf(':'); + + // There's a colon right? + if (-1 == colonAt) { + throw new URISyntaxException(source.toString(), "URN namespace was missing."); + } + + // check the namespace + if (!net.jxta.id.ID.URNNamespace.equalsIgnoreCase(decoded.substring(0, colonAt))) { + throw new URISyntaxException(source.toString() + , + "URN namespace was not as expected. (" + net.jxta.id.ID.URNNamespace + "!=" + decoded.substring(0, colonAt) + + ")"); + } + + // skip the namespace portion and the colon + decoded = decoded.substring(colonAt + 1); + + return fromURNNamespaceSpecificPart(decoded); + } + + /** + * {@inheritDoc} + **/ + public net.jxta.id.ID fromURNNamespaceSpecificPart(String source) throws URISyntaxException { + ID result = new ID(source); + + return result; + + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/package.html new file mode 100644 index 000000000..9163b7106 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/id/unknown/package.html @@ -0,0 +1,13 @@ + + + + + + + The 'unknown' format is a special JXTA ID format used by the J2SE + implementation to manage ids of formats which are not recognized. No ids of + format 'unknown' are ever emitted nor can any new ids be created. + + @see JXTA Protocols Specification : IDs + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/RefJxtaLoader.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/RefJxtaLoader.java new file mode 100644 index 000000000..468349983 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/RefJxtaLoader.java @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.loader; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.impl.peergroup.CompatibilityEquater; +import net.jxta.platform.JxtaLoader; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleImplAdvertisement; + +import java.io.IOException; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.logging.Logging; +import net.jxta.platform.Module; + + +/** + * This class is the reference implementation of the JxtaLoader. + */ +public class RefJxtaLoader extends JxtaLoader { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RefJxtaLoader.class.getName()); + + /** + * The equator we will use to determine if compatibility statements are + * compatible with this JXTA implementation. + */ + private final CompatibilityEquater equator; + + /** + *

              + *
            • Keys are {@link net.jxta.platform.ModuleSpecID}.
            • + *
            • Values are {@link java.util.Map}. + *
                + *
              • Keys are {@link java.lang.String} Compatibility Statements serialized as XML UTF-8
              • + *
              • Values are {@link java.lang.Class}.
              • + *
              + *
            • + *
            + */ + private final Map>> classes = new HashMap>>(); + + /** + * Classes and ImplAdvs we have known. Weak Map so that classes can be GCed. + */ + private final Map, ModuleImplAdvertisement> implAdvs = new WeakHashMap, ModuleImplAdvertisement>(); + + /** + * Construct a new loader for the specified URLS with the default parent + * loader and specified compatibility equator. + * + * @param urls The URLs from which to load classes and resources. + * @param equator The equator to use in comparing compatibility statements. + */ + public RefJxtaLoader(URL[] urls, CompatibilityEquater equator) { + this(urls, RefJxtaLoader.class.getClassLoader(), equator); + } + + /** + * Construct a new loader for the specified URLS with the specified parent + * loader and specified compatibility equator. + * + * @param urls The URLs from which to load classes and resources. + * @param parent The parent class loader for delegation. + * @param equator The equator to use in comparing compatibility statements. + */ + public RefJxtaLoader(URL[] urls, ClassLoader parent, CompatibilityEquater equator) { + super(urls, parent); + this.equator = equator; + } + + /** + * Make a stub for a version that uses URL, so that code that load + * services can be written properly, even if it works only for classes + * that do not need download. + * + * @param name The class name. + * @param url The location of the class. + * @param resolve If {@code true} then resolve the class. + * @return the class + * @throws ClassNotFoundException if class not found + */ + protected Class loadClass(String name, URL url, boolean resolve) throws ClassNotFoundException { + try { + return loadClass(name, resolve); + } catch (ClassNotFoundException e) { + if (url != null) { + addURL(url); + return loadClass(name, resolve); + } else { + throw e; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + + Class newClass = (Class) findLoadedClass(name); + + if (newClass == null) { // I'd rather say parent.loadClass() but it is private + try { + newClass = (Class) super.loadClass(name, false); + } catch (ClassNotFoundException ignored) { + // that's ok + } + } + + if (newClass == null) { + try { + newClass = (Class) findSystemClass(name); + if (newClass != null) { + return newClass; + } + } catch (ClassNotFoundException ignored) { + // that's ok + } + + // We need to also check if the Context ClassLoader associated to the + // the current thread can load the class. + if (newClass == null) { + try { + newClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(name); + if (newClass != null) { + return newClass; + } + } catch (ClassNotFoundException ignored) { + // that's ok + } + } + + // try { + // byte[] buf = bytesForClass(name); + // newClass = defineClass(name, buf, 0, buf.length); + // } catch (IOException e) { + // throw new ClassNotFoundException(e.toString()); + // } + } + + if (resolve) { + resolveClass(newClass); + } + + return newClass; + } + + // /** + // * {@inheritDoc} + // **/ + // protected byte[] bytesForClass(String name) + // throws IOException, ClassNotFoundException { + // + // File file = new File( dir, name.replace('.', File.separatorChar) + ".java"); + // FileInputStream in = new FileInputStream(file); + // int length = (int) file.length(); + // if (length == 0) + // throw new ClassNotFoundException(name); + // byte[] buf = new byte[length]; + // in.read(buf); + // return buf; + // } + + /** + * {@inheritDoc} + */ + @Override + public synchronized Class findClass(ModuleSpecID spec) throws ClassNotFoundException { + + Map> compats = classes.get(spec); + + if (null == compats) { + throw new ClassNotFoundException("No matching class for : " + spec); + } + + for (Map.Entry> anEntry : compats.entrySet()) { + String aCompat = anEntry.getKey(); + + StructuredDocument asDoc; + + try { + asDoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(aCompat)); + } catch (IOException ignored) { + continue; + } + + if (equator.compatible(asDoc)) { + return anEntry.getValue(); + } + } + + throw new ClassNotFoundException(spec.toString()); + } + + /** + * {@inheritDoc} + */ + @Override + public Class loadClass(ModuleSpecID spec) throws ClassNotFoundException { + + Class found = findClass(spec); + + resolveClass(found); + + return found; + } + + /** + * Loads a class + * + * @param name class name + * @param url url to class + * @return the Class + * @throws ClassNotFoundException if class not found + */ + public Class loadClass(String name, URL url) throws ClassNotFoundException { + return loadClass(name, url, true); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized Class defineClass(ModuleImplAdvertisement impl) throws ClassFormatError { + String asString = impl.getCompat().toString(); + + // See if we have any classes defined for this ModuleSpecID. + // Note that there may be multiple definitions with different compatibility statements. + Map> compats = classes.get(impl.getModuleSpecID()); + + if (null == compats) { + compats = new HashMap>(); + classes.put(impl.getModuleSpecID(), compats); + } + + // See if there is a class defined which matches the compatibility statement of the implAdv. + Class loaded = compats.get(asString); + + if (null == loaded) { + try { + loaded = loadClass(impl.getCode(), new URL(impl.getUri()), false); + } catch (ClassNotFoundException failed) { + throw new ClassFormatError("Class '" + impl.getCode() + "' could not be loaded from : " + impl.getUri()); + } catch (MalformedURLException failed) { + throw new ClassFormatError("Cannot load class '" + impl.getCode() + "' from : " + impl.getUri()); + } + + // Remember the class along with the matching compatibility statement. + compats.put(asString, loaded); + } + + // Force update of impl advertisement. This is done because the class will frequently redefine itself. + implAdvs.put(loaded, impl); + + return loaded; + } + + /** + * {@inheritDoc} + */ + @Override + public ModuleImplAdvertisement findModuleImplAdvertisement(Class clazz) { + ModuleImplAdvertisement result = implAdvs.get(clazz); + + if (null == result) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "No module imp adv for " + clazz); + } + return null; + } else { + return result.clone(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public ModuleImplAdvertisement findModuleImplAdvertisement(ModuleSpecID msid) { + Class moduleClass; + + try { + moduleClass = findClass(msid); + } catch (ClassNotFoundException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to find class for " + msid, failed); + } + return null; + } + + if (null == moduleClass) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "No class for " + msid); + } + return null; + } else { + return findModuleImplAdvertisement(moduleClass); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + + result.append("Classes : "); + for (Map.Entry>> eachMCID : classes.entrySet()) { + ModuleSpecID mcid = eachMCID.getKey(); + result.append("\n\t" + mcid + " :"); + for (Map.Entry> eachClass : eachMCID.getValue().entrySet()) { + result.append("\n\t\t" + eachClass.getValue().toString()); + } + } + + return result.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/package.html new file mode 100644 index 000000000..241ec06be --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/loader/package.html @@ -0,0 +1,10 @@ + + + + + + + An implementation of {@link net.jxta.platform.JxtaLoader} for use by the + standard peer group implementations. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/PasswdMembershipService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/PasswdMembershipService.java new file mode 100644 index 000000000..e6807a711 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/PasswdMembershipService.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership; + + +import java.net.MalformedURLException; +import java.net.UnknownServiceException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.platform.JxtaLoader; +import net.jxta.membership.Authenticator; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleImplAdvertisement; + +import net.jxta.exception.JxtaError; + +import net.jxta.impl.loader.RefJxtaLoader; +import net.jxta.impl.peergroup.StdPeerGroup; + + +/** + * The passwd membership service provides a Membership Service implementation + * which is based on a password scheme similar to the unix + * /etc/passwd system.
            + * + * @deprecated This service is intended only as a sample and should not be used + * for real membership applications. IT IS NOT SECURE. The implementation has + * also moved to {@link net.jxta.impl.membership.passwd.PasswdMembershipService} + * + *

            This implementation is intended mostly as an example of a + * simple Membership Service service and not as a practical secure + * Membership Service. + * + * @see net.jxta.membership.MembershipService + * + **/ +@Deprecated +public class PasswdMembershipService { + + /** + * Log4J Logger + **/ + private static final Logger LOG = Logger.getLogger(PasswdMembershipService.class.getName()); + + /** + * Well known service specification identifier: password membership + */ + public static final ModuleSpecID passwordMembershipSpecID = net.jxta.impl.membership.passwd.PasswdMembershipService.passwordMembershipSpecID; + + /** + * Register the "real" password membership service as soon as someone + * references this class. + **/ + static { + JxtaLoader loader = net.jxta.impl.peergroup.GenericPeerGroup.getJxtaLoader(); + + ModuleImplAdvertisement implAdv = (ModuleImplAdvertisement) AdvertisementFactory.newAdvertisement( + ModuleImplAdvertisement.getAdvertisementType()); + + implAdv.setCode(net.jxta.impl.membership.passwd.PasswdMembershipService.class.getName()); + implAdv.setCompat(StdPeerGroup.STD_COMPAT); + implAdv.setDescription("Password Membership Service"); + implAdv.setModuleSpecID(passwordMembershipSpecID); + implAdv.setProvider(StdPeerGroup.MODULE_IMPL_STD_PROVIDER); + implAdv.setUri(StdPeerGroup.MODULE_IMPL_STD_URI); + + loader.defineClass(implAdv); + } + + public abstract static class PasswdAuthenticator implements Authenticator { + + public abstract void setAuth1Identity(String who); + + public abstract String getAuth1Identity(); + + public abstract void setAuth2_Password(String secret); + + protected abstract String getAuth2_Password(); + } + + /** + * This is the method used to make the password strings. We only provide + * one way encoding since we can compare the encoded strings. + * + *

            FIXME 20010402bondolo@jxta.org : switch to use the standard + * crypt(3) algorithm for encoding the passwords. The current algorithm has + * been breakable since ancient times, crypt(3) is also weak, but harder to + * break. + * + * @param source the string to encode + * @return String the encoded version of the password. + * + **/ + public static String makePsswd(String source) { + + /** + * + * A->D B->Q C->K D->W E->H F->R G->T H->E I->N J->O K->G L->X M->C + * N->V O->Y P->S Q->F R->J S->P T->I U->L V->Z W->A X->B Y->M Z->U + * + **/ + + final String xlateTable = "DQKWHRTENOGXCVYSFJPILZABMU"; + + StringBuilder work = new StringBuilder(source); + + for (int eachChar = work.length() - 1; eachChar >= 0; eachChar--) { + char aChar = Character.toUpperCase(work.charAt(eachChar)); + + int replaceIdx = xlateTable.indexOf(aChar); + + if (-1 != replaceIdx) { + work.setCharAt(eachChar, (char) ('A' + replaceIdx)); + } + } + + return work.toString(); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/NoneMembershipService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/NoneMembershipService.java new file mode 100644 index 000000000..cd11469bc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/NoneMembershipService.java @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.none; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import java.net.URISyntaxException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.credential.Credential; +import net.jxta.credential.CredentialPCLSupport; +import net.jxta.document.Attribute; +import net.jxta.document.Attributable; +import net.jxta.document.Advertisement; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.TextElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.membership.Authenticator; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.service.Service; + +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.exception.PeerGroupException; + + +/** + * A Membership Service implementation which is intended to be used with peer + * groups which require no real authentication. + * + *

            The none service allows you to claim any identity within the peergroup, + * but for peergroups which use this Membership Service method, it is + * likely that the identity is used only for informational purposes. + * + *

            A default credential with the name "nobody" is automatically available + * without requiring authentication by this service. + * + */ +public class NoneMembershipService implements MembershipService { + + /** + * Log4J Logger + **/ + private static final Logger LOG = Logger.getLogger(NoneMembershipService.class.getName()); + + /** + * Credential format for the None Membership service. + * + *

            Credentials for the None Membership Service consist of the following + * unencrypted, unsigned XML tags: + * + *

              + *
            • PeerGroupID
            • + *
            • PeerID
            • + *
            • Identity
            • + *
            + **/ + private final static class NoneCredential implements Credential, CredentialPCLSupport { + + private NoneMembershipService source; + + private String whoami; + + private ID peerid; + + /** + * Whether the credential is valid. + **/ + boolean valid = true; + + /** + * property change support + **/ + private PropertyChangeSupport support = new PropertyChangeSupport(this); + + protected NoneCredential(NoneMembershipService source, String whoami) { + + this.source = source; + this.whoami = whoami; + this.peerid = source.peergroup.getPeerID(); + } + + protected NoneCredential(NoneMembershipService source, Element root) throws PeerGroupException { + + this.source = source; + + initialize(root); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerGroupID() { + return source.peergroup.getPeerGroupID(); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerID() { + return peerid; + } + + /** + * + **/ + private void setPeerID(PeerID peerid) { + this.peerid = peerid; + } + + /** + * {@inheritDoc} + * + *

            NoneCredential are always valid. + **/ + public boolean isExpired() { + return false; + } + + /** + * {@inheritDoc} + * + *

            NoneCredential are always valid. + **/ + public boolean isValid() { + return valid; + } + + /** + * {@inheritDoc} + * + *

            PasswdCredential are always valid except after resign. + **/ + private void setValid(boolean valid) { + boolean oldValid = isValid(); + + this.valid = valid; + + if (oldValid != valid) { + support.firePropertyChange("valid", oldValid, valid); + } + } + + /** + * {@inheritDoc} + **/ + public Object getSubject() { + return whoami; + } + + /** + * + **/ + private void setSubject(String subject) { + whoami = subject; + } + + /** + * {@inheritDoc} + **/ + public Service getSourceService() { + return source.getInterface(); + } + + /** + * {@inheritDoc} + **/ + public StructuredDocument getDocument(MimeMediaType as) throws Exception { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + ((Attributable) doc).addAttribute("type", "jxta:NullCred"); + } + + Element e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + + doc.appendChild(e); + + e = doc.createElement("PeerID", peerid.toString()); + doc.appendChild(e); + + e = doc.createElement("Identity", whoami); + doc.appendChild(e); + + return doc; + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + **/ + protected boolean handleElement(TextElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + URI gID = new URI(elem.getTextValue()); + ID pgid = IDFactory.fromURI(gID); + + if (!pgid.equals(getPeerGroupID())) { + throw new IllegalArgumentException( + "Operation is from a different group. " + pgid + " != " + getPeerGroupID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerGroupID in advertisement: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("PeerID")) { + try { + URI pID = new URI(elem.getTextValue()); + ID pid = IDFactory.fromURI(pID); + + setPeerID((PeerID) pid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad Peer ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a peer id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Identity")) { + setSubject(elem.getTextValue()); + return true; + } + + // element was not handled + return false; + } + + /** + * Intialize from a portion of a structured document. + **/ + protected void initialize(Element root) { + + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + TextElement doc = (TextElement) root; + + String typedoctype = ""; + + if (root instanceof Attributable) { + Attribute itsType = ((Attributable) root).getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + } + + String doctype = doc.getName(); + + if (!doctype.equals("jxta:NullCred") && !typedoctype.equals("jxta:NullCred")) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandleded element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + if (null == getSubject()) { + throw new IllegalArgumentException("subject was never initialized."); + } + + if (null == getPeerID()) { + throw new IllegalArgumentException("peer id was never initialized."); + } + + // FIXME bondolo@jxta.org 20030409 should check for duplicate elements and for peergroup element + } + + /** + * Add a listener + * + * @param listener the listener + **/ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * Add a listener + * + * @param propertyName the property to watch + * @param listener the listener + **/ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a listener + * + * @param listener the listener + **/ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + **/ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + } + + + /** + * Authenticator Class for the None Membership Service. Pre-filled in and + * ready for join(). + **/ + public final static class NoneAuthenticator implements Authenticator { + + MembershipService source; + AuthenticationCredential application; + + String whoami = "nobody"; + + /** + * Creates an authenticator for the null membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the null membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + NoneAuthenticator(NoneMembershipService source, AuthenticationCredential application) { + this.source = source; + this.application = application; + } + + /** + * Returns the service which generated this authenticator. + **/ + public MembershipService getSourceService() { + return source; + } + + /** + * {@inheritDoc} + * + *

            This implementation is always ready for + * join() + **/ + synchronized public boolean isReadyForJoin() { + // always ready. + return true; + } + + /** + * {@inheritDoc} + **/ + public String getMethodName() { + return "NullAuthentication"; + } + + /** + * {@inheritDoc} + **/ + public AuthenticationCredential getAuthenticationCredential() { + return application; + } + + public void setAuth1Identity(String who) { + if (null == who) { + throw new IllegalArgumentException("You must supply an identity"); + } + whoami = who; + } + + public String getAuth1Identity() { + return whoami; + } + } + + private ModuleImplAdvertisement implAdvertisement = null; + + /** + * The peergroup we live in. + **/ + private PeerGroup peergroup = null; + + /** + * our current credentials + **/ + private List principals; + + /** + * our current auth credentials + **/ + private List principalsAuth; + + /** + * the default "nobody" credential + **/ + private NoneCredential defaultCredential = null; + + /** + * property change support + **/ + private PropertyChangeSupport support; + + /** + * default constructor. Normally called only by the peer group. + **/ + public NoneMembershipService() throws PeerGroupException { + principals = new ArrayList(); + principalsAuth = new ArrayList(); + support = new PropertyChangeSupport(getInterface()); + } + + /** + * Add a listener + * + * @param listener the listener + **/ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * Add a listener + * + * @param propertyName the property to watch + * @param listener the listener + **/ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a listener + * + * @param listener the listener + **/ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + **/ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + /** + * {@inheritDoc} + **/ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + implAdvertisement = (ModuleImplAdvertisement) impl; + + peergroup = group; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring None Membership Service : " + assignedID); + + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tModule Spec ID: " + implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: " + group.getPeerID()); + LOG.config(configInfo.toString()); + } + + defaultCredential = new NoneCredential(this, "nobody"); + + resign(); + } + + /** + * {@inheritDoc} + **/ + public Service getInterface() { + return this; // we have no method access control + } + + /** + * {@inheritDoc} + **/ + public int startApp(String[] arg) { + return 0; + } + + /** + * {@inheritDoc} + **/ + public void stopApp() { + resign(); + + peergroup = null; + } + + /** + * {@inheritDoc} + **/ + public Advertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + **/ + public Authenticator apply(AuthenticationCredential application) throws PeerGroupException, ProtocolNotSupportedException { + + String method = application.getMethod(); + + if ((null != method) && !"StringAuthentication".equals(method) && !"NoneAuthentication".equals(method)) { + throw new ProtocolNotSupportedException("Authentication method not recognized"); + } + + return new NoneAuthenticator(this, application); + } + + /** + * {@inheritDoc} + **/ + public Credential getDefaultCredential() { + return defaultCredential; + } + + /** + * {@inheritDoc} + **/ + public synchronized Enumeration getCurrentCredentials() { + return Collections.enumeration(principals); + } + + /** + * {@inheritDoc} + **/ + public synchronized Enumeration getAuthCredentials() { + return Collections.enumeration(principalsAuth); + } + + /** + * {@inheritDoc} + **/ + public Credential join(Authenticator authenticated) throws PeerGroupException { + + if (!(authenticated instanceof NoneAuthenticator)) { + throw new ClassCastException("This is not my authenticator!"); + } + + if (!authenticated.isReadyForJoin()) { + throw new PeerGroupException("Not ready to join()!"); + } + + NoneAuthenticator myAuthenticated = (NoneAuthenticator) authenticated; + + Credential newCred; + + synchronized (this) { + newCred = new NoneCredential(this, myAuthenticated.getAuth1Identity()); + + principals.add(newCred); + principalsAuth.add(myAuthenticated.application); + } + + support.firePropertyChange("addCredential", null, newCred); + + return newCred; + } + + /** + * {@inheritDoc} + **/ + public void resign() { + List allCreds = new ArrayList(); + + allCreds.addAll(principals); + allCreds.remove(defaultCredential); + + synchronized (this) { + // remove all existing credentials + principals.clear(); + principalsAuth.clear(); + + // re-add the default credential. + principals.add(defaultCredential); + } + + Iterator eachCred = allCreds.iterator(); + + while (eachCred.hasNext()) { + NoneCredential aCred = (NoneCredential) eachCred.next(); + + aCred.setValid(false); + } + } + + /** + * {@inheritDoc} + **/ + public Credential makeCredential(Element element) throws PeerGroupException, Exception { + return new NoneCredential(this, element); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/NoneMembershipServiceBeanInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/NoneMembershipServiceBeanInfo.java new file mode 100644 index 000000000..d2a05b220 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/NoneMembershipServiceBeanInfo.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.none; + + +import java.beans.BeanDescriptor; +import java.beans.EventSetDescriptor; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +import java.beans.IntrospectionException; +import java.lang.reflect.UndeclaredThrowableException; + + +/** + * Our beaninfo + **/ +public class NoneMembershipServiceBeanInfo extends SimpleBeanInfo { + + /** + * {@inheritDoc} + **/ + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(NoneMembershipService.class); + } + + /** + * {@inheritDoc} + **/ + @Override + public EventSetDescriptor[] getEventSetDescriptors() { + try { + EventSetDescriptor changed = new EventSetDescriptor(NoneMembershipService.class, "propertyChange" + , + PropertyChangeListener.class, "propertyChange"); + + changed.setDisplayName("bound property change"); + + EventSetDescriptor[] rv = { changed }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } + + /** + * {@inheritDoc} + **/ + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor defaultcredential = new PropertyDescriptor("defaultCredential", NoneMembershipService.class); + + defaultcredential.setBound(true); + + PropertyDescriptor rv[] = { defaultcredential }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/package.html new file mode 100644 index 000000000..ae78841b3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/none/package.html @@ -0,0 +1,17 @@ + + + + + + + A Membership Service implementation which is intended to be used with peer + groups which require no real authentication. + +

            The none service allows you to claim any identity within the peergroup, + but for peergroups which use this Membership Service method, it is + likely that the identity is used only for informational purposes. + +

            A default credential with the name "nobody" is automatically available + without requiring authentication by this service. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/package.html new file mode 100644 index 000000000..45054eb19 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/package.html @@ -0,0 +1,14 @@ + + + + + + + The membership service allows a peer to establish an identity within a peer + group. + +

            This package contains implementations of the Membership service. + + @see net.jxta.membership + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/PasswdMembershipService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/PasswdMembershipService.java new file mode 100644 index 000000000..ab61af508 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/PasswdMembershipService.java @@ -0,0 +1,909 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.passwd; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +import java.net.URISyntaxException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.credential.Credential; +import net.jxta.credential.CredentialPCLSupport; +import net.jxta.document.Advertisement; +import net.jxta.document.Attribute; +import net.jxta.document.Attributable; +import net.jxta.document.Element; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.membership.Authenticator; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.ModuleSpecID; +import net.jxta.service.Service; + +import net.jxta.exception.JxtaError; +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.exception.PeerGroupException; + + +/** + * The passwd membership service provides a Membership Service implementation + * which is based on a password scheme similar to the unix + * /etc/passwd system.
            + * + *

            This implementation is intended as an example of a + * simple Membership Service and NOT as a practical secure + * Membership Service. + * + * @see net.jxta.membership.MembershipService + * + **/ +public class PasswdMembershipService implements MembershipService { + + /** + * Log4J Logger + **/ + private static final Logger LOG = Logger.getLogger(PasswdMembershipService.class.getName()); + + /** + * Well known service specification identifier: password membership + */ + public static final ModuleSpecID passwordMembershipSpecID = (ModuleSpecID) + ID.create(URI.create("urn:jxta:uuid-DeadBeefDeafBabaFeedBabe000000050206")); + + /** + * This class provides the sub-class of Credential which is associated + * with the password membership service. + **/ + public final static class PasswdCredential implements Credential, CredentialPCLSupport { + + /** + * The MembershipService service which generated this credential. + **/ + PasswdMembershipService source; + + /** + * The identity associated with this credential + **/ + String whoami; + + /** + * The peerid associated with this credential. + **/ + ID peerid; + + /** + * The peerid which has been "signed" so that the identity may be verified. + **/ + String signedPeerID; + + /** + * property change support + **/ + private PropertyChangeSupport support = new PropertyChangeSupport(this); + + /** + * Whether the credential is valid. + **/ + boolean valid = true; + + protected PasswdCredential(PasswdMembershipService source, String whoami, String signedPeerID) { + + this.source = source; + this.whoami = whoami; + this.peerid = source.peergroup.getPeerID(); + this.signedPeerID = signedPeerID; + } + + protected PasswdCredential(PasswdMembershipService source, Element root) throws PeerGroupException { + + this.source = source; + + initialize(root); + } + + /** + * Add a listener + * + * @param listener the listener + **/ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * Add a listener + * + * @param propertyName the property to watch + * @param listener the listener + **/ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a listener + * + * @param listener the listener + **/ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + **/ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerGroupID() { + return source.peergroup.getPeerGroupID(); + } + + /** + * {@inheritDoc} + **/ + public ID getPeerID() { + return peerid; + } + + /** + * Set the peerid for this credential. + * + * @param peerid the peerid for this credential + **/ + private void setPeerID(PeerID peerid) { + this.peerid = peerid; + } + + /** + * {@inheritDoc} + * + *

            PasswdCredential never expire. + **/ + public boolean isExpired() { + return false; + } + + /** + * {@inheritDoc} + * + *

            PasswdCredential are almost always valid. + **/ + public boolean isValid() { + return valid; + } + + /** + * {@inheritDoc} + * + *

            PasswdCredential are always valid except after resign. + **/ + private void setValid(boolean valid) { + boolean oldValid = isValid(); + + this.valid = valid; + + if (oldValid != valid) { + support.firePropertyChange("valid", oldValid, valid); + } + } + + /** + * {@inheritDoc} + **/ + public Object getSubject() { + return whoami; + } + + /** + * Sets the subject for this Credential + * + * @param subject The subject for this credential. + **/ + private void setSubject(String subject) { + whoami = subject; + } + + /** + * {@inheritDoc} + **/ + public Service getSourceService() { + return source; + } + + /** + * {@inheritDoc} + **/ + public StructuredDocument getDocument(MimeMediaType as) throws Exception { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); + + if (doc instanceof XMLDocument) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + } + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("type", "jxta:PasswdCred"); + } + + Element e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + + doc.appendChild(e); + + e = doc.createElement("PeerID", getPeerID().toString()); + doc.appendChild(e); + + e = doc.createElement("Identity", whoami); + doc.appendChild(e); + + // FIXME 20010327 Do some kind of signing here based on password. + e = doc.createElement("ReallyInsecureSignature", signedPeerID); + doc.appendChild(e); + + return doc; + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + **/ + protected boolean handleElement(XMLElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + URI gID = new URI(elem.getTextValue()); + ID pgid = IDFactory.fromURI(gID); + + if (!pgid.equals(getPeerGroupID())) { + throw new IllegalArgumentException( + "Operation is from a different group. " + pgid + " != " + getPeerGroupID()); + } + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerGroupID in advertisement: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("PeerID")) { + try { + URI pID = new URI(elem.getTextValue()); + ID pid = IDFactory.fromURI(pID); + + setPeerID((PeerID) pid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad Peer ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a peer id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Identity")) { + setSubject(elem.getTextValue()); + return true; + } + + if (elem.getName().equals("ReallyInsecureSignature")) { + signedPeerID = elem.getTextValue(); + return true; + } + + // element was not handled + return false; + } + + /** + * Intialize from a portion of a structured document. + **/ + protected void initialize(Element root) { + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + + XMLElement doc = (XMLElement) root; + + String typedoctype = ""; + Attribute itsType = ((Attributable) root).getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + String doctype = doc.getName(); + + if (!doctype.equals("jxta:PasswdCred") && !typedoctype.equals("jxta:PasswdCred")) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandleded element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + if (null == getSubject()) { + throw new IllegalArgumentException("subject was never initialized."); + } + + if (null == getPeerID()) { + throw new IllegalArgumentException("peer id was never initialized."); + } + + if (null == signedPeerID) { + throw new IllegalArgumentException("signed peer id was never initialized."); + } + + // FIXME bondolo@jxta.org 20030409 should check for duplicate elements and for peergroup element + } + } + + + /** + * Creates an authenticator for the passwd membership service. Anything + * entered into the identity info section of the Authentication + * credential is ignored. + * + *

            HACK ALERT! THE INHERITANCE FROM + * net.jxta.impl.membership.PasswdMembershipService.PasswdAuthenticator + * IS A TOTAL HACK FOR BACKWARDS COMPATIBILITY. + * + * @param source The instance of the passwd membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + public final static class PasswdAuthenticator extends net.jxta.impl.membership.PasswdMembershipService.PasswdAuthenticator { + + /** + * The Membership Service which generated this authenticator. + **/ + PasswdMembershipService source; + + /** + * The Authentication which was provided to the Apply operation of the + * membership service. + **/ + AuthenticationCredential application; + + /** + * the identity which is being claimed + **/ + String whoami = null; + + /** + * the password for that identity. + **/ + String password = null; + + /** + * Creates an authenticator for the password MembershipService service. The only method + * supported is "PasswdAuthentication". Anything entered into the identity info + * section of the Authentication credential is ignored. + * + * @param source The instance of the password membership service which created this + * authenticator. + * @param application The Anything entered into the identity info section of the Authentication + * credential is ignored. + **/ + PasswdAuthenticator(PasswdMembershipService source, AuthenticationCredential application) { + this.source = source; + this.application = application; + + // XXX 20010328 bondolo@jxta.org Could do something with the authentication credential here. + } + + /** + * {@inheritDoc} + **/ + public MembershipService getSourceService() { + return (MembershipService) source.getInterface(); + } + + /** + * {@inheritDoc} + **/ + synchronized public boolean isReadyForJoin() { + return ((null != password) && (null != whoami)); + } + + /** + * {@inheritDoc} + **/ + public String getMethodName() { + return "PasswdAuthentication"; + } + + /** + * {@inheritDoc} + **/ + public AuthenticationCredential getAuthenticationCredential() { + return application; + } + + @Override + public void setAuth1Identity(String who) { + whoami = who; + } + + @Override + public String getAuth1Identity() { + return whoami; + } + + @Override + public void setAuth2_Password(String secret) { + password = secret; + } + + @Override + protected String getAuth2_Password() { + return password; + } + } + + /** + * the peergroup to which this service is associated. + **/ + private PeerGroup peergroup = null; + + /** + * the default "nobody" credential + **/ + private Credential defaultCredential = null; + + /** + * The current set of principals associated with this peer within this peegroup. + **/ + private List principals; + + /** + * The set of AuthenticationCredentials which were used to establish the principals. + **/ + private List authCredentials; + + /** + * The ModuleImplAdvertisement which was used to instantiate this service. + **/ + private ModuleImplAdvertisement implAdvertisement = null; + + /** + * An internal table containing the identity and password pairs as parsed from the + * the PeerGroupAdvertisement. + **/ + private Map logins = null; + + /** + * property change support + **/ + private PropertyChangeSupport support; + + /** + * Default constructor. Normally only called by the peer group. + **/ + public PasswdMembershipService() throws PeerGroupException { + principals = new ArrayList(); + authCredentials = new ArrayList(); + + support = new PropertyChangeSupport(getInterface()); + } + + /** + * Add a listener + * + * @param listener the listener + **/ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * Add a listener + * + * @param propertyName the property to watch + * @param listener the listener + **/ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a listener + * + * @param listener the listener + **/ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + **/ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + /** + * {@inheritDoc} + **/ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + + peergroup = group; + implAdvertisement = (ModuleImplAdvertisement) impl; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Password Membership Service : " + assignedID); + + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tModule Spec ID: " + implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: " + group.getPeerID()); + LOG.config(configInfo.toString()); + } + + PeerGroupAdvertisement configAdv = group.getPeerGroupAdvertisement(); + + XMLElement myParam = (XMLElement) configAdv.getServiceParam(assignedID); + + logins = new HashMap(); + + if (null == myParam) { + throw new PeerGroupException("parameters for group passwords missing"); + } + + for (Enumeration allLogins = myParam.getChildren(); allLogins.hasMoreElements();) { + XMLElement aLogin = (XMLElement) allLogins.nextElement(); + + if (aLogin.getName().equals("login")) { + String etcPasswd = aLogin.getTextValue(); + int nextDelim = etcPasswd.indexOf(':'); + + if (-1 == nextDelim) { + continue; + } + String login = etcPasswd.substring(0, nextDelim).trim(); + int lastDelim = etcPasswd.indexOf(':', nextDelim + 1); + String passwd = etcPasswd.substring(nextDelim + 1, lastDelim); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding login : \'" + login + "\' with encoded password : \'" + passwd + "\'"); + } + logins.put(login, passwd); + } + } + + // FIXME 20010327 bondolo@jxta.org Make up the signed bit. + + // We initialise our set of principals to the resigned state. + resign(); + } + + /** + * {@inheritDoc} + **/ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + **/ + public Advertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + * + *

            Currently this service starts by itself and does not expect + * arguments. + */ + public int startApp(String[] arg) { + return 0; + } + + /** + * {@inheritDoc} + * + *

            This request is currently ignored. + **/ + public void stopApp() { + resign(); + } + + /** + * {@inheritDoc} + **/ + public Authenticator apply(AuthenticationCredential application) throws PeerGroupException, ProtocolNotSupportedException { + + String method = application.getMethod(); + + if ((null != method) && !"StringAuthentication".equals(method) && !"PasswdAuthentication".equals(method)) { + throw new ProtocolNotSupportedException("Authentication method not recognized"); + } + + return new PasswdAuthenticator(this, application); + } + + /** + * {@inheritDoc} + **/ + public Credential getDefaultCredential() { + return defaultCredential; + } + + /** + * {@inheritDoc} + **/ + private void setDefaultCredential(Credential newDefault) { + Credential oldDefault = defaultCredential; + + defaultCredential = newDefault; + + support.firePropertyChange("defaultCredential", oldDefault, newDefault); + } + + /** + * {@inheritDoc} + **/ + public synchronized Enumeration getCurrentCredentials() { + return Collections.enumeration(principals); + } + + /** + * {@inheritDoc} + **/ + public synchronized Enumeration getAuthCredentials() { + return Collections.enumeration(authCredentials); + } + + /** + * {@inheritDoc} + **/ + public Credential join(Authenticator authenticated) throws PeerGroupException { + + if (!(authenticated instanceof PasswdAuthenticator)) { + throw new ClassCastException("This is not my authenticator!"); + } + + if (this != authenticated.getSourceService()) { + throw new ClassCastException("This is not my authenticator!"); + } + + if (!authenticated.isReadyForJoin()) { + throw new PeerGroupException("Not Ready to join!"); + } + + String identity = ((PasswdAuthenticator) authenticated).getAuth1Identity(); + String password = ((PasswdAuthenticator) authenticated).getAuth2_Password(); + + if (!checkPasswd(identity, password)) { + throw new PeerGroupException("Incorrect Password!"); + } + + // FIXME 20010327 bondolo@jxta.org Make up the signed bit. + + Credential newCred; + + synchronized (this) { + newCred = new PasswdCredential(this, identity, "blah"); + + principals.add(newCred); + + authCredentials.add(authenticated.getAuthenticationCredential()); + } + + support.firePropertyChange("addCredential", null, newCred); + + if (null == getDefaultCredential()) { + setDefaultCredential(newCred); + } + + return newCred; + } + + /** + * {@inheritDoc} + **/ + public synchronized void resign() { + Iterator eachCred = Arrays.asList(principals.toArray()).iterator(); + + synchronized (this) { + principals.clear(); + authCredentials.clear(); + } + + setDefaultCredential(null); + + while (eachCred.hasNext()) { + PasswdCredential aCred = (PasswdCredential) eachCred.next(); + + aCred.setValid(false); + } + } + + /** + * {@inheritDoc} + **/ + public Credential makeCredential(Element element) throws PeerGroupException, Exception { + + return new PasswdCredential(this, element); + } + + /** + * Given an identity and an encoded password determine if the password is + * correct. + * + * @param identity the identity which the user is trying to claim + * @param passwd the password guess being tested. + * @return true if the password was correct for the specified identity + * otherwise false. + **/ + private boolean checkPasswd(String identity, String passwd) { + boolean result; + + if (!logins.containsKey(identity)) { + return false; + } + + String encodedPW = makePsswd(passwd); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Password \'" + passwd + "\' encodes as: \'" + encodedPW + "\'"); + } + + String mustMatch = (String) logins.get(identity); + + // if there is a null password for this identity then match everything. + if (mustMatch.equals("")) { + return true; + } + + result = encodedPW.equals(mustMatch); + + return result; + } + + /** + * This is the method used to make the password strings. We only provide + * one way encoding since we can compare the encoded strings. + * + *

            FIXME 20010402 bondolo : switch to use the standard + * crypt(3) algorithm for encoding the passwords. The current algorithm has + * been breakable since ancient times, crypt(3) is also weak, but harder to + * break. + * + * @param source the string to encode + * @return String the encoded version of the password. + * + **/ + public static String makePsswd(String source) { + + /** + * + * A->D B->Q C->K D->W E->H F->R G->T H->E I->N J->O K->G L->X M->C + * N->V O->Y P->S Q->F R->J S->P T->I U->L V->Z W->A X->B Y->M Z->U + * + **/ + + final String xlateTable = "DQKWHRTENOGXCVYSFJPILZABMU"; + + StringBuilder work = new StringBuilder(source); + + for (int eachChar = work.length() - 1; eachChar >= 0; eachChar--) { + char aChar = Character.toUpperCase(work.charAt(eachChar)); + + int replaceIdx = xlateTable.indexOf(aChar); + + if (-1 != replaceIdx) { + work.setCharAt(eachChar, (char) ('A' + replaceIdx)); + } + } + + return work.toString(); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/PasswdMembershipServiceBeanInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/PasswdMembershipServiceBeanInfo.java new file mode 100644 index 000000000..145312164 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/PasswdMembershipServiceBeanInfo.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.passwd; + + +import java.beans.BeanDescriptor; +import java.beans.EventSetDescriptor; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +import java.beans.IntrospectionException; +import java.lang.reflect.UndeclaredThrowableException; + + +/** + * Our beaninfo + **/ +public class PasswdMembershipServiceBeanInfo extends SimpleBeanInfo { + + /** + * {@inheritDoc} + **/ + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(PasswdMembershipService.class); + } + + /** + * {@inheritDoc} + **/ + @Override + public EventSetDescriptor[] getEventSetDescriptors() { + try { + EventSetDescriptor changed = new EventSetDescriptor(PasswdMembershipService.class, "propertyChange" + , + PropertyChangeListener.class, "propertyChange"); + + changed.setDisplayName("bound property change"); + + EventSetDescriptor[] rv = { changed }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } + + /** + * {@inheritDoc} + **/ + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor defaultcredential = new PropertyDescriptor("defaultCredential", PasswdMembershipService.class); + + defaultcredential.setBound(true); + + PropertyDescriptor rv[] = { defaultcredential }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/package.html new file mode 100644 index 000000000..34e85e71d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/passwd/package.html @@ -0,0 +1,17 @@ + + + + + + + The passwd membership service provides a Membership Service implementation + which is based on a password scheme similar to the POSIX + /etc/passwd system. + +

            This implementation is intended as an example of a + simple Membership Service and NOT as a practical secure + Membership Service. + + @see net.jxta.membership + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/CMKeyStoreManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/CMKeyStoreManager.java new file mode 100644 index 000000000..39a49f8c1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/CMKeyStoreManager.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.security.KeyStore; + +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchProviderException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; + +import net.jxta.impl.cm.Cm; +import net.jxta.impl.peergroup.StdPeerGroup; + + +/** + * Manages a Keystore located within the JXTA CM. + **/ +public class CMKeyStoreManager implements KeyStoreManager { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(CMKeyStoreManager.class.getName()); + + /** + * Our default keystore type. + **/ + private final static String DEFAULT_KEYSTORE_TYPE = "jks"; + + /** + * The keystore type + **/ + private final String keystore_type; + + /** + * The keystore type + **/ + private final String keystore_provider; + + /** + * The JXTA CM where the keystore lives. + **/ + private final Cm keystore_cm; + + /** + * The CM ID where the keystore lives. + **/ + private final ID keystore_location; + + /** + * Default constructor. + * + * @param type The keystore type to use. The current default is the "JKS" + * keystore which is specified via {@code null}. + * @param provider The JCE cryptographic provider to use for the keystore. + * May also be {@code null} for the default provider. + * @param group The peer group which will provide the CM. + * @param location The ID under which the keystore will be stored in the + * CM. + * @throws NoSuchProviderException Thrown if the requested provider is not + * available. + * @throws KeyStoreException Thrown for errors getting a keystore of the + * requested type. + **/ + public CMKeyStoreManager(String type, String provider, PeerGroup group, ID location) throws NoSuchProviderException, KeyStoreException { + + if (null == type) { + type = DEFAULT_KEYSTORE_TYPE; + provider = null; + } + + keystore_type = type; + + keystore_provider = provider; + + keystore_cm = ((StdPeerGroup) group).getCacheManager(); + + keystore_location = location; + + // check if we can get an instance. + if (null == keystore_provider) { + KeyStore.getInstance(keystore_type); + } else { + KeyStore.getInstance(keystore_type, keystore_provider); + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("pse location = " + keystore_location + " in " + keystore_cm); + } + } + + /** + * {@inheritDoc} + **/ + public boolean isInitialized() { + return isInitialized(null); + } + + /** + * {@inheritDoc} + **/ + public boolean isInitialized(char[] store_password) { + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + InputStream is = keystore_cm.getInputStream("Raw", keystore_location.toString()); + + if (null == is) { + return false; + } + + store.load(is, store_password); + + return true; + } catch (Exception failed) { + return false; + } + } + + /** + * {@inheritDoc} + **/ + public void createKeyStore(char[] store_password) throws KeyStoreException, IOException { + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(null, store_password); + + saveKeyStore(store, store_password); + } catch (NoSuchProviderException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchProviderException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + **/ + public KeyStore loadKeyStore(char[] password) throws KeyStoreException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loading (" + keystore_type + "," + keystore_provider + ") store from " + keystore_location); + } + + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + InputStream is = keystore_cm.getInputStream("Raw", keystore_location.toString()); + + store.load(is, password); + + return store; + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (NoSuchProviderException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchProviderException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + **/ + public void saveKeyStore(KeyStore store, char[] password) throws IOException, KeyStoreException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Writing " + store + " to " + keystore_location); + } + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + store.store(bos, password); + bos.close(); + + keystore_cm.save("Raw", keystore_location.toString(), bos.toByteArray(), Long.MAX_VALUE, 0); + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + **/ + public void eraseKeyStore() throws IOException { + + keystore_cm.remove("Raw", keystore_location.toString()); + } + + /** + * {@inheritDoc} + **/ + public String toString() { + StringBuilder sb = new StringBuilder("PSE keystore details: \n"); + sb.append(" Class: ").append(this.getClass().getName()).append("\n"); + sb.append(" Type: ").append(keystore_type==null ? "" : keystore_type).append("\n"); + sb.append(" Provider: ").append(keystore_provider==null ? "" : keystore_provider).append("\n"); + sb.append(" Location: ").append(keystore_location==null ? "" : keystore_location.toString()).append("\n"); + return sb.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/DialogAuthenticator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/DialogAuthenticator.java new file mode 100644 index 000000000..42b79195e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/DialogAuthenticator.java @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Iterator; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; + +import javax.crypto.EncryptedPrivateKeyInfo; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.id.ID; +import net.jxta.membership.InteractiveAuthenticator; +import net.jxta.peer.PeerID; + + +/** + * An interactive graphical authenticator associated with the PSE membership + * service. + * + * @see net.jxta.membership.Authenticator + * @see net.jxta.membership.InteractiveAuthenticator + * @see net.jxta.membership.MembershipService + * @see net.jxta.impl.membership.pse.PSEMembershipService + **/ +public final class DialogAuthenticator extends StringAuthenticator implements InteractiveAuthenticator { + + /** + * Entries we stick into the combo list + **/ + private static class JComboEntry { + ID itsID; + + X509Certificate itsCertificate; + + String itsName; + + JComboEntry(ID entryID, X509Certificate itsCert) { + itsID = entryID; + itsCertificate = itsCert; + itsName = PSEUtils.getCertSubjectCName(itsCertificate); + + if (null == itsName) { + itsName = "< no common name >"; + } + + // remove the -CA which is common to ca root certs. + if (itsName.endsWith("-CA")) { + itsName = itsName.substring(0, itsName.length() - 3); + } + } + + /** + * {@inheritDoc} + **/ + @Override + public String toString() { + return itsName; + } + } + + + /** + * Swing user interface for password entry and identity selection. + * + *

            FIXME bondolo 20040329 should be localizable. + **/ + private class PasswordDialog extends JDialog implements ActionListener { + + private boolean initKeyStore; + private final PeerID seedPeer; + private final X509Certificate seedCert; + private final EncryptedPrivateKeyInfo seedKey; + + private final JLabel storePassLabel; + private final JPasswordField storePassField; + + private final JLabel identityLabel; + private final JComboBox identityList; + + private final JLabel identityPassLabel; + private final JPasswordField identityPassField; + + private final JButton okButton; + + private final JButton cancelButton; + + private boolean canceled = true; + + /** + * Dialog to prompt for a password + **/ + PasswordDialog(PeerID seedPeer, X509Certificate seedCert, EncryptedPrivateKeyInfo seedKey) { + super(JOptionPane.getRootFrame(), ((null != seedCert) ? "Initialize JXTA Keystore" : "JXTA Secure Login") + , /* modal*/ + true); + + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + addWindowListener(new WindowAdapter() { + + /** + * @inheritDoc + */ + + @Override + public void windowClosing(WindowEvent e) { + canceled = true; + } + }); + + this.seedPeer = seedPeer; + this.seedCert = seedCert; + this.seedKey = seedKey; + + initKeyStore = (null != seedCert); + + JPanel contentPane = new JPanel(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START + , + GridBagConstraints.BOTH, new Insets(4, 4, 4, 4), 0, 0); + + storePassField = new JPasswordField("", 10); + + if (!initKeyStore) { + // add listener to populate identities list + storePassField.addKeyListener(new PasswordDialogKeyHandler()); + } + + if (!initKeyStore) { + identityList = new JComboBox(); + } else { + JComboEntry seedEntry = new JComboEntry(seedPeer, seedCert); + + Object[] names = { seedEntry }; + + identityList = new JComboBox(names); + identityList.setMaximumRowCount(1); + } + + identityPassField = new JPasswordField("", 10); + + identityPassField.addKeyListener(new PasswordDialogKeyHandler()); + + storePassLabel = new JLabel("Key Store Password"); + storePassLabel.setLabelFor(storePassField); + contentPane.add(storePassLabel, c); + c.gridx = 1; + contentPane.add(storePassField, c); + + c.gridx = 0; + c.gridy = 1; + c.anchor = GridBagConstraints.LINE_START; + identityLabel = new JLabel("Identity"); + identityLabel.setLabelFor(identityList); + contentPane.add(identityLabel, c); + c.gridx = 1; + c.fill = GridBagConstraints.BOTH; + contentPane.add(identityList, c); + + c.gridx = 0; + c.gridy = 2; + c.fill = GridBagConstraints.BOTH; + identityPassLabel = new JLabel("Identity Password"); + identityPassLabel.setLabelFor(identityPassField); + contentPane.add(identityPassLabel, c); + c.gridx = 1; + contentPane.add(identityPassField, c); + + JPanel buttonPanel = new JPanel(new GridLayout(/* rows*/1, /* cols*/0)); + + okButton = new JButton("OK"); + okButton.addActionListener(this); + buttonPanel.add(okButton); + + cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(this); + buttonPanel.add(cancelButton); + + c.gridx = 0; + c.gridy = 3; + c.gridwidth = 2; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.fill = GridBagConstraints.VERTICAL; + cancelButton.addActionListener(this); + contentPane.add(buttonPanel, c); + + setContentPane(contentPane); + + if (initKeyStore) { + identityPassField.requestFocusInWindow(); + } else { + storePassField.requestFocusInWindow(); + } + } + + /** + * Handler for key events. + **/ + private class PasswordDialogKeyHandler extends KeyAdapter { + + /** + * {@inheritDoc} + **/ + @Override + public void keyReleased(KeyEvent e) { + setOKState(); + } + } + + /** + **/ + private void setOKState() { + boolean enableOK = false; + + if (initKeyStore) { + enableOK = (null + != PSEUtils.pkcs5_Decrypt_pbePrivateKey(identityPassField.getPassword() + , + seedCert.getPublicKey().getAlgorithm(), seedKey)); + + storePassLabel.setEnabled(enableOK); + storePassField.setEnabled(enableOK); + } else { + boolean enableIdentityList = false; + + ID[] roots = getIdentities(storePassField.getPassword()); + + if (null != roots) { + Iterator eachRoot = Arrays.asList(roots).iterator(); + + while (eachRoot.hasNext()) { + ID aPeer = (ID) eachRoot.next(); + + try { + X509Certificate aCert = DialogAuthenticator.this.source.getPSEConfig().getTrustedCertificate(aPeer); + JComboEntry anEntry = new JComboEntry(aPeer, aCert); + + if (!enableIdentityList) { + enableIdentityList = true; + identityList.removeAllItems(); + identityList.setSelectedIndex(-1); + } + + identityList.addItem(anEntry); + identityList.setSelectedIndex(0); + } catch (Exception ignore) { + continue; + } + } + } + + if (enableIdentityList) { + identityList.setMaximumRowCount(identityList.getItemCount()); + } else { + identityList.removeAllItems(); + identityList.setSelectedIndex(-1); + identityPassField.setText(""); + } + + identityLabel.setEnabled(enableIdentityList); + identityList.setEnabled(enableIdentityList); + identityPassLabel.setEnabled(enableIdentityList); + identityPassField.setEnabled(enableIdentityList); + } + + if ((null != getIdentity()) && (null != getKeyStorePassword()) && (null != getIdentityPassword())) { + setAuth1_KeyStorePassword(getKeyStorePassword()); + setAuth2Identity(getIdentity()); + setAuth3_IdentityPassword(getIdentityPassword()); + enableOK = isReadyForJoin(); + } + + okButton.setEnabled(enableOK); + } + + /** + * {@inheritDoc} + **/ + public void actionPerformed(ActionEvent e) { + + if (okButton == e.getSource()) { + canceled = false; + dispose(); + } else if (cancelButton == e.getSource()) { + canceled = true; + dispose(); + } else {} + } + + public void showDialog() { + pack(); + setLocationRelativeTo(null); + + setOKState(); + + setVisible(true); + } + + /** + * Returns the KeyStore password. + * + * @return the KeyStore password. + **/ + public char[] getKeyStorePassword() { + if (!storePassField.isEnabled()) { + return null; + } + + char[] result = storePassField.getPassword(); + + return result; + } + + /** + * Returns the selected Identity. + * + * @return the selected Identity. + **/ + public ID getIdentity() { + if (!identityList.isEnabled()) { + return null; + } + + JComboEntry selectedIdentity = (JComboEntry) identityList.getSelectedItem(); + + if (null == selectedIdentity) { + return null; + } + + return selectedIdentity.itsID; + } + + /** + * Returns the Identity password. + * + * @return the Identity password. + **/ + public char[] getIdentityPassword() { + if (!identityPassField.isEnabled()) { + return null; + } + + char[] result = identityPassField.getPassword(); + + return result; + } + + /** + * Returns the final state of the dialog. Until the "OK" button is + * pressed the dialog is "cancelled". + * + * @param returns the final state of the dialog. + **/ + public boolean wasCanceled() { + return canceled; + } + } + + /** + * Creates an authenticator for the PSE membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the PSE membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + DialogAuthenticator(PSEMembershipService source, AuthenticationCredential application) { + super(source, application); + + // XXX 20010328 bondolo@jxta.org Could do something with the authentication credential here. + } + + /** + * Creates an authenticator for the PSE membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the PSE membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + DialogAuthenticator(PSEMembershipService source, AuthenticationCredential application, X509Certificate seedCert, EncryptedPrivateKeyInfo seedKey) { + super(source, application, seedCert, seedKey); + + // XXX 20010328 bondolo@jxta.org Could do something with the authentication credential here. + } + + /** + * {@inheritDoc} + **/ + @Override + public String getMethodName() { + return "DialogAuthentication"; + } + + /** + * {@inheritDoc} + **/ + public boolean interact() { + PasswordDialog p = new PasswordDialog(source.group.getPeerID(), seedCert, seedKey); + + p.showDialog(); + + if (p.wasCanceled()) { + setAuth1_KeyStorePassword((char[]) null); + setAuth2Identity((ID) null); + setAuth3_IdentityPassword((char[]) null); + + } else { + setAuth1_KeyStorePassword(p.getKeyStorePassword()); + setAuth2Identity(p.getIdentity()); + setAuth3_IdentityPassword(p.getIdentityPassword()); + } + + return !p.wasCanceled(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/EngineAuthenticator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/EngineAuthenticator.java new file mode 100644 index 000000000..37720c12b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/EngineAuthenticator.java @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.net.URI; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.security.cert.X509Certificate; +import javax.crypto.EncryptedPrivateKeyInfo; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.KeyStoreException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.membership.Authenticator; +import net.jxta.membership.MembershipService; + + +/** + * An authenticator associated with the PSE membership service. + * + *@see net.jxta.membership.Authenticator + *@see net.jxta.membership.MembershipService + **/ +public class EngineAuthenticator implements Authenticator { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(EngineAuthenticator.class.getName()); + + /** + * The Membership Service which generated this authenticator. + **/ + transient PSEMembershipService source; + + /** + * The Authentication which was provided to the Apply operation of the + * membership service. + **/ + transient AuthenticationCredential application; + + /** + * + **/ + transient X509Certificate seedCert; + + /** + * + **/ + transient PSEAuthenticatorEngine authenticatorEngine; + + /** + * + **/ + // transient EncryptedPrivateKeyInfo seedKey; + + /** + * the password for that identity. + **/ + transient char[] store_password = null; + + /** + * the identity which is being claimed + **/ + transient ID identity = null; + + /** + * the password for that identity. + **/ + transient char[] key_password = null; + + /** + * Creates an authenticator for the PSE membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the PSE membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + EngineAuthenticator(PSEMembershipService source, AuthenticationCredential application, PSEAuthenticatorEngine authenticatorEngine) { + // this( source, application ); + + this.source = source; + this.application = application; + this.seedCert = authenticatorEngine.getX509Certificate(); + this.authenticatorEngine = authenticatorEngine; + } + + /** + * Creates an authenticator for the PSE membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the PSE membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + EngineAuthenticator(PSEMembershipService source, AuthenticationCredential application) { + this.source = source; + this.application = application; + + // XXX 20010328 bondolo@jxta.org Could do something with the authentication credential here. + } + + /** + * {@inheritDoc} + **/ + @Override + protected void finalize() throws Throwable { + if (null != store_password) { + Arrays.fill(store_password, '\0'); + } + + if (null != key_password) { + Arrays.fill(key_password, '\0'); + } + + super.finalize(); + } + + /** + * {@inheritDoc} + **/ + public MembershipService getSourceService() { + return (MembershipService) source.getInterface(); + } + + /** + * {@inheritDoc} + **/ + public AuthenticationCredential getAuthenticationCredential() { + return application; + } + + /** + * {@inheritDoc} + **/ + public String getMethodName() { + return "EngineAuthentication"; + } + + /** + * {@inheritDoc} + **/ + synchronized public boolean isReadyForJoin() { + if (null != seedCert) { + return authenticatorEngine.isEnginePresent(); + } else { + return source.pseStore.validPasswd(identity, store_password, key_password); + } + } + + /** + * Get KeyStore password + **/ + public char[] getAuth1_KeyStorePassword() { + return store_password; + } + + /** + * Set KeyStore password + **/ + public void setAuth1_KeyStorePassword(String store_password) { + if (null == store_password) { + setAuth1_KeyStorePassword((char[]) null); + } else { + setAuth1_KeyStorePassword(store_password.toCharArray()); + } + } + + /** + * Set KeyStore password + **/ + public void setAuth1_KeyStorePassword(char[] store_password) { + if (null != this.store_password) { + Arrays.fill(this.store_password, '\0'); + } + + if (null == store_password) { + this.store_password = null; + } else { + this.store_password = store_password.clone(); + } + } + + /** + * Return the available identities. + **/ + public PeerID[] getIdentities(char[] store_password) { + + if (seedCert != null) { + PeerID[] seed = { source.group.getPeerID() }; + + return seed; + } else { + try { + ID[] allkeys = source.pseStore.getKeysList(store_password); + + // XXX bondolo 20040329 it may be appropriate to login + // something other than a peer id. + List peersOnly = new ArrayList(); + + Iterator eachKey = Arrays.asList(allkeys).iterator(); + + while (eachKey.hasNext()) { + ID aKey = (ID) eachKey.next(); + + if (aKey instanceof PeerID) { + peersOnly.add(aKey); + } + } + + return (PeerID[]) peersOnly.toArray(new PeerID[peersOnly.size()]); + } catch (IOException failed) { + return null; + } catch (KeyStoreException failed) { + return null; + } + } + } + + public X509Certificate getCertificate(char[] store_password, ID aPeer) { + if (seedCert != null) { + if (aPeer.equals(source.group.getPeerID())) { + return seedCert; + } else { + return null; + } + } else { + try { + return source.pseStore.getTrustedCertificate(aPeer, store_password); + } catch (IOException failed) { + return null; + } catch (KeyStoreException failed) { + return null; + } + } + } + + /** + * Get Identity + **/ + public ID getAuth2Identity() { + return identity; + } + + /** + * Set Identity + **/ + public void setAuth2Identity(String id) { + try { + URI idURI = new URI(id); + ID identity = IDFactory.fromURI(idURI); + + setAuth2Identity(identity); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad ID"); + } + } + + /** + * Set Identity + **/ + public void setAuth2Identity(ID identity) { + this.identity = identity; + } + + /** + * Get identity password + **/ + public char[] getAuth3_IdentityPassword() { + return key_password; + } + + /** + * Set identity password + **/ + public void setAuth3_IdentityPassword(String key_password) { + setAuth3_IdentityPassword(key_password.toCharArray()); + } + + /** + * Set identity password + **/ + public void setAuth3_IdentityPassword(char[] key_password) { + if (null != this.key_password) { + Arrays.fill(this.key_password, '\0'); + } + + if (null == key_password) { + this.key_password = null; + } else { + this.key_password = key_password.clone(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/FileKeyStoreManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/FileKeyStoreManager.java new file mode 100644 index 000000000..21a2475f6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/FileKeyStoreManager.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import net.jxta.logging.Logging; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Manages a Keystore located within a single File. + */ +public class FileKeyStoreManager implements KeyStoreManager { + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(URIKeyStoreManager.class.getName()); + + private final static String DEFAULT_KEYSTORE_TYPE = "jks"; + + private final static String DEFAULT_KEYSTORE_FILENAME = "jxta_keystore"; + + /** + * The keystore type + */ + private final String keystore_type; + + /** + * The keystore type + */ + private final String keystore_provider; + + /** + * The file where the keystore lives. This must be a file even if the + * keystore really is a set of files or a directory. + */ + private final File keystore_location; + + /** + * Default constructor. + * + * @param type keystore type + * @param provider the provider + * @param location Store location + * @throws NoSuchProviderException if the security provider requested is not available in the environment. + * @throws KeyStoreException if a keystore error occurs + */ + public FileKeyStoreManager(String type, String provider, File location) throws NoSuchProviderException, KeyStoreException { + if (null == type) { + type = DEFAULT_KEYSTORE_TYPE; + provider = null; + } + + // if provided a directory, use the default file name. + if (location.isDirectory()) { + location = new File(location, DEFAULT_KEYSTORE_FILENAME); + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("pse location = " + location); + } + + keystore_type = type; + + keystore_provider = provider; + + keystore_location = location; + + // check if we can get an instance. + if (null == keystore_provider) { + KeyStore.getInstance(keystore_type); + } else { + KeyStore.getInstance(keystore_type, keystore_provider); + } + } + + /** + * {@inheritDoc} + */ + public boolean isInitialized() { + return isInitialized(null); + } + + /** + * {@inheritDoc} + */ + public boolean isInitialized(char[] store_password) { + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(keystore_location.toURI().toURL().openStream(), store_password); + + return true; + } catch (Exception failed) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public void createKeyStore(char[] store_password) throws KeyStoreException, IOException { + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(null, store_password); + + saveKeyStore(store, store_password); + } catch (NoSuchProviderException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchProviderException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + */ + public KeyStore loadKeyStore(char[] password) throws KeyStoreException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loading (" + keystore_type + "," + keystore_provider + ") store from " + keystore_location); + } + + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(keystore_location.toURI().toURL().openStream(), password); + + return store; + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (NoSuchProviderException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchProviderException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + */ + public void saveKeyStore(KeyStore store, char[] password) throws KeyStoreException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Writing " + store + " to " + keystore_location); + } + + try { + OutputStream os = new FileOutputStream(keystore_location); + + store.store(os, password); + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + */ + public void eraseKeyStore() throws IOException { + + if (keystore_location.isFile() && keystore_location.canWrite()) { + keystore_location.delete(); + } else { + throw new UnsupportedOperationException("Unable to delete"); + } + } + + /** + * {@inheritDoc} + **/ + public String toString() { + StringBuilder sb = new StringBuilder("PSE keystore details: \n"); + sb.append(" Class: ").append(this.getClass().getName()).append("\n"); + sb.append(" Type: ").append(keystore_type==null ? "" : keystore_type).append("\n"); + sb.append(" Provider: ").append(keystore_provider==null ? "" : keystore_provider).append("\n"); + sb.append(" Location: ").append(keystore_location==null ? "" : keystore_location.toString()).append("\n"); + return sb.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/KeyStoreManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/KeyStoreManager.java new file mode 100644 index 000000000..0775320cc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/KeyStoreManager.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; + + +/** + * Abstracts the management of KeyStores. This is commonly used to abstract the + * location of the KeyStore and the details of creating, loading, saving and + * deleting the KeyStore. + *

            + *

            Applications should not assume that accesses to KeyStoreManager are + * thread safe. All access to the KeyStoreManager should be externally + * synchronized on the KeyStoreManager object. + */ +public interface KeyStoreManager { + + /** + * Returns true if the KeyStore has been initialized (created). + * Since this method does not provide a passphrase it is really only useful + * for determining if a new KeyStore needs to be created. + * + * @return true if the KeyStore has been previously initialized + * otherwise false. + * @throws KeyStoreException If the KeyStore is protected by a store + * password that has not been set. + */ + boolean isInitialized() throws KeyStoreException; + + /** + * Returns true if the Keystore has been initialized (created). + * This method also ensures that the provided passphrase is valid for the + * keystore. + * + * @param password The KeyStore passphrase. + * @return true if the Keystore has been initialized otherwise + * false. + * @throws KeyStoreException If an incorrect KeyStore password is provided. + */ + boolean isInitialized(char[] password) throws KeyStoreException; + + /** + * Create the KeyStore using the specified KeyStore passphrase. + * + * @param password The KeyStore passphrase. + * @throws KeyStoreException If an incorrect KeyStore passphrase is provided. + * @throws IOException If there is a problem creating the KeyStore. + */ + void createKeyStore(char[] password) throws IOException, KeyStoreException; + + /** + * Load the KeyStore. + * + * @param password The KeyStore passphrase. + * @throws KeyStoreException If an incorrect KeyStore password is provided. + * @throws IOException If there is a problem loading the KeyStore. + * @return the keystore + */ + KeyStore loadKeyStore(char[] password) throws IOException, KeyStoreException; + + /** + * Save the provided KeyStore using the specified KeyStore passphrase. + * + * @param store The KeyStore to save. + * @param password The encryption passphrase for the keystore. + * @throws IOException Thrown for errors writing the keystore. + * @throws KeyStoreException Thrown for errors with the provided key or key store. + */ + void saveKeyStore(KeyStore store, char[] password) throws IOException, KeyStoreException; + + /** + * Erase the KeyStore. Some KeyStore implementations may not allow the + * KeyStore container itself to be erased and in some cases specific + * certificates and keys may be unerasable. All implementations should + * erase all user provided certificates and keys. + * + * @throws IOException If there is a problem erasing the KeyStore or the + * KeyStore cannot be erased. + */ + void eraseKeyStore() throws IOException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEAuthenticatorEngine.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEAuthenticatorEngine.java new file mode 100644 index 000000000..2c386bbad --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEAuthenticatorEngine.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.membership.pse; + + +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.SignatureException; +import java.security.NoSuchAlgorithmException; + +import net.jxta.peergroup.PeerGroup; + + +/** + * + * @author aubergine + */ +public interface PSEAuthenticatorEngine { + + public PublicKey getPublicKey() throws SecurityException; + + public byte[] sign(byte[] data) throws InvalidKeyException, SignatureException, IOException; + + public String getSignatureAlgorithm(); + + public boolean isEnginePresent() throws SecurityException; + + public X509Certificate getX509Certificate() throws SecurityException; + + public char[] getKeyPass(PeerGroup peerGroup) throws SecurityException; + + public char[] getStorePass(PeerGroup peerGroup) throws SecurityException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEAuthenticatorEngineFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEAuthenticatorEngineFactory.java new file mode 100644 index 000000000..d1c6cf9b6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEAuthenticatorEngineFactory.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.exception.PeerGroupException; +import net.jxta.impl.protocol.PSEConfigAdv; + + +/** + * + * @author nick + */ +public abstract class PSEAuthenticatorEngineFactory { + + private static PSEAuthenticatorEngineFactory defaultEngine = null; + + public static void setPSESecurityEngineFactory(PSEAuthenticatorEngineFactory newEngine) { + synchronized (PSEAuthenticatorEngineFactory.class) { + defaultEngine = newEngine; + } + } + + /** + * Returns the default Authenticator Engine. + * + * @return The current default Authenticator Engine. + **/ + public static PSEAuthenticatorEngineFactory getDefault() { + synchronized (PSEAuthenticatorEngineFactory.class) { + if (defaultEngine == null) { + defaultEngine = new PSEAuthenticatorEngineDefaultFactory(); + } + + return defaultEngine; + } + } + + /** + * Creates a new Authenticator Engine instance based upon the context and configuration. + * + * @param service The service that this keystore manager will be working for. + * @param config The configuration parameters. + **/ + public abstract PSEAuthenticatorEngine getInstance(PSEMembershipService service, PSEConfigAdv config) throws PeerGroupException; + + /** + * Default implementation which provides the default behaviour (which is to do nothing). + **/ + private static class PSEAuthenticatorEngineDefaultFactory extends PSEAuthenticatorEngineFactory { + + @Override + public PSEAuthenticatorEngine getInstance(PSEMembershipService service, PSEConfigAdv config) throws PeerGroupException { + return null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEConfig.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEConfig.java new file mode 100644 index 000000000..b578083dd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEConfig.java @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.*; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Manages the state of a Personal Security Enviroment. + */ +public final class PSEConfig { + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(PSEConfig.class.getName()); + + /** + * Manager for the keystore we are using. + */ + private final KeyStoreManager keystore_manager; + + /** + * The keystore passphrase. + */ + private char[] keystore_password = null; + + /** + * Standard constructor. + * + * @param storeManager The StoreManager to be used for this PSEConfig + * instance. + * @param store_password The passphrase for the keystore or null. + * The passphrase may be set independantly via + * {@link #setKeyStorePassword(char[])}. + */ + PSEConfig(KeyStoreManager storeManager, char[] store_password) { + this.keystore_manager = storeManager; + setKeyStorePassword(store_password); + } + + /** + * Sets the passphrase to be used when unlocking the keystore. + * + * @param store_password The passphrase used to unlock the keystore may be + * {@code null} for keystores with no passphrase. + */ + public final void setKeyStorePassword(char[] store_password) { + if (null != this.keystore_password) { + Arrays.fill(this.keystore_password, '\0'); + } + + if (null == store_password) { + this.keystore_password = null; + } else { + this.keystore_password = store_password.clone(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void finalize() throws Throwable { + if (null != keystore_password) { + Arrays.fill(keystore_password, '\0'); + } + + super.finalize(); + } + + /** + * Returns {@code true} if the PSE has been initialized (created). Some + * keystore formats may not require initialization and may always return + * {@code true}. {@code false} may also be returned if the keystore passphrase is + * incorrect. + * + * @return {@code true} if the PSE has been previously initialized + * otherwise {@code false}. + */ + public boolean isInitialized() { + try { + if (keystore_password != null) { + return keystore_manager.isInitialized(keystore_password); + } else { + return keystore_manager.isInitialized(); + } + } catch (Exception ignored) { + return false; + } + } + + /** + * Initializes the PSE environment. + * + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public void initialize() throws KeyStoreException, IOException { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Initializing new PSE keystore..."); + } + + synchronized (keystore_manager) { + try { + if (keystore_manager.isInitialized(keystore_password)) { + return; + } + + keystore_manager.createKeyStore(keystore_password); + } catch (KeyStoreException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failure accessing or creating keystore.", failed); + } + + keystore_manager.eraseKeyStore(); + + throw failed; + } + } + } + + /** + * Removes an existing PSE enviroment. + * + * @throws IOException If the PSE cannot be successfully deleted. + */ + public void erase() throws IOException { + synchronized (keystore_manager) { + keystore_manager.eraseKeyStore(); + } + } + + /** + * Gets a copy of the KeyStore associated with this PSE instance. The + * returned KeyStore is a copy and not tied to the instance maintained by + * the PSE. Changing the returned keystore will not result in changes to + * the PSE. + * + * @return The keystore or {@code null} if it cannot be retrieved. + */ + public KeyStore getKeyStore() { + Throwable failure; + + try { + return getKeyStore(keystore_password); + } catch (KeyStoreException failed) { + failure = failed; + } catch (IOException failed) { + failure = failed; + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failure recovering keystore : " + failure); + } + + return null; + } + + /** + * Gets a copy of the KeyStore associated with this PSE instance. The + * returned KeyStore is a copy and not tied to the instance maintained by + * the PSE. Changing the returned keystore will not result in changes to + * the PSE. + * + * @param store_password The passphrase used to unlock the keystore may be + * {@code null} for keystores with no passphrase. + * @return The keystore. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + * @since JXTA 2.4 + */ + public KeyStore getKeyStore(char[] store_password) throws KeyStoreException, IOException { + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(store_password); + + return store; + } + } + + /** + * Check if the provided passwords are correct for the specified identity. + * + * @param id The identity to be validated. + * @param store_password The passphrase used to unlock the keystore may be + * {@code null} for keystores with no passphrase. + * @param key_password The passphrase associated with the private key or + * {@code null} if the key has no passphrase. + * @return {@code true} if the passwords were valid for the given id + * otherwise {@code false}. + */ + boolean validPasswd(ID id, char[] store_password, char[] key_password) { + + if (null == id) { + return false; + } + + Throwable failure; + + try { + synchronized (keystore_manager) { + KeyStore store; + + if (null != store_password) { + store = keystore_manager.loadKeyStore(store_password); + } else { + if (null != keystore_password) { + store = keystore_manager.loadKeyStore(keystore_password); + } else { + throw new UnrecoverableKeyException("KeyStore passphrase not initialized"); + } + } + + String alias = id.toString(); + + Key key = store.getKey(alias, key_password); + + return (null != key); + } + } catch (UnrecoverableKeyException failed) { + failure = failed; + } catch (NoSuchAlgorithmException failed) { + failure = failed; + } catch (KeyStoreException failed) { + failure = failed; + } catch (IOException failed) { + failure = failed; + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failure checking passphrase : " + failure); + } + + return false; + } + + /** + * Returns the list of the trusted certificates available in this keystore. + * + * @return an array of the IDs of the available trusted certificates. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public ID[] getTrustedCertsList() throws KeyStoreException, IOException { + List trustedCertsList = new ArrayList(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + Enumeration eachAlias = store.aliases(); + + while (eachAlias.hasMoreElements()) { + String anAlias = eachAlias.nextElement(); + + if (store.isCertificateEntry(anAlias) || store.isKeyEntry(anAlias)) { + try { + URI id = new URI(anAlias); + + trustedCertsList.add(IDFactory.fromURI(id)); + } catch (URISyntaxException badID) {// ignored + } + } + } + + return trustedCertsList.toArray(new ID[trustedCertsList.size()]); + } + } + + /** + * Returns the list of root certificates for which there is an associated + * local private key. + * + * @return an array of the available keys. May be an empty array. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public ID[] getKeysList() throws KeyStoreException, IOException { + return getKeysList(keystore_password); + } + + /** + * Returns the list of root certificates for which there is an associated + * local private key. + * + * @param store_password The passphrase used to unlock the keystore may be + * {@code null} for keystores with no passphrase. + * @return an array of the available keys. May be an empty array. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + ID[] getKeysList(char[] store_password) throws KeyStoreException, IOException { + List keyedRootsList = new ArrayList(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(store_password); + + Enumeration eachAlias = store.aliases(); + + while (eachAlias.hasMoreElements()) { + String anAlias = eachAlias.nextElement(); + + if (store.isKeyEntry(anAlias)) { + try { + URI id = new URI(anAlias); + + keyedRootsList.add(IDFactory.fromURI(id)); + } catch (URISyntaxException badID) {// ignored + } + } + } + + return keyedRootsList.toArray(new ID[keyedRootsList.size()]); + } + } + + /** + * Returns the ID of the provided certificate or null if the certificate is + * not found in the keystore. + * + * @param cert The certificate who's ID is desired. + * @return The ID of the certificate or null if no matching + * Certificate was found. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public ID getTrustedCertificateID(X509Certificate cert) throws KeyStoreException, IOException { + + String anAlias = null; + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + anAlias = store.getCertificateAlias(cert); + } + + // not found. + if (null == anAlias) { + return null; + } + + try { + URI id = new URI(anAlias); + + return IDFactory.fromURI(id); + } catch (URISyntaxException badID) { + return null; + } + } + + /** + * Returns the trusted cert for the specified id. + * + * @param id The id of the Certificate to retrieve. + * @return Certificate for the specified ID or null if the store does not + * contain the specified certificate. + * @throws KeyStoreException When the wrong keystore key has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public X509Certificate getTrustedCertificate(ID id) throws KeyStoreException, IOException { + + return getTrustedCertificate(id, keystore_password); + } + + /** + * Returns the trusted cert for the specified id. + * + * @param id The id of the Certificate to retrieve. + * @param store_password The passphrase used to unlock the keystore may be + * {@code null} for keystores with no passphrase. + * @return Certificate for the specified ID or null if the store does not + * contain the specified certificate. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + X509Certificate getTrustedCertificate(ID id, char[] store_password) throws KeyStoreException, IOException { + + String alias = id.toString(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(store_password); + + if (!store.containsAlias(alias)) { + return null; + } + + return (X509Certificate) store.getCertificate(alias); + } + } + + /** + * Returns the trusted cert chain for the specified id. + * + * @param id The ID of the certificate who's certificate chain is desired. + * @return Certificate chain for the specified ID or null if the PSE does + * not contain the specified certificate. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public X509Certificate[] getTrustedCertificateChain(ID id) throws KeyStoreException, IOException { + + String alias = id.toString(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + if (!store.containsAlias(alias)) { + return null; + } + + Certificate certs[] = store.getCertificateChain(alias); + + if (null == certs) { + return null; + } + + X509Certificate x509certs[] = new X509Certificate[certs.length]; + + System.arraycopy(certs, 0, x509certs, 0, certs.length); + + return x509certs; + } + } + + /** + * Returns the private key for the specified ID. + * + * @param id The ID of the requested private key. + * @param key_password The passphrase associated with the private key or + * {@code null} if the key has no passphrase. + * @return PrivateKey for the specified ID. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public PrivateKey getKey(ID id, char[] key_password) throws KeyStoreException, IOException { + + String alias = id.toString(); + + try { + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + if (!store.containsAlias(alias) || !store.isKeyEntry(alias)) { + return null; + } + + return (PrivateKey) store.getKey(alias, key_password); + } + } catch (NoSuchAlgorithmException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Something failed", failed); + } + + KeyStoreException failure = new KeyStoreException("Something Failed"); + + failure.initCause(failed); + throw failure; + } catch (UnrecoverableKeyException failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Key passphrase failure", failed); + } + + KeyStoreException failure = new KeyStoreException("Key passphrase failure"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * Returns true if the specified id is associated with a private + * key. + * + * @param id The ID of the requested private key. + * @return true if a private key with the specified ID is present + * otherwise false + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public boolean isKey(ID id) throws KeyStoreException, IOException { + return isKey(id, keystore_password); + } + + /** + * Returns true if the specified id is associated with a private + * key. + * + * @param id The ID of the requested private key. + * @param store_password The passphrase used to unlock the keystore may be + * {@code null} for keystores with no passphrase. + * @return true if a private key with the specified ID is present + * otherwise false + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public boolean isKey(ID id, char[] store_password) throws KeyStoreException, IOException { + String alias = id.toString(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(store_password); + + return store.containsAlias(alias) & store.isKeyEntry(alias); + } + } + + /** + * Adds a trusted certificate with the specified id to the key store. The + * certificate replaces any existing certificate or private key stored at + * this ID. + * + * @param id The ID under which the certificate will be stored. + * @param cert Certificate for the specified ID. + * @throws KeyStoreException When the wrong keystore has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public void setTrustedCertificate(ID id, X509Certificate cert) throws KeyStoreException, IOException { + String alias = id.toString(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + store.deleteEntry(alias); + + store.setCertificateEntry(alias, cert); + + keystore_manager.saveKeyStore(store, keystore_password); + } + } + + /** + * Adds a private key to the PSE using the specified ID. The key replaces + * any existing certificate or private key stored at this ID. The key is + * stored using the provided key passphrase. + * + * @param id The ID under which the certificate chain and private key will be stored. + * @param certchain The certificate chain matching the private key. + * @param key The private key to be stored in the kestore. + * @param key_password The passphrase associated with the private key or + * {@code null} if the key has no passphrase. + * @throws KeyStoreException When the wrong keystore key has been provided. + * @throws IOException For errors related to processing the keystore. + */ + public void setKey(ID id, Certificate[] certchain, PrivateKey key, char[] key_password) throws KeyStoreException, IOException { + + String alias = id.toString(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + // Remove any existing entry. + store.deleteEntry(alias); + + store.setKeyEntry(alias, key, key_password, certchain); + + keystore_manager.saveKeyStore(store, keystore_password); + } + } + + /** + * Erases the specified id from the keystore. + * + * @param id The ID of the key or certificate to be deleted. + * @throws KeyStoreException When the wrong keystore password has been + * provided. + * @throws IOException For errors related to processing the keystore. + */ + public void erase(ID id) throws KeyStoreException, IOException { + String alias = id.toString(); + + synchronized (keystore_manager) { + KeyStore store = keystore_manager.loadKeyStore(keystore_password); + + store.deleteEntry(alias); + + keystore_manager.saveKeyStore(store, keystore_password); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSECredential.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSECredential.java new file mode 100644 index 000000000..0916f0049 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSECredential.java @@ -0,0 +1,861 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import net.jxta.credential.Credential; +import net.jxta.credential.CredentialPCLSupport; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.service.Service; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertPath; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class provides the sub-class of Credential which is associated with the + * PSE membership service. + *

            + * There are two varients of the credential: + *

            + *

              + *
            • local - Generated as a result of local login. This type of + * credential can be used for signing and can be serialized for inclusion + * in protocols.
            • + *
            • remote - Generated as a result of deserialization from protocols. + * The credential is verified to ensure that the contents are valid at the + * time it is created.
            • + *
            + *

            + * The schema for this credential format: + *

            + *

            
            + *  <xs:element name="PSECred" type="jxta:PSECred" />
            + * 

            + * <xs:complexType name="PSECred"> + * <xs:sequence> + * <xs:element name="PeerGroupID" type="jxta:JXTAID" /> + * <xs:element name="PeerID" type="jxta:JXTAID" /> + * <!-- An X.509 Certificate --> + * <xs:element name="Certificate" type="xs:string" minOccurs="1" maxOccurs="unbounded" /> + * <!-- A SHA1WithRSA Signature --> + * <xs:element name="Signature" type="xs:string" /> + * </xs:sequence> + * </xs:complexType> + * </code>

            + *

            + * FIXME 20050625 bondolo If the certificate chain for a credential is + * updated in the PSE keystore after a credential is created then the + * credential instance will not reflect those changes. This can be a problem if + * the issuer chain changes or expiries are updated. Even though it's going to + * be hit on performance PSECredential needs to changed to be backed by the PSE + * keystore directly rather than containing the certs. Either that or some kind + * of notification systems. It's probably best to assume that our simple cm + * based keystore is the easiest and least dynamic case. Every other key store + * is going to be more dynamic and difficult. The work around for now is to + * force a membership resign everytime the keystore contents are changed. + * + * @see net.jxta.credential.Credential + * @see net.jxta.impl.membership.pse.PSEMembershipService + */ +public final class PSECredential implements Credential, CredentialPCLSupport { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(PSECredential.class.getName()); + + /** + * A Timer we use for managing the cert expirations. + */ + private static Timer expirationTimer = new Timer("PSECredential Expiration Timer", true); + + /** + * The MembershipService service which generated this credential. + *

            + * XXX 20030609 bondolo@jxta.org Perhaps this should be a weak reference. + */ + private PSEMembershipService source; + + /** + * The peer group associated with this credential. + */ + private ID peerGroupID = null; + + /** + * The peerid associated with this credential. + */ + private ID peerID = null; + + /** + * The pse alias from which this credential was generated. Only locally + * created credentials will be intialized with a key ID. + */ + private ID keyID = null; + + /** + * The identity associated with this credential + */ + private CertPath certs = null; + + /** + * The private key associated with this credential. Used for signing. Only + * a locally created credential will have an initialized private key. + */ + private PrivateKey privateKey = null; + + /** + * Optional Timer task + */ + private TimerTask becomesValidTask = null; + private TimerTask expiresTask = null; + + /** + * Are we still a valid credential? + */ + private boolean valid = true; + + /** + * Is this a local credential? + */ + private final boolean local; + + /** + * property change support + */ + private PropertyChangeSupport support = new PropertyChangeSupport(this); + + /** + * Create a new local credential. This credential can be used for signing + * and can be serialized. + */ + protected PSECredential(PSEMembershipService source, ID keyID, CertPath certChain, PrivateKey privateKey) throws IOException { + this.source = source; + this.peerID = source.group.getPeerID(); + this.peerGroupID = source.group.getPeerGroupID(); + setKeyID(keyID); + setCertificateChain(certChain); + setPrivateKey(privateKey); + this.local = true; + } + + /** + * Create a new remote credential. This credential cannot be used for + * signing and cannot be re-serialized. + */ + public PSECredential(Element root) { + this.local = false; + initialize(root); + } + + /** + * Create a new remote credential. This credential cannot be used for + * signing and cannot be re-serialized. + */ + public PSECredential(PSEMembershipService source, Element root) { + this.local = false; + this.source = source; + initialize(root); + + if (!peerGroupID.equals(source.group.getPeerGroupID())) { + throw new IllegalArgumentException( + "Credential is from a different group. " + peerGroupID + " != " + source.group.getPeerGroupID()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + + if (this == target) { + return true; + } + + if (target instanceof PSECredential) { + PSECredential asCred = (PSECredential) target; + + boolean result = peerID.equals(asCred.peerID) + && source.group.getPeerGroupID().equals(asCred.source.group.getPeerGroupID()); + + result &= certs.equals(asCred.certs); + + return result; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + protected void finalize() throws Throwable { + if (null != becomesValidTask) { + becomesValidTask.cancel(); + } + + if (null != expiresTask) { + expiresTask.cancel(); + } + + super.finalize(); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = peerID.hashCode() * source.group.getPeerGroupID().hashCode() * certs.hashCode(); + + if (0 == result) { + result = 1; + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "\"" + getSubject() + "\" " + getPeerID() + " [" + source + " / " + getPeerGroupID() + "]"; + } + + /** + * Add a listener + * + * @param listener the listener + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * Add a listener + * + * @param propertyName the property to watch + * @param listener the listener + */ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.addPropertyChangeListener(propertyName, listener); + } + + /** + * Remove a listener + * + * @param listener the listener + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + /** + * Remove a listener + * + * @param propertyName the property which was watched + * @param listener the listener + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + /** + * {@inheritDoc} + */ + public ID getPeerGroupID() { + return peerGroupID; + } + + /** + * set the peer id associated with this credential + */ + private void setPeerGroupID(ID newID) { + this.peerGroupID = newID; + } + + /** + * {@inheritDoc} + */ + public ID getPeerID() { + return peerID; + } + + /** + * set the peer id associated with this credential + */ + private void setPeerID(PeerID peerID) { + this.peerID = peerID; + } + + /** + * {@inheritDoc} + *

            + * A PSE Credential is valid as long as the associated certificate is + * valid. + */ + public boolean isExpired() { + try { + ((X509Certificate) certs.getCertificates().get(0)).checkValidity(); + return false; + } catch (CertificateExpiredException expired) { + return true; + } catch (CertificateNotYetValidException notyet) { + return true; + } + } + + /** + * {@inheritDoc} + *

            + * A PSE Credential is valid as long as the associated certificate is + * valid and as long as the membership service still has the credential. + */ + public boolean isValid() { + return valid && !isExpired(); + } + + /** + * {@inheritDoc} + *

            + * A PSE Credential is valid as long as the associated certificate is + * valid. + */ + void setValid(boolean valid) { + boolean oldValid = isValid(); + + this.valid = valid; + + if (oldValid != valid) { + support.firePropertyChange("valid", oldValid, valid); + } + } + + /** + * {@inheritDoc} + */ + public Object getSubject() { + return ((X509Certificate) certs.getCertificates().get(0)).getSubjectDN(); + } + + /** + * {@inheritDoc} + */ + public Service getSourceService() { + return source; + } + + /** + * {@inheritDoc} + */ + public StructuredDocument getDocument(MimeMediaType encodeAs) throws Exception { + if (!isValid()) { + throw new javax.security.cert.CertificateException("Credential is not valid. Cannot generate document."); + } + + if (!local) { + throw new IllegalStateException("This credential is not a local credential and document cannot be created."); + } + + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(encodeAs, "jxta:Cred"); + + if (doc instanceof XMLDocument) { + ((XMLDocument) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((XMLDocument) doc).addAttribute("xml:space", "preserve"); + } + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("type", "jxta:PSECred"); + } + + Element e; + + e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); + doc.appendChild(e); + + e = doc.createElement("PeerID", getPeerID().toString()); + doc.appendChild(e); + + // add the Certificate element + + net.jxta.impl.protocol.Certificate certChain = new net.jxta.impl.protocol.Certificate(); + + List certsList = certs.getCertificates(); + + certChain.setCertificates(certsList); + + StructuredDocument certsDoc = (StructuredDocument) certChain.getDocument(encodeAs); + + if (certsDoc instanceof Attributable) { + ((Attributable) certsDoc).addAttribute("type", certsDoc.getKey().toString()); + } + + StructuredDocumentUtils.copyElements(doc, doc, certsDoc, "Certificate"); + + // Add the signature. + + List someStreams = new ArrayList(3); + + try { + someStreams.add(new ByteArrayInputStream(getPeerGroupID().toString().getBytes("UTF-8"))); + someStreams.add(new ByteArrayInputStream(getPeerID().toString().getBytes("UTF-8"))); + for (Object aCertsList : certsList) { + X509Certificate aCert = (X509Certificate) aCertsList; + + someStreams.add(new ByteArrayInputStream(aCert.getEncoded())); + } + + InputStream signStream = new SequenceInputStream(Collections.enumeration(someStreams)); + + byte[] sig = source.peerSecurityEngine.sign(source.peerSecurityEngine.getSignatureAlgorithm(), this, signStream); + + e = doc.createElement("Signature", PSEUtils.base64Encode(sig)); + doc.appendChild(e); + } catch (java.io.UnsupportedEncodingException never) {// UTF-8 is always available + } + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("algorithm", source.peerSecurityEngine.getSignatureAlgorithm()); + } + + return doc; + } + + /** + * Returns the certificate associated with this credential. + * + * @return the certificate associated with this credential. + */ + public X509Certificate getCertificate() { + return (X509Certificate) certs.getCertificates().get(0); + } + + /** + * Returns the certificate chain associated with this credential. + * + * @return the certificate chain associated with this credential. + */ + public X509Certificate[] getCertificateChain() { + List certList = certs.getCertificates(); + + return (X509Certificate[]) certList.toArray(new X509Certificate[certList.size()]); + } + + /** + * Set the certificate associated with this credential + * + * @param certChain the certificate chain associated with this credential. + */ + private void setCertificateChain(CertPath certChain) { + + certs = certChain; + + Date now = new Date(); + Date becomesValid = ((X509Certificate) certs.getCertificates().get(0)).getNotBefore(); + Date expires = ((X509Certificate) certs.getCertificates().get(0)).getNotAfter(); + + if (becomesValid.compareTo(now) > 0) { + if (null != becomesValidTask) { + becomesValidTask.cancel(); + } + + becomesValidTask = new TimerTask() { + + @Override + public void run() { + support.firePropertyChange("expired", false, true); + if (valid) { + support.firePropertyChange("valid", false, true); + } + } + }; + + expirationTimer.schedule(becomesValidTask, becomesValid); + } + + if (null != expiresTask) { + expiresTask.cancel(); + } + + if (expires.compareTo(now) > 0) { + expiresTask = new TimerTask() { + + @Override + public void run() { + support.firePropertyChange("expired", true, false); + if (valid) { + support.firePropertyChange("valid", true, false); + } + } + }; + + expirationTimer.schedule(expiresTask, expires); + } + + boolean nowGood = (null == becomesValidTask) && (null != expiresTask); + + support.firePropertyChange("expired", true, nowGood); + setValid(nowGood); + } + + /** + * Returns the private key associated with this credential. Only valid for + * locally generated credentials. + * + * @return the private key associated with this credential. + * @deprecated Use <@link #getSigner(String)> or <@link #getSignatureVerifier(String)> instead. + */ + @Deprecated + public PrivateKey getPrivateKey() { + + if (!local) { + throw new IllegalStateException("This credential is not a local credential and cannot be used for signing."); + } + + if (null == privateKey) { + throw new IllegalStateException("This local credential is engine based and cannot provide the private key."); + } + + return privateKey; + } + + /** + * Sets the private key associated with this credential. + * + * @param privateKey the private key associated with this credential. + */ + private void setPrivateKey(PrivateKey privateKey) { + + this.privateKey = privateKey; + } + + /** + * Returns the key id associated with this credential, if any. Only locally + * generated credentials have a key ID. + * + * @return Returns the key id associated with this credential, if any. + */ + public ID getKeyID() { + return keyID; + } + + /** + * Sets the key id associated with this credential. + */ + private void setKeyID(ID keyID) { + this.keyID = keyID; + } + + /** + * Get a Signature object based upon the private key associated with this + * credential. + * + * @param algorithm the signing algorithm to use. + * @return Signature. + */ + public Signature getSigner(String algorithm) throws NoSuchAlgorithmException { + if (!local) { + throw new IllegalStateException("This credential is not a local credential and cannot be used for signing."); + } + + Signature sign = Signature.getInstance(algorithm); + + try { + sign.initSign(privateKey); + } catch (java.security.InvalidKeyException failed) { + IllegalStateException failure = new IllegalStateException("Invalid private key"); + + failure.initCause(failed); + throw failure; + } + + return sign; + } + + /** + * /** + * Get a Signature verifier object based upon the certificate associated + * with this credential. + * + * @param algorithm the signing algorithm to use. + * @return Signature. + */ + public Signature getSignatureVerifier(String algorithm) throws NoSuchAlgorithmException { + Signature verify = Signature.getInstance(algorithm); + + try { + verify.initVerify((X509Certificate) certs.getCertificates().get(0)); + } catch (java.security.InvalidKeyException failed) { + IllegalStateException failure = new IllegalStateException("Invalid certificate"); + + failure.initCause(failed); + throw failure; + } + + return verify; + } + + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + */ + protected boolean handleElement(XMLElement elem) { + if (elem.getName().equals("PeerGroupID")) { + try { + ID pid = IDFactory.fromURI(new URI(elem.getTextValue())); + + setPeerGroupID((PeerGroupID) pid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerGroupID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a group id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("PeerID")) { + try { + ID pid = IDFactory.fromURI(new URI(elem.getTextValue())); + + setPeerID((PeerID) pid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad Peer ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a peer id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals("Certificate")) { + // XXX Compatibility hack so that net.jxta.impl.protocol.Certificate will recognize element + // as a certificate. + if (null == elem.getAttribute("type")) { + elem.addAttribute("type", net.jxta.impl.protocol.Certificate.getMessageType()); + } + + net.jxta.impl.protocol.Certificate certChain = new net.jxta.impl.protocol.Certificate(elem); + + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + certs = cf.generateCertPath(Arrays.asList(certChain.getCertificates())); + } catch (java.security.cert.CertificateException failure) { + throw new IllegalArgumentException("bad certificates in chain."); + } + + return true; + } + + if (elem.getName().equals("Signature")) { + + if (null == certs) { + throw new IllegalArgumentException("Signature out of order in Credential."); + } + + List someStreams = new ArrayList(3); + + try { + byte[] signatureToCompare = PSEUtils.base64Decode(new StringReader(elem.getTextValue())); + + someStreams.add(new ByteArrayInputStream(getPeerGroupID().toString().getBytes("UTF-8"))); + someStreams.add(new ByteArrayInputStream(getPeerID().toString().getBytes("UTF-8"))); + Iterator eachCert = certs.getCertificates().iterator(); + + for (Certificate certificate : certs.getCertificates()) { + X509Certificate aCert = (X509Certificate) certificate; + + someStreams.add(new ByteArrayInputStream(aCert.getEncoded())); + } + + InputStream signStream = new SequenceInputStream(Collections.enumeration(someStreams)); + + // FIXME 20051007 bondolo Fix handling of signature type. + + if (!PSEUtils.verifySignature("SHA1WITHRSA", getCertificate(), signatureToCompare, signStream)) { + throw new IllegalArgumentException("Certificated did not match"); + } + } catch (Throwable failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to validate signature ", failed); + } + + throw new IllegalArgumentException("Failed to validate signature " + failed.getMessage()); + } + + return true; + } + + // element was not handled + return false; + } + + /** + * Intialize from a portion of a structured document. + */ + protected void initialize(Element root) { + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + + XMLElement doc = (XMLElement) root; + + String typedoctype = ""; + + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + String doctype = doc.getName(); + + if (!doctype.equals("jxta:PSECred") && !typedoctype.equals("jxta:PSECred")) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + + // sanity check time! + + if (null == getSubject()) { + throw new IllegalArgumentException("subject was never initialized."); + } + + if (null == getPeerGroupID()) { + throw new IllegalArgumentException("peer group was never initialized."); + } + + if (null == getPeerID()) { + throw new IllegalArgumentException("peer id was never initialized."); + } + + if (null == certs) { + throw new IllegalArgumentException("certificates were never initialized."); + } + + // FIXME bondolo@jxta.org 20030409 should check for duplicate elements and for peergroup element + } + + public X509Certificate[] generateServiceCertificate(ID assignedID) throws IOException, KeyStoreException, InvalidKeyException, SignatureException { + return source.generateServiceCertificate(assignedID, this); + } + + public PSECredential getServiceCredential(ID assignedID) throws IOException, PeerGroupException, InvalidKeyException, SignatureException { + return source.getServiceCredential(assignedID, this); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSECrendentialBeanInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSECrendentialBeanInfo.java new file mode 100644 index 000000000..cf48a89ba --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSECrendentialBeanInfo.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.beans.BeanDescriptor; +import java.beans.EventSetDescriptor; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +import java.beans.IntrospectionException; +import java.lang.reflect.UndeclaredThrowableException; + + +/** + * BeanInfo for PSECrendential + **/ +public class PSECrendentialBeanInfo extends SimpleBeanInfo { + + /** + * {@inheritDoc} + **/ + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(PSECredential.class); + } + + /** + * {@inheritDoc} + **/ + @Override + public EventSetDescriptor[] getEventSetDescriptors() { + try { + EventSetDescriptor changed = new EventSetDescriptor(PSECredential.class, "propertyChange" + , + PropertyChangeListener.class, "propertyChange"); + + changed.setDisplayName("bound property change"); + + EventSetDescriptor[] rv = { changed }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } + + /** + * {@inheritDoc} + **/ + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor subject = new PropertyDescriptor("subject", PSECredential.class); + + PropertyDescriptor peerid = new PropertyDescriptor("peerID", PSECredential.class); + + PropertyDescriptor peerGroupID = new PropertyDescriptor("peerGroupID", PSECredential.class); + + PropertyDescriptor certificate = new PropertyDescriptor("certificate", PSECredential.class); + + PropertyDescriptor privatekey = new PropertyDescriptor("privateKey", PSECredential.class); + + PropertyDescriptor expired = new PropertyDescriptor("expired", PSECredential.class); + + expired.setBound(true); + + PropertyDescriptor valid = new PropertyDescriptor("valid", PSECredential.class); + + valid.setBound(true); + + PropertyDescriptor rv[] = { subject, peerid, peerGroupID, certificate, privatekey, expired, valid }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEKeyStoreManagerFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEKeyStoreManagerFactory.java new file mode 100644 index 000000000..3d28b78bb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEKeyStoreManagerFactory.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.util.NoSuchElementException; +import java.net.URI; +import java.io.File; + +import java.security.KeyStoreException; +import java.security.NoSuchProviderException; + +import net.jxta.peergroup.PeerGroup; +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.document.Element; +import net.jxta.protocol.ConfigParams; +import net.jxta.exception.PeerGroupException; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLElement; + +import net.jxta.impl.cm.Cm; +import net.jxta.impl.peergroup.StdPeerGroup; +import net.jxta.impl.protocol.PSEConfigAdv; + + +/** + * Encapsulates the behaviour for creating KeyStoreManager Objects. + **/ +public abstract class PSEKeyStoreManagerFactory { + + /** + * The default KeyStoreManagerGenerator + **/ + private static PSEKeyStoreManagerFactory defaultGenerator = null; + + /** + * Sets the default KeyStoreManagerGenerator. + * + * @param newDefault The new default KeyStoreManagerGenerator. + **/ + public static void setDefault(PSEKeyStoreManagerFactory newDefault) { + synchronized (PSEKeyStoreManagerFactory.class) { + defaultGenerator = newDefault; + } + } + + /** + * Returns the default KeyStoreManagerGenerator. + * + * @return The current default KeyStoreManagerGenerator. + **/ + public static PSEKeyStoreManagerFactory getDefault() { + synchronized (PSEKeyStoreManagerFactory.class) { + if (defaultGenerator == null) { + defaultGenerator = new PSEKeyStoreManagerFactoryDefault(); + } + + return defaultGenerator; + } + } + + /** + * Creates a new KeyStoreManager instance based upon the context and configuration. + * + * @param service The service that this keystore manager will be working for. + * @param config The configuration parameters. + **/ + public abstract KeyStoreManager getInstance(PSEMembershipService service, PSEConfigAdv config) throws PeerGroupException; + + /** + * Provides the default behaviour for generating KeyStore managers for PSE Membership Service Instances. + **/ + private static class PSEKeyStoreManagerFactoryDefault extends PSEKeyStoreManagerFactory { + + /** + * {@inheritDoc} + * + *

            If no location is specified then use the CMKeyStoreManager otherwise use the URIKeyStoreManager. + **/ + @Override + public KeyStoreManager getInstance(PSEMembershipService service, PSEConfigAdv config) throws PeerGroupException { + + URI location = config.getKeyStoreLocation(); + KeyStoreManager store_manager; + + try { + if (null == location) { + store_manager = new CMKeyStoreManager(config.getKeyStoreType(), config.getKeyStoreProvider() + , + service.getGroup(), service.getAssignedID()); + } else { + if (!location.isAbsolute()) { + // Resolve the location of the keystore relative to our prefs location. + location = service.group.getStoreHome().resolve(location); + } + + store_manager = new URIKeyStoreManager(config.getKeyStoreType(), config.getKeyStoreProvider(), location); + } + + return store_manager; + } catch (NoSuchProviderException not_available) { + throw new PeerGroupException("Requested KeyStore provider not available", not_available); + } catch (KeyStoreException bad) { + throw new PeerGroupException("KeyStore failure initializing KeyStoreManager", bad); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEMembershipService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEMembershipService.java new file mode 100644 index 000000000..0a6de2e14 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEMembershipService.java @@ -0,0 +1,797 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.net.URI; +import java.security.PrivateKey; +import java.security.cert.CertPath; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.InvalidKeyException; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.util.NoSuchElementException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.credential.Credential; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.membership.Authenticator; +import net.jxta.membership.MembershipService; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.service.Service; + +import net.jxta.id.ID; + +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; + +import net.jxta.impl.protocol.Certificate; +import net.jxta.impl.protocol.PSEConfigAdv; +import net.jxta.impl.membership.pse.PSEUtils.IssuerInfo; + + +/** + * A JXTA Membership Service utilizing PKI to provide secure identities. + * + * @see net.jxta.membership.MembershipService + **/ +public final class PSEMembershipService implements MembershipService { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(PSEMembershipService.class.getName()); + + /** + * Well known service specification identifier: pse membership + */ + public final static ModuleSpecID pseMembershipSpecID = (ModuleSpecID) ID.create( + URI.create(ID.URIEncodingName + ":" + ID.URNNamespace + ":uuid-DeadBeefDeafBabaFeedBabe000000050306")); + + /** + * the peergroup to which this service is associated. + **/ + PeerGroup group = null; + + /** + * The ID assigned to this instance. + **/ + private ID assignedID = null; + + /** + * The ModuleImplAdvertisement which was used to instantiate this service. + **/ + private ModuleImplAdvertisement implAdvertisement = null; + + /** + * The current set of principals associated with this peer within this peergroup. + **/ + private final List principals = new ArrayList(); + + /** + * The set of AuthenticationCredentials which were used to establish the principals. + **/ + private final List authCredentials = new ArrayList(); + + /** + * property change support + **/ + private final PropertyChangeSupport support; + + /** + * the keystore we are working with. + **/ + PSEConfig pseStore = null; + + /** + * the default credential + **/ + private PSECredential defaultCredential = null; + + /** + * The configuration we are using. + **/ + private PSEConfigAdv config; + + /** + * PSEPeerSecurityEngine ( and PSEAuthenticatorEngine ) loader + */ + + PSEPeerSecurityEngine peerSecurityEngine = null; + + private PSEAuthenticatorEngine authenticatorEngine = null; + + /** + * Default constructor. Normally only called by the peer group. + **/ + public PSEMembershipService() throws PeerGroupException { + support = new PropertyChangeSupport(getInterface()); + } + + /** + * @inheritDoc + **/ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * @inheritDoc + **/ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.addPropertyChangeListener(propertyName, listener); + } + + /** + * @inheritDoc + **/ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + /** + * @inheritDoc + **/ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + /** + * {@inheritDoc} + **/ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + this.group = group; + this.assignedID = assignedID; + this.implAdvertisement = (ModuleImplAdvertisement) impl; + + ConfigParams configAdv = group.getConfigAdvertisement(); + + // Get our peer-defined parameters in the configAdv + Element param = configAdv.getServiceParam(assignedID); + + Advertisement paramsAdv = null; + + if (null != param) { + try { + paramsAdv = AdvertisementFactory.newAdvertisement((XMLElement) param); + } catch (NoSuchElementException ignored) { + ; + } + + if (!(paramsAdv instanceof PSEConfigAdv)) { + throw new PeerGroupException("Provided Advertisement was not a " + PSEConfigAdv.getAdvertisementType()); + } + + config = (PSEConfigAdv) paramsAdv; + } else { + // Create the default advertisement. + config = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); + } + + peerSecurityEngine = PSESecurityEngineFactory.getDefault().getInstance(this, config); + + authenticatorEngine = PSEAuthenticatorEngineFactory.getDefault().getInstance(this, config); + + KeyStoreManager storeManager = PSEKeyStoreManagerFactory.getDefault().getInstance(this, config); + + pseStore = new PSEConfig(storeManager, null); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring PSE Membership Service : " + assignedID); + + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: " + implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : " + implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : " + implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : " + implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : " + group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID : " + group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID : " + group.getPeerID()); + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tPSE state : " + (pseStore.isInitialized() ? "inited" : "new")); + configInfo.append( + "\n\t\tPSE KeyStore location : " + + ((null != config.getKeyStoreLocation()) + ? config.getKeyStoreLocation().toString() + : assignedID.toString())); + configInfo.append( + "\n\t\tPSE KeyStore type : " + ((null != config.getKeyStoreType()) ? config.getKeyStoreType() : "")); + configInfo.append( + "\n\t\tPSE KeyStore provider : " + + ((null != config.getKeyStoreProvider()) ? config.getKeyStoreProvider() : "")); + LOG.config(configInfo.toString()); + } + + resign(); + } + + /** + * {@inheritDoc} + **/ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + **/ + public Advertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + * + *

            Currently this service starts by itself and does not expect + * arguments. + */ + public int startApp(String[] arg) { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("PSE Membmership Service started."); + } + + return 0; + } + + /** + * {@inheritDoc} + **/ + public void stopApp() { + resign(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("PSE Membmership Service stopped."); + } + } + + public PeerGroup getGroup() { + return group; + } + + public ID getAssignedID() { + return assignedID; + } + + /** + * {@inheritDoc} + * + *

            Supports methods "StringAuthentication", + * "DialogAuthentication", + * "EngineAuthentication" and + * "InteractiveAuthentication" (an alias for + * "DialogAuthentication") + **/ + public Authenticator apply(AuthenticationCredential application) throws ProtocolNotSupportedException { + + String method = application.getMethod(); + + boolean newKey; + + if (!pseStore.isInitialized()) { + // It is not inited, it's new. + newKey = true; + } else { + X509Certificate configCert = config.getCertificate(); + + if (null != configCert) { + try { + ID allTrustedCerts[] = pseStore.getTrustedCertsList(); + + Iterator eachTrustedCert = Arrays.asList(allTrustedCerts).iterator(); + + newKey = true; + + // See if the config cert is already in the keystore. + while (eachTrustedCert.hasNext()) { + ID aTrustedCertID = (ID) eachTrustedCert.next(); + + if (pseStore.isKey(aTrustedCertID)) { + X509Certificate aTrustedCert = pseStore.getTrustedCertificate(aTrustedCertID); + + if (aTrustedCert.equals(configCert)) { + newKey = false; + break; + } + } + } + } catch (KeyStoreException bad) { + // The keystore is probably initialized but locked. Nothing else we can do. + newKey = false; + } catch (IOException bad) { + // Could not read the keystore. I'm not sure it wouldn't be better to just fail. + newKey = false; + } + } else { + // don't have anything to validate against. + newKey = false; + } + } + + if ("StringAuthentication".equals(method)) { + if (newKey) { + return new StringAuthenticator(this, application, config.getCertificate(), config.getEncryptedPrivateKey()); + } else { + return new StringAuthenticator(this, application); + } + } else if ("EngineAuthentication".equals(method)) { + if (pseStore.isInitialized()) { + return new EngineAuthenticator(this, application, authenticatorEngine); + } else { + return new EngineAuthenticator(this, application, authenticatorEngine); + } + } else if ("DialogAuthentication".equals(method) || "InteractiveAuthentication".equals(method) || (null == method)) { + if (newKey) { + return new DialogAuthenticator(this, application, config.getCertificate(), config.getEncryptedPrivateKey()); + } else { + return new DialogAuthenticator(this, application); + } + } else { + throw new ProtocolNotSupportedException("Authentication method not recognized"); + } + } + + /** + * {@inheritDoc} + **/ + public Credential getDefaultCredential() { + return defaultCredential; + } + + /** + * Sets the default credential. Also updates the peer advertisement with + * the certificate of the default credential. + * + * @param newDefault the new default credential. May also be + * null if no default is desired. + **/ + private void setDefaultCredential(PSECredential newDefault) { + + Credential oldDefault = defaultCredential; + + synchronized (this) { + defaultCredential = newDefault; + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("New Default credential : " + newDefault); + } + + try { + // include the root cert in the peer advertisement + PeerAdvertisement peeradv = group.getPeerAdvertisement(); + + if (null != newDefault) { + // include the root cert in the peer advertisement + XMLDocument paramDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + + Certificate peerCerts = new Certificate(); + + peerCerts.setCertificates(newDefault.getCertificateChain()); + + XMLDocument peerCertsAsDoc = (XMLDocument) peerCerts.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(paramDoc, paramDoc, peerCertsAsDoc, "RootCert"); + + peeradv.putServiceParam(PeerGroup.peerGroupClassID, paramDoc); + } else { + peeradv.removeServiceParam(PeerGroup.peerGroupClassID); + } + } catch (Exception ignored) { + ; + } + + support.firePropertyChange("defaultCredential", oldDefault, newDefault); + } + + /** + * {@inheritDoc} + **/ + public Enumeration getCurrentCredentials() { + List credList = new ArrayList(principals); + + return Collections.enumeration(credList); + } + + /** + * {@inheritDoc} + **/ + public Enumeration getAuthCredentials() { + List credList = new ArrayList(authCredentials); + + return Collections.enumeration(credList); + } + + /** + * {@inheritDoc} + **/ + public Credential join(Authenticator authenticated) throws PeerGroupException { + + if (this != authenticated.getSourceService()) { + throw new ClassCastException("This is not my authenticator!"); + } + + if (!authenticated.isReadyForJoin()) { + throw new PeerGroupException("Authenticator not ready to join!"); + } + + PSECredential newCred; + + char[] store_password = null; + ID identity; + char[] key_password = null; + + try { + if (authenticated instanceof StringAuthenticator) { + StringAuthenticator auth = (StringAuthenticator) authenticated; + + store_password = auth.getAuth1_KeyStorePassword(); + identity = auth.getAuth2Identity(); + key_password = auth.getAuth3_IdentityPassword(); + } else if (authenticated instanceof EngineAuthenticator) { + EngineAuthenticator auth = (EngineAuthenticator) authenticated; + + store_password = auth.getAuth1_KeyStorePassword(); + identity = auth.getAuth2Identity(); + key_password = auth.getAuth3_IdentityPassword(); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("I dont know how to deal with this authenticator " + authenticated); + } + + throw new PeerGroupException("I dont know how to deal with this authenticator"); + } + + if (null != store_password) { + pseStore.setKeyStorePassword(store_password); + } + + if (!pseStore.isInitialized()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Initializing the PSE key store."); + } + + try { + pseStore.initialize(); + } catch (KeyStoreException bad) { + throw new PeerGroupException("Could not initialize new PSE keystore.", bad); + } catch (IOException bad) { + throw new PeerGroupException("Could not initialize new PSE keystore.", bad); + } + } + + try { + ID[] allkeys = pseStore.getKeysList(); + + if (!Arrays.asList(allkeys).contains(identity)) { + // Add this key to the keystore. + X509Certificate[] seed_cert = config.getCertificateChain(); + + if (null == seed_cert) { + throw new IOException("Could not read root certificate chain"); + } + + PrivateKey seedPrivKey = config.getPrivateKey(key_password); + + if (null == seedPrivKey) { + throw new IOException("Could not read private key"); + } + + pseStore.setKey(identity, seed_cert, seedPrivKey, key_password); + } + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not save new key pair.", failed); + } + + throw new PeerGroupException("Could not save new key pair.", failed); + } catch (KeyStoreException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not save new key pair.", failed); + } + + throw new PeerGroupException("Could not save new key pair.", failed); + } + + try { + X509Certificate certList[] = pseStore.getTrustedCertificateChain(identity); + + if (null == certList) { + certList = new X509Certificate[1]; + + certList[0] = pseStore.getTrustedCertificate(identity); + + if (certList[0] == null && authenticatorEngine != null) { + certList[0] = authenticatorEngine.getX509Certificate(); + } + } + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + CertPath certs = cf.generateCertPath(Arrays.asList(certList)); + + PrivateKey privateKey = pseStore.getKey(identity, key_password); + + newCred = new PSECredential(this, identity, certs, privateKey); + + synchronized (this) { + principals.add(newCred); + + authCredentials.add(authenticated.getAuthenticationCredential()); + } + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not create credential.", failed); + } + + throw new PeerGroupException("Could not create credential.", failed); + } catch (KeyStoreException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not create credential.", failed); + } + + throw new PeerGroupException("Could not create credential.", failed); + } catch (CertificateException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not create credential.", failed); + } + + throw new PeerGroupException("Could not create credential.", failed); + } + } finally { + if (null != store_password) { + Arrays.fill(store_password, '\0'); + } + + if (null != key_password) { + Arrays.fill(key_password, '\0'); + } + } + + // XXX bondolo potential but unlikely race condition here. + if (null == getDefaultCredential()) { + setDefaultCredential(newCred); + } + + support.firePropertyChange("addCredential", null, newCred); + + return newCred; + } + + /** + * {@inheritDoc} + **/ + public void resign() { + Iterator eachCred = Arrays.asList(principals.toArray()).iterator(); + + synchronized (this) { + principals.clear(); + authCredentials.clear(); + } + + setDefaultCredential(null); + + // clear the keystore password. + pseStore.setKeyStorePassword(null); + + while (eachCred.hasNext()) { + PSECredential aCred = (PSECredential) eachCred.next(); + + aCred.setValid(false); + } + } + + /** + * {@inheritDoc} + **/ + public Credential makeCredential(Element element) { + + return new PSECredential(this, element); + } + + /** + * Returns the key store object associated with this PSE Membership Service. + **/ + public PSEConfig getPSEConfig() { + return pseStore; + } + + /** + * Service Certificates Support + */ + + /** + * Generate a new service certificate for the assigned ID given an authenticated local credential. + * + * @param assignedID The assigned ID of the service credential. + * @param credential The issuer credential for the service credential. + **/ + X509Certificate[] generateServiceCertificate(ID assignedID, PSECredential credential) throws IOException, KeyStoreException, InvalidKeyException, SignatureException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Generating new service cert for " + assignedID); + } + + IssuerInfo serviceinfo = peerSecurityEngine.generateCertificate(credential); + + // write the client root cert and private key + X509Certificate[] serviceChain = { serviceinfo.cert, serviceinfo.issuer }; + + char keyPass[]; + + if (null != serviceinfo.issuerPkey) { + ByteArrayInputStream bis = new ByteArrayInputStream(serviceinfo.issuerPkey.getEncoded()); + byte privateKeySignature[] = peerSecurityEngine.sign(null, credential, bis); + + keyPass = PSEUtils.base64Encode(privateKeySignature, false).toCharArray(); + } else { + keyPass = authenticatorEngine.getKeyPass(group); + } + + getPSEConfig().setKey(assignedID, serviceChain, serviceinfo.subjectPkey, keyPass); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Generated new service cert"); + } + + return serviceChain; + } + + /** + * Recover the service credential for the assigned ID given an authenticated local credential. + * + * @param assignedID The assigned ID of the service credential. + * @param credential The issuer credential for the service credential. + **/ + public PSECredential getServiceCredential(ID assignedID, PSECredential credential) throws IOException, PeerGroupException, InvalidKeyException, SignatureException { + + PSECredential pseCredential = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting service redential for " + assignedID); + } + + Authenticator authenticate = null; + + if (null != authenticatorEngine) { + AuthenticationCredential authCred = new AuthenticationCredential(group, "EngineAuthentication", null); + + try { + authenticate = apply(authCred); + } catch (Exception failed) { + ; + } + + if (null == authenticate) { + return null; + } + + EngineAuthenticator auth = (EngineAuthenticator) authenticate; + + auth.setAuth1_KeyStorePassword(authenticatorEngine.getStorePass(group)); + auth.setAuth2Identity(assignedID); + auth.setAuth3_IdentityPassword(authenticatorEngine.getKeyPass(group)); + } else { + AuthenticationCredential authCred = new AuthenticationCredential(group, "StringAuthentication", null); + + try { + authenticate = apply(authCred); + } catch (Exception failed) { + ; + } + + if (null == authenticate) { + return null; + } + + PrivateKey privateKey = credential.getPrivateKey(); + + // make a new service certificate + ByteArrayInputStream bis = new ByteArrayInputStream(privateKey.getEncoded()); + byte privateKeySignature[] = peerSecurityEngine.sign(null, credential, bis); + String passkey = PSEUtils.base64Encode(privateKeySignature, false); + + StringAuthenticator auth = (StringAuthenticator) authenticate; + + auth.setAuth1_KeyStorePassword((String) null); + auth.setAuth2Identity(assignedID); + auth.setAuth3_IdentityPassword(passkey); + } + + if (authenticate.isReadyForJoin()) { + pseCredential = (PSECredential) join(authenticate); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not authenticate service credential"); + } + } + + return pseCredential; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEMembershipServiceBeanInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEMembershipServiceBeanInfo.java new file mode 100644 index 000000000..559a61caa --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEMembershipServiceBeanInfo.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.membership.pse; + + +import java.beans.BeanDescriptor; +import java.beans.EventSetDescriptor; +import java.beans.SimpleBeanInfo; +import java.beans.PropertyDescriptor; + +import java.beans.IntrospectionException; +import java.lang.reflect.UndeclaredThrowableException; + + +/** + * Our beaninfo + **/ +public class PSEMembershipServiceBeanInfo extends SimpleBeanInfo { + + /** + * {@inheritDoc} + **/ + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(PSEMembershipService.class); + } + + /** + * {@inheritDoc} + **/ + @Override + public EventSetDescriptor[] getEventSetDescriptors() { + try { + EventSetDescriptor changed = new EventSetDescriptor(PSEMembershipService.class, "propertyChange" + , + java.beans.PropertyChangeListener.class, "propertyChange"); + + changed.setDisplayName("bound property change"); + + EventSetDescriptor[] rv = { changed }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } + + /** + * {@inheritDoc} + **/ + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor defaultcredential = new PropertyDescriptor("defaultCredential", PSEMembershipService.class + , + "getDefaultCredential", "setDefaultCredential"); + + defaultcredential.setBound(true); + + PropertyDescriptor addcredential = new PropertyDescriptor("addCredential", PSEMembershipService.class); + + addcredential.setBound(true); + + PropertyDescriptor rv[] = { addcredential, defaultcredential }; + + return rv; + } catch (IntrospectionException failed) { + throw new UndeclaredThrowableException(failed, "Configuration error"); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEPeerSecurityEngine.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEPeerSecurityEngine.java new file mode 100644 index 000000000..11c544b61 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEPeerSecurityEngine.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.membership.pse; + + +import java.io.InputStream; +import java.io.IOException; +import java.security.PublicKey; +import java.security.InvalidKeyException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.KeyPair; + +import javax.security.auth.x500.X500Principal; + +import net.jxta.impl.membership.pse.PSEUtils.IssuerInfo; + + +/** + * Provides algorithm support for PSE. + * + **/ +public interface PSEPeerSecurityEngine { + + /** + * Cryptographically sign an input stream using the specified credential + * with the specified algorithm. + * + * @param algorithm The signature algorithm to use. + * @param credential The credential which is signing the stream. + * @param bis The input stream to be signed. + * @return The resulting signature. + **/ + public byte[] sign(String algorithm, PSECredential credential, InputStream bis) throws InvalidKeyException, SignatureException, IOException; + + /** + * Cryptographically verify a signature against an input stream using the + * specified credential with the specified algorithm. + * + * @param algorithm The signature algorithm to use. + * @param signature The signature to be verified. + * @param credential The credential which is signing the stream. + * @param bis The input stream to be signed. + * @return {@code true} If the signature is valid otherwise {@code false}. + **/ + public boolean verify(String algorithm, PSECredential credential, byte[] signature, InputStream bis) throws InvalidKeyException, SignatureException, IOException; + + /** + * Generate a new service certificate. + * + * @param credential The credential which will be the issuer of the service certificate. + **/ + public IssuerInfo generateCertificate(PSECredential credential) throws SecurityException; + + /** + * Returns the default signature algorithm for this security engine. + **/ + public String getSignatureAlgorithm(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSESecurityEngineFactory.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSESecurityEngineFactory.java new file mode 100644 index 000000000..b108b3f52 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSESecurityEngineFactory.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.SignatureException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.exception.PeerGroupException; +import net.jxta.impl.protocol.PSEConfigAdv; + +import net.jxta.impl.membership.pse.PSEUtils.IssuerInfo; + + +/** + * A factory for PSE Security Engines. + * + * @see PSEPeerSecurityEngine + */ +public abstract class PSESecurityEngineFactory { + + private static PSESecurityEngineFactory defaultSecurityEngine = null; + + /** + * Set the default PSESecurityEngineFactoryss + **/ + public static void setPSESecurityEngineManager(PSESecurityEngineFactory newSecurityEngine) { + synchronized (PSESecurityEngineFactory.class) { + defaultSecurityEngine = newSecurityEngine; + } + } + + /** + * Returns the default Security Engine Factory. + * + * @return The current default Security Engine Factory. + **/ + public static PSESecurityEngineFactory getDefault() { + synchronized (PSESecurityEngineFactory.class) { + if (defaultSecurityEngine == null) { + defaultSecurityEngine = new PSESecurityEngineDefaultFactory(); + } + + return defaultSecurityEngine; + } + } + + /** + * Creates a new Peer Security Engine instance based upon the context and configuration.sss + * + * @param service The service that this keystore manager will be working for. + * @param config The configuration parameters. + **/ + public abstract PSEPeerSecurityEngine getInstance(PSEMembershipService service, PSEConfigAdv config) throws PeerGroupException; + + /** + * Default implementation which provides the default behaviour (which is to do nothing). + **/ + private static class PSESecurityEngineDefaultFactory extends PSESecurityEngineFactory { + @Override + public PSEPeerSecurityEngine getInstance(PSEMembershipService service, PSEConfigAdv config) throws PeerGroupException { + return new PSEPeerSecurityEngineDefault(); + } + } + + + /** + * Default implementation which provides the default behaviour. + **/ + private static class PSEPeerSecurityEngineDefault implements PSEPeerSecurityEngine { + + /** + * Log4J Logger + **/ + private static final Logger LOG = Logger.getLogger(PSEPeerSecurityEngineDefault.class.getName()); + + /** + * {@inheritDoc} + **/ + public byte[] sign(String algorithm, PSECredential credential, InputStream bis) throws InvalidKeyException, SignatureException, IOException { + + if (null == algorithm) { + algorithm = getSignatureAlgorithm(); + } + + return PSEUtils.computeSignature(algorithm, credential.getPrivateKey(), bis); + } + + /** + * {@inheritDoc} + **/ + public boolean verify(String algorithm, PSECredential credential, byte[] signature, InputStream bis) throws InvalidKeyException, SignatureException, IOException { + if (null == algorithm) { + algorithm = getSignatureAlgorithm(); + } + + return PSEUtils.verifySignature(algorithm, credential.getCertificate(), signature, bis); + } + + /** + * {@inheritDoc} + **/ + public IssuerInfo generateCertificate(PSECredential credential) throws SecurityException { + + // we need a new cert. + IssuerInfo info = new IssuerInfo(); + + info.cert = credential.getCertificate(); + info.subjectPkey = credential.getPrivateKey(); + String cname = PSEUtils.getCertSubjectCName(info.cert); + + if (null != cname) { + // remove the -CA which is common to ca root certs. + if (cname.endsWith("-CA")) { + cname = cname.substring(0, cname.length() - 3); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Generating new service cert for \'" + cname + "\'"); + } + + // generate the service cert and private key + IssuerInfo serviceinfo = PSEUtils.genCert(cname, info); + + // IssuerInfo serviceinfo = membership.genCert( cname, info, "SHA1withRSA" ); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Generated new service cert for \'" + cname + "\'"); + } + + return serviceinfo; + } + + /** + * {@inheritDoc} + **/ + public String getSignatureAlgorithm() { + return "SHA1withRSA"; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEUtils.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEUtils.java new file mode 100644 index 000000000..9e923a7b7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEUtils.java @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import net.jxta.impl.util.BASE64InputStream; +import net.jxta.impl.util.BASE64OutputStream; +import net.jxta.logging.Logging; +import org.bouncycastle.asn1.x509.X509NameTokenizer; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.x509.X509V3CertificateGenerator; + +import javax.crypto.Cipher; +import javax.crypto.EncryptedPrivateKeyInfo; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import javax.security.auth.x500.X500Principal; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Calendar; +import java.util.Date; +import java.util.Hashtable; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Singleton class of static utility methods. + */ +public final class PSEUtils { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(PSEUtils.class.getName()); + + /** + * Singleton instance. + */ + private static final PSEUtils UTILS = new PSEUtils(); + + /** + * A SecureRandom for generating keys. + */ + final transient SecureRandom srng = new SecureRandom(); + + /** + * Singleton utility class + */ + private PSEUtils() { + + try { + ClassLoader sysloader = ClassLoader.getSystemClassLoader(); + + Class loaded = sysloader.loadClass(BouncyCastleProvider.class.getName()); + + Provider provider = (Provider) loaded.newInstance(); + + Security.addProvider(provider); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Loaded Security Providers into system class loader"); + } + } catch (Exception disallowed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, + "Failed loading Security Providers into System Class Loader. Will try local class loader (which may not work)", + disallowed); + } + + // Add the providers we use. + Security.addProvider(new BouncyCastleProvider()); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Loaded Security Providers into local class loader"); + } + } + + // Provider [] providers = Security.getProviders(); + // Iterator eachProvider = Arrays.asList(providers).iterator(); + // + // while (eachProvider.hasNext()) { + // Provider aProvider = (Provider) eachProvider.next(); + // + // System.out.println("\n\n" + aProvider.getName() + " - " + aProvider.getVersion() + " - " + aProvider.getInfo()); + // + // Iterator allMappings = aProvider.entrySet().iterator(); + // + // while (allMappings.hasNext()) { + // Map.Entry aMapping = (Map.Entry) allMappings.next(); + // + // Object key = aMapping.getKey(); + // System.out.println(key + " (" + key.getClass().getName() + ") --> " + aMapping.getValue() + " (" + key.getClass().getName() + ")"); + // } + // } + } + + /** + * Issuer Information + */ + public static class IssuerInfo { + public X509Certificate cert; // subject Cert + public PrivateKey subjectPkey; // subject private key + public X509Certificate issuer; // issuer Cert + public PrivateKey issuerPkey; // issuer private key + } + + /** + * Generate a Cert + * + * @param cn subject cn for the certificate + * @param issuerinfo the cert issuer or null if self-signed root cert. + * @return the details of the generated cert. + * @throws SecurityException if the cert could not be generated. + */ + public static IssuerInfo genCert(String cn, IssuerInfo issuerinfo) throws SecurityException { + try { + String useCN; + + if (null == issuerinfo) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Generating Self Signed Cert ..."); + } + + if (!cn.endsWith("-CA")) { + useCN = cn + "-CA"; + } else { + useCN = cn; + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Generating Client Cert ..."); + } + + useCN = cn; + } + + // set name attribute + Hashtable attrs = new Hashtable(); + + attrs.put(X509Principal.CN, useCN); + attrs.put(X509Principal.O, "www.jxta.org"); + + // XXX bondolo 20040405 wouldn't SN or UID be a better choice? + // set ou to 20 random digits + byte[] ou = new byte[10]; + + UTILS.srng.nextBytes(ou); + String ouStr = toHexDigits(ou); + + attrs.put(X509Principal.OU, ouStr); + + X509Principal subject = new X509Principal(attrs); + X500Principal samesubject = new X500Principal(subject.getEncoded()); + KeyPairGenerator g = KeyPairGenerator.getInstance("RSA"); + + g.initialize(1024, UTILS.srng); + + KeyPair keypair = g.generateKeyPair(); + + return genCert(samesubject, keypair, issuerinfo); + } catch (NoSuchAlgorithmException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not generate certificate", e); + } + SecurityException failure = new SecurityException("Could not generate certificate"); + + failure.initCause(e); + throw failure; + } + } + + /** + * Generate a Cert given a keypair + * + * @param subject subjectDN for the certificate + * @param keypair the keypair to use. + * @param issuerinfo the cert issuer or null if self-signed root cert. + * @return the details of the generated cert. + * @throws SecurityException if the cert could not be generated. + */ + public static IssuerInfo genCert(X500Principal subject, KeyPair keypair, IssuerInfo issuerinfo) throws SecurityException { + try { + // set up issuer + PrivateKey signer; + X509Principal issuer; + + if (null == issuerinfo) { // self-signed root cert + signer = keypair.getPrivate(); + issuer = new X509Principal(subject.getEncoded()); + } else { // issuer signed service sert + signer = issuerinfo.subjectPkey; + X500Principal issuer_subject = issuerinfo.cert.getSubjectX500Principal(); + + issuer = new X509Principal(issuer_subject.getEncoded()); + } + + // set validity 10 years from today + Date today = new Date(); + Calendar cal = Calendar.getInstance(); + + cal.setTime(today); + cal.add(Calendar.YEAR, 10); + Date until = cal.getTime(); + + // generate cert + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + + certGen.setIssuerDN(issuer); + certGen.setSubjectDN(new X509Principal(subject.getEncoded())); + certGen.setNotBefore(today); + certGen.setNotAfter(until); + certGen.setPublicKey(keypair.getPublic()); + // certGen.setSignatureAlgorithm("SHA1withDSA"); + certGen.setSignatureAlgorithm("SHA1WITHRSA"); + // FIXME bondolo 20040317 needs fixing. + certGen.setSerialNumber(BigInteger.valueOf(1)); + + // return issuer info for generating service cert + IssuerInfo info = new IssuerInfo(); + + // the cert + info.cert = certGen.generateX509Certificate(signer, UTILS.srng); + + // For saving service cert private key + info.subjectPkey = keypair.getPrivate(); + + // for signing service cert + info.issuer = (null == issuerinfo) ? info.cert : issuerinfo.cert; + + // for signing service cert + info.issuerPkey = signer; + + // dump the certificate? + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (null == issuer) { + LOG.fine("Root Cert : \n" + info.cert.toString()); + } else { + LOG.fine("Client Cert : \n" + info.cert.toString()); + } + } + + return info; + } catch (SignatureException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.FINE, "Could not generate certificate", e); + } + + SecurityException failure = new SecurityException("Could not generate certificate"); + + failure.initCause(e); + throw failure; + } catch (InvalidKeyException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.FINE, "Could not generate certificate", e); + } + + SecurityException failure = new SecurityException("Could not generate certificate"); + + failure.initCause(e); + throw failure; + } catch (IOException e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.FINE, "Could not generate certificate", e); + } + + SecurityException failure = new SecurityException("Could not generate certificate"); + + failure.initCause(e); + throw failure; + } + } + + /** + * return the CN token from the provided cert's subjectDN + * + * @param cert the certificate to examine + * @return the CN name or null if none could be found. + */ + public static String getCertSubjectCName(X509Certificate cert) { + + // get the subject dname + X500Principal subject = cert.getSubjectX500Principal(); + + X509NameTokenizer tokens = new X509NameTokenizer(subject.getName()); + + // iterate over the attributes of the dname + while (tokens.hasMoreTokens()) { + String aToken = tokens.nextToken(); + + if (aToken.length() < 3) { + continue; + } + + String attribute = aToken.substring(0, 3); + + if ("CN=".equalsIgnoreCase(attribute)) { + return aToken.substring(3); + } + } + + return null; + } + + /** + * return the CN token from the provided cert's issuerDN + * + * @param cert the certificate to examine + * @return the CN name or null if none could be found. + */ + public static String getCertIssuerCName(X509Certificate cert) { + + // get the subject dname + X500Principal issuer = cert.getIssuerX500Principal(); + + X509NameTokenizer tokens = new X509NameTokenizer(issuer.getName()); + + // iterate over the attributes of the dname + while (tokens.hasMoreTokens()) { + String aToken = tokens.nextToken(); + + if (aToken.length() < 3) { + continue; + } + + String attribute = aToken.substring(0, 3); + + if ("CN=".equalsIgnoreCase(attribute)) { + return aToken.substring(3); + } + } + + return null; + } + + /** + * Compute the signature of a stream. + * + * @param key the private key used to sign the stream + * @param stream the stream to sign. + * @return byte[] the signature + */ + public static byte[] computeSignature(String algorithm, PrivateKey key, InputStream stream) throws InvalidKeyException, SignatureException, IOException { + Signature sign; + + try { + sign = Signature.getInstance(algorithm); + } catch (NoSuchAlgorithmException badsigner) { + throw new IOException("Could not initialize signer with algorithm " + algorithm); + } + sign.initSign(key, UTILS.srng); + + byte[] buffer = new byte[1024]; + + while (true) { + int read = stream.read(buffer); + + if (read < 0) { + break; + } + + sign.update(buffer, 0, read); + } + + return sign.sign(); + } + + /** + * Verify a signature of a stream. + * + * @param cert The certificate containing the public key which will be used + * to verify the signature. + * @param signature The signature to verify. + * @param stream The stream to verify. + * @return boolean true if the signature was valid otherwise false. + */ + public static boolean verifySignature(String algorithm, Certificate cert, byte[] signature, InputStream stream) throws InvalidKeyException, SignatureException, IOException { + Signature sign; + + try { + sign = Signature.getInstance(algorithm); + } catch (NoSuchAlgorithmException badsigner) { + throw new IOException("Could not initialize signer with algorithm " + algorithm); + } + + sign.initVerify(cert); + + byte[] buffer = new byte[1024]; + + while (true) { + int read = stream.read(buffer); + + if (read < 0) { + break; + } + + sign.update(buffer, 0, read); + } + + return sign.verify(signature); + } + + /** + * returns a hash SHA-1 of the given byte array + * + * @param data the data to be hashed + * @return byte[] the hash of the data + */ + public static byte[] hash(String algorithm, byte[] data) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + + return digest.digest(data); + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + /** + * We are trying to use : PBEWITHMD5ANDDES + */ + static final String PKCS5_PBSE1_ALGO = "PBEWITHMD5ANDDES"; + + /** + * Given a private key and a password, encrypt the private key using the + * PBESE1 algorithm. + * + * @param password The password which will be used. + * @param privkey The private key to be encrypted. + * @param iterations Number of iterations. + * @return An encrypted private key info or null if the key could not be + * encrypted. + */ + public static EncryptedPrivateKeyInfo pkcs5_Encrypt_pbePrivateKey(char[] password, PrivateKey privkey, int iterations) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Encrypting " + privkey + " with \'" + new String(password) + "\'"); + } + + PBEKeySpec pbeKeySpec = new PBEKeySpec(password); + byte[] salt = new byte[8]; + + UTILS.srng.nextBytes(salt); + + try { + PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, iterations); + + // convert password into a SecretKey object, using a PBE key factory. + SecretKeyFactory keyFac = SecretKeyFactory.getInstance(PKCS5_PBSE1_ALGO); + SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); + + // Create PBE Cipher + Cipher pbeCipher = Cipher.getInstance(PKCS5_PBSE1_ALGO); + + // Initialize PBE Cipher with key and parameters + pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); + + byte[] encryptedPrivKey = pbeCipher.doFinal(privkey.getEncoded()); + + AlgorithmParameters algo = AlgorithmParameters.getInstance(PKCS5_PBSE1_ALGO); + + algo.init(pbeParamSpec); + + EncryptedPrivateKeyInfo result = new EncryptedPrivateKeyInfo(algo, encryptedPrivKey); + + return result; + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Encrypt failed", failed); + } + return null; + } + } + + /** + * Given an encrypted private key and a password, decrypt the private key + * using the PBESE1 algorithm. + * + * @param password The password which will be used. + * @param encryptedPrivKey The private key to be encrypted. + * @return The decrypted private key or null if the key could not be decrpyted. + */ + public static PrivateKey pkcs5_Decrypt_pbePrivateKey(char[] password, String algorithm, EncryptedPrivateKeyInfo encryptedPrivKey) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Decrypting " + encryptedPrivKey + "/" + algorithm + " with \'" + new String(password) + "\'"); + } + + PBEKeySpec pbeKeySpec = new PBEKeySpec(password); + + try { + AlgorithmParameters algo = encryptedPrivKey.getAlgParameters(); + + if (null == algo) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not get algo parameters from " + encryptedPrivKey); + } + + throw new IllegalStateException("Could not get algo parameters from " + encryptedPrivKey); + } + + PBEParameterSpec pbeParamSpec = algo.getParameterSpec(PBEParameterSpec.class); + + // convert password into a SecretKey object, using a PBE key factory. + try { + SecretKeyFactory keyFac = SecretKeyFactory.getInstance(PKCS5_PBSE1_ALGO); + SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); + + // Create PBE Cipher + Cipher pbeCipher = Cipher.getInstance(PKCS5_PBSE1_ALGO); + + // Initialize PBE Cipher with key and parameters + pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec); + + KeySpec key_spec; + + key_spec = encryptedPrivKey.getKeySpec(pbeCipher); + + KeyFactory kf = KeyFactory.getInstance(algorithm); + + return kf.generatePrivate(key_spec); + } catch (InvalidKeySpecException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Incorrect key for " + encryptedPrivKey + " : " + failed); + } + return null; + } + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Decrypt failed", failed); + } + return null; + } + } + + // Load a wrapped object in base64 format: + // The following three methods were modified + // from similar pureTLS methods. + /** + * WrappedObject.java + *

            + * Copyright (C) 1999, Claymore Systems, Inc. + * All Rights Reserved. + *

            + * ekr@rtfm.com Fri Jun 4 09:11:27 1999 + *

            + * This package is a SSLv3/TLS implementation written by Eric Rescorla + * and licensed by Claymore Systems, Inc. + *

            + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Claymore Systems, Inc. + * 4. Neither the name of Claymore Systems, Inc. nor the name of Eric + * Rescorla may be used to endorse or promote products derived from this + * software without specific prior written permission. + *

            + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + public static String loadBase64Object(BufferedReader rdr, String type) throws IOException { + if (null != findObject(rdr, type)) { + return readBase64Object(rdr, type); + } else { + return null; + } + } + + public static byte[] loadObject(BufferedReader rdr, String type) throws IOException { + if (null != findObject(rdr, type)) { + return readObject(rdr, type); + } else { + return null; + } + } + + public static String findObject(BufferedReader br, String type) throws IOException { + String prefix = "-----BEGIN "; + String suffix = (type == null) ? "-----" : type + "-----"; + + while (true) { + br.mark(1024); + + String line = br.readLine(); + + if (null == line) { + return null; + } + + if (!line.startsWith(prefix)) { + continue; + } + + if (!line.endsWith(suffix)) { + continue; + } + + br.reset(); + + return line.substring(prefix.length(), line.length() - 5); + } + } + + /** + * We read a block of n-lines (\n terminated) and return a String of n-lines + * concatenated together. This keeps the format consistent with the pureTLS + * requirements. + */ + public static String readBase64Object(BufferedReader br, String type) throws IOException { + String line = br.readLine(); + + String prefix = "-----BEGIN "; + String suffix = (type == null) ? "-----" : type + "-----"; + + if (!line.startsWith(prefix) || !line.endsWith(suffix)) { + throw new IOException("Not at begining of object"); + } + + StringBuilder block = new StringBuilder(); + + while (true) { + line = br.readLine(); + + if (null == line) { + break; + } + + if (line.startsWith("-----END ")) { + break; + } + + block.append(line); + block.append('\n'); + } + + return block.toString(); + } + + /** + * Read an object + */ + public static byte[] readObject(BufferedReader br, String type) throws IOException { + String base64 = readBase64Object(br, type); + + return base64Decode(new StringReader(base64)); + } + + /** + * + */ + + /** + * Write an object that is already base64 encoded. + */ + public static void writeBase64Object(BufferedWriter bw, String type, String object) throws IOException { + + bw.write("-----BEGIN "); + bw.write(type); + bw.write("-----"); + bw.newLine(); + + bw.write(object); + + char lastChar = object.charAt(object.length() - 1); + + if (('\n' != lastChar) && ('\r' != lastChar)) { + bw.newLine(); + } + + bw.write("-----END "); + bw.write(type); + bw.write("-----"); + bw.newLine(); + + bw.flush(); + } + + public static void writeObject(BufferedWriter out, String type, byte[] object) throws IOException { + String base64 = base64Encode(object); + + writeBase64Object(out, type, base64); + } + + /** + * Convert a byte array into a BASE64 encoded String. + * + * @param in The bytes to be converted + * @return the BASE64 encoded String. + */ + public static String base64Encode(byte[] in) throws IOException { + return base64Encode(in, true); + } + + /** + * Convert a byte array into a BASE64 encoded String. + * + * @param in the bytes to be converted + * @return the BASE64 encoded String. + */ + public static String base64Encode(byte[] in, boolean wrap) throws IOException { + StringWriter base64 = new StringWriter(); + + BASE64OutputStream b64os; + + if (wrap) { + b64os = new BASE64OutputStream(base64, 72); + } else { + b64os = new BASE64OutputStream(base64); + } + b64os.write(in); + b64os.close(); + + String encoded = base64.toString(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Encoded " + in.length + " bytes -> " + encoded.length() + " characters."); + } + + return encoded; + } + + /** + * Convert a BASE64 Encoded String into byte array. + * + * @param in BASE64 encoded String + * @return the decoded bytes. + */ + public static byte[] base64Decode(Reader in) throws IOException { + BASE64InputStream b64is = new BASE64InputStream(in); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + do { + int c = b64is.read(); + + if (c < 0) { + break; + } + + bos.write(c); + } while (true); + + byte[] result = bos.toByteArray(); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Decoded " + result.length + " bytes."); + } + + return result; + } + + /** + * Private replacement for toHexString since we need the leading 0 digits. + * Returns a String containing byte value encoded as 2 hex characters. + * + * @param theByte a byte containing the value to be encoded. + * @return String containing byte value encoded as 2 hex characters. + */ + private static String toHexDigits(byte theByte) { + final char[] HEXDIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + StringBuilder result = new StringBuilder(2); + + result.append(HEXDIGITS[(theByte >>> 4) & 15]); + result.append(HEXDIGITS[theByte & 15]); + + return result.toString(); + } + + private static String toHexDigits(byte[] bytes) { + StringBuilder encoded = new StringBuilder(bytes.length * 2); + + // build the string. + for (byte aByte : bytes) { + encoded.append(toHexDigits(aByte).toUpperCase()); + } + return encoded.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/StringAuthenticator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/StringAuthenticator.java new file mode 100644 index 000000000..9b6180ff4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/StringAuthenticator.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.net.URI; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.security.cert.X509Certificate; +import javax.crypto.EncryptedPrivateKeyInfo; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.KeyStoreException; + +import net.jxta.credential.AuthenticationCredential; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.membership.Authenticator; +import net.jxta.membership.MembershipService; + + +/** + * An authenticator associated with the PSE membership service. + * + *@see net.jxta.membership.Authenticator + *@see net.jxta.membership.MembershipService + **/ +public class StringAuthenticator implements Authenticator { + + /** + * The Membership Service which generated this authenticator. + **/ + transient PSEMembershipService source; + + /** + * The Authentication which was provided to the Apply operation of the + * membership service. + **/ + transient AuthenticationCredential application; + + /** + * The certficate which we are authenticating against + **/ + transient X509Certificate seedCert; + + /** + * The encrypted private key which we must unlock. + **/ + transient EncryptedPrivateKeyInfo seedKey; + + /** + * the password for that identity. + **/ + transient char[] store_password = null; + + /** + * the identity which is being claimed + **/ + transient ID identity = null; + + /** + * the password for that identity. + **/ + transient char[] key_password = null; + + /** + * Creates an authenticator for the PSE membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the PSE membership service which + * created this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + StringAuthenticator(PSEMembershipService source, AuthenticationCredential application, X509Certificate seedCert, EncryptedPrivateKeyInfo seedKey) { + this(source, application); + + this.seedCert = seedCert; + this.seedKey = seedKey; + } + + /** + * Creates an authenticator for the PSE membership service. Anything entered + * into the identity info section of the Authentication credential is + * ignored. + * + * @param source The instance of the PSE membership service which created + * this authenticator. + * @param application Anything entered into the identity info section of + * the Authentication credential is ignored. + **/ + StringAuthenticator(PSEMembershipService source, AuthenticationCredential application) { + this.source = source; + this.application = application; + + // XXX 20010328 bondolo@jxta.org Could do something with the authentication credential here. + } + + /** + * {@inheritDoc} + **/ + @Override + protected void finalize() throws Throwable { + if (null != store_password) { + Arrays.fill(store_password, '\0'); + } + + if (null != key_password) { + Arrays.fill(key_password, '\0'); + } + + super.finalize(); + } + + /** + * {@inheritDoc} + **/ + public MembershipService getSourceService() { + return (MembershipService) source.getInterface(); + } + + /** + * {@inheritDoc} + **/ + public AuthenticationCredential getAuthenticationCredential() { + return application; + } + + /** + * {@inheritDoc} + **/ + public String getMethodName() { + return "StringAuthentication"; + } + + /** + * {@inheritDoc} + **/ + synchronized public boolean isReadyForJoin() { + if (null != seedCert) { + return null != PSEUtils.pkcs5_Decrypt_pbePrivateKey(key_password, seedCert.getPublicKey().getAlgorithm(), seedKey); + } else { + return source.pseStore.validPasswd(identity, store_password, key_password); + } + } + + /** + * Get KeyStore password + **/ + public char[] getAuth1_KeyStorePassword() { + return store_password; + } + + /** + * Set KeyStore password + **/ + public void setAuth1_KeyStorePassword(String store_password) { + if (null == store_password) { + setAuth1_KeyStorePassword((char[]) null); + } else { + setAuth1_KeyStorePassword(store_password.toCharArray()); + } + } + + /** + * Set KeyStore password + **/ + public void setAuth1_KeyStorePassword(char[] store_password) { + if (null != this.store_password) { + Arrays.fill(this.store_password, '\0'); + } + + if (null == store_password) { + this.store_password = null; + } else { + this.store_password = store_password.clone(); + } + } + + /** + * Return the available identities. + **/ + public PeerID[] getIdentities(char[] store_password) { + + if (seedCert != null) { + PeerID[] seed = { source.group.getPeerID() }; + + return seed; + } else { + try { + ID[] allkeys = source.pseStore.getKeysList(store_password); + + // XXX bondolo 20040329 it may be appropriate to login + // something other than a peer id. + List peersOnly = new ArrayList(); + + Iterator eachKey = Arrays.asList(allkeys).iterator(); + + while (eachKey.hasNext()) { + ID aKey = (ID) eachKey.next(); + + if (aKey instanceof PeerID) { + peersOnly.add(aKey); + } + } + + return (PeerID[]) peersOnly.toArray(new PeerID[peersOnly.size()]); + } catch (IOException failed) { + return null; + } catch (KeyStoreException failed) { + return null; + } + } + } + + /** + * Returns the X509 Certificate associated with the specified ID. + * + * @param store_password The password for the keystore. + * @param aPeer The peer who's certificate is desired. For uninitialized + * keystores this must be the peerid of the registering peer. + **/ + public X509Certificate getCertificate(char[] store_password, ID aPeer) { + if (seedCert != null) { + if (aPeer.equals(source.group.getPeerID())) { + return seedCert; + } else { + return null; + } + } else { + try { + return source.pseStore.getTrustedCertificate(aPeer, store_password); + } catch (IOException failed) { + return null; + } catch (KeyStoreException failed) { + return null; + } + } + } + + /** + * Get Identity + **/ + public ID getAuth2Identity() { + return identity; + } + + /** + * Set Identity + **/ + public void setAuth2Identity(String id) { + try { + URI idURI = new URI(id); + ID identity = IDFactory.fromURI(idURI); + + setAuth2Identity(identity); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad ID"); + } + } + + /** + * Set Identity + **/ + public void setAuth2Identity(ID identity) { + this.identity = identity; + } + + /** + * Get identity password + **/ + public char[] getAuth3_IdentityPassword() { + return key_password; + } + + /** + * Set identity password + **/ + public void setAuth3_IdentityPassword(String key_password) { + setAuth3_IdentityPassword(key_password.toCharArray()); + } + + /** + * Set identity password + **/ + public void setAuth3_IdentityPassword(char[] key_password) { + if (null != this.key_password) { + Arrays.fill(this.key_password, '\0'); + } + + if (null == key_password) { + this.key_password = null; + } else { + this.key_password = key_password.clone(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/URIKeyStoreManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/URIKeyStoreManager.java new file mode 100644 index 000000000..485de10ab --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/URIKeyStoreManager.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.membership.pse; + + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.net.URI; +import java.security.KeyStore; + +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchProviderException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * Manages a Keystore located at URI. This version precludes KeyStores which + * are built from multiple URIs. + **/ +public class URIKeyStoreManager implements KeyStoreManager { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(URIKeyStoreManager.class.getName()); + + /** + * The default keystore type we will use. + **/ + private final static String DEFAULT_KEYSTORE_TYPE = "jks"; + + /** + * The keystore type + **/ + private final String keystore_type; + + /** + * The keystore type + **/ + private final String keystore_provider; + + /** + * The location where the keystore lives. + **/ + private final URI keystore_location; + + /** + * Default constructor. + **/ + public URIKeyStoreManager(String type, String provider, URI location) throws NoSuchProviderException, KeyStoreException { + if (null == type) { + type = DEFAULT_KEYSTORE_TYPE; + provider = null; + } + + if (!location.isAbsolute()) { + throw new IllegalArgumentException("location must be an absolute URI"); + } + + if ("file".equalsIgnoreCase(location.getScheme())) { + File asFile = new File(location); + + if (asFile.exists() && !asFile.isFile()) { + throw new IllegalArgumentException("location must refer to a file"); + } + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("pse location = " + location); + } + + keystore_type = type; + + keystore_provider = provider; + + keystore_location = location; + + // check if we can get an instance. + if (null == keystore_provider) { + KeyStore.getInstance(keystore_type); + } else { + KeyStore.getInstance(keystore_type, keystore_provider); + } + } + + /** + * {@inheritDoc} + **/ + public boolean isInitialized() { + return isInitialized(null); + } + + /** + * {@inheritDoc} + **/ + public boolean isInitialized(char[] store_password) { + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(keystore_location.toURL().openStream(), store_password); + + return true; + } catch (Exception failed) { + return false; + } + } + + /** + * {@inheritDoc} + **/ + public void createKeyStore(char[] store_password) throws KeyStoreException, IOException { + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(null, store_password); + + saveKeyStore(store, store_password); + } catch (NoSuchProviderException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchProviderException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + **/ + public KeyStore loadKeyStore(char[] password) throws KeyStoreException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loading (" + keystore_type + "," + keystore_provider + ") store from " + keystore_location); + } + + try { + KeyStore store; + + if (null == keystore_provider) { + store = KeyStore.getInstance(keystore_type); + } else { + store = KeyStore.getInstance(keystore_type, keystore_provider); + } + + store.load(keystore_location.toURL().openStream(), password); + + return store; + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (NoSuchProviderException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchProviderException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + **/ + public void saveKeyStore(KeyStore store, char[] password) throws KeyStoreException, IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Writing " + store + " to " + keystore_location); + } + + try { + OutputStream os = null; + + if ("file".equalsIgnoreCase(keystore_location.getScheme())) { + // Sadly we can't use URL.openConnection() to create the + // OutputStream for file:// URLs. bogus. + os = new FileOutputStream(new File(keystore_location)); + } else { + os = keystore_location.toURL().openConnection().getOutputStream(); + } + store.store(os, password); + } catch (NoSuchAlgorithmException failed) { + KeyStoreException failure = new KeyStoreException("NoSuchAlgorithmException during keystore processing"); + + failure.initCause(failed); + throw failure; + } catch (CertificateException failed) { + KeyStoreException failure = new KeyStoreException("CertificateException during keystore processing"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * {@inheritDoc} + **/ + public void eraseKeyStore() { + + if ("file".equalsIgnoreCase(keystore_location.getScheme())) { + File asFile = new File(keystore_location); + + if (asFile.exists() && asFile.isFile() && asFile.canWrite()) { + asFile.delete(); + } + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Unable to delete non-file URI :" + keystore_location); + } + + throw new UnsupportedOperationException("Unable to delete non-file URI"); + } + } + + /** + * {@inheritDoc} + **/ + public String toString() { + StringBuilder sb = new StringBuilder("PSE keystore details: \n"); + sb.append(" Class: ").append(this.getClass().getName()).append("\n"); + sb.append(" Type: ").append(keystore_type==null ? "" : keystore_type).append("\n"); + sb.append(" Provider: ").append(keystore_provider==null ? "" : keystore_provider).append("\n"); + sb.append(" Location: ").append(keystore_location==null ? "" : keystore_location.toString()).append("\n"); + return sb.toString(); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/package.html new file mode 100644 index 000000000..1bf6794f4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/package.html @@ -0,0 +1,11 @@ + + + + + + + A JXTA Membership Service utilizing PKI to provide secure identities. + + @see net.jxta.membership + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ConditionalMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ConditionalMeterBuildSettings.java new file mode 100644 index 000000000..cbf2f50ac --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ConditionalMeterBuildSettings.java @@ -0,0 +1,80 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.meter; + +import java.util.ResourceBundle; +import net.jxta.impl.meter.*; + +public class ConditionalMeterBuildSettings { + public static boolean isRuntimeMetering() { + boolean runtimeMetering = false; + + try { + ResourceBundle userResourceBundle = ResourceBundle.getBundle( "net.jxta.user" ); + String meteringProperty = "net.jxta.meter.conditionalMetering"; + String meteringValue = userResourceBundle.getString( meteringProperty ); + runtimeMetering = "on".equalsIgnoreCase( meteringValue ); + } catch (Exception ignored) { + } + + return runtimeMetering; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/GenericServiceMonitor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/GenericServiceMonitor.java new file mode 100644 index 000000000..b4a996037 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/GenericServiceMonitor.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.meter; + + +import net.jxta.document.Advertisement; +import net.jxta.exception.JxtaException; +import net.jxta.id.ID; +import net.jxta.meter.MonitorResources; +import net.jxta.meter.ServiceMetric; +import net.jxta.meter.ServiceMonitorFilter; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleClassID; +import net.jxta.protocol.ModuleImplAdvertisement; + + +public abstract class GenericServiceMonitor implements ServiceMonitorImpl, Module { + private ModuleClassID moduleClassID; + protected MonitorManager monitorManager; + + protected long reportRate; + protected int reportRateIndex; + protected ServiceMetric cumulativeServiceMetric; + protected ServiceMetric deltaServiceMetrics[]; + protected ModuleImplAdvertisement implAdvertisement; + + public GenericServiceMonitor() {} + + // public void init(MonitorManager monitorManager, ModuleClassID moduleClassID) { + + public void init(PeerGroup group, ID assignedID, Advertisement advertisement) { + group.unref(); // We do not use the group. These are not quite real modules. + this.implAdvertisement = (ModuleImplAdvertisement) advertisement; + this.moduleClassID = (ModuleClassID) assignedID; + } + + public void init(MonitorManager monitorManager) { + this.monitorManager = monitorManager; + + if (MeterBuildSettings.METERING) { + cumulativeServiceMetric = createServiceMetric(); + deltaServiceMetrics = new ServiceMetric[monitorManager.getReportRatesCount()]; + init(); + } + } + + /* + public void init(MonitorManager monitorManager) { + this.monitorManager = monitorManager; + } + */ + + public int startApp(java.lang.String[] args) { + return 0; + } // fix-me: what's the right return? + + public void stopApp() {} + + protected void init() {} + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + public PeerGroup getPeerGroup() { + return monitorManager.getPeerGroup(); + } + + protected ServiceMetric getCumulativeServiceMetric() { + return cumulativeServiceMetric; + } + + public void resetPulseRate(ServiceMonitorPulseInfo pulseInfo, int oldPulseRateIndex) { + this.reportRate = pulseInfo.getPulseRate(); + this.reportRateIndex = pulseInfo.getPulseRateIndex(); + } + + public void validateCumulativeServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter) {// base implementation is to accept + } + + public ServiceMonitorFilter createSupportedCumulativeServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter) { + // base implementation is to accept + return serviceMonitorFilter; + } + + public void validateServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, long reportRate) {// base implementation is to accept + } + + public ServiceMonitorFilter createSupportedServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, long reportRate) { + // base implementation is to accept + return serviceMonitorFilter; + } + + protected ServiceMetric createServiceMetric() { + try { + return MonitorResources.createServiceMetric(moduleClassID); + } catch (JxtaException e) { // this will always succeed since we were able to lad the monitor + return null; + } + } + + /** + * Get the service metrics accrued since the last pulse + * + * @return null if there were no metrices since the last call + */ + protected abstract ServiceMetric collectServiceMetrics(); + + public synchronized void beginPulse(ServiceMonitorPulseInfo pulseInfo) { + ServiceMetric baseDeltaServiceMetric = collectServiceMetrics(); + + deltaServiceMetrics[reportRateIndex] = baseDeltaServiceMetric; + + if (baseDeltaServiceMetric != null) { + for (int reportRate = reportRateIndex + 1; reportRate < deltaServiceMetrics.length; reportRate++) { + + if (pulseInfo.isRegisteredFilterForRate(reportRate)) { + + if (deltaServiceMetrics[reportRate] == null) { + deltaServiceMetrics[reportRate] = createServiceMetric(); + } + + deltaServiceMetrics[reportRate].mergeMetrics(baseDeltaServiceMetric); + } + } + } + } + + public void endPulse(ServiceMonitorPulseInfo pulseInfo) { + for (int reportRateIndex = 0; reportRateIndex < monitorManager.getReportRatesCount(); reportRateIndex++) { + if (pulseInfo.isEvenPulseForRateIndex(reportRateIndex)) { + deltaServiceMetrics[reportRateIndex] = null; + } + } + } + + public void beginCumulativeReport() {} + + public void endCumulativeReport() {} + + public ServiceMetric getServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime, int reportIndex, long reportRate) { + int deltaReportRateIndex = monitorManager.getReportRateIndex(reportRate); + + // Fix-Me: For now we are not yet supporting filters + + return deltaServiceMetrics[deltaReportRateIndex]; + } + + public ServiceMetric getCumulativeServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime) { + // Fix-Me: For now we are not yet supporting filters + + return cumulativeServiceMetric; + } + + public void serviceMonitorFilterRegistered(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex, long reportRate, boolean newRate) { + if (newRate) { + deltaServiceMetrics[reportRateIndex] = createServiceMetric(); + } + } + + public void serviceMonitorFilterDeregistered(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex, long reportRate, boolean retiredRate) { + if (retiredRate) { + deltaServiceMetrics[reportRateIndex] = null; + } + } + + public void destroy() {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MeterBuildSettings.java new file mode 100644 index 000000000..4f43a1137 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MeterBuildSettings.java @@ -0,0 +1,67 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.meter; + +import net.jxta.impl.meter.*; + +public interface MeterBuildSettings { + public static final boolean METERING = ConditionalMeterBuildSettings.isRuntimeMetering(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MetricUtilities.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MetricUtilities.java new file mode 100644 index 000000000..b0e98e521 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MetricUtilities.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.meter; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; + +import java.net.URI; +import java.net.URISyntaxException; + + +public class MetricUtilities { + private static PeerID unknownPeer = (PeerID) ID.create(URI.create("urn:jxta:uuid-DEAF03")); + private static PeerID badPeer = (PeerID) ID.create(URI.create("urn:jxta:uuid-BADBAD03")); + + public static final PeerID UNKNOWN_PEERID = unknownPeer; + public static final PeerID BAD_PEERID = badPeer; + + public static PeerID getPeerIdFromString(String peerIdString) { + PeerID peerId; + + try { + peerId = (PeerID) IDFactory.fromURI(new URI(peerIdString)); + } catch (URISyntaxException e) { + peerId = BAD_PEERID; + } + return peerId; + } + + public static PeerID getPeerIdFromEndpointAddress(EndpointAddress endpointAddress) { + PeerID peerId; + + try { + peerId = (PeerID) IDFactory.fromURI( + new URI( + ID.URIEncodingName + ":" + endpointAddress.getProtocolName() + ":" + + endpointAddress.getProtocolAddress())); + } catch (URISyntaxException e) { + peerId = BAD_PEERID; + } + return peerId; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MonitorManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MonitorManager.java new file mode 100644 index 000000000..4d25c7bad --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/MonitorManager.java @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.meter; + + +import net.jxta.document.Advertisement; +import net.jxta.exception.JxtaException; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import net.jxta.meter.MonitorEvent; +import net.jxta.meter.MonitorException; +import net.jxta.meter.MonitorFilter; +import net.jxta.meter.MonitorFilterException; +import net.jxta.meter.MonitorListener; +import net.jxta.meter.MonitorReport; +import net.jxta.meter.MonitorResources; +import net.jxta.meter.PeerMonitorInfo; +import net.jxta.meter.ServiceMetric; +import net.jxta.meter.ServiceMonitor; +import net.jxta.meter.ServiceMonitorFilter; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.ModuleClassID; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.service.Service; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; + + +public class MonitorManager implements Service { + private final static long timeZero = System.currentTimeMillis(); + public static final int NOT_PULSING = -1; + + private static final int NO_PRIOR_REPORT = 0; + + private static long supportedReportRates[] = new long[] { + 500, TimeUtils.ASECOND, 5 * TimeUtils.ASECOND, 10 * TimeUtils.ASECOND, 15 * TimeUtils.ASECOND, 30 * TimeUtils.ASECOND + , + TimeUtils.AMINUTE, 5 * TimeUtils.AMINUTE, 10 * TimeUtils.AMINUTE, 15 * TimeUtils.AMINUTE, 30 * TimeUtils.AMINUTE + , + TimeUtils.ANHOUR, 3 * TimeUtils.ANHOUR, 6 * TimeUtils.ANHOUR, 12 * TimeUtils.ANHOUR, TimeUtils.ADAY, TimeUtils.AWEEK}; + + private int pulsesPerRate[] = new int[supportedReportRates.length]; + private long startTime = System.currentTimeMillis(); + + private LinkedList monitorListenerInfos = new LinkedList(); + private Hashtable serviceMonitorPulseInfos = new Hashtable(); + private int filtersPerRate[] = new int[supportedReportRates.length]; + private long previousReportTimes[] = new long[supportedReportRates.length]; + + private PeerGroup peerGroup; + private Thread reportThread; + + private long pulseRate = NOT_PULSING; + private int pulseRateIndex = NOT_PULSING; + private int pulseNumber = 0; + private long nextPulseTime = NO_PRIOR_REPORT; + private boolean isRunning = true; // true until monitor is destroyed, triggers termination of report thread + + private ModuleClassID[] supportedModuleClassIDs; + private ModuleImplAdvertisement implAdvertisement; + private long lastResetTime = System.currentTimeMillis(); + + public Advertisement getImplAdvertisement() { + return implAdvertisement; + } + + public Service getInterface() { + // This is good enough. No need to get fancy. + return this; + } + + // public MonitorManager(PeerGroup peerGroup) { + + public void init(PeerGroup peerGroup, ID assignedID, Advertisement implAdvertisement) { + this.implAdvertisement = (ModuleImplAdvertisement) implAdvertisement; + this.peerGroup = peerGroup; + createReportThread(); + + for (int i = 0; i < previousReportTimes.length; i++) { + pulsesPerRate[i] = (int) (supportedReportRates[i] / supportedReportRates[0]); + } + } + + public int startApp(java.lang.String[] args) { + return 0; // fix-me + } + + public void stopApp() { + destroy(); + } + + private class MonitorListenerInfo { + MonitorListener monitorListener; + MonitorFilter monitorFilter; + long reportRate; + int reportRateIndex; + boolean sendCumulativeFirst = false; + boolean wasCumulativeSent = false; + + MonitorListenerInfo(MonitorListener monitorListener, long reportRate, MonitorFilter monitorFilter, boolean cumulativeFirst) { + this.monitorListener = monitorListener; + this.monitorFilter = monitorFilter; + this.reportRate = reportRate; + this.sendCumulativeFirst = cumulativeFirst; + this.reportRateIndex = getReportRateIndex(reportRate); + } + } + + public static long[] getReportRates() { // return copy so that users can't modify. + long copy[] = new long[supportedReportRates.length]; + + System.arraycopy(supportedReportRates, 0, copy, 0, supportedReportRates.length); + return copy; + } + + public boolean isLocalMonitoringAvailable(ModuleClassID moduleClassID) { + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + return (serviceMonitor != null); + } + + public PeerGroup getPeerGroup() { + return peerGroup; + } + + // Cooperate with the code that loaded this module to replace the strong + // group interface given by init() with a non-counted one. + private void setPeerGroup(PeerGroup pg) { + PeerGroup tmp = peerGroup; + + peerGroup = pg; + tmp.unref(); + tmp = null; + } + + public PeerMonitorInfo getPeerMonitorInfo() { + long[] reportRates = getReportRates(); // makes a copy + ModuleClassID[] moduleClassIDs = getMonitorableServiceTypes(); // ensures that array is initialized. + long runningTime = System.currentTimeMillis() - lastResetTime; + + return new PeerMonitorInfo(MeterBuildSettings.METERING, moduleClassIDs, reportRates, lastResetTime, runningTime); + } + + public int getReportRatesCount() { + return supportedReportRates.length; + } + + public int getReportRateIndex(long reportRate) { + for (int i = 0; i < supportedReportRates.length; i++) { + if (supportedReportRates[i] == reportRate) { + return i; + } + } + + return -1; + } + + public boolean isSupportedReportRate(long reportRate) { + return getReportRateIndex(reportRate) >= 0; + } + + public long getReportRate(int index) { + return supportedReportRates[index]; + } + + public long getBestReportRate(long desiredReportRate) { + for (long supportedReportRate : supportedReportRates) { + if (desiredReportRate <= supportedReportRate) { + return supportedReportRate; + } + } + + return supportedReportRates[supportedReportRates.length - 1]; + } + + public ServiceMonitor getServiceMonitor(ModuleClassID moduleClassID) { + ServiceMonitorPulseInfo serviceMonitorPulseInfo = serviceMonitorPulseInfos.get(moduleClassID); + + if (serviceMonitorPulseInfo != null) { + return serviceMonitorPulseInfo.serviceMonitor; + } else { + + try { + ModuleImplAdvertisement moduleImplAdvertisement = MonitorResources.getServiceMonitorImplAdvertisement( + moduleClassID, implAdvertisement); + ServiceMonitor serviceMonitor = (ServiceMonitor) peerGroup.loadModule(moduleClassID, moduleImplAdvertisement); + + MonitorResources.registerServiceMonitorModuleImplAdvertisement(moduleImplAdvertisement); + + if (serviceMonitor instanceof ServiceMonitorImpl) { + ((ServiceMonitorImpl) serviceMonitor).init(this); + + } + + serviceMonitorPulseInfo = new ServiceMonitorPulseInfo(this, serviceMonitor); + serviceMonitorPulseInfos.put(moduleClassID, serviceMonitorPulseInfo); + return serviceMonitor; + } catch (JxtaException e) { + throw new RuntimeException("Unable to load Service Monitor: " + moduleClassID + "\n\tException: " + e); + } + } + } + + private void resetPulseRate() { + int oldPulseRateIndex = pulseRateIndex; + + pulseRateIndex = NOT_PULSING; + pulseRate = NOT_PULSING; + + for (int i = 0; i < filtersPerRate.length; i++) { + if (filtersPerRate[i] != 0) { + pulseRateIndex = i; + pulseRate = getReportRate(pulseRateIndex); + break; + } + } + + if (oldPulseRateIndex == pulseRateIndex) { + return; + } // nothing changed + + long now = System.currentTimeMillis(); + + if (oldPulseRateIndex == NOT_PULSING) { // case 1: No pulse to pulse + for (int i = 0; i < filtersPerRate.length; i++) { + if (filtersPerRate[i] != 0) { + previousReportTimes[i] = now; + } else { + previousReportTimes[i] = NO_PRIOR_REPORT; + } + } + + pulseNumber = 0; + nextPulseTime = now + pulseRate; + } else if (pulseRateIndex == NOT_PULSING) {// case 2: pulse to No pulse + // Do nothing + } else if (pulseRateIndex < oldPulseRateIndex) { // case 3: pulse going to a faster pulse + for (int i = pulseRateIndex; i < (oldPulseRateIndex - 1); i++) { + if (filtersPerRate[i] != 0) { + previousReportTimes[i] = now; + } else { + previousReportTimes[i] = NO_PRIOR_REPORT; + } + } + + long timeToNextPulse = nextPulseTime - now; + + if (pulseRate < timeToNextPulse) { + int numPulsesToNow = (int) (timeToNextPulse / pulseRate); + int numNewToOldPulses = (int) (supportedReportRates[oldPulseRateIndex] / supportedReportRates[pulseRateIndex]); + + pulseNumber += (numNewToOldPulses - numPulsesToNow) * pulsesPerRate[pulseRateIndex]; + timeToNextPulse = now - (numPulsesToNow * pulseRate); + } else { + pulseNumber += (pulsesPerRate[oldPulseRateIndex] - pulsesPerRate[pulseRateIndex]); + } + + } else if (pulseRateIndex > oldPulseRateIndex) { // case 3: pulse going to a slower pulse + int nextPulseNumber = pulseNumber + pulsesPerRate[oldPulseRateIndex]; + + pulseNumber = ((nextPulseNumber - 1) / pulsesPerRate[pulseRateIndex]) * pulsesPerRate[pulseRateIndex]; + nextPulseTime += (nextPulseNumber - pulseNumber) * supportedReportRates[0]; + + for (int i = 0; i < pulseRateIndex; i++) { + previousReportTimes[i] = NO_PRIOR_REPORT; + } + } + + reportThread.interrupt(); + } + + private MonitorReport getMonitorReport(MonitorFilter monitorFilter, long reportRate, long previousDeltaTime, long beginReportTime) { + MonitorReport monitorReport = new MonitorReport(previousDeltaTime, beginReportTime, false); + + for (Iterator i = monitorFilter.getModuleClassIDs(); i.hasNext();) { + ModuleClassID moduleClassID = (ModuleClassID) i.next(); + + ServiceMonitorFilter serviceMonitorFilter = monitorFilter.getServiceMonitorFilter(moduleClassID); + + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + if (serviceMonitorFilter != null) { + ServiceMetric serviceMetric = serviceMonitor.getServiceMetric(serviceMonitorFilter, previousDeltaTime + , + beginReportTime, getReportRateIndex(reportRate), reportRate); + + if (serviceMetric != null) { + monitorReport.addServiceMetric(serviceMetric); + } + } + } + return monitorReport; + } + + public void validateCumulativeMonitorFilter(MonitorFilter monitorFilter) throws MonitorFilterException { + boolean isAnyServiceFilters = false; + + for (Iterator i = monitorFilter.getServiceMonitorFilters(); i.hasNext();) { + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) i.next(); + + ModuleClassID moduleClassID = serviceMonitorFilter.getModuleClassID(); + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + if (serviceMonitor == null) { + throw new MonitorFilterException(MonitorFilterException.SERVICE_NOT_SUPPORTED, moduleClassID); + } + + serviceMonitor.validateCumulativeServiceMonitorFilter(serviceMonitorFilter); + isAnyServiceFilters = true; + } + + if (!isAnyServiceFilters) { + throw new MonitorFilterException("Empty Monitor Filter"); + } + + } + + public void validateMonitorFilter(MonitorFilter monitorFilter, long reportRate) throws MonitorFilterException { + + if (!isSupportedReportRate(reportRate)) { + throw new MonitorFilterException(MonitorFilterException.REPORT_RATE_NOT_SUPPORTED, reportRate); + } + + boolean isAnyServiceFilters = false; + + for (Iterator i = monitorFilter.getServiceMonitorFilters(); i.hasNext();) { + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) i.next(); + + ModuleClassID moduleClassID = serviceMonitorFilter.getModuleClassID(); + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + if (serviceMonitor == null) { + throw new MonitorFilterException(MonitorFilterException.SERVICE_NOT_SUPPORTED, moduleClassID); + } + + serviceMonitor.validateServiceMonitorFilter(serviceMonitorFilter, reportRate); + isAnyServiceFilters = true; + } + + if (!isAnyServiceFilters) { + throw new MonitorFilterException("Empty Monitor Filter"); + } + } + + public MonitorFilter createSupportedCumulativeMonitorFilter(MonitorFilter monitorFilter) throws MonitorFilterException { + MonitorFilter newMonitorFilter = new MonitorFilter(monitorFilter.getDescription()); + boolean anythingAdded = false; + + for (Iterator i = monitorFilter.getServiceMonitorFilters(); i.hasNext();) { + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) i.next(); + + ModuleClassID moduleClassID = serviceMonitorFilter.getModuleClassID(); + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + if (serviceMonitor == null) { + continue; + } + + ServiceMonitorFilter newServiceMonitorFilter = serviceMonitor.createSupportedCumulativeServiceMonitorFilter( + serviceMonitorFilter); + + if (newServiceMonitorFilter != null) { + newMonitorFilter.addServiceMonitorFilter(newServiceMonitorFilter); + anythingAdded = true; + } + } + + if (anythingAdded) { + return newMonitorFilter; + } else { + return null; + } + } + + public MonitorFilter createSupportedMonitorFilter(MonitorFilter monitorFilter, long reportRate) throws MonitorFilterException { + MonitorFilter newMonitorFilter = new MonitorFilter(monitorFilter.getDescription()); + boolean anythingAdded = false; + + for (Iterator i = monitorFilter.getServiceMonitorFilters(); i.hasNext();) { + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) i.next(); + + ModuleClassID moduleClassID = serviceMonitorFilter.getModuleClassID(); + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + if (serviceMonitor == null) { + continue; + } + + ServiceMonitorFilter newServiceMonitorFilter = serviceMonitor.createSupportedServiceMonitorFilter(serviceMonitorFilter + , + reportRate); + + if (newServiceMonitorFilter != null) { + newMonitorFilter.addServiceMonitorFilter(newServiceMonitorFilter); + anythingAdded = true; + } + } + + if (anythingAdded) { + return newMonitorFilter; + } else { + return null; + } + } + + public synchronized long addMonitorListener(MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener) throws MonitorException { + + validateMonitorFilter(monitorFilter, reportRate); // if validation fails, it will throw an exception + + if (includeCumulative) { + validateCumulativeMonitorFilter(monitorFilter); + } // if validation fails, it will throw an exception + + int reportRateIndex = getReportRateIndex(reportRate); + + try { + monitorFilter = (MonitorFilter) DocumentSerializableUtilities.copyDocumentSerializable(monitorFilter); // make a copy of the filter + } catch (DocumentSerializationException e) { + throw new MonitorException(MonitorException.SERIALIZATION, "Error trying to copy MonitorFilter"); + } + + MonitorListenerInfo monitorListenerInfo = new MonitorListenerInfo(monitorListener, reportRate, monitorFilter + , + includeCumulative); + + monitorListenerInfos.add(monitorListenerInfo); + filtersPerRate[reportRateIndex]++; + + if ((filtersPerRate[reportRateIndex] == 1) && (pulseRateIndex != NOT_PULSING) && (reportRateIndex > pulseRateIndex)) { + previousReportTimes[reportRateIndex] = previousReportTimes[pulseRateIndex]; + } + + for (Iterator i = monitorFilter.getModuleClassIDs(); i.hasNext();) { + ModuleClassID moduleClassID = (ModuleClassID) i.next(); + + ServiceMonitorFilter serviceMonitorFilter = monitorFilter.getServiceMonitorFilter(moduleClassID); + ServiceMonitorPulseInfo serviceMonitorPulseInfo = serviceMonitorPulseInfos.get(moduleClassID); + + serviceMonitorPulseInfo.registerServiceMonitorFilter(serviceMonitorFilter, reportRateIndex, reportRate); + } + + resetPulseRate(); + + return reportRate; + } + + private MonitorListenerInfo getMonitorListenerInfo(MonitorListener monitorListener) { + for (Object monitorListenerInfo1 : monitorListenerInfos) { + MonitorListenerInfo monitorListenerInfo = (MonitorListenerInfo) monitorListenerInfo1; + + if (monitorListenerInfo.monitorListener == monitorListener) { + return monitorListenerInfo; + } + } + return null; + } + + public synchronized int removeMonitorListener(MonitorListener monitorListener) { + int numRemoved = 0; + + for (;;) { // remove all instances of this listener + MonitorListenerInfo monitorListenerInfo = getMonitorListenerInfo(monitorListener); + + if (monitorListenerInfo == null) { + break; + } else { + MonitorFilter monitorFilter = monitorListenerInfo.monitorFilter; + long reportRate = monitorListenerInfo.reportRate; + int reportRateIndex = monitorListenerInfo.reportRateIndex; + + monitorListenerInfos.remove(monitorListenerInfo); + numRemoved++; + filtersPerRate[reportRateIndex]--; + + for (Iterator i = monitorFilter.getModuleClassIDs(); i.hasNext();) { + ModuleClassID moduleClassID = (ModuleClassID) i.next(); + + ServiceMonitorFilter serviceMonitorFilter = monitorFilter.getServiceMonitorFilter(moduleClassID); + ServiceMonitorPulseInfo serviceMonitorPulseInfo = serviceMonitorPulseInfos.get(moduleClassID); + + serviceMonitorPulseInfo.deregisterServiceMonitorFilter(serviceMonitorFilter, reportRateIndex, reportRate); + } + } + } + + resetPulseRate(); + + return numRemoved; + } + + public synchronized MonitorReport getCumulativeMonitorReport(MonitorFilter monitorFilter) throws MonitorException { + validateCumulativeMonitorFilter(monitorFilter); + + long beginReportTime = System.currentTimeMillis(); + + MonitorReport monitorReport = new MonitorReport(startTime, beginReportTime, true); + + for (Iterator i = monitorFilter.getModuleClassIDs(); i.hasNext();) { + ModuleClassID moduleClassID = (ModuleClassID) i.next(); + + ServiceMonitorFilter serviceMonitorFilter = monitorFilter.getServiceMonitorFilter(moduleClassID); + ServiceMonitor serviceMonitor = getServiceMonitor(moduleClassID); + + ServiceMetric serviceMetric = serviceMonitor.getCumulativeServiceMetric(serviceMonitorFilter, timeZero + , + beginReportTime); + + monitorReport.addServiceMetric(moduleClassID, serviceMetric); + } + + return monitorReport; + } + + public ModuleClassID[] getMonitorableServiceTypes() { + if (supportedModuleClassIDs == null) { + ModuleClassID[] registeredModuleClassIDs = MonitorResources.getRegisteredModuleClassIDs(); + LinkedList supportedModuleClassIDsList = new LinkedList(); + + for (ModuleClassID registeredModuleClassID : registeredModuleClassIDs) { + if (isLocalMonitoringAvailable(registeredModuleClassID)) { + supportedModuleClassIDsList.add(registeredModuleClassID); + } + } + + supportedModuleClassIDs = supportedModuleClassIDsList.toArray(new ModuleClassID[0]); + } + return supportedModuleClassIDs; + } + + // fastest pulse rate registered anywhere + public long getPulseRate() { + return getReportRate(pulseRateIndex); + } + + // index of fastest pulse anywhere + public int getPulseRateIndex() { + return pulseRateIndex; + } + + // pulse rate for this monitor + public long getPulseRate(ServiceMonitor serviceMonitor) { + ServiceMonitorPulseInfo serviceMonitorPulseInfo = serviceMonitorPulseInfos.get(serviceMonitor.getModuleClassID()); + + if (serviceMonitorPulseInfo != null) { + return serviceMonitorPulseInfo.getPulseRate(); + } else { + return ServiceMonitorPulseInfo.NOT_PULSING; + } + } + + // index of pulse rate for this monitor + public long getPulseRateIndex(ServiceMonitor serviceMonitor) { + ServiceMonitorPulseInfo serviceMonitorPulseInfo = serviceMonitorPulseInfos.get(serviceMonitor.getModuleClassID()); + + if (serviceMonitorPulseInfo != null) { + return serviceMonitorPulseInfo.getPulseRateIndex(); + } else { + return ServiceMonitorPulseInfo.NOT_PULSING; + } + } + + private void generateReports() { + long beginReportTime = System.currentTimeMillis(); + + for (Enumeration e = serviceMonitorPulseInfos.elements(); e.hasMoreElements();) { + ServiceMonitorPulseInfo serviceMonitorPulseInfo = e.nextElement(); + int servicePulseRateIndex = serviceMonitorPulseInfo.getPulseRateIndex(); + + if ((serviceMonitorPulseInfo.serviceMonitor instanceof ServiceMonitorImpl) + && isEvenPulseForRateIndex(servicePulseRateIndex)) { + ((ServiceMonitorImpl) serviceMonitorPulseInfo.serviceMonitor).beginPulse(serviceMonitorPulseInfo); + } + } + + for (Object monitorListenerInfo1 : monitorListenerInfos) { + MonitorListenerInfo monitorListenerInfo = (MonitorListenerInfo) monitorListenerInfo1; + MonitorFilter monitorFilter = monitorListenerInfo.monitorFilter; + MonitorListener monitorListener = monitorListenerInfo.monitorListener; + + int reportRateIndex = monitorListenerInfo.reportRateIndex; + long reportRate = monitorListenerInfo.reportRate; + + if (isEvenPulseForRateIndex(reportRateIndex)) { + MonitorReport monitorReport = null; + + try { + if (monitorListenerInfo.sendCumulativeFirst && !monitorListenerInfo.wasCumulativeSent) { + monitorReport = getCumulativeMonitorReport(monitorFilter); + + MonitorEvent monitorEvent = new MonitorEvent(peerGroup.getPeerGroupID(), monitorReport); + + monitorListener.processMonitorReport(monitorEvent); + monitorListenerInfo.wasCumulativeSent = true; + } else { + monitorReport = getMonitorReport(monitorFilter, reportRate, previousReportTimes[reportRateIndex] + , + beginReportTime); + MonitorEvent monitorEvent = new MonitorEvent(peerGroup.getPeerGroupID(), monitorReport); + + monitorListener.processMonitorReport(monitorEvent); + } + } catch (Throwable e) { + e.printStackTrace(); + // Fix-Me: Where should we report an uncaught exception in one of our listeners? + } + } + } + + for (int rateIndex = 0; rateIndex < supportedReportRates.length; rateIndex++) { + if (isEvenPulseForRateIndex(rateIndex)) { + if (filtersPerRate[rateIndex] != 0) { + previousReportTimes[rateIndex] = beginReportTime; + } else { + previousReportTimes[rateIndex] = NO_PRIOR_REPORT; + } + } + } + + for (Enumeration e = serviceMonitorPulseInfos.elements(); e.hasMoreElements();) { + ServiceMonitorPulseInfo serviceMonitorPulseInfo = e.nextElement(); + int servicePulseRateIndex = serviceMonitorPulseInfo.getPulseRateIndex(); + + if ((serviceMonitorPulseInfo.serviceMonitor instanceof ServiceMonitorImpl) + && isEvenPulseForRateIndex(servicePulseRateIndex)) { + ((ServiceMonitorImpl) serviceMonitorPulseInfo.serviceMonitor).endPulse(serviceMonitorPulseInfo); + } + } + } + + boolean isEvenPulseForRateIndex(int pulseRateIndex) { + if (pulseRateIndex < 0 || pulseRateIndex > pulsesPerRate.length) { + return false; + } + return ((pulseNumber % pulsesPerRate[pulseRateIndex]) == 0); + } + + private void createReportThread() { + reportThread = new Thread(new Runnable() { + public void run() { + mainLoop: + while (isRunning) { + synchronized (MonitorManager.this) { // no new listeners while reporting + while (pulseRate == NOT_PULSING) { + try { + MonitorManager.this.wait(); + } catch (InterruptedException e) { + continue mainLoop; + } + } + + while (pulseRate != NOT_PULSING) { + if (Thread.interrupted()) { + continue mainLoop; + } + + long now = System.currentTimeMillis(); + + try { + long waitTime = nextPulseTime - now; + + if (waitTime > 0) { + MonitorManager.this.wait(nextPulseTime - now); + } + + pulseNumber += pulsesPerRate[pulseRateIndex]; + generateReports(); + nextPulseTime += pulseRate; + } catch (InterruptedException e) { + if (pulseRateIndex == NOT_PULSING) { + continue mainLoop; + } + } catch (Exception ex) { + // don't die forever on exceptions!! + ex.printStackTrace(); // fix-me: report this + } + } + } + } + } + }, "Meter-Monitor-Report"); + + reportThread.setDaemon(true); + reportThread.start(); + } + + public synchronized void destroy() { + isRunning = false; + reportThread.interrupt(); + + for (Enumeration e = serviceMonitorPulseInfos.elements(); e.hasMoreElements();) { + ServiceMonitorPulseInfo serviceMonitorPulseInfo = e.nextElement(); + ServiceMonitor serviceMonitor = serviceMonitorPulseInfo.serviceMonitor; + + serviceMonitor.destroy(); + } + } + + /** + * DO NOT USE THIS FIELD: It will be deprecated when MonitorManager becomes a + * FULL FLEDGED SERVICE + */ + + private static Hashtable monitorManagers = new Hashtable(); + + /** + * DO NOT USE THIS METHOD: It will be deprecated when MonitorManager becomes a + * FULL FLEDGED SERVICE + */ + + public static MonitorManager registerMonitorManager(PeerGroup peerGroup) throws JxtaException { + PeerGroupID peerGroupID = peerGroup.getPeerGroupID(); + MonitorManager monitorManager = monitorManagers.get(peerGroupID); + + if (monitorManager == null) { + boolean includeTransports = true; + ModuleImplAdvertisement moduleImplAdvertisement = MonitorResources.getReferenceAllPurposeMonitorServiceImplAdvertisement( + includeTransports); + + monitorManager = (MonitorManager) peerGroup.loadModule(MonitorResources.refMonitorServiceSpecID + , + moduleImplAdvertisement); + monitorManagers.put(peerGroupID, monitorManager); + + // FIXME jice@jxta.org - 20021103 : this + // monitorManager is not a real group service: + // it is being loadModule()'d by another as a + // result, it holds a counted reference to the + // group. Idealy, we'd need the groupAPI to + // offer a means to loadModule() without + // making a counted reference, so that group + // services can loadModule() things without + // preventing group termination. This could be + // achieved elegantly by making this only + // behaviour available through a weak + // GroupInterface. So it would be enough to + // obtain a weak interface from one's group + // and then use its loadmodule method rather + // than that of the strong group interface. + // However that's a bit too big a change to be + // decided without more carefull + // consideration. Instead, we just simulate + // it for now: we give to the monitor manager + // the real group reference after loadModule + // is done, and it discards the strong + // interface object that was passed to its + // init routine. + + monitorManager.setPeerGroup(peerGroup); + } + return monitorManager; + } + + /** + * DO NOT USE THIS METHOD: It will be deprecated when MonitorManager becomes a + * FULL FLEDGED SERVICE + */ + + public static void unregisterMonitorManager(PeerGroup peerGroup) { + PeerGroupID peerGroupID = peerGroup.getPeerGroupID(); + + monitorManagers.remove(peerGroupID); + } + + public static ServiceMonitor getServiceMonitor(PeerGroup peerGroup, ModuleClassID serviceClassID) { + try { + PeerGroupID peerGroupID = peerGroup.getPeerGroupID(); + MonitorManager monitorManager = monitorManagers.get(peerGroupID); + + return monitorManager.getServiceMonitor(serviceClassID); + } catch (Exception e) { // Fix-Me: This is a bit sloppy + throw new RuntimeException("Unable to find MonitorManager or MonitorService"); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorImpl.java new file mode 100644 index 000000000..509bc0cbe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.meter; + + +import net.jxta.meter.ServiceMonitor; + + +public interface ServiceMonitorImpl extends ServiceMonitor { + public void init(MonitorManager monitorManager); + + public void resetPulseRate(ServiceMonitorPulseInfo info, int oldPulseRateIndex); + + public void beginPulse(ServiceMonitorPulseInfo pulseInfo); + + public void endPulse(ServiceMonitorPulseInfo pulseInfo); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorPulseInfo.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorPulseInfo.java new file mode 100644 index 000000000..a574e119c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorPulseInfo.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.meter; + + +import net.jxta.meter.*; +import java.util.*; + + +public class ServiceMonitorPulseInfo { + public static final int NOT_PULSING = MonitorManager.NOT_PULSING; + + private MonitorManager monitorManager; + ServiceMonitor serviceMonitor; + private LinkedList registeredServiceMonitorFilters = new LinkedList(); + private int pulseRateIndex = NOT_PULSING; // quickestReportRateIndex registered for this service + private long pulseRate = NOT_PULSING; // quickestReportRate registered for this service + private int filtersPerRate[]; + private boolean pulsing; + + private class RegisteredServiceMonitorFilter { + ServiceMonitorFilter serviceMonitorFilter; + int reportRateIndex; + + RegisteredServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex) { + this.serviceMonitorFilter = serviceMonitorFilter; + this.reportRateIndex = reportRateIndex; + } + } + + public ServiceMonitorPulseInfo() {} + + ServiceMonitorPulseInfo(MonitorManager monitorManager, ServiceMonitor serviceMonitor) { + this.monitorManager = monitorManager; + this.serviceMonitor = serviceMonitor; + filtersPerRate = new int[monitorManager.getReportRatesCount()]; + } + + public ServiceMonitor getServiceMonitor() { + return serviceMonitor; + } + + public int getPulseRateIndex() { + return pulseRateIndex; + } + + public long getPulseRate() { + return pulseRate; + } + + public boolean isPulsing() { + return pulsing; + } + + public boolean isEvenPulseForRateIndex(int pulseRateIndex) { + return monitorManager.isEvenPulseForRateIndex(pulseRateIndex); + } + + public boolean isRegisteredFilterForRate(int pulseRateIndex) { + return (filtersPerRate[pulseRateIndex] != 0); + } + + void registerServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex, long reportRate) { + RegisteredServiceMonitorFilter registeredServiceMonitorFilter = new RegisteredServiceMonitorFilter(serviceMonitorFilter + , + reportRateIndex); + + registeredServiceMonitorFilters.add(registeredServiceMonitorFilter); + + filtersPerRate[reportRateIndex]++; + + if ((pulseRateIndex == NOT_PULSING) || (reportRateIndex < pulseRateIndex)) { + int oldPulseRateIndex = pulseRateIndex; + + pulseRateIndex = reportRateIndex; + pulseRate = reportRate; + pulsing = true; + if (serviceMonitor instanceof ServiceMonitorImpl) { + ((ServiceMonitorImpl) serviceMonitor).resetPulseRate(this, oldPulseRateIndex); + } + } + + boolean newRate = (filtersPerRate[reportRateIndex] == 1); + + serviceMonitor.serviceMonitorFilterRegistered(serviceMonitorFilter, reportRateIndex, reportRate, newRate); + } + + boolean deregisterServiceMonitorFilter(ServiceMonitorFilter serviceMonitorFilter, int reportRateIndex, long reportRate) { + boolean removed = false; + + for (Iterator i = registeredServiceMonitorFilters.iterator(); i.hasNext();) { + RegisteredServiceMonitorFilter registeredMonitorFilter = i.next(); + + if ((registeredMonitorFilter.serviceMonitorFilter == serviceMonitorFilter) + && (registeredMonitorFilter.reportRateIndex == reportRateIndex)) { + i.remove(); + removed = true; + break; + } + } + + if (!removed) { // Fix-Me: This should never happen if Monitor Manager works properly. + return false; + } + + filtersPerRate[reportRateIndex]--; + + serviceMonitor.serviceMonitorFilterDeregistered(serviceMonitorFilter, reportRateIndex, reportRate + , + filtersPerRate[reportRateIndex] == 0); + + if ((filtersPerRate[reportRateIndex] == 0) && (reportRateIndex == pulseRateIndex)) { + // pulseRateSlowing Down + int newPulseRateIndex = NOT_PULSING; + + for (int i = pulseRateIndex; i < filtersPerRate.length; i++) { + if (filtersPerRate[i] != 0) { + newPulseRateIndex = i; + break; + } + } + + int oldPulserRateIndex = pulseRateIndex; + + pulseRateIndex = newPulseRateIndex; + + if (newPulseRateIndex != NOT_PULSING) { + pulseRate = monitorManager.getReportRate(pulseRateIndex); + pulsing = true; + } else { + pulseRate = NOT_PULSING; + pulsing = false; + } + + if (serviceMonitor instanceof ServiceMonitorImpl) { + ((ServiceMonitorImpl) serviceMonitor).resetPulseRate(this, oldPulserRateIndex); + } + } + return removed; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorResource.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorResource.java new file mode 100644 index 000000000..db5075de4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/meter/ServiceMonitorResource.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.meter; + + +import net.jxta.exception.JxtaException; +import net.jxta.meter.ServiceMonitor; +import net.jxta.platform.ModuleClassID; +import net.jxta.service.Service; + + +public interface ServiceMonitorResource extends Service { + public ServiceMonitor getServiceMonitor(ModuleClassID moduleClassID) throws JxtaException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/monitor.properties b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/monitor.properties new file mode 100644 index 000000000..479d94a4b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/monitor.properties @@ -0,0 +1,64 @@ + +net.meter.standardEndpoint=Endpoint, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000080106, \ + net.jxta.impl.endpoint.endpointMeter.EndpointServiceMonitor, \ + net.jxta.impl.endpoint.endpointMeter.EndpointServiceMonitorFilter, \ + net.jxta.impl.endpoint.endpointMeter.EndpointServiceMetric, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000080106 + +net.meter.standardTransport=Transport, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000080106, \ + net.jxta.impl.endpoint.transportMeter.TransportServiceMonitor, \ + net.jxta.impl.endpoint.transportMeter.TransportServiceMonitorFilter, \ + net.jxta.impl.endpoint.transportMeter.TransportServiceMetric, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE0000000A0106 \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000090106 \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE0000000B0106 + +#net.meter.standardPipe=Pipe, \ +# urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000040106, +# net.jxta.impl.pipe.pipeMeter.PipeServiceMonitor, \ +# net.jxta.impl.pipe.pipeMeter.PipeServiceMonitorFilter, \ +# net.jxta.impl.resolver.pipeMeter.PipeServiceMetric, \ +# urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000040106 +# + +net.meter.standardResolver=Resolver, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000020106, \ + net.jxta.impl.resolver.resolverMeter.ResolverServiceMonitor, \ + net.jxta.impl.resolver.resolverMeter.ResolverServiceMonitorFilter, \ + net.jxta.impl.resolver.resolverMeter.ResolverServiceMetric, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000020106 + +net.meter.standardRendezvous=Rendezvous, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000060106, \ + net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMonitor, \ + net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMonitorFilter, \ + net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMetric, \ + urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000060106 + +#net.meter.standardProxy=Proxy, \ +# net.jxta.impl.endpoint.ProxyMeter.ProxyServiceMonitor, \ +# net.jxta.impl.endpoint.ProxyMeter.ProxyServiceMonitorFilter, \ +# net.jxta.impl.endpoint.ProxyMeter.RendezvousServiceMetric, \ +# urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE0000000E0106 +# +#net.meter.standardDiscovery=Discovery, \ +# net.jxta.impl.discovery.discoveryMeter.DiscoveryServiceMonitor, \ +# net.jxta.impl.discovery.discoveryMeter.DiscoveryServiceMonitorFilter, \ +# net.jxta.impl.discovery.discoveryMeter.DiscoveryServiceMetric, \ +# urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000030106 +# +#net.meter.standardMembership=Membership, \ +# net.jxta.impl.membership.membershipMeter.MembershipServiceMonitor, \ +# net.jxta.impl.membership.membershipMeter.MembershipServiceMonitorFilter, \ +# net.jxta.impl.membership.membershipMeter.MembershipServiceMetric, \ +# urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000050106 +# +#net.meter.standardEndpoint=PeerInfo, \ +# net.jxta.impl.peer.peerInfoMeter.PeerInfoServiceMonitor, \ +# net.jxta.impl.peer.peerInfoMeter.PeerInfoServiceMonitorFilter, \ +# net.jxta.impl.peer.peerInfoMeter.PeerInfoServiceMetric, \ +# urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000070106 +# + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/overview.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/overview.html new file mode 100644 index 000000000..c249f030e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/overview.html @@ -0,0 +1,26 @@ + + + + + + + These packages provide the reference implementation of the JXTA Protocols + using Java Standard Edition 5.0. The JSE reference implementation is + divided into two parts: + The JSE Standard JXTA API + and, this package, the JSE JXTA Reference Implementation. + +

            Additional optional packages which are useful for developers building + JXTA applications can be found in the JXTA JSE Extensions. + + +

            Important Note: Applications and services are very + strongly encouraged to not import classes or interfaces from these + implementation packages. Specificially do not import from + net.jxta.impl.*. The content of these packages may change + significantly (including removal) from release to release with no advance + notice. + + @see JXTA Protocols Specification + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoHandler.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoHandler.java new file mode 100644 index 000000000..965e4a420 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoHandler.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peer; + + +import net.jxta.peer.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.protocol.*; + + +interface PeerInfoHandler { + public void processRequest(int queryId, PeerID requestSourceID, PeerInfoQueryMessage peerInfoQueryMessage, Element requestElement, PeerInfoMessenger peerInfoMessenger); + public void processResponse(int queryId, PeerInfoResponseMessage peerInfoResponseMessage, Element responseElement, PeerInfoMessenger peerInfoMessenger); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoMessenger.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoMessenger.java new file mode 100644 index 000000000..0772e7983 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoMessenger.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peer; + + +import net.jxta.peer.*; +import net.jxta.util.documentSerializable.*; + + +interface PeerInfoMessenger { + public void sendPeerInfoRequest(int queryID, PeerID destinationPeerID, String peerInfoHandler, DocumentSerializable request); + public void sendPeerInfoResponse(int queryId, PeerID destinationPeerID, String peerInfoHandler, DocumentSerializable response); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoServiceImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoServiceImpl.java new file mode 100644 index 000000000..f9ddfeffe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoServiceImpl.java @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peer; + + +import java.util.Hashtable; +import java.util.Random; +import java.io.StringReader; +import java.net.URI; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.service.Service; +import net.jxta.endpoint.EndpointService; +import net.jxta.resolver.ResolverService; +import net.jxta.resolver.QueryHandler; +import net.jxta.document.Advertisement; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.MimeMediaType; +import net.jxta.document.Element; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerInfoQueryMessage; +import net.jxta.protocol.PeerInfoResponseMessage; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peer.PeerInfoService; +import net.jxta.credential.Credential; +import net.jxta.membership.MembershipService; +import net.jxta.impl.protocol.ResolverQuery; +import net.jxta.impl.protocol.ResolverResponse; +import net.jxta.impl.protocol.PeerInfoQueryMsg; +import net.jxta.impl.protocol.PeerInfoResponseMsg; +import net.jxta.exception.JxtaException; +import net.jxta.exception.PeerGroupException; + +import net.jxta.meter.*; +import net.jxta.impl.meter.*; +import net.jxta.peer.*; +import net.jxta.platform.*; +import net.jxta.util.documentSerializable.*; + + +/** + * Peer Info provides a mechanism to obtain information about peers. + * + */ + +public class PeerInfoServiceImpl implements PeerInfoService { + + private final static Logger LOG = Logger.getLogger(PeerInfoServiceImpl.class.getName()); + + /** + * Time in milli seconds since midnight, January 1, 1970 UTC and when this + * peer was started. + */ + private long startTime = 0; + + private ResolverService resolver = null; + private PeerGroup group = null; + private EndpointService endpoint = null; + private PeerID localPeerId = null; + private ModuleImplAdvertisement implAdvertisement = null; + private String resolverHandlerName = null; + private MembershipService membership = null; + private Credential credential = null; + private StructuredDocument credentialDoc = null; + private MonitorManager monitorManager; + private Hashtable peerInfoHandlers = new Hashtable(); + private PipQueryHandler pipQueryHandler = new PipQueryHandler(); + private RemoteMonitorPeerInfoHandler remoteMonitorPeerInfoHandler; + private PeerInfoMessenger resolverServicePeerInfoMessenger = new ResolverServicePeerInfoMessenger(); + + private int nextQueryId = 1000; + private static final Random rand = new Random(); + + // This static package public hashtable of registered PeerInfoServiceImpls + // allows us to do Peergroup Monitoring via an IP Bridge to the PIP + // See the documentation on the JXTA Monitor + static Hashtable peerInfoServices = new Hashtable(); + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException { + this.group = group; + + implAdvertisement = (ModuleImplAdvertisement) impl; + localPeerId = group.getPeerID(); + resolverHandlerName = assignedID.toString(); + + // Fix-Me: When MonitorManager is a true Service, this should be moved to startApp() + try { + if (MeterBuildSettings.METERING) { + monitorManager = MonitorManager.registerMonitorManager(group); + } + // FIXME This will become a service lookup when MonitorService is a real service + } catch (JxtaException e) { + throw new PeerGroupException("Unable to load MonitorManager", e); + } + + // record start time at end of successful init + startTime = System.currentTimeMillis(); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring PeerInfo Service : " + assignedID); + + configInfo.append("\n\tImplementation:"); + configInfo.append("\n\t\tImpl Description: "); + configInfo.append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params:"); + configInfo.append("\n\t\tGroup: ").append(group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID: ").append(group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID: ").append(group.getPeerID()); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + + resolver = group.getResolverService(); + + if (null == resolver) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a resolver service"); + } + + return START_AGAIN_STALLED; + } + + /* Fix-Me: When MonitorService is a true service, this should be moved here from init() + try { + if (MeterBuildSettings.METERING) + monitorManager = MonitorManager.registerMonitorManager(group); + // FIXME : This will become a service lookup when MonitorService is a real service + } catch (JxtaException e) { + return -1; // Fix-Me: This is related to the initialization sequence work on the dev list on load order + } + */ + + // remoteMonitorPeerInfoHandler = new RemoteMonitorPeerInfoHandler(group, this); + // peerInfoHandlers.put(RemoteMonitorPeerInfoHandler.MONITOR_HANDLER_NAME, remoteMonitorPeerInfoHandler); + + resolver = group.getResolverService(); + resolver.registerHandler(resolverHandlerName, pipQueryHandler); + + peerInfoServices.put(group, this); + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + + peerInfoServices.remove(group); + resolver.unregisterHandler(resolverHandlerName); + resolver = null; + + // peerInfoHandlers.remove(RemoteMonitorPeerInfoHandler.MONITOR_HANDLER_NAME); + // remoteMonitorPeerInfoHandler.stop(); + + if (MeterBuildSettings.METERING) { + MonitorManager.unregisterMonitorManager(group); + } + + group = null; + } + + /** + * {@inheritDoc} + */ + public Service getInterface() { + return new PeerInfoServiceInterface(this); + } + + /** + * {@inheritDoc} + */ + public Advertisement getImplAdvertisement() { + return implAdvertisement; + } + + PeerInfoHandler getPeerInfoHandler(String name) { + return (PeerInfoHandler) peerInfoHandlers.get(name); + } + + int getNextQueryId() { + int id = 0; + + synchronized (rand) { + id = rand.nextInt(Integer.MAX_VALUE); + } + return id; + } + + /** + * Returns the group to which this service is attached. + * + * @return PeerGroup the group + */ + public PeerGroup getGroup() { + return group; + } + + /** + * {@inheritDoc} + */ + public boolean isLocalMonitoringAvailable() { + return MeterBuildSettings.METERING; + } + + /** + * {@inheritDoc} + */ + public boolean isLocalMonitoringAvailable(ModuleClassID moduleClassID) { + return MeterBuildSettings.METERING && monitorManager.isLocalMonitoringAvailable(moduleClassID); + } + + /** + * {@inheritDoc} + */ + public long[] getSupportedReportRates() { + return MonitorManager.getReportRates(); + } + + /** + * {@inheritDoc} + */ + public boolean isSupportedReportRate(long reportRate) { + return monitorManager.isSupportedReportRate(reportRate); + } + + /** + * {@inheritDoc} + */ + public long getBestReportRate(long desiredReportRate) { + return monitorManager.getBestReportRate(desiredReportRate); + } + + /** + * {@inheritDoc} + */ + public PeerMonitorInfo getPeerMonitorInfo() { + if (monitorManager != null) { + return monitorManager.getPeerMonitorInfo(); + } else { + return PeerMonitorInfo.NO_PEER_MONITOR_INFO; + } + } + + /** + * {@inheritDoc} + */ + public void getPeerMonitorInfo(final PeerID peerID, PeerMonitorInfoListener peerMonitorInfoListener, long timeout) throws MonitorException { + remoteMonitorPeerInfoHandler.getPeerMonitorInfo(peerID, peerMonitorInfoListener, timeout, resolverServicePeerInfoMessenger); + } + + /** + * {@inheritDoc} + */ + public MonitorReport getCumulativeMonitorReport(MonitorFilter monitorFilter) throws MonitorException { + if (MeterBuildSettings.METERING) { + throw new MonitorException(MonitorException.METERING_NOT_SUPPORTED, "Local Monitoring not Available"); + } + return monitorManager.getCumulativeMonitorReport(monitorFilter); + + } + + /** + * {@inheritDoc} + */ + public void getCumulativeMonitorReport(PeerID peerID, MonitorFilter monitorFilter, MonitorListener monitorListener, long timeout) throws MonitorException { + remoteMonitorPeerInfoHandler.getCumulativeMonitorReport(peerID, monitorFilter, monitorListener, timeout + , + resolverServicePeerInfoMessenger); + } + + /** + * {@inheritDoc} + */ + public long addMonitorListener(MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener) throws MonitorException { + if (!MeterBuildSettings.METERING) { + throw new MonitorException(MonitorException.METERING_NOT_SUPPORTED, "Local Monitoring not Available"); + } + + return monitorManager.addMonitorListener(monitorFilter, reportRate, includeCumulative, monitorListener); + } + + /** + * {@inheritDoc} + */ + public void addRemoteMonitorListener(PeerID peerID, MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener, long lease, long timeout) throws MonitorException { + remoteMonitorPeerInfoHandler.addRemoteMonitorListener(peerID, monitorFilter, reportRate, includeCumulative + , + monitorListener, lease, timeout, resolverServicePeerInfoMessenger); + } + + /** + * {@inheritDoc} + */ + public boolean removeMonitorListener(MonitorListener monitorListener) throws MonitorException { + + int numRemoved = monitorManager.removeMonitorListener(monitorListener); + + return numRemoved > 0; + } + + /** + * {@inheritDoc} + */ + public void removeRemoteMonitorListener(PeerID peerID, MonitorListener monitorListener, long timeout) throws MonitorException { + remoteMonitorPeerInfoHandler.removeRemoteMonitorListener(peerID, monitorListener, timeout + , + resolverServicePeerInfoMessenger); + } + + /** + * {@inheritDoc} + */ + public void removeRemoteMonitorListener(MonitorListener monitorListener, long timeout) throws MonitorException { + remoteMonitorPeerInfoHandler.removeRemoteMonitorListener(monitorListener, timeout, resolverServicePeerInfoMessenger); + } + + class PipQueryHandler implements QueryHandler { + + /** + * {@inheritDoc} + */ + public int processQuery(ResolverQueryMsg query) { + int queryId = query.getQueryId(); + PeerID requestSourceID = null; + + try { + requestSourceID = (PeerID) IDFactory.fromURI(new URI(query.getSrc())); + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "PeerInfoService.processQuery got a bad query, not valid src", e); + } + return ResolverService.OK; + } + + XMLDocument doc = null; + + try { + doc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(query.getQuery())); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "PeerInfoService.processQuery got a bad adv", e); + } + return ResolverService.OK; + } + + PeerInfoQueryMessage pipquery = new PeerInfoQueryMsg(doc); + + Element requestElement = pipquery.getRequest(); + String queryType = (String) requestElement.getKey(); + + if (queryType != null) { + PeerInfoHandler peerInfoHandler = getPeerInfoHandler(queryType); + + if (peerInfoHandler != null) { + peerInfoHandler.processRequest(queryId, requestSourceID, pipquery, requestElement + , + resolverServicePeerInfoMessenger); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No registered PeerInfoHandler for this type of request"); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No request PeerInfoQueryMessage Request Element found"); + } + } + + return ResolverService.OK; + } + + /** + * {@inheritDoc} + */ + public void processResponse(ResolverResponseMsg response) { + + int queryId = response.getQueryId(); + + PeerInfoResponseMessage resp = null; + + try { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8 + , + new StringReader(response.getResponse())); + + resp = new PeerInfoResponseMsg(doc); + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "PeerInfoService.processResponse got a bad adv", e); + } + return; + } + + Element responseElement = resp.getResponse(); + String responseType = (String) responseElement.getKey(); + + if (responseType != null) { + PeerInfoHandler peerInfoHandler = getPeerInfoHandler(responseType); + + if (peerInfoHandler != null) { + peerInfoHandler.processResponse(queryId, resp, responseElement, resolverServicePeerInfoMessenger); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No registered PeerInfoHandler for this type of response"); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No request PeerInfoResponseMessage Response Element found"); + } + } + } + } + + + private class ResolverServicePeerInfoMessenger implements PeerInfoMessenger { + + /** + * {@inheritDoc} + */ + public void sendPeerInfoResponse(int queryId, PeerID destinationPeerID, String peerInfoHandler, DocumentSerializable response) { + try { + PeerInfoResponseMessage peerInfoResponseMessage = new PeerInfoResponseMsg(); + + peerInfoResponseMessage.setSourcePid(destinationPeerID); + peerInfoResponseMessage.setTargetPid(localPeerId); + + long now = System.currentTimeMillis(); + + peerInfoResponseMessage.setUptime(now - startTime); + peerInfoResponseMessage.setTimestamp(now); + + Element responseElement = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, peerInfoHandler); + + response.serializeTo(responseElement); + + peerInfoResponseMessage.setResponse(responseElement); + + XMLDocument doc = (XMLDocument) peerInfoResponseMessage.getDocument(MimeMediaType.XMLUTF8); + String peerInfoResponse = doc.toString(); + + ResolverResponse resolverResponse = new ResolverResponse(resolverHandlerName, credentialDoc, queryId + , + peerInfoResponse); + + resolver.sendResponse(destinationPeerID.toString(), resolverResponse); + } catch (JxtaException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure building document", e); + } + } + } + + /** + * {@inheritDoc} + */ + public void sendPeerInfoRequest(int queryID, PeerID destinationPeerID, String peerInfoHandler, DocumentSerializable request) { + try { + PeerInfoQueryMsg peerInfoQueryMsg = new PeerInfoQueryMsg(); + + peerInfoQueryMsg.setSourcePid(localPeerId); + peerInfoQueryMsg.setTargetPid(destinationPeerID); + + Element requestElement = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, peerInfoHandler); + + request.serializeTo(requestElement); + + peerInfoQueryMsg.setRequest(requestElement); + + XMLDocument doc = (XMLDocument) peerInfoQueryMsg.getDocument(MimeMediaType.XMLUTF8); + String peerInfoRequest = doc.toString(); + + ResolverQuery resolverQuery = new ResolverQuery(resolverHandlerName, credentialDoc, localPeerId.toString() + , + peerInfoRequest, queryID); + + resolver.sendQuery(destinationPeerID.toString(), resolverQuery); + } catch (JxtaException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure to build resolver query", e); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoServiceInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoServiceInterface.java new file mode 100644 index 000000000..5f5c87516 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/PeerInfoServiceInterface.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peer; + + +import java.io.IOException; +import java.util.Enumeration; +import net.jxta.document.Advertisement; +import net.jxta.service.Service; +import net.jxta.id.ID; +import net.jxta.peer.PeerInfoService; +import net.jxta.peer.PeerInfoListener; +import net.jxta.peer.PeerInfoEvent; +import net.jxta.peergroup.PeerGroup; +import net.jxta.exception.PeerGroupException; +import net.jxta.protocol.PeerInfoResponseMessage; +import net.jxta.impl.peer.PeerInfoServiceImpl; +import net.jxta.peer.*; +import net.jxta.meter.*; +import net.jxta.platform.*; + + +/** + * PeerInfoServiceInterface provides a pure interface object that permits + * interaction with the actual PeerInfoService implementation without giving + * access to the real object. + */ +public class PeerInfoServiceInterface implements PeerInfoService { + + private PeerInfoService impl; + + /** + * {@inheritDoc} + * Since THIS is already such an + * object, it returns itself. FIXME: it is kind of absurd to have this + * method part of the interface but we do not want to define two levels + * of Service interface just for that. + * + */ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + * + */ + public Advertisement getImplAdvertisement() { + return impl.getImplAdvertisement(); + } + + /** + * Only authorized constructor + * + *@param theRealThing + */ + public PeerInfoServiceInterface(PeerInfoService theRealThing) { + impl = theRealThing; + } + + /** + * {@inheritDoc} + *

            Initialize the application FIXME: This is meaningless for the + * interface object; it is there only to satisfy the requirements of + * the interface that we implement. Ultimately, the API should define + * two levels of interfaces: one for the real service implementation + * and one for the interface object. Right now it feels a bit heavy to + * so that since the only different between the two would be init() and + * may-be getName(). + * + */ + public void init(PeerGroup pg, ID assignedID, Advertisement impl) {} + + /** + * {@inheritDoc} + *

            This is here for temporary class hierarchy reasons. it is ALWAYS + * ignored. By definition, the interface object protects the real + * object's start/stop methods from being called + * + */ + public int startApp(String[] arg) { + return 0; + } + + /** + * {@inheritDoc} + *

            This is here for temporary class hierarchy reasons. it is ALWAYS + * ignored. By definition, the interface object protects the real + * object's start/stop methods from being called This request is + * currently ignored. + */ + public void stopApp() {} + + public boolean isLocalMonitoringAvailable() { + return (impl.isLocalMonitoringAvailable()); + } + + public boolean isLocalMonitoringAvailable(ModuleClassID moduleClassID) { + return (impl.isLocalMonitoringAvailable(moduleClassID)); + } + + public long[] getSupportedReportRates() { + return impl.getSupportedReportRates(); + } + + public boolean isSupportedReportRate(long reportRate) { + return impl.isSupportedReportRate(reportRate); + } + + public long getBestReportRate(long desiredReportRate) { + return impl.getBestReportRate(desiredReportRate); + } + + public PeerMonitorInfo getPeerMonitorInfo() { + return impl.getPeerMonitorInfo(); + } + + public void getPeerMonitorInfo(PeerID peerID, PeerMonitorInfoListener peerMonitorInfoListener, long timeout) throws MonitorException { + impl.getPeerMonitorInfo(peerID, peerMonitorInfoListener, timeout); + } + + public MonitorReport getCumulativeMonitorReport(MonitorFilter monitorFilter) throws MonitorException { + return impl.getCumulativeMonitorReport(monitorFilter); + } + + public void getCumulativeMonitorReport(PeerID peerID, MonitorFilter monitorFilter, MonitorListener monitorListener, long timeout) throws MonitorException { + impl.getCumulativeMonitorReport(peerID, monitorFilter, monitorListener, timeout); + } + + public long addMonitorListener(MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener) throws MonitorException { + return impl.addMonitorListener(monitorFilter, reportRate, includeCumulative, monitorListener); + } + + public void addRemoteMonitorListener(PeerID peerID, MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener, long lease, long timeout) throws MonitorException { + impl.addRemoteMonitorListener(peerID, monitorFilter, reportRate, includeCumulative, monitorListener, lease, timeout); + } + + public boolean removeMonitorListener(MonitorListener monitorListener) throws MonitorException { + return impl.removeMonitorListener(monitorListener); + } + + public void removeRemoteMonitorListener(PeerID peerID, MonitorListener monitorListener, long timeout) throws MonitorException { + impl.removeRemoteMonitorListener(peerID, monitorListener, timeout); + } + + public void removeRemoteMonitorListener(MonitorListener monitorListener, long timeout) throws MonitorException { + impl.removeRemoteMonitorListener(monitorListener, timeout); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorPeerInfoHandler.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorPeerInfoHandler.java new file mode 100644 index 000000000..a92d4857d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorPeerInfoHandler.java @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peer; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Hashtable; +import java.util.Random; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.document.Element; +import net.jxta.protocol.PeerInfoQueryMessage; +import net.jxta.protocol.PeerInfoResponseMessage; +import net.jxta.peergroup.PeerGroup; +import net.jxta.exception.PeerGroupException; +import net.jxta.peer.PeerInfoService; +import net.jxta.peergroup.PeerGroupID; + +import net.jxta.meter.MonitorEvent; +import net.jxta.meter.MonitorException; +import net.jxta.meter.MonitorFilter; +import net.jxta.meter.MonitorFilterException; +import net.jxta.meter.MonitorListener; +import net.jxta.meter.MonitorReport; +import net.jxta.meter.MonitorResources; +import net.jxta.meter.PeerMonitorInfo; +import net.jxta.meter.PeerMonitorInfoEvent; +import net.jxta.meter.PeerMonitorInfoListener; +import net.jxta.meter.ServiceMonitorFilter; +import net.jxta.peer.PeerID; +import net.jxta.util.documentSerializable.DocumentSerializableUtilities; +import net.jxta.util.documentSerializable.DocumentSerializationException; +import net.jxta.impl.util.TimerThreadNamer; + +class RemoteMonitorPeerInfoHandler implements PeerInfoHandler { + public static final String MONITOR_HANDLER_NAME = "Monitor"; + public static final int MAX_LEASE = 5 * 60 * 1000; // 5 minutes + public static final int MIN_LEASE = 60 * 1000; // 1 minute + + private static final Random rand = new Random(); + private final static Logger LOG = Logger.getLogger(RemoteMonitorPeerInfoHandler.class.getName()); + + private Hashtable requestInfos = new Hashtable(); + private Hashtable leaseInfos = new Hashtable(); + private Hashtable timeouts = new Hashtable(); + private PeerGroup peerGroup; + private PeerInfoServiceImpl peerInfoServiceImpl; + private Timer timer = new Timer(true); + + RemoteMonitorPeerInfoHandler(PeerGroup peerGroup, PeerInfoServiceImpl peerInfoServiceImpl) { + this.peerGroup = peerGroup; + this.peerInfoServiceImpl = peerInfoServiceImpl; + timer.schedule(new TimerThreadNamer("RemoteMonitorPeerInfo timer for " + peerGroup.getPeerGroupID()), 0); + } + + public void stop() { + timer.cancel(); + } + + private int getNextLeaseId() { + int id; + synchronized (rand) { + id = rand.nextInt(Integer.MAX_VALUE); + } + return id; + } + + private class RequestInfo { + long requestTime = System.currentTimeMillis(); + PeerID peerId; + int queryId; + int origRequestId; + MonitorListener monitorListener; + PeerMonitorInfoListener peerMonitorInfoListener; + long timeout; + long validUntil; + boolean responseReceived = false; + int leaseId; // other guys leaseId. + long requestedLease; + PeerInfoMessenger peerInfoMessenger; + RequestInfo(PeerID peerId, int queryId, MonitorListener monitorListener, long timeout, PeerInfoMessenger peerInfoMessenger) { + this(peerId, queryId, timeout, peerInfoMessenger); + this.monitorListener = monitorListener; + } + + RequestInfo(PeerID peerId, int queryId, PeerMonitorInfoListener peerMonitorInfoListener, long timeout, PeerInfoMessenger peerInfoMessenger) { + this(peerId, queryId, timeout, peerInfoMessenger); + this.peerMonitorInfoListener = peerMonitorInfoListener; + } + + RequestInfo(PeerID peerId, int queryId, long timeout, PeerInfoMessenger peerInfoMessenger) { + this.peerId = peerId; + this.queryId = queryId; + this.timeout = timeout; + this.peerInfoMessenger = peerInfoMessenger; + this.validUntil = System.currentTimeMillis() + timeout; + } + } + + + private class LeaseInfo { + int leaseId; + PeerID peerID; // Peer that requested the lease + int queryId; // The other guy's query Id + MonitorListener monitorListener; + long validUntil; + boolean listenerAddedToWorldGroup = false; + PeerGroup worldGroup; + PeerInfoMessenger peerInfoMessenger; + LeaseInfo(int leaseId, PeerID peerID, int queryId, MonitorListener monitorListener, long leaseLength, PeerInfoMessenger peerInfoMessenger) { + this.leaseId = leaseId; + this.peerID = peerID; + this.queryId = queryId; + this.monitorListener = monitorListener; + this.peerInfoMessenger = peerInfoMessenger; + validUntil = System.currentTimeMillis() + leaseLength; + } + + } + + public void getPeerMonitorInfo(final PeerID peerID, PeerMonitorInfoListener peerMonitorInfoListener, long timeout, PeerInfoMessenger peerInfoMessenger) throws MonitorException { + int queryId = peerInfoServiceImpl.getNextQueryId(); + + RemoteMonitorQuery remoteMonitorQuery = RemoteMonitorQuery.createPeerMonitorInfoQuery(); + peerInfoMessenger.sendPeerInfoRequest(queryId, peerID, MONITOR_HANDLER_NAME, remoteMonitorQuery); + final RequestInfo requestInfo = new RequestInfo(peerID, queryId, peerMonitorInfoListener, timeout, peerInfoMessenger); + requestInfos.put(queryId, requestInfo); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (!requestInfo.responseReceived) { + PeerMonitorInfoEvent peerMonitorInfoEvent = new PeerMonitorInfoEvent(peerID, null); + + requestInfo.peerMonitorInfoListener.peerMonitorInfoNotReceived(peerMonitorInfoEvent); + requestInfos.remove(requestInfo.queryId); + } + } + }, timeout); + } + + public void getCumulativeMonitorReport(PeerID peerID, MonitorFilter monitorFilter, MonitorListener monitorListener, long timeout, PeerInfoMessenger peerInfoMessenger) throws MonitorException { + int queryId = peerInfoServiceImpl.getNextQueryId(); + RemoteMonitorQuery remoteMonitorQuery = RemoteMonitorQuery.createGetCumulativeReportQuery(monitorFilter); + peerInfoMessenger.sendPeerInfoRequest(queryId, peerID, MONITOR_HANDLER_NAME, remoteMonitorQuery); + final RequestInfo requestInfo = new RequestInfo(peerID, queryId, monitorListener, timeout, peerInfoMessenger); + requestInfos.put(queryId, requestInfo); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (!requestInfo.responseReceived) { + requestInfos.remove(requestInfo.queryId); + } + } + }, timeout); + } + + public void addRemoteMonitorListener(PeerID peerID, MonitorFilter monitorFilter, long reportRate, boolean includeCumulative, MonitorListener monitorListener, long lease, long timeout, PeerInfoMessenger peerInfoMessenger) throws MonitorException { + int queryId = peerInfoServiceImpl.getNextQueryId(); + RemoteMonitorQuery remoteMonitorQuery = RemoteMonitorQuery.createRegisterMonitorQuery(includeCumulative, monitorFilter, reportRate, lease); + peerInfoMessenger.sendPeerInfoRequest(queryId, peerID, MONITOR_HANDLER_NAME, remoteMonitorQuery); + final RequestInfo requestInfo = new RequestInfo(peerID, queryId, monitorListener, timeout, peerInfoMessenger); + requestInfo.requestedLease = lease; + requestInfos.put(queryId, requestInfo); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (!requestInfo.responseReceived) { + MonitorEvent monitorEvent = MonitorEvent.createFailureEvent(MonitorEvent.TIMEOUT, requestInfo.peerId, + requestInfo.queryId); + + requestInfo.monitorListener.monitorRequestFailed(monitorEvent); + requestInfos.remove(requestInfo.queryId); + } + } + }, timeout); + scheduleTimeout(requestInfo); + } + + public void removeRemoteMonitorListener(PeerID peerID, MonitorListener monitorListener, long timeout, PeerInfoMessenger peerInfoMessenger) throws MonitorException { + int queryId = peerInfoServiceImpl.getNextQueryId(); + + RequestInfo oldRequestInfo = null; + for (Enumeration e = requestInfos.elements(); e.hasMoreElements();) { + RequestInfo ri = e.nextElement(); + + if (ri.monitorListener == monitorListener) { + oldRequestInfo = ri; + break; + } + } + + if (oldRequestInfo != null) { + RemoteMonitorQuery remoteMonitorQuery = RemoteMonitorQuery.createRemoveMonitorListenerQuery(oldRequestInfo.leaseId); + peerInfoMessenger.sendPeerInfoRequest(queryId, peerID, MONITOR_HANDLER_NAME, remoteMonitorQuery); + final RequestInfo requestInfo = new RequestInfo(peerID, queryId, monitorListener, timeout, peerInfoMessenger); + requestInfo.origRequestId = oldRequestInfo.queryId; + requestInfos.put(queryId, requestInfo); + } + + final RequestInfo requestInfo = oldRequestInfo; + timer.schedule(new TimerTask() { + + @Override + public void run() { + requestInfos.remove(new Integer(requestInfo.queryId)); + } + }, timeout); + } + + public void removeRemoteMonitorListener(MonitorListener monitorListener, long timeout, PeerInfoMessenger peerInfoMessenger) throws MonitorException { + for (Enumeration e = requestInfos.elements(); e.hasMoreElements();) { + RequestInfo requestInfo = e.nextElement(); + + if (requestInfo.monitorListener == monitorListener) { + removeRemoteMonitorListener(requestInfo.peerId, monitorListener, timeout, peerInfoMessenger); + } + } + } + + public void processRequest(int queryId, PeerID requestSourceID, PeerInfoQueryMessage peerInfoQueryMessage, Element requestElement, PeerInfoMessenger peerInfoMessenger) { + try { + RemoteMonitorQuery remoteMonitorQuery = (RemoteMonitorQuery) DocumentSerializableUtilities.getDocumentSerializable(requestElement, RemoteMonitorQuery.class); + + if (remoteMonitorQuery.isRegisterMonitorQuery()) { + handleRegisterMonitorQuery(queryId, requestSourceID, remoteMonitorQuery, peerInfoMessenger); + + } else if (remoteMonitorQuery.isCumulativeReportQuery()) { + handleCumulativeReportQuery(queryId, requestSourceID, remoteMonitorQuery.getMonitorFilter(), peerInfoMessenger); + + } else if (remoteMonitorQuery.isRemoveMonitorQuery()) { + handleRemoveMonitorQuery(queryId, requestSourceID, remoteMonitorQuery, peerInfoMessenger); + + } else if (remoteMonitorQuery.isPeerMonitorInfoQuery()) { + handlePeerMonitorInfoQuery(queryId, requestSourceID, peerInfoMessenger); + + } else if (remoteMonitorQuery.isLeaseRenewal()) { + handleLeaseRenewalQuery(queryId, requestSourceID, remoteMonitorQuery, peerInfoMessenger); + + } + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Monitor failed in processQuery", e); + } + } + } + + public void processResponse(int queryId, PeerInfoResponseMessage peerInfoResponseMessage, Element responseElement, PeerInfoMessenger peerInfoMessenger) { + + RemoteMonitorResponse remoteMonitorResponse; + + try { + remoteMonitorResponse = (RemoteMonitorResponse) DocumentSerializableUtilities.getDocumentSerializable(responseElement, RemoteMonitorResponse.class); + RequestInfo requestInfo = requestInfos.get(new Integer(queryId)); + + if (requestInfo != null) { + requestInfo.responseReceived = true; + + resetTimeout(requestInfo); + if (remoteMonitorResponse.isMonitorRegistered()) { + int leaseId = remoteMonitorResponse.getLeaseId(); + long leaseLength = remoteMonitorResponse.getLease(); + + requestInfo.leaseId = leaseId; + scheduleLeaseRenewal(requestInfo, leaseLength); + + } else if (remoteMonitorResponse.isMonitorRemoved()) { + requestInfos.remove(new Integer(requestInfo.origRequestId)); + requestInfos.remove(new Integer(queryId)); + + } else if (remoteMonitorResponse.isCumulativeReport() || remoteMonitorResponse.isMonitorReport()) { + MonitorReport monitorReport = remoteMonitorResponse.getMonitorReport(); + MonitorEvent monitorEvent = MonitorEvent.createRemoteMonitorReportEvent(requestInfo.peerId, requestInfo.queryId, monitorReport); + requestInfo.monitorListener.processMonitorReport(monitorEvent); + } else if (remoteMonitorResponse.isInvalidFilter()) { + MonitorEvent monitorEvent = MonitorEvent.createFailureEvent(MonitorEvent.INVALID_MONITOR_FILTER, requestInfo.peerId, requestInfo.queryId); + requestInfo.monitorListener.monitorRequestFailed(monitorEvent); + requestInfos.remove(new Integer(queryId)); + } else if (remoteMonitorResponse.isInvalidReportRate()) { + MonitorEvent monitorEvent = MonitorEvent.createFailureEvent(MonitorEvent.INVALID_REPORT_RATE, requestInfo.peerId, requestInfo.queryId); + requestInfo.monitorListener.monitorRequestFailed(monitorEvent); + requestInfos.remove(new Integer(queryId)); + } else if (remoteMonitorResponse.isMeteringNotSupported()) { + MonitorEvent monitorEvent = MonitorEvent.createFailureEvent(MonitorEvent.REFUSED, requestInfo.peerId, requestInfo.queryId); + requestInfo.monitorListener.monitorRequestFailed(monitorEvent); + requestInfos.remove(new Integer(queryId)); + } else if (remoteMonitorResponse.isRequestDenied()) { + MonitorEvent monitorEvent = MonitorEvent.createFailureEvent(MonitorEvent.REFUSED, requestInfo.peerId, requestInfo.queryId); + requestInfo.monitorListener.monitorRequestFailed(monitorEvent); + } else if (remoteMonitorResponse.isPeerMonitorInfo()) { + PeerMonitorInfoEvent peerMonitorInfoEvent = new PeerMonitorInfoEvent(requestInfo.peerId, remoteMonitorResponse.getPeerMonitorInfo()); + requestInfo.peerMonitorInfoListener.peerMonitorInfoReceived(peerMonitorInfoEvent); + requestInfos.remove(new Integer(queryId)); + } else if (remoteMonitorResponse.isLeaseRenewed()) { + long lease = remoteMonitorResponse.getLease(); + int origRequestId = requestInfo.origRequestId; + RequestInfo origRequest = requestInfos.get(new Integer(origRequestId)); + scheduleLeaseRenewal(origRequest, lease); + requestInfos.remove(new Integer(queryId)); + } + } + } catch (DocumentSerializationException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Document Serialization Failed", e); + } + } + } + + private void resetTimeout(RequestInfo requestInfo) { + timeouts.put(requestInfo.queryId, requestInfo.timeout + System.currentTimeMillis()); + } + + private long getTimeout(int queryId) { + return timeouts.get(queryId); + } + + private void scheduleTimeout(final RequestInfo requestInfo) { + final int queryId = requestInfo.queryId; + + timer.schedule( + new TimerTask() { + @Override + public void run() { + if (requestInfos.containsKey(new Integer(queryId))) { + try { + if (System.currentTimeMillis() > getTimeout(queryId)) { + MonitorEvent monitorEvent = MonitorEvent.createFailureEvent(MonitorEvent.TIMEOUT, requestInfo.peerId, queryId); + requestInfo.monitorListener.monitorRequestFailed(monitorEvent); + } + } catch (Exception e) { + //ignored + } + } else { + cancel(); + } + } + }, requestInfo.timeout, requestInfo.timeout); + } + + private void scheduleLeaseRenewal(RequestInfo requestInfo, long leaseLength) { + long roundTrip = requestInfo.requestTime - System.currentTimeMillis(); + long renewTime = leaseLength - roundTrip - 30 * 1000L; // 30s comfort + // zone. + final int queryId = requestInfo.queryId; + + if (renewTime > MIN_LEASE) { + timer.schedule(new TimerTask() { + + @Override + public void run() { + try { + renewLease(queryId); + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Lease Renewal Failed", e); + } + } + } + }, renewTime); + } + } + + private void handleRegisterMonitorQuery(final int queryId, final PeerID requestSourceID, RemoteMonitorQuery remoteMonitorQuery, final PeerInfoMessenger peerInfoMessenger) { + MonitorFilter monitorFilter = remoteMonitorQuery.getMonitorFilter(); + long lease = remoteMonitorQuery.getLease(); + long reportRate = remoteMonitorQuery.getReportRate(); + boolean includeCumulative = remoteMonitorQuery.isIncludeCumulative(); + + MonitorListener monitorListener = new MonitorListener() { + + public void processMonitorReport(MonitorEvent monitorEvent) { + MonitorReport monitorReport = monitorEvent.getMonitorReport(); + try { + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createMonitorReportResponse(queryId, monitorReport); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + + public void monitorReportingCancelled(MonitorEvent monitorEvent) { + throw new RuntimeException("METHOD NOT IMPLEMENTED"); + } + + public void monitorRequestFailed(MonitorEvent monitorEvent) { + throw new RuntimeException("METHOD NOT IMPLEMENTED"); + } + }; + + int leaseId = getNextLeaseId(); + final LeaseInfo leaseInfo = new LeaseInfo(leaseId, requestSourceID, queryId, monitorListener, lease, peerInfoMessenger); + long leaseTime = getLeaseTime(lease); + + setupLeaseTimeout(leaseInfo.leaseId, leaseTime); + + try { + /* + * Currently we can neither ask peers in the netgroup for transport + * metrics, nor discover peers in the world group. Therefore we're + * asking peers in the netgroup to send TransportMetrics, but that + * peer is actually attaching the MonitorFilter to it's WorldGroup + * peer. + */ + for (Iterator i = monitorFilter.getServiceMonitorFilters(); i.hasNext();) { + ServiceMonitorFilter serviceMonitorFilter = (ServiceMonitorFilter) i.next(); + + if (serviceMonitorFilter.getModuleClassID().equals(MonitorResources.transportServiceMonitorClassID)) { + try { + MonitorFilter worldGroupFilter = new MonitorFilter("worldGroupFilter"); + + worldGroupFilter.addServiceMonitorFilter(serviceMonitorFilter); + i.remove(); + PeerGroup worldGroup = peerGroup.newGroup(PeerGroupID.worldPeerGroupID); + PeerInfoService worldService = worldGroup.getPeerInfoService(); + + worldService.addMonitorListener(worldGroupFilter, remoteMonitorQuery.getReportRate(), includeCumulative, + monitorListener); + leaseInfo.listenerAddedToWorldGroup = true; + leaseInfo.worldGroup = worldGroup; + } catch (PeerGroupException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + } + if (monitorFilter.getServiceMonitorFilterCount() > 0) { + peerInfoServiceImpl.addMonitorListener(monitorFilter, reportRate, includeCumulative, monitorListener); + } + leaseInfos.put(leaseId, leaseInfo); + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createMonitorRegisteredResponse(queryId, leaseId, leaseTime); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } catch (MonitorFilterException e) { + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createInvalidFilterResponse(queryId); + + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } catch (MonitorException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + + private void handleRemoveMonitorQuery(int queryId, PeerID requestSourceID, RemoteMonitorQuery remoteMonitorQuery, PeerInfoMessenger peerInfoMessenger) { + try { + int leaseId = remoteMonitorQuery.getLeaseId(); + LeaseInfo leaseInfo = leaseInfos.get(new Integer(leaseId)); + + if (leaseInfo != null) { + MonitorListener monitorListener = leaseInfo.monitorListener; + + peerInfoServiceImpl.removeMonitorListener(monitorListener); + if (leaseInfo.listenerAddedToWorldGroup) { + PeerInfoService peerInfoService = leaseInfo.worldGroup.getPeerInfoService(); + peerInfoService.removeMonitorListener(monitorListener); + } + + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createMonitorRemovedResponse(queryId); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } + } catch (MonitorException e) { + // Currently not thrown by MonitorManager.removeMonitorListener() + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + + private void handleCumulativeReportQuery(int queryId, PeerID requestSourceID, MonitorFilter monitorFilter, PeerInfoMessenger peerInfoMessenger) throws MonitorException, DocumentSerializationException { + MonitorReport monitorReport = peerInfoServiceImpl.getCumulativeMonitorReport(monitorFilter); + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createCumulativeReportResponse(queryId, monitorReport); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } + + private void handlePeerMonitorInfoQuery(int queryId, PeerID requestSourceID, PeerInfoMessenger peerInfoMessenger) throws DocumentSerializationException { + // FIX-ME: + /* Asking the NetGroup Peer won't tell me if it supports transport + * monitoring or not, but asking the world group guy gives me + * everything I need because as currently implemented you can't turn + * monitoring on or off at the PeerGroup level, only the device level. + */ + try { + PeerGroup worldGroup = peerGroup.newGroup(PeerGroupID.worldPeerGroupID); + PeerInfoService worldService = worldGroup.getPeerInfoService(); + + PeerMonitorInfo peerMonitorInfo = worldService.getPeerMonitorInfo(); + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createPeerMonitorInfoResponse(queryId, peerMonitorInfo); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } catch (PeerGroupException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(e.toString()); + } + } + } + + private void handleLeaseRenewalQuery(int queryId, PeerID requestSourceID, RemoteMonitorQuery remoteMonitorQuery, PeerInfoMessenger peerInfoMessenger) throws DocumentSerializationException { + int leaseId = remoteMonitorQuery.getLeaseId(); + LeaseInfo leaseInfo = leaseInfos.get(new Integer(leaseId)); + + if (leaseInfo != null) { + long reqLease = remoteMonitorQuery.getLease(); + long lease = getLeaseTime(reqLease); + + leaseInfo.validUntil = System.currentTimeMillis() + lease; + setupLeaseTimeout(leaseInfo.leaseId, lease); + + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createLeaseRenewedResponse(queryId, leaseInfo.leaseId, lease); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } else { + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createDeniedResponse(queryId); + peerInfoMessenger.sendPeerInfoResponse(queryId, requestSourceID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } + } + + long getLeaseTime(long requestedLease) { + long leaseTime = requestedLease < MAX_LEASE ? requestedLease : MAX_LEASE; + + leaseTime = leaseTime > MIN_LEASE ? leaseTime : MIN_LEASE; + return leaseTime; + } + + private void cancelLease(LeaseInfo leaseInfo) throws MonitorException, DocumentSerializationException { + if (leaseInfo.listenerAddedToWorldGroup) { + leaseInfo.worldGroup.getPeerInfoService().removeMonitorListener(leaseInfo.monitorListener); + } + + RemoteMonitorResponse remoteMonitorResponse = RemoteMonitorResponse.createLeaseEndedResponse(leaseInfo.queryId, leaseInfo.leaseId); + leaseInfo.peerInfoMessenger.sendPeerInfoResponse(leaseInfo.queryId, leaseInfo.peerID, MONITOR_HANDLER_NAME, remoteMonitorResponse); + } + + private void renewLease(int queryId) { + try { + RequestInfo requestInfo = requestInfos.get(new Integer(queryId)); + + if (requestInfo != null) { + int renewalQueryId = peerInfoServiceImpl.getNextQueryId(); + PeerID peerID = requestInfo.peerId; + long timeout = requestInfo.timeout; + + RemoteMonitorQuery remoteMonitorQuery = RemoteMonitorQuery.createLeaseRenewalQuery(requestInfo.leaseId, requestInfo.requestedLease); + + requestInfo.peerInfoMessenger.sendPeerInfoRequest(queryId, peerID, MONITOR_HANDLER_NAME, remoteMonitorQuery); + final RequestInfo renewalRequestInfo = new RequestInfo(peerID, queryId, timeout, requestInfo.peerInfoMessenger); + + renewalRequestInfo.requestedLease = requestInfo.requestedLease; + renewalRequestInfo.origRequestId = queryId; + requestInfos.put(renewalQueryId, renewalRequestInfo); + } + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "error while attempting Monitor lease renewal", e); + } + } + } + + private void setupLeaseTimeout(final int leaseId, long lease) { + + timer.schedule(new TimerTask() { + + @Override + public void run() { + LeaseInfo leaseInfo = leaseInfos.get(new Integer(leaseId)); + + if (leaseInfo != null) { + long currentTime = System.currentTimeMillis(); + + if (leaseInfo.validUntil <= currentTime) { + try { + cancelLease(leaseInfo); + } catch (Exception e) { + // ignored + } finally { + leaseInfos.remove(leaseInfo.queryId); + } + } + } + } + }, lease); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorQuery.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorQuery.java new file mode 100644 index 000000000..dad252ec8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorQuery.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peer; + + +import net.jxta.document.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.meter.*; + +import java.util.*; + + +public class RemoteMonitorQuery implements DocumentSerializable { + + public static final String CUMULATIVE_REPORT_REQUEST = "cumulativeReport"; + public static final String REGISTER_MONITOR_REQUEST = "registerMonitor"; + public static final String REMOVE_MONITOR_REQUEST = "removeMonitor"; + public static final String VALIDATE_FILTER_REQUEST = "validateFilter"; + public static final String VALIDATE_CUMULATIVE_FILTER_REQUEST = "validateCumulativeFilter"; + public static final String GET_MONITORING_CAPABILITIES_REQUEST = "remoteMonitoringCapabilities"; + public static final String PEER_MONITOR_INFO = "peerMonitorInfo"; + public static final String RENEW_LEASE = "renewLease"; + + private String requestType; + private MonitorFilter monitorFilter; + private boolean includeCumulative; + private long reportRate = -1; + private long lease = -1; + private int leaseId; + + public RemoteMonitorQuery() {} // for serialization code. + + private RemoteMonitorQuery(String requestType) { + this.requestType = requestType; + } + + public MonitorFilter getMonitorFilter() { + return monitorFilter; + } + + private String getRequestType() { + return requestType; + } + + public long getReportRate() { + return reportRate; + } + + public long getLease() { + return lease; + } + + public int getLeaseId() { + return leaseId; + } + + public boolean isIncludeCumulative() { + return includeCumulative; + } + + boolean isCumulativeReportQuery() { + return requestType.equals(CUMULATIVE_REPORT_REQUEST); + } + + boolean isRegisterMonitorQuery() { + return requestType.equals(REGISTER_MONITOR_REQUEST); + } + + boolean isRemoveMonitorQuery() { + return requestType.equals(REMOVE_MONITOR_REQUEST); + } + + boolean isValidateFilterRequest() { + return requestType.equals(VALIDATE_FILTER_REQUEST); + } + + boolean isValidateCumulativeFilterRequest() { + return requestType.equals(VALIDATE_CUMULATIVE_FILTER_REQUEST); + } + + boolean isPeerMonitorInfoQuery() { + return requestType.equals(PEER_MONITOR_INFO); + } + + boolean isLeaseRenewal() { + return requestType.equals(RENEW_LEASE); + } + + static RemoteMonitorQuery createGetCumulativeReportQuery(MonitorFilter monitorFilter) { + RemoteMonitorQuery remoteMonitorQuery = new RemoteMonitorQuery(CUMULATIVE_REPORT_REQUEST); + + remoteMonitorQuery.monitorFilter = monitorFilter; + return remoteMonitorQuery; + } + + static RemoteMonitorQuery createRegisterMonitorQuery(boolean includeCumulative, MonitorFilter monitorFilter, long reportRate, long lease) { + RemoteMonitorQuery remoteMonitorQuery = new RemoteMonitorQuery(REGISTER_MONITOR_REQUEST); + + remoteMonitorQuery.monitorFilter = monitorFilter; + remoteMonitorQuery.reportRate = reportRate; + remoteMonitorQuery.lease = lease; + remoteMonitorQuery.includeCumulative = includeCumulative; + return remoteMonitorQuery; + } + + static RemoteMonitorQuery createRemoveMonitorListenerQuery(int leaseId) { + RemoteMonitorQuery remoteMonitorQuery = new RemoteMonitorQuery(REMOVE_MONITOR_REQUEST); + + remoteMonitorQuery.leaseId = leaseId; + return remoteMonitorQuery; + } + + static RemoteMonitorQuery createPeerMonitorInfoQuery() { + RemoteMonitorQuery remoteMonitorQuery = new RemoteMonitorQuery(PEER_MONITOR_INFO); + + return remoteMonitorQuery; + } + + static RemoteMonitorQuery createLeaseRenewalQuery(int leaseId, long requestedLease) { + RemoteMonitorQuery remoteMonitorQuery = new RemoteMonitorQuery(RENEW_LEASE); + + remoteMonitorQuery.leaseId = leaseId; + remoteMonitorQuery.lease = requestedLease; + return remoteMonitorQuery; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addString(element, "requestType", requestType); + + if (monitorFilter != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "monitorFilter", monitorFilter); + } + + if (lease > 0) { + DocumentSerializableUtilities.addLong(element, "lease", lease); + } + + if (leaseId > -1) { + DocumentSerializableUtilities.addInt(element, "leaseId", leaseId); + } + + if (reportRate > 0) { + DocumentSerializableUtilities.addLong(element, "reportRate", reportRate); + } + + if (includeCumulative) { + DocumentSerializableUtilities.addBoolean(element, "includeCumulative", includeCumulative); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("requestType")) { + requestType = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("monitorFilter")) { + monitorFilter = (MonitorFilter) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + MonitorFilter.class); + } else if (tagName.equals("lease")) { + lease = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("leaseId")) { + leaseId = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("reportRate")) { + reportRate = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("includeCumulative")) { + includeCumulative = DocumentSerializableUtilities.getBoolean(childElement); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorResponse.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorResponse.java new file mode 100644 index 000000000..a1ebefe4c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/RemoteMonitorResponse.java @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peer; + + +import net.jxta.document.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.meter.*; +import java.util.*; + + +public class RemoteMonitorResponse implements DocumentSerializable { + public static final String MONITOR_REGISTERED = "monitorRegistered"; + public static final String MONITOR_REMOVED = "monitorGone"; + public static final String CUMULATIVE_REPORT_RESPONSE = "cumulativeReport"; + public static final String MONITOR_REPORT_RESPONSE = "monitorReport"; + public static final String INVALID_FILTER = "invalidFilter"; + public static final String INVALID_REPORT_RATE = "invalidReportRate"; + public static final String VALID_FILTER = "validFilter"; + public static final String SERVICE_NOT_SUPPORTED = "serviceNotSupported"; + public static final String METERING_NOT_SUPPORTED = "metereringNotSupported"; + public static final String METERING_SUPPORTED = "meteringSupported"; + public static final String METERING_REQUEST_DENIED = "meteringRequestDenied"; + public static final String PEER_MONITOR_INFO = "peerMonitorInfo"; + public static final String LEASE_ENDED = "leaseOver"; + public static final String LEASE_RENEWED = "leaseRenewed"; + + /* + ResponseCode: Not Supported + ResponseCode: Invalid Reporting Rate + Suggested Reporting Rate + ResponseCode: Invalid Filter + Suggested Filter + */ + + private String responseType; + private int requestId; + private int leaseId; + private MonitorReport monitorReport; + private boolean isCumulative; + private MonitorFilter monitorFilter; + private long lease = -1; + private PeerMonitorInfo peerMonitorInfo; + + private long reportRates[]; + private LinkedList supportedModuleClassIDs; + + public RemoteMonitorResponse() {} // for serialization. + + private RemoteMonitorResponse(String responseType, int requestId) { + this.responseType = responseType; + this.requestId = requestId; + } + + public long getLease() { + return lease; + } + + public boolean isCumulative() { + return isCumulative; + } + + public String getResponseType() { + return responseType; + } + + public int getRequestId() { + return requestId; + } + + public int getLeaseId() { + return leaseId; + } + + public MonitorReport getMonitorReport() { + return monitorReport; + } + + public MonitorFilter getMonitorFilter() { + return monitorFilter; + } + + public PeerMonitorInfo getPeerMonitorInfo() { + return peerMonitorInfo; + } + + public boolean isMonitorRegistered() { + return responseType.equals(MONITOR_REGISTERED); + } + + public boolean isMonitorRemoved() { + return responseType.equals(MONITOR_REMOVED); + } + + public boolean isCumulativeReport() { + return responseType.equals(CUMULATIVE_REPORT_RESPONSE); + } + + public boolean isMonitorReport() { + return responseType.equals(MONITOR_REPORT_RESPONSE); + } + + public boolean isValidFilter() { + return responseType.equals(VALID_FILTER); + } + + public boolean isInvalidFilter() { + return responseType.equals(INVALID_FILTER); + } + + public boolean isInvalidReportRate() { + return responseType.equals(INVALID_REPORT_RATE); + } + + public boolean isServiceNotSupported() { + return responseType.equals(SERVICE_NOT_SUPPORTED); + } + + public boolean isMeteringNotSupported() { + return responseType.equals(METERING_NOT_SUPPORTED); + } + + public boolean isMeteringSupported() { + return responseType.equals(METERING_SUPPORTED); + } + + public boolean isRequestDenied() { + return responseType.equals(METERING_REQUEST_DENIED); + } + + public boolean isPeerMonitorInfo() { + return responseType.equals(PEER_MONITOR_INFO); + } + + public boolean isLeaseRenewed() { + return responseType.equals(LEASE_RENEWED); + } + + public static RemoteMonitorResponse createMonitorRegisteredResponse(int requestId, int leaseId, long lease) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(MONITOR_REGISTERED, requestId); + + remoteMonitorResponse.leaseId = leaseId; + remoteMonitorResponse.lease = lease; + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createMonitorRemovedResponse(int requestId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(MONITOR_REMOVED, requestId); + + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createLeaseEndedResponse(int requestId, int leaseId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(LEASE_ENDED, requestId); + + remoteMonitorResponse.leaseId = leaseId; + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createCumulativeReportResponse(int requestId, MonitorReport monitorReport) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(CUMULATIVE_REPORT_RESPONSE, requestId); + + remoteMonitorResponse.monitorReport = monitorReport; + remoteMonitorResponse.isCumulative = true; + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createMonitorReportResponse(int requestId, MonitorReport monitorReport) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(MONITOR_REPORT_RESPONSE, requestId); + + remoteMonitorResponse.monitorReport = monitorReport; + remoteMonitorResponse.isCumulative = false; + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createInvalidReportRateResponse(int requestId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(INVALID_REPORT_RATE, requestId); + + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createServiceNotSupportedResponse(int requestId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(SERVICE_NOT_SUPPORTED, requestId); + + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createInvalidFilterResponse(int requestId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(INVALID_FILTER, requestId); + + return remoteMonitorResponse; + } + + /* + public static RemoteMonitorResponse createValidFilterResponse(int requestId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(VALID_FILTER, requestId); + return remoteMonitorResponse; + } + */ + public static RemoteMonitorResponse createDeniedResponse(int requestId) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(METERING_REQUEST_DENIED, requestId); + + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createPeerMonitorInfoResponse(int requestId, PeerMonitorInfo peerMonitorInfo) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(PEER_MONITOR_INFO, requestId); + + remoteMonitorResponse.peerMonitorInfo = peerMonitorInfo; + return remoteMonitorResponse; + } + + public static RemoteMonitorResponse createLeaseRenewedResponse(int requestId, int leaseId, long lease) { + RemoteMonitorResponse remoteMonitorResponse = new RemoteMonitorResponse(LEASE_RENEWED, requestId); + + remoteMonitorResponse.leaseId = leaseId; + remoteMonitorResponse.lease = lease; + return remoteMonitorResponse; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addString(element, "responseType", responseType); + DocumentSerializableUtilities.addInt(element, "requestId", requestId); + + if (monitorReport != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "monitorReport", monitorReport); + } + + if (monitorFilter != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "monitorFilter", monitorFilter); + } + + if (lease > 0) { + DocumentSerializableUtilities.addLong(element, "lease", lease); + } + + if (leaseId > -1) { + DocumentSerializableUtilities.addInt(element, "leaseId", leaseId); + } + + if (isCumulative) { + DocumentSerializableUtilities.addBoolean(element, "isCumulative", isCumulative); + } + + if (peerMonitorInfo != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "peerMonitorInfo", peerMonitorInfo); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("responseType")) { + responseType = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("requestId")) { + requestId = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("monitorReport")) { + monitorReport = (MonitorReport) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + MonitorReport.class); + } else if (tagName.equals("monitorFilter")) { + monitorFilter = (MonitorFilter) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + MonitorFilter.class); + } else if (tagName.equals("lease")) { + lease = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("leaseId")) { + leaseId = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("isCumulative")) { + isCumulative = DocumentSerializableUtilities.getBoolean(childElement); + } else if (tagName.equals("peerMonitorInfo")) { + peerMonitorInfo = (PeerMonitorInfo) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + PeerMonitorInfo.class); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/package.html new file mode 100644 index 000000000..91b9a7086 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peer/package.html @@ -0,0 +1,11 @@ + + + + + + + Provides definition for the standard JXTA Peer Info Service. + + @see JXTA Protocols Specification : Peer Info Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/AutomaticConfigurator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/AutomaticConfigurator.java new file mode 100644 index 000000000..9f6dee07f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/AutomaticConfigurator.java @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peergroup; + + +import java.net.InetAddress; +import java.net.URI; +import java.util.Enumeration; +import java.util.Iterator; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.TransportAdvertisement; + +import net.jxta.exception.ConfiguratorException; + +import net.jxta.impl.endpoint.IPUtils; +import net.jxta.impl.protocol.HTTPAdv; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.impl.protocol.PSEConfigAdv; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.protocol.RelayConfigAdv; +import net.jxta.impl.protocol.TCPAdv; + + +/** + * A simple platform configurator. This implementation provides reasonable + * automatic configuration for edge peers on the JXTA public network. + *

            + * This implementation will read default values from several Java system + * properties as appropriate: + *

            + * jxta.peer.name -- The peer name to use. + * jxta.http.port -- The http port to use. + * jxta.tcp.port -- The tcp port to use. + * + * @see net.jxta.peergroup.Configurator + */ +public class AutomaticConfigurator extends NullConfigurator { + + /** + * Log4J logger + */ + private final static transient Logger LOG = Logger.getLogger(AutomaticConfigurator.class.getName()); + + /** + * Configures the platform using the specified directory. + * @param jxtaHome store home URI + * @throws net.jxta.exception.ConfiguratorException if a configuration error occurs + */ + public AutomaticConfigurator(URI jxtaHome) throws ConfiguratorException { + super(jxtaHome); + } + + /** + * {@inheritDoc} + */ + @Override + public PlatformConfig getPlatformConfig() throws ConfiguratorException { + super.getPlatformConfig(); + + boolean reconf; + + try { + reconf = buildPlatformConfig(); + } catch (RuntimeException serious) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Trouble while fixing PlatformConfig. Hope for the best.", serious); + } + + reconf = true; + } + + // See if we need a reconf + if (reconf) { + throw new IncompleteConfigurationException("Damaged platform configuration."); + } + + // Save the updated config. + save(); + + return advertisement; + } + + /** + * Makes sure a PlatformConfig is present and if not, creates one. + *

            + * Performs some checking of PlatformConfig values and will fix some + * minor configuration problems automatically. + * + * @return If true then manual reconfiguration (of some form) is required. + */ + private boolean buildPlatformConfig() { + + boolean reconf = false; + + if (advertisement == null) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("New PlatformConfig Advertisement"); + } + advertisement = (PlatformConfig) AdvertisementFactory.newAdvertisement(PlatformConfig.getAdvertisementType()); + advertisement.setDescription("Platform Config Advertisement created by : " + AutomaticConfigurator.class.getName()); + } + + // Set the peer name + String peerName = advertisement.getName(); + + if ((null == peerName) || (0 == peerName.trim().length())) { + String jpn = System.getProperty("jxta.peer.name", ""); + + if (0 != jpn.trim().length()) { + advertisement.setName(jpn); + } + } + + // Check the HTTP Message Transport parameters. + XMLDocument http = (XMLDocument) advertisement.getServiceParam(PeerGroup.httpProtoClassID); + HTTPAdv httpAdv = null; + boolean httpEnabled = true; + + if (http != null) { + try { + httpEnabled = advertisement.isSvcEnabled(PeerGroup.httpProtoClassID); + + XMLElement param = null; + + Enumeration httpChilds = http.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the HTTPAdv from TransportAdv + if (httpChilds.hasMoreElements()) { + param = (XMLElement) httpChilds.nextElement(); + } + + if (null != param) { + httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(param); + + if (httpEnabled) { + // check if the interface address is still valid. + String intf = httpAdv.getInterfaceAddress(); + + if ((null != intf) && !isValidInetAddress(intf)) { + reconf = true; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Reconfig requested - invalid interface address"); + } + } + } + } + } catch (RuntimeException advTrouble) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "HTTP advertisement corrupted", advTrouble); + } + + httpAdv = null; + } + } + + if (httpAdv == null) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("HTTP advertisement missing, making a new one."); + } + + int port = 0; + // get the port from a property + String httpPort = System.getProperty("jxta.http.port"); + + if (httpPort != null) { + try { + int propertyPort = Integer.parseInt(httpPort); + + if ((propertyPort < 65536) && (propertyPort >= 0)) { + port = propertyPort; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Property \'jxta.http.port\' is not a valid port number : " + propertyPort); + } + } + } catch (NumberFormatException ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Property \'jxta.http.port\' was not an integer : " + http); + } + } + } + + httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(HTTPAdv.getAdvertisementType()); + httpAdv.setProtocol("http"); + httpAdv.setPort(port); + httpAdv.setServerEnabled(false); + } + + // Create new param docs that contain the updated adv + http = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + XMLDocument httAdvDoc = (XMLDocument) httpAdv.getDocument(MimeMediaType.XMLUTF8); + + StructuredDocumentUtils.copyElements(http, http, httAdvDoc); + if (!httpEnabled) { + http.appendChild(http.createElement("isOff")); + } + advertisement.putServiceParam(PeerGroup.httpProtoClassID, http); + + // Check the TCP Message Transport parameters. + XMLDocument tcp = (XMLDocument) advertisement.getServiceParam(PeerGroup.tcpProtoClassID); + TCPAdv tcpAdv = null; + boolean tcpEnabled = true; + + if (tcp != null) { + try { + tcpEnabled = advertisement.isSvcEnabled(PeerGroup.tcpProtoClassID); + + XMLElement param = null; + + Enumeration tcpChilds = tcp.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv + if (tcpChilds.hasMoreElements()) { + param = (XMLElement) tcpChilds.nextElement(); + } + + if (null != param) { + tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(param); + + if (tcpEnabled) { + String intf = tcpAdv.getInterfaceAddress(); + + if ((null != intf) && !isValidInetAddress(intf)) { + reconf = true; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Reconfig requested - invalid interface address"); + } + } + } + } + } catch (RuntimeException advTrouble) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "TCP advertisement corrupted", advTrouble); + } + + tcpAdv = null; + } + } + + if (tcpAdv == null) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("TCP advertisement missing, making a new one."); + } + + int port = 0; + // get the port from a property + String tcpPort = System.getProperty("jxta.tcp.port"); + + if (tcpPort != null) { + try { + int propertyPort = Integer.parseInt(tcpPort); + + if ((propertyPort < 65536) && (propertyPort >= 0)) { + port = propertyPort; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Property \'jxta.tcp.port\' is not a valid port number : " + propertyPort); + } + } + } catch (NumberFormatException ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Property \'jxta.tcp.port\' was not an integer : " + tcpPort); + } + } + } + + tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(TCPAdv.getAdvertisementType()); + + tcpAdv.setProtocol("tcp"); + tcpAdv.setPort(port); + tcpAdv.setMulticastAddr("224.0.1.85"); + tcpAdv.setMulticastPort(1234); + tcpAdv.setMulticastSize(16384); + tcpAdv.setMulticastState(true); + } + + tcp = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + + StructuredDocumentUtils.copyElements(tcp, tcp, (XMLDocument) tcpAdv.getDocument(MimeMediaType.XMLUTF8)); + if (!tcpEnabled) { + tcp.appendChild(tcp.createElement("isOff")); + } + advertisement.putServiceParam(PeerGroup.tcpProtoClassID, tcp); + + // Check the relay config + RelayConfigAdv relayConfig = null; + + try { + XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.relayProtoClassID); + + if (param != null) { + // XXX 20041027 backwards compatibility + param.addAttribute("type", RelayConfigAdv.getAdvertisementType()); + + relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(param); + } + } catch (Exception failure) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Problem reading relay configuration", failure); + } + } + + if (null == relayConfig) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Relay Config advertisement missing, making a new one."); + } + + // restore default values. + relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(RelayConfigAdv.getAdvertisementType()); + + // Enable relay if any transport doesn't support incoming. + if (!tcpAdv.isServerEnabled() || !httpAdv.isServerEnabled()) { + relayConfig.setClientEnabled(true); + } + } + + /* + if( (0 == relayConfig.getSeedingURIs().length) && (0 == relayConfig.getSeedRelays().length) && !relayConfig.isServerEnabled() ) { + // add the default relay seeding peer. + relayConfig.addSeedingURI( "http://rdv.jxtahosts.net/cgi-bin/relays.cgi?3" ); + } + */ + + XMLDocument relayDoc = (XMLDocument) relayConfig.getDocument(MimeMediaType.XMLUTF8); + + advertisement.putServiceParam(PeerGroup.relayProtoClassID, relayDoc); + + // Check Rendezvous Configuration + RdvConfigAdv rdvAdv = null; + + try { + XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.rendezvousClassID); + + if (param != null) { + // XXX 20041027 backwards compatibility + param.addAttribute("type", RdvConfigAdv.getAdvertisementType()); + + rdvAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(param); + } + } catch (Exception failure) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Problem reading rendezvous configuration", failure); + } + } + + if (null == rdvAdv) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Rdv Config advertisement missing, making a new one."); + } + + // restore default values. + rdvAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + } + + /* + if( (0 == rdvAdv.getSeedingURIs().length) && + (0 == rdvAdv.getSeedRendezvous().length) && + (RdvConfigAdv.RendezVousConfiguration.RENDEZVOUS != rdvAdv.getConfiguration()) && + (RdvConfigAdv.RendezVousConfiguration.AD_HOC != rdvAdv.getConfiguration()) && + !relayConfig.isClientEnabled() ) { + // add the default rendezvous seeding peer if we don't know of any rendezvous, aren't a rendezvous ourselves, aren't in ad-hoc mode or using a relay. + rdvAdv.addSeedingURI( "http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3" ); + } + */ + XMLDocument rdvDoc = (XMLDocument) rdvAdv.getDocument(MimeMediaType.XMLUTF8); + + advertisement.putServiceParam(PeerGroup.rendezvousClassID, rdvDoc); + + // if no proxy param section, disable it. + XMLDocument proxy = (XMLDocument) advertisement.getServiceParam(PeerGroup.proxyClassID); + + if (null == proxy) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Proxy config advertisement missing, making a new one."); + } + + proxy = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + proxy.appendChild(proxy.createElement("isOff")); + advertisement.putServiceParam(PeerGroup.proxyClassID, proxy); + } + + // Check the PSE Configuration + PSEConfigAdv pseConfig = null; + + try { + XMLElement param = (XMLElement) advertisement.getServiceParam(PeerGroup.membershipClassID); + + if (param != null) { + // XXX 20041027 backwards compatibility + param.addAttribute("type", PSEConfigAdv.getAdvertisementType()); + + pseConfig = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(param); + } + } catch (Exception failure) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Problem reading pse configuration", failure); + } + } + + if (null == pseConfig) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("PSE Config advertisement missing, making a new one."); + } + + // restore default values. + pseConfig = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); + XMLDocument pseDoc = (XMLDocument) pseConfig.getDocument(MimeMediaType.XMLUTF8); + + advertisement.putServiceParam(PeerGroup.membershipClassID, pseDoc); + } + + // If we did not modify anything of importance or see anything wrong, + // leave the adv alone. + + return reconf; + } + + private boolean isValidInetAddress(String address) { + boolean found = false; + boolean loopback; + + InetAddress[] ias; + + try { + ias = InetAddress.getAllByName(address); + } catch (java.net.UnknownHostException notfound) { + return false; + } + + for (Iterator la = IPUtils.getAllLocalAddresses(); la.hasNext() && !found;) { + for (InetAddress ia1 : ias) { + found |= ia1.equals(la.next()); + } + } + + loopback = true; + + for (InetAddress ia1 : ias) { + loopback &= ia1.isLoopbackAddress(); + } + + return found || loopback; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/Boot.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/Boot.java new file mode 100644 index 000000000..d8f1fae3e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/Boot.java @@ -0,0 +1,169 @@ +/* +Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + + +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.NetworkManager; +import net.jxta.platform.NetworkConfigurator; + +import java.util.logging.Logger; + +import java.io.File; +import java.text.MessageFormat; +import java.util.Collections; + + +/** + * A default "main" for starting JXTA. + * + * @deprecated This code is in no-way dependent upon the implementation and + * should not have been located here. Developers are encouraged to copy this + * source to their own projects. Consider using alternative JXTA "main" + * See NetworkManager tutorial . + */ +@Deprecated +public class Boot { + + /** + * main + * + * @param args command line arguments + */ + public static void main(String args[]) { + // Name the main thread. For unknown reasons it usually has a boring name like "thread1" + Thread.currentThread().setName(Boot.class.getName() + ".main()"); + + try { + boolean server; + // Get the optional location of the directory we should use for cache. + String jxta_home = System.getProperty("JXTA_HOME"); + File home; + String instanceName; + + if (null != jxta_home) { + // Use the location from the older JXTA_HOME system property. + server = false; + instanceName = "BootCustom"; + home = new File(jxta_home); + } else { + // Use the location defined by the newer role convention. + server = args.length > 0 && ("-server".equalsIgnoreCase(args[0])); + + if (server) { + instanceName = "BootServer"; + } else { + instanceName = "BootEdge"; + } + + home = new File(new File(".cache"), instanceName); + } + + // If the home directory doesn't exist, create it. + if (!home.exists()) { + home.mkdirs(); + } + + NetworkManager manager; + + if (server) { + manager = new NetworkManager(NetworkManager.ConfigMode.SUPER, instanceName, home.toURI()); + + /* + NetworkConfigurator config = manager.getConfigurator(); + + //disable http + config.setHttpEnabled(false); + //disable seeding + config.setRelaySeedURIs(Collections.emptyList()); + config.setRendezvousSeedURIs(Collections.emptyList()); + */ + } else { + manager = new NetworkManager(NetworkManager.ConfigMode.EDGE, instanceName, home.toURI()); + } + // register a hook + // manager.registerShutdownHook(); + + System.out.println(MessageFormat.format("Starting the JXTA platform in mode : {0}", manager.getMode())); + long startTime = System.currentTimeMillis(); + + manager.startNetwork(); + System.out.println( + MessageFormat.format("Boot started in {0} millis, in mode : {1}", System.currentTimeMillis() - startTime + , + manager.getMode())); + + PeerGroup netPeerGroup = manager.getNetPeerGroup(); + + netPeerGroup.startApp(null); + + System.out.println(MessageFormat.format("Boot started in mode : {0}", manager.getMode())); + if (server) { + // Put this thread permanently to sleep so that JXTA keeps running. + Thread.sleep(Long.MAX_VALUE); + } + } catch (Throwable e) { + System.out.flush(); + // make sure output buffering doesn't wreck console display. + System.err.println("Uncaught Throwable caught by 'main':"); + e.printStackTrace(System.err); + System.exit(1); + } finally { + System.err.flush(); + System.out.flush(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/CompatibilityEquater.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/CompatibilityEquater.java new file mode 100644 index 000000000..72a2ac936 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/CompatibilityEquater.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import net.jxta.document.Element; + +public interface CompatibilityEquater { + + /** + * Evaluates if the given compatibility statement makes the module that + * bears it is lodable by this group. + * + * @param test the element to test + * @return boolean True if test is compatible with target. + */ + public boolean compatible(Element test); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/ConfigDialog.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/ConfigDialog.java new file mode 100644 index 000000000..285e3a848 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/ConfigDialog.java @@ -0,0 +1,2022 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.CardLayout; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.TransportAdvertisement; + +import net.jxta.exception.JxtaError; +import net.jxta.exception.ConfiguratorException; + +import net.jxta.impl.endpoint.IPUtils; +import net.jxta.impl.membership.pse.PSEUtils; +import net.jxta.impl.protocol.HTTPAdv; +import net.jxta.impl.protocol.PSEConfigAdv; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.protocol.RdvConfigAdv.RendezVousConfiguration; +import net.jxta.impl.protocol.RelayConfigAdv; +import net.jxta.impl.protocol.TCPAdv; + +/** + * The standard and much loved AWT Configuration dialog + */ +@SuppressWarnings("serial") +public class ConfigDialog extends Frame { + + static final GridBagConstraints stdConstr; + static final GridBagConstraints centerConstr; + static final GridBagConstraints centerLastConstr; + static final GridBagConstraints fillConstr; + static final GridBagConstraints fillInsetConstr; + + static { + stdConstr = new GridBagConstraints(); + stdConstr.gridwidth = GridBagConstraints.REMAINDER; + stdConstr.gridheight = 1; + stdConstr.gridx = 0; + stdConstr.gridy = GridBagConstraints.RELATIVE; + stdConstr.fill = GridBagConstraints.NONE; + stdConstr.weightx = 1; + stdConstr.anchor = GridBagConstraints.NORTHWEST; + stdConstr.insets = new Insets(0, 0, 0, 0); + + fillConstr = (GridBagConstraints) stdConstr.clone(); + fillConstr.fill = GridBagConstraints.HORIZONTAL; + + centerConstr = (GridBagConstraints) stdConstr.clone(); + centerConstr.anchor = GridBagConstraints.NORTH; + + centerLastConstr = (GridBagConstraints) centerConstr.clone(); + centerLastConstr.weighty = 1; + + fillInsetConstr = (GridBagConstraints) fillConstr.clone(); + + fillInsetConstr.insets = new Insets(5, 5, 5, 5); + } + + // A few widgets. + + /** + * Grid Bag layout panel + */ + static class PanelGBL extends Panel { + + protected Insets insets = new Insets(0, 0, 0, 0); + + GridBagLayout lay = new GridBagLayout(); + + private static final GridBagConstraints constrLabel = new GridBagConstraints(); + + static { + constrLabel.gridwidth = GridBagConstraints.REMAINDER; + constrLabel.gridheight = 1; + constrLabel.gridy = GridBagConstraints.RELATIVE; + constrLabel.weightx = 1; + constrLabel.weighty = 1; + constrLabel.anchor = GridBagConstraints.FIRST_LINE_START; + constrLabel.fill = GridBagConstraints.HORIZONTAL; + } + + public PanelGBL(String label) { + this(); + add(new Label(label, Label.LEFT), constrLabel); + } + + public PanelGBL() { + super(); + setLayout(lay); + } + + /** + * {@inheritDoc} + */ + @Override + public Insets getInsets() { + return insets; + } + } + + + /** + * A Grid Bag Panel with a border + */ + static class BorderPanelGBL extends PanelGBL { + + public static final int NONE = 0; + public static final int RAISED = 1; + public static final int LOWERED = 2; + public static final int GROOVE = 3; + public static final int BUMP = 4; + + int style = GROOVE; + String title; + int ascent = 0; + int descent = 0; + int leading = 0; + int titleWidth = 0; + + public BorderPanelGBL(String title) { + super(); + this.title = title; + } + + public BorderPanelGBL(String title, String advice) { + super(advice); + this.title = title; + } + + public BorderPanelGBL(String title, String advice, int s) { + super(advice); + this.title = title; + if ((s < NONE) && (s > BUMP)) { + return; + } + if ((s == RAISED) || (s == LOWERED)) { + this.title = null; + } + style = s; + } + + private void checkMetrics() { + Font font = getFont(); + + if ((title == null) || (font == null)) { + ascent = 2; + } else { + FontMetrics fmetrics = getFontMetrics(font); + + ascent = fmetrics.getAscent(); + descent = fmetrics.getDescent(); + leading = fmetrics.getLeading(); + titleWidth = fmetrics.stringWidth(title); + } + insets = new Insets(descent + ascent + leading + 2, 7, 7, 7); + } + + /** + * {@inheritDoc} + */ + @Override + public Insets getInsets() { + checkMetrics(); + return insets; + } + + private void paintLowered(Graphics g) { + checkMetrics(); + if (ascent == 0) { + return; + } + + Dimension d = getSize(); + + g.setColor(Color.black); + g.drawRect(1, ascent - 2, d.width - 4, d.height - ascent); + g.setColor(Color.white); + g.drawRect(2, ascent - 1, d.width - 4, d.height - ascent); + g.setColor(getBackground()); + g.drawRect(2, ascent - 1, d.width - 5, d.height - ascent - 1); + } + + private void paintRaised(Graphics g) { + checkMetrics(); + if (ascent == 0) { + return; + } + + Dimension d = getSize(); + + g.setColor(Color.white); + g.drawRect(1, ascent - 2, d.width - 4, d.height - ascent); + g.setColor(Color.black); + g.drawRect(2, ascent - 1, d.width - 4, d.height - ascent); + g.setColor(getBackground()); + g.drawRect(2, ascent - 1, d.width - 5, d.height - ascent - 1); + } + + private void paintGroove(Graphics g) { + checkMetrics(); + if (ascent == 0) { + return; + } + + Dimension d = getSize(); + + g.setColor(Color.black); + g.drawRect(1, ascent - 2, d.width - 4, d.height - ascent); + g.setColor(Color.white); + g.drawRect(2, ascent - 1, d.width - 4, d.height - ascent); + + g.setColor(Color.white); + g.clearRect(10, 0, titleWidth + 6, descent + ascent + leading + 1); + g.drawString(title, 12, ascent + 1); + g.setColor(Color.black); + g.drawString(title, 13, ascent + 2); + + // Work around a bug of at least the awt implem I'm using. + // A few wild pixels appear on that line during drawstring. + g.clearRect(0, 0, d.width, 1); + } + + private void paintBump(Graphics g) { + checkMetrics(); + if (ascent == 0) { + return; + } + + Dimension d = getSize(); + + g.setColor(Color.white); + g.drawRect(1, ascent - 2, d.width - 4, d.height - ascent); + g.setColor(Color.black); + g.drawRect(2, ascent - 1, d.width - 4, d.height - ascent); + + g.setColor(Color.white); + g.clearRect(10, 0, titleWidth + 6, descent + ascent + leading + 1); + g.drawString(title, 12, ascent + 1); + g.setColor(Color.black); + g.drawString(title, 13, ascent + 2); + + // Work around a bug of at least the awt implem I'm using. + // A few wild pixels appear on that line during drawstring. + g.clearRect(0, 0, d.width, 1); + } + + /** + * {@inheritDoc} + */ + @Override + public void paint(Graphics g) { + switch (style) { + case GROOVE: + paintGroove(g); + break; + + case BUMP: + paintBump(g); + break; + + case RAISED: + paintRaised(g); + break; + + case LOWERED: + paintLowered(g); + break; + + default: + } + super.paint(g); + } + } + + + /** + * Panel implementing paged tabs. + */ + static class PagesPanel extends Panel implements ActionListener { + private final CardLayout layout; + private final Panel pages; + private final Panel buttons; + + public PagesPanel() { + super(new BorderLayout()); + layout = new CardLayout(); + pages = new Panel(layout); + buttons = new Panel(new FlowLayout(FlowLayout.LEFT, 0, 0)); + + add(pages, BorderLayout.CENTER); + add(buttons, BorderLayout.NORTH); + } + + /** + * {@inheritDoc} + */ + public void actionPerformed(ActionEvent e) { + layout.show(pages, e.getActionCommand()); + } + + public PanelGBL addPage(String buttonName, String comment) { + BorderPanelGBL p = new BorderPanelGBL(buttonName, comment, BorderPanelGBL.RAISED); + + pages.add(p, buttonName); + Button b = new Button(buttonName); + + buttons.add(b); + b.addActionListener(this); + return p; + } + + public void showPage(String pageName) { + layout.show(pages, pageName); + } + } + + + /** + * Allows for entry of a host address and port number. Besides the host + * address and port number text fields there are two optional features: + *

            + *

              + *
            • A checkbox with annotation to enable/disable the control.
            • + *
            • A label for the address.
            • + *
            + */ + static class HostPortPanel extends Panel implements ItemListener { + + private final Checkbox useMe; + + private Label addressLabel = null; + + private final TextField host; + private final TextField port; + + HostPortPanel(String checkLabel, String addrLabel, String defaultHost, String defaultPort, boolean defaultState) { + + super(new GridBagLayout()); + + useMe = new Checkbox(checkLabel, defaultState); + host = new TextField(defaultHost, 25); + port = new TextField(defaultPort, 6); + + GridBagConstraints constraints = new GridBagConstraints(); + + constraints.weightx = 1.0; + constraints.weighty = 1.0; + + constraints.gridx = 0; + constraints.gridy = 0; + constraints.gridwidth = (null == addrLabel) ? 2 : 3; + constraints.anchor = GridBagConstraints.FIRST_LINE_START; + + if (null != checkLabel) { + add(useMe, constraints); + // if check label and addr label then use 2 lines. + if (null != addrLabel) { + constraints.gridy++; + constraints.gridx = 0; + constraints.anchor = GridBagConstraints.LAST_LINE_START; + } else { + constraints.gridx++; + constraints.gridx = GridBagConstraints.RELATIVE; + } + } + + if (null != addrLabel) { + constraints.gridwidth = 1; + addressLabel = new Label(addrLabel, Label.RIGHT); + add(addressLabel, constraints); + } + + constraints.gridx = GridBagConstraints.RELATIVE; + + add(host, constraints); + add(port, constraints); + + setState(defaultState); + useMe.addItemListener(this); + } + + /** + * {@inheritDoc} + */ + public void itemStateChanged(ItemEvent e) { + setState(useMe.getState()); + } + + /** + * {@inheritDoc} + */ + public boolean getState() { + return useMe.getState() && isEnabled(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabling) { + super.setEnabled(enabling); + + useMe.setEnabled(enabling); + + if (null != addressLabel) { + addressLabel.setEnabled(useMe.getState()); + } + + host.setEnabled(useMe.getState()); + port.setEnabled(useMe.getState()); + } + + /** + * {@inheritDoc} + */ + public void setState(boolean state) { + useMe.setState(state); // sometimes redundant but not always. + + if (null != addressLabel) { + addressLabel.setEnabled(state); + } + + host.setEnabled(state); + port.setEnabled(state); + } + + /** + * Returns the value of the host field + * + * @return the value of the hot field + */ + public String getHost() { + return host.getText().trim(); + } + + /** + * Returns the value of the port field + * + * @return the value of the port field + */ + public String getPort() { + return port.getText().trim(); + } + } + + + /** + * A list of URIs + */ + static class HostListPanel extends Panel implements ActionListener { + + private final String purpose; + private final TextField host; + private final TextField port; + private final java.awt.List list; + private final Label listLabel; + + private final Button insert; + private final Button remove; + + public HostListPanel(String purpose, String lstLabel, boolean defaultState, boolean showPort) { + + super(new GridBagLayout()); + this.purpose = purpose; + + host = new TextField("", showPort ? 25 : 30); + if (showPort) { + port = new TextField("", 5); + } else { + port = null; + } + insert = new Button("+"); + remove = new Button("-"); + + list = new java.awt.List(2, true); + listLabel = new Label(lstLabel); + + GridBagConstraints c1 = new GridBagConstraints(); + + c1.gridx = 0; + c1.gridy = 0; + c1.anchor = GridBagConstraints.FIRST_LINE_START; + c1.fill = GridBagConstraints.NONE; + add(listLabel, c1); + + c1.gridx = 0; + c1.gridy++; + if (!showPort) { + c1.gridwidth = 2; + } + c1.weightx = 2.0; + c1.anchor = GridBagConstraints.LINE_START; + c1.fill = GridBagConstraints.HORIZONTAL; + add(host, c1); + + if (showPort) { + c1.weightx = 0.0; + c1.gridx = 1; + c1.anchor = GridBagConstraints.LINE_END; + c1.fill = GridBagConstraints.NONE; + add(port, c1); + } + + c1.gridx = 0; + c1.gridy++; + c1.gridwidth = 1; + c1.weightx = 2.0; + c1.anchor = GridBagConstraints.LAST_LINE_START; + c1.fill = GridBagConstraints.HORIZONTAL; + add(list, c1); + + Panel p2 = new Panel(new GridLayout(2, 1, 1, 1)); + + p2.add(insert); + p2.add(remove); + + c1.gridx++; + c1.weightx = 0.0; + c1.anchor = GridBagConstraints.LAST_LINE_END; + c1.fill = GridBagConstraints.NONE; + c1.insets = new Insets(0, 4, 0, 1); + add(p2, c1); + + host.addActionListener(this); + insert.addActionListener(this); + remove.addActionListener(this); + list.addActionListener(this); + + setEnabled(defaultState); + } + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(boolean state) { + super.setEnabled(state); + + listLabel.setEnabled(state); + host.setEnabled(state); + if (null != port) { + port.setEnabled(state); + } + list.setEnabled(state); + insert.setEnabled(state); + remove.setEnabled(state); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEnabled() { + return listLabel.isEnabled(); + } + + /** + * {@inheritDoc} + */ + public void actionPerformed(ActionEvent e) { + if ((insert == e.getSource()) || (host == e.getSource())) { + StringBuilder addHost = new StringBuilder(host.getText()); + + if (null != port) { + String portText = port.getText().trim(); + + if (portText.length() > 0) { + // if( !verifyPort( "Host port", portText, false ) ) { + // return; + // } + addHost.append(':'); + addHost.append(portText); + } + } + if (addItem(addHost.toString())) { + host.setText(""); + host.setCaretPosition(0); + if (null != port) { + port.setText(""); + port.setCaretPosition(0); + } + } + return; + } + + if (e.getSource() == remove) { + int[] sel = list.getSelectedIndexes(); + int i = sel.length; + + while (i-- > 0) { + list.remove(sel[i]); + } + + return; + } + + // double click on a host in the list + if (e.getSource() == list) { + String cmd = e.getActionCommand(); + + if (null != port) { + int colonAt = cmd.lastIndexOf(':'); + String newHost = cmd.substring(0, colonAt); + String newPort = cmd.substring(colonAt + 1); + + host.setText(newHost); + host.setCaretPosition(newHost.length()); + port.setText(newPort); + port.setCaretPosition(newHost.length()); + } else { + host.setText(cmd); + host.setCaretPosition(cmd.length()); + } + } + } + + public boolean addItem(String item) { + String hostURI = item.trim(); + + if (0 == hostURI.trim().length()) { + return false; + } + + // See if it is "really" a URI. + try { + new URI(hostURI); + } catch (URISyntaxException failed) { + return false; + } + + try { + while (true) { + try { + list.remove(hostURI); + } catch (IllegalArgumentException notThere) { + break; + } + } + + list.add(hostURI); + } catch (Exception e) { + return false; + } + + return true; + } + + public String getPurpose() { + return purpose; + } + + public String[] getItems() { + return list.getItems(); + } + } + + + /** + * An interface and port selection panel. + */ + static class IfAddrPanel extends Panel implements ItemListener { + private final Checkbox manual; + + private final CardLayout addrLayout; + + private final Panel addrPanel; + private final TextField interfaceAddr; + private final TextField localPort; + + private final Choice ips; + + public IfAddrPanel(String defaultInterfaceAddr, String defaultPort) { + + super(new FlowLayout(FlowLayout.LEADING, 0, 0)); + + ips = new Choice(); + boolean modeManual = false; + + ips.add("Any/All Local Addresses"); + + try { + Iterator allIntf = IPUtils.getAllLocalAddresses(); + boolean sawValid = false; + + while (allIntf.hasNext()) { + InetAddress anAddr = allIntf.next(); + + if (IPUtils.LOOPBACK.equals(anAddr)) { + continue; + } + + ips.add(IPUtils.getHostAddress(anAddr)); + sawValid = true; + } + + if (!sawValid) { + modeManual = true; + } + + // if an address was previously configured, switch to manual + // if we do not find any interface, switch to manual too. + if (defaultInterfaceAddr != null) { + InetAddress defaultIntf = InetAddress.getByName(defaultInterfaceAddr); + + if (!IPUtils.ANYADDRESS.equals(defaultIntf)) { + modeManual = true; + + // However, if this address is in the automatic list, + // switch back to automatic and select it. + allIntf = IPUtils.getAllLocalAddresses(); + + while (allIntf.hasNext()) { + InetAddress anAddr = allIntf.next(); + + if (defaultIntf.equals(anAddr)) { + modeManual = false; + ips.select(defaultInterfaceAddr); + } + } + } + } + } catch (Exception e) { + modeManual = true; + } + + manual = new Checkbox("Manual", null, modeManual); + add(manual); + manual.addItemListener(this); + + addrLayout = new CardLayout(); + addrPanel = new Panel(addrLayout); + + Panel autoPanel = new Panel(new FlowLayout(FlowLayout.LEADING)); + + autoPanel.add(ips); + + Panel manPanel = new Panel(new FlowLayout(FlowLayout.LEADING)); + + interfaceAddr = new TextField(defaultInterfaceAddr, 20); + manPanel.add(interfaceAddr); + + addrPanel.add(manPanel, "man"); + addrPanel.add(autoPanel, "auto"); + + add(addrPanel); + + localPort = new TextField(defaultPort, 6); + add(localPort); + + setManual(modeManual); + } + + /** + * {@inheritDoc} + */ + private void setManual(boolean manMode) { + addrLayout.show(addrPanel, manMode ? "man" : "auto"); + + this.validate(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + + manual.setEnabled(enabled); + ips.setEnabled(enabled); + interfaceAddr.setEnabled(enabled); + localPort.setEnabled(enabled); + } + + /** + * {@inheritDoc} + */ + public void itemStateChanged(ItemEvent e) { + if (e.getSource() == manual) { + setManual(manual.getState()); + } + } + + public String getAddress() { + if (manual.getState()) { + return interfaceAddr.getText().trim(); + } else { + return ips.getSelectedItem().trim(); + } + } + + public String getPort() { + return localPort.getText().trim(); + } + + public String getMode() { + return manual.getState() ? "manual" : "auto"; + } + + } + + + static final class IPTptPanel extends BorderPanelGBL implements ItemListener { + + enum TransportType { + TYPE_HTTP, TYPE_TCP + } + + + ; + + private final Checkbox useMe; + private final Checkbox pubAddrOnly; + private final Checkbox multicast; + private final Checkbox clientEnabled; + + private final IfAddrPanel ifAddr; + private final HostPortPanel publicAddr; + + public IPTptPanel(TransportType type, boolean defaultState, String name, String defaultInterfaceAddr, String defaultPort, boolean clientState, boolean serverState, String defaultPublicAddr, String defaultPublicPort, boolean pubAddrOnlyState) { + this(type, defaultState, name, defaultInterfaceAddr, defaultPort, clientState, serverState, defaultPublicAddr + , + defaultPublicPort, pubAddrOnlyState, false); + } + + public IPTptPanel(TransportType type, boolean defaultState, String name, String defaultInterfaceAddr, String defaultPort, boolean clientState, boolean serverState, String defaultPublicAddr, String defaultPublicPort, boolean pubAddrOnlyState, boolean multicastState) { + + super(name); + + ifAddr = new IfAddrPanel(defaultInterfaceAddr, defaultPort); + + useMe = new Checkbox("Enabled", null, defaultState); + + if (type == TransportType.TYPE_TCP) { + multicast = new Checkbox("Multicast", null, multicastState); + } else { + multicast = null; + } + + clientEnabled = new Checkbox("Enable Outgoing connections", null, clientState); + + pubAddrOnly = new Checkbox("Hide private addresses", null, pubAddrOnlyState); + + publicAddr = new HostPortPanel("Enable Incoming Connections", "(Optional) Public address", defaultPublicAddr + , + defaultPublicPort, serverState); + + GridBagConstraints constraints = new GridBagConstraints(); + + constraints.weightx = 1.0; + constraints.weighty = 1.0; + + constraints.gridx = 0; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.FIRST_LINE_START; + add(useMe, constraints); + + if (type == TransportType.TYPE_TCP) { + constraints.anchor = GridBagConstraints.FIRST_LINE_END; + add(multicast, constraints); + } + + constraints.gridx = 0; + constraints.gridy++; + constraints.anchor = GridBagConstraints.LINE_START; + add(ifAddr, constraints); + + constraints.gridx = 0; + constraints.gridy++; + + constraints.anchor = GridBagConstraints.LINE_START; + add(clientEnabled, constraints); + + constraints.anchor = GridBagConstraints.EAST; + add(pubAddrOnly, constraints); + + constraints.gridx = 0; + constraints.gridy++; + + constraints.anchor = GridBagConstraints.LINE_START; + add(publicAddr, constraints); + publicAddr.setState(serverState); + + setState(defaultState); + useMe.addItemListener(this); + } + + /** + * {@inheritDoc} + */ + public void setState(boolean state) { + useMe.setState(state); + ifAddr.setEnabled(state); + publicAddr.setEnabled(state); + if (multicast != null) { + multicast.setEnabled(state); + } + clientEnabled.setEnabled(state); + pubAddrOnly.setEnabled(state); + } + + /** + * {@inheritDoc} + */ + public void itemStateChanged(ItemEvent e) { + setState(useMe.getState()); + } + + public String getInterfaceAddress() { + return ifAddr.getAddress().trim(); + } + + public String getConfigMode() { + return ifAddr.getMode(); + } + + public boolean getPubAddrOnly() { + return pubAddrOnly.getState(); + } + + public void setPubAddrOnly(boolean state) { + pubAddrOnly.setState(state); + } + } + + + /** + * Manages Peer Identity configuration + */ + final class IdPanel extends Panel implements ActionListener { + + private final TextField peerName; + private final TextField passwd; + private final TextField vpasswd; + + public IdPanel(String defaultPeerName, boolean needSecurityConfig) { + + super(new GridBagLayout()); + + peerName = new TextField(defaultPeerName, 20); + + GridBagConstraints constraints = new GridBagConstraints(); + + constraints.gridx = 0; + constraints.gridy = 0; + constraints.anchor = GridBagConstraints.FIRST_LINE_END; + add(new Label("Peer Name", Label.RIGHT), constraints); + + constraints.gridx++; + constraints.anchor = GridBagConstraints.FIRST_LINE_START; + add(peerName, constraints); + + if (needSecurityConfig) { + passwd = new TextField("", 20); + vpasswd = new TextField("", 20); + passwd.setEchoChar('*'); + vpasswd.setEchoChar('*'); + + constraints.gridx = 0; + constraints.gridy++; + constraints.anchor = GridBagConstraints.LINE_END; + add(new Label("Password", Label.RIGHT), constraints); + + constraints.gridx++; + constraints.anchor = GridBagConstraints.LINE_START; + add(passwd, constraints); + + constraints.gridx = 0; + constraints.gridy++; + constraints.anchor = GridBagConstraints.LINE_END; + add(new Label("Verify Password", Label.RIGHT), constraints); + + constraints.gridx++; + constraints.anchor = GridBagConstraints.LINE_START; + add(vpasswd, constraints); + } else { + passwd = null; + vpasswd = null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return peerName.getText().trim(); + } + + public String getPassword() { + return passwd.getText(); + } + + public String getVerifyPassword() { + return vpasswd.getText(); + } + + public void clearPasswords() { + passwd.setText(""); + vpasswd.setText(""); + } + + /** + * {@inheritDoc} + */ + public void actionPerformed(ActionEvent e) { + } + } + + + /** + * Manages Service Enabling + */ + final static class EnablingPanel extends BorderPanelGBL { + + private final Checkbox isRelay; + private final Checkbox isRendezvous; + private final Checkbox isJxmeProxy; + + EnablingPanel(boolean actAsRelay, boolean actAsRendezvous, boolean actAsJxmeProxy) { + super("Services Settings"); + + isRelay = new Checkbox("Act as a Relay", null, actAsRelay); + isRendezvous = new Checkbox("Act as a Rendezvous", null, actAsRendezvous); + isJxmeProxy = new Checkbox("Act as a JXME proxy", null, actAsJxmeProxy); + + add(isRelay, stdConstr); + add(isRendezvous, stdConstr); + add(isJxmeProxy, stdConstr); + } + } + + + /** + * Manages Rendezvous service options + */ + final static class RdvPanel extends BorderPanelGBL implements ItemListener { + + private final Checkbox useRdv; + private final Checkbox useOnlySeeds; + private final HostListPanel seeding; + private final HostListPanel seeds; + + RdvPanel(boolean useARdv, boolean onlySeeds) { + super("Rendezvous Settings"); + + useRdv = new Checkbox("Use a rendezvous", null, useARdv); + useOnlySeeds = new Checkbox("Use only configured seeds", null, onlySeeds); + seeds = new HostListPanel("Seeds", "Rendezvous seed peers", true, false); + seeding = new HostListPanel("Seeding", "Rendezvous seeding URIs", true, false); + + GridBagConstraints c1 = new GridBagConstraints(); + + c1.gridx = 0; + c1.gridy = 0; + c1.anchor = GridBagConstraints.LINE_START; + add(useRdv, c1); + useRdv.addItemListener(this); + + c1.gridx++; + c1.anchor = GridBagConstraints.LINE_END; + add(useOnlySeeds, c1); + + c1.gridx = 0; + c1.gridy++; + c1.gridwidth = 2; + c1.weightx = 1.0; + c1.fill = GridBagConstraints.HORIZONTAL; + c1.anchor = GridBagConstraints.LINE_START; + add(seeding, c1); + + c1.gridy++; + add(seeds, c1); + } + + /** + * {@inheritDoc} + */ + public void itemStateChanged(ItemEvent e) { + seeds.setEnabled(useRdv.getState()); + seeding.setEnabled(useRdv.getState()); + useOnlySeeds.setEnabled(useRdv.getState()); + } + } + + + /** + * Manages relay service parameters + */ + final static class RelayPanel extends BorderPanelGBL implements ItemListener { + + private final Checkbox useRelay; + private final Checkbox useOnlySeeds; + private final HostListPanel seeding; + private final HostListPanel seeds; + + public RelayPanel(boolean useARelay, boolean onlySeeds) { + + super("Relay Settings"); + + useRelay = new Checkbox("Use a relay", null, useARelay); + useOnlySeeds = new Checkbox("Use only configured seeds", null, onlySeeds); + useOnlySeeds.setEnabled(useARelay); + seeds = new HostListPanel("Seeds", "Relay seed peers", useARelay, false); + seeding = new HostListPanel("Seeding", "Relay seeding URIs", useARelay, false); + + GridBagConstraints c1 = new GridBagConstraints(); + + c1.gridx = 0; + c1.gridy = 0; + c1.anchor = GridBagConstraints.LINE_START; + add(useRelay, c1); + useRelay.addItemListener(this); + + c1.gridx++; + c1.anchor = GridBagConstraints.LINE_END; + add(useOnlySeeds, c1); + + c1.gridx = 0; + c1.gridy++; + c1.gridwidth = 2; + c1.weightx = 1.0; + c1.fill = GridBagConstraints.HORIZONTAL; + c1.anchor = GridBagConstraints.LINE_START; + add(seeding, c1); + + c1.gridy++; + add(seeds, c1); + } + + /** + * {@inheritDoc} + */ + public void itemStateChanged(ItemEvent e) { + seeds.setEnabled(useRelay.getState()); + seeding.setEnabled(useRelay.getState()); + useOnlySeeds.setEnabled(useRelay.getState()); + } + } + + private final PlatformConfig configAdv; + + private final Label helpLabel; + private final IdPanel idPanel; + private final EnablingPanel enablingPanel; + private final IPTptPanel tcpPanel; + private final IPTptPanel httpPanel; + private final RdvPanel rdvPanel; + private final RelayPanel relayPanel; + + private final Button ok; + private final Button cancel; + private final PagesPanel pages = new PagesPanel(); + + boolean done = false; + boolean canceled = false; + + String tcpMulticastAddr; + int tcpMulticastPort; + int tcpMulticastLength; + + public ConfigDialog(PlatformConfig configAdv) throws ConfiguratorException { + super("JXTA Configurator"); + + this.configAdv = configAdv; + + // Identity settings + String peerName = configAdv.getName(); + + if ((null == peerName) || (0 == peerName.trim().length())) { + peerName = ""; + } + + // Security settings + boolean needSecurityConfig = true; + + // If security is already in place, then the security info is not shown. + XMLElement param = (XMLElement) configAdv.getServiceParam(PeerGroup.membershipClassID); + + if (param != null) { + Advertisement adv = null; + + try { + adv = AdvertisementFactory.newAdvertisement(param); + } catch (NoSuchElementException notAnAdv) { + ; // that's ok. + } catch (IllegalArgumentException badAdv) { + ; // that's ok. + } + + if (adv instanceof PSEConfigAdv) { + PSEConfigAdv pseConfig = (PSEConfigAdv) adv; + + // no certificate? That means we need to make one. + needSecurityConfig = (null == pseConfig.getCertificate()); + } + } + + // JXME Proxy Settings + boolean isJxmeProxy = false; + + try { + param = (XMLElement) configAdv.getServiceParam(PeerGroup.proxyClassID); + + if (param != null && configAdv.isSvcEnabled(PeerGroup.proxyClassID)) { + isJxmeProxy = true; + } + } catch (Exception nobigdeal) { + nobigdeal.printStackTrace(); + } + + int index; + + // TCP Settings + boolean tcpEnabled; + boolean clientDefaultT; + boolean serverDefaultT; + String defaultInterfaceAddressT; + String defaultPortT; + String defaultServerNameT; + String defaultServerPortT; + boolean multicastEnabledT; + boolean noPublicAddressesT; + + try { + param = (XMLElement) configAdv.getServiceParam(PeerGroup.tcpProtoClassID); + + tcpEnabled = configAdv.isSvcEnabled(PeerGroup.tcpProtoClassID); + + Enumeration tcpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv from either TransportAdv or tcpAdv + if (tcpChilds.hasMoreElements()) { + param = tcpChilds.nextElement(); + } else { + throw new IllegalStateException("Missing TCP Advertisment"); + } + + TCPAdv tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(param); + + clientDefaultT = tcpAdv.isClientEnabled(); + serverDefaultT = tcpAdv.isServerEnabled(); + + defaultInterfaceAddressT = tcpAdv.getInterfaceAddress(); + + if ((null == defaultInterfaceAddressT) || (0 == defaultInterfaceAddressT.trim().length())) { + defaultInterfaceAddressT = null; + } + + defaultPortT = Integer.toString(tcpAdv.getPort()); + if ((defaultPortT == null) || (0 == defaultPortT.trim().length())) { + defaultPortT = "9701"; + } + + defaultServerNameT = tcpAdv.getServer(); + + if ((null == defaultServerNameT) || (0 == defaultServerNameT.trim().length())) { + defaultServerNameT = ""; + } + + if (defaultServerNameT != null && (index = defaultServerNameT.lastIndexOf(":")) != -1) { + if ((0 == index) || (index == defaultServerNameT.length())) { + throw new IllegalArgumentException("Bad TCP server name . Cannot proceed."); + } + defaultServerPortT = defaultServerNameT.substring(index + 1); + defaultServerNameT = defaultServerNameT.substring(0, index); + } else { + defaultServerNameT = ""; + defaultServerPortT = "9701"; + } + + noPublicAddressesT = tcpAdv.getPublicAddressOnly(); + multicastEnabledT = tcpAdv.getMulticastState(); + + // we will just pass these to save. + tcpMulticastAddr = tcpAdv.getMulticastAddr(); + tcpMulticastPort = tcpAdv.getMulticastPort(); + tcpMulticastLength = tcpAdv.getMulticastSize(); + } catch (Exception failure) { + throw new ConfiguratorException("Broken Platform Config. Cannot proceed.", failure); + } + + // HTTP Settings + boolean httpEnabled; + boolean clientDefaultH; + boolean serverDefaultH; + String defaultInterfaceAddressH; + String defaultPortH; + String defaultServerNameH; + String defaultServerPortH; + boolean noPublicAddressesH; + + try { + param = (XMLElement) configAdv.getServiceParam(PeerGroup.httpProtoClassID); + + httpEnabled = configAdv.isSvcEnabled(PeerGroup.httpProtoClassID); + + Enumeration httpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType()); + + // get the TransportAdv from either TransportAdv + if (httpChilds.hasMoreElements()) { + param = httpChilds.nextElement(); + } else { + throw new IllegalStateException("Missing HTTP Advertisment"); + } + + // Read-in the adv as it is now. + HTTPAdv httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(param); + + clientDefaultH = httpAdv.isClientEnabled(); + serverDefaultH = httpAdv.isServerEnabled(); + + defaultInterfaceAddressH = httpAdv.getInterfaceAddress(); + + if ((null == defaultInterfaceAddressH) || (0 == defaultInterfaceAddressH.trim().length())) { + defaultInterfaceAddressH = null; + } + + defaultPortH = Integer.toString(httpAdv.getPort()); + + if ((defaultPortH == null) || (0 == defaultPortH.trim().length())) { + defaultPortH = "9700"; + } + + defaultServerNameH = httpAdv.getServer(); + + if ((null != defaultServerNameH) && (0 == defaultServerNameH.trim().length())) { + defaultServerNameH = ""; + } + + defaultServerPortH = "9700"; + + if (defaultServerNameH != null && (index = defaultServerNameH.lastIndexOf(":")) != -1) { + if ((0 == index) || (index == defaultServerNameH.length())) { + throw new IllegalArgumentException("Bad HTTP server name. Cannot proceed."); + } + defaultServerPortH = defaultServerNameH.substring(index + 1); + defaultServerNameH = defaultServerNameH.substring(0, index); + } else { + defaultServerNameH = ""; + defaultServerPortH = "9700"; + } + + noPublicAddressesH = httpAdv.getPublicAddressOnly(); + } catch (Exception failure) { + throw new ConfiguratorException("Broken Platform Config. Cannot proceed.", failure); + } + + // Rendezvous Settings + boolean isRendezvous; + boolean isAdhoc; + boolean onlySeeds; + List seedRdvs = new ArrayList(); + List seedingRdvs = new ArrayList(); + + try { + RdvConfigAdv rdvConfigAdv; + + param = (XMLElement) configAdv.getServiceParam(PeerGroup.rendezvousClassID); + + rdvConfigAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(param); + + isRendezvous = (RendezVousConfiguration.RENDEZVOUS == rdvConfigAdv.getConfiguration()); + + isAdhoc = (RendezVousConfiguration.AD_HOC == rdvConfigAdv.getConfiguration()); + + onlySeeds = rdvConfigAdv.getUseOnlySeeds(); + + for (URI uri : Arrays.asList(rdvConfigAdv.getSeedRendezvous())) { + seedRdvs.add(uri.toString()); + } + + for (URI uri1 : Arrays.asList(rdvConfigAdv.getSeedingURIs())) { + seedingRdvs.add(uri1.toString()); + } + } catch (Exception failure) { + throw new ConfiguratorException("Broken Platform Config. Cannot proceed.", failure); + } + + // Relay Settings + boolean isRelay; + boolean useRelay; + boolean useOnlySeedRelays; + List seedRelays = new ArrayList(); + List seedingRelays = new ArrayList(); + + try { + param = (XMLElement) configAdv.getServiceParam(PeerGroup.relayProtoClassID); + + RelayConfigAdv relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement(param); + + isRelay = relayConfig.isServerEnabled(); + + useRelay = relayConfig.isClientEnabled(); + + useOnlySeedRelays = relayConfig.getUseOnlySeeds(); + + for (EndpointAddress endpointAddress : Arrays.asList(relayConfig.getSeedRelays())) { + seedRelays.add(endpointAddress.toString()); + } + + for (URI uri : Arrays.asList(relayConfig.getSeedingURIs())) { + seedingRelays.add(uri.toString()); + } + } catch (Exception failure) { + throw new ConfiguratorException("Broken Platform Config. Cannot proceed.", failure); + } + + // BEGIN BUILDING UI + + GridBagLayout layout = new GridBagLayout(); + + setLayout(layout); + + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + beCanceled(); + } + }); + + helpLabel = new Label("See \"http://jxta-jxse.dev.java.net/confighelp.html\" for config help", Label.CENTER); + helpLabel.setBackground(new Color(220, 220, 220)); + helpLabel.setForeground(Color.black); + + helpLabel.addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + helpLabel.setForeground(Color.black); + helpLabel.setText("See \"http://jxta-jxse.dev.java.net/confighelp.html\" for config help"); + } + }); + + idPanel = new IdPanel(peerName, needSecurityConfig); + + enablingPanel = new EnablingPanel(isRelay, isRendezvous, isJxmeProxy); + + tcpPanel = new IPTptPanel(IPTptPanel.TransportType.TYPE_TCP, tcpEnabled, "TCP Settings", defaultInterfaceAddressT, + defaultPortT, clientDefaultT, serverDefaultT, defaultServerNameT, defaultServerPortT, noPublicAddressesT, + multicastEnabledT); + + httpPanel = new IPTptPanel(IPTptPanel.TransportType.TYPE_HTTP, httpEnabled, "HTTP Settings", defaultInterfaceAddressH, + defaultPortH, clientDefaultH, serverDefaultH, defaultServerNameH, defaultServerPortH, noPublicAddressesH); + + rdvPanel = new RdvPanel(!isAdhoc, onlySeeds); + + // add the relays + + for (Object seedRdv : seedRdvs) { + rdvPanel.seeds.addItem((String) seedRdv); + } + + for (Object seedingRdv : seedingRdvs) { + rdvPanel.seeding.addItem((String) seedingRdv); + } + + relayPanel = new RelayPanel(useRelay, useOnlySeedRelays); + + // add the relays + for (Object seedRelay : seedRelays) { + relayPanel.seeds.addItem((String) seedRelay); + } + + for (Object seedingRelay : seedingRelays) { + relayPanel.seeding.addItem((String) seedingRelay); + } + + ok = new Button(" OK "); + + ok.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (verifyInput()) { + if (saveValues()) { + beDone(); + } else { + beCanceled(); + } + } + } + }); + + cancel = new Button("Cancel"); + cancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + beCanceled(); + } + }); + + Panel okPanel = new Panel(); + + okPanel.add(ok); + okPanel.add(cancel); + + // build basic panel + Panel basicsPanel = pages.addPage("Basic", "Basic settings"); + + GridBagConstraints centerWConstr = (GridBagConstraints) centerConstr.clone(); + + centerWConstr.weighty = 1; + + basicsPanel.add(idPanel, centerWConstr); + + // build Advanced panel + Panel advancedPanel = pages.addPage("Advanced", "Experienced Users Only"); + + advancedPanel.add(enablingPanel, fillInsetConstr); + advancedPanel.add(tcpPanel, fillInsetConstr); + advancedPanel.add(httpPanel, fillInsetConstr); + + Panel proxyRdvRelayPanel = pages.addPage("Rendezvous/Relays", "Experienced Users Only"); + + proxyRdvRelayPanel.add(rdvPanel, fillInsetConstr); + proxyRdvRelayPanel.add(relayPanel, fillInsetConstr); + + add(helpLabel, fillConstr); + add(pages, fillInsetConstr); + add(okPanel, centerLastConstr); + + pack(); + setVisible(true); + } + + public synchronized boolean untilDone() { + try { + while (!done) { + wait(); + } + } catch (InterruptedException e) { + Thread.interrupted(); + } + + if (canceled) { + throw new JxtaError("Canceled during configuration"); + } + return (done); + } + + private synchronized boolean beDone() { + done = true; + notify(); + dispose(); + + return canceled; + } + + private synchronized boolean beCanceled() { + canceled = true; + done = true; + notify(); + dispose(); + + return canceled; + } + + private boolean verifyPort(String portName, String ports, boolean dynamicok) { + int p1; + + if ((null == ports) || (0 == ports.trim().length())) { + ports = "0"; + } + + try { + p1 = Integer.parseInt(ports); + } catch (Exception ex) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText(portName + " port number must be an integer: " + ports); + return false; + } + if ((p1 > 65535) || (p1 < (dynamicok ? 0 : 1))) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText( + portName + " port number must be an integer between " + (dynamicok ? "0" : "1") + " and 65535, found " + p1); + return false; + } + return true; + } + + private boolean verifyAddr(String proto, boolean serverOn, String localPort, String publicAddress, String publicPort) { + + // if a public name is specified, check its port. + if (serverOn && (publicAddress.length() > 0)) { + if (!verifyPort(proto + " local", localPort, false)) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Dynamic tcp port selection not supported when server public address is specified."); + pages.showPage("Advanced"); + return false; + } + + if (!verifyPort(proto + " public", publicPort, false)) { + pages.showPage("Advanced"); + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Dynamic tcp port selection not supported for server public address."); + return false; + } + } else if (!verifyPort(proto + " local", localPort, true)) { + pages.showPage("Advanced"); + return false; + } + + return true; + } + + private boolean verifyInput() { + + if (0 == idPanel.getName().trim().length()) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("A peer name is required."); + pages.showPage("Basic"); + return false; + } + + // Verify security parameters if we are not initialized + // Password and principal + if (null != idPanel.passwd) { + String passwd = idPanel.getPassword(); + String vpasswd = idPanel.getVerifyPassword(); + + // Verify password + // must be at least 8 chars a la unix + if (passwd.length() < 8) { + // Clear password text boxes + idPanel.clearPasswords(); + + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Passwords must be at least 8 characters"); + pages.showPage("Basic"); + return false; + } + + // must be identical + if (!passwd.equals(vpasswd)) { + // Clear password text boxes + idPanel.clearPasswords(); + + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Password does not match Verify Password"); + pages.showPage("Basic"); + return false; + } + } + + // make sure *some* transport is enabled. + if ((!(httpPanel.useMe.getState())) && (!(tcpPanel.useMe.getState()))) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("At least one of TCP or HTTP must be enabled."); + pages.showPage("Advanced"); + return false; + } + + // http settings + if (httpPanel.useMe.getState()) { + // make sure at least incoming or outgoing enabled. + if (!httpPanel.clientEnabled.getState() && !httpPanel.publicAddr.getState()) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must enable incoming and/or outcoming to enable HTTP"); + pages.showPage("Advanced"); + return false; + } + + // Check the http port fields. + boolean valid = verifyAddr("HTTP", httpPanel.publicAddr.getState(), httpPanel.ifAddr.getPort(), + httpPanel.publicAddr.getHost(), httpPanel.publicAddr.getPort()); + + if (!valid) { + return false; + } + } + + // tcp settings + if (tcpPanel.useMe.getState()) { + // make sure at least incoming or outgoing enabled. + if (!tcpPanel.clientEnabled.getState() && !tcpPanel.publicAddr.getState() && !tcpPanel.multicast.getState()) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must enable at least one of incoming, outcoming or multicast to enable TCP"); + pages.showPage("Advanced"); + return false; + } + + // Check the tcp port fields. + boolean valid = verifyAddr("TCP", tcpPanel.publicAddr.getState(), tcpPanel.ifAddr.getPort(), + tcpPanel.publicAddr.getHost(), tcpPanel.publicAddr.getPort()); + + if (!valid) { + return false; + } + } + + if (!relayPanel.useRelay.getState() && (!httpPanel.useMe.getState() || !httpPanel.publicAddr.getState()) + && (!tcpPanel.useMe.getState() || !tcpPanel.publicAddr.getState())) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must use Relay if incoming not enabled for TCP and/or HTTP"); + pages.showPage("Relay/Rendezvous"); + return false; + } + + if (enablingPanel.isRelay.getState() && (!httpPanel.useMe.getState() || !httpPanel.publicAddr.getState()) + && (!tcpPanel.useMe.getState() || !tcpPanel.publicAddr.getState())) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must enable incoming for TCP and/or HTTP to enable Relay"); + pages.showPage("Advanced"); + return false; + } + + if (enablingPanel.isRendezvous.getState() && (!httpPanel.useMe.getState() || !httpPanel.publicAddr.getState()) + && (!tcpPanel.useMe.getState() || !tcpPanel.publicAddr.getState())) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must enable incoming for TCP and/or HTTP to enable Rendezvous"); + pages.showPage("Advanced"); + return false; + } + + // if use only seeds is specified then at least one seed must be + // provided. + if (rdvPanel.useOnlySeeds.getState()) { + String[] rdvAddrs = rdvPanel.seeds.getItems(); + + String[] rdvSeedAddrs = rdvPanel.seeding.getItems(); + + if ((rdvAddrs.length == 0) && (rdvSeedAddrs.length == 0)) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must provide at least one seed rendezvous"); + pages.showPage("Rendezvous/Relays"); + return false; + } + } + + // if relay is to be used, make sure we have atleast one relay + // addr for the enabled transport(s) + if (relayPanel.useRelay.getState()) { + String[] relayaddrs = relayPanel.seeds.getItems(); + + String[] relaySeedaddrs = relayPanel.seeding.getItems(); + + if ((relayaddrs.length == 0) && (relaySeedaddrs.length == 0)) { + helpLabel.setForeground(Color.red.darker()); + helpLabel.setText("Must provide at least one seed Relay address"); + pages.showPage("Rendezvous/Relays"); + return false; + } + } + + return true; + } + + /* + * Updates the PlatformConfig Advertisement + */ + private boolean saveValues() { + try { + // set the peer name + configAdv.setName(idPanel.getName()); + + // Save the http config + HTTPAdv httpAdv = (HTTPAdv) AdvertisementFactory.newAdvertisement(HTTPAdv.getAdvertisementType()); + + httpAdv.setConfigMode(httpPanel.getConfigMode()); + + String chosenIntf = httpPanel.getInterfaceAddress(); + + if (chosenIntf.startsWith("A")) { + httpAdv.setInterfaceAddress(null); + } else { + httpAdv.setInterfaceAddress(chosenIntf); + } + + httpAdv.setPort(Integer.parseInt(httpPanel.ifAddr.getPort())); + + httpAdv.setClientEnabled(httpPanel.clientEnabled.getState()); + + httpAdv.setServerEnabled(httpPanel.publicAddr.getState()); + + // If there's nothing interesting inthere, do not save it. + if (0 == httpPanel.publicAddr.getHost().trim().length()) { + httpAdv.setServer(null); + } else { + httpAdv.setServer(httpPanel.publicAddr.getHost() + ":" + httpPanel.publicAddr.getPort()); + } + + httpAdv.setPublicAddressOnly(httpPanel.getPubAddrOnly()); + + configAdv.putServiceParam(PeerGroup.httpProtoClassID, wrapParm(httpAdv, httpPanel.useMe.getState())); + + // Save tcp configuration + TCPAdv tcpAdv = (TCPAdv) AdvertisementFactory.newAdvertisement(TCPAdv.getAdvertisementType()); + + tcpAdv.setConfigMode(tcpPanel.getConfigMode()); + + chosenIntf = tcpPanel.getInterfaceAddress(); + if (chosenIntf.startsWith("A")) { + tcpAdv.setInterfaceAddress(null); + } else { + tcpAdv.setInterfaceAddress(chosenIntf); + } + + try { + int theTcpPort = Integer.parseInt(tcpPanel.ifAddr.getPort()); + + tcpAdv.setPort(theTcpPort); + if (0 == theTcpPort) { + tcpAdv.setStartPort(0); + tcpAdv.setEndPort(0); + } + } catch (NumberFormatException ignored) { + /* verifyInput already checked it */ + } + + tcpAdv.setClientEnabled(tcpPanel.clientEnabled.getState()); + + tcpAdv.setServerEnabled(tcpPanel.publicAddr.getState()); + + if (0 == tcpPanel.publicAddr.getHost().trim().length()) { + tcpAdv.setServer(null); + } else { + tcpAdv.setServer(tcpPanel.publicAddr.getHost() + ":" + tcpPanel.publicAddr.getPort()); + } + + tcpAdv.setMulticastState(tcpPanel.multicast.getState()); + tcpAdv.setMulticastAddr(tcpMulticastAddr); + tcpAdv.setMulticastPort(tcpMulticastPort); + tcpAdv.setMulticastSize(tcpMulticastLength); + + tcpAdv.setPublicAddressOnly(tcpPanel.getPubAddrOnly()); + + configAdv.putServiceParam(PeerGroup.tcpProtoClassID, wrapParm(tcpAdv, tcpPanel.useMe.getState())); + + // save the proxy service settings + XMLDocument proxy = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + + if (!enablingPanel.isJxmeProxy.getState()) { + proxy.appendChild(proxy.createElement("isOff")); + } + + configAdv.putServiceParam(PeerGroup.proxyClassID, proxy); + + // Save the Rendezvous Configuration + RdvConfigAdv rdvConf = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + + rdvConf.setConfiguration( + enablingPanel.isRendezvous.getState() ? RendezVousConfiguration.RENDEZVOUS : + rdvPanel.useRdv.getState() ? RendezVousConfiguration.EDGE : RendezVousConfiguration.AD_HOC); + rdvConf.setUseOnlySeeds(rdvPanel.useOnlySeeds.getState()); + + for (String s2 : Arrays.asList(rdvPanel.seeds.getItems())) { + rdvConf.addSeedRendezvous(s2); + } + + for (String s3 : Arrays.asList(rdvPanel.seeding.getItems())) { + rdvConf.addSeedingURI(s3); + } + + XMLDocument rdvDoc = (XMLDocument) rdvConf.getDocument(MimeMediaType.XMLUTF8); + + configAdv.putServiceParam(PeerGroup.rendezvousClassID, rdvDoc); + + // save the relay settings + RelayConfigAdv relayConfig = (RelayConfigAdv) AdvertisementFactory.newAdvertisement( + RelayConfigAdv.getAdvertisementType()); + + relayConfig.setServerEnabled(enablingPanel.isRelay.getState()); + relayConfig.setClientEnabled(relayPanel.useRelay.getState()); + + for (String s : Arrays.asList(relayPanel.seeds.getItems())) { + relayConfig.addSeedRelay(s); + } + + for (String s1 : Arrays.asList(relayPanel.seeding.getItems())) { + relayConfig.addSeedingURI(s1); + } + + relayConfig.setUseOnlySeeds(relayPanel.useOnlySeeds.getState()); + + XMLDocument relayDoc = (XMLDocument) relayConfig.getDocument(MimeMediaType.XMLUTF8); + + // check if the relay service should be disabled completely + boolean relayDisabled = (!enablingPanel.isRelay.getState() && !relayPanel.useRelay.getState()); + + if (relayDisabled) { + relayDoc.appendChild(relayDoc.createElement("isOff")); + } + + configAdv.putServiceParam(PeerGroup.relayProtoClassID, relayDoc); + + // Save the security configuration parameters + // If we initialized security + // Otherwise they come from the security login dialog + if (null != idPanel.passwd) { + PSEConfigAdv pseConf = (PSEConfigAdv) AdvertisementFactory.newAdvertisement(PSEConfigAdv.getAdvertisementType()); + + PSEUtils.IssuerInfo info = PSEUtils.genCert(idPanel.getName(), null); + + pseConf.setCertificate(info.cert); + pseConf.setPrivateKey(info.subjectPkey, idPanel.getPassword().toCharArray()); + + XMLDocument pseDoc = (XMLDocument) pseConf.getDocument(MimeMediaType.XMLUTF8); + + configAdv.putServiceParam(PeerGroup.membershipClassID, pseDoc); + } + } catch (Throwable bad) { + bad.printStackTrace(); + return false; + } + + return true; + } + + private XMLDocument wrapParm(Advertisement srcAdv, boolean enabled) { + try { + XMLDocument advDoc = (XMLDocument) srcAdv.getDocument(MimeMediaType.XMLUTF8); + + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + + StructuredDocumentUtils.copyElements(doc, doc, advDoc); + if (!enabled) { + doc.appendChild(doc.createElement("isOff")); + } + + return doc; + } catch (Throwable ez1) { + ez1.printStackTrace(); + return null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/DefaultConfigurator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/DefaultConfigurator.java new file mode 100644 index 000000000..ed74338c5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/DefaultConfigurator.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLDocument; +import net.jxta.exception.ConfiguratorException; +import net.jxta.exception.JxtaError; +import net.jxta.impl.protocol.PSEConfigAdv; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URI; +import java.util.NoSuchElementException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This implementation provides the ability to reconfigure a JXTA PlatformConfig + * via an AWT based dialog. This is the original JXTA configuration mechanism. + */ +public class DefaultConfigurator extends AutomaticConfigurator { + + /** + * logger + */ + private final static transient Logger LOG = Logger.getLogger(DefaultConfigurator.class.getName()); + + /** + * Configures the platform using the specified directory. + * + * @param jxtaHome store home URI + * @throws net.jxta.exception.ConfiguratorException + * if a configuration error occurs + */ + public DefaultConfigurator(URI jxtaHome) throws ConfiguratorException { + super(jxtaHome); + } + + /** + * {@inheritDoc} + *

            + *

            Kinda hackish in that we don't really do anything if home is not a file. + */ + @Override + public boolean isReconfigure() { + if (!"file".equalsIgnoreCase(jxtaHome.getScheme())) { + return false; + } + + File jxtaHomeDir = new File(jxtaHome); + try { + boolean forceReconfig; + File file = new File(jxtaHomeDir, "reconf"); + forceReconfig = file.exists(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("force reconfig : " + forceReconfig); + } + + return forceReconfig; + } catch (Exception ex1) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not check \'reconf\' file. Assuming it exists.", ex1); + } + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Reconfig required - error getting \'reconf\' file"); + } + return true; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setReconfigure(boolean reconfigure) { + if (!"file".equalsIgnoreCase(jxtaHome.getScheme())) { + return; + } + + File jxtaHomeDir = new File(jxtaHome); + File f = new File(jxtaHomeDir, "reconf"); + + if (reconfigure) { + try { + f.createNewFile(); + } catch (IOException ex1) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not create \'reconf\' file", ex1); + LOG.severe("Create the file \'reconf\' by hand before retrying."); + } + } + } else { + try { + f.delete(); + } catch (Exception ex1) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not remove \'reconf\' file", ex1); + LOG.severe("Delete the file \'reconf\' by hand before retrying."); + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public PlatformConfig getPlatformConfig() throws ConfiguratorException { + boolean needsConfig = isReconfigure(); + + if (needsConfig && Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Reconfig requested - Forced reconfigure"); + } + + try { + super.getPlatformConfig(); + + // Automatic configuration doesn't do any security config. We use + // this fact to decide if we must do configuration. + XMLDocument security = (XMLDocument) advertisement.getServiceParam(PeerGroup.membershipClassID); + + if (null == security) { + needsConfig = true; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("Reconfig requested - No security info"); + } + } else { + Advertisement adv = null; + + try { + adv = AdvertisementFactory.newAdvertisement(security); + } catch (NoSuchElementException notAnAdv) {// that's ok. + } catch (IllegalArgumentException badAdv) {// that's ok. + } + + if (adv instanceof PSEConfigAdv) { + PSEConfigAdv pseConfig = (PSEConfigAdv) adv; + + // no certificate? That means we need to make one. + needsConfig |= (null == pseConfig.getCertificate()); + } else { + needsConfig = true; + } + } + } catch (IncompleteConfigurationException configBad) { + needsConfig = true; + } + + if (needsConfig) { + setReconfigure(true); + + try { + if (java.awt.EventQueue.isDispatchThread()) { + LOG.severe("The JXTA AWT Configuration Dialog cannot be run from the event dispatch thread. It\'s modal nature is fundamentally incompatible with running on the event dispatch thread. Either change to a different Configurator via PeerGroupFactory.setConfiguratorClass() or start JXTA from the application main Thread before starting your GUI via invokeLater()."); + // cruel but fair, the alternative is a UI deadlock. + System.exit(1); + } + ConfigDialog configUI = new ConfigDialog(advertisement); + + configUI.untilDone(); + setReconfigure(false); + } catch (Throwable t) { + if (t instanceof JxtaError) { + throw (JxtaError) t; + } + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not initialize graphical config dialog", t); + } + + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + + // clear any type-ahead + try { + while (in.ready()) { + in.readLine(); + } + } catch (Exception ignored) {// ignored + } + + System.err.flush(); + System.out.flush(); + System.out.println("The window-based configurator does not seem to be usable."); + System.out.print("Do you want to stop and edit the current configuration ? [no]: "); + System.out.flush(); + String answer = "no"; + + try { + answer = in.readLine(); + } catch (Exception ignored) {// ignored + } + + // this will cover all the cases of the answer yes, while + // allowing non-gui/batch type scripts to load the platform + // see platform issue #45 + + if ("yes".equalsIgnoreCase(answer)) { + save(); + System.out.println("Exiting; edit the file \"" + configFile.getPath() + + "\", remove the file \"reconf\", and then launch JXTA again."); + throw new JxtaError("Manual Configuration Requested"); + } else { + System.out.println("Attempting to continue using the current configuration."); + } + } + } + return advertisement; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/GenericPeerGroup.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/GenericPeerGroup.java new file mode 100644 index 000000000..33c259bd9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/GenericPeerGroup.java @@ -0,0 +1,1720 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import net.jxta.access.AccessService; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointService; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.loader.RefJxtaLoader; +import net.jxta.impl.protocol.PSEConfigAdv; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peer.PeerInfoService; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.PipeService; +import net.jxta.platform.JxtaLoader; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.resolver.ResolverService; +import net.jxta.service.Service; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.URI; +import java.net.URL; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Provides common services for most peer group implementations. + */ +public abstract class GenericPeerGroup implements PeerGroup { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(GenericPeerGroup.class.getName()); + + /** + * Holder for configuration parameters for groups in the process of being created. + */ + private final static Map group_configs = Collections.synchronizedMap(new HashMap()); + + /** + * The loader - use the getter and setter for modifying the ClassLoader for + * a security manager. + *

            + * This should eventually be group scoped rather than implementation + * scoped. We are currently allowing classes to loaded into contexts which + * they should not be known. + */ + private final static JxtaLoader loader = new RefJxtaLoader(new URL[0], new CompatibilityEquater() { + public boolean compatible(Element test) { + return StdPeerGroup.isCompatible(test); + } + }); + + /* + * Shortcuts to well known services. + */ + private EndpointService endpoint; + private ResolverService resolver; + private DiscoveryService discovery; + private PipeService pipe; + private MembershipService membership; + private RendezVousService rendezvous; + private PeerInfoService peerinfo; + private AccessService access; + + /** + * This peer's advertisement in this group. + */ + private final PeerAdvertisement peerAdvertisement; + + /** + * This group's advertisement. + */ + private PeerGroupAdvertisement peerGroupAdvertisement = null; + + /** + * This group's implAdvertisement. + */ + protected ModuleImplAdvertisement implAdvertisement = null; + + /** + * This peer's config advertisement. + */ + protected ConfigParams configAdvertisement = null; + + /** + * This service implements a group but, being a Service, it runs inside of + * some group. That's its home group. + *

            + * Exception: The platform peer group does not have a parent group. It + * has to be entirely self sufficient. + */ + protected PeerGroup parentGroup = null; + + /** + * The location of our store + */ + protected URI jxtaHome = null; + + /** + * The services that do the real work of the Peer Group. + */ + private final Map services = new HashMap(); + + /** + * {@code true} when we have decided to stop this group. + */ + private volatile boolean stopping = false; + + /** + * {@code true} when the PG adv has been published. + */ + private boolean published = false; // assume it hasn't + + /** + * Counts the number of times an interface to this group has been given out. + * This is decremented every time an interface object is GCed or + * its owner calls unref(). + * + *

            When it reaches zero, if it is time to tear-down the group instance; + * nomatter what the GC thinks. There are threads that need to be stopped + * before the group instance object ever becomes un-reachable. + */ + private int masterRefCount = 0; + + /** + * Is {@code true} when at least one interface object has been generated AFTER + * initComplete has become true. If true, the group stops when its ref + * count reaches zero. + */ + private boolean stopWhenUnreferenced = false; + + /** + * Is set to {@code true} when {@code init()} is completed enough that it + * makes sense to perform ref-counting. + */ + protected volatile boolean initComplete = false; + + /** + * The thread group in which threads created by this group or services of + * this group should live. The thread group is used primarily for debugging + * and classification purposes--we don't try to use any of the fancy (and + * mostly useless) ThreadGroup features. + */ + private ThreadGroup threadGroup = null; + + /** + * The minimum number of Threads our Executor will reserve. Once started + * these Threads will remain. + * + * todo convert these hardcoded settings into group config params. + */ + private final int COREPOOLSIZE = 5; + + + /** + * The number of seconds that Threads above {@code COREPOOLSIZE} will + * remain idle before terminating. + * + * todo convert these hardcoded settings into group config params. + */ + private final long KEEPALIVETIME = 15; + + + /** + * The intended upper bound on the number of threads we will allow our + * Executor to create. We will allow the pool to grow to twice this size if + * we run out of threads. + * + * todo convert these hardcoded settings into group config params. + */ + private final int MAXPOOLSIZE = 100; + + + /** + * Queue for tasks waiting to be run by our {@code Executor}. + */ + private BlockingQueue taskQueue; + + + /** + * The PeerGroup ThreadPool + */ + private ThreadPoolExecutor threadPool; + + /** + * The PeerGroup ScheduledExecutor + */ + private ScheduledThreadPoolExecutor scheduledExecutor; + + + /** + * {@inheritDoc} + *

            + * We do not want to count on the invoker to properly unreference the group + * object that we return; this call is often used in a loop and it is silly + * to increment and decrement ref-counts for references that are sure to + * live shorter than the referee. + *

            + * On the other hand it is dangerous for us to share our reference object to + * the parent group. That's where weak interface objects come in handy. We + * can safely make one and give it away. + */ + public PeerGroup getParentGroup() { + if (parentGroup == null) { + return null; + } + return parentGroup.getWeakInterface(); + } + + /** + * {@inheritDoc} + */ + public URI getStoreHome() { + return jxtaHome; + } + + /** + * Sets the root location for the store to be used by this peergroup. + *

            + * This should be set early in the peer group's life and then never + * changed. + * + * @param newHome The new store location. + */ + protected void setStoreHome(URI newHome) { + jxtaHome = newHome; + } + + /** + * {@inheritDoc} + */ + public static JxtaLoader getJxtaLoader() { + return loader; + } + + public GenericPeerGroup() { + // Start building our peer adv. + peerAdvertisement = (PeerAdvertisement) + AdvertisementFactory.newAdvertisement(PeerAdvertisement.getAdvertisementType()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + if (!(target instanceof PeerGroup)) { + return false; + } + + PeerGroup targetAsPeerGroup = (PeerGroup) target; + + // both null or both non-null. + if ((null == parentGroup) && (null != targetAsPeerGroup.getParentGroup())) { + return false; + } + + if ((null != parentGroup) && (null == targetAsPeerGroup.getParentGroup())) { + return false; + } + + if ((null != parentGroup) && !parentGroup.equals(targetAsPeerGroup.getParentGroup())) { + return false; + } + + // and same peer ids. + return getPeerGroupID().equals(targetAsPeerGroup.getPeerGroupID()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + // before init we must fail. + if ((null == peerAdvertisement) || (null == getPeerGroupID())) { + throw new IllegalStateException("PeerGroup not sufficiently initialized"); + } + + // XXX 20050907 bondolo including parentGroup would improve the hash. + return getPeerGroupID().hashCode(); + } + + /** + * {@inheritDoc} + *

            + * An implementation suitable for debugging. Don't try to parse + * this string! All of the information is available from other sources. + */ + @Override + public String toString() { + if (null == getPeerGroupID()) { + return super.toString(); + } + + StringBuilder result = new StringBuilder(); + + result.append(getPeerGroupID().toString()); + String peerGroupName = peerGroupAdvertisement.getName(); + + if (null != peerGroupName) { + result.append(" \""); + result.append(peerGroupName); + result.append('\"'); + } + + result.append('['); + result.append(masterRefCount); + result.append(']'); + + if (null != parentGroup) { + result.append(" / "); + result.append(parentGroup.toString()); + } + + return result.toString(); + } + + /** + * {@inheritDoc} + */ + public ThreadGroup getHomeThreadGroup() { + return threadGroup; + } + + /** + * Discover advertisements. + * + * @param discovery The discovery service to use. + * @param type the Discovery advertisement type. + * @param attr The attribute to search for or {@code null}. + * @param value The attribute value to match or {@code null}. + * @param seconds The number of seconds to search. + * @param thisClass The Advertisement class which the advertisement must + * match. + * @return a Collection of advertisements + */ + private Collection discoverSome(DiscoveryService discovery, int type, String attr, String value, int seconds, Class thisClass) { + long discoverUntil = TimeUtils.toAbsoluteTimeMillis(seconds * TimeUtils.ASECOND); + long lastRemoteAt = 0; // no previous remote discovery made. + + List results = new ArrayList(); + + try { + do { + Enumeration res = discovery.getLocalAdvertisements(type, attr, value); + + while (res.hasMoreElements()) { + Advertisement a = res.nextElement(); + + if (thisClass.isInstance(a)) { + results.add(a); + } + } + + if (!results.isEmpty()) { + break; + } + + if (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), lastRemoteAt) > (30 * TimeUtils.ASECOND)) { + discovery.getRemoteAdvertisements(null, type, attr, value, 20); + lastRemoteAt = TimeUtils.timeNow(); + } + + // snooze waiting for responses to come in. + Thread.sleep(1000); + } while (TimeUtils.timeNow() < discoverUntil); + } catch (Exception whatever) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure during discovery", whatever); + } + } + + return results; + } + + /** + * Discover an advertisement within the local peer group. + * + * @param type the Discovery advertisement type. + * @param attr The attribute to search for or {@code null}. + * @param value The attribute value to match or {@code null}. + * @param seconds The number of seconds to search. + * @param thisClass The Advertisement class which the advertisement must match. + * @return a Collection of advertisements + */ + private Advertisement discoverOne(int type, String attr, String value, int seconds, Class thisClass) { + Iterator res = discoverSome(discovery, type, attr, value, seconds, thisClass).iterator(); + + if (!res.hasNext()) { + return null; + } + return res.next(); + } + + /** + * Shortcuts to the standard basic services. + * + * @param mcid The Module Class ID of the service. + * @param service The service instance to set as the shortcut or + * {@code null} to clear the shortcut. + */ + private void setShortCut(ModuleClassID mcid, Service service) { + if (endpointClassID.equals(mcid)) { + endpoint = (EndpointService) service; + return; + } + if (resolverClassID.equals(mcid)) { + resolver = (ResolverService) service; + return; + } + if (discoveryClassID.equals(mcid)) { + discovery = (DiscoveryService) service; + return; + } + if (pipeClassID.equals(mcid)) { + pipe = (PipeService) service; + return; + } + if (membershipClassID.equals(mcid)) { + membership = (MembershipService) service; + return; + } + if (peerinfoClassID.equals(mcid)) { + peerinfo = (PeerInfoService) service; + return; + } + if (rendezvousClassID.equals(mcid)) { + rendezvous = (RendezVousService) service; + return; + } + if (accessClassID.equals(mcid)) { + access = (AccessService) service; + } + } + + /** + * Add a service to the collection of known services. + * + * @param mcid The Module Class ID of the service. + * @param service The service instance to set as the shortcut or + */ + protected synchronized void addService(ModuleClassID mcid, Service service) { + if (stopping) { + return; + } + + if (services.containsKey(mcid)) { + throw new IllegalStateException("Service" + mcid + " already registered."); + } + + services.put(mcid, service); + + setShortCut(mcid, service); + } + + /** + * {@inheritDoc} + */ + synchronized public Service lookupService(ID mcid) throws ServiceNotFoundException { + Service p = services.get(mcid); + + if (p == null) { + throw new ServiceNotFoundException("Not found: " + mcid.toString()); + } + + return p.getInterface(); + } + + /** + * {@inheritDoc} + *

            + * Group implementations do not have to support mapping. + * it would be nice to separate better Interfaces, so that + * Interface Objects can do things that the real service does + * not have to implement. + */ + public Service lookupService(ID mcid, int roleIndex) throws ServiceNotFoundException { + + // If the role number is != 0, it can't be honored: we + // do not have an explicit map. + + if (roleIndex != 0) { + throw new ServiceNotFoundException("Not found: " + mcid + "[" + roleIndex + "]"); + } + + return lookupService(mcid); + } + + /** + * {@inheritDoc} + */ + public Iterator getRoleMap(ID name) { + // No translation; use the given name in a singleton. + return Collections.singletonList(name).iterator(); + } + + /** + * check that all required core services are registered + * + * @throws ServiceNotFoundException If a required service was not found. + */ + protected void checkServices() throws ServiceNotFoundException { + Service ignored; + + ignored = lookupService(endpointClassID); + ignored = lookupService(resolverClassID); + ignored = lookupService(membershipClassID); + ignored = lookupService(accessClassID); + + /** + * ignored = lookupService(discoveryClassID); + * ignored = lookupService(pipeClassID); + * ignored = lookupService(rendezvousClassID); + * ignored = lookupService(peerinfoClassID); + */ + } + + /** + * Ask a group to unregister and unload a service + * + * @param mcid The service to be removed. + * @throws ServiceNotFoundException if service is not found + */ + protected synchronized void removeService(ModuleClassID mcid) throws ServiceNotFoundException { + setShortCut(mcid, null); + + Service p = services.remove(mcid); + + if (p == null) { + throw new ServiceNotFoundException("Not found: " + mcid.toString()); + } + + p.stopApp(); + + // service.terminate(); FIXME. We probably need a terminate() + // method. + // FIXME: [jice@jxta.org 20011013] to make sure the service is + // no-longer referenced, we should always return interfaces, and + // have a way to cut the reference to the real service in the + // interfaces. One way of doing that would be to have to levels + // of indirection: we should keep one and return references to it. + // when we want to cut the service loose, we should clear the + // reference from the interface that we own before letting it go. + // We need to study the consequences of doing that before implementing + // it. + } + + /** + * {@inheritDoc} + */ + public Module loadModule(ID assigned, Advertisement impl) throws ProtocolNotSupportedException, PeerGroupException { + return loadModule(assigned, (ModuleImplAdvertisement) impl, false); + } + + /** + * Load a Module from a ModuleImplAdv. + *

            + * Compatibility is checked and load is attempted. If compatible and + * loaded successfully, the resulting Module is initialized and returned. + * In most cases the other loadModule() method should be preferred, since + * unlike this one, it will seek many compatible implementation + * advertisements and try them all until one works. The home group of the new + * module (its' parent group if the new Module is a group) will be this group. + * + * @param assigned Id to be assigned to that module (usually its ClassID). + * @param implAdv An implementation advertisement for that module. + * @param privileged If {@code true} then the module is provided the true + * group obj instead of just an interface to the group object. This is + * normally used only for the group's defined services and applications. + * @return Module the module loaded and initialized. + * @throws ProtocolNotSupportedException The module is incompatible. + * @throws PeerGroupException The module could not be loaded or initialized + */ + protected Module loadModule(ID assigned, ModuleImplAdvertisement implAdv, boolean privileged) throws ProtocolNotSupportedException, PeerGroupException { + + Element compat = implAdv.getCompat(); + + if (null == compat) { + throw new IllegalArgumentException("No compatibility statement for : " + assigned); + } + + if (!compatible(compat)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Incompatible Module : " + assigned); + } + + throw new ProtocolNotSupportedException("Incompatible Module : " + assigned); + } + + Module newMod = null; + + if ((null != implAdv.getCode()) && (null != implAdv.getUri())) { + try { + // Good one. Try it. + Class clazz; + + try { + clazz = (Class) loader.findClass(implAdv.getModuleSpecID()); + } catch (ClassNotFoundException notLoaded) { + clazz = (Class) loader.defineClass(implAdv); + } + + if (null == clazz) { + throw new ClassNotFoundException("Cannot load class (" + implAdv.getCode() + ") : " + assigned); + } + + newMod = clazz.newInstance(); + + newMod.init(privileged ? this : (PeerGroup) getInterface(), assigned, implAdv); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( "Loaded" + (privileged ? " privileged" : "") + + " module : " + implAdv.getDescription() + " (" + implAdv.getCode() + ")"); + } + } catch (Exception ex) { + try { + newMod.stopApp(); + } catch (Throwable ignored) { + // If this does not work, nothing needs to be done. + } + throw new PeerGroupException("Could not load module for : " + assigned + " (" + implAdv.getDescription() + ")", ex); + } + } else { + String error; + + if (null == implAdv.getCode()) { + error = "ModuleImpAdvertisement missing Code element"; + } else if (null == implAdv.getUri()) { + error = "ModuleImpAdvertisement missing URI element"; + } else { + error = "ModuleImpAdvertisement missing both Code and URI elements"; + } + throw new PeerGroupException("Can not load module : " + error + " for" + assigned); + } + + // Publish or renew the lease of this adv since we're using it. + try { + if (discovery != null) { + discovery.publish(implAdv, DEFAULT_LIFETIME, DEFAULT_EXPIRATION); + } + } catch (Exception ignored) {// ignored + } + + // If we reached this point we're done. + return newMod; + } + + /** + * {@inheritDoc} + */ + public Module loadModule(ID assigned, ModuleSpecID specID, int where) { + return loadModule(assigned, specID, where, false); + } + + /** + * Load a module from a ModuleSpecID + *

            + * Advertisement is sought, compatibility is checked on all candidates and + * load is attempted. The first one that is compatible and loads + * successfully is initialized and returned. + * + * @param assignedID Id to be assigned to that module (usually its ClassID). + * @param specID The specID of this module. + * @param where May be one of: {@code Here}, {@code FromParent}, or + * {@code Both}, meaning that the implementation advertisement will be + * searched in this group, its parent or both. As a general guideline, the + * implementation advertisements of a group should be searched in its + * prospective parent (that is Here), the implementation advertisements of a + * group standard service should be searched in the same group than where + * this group's advertisement was found (that is, FromParent), while + * applications may be sought more freely (Both). + * @param privileged If {@code true} then the module is provided the true + * group obj instead of just an interface to the group object. This is + * normally used only for the group's defined services and applications. + * @return Module the new module, or {@code null} if no usable implementation was found. + */ + protected Module loadModule(ID assignedID, ModuleSpecID specID, int where, boolean privileged) { + + List allModuleImplAdvs = new ArrayList(); + + ModuleImplAdvertisement loadedImplAdv = loader.findModuleImplAdvertisement(specID); + if(null != loadedImplAdv) { + // We already have a module defined for this spec id. Use that. + allModuleImplAdvs.add(loadedImplAdv); + } else { + // Search for a module to use. + boolean fromHere = (where == Here || where == Both); + boolean fromParent = (where == FromParent || where == Both); + + if (fromHere && (null != discovery)) { + Collection here = discoverSome(discovery, DiscoveryService.ADV, + "MSID", specID.toString(), 120, ModuleImplAdvertisement.class); + + allModuleImplAdvs.addAll(here); + } + + if (fromParent && (null != getParentGroup()) && (null != parentGroup.getDiscoveryService())) { + Collection parent = discoverSome(parentGroup.getDiscoveryService(), DiscoveryService.ADV, + "MSID", specID.toString(), 120, ModuleImplAdvertisement.class); + + allModuleImplAdvs.addAll(parent); + } + } + + Throwable recentFailure = null; + + for (Advertisement eachAdv : allModuleImplAdvs) { + if( !(eachAdv instanceof ModuleImplAdvertisement) ) { + continue; + } + + ModuleImplAdvertisement foundImpl = (ModuleImplAdvertisement) eachAdv; + + try { + // First check that the MSID is really the one we're looking for. + // It could have appeared somewhere else in the adv than where + // we're looking, and discovery doesn't know the difference. + if (!specID.equals(foundImpl.getModuleSpecID())) { + continue; + } + + Module newMod = loadModule(assignedID, foundImpl, privileged); + + // If we reach that point, the module is good. + return newMod; + } catch (ProtocolNotSupportedException failed) { + // Incompatible implementation. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Incompatbile impl adv"); + } + } catch (PeerGroupException failed) { + // Initialization failure. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Initialization failed", failed); + } + } catch (Throwable e) { + recentFailure = e; + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Not a usable impl adv: ", e); + } + } + } + + // Throw an exception if there was a recent failure. + if (null != recentFailure) { + if (recentFailure instanceof Error) { + throw (Error) recentFailure; + } else if (recentFailure instanceof RuntimeException) { + throw (RuntimeException) recentFailure; + } else { + throw new UndeclaredThrowableException(recentFailure); + } + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not find a loadable implementation for SpecID: " + specID); + } + + return null; + } + + /** + * {@inheritDoc} + */ + public ConfigParams getConfigAdvertisement() { + return configAdvertisement; + } + + /** + * Sets the configuration advertisement for this peer group. + * + * @param config The configuration advertisement which will be used for + * this peer group or {@code null} if no configuration advertisement is to + * be used. + */ + protected void setConfigAdvertisement(ConfigParams config) { + configAdvertisement = config; + } + + /** + * Adds configuration parameters for the specified group. The configuration + * parameters remain cached until either the specified group is started or + * the parameters are replaced. + * + * @param groupid The group for who's params are being provided. + * @param params The parameters to be provided to the peer group when it is + * created. + */ + public static void setGroupConfigAdvertisement(ID groupid, ConfigParams params) { + if( null != params) { + group_configs.put(groupid, params); + } else { + group_configs.remove(groupid); + } + } + + /* + * Now comes the implementation of the public API, including the + * API mandated by the Service interface. + */ + + /** + * {@inheritDoc} + *

            + * It is not recommended to overload this method. Instead, subclassers + * should overload either or both of + * {@link #initFirst(PeerGroup,ID,Advertisement)} and {@link #initLast()}. + * If this method is to be overloaded, the overloading method must + * invoke super.init. + *

            + * This method invokes initFirst + * with identical parameters. initLast does not take + * parameters since the relevant information can be obtained from the + * group following completion of the initFirst phase. + * The resulting values may be different from the parameters to + * initFirst since initFirst may + * be overLoaded and the overloading method may modify these parameters + * when calling super.initFirst. (See + * {@link net.jxta.impl.peergroup.Platform} for an example of such a case). + *

            + * Upon completion, the group object is marked as completely initialized + * in all cases. Once a group object is completely initialized, it becomes + * sensitive to reference counting. + *

            + * In the future this method may become final. + */ + public void init(PeerGroup homeGroup, ID assignedID, Advertisement impl) throws PeerGroupException { + try { + initFirst(homeGroup, assignedID, impl); + initLast(); + } finally { + // This must be done in all cases. + initComplete = true; + } + } + + /** + * Performs all initialization steps that need to be performed + * before any subclass initialization is performed. + *

            + * Classes that override this method should always call + * super.initFirst() before doing + * any of their own work. + * + * @param homeGroup The group that serves as a parent to this group. + * @param assignedID The unique ID assigned to this module. For + * group this is the group ID or null if a group ID + * has not yet been assigned. If null is passed, GenericPeerGroup + * will generate a new group ID. + * @param impl The ModuleImplAdvertisement which defines this + * group's implementation. + * @throws PeerGroupException if a group initialization error occurs + */ + protected void initFirst(PeerGroup homeGroup, ID assignedID, Advertisement impl) throws PeerGroupException { + + this.implAdvertisement = (ModuleImplAdvertisement) impl; + this.parentGroup = homeGroup; + + if (null != parentGroup) { + jxtaHome = parentGroup.getStoreHome(); + } + + // Set the peer configuration before we start. + if((null != assignedID) && (null == getConfigAdvertisement())) { + setConfigAdvertisement(group_configs.remove(assignedID)); + } + + try { + // FIXME 20030919 bondolo@jxta.org This setup doesnt give us any + // capability to use seed material or parent group. + if (null == assignedID) { + if ("cbid".equals(IDFactory.getDefaultIDFormat())) { + throw new IllegalStateException("Cannot generate group id for cbid group"); + } else { + assignedID = IDFactory.newPeerGroupID(); + } + } else { + if (parentGroup != null) { + DiscoveryService disco = parentGroup.getDiscoveryService(); + if (null != disco) { + Enumeration found = disco.getLocalAdvertisements(DiscoveryService.GROUP, "GID", assignedID.toString()); + if (found.hasMoreElements()) { + peerGroupAdvertisement = (PeerGroupAdvertisement) found.nextElement(); + } + } + } + } + + if (!(assignedID instanceof PeerGroupID)) { + throw new PeerGroupException("assignedID must be a peer group ID"); + } + + peerAdvertisement.setPeerGroupID((PeerGroupID) assignedID); + + // // make sure the parent group is the required group + // if (null != peerAdvertisement.getPeerGroupID().getParentPeerGroupID()) { + // if (null == parentGroup) { + // throw new PeerGroupException("Group requires parent group : " + peerAdvertisement.getPeerGroupID().getParentPeerGroupID()); + // } else if (!parentGroup.getPeerGroupID().equals(peerAdvertisement.getPeerGroupID().getParentPeerGroupID())) { + // throw new PeerGroupException("Group requires parent group : " + peerAdvertisement.getPeerGroupID().getParentPeerGroupID() + ". Provided parent was : " + parentGroup.getPeerGroupID()); + // } + // } + + // Do our part of the PeerAdv construction. + if ((configAdvertisement != null) && (configAdvertisement instanceof PlatformConfig)) { + PlatformConfig platformConfig = (PlatformConfig) configAdvertisement; + + // Normally there will be a peer ID and a peer name in the config. + PeerID configPID = platformConfig.getPeerID(); + + if ((null == configPID) || (ID.nullID == configPID)) { + if ("cbid".equals(IDFactory.getDefaultIDFormat())) { + // Get our peer-defined parameters in the configAdv + XMLElement param = (XMLElement) platformConfig.getServiceParam(PeerGroup.membershipClassID); + + if (null == param) { + throw new IllegalArgumentException(PSEConfigAdv.getAdvertisementType() + " could not be located"); + } + + Advertisement paramsAdv = null; + try { + paramsAdv = AdvertisementFactory.newAdvertisement(param); + } catch (NoSuchElementException noadv) {// ignored + } + if (!(paramsAdv instanceof PSEConfigAdv)) { + throw new IllegalArgumentException( + "Provided Advertisement was not a " + PSEConfigAdv.getAdvertisementType()); + } + + PSEConfigAdv config = (PSEConfigAdv) paramsAdv; + Certificate clientRoot = config.getCertificate(); + byte[] pub_der = clientRoot.getPublicKey().getEncoded(); + + platformConfig.setPeerID(IDFactory.newPeerID((PeerGroupID) assignedID, pub_der)); + } else { + platformConfig.setPeerID(IDFactory.newPeerID((PeerGroupID) assignedID)); + } + } + + peerAdvertisement.setPeerID(platformConfig.getPeerID()); + peerAdvertisement.setName(platformConfig.getName()); + peerAdvertisement.setDesc(platformConfig.getDesc()); + } else { + if (null == parentGroup) { + // If we did not get a valid peer id, we'll initialize it here. + peerAdvertisement.setPeerID(IDFactory.newPeerID((PeerGroupID) assignedID)); + } else { + // We're not the world peer group, which is the authoritative source of these values. + peerAdvertisement.setPeerID(parentGroup.getPeerAdvertisement().getPeerID()); + peerAdvertisement.setName(parentGroup.getPeerAdvertisement().getName()); + peerAdvertisement.setDesc(parentGroup.getPeerAdvertisement().getDesc()); + } + } + + if (peerGroupAdvertisement == null) { + // No existing gadv. OK then we're creating the group or we're + // the platform, it seems. Start a grp adv with the essentials + // that we know. + peerGroupAdvertisement = (PeerGroupAdvertisement) + AdvertisementFactory.newAdvertisement(PeerGroupAdvertisement.getAdvertisementType()); + + peerGroupAdvertisement.setPeerGroupID((PeerGroupID) assignedID); + peerGroupAdvertisement.setModuleSpecID(implAdvertisement.getModuleSpecID()); + } else { + published = true; + } + + // If we still do not have a config adv, make one with the minimal info in it. + // All groups but the Platform and the netPG are in that case. + // In theory a plain ConfigParams would be enough for subgroups. But for now + // GenericPeerGroup always has a full Platformconfig and there is no other concrete + // ConfigParams subclass. + if (configAdvertisement == null) { + PlatformConfig conf = (PlatformConfig) AdvertisementFactory.newAdvertisement(PlatformConfig.getAdvertisementType()); + + conf.setPeerID(peerAdvertisement.getPeerID()); + conf.setName(peerAdvertisement.getName()); + conf.setDesc(peerAdvertisement.getDesc()); + configAdvertisement = conf; + } + + // Merge service params with those specified by the group (if any). The only + // policy, right now, is to give peer params the precedence over group params. + Hashtable grpParams = peerGroupAdvertisement.getServiceParams(); + Enumeration keys = grpParams.keys(); + + while (keys.hasMoreElements()) { + ID key = (ID) keys.nextElement(); + Element e = (Element) grpParams.get(key); + + if (configAdvertisement.getServiceParam(key) == null) { + configAdvertisement.putServiceParam(key, e); + } + } + + /* + * Now seems like the right time to attempt to register the group. + * The only trouble is that it could cause the group to + * be used before all the services are initialized, but on the + * other hand, we do not want to let a redundant group go through + * it's service initialization because that would cause irreparable + * damage to the legitimate instance. There should be a synchro on + * on the get() and lookupService() routines. + */ + if (!globalRegistry.registerInstance((PeerGroupID) assignedID, this)) { + throw new PeerGroupException("Group already instantiated"); + } + } catch (Throwable any) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Group init failed", any); + } + + if (any instanceof Error) { + throw (Error) any; + } else if (any instanceof RuntimeException) { + throw (RuntimeException) any; + } else if (any instanceof PeerGroupException) { + throw (PeerGroupException) any; + } + + throw new PeerGroupException("Group init failed", any); + } + + ThreadGroup parentThreadGroup = (null != this.parentGroup) + ? parentGroup.getHomeThreadGroup() + : Thread.currentThread().getThreadGroup(); + + threadGroup = new ThreadGroup(parentThreadGroup, "Group " + peerGroupAdvertisement.getPeerGroupID()); + + taskQueue = new ArrayBlockingQueue(COREPOOLSIZE * 2); + threadPool = new ThreadPoolExecutor(COREPOOLSIZE, MAXPOOLSIZE, + KEEPALIVETIME, TimeUnit.SECONDS, + taskQueue, + new PeerGroupThreadFactory("Executor", getHomeThreadGroup()), + new CallerBlocksPolicy()); + + // Try to allow core threads to idle out. (Requires a 1.6 method) + try { + Method allowCoreThreadTimeOut = threadPool.getClass().getMethod("allowCoreThreadTimeOut", boolean.class); + + allowCoreThreadTimeOut.invoke(threadPool, Boolean.TRUE); + } catch(Throwable ohWell) { + // Our attempt failed. + if (Logging.SHOW_FINEST && LOG.isLoggable(Level.FINEST)) { + LOG.log(Level.FINEST, "Failed to enable 'allowCoreThreadTimeOut'", ohWell); + } + } + + scheduledExecutor = new ScheduledThreadPoolExecutor(1, + new PeerGroupThreadFactory("Scheduled Executor", getHomeThreadGroup())); + + /* + * The rest of construction and initialization are left to the + * group subclass, between here and the begining for initLast. + * That should include instanciating and setting the endpoint, and + * finally supplying it with endpoint protocols. + * That also includes instanciating the appropriate services + * and registering them. + * For an example, see the StdPeerGroup class. + */ + } + + /** + * Perform all initialization steps that need to be performed + * after any subclass initialization is performed. + *

            + * Classes that override this method should always call super.initLast + * after doing any of their own work. + * @throws PeerGroupException if a group initialization error occurs + */ + protected void initLast() throws PeerGroupException { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Group : " + getPeerGroupID()); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tModule Spec ID : ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tPeer Group ID : ").append(getPeerGroupID()); + configInfo.append("\n\t\tGroup Name : ").append(getPeerGroupName()); + configInfo.append("\n\t\tPeer ID in Group : ").append(getPeerID()); + configInfo.append("\n\tConfiguration :"); + if (null == parentGroup) { + configInfo.append("\n\t\tHome Group : (none)"); + } else { + configInfo.append("\n\t\tHome Group : \"").append(parentGroup.getPeerGroupName()).append("\" / ").append( + parentGroup.getPeerGroupID()); + } + configInfo.append("\n\t\tServices :"); + for (Map.Entry anEntry : services.entrySet()) { + ModuleClassID aMCID = anEntry.getKey(); + ModuleImplAdvertisement anImplAdv = (ModuleImplAdvertisement) anEntry.getValue().getImplAdvertisement(); + + configInfo.append("\n\t\t\t").append(aMCID).append("\t").append(anImplAdv.getDescription()); + } + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

            + * PeerGroupInterface's stopApp() does nothing. Only a real reference to the + * group object permits to stop it without going through ref counting. + */ + public void stopApp() { + stopping = true; + + Collection allServices = new ArrayList(services.keySet()); + + // Stop and remove all remaining services. + for (ModuleClassID aService : allServices) { + try { + removeService(aService); + } catch (Exception failure) { + LOG.log(Level.WARNING, "Failure shutting down service : " + aService, failure); + } + } + + if (!services.isEmpty()) { + LOG.warning(services.size() + " services could not be shut down during peer group stop."); + } + + // remove everything (just in case); + services.clear(); + + globalRegistry.unRegisterInstance(peerGroupAdvertisement.getPeerGroupID(), this); + + // Explicitly unreference our parent group in order to allow it + // to terminate if this group object was itself the last reference + // to it. + if (parentGroup != null) { + parentGroup.unref(); + parentGroup = null; + } + + // shutdown the threadpool + threadPool.shutdownNow(); + scheduledExecutor.shutdownNow(); + + // No longer initialized. + initComplete = false; + } + + /** + * {@inheritDoc} + *

            + * May be called by a module which has a direct reference to the group + * object and wants to notify its abandoning it. Has no effect on the real + * group object. + */ + public void unref() {} + + /** + * Called every time an interface object that refers to this group + * goes away, either by being finalized or by its unref() method being + * invoked explicitly. + */ + protected void decRefCount() { + synchronized (this) { + --masterRefCount; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + Throwable trace = new Throwable("Stack Trace"); + StackTraceElement elements[] = trace.getStackTrace(); + LOG.info("[" + getPeerGroupID() + "] GROUP REF COUNT DECCREMENTED TO: " + masterRefCount + " by\n\t" + elements[2]); + } + + if (masterRefCount != 0) { + return; + } + + if (!stopWhenUnreferenced) { + return; + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("[" + getPeerGroupID() + "] STOPPING UNREFERENCED GROUP"); + } + + stopApp(); + masterRefCount = Integer.MIN_VALUE; + } + + /* + * Implement the Service API so that we can make groups services when we + * decide to. + */ + + /** + * {@inheritDoc} + */ + public Service getInterface() { + synchronized (this) { + ++masterRefCount; + + if (masterRefCount < 1) { + throw new IllegalStateException("Group has been shutdown. getInterface() is not available"); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + Throwable trace = new Throwable("Stack Trace"); + StackTraceElement elements[] = trace.getStackTrace(); + + LOG.info("[" + getPeerGroupID() + "] GROUP REF COUNT INCREMENTED TO: " + masterRefCount + " by\n\t" + elements[2]); + } + + if (initComplete) { + // If init is complete the group can become sensitive to + // its ref count reaching zero. Before there could be + // transient references before there is a chance to give + // a permanent reference to the invoker of newGroup. + stopWhenUnreferenced = true; + } + } + + return new RefCountPeerGroupInterface(this); + } + + /** + * {@inheritDoc} + */ + public PeerGroup getWeakInterface() { + return new PeerGroupInterface(this); + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement.clone(); + } + + /** + * {@inheritDoc} + */ + public void publishGroup(String name, String description) throws IOException { + + if (published) { + return; + } + + peerGroupAdvertisement.setName(name); + peerGroupAdvertisement.setDescription(description); + + if (parentGroup == null) { + return; + } + + DiscoveryService parentDiscovery = parentGroup.getDiscoveryService(); + + if (null == parentDiscovery) { + return; + } + + parentDiscovery.publish(peerGroupAdvertisement, DEFAULT_LIFETIME, DEFAULT_EXPIRATION); + published = true; + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(Advertisement pgAdv) throws PeerGroupException { + + PeerGroupAdvertisement adv = (PeerGroupAdvertisement) pgAdv; + PeerGroupID gid = adv.getPeerGroupID(); + + if ((gid == null) || ID.nullID.equals(gid)) { + throw new IllegalArgumentException("Advertisement did not contain a peer group ID"); + } + + PeerGroup theNewGroup = globalRegistry.lookupInstance(gid); + + if (theNewGroup != null) { + return theNewGroup; + } + + // We do not know if the grp adv had been previously published or not... Since it may contain information essential to + // the configuration of services, we need to make sure it is published localy, rather than letting the group publish + // itself after the fact. + + // FIXME jice@jxta.org 20040713 : The downside is that we're publishing the adv even before making sure that this group + // can really be instantiated. We're basically using the cm as a means to pass parameters to the module because it is a + // group. We have the same parameter issue with the config adv. Eventually we need to find a clean way of passing + // parameters specific to a certain types of module. + + try { + discovery.publish(adv, DEFAULT_LIFETIME, DEFAULT_EXPIRATION); + } catch (Exception any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish the group advertisement: ", any); + } + } + + theNewGroup = (PeerGroup) loadModule(adv.getPeerGroupID(), adv.getModuleSpecID(), Here, false); + + if (theNewGroup == null) { + throw new PeerGroupException("Could not find group implementation with " + adv.getModuleSpecID()); + } + + return (PeerGroup) theNewGroup.getInterface(); + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(PeerGroupID gid, Advertisement impl, String name, String description) throws PeerGroupException { + PeerGroup theNewGroup = null; + + if (null != gid) { + theNewGroup = globalRegistry.lookupInstance(gid); + } + + if (theNewGroup != null) { + return theNewGroup; + } + + try { + theNewGroup = (PeerGroup) loadModule(gid, (ModuleImplAdvertisement) impl, false); + } catch (Throwable any) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Could not load group implementation", any); + } + + throw new PeerGroupException("Could not load group implementation", any); + } + + try { + // The group adv definitely needs to be published. + theNewGroup.publishGroup(name, description); + } catch (Exception any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish group or implementation:", any); + } + } + return (PeerGroup) theNewGroup.getInterface(); + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(PeerGroupID gid) throws PeerGroupException { + + if ((gid == null) || ID.nullID.equals(gid)) { + throw new IllegalArgumentException("Invalid peer group ID"); + } + + PeerGroup result = globalRegistry.lookupInstance(gid); + + if (result != null) { + return result; + } + + PeerGroupAdvertisement adv; + + try { + adv = (PeerGroupAdvertisement) + discoverOne(DiscoveryService.GROUP, "GID", gid.toString(), 120, PeerGroupAdvertisement.class); + } catch (Throwable any) { + throw new PeerGroupException("Failed finding group advertisement for " + gid, any); + } + + if (adv == null) { + throw new PeerGroupException("Could not find group advertisement for group " + gid); + } + + return newGroup(adv); + } + + /** + * {@inheritDoc} + */ + public JxtaLoader getLoader() { + return loader; + } + + /** + * {@inheritDoc} + */ + public String getPeerName() { + // before init we must fail. + if (null == peerAdvertisement) { + throw new IllegalStateException("PeerGroup not sufficiently initialized"); + } + return peerAdvertisement.getName(); + } + + /** + * {@inheritDoc} + */ + public String getPeerGroupName() { + // before init we must fail. + if (null == peerGroupAdvertisement) { + throw new IllegalStateException("PeerGroup not sufficiently initialized"); + } + return peerGroupAdvertisement.getName(); + } + + /** + * {@inheritDoc} + */ + public PeerGroupID getPeerGroupID() { + // before init we must fail. + if (null == peerGroupAdvertisement) { + throw new IllegalStateException("PeerGroup not sufficiently initialized"); + } + + return peerGroupAdvertisement.getPeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public PeerID getPeerID() { + // before init we must fail. + if (null == peerAdvertisement) { + throw new IllegalStateException("PeerGroup not sufficiently initialized"); + } + return peerAdvertisement.getPeerID(); + } + + /** + * {@inheritDoc} + */ + public PeerAdvertisement getPeerAdvertisement() { + return peerAdvertisement; + } + + /** + * {@inheritDoc} + */ + public PeerGroupAdvertisement getPeerGroupAdvertisement() { + return peerGroupAdvertisement; + } + + /** + * {@inheritDoc} + */ + public boolean isRendezvous() { + if (rendezvous == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Rendezvous service null"); + } + } + return (rendezvous != null) && rendezvous.isRendezVous(); + } + + /* + * shortcuts to the well-known services, in order to avoid calls to lookup. + */ + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + if (endpoint == null) { + return null; + } + return (EndpointService) endpoint.getInterface(); + } + + /** + * {@inheritDoc} + */ + public ResolverService getResolverService() { + if (resolver == null) { + return null; + } + return (ResolverService) resolver.getInterface(); + } + + /** + * {@inheritDoc} + */ + public DiscoveryService getDiscoveryService() { + if (discovery == null) { + return null; + } + return (DiscoveryService) discovery.getInterface(); + } + + /** + * {@inheritDoc} + */ + public PeerInfoService getPeerInfoService() { + if (peerinfo == null) { + return null; + } + return (PeerInfoService) peerinfo.getInterface(); + } + + /** + * {@inheritDoc} + */ + public MembershipService getMembershipService() { + if (membership == null) { + return null; + } + return (MembershipService) membership.getInterface(); + } + + /** + * {@inheritDoc} + */ + public PipeService getPipeService() { + if (pipe == null) { + return null; + } + return (PipeService) pipe.getInterface(); + } + + /** + * {@inheritDoc} + */ + public RendezVousService getRendezVousService() { + if (rendezvous == null) { + return null; + } + return (RendezVousService) rendezvous.getInterface(); + } + + /** + * {@inheritDoc} + */ + public AccessService getAccessService() { + if (access == null) { + return null; + } + return (AccessService) access.getInterface(); + } + + /** + * Returns the executor pool + * + * @return the executor pool + */ + public Executor getExecutor() { + return threadPool; + } + + /** + * Returns the scheduled executor. The + * + * @return the scheduled executor + */ + public ScheduledExecutorService getScheduledExecutor() { + // FIXME 20070815 bondolo We should return a proxy object to disable shutdown() + return scheduledExecutor; + } + + /** + * Our rejected execution handler which has the effect of pausing the + * caller until the task can be queued. + */ + private static class CallerBlocksPolicy implements RejectedExecutionHandler { + + private CallerBlocksPolicy() { + } + + /** + * {@inheritDoc} + */ + public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { + BlockingQueue queue = executor.getQueue(); + + while (!executor.isShutdown()) { + executor.purge(); + + try { + boolean pushed = queue.offer(runnable, 500, TimeUnit.MILLISECONDS); + + if (pushed) { + break; + } + } catch (InterruptedException woken) { + throw new RejectedExecutionException("Interrupted while attempting to enqueue", woken); + } + } + } + } + + /** + * Our thread factory that adds the threads to our thread group and names + * the thread to something recognizable. + */ + static class PeerGroupThreadFactory implements ThreadFactory { + final AtomicInteger threadNumber = new AtomicInteger(1); + final String name; + final ThreadGroup threadgroup; + + PeerGroupThreadFactory(String name, ThreadGroup threadgroup) { + this.name = name; + this.threadgroup = threadgroup; + } + + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(threadgroup, runnable, name + " - " + threadNumber.getAndIncrement(), 0); + if(thread.isDaemon()) { + thread.setDaemon(false); + } + if (thread.getPriority() != Thread.NORM_PRIORITY) { + thread.setPriority(Thread.NORM_PRIORITY); + } + return thread; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/IncompleteConfigurationException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/IncompleteConfigurationException.java new file mode 100644 index 000000000..e08308b90 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/IncompleteConfigurationException.java @@ -0,0 +1,66 @@ +/* + * IncompleteConfigurationException.java + * + * Created on September 13, 2005, 12:11 PM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ +package net.jxta.impl.peergroup; + +import net.jxta.exception.ConfiguratorException; + +import java.util.List; + +/** + * A configurator exception which is generated when intervention + */ +public class IncompleteConfigurationException extends ConfiguratorException { + + /** + * Constucts a {@link IncompleteConfigurationException} with no specified details. + */ + public IncompleteConfigurationException() { + super(); + } + + /** + * Constructs a {@link IncompleteConfigurationException} with the specified message. + * + * @param msg message + */ + public IncompleteConfigurationException(String msg) { + super(msg); + } + + /** + * Constructs a {@link IncompleteConfigurationException} with the specified {@link + * java.lang.Throwable cause}. + * + * @param ex cause + */ + public IncompleteConfigurationException(Throwable ex) { + super(ex); + } + + /** + * Constructs a {@link IncompleteConfigurationException} with the specified message and {@link + * java.lang.Throwable cause}. + * + * @param msg message + * @param ex cause + */ + public IncompleteConfigurationException(String msg, Throwable ex) { + super(msg, ex); + } + + /** + * Constructs a {@link IncompleteConfigurationException} with the specified {@link + * java.util.List} of {@link java.lang.Throwable causes}. + * + * @param ex causes + */ + public IncompleteConfigurationException(List ex) { + super(ex); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/NullConfigurator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/NullConfigurator.java new file mode 100644 index 000000000..bc3f0a960 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/NullConfigurator.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.exception.ConfiguratorException; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.logging.Logging; +import net.jxta.protocol.ConfigParams; + +import java.io.*; +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A minimal Platform Configurator. This implementation can load a + * configuration from an existing PlatformConfig file and also save a + * configuration to the PlatformConfig file. + *

            + * This configurator provides no explict validation of the PlatformConfig + * as it is read from the file (Some is done by the PlatformConfig class) and + * provides no mechanism for reconfiguration. The NullConfigurator provides a + * useful base implementation for extending your own Configurator and also + * provides the minimal implementation needed for applications which perform + * their own configuration. + */ +public class NullConfigurator implements PlatformConfigurator { + + /** + * logger + */ + private final static transient Logger LOG = Logger.getLogger(NullConfigurator.class.getName()); + + /** + * The location in which the configuration files will reside. + */ + protected final URI jxtaHome; + + /** + * The file in which contains the platform configurtation. + */ + protected final URI configFile; + + /** + * The platform config + */ + protected PlatformConfig advertisement = null; + + /** + * Constructor for the NullConfigurator + * + * @param homeRoot The location in which the configuration files will reside. + * @throws ConfiguratorException If there is a problem accessing the configuration information. + */ + public NullConfigurator(URI homeRoot) throws ConfiguratorException { + if (!homeRoot.isAbsolute()) { + throw new IllegalArgumentException("homeRoot must be an absoluteURI"); + } + + jxtaHome = homeRoot; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("JXTA_HOME = " + jxtaHome.toASCIIString()); + } + + if ("file".equalsIgnoreCase(jxtaHome.getScheme())) { + File jxtaHomeDir = new File(jxtaHome); + + if (jxtaHomeDir.exists() && !jxtaHomeDir.isDirectory()) { + throw new IllegalArgumentException("'" + jxtaHomeDir + "' is not a directory."); + } + + if (!jxtaHomeDir.exists()) { + if (!jxtaHomeDir.mkdirs()) { + throw new IllegalStateException("Could not create '" + jxtaHomeDir + "'."); + } + } + + configFile = new File(jxtaHomeDir, "PlatformConfig").toURI(); + } else { + configFile = jxtaHome.resolve("PlatformConfig"); + } + } + + /** + * @inheritDoc + */ + public PlatformConfig getPlatformConfig() throws ConfiguratorException { + advertisement = (PlatformConfig) load(); + + return advertisement; + } + + /** + * @inheritDoc + */ + public final void setPlatformConfig(PlatformConfig config) { + advertisement = config; + } + + /** + * @inheritDoc + */ + public ConfigParams getConfigParams() throws ConfiguratorException { + return getPlatformConfig(); + } + + /** + * @inheritDoc + */ + public void setConfigParams(ConfigParams cp) { + setPlatformConfig((PlatformConfig) cp); + } + + /** + * @inheritDoc + */ + public void setReconfigure(boolean reconfigure) {// This implementation doesn't do configuration so ignores this operation. + } + + /** + * @inheritDoc + */ + public boolean isReconfigure() { + return false; + } + + /** + * {@inheritDoc} + */ + public ConfigParams load() throws ConfiguratorException { + return load(configFile); + } + + /** + * Retrieves the persisted parameters associated with this configuration + * from the standard location. + * + * @param loadFile The location from which the configuration data should be + * loaded. + * @return The configuration parameters. + * @throws ConfiguratorException If there was a failure in retrieving the + * persisted parameters. This is normally a chained exception to the + * underlying cause. + * @deprecated Loading of existing configuration is best accomplished by use + * of specific constructors of the implementing configurator. This method + * complicates the state management of configuration parameters and may have + * unpredictable results depending upon the constructor and configuration + * set methods used prior to it's execution. + */ + @Deprecated + protected PlatformConfig load(URI loadFile) throws ConfiguratorException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reading Platform Config from : " + loadFile); + } + + InputStream advStream = null; + + try { + advStream = loadFile.toURL().openStream(); + + XMLDocument xmlDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, advStream); + PlatformConfig result = (PlatformConfig) AdvertisementFactory.newAdvertisement(xmlDoc); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Recovered Platform Config from : " + loadFile); + } + + return result; + } catch (FileNotFoundException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Platform Config not found : " + loadFile); + } + + return null; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to Recover \'" + loadFile + "\' due to : ", e); + } + + throw new ConfiguratorException("Failed to recover PlatformConfig", e); + } finally { + try { + if (advStream != null) { + advStream.close(); + } + advStream = null; + } catch (Exception ignored) {// ignored + } + } + } + + /** + * {@inheritDoc} + */ + public boolean save() throws ConfiguratorException { + return save(configFile); + } + + /** + * Persist the parameters associated with this configuration to the + * specified location. + * + * @param saveFile The location to which the configuration should be saved. + * @return true if the configuration was successfully saved + * otherwise false. If the parameters are not persisted then + * false/code> is returned. + * @throws ConfiguratorException If there was a failure in persisting the + * parameters. This is normally a chained exception to the underlying + * cause. + */ + protected boolean save(URI saveFile) throws ConfiguratorException { + + // Save the adv as input for future reconfiguration + OutputStream out = null; + + try { + XMLDocument aDoc = (XMLDocument) advertisement.getDocument(MimeMediaType.XMLUTF8); + + if ("file".equalsIgnoreCase(saveFile.getScheme())) { + out = new FileOutputStream(new File(saveFile)); + } else { + out = saveFile.toURL().openConnection().getOutputStream(); + } + + OutputStreamWriter os = new OutputStreamWriter(out, "UTF-8"); + + aDoc.sendToWriter(os); + os.flush(); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not save to : " + saveFile, e); + } + + throw new ConfiguratorException("Could not save to : " + saveFile, e); + } finally { + try { + if (null != out) { + out.close(); + } + } catch (Exception ignored) {// ignored + } + out = null; + } + return true; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/PeerGroupInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/PeerGroupInterface.java new file mode 100644 index 000000000..08b83b46c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/PeerGroupInterface.java @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import net.jxta.access.AccessService; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.Element; +import net.jxta.endpoint.EndpointService; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ProtocolNotSupportedException; +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peer.PeerInfoService; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.PipeService; +import net.jxta.platform.JxtaLoader; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.resolver.ResolverService; +import net.jxta.service.Service; +import java.util.logging.Logger; + +import java.io.IOException; +import java.net.URI; +import java.util.Iterator; + +/** + * PeerGroupInterface provides a pure interface object that permits interaction + * with the actual PeerGroup implementation without giving access to the real + * object. + *

            + * This class defines immutable objects. It has no control over the wrapped + * peer group object's life cycle. It serves to make weak PeerGroup interface + * object. + */ +class PeerGroupInterface implements PeerGroup { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(PeerGroupInterface.class.getName()); + + /** + * The peer group instance which backs this interface object. + */ + protected PeerGroup groupImpl; + + /** + * Constructs an interface object that front-ends a given GenericPeerGroup. + * @param theRealThing the real PeerGroup + */ + PeerGroupInterface(PeerGroup theRealThing) { + groupImpl = theRealThing; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object target) { + PeerGroup temp = groupImpl; + + if (null != temp) { + return temp.equals(target); + } else { + return super.equals(target); + } + } + + /** + * {@inheritDoc} + *

            + * An implementation suitable for debugging. Don't try to parse + * this string! All of the information is available from other sources. + */ + @Override + public String toString() { + PeerGroup temp = groupImpl; + + if (null != temp) { + return temp.toString(); + } else { + return super.toString(); + } + } + + /** + * {@inheritDoc} + *

            + * This is here for class hierarchy reasons. It is normaly ignored. By + * definition, the interface object protects the real object's start/stop + * methods from being called. + */ + + public void init(PeerGroup pg, ID assignedID, Advertisement impl) {} + + /** + * {@inheritDoc} + *

            + * This is here for class hierarchy reasons. It is normaly ignored. By + * definition, the interface object protects the real object's start/stop + * methods from being called. + */ + public int startApp(String[] arg) { + return 0; + } + + /** + * {@inheritDoc} + *

            + * This is here for class hierarchy reasons. It is normaly ignored. By + * definition, the interface object protects the real object's start/stop + * methods from being called. + */ + public void stopApp() {} + + /** + * {@inheritDoc} + */ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public PeerGroup getWeakInterface() { + return this; + } + + /** + * {@inheritDoc} + *

            + * Does nothing. + */ + public void unref() {} + + /** + * {@inheritDoc} + */ + public Advertisement getImplAdvertisement() { + return groupImpl.getImplAdvertisement(); + } + + /** + * {@inheritDoc} + */ + public ThreadGroup getHomeThreadGroup() { + return groupImpl.getHomeThreadGroup(); + } + + /** + * {@inheritDoc} + */ + public URI getStoreHome() { + return groupImpl.getStoreHome(); + } + + /** + * {@inheritDoc} + */ + public JxtaLoader getLoader() { + return groupImpl.getLoader(); + } + + /** + * {@inheritDoc} + */ + public boolean isRendezvous() { + return groupImpl.isRendezvous(); + } + + /** + * {@inheritDoc} + */ + public PeerGroupAdvertisement getPeerGroupAdvertisement() { + return groupImpl.getPeerGroupAdvertisement(); + } + + /** + * {@inheritDoc} + */ + public PeerAdvertisement getPeerAdvertisement() { + return groupImpl.getPeerAdvertisement(); + } + + /** + * {@inheritDoc} + */ + public Service lookupService(ID name) throws ServiceNotFoundException { + return groupImpl.lookupService(name); + } + + /** + * {@inheritDoc} + */ + public Service lookupService(ID name, int roleIndex) throws ServiceNotFoundException { + return groupImpl.lookupService(name, roleIndex); + } + + /** + * {@inheritDoc} + */ + public Iterator getRoleMap(ID name) { + return groupImpl.getRoleMap(name); + } + + /** + * {@inheritDoc} + */ + public boolean compatible(Element compat) { + return groupImpl.compatible(compat); + } + + /** + * {@inheritDoc} + *

            + * FIXME 20031103 jice Ideally, we'd need the groupAPI to offer a means to + * loadModule() without making a counted reference, so that group services + * can loadModule() things without preventing group termination. This could + * be achieved elegantly by making this the only behaviour available through + * a weak GroupInterface. So it would be enough to obtain a weak interface + * from one's group and then use its loadmodule method rather than that of + * the strong group reference. However, that's a bit too big a change to be + * decided without more careful consideration. + */ + public Module loadModule(ID assignedID, Advertisement impl) throws ProtocolNotSupportedException, PeerGroupException { + return groupImpl.loadModule(assignedID, impl); + } + + /** + * {@inheritDoc} + */ + public Module loadModule(ID assignedID, ModuleSpecID specID, int where) { + return groupImpl.loadModule(assignedID, specID, where); + } + + /** + * {@inheritDoc} + */ + public void publishGroup(String name, String description) throws IOException { + groupImpl.publishGroup(name, description); + } + + /* + * Valuable application helpers: Various methods to instantiate groups. + */ + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(Advertisement pgAdv) throws PeerGroupException { + return groupImpl.newGroup(pgAdv); + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(PeerGroupID gid, Advertisement impl, String name, String description) throws PeerGroupException { + return groupImpl.newGroup(gid, impl, name, description); + } + + /** + * {@inheritDoc} + */ + public PeerGroup newGroup(PeerGroupID gid) throws PeerGroupException { + return groupImpl.newGroup(gid); + } + + /* + * shortcuts to the well-known services, in order to avoid calls to lookup. + */ + + /** + * {@inheritDoc} + */ + public RendezVousService getRendezVousService() { + return groupImpl.getRendezVousService(); + } + + /** + * {@inheritDoc} + */ + public EndpointService getEndpointService() { + return groupImpl.getEndpointService(); + } + + /** + * {@inheritDoc} + */ + public ResolverService getResolverService() { + return groupImpl.getResolverService(); + } + + /** + * {@inheritDoc} + */ + public DiscoveryService getDiscoveryService() { + return groupImpl.getDiscoveryService(); + } + + /** + * {@inheritDoc} + */ + public PeerInfoService getPeerInfoService() { + return groupImpl.getPeerInfoService(); + } + + /** + * {@inheritDoc} + */ + public MembershipService getMembershipService() { + return groupImpl.getMembershipService(); + } + + /** + * {@inheritDoc} + */ + public PipeService getPipeService() { + return groupImpl.getPipeService(); + } + + /** + * {@inheritDoc} + */ + public AccessService getAccessService() { + return groupImpl.getAccessService(); + } + + /* + * A few convenience methods. This information is available from + * the peer and peergroup advertisement. + */ + + /** + * {@inheritDoc} + */ + public PeerGroupID getPeerGroupID() { + return groupImpl.getPeerGroupID(); + } + + /** + * {@inheritDoc} + */ + public PeerID getPeerID() { + return groupImpl.getPeerID(); + } + + /** + * {@inheritDoc} + */ + public String getPeerGroupName() { + return groupImpl.getPeerGroupName(); + } + + /** + * {@inheritDoc} + */ + public String getPeerName() { + return groupImpl.getPeerName(); + } + + /** + * {@inheritDoc} + */ + public ConfigParams getConfigAdvertisement() { + ConfigParams configAdvertisement = groupImpl.getConfigAdvertisement(); + + if (configAdvertisement == null) { + return null; + } + return configAdvertisement.clone(); + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() throws Exception { + return groupImpl.getAllPurposePeerGroupImplAdvertisement(); + } + + public PeerGroup getParentGroup() { + return groupImpl.getParentGroup(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/Platform.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/Platform.java new file mode 100644 index 000000000..b35dacbf9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/Platform.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.exception.JxtaError; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.JxtaLoader; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; + +import net.jxta.impl.endpoint.cbjx.CbJxDefs; +import net.jxta.impl.endpoint.mcast.McastTransport; +import net.jxta.impl.membership.pse.PSEMembershipService; +import net.jxta.service.Service; + +/** + * Provides the implementation for the World PeerGroup. The World peer group + * differs from other peer groups in the following ways : + *

              + *
            • The World Peer Group has no parent. It is the primordial peer group. + *
            • + *
            • The World Peer Group provides the default definition for the Network + * Peer Group. Peers are free to use alternate implementations for the + * Network PeerGroup.
            • + *
            • The World Peer Group is initialized with configuration parameters and + * the store home location.
            • + *
            + */ +public class Platform extends StdPeerGroup { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(Platform.class.getName()); + + /** + * Create and populate the default module impl Advertisement for this class. + * + * @return The default module impl advertisement for this class. + */ + public static ModuleImplAdvertisement getDefaultModuleImplAdvertisement() { + ModuleImplAdvertisement implAdv = mkImplAdvBuiltin(PeerGroup.refPlatformSpecID, Platform.class.getName(), "Standard World PeerGroup Reference Implementation"); + + // Build the param section now. + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(); + + // Do the Services + + // "Core" Services + paramAdv.addService(PeerGroup.endpointClassID, PeerGroup.refEndpointSpecID); + paramAdv.addService(PeerGroup.resolverClassID, PeerGroup.refResolverSpecID); + paramAdv.addService(PeerGroup.membershipClassID, PeerGroup.refMembershipSpecID); + paramAdv.addService(PeerGroup.accessClassID, PeerGroup.refAccessSpecID); + + // "Standard" Services + + paramAdv.addService(PeerGroup.discoveryClassID, PeerGroup.refDiscoverySpecID); + paramAdv.addService(PeerGroup.rendezvousClassID, PeerGroup.refRendezvousSpecID); + paramAdv.addService(PeerGroup.peerinfoClassID, PeerGroup.refPeerinfoSpecID); + + // Do the Message Transports + + paramAdv.addProto(PeerGroup.tcpProtoClassID, PeerGroup.refTcpProtoSpecID); + paramAdv.addProto(PeerGroup.httpProtoClassID, PeerGroup.refHttpProtoSpecID); + paramAdv.addProto(McastTransport.MCAST_TRANSPORT_CLASSID, McastTransport.MCAST_TRANSPORT_SPECID); + + // Do the Applications + + // (none) + + // Insert the paramAdv in the World PeerGroup Impl Advertisement. + implAdv.setParam((XMLDocument) paramAdv.getDocument(MimeMediaType.XMLUTF8)); + + return implAdv; + } + + /** + * This constructor was originally the standard constructor and must be + * retained in case the World PeerGroup is accidentally instantiated via + * the module loading infrastructure. + * + * @throws PeerGroupException if an initialization error occurs + */ + public Platform() throws PeerGroupException { + throw new JxtaError("Zero params constructor is no longer supported for World PeerGroup class."); + } + + /** + * Default constructor + * + * @param config The configuration. + * @param storeHome Persistent store home. + */ + public Platform(ConfigParams config, URI storeHome) { + // initialize the store location. + setStoreHome(storeHome); + + // initialize the configuration advertisement. + setConfigAdvertisement(config); + } + + /** + * {@inheritDoc} + */ + @Override + protected synchronized void initFirst(PeerGroup nullParent, ID assignedID, Advertisement impl) throws PeerGroupException { + if (initComplete) { + LOG.severe("You cannot initialize more than one World PeerGroup!"); + throw new PeerGroupException("You cannot initialize more than one World PeerGroup!"); + } + + if (nullParent != null) { + LOG.severe("World PeerGroup cannot be instantiated with a parent group!"); + throw new PeerGroupException("World PeerGroup cannot be instantiated with a parent group!"); + } + + ModuleImplAdvertisement implAdv = (ModuleImplAdvertisement) impl; + + if(null == implAdv) { + implAdv = getJxtaLoader().findModuleImplAdvertisement(getClass()); + } + + if (null != jxtaHome) { + try { + URL downloadablesURL = jxtaHome.resolve("Downloaded/").toURL(); + + getJxtaLoader().addURL(downloadablesURL); + } catch (MalformedURLException badPath) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not install path for downloadables into JXTA Class Loader."); + } + } + } + + // Initialize the group. + super.initFirst(null, PeerGroupID.worldPeerGroupID, implAdv); + } + + /** + * {@inheritDoc} + */ + @Override + protected synchronized void initLast() throws PeerGroupException { + super.initLast(); + + // Publish our own adv. + try { + publishGroup("World PeerGroup", "Standard World PeerGroup Reference Implementation"); + } catch (IOException e) { + throw new PeerGroupException("Failed to publish World PeerGroup Advertisement", e); + } + } + + /** + * Returns a ModuleImplAdvertisement suitable for the Network Peer Group. + *

            + * The ModuleImplAdvertisement returned differs from the one returned by + * StdPeerGroup in that it has a different specID, name and description, as + * well as the high-level message transports . This definition is always the + * same and has a well known ModuleSpecID. It includes the basic services, + * high-level message transports and the shell for main application. + * + * @return A ModuleImplAdvertisement suitable for the Network Peer Group. + */ + @Override + public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() { + JxtaLoader loader = getJxtaLoader(); + + // For now, use the well know NPG naming, it is not identical to the + // allPurpose PG because we use the class ShadowPeerGroup which + // initializes the peer config from its parent. + ModuleImplAdvertisement implAdv = loader.findModuleImplAdvertisement(PeerGroup.refNetPeerGroupSpecID); + + return implAdv; + } + + /** + * {@inheritDoc} + */ + @Override + protected void checkServices() throws ServiceNotFoundException { + super.checkServices(); + Service ignored; + ignored = lookupService(discoveryClassID); + ignored = lookupService(rendezvousClassID); + ignored = lookupService(peerinfoClassID); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/PlatformConfigurator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/PlatformConfigurator.java new file mode 100644 index 000000000..ad4a684a8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/PlatformConfigurator.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + + +import net.jxta.exception.ConfiguratorException; +import net.jxta.impl.protocol.PlatformConfig; +import net.jxta.peergroup.Configurator; + + +/** + * Defines a configurator for the JXTA Platform peer group. + * + * @deprecated This interface has been replaced with the {@link net.jxta.platform.NetworkConfigurator}. + */ +@Deprecated +public interface PlatformConfigurator extends Configurator { + + /** + * Retrieve the associated {@link net.jxta.impl.protocol.PlatformConfig} and + * potentially performing any required configuration of the parameters + * before returning. + * + * @return PlatformConfig + * @throws net.jxta.exception.ConfiguratorException If configuration error + * occurs. + */ + public PlatformConfig getPlatformConfig() throws ConfiguratorException; + + /** + * Sets the associated {@link net.jxta.impl.protocol.PlatformConfig}. + * + * @param pc the configuration + */ + public void setPlatformConfig(PlatformConfig pc); + + /** + * Sets the reconfiguration status to the specified status. If + * {@code true} then reconfiguration will be forced the next time the + * {@link net.jxta.impl.protocol.PlatformConfig} is retrieved. + * + * @param forceReconfig If {@code true} then a forced reconfiguration will + * occur the next time {@link #getPlatformConfig()} is called. + */ + public void setReconfigure(boolean forceReconfig); + + /** + * Determine if a forced reconfiguration is set for the next call to + * {@link #getPlatformConfig()}. + * + * @return Returns {@code true} if a forced reconfiguration will occur the + * next time {@link #getPlatformConfig()} is called. + */ + public boolean isReconfigure(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/RefCountPeerGroupInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/RefCountPeerGroupInterface.java new file mode 100644 index 000000000..f7deb2260 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/RefCountPeerGroupInterface.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.service.Service; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; + +/** + * RefCountPeerGroupInterface is a PeerGroupInterface object that + * also serves as a peergroup very-strong reference. When the last + * such goes away, the peergroup terminates itself despite the existence + * of aeternal strong references from the various service's threads + * that would prevent it from ever being finalized. + * The alternative: to give only weak references to threads seems impractical. + */ +class RefCountPeerGroupInterface extends PeerGroupInterface { + + private Map roleMap; + + /** + * Constructs an interface object that front-ends a given + * PeerGroup object. + * + * @param theRealThing the peer group + */ + RefCountPeerGroupInterface(GenericPeerGroup theRealThing) { + super(theRealThing); + } + + RefCountPeerGroupInterface(GenericPeerGroup theRealThing, Map roleMap) { + super(theRealThing); + this.roleMap = roleMap; + } + + /** + * {@inheritDoc} + *

            + * Normally it is ignored. By definition, the interface object + * protects the real object's start/stop methods from being called. + *

            + * However we have to make an exception for groups: even the creator + * of a group does not have access to the real object. So the interface + * has to forward startApp to the group, which is responsible for + * ensuring that it is executed only once (if needed). + * + * @param arg A table of strings arguments. + * @return int status indication. + */ + @Override + public int startApp(String[] arg) { + // Unlike our superclass's method, we do call the real + // startApp method. + PeerGroup temp = groupImpl; + + if (null == temp) { + throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used."); + } + + return temp.startApp(arg); + } + + /** + * {@inheritDoc} + *

            + * This is here for temporary class hierarchy reasons. + * it is normally ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + *

            + * In that case we have to make an exception. Most applications + * currently assume that they do not share the group object and that they do + * refer to the real object directly. They call stopApp to signify their + * intention of no-longer using the group. Now that groups are shared, + * we convert stopApp() to unref() for compatibility. + * We could also just do nothing and let the interface be GC'd but + * calling unref() makes the group go away immediately if not shared, + * which is what applications that call stopApp expect. + */ + @Override + public void stopApp() { + unref(); + } + + /** + * {@inheritDoc} + *

            + * Since THIS is already such an object, it could return itself. + * However, we want the group to know about the number of interfaces + * objects floating around, so, we'll have the group make a new one. + * That way, applications which want to use unref() on interfaces can + * avoid sharing interface objects by using getInterface() as a sort of + * clone with the additional ref-counting semantics. + * + * @return Service An interface object that implements + * this service and nothing more. + */ + @Override + public Service getInterface() { + PeerGroup temp = groupImpl; + if (null == temp) { + throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used."); + } + return temp.getInterface(); + } + + /** + * {@inheritDoc} + *

            + * Returns a weak interface object that refers to this interface + * object rather than to the group directly. The reason for that + * is that we want the owner of this interface object to be able + * to invalidate all weak interface objects made out of this interface + * object, without them keeping a reference to the group object, and + * without necessarily having to terminate the group. + * + * @return PeerGroup A weak interface object that implements + * this group and nothing more. + */ + + @Override + public PeerGroup getWeakInterface() { + return new PeerGroupInterface(this); + } + + /** + * Can only be called once. After that the reference is no-longer usuable. + */ + @Override + public void unref() { + GenericPeerGroup theGrp; + + synchronized (this) { + if (groupImpl == null) { + return; + } + + theGrp = (GenericPeerGroup) groupImpl; + groupImpl = null; + } + theGrp.decRefCount(); + } + + /** + * Service-specific role mapping is implemented here. + **/ + + /** + * {@inheritDoc} + */ + @Override + public Service lookupService(ID name) throws ServiceNotFoundException { + + return lookupService(name, 0); + } + + /** + * {@inheritDoc} + */ + @Override + public Service lookupService(ID name, int roleIndex) throws ServiceNotFoundException { + + if (roleMap != null) { + ID[] map = (ID[]) roleMap.get(name); + + // If there is a map, remap; else, identity is the default for + // role 0 only; the default mapping has only index 0. + + if (map != null) { + if (roleIndex < 0 || roleIndex >= map.length) { + throw new ServiceNotFoundException(name + "[" + roleIndex + "]"); + } + + // We have a translation; look it up directly + return groupImpl.lookupService(map[roleIndex]); + } + } + + // No translation; use the name as-is, provided roleIndex is 0. + // Do not call groupImpl.lookupService(name, id); group impls + // should not have to implement it at all. + + if (roleIndex != 0) { + throw new ServiceNotFoundException(name + "[" + roleIndex + "]"); + } + return groupImpl.lookupService(name); + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getRoleMap(ID name) { + + if (roleMap != null) { + ID[] map = (ID[]) roleMap.get(name); + + // If there is a map, remap; else, identity is the default for + // role 0 only; the default mapping has only index 0. + + if (map != null) { + // return an iterator on it. + return Collections.unmodifiableList(Arrays.asList(map)).iterator(); + } + } + // No translation; use the given name in a singleton. + return Collections.singletonList(name).iterator(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/ShadowPeerGroup.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/ShadowPeerGroup.java new file mode 100644 index 000000000..7d6adfee7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/ShadowPeerGroup.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import net.jxta.document.Advertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.exception.PeerGroupException; +import net.jxta.impl.endpoint.cbjx.CbJxDefs; +import net.jxta.impl.membership.pse.PSEMembershipService; +import net.jxta.platform.Application; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; + +/** + * ShadowPeerGroup is almost a regular StdPeerGroup, except that it borrows its + * parent's configuration. The only real use is for the Net Peer Group. + */ +public class ShadowPeerGroup extends StdPeerGroup { + + /** + * Our application is the JXSE Shell. + */ + private Application shell = null; + + /** + * Create and populate the default module impl Advertisement for this class. + * + * @return The default module impl advertisement for this class. + */ + public static ModuleImplAdvertisement getDefaultModuleImplAdvertisement() { + ModuleImplAdvertisement implAdv = mkImplAdvBuiltin(PeerGroup.refNetPeerGroupSpecID, ShadowPeerGroup.class.getName(), "Default Network PeerGroup reference implementation"); + + // Build the param section now. + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(); + + // Set the services + // "Core" Services + paramAdv.addService(PeerGroup.endpointClassID, PeerGroup.refEndpointSpecID); + paramAdv.addService(PeerGroup.resolverClassID, PeerGroup.refResolverSpecID); + paramAdv.addService(PeerGroup.membershipClassID, PSEMembershipService.pseMembershipSpecID); + paramAdv.addService(PeerGroup.accessClassID, PeerGroup.refAccessSpecID); + + // "Standard" Services + paramAdv.addService(PeerGroup.discoveryClassID, PeerGroup.refDiscoverySpecID); + paramAdv.addService(PeerGroup.rendezvousClassID, PeerGroup.refRendezvousSpecID); + paramAdv.addService(PeerGroup.pipeClassID, PeerGroup.refPipeSpecID); + paramAdv.addService(PeerGroup.peerinfoClassID, PeerGroup.refPeerinfoSpecID); + paramAdv.addService(PeerGroup.proxyClassID, PeerGroup.refProxySpecID); + + // High-level Message Transports. + paramAdv.addProto(PeerGroup.routerProtoClassID, PeerGroup.refRouterProtoSpecID); + paramAdv.addProto(PeerGroup.tlsProtoClassID, PeerGroup.refTlsProtoSpecID); + paramAdv.addProto(CbJxDefs.msgtptClassID, CbJxDefs.cbjxMsgTransportSpecID); + paramAdv.addProto(PeerGroup.relayProtoClassID, PeerGroup.refRelayProtoSpecID); + + // Pour our newParamAdv in implAdv + XMLElement paramElement = (XMLElement) paramAdv.getDocument(MimeMediaType.XMLUTF8); + + implAdv.setParam(paramElement); + + return implAdv; + } + + /** + * {@inheritDoc} + * + *

            This implementation initializes the configuration advertisement with + * that of the parent group and otherwise behave exactly like its superclass. + */ + @Override + protected void initFirst(PeerGroup parent, ID assignedID, Advertisement impl) throws PeerGroupException { + + // Set the peer configuration before we start. + setConfigAdvertisement(parent.getConfigAdvertisement()); + + // Do the regular stuff now. + super.initFirst(parent, assignedID, impl); + } + + /** + * {@inheritDoc} + */ + @Override + protected void initLast() throws PeerGroupException { + // Nothing special, but that could change in the future + // Just remember that the possibility exists. + super.initLast(); + } + + /** + * {@inheritDoc} + *

            + * If it is available, start the shell. + */ + @Override + public int startApp(String[] args) { + int result = super.startApp(args); + + if (Module.START_OK != result) { + return result; + } + + // Main app is the shell (if it is available). + if (null != getLoader().findModuleImplAdvertisement(PeerGroup.refShellSpecID)) { + shell = (Application) loadModule(PeerGroup.applicationClassID, PeerGroup.refShellSpecID, PeerGroup.Both); + + if (null == shell) { + return -1; + } + + result = shell.startApp(new String[0]); + } + + return result; + } + + /** + * {@inheritDoc} + *

            If we started the shell we now must stop it. + */ + @Override + public void stopApp() { + if (null != shell) { + shell.stopApp(); + shell = null; + } + + super.stopApp(); + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/StdPeerGroup.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/StdPeerGroup.java new file mode 100644 index 000000000..f41793501 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/StdPeerGroup.java @@ -0,0 +1,986 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.peergroup; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URL; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.MessageTransport; +import net.jxta.exception.PeerGroupException; +import net.jxta.exception.ServiceNotFoundException; +import net.jxta.id.ID; +import net.jxta.impl.cm.Cm; +import net.jxta.impl.cm.SrdiIndex; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.JxtaLoader; +import net.jxta.platform.Module; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.service.Service; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.document.TextElement; + +/** + * A subclass of GenericPeerGroup that makes a peer group out of independent + * plugin services listed in its impl advertisement. + */ +public class StdPeerGroup extends GenericPeerGroup { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(StdPeerGroup.class.getName()); + + // A few things common to all ImplAdv for built-in things. + public static final XMLDocument STD_COMPAT = mkCS(); + public static final String MODULE_IMPL_STD_URI = "http://jxta-jxse.dev.java.net/download/jxta.jar"; + public static final String MODULE_IMPL_STD_PROVIDER = "sun.com"; + + protected static final String STD_COMPAT_FORMAT = "Efmt"; + + // FIXME 20061206 bondolo Update this to "JRE1.5" after 2.5 release. 2.4.1 and earlier don't do version comparison correctly. + + /** + * The Specification title and Specification version we require. + */ + protected static final String STD_COMPAT_FORMAT_VALUE = "JDK1.4.1"; + protected static final String STD_COMPAT_BINDING = "Bind"; + protected static final String STD_COMPAT_BINDING_VALUE = "V2.0 Ref Impl"; + + static { + // Initialize the JXTA class loader with the standard modules. + try { + Enumeration allProviderLists = GenericPeerGroup.class.getClassLoader().getResources("META-INF/services/net.jxta.platform.Module"); + for (URL providers : Collections.list(allProviderLists)) { + registerFromFile(providers); + } + } catch (IOException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to locate provider lists", ex); + } + } + + // XXX Force redefinition of StdPeerGroup implAdvertisement. + getJxtaLoader().defineClass(getDefaultModuleImplAdvertisement()); + } + + /** + * Register instance classes given a URL to a file containing modules which + * must be found on the current class path. Each line of the file contains a + * module spec ID, the class name and the Module description. The fields are + * separated by whitespace. Comments are marked with a '#', the pound sign. + * Any text following # on any line in the file is ignored. + * + * @param providerList the URL to a file containing a list of modules + * @return {@code true} if at least one of the instance classes could be + * registered otherwise {@code false}. + */ + private static boolean registerFromFile(URL providers) { + boolean registeredSomething = false; + InputStream urlStream = null; + + try { + urlStream = providers.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(urlStream, "UTF-8")); + + String provider; + while ((provider = reader.readLine()) != null) { + int comment = provider.indexOf('#'); + + if (comment != -1) { + provider = provider.substring(0, comment); + } + + provider = provider.trim(); + + if (0 == provider.length()) { + continue; + } + + try { + String[] parts = provider.split("\\s", 3); + + if (3 == parts.length) { + ModuleSpecID msid = ModuleSpecID.create(URI.create(parts[0])); + String code = parts[1]; + String description = parts[2]; + + ModuleImplAdvertisement moduleImplAdv; + + try { + Class moduleClass = (Class) Class.forName(code); + + Method getImplAdvMethod = moduleClass.getMethod("getDefaultModuleImplAdvertisement"); + + moduleImplAdv = (ModuleImplAdvertisement) getImplAdvMethod.invoke(null); + } catch(Exception failed) { + // Use default ModuleImplAdvertisement. + moduleImplAdv = StdPeerGroup.mkImplAdvBuiltin(msid, code, description); + } + + getJxtaLoader().defineClass(moduleImplAdv); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Registered Module " + msid + " : " + parts[1]); + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to register \'" + provider + "\'"); + } + } + } catch (Exception allElse) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to register \'" + provider + "\'", allElse); + } + } + } + } catch (IOException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to read provider list " + providers, ex); + } + } finally { + if (null != urlStream) { + try { + urlStream.close(); + } catch (IOException ignored) { + + } + } + } + return registeredSomething; + } + + /** + * If {@code true} then the PeerGroup has been started. + */ + private volatile boolean started = false; + + /** + * The order in which we started the services. + */ + private final List moduleStartOrder = new ArrayList(); + + /** + * A map of the Message Transports for this group. + *

            + *

              + *
            • keys are {@link net.jxta.platform.ModuleClassID}
            • + *
            • values are {@link net.jxta.platform.Module}, but should also be + * {@link net.jxta.endpoint.MessageTransport}
            • + *
            + */ + private final Map messageTransports = new HashMap(); + + /** + * A map of the applications for this group. + *

            + *

              + *
            • keys are {@link net.jxta.platform.ModuleClassID}
            • + *
            • values are {@link net.jxta.platform.Module} or + * {@link net.jxta.protocol.ModuleImplAdvertisement} or + * {@link net.jxta.platform.ModuleSpecID}
            • + *
            + */ + private final Map applications = new HashMap(); + + /** + * Cache for this group. + */ + private Cm cm = null; + + private static XMLDocument mkCS() { + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Comp"); + + XMLElement e = doc.createElement(STD_COMPAT_FORMAT, STD_COMPAT_FORMAT_VALUE); + + doc.appendChild(e); + + e = doc.createElement(STD_COMPAT_BINDING, STD_COMPAT_BINDING_VALUE); + doc.appendChild(e); + return doc; + } + + /** + * An internal convenience method essentially for bootstrapping. + * Make a standard ModuleImplAdv for any service that comes builtin this + * reference implementation. + * In most cases there are no params, so we do not take that argument. + * The invoker may add params afterwards. + * + * @param specID spec ID + * @param code code uri + * @param descr description + * @return a ModuleImplAdvertisement + */ + static ModuleImplAdvertisement mkImplAdvBuiltin(ModuleSpecID specID, String code, String descr) { + ModuleImplAdvertisement implAdv = (ModuleImplAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType()); + + implAdv.setModuleSpecID(specID); + implAdv.setCompat(STD_COMPAT); + implAdv.setCode(code); + implAdv.setUri(MODULE_IMPL_STD_URI); + implAdv.setProvider(MODULE_IMPL_STD_PROVIDER); + implAdv.setDescription(descr); + + return implAdv; + } + + /** + * Create and populate the default module impl Advertisement for this class. + * + * @return The default module impl advertisement for this class. + */ + private static ModuleImplAdvertisement getDefaultModuleImplAdvertisement() { + ModuleImplAdvertisement implAdv = mkImplAdvBuiltin(PeerGroup.allPurposePeerGroupSpecID, StdPeerGroup.class.getName(), "General Purpose Peer Group Implementation"); + + // Create the service list for the group. + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(); + ModuleImplAdvertisement moduleAdv; + + // set the services + + // core services + JxtaLoader loader = getJxtaLoader(); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refEndpointSpecID); + paramAdv.addService(PeerGroup.endpointClassID, moduleAdv); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refResolverSpecID); + paramAdv.addService(PeerGroup.resolverClassID, moduleAdv); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refMembershipSpecID); + paramAdv.addService(PeerGroup.membershipClassID, moduleAdv); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refAccessSpecID); + paramAdv.addService(PeerGroup.accessClassID, moduleAdv); + + // standard services + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refDiscoverySpecID); + paramAdv.addService(PeerGroup.discoveryClassID, moduleAdv); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refRendezvousSpecID); + paramAdv.addService(PeerGroup.rendezvousClassID, moduleAdv); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refPipeSpecID); + paramAdv.addService(PeerGroup.pipeClassID, moduleAdv); + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refPeerinfoSpecID); + paramAdv.addService(PeerGroup.peerinfoClassID, moduleAdv); + + // Applications + + moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refShellSpecID); + if (null != moduleAdv) { + paramAdv.addApp(PeerGroup.applicationClassID, moduleAdv); + } + + // Insert the newParamAdv in implAdv + XMLElement paramElement = (XMLElement) paramAdv.getDocument(MimeMediaType.XMLUTF8); + + implAdv.setParam(paramElement); + + return implAdv; + } + + /** + * constructor + */ + public StdPeerGroup() { + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean compatible(Element compat) { + return isCompatible(compat); + } + + /** + * Evaluates if the given compatibility statement makes the module that + * bears it is loadable by this group. + * + * @param compat The compatibility statement being tested. + * @return {@code true} if we are compatible with the provided statement + * otherwise {@code false}. + */ + static boolean isCompatible(Element compat) { + boolean formatOk = false; + boolean bindingOk = false; + + if(!(compat instanceof TextElement)) { + return false; + } + + try { + Enumeration hisChildren = ((TextElement)compat).getChildren(); + int i = 0; + while (hisChildren.hasMoreElements()) { + // Stop after 2 elements; there shall not be more. + if (++i > 2) { + return false; + } + + TextElement e = hisChildren.nextElement(); + String key = e.getKey(); + String val = e.getValue().trim(); + + if (STD_COMPAT_FORMAT.equals(key)) { + Package javaLangPackage = Package.getPackage("java.lang"); + + boolean specMatches; + String version; + + if (val.startsWith("JDK") || val.startsWith("JRE")) { + specMatches = true; + version = val.substring(3).trim(); // allow for spaces. + } else if (val.startsWith(javaLangPackage.getSpecificationTitle())) { + specMatches = true; + version = val.substring(javaLangPackage.getSpecificationTitle().length()).trim(); // allow for spaces. + } else { + specMatches = false; + version = null; + } + + formatOk = specMatches && javaLangPackage.isCompatibleWith(version); + } else if (STD_COMPAT_BINDING.equals(key) && STD_COMPAT_BINDING_VALUE.equals(val)) { + bindingOk = true; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Bad element in compatibility statement : " + key); + } + return false; // Might as well stop right now. + } + } + } catch (Exception any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure handling compatibility statement", any); + } + return false; + } + + return formatOk && bindingOk; + } + + /** + * Builds a table of modules indexed by their class ID. + * The values are the loaded modules, the keys are their classId. + * This routine interprets the parameter list in the advertisement. + * + * @param modules The modules to load + * @param privileged if true then modules will get a real reference to + * the group loading them, otherwise its an interface object. + */ + protected void loadAllModules(Map modules, boolean privileged) { + + Iterator> eachModule = modules.entrySet().iterator(); + + while (eachModule.hasNext()) { + Map.Entry anEntry = eachModule.next(); + ModuleClassID classID = anEntry.getKey(); + Object value = anEntry.getValue(); + + // Already loaded. + if (value instanceof Module) { + continue; + } + + // Try and load it. + try { + Module theModule = null; + + if (value instanceof ModuleImplAdvertisement) { + // Load module will republish locally but not in the + // parent since that adv does not come from there. + theModule = loadModule(classID, (ModuleImplAdvertisement) value, privileged); + } else if (value instanceof ModuleSpecID) { + // loadModule will republish both locally and in the parent + // Where the module was fetched. + theModule = loadModule(classID, (ModuleSpecID) value, FromParent, privileged); + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Skipping: " + classID + " Unsupported module descriptor : " + value.getClass().getName()); + } + eachModule.remove(); + continue; + } + + if (theModule == null) { + throw new PeerGroupException("Could not find a loadable implementation for : " + classID); + } + + anEntry.setValue(theModule); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not load module for class ID : " + classID, e); + if (value instanceof ModuleImplAdvertisement) { + LOG.log(Level.WARNING, "Will be missing from peer group : " + + ((ModuleImplAdvertisement) value).getDescription()); + } else { + LOG.log(Level.WARNING, "Will be missing from peer group: " + value); + } + } + eachModule.remove(); + } + } + } + + /** + * The group does not care for start args, and does not come-up + * with args to pass to its main app. So, until we decide on something + * more useful, the args of the group's startApp are passed-on to the + * group's main app. NB: both the apps init and startApp methods are + * invoked. + * + * @return int Status. + */ + @Override + public int startApp(String[] arg) { + + if (!initComplete) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Group has not been initialized or init failed."); + } + return -1; + } + + // FIXME: maybe concurrent callers should be blocked until the + // end of startApp(). That could mean forever, though. + if (started) { + return Module.START_OK; + } + + started = true; + + // Normally does nothing, but we have to. + int res = super.startApp(arg); + + if (Module.START_OK != res) { + return res; + } + + loadAllModules(applications, false); // Apps are non-privileged; + + res = startModules((Map) applications); + + return res; + } + + /** + * {@inheritDoc} + */ + @Override + public void stopApp() { + // Shut down the group services and message transports. + Collections.reverse(moduleStartOrder); + + for (ModuleClassID aModule : moduleStartOrder) { + try { + if (messageTransports.containsKey(aModule)) { + Module theMessageTransport = (Module) messageTransports.remove(aModule); + + theMessageTransport.stopApp(); + } else { + removeService(aModule); + } + } catch (Exception any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to stop module: " + aModule, any); + } + } + } + + moduleStartOrder.clear(); + + if (!messageTransports.isEmpty()) { + LOG.warning(messageTransports.size() + " message transports could not be shut down during peer group stop."); + } + + messageTransports.clear(); + + super.stopApp(); + + if (cm != null) { + cm.stop(); + cm = null; + } + } + + /** + * Given a list of all the modules we need to start attempt to start them. + * There is an a-priori order, but we'll iterate over the list until all + * where able to complete their start phase or no progress is made. Since we + * give modules the opportunity to pretend that they are making progress, we + * need to have a safeguard: we will not iterate through the list more than + * N^2 + 1 times without at least one module completing; N being the number + * of modules still in the list. This should cover the worst case scenario + * and still allow the process to eventually fail if it has no chance of + * success. + * + * @param services The services to start. + */ + private int startModules(Map services) { + int iterations = 0; + int maxIterations = services.size() * services.size() + iterations + 1; + + boolean progress = true; + + while (!services.isEmpty() && (progress || (iterations < maxIterations))) { + progress = false; + iterations++; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Service startApp() round {0} of {1}(max)", iterations, maxIterations)); + } + + Iterator> eachService = services.entrySet().iterator(); + + while (eachService.hasNext()) { + Map.Entry anEntry = eachService.next(); + ModuleClassID mcid = anEntry.getKey(); + Module aModule = anEntry.getValue(); + + int res; + + try { + res = aModule.startApp(null); + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Exception in startApp() : " + aModule, all); + } + res = -1; + } + + switch (res) { + case Module.START_OK: + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Module started : " + aModule); + } + if (aModule instanceof Service) { + addService(mcid, (Service) aModule); + } else { + messageTransports.put(mcid, aModule); + } + + moduleStartOrder.add(mcid); + eachService.remove(); + progress = true; + break; + + case Module.START_AGAIN_PROGRESS: + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Service made progress during start : " + aModule); + } + progress = true; + break; + + case Module.START_AGAIN_STALLED: + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Service stalled during start : " + aModule); + } + break; + + case Module.START_DISABLED: + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Service declined to start : " + aModule); + } + eachService.remove(); + progress = true; + break; + + default: // (negative) + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Service failed to start (" + res + ") : " + aModule); + } + eachService.remove(); + progress = true; + break; + } + } + + if (progress) { + maxIterations = services.size() * services.size() + iterations + 1; + } + } + + // Uh-oh. Services co-dependency prevented them from starting. + if (!services.isEmpty()) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + StringBuilder failed = new StringBuilder( "No progress is being made in starting services after " + + iterations + " iterations. Giving up."); + + failed.append("\nThe following services could not be started : "); + + for (Map.Entry aService : services.entrySet()) { + failed.append("\n\t"); + failed.append(aService.getKey()); + failed.append(" : "); + failed.append(aService.getValue()); + } + + LOG.severe(failed.toString()); + } + + return -1; + } + + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

            + * This method loads and initializes all of the peer group modules + * described in the provided implementation advertisement. Then, all modules + * are placed in a list and the list is processed iteratively. During each + * iteration, the {@link Module#startApp(String[])} method of each module + * is invoked once. Iterations continue until no progress is being made or + * the list is empty. + *

            + * The status returned by the {@link Module#startApp(String[])} method + * of each module is considered as follows: + *

            + *

              + *
            • {@link Module#START_OK}: The module is removed from the list of + * modules to be started and its {@link Module#startApp(String[])} + * method will not be invoked again. + *
            • + *

              + *

            • {@link Module#START_AGAIN_PROGRESS}: The module remains in the + * list of modules to be started and its {@link Module#startApp(String[])} + * method will be invoked during the next iteration, if there is one.
            • + *

              + *

            • {@link Module#START_AGAIN_STALLED}: The module remains in the list + * of modules to be started and its {@link Module#startApp(String[])} + * method will be invoked during the next iteration if there is one.
            • + *

              + *

            • Any other value: The module failed to initialize. Its + * {@link Module#startApp(String[])} method will not be invoked again.
            • + *
            + *

            + * Iterations through the list stop when: + *

              + *
            • The list is empty: the group initialization proceeds.
            • + *

              + *

            • A complete iteration was performed and all modules returned + * {@link Module#START_AGAIN_STALLED}: a {@link PeerGroupException} + * is thrown.
            • + *

              + *

            • A number of complete iteration completed without any module + * returning {@link Module#START_OK}: a {@link PeerGroupException} + * is thrown. The number of complete iterations before that happens is + * computed as 1 + the square of the number of modules currently in the + * list.
            • + *
            + */ + @Override + protected synchronized void initFirst(PeerGroup parent, ID assignedID, Advertisement impl) throws PeerGroupException { + + if (initComplete) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("You cannot initialize a PeerGroup more than once !"); + } + return; + } + + // Set-up the minimal GenericPeerGroup + super.initFirst(parent, assignedID, impl); + + // assignedID might have been null. It is now the peer group ID. + assignedID = getPeerGroupID(); + + // initialize cm before starting services. + try { + cm = new Cm(getHomeThreadGroup(), + getStoreHome(), assignedID.getUniqueValue().toString(), + Cm.DEFAULT_GC_MAX_INTERVAL, false); + } catch (Exception e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Error during creation of local store", e); + } + throw new PeerGroupException("Error during creation of local store", e); + } + + // flush srdi for this group + SrdiIndex.clearSrdi(this); + + // Load the list of peer group services from the impl advertisement params. + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(implAdvertisement.getParam()); + + Map initServices = new HashMap(paramAdv.getServices()); + + initServices.putAll(paramAdv.getProtos()); + + // Remove the modules disabled in the configuration file. + ConfigParams conf = getConfigAdvertisement(); + + if(null != conf) { + Iterator eachModule = initServices.keySet().iterator(); + + while(eachModule.hasNext()) { + ModuleClassID aModule = eachModule.next(); + + if(!conf.isSvcEnabled(aModule)) { + // remove disabled module + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Module disabled in configuration : " + aModule); + } + + eachModule.remove(); + } + } + } + + // We Applications are shelved until startApp() + applications.putAll(paramAdv.getApps()); + + if(null != conf) { + Iterator eachModule = applications.keySet().iterator(); + + while(eachModule.hasNext()) { + ModuleClassID aModule = eachModule.next(); + + if(!conf.isSvcEnabled(aModule)) { + // remove disabled module + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Application disabled in configuration : " + aModule); + } + + eachModule.remove(); + } + } + } + + loadAllModules(initServices, true); + + int res = startModules((Map) initServices); + + if(Module.START_OK != res) { + throw new PeerGroupException("Failed to start peer group services. res : " + res); + } + + // Make sure all the required services are loaded. + try { + checkServices(); + } catch (ServiceNotFoundException e) { + LOG.log(Level.SEVERE, "Missing peer group service", e); + throw new PeerGroupException("Missing peer group service", e); + } + + /* + * Publish a few things that have not been published in this + * group yet. + */ + DiscoveryService discoveryService = getDiscoveryService(); + + if (discoveryService != null) { + // It should work but if it does not we can survive. + try { + // Discovery service adv could not be published localy, + // since at that time there was no local discovery to + // publish to. + discoveryService.publish(discoveryService.getImplAdvertisement(), DEFAULT_LIFETIME, DEFAULT_EXPIRATION); + + // Try to publish our impl adv within this group. (it was published + // in the parent automatically when loaded. + discoveryService.publish(implAdvertisement, DEFAULT_LIFETIME, DEFAULT_EXPIRATION); + } catch (Exception nevermind) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to publish Impl adv within group.", nevermind); + } + } + } + } + + /** + * {@inheritDoc} + *

            + * Nothing special for now, but we might want to move some steps from + * initFirst() in the future. + */ + @Override + protected synchronized void initLast() throws PeerGroupException { + + super.initLast(); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Group : " + getPeerGroupID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tCompatibility Statement :\n\t\t\t"); + StringBuilder indent = new StringBuilder(STD_COMPAT.toString().trim()); + int from = indent.length(); + + while (from > 0) { + int returnAt = indent.lastIndexOf("\n", from); + + from = returnAt - 1; + if ((returnAt >= 0) && (returnAt != indent.length())) { + indent.insert(returnAt + 1, "\t\t\t"); + } + } + configInfo.append(indent); + Iterator eachProto = messageTransports.entrySet().iterator(); + + if (eachProto.hasNext()) { + configInfo.append("\n\t\tMessage Transports :"); + } + while (eachProto.hasNext()) { + Map.Entry anEntry = (Map.Entry) eachProto.next(); + ModuleClassID aMCID = (ModuleClassID) anEntry.getKey(); + Module anMT = (Module) anEntry.getValue(); + + configInfo.append("\n\t\t\t").append(aMCID).append("\t").append( + (anMT instanceof MessageTransport) + ? ((MessageTransport) anMT).getProtocolName() + : anMT.getClass().getName()); + } + Iterator> eachApp = applications.entrySet().iterator(); + + if (eachApp.hasNext()) { + configInfo.append("\n\t\tApplications :"); + } + while (eachApp.hasNext()) { + Map.Entry anEntry = eachApp.next(); + ModuleClassID aMCID = anEntry.getKey(); + Object anApp = anEntry.getValue(); + + if (anApp instanceof ModuleImplAdvertisement) { + ModuleImplAdvertisement adv = (ModuleImplAdvertisement) anApp; + + configInfo.append("\n\t\t\t").append(aMCID).append("\t").append(adv.getCode()); + } else { + configInfo.append("\n\t\t\t").append(aMCID).append("\t").append(anApp.getClass().getName()); + } + } + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + *

            + * FIXME 20070801 bondolo To improve compatibility with existing + * applications the returned {@code ModuleImplAdvertisement} will contain + * embedded {@code ModuleImplAdvertisement}s for the referenced services as + * opposed to {@code ModuleSpecID}s. This is because JXSE 2.4.1 and earlier + * do not handle load failures of modules loaded by spec id correctly. + * After JXSE 2.5 is released this should be changed to use the better + * {@code ModuleSpecID} based peer group module specification. + */ + // @Override + public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() { + JxtaLoader loader = getJxtaLoader(); + + // grab an impl adv + ModuleImplAdvertisement implAdv = loader.findModuleImplAdvertisement(PeerGroup.allPurposePeerGroupSpecID); + + return implAdv; + } + + + /** + * Returns the cache manager associated with this group. + * + * @return the cache manager associated with this group. + */ + public Cm getCacheManager() { + return cm; + } + + /** + * Return a map of the applications for this group. + *

            + *

              + *
            • keys are {@link net.jxta.platform.ModuleClassID}
            • + *
            • values are {@link net.jxta.platform.Module} or + * {@link net.jxta.protocol.ModuleImplAdvertisement}
            • + *
            + * + * @return a map of the applications for this group. + */ + public Map getApplications() { + return Collections.unmodifiableMap(applications); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/StdPeerGroupParamAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/StdPeerGroupParamAdv.java new file mode 100644 index 000000000..c35b9ce41 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/StdPeerGroupParamAdv.java @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.peergroup; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLElement; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleImplAdvertisement; + +import java.net.URI; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Not actually an advertisement, but often acts as part of one. + * + * @deprecated This internal class will eventually be removed. It has several + * problems which make it difficult to support. (The most obvious that it + * provides poor abstraction and provides references to its' own internal data + * structures). This class is expected to be replaced by a public API class + * performing a similar function though such an alternative is not yet available. + * You are encouraged to copy this code into your own application or service if + * if you depend upon it. + */ +@Deprecated +public class StdPeerGroupParamAdv { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(StdPeerGroupParamAdv.class.getName()); + + private static final String PARAM_TAG = "Parm"; + private static final String PROTO_TAG = "Proto"; + private static final String APP_TAG = "App"; + private static final String SVC_TAG = "Svc"; + private static final String MCID_TAG = "MCID"; + private static final String MSID_TAG = "MSID"; + private static final String MIA_TAG = ModuleImplAdvertisement.getAdvertisementType(); + + // In the future we should be able to manipulate all modules regardless of + // their kind, but right now it helps to keep them categorized as follows. + + /** + * The services which will be loaded for this peer group. + *

            + *

              + *
            • Keys are {@link net.jxta.platform.ModuleClassID}.
            • + *
            • Values are {@link net.jxta.platform.ModuleSpecID} or + * {@link net.jxta.protocol.ModuleImplAdvertisement}.
            • + *
            + */ + private final Map services = new HashMap(); + + /** + * The protocols (message transports) which will be loaded for this peer + * group. + *

            + *

              + *
            • Keys are {@link net.jxta.platform.ModuleClassID}.
            • + *
            • Values are {@link net.jxta.platform.ModuleSpecID} or + * {@link net.jxta.protocol.ModuleImplAdvertisement}.
            • + *
            + */ + private final Map transports = new HashMap(); + + /** + * The applications which will be loaded for this peer group. + *

            + *

              + *
            • Keys are {@link net.jxta.platform.ModuleClassID}.
            • + *
            • Values are {@link net.jxta.platform.ModuleSpecID} or + * {@link net.jxta.protocol.ModuleImplAdvertisement}.
            • + *
            + */ + private final Map apps = new HashMap(); + + /** + * Private constructor for new instances. + */ + public StdPeerGroupParamAdv() { + } + + /** + * Private constructor for serialized instances. + * + * @param root the root element + */ + public StdPeerGroupParamAdv(Element root) { + if (!(root instanceof XMLElement)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + initialize((XMLElement) root); + } + + /** + * Private constructor for xml serialized instances. + * + * @param doc The XML serialization of the advertisement. + */ + public StdPeerGroupParamAdv(XMLElement doc) { + initialize(doc); + } + + /** + * Add a service to the set of services entries described in this + * Advertisement. + * + * @param mcid The module class id of the module being added. + * @param module The module being added. + */ + public void addService(ModuleClassID mcid, Object module) { + if(null == mcid) { + throw new IllegalArgumentException("Illegal ModuleClassID"); + } + + if(null == module) { + throw new IllegalArgumentException("Illegal module"); + } + + services.put(mcid, module); + } + + /** + * Return the services entries described in this Advertisement. + *

            + * The result (very unwisely) is the internal map of this + * Advertisement. Modifying it results in changes to this Advertisement. + * For safety the Map should be copied before being modified. + * + * @return the services entries described in this Advertisement. + */ + public Map getServices() { + return services; + } + + /** + * Add a protocol (message transport) to the set of protocol entries + * described in this Advertisement. + * + * @param mcid The module class id of the module being added. + * @param module The module being added. + */ + public void addProto(ModuleClassID mcid, Object module) { + if(null == mcid) { + throw new IllegalArgumentException("Illegal ModuleClassID"); + } + + if(null == module) { + throw new IllegalArgumentException("Illegal module"); + } + + transports.put(mcid, module); + } + + /** + * Return the protocols (message transports) entries described in this Advertisement. + *

            + * The result (very unwisely) is the internal map of this Advertisement. + * Modifying it results in changes to this Advertisement. + * For safety the Map should be copied before being modified. + * + * @return the protocols (message transports) entries described in this Advertisement. + */ + public Map getProtos() { + return transports; + } + + /** + * Add an application to the set of application entries described in this + * Advertisement. + * + * @param mcid The module class id of the module being added. + * @param module The module being added. + */ + public void addApp(ModuleClassID mcid, Object module) { + if(null == mcid) { + throw new IllegalArgumentException("Illegal ModuleClassID"); + } + + if(null == module) { + throw new IllegalArgumentException("Illegal module"); + } + + apps.put(mcid, module); + } + + /** + * Return the application entries described in this Advertisement. + *

            + * The result (very unwisely) is the internal map of this Advertisement. + * Modifying it results in changes to this Advertisement. + * For safety the Map should be copied before being modified. + * + * @return the application entries described in this Advertisement. + */ + public Map getApps() { + return apps; + } + + /** + * Replaces the table of services described by this Advertisement. All + * existing entries are lost. + * + * @param servicesTable the services table + */ + public void setServices(Map servicesTable) { + if(servicesTable.containsKey(null)) { + throw new IllegalArgumentException("null key in servicesTable"); + } + + if(servicesTable.containsValue(null)) { + throw new IllegalArgumentException("null value in servicesTable"); + } + + if (servicesTable == this.services) { + return; + } + + this.services.clear(); + + if (null != servicesTable) { + this.services.putAll(servicesTable); + } + } + + /** + * Replaces the table of protocols described by this Advertisement. All + * existing entries are lost. + * + * @param protosTable The message transport descriptors for the group. + */ + public void setProtos(Map protosTable) { + if(protosTable.containsKey(null)) { + throw new IllegalArgumentException("null key in protosTable"); + } + + if(protosTable.containsValue(null)) { + throw new IllegalArgumentException("null value in protosTable"); + } + + if (protosTable == this.transports) { + return; + } + + this.transports.clear(); + + if (null != protosTable) { + this.transports.putAll(protosTable); + } + } + + /** + * Replaces the table of applications described by this Advertisement. All + * existing entries are lost. + * + * @param appsTable The application descriptors for the group. + */ + public void setApps(Map appsTable) { + if(appsTable.containsKey(null)) { + throw new IllegalArgumentException("null key in appsTable"); + } + + if(appsTable.containsValue(null)) { + throw new IllegalArgumentException("null value in appsTable"); + } + + if (appsTable == this.apps) { + return; + } + + this.apps.clear(); + + if (null != appsTable) { + this.apps.putAll(appsTable); + } + } + + private void initialize(XMLElement doc) { + if (!doc.getName().equals(PARAM_TAG)) { + throw new IllegalArgumentException("Can not construct " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + // set defaults + int appCount = 0; + Enumeration modules = doc.getChildren(); + + while (modules.hasMoreElements()) { + XMLElement module = modules.nextElement(); + String tagName = module.getName(); + + Map theTable; + + if (SVC_TAG.equals(tagName)) { + theTable = services; + } else if (APP_TAG.equals(tagName)) { + theTable = apps; + } else if (PROTO_TAG.equals(tagName)) { + theTable = transports; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unhandled top-level tag : " + tagName); + } + continue; + } + + ModuleSpecID specID = null; + ModuleClassID classID = null; + ModuleImplAdvertisement inLineAdv = null; + + try { + if (module.getTextValue() != null) { + specID = (ModuleSpecID) IDFactory.fromURI(new URI(module.getTextValue())); + } + + // Check for children anyway. + Enumeration fields = module.getChildren(); + + while (fields.hasMoreElements()) { + XMLElement field = fields.nextElement(); + + String fieldName = field.getName(); + + if (MCID_TAG.equals(fieldName)) { + classID = (ModuleClassID) IDFactory.fromURI(new URI(field.getTextValue())); + } else if (MSID_TAG.equals(field.getName())) { + specID = (ModuleSpecID) IDFactory.fromURI(new URI(field.getTextValue())); + } else if (MIA_TAG.equals(field.getName())) { + inLineAdv = (ModuleImplAdvertisement) AdvertisementFactory.newAdvertisement(field); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Unhandled field : " + fieldName); + } + } + } + } catch (Exception any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Broken entry; skipping", any); + } + continue; + } + + if (inLineAdv == null && specID == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Insufficent entry; skipping"); + } + continue; + } + + Object theValue; + + if (inLineAdv != null) { + specID = inLineAdv.getModuleSpecID(); + theValue = inLineAdv; + } else { + theValue = specID; + } + + if (classID == null) { + classID = specID.getBaseClass(); + } + + // For applications, the role does not matter. We just create a + // unique role ID on the fly. + // When outputing the adv we get rid of it to save space. + + if (theTable == apps) { + // Only the first (or only) one may use the base class. + if (classID == PeerGroup.applicationClassID) { + if (appCount++ != 0) { + classID = IDFactory.newModuleClassID(classID); + } + } + } + theTable.put(classID, theValue); + } + } + + /** + * {@inheritDoc} + */ + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(encodeAs, PARAM_TAG); + + outputModules(doc, services, SVC_TAG); + outputModules(doc, transports, PROTO_TAG); + outputModules(doc, apps, APP_TAG); + + return doc; + } + + private void outputModules(StructuredDocument doc, Map modulesTable, String mainTag) { + + for (Map.Entry entry : modulesTable.entrySet()) { + ModuleClassID mcid = entry.getKey(); + Object val = entry.getValue(); + Element m; + + if(null == mcid) { + throw new IllegalStateException("null ModuleClassID in " + mainTag ); + } + + // For applications, we ignore the role ID. It is not meaningfull, + // and a new one is assigned on the fly when loading this adv. + + if (val instanceof Advertisement) { + m = doc.createElement(mainTag); + doc.appendChild(m); + + if (modulesTable != apps && !mcid.equals(mcid.getBaseClass())) { + // It is not an app and there is a role ID. Output it. + Element i = doc.createElement(MCID_TAG, mcid.toString()); + + m.appendChild(i); + } + + StructuredDocument advdoc = (StructuredDocument) ((Advertisement) val).getDocument(doc.getMimeType()); + + StructuredDocumentUtils.copyElements(doc, m, advdoc); + } else if (val instanceof ModuleSpecID) { + if (modulesTable == apps || mcid.equals(mcid.getBaseClass())) { + // Either it is an app or there is no role ID. + // So the specId is good enough. + m = doc.createElement(mainTag, val.toString()); + doc.appendChild(m); + } else { + // The role ID matters, so the classId must be separate. + m = doc.createElement(mainTag); + doc.appendChild(m); + + Element i; + + i = doc.createElement(MCID_TAG, mcid.toString()); + m.appendChild(i); + + i = doc.createElement(MSID_TAG, val.toString()); + m.appendChild(i); + } + } else { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("unsupported descriptor for " + mcid + " in " + mainTag +" module table : " + val); + } + throw new IllegalStateException("unsupported descriptor for " + mcid + " in " + mainTag +" module table : " + val); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/package.html new file mode 100644 index 000000000..86deacfd0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/peergroup/package.html @@ -0,0 +1,13 @@ + + + + + + + Provides the standard JXTA Peer Group implementations as well as legacy peer + group configuration functionality. The legacy peer configuration classes are + all deprecated. + + @see JXTA Protocols Specification + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/BlockingWireOutputPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/BlockingWireOutputPipe.java new file mode 100644 index 000000000..9a304434c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/BlockingWireOutputPipe.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.impl.endpoint.tcp.TcpMessenger; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.OutputPipe; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This Object is created when a call to PipeService.createOutputPipe(propgateAdv) with a Set containing a single + * PeerID. This pipe blocks until a valid messeger is created (i.e. resolved and useable). With this object it is + * possible to detect connection failures during the messenger resolution. Notge, this pipe also avoids utilitizing the + * rendezvous for propagation, effectively reducing message overhead, resulting in improved performance. + *

            + * #send is remains asynchronous. + */ +public class BlockingWireOutputPipe implements OutputPipe { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(NonBlockingWireOutputPipe.class.getName()); + + /** + * If true then the pipe has been closed and will no longer accept messages. + */ + private volatile boolean closed = false; + + /** + * The advertisement we were created from. + */ + private final PipeAdvertisement pAdv; + + private final PeerGroup group; + private Messenger destMessenger = null; + private EndpointAddress destination; + private EndpointService endpoint = null; + private RouteAdvertisement route = null; + + /** + * Create a new blocking output pipe + * + * @param group The peergroup context. + * @param pAdv advertisement for the pipe we are supporting. + * @param peerID the destination PeerID. + */ + public BlockingWireOutputPipe(PeerGroup group, PipeAdvertisement pAdv, PeerID peerID) { + + this.pAdv = pAdv; + this.group = group; + this.endpoint = group.getEndpointService(); + destination = new EndpointAddress("jxta", peerID.getUniqueValue().toString(), "PipeService", pAdv.getID().toString()); + destMessenger = endpoint.getMessenger(destination); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Created output pipe for " + getPipeID()); + } + } + /** + * Create a new blocking output pipe + * + * @param group The peergroup context. + * @param pAdv advertisement for the pipe we are supporting. + * @param peerID the destination PeerID. + * @param route the destination route. + */ + public BlockingWireOutputPipe(PeerGroup group, PipeAdvertisement pAdv, PeerID peerID, RouteAdvertisement route) { + this.route = route; + this.pAdv = pAdv; + this.group = group; + this.endpoint = group.getEndpointService(); + destination = new EndpointAddress("jxta", peerID.getUniqueValue().toString(), "PipeService", pAdv.getID().toString()); + if (route != null) { + destMessenger = endpoint.getDirectMessenger(destination, route, true); + } + if (destMessenger == null) { + destMessenger = endpoint.getMessenger(destination); + } + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Created output pipe for " + getPipeID()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized void close() { + + if (closed) { + return; + } + // Close the queue so that no more messages are accepted + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing queue for " + getPipeID()); + } + closed = true; + } + + /** + * {@inheritDoc} + */ + public boolean isClosed() { + return closed; + } + + /** + * {@inheritDoc} + */ + public final String getType() { + return pAdv.getType(); + } + + /** + * {@inheritDoc} + */ + public final ID getPipeID() { + return pAdv.getPipeID(); + } + + /** + * {@inheritDoc} + */ + public final String getName() { + return pAdv.getName(); + } + + /** + * {@inheritDoc} + */ + public final PipeAdvertisement getAdvertisement() { + return pAdv; + } + + private void checkMessenger() throws IOException { + if (!(destMessenger instanceof TcpMessenger) && destMessenger != null && (destMessenger.getState() & Messenger.USABLE) != 0) { + return; + } + if (destMessenger != null && !destMessenger.isClosed()) { + return; + } + synchronized (this) { + if (route != null) { + destMessenger = endpoint.getDirectMessenger(destination, route, true); + } + destMessenger = endpoint.getMessenger(destination); + if (!(destMessenger instanceof TcpMessenger) && destMessenger == null || (destMessenger.getState() & Messenger.TERMINAL) != 0) { + if (destMessenger != null) { + destMessenger.close(); + destMessenger = null; + } + throw new IOException("Unable to create a messenger to " + destination.toString()); + } + } + } + + /** + * {@inheritDoc} + */ + public boolean send(Message message) throws IOException { + if (closed) { + throw new IOException("Pipe closed"); + } + WireHeader header = new WireHeader(); + + header.setPipeID(getPipeID()); + header.setSrcPeer(group.getPeerID()); + header.setTTL(1); + header.setMsgId(WirePipe.createMsgId()); + + XMLDocument asDoc = (XMLDocument) header.getDocument(MimeMediaType.XMLUTF8); + MessageElement elem = new TextDocumentMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAME, asDoc, null); + Message msg = message.clone(); + + msg.replaceMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAMESPACE, elem); + checkMessenger(); + try { + if (destMessenger instanceof TcpMessenger) { + ((TcpMessenger) destMessenger).sendMessageDirect(msg, null, null, true); + } else if (!destMessenger.sendMessage(msg, null, null)) { + throw new IOException("Pipe closed"); + } + } catch (IOException io) { + checkMessenger(); + if (!destMessenger.sendMessage(msg, null, null)) { + throw new IOException("Pipe closed"); + } + } + return true; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/InputPipeImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/InputPipeImpl.java new file mode 100644 index 000000000..0c318380b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/InputPipeImpl.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.UnbiasedQueue; +import net.jxta.logging.Logging; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implements the {@link net.jxta.pipe.InputPipe} interface by listening on the + * endpoint for messages to service "PipeService" and a param of the Pipe ID. + */ +class InputPipeImpl implements EndpointListener, InputPipe { + + /** + * logger + */ + private final static Logger LOG = Logger.getLogger(InputPipeImpl.class.getName()); + + protected final static int QUEUESIZE = 100; + + protected PipeRegistrar registrar; + + protected final PipeAdvertisement pipeAdv; + protected final ID pipeID; + + protected volatile boolean closed = false; + + protected PipeMsgListener listener; + protected final UnbiasedQueue queue; + + /** + * Constructor for the InputPipeImpl object + * + * @param r pipe resolver + * @param adv pipe advertisement + * @param listener listener to receive messages + * @throws IOException if an io error occurs + */ + InputPipeImpl(PipeRegistrar r, PipeAdvertisement adv, PipeMsgListener listener) throws IOException { + registrar = r; + this.pipeAdv = adv; + this.listener = listener; + + pipeID = adv.getPipeID(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( + "Creating InputPipe for " + pipeID + " of type " + adv.getType() + " with " + + ((null != listener) ? "listener" : "queue")); + } + + // queue based inputpipe? + if (listener == null) { + queue = UnbiasedQueue.synchronizedQueue(new UnbiasedQueue(QUEUESIZE, true)); + } else { + queue = null; + } + + if (!registrar.register(this)) { + throw new IOException("Could not register input pipe (already registered) for " + pipeID); + } + } + + /** + * {@inheritDoc} + *

            + * Closes the pipe. + */ + @Override + protected synchronized void finalize() throws Throwable { + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe is being finalized without being previously closed. This is likely a bug."); + } + } + close(); + super.finalize(); + } + + /** + * {@inheritDoc} + */ + public Message waitForMessage() throws InterruptedException { + return poll(0); + } + + /** + * {@inheritDoc} + */ + public Message poll(int timeout) throws InterruptedException { + if (listener == null) { + return (Message) queue.pop(timeout); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("poll() has no effect in listener mode."); + } + return null; + } + } + + /** + * {@inheritDoc} + */ + public synchronized void close() { + if (closed) { + return; + } + closed = true; + + // Close the queue + if (null == listener) { + queue.close(); + } + + listener = null; + // Remove myself from the pipe registrar. + if (!registrar.forget(this)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("close() : pipe was not registered with registrar."); + } + } + registrar = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closed " + pipeID); + } + } + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + // if we are closed, ignore any additional messages + if (closed) { + return; + } + + // XXX: header check, security and such should be done here + // before pushing the message onto the queue. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + msg + " from " + srcAddr + " for " + pipeID); + } + // determine where demux the msg, to listener, or onto the queue + if (null == queue) { + PipeMsgListener temp = listener; + if (null == temp) { + return; + } + + PipeMsgEvent event = new PipeMsgEvent(this, msg, (PipeID) pipeID); + try { + temp.pipeMsgEvent(event); + } catch (Throwable ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in listener for : " + pipeID + "(" + temp.getClass().getName() + ")", ignored); + } + } + } else { + boolean pushed = false; + while (!pushed && !queue.isClosed()) { + try { + pushed = queue.push(msg, TimeUtils.ASECOND); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + synchronized (this) { + LOG.fine("Queued " + msg + " for " + pipeID + "\n\tqueue closed : " + queue.isClosed() + "\tnumber in queue : " + + queue.getCurrentInQueue() + "\tnumber queued : " + queue.getNumEnqueued() + "\tnumber dequeued : " + + queue.getNumDequeued()); + } + } + } + } + + /** + * Gets the pipe type + * + * @return The type + */ + public String getType() { + return pipeAdv.getType(); + } + + /** + * Gets the pipe id + * + * @return The type + */ + public ID getPipeID() { + return pipeID; + } + + /** + * Gets the pipe name + * + * @return The name + */ + public String getName() { + return pipeAdv.getName(); + } + + /** + * Gets the pipe advertisement + * + * @return The advertisement + */ + public PipeAdvertisement getAdvertisement() { + return pipeAdv; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/NonBlockingOutputPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/NonBlockingOutputPipe.java new file mode 100644 index 000000000..eccf5342c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/NonBlockingOutputPipe.java @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.UnbiasedQueue; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeID; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An implementation of Ouput Pipe which sends messages on the pipe + * asynchronously. The send() method for this implementation will + * never block. + */ +class NonBlockingOutputPipe implements PipeResolver.Listener, OutputPipe, Runnable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(NonBlockingOutputPipe.class.getName()); + + /** + * Amount of time an idle worker thread will linger + */ + private static final long IDLEWORKERLINGER = 10 * TimeUtils.ASECOND; + + /** + * Minimum Query interval. Queries will not be sent more frequently than + * this interval. + */ + private static final long QUERYINTERVALMIN = 15 * TimeUtils.ASECOND; + + /** + * Query timeout minimum. Waits for query response will not be shorter than + * this interval. + */ + private static final long QUERYTIMEOUTMIN = 1 * TimeUtils.AMINUTE; + + /** + * If true then the pipe has been closed and will no longer accept messages. + */ + private volatile boolean closed = false; + + /** + * If true then this pipe has just migrated. Used to prevent re-entering + * migration from an unfinished migration. + */ + private boolean migrated = false; + + /** + * Group in which we are working. + */ + private PeerGroup peerGroup = null; + + /** + * The endpoint of our group. + */ + private EndpointService endpoint = null; + + /** + * The pipe resolver we will use for migrate and verify. + */ + private PipeResolver pipeResolver = null; + + /** + * The advertisement we were created from. + */ + private PipeAdvertisement pAdv = null; + + /** + * The current peer the pipe is resolved to. + */ + private ID destPeer = null; + + /** + * The set of peers to which the pipe can be resolved. + */ + private Set resolvablePeers = null; + + /** + * The endpoint destination address for the remote peer we are resolved to. + */ + private EndpointAddress destAddress = null; + private Messenger destMessenger = null; + + /** + * The worker thread which actually sends messages on the pipe + */ + private volatile Thread serviceThread = null; + + /** + * Absolute time in milliseconds at which we will send the next verify + * request. + */ + private long nextVerifyAt = 0; + + /** + * Queue of messages waiting to be sent. + */ + private final UnbiasedQueue queue = UnbiasedQueue.synchronizedQueue(new UnbiasedQueue(50, false)); + + /** + * Tracks the state of our worker thread. + */ + enum WorkerState { + /** + * Find a new eligible destination peer which is listening on the pipe. + */ + STARTMIGRATE, + + /** + * Issue resolution queries and wait for responses + */ + PENDINGMIGRATE, + + /** + * Determine if the destination peer is still listening on the pipe. + */ + STARTVERIFY, + + /** + * Issue verify queries and wait for responses + */ + PENDINGVERIFY, + + /** + * Acquire a messenger to the destination peer. + */ + ACQUIREMESSENGER, + + /** + * Send messages via the messenger to the destination peer. + */ + SENDMESSAGES, + + /** + * Exit. + */ + CLOSED + } + + /** + * The current state of the worker thread + */ + private WorkerState workerstate; + + /** + * The query id we are currently operating under. + */ + private int queryID = -1; + + /** + * Create a new output pipe + * + * @param peerGroup peergroup we are working in. + * @param pipeResolver the piperesolver this pipe is bound to. + * @param pAdv advertisement for the pipe we are supporting. + * @param destPeer the peer this pipe is currently bound to. + * @param peers the set of peers we allow this pipe to be bound to. + */ + public NonBlockingOutputPipe(PeerGroup peerGroup, PipeResolver pipeResolver, PipeAdvertisement pAdv, ID destPeer, Set peers) { + + this.peerGroup = peerGroup; + endpoint = peerGroup.getEndpointService(); + this.pipeResolver = pipeResolver; + + this.pAdv = pAdv; + this.destPeer = destPeer; + this.resolvablePeers = new HashSet(peers); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Constructing for " + getPipeID()); + } + workerstate = WorkerState.ACQUIREMESSENGER; + startServiceThread(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void finalize() throws Throwable { + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe is being finalized without being previously closed. This is likely a bug."); + } + } + close(); + super.finalize(); + } + + /** + * {@inheritDoc} + */ + public synchronized void close() { + + // Close the queue so that no more messages are accepted + if (!closed) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing for " + getPipeID()); + } + queue.close(); + } + closed = true; + } + + /** + * {@inheritDoc} + */ + public boolean isClosed() { + return closed; + } + + /** + * {@inheritDoc} + */ + public final String getType() { + return pAdv.getType(); + } + + /** + * {@inheritDoc} + */ + public final ID getPipeID() { + return pAdv.getPipeID(); + } + + /** + * {@inheritDoc} + */ + public final String getName() { + return pAdv.getName(); + } + + /** + * {@inheritDoc} + */ + public final PipeAdvertisement getAdvertisement() { + return pAdv; + } + + /** + * {@inheritDoc} + */ + public boolean send(Message msg) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Queuing " + msg + " for pipe " + getPipeID()); + } + + boolean pushed = false; + while (!queue.isClosed()) { + try { + pushed = queue.push(msg, 250 * TimeUtils.AMILLISECOND); + break; + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + + if (!pushed && queue.isClosed()) { + IOException failed = new IOException("Could not enqueue " + msg + " for sending. Pipe is closed."); + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failed.getMessage(), failed); + } + throw failed; + } + startServiceThread(); + return pushed; + } + + /** + * {@inheritDoc} + *

            + * Sends the messages. + *

            + * This method does a lot of things. It has several distinct states: + *

            + * + * + * + * + * + * + * + *

            + *

            + * + * Acquire a messenger to the specified destination peer. If a + * messenger is acquired, then go to SENDMESSAGES state + * otherwise go to STARTMIGRATE. + * + *

            + *

            + * + * + * + *

            + *

            + * + * + * + *

            + *

            + * + * + * + *

            + *

            + * + * + * + *

            + *

            + * + * + * + *

            + *

            + * + * + * + * + *
            STATEActivity
            ACQUIREMESSENGER
            SENDMESSAGESSend messages until queue is closed and all messages have + * been sent. Go to state CLOSED when done. If the messenger + * becomes closed then go to ACQUIREMESSENGER. If + * there are no messages to send for IDLEWORKERLINGER + * milliseconds then the worker thread will exit. It will only be + * restarted if another message is eventually enqueued. + *
            STARTVERIFYStarts a verification query(s) to the destination peer. This + * state is activated after + * PipeServiceImpl.VERIFYINTERVAL milliseconds of + * sending messages. The query responses will be tracked in the + * PENDINGVERIFY state.
            STARTMIGRATEStarts a query(s) for peers listening on this pipe. The + * query responses will be tracked in the PENDINGMIGRATE + * state.
            PENDINGVERIFYIssues query messages to verify that the destination peer is + * still listening on the pipe. Queries are issued every + * QUERYINTERVAL milliseconds. If a positive response + * is received, go to state ACQUIREMESSENGER. If no response + * is received within QUERYTIMEOUT milliseconds or a + * negative response is received then go to state + * STARTMIGRATE.
            PENDINGMIGRATEIssues query messages to find a new destination peer. + * Queries are issued every QUERYINTERVAL milliseconds. + * If a positive response is received, go to state + * ACQUIREMESSENGER. If no positive response from an + * eligible peer is received within QUERYTIMEOUT + * milliseconds go to state CLOSED.
            CLOSEDExit the worker thread.
            + */ + public void run() { + long absoluteTimeoutAt = -1; + long nextQueryAt = -1; + + try { + // state loop + while (WorkerState.CLOSED != workerstate) { + synchronized (this) { + LOG.fine("NON-BLOCKING WORKER AT STATE : " + workerstate + + ((WorkerState.SENDMESSAGES == workerstate) + ? "\n\t" + TimeUtils.toRelativeTimeMillis(nextVerifyAt, TimeUtils.timeNow()) + + " until verify." + : "")); + + // switch() emulation + if ((WorkerState.STARTVERIFY == workerstate) || (WorkerState.STARTMIGRATE == workerstate)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + if (null == destPeer) { + LOG.fine("Starting re-resolve for \'" + getPipeID()); + } else { + LOG.fine("Starting verify for \'" + getPipeID() + "\' to : " + destPeer); + } + } + + queryID = PipeResolver.getNextQueryID(); + pipeResolver.addListener(getPipeID(), this, queryID); + absoluteTimeoutAt = TimeUtils.toAbsoluteTimeMillis( + Math.max(QUERYTIMEOUTMIN, (PipeServiceImpl.VERIFYINTERVAL / 20))); + nextQueryAt = TimeUtils.timeNow(); + + if (WorkerState.STARTVERIFY == workerstate) { + workerstate = WorkerState.PENDINGVERIFY; + } else if (WorkerState.STARTMIGRATE == workerstate) { + workerstate = WorkerState.PENDINGMIGRATE; + } + + // move on to the next state. + } else if ((WorkerState.PENDINGVERIFY == workerstate) || (WorkerState.PENDINGMIGRATE == workerstate)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Pipe " + ((WorkerState.PENDINGVERIFY == workerstate) ? "verify" : "migrate") + + "in progress. Continues for " + + TimeUtils.toRelativeTimeMillis(absoluteTimeoutAt, TimeUtils.timeNow()) + + "ms. Next query in " + TimeUtils.toRelativeTimeMillis(nextQueryAt, TimeUtils.timeNow()) + + "ms."); + } + + // check to see if we are completely done. + if (TimeUtils.toRelativeTimeMillis(absoluteTimeoutAt, TimeUtils.timeNow()) <= 0) { + pipeResolver.removeListener(getPipeID(), queryID); + + if (WorkerState.PENDINGVERIFY == workerstate) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Pipe \'" + getPipeID() + "\' has migrated from " + destPeer); + } + workerstate = WorkerState.STARTMIGRATE; + // move on to the next state. + continue; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe \'" + getPipeID() + "\' cannot be migrated and is being closed"); + } + workerstate = WorkerState.CLOSED; + close(); + // move on to the next state. + continue; + } + } + + // check if its time ot send another copy of the query. + if (TimeUtils.toRelativeTimeMillis(nextQueryAt, TimeUtils.timeNow()) <= 0) { + if (null != destPeer) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Sending out verify query (" + queryID + ") for \'" + getPipeID() + "\' to : " + + destPeer); + } + pipeResolver.sendPipeQuery(pAdv, Collections.singleton(destPeer), queryID); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending out resolve query (" + queryID + ") for " + getPipeID()); + } + pipeResolver.sendPipeQuery(pAdv, resolvablePeers, queryID); + } + nextQueryAt = TimeUtils.toAbsoluteTimeMillis( + Math.max(QUERYINTERVALMIN, (PipeServiceImpl.VERIFYINTERVAL / 50))); + } + + long sleep = TimeUtils.toRelativeTimeMillis(Math.min(nextQueryAt, absoluteTimeoutAt), TimeUtils.timeNow()); + + if (sleep >= 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting " + sleep + "ms for response for (" + queryID + ") for " + getPipeID()); + } + try { + wait(sleep); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + + // move on to the next state. + } else if (WorkerState.ACQUIREMESSENGER == workerstate) { + if ((null == destMessenger) || destMessenger.isClosed()) { + destMessenger = null; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting messenger to \'" + destPeer + "\' for pipe " + getPipeID()); + } + + destAddress = mkAddress(destPeer, getPipeID()); + // todo 20031011 bondolo@jxta.org This should not be done under sync + destMessenger = endpoint.getMessenger(destAddress); + if (destMessenger == null) { + // We could not get a messenger to the peer, forget it and try again. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not get messenger to : " + destPeer + ". "); + } + + if (migrated) { + // we can't migrate again, we never finished. + // the last migrate! + workerstate = WorkerState.CLOSED; + close(); + } else { + workerstate = WorkerState.STARTMIGRATE; + } + pipeResolver.removeListener((PipeID) getPipeID(), queryID); + queryID = -1; + destPeer = null; + destAddress = null; + + // move on to the next state. + continue; + } else { + // migration completed. + migrated = false; + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Using existing messenger to : " + destPeer); + } + } + + workerstate = WorkerState.SENDMESSAGES; + nextVerifyAt = TimeUtils.toAbsoluteTimeMillis(PipeServiceImpl.VERIFYINTERVAL); + + // move on to the next state. + continue; // can't just fall through because we would start sending messages immediately. + } else if (WorkerState.SENDMESSAGES == workerstate) { + // is it time to do verification again? + if (TimeUtils.toRelativeTimeMillis(nextVerifyAt, TimeUtils.timeNow()) <= 0) { + workerstate = WorkerState.STARTVERIFY; + pipeResolver.removeListener(getPipeID(), queryID); + queryID = -1; + } + // move on to the next state. + } else if (WorkerState.CLOSED == workerstate) { + queue.clear(); // they aren't going to be sent + if (null != destMessenger) { + destMessenger.close(); + destMessenger = null; + } + serviceThread = null; + break; + } else { + LOG.warning("Unrecognized state in worker thread : " + workerstate); + } + } + + // now actually send messages. We don't do this under the global sync. + if (WorkerState.SENDMESSAGES == workerstate) { + Message msg = null; + + try { + msg = (Message) queue.pop(IDLEWORKERLINGER); + } catch (InterruptedException woken) { + Thread.interrupted(); + continue; + } + + if (null == msg) { + synchronized (this) { + // before deciding to die, we need to make sure that + // nobody snuck something into the queue. If there + // is, then we have to be the one to service the + // queue. + if (null == queue.peek()) { + if (closed) { + workerstate = WorkerState.CLOSED; + continue; + } else { + serviceThread = null; + break; + } + } else { + continue; + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " on " + getPipeID()); + } + + if (!destMessenger.isClosed()) { + try { + destMessenger.sendMessageB(msg, null, null); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure sending " + msg + " on " + getPipeID(), failed); + } + } + } + + // May be now closed due to failing to send. + if (destMessenger.isClosed()) { + synchronized (this) { + workerstate = WorkerState.ACQUIREMESSENGER; + destMessenger = null; + } + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + + // give another thread the chance to start unless one already has. + // If the exception was caused by damaged state on this object then + // starting a new Thread may just cause the same exception again. + // Unfortunate tradeoff. + synchronized (this) { + if (serviceThread == Thread.currentThread()) { + serviceThread = null; + } + } + } finally { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( + "Thread exit : " + Thread.currentThread().getName() + "\n\tworker state : " + workerstate + + "\tqueue closed : " + queue.isClosed() + "\tnumber in queue : " + queue.getCurrentInQueue() + + "\tnumber queued : " + queue.getNumEnqueued() + "\tnumber dequeued : " + queue.getNumDequeued()); + } + } + } + + /** + * Starts the worker thread if it is not already running. + */ + private synchronized void startServiceThread() { + // if there is no service thread, start one. + if ((null == serviceThread) && !closed) { + serviceThread = new Thread(peerGroup.getHomeThreadGroup(), this + , + "Worker Thread for NonBlockingOutputPipe : " + getPipeID()); + serviceThread.setDaemon(true); + serviceThread.start(); + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( + "Thread start : " + serviceThread.getName() + "\n\tworker state : " + workerstate + "\tqueue closed : " + + queue.isClosed() + "\tnumber in queue : " + queue.getCurrentInQueue() + "\tnumber queued : " + + queue.getNumEnqueued() + "\tnumber dequeued : " + queue.getNumDequeued()); + } + } + } + + /** + * Convenience method for constructing a peer endpoint address from its + * peer id + * + * @param destPeer the desitnation peer + * @param pipeID the pipe to put in the param field. + * @return the pipe endpoint address. + */ + protected EndpointAddress mkAddress(ID destPeer, ID pipeID) { + return new EndpointAddress("jxta", destPeer.getUniqueValue().toString(), "PipeService", pipeID.toString()); + } + + /** + * {@inheritDoc} + */ + public synchronized boolean pipeNAKEvent(PipeResolver.Event event) { + + if (((workerstate == WorkerState.PENDINGVERIFY) || (workerstate == WorkerState.ACQUIREMESSENGER) + || (workerstate == WorkerState.SENDMESSAGES)) + && (event.getPeerID().equals(destPeer) && (event.getQueryID() == queryID))) { + // we have been told that the destination peer no longer wants + // to talk with us. We will try to migrate to another peer. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe \'" + getPipeID() + "\' is closed at " + event.getPeerID()); + } + + workerstate = WorkerState.STARTMIGRATE; + pipeResolver.removeListener(getPipeID(), queryID); + queryID = -1; + destPeer = null; + destAddress = null; + if (null != destMessenger) { + destMessenger.close(); + destMessenger = null; + } + notify(); + return true; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring NAK from " + event.getPeerID()); + } + + // didn't refer to us or we don't care. + return false; + } + + /** + * {@inheritDoc} + */ + public synchronized boolean pipeResolveEvent(PipeResolver.Event event) { + + if (((workerstate == WorkerState.PENDINGVERIFY) || (workerstate == WorkerState.PENDINGMIGRATE)) + && (event.getQueryID() == queryID)) { + if ((workerstate == WorkerState.PENDINGVERIFY) && !event.getPeerID().equals(destPeer)) { + // not from the right peer so ignore it. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring response from " + event.getPeerID()); + } + return false; + } else { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Pipe \'" + getPipeID() + "\' is verified for " + destPeer); + } + } + + workerstate = WorkerState.ACQUIREMESSENGER; + migrated = true; + destPeer = event.getPeerID(); + + if ((workerstate == WorkerState.PENDINGMIGRATE) && Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Pipe \'" + getPipeID() + "\' has migrated to " + destPeer); + } + notify(); + return true; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring resolve from " + event.getPeerID()); + } + // didn't refer to us or we don't care. + return false; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/NonBlockingWireOutputPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/NonBlockingWireOutputPipe.java new file mode 100644 index 000000000..93023f1cc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/NonBlockingWireOutputPipe.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.OutputPipe; +import net.jxta.protocol.PipeAdvertisement; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An implementation of Ouput Pipe which sends messages on the pipe + * asynchronously. The send() method for this implementation will + * never block. + */ +class NonBlockingWireOutputPipe implements OutputPipe { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(NonBlockingWireOutputPipe.class.getName()); + + /** + * If true then the pipe has been closed and will no longer accept messages. + */ + private volatile boolean closed = false; + + /** + * Group in which we are working. + */ + private final PeerGroup peerGroup; + + /** + * The endpoint of our group. + */ + private final WirePipe wire; + + /** + * The advertisement we were created from. + */ + private final PipeAdvertisement pAdv; + + /** + * The set of peers to which messages on this pipe are sent. If empty then + * the message is sent to all propagation targets. + */ + private final Set destPeers; + + /** + * Create a new output pipe + * + * @param group The peergroup we are working in. + * @param wire The propagate pipe service. + * @param pAdv advertisement for the pipe we are supporting. + * @param peers the set of peers we allow this pipe to be bound to. + */ + public NonBlockingWireOutputPipe(PeerGroup group, WirePipe wire, PipeAdvertisement pAdv, Set peers) { + + peerGroup = group; + this.wire = wire; + this.destPeers = new HashSet(peers); + this.pAdv = pAdv; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Constructing for " + getPipeID()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized void close() { + + // Close the queue so that no more messages are accepted + if (!closed) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closing queue for " + getPipeID()); + } + } + closed = true; + } + + /** + * {@inheritDoc} + */ + public boolean isClosed() { + return closed; + } + + /** + * {@inheritDoc} + */ + public final String getType() { + return pAdv.getType(); + } + + /** + * {@inheritDoc} + */ + public final ID getPipeID() { + return pAdv.getPipeID(); + } + + /** + * {@inheritDoc} + */ + public final String getName() { + return pAdv.getName(); + } + + /** + * {@inheritDoc} + */ + public final PipeAdvertisement getAdvertisement() { + return pAdv; + } + + /** + * {@inheritDoc} + */ + public boolean send(Message message) throws IOException { + if (closed) { + // also throw it here to void the extra operations + throw new IOException("Pipe closed"); + } + + WireHeader header = new WireHeader(); + header.setPipeID(getPipeID()); + header.setSrcPeer(peerGroup.getPeerID()); + header.setTTL(destPeers.isEmpty() ? 200 : 1); + header.setMsgId(WirePipe.createMsgId()); + + XMLDocument asDoc = (XMLDocument) header.getDocument(MimeMediaType.XMLUTF8); + MessageElement elem = new TextDocumentMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAME, asDoc, null); + + Message msg = message.clone(); + msg.replaceMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAMESPACE, elem); + return sendUnModified(msg, header); + } + + /** + * Sends a message unaltered + * + * @param msg the message to send + * @return true if successful + * @throws IOException if an io error occurs + * @param header message header + */ + boolean sendUnModified(Message msg, WireHeader header) throws IOException { + if (closed) { + throw new IOException("Pipe closed"); + } + wire.sendMessage(msg, destPeers, header); + // we are here, there are not io exception, we assume it succeeded + return true; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeRegistrar.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeRegistrar.java new file mode 100644 index 000000000..71bd0f1d5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeRegistrar.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.pipe.InputPipe; + +/** + * Interface for classes which manage input pipe registrations. + */ +interface PipeRegistrar { + + /** + * Register that this peer is an InputPipe for the specified Pipe ID. + * + * @param pipe The InputPipe to be registered. + * @return If {@code true} then the pipe was registered, otherwise + * {@code false}. + */ + boolean register(InputPipe pipe); + + /** + * This peer is no longer listening on the specified pipe. + * + * @param pipe The InputPipe to be forgotten. + * @return {@code true} if the pipe was removed otherwise {@code false}. + */ + boolean forget(InputPipe pipe); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeResolver.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeResolver.java new file mode 100644 index 000000000..768bb15ba --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeResolver.java @@ -0,0 +1,1218 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.credential.Credential; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.id.ID; +import net.jxta.impl.cm.Srdi; +import net.jxta.impl.cm.Srdi.SrdiInterface; +import net.jxta.impl.cm.SrdiIndex; +import net.jxta.impl.protocol.PipeResolverMsg; +import net.jxta.impl.protocol.ResolverQuery; +import net.jxta.impl.protocol.SrdiMessageImpl; +import net.jxta.impl.resolver.InternalQueryHandler; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.protocol.PipeResolverMessage; +import net.jxta.protocol.PipeResolverMessage.MessageType; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.protocol.SrdiMessage; +import net.jxta.protocol.SrdiMessage.Entry; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezVousStatus; +import net.jxta.resolver.ResolverService; +import net.jxta.resolver.SrdiHandler; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EventListener; +import java.util.EventObject; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements the Resolver interfaces for a PipeServiceImpl. + */ +class PipeResolver implements SrdiInterface, InternalQueryHandler, SrdiHandler, PipeRegistrar { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(PipeResolver.class.getName()); + + private final static String PipeResolverName = "JxtaPipeResolver"; + private final static String srdiIndexerFileName = "pipeResolverSrdi"; + + /** + * Local SRDI GC Interval + */ + private final static long GcDelay = 1 * TimeUtils.AMINUTE; + + /** + * Constant for pipe event listeners to signify any query id. + */ + final static int ANYQUERY = 0; + + /** + * The current query ID. The next value returned by {@link #getNextQueryID()} + * will be one greater than this value. + */ + private static int currentQueryID = 1; + + /** + * Group we are working for + */ + private PeerGroup myGroup = null; + /** + * Group we are working for + */ + private EndpointService endpoint = null; + + /** + * Resolver Service we will register with + */ + private ResolverService resolver = null; + + /** + * The discovery service we will use + */ + private DiscoveryService discovery = null; + + /** + * Membership Service we will use + */ + private MembershipService membership = null; + + private Srdi srdi = null; + private Thread srdiThread = null; + private SrdiIndex srdiIndex = null; + private RendezVousService rendezvous = null; + + /** + * The locally registered {@link net.jxta.pipe.InputPipe}s + */ + private final Map localInputPipes = new HashMap(); + + /** + * Registered listeners for pipe events. + */ + private final Map> outputpipeListeners = new HashMap>(); + + /** + * Encapsulates current Membership Service credential. + */ + final static class CurrentCredential { + /** + * The current default credential + */ + final Credential credential; + + /** + * The current default credential in serialized XML form. + */ + final XMLDocument credentialDoc; + + CurrentCredential(Credential credential, XMLDocument credentialDoc) { + this.credential = credential; + this.credentialDoc = credentialDoc; + } + } + + /** + * The current Membership service default credential. + */ + CurrentCredential currentCredential; + + /** + * Listener we use for membership property events. + */ + private class CredentialListener implements PropertyChangeListener { + + /** + * Standard Constructor + */ + CredentialListener() {} + + /** + * {@inheritDoc} + */ + public void propertyChange(PropertyChangeEvent evt) { + if (MembershipService.DEFAULT_CREDENTIAL_PROPERTY.equals(evt.getPropertyName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New default credential event"); + } + + synchronized (PipeResolver.this) { + Credential cred = (Credential) evt.getNewValue(); + XMLDocument credentialDoc; + + if (null != cred) { + try { + credentialDoc = (XMLDocument) cred.getDocument(MimeMediaType.XMLUTF8); + currentCredential = new CurrentCredential(cred, credentialDoc); + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not generate credential document", all); + } + currentCredential = null; + } + } else { + currentCredential = null; + } + } + } + } + } + + final CredentialListener membershipCredListener = new CredentialListener(); + + /** + * A pipe resolver event. + */ + static class Event extends EventObject { + + private final ID peerid; + private final ID pipeid; + private final String type; + private final int queryID; + + /** + * Creates a new pipe resolution event + * + * @param source The PipeResolver generating the event. + * @param peerid The peer on which the pipe was found + * @param pipeid the pipe which was found + * @param type the type of pipe which was found + * @param queryid The query id associated with the response returned in this event + */ + public Event(PipeResolver source, ID peerid, ID pipeid, String type, int queryid) { + super(source); + this.peerid = peerid; + this.pipeid = pipeid; + this.type = type; + this.queryID = queryid; + } + + /** + * Returns the peer associated with the event + * + * @return peerid + */ + public ID getPeerID() { + return peerid; + } + + /** + * Returns the pipe associated with the event + * + * @return pipeid + */ + public ID getPipeID() { + return pipeid; + } + + /** + * Returns the type of the pipe that is associated with the event + * + * @return type + */ + public String getType() { + return type; + } + + /** + * Returns The query id associated with the response returned in this event + * + * @return query id associated with the response + */ + public int getQueryID() { + return queryID; + } + } + + + /** + * Pipe Resolver Event Listener. Implement this interface is you wish to + * Receive Pipe Resolver events. + */ + interface Listener extends EventListener { + /** + * Pipe Resolve event + * + * @param event event the PipeResolver Event + * @return true if the event was handled otherwise false + */ + boolean pipeResolveEvent(Event event); + + /** + * A NAK Event was received for this pipe + * + * @param event event the PipeResolver Event + * @return true if the event was handled otherwise false + */ + boolean pipeNAKEvent(Event event); + } + + /** + * return the next query id. + * + * @return the next eligible query id. + */ + static synchronized int getNextQueryID() { + currentQueryID++; + if (currentQueryID == Integer.MAX_VALUE) { + currentQueryID = 1; + } + return currentQueryID; + } + + /** + * Constructor for the PipeResolver object + * + * @param peerGroup group for which this PipeResolver operates in + */ + PipeResolver(PeerGroup peerGroup) { + + myGroup = peerGroup; + resolver = myGroup.getResolverService(); + membership = myGroup.getMembershipService(); + rendezvous = myGroup.getRendezVousService(); + endpoint = myGroup.getEndpointService(); + + // Register to the Generic ResolverServiceImpl + resolver.registerHandler(PipeResolverName, this); + + // start srdi + srdiIndex = new SrdiIndex(myGroup, srdiIndexerFileName, GcDelay); + + srdi = new Srdi(myGroup, PipeResolverName, this, srdiIndex, 2 * TimeUtils.AMINUTE, 1 * TimeUtils.AYEAR); + srdiThread = new Thread(myGroup.getHomeThreadGroup(), srdi, "Pipe Resolver Srdi Thread"); + srdiThread.setDaemon(true); + srdiThread.start(); + + resolver.registerSrdiHandler(PipeResolverName, this); + synchronized (this) { + // register our credential listener. + membership.addPropertyChangeListener(MembershipService.DEFAULT_CREDENTIAL_PROPERTY, membershipCredListener); + try { + // set the initial version of the default credential. + currentCredential = null; + Credential credential = membership.getDefaultCredential(); + XMLDocument credentialDoc; + + if (null != credential) { + credentialDoc = (XMLDocument) credential.getDocument(MimeMediaType.XMLUTF8); + currentCredential = new CurrentCredential(credential, credentialDoc); + } + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not get default credential", all); + } + } + } + } + + private boolean isRendezvous() { + if (rendezvous == null) { + rendezvous = myGroup.getRendezVousService(); + } + RendezVousStatus mode = rendezvous.getRendezVousStatus(); + return (mode == RendezVousStatus.RENDEZVOUS ||mode == RendezVousStatus.AUTO_RENDEZVOUS); + } + + /** + * {@inheritDoc} + */ + public int processQuery(ResolverQueryMsg query) { + return processQuery(query, null); + } + + /** + * {@inheritDoc} + */ + public int processQuery(ResolverQueryMsg query, EndpointAddress srcAddr) { + + String queryFrom; + + if (null != srcAddr) { + if ("jxta".equals(srcAddr.getProtocolName())) { + queryFrom = ID.URIEncodingName + ":" + ID.URNNamespace + ":" + srcAddr.getProtocolAddress(); + } else { + // we don't know who routed us the query. Assume it came from the source. + queryFrom = query.getSrcPeer().toString(); + } + } else { + // we don't know who routed us the query. Assume it came from the source. + queryFrom = query.getSrcPeer().toString(); + } + + String responseDest = query.getSrcPeer().toString(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Starting for :" + query.getQueryId() + " from " + srcAddr); + } + + Reader queryReader = new StringReader(query.getQuery()); + StructuredTextDocument doc = null; + try { + doc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, queryReader); + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "discarding malformed request ", e); + } + // no sense in re-propagation here + return ResolverService.OK; + } finally { + try { + queryReader.close(); + } catch (IOException ignored) { + // ignored + } + queryReader = null; + } + + PipeResolverMessage pipeQuery; + try { + pipeQuery = new PipeResolverMsg(doc); + } catch (IllegalArgumentException badDoc) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "discarding malformed request ", badDoc); + } + // no sense in re-propagation here + return ResolverService.OK; + } finally { + doc = null; + } + + // is it a query? + if (!pipeQuery.getMsgType().equals(MessageType.QUERY)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("expected query - discarding."); + } + // no sense in re-propagation here + return ResolverService.OK; + } + + // see if it is a query directed at our peer. + Set destPeers = pipeQuery.getPeerIDs(); + boolean directedQuery = !destPeers.isEmpty(); + boolean queryForMe = !directedQuery; + + if (directedQuery) { + for (Object destPeer : destPeers) { + ID aPeer = (ID) destPeer; + if (aPeer.equals(myGroup.getPeerID())) { + queryForMe = true; + break; + } + } + + if (!queryForMe) { + // It is an directed query, but request wasn't for this peer. + if (query.getSrcPeer().toString().equals(queryFrom)) { + // we only respond if the original src was not the query forwarder + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("discarding query. Query not for us."); + } + // tell the resolver no further action is needed. + return ResolverService.OK; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("responding to \'misdirected\' forwarded query."); + } + responseDest = queryFrom; + } + } + + PeerID peerID = null; + if (queryForMe) { + // look locally. + InputPipe ip = findLocal((PipeID) pipeQuery.getPipeID()); + if ((ip != null) && (ip.getType().equals(pipeQuery.getPipeType()))) { + peerID = myGroup.getPeerID(); + } + } + + if ((null == peerID) && !directedQuery) { + // This request was sent to everyone. + if (myGroup.isRendezvous()) { + // We are a RDV, allow the ResolverService to repropagate the query + List results = srdiIndex.query(pipeQuery.getPipeType(), PipeAdvertisement.IdTag, + pipeQuery.getPipeID().toString(), 20); + + if (!results.isEmpty()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("forwarding query to " + results.size() + " peers"); + } + srdi.forwardQuery(results, query); + // tell the resolver no further action is needed. + return ResolverService.OK; + } + + // we don't know anything, continue the walk. + return ResolverService.Repropagate; + } else { + // We are an edge + if (query.getSrcPeer().toString().equals(queryFrom)) { + // we only respond if the original src was not the query forwarder + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("discarding query."); + } + + // tell the resolver no further action is needed. + return ResolverService.OK; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("responding to query forwarded for \'misdirected\' query."); + } + responseDest = queryFrom; + } + } + + // Build the answer + PipeResolverMessage pipeResp = new PipeResolverMsg(); + + pipeResp.setMsgType(MessageType.ANSWER); + pipeResp.setPipeID(pipeQuery.getPipeID()); + pipeResp.setPipeType(pipeQuery.getPipeType()); + if (null == peerID) { + // respond negative. + pipeResp.addPeerID(myGroup.getPeerID()); + pipeResp.setFound(false); + } else { + pipeResp.addPeerID(peerID); + pipeResp.setFound(true); + pipeResp.setInputPeerAdv(myGroup.getPeerAdvertisement()); + } + + // make a response from the incoming query + ResolverResponseMsg res = query.makeResponse(); + + CurrentCredential current = currentCredential; + if (null != current) { + res.setCredential(current.credentialDoc); + } + res.setResponse(pipeResp.getDocument(MimeMediaType.XMLUTF8).toString()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending answer for query \'" + query.getQueryId() + "\' to : " + responseDest); + } + resolver.sendResponse(responseDest, res); + return ResolverService.OK; + } + + /** + * {@inheritDoc} + */ + public void processResponse(ResolverResponseMsg response) { + processResponse(response, null); + } + + /** + * {@inheritDoc} + */ + public void processResponse(ResolverResponseMsg response, EndpointAddress srcAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("got a response for \'" + response.getQueryId() + "\'"); + } + + Reader resp = new StringReader(response.getResponse()); + StructuredTextDocument doc = null; + try { + doc = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, resp); + } catch (Throwable e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "malformed response - discard", e); + } + return; + } finally { + try { + resp.close(); + } catch (IOException ignored) {// ignored + } + resp = null; + } + + PipeResolverMessage pipeResp; + + try { + pipeResp = new PipeResolverMsg(doc); + } catch (Throwable caught) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "malformed response - discarding.", caught); + } + return; + } finally { + doc = null; + } + + // check if it's a response. + if (!pipeResp.getMsgType().equals(MessageType.ANSWER)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("expected response - discarding."); + } + return; + } + + PeerAdvertisement padv = pipeResp.getInputPeerAdv(); + + if ((null != padv) && !(myGroup.getPeerID().equals(padv.getPeerID()))) { + try { + // This is not our own peer adv so we keep it only for the default + // expiration time. + if (null == discovery) { + discovery = myGroup.getDiscoveryService(); + } + if (null != discovery) { + discovery.publish(padv, DiscoveryService.DEFAULT_EXPIRATION, DiscoveryService.DEFAULT_EXPIRATION); + } + } catch (IOException ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("could not publish peer adv"); + } + } + } + + String ipId = pipeResp.getPipeID().toString(); + + Set peerRsps = pipeResp.getPeerIDs(); + + for (Object peerRsp : peerRsps) { + // process each peer for which this response is about. + PeerID peer = (PeerID) peerRsp; + if (!pipeResp.isFound()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("NACK for pipe \'" + ipId + "\' from peer " + peer); + } + + // We have received a NACK. Remove that entry. + srdiIndex.add(pipeResp.getPipeType(), PipeAdvertisement.IdTag, ipId, peer, 0); + } else { + long exp = getEntryExp(pipeResp.getPipeType(), PipeAdvertisement.IdTag, ipId, peer); + if ((PipeServiceImpl.VERIFYINTERVAL / 2) > exp) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Using Expiration " + (PipeServiceImpl.VERIFYINTERVAL / 2) + " which is > " + exp); + } + // create antry only if one does not exist,or entry exists with + // lesser lifetime + // cache the result for half the verify interval + srdiIndex.add(pipeResp.getPipeType(), PipeAdvertisement.IdTag, ipId, peer, + (PipeServiceImpl.VERIFYINTERVAL / 2)); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("DB Expiration " + exp + " > " + (PipeServiceImpl.VERIFYINTERVAL / 2) + + " overriding attempt to decrease lifetime"); + } + } + } + + // call listener for pipeid + callListener(response.getQueryId(), pipeResp.getPipeID(), pipeResp.getPipeType(), peer, !pipeResp.isFound()); + } + } + + private long getEntryExp(String pkey, String skey, String value, PeerID peerid) { + List list = srdiIndex.getRecord(pkey, skey, value); + + for (SrdiIndex.Entry entry : list) { + if (entry.peerid.equals(peerid)) { + // exp in millis + return TimeUtils.toRelativeTimeMillis(entry.expiration); + } + } + return -1; + } + + /** + * {@inheritDoc} + */ + public boolean processSrdi(ResolverSrdiMsg message) { + + if (!isRendezvous()) { + // avoid caching in non rendezvous mode + return true; + } + if (message == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("no SRDI message"); + } + return false; + } + + if (message.getPayload() == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("empty SRDI message"); + } + return false; + } + + SrdiMessage srdiMsg; + try { + StructuredTextDocument asDoc = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(message.getPayload())); + srdiMsg = new SrdiMessageImpl(asDoc); + } catch (Throwable e) { + // we don't understand this msg, let's skip it + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Invalid SRDI message", e); + } + return false; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received an SRDI messsage with " + srdiMsg.getEntries().size() + " entries from " + srdiMsg.getPeerID()); + } + + for (Object o : srdiMsg.getEntries()) { + Entry entry = (Entry) o; + srdiIndex.add(srdiMsg.getPrimaryKey(), entry.key, entry.value, srdiMsg.getPeerID(), entry.expiration); + } + + if (!PipeService.PropagateType.equals(srdiMsg.getPrimaryKey())) { + // don't replicate entries for propagate pipes. For unicast type + // pipes the replica is useful in finding pipe instances. Since + // walking rather than searching is done for propagate pipes this + // appropriate. + srdi.replicateEntries(srdiMsg); + } + return true; + } + + /** + * {@inheritDoc} + */ + public void messageSendFailed(PeerID peerid, OutgoingMessageEvent e) {// so what. + } + + /** + * {@inheritDoc} + */ + public void pushEntries(boolean all) { + pushSrdi((PeerID) null, all); + } + + /** + * unregisters the resolver handler + */ + void stop() { + + resolver.unregisterHandler(PipeResolverName); + resolver.unregisterSrdiHandler(PipeResolverName); + + srdiIndex.stop(); + srdiIndex = null; + // stop the srdi thread + if (srdiThread != null) { + srdi.stop(); + } + srdiThread = null; + srdi = null; + + membership.removePropertyChangeListener("defaultCredential", membershipCredListener); + currentCredential = null; + + // Avoid cross-reference problems with GC + myGroup = null; + resolver = null; + discovery = null; + membership = null; + + outputpipeListeners.clear(); + + // close the local pipes + List openLocalPipes = new ArrayList(localInputPipes.values()); + for (InputPipe aPipe : openLocalPipes) { + try { + aPipe.close(); + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failure closing " + aPipe); + } + } + } + + localInputPipes.clear(); + } + + /** + * {@inheritDoc} + */ + public boolean register(InputPipe ip) { + + PipeID pipeID = (PipeID) ip.getPipeID(); + synchronized (this) { + if (localInputPipes.containsKey(pipeID)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Existing registered InputPipe for " + pipeID); + } + return false; + } + + // Register this input pipe + boolean registered = endpoint.addIncomingMessageListener((EndpointListener) ip, "PipeService", pipeID.toString()); + if (!registered) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Existing registered Endpoint Listener for " + pipeID); + } + return false; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Registering local InputPipe for " + pipeID); + } + localInputPipes.put(pipeID, ip); + } + + // Announce the pipe to SRDI so that others will know we are listening. + pushSrdi(ip, true); + + // Call anyone who may be listening for this input pipe. + callListener(0, pipeID, ip.getType(), myGroup.getPeerID(), false); + return true; + } + + /** + * Return the local {@link net.jxta.pipe.InputPipe InputPipe}, if any, for the + * specified {@link net.jxta.pipe.PipeID PipeID}. + * + * @param pipeID the PipeID who's InputPipe is desired. + * @return The InputPipe object. + */ + public InputPipe findLocal(PipeID pipeID) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Find local InputPipe for " + pipeID); + } + + // First look if the pipe is a local InputPipe + InputPipe ip = localInputPipes.get(pipeID); + // Found it. + if ((null != ip) && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("found local InputPipe for " + pipeID); + } + return ip; + } + + /** + * {@inheritDoc} + */ + public boolean forget(InputPipe pipe) { + + PipeID pipeID = (PipeID) pipe.getPipeID(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unregistering local InputPipe for " + pipeID); + } + + // Unconditionally announce the change to SRDI. + // FIXME 20040529 bondolo This is overkill, it should be able to wait + // until the deltas are pushed. + pushSrdi(pipe, false); + + InputPipe ip; + + synchronized (this) { + ip = localInputPipes.remove(pipeID); + } + + if (pipe != ip) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe removed was not the same as the pipe to be removed!"); + } + } + + if (null != ip) { + // remove the queue for the general demux + EndpointListener removed = endpoint.removeIncomingMessageListener("PipeService", pipeID.toString()); + + if ((null == removed) || (pipe != removed)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("removeIncomingMessageListener() did not remove correct pipe!"); + } + } + } + + return (ip != null); + } + + /** + * Add a pipe resolver listener + * + * @param listener listener + * @param queryID The query this callback is being made in response to. + * @param pipeID The pipe which is the subject of the event. + * @return true if sucessfully added + */ + synchronized boolean addListener(ID pipeID, Listener listener, int queryID) { + + Map perpipelisteners = outputpipeListeners.get(pipeID); + + // if no map for this pipeid, make one and add it to the top map. + if (null == perpipelisteners) { + perpipelisteners = new HashMap(); + outputpipeListeners.put(pipeID, perpipelisteners); + } + + boolean alreadyThere = perpipelisteners.containsKey(queryID); + + if (!alreadyThere) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("adding listener for " + pipeID + " / " + queryID); + } + + perpipelisteners.put(queryID, listener); + } + + return alreadyThere; + } + + /** + * Call the listener for the specified pipe id informing it about the + * specified peer. + * + * @param qid The query this callback is being made in response to. + * @param pipeID The pipe which is the subject of the event. + * @param type The type of the pipe which is the subject of the event. + * @param peer The peer on which the remote input pipe was found. + * @param NAK indicate whether the event is a nack + */ + void callListener(int qid, ID pipeID, String type, PeerID peer, boolean NAK) { + + Event newevent = new Event(this, peer, pipeID, type, qid); + boolean handled = false; + + while (!handled) { + Listener pipeListener; + + synchronized (this) { + Map perpipelisteners = outputpipeListeners.get(pipeID); + if (null == perpipelisteners) { + if ((ANYQUERY != qid) && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No listener for pipe " + pipeID); + } + break; + } + pipeListener = perpipelisteners.get(qid); + } + + if (null != pipeListener) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Calling Pipe resolver listener " + (NAK ? "NAK " : "") + "for " + pipeID); + } + + try { + if (NAK) { + handled = pipeListener.pipeNAKEvent(newevent); + } else { + handled = pipeListener.pipeResolveEvent(newevent); + } + } catch (Throwable ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING + , + "Uncaught Throwable in listener for: " + pipeID + "(" + pipeListener.getClass().getName() + ")", ignored); + } + } + } + + // if we havent tried it already, try it with the ANYQUERY + if (ANYQUERY == qid) { + break; + } + qid = ANYQUERY; + } + } + + /** + * Remove a pipe resolver listener + * + * @param pipeID listener to remove + * @param queryID matching queryid. + * @return listener object removed + */ + synchronized Listener removeListener(ID pipeID, int queryID) { + + Map perpipelisteners = outputpipeListeners.get(pipeID); + + if (null == perpipelisteners) { + return null; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removing listener for " + pipeID + " / " + queryID); + } + Listener removedListener = perpipelisteners.remove(queryID); + + if (perpipelisteners.isEmpty()) { + outputpipeListeners.remove(pipeID); + } + + return removedListener; + } + + /** + * Send a request to find an input pipe + * + * @param adv the advertisement for the pipe we are seeking. + * @param acceptablePeers the set of peers at which we wish the pipe to + * be resolved. We will not accept responses from peers other than those + * in this set. Empty set means all peers are acceptable. + * @param queryID the query ID to use for the query. if zero then a query + * ID will be generated + * @return the query id under which the request was sent + */ + int sendPipeQuery(PipeAdvertisement adv, Set acceptablePeers, int queryID) { + + // choose a query id if non-prechosen. + if (0 == queryID) { + queryID = getNextQueryID(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine((acceptablePeers.isEmpty() ? "Undirected" : "Directed") + " query (" + queryID + ") for " + adv.getPipeID()); + } + + Collection targetPeers = new ArrayList(acceptablePeers); + + // check local srdi to see if we have a potential answer + List knownLocations = srdiIndex.query(adv.getType(), PipeAdvertisement.IdTag, adv.getPipeID().toString(), 100); + + if (!knownLocations.isEmpty()) { + // we think we know where the pipe might be... + + if (!acceptablePeers.isEmpty()) { + // only keep those peers which are acceptable. + knownLocations.retainAll(acceptablePeers); + } + + // if the known locations contain any of the acceptable peers then + // we will send a directed query to ONLY those peers. + if (!knownLocations.isEmpty()) { + targetPeers = knownLocations; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Using SRDI cache results for directed query (" + queryID + ") for " + adv.getPipeID()); + } + } + } + + // build the pipe query message. + PipeResolverMessage pipeQry = new PipeResolverMsg(); + + pipeQry.setMsgType(MessageType.QUERY); + pipeQry.setPipeID(adv.getPipeID()); + pipeQry.setPipeType(adv.getType()); + + for (Object targetPeer : targetPeers) { + pipeQry.addPeerID((PeerID) targetPeer); + } + + StructuredTextDocument asDoc = (StructuredTextDocument) pipeQry.getDocument(MimeMediaType.XMLUTF8); + + // build the resolver query + ResolverQuery query = new ResolverQuery(); + + query.setHandlerName(PipeResolverName); + query.setQueryId(queryID); + query.setSrcPeer(myGroup.getPeerID()); + query.setQuery(asDoc.toString()); + + CurrentCredential current = currentCredential; + + if (null != current) { + query.setCredential(current.credentialDoc); + } + + if (targetPeers.isEmpty()) { + // we have no idea, walk the tree + + if (myGroup.isRendezvous()) { + // We are a rdv, then send it to the replica peer. + + PeerID peer = srdi.getReplicaPeer(pipeQry.getPipeType() + PipeAdvertisement.IdTag + pipeQry.getPipeID().toString()); + if (null != peer) { + srdi.forwardQuery(peer, query); + return queryID; + } + } + + resolver.sendQuery(null, query); + } else { + // send it only to the peers whose result we would accept. + + for (ID targetPeer : targetPeers) { + resolver.sendQuery(targetPeer.toString(), query); + } + } + return queryID; + } + + /** + * {@inheritDoc} + */ + SrdiIndex getSrdiIndex() { + return srdiIndex; + } + + /** + * {@inheritDoc} + *

            + * This implementation knows nothing of deltas, it just pushes it all. + */ + private void pushSrdi(PeerID peer, boolean all) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Pushing " + (all ? "all" : "deltas") + " SRDI to " + peer); + } + + Map> types = new HashMap>(); + + synchronized (this) { + for (InputPipe ip : localInputPipes.values()) { + Entry entry = new Entry(PipeAdvertisement.IdTag, ip.getPipeID().toString(), Long.MAX_VALUE); + String type = ip.getType(); + List entries = types.get(type); + + if (null == entries) { + entries = new ArrayList(); + types.put(type, entries); + } + entries.add(entry); + } + } + + for (String type : types.keySet()) { + List entries = types.get(type); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a Pipe SRDI messsage in " + myGroup.getPeerGroupID() + " of " + entries.size() + " entries of type " + type); + } + + SrdiMessage srdiMsg = new SrdiMessageImpl(myGroup.getPeerID(), 1, type, entries); + if (null == peer) { + srdi.pushSrdi(null, srdiMsg); + } else { + srdi.pushSrdi(peer, srdiMsg); + } + } + } + + /** + * Push SRDI entry for the specified pipe + * + * @param ip the pipe who's entry we are pushing + * @param adding adding an entry for the pipe or expiring the entry? + */ + private void pushSrdi(InputPipe ip, boolean adding) { + + srdiIndex.add(ip.getType(), PipeAdvertisement.IdTag, ip.getPipeID().toString(), myGroup.getPeerID(), + adding ? Long.MAX_VALUE : 0); + + SrdiMessage srdiMsg; + try { + srdiMsg = new SrdiMessageImpl(myGroup.getPeerID(), 1, // ttl + ip.getType(), PipeAdvertisement.IdTag, ip.getPipeID().toString(), adding ? Long.MAX_VALUE : 0); + + if (myGroup.isRendezvous()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Replicating a" + (adding ? "n add" : " remove") + " Pipe SRDI entry for pipe [" + ip.getPipeID() + + "] of type " + ip.getType()); + } + + srdi.replicateEntries(srdiMsg); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a" + (adding ? "n add" : " remove") + " Pipe SRDI messsage for pipe [" + ip.getPipeID() + + "] of type " + ip.getType()); + } + srdi.pushSrdi(null, srdiMsg); + } + } catch (Throwable e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught throwable pushing SRDI entries", e); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeServiceImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeServiceImpl.java new file mode 100644 index 000000000..e36833d0b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeServiceImpl.java @@ -0,0 +1,748 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.pipe; + + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.OutputPipeEvent; +import net.jxta.pipe.OutputPipeListener; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.service.Service; +import net.jxta.peer.PeerID; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.text.MessageFormat; + + +/** + * A JXTA {@link net.jxta.pipe.PipeService} implementation which implements the + * standard JXTA Pipe Resolver Protocol (PRP). + *

            + * This class provides implementation for Unicast, unicast secure and + * (indirectly) propagate pipes. + * + * @see net.jxta.pipe.PipeService + * @see net.jxta.pipe.InputPipe + * @see net.jxta.pipe.OutputPipe + * @see net.jxta.endpoint.Message + * @see net.jxta.protocol.PipeAdvertisement + * @see net.jxta.protocol.PipeResolverMessage + * @see JXTA Protocols Specification : Pipe Binding Protocol + */ +public class PipeServiceImpl implements PipeService, PipeResolver.Listener { + + /** + * The Logger + */ + private final static Logger LOG = Logger.getLogger(PipeServiceImpl.class.getName()); + + /** + * the interval at which we verify that a pipe is still resolved at a + * remote peer. + */ + static final long VERIFYINTERVAL = 20 * TimeUtils.AMINUTE; + + /** + * The group this PipeService is working for. + */ + private PeerGroup group = null; + + /** + * Our resolver handler. + */ + private PipeResolver pipeResolver = null; + + /** + * Link to wire pipe impl. + */ + private WirePipeImpl wirePipe = null; + + /** + * the interface object we will hand out. + */ + private PipeService myInterface = null; + + /** + * the impl advertisement for this impl. + */ + private ModuleImplAdvertisement implAdvertisement = null; + + /** + * Table of listeners for asynchronous output pipe creation. + *

            + *

              + *
            • keys are {@link net.jxta.pipe.PipeID}
            • + *
            • values are {@link java.util.Map}
            • + *
            + * Within the value Map: + *
              + *
            • keys are {@link java.lang.Integer} representing queryid
            • + *
            • values are {@link OutputPipeHolder}
            • + *
            + */ + private final Map> outputPipeListeners = new HashMap>(); + + /** + * Has the pipe service been started? + */ + private volatile boolean started = false; + + /** + * holds a pipe adv and a listener which will be called for resolutions + * of the pipe. + */ + private static class OutputPipeHolder { + final PipeAdvertisement adv; + final Set peers; + final OutputPipeListener listener; + final int queryid; + + OutputPipeHolder(PipeAdvertisement adv, Set peers, OutputPipeListener listener, int queryid) { + this.adv = adv; + this.peers = peers; + this.listener = listener; + this.queryid = queryid; + } + } + + + /** + * A listener useful for implementing synchronous behaviour. + */ + private static class syncListener implements OutputPipeListener { + + volatile OutputPipeEvent event = null; + + syncListener() {} + + /** + * Called when a input pipe has been located for a previously registered + * pipe. The event contains an {@link net.jxta.pipe.OutputPipe} which can + * be used to communicate with the remote peer. + * + * @param event net.jxta.pipe.outputPipeEvent event + */ + public synchronized void outputPipeEvent(OutputPipeEvent event) { + // we only accept the first event. + if (null == this.event) { + this.event = event; + notifyAll(); + } + } + } + + /** + * Default Constructor (don't delete) + */ + public PipeServiceImpl() {// What is reason for this constructor??? + // the same is automatically generated. + } + + /** + * {@inheritDoc} + *

            + * We create only a single interface object and return it over and over + * again. + */ + public synchronized PipeService getInterface() { + if (null == myInterface) { + myInterface = new PipeServiceInterface(this); + } + return myInterface; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + */ + public synchronized void init(PeerGroup group, ID assignedID, Advertisement impl) { + + this.group = group; + implAdvertisement = (ModuleImplAdvertisement) impl; + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Pipe Service : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tVerify Interval : " + VERIFYINTERVAL + "ms"); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + *

            + * Currently this service does not expect arguments. + */ + public synchronized int startApp(String[] args) { + + Service needed = group.getEndpointService(); + + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return START_AGAIN_STALLED; + } + + needed = group.getResolverService(); + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a resolver service"); + } + return START_AGAIN_STALLED; + } + + needed = group.getMembershipService(); + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + return START_AGAIN_STALLED; + } + + needed = group.getRendezVousService(); + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a rendezvous service"); + } + return START_AGAIN_STALLED; + } + + // create our resolver handler; it will register itself w/ the resolver. + pipeResolver = new PipeResolver(group); + + // Create the WirePipe (propagated pipe) + wirePipe = new WirePipeImpl(group, pipeResolver); + + // XXX 20061221 We could check the result of this. + wirePipe.startApp(args); + + started = true; + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public synchronized void stopApp() { + started = false; + + try { + if (wirePipe != null) { + wirePipe.stopApp(); + } + } catch (Throwable failed) { + LOG.log(Level.SEVERE, "Failed to stop wire pipe", failed); + } finally { + wirePipe = null; + } + + try { + if (pipeResolver != null) { + pipeResolver.stop(); + } + } catch (Throwable failed) { + LOG.log(Level.SEVERE, "Failed to stop pipe resolver", failed); + } finally { + pipeResolver = null; + } + + // Avoid cross-reference problem with GC + group = null; + myInterface = null; + + // clear outputPipeListeners + Collection> values = outputPipeListeners.values(); + + for (Map value : values) { + value.clear(); + } + outputPipeListeners.clear(); + } + + /** + * {@inheritDoc} + */ + public InputPipe createInputPipe(PipeAdvertisement adv) throws IOException { + return createInputPipe(adv, null); + } + + /** + * {@inheritDoc} + */ + public InputPipe createInputPipe(PipeAdvertisement adv, PipeMsgListener listener) throws IOException { + + if (!started) { + throw new IllegalStateException("Pipe Service has not been started or has been stopped"); + } + + String type = adv.getType(); + + if (type == null) { + throw new IllegalArgumentException("PipeAdvertisement type may not be null"); + } + + PipeID pipeId = (PipeID) adv.getPipeID(); + + if (pipeId == null) { + throw new IllegalArgumentException("PipeAdvertisement PipeID may not be null"); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Create " + type + " InputPipe for " + pipeId); + } + + InputPipe inputPipe; + // create an InputPipe. + if (type.equals(PipeService.UnicastType)) { + inputPipe = new InputPipeImpl(pipeResolver, adv, listener); + } else if (type.equals(PipeService.UnicastSecureType)) { + inputPipe = new SecureInputPipeImpl(pipeResolver, adv, listener); + } else if (type.equals(PipeService.PropagateType)) { + if (wirePipe != null) { + inputPipe = wirePipe.createInputPipe(adv, listener); + } else { + throw new IOException("No propagated pipe servive available"); + } + } else { + // Unknown type + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Cannot create pipe for unknown type : " + type); + } + throw new IOException("Cannot create pipe for unknown type : " + type); + } + return inputPipe; + } + + /** + * {@inheritDoc} + */ + public OutputPipe createOutputPipe(PipeAdvertisement pipeAdv, long timeout) throws IOException { + return createOutputPipe(pipeAdv, Collections.emptySet(), timeout); + } + + /** + * {@inheritDoc} + */ + public OutputPipe createOutputPipe(PipeAdvertisement adv, Set resolvablePeers, long timeout) throws IOException { + // convert zero to max value. + if (0 == timeout) { + timeout = Long.MAX_VALUE; + } + + long absoluteTimeOut = TimeUtils.toAbsoluteTimeMillis(timeout); + + // Make a listener, start async resolution and then wait until the timeout expires. + syncListener localListener = new syncListener(); + + int queryid = PipeResolver.getNextQueryID(); + + createOutputPipe(adv, resolvablePeers, localListener, queryid); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Waiting synchronously for " + timeout + "ms to resolve OutputPipe for " + adv.getPipeID()); + } + + try { + synchronized (localListener) { + while ((null == localListener.event) && (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), absoluteTimeOut) < 0)) { + try { + localListener.wait(TimeUtils.ASECOND); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + } + } finally { + // remove the listener we installed. + removeOutputPipeListener(adv.getPipeID().toString(), queryid); + } + + if (null != localListener.event) { + return localListener.event.getOutputPipe(); + } else { + throw new IOException("Output Pipe could not be resolved after " + timeout + "ms."); + } + } + + /** + * {@inheritDoc} + */ + public void createOutputPipe(PipeAdvertisement pipeAdv, OutputPipeListener listener) throws IOException { + createOutputPipe(pipeAdv, Collections.emptySet(), listener); + } + + /** + * {@inheritDoc} + */ + public void createOutputPipe(PipeAdvertisement pipeAdv, Set resolvablePeers, OutputPipeListener listener) throws IOException { + createOutputPipe(pipeAdv, resolvablePeers, listener, PipeResolver.getNextQueryID()); + } + + private void createOutputPipe(PipeAdvertisement pipeAdv, Set resolvablePeers, OutputPipeListener listener, int queryid) throws IOException { + + if (!started) { + throw new IOException("Pipe Service has not been started or has been stopped"); + } + + // Recover the PipeId from the PipeServiceImpl Advertisement + PipeID pipeId = (PipeID) pipeAdv.getPipeID(); + String type = pipeAdv.getType(); + + if (null == type) { + IllegalArgumentException failed = new IllegalArgumentException("Pipe type was not set"); + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, failed.getMessage(), failed); + } + throw failed; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Create " + type + " OutputPipe for " + pipeId); + } + + if (PipeService.PropagateType.equals(type)) { + OutputPipe op; + + if (resolvablePeers.size() == 1) { + op = new BlockingWireOutputPipe(group, pipeAdv, (PeerID) resolvablePeers.iterator().next()); + } else { + if (wirePipe != null) { + op = wirePipe.createOutputPipe(pipeAdv, resolvablePeers); + } else { + throw new IOException("No propagated pipe service available"); + } + } + + if (null != op) { + OutputPipeEvent newevent = new OutputPipeEvent(this.getInterface(), op, pipeId.toString(), PipeResolver.ANYQUERY); + + try { + listener.outputPipeEvent(newevent); + } catch (Throwable ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, + "Uncaught Throwable in listener for " + pipeId + " (" + listener.getClass().getName() + ")", + ignored); + } + } + } + } else if (PipeService.UnicastType.equals(type) || PipeService.UnicastSecureType.equals(type)) { + + addOutputPipeListener(pipeId, new OutputPipeHolder(pipeAdv, resolvablePeers, listener, queryid)); + pipeResolver.addListener(pipeId, this, queryid); + pipeResolver.sendPipeQuery(pipeAdv, resolvablePeers, queryid); + + // look locally for the pipe + if (resolvablePeers.isEmpty() || resolvablePeers.contains(group.getPeerID())) { + InputPipe local = pipeResolver.findLocal(pipeId); + + // if we have a local instance, make sure the local instance is of the same type. + if (null != local) { + if (local.getType().equals(pipeAdv.getType())) { + pipeResolver.callListener(queryid, pipeId, local.getType(), group.getPeerID(), false); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning(MessageFormat.format("rejecting local pipe ({0}) because type is not ({1})", local.getType(), + pipeAdv.getType())); + } + } + } + } + } else { + // Unknown type + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("createOutputPipe: cannot create pipe for unknown type : " + type); + } + throw new IOException("cannot create pipe for unknown type : " + type); + } + } + + /* + * Add an output listener for the given pipeId. + */ + private void addOutputPipeListener(PipeID pipeId, OutputPipeHolder pipeHolder) { + synchronized (outputPipeListeners) { + Map perpipelisteners = outputPipeListeners.get(pipeId); + + if (perpipelisteners == null) { + perpipelisteners = new HashMap(); + outputPipeListeners.put(pipeId, perpipelisteners); + } + if (perpipelisteners.get(pipeHolder.queryid) != null) { + LOG.warning("Clobbering output pipe listener for query " + pipeHolder.queryid); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Adding pipe listener for pipe " + pipeId + " and query " + pipeHolder.queryid); + } + perpipelisteners.put(pipeHolder.queryid, pipeHolder); + } + } + + /** + * {@inheritDoc} + */ + public OutputPipeListener removeOutputPipeListener(String pipeID, OutputPipeListener listener) { + throw new UnsupportedOperationException("Legacy method not supported. Use interface object if you need this method."); + } + + /** + * {@inheritDoc} + */ + public OutputPipeListener removeOutputPipeListener(ID pipeID, OutputPipeListener listener) { + + // remove all instances of this listener, regardless of queryid + if (pipeResolver == null) { + return null; + } + + if (!(pipeID instanceof PipeID)) { + throw new IllegalArgumentException("pipeID must be a PipeID."); + } + + synchronized (outputPipeListeners) { + Map perpipelisteners = outputPipeListeners.get(pipeID); + + if (perpipelisteners != null) { + Set> entries = perpipelisteners.entrySet(); + + for (Map.Entry entry : entries) { + OutputPipeHolder pl = entry.getValue(); + + if (pl.listener == listener) { + pipeResolver.removeListener((PipeID) pipeID, pl.queryid); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing listener for query " + pl.queryid); + } + perpipelisteners.remove(entry.getKey()); + } + } + // clean up the map if there are no more listeners for the pipe + if (perpipelisteners.isEmpty()) { + outputPipeListeners.remove(pipeID); + } + } + } + return listener; + } + + private OutputPipeListener removeOutputPipeListener(String opID, int queryID) { + + if (pipeResolver == null) { + return null; + } + + PipeID pipeID; + try { + URI aPipeID = new URI(opID); + pipeID = (PipeID) IDFactory.fromURI(aPipeID); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad pipe ID: " + opID); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("id was not a pipe id: " + opID); + } + + synchronized (outputPipeListeners) { + Map perpipelisteners = outputPipeListeners.get(pipeID); + + if (perpipelisteners != null) { + OutputPipeHolder pipeHolder = perpipelisteners.get(queryID); + + perpipelisteners.remove(queryID); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing listener for query " + queryID); + } + // clean up the map if there are no more listeners for the pipe + if (perpipelisteners.isEmpty()) { + outputPipeListeners.remove(pipeID); + } + pipeResolver.removeListener(pipeID, queryID); + if (pipeHolder != null) { + return pipeHolder.listener; + } + } + + } + return null; + } + + /** + * {@inheritDoc} + */ + public boolean pipeResolveEvent(PipeResolver.Event event) { + + try { + ID peerID = event.getPeerID(); + ID pipeID = event.getPipeID(); + int queryID = event.getQueryID(); + OutputPipeHolder pipeHolder; + + synchronized (outputPipeListeners) { + Map perpipelisteners = outputPipeListeners.get(pipeID); + + if (perpipelisteners == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No listener for event for pipe " + pipeID); + } + return false; + } + pipeHolder = perpipelisteners.get(queryID); + if (pipeHolder == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No listener for event for query " + queryID); + } + return false; + } + } + + // check if they wanted a resolve from a specific peer. + if (!pipeHolder.peers.isEmpty() && !pipeHolder.peers.contains(peerID)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Event was for wrong peer \'" + peerID + "\'. Discarding."); + } + return false; + } + + // create op + String type = pipeHolder.adv.getType(); + OutputPipe op; + + if (PipeService.UnicastType.equals(type)) { + op = new NonBlockingOutputPipe(group, pipeResolver, pipeHolder.adv, peerID, pipeHolder.peers); + } else if (PipeService.UnicastSecureType.equals(type)) { + op = new SecureOutputPipe(group, pipeResolver, pipeHolder.adv, peerID, pipeHolder.peers); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not create output pipe of type \'" + type + "\'. Discarding."); + } + return false; + } + + // Generate an event when the output pipe was succesfully opened. + OutputPipeEvent newevent = new OutputPipeEvent(this.getInterface(), op, pipeID.toString(), queryID); + try { + pipeHolder.listener.outputPipeEvent(newevent); + } catch (Throwable ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE + , + "Uncaught Throwable in listener for " + pipeID + "(" + pipeHolder.getClass().getName() + ")", ignored); + } + } + removeOutputPipeListener(pipeID.toString(), queryID); + return true; + } catch (IOException ie) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Error creating output pipe " + event.getPipeID(), ie); + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No listener for event for " + event.getPipeID()); + } + return false; + } + + /** + * {@inheritDoc} + *

            + * We don't do anything with NAKs (yet) + */ + public boolean pipeNAKEvent(PipeResolver.Event event) { + return false; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeServiceInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeServiceInterface.java new file mode 100644 index 000000000..b36266911 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/PipeServiceInterface.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.*; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.peer.PeerID; + +import java.io.IOException; +import java.net.URI; +import java.util.Set; +import net.jxta.protocol.ModuleImplAdvertisement; + +/** + * This class implements the Pipe interface. + */ +class PipeServiceInterface implements PipeService { + + PipeServiceImpl impl; + + /** + * The only authorized constructor. + * @param theRealThing the PipeService + */ + public PipeServiceInterface(PipeServiceImpl theRealThing) { + impl = theRealThing; + } + + /** + * {@inheritDoc} + *

            + * Since THIS is already such an object, it returns itself. + * FIXME: it is kind of absurd to have this method part of the + * interface but we do not want to define two levels of Service interface + * just for that. + * + * @return ResolverService An interface object that implements + * this service and nothing more. + */ + public PipeService getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return impl.getImplAdvertisement(); + } + + /** + * {@inheritDoc} + *

            + * FIXME: This is meaningless for the interface object; + * it is there only to satisfy the requirements of the + * interface that we implement. Ultimately, the API should define + * two levels of interfaces: one for the real service implementation + * and one for the interface object. Right now it feels a bit heavy + * to so that since the only different between the two would be + * init() and may-be getName(). + */ + public void init(PeerGroup pg, ID assignedID, Advertisement impl) {} + + /** + * {@inheritDoc} + *

            + * This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + */ + public int startApp(String[] arg) { + return 0; + } + + /** + * {@inheritDoc} + *

            + * This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + *

            + * This request is currently ignored. + */ + public void stopApp() {} + + /** + * {@inheritDoc} + */ + public InputPipe createInputPipe(PipeAdvertisement adv) throws IOException { + return impl.createInputPipe(adv); + } + + /** + * {@inheritDoc} + */ + public InputPipe createInputPipe(PipeAdvertisement adv, PipeMsgListener listener) throws IOException { + return impl.createInputPipe(adv, listener); + } + + /** + * {@inheritDoc} + */ + public OutputPipe createOutputPipe(PipeAdvertisement pipeAdv, long timeout) throws IOException { + return impl.createOutputPipe(pipeAdv, timeout); + } + + /** + * {@inheritDoc} + */ + public OutputPipe createOutputPipe(PipeAdvertisement adv, Set peers, long timeout) throws IOException { + return impl.createOutputPipe(adv, peers, timeout); + } + + /** + * {@inheritDoc} + */ + public void createOutputPipe(PipeAdvertisement pipeAdv, OutputPipeListener listener) throws IOException { + impl.createOutputPipe(pipeAdv, listener); + } + + /** + * {@inheritDoc} + */ + public void createOutputPipe(PipeAdvertisement adv, Set peers, OutputPipeListener listener) throws IOException { + impl.createOutputPipe(adv, peers, listener); + } + + /** + * {@inheritDoc} + */ + public OutputPipeListener removeOutputPipeListener(String pipeID, OutputPipeListener listener) { + return removeOutputPipeListener(ID.create(URI.create(pipeID)), listener); + } + + /** + * {@inheritDoc} + */ + public OutputPipeListener removeOutputPipeListener(ID pipeID, OutputPipeListener listener) { + return impl.removeOutputPipeListener(pipeID, listener); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/SecureInputPipeImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/SecureInputPipeImpl.java new file mode 100644 index 000000000..8bdaae84c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/SecureInputPipeImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.impl.endpoint.tls.TlsTransport; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.protocol.PipeAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; + +/** + * Implements the {@link net.jxta.pipe.InputPipe} interface by listening on the + * endpoint for messages to service "PipeService" and a param of the Pipe ID. + */ +public class SecureInputPipeImpl extends InputPipeImpl { + private final static Logger LOG = Logger.getLogger(SecureInputPipeImpl.class.getName()); + + /** + * Constructor for the SecureInputPipeImpl object + * + * @param pipeResolver pipe resolver + * @param adv pipe advertisement + * @throws IOException if an io error occurs + */ + SecureInputPipeImpl(PipeResolver pipeResolver, PipeAdvertisement adv) throws IOException { + + this(pipeResolver, adv, null); + } + + /** + * Constructor for the SecureInputPipeImpl object + * @param r pipe resolver + * @param adv the pipe advertisement + * @param listener the message listener + * @throws IOException if an io error occurs + */ + SecureInputPipeImpl(PipeResolver r, PipeAdvertisement adv, PipeMsgListener listener) throws IOException { + + super(r, adv, listener); + } + + /** + * {@inheritDoc} + */ + @Override + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + Object fromTLS = msg.getMessageProperty(TlsTransport.class); + + if (null != fromTLS) { + super.processIncomingMessage(msg, srcAddr, dstAddr); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("processIncomingMessage : Discarding " + msg + " because it did not come from TLS"); + } + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/SecureOutputPipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/SecureOutputPipe.java new file mode 100644 index 000000000..15775068c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/SecureOutputPipe.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PipeAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.util.Set; + +/** + * This class implements the Secure non blocking Output Pipe + */ +class SecureOutputPipe extends NonBlockingOutputPipe { + + private static final Logger LOG = Logger.getLogger(SecureOutputPipe.class.getName()); + + public SecureOutputPipe(PeerGroup group, PipeResolver resolver, PipeAdvertisement pipeAdv, ID destPeer, Set peers) throws IOException { + super(group, resolver, pipeAdv, destPeer, peers); + } + + /** + * {@inheritDoc} + * + *

            + * We can't fail to send a message. Secure pipes are expected to be + * reliable and ordered. + */ + @Override + public synchronized boolean send(Message msg) throws IOException { + + boolean sent = false; + int attempts = 1; + + while (!sent && !isClosed()) { + try { + sent = super.send(msg); + + if (!sent) { + wait(10 + (1 << Math.min(attempts, 14))); + attempts++; + } + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + + if (!sent && isClosed()) { + IOException failed = new IOException("Could not enqueue " + msg + " for sending. Pipe is closed."); + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, failed.getMessage(), failed); + } + throw failed; + } + return sent; + } + + /** + * {@inheritDoc} + */ + @Override + protected EndpointAddress mkAddress(ID destPeer, ID pipeID) { + return new EndpointAddress("jxtatls", destPeer.getUniqueValue().toString(), "PipeService", pipeID.toString()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WireHeader.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WireHeader.java new file mode 100644 index 000000000..e6abfb4f8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WireHeader.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements a JXTA-WIRE header. + */ +public class WireHeader { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(WireHeader.class.getName()); + + private static final String Name = "JxtaWire"; + private static final String MsgIdTag = "MsgId"; + private static final String PipeIdTag = "PipeId"; + private static final String SrcTag = "SrcPeer"; + private static final String TTLTag = "TTL"; + private static final String PeerTag = "VisitedPeer"; + + private ID srcPeer = ID.nullID; + private ID pipeID = ID.nullID; + private String msgId = null; + private int TTL = Integer.MIN_VALUE; + + public WireHeader() {} + + public WireHeader(Element root) { + initialize(root); + } + + public void setSrcPeer(ID p) { + srcPeer = p; + } + + public ID getSrcPeer() { + return srcPeer; + } + + public void setTTL(int t) { + TTL = t; + } + + public int getTTL() { + return TTL; + } + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String id) { + this.msgId = id; + } + + public ID getPipeID() { + return pipeID; + } + + public void setPipeID(ID id) { + this.pipeID = id; + } + + /** + * Called to handle elements during parsing. + * + * @param elem Element to parse + * @return true if element was handled, otherwise false. + */ + protected boolean handleElement(XMLElement elem) { + if (elem.getName().equals(SrcTag)) { + try { + URI pID = new URI(elem.getTextValue()); + setSrcPeer(IDFactory.fromURI(pID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID ID in header: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals(MsgIdTag)) { + msgId = elem.getTextValue(); + return true; + } + + if (elem.getName().equals(PipeIdTag)) { + try { + URI pipeID = new URI(elem.getTextValue()); + setPipeID(IDFactory.fromURI(pipeID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad pipe ID in header"); + } + return true; + } + + if (elem.getName().equals(TTLTag)) { + TTL = Integer.parseInt(elem.getTextValue()); + return true; + } + + // IGNORE obsolete element "VisitedPeer" + return elem.getName().equals(PeerTag); + + } + + /** + * internal method to process a document into a header. + * + * @param root where to start. + */ + protected void initialize(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + String doctype = doc.getName(); + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(Name) && !Name.equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.getName()); + } + } + } + + // Sanity Check! + + if (null == getMsgId()) { + throw new IllegalArgumentException("Header does not contain a message id"); + } + + if (ID.nullID == getPipeID()) { + throw new IllegalArgumentException("Header does not contain a pipe id"); + } + + if (TTL < 1) { + throw new IllegalArgumentException("TTL must be >= 1"); + } + } + + /** + * Returns the docment for this header + * + * @param encodeAs mime type encoding + * @return the docment for this header + */ + public Document getDocument(MimeMediaType encodeAs) { + StructuredTextDocument doc = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(encodeAs, Name); + + if (doc instanceof XMLDocument) { + ((XMLDocument) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + if (null == getMsgId()) { + throw new IllegalStateException("Message id is not initialized"); + } + + if (ID.nullID == getPipeID()) { + throw new IllegalStateException("PipeID is not initialized"); + } + + if (TTL < 1) { + throw new IllegalStateException("TTL must be >= 1"); + } + + Element e; + if ((srcPeer != null) && (srcPeer != ID.nullID)) { + e = doc.createElement(SrcTag, srcPeer.toString()); + doc.appendChild(e); + } + + e = doc.createElement(PipeIdTag, getPipeID().toString()); + doc.appendChild(e); + + e = doc.createElement(MsgIdTag, getMsgId()); + doc.appendChild(e); + + e = doc.createElement(TTLTag, Integer.toString(TTL)); + doc.appendChild(e); + + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WirePipe.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WirePipe.java new file mode 100644 index 000000000..22dbbe381 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WirePipe.java @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.*; +import net.jxta.id.ID; +import net.jxta.impl.cm.SrdiIndex; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.rendezvous.RendezVousService; + +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * WirePipe (aka Propagated pipe) is very similar to IGMP, where a creation of an + * input pipe results in a propagated pipe membership registration with the peer's + * rendezvous peer, and a closure results in a propagated pipe group resignation, + * these group registration/resignation are simply PipeService SRDI messages. + */ +public class WirePipe implements EndpointListener, InputPipe, PipeRegistrar { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(WirePipe.class.getName()); + + /** + * The number of message ID we track to eliminate duplicate messages. + */ + private static final int MAX_RECORDED_MSGIDS = 250; + + private volatile boolean closed = false; + + private final PeerGroup peerGroup; + private final PipeResolver pipeResolver; + private final WirePipeImpl wireService; + private final PipeAdvertisement pipeAdv; + + private final RendezVousService rendezvous; + private final PeerID localPeerId; + private NonBlockingWireOutputPipe repropagater; + int messagesReceived = 0; + + /** + * Table of local input pipes listening on this pipe. Weak map (used as a + * Set) so that we don't keep pipes unnaturally alive and consuming + * resources. + */ + private final Map wireinputpipes = new WeakHashMap(); + + /** + * The list of message ids we have already seen. The most recently seen + * messages are at the end of the list. + *

            + * XXX 20031102 bondolo@jxta.org: We might want to consider three + * performance enhancements: + *

            + *

              + *
            • Reverse the order of elements in the list. This would result + * in faster searching since the default strategy for ArrayList to + * search in index order. We are most likely to see duplicate messages + * amongst the messages we have seen recently. This would make + * additions more costly.
            • + *

              + *

            • When we do find a duplicate in the list, exchange it's location + * with the newest message in the list. This will keep annoying dupes + * close to the start of the list.
            • + *

              + *

            • When the array reaches MaxNbOfStoredIds treat it as a ring.
            • + *
            + */ + private final List msgIds = new ArrayList(MAX_RECORDED_MSGIDS); + + /** + * Constructor + * + * @param group The Group associated with this service + * @param pipeResolver the associated pipe resolver + * @param wireService The pipe service associated with this pipe + * @param adv pipe advertisement + */ + public WirePipe(PeerGroup group, PipeResolver pipeResolver, WirePipeImpl wireService, PipeAdvertisement adv) { + this.peerGroup = group; + this.pipeResolver = pipeResolver; + this.wireService = wireService; + this.pipeAdv = adv; + localPeerId = peerGroup.getPeerID(); + rendezvous = group.getRendezVousService(); + } + + /** + * {@inheritDoc} + *

            + * Closes the pipe. + */ + @Override + protected synchronized void finalize() throws Throwable { + + if (!closed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe is being finalized without being previously closed. This is likely a bug."); + } + } + close(); + super.finalize(); + } + + /** + * {@inheritDoc} + */ + public synchronized boolean register(InputPipe wireinputpipe) { + if (closed) { + return false; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Registering input pipe for " + pipeAdv.getPipeID()); + } + + wireinputpipes.put(wireinputpipe, null); + boolean registered; + if (1 == wireinputpipes.size()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Registering " + pipeAdv.getPipeID() + " with pipe resolver."); + } + registered = pipeResolver.register(this); + } else { + registered = true; + } + return registered; + } + + /** + * {@inheritDoc} + */ + public synchronized boolean forget(InputPipe wireinputpipe) { + boolean removed = null != wireinputpipes.remove(wireinputpipe); + + if (wireinputpipes.isEmpty()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Deregistering wire pipe with pipe resolver"); + } + pipeResolver.forget(this); + } + + if (removed && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removed input pipe for " + pipeAdv.getPipeID()); + } + return removed; + } + + // This is the InputPipe API implementation. + // This is needed only to be able to register an InputPipe to the PipeResolver. + // Not everything has to be implemented. + + /** + * {@inheritDoc} + */ + public Message waitForMessage() throws InterruptedException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("This method is not really supported."); + } + return null; + } + + /** + * {@inheritDoc} + */ + public Message poll(int timeout) throws InterruptedException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("This method is not really supported."); + } + return null; + } + + /** + * {@inheritDoc} + */ + public synchronized void close() { + if (closed) { + return; + } + + closed = true; + + if (null != repropagater) { + repropagater.close(); + repropagater = null; + } + + List inputPipes = new ArrayList(wireinputpipes.keySet()); + + for (InputPipe anInputPipe : inputPipes) { + anInputPipe.close(); + } + + wireinputpipes.clear(); + msgIds.clear(); + wireService.forgetWirePipe(pipeAdv.getPipeID()); + } + + /** + * {@inheritDoc} + */ + public String getType() { + return pipeAdv.getType(); + } + + /** + * {@inheritDoc} + */ + public ID getPipeID() { + return pipeAdv.getPipeID(); + } + + /** + * {@inheritDoc} + */ + public String getName() { + return pipeAdv.getName(); + } + + /** + * {@inheritDoc} + */ + public PipeAdvertisement getAdvertisement() { + return pipeAdv; + } + + /** + * {@inheritDoc} + *

            + * Handler for messages received through the normal pipe endpoint + * listener. + *

            + * "PipeService" / <PipeID> + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + // Check if there is a JXTA-WIRE header + MessageElement elem = message.getMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAMESPACE, + WirePipeImpl.WIRE_HEADER_ELEMENT_NAME); + + if (null == elem) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No JxtaWireHeader element. Discarding " + message); + } + return; + } + + WireHeader header; + try { + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(elem); + header = new WireHeader(doc); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "bad wire header", e); + } + return; + } + processIncomingMessage(message, header, srcAddr, dstAddr); + } + + /** + * local version with the wire header already parsed. There are two paths + * to this point; via the local endpoint listener or via the general + * propagation listener in WirePipeImpl. + * + * @param message the message + * @param header the wire header + * @param srcAddr source + * @param dstAddr destination + */ + void processIncomingMessage(Message message, WireHeader header, EndpointAddress srcAddr, EndpointAddress dstAddr) { + if (recordSeenMessage(header.getMsgId())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding duplicate " + message); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Processing " + message + " from " + srcAddr + " on " + pipeAdv.getPipeID()); + } + callLocalListeners(message, srcAddr, dstAddr); + if (peerGroup.isRendezvous()) { + repropagate(message, header); + } + } + + /** + * Calls the local listeners for a given pipe. + * + * @param message the message + * @param srcAddr source The peer which sent us the message (last hop). + * @param dstAddr dest The wire pipe the message was sent to. + */ + private void callLocalListeners(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + List listeners = new ArrayList(wireinputpipes.keySet()); + if (listeners.isEmpty()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No local listeners for " + pipeAdv.getPipeID()); + } + } else { + int listenersCalled = 0; + for (InputPipeImpl anInputPipe : listeners) { + try { + anInputPipe.processIncomingMessage(message.clone(), srcAddr, dstAddr); + listenersCalled++; + } catch (Throwable ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable during callback (" + anInputPipe + ") for " + anInputPipe.getPipeID(), ignored); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Called " + listenersCalled + " of " + listeners.size() + " local listeners for " + pipeAdv.getPipeID()); + } + } + } + + /** + * Repropagate a message. + * + * @param message the message + * @param header the header + */ + void repropagate(Message message, WireHeader header) { + + if (closed) { + return; + } + + if ((header.getTTL() <= 1)) { + // This message has run out of fuel. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No TTL remaining - discarding " + message + " on " + header.getPipeID()); + } + return; + } + + Message msg = message.clone(); + header.setTTL(header.getTTL() - 1); + XMLDocument headerDoc = (XMLDocument) header.getDocument(MimeMediaType.XMLUTF8); + MessageElement elem = new TextDocumentMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAME, headerDoc, null); + + msg.replaceMessageElement(WirePipeImpl.WIRE_HEADER_ELEMENT_NAMESPACE, elem); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Repropagating " + msg + " on " + header.getPipeID()); + } + + synchronized (this) { + if (closed) { + return; + } + if (null == repropagater) { + repropagater = wireService.createOutputPipe(pipeAdv, Collections.EMPTY_SET); + } + } + + try { + if (!repropagater.sendUnModified(msg, header)) { + // XXX bondolo@jxta.org we don't make any attempt to retry. + // There is a potential problem in that we have accepted the + // message locally but didn't resend it. If we get another copy + // of this message then we will NOT attempt to repropagate it + // even if we should. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failure repropagating " + msg + " on " + header.getPipeID() + ". Could not queue message."); + } + } + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure repropagating " + msg + " on " + header.getPipeID(), failed); + } + } + } + + /** + * Sends a message on the propagated pipe. if set is not empty, then the + * message is sent to set of peers. + * + * @param message The message to send. + * @param peers The peers to which the message will be sent. If the + * set is empty then the message is sent to all members of the pipe that are + * connected to the rendezvous, as well as walk the message through the network + * @param header message header + * @throws java.io.IOException if an io error occurs + */ + void sendMessage(Message message, Set peers, WireHeader header) throws IOException { + message = message.clone(); + + // do local listeners if we are to be one of the destinations + if (peers.isEmpty() || peers.contains(localPeerId)) { + if (!recordSeenMessage(header.getMsgId())) { + callLocalListeners(message, new EndpointAddress(localPeerId, null, null), + new EndpointAddress(pipeAdv.getPipeID(), null, null)); + } + } + + if (peers.isEmpty()) { + if (peerGroup.isRendezvous()) { + // propagate to my clients + SrdiIndex srdiIndex = pipeResolver.getSrdiIndex(); + List peerids = srdiIndex.query(PipeService.PropagateType, PipeAdvertisement.IdTag, getPipeID().toString(), + Integer.MAX_VALUE); + + peerids.retainAll(rendezvous.getConnectedPeerIDs()); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + message + " to " + peerids.size() + " subscriber peers."); + } + rendezvous.propagate(Collections.enumeration(peerids), message, WirePipeImpl.WIRE_SERVICE_NAME, + wireService.getServiceParameter(), 1); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + message + " to whole network."); + } + // propagate to local sub-net + rendezvous.propagateToNeighbors(message, WirePipeImpl.WIRE_SERVICE_NAME, wireService.getServiceParameter(), + RendezVousService.DEFAULT_TTL); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Walking " + message + " through peerview."); + } + // walk the message through rdv network (edge, or rendezvous) + rendezvous.walk(message, WirePipeImpl.WIRE_SERVICE_NAME, wireService.getServiceParameter(), + RendezVousService.DEFAULT_TTL); + } else { + // Send to specific peers + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + message + " to " + peers.size() + " peers."); + } + rendezvous.propagate(Collections.enumeration(peers), message, WirePipeImpl.WIRE_SERVICE_NAME, + wireService.getServiceParameter(), 1); + } + } + + /** + * Create a unique (mostly) identifier for this message + * + * @return a message sequence uuid + */ + static String createMsgId() { + return UUIDFactory.newSeqUUID().toString(); + } + + /** + * Adds a message ID to our table or stored IDs. + * + * @param id to add. + * @return false if ID was added, true if it was a duplicate. + */ + private boolean recordSeenMessage(String id) { + + UUID msgid; + try { + msgid = new UUID(id); + } catch (IllegalArgumentException notauuid) { + // XXX 20031024 bondolo@jxta.org these two conversions are provided + // for backwards compatibility and should eventually be removed. + try { + msgid = UUIDFactory.newHashUUID(Long.parseLong(id), 0); + } catch (NumberFormatException notanumber) { + msgid = UUIDFactory.newHashUUID(id.hashCode(), 0); + } + } + synchronized (msgIds) { + if (msgIds.contains(msgid)) { + // Already there. Nothing to do + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("duplicate " + msgid); + } + return true; + } + if (msgIds.size() < MAX_RECORDED_MSGIDS) { + msgIds.add(msgid); + } else { + msgIds.set((messagesReceived % MAX_RECORDED_MSGIDS), msgid); + } + messagesReceived++; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("added " + msgid); + } + return false; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WirePipeImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WirePipeImpl.java new file mode 100644 index 000000000..c976b54d2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/WirePipeImpl.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.pipe; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.id.ID; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.platform.Module; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.rendezvous.RendezVousService; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The Wire (Propagated) Pipe Service. + */ +public class WirePipeImpl implements EndpointListener { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(WirePipeImpl.class.getName()); + + /** + * Service name we register our listener with. + */ + final static String WIRE_SERVICE_NAME = "jxta.service.wirepipe"; + + /** + * Service param we register our listener with. + *

            + * Including the wireParam as part of the destination endpoint address + * is needed only for backwards compatibility with legacy version of JXTA. + * The wireParam is no longer registered as part of the endpoint listener + * address. + */ + private final String wireParam; + + /** + * The Message namespace we use for passing the wire header. + */ + final static String WIRE_HEADER_ELEMENT_NAMESPACE = "jxta"; + + /** + * The Message Element name we use for passing the wire header. + */ + final static String WIRE_HEADER_ELEMENT_NAME = "JxtaWireHeader"; + + /** + * The wire pipes we know of. + */ + private final Map wirePipes = new HashMap(); + + private final PeerGroup group; + private final PipeResolver pipeResolver; + + private EndpointService endpoint = null; + private RendezVousService rendezvous = null; + + /** + * @param group Description of the Parameter + * @param pipeResolver Description of the Parameter + */ + WirePipeImpl(PeerGroup group, PipeResolver pipeResolver) { + this.group = group; + this.pipeResolver = pipeResolver; + this.wireParam = group.getPeerGroupID().getUniqueValue().toString(); + } + + /** + * To support WirePipe.send(Message, Enumeration) + * + * @return The serviceParameter value + */ + public String getServiceParameter() { + return wireParam; + } + + /** + * Supply arguments and starts this service if it hadn't started by itself. + *

            + * Currently this service does not expect arguments. + * + * @param arg A table of strings arguments. + * @return int status indication. + */ + public int startApp(String[] arg) { + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return Module.START_AGAIN_STALLED; + } + + rendezvous = group.getRendezVousService(); + if (null == rendezvous) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a rendezvous service"); + } + return Module.START_AGAIN_STALLED; + } + + // Set our Endpoint Listener + try { + endpoint.addIncomingMessageListener(this, WIRE_SERVICE_NAME, null); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed registering Endpoint Listener", e); + } + throw new IllegalStateException("Failed registering Endpoint Listener"); + } + return Module.START_OK; + } + + /** + * Ask this service to stop. + */ + public void stopApp() { + Collection allWirePipes = new ArrayList(wirePipes.values()); + + for (WirePipe aWirePipe : allWirePipes) { + // Close all of the wire pipes. + aWirePipe.close(); + } + wirePipes.clear(); + + // Clear our listener + endpoint.removeIncomingMessageListener(WIRE_SERVICE_NAME, null); + + endpoint = null; + rendezvous = null; + } + + /** + * create an InputPipe from a pipe Advertisement + * + * @param adv is the advertisement of the PipeServiceImpl. + * @param listener PipeMsgListener to receive msgs. + * @return InputPipe InputPipe object created + * @throws IOException error creating input pipe + */ + InputPipe createInputPipe(PipeAdvertisement adv, PipeMsgListener listener) throws IOException { + WirePipe wirePipe = getWirePipe(adv); + return new InputPipeImpl(wirePipe, adv, listener); + } + + /** + * create an OutputPipe from the pipe Advertisement giving a PeerId(s) + * where the corresponding InputPipe is supposed to be. + * + * @param adv is the advertisement of the NetPipe. + * @param peers is a set of the PeerId of the peers where to look + * for the corresponding Pipes + * @return OuputPipe corresponding OutputPipe + */ + NonBlockingWireOutputPipe createOutputPipe(PipeAdvertisement adv, Set peers) { + WirePipe wirePipe = getWirePipe(adv); + return new NonBlockingWireOutputPipe(group, wirePipe, adv, peers); + } + + /** + * PropagateType pipes + * + * @param adv the pipe adv + * @return the wire pipe + */ + private WirePipe getWirePipe(PipeAdvertisement adv) { + WirePipe wirePipe; + + synchronized (wirePipes) { + // First see if we have already a WirePipe for this pipe + wirePipe = wirePipes.get(adv.getPipeID()); + + if (null == wirePipe) { + // No.. There is none. Create a new one. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating new wire pipe for " + adv.getPipeID()); + } + wirePipe = new WirePipe(group, pipeResolver, this, adv); + wirePipes.put(adv.getPipeID(), wirePipe); + } + } + return wirePipe; + } + + /** + * PropagateType pipes + * + * @param pipeID Pipe ID + * @param create if true create one if one does not exist + * @return the wire pipe + */ + private WirePipe getWirePipe(ID pipeID, boolean create) { + WirePipe wirePipe; + + synchronized (wirePipes) { + // First see if we have already a WirePipe for this pipe + wirePipe = wirePipes.get(pipeID); + + if ((null == wirePipe) && create) { + // No.. There is none. Create a new one. + // XXX 20031019 bondolo@jxta.org Check for the adv in local discovery maybe? + PipeAdvertisement adv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement( + PipeAdvertisement.getAdvertisementType()); + + adv.setPipeID(pipeID); + adv.setType(PipeService.PropagateType); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating new wire pipe for " + adv.getPipeID()); + } + wirePipe = new WirePipe(group, pipeResolver, this, adv); + wirePipes.put(pipeID, wirePipe); + } + } + return wirePipe; + } + + /** + * Remove a wire pipe from our collection of wire pipes. + * + * @param pipeID The ID of the wire pipe to forget. + * @return {@code true} if the wire pipe had been registered otherwise + * {@code false}. + */ + boolean forgetWirePipe(ID pipeID) { + synchronized (wirePipes) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removing wire pipe for " + pipeID); + } + return null != wirePipes.remove(pipeID); + } + } + + /** + * {@inheritDoc} + *

            + * Listener for "jxta.service.wirepipe" / <null> + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + // Check if there is a JXTA-WIRE header + MessageElement elem = message.getMessageElement(WIRE_HEADER_ELEMENT_NAMESPACE, WIRE_HEADER_ELEMENT_NAME); + + if (null == elem) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No JxtaWireHeader element. Discarding " + message); + } + return; + } + + WireHeader header; + + try { + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(elem); + header = new WireHeader(doc); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "bad wire header for " + message, e); + } + return; + } + + WirePipe wirePipe = getWirePipe(header.getPipeID(), rendezvous.isRendezVous()); + if (null != wirePipe) { + wirePipe.processIncomingMessage(message, header, srcAddr, dstAddr); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring message " + message + " for id " + header.getPipeID()); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/package.html new file mode 100644 index 000000000..b4d52dd8c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/pipe/package.html @@ -0,0 +1,18 @@ + + + + + + +A JXTA {@link net.jxta.pipe.PipeService} implementation which implements the +standard JXTA Pipe Resolver Protocol (PRP). + +@see net.jxta.pipe.PipeService +@see net.jxta.pipe.InputPipe +@see net.jxta.pipe.OutputPipe +@see net.jxta.protocol.PipeAdvertisement +@see net.jxta.endpoint.Message +@see JXTA Protocols + Specification : Pipe Binding Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/AccessPointAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/AccessPointAdv.java new file mode 100644 index 000000000..d6d6946ea --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/AccessPointAdv.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.protocol.AccessPointAdvertisement; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Associates a set of EndpointAddresses with a PeerID. + *

            + *

            + *    <xs:complexType name ="jxta:APA">
            + *      <xs:sequence>
            + *        <xs:element name="PID" type="jxta:JXTAID" minOccurs="0" maxOccurs="1"/>
            + *        <xs:sequence>
            + *          <xs:element name="EA" type="jxta:JXTAID" minOccurs="0" maxOccurs="unbounded"/>
            + *        </xs:sequence>
            + *      </xs:sequence>
            + *    </xs:complexType>
            + *  
            + * + * @see net.jxta.protocol.AccessPointAdvertisement + */ +public class AccessPointAdv extends AccessPointAdvertisement implements Cloneable { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(AccessPointAdv.class.getName()); + + private static final String PID_TAG = "PID"; + private static final String EA_TAG = "EA"; + + private static final String[] INDEXFIELDS = { PID_TAG}; + + /** + * Instantiator for AdvertisementFactory + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return AccessPointAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new AccessPointAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + return new AccessPointAdv(root); + } + } + + /** + * Returns the identifying type of this Advertisement. + *

            + * Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisment. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + *

            + * This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertiement.getAdvertisementType() no matter what the real type of the + * advertisment. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:APA"; + } + + /** + * Private constructor. Use the Advertisement factory and accessors. + */ + private AccessPointAdv() {} + + /** + * Private constructor. Use the Advertisement factory and accessors. + * + * @param root the element + */ + private AccessPointAdv(Element root) { + if (!(root instanceof XMLElement)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public AccessPointAdv clone() { + return (AccessPointAdv) super.clone(); + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEXFIELDS; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + ID pid = getPeerID(); + + if (null == pid) { + throw new IllegalStateException("cannot build ID: no peer id"); + } + + try { + // We have not yet built it. Do it now + String seed = getAdvType() + getPeerID().toString(); + + InputStream in = new ByteArrayInputStream(seed.getBytes()); + + return IDFactory.newCodatID(PeerGroupID.worldPeerGroupID, seed.getBytes(), in); + } catch (Exception ez) { + IllegalStateException failed = new IllegalStateException("cannot build ID"); + + failed.initCause(ez); + + throw failed; + } + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (PID_TAG.equals(elem.getName())) { + String uri = elem.getTextValue(); + + if (null != uri) { + try { + URI pID = new URI(uri.trim()); + + setPeerID((PeerID) IDFactory.fromURI(pID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID ID in advertisement"); + } catch (ClassCastException notPID) { + throw new IllegalArgumentException("Not a Peer ID"); + } + + return true; + } + } + + if (EA_TAG.equals(elem.getName())) { + String epa = elem.getTextValue(); + + if (null != epa) { + addEndpointAddress(epa.trim()); + return true; + } + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (getPeerID() != null) { + Element e = adv.createElement(PID_TAG, getPeerID().toString()); + + adv.appendChild(e); + } + + Enumeration each = getEndpointAddresses(); + + while (each.hasMoreElements()) { + Element e2 = adv.createElement(EA_TAG, each.nextElement().toString()); + + adv.appendChild(e2); + } + return adv; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/Certificate.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/Certificate.java new file mode 100644 index 000000000..adb8fb925 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/Certificate.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.impl.membership.pse.PSEUtils; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.*; + + +/** + * A lightweight container for X.509 Certificates. + * * + *

            
            + *   <xs:element name="jxta:cert" type="Certificate"/>
            + * 

            + * <xs:complexType name="Certificate" type="xs:string"> + * <xs:element name="Issuer" type="jxta:cert" minOccurs="0" /> + * </xs:complexType> + *

            + */ +public class Certificate { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(Certificate.class.getName()); + + /** + * + **/ + private List certs = null; + + /** + **/ + public Certificate() { + super(); + } + + public Certificate(Element root) { + this(); + certs = new ArrayList(); + initialize(root); + } + + /** + * returns the Message type. This will match the XML doctype declaration. + * + * @return a string + */ + public static String getMessageType() { + return "jxta:cert"; + } + + public X509Certificate[] getCertificates() { + return certs.toArray(new X509Certificate[certs.size()]); + } + + public void setCertificates(X509Certificate[] certs) { + this.certs = new ArrayList(Arrays.asList(certs)); + } + + public void setCertificates(List certs) { + this.certs = new ArrayList(certs); + } + + /** + * Initializes the message from a document. + * + * @param root the element + */ + private void initialize(Element root) { + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getMessageType()) && !getMessageType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + String value = doc.getTextValue(); + + value = value.trim(); + + try { + byte[] cert_der = PSEUtils.base64Decode(new StringReader(value)); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + certs.add((X509Certificate) cf.generateCertificate(new ByteArrayInputStream(cert_der))); + } catch (IOException error) { + throw new IllegalArgumentException("bad certificate."); + } catch (CertificateException error) { + throw new IllegalArgumentException("bad certificate."); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + Element elem = (Element) elements.nextElement(); + + if (!elem.getKey().equals("Issuer")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + continue; + } + + Certificate issuer = new Certificate(elem); + + certs.addAll(Arrays.asList(issuer.getCertificates())); + } + + // Begin checking sanity! + if (certs.isEmpty()) { + throw new IllegalArgumentException("certificate not initialized."); + } + } + + /** + * Creates a document out of the message. + * + * @param encodeAs The document representation format requested. + * @return the message as a document. + */ + public Document getDocument(MimeMediaType encodeAs) { + String encodedCert; + + try { + encodedCert = PSEUtils.base64Encode((certs.get(0)).getEncoded()); + } catch (CertificateEncodingException failed) { + IllegalStateException failure = new IllegalStateException("bad certificate."); + + failure.initCause(failed); + + throw failure; + } catch (IOException failed) { + IllegalStateException failure = new IllegalStateException("Could not encode certificate."); + + failure.initCause(failed); + + throw failure; + } + + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(encodeAs, getMessageType(), encodedCert); + + if (doc instanceof XMLDocument) { + ((XMLDocument) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((XMLDocument) doc).addAttribute("xml:space", "preserve"); + } + + Iterator eachCert = certs.iterator(); + + eachCert.next(); // skip me. + + Element addTo = doc; + + while (eachCert.hasNext()) { + X509Certificate anIssuer = eachCert.next(); + + try { + encodedCert = PSEUtils.base64Encode(anIssuer.getEncoded()); + } catch (CertificateEncodingException failed) { + IllegalStateException failure = new IllegalStateException("bad certificate."); + + failure.initCause(failed); + + throw failure; + } catch (IOException failed) { + IllegalStateException failure = new IllegalStateException("Could not encode certificate."); + + failure.initCause(failed); + + throw failure; + } + + Element issuerElement = doc.createElement("Issuer", encodedCert); + + addTo.appendChild(issuerElement); + + if (doc instanceof Attributable) { + ((Attributable) issuerElement).addAttribute("type", getMessageType()); + } + + addTo = issuerElement; + } + + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/CertificateSigningRequest.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/CertificateSigningRequest.java new file mode 100644 index 000000000..d10a85e16 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/CertificateSigningRequest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.io.StringReader; + +import java.io.IOException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import org.bouncycastle.jce.PKCS10CertificationRequest; + +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; + +import net.jxta.impl.membership.pse.PSEUtils; + + +/** + * A lightweight container for a PKCS#10/RFC2986 Certificate Signing Request. + * + * @deprecated The types exported from this implementation are subject to + * change. + * + *
            
            + *   <xs:element name="jxta:csr" type="CertificateSigningRequest"/>
            + *
            + *   <xs:complexType name="csr">
            + *     <xs:all>
            + *     </xs:all>
            + *   </xs:complexType>
            + * 
            + * + * @see PKCS #10 + * @see IETF RFC 2986 + **/ +@Deprecated +public class CertificateSigningRequest { + + /** + * Logger + **/ + private final static transient Logger LOG = Logger.getLogger(CertificateSigningRequest.class.getName()); + + private PKCS10CertificationRequest csr = null; + + public CertificateSigningRequest() { + super(); + } + + public CertificateSigningRequest(Element root) { + this(); + initialize(root); + } + + /** + * returns the Message type. This will match the XML doctype declaration. + * + * @return a string + **/ + public static String getMessageType() { + return "jxta:CertificateSigningRequest"; + } + + public PKCS10CertificationRequest getCSR() { + return csr; + } + + public void setCSR(PKCS10CertificationRequest csr) { + this.csr = csr; + } + + /** + * Initializes the message from a document. + **/ + protected void initialize(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + + XMLElement doc = (XMLElement) root; + + String docName = doc.getName(); + + if (!docName.equals(getMessageType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + docName); + } + + String value = doc.getTextValue(); + + value = value.trim(); + + try { + byte[] csr_der = PSEUtils.base64Decode(new StringReader(value)); + + csr = new PKCS10CertificationRequest(csr_der); + } catch (IOException error) { + throw new IllegalArgumentException("bad certificate signing request."); + } + + // Begin checking sanity! + if (null == csr) { + throw new IllegalArgumentException("certificate signing request not initialized."); + } + } + + /** + * Creates a document out of the message. + * + * @param encodeAs The document representation format requested. + * @return the message as a document. + **/ + public Document getDocument(MimeMediaType encodeAs) { + + String encodedCSR; + + try { + encodedCSR = PSEUtils.base64Encode(csr.getEncoded()); + } catch (IOException failed) { + IllegalStateException failure = new IllegalStateException("Could not encode certificate signing request."); + + failure.initCause(failed); + + throw failure; + } + + StructuredTextDocument doc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(encodeAs + , + getMessageType(), encodedCSR); + + if (doc instanceof XMLDocument) { + ((XMLDocument) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((XMLDocument) doc).addAttribute("xml:space", "preserve"); + } + + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryConfigAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryConfigAdv.java new file mode 100644 index 000000000..6e5a9d5ae --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryConfigAdv.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.util.Enumeration; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * Contains parameters for configuration of the Reference Implemenation + * Rendezvous Service. + * + *

            
            + *
            + * 
            + * + */ +public final class DiscoveryConfigAdv extends ExtendableAdvertisement { + + /** + * Instantiator for DiscoveryConfigAdv + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new DiscoveryConfigAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + return new DiscoveryConfigAdv(root); + } + } + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(DiscoveryConfigAdv.class.getName()); + + /** + * Our DOCTYPE + */ + private static final String advType = "jxta:DiscoConfigAdv"; + + private static final String FORWARD_ALWAYS_REPLICA = "forwardAlwaysReplica"; + private static final String FORWARD_BELOW_TRESHOLD = "forwardBelowThreshold"; + private static final String LOCAL_ONLY = "localOnly"; + + private static final String[] fields = {}; + + /** + * If true, the discovery service will always forward queries to the replica peer + * even if there are local responses, unless the replica peer is the local peer. + */ + private boolean forwardAlwaysReplica = false; + + /** + * If true, the discovery service will always forward queries if the number of local + * responses is below the specified threshold. The threshold may be reduced by the number + * of local responses before forwarding. NOTE: not yet implemented. + */ + private boolean forwardBelowTreshold = false; + + /** + * localOnly discovery. + */ + private boolean localOnly = false; + + /** + * Returns the identifying type of this Advertisement. + * + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisment. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + * + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertiement.getAdvertisementType() no matter what the real type of the + * advertisment. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return advType; + } + + /** + * Use the Instantiator through the factory + */ + DiscoveryConfigAdv() {} + + /** + * Use the Instantiator through the factory + * @param root the element + */ + DiscoveryConfigAdv(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration eachAttr = doc.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aDiscoAttr = (Attribute) eachAttr.nextElement(); + String name = aDiscoAttr.getName(); + boolean flag = Boolean.valueOf(aDiscoAttr.getValue().trim()); + + if (FORWARD_ALWAYS_REPLICA.equals(name)) { + forwardAlwaysReplica = flag; + } else if (FORWARD_BELOW_TRESHOLD.equals(name)) { + forwardBelowTreshold = flag; + } else if (LOCAL_ONLY.equals(name)) { + localOnly = flag; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + name); + } + } + } + } + + /** + * Make a safe clone of this DiscoveryConfigAdv. + * + * @return Object A copy of this DiscoveryConfigAdv + */ + @Override + public DiscoveryConfigAdv clone() throws CloneNotSupportedException { + + throw new CloneNotSupportedException("Not implemented"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + return ID.nullID; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (adv instanceof Attributable) { + Attributable attrDoc = (Attributable) adv; + + // Do not output if false. It is the default value. + if (forwardAlwaysReplica) { + attrDoc.addAttribute(FORWARD_ALWAYS_REPLICA, Boolean.toString(forwardAlwaysReplica)); + } + if (forwardBelowTreshold) { + attrDoc.addAttribute(FORWARD_BELOW_TRESHOLD, Boolean.toString(forwardBelowTreshold)); + } + if (localOnly) { + attrDoc.addAttribute(FORWARD_BELOW_TRESHOLD, Boolean.toString(localOnly)); + } + } + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return fields; + } + + /** + * True if this discovery service will forward queries to the replica peer in all cases, rather + * than only in the absence of local responses. + * + * @return The current setting. + */ + public boolean getForwardAlwaysReplica() { + return forwardAlwaysReplica; + } + + /** + * Specifies if this discovery service will forward queries to the replica peer in all cases, rather than only in the absence + * of local responses. + * + * @param newvalue The new setting. + */ + public void setForwardAlwaysReplica(boolean newvalue) { + forwardAlwaysReplica = newvalue; + } + + /** + * True if this discovery service will forward queries when the number of local responses + * is below the specified treshold, rather than only in the absence of local responses. + * + * @return The current setting. + */ + public boolean getForwardBelowTreshold() { + return forwardBelowTreshold; + } + + /** + * Specifies if this discovery service will forward queries when the number of local responses is below the specified + * treshold, rather than only in the absence of local responses. + * + * @param newvalue The new setting. + */ + public void setForwardBelowTreshold(boolean newvalue) { + forwardBelowTreshold = newvalue; + } + + /** + * True if this discovery service performs only local discovery. + * + * @return The current setting. + */ + public boolean getLocalOnly() { + return localOnly; + } + + /** + * Specifies if this discovery service will perform local only discovery. + * + * @param newvalue The new setting. + */ + public void setLocalOnly(boolean newvalue) { + localOnly = newvalue; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryQuery.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryQuery.java new file mode 100644 index 000000000..3c3dbee5f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryQuery.java @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.io.IOException; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.*; +import net.jxta.protocol.DiscoveryQueryMsg; +import net.jxta.protocol.PeerAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.StringReader; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Enumeration; + + +/** + * Implements the Discovery Query Message according to the schema defined by the + * standard JXTA Peer Discovery Protocol (PDP). + *

            + *

            + * <xs:element name="DiscoveryQuery" type="jxta:DiscoveryQuery"/>
            + * 

            + * <xsd:simpleType name="DiscoveryQueryType"> + * <xsd:restriction base="xsd:string"> + * <!-- peer --> + * <xsd:enumeration value="0"/> + * <!-- group --> + * <xsd:enumeration value="1"/> + * <!-- adv --> + * <xsd:enumeration value="2"/> + * </xsd:restriction> + * </xsd:simpleType> + *

            + * <xs:complexType name="DiscoveryQuery"> + * <xs:sequence> + * <xs:element name="Type" type="jxta:DiscoveryQueryType"/> + * <xs:element name="Threshold" type="xs:unsignedInt" minOccurs="0"/> + * <xs:element name="Attr" type="xs:string" minOccurs="0"/> + * <xs:element name="Value" type="xs:string" minOccurs="0"/> + * <!-- The following should refer to a peer adv, but is instead a whole doc for historical reasons --> + * <xs:element name="PeerAdv" type="xs:string" minOccurs="0"/> + * </xs:sequence> + * </xs:complexType> + *

            + * + * @see net.jxta.discovery.DiscoveryService + * @see net.jxta.impl.discovery.DiscoveryServiceImpl + * @see JXTA Protocols Specification : Peer Discovery Protocol + */ +public class DiscoveryQuery extends DiscoveryQueryMsg { + + private static final Logger LOG = Logger.getLogger(DiscoveryQuery.class.getName()); + + private static final String typeTag = "Type"; + private static final String peerAdvTag = "PeerAdv"; + private static final String thresholdTag = "Threshold"; + private static final String queryAttrTag = "Attr"; + private static final String queryValueTag = "Value"; + + /** + * Default constructor + */ + public DiscoveryQuery() {} + + /** + * Construct from a StructuredDocument + * + * @param doc the element + */ + public DiscoveryQuery(Element doc) { + initialize(doc); + } + + /** + * Process an individual element from the document during parse. Normally, + * implementations will allow the base advertisments a chance to handle the + * element before attempting ot handle the element themselves. ie. + *

            + *

            
            +     *  protected boolean handleElement(Element elem) {
            +     * 

            + * if (super.handleElement()) { + * // it's been handled. + * return true; + * } + *

            + * ... handle elements here ... + *

            + * // we don't know how to handle the element + * return false; + * } + *

            + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + */ + protected boolean handleElement(XMLElement elem) { + + String value = elem.getTextValue(); + + if(null == value) { + return false; + } + + value = value.trim(); + + if(0 == value.length()) { + return false; + } + + if (elem.getName().equals(typeTag)) { + setDiscoveryType(Integer.parseInt(value)); + return true; + } + if (elem.getName().equals(thresholdTag)) { + setThreshold(Integer.parseInt(value)); + return true; + } + if (elem.getName().equals(peerAdvTag)) { + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, new StringReader(value)); + PeerAdvertisement adv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + setPeerAdvertisement(adv); + return true; + } catch(IOException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Bad Peer Advertisement"); + failure.initCause(failed); + + throw failure; + } + } + if (elem.getName().equals(queryAttrTag)) { + setAttr(value); + return true; + } + if (elem.getName().equals(queryValueTag)) { + setValue(value); + return true; + } + + // element was not handled + return false; + } + + /** + * Intialize a Discovery Query from a portion of a structured document. + * + * @param root document to intialize from + */ + protected void initialize(Element root) { + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + + XMLElement doc = (XMLElement) root; + + if (!doc.getName().equals(getAdvertisementType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + setDiscoveryType(-1); // force illegal value; + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element : " + elem.toString()); + } + } + } + + // sanity check time! + + if ((DiscoveryService.PEER != getDiscoveryType()) && (DiscoveryService.GROUP != getDiscoveryType()) + && (DiscoveryService.ADV != getDiscoveryType())) { + throw new IllegalArgumentException("Type is not one of the required values."); + } + if (getThreshold() < 0) { + throw new IllegalArgumentException("Threshold must not be less than zero."); + } + if ((getDiscoveryType() != DiscoveryService.PEER) && (getThreshold() == 0)) { + throw new IllegalArgumentException("Threshold may not be zero."); + } + if ((null == getAttr()) && (null != getValue())) { + throw new IllegalArgumentException("Value specified without attribute."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType asMimeType) { + StructuredDocument adv = StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); + + if (adv instanceof XMLDocument) { + XMLDocument xmlDoc = (XMLDocument) adv; + + xmlDoc.addAttribute("xmlns:jxta", "http://jxta.org"); + xmlDoc.addAttribute("xml:space", "preserve"); + } + + Element e; + + e = adv.createElement(typeTag, Integer.toString(getDiscoveryType())); + adv.appendChild(e); + + int threshold = getThreshold(); + + if (threshold < 0) { + throw new IllegalStateException("threshold must be >= 0"); + } + e = adv.createElement(thresholdTag, Integer.toString(threshold)); + adv.appendChild(e); + + PeerAdvertisement peerAdv = getPeerAdvertisement(); + + if ((peerAdv != null)) { + e = adv.createElement(peerAdvTag, peerAdv.toString()); + adv.appendChild(e); + } + + String attr = getAttr(); + + if ((attr != null) && (attr.length() > 0)) { + e = adv.createElement(queryAttrTag, attr.trim()); + adv.appendChild(e); + + String value = getValue(); + + if ((value != null) && (value.length() > 0)) { + e = adv.createElement(queryValueTag, value.trim()); + adv.appendChild(e); + } else { + if (threshold < 0) { + throw new IllegalStateException("Attribute specified, but no value was specified."); + } + } + } + return adv; + } + + /** + * return the string representaion of this doc + * + * @deprecated should not be used. use getDocument().toString() instead. + */ + @Override + @Deprecated + public String toString() { + + try { + StructuredTextDocument doc = (StructuredTextDocument) getDocument(MimeMediaType.XMLUTF8); + + return doc.toString(); + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new UndeclaredThrowableException(e); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryResponse.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryResponse.java new file mode 100644 index 000000000..bfeba1baa --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/DiscoveryResponse.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.protocol.DiscoveryResponseMsg; +import net.jxta.protocol.PeerAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * DiscoveryResponse. + * + *

            This message is part of the standard JXTA Peer Discovery Protocol (PDP). + * + *

            + * <xs:element name="DiscoveryResponse" type="jxta:DiscoveryResponse"/>
            + *
            + * <xs:complexType name="DiscoveryResponse">
            + *   <xs:sequence>
            + *     <xs:element name="Type" type="jxta:DiscoveryQueryType"/>
            + *     <xs:element name="Count" type="xs:unsignedInt" minOccurs="0"/>
            + *     <xs:element name="Attr" type="xs:string" minOccurs="0"/>
            + *     <xs:element name="Value" type="xs:string" minOccurs="0"/>
            + *     <!-- The following should refer to a peer adv, but is instead a whole doc for historical reasons -->
            + *     <xs:element name="PeerAdv" minOccurs="0">
            + *     <xs:complexType>
            + *       <xs:simpleContent>
            + *         <xs:extension base="xs:string">
            + *           <xs:attribute name="Expiration" type="xs:unsignedLong"/>
            + *         </xs:extension>
            + *       </xs:simpleContent>
            + *     </xs:complexType>
            + *     </xs:element>
            + *     <xs:element name="Response" maxOccurs="unbounded">
            + *     <xs:complexType>
            + *       <xs:simpleContent>
            + *         <xs:extension base="xs:string">
            + *           <xs:attribute name="Expiration" type="xs:unsignedLong"/>
            + *         </xs:extension>
            + *       </xs:simpleContent>
            + *     </xs:complexType>
            + *     </xs:element>
            + *   </xs:sequence>
            + * </xs:complexType>
            + * 
            + * + *@see net.jxta.discovery.DiscoveryService + *@see net.jxta.impl.discovery.DiscoveryServiceImpl + *@see JXTA Protocols Specification : Peer Discovery Protocol + */ +public class DiscoveryResponse extends DiscoveryResponseMsg { + + private final static transient Logger LOG = Logger.getLogger(DiscoveryResponse.class.getName()); + + private final static String countTag = "Count"; + private final static String expirationTag = "Expiration"; + private final static String peerAdvTag = "PeerAdv"; + private final static String queryAttrTag = "Attr"; + private final static String queryValueTag = "Value"; + private final static String responsesTag = "Response"; + private final static String typeTag = "Type"; + + /** + * Constructor for new instances. + */ + public DiscoveryResponse() {} + + /** + * Construct from a StructuredDocument + * + *@param root Description of the Parameter + */ + public DiscoveryResponse(Element root) { + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + XMLElement doc = (XMLElement) root; + String docName = doc.getName(); + + if (!getAdvertisementType().equals(docName)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + " from doc containing a " + docName); + } + readIt(doc); + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType asMimeType) { + + StructuredTextDocument adv = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); + + if (adv instanceof XMLDocument) { + ((XMLDocument) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e; + + e = adv.createElement(countTag, Integer.toString(responses.size())); + adv.appendChild(e); + e = adv.createElement(typeTag, Integer.toString(type)); + adv.appendChild(e); + + PeerAdvertisement myPeerAdv = getPeerAdvertisement(); + + if (null != myPeerAdv) { + e = adv.createElement(peerAdvTag, myPeerAdv.toString()); + adv.appendChild(e); + } + + if ((attr != null) && (attr.length() > 0)) { + e = adv.createElement(queryAttrTag, getQueryAttr()); + adv.appendChild(e); + if ((value != null) && (value.length() > 0)) { + e = adv.createElement(queryValueTag, value); + adv.appendChild(e); + } + } + + Enumeration advs = getResponses(); + Enumeration exps = getExpirations(); + + try { + while (advs.hasMoreElements()) { + Long l = (Long) exps.nextElement(); + String response = advs.nextElement(); + + e = adv.createElement(responsesTag, response); + + adv.appendChild(e); + if (adv instanceof Attributable) { + ((Attributable) e).addAttribute(expirationTag, l.toString()); + } + } + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Got an Exception during doc creation", failed); + } + IllegalStateException failure = new IllegalStateException("Got an Exception during doc creation"); + + failure.initCause(failed); + throw failure; + } + return adv; + } + + /** + * Parses a document into this object + * + *@param doc Document + */ + private void readIt(XMLElement doc) { + Vector res = new Vector(); + Vector exps = new Vector(); + + try { + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (elem.getName().equals(typeTag)) { + type = Integer.parseInt(elem.getTextValue()); + continue; + } + + if (elem.getName().equals(peerAdvTag)) { + String peerString = elem.getTextValue(); + + if (null == peerString) { + continue; + } + + peerString = peerString.trim(); + if (peerString.length() > 0) { + XMLDocument xmlPeerAdv = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( + MimeMediaType.XMLUTF8, new StringReader(peerString)); + + setPeerAdvertisement((PeerAdvertisement) AdvertisementFactory.newAdvertisement(xmlPeerAdv)); + } + continue; + } + + if (elem.getName().equals(queryAttrTag)) { + setQueryAttr(elem.getTextValue()); + continue; + } + + if (elem.getName().equals(queryValueTag)) { + setQueryValue(elem.getTextValue()); + continue; + } + + if (elem.getName().equals(responsesTag)) { + // get the response + String aResponse = elem.getTextValue(); + + if (null == aResponse) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding an empty response tag"); + } + continue; + } + res.add(aResponse); + + long exp; + // get expiration associated with this response + Attribute attr = (elem).getAttribute(expirationTag); + + if (null != attr) { + exp = Long.parseLong(attr.getValue()); + } else { + // if there are no attribute use DEFAULT_EXPIRATION + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Received an old-style DiscoveryResponse.\n You received a response from a peer that does \nnot support advertisement aging. \nSetting expiration to DiscoveryService.DEFAULT_EXPIRATION "); + } + exp = DiscoveryService.DEFAULT_EXPIRATION; + } + + exps.add(exp); + } + } + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Got an Exception during Parse ", failed); + } + IllegalArgumentException failure = new IllegalArgumentException("Got an Exception during parse"); + + failure.initCause(failed); + throw failure; + } + + setResponses(res); + setExpirations(exps); + } + + /** + * Return a string representation of this message. The string will + * contain the message formated as a UTF-8 encoded XML Document. + * + * @return String a String containing the message. + */ + @Override + public String toString() { + + try { + XMLDocument doc = (XMLDocument) getDocument(MimeMediaType.XMLUTF8); + + return doc.toString(); + } catch (Throwable e) { + if (e instanceof Error) { + throw (Error) e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new UndeclaredThrowableException(e); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/GroupConfig.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/GroupConfig.java new file mode 100644 index 000000000..6eef38cc9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/GroupConfig.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.logging.Logging; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.id.ID; +import net.jxta.protocol.ConfigParams; + + +/** + * Configuration container for any Peer Group. + */ +public class GroupConfig extends ConfigParams implements Cloneable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(GroupConfig.class.getName()); + + private static final String advType = "jxta:GroupConfig"; + + /** + * Instantiator for GroupConfig + */ + public final static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new GroupConfig(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new GroupConfig((XMLElement) root); + } + } + + /** + * Use the Instantiator through the factory + */ + GroupConfig() {} + + /** + * Use the Instantiator through the factory + * + * @param root the element + */ + GroupConfig(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + Element elem = (Element) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + } + + /** + * Make a safe clone of this GroupConfig. + * + * @return Object an object of class GroupConfig that is a deep-enough + * copy of this one. + */ + @Override + public GroupConfig clone() { + GroupConfig result = (GroupConfig) super.clone(); + + return result; + } + + /** + * returns the advertisement type + * + * @return string type + */ + public static String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public StructuredDocument getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + addDocumentElements(adv); + + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return new String[0]; + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + return null; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/HTTPAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/HTTPAdv.java new file mode 100644 index 000000000..e253c968a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/HTTPAdv.java @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.protocol.TransportAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.util.Arrays; +import java.util.Enumeration; + + +/** + * Configuration parameters for HttpServelet Message Transport. + */ +public class HTTPAdv extends TransportAdvertisement { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(HTTPAdv.class.getName()); + + private static final String CONFIGMODES[] = { "auto", "manual"}; + private static final String INDEXFIELDS[] = {/* none */}; + + private static final String ProtocolTag = "Protocol"; + private static final String ProxyTag = "Proxy"; + private static final String ServerTag = "Server"; + private static final String PortTag = "Port"; + private static final String IntfAddrTag = "InterfaceAddress"; + private static final String ConfModeTag = "ConfigMode"; + private static final String FlagsTag = "Flags"; + private static final String PublicAddressOnlyAttr = "PublicAddressOnly"; + private static final String ProxyOffTag = "ProxyOff"; + private static final String ServerOffTag = "ServerOff"; + private static final String ClientOffTag = "ClientOff"; + + private String proxy = null; + private String server = null; + private int listenPort = -1; // The real port a server listens to + + private String interfaceAddress = null; // What IP to bind to locally + + private String configMode = CONFIGMODES[0]; + private boolean publicAddressOnly = false; + + // These are for configuration; They get saved in the document only if they are + // off and the correspondig item has a non-null value. So that the value is not lost. + // When HttpTransport is done initializing, the unused values are set to null, and thus + // pruned from the published adv. + + private boolean proxyEnabled = true; + private boolean serverEnabled = true; + private boolean clientEnabled = true; + + /** + * Our instantiator. + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return HTTPAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new HTTPAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new HTTPAdv((XMLElement) root); + } + } + + /** + * Returns the identifying type of this Advertisement. + *

            + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + *

            + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertisement.getAdvertisementType() no matter what the real type of the + * advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:HTTPTransportAdvertisement"; + } + + /** + * Private constructor for new instances. Use the instantiator. + */ + private HTTPAdv() { + } + + /** + * Private constructor for xml serialized instances. Use the instantiator. + * + * @param doc The XML serialization of the advertisement. + */ + private HTTPAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Attribute attr = doc.getAttribute(FlagsTag); + + if (attr != null) { + String options = attr.getValue(); + + publicAddressOnly = (options.indexOf(PublicAddressOnlyAttr) != -1); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + // For consistency we force the flags to "disabled" for items we do not + // have data for. However, the flags truely matter only when there is + // data. + if (proxy == null) { + proxyEnabled = false; + } + + if (serverEnabled && (0 == listenPort)) { + throw new IllegalArgumentException("Dynmaic port selection not supported with incoming connections."); + } + + if ((listenPort < -1) || (listenPort > 65535)) { + throw new IllegalArgumentException("Illegal Listen Port Value"); + } + + if (!Arrays.asList(CONFIGMODES).contains(configMode)) { + throw new IllegalArgumentException("Unsupported configuration mode."); + } + + // XXX 20050118 bondolo Some versions apparently don't initialize this field. Eventually make it required. + if (null == getProtocol()) { + setProtocol("http"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + String tag = elem.getName(); + + if (tag.equals(ProxyOffTag)) { + proxyEnabled = false; + return true; + } + + if (tag.equals(ServerOffTag)) { + serverEnabled = false; + return true; + } + + if (tag.equals(ClientOffTag)) { + clientEnabled = false; + return true; + } + + String value = elem.getTextValue(); + + if (null == value) { + return false; + } + + value = value.trim(); + + if (0 == value.length()) { + return false; + } + + if (tag.equals(ProtocolTag)) { + setProtocol(value); + return true; + } + + if (tag.equals(IntfAddrTag)) { + setInterfaceAddress(value); + return true; + } + + if (tag.equals(ConfModeTag)) { + setConfigMode(value); + return true; + } + + if (tag.equals(PortTag)) { + setPort(Integer.parseInt(value.trim())); + return true; + } + + if (tag.equals(ProxyTag)) { + proxy = value; + return true; + } + + if (tag.equals(ServerTag)) { + server = value; + return true; + } + + return false; + } + + /** + * {@inheritDoc} + *

            + *

            NB: we do not try to enforce dependency rules + * such as Proxy only when router, because we want to convey the complete + * configuration, even items corresponding to not currently enabled + * features. HttpTransport will gracefully disregard items that have + * no use in the current context. + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + if (serverEnabled && (0 == listenPort)) { + throw new IllegalStateException("Dynmaic port selection not supported with incoming connections."); + } + + if ((listenPort < -1) || (listenPort > 65535)) { + throw new IllegalStateException("Illegal Listen Port Value"); + } + + if (!Arrays.asList(CONFIGMODES).contains(configMode)) { + throw new IllegalStateException("Unsupported configuration mode."); + } + + // XXX 20050118 bondolo Some versions apparently don't initialize this field. Eventually make it required. + if (null == getProtocol()) { + setProtocol("http"); + } + + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (adv instanceof Attributable) { + // Only one flag for now. Easy. + if (publicAddressOnly) { + ((Attributable) adv).addAttribute(FlagsTag, PublicAddressOnlyAttr); + } + } + + Element e1 = adv.createElement(ProtocolTag, getProtocol()); + + adv.appendChild(e1); + + if (null != getInterfaceAddress()) { + Element e2 = adv.createElement(IntfAddrTag, getInterfaceAddress()); + + adv.appendChild(e2); + } + + Element e3 = adv.createElement(ConfModeTag, getConfigMode()); + + adv.appendChild(e3); + + Element e4 = adv.createElement(PortTag, Integer.toString(getPort())); + + adv.appendChild(e4); + + Element ext; + + if (proxy != null) { + ext = adv.createElement(ProxyTag, proxy); + adv.appendChild(ext); + } + + // If disabled, say it; otherwise it is assumed on. In published + // advs, we only keep data for items that are ON, so we do not + // have to clutter them with the flag. + if (!proxyEnabled) { + ext = adv.createElement(ProxyOffTag); + adv.appendChild(ext); + } + + if (server != null) { + ext = adv.createElement(ServerTag, server); + adv.appendChild(ext); + } + + // If disabled, say it; otherwise it is assumed on. In published + // advs, we only keep data for items that are ON, so we do not + // have to clutter them with the flag. + if (!serverEnabled) { + ext = adv.createElement(ServerOffTag); + adv.appendChild(ext); + } + + // If disabled, say it; otherwise it is assumed on. In published + // advs, we only keep data for items that are ON, so we do not + // have to clutter them with the flag. + if (!clientEnabled) { + ext = adv.createElement(ClientOffTag); + adv.appendChild(ext); + } + + return adv; + } + + /** + * Returns the interfaceAddr. That is, the ip of the IF to which to bind + * locally created sockets. + * + * @return string The address. + */ + public String getInterfaceAddress() { + return interfaceAddress; + } + + /** + * Sets the interfaceAddr. That is, the ip of the IF to which to bind + * locally created sockets. + * + * @param address The address + */ + public void setInterfaceAddress(String address) { + this.interfaceAddress = address; + } + + public boolean getPublicAddressOnly() { + return publicAddressOnly; + } + + public void setPublicAddressOnly(boolean only) { + publicAddressOnly = only; + } + + /** + * returns the config mode. That is, how the user prefers to configure + * the interface address: "auto", "manual" + * + * @return string config mode + */ + public String getConfigMode() { + return configMode; + } + + /** + * set the config mode. That is, how the user prefers to configure + * the interface address: "auto", "manual" + *

            + * This is just a pure config item. It is never in published advs. The TCP + * transport strips it when it initializes. + * + * @param mode Can be "auto", "manual" other settings will act as the default + * which is "auto". + */ + public void setConfigMode(String mode) { + if (!Arrays.asList(CONFIGMODES).contains(mode)) { + throw new IllegalArgumentException("Unsupported configuration mode."); + } + + configMode = mode; + } + + /** + * Returns the port number to which server sockets are locally bound. + * + * @return String the port + */ + public int getPort() { + return listenPort; + } + + /** + * Sets the port number to which server sockets are locally bound. + * + * @param newPort the port + */ + public void setPort(int newPort) { + listenPort = newPort; + } + + /** + * @return the proxy string + * @deprecated This has been deprecated. Set your proxy directly with the JVM + */ + @Deprecated + public String getProxy() { + return proxy; + } + + public String getServer() { + return server; + } + + /** + * @return true if proxy enabled + * @deprecated This has been deprecated. Set your proxy directly with the JVM + */ + @Deprecated + public boolean isProxyEnabled() { + return proxyEnabled; + } + + public boolean isServerEnabled() { + return serverEnabled; + } + + public boolean isClientEnabled() { + return clientEnabled; + } + + // If one of proxy, server, or router is cleared, the corresponding + // enabled flag should be false (the opposite is not true). + + /** + * @param name the proxy string + * @deprecated This has been deprecated. Set your proxy directly with the JVM + */ + @Deprecated + public void setProxy(String name) { + proxy = name; + if (name == null) { + proxyEnabled = false; + } + } + + public void setServer(String name) { + server = name; + } + + /** + * @param enabled true if proxy is enabled + * @deprecated This has been deprecated. Set your proxy directly with the JVM + */ + @Deprecated + public void setProxyEnabled(boolean enabled) { + proxyEnabled = enabled; + } + + public void setServerEnabled(boolean enabled) { + serverEnabled = enabled; + } + + public void setClientEnabled(boolean enabled) { + clientEnabled = enabled; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEXFIELDS; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LeaseRequestMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LeaseRequestMsg.java new file mode 100644 index 000000000..ae3607866 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LeaseRequestMsg.java @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.net.URI; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.UUID; + +import java.net.URISyntaxException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.Attribute; +import net.jxta.document.Attributable; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.protocol.PeerAdvertisement; + + +/** + * A Leasing Protocol Request Message. + * + *

            
            + *  <xs:complexType name="LeaseRequestMessage">
            + *      <xs:sequence>
            + *          <xs:element name="Credential" type="jxta:Cred" />
            + *          <xs:element name="ClientAdv" minOccurs="0" >
            + *              <xs:complexType>
            + *                  <xs:complexContent>
            + *                      <xs:extension  base="jxta:PA">
            + *                          <xs:attribute name="expiration" use="required" type="xs:unsignedLong" />
            + *                      </xs:extension>
            + *                  </xs:complexContent>
            + *              </xs:complexType>
            + *          </xs:element>
            + *          <xs:element name="Option" minOccurs="0" maxOccurs="unbounded" type="xs:anyType" />
            + *      </xs:sequence>
            + *      <xs:attribute name="client_id" use="required" type="jxta:JXTAID" />
            + *      <xs:attribute name="requested_lease" type="xs:unsignedLong" />
            + *      <xs:attribute name="server_adv_gen" type="jxta:uuid" />
            + *      <xs:attribute name="referral_advs" type="xs:unsignedInt" />
            + *  </xs:complexType>
            + * 
            + * + * @since 2.5 + */ +public class LeaseRequestMsg { + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(LeaseRequestMsg.class.getName()); + + private final static String LEASE_REQUEST_MSG = "LeaseRequestMessage"; + private final static String CLIENT_ID_ATTR = "client_id"; + private final static String REQUESTED_LEASE_ATTR = "requested_lease"; + private final static String SERVER_ADV_GEN_ATTR = "server_adv_gen"; + private final static String REFERRAL_ADVS_ATTR = "referral_advs"; + + private final static String CLIENT_CRED_TAG = "Credential"; + private final static String CLIENT_ADV_TAG = "ClientAdv"; + private final static String CLIENT_ADV_EXP_ATTR = "ClientAdv"; + + private final static String OPTION_TAG = "Options"; + + /** + * The ID of the client. + */ + private ID clientID = null; + + /** + * Length of lease to request. {@code Long.MIN_VALUE} means that no lease + * is being requested, instead the message is being sent to retrieve + * referrals. + */ + private long requestedLease = Long.MIN_VALUE; + + /** + * last UUID version of the server's advertisement that the client saw or + * {@code null} if client claims to have seen no pervious version. + */ + private UUID serverAdvGen = null; + + /** + * The number of referral advertisements being requested. + */ + private int referralAdvs = Integer.MIN_VALUE; + + /** + * The credential of the client. + */ + private XMLElement credential = null; + + /** + * The optional peer advertisement of the client. + */ + private PeerAdvertisement clientAdv = null; + + /** + * Expiration value for client peer advertisement. {@code Long.MIN_VALUE} + * means that no value has been specified. + */ + private long clientAdvExp = Integer.MIN_VALUE; + + /** + * Options + */ + private List options = new ArrayList(); + + /** + * New LeaseRequestMsg + */ + public LeaseRequestMsg() {} + + /** + * Construct from a XLMElement + **/ + public LeaseRequestMsg(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doc.getName().equals(getMessageType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + " from doc containing a '" + doc.getName() + + "'. Should be : " + getMessageType()); + } + + Enumeration eachAttr = doc.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aLeaseReqAttr = (Attribute) eachAttr.nextElement(); + + if (REQUESTED_LEASE_ATTR.equals(aLeaseReqAttr.getName())) { + requestedLease = Long.valueOf(aLeaseReqAttr.getValue()); + } else if (SERVER_ADV_GEN_ATTR.equals(aLeaseReqAttr.getName())) { + serverAdvGen = UUID.fromString(aLeaseReqAttr.getValue()); + } else if (CLIENT_ID_ATTR.equals(aLeaseReqAttr.getName())) { + try { + URI srcURI = new URI(aLeaseReqAttr.getValue()); + ID srcID = IDFactory.fromURI(srcURI); + + setClientID(srcID); + } catch (URISyntaxException badID) { + IllegalArgumentException iae = new IllegalArgumentException("Bad ID in message"); + + iae.initCause(badID); + throw iae; + } + } else if ("type".equals(aLeaseReqAttr.getName())) { + ; + } else if ("xmlns:jxta".equals(aLeaseReqAttr.getName())) { + ; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aLeaseReqAttr.getName()); + } + } + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + if (null == getClientID()) { + throw new IllegalArgumentException("Missing client ID value."); + } + + if ((getRequestedLease() < 0) && (getRequestedLease() != Long.MIN_VALUE)) { + throw new IllegalArgumentException("Invalid requested lease duration."); + } + + if ((getReferralAdvs() < 0) && (getReferralAdvs() != Integer.MIN_VALUE)) { + throw new IllegalArgumentException("Invalid referral advertisements request value."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object clone() throws CloneNotSupportedException { + LeaseRequestMsg clone = (LeaseRequestMsg) super.clone(); + + clone.setClientID(getClientID()); + clone.setServerAdvGen(getServerAdvGen()); + clone.setRequestedLease(getRequestedLease()); + clone.setReferralAdvs(getReferralAdvs()); + clone.setCredential(getCredential()); + return clone; + } + + /** + * Returns the ID of the client making this request. + * + * @return ID of the client. + */ + public ID getClientID() { + return clientID; + } + + /** + * Sets the ID of the client making this request. + * + * @param clientID ID of the client. + */ + public void setClientID(ID clientID) { + this.clientID = clientID; + } + + /** + * Returns the advertisement generation of the server advertisement which + * is known to the client. May be {@code null} to indicate that the client + * does not have a previous version of the server advertisement. + * + * @return The server advertisement generation. + */ + public UUID getServerAdvGen() { + return serverAdvGen; + } + + /** + * Sets the advertisement generation of the server advertisement which is + * known to the client. May be {@code null} to indicate that the client + * does not have a previous version of the server advertisement. + * + * @param serverAdvGen The server advertisement generation. + */ + public void setServerAdvGen(UUID serverAdvGen) { + this.serverAdvGen = serverAdvGen; + } + + /** + * Return the duration of the lease being requested. The duration must be + * a positive integer or {@code Long.MIN_VALUE} which indicates that no + * lease is being requested. + * + * @return The duration of the lease being requested. + */ + public long getRequestedLease() { + return requestedLease; + } + + /** + * Set the duration of the lease being requested. The duration must be + * a positive integer or {@code Long.MIN_VALUE} which indicates that no + * lease is being requested. + * + * @param requestedLease The duration of the lease being requested. + */ + public void setRequestedLease(long requestedLease) { + this.requestedLease = requestedLease; + } + + /** + * Returns the number of referral advertisements requested by the client. + * Must be a positive integer or {@code Integer.MIN_VALUE} which indicates + * that the default number is requested. + * @return the number of referral advertisements requested by the client. + */ + public int getReferralAdvs() { + return referralAdvs; + } + + /** + * Sets the number of referral advertisements requested by the client. + * Must be a positive integer or {@code Integer.MIN_VALUE} which indicates + * that the default number is requested. + * + * @param referralAdvs The number of referral advertisements requested. + */ + public void setReferralAdvs(int referralAdvs) { + this.referralAdvs = referralAdvs; + } + + /** + * Returns the credential of the client making this request in XML format. + * + * @return The credential associated with this request if any. May be + * {@code null} to indicate that no credential was provided. + */ + public XMLElement getCredential() { + return (XMLElement) ((null != credential) ? StructuredDocumentUtils.copyAsDocument(credential) : null); + } + + /** + * Sets the credential of the client making this request in XML format. + * + * @param newCred The credential associated with this request if any. May + * be {@code null} to indicate that no credential is being provided. + */ + public void setCredential(XMLElement newCred) { + this.credential = (XMLElement) ((null != newCred) ? StructuredDocumentUtils.copyAsDocument(newCred) : null); + } + + /** + * Our DOCTYPE + * + * @return the type of this message. + **/ + public static String getMessageType() { + return "jxta:LeaseRequestMsg"; + } + + protected boolean handleElement(XMLElement elem) { + + if (CLIENT_CRED_TAG.equals(elem.getName())) { + credential = (XMLElement) StructuredDocumentUtils.copyAsDocument(elem); + + return true; + } + + String value = elem.getTextValue(); + + if (null != value) { + value = value.trim(); + + if (0 == value.length()) { + value = null; + } + } + + if (null == value) { + return false; + } + + return false; + } + + /** + * {@inheritDoc} + **/ + public Document getDocument(MimeMediaType mediaType) { + + if (null == getClientID()) { + throw new IllegalStateException("Missing client ID value."); + } + + if ((getRequestedLease() < 0) && (getRequestedLease() != Long.MIN_VALUE)) { + throw new IllegalStateException("Invalid requested lease duration."); + } + + if ((getReferralAdvs() < 0) && (getReferralAdvs() != Integer.MIN_VALUE)) { + throw new IllegalStateException("Invalid referral advertisements request value."); + } + + StructuredDocument msg = StructuredDocumentFactory.newStructuredDocument(mediaType, getMessageType()); + + if (!(msg instanceof Attributable)) { + throw new UnsupportedOperationException("Only 'Attributable' document types are supported."); + } + + if (msg instanceof XMLDocument) { + ((XMLDocument) msg).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + ((Attributable) msg).addAttribute(CLIENT_ID_ATTR, getClientID().toString()); + + if (Long.MIN_VALUE != getRequestedLease()) { + ((Attributable) msg).addAttribute(REQUESTED_LEASE_ATTR, Long.toString(getRequestedLease())); + } + + if (null != getServerAdvGen()) { + ((Attributable) msg).addAttribute(SERVER_ADV_GEN_ATTR, getServerAdvGen().toString()); + } + + if (null != credential) { + StructuredDocumentUtils.copyElements(msg, msg, credential, CLIENT_CRED_TAG); + } + + return msg; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LeaseResponseMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LeaseResponseMsg.java new file mode 100644 index 000000000..b0297458c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LeaseResponseMsg.java @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import java.net.URISyntaxException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Attributable; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.protocol.RdvAdvertisement; + + +/** + * A Leasing Protocol Response Message. + * + *

            
            + * 
            + *   
            + *     
            + *     
            + *       
            + *         
            + *           
            + *              
            + *             
            + *           
            + *         
            + *       
            + *     
            + *     
            + *       
            + *         
            + *           
            + *             
            + *           
            + *         
            + *       
            + *     
            + *   
            + *   
            + *   
            + * 
            + * 
            + * + * @since JXTA 2.4 + */ +public class LeaseResponseMsg { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(LeaseResponseMsg.class.getName()); + + private final static String OFFERED_LEASE_ATTR = "offeredLease"; + + private final static String SERVER_ID_ATTR = "serverID"; + + private final static String SERVER_ADV_TAG = "serverAdv"; + private final static String ADV_GEN_ATTR = "advGen"; + private final static String ADV_EXP_ATTR = "expiration"; + private final static String REFERRAL_ADV_TAG = "referralAdv"; + + private final static String SERVER_CRED_TAG = "credential"; + + /** + * ID of the server providing this response. + */ + private ID serverID = null; + + /** + * The advertisement of the server providing this response. + */ + private RdvAdvertisement serverAdv = null; + + /** + * The expiration duration of the server advertisement. + */ + private long serverAdvExp = Long.MIN_VALUE; + + /** + * The advertisement generation of the server advertisement. + */ + private UUID serverAdvGen = null; + + /** + * Credential of the server. + */ + private XMLElement credential = null; + + /** + * Ordered list of referral advertisements. + */ + private List referralAdvs = new ArrayList(); + + /** + * Ordered list of referral advertisement expirations. The order matches + * the order of advertisements in {@link #referralAdvs}. + */ + private List referralAdvExps = new ArrayList(); + + /** + * The duration of the offered lease. May also be {@code Long.MIN_VALUE} to + * indicate that no lease is being offered. + */ + private long offeredLease = Long.MIN_VALUE; + + /** + * New LeaseResponseMsg + */ + public LeaseResponseMsg() {} + + /** + * Construct from a StructuredDocument + * @param root the element + */ + public LeaseResponseMsg(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doc.getName().equals(getMessageType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + " from doc containing a '" + doc.getName() + + "'. Should be : " + getMessageType()); + } + + Enumeration eachAttr = doc.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aRdvAttr = (Attribute) eachAttr.nextElement(); + + if (SERVER_ID_ATTR.equals(aRdvAttr.getName())) { + try { + URI srcURI = new URI(aRdvAttr.getValue()); + ID srcID = IDFactory.fromURI(srcURI); + + setServerID(srcID); + } catch (URISyntaxException badID) { + IllegalArgumentException iae = new IllegalArgumentException("Bad server ID in message"); + + iae.initCause(badID); + throw iae; + } + } else if (OFFERED_LEASE_ATTR.equals(aRdvAttr.getName())) { + offeredLease = Long.valueOf(aRdvAttr.getValue()); + } else if ("type".equals(aRdvAttr.getName())) { + ; + } else if ("xmlns:jxta".equals(aRdvAttr.getName())) { + ; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aRdvAttr.getName()); + } + } + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + if (null == serverID) { + throw new IllegalArgumentException("Missing Server ID."); + } + + if ((null != serverAdv) && (null == serverAdvGen)) { + throw new IllegalArgumentException("Missing Server Advertisement Generation."); + } + + if ((null != serverAdv) && (Long.MIN_VALUE == serverAdvExp)) { + throw new IllegalArgumentException("Missing Server Advertisement Expiration."); + } + + if ((null != serverAdv) && (serverAdvExp <= 0)) { + throw new IllegalArgumentException("Illegal Server Advertisement Expiration."); + } + + if ((offeredLease < 0) && (Long.MIN_VALUE != offeredLease)) { + throw new IllegalArgumentException("Illegal Lease offered."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object clone() throws CloneNotSupportedException { + LeaseResponseMsg clone = (LeaseResponseMsg) super.clone(); + + clone.setServerID(getServerID()); + clone.setServerAdv(getServerAdv(), getServerAdvGen(), getServerAdvExp()); + clone.setCredential(getCredential()); + clone.addReferralAdvs(Arrays.asList(getReferralAdvs()), Arrays.asList(getReferralAdvExps())); + clone.setOfferedLease(getOfferedLease()); + return clone; + } + + /** + * Returns the ID of the server providing this response. + * + * @return ID of the server. + */ + public ID getServerID() { + return serverID; + } + + /** + * Sets the ID of the server providing this response. + * + * @param serverID ID of the server. + */ + public void setServerID(ID serverID) { + this.serverID = serverID; + } + + /** + * Returns the advertisement of the server providing this response. + * + * @return The servers advertisement. + */ + public RdvAdvertisement getServerAdv() { + return serverAdv; + } + + /** + * Returns the advertisement generation of the server's advertisement. + * + * @return The advertisement generation of the server's advertisement. + */ + public UUID getServerAdvGen() { + return serverAdvGen; + } + + /** + * Returns the advertisement expiration duration of the server's + * advertisement. Must be a positive integer. + * + * @return The advertisement expiration duration of the server's advertisement. + */ + public long getServerAdvExp() { + return serverAdvExp; + } + + /** + * Sets the server advertisement and the associated advertisement + * generation and expiration. + * + * @param serverAdv The servers advertisement. + * @param serverAdvGen The advertisement generation of the server's + * advertisement. Must be a positive integer. + * @param serverAdvExp The advertisement expiration duration of the + * server's advertisement. + */ + public void setServerAdv(RdvAdvertisement serverAdv, UUID serverAdvGen, long serverAdvExp) { + this.serverAdv = serverAdv; + this.serverAdvGen = serverAdvGen; + this.serverAdvExp = serverAdvExp; + } + + /** + * Returns an ordered list of the referral advertisements. + * + * @return An ordered list of the referral advertisements. + */ + public RdvAdvertisement[] getReferralAdvs() { + return referralAdvs.toArray(new RdvAdvertisement[referralAdvs.size()]); + } + + /** + * Returns an ordered list of the referral advertisements expirations. The + * order of the expirations matches the order of advertisements returned + * by {@link #getReferralAdvs()}. Each entry is a positive integer. + * + * @return An ordered list of the referral advertisements expirations. + */ + public Long[] getReferralAdvExps() { + return referralAdvExps.toArray(new Long[referralAdvExps.size()]); + } + + /** + * Adds a referral advertisement to the collection of referral + * advertisements. The advertisement is added at the end of the ordered + * list. + * + * @param referralAdv The referral advertisement. + * @param referralAdvExp The expiration time of the referral advertisement. + * The value must be a positive integer. + */ + public void addReferralAdv(RdvAdvertisement referralAdv, long referralAdvExp) { + referralAdvs.add(referralAdv); + referralAdvExps.add(referralAdvExp); + } + + /** + * Adds referral advertisements to the collection of referral + * advertisements. The advertisements are added at the end of the ordered + * list. + * + * @param referralAdvs The referral advertisements. + * @param referralAdvExps The expiration times of the referral advertisement. + * The values must be a positive integer. + */ + public void addReferralAdvs(List referralAdvs, List referralAdvExps) { + this.referralAdvs.addAll(referralAdvs); + this.referralAdvExps.addAll(referralAdvExps); + } + + /** + * Clears the list of referral advertisements. + */ + public void clearReferralAdvs() { + referralAdvs.clear(); + referralAdvExps.clear(); + } + + /** + * Returns the lease being offered. The value must be greater than or + * equal to zero or the constant {@code Long.MIN_VALUE} which indicates + * that no lease is being offered. + * + * @return The lease being offered. + */ + public long getOfferedLease() { + return offeredLease; + } + + /** + * Sets the lease being offered. The value must be greater than or + * equal to zero or the constant {@code Long.MIN_VALUE} which indicates + * that no lease is being offered. + * + * @param offeredLease The lease being offered. + */ + public void setOfferedLease(long offeredLease) { + this.offeredLease = offeredLease; + } + + /** + * Returns the credential of the server providing this response in XML + * format. + * + * @return The credential associated with this response if any. May be + * {@code null} to indicate that no credential was provided. + */ + public XMLElement getCredential() { + return (XMLElement) ((null != credential) ? StructuredDocumentUtils.copyAsDocument(credential) : null); + } + + /** + * Sets the credential of the server providing this response in XML + * format. + * + * @param newCred The credential associated with this response if any. May + * be {@code null} to indicate that no credential is being provided. + */ + public void setCredential(XMLElement newCred) { + this.credential = (XMLElement) ((null != newCred) ? StructuredDocumentUtils.copyAsDocument(newCred) : null); + } + + /** + * Our DOCTYPE + * + * @return the type of this message. + */ + public static String getMessageType() { + return "jxta:LeaseResponseMsg"; + } + + /** + * Process an element of the message XML document. + * + * @param elem The element to process. + * @return If {@code true} then the element was processed otherwise {@code false}. + */ + protected boolean handleElement(XMLElement elem) { + + if (SERVER_ADV_TAG.equals(elem.getName())) { + Enumeration eachAttr = elem.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute anAdvAttr = (Attribute) eachAttr.nextElement(); + + if (ADV_GEN_ATTR.equals(anAdvAttr.getName())) { + serverAdvGen = UUID.fromString(anAdvAttr.getValue()); + } else if (ADV_EXP_ATTR.equals(anAdvAttr.getName())) { + serverAdvExp = Long.valueOf(anAdvAttr.getValue()); + } else if ("type".equals(anAdvAttr.getName())) { + ; + } else if ("xmlns:jxta".equals(anAdvAttr.getName())) { + ; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + anAdvAttr.getName()); + } + } + } + + serverAdv = (RdvAdvertisement) AdvertisementFactory.newAdvertisement(elem); + return true; + } else if (REFERRAL_ADV_TAG.equals(elem.getName())) { + long expiration = Long.MIN_VALUE; + + Enumeration eachAttr = elem.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute anAdvAttr = (Attribute) eachAttr.nextElement(); + + if (ADV_EXP_ATTR.equals(anAdvAttr.getName())) { + expiration = Long.valueOf(anAdvAttr.getValue()); + } else if ("type".equals(anAdvAttr.getName())) { + ; + } else if ("xmlns:jxta".equals(anAdvAttr.getName())) { + ; + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + anAdvAttr.getName()); + } + } + } + + if (Long.MIN_VALUE == expiration) { + throw new IllegalArgumentException("Missing Referral Advertisement Expiration."); + } + + if (expiration <= 0) { + throw new IllegalArgumentException("Illegal Referral Advertisement Expiration."); + } + + RdvAdvertisement referralAdv = (RdvAdvertisement) AdvertisementFactory.newAdvertisement(elem); + + // Fix the embedded Route Adv. Often it does not contain a PeerID + // in the route because its redundant. + referralAdv.getRouteAdv().setDestPeerID(referralAdv.getPeerID()); + + referralAdvs.add(referralAdv); + referralAdvExps.add(expiration); + return true; + } else if (SERVER_CRED_TAG.equals(elem.getName())) { + credential = (XMLElement) StructuredDocumentUtils.copyAsDocument(elem); + + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + public Document getDocument(MimeMediaType mediaType) { + if (null == serverID) { + throw new IllegalStateException("Missing Server ID."); + } + + if ((null != serverAdv) && (null == serverAdvGen)) { + throw new IllegalStateException("Missing Server Advertisement Generation."); + } + + if ((null != serverAdv) && (Long.MIN_VALUE == serverAdvExp)) { + throw new IllegalStateException("Missing Server Advertisement Expiration."); + } + + if ((null != serverAdv) && (serverAdvExp <= 0)) { + throw new IllegalStateException("Illegal Server Advertisement Expiration."); + } + + if ((offeredLease < 0) && (Long.MIN_VALUE != offeredLease)) { + throw new IllegalStateException("Illegal Lease offered."); + } + + StructuredDocument msg = StructuredDocumentFactory.newStructuredDocument(mediaType, getMessageType()); + + if (!(msg instanceof Attributable)) { + throw new UnsupportedOperationException("Only 'Attributable' document types are supported."); + } + + if (msg instanceof XMLDocument) { + ((XMLDocument) msg).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + ((Attributable) msg).addAttribute(SERVER_ID_ATTR, getServerID().toString()); + + if (Long.MIN_VALUE != offeredLease) { + ((Attributable) msg).addAttribute(OFFERED_LEASE_ATTR, Long.toString(getOfferedLease())); + } + + if (null != credential) { + StructuredDocumentUtils.copyElements(msg, msg, credential, SERVER_CRED_TAG); + } + + Element e; + + if (null != serverAdv) { + e = StructuredDocumentUtils.copyElements(msg, msg, (StructuredDocument) serverAdv.getDocument(mediaType) + , + SERVER_ADV_TAG); + + if (null != getServerAdvGen()) { + ((Attributable) e).addAttribute(ADV_GEN_ATTR, getServerAdvGen().toString()); + } + + if (Long.MIN_VALUE != getServerAdvExp()) { + ((Attributable) e).addAttribute(ADV_EXP_ATTR, Long.toString(getServerAdvExp())); + } + } + + Iterator eachReferralAdvExp = referralAdvExps.iterator(); + + for (RdvAdvertisement aReferralAdv : referralAdvs) { + e = StructuredDocumentUtils.copyElements(msg, msg, (StructuredDocument) aReferralAdv.getDocument(mediaType) + , + REFERRAL_ADV_TAG); + + long expiration = eachReferralAdvExp.next(); + + if (Long.MIN_VALUE == expiration) { + throw new IllegalStateException("Missing Referral Advertisement Expiration."); + } + + if (expiration <= 0) { + throw new IllegalStateException("Illegal Referral Advertisement Expiration."); + } + + ((Attributable) e).addAttribute(ADV_EXP_ATTR, Long.toString(expiration)); + } + + return msg; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LimitedRangeRdvMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LimitedRangeRdvMsg.java new file mode 100644 index 000000000..57b3d747e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/LimitedRangeRdvMsg.java @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + + +/** + * The LimitedRangeRdv walk header message. + *

            + *

            
            + * <xs:simpleType name="WalkDirection">
            + *   <xs:restriction base="xs:unsignedInt">
            + *     <!-- UP -->
            + *     <xs:enumeration value="1" />
            + *     <!-- DOWN -->
            + *     <xs:enumeration value="2" />
            + *     <!-- BOTH -->
            + *     <xs:enumeration value="3" />
            + *   </xs:restriction>
            + * </xs:simpleType>
            + * 

            + * <xs:complexType name="LimitedRangeRdvMessage"> + * <xs:sequence> + * <xs:element name="TTL" type="xs:unsignedInt" /> + * <xs:element name="Dir" type="jxta:WalkDirection" /> + * <xs:element name="SrcPeerID" type="jxta:JXTAID" /> + * <xs:element name="SrcSvcName" type="xs:string" /> + * <xs:element name="SrcSvcParams" minOccurs="0" type="xs:string" /> + * </xs:sequence> + * </xs:complexType> + *

            + * + * @see net.jxta.impl.rendezvous.limited.LimitedRangeWalk + * @see net.jxta.impl.rendezvous.limited.LimitedRangeWalker + * @see net.jxta.impl.rendezvous.limited.LimitedRangeGreeter + * @since JXTA 2.0 + */ +public class LimitedRangeRdvMsg { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(LimitedRangeRdvMsg.class.getName()); + + private final static String TTL_ELEMENT = "TTL"; + private final static String DIRECTION_ELEMENT = "Dir"; + private final static String SRCPEERID_ELEMENT = "SrcPeerID"; + private final static String SRCSVCNAME_ELEMENT = "SrcSvcName"; + private final static String SRCSVCPARAM_ELEMENT = "SrcSvcParams"; + + private int ttl = 0; + private WalkDirection direction = null; + private PeerID srcPeerID = null; + private String srcSvcName = null; + private String srcSvcParams = null; + + /** + * Enumeration of possible walk directions. + */ + public enum WalkDirection { + UP(1), DOWN(2), BOTH(3); + + /** + * The protocol integer value associated with this direction. + */ + private final int proto_direction; + + private WalkDirection(int direction) { + proto_direction = direction; + } + + /** + * Convert a walk code as used by the standard walker protocol to a + * direction object. + * + * @param code the protocol code + * @return A direction object. + * @throws IllegalArgumentException For illegal protocol codes. + */ + public static WalkDirection toWalkDirection(int code) { + switch (code) { + case 1: + return UP; + + case 2: + return DOWN; + + case 3: + return BOTH; + + default: + throw new IllegalArgumentException("Illegal direction"); + } + } + + /** + * Return the protocol code used by the standard walker protocol for + * this WalkDirection. + * + * @return the walk direction as a numeric value for use in protocol + * messages. + */ + public int toProtocolCode() { + return proto_direction; + } + } + + /** + * Constructor + */ + public LimitedRangeRdvMsg() {} + + /** + * Construct from a StructuredDocument + * + * @param root the element + */ + public LimitedRangeRdvMsg(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); + } + + XMLElement doc = (XMLElement) root; + + if (!doc.getName().equals(getMessageType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + " from doc containing a '" + doc.getName() + + "'. Should be : " + getMessageType()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem); + } + } + } + + // Sanity check time! + if (getTTL() < 1) { + throw new IllegalArgumentException("Illegal TTL value."); + } + + if (null == getDirection()) { + throw new IllegalArgumentException("No Direction specified."); + } + + if (null == getSrcPeerID()) { + throw new IllegalArgumentException("No source peer id specified."); + } + + if (null == getSrcSvcName()) { + throw new IllegalArgumentException("No source service name specified."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public LimitedRangeRdvMsg clone() { + + try { + LimitedRangeRdvMsg clone = (LimitedRangeRdvMsg) super.clone(); + + clone.setSrcPeerID(getSrcPeerID()); + clone.setDirection(getDirection()); + clone.setTTL(getTTL()); + clone.setSrcSvcName(getSrcSvcName()); + clone.setSrcSvcParams(getSrcSvcParams()); + + return clone; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * Get the TTL + * + * @return Time To Live + */ + public int getTTL() { + return ttl; + } + + /** + * set the TTL + * + * @param ttl TTL + */ + public void setTTL(int ttl) { + this.ttl = ttl; + } + + /** + * Get the direction the message will take + * + * @return UP, DOWN or BOTH + */ + public WalkDirection getDirection() { + return direction; + } + + /** + * Set the direction the message will take + * + * @param dir direction + */ + public void setDirection(WalkDirection dir) { + direction = dir; + } + + /** + * Get the Source Service Name (listening for the response) + * + * @return Source Service Name + */ + public String getSrcSvcName() { + return srcSvcName; + } + + /** + * Set the Source Service Name (listening for the response) + * + * @param srcSvcName Source Service Name + */ + public void setSrcSvcName(String srcSvcName) { + this.srcSvcName = srcSvcName; + } + + /** + * Get the Source Service Param (listening for the response) + * + * @return Source Service Param + */ + public String getSrcSvcParams() { + return srcSvcParams; + } + + /** + * Set the Source Service Params (listening for the response) + * + * @param srcSvcParams Source Service Params + */ + public void setSrcSvcParams(String srcSvcParams) { + this.srcSvcParams = srcSvcParams; + } + + /** + * Get the Source PeerID (walk originiator) + * + * @return Source PeerID + */ + public ID getSrcPeerID() { + return srcPeerID; + } + + /** + * Set the Source PeerID (walk originiator) + * + * @param srcPeerID Source PeerID + */ + public void setSrcPeerID(ID srcPeerID) { + this.srcPeerID = (PeerID) srcPeerID; + } + + /** + * Our DOCTYPE + * + * @return the type of this message. + */ + public static String getMessageType() { + return "jxta:LimitedRangeRdvMessage"; + } + + /** + * Process an individual element from the document during parse. Normally, + * implementations will allow the base advertisments a chance to handle the + * element before attempting ot handle the element themselves. ie. + *

            + *

            
            +     *  protected boolean handleElement( Element elem ) {
            +     * 

            + * if ( super.handleElement() ) { + * // it's been handled. + * return true; + * } + *

            + * ... handle elements here ... + *

            + * // we don't know how to handle the element + * return false; + * } + *

            + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + */ + protected boolean handleElement(XMLElement elem) { + + String value = elem.getTextValue(); + + if (null != value) { + value = value.trim(); + + if (0 == value.length()) { + value = null; + } + } + + if (null == value) { + return false; + } + + if (elem.getName().equals(TTL_ELEMENT)) { + setTTL(Integer.parseInt(value)); + return true; + } + + if (elem.getName().equals(DIRECTION_ELEMENT)) { + int direction = Integer.parseInt(value); + + setDirection(LimitedRangeRdvMsg.WalkDirection.toWalkDirection(direction)); + return true; + } + + if (elem.getName().equals(SRCPEERID_ELEMENT)) { + try { + URI srcURI = new URI(value); + ID srcID = IDFactory.fromURI(srcURI); + + setSrcPeerID(srcID); + } catch (URISyntaxException badID) { + IllegalArgumentException iae = new IllegalArgumentException("Bad ID in message"); + + iae.initCause(badID); + throw iae; + } + return true; + } + + if (elem.getName().equals(SRCSVCNAME_ELEMENT)) { + setSrcSvcName(value); + return true; + } + + if (elem.getName().equals(SRCSVCPARAM_ELEMENT)) { + setSrcSvcParams(value); + return true; + } + + return false; + } + + /** + * @inheritDoc + */ + public Document getDocument(MimeMediaType mediaType) { + + if (getTTL() < 1) { + throw new IllegalStateException("Illegal TTL value."); + } + + if (null == getDirection()) { + throw new IllegalStateException("No Direction specified."); + } + + if (null == getSrcPeerID()) { + throw new IllegalStateException("No source peer id specified."); + } + + if (null == getSrcSvcName()) { + throw new IllegalStateException("No source service name specified."); + } + + StructuredDocument msg = StructuredDocumentFactory.newStructuredDocument(mediaType, getMessageType()); + + if (msg instanceof XMLDocument) { + ((XMLDocument) msg).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e = msg.createElement(TTL_ELEMENT, Integer.toString(getTTL())); + + msg.appendChild(e); + + e = msg.createElement(DIRECTION_ELEMENT, Integer.toString(getDirection().toProtocolCode())); + msg.appendChild(e); + + e = msg.createElement(SRCPEERID_ELEMENT, getSrcPeerID().toString()); + msg.appendChild(e); + + e = msg.createElement(SRCSVCNAME_ELEMENT, getSrcSvcName()); + msg.appendChild(e); + + if (getSrcSvcParams() != null) { + e = msg.createElement(SRCSVCPARAM_ELEMENT, getSrcSvcParams()); + msg.appendChild(e); + } + + return msg; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ModuleClassAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ModuleClassAdv.java new file mode 100644 index 000000000..0575bd2b2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ModuleClassAdv.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.IDFactory; +import net.jxta.platform.ModuleClassID; +import net.jxta.protocol.ModuleClassAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + + +/** + * Provides XML serialization support for ModuleClassAdvertisement matching the + * schema defined by the JXTA Core Specification. + *

            + *

            + *  <xs:complexType name="MCA">
            + *    <xs:sequence>
            + *      <xs:element name="MCID" type="jxta:JXTAID" />
            + *      <xs:element name="Name" type="xs:string" minOccurs="0" />
            + *      <xs:element name="Desc" type="xs:anyType" minOccurs="0" />
            + *    </xs:sequence>
            + *  </xs:complexType>
            + *  
            + * + * @see net.jxta.document.Advertisement + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + if (null == getModuleClassID()) { + throw new IllegalArgumentException("Module Class ID was not specified."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (elem.getName().equals(nameTag)) { + setName(elem.getTextValue()); + return true; + } + + if (elem.getName().equals(descTag)) { + setDesc(elem); + return true; + } + + if (elem.getName().equals(idTag)) { + try { + URI clID = new URI(elem.getTextValue()); + + setModuleClassID((ModuleClassID) IDFactory.fromURI(clID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad mcid in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Unusable mcid in advertisement"); + } + return true; + } + + return false; + + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + if (null == getModuleClassID()) { + throw new IllegalStateException("Module Class ID was not specified."); + } + + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + Element e; + + e = adv.createElement(idTag, getModuleClassID().toString()); + adv.appendChild(e); + + // name is optional + String name = getName(); + + if (null != name) { + e = adv.createElement(nameTag, name); + adv.appendChild(e); + } + + // desc is optional + StructuredDocument desc = getDesc(); + + if (desc != null) { + StructuredDocumentUtils.copyElements(adv, adv, desc); + } + + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return fields; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ModuleImplAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ModuleImplAdv.java new file mode 100644 index 000000000..6dea104d0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ModuleImplAdv.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleImplAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + + +/** + * Provides XML serialization support for ModuleImplAdvertisement matching the + * schema defined by the JXTA Core Specification. + *

            + *

            + * <xs:complexType name="MIA">
            + *   <xs:sequence>
            + *     <xs:element name="MSID" type="jxta:JXTAID"/>
            + *     <xs:element name="Comp" type="xs:anyType"/>
            + *     <xs:element name="Code" type="xs:anyType"/>
            + *     <xs:element name="PURI" type="xs:anyURI" minOccurs="0"/>
            + *     <xs:element name="Prov" type="xs:string" minOccurs="0"/>
            + *     <xs:element name="Desc" type="xs:anyType" minOccurs="0"/>
            + *     <xs:element name="Parm" type="xs:anyType" minOccurs="0"/>
            + *   </xs:sequence>
            + * </xs:complexType>
            + * 
            + * + * @see net.jxta.document.Advertisement + * @see net.jxta.protocol.ModuleImplAdvertisement + * @see
            for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.IDFactory; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + + +/** + * Provides XML serialization support for ModuleSpecAdvertisement matching the + * schema defined by the JXTA Core Specification. + *

            + *

            + *  <xs:complexType name="MSA">
            + *    <xs:sequence>
            + *      <xs:element name="MSID" type="jxta:JXTAID" />
            + *      <xs:element name="Name" type="xs:string" minOccurs="0" />
            + *      <xs:element name="Desc" type="xs:anyType" minOccurs="0" />
            + *      <xs:element name="Crtr" type="xs:string" minOccurs="0" />
            + *      <xs:element name="SURI" type="xs:anyURI" minOccurs="0" />
            + *      <xs:element name="Vers" type="xs:string" />
            + *      <xs:element name="Parm" type="xs:anyType" minOccurs="0" />
            + *      <xs:element ref="jxta:PipeAdvertisement" minOccurs="0" />
            + *      <xs:element name="Proxy" type="xs:anyURI" minOccurs="0" />
            + *      <xs:element name="Auth" type="jxta:JXTAID" minOccurs="0" />
            + *    </xs:sequence>
            + *  </xs:complexType>
            + * 
            + * + * @see net.jxta.document.Advertisement + * @see net.jxta.protocol.ModuleSpecAdvertisement + * @see
            for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.StringReader; +import java.net.URI; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.security.cert.CertificateFactory; +import java.util.Enumeration; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import javax.crypto.EncryptedPrivateKeyInfo; + +import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.URISyntaxException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.membership.pse.PSEUtils; +import net.jxta.peergroup.PeerGroupID; + + +/** + * Contains parameters for configuration of the PSE Membership Service. + * + *

            The configuration advertisement can include an optional seed certificate + * chain and encrypted private key. If this seed information is present the PSE + * Membership Service will require an initial authentication to unlock the + * encrypted private key before creating the PSE keystore. The newly created + * PSE keystore will be "seeded" with the certificate chain and the private key. + * + *

            This mechanism allows for out-of-band distribution of JXTA identity + * information and avoids the need for remote authentication. + * + *

            Note: This implementation contemplates multiple root certs in its + * schema, but the API has not yet been extended to include this functionality. + */ +public final class PSEConfigAdv extends ExtendableAdvertisement implements Cloneable { + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(PSEConfigAdv.class.getName()); + + /** + * Our DOCTYPE + */ + private final static String advType = "jxta:PSEConfig"; + + /** + * Instantiator for PSEConfigAdv + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new PSEConfigAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + return new PSEConfigAdv(root); + } + } + + private final static String ROOT_CERT_TAG = "RootCert"; + private final static String CERT_TAG = "Certificate"; + private final static String ENCRYPTED_PRIVATE_KEY_TAG = "EncryptedPrivateKey"; + private final static String KEY_STORE_TYPE_ATTR = "KeyStoreType"; + private final static String KEY_STORE_PROVIDER_ATTR = "KeyStoreProvider"; + private final static String KEY_STORE_LOCATION_TAG = "KeyStoreLocation"; + + private final static String[] INDEX_FIELDS = {}; + + private final List certs = new ArrayList(); + + private EncryptedPrivateKeyInfo encryptedPrivateKey = null; + + private String privAlgorithm = null; + + private String keyStoreType = null; + + private String keyStoreProvider = null; + + private URI keyStoreLocation = null; + + /** + * Returns the identifying type of this Advertisement. + * + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + * + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * {@code Advertisement.getAdvertisementType()} no matter what the real + * type of the advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return advType; + } + + /** + * Use the Instantiator through the factory + */ + private PSEConfigAdv() {} + + /** + * Use the Instantiator through the factory + * + * @param root The XMLElement which is the root element of the PSEConfigAdv. + */ + private PSEConfigAdv(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration eachAttr = doc.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute anAttr = (Attribute) eachAttr.nextElement(); + + if (super.handleAttribute(anAttr)) { + // nothing to do + ; + } else if (KEY_STORE_TYPE_ATTR.equals(anAttr.getName())) { + keyStoreType = anAttr.getValue().trim(); + } else if (KEY_STORE_PROVIDER_ATTR.equals(anAttr.getName())) { + keyStoreProvider = anAttr.getValue().trim(); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + anAttr.getName()); + } + } + } + + certs.clear(); + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + } + + /** + * {@inheritDoc} + */ + @Override + public PSEConfigAdv clone() { + + PSEConfigAdv result; + + try { + result = (PSEConfigAdv) super.clone(); + } catch (CloneNotSupportedException e) { + throw new Error("Object.clone() threw CloneNotSupportedException", e); + } + + result.setKeyStoreLocation(getKeyStoreLocation()); + result.setKeyStoreType(getKeyStoreType()); + result.setKeyStoreProvider(getKeyStoreProvider()); + + result.setEncryptedPrivateKey(getEncryptedPrivateKey(), getEncryptedPrivateKeyAlgo()); + result.setCertificateChain(getCertificateChain()); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + InputStream data = new ByteArrayInputStream(getCert().getBytes()); + + try { + return IDFactory.newCodatID(PeerGroupID.worldPeerGroupID, new byte[16], data); + } catch (IOException failed) { + throw new UndeclaredThrowableException(failed, "Could not generate id"); + } + } + + /** + * Returns the seed certificate. If present, this certificate will be used + * to initialize the PSE keystore and will be stored using the peer id of + * the authenticating peer. + * + * @return The seed certificate or {@code null} if there is no seed + * certificate defined. + */ + public X509Certificate getCertificate() { + if (certs.isEmpty()) { + return null; + } else { + return certs.get(0); + } + } + + /** + * Returns the seed certificate chain. If present, this certificate chain + * will be used to initialize the PSE keystore and will be stored using the + * peer id of the authenticating peer. + * + * @return the seed certificate chain for this peer or {@code null} if + * there is no seed certificate chain defined. + */ + public X509Certificate[] getCertificateChain() { + return certs.toArray(new X509Certificate[certs.size()]); + } + + /** + * Returns the seed certificate encoded as a BASE64 String. + * + * @return the seed certificate encoded as a BASE64 String. + */ + public String getCert() { + X509Certificate rootCert = getCertificate(); + + if (null != rootCert) { + try { + return PSEUtils.base64Encode(getCertificate().getEncoded()); + } catch (Throwable failed) { + throw new IllegalStateException("Failed to process seed cert"); + } + } else { + return null; + } + } + + /** + * Sets the seed certificate for this peer from a BASE64 String. + * + * @param newCert The seed certificate for this peer as a BASE64 String. + */ + public void setCert(String newCert) { + try { + byte[] cert_der = PSEUtils.base64Decode(new StringReader(newCert)); + + CertificateFactory cf = CertificateFactory.getInstance("X509"); + + setCertificate((X509Certificate) cf.generateCertificate(new ByteArrayInputStream(cert_der))); + } catch (Exception failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to process seed cert", failed); + } + + IllegalArgumentException failure = new IllegalArgumentException("Failed to process seed cert"); + + failure.initCause(failed); + + throw failure; + } + } + + /** + * Sets the seed certificate for this peer. If {@code null} then the + * Private Key is also cleared. + * + * @param newCert The seed certificate for this PSE instance or {@code null} + * to clear the seed certificates and private key. + */ + public void setCertificate(X509Certificate newCert) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("setCert : " + newCert); + } + + certs.clear(); + + if (null == newCert) { + encryptedPrivateKey = null; + } else { + certs.add(newCert); + } + } + + /** + * Sets the seed Certificate chain for this peer. If {@code null} then the + * Private Key is also cleared. + * + * @param newCerts The seed certificate chain or {@code null} + * to clear the seed certificates and private key. + */ + public void setCertificateChain(X509Certificate[] newCerts) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("setCert : " + newCerts); + } + + certs.clear(); + + if (null == newCerts) { + encryptedPrivateKey = null; + } else { + certs.addAll(Arrays.asList(newCerts)); + } + } + + /** + * Get the seed private key from this advertisement. The private key is + * retrieved from the advertisement using the provided password. + * + * @param password the password to use in attempting to decrypt the private + * key. + * @return the decrypted private key. + */ + public PrivateKey getPrivateKey(char[] password) { + + return PSEUtils.pkcs5_Decrypt_pbePrivateKey(password, privAlgorithm, encryptedPrivateKey); + } + + /** + * Get the encrypted seed private key from this advertisement. + * + * @return the encrypted seed private key. + */ + public EncryptedPrivateKeyInfo getEncryptedPrivateKey() { + + return encryptedPrivateKey; + } + + /** + * Get the encrypted seed private key algorithm from this advertisement. + * + * @return the decrypted seed private key algorithm. + */ + public String getEncryptedPrivateKeyAlgo() { + + return privAlgorithm; + } + + /** + * Get the encrypted seed private key from this advertisement. + * + * @return the encoded encrypted private key, a BASE64 String of a DER + * encoded PKCS8 EncrpytePrivateKeyInfo. + */ + public String getEncryptedPrivKey() { + try { + if (null == encryptedPrivateKey) { + return null; + } + + return PSEUtils.base64Encode(encryptedPrivateKey.getEncoded()); + } catch (Exception failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to process private key", failed); + } + + IllegalStateException failure = new IllegalStateException("Failed to process private key"); + + failure.initCause(failed); + throw failure; + } + } + + /** + * Return the JCE Keystore type which the PSE Membership Service should use. + * This value should be the name of valid JCE Keystore or {@code null} if + * the default Keystore type should be used. The PSE Membership Service + * will create the keystore via + * {@code KeyStore.getInstance(keystore_type)}. + * + * @return The name of the Keystore type which the PSE Membership Service + * will use or {@code null} if the default keystore type should be used. + */ + public String getKeyStoreType() { + return keyStoreType; + } + + /** + * Set the JCE Keystore type which the PSE Membership Service + * should use. This value should be the name of valid JCE Keystore or + * {@code null} if the default Keystore type should be used. The PSE + * Membership Service will create the keystore via + * {@code KeyStore.getInstance(keystore_type)}. + * + * @param type The JCE Keystore type which the PSE Membership Service + * should use. This value should be the name of valid JCE Keystore or + * {@code null} if the default Keystore type should be used. + */ + public void setKeyStoreType(String type) { + keyStoreType = type; + } + + /** + * Return the JCE provider which the PSE Membership Service + * should use for Keystores. This value should be the name of valid JCE + * provider or {@code null} if the default provider should be used. The PSE + * Membership Service will create the keystore via + * {@code KeyStore.getInstance(keystore_type, provider)}. + * + * @return The JCE provider which the PSE Membership Service + * should use for Keystores. This value should be the name of valid JCE + * provider or {@code null} if the default provider should be used. + */ + public String getKeyStoreProvider() { + return keyStoreProvider; + } + + /** + * Set the JCE provider which the PSE Membership Service + * should use for Keystores. This value should be the name of valid JCE + * provider or {@code null} if the default provider should be used. The PSE + * Membership Service will create the keystore via + * {@code KeyStore.getInstance(keystore_type, provider)}. + * + * @param provider The JCE provider which the PSE Membership Service + * should use for Keystores. This value should be the name of valid JCE + * provider or {@code null} if the default provider should be used. + */ + public void setKeyStoreProvider(String provider) { + keyStoreProvider = provider; + } + + /** + * Return the location of the Keystore or {@code null} if the PSE + * Membership Service should use the default location. The actual default + * location may vary depending upon they Keystore type and provider and not + * all location values may be valid for all Keystore types and providers. + * + * @return The location of the Keystore or {@code null} if the PSE + * Membership Service should use the default location. + */ + public URI getKeyStoreLocation() { + return keyStoreLocation; + } + + /** + * Set the location of the Keystore or {@code null} if the PSE + * Membership Service should use the default location. The actual default + * location may vary depending upon they Keystore type and provider and not + * all location values may be valid for all Keystore types and providers. + * + * @param location The location of the Keystore or {@code null} if the PSE + * Membership Service should use the default location. + */ + public void setKeyStoreLocation(URI location) { + keyStoreLocation = location; + } + + /** + * Set the encrypted private key for this advertisement. The private key + * is provided as a BASE64 String of a DER encoded PKCS8 + * EncrpytePrivateKeyInfo. + * + * @param newPriv a BASE64 String of a DER encoded PKCS8 + * EncrpytePrivateKeyInfo. + * @param algorithm The public key algorithm used by this private key. + * Currently only "RSA" is supported. + */ + public void setEncryptedPrivateKey(String newPriv, String algorithm) { + try { + byte[] key_der = PSEUtils.base64Decode(new StringReader(newPriv)); + + EncryptedPrivateKeyInfo newEncryptedPriv = new EncryptedPrivateKeyInfo(key_der); + + setEncryptedPrivateKey(newEncryptedPriv, algorithm); + } catch (Exception failed) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to process private key", failed); + } + + IllegalArgumentException failure = new IllegalArgumentException("Failed to process private key"); + + failure.initCause(failed); + + throw failure; + } + } + + /** + * Set the encrypted seed private key for this advertisement. + * + * @param newPriv The encrypted seed private key. + * @param algorithm The public key algorithm used by this private key. + * Currently only "RSA" is supported. + */ + public void setEncryptedPrivateKey(EncryptedPrivateKeyInfo newPriv, String algorithm) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("setPrivateKey : " + newPriv); + } + + encryptedPrivateKey = newPriv; + privAlgorithm = algorithm; + } + + /** + * Set the encrypted seed private key for this advertisement. + * + * @param password The password to be used in encrypting the private key + * @param newPriv The private key to be stored in encrypted form. + */ + public void setPrivateKey(PrivateKey newPriv, char[] password) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("setPrivateKey : " + newPriv); + } + + EncryptedPrivateKeyInfo encypted = PSEUtils.pkcs5_Encrypt_pbePrivateKey(password, newPriv, 500); + + setEncryptedPrivateKey(encypted, newPriv.getAlgorithm()); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (ROOT_CERT_TAG.equals(elem.getName())) { + + Enumeration elements = elem.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement eachcertelem = (XMLElement) elements.nextElement(); + + if (CERT_TAG.equals(eachcertelem.getName())) { + // XXX bondolo 20040415 backwards compatibility + eachcertelem.addAttribute("type", net.jxta.impl.protocol.Certificate.getMessageType()); + + net.jxta.impl.protocol.Certificate certChain = new net.jxta.impl.protocol.Certificate(eachcertelem); + + setCertificateChain(certChain.getCertificates()); + + continue; + } + + if (ENCRYPTED_PRIVATE_KEY_TAG.equals(eachcertelem.getName())) { + String value = eachcertelem.getTextValue(); + + if (null == value) { + throw new IllegalArgumentException("Empty Private Key element"); + } + + value = value.trim(); + + Attribute algo = eachcertelem.getAttribute("algorithm"); + + if (null == algo) { + throw new IllegalArgumentException("Private Key element must include algorithm attribute"); + } + + setEncryptedPrivateKey(value, algo.getValue()); + continue; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + eachcertelem.getName()); + } + + } + + return true; + } + + if (KEY_STORE_LOCATION_TAG.equals(elem.getName())) { + try { + keyStoreLocation = new URI(elem.getTextValue()); + } catch (URISyntaxException badURI) { + IllegalArgumentException iae = new IllegalArgumentException("Bad key store location URI"); + + iae.initCause(badURI); + + throw iae; + } + + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (adv instanceof Attributable) { + Attributable attrDoc = (Attributable) adv; + + if (null != keyStoreType) { + attrDoc.addAttribute(KEY_STORE_TYPE_ATTR, keyStoreType); + + if (null != keyStoreProvider) { + attrDoc.addAttribute(KEY_STORE_PROVIDER_ATTR, keyStoreProvider); + } + } + } + + if (null != keyStoreLocation) { + Element keyStoreLocationURI = adv.createElement(KEY_STORE_LOCATION_TAG, keyStoreLocation.toString()); + + adv.appendChild(keyStoreLocationURI); + } + + String encodedRoot = getCert(); + String encodedPrivateKey = getEncryptedPrivKey(); + + if ((null != encodedRoot) && (null != encodedPrivateKey)) { + Element rootcert = adv.createElement(ROOT_CERT_TAG, null); + + adv.appendChild(rootcert); + + // FIXME bondolo 20040501 needs to write certificate chain. + + Element cert = adv.createElement(CERT_TAG, encodedRoot); + + rootcert.appendChild(cert); + + Element privatekey = adv.createElement(ENCRYPTED_PRIVATE_KEY_TAG, encodedPrivateKey); + + rootcert.appendChild(privatekey); + + if (privatekey instanceof Attributable) { + ((Attributable) privatekey).addAttribute("algorithm", privAlgorithm); + } + } + + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEX_FIELDS; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerAdv.java new file mode 100644 index 000000000..39c8a0a69 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerAdv.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.net.URI; +import java.util.Enumeration; +import java.util.Hashtable; + +import java.net.URISyntaxException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.ModuleClassID; +import net.jxta.protocol.PeerAdvertisement; + + +/** + * Implementation of {@link PeerAdvertisement} matching the standard JXTA + * Protocol Specification. + * + * It implements Peer Advertisement using the following schema: + * + *

            
            + * <xs:complexType name="PA">
            + *   <xs:sequence>
            + *     <xs:element name="PID" type="JXTAID"/>
            + *     <xs:element name="GID" type="JXTAID"/>
            + *     <xs:element name="Name" type="xs:string" minOccurs="0"/>
            + *     <xs:element name="Desc" type="xs:anyType" minOccurs="0"/>
            + *     <xs:element name="Svc" type="jxta:serviceParams" minOccurs="0" maxOccurs="unbounded"/>
            + *   <xs:sequence>
            + * </xs:complexType>
            + * 
            + * + * @see net.jxta.protocol.PeerAdvertisement + * @see
            JXTA Protocols Specification : Peer Advertisement + **/ +public class PeerAdv extends PeerAdvertisement { + + /** + * Logger + **/ + private static final Logger LOG = Logger.getLogger(PeerAdv.class.getName()); + + private static final String pidTag = "PID"; + private static final String gidTag = "GID"; + private static final String nameTag = "Name"; + private static final String descTag = "Desc"; + private static final String svcTag = "Svc"; + private static final String mcidTag = "MCID"; + private static final String paramTag = "Parm"; + private static final String[] fields = { nameTag, pidTag }; + + /** + * Creates instances of PeerAdvertisement. + **/ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + **/ + public String getAdvertisementType() { + return PeerAdvertisement.getAdvertisementType(); + } + + /** + * {@inheritDoc} + **/ + public Advertisement newInstance() { + return new PeerAdv(); + } + + /** + * {@inheritDoc} + **/ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new PeerAdv((XMLElement) root); + } + } + + /** + * Private constructor for new instances. Use the instantiator. + */ + private PeerAdv() {} + + /** + * Private constructor for xml serialized instances. Use the instantiator. + * + * @param doc The XML serialization of the advertisement. + */ + private PeerAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + // sanity check time! + if (null == getPeerID()) { + throw new IllegalArgumentException("Peer Advertisement did not contain a peer id."); + } + + if (null == getPeerGroupID()) { + throw new IllegalArgumentException("Peer Advertisement did not contain a peer group id."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + **/ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (elem.getName().equals(pidTag)) { + try { + URI pID = new URI(elem.getTextValue()); + + setPeerID((PeerID) IDFactory.fromURI(pID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a peer id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals(gidTag)) { + try { + URI gID = new URI(elem.getTextValue()); + + setPeerGroupID((PeerGroupID) IDFactory.fromURI(gID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerGroupID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a group id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals(nameTag)) { + setName(elem.getTextValue()); + return true; + } + + if (elem.getName().equals(descTag)) { + setDesc(elem); + return true; + } + + if (elem.getName().equals(svcTag)) { + Enumeration elems = elem.getChildren(); + ModuleClassID classID = null; + Element param = null; + + while (elems.hasMoreElements()) { + XMLElement e = (XMLElement) elems.nextElement(); + + if (e.getName().equals(mcidTag)) { + try { + URI mcid = new URI(e.getTextValue()); + + classID = (ModuleClassID) IDFactory.fromURI(mcid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Unusable ModuleClassID in advertisement: " + e.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a ModuleClassID: " + e.getTextValue()); + } + continue; + } + if (e.getName().equals(paramTag)) { + param = e; + } + } + if (classID != null && param != null) { + // Add this param to the table. putServiceParam() + // clones param into a standalone document automatically. + // (classID gets cloned too). + putServiceParam(classID, param); + } + return true; + } + + // element was not handled + return false; + } + + /** + * {@inheritDoc} + **/ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + PeerID peerID = getPeerID(); + + if ((null == peerID) || ID.nullID.equals(peerID)) { + throw new IllegalStateException("Cannot generate Peer Advertisement with no Peer ID!"); + } + Element e = adv.createElement(pidTag, peerID.toString()); + + adv.appendChild(e); + + PeerGroupID groupID = getPeerGroupID(); + + if ((null == groupID) || ID.nullID.equals(groupID)) { + throw new IllegalStateException("Cannot generate Peer Advertisement with no group ID!"); + } else { + e = adv.createElement(gidTag, groupID.toString()); + adv.appendChild(e); + } + + // name is optional + if (getName() != null) { + e = adv.createElement(nameTag, getName()); + adv.appendChild(e); + } + + // desc is optional + StructuredDocument desc = getDesc(); + + if (desc != null) { + StructuredDocumentUtils.copyElements(adv, adv, desc); + } + + // service params are optional + // FIXME: this is inefficient - we force our base class to make + // a deep clone of the table. + Hashtable serviceParams = getServiceParams(); + Enumeration classIds = serviceParams.keys(); + + while (classIds.hasMoreElements()) { + ModuleClassID classId = (ModuleClassID) classIds.nextElement(); + + Element s = adv.createElement(svcTag); + + adv.appendChild(s); + + e = adv.createElement(mcidTag, classId.toString()); + s.appendChild(e); + + e = (Element) serviceParams.get(classId); + StructuredDocumentUtils.copyElements(adv, s, e, paramTag); + } + return adv; + } + + /** + * {@inheritDoc} + **/ + @Override + public String[] getIndexFields() { + return fields; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerGroupAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerGroupAdv.java new file mode 100644 index 000000000..c700407da --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerGroupAdv.java @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.TextElement; +import net.jxta.document.XMLElement; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.PeerGroupAdvertisement; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.logging.Level; +import java.util.logging.Logger; + + +public class PeerGroupAdv extends PeerGroupAdvertisement { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(PeerGroupAdv.class.getName()); + + private static final String nameTag = "Name"; + private static final String gidTag = "GID"; + private static final String descTag = "Desc"; + private static final String msidTag = "MSID"; + private static final String svcTag = "Svc"; + private static final String mcidTag = "MCID"; + private static final String paramTag = "Parm"; + private static final String[] fields = { nameTag, gidTag, descTag, msidTag}; + + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + + public String getAdvertisementType() { + return PeerGroupAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new PeerGroupAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(net.jxta.document.Element root) { + return new PeerGroupAdv(root); + } + } + + /** + * Use the Instantiator method to construct Peer Group Advs. + */ + private PeerGroupAdv() {} + + /** + * Use the Instantiator method to construct Peer Group Advs. + * + * @param root the element + */ + private PeerGroupAdv(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + if (null == getPeerGroupID()) { + throw new IllegalArgumentException("Peer Group Advertisement did not contain a peer group id."); + } + + if (null == getModuleSpecID()) { + throw new IllegalArgumentException("Peer Group Advertisement did not contain a module spec id."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (elem.getName().equals(nameTag)) { + setName(elem.getTextValue()); + return true; + } + + if (elem.getName().equals(descTag)) { + setDesc(elem); + return true; + } + + if (elem.getName().equals(gidTag)) { + try { + URI grID = new URI(elem.getTextValue()); + + setPeerGroupID((PeerGroupID) IDFactory.fromURI(grID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad peer group ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a group id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals(msidTag)) { + try { + URI specID = new URI(elem.getTextValue()); + + setModuleSpecID((ModuleSpecID) IDFactory.fromURI(specID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad msid in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a module spec id: " + elem.getTextValue()); + } + return true; + } + + if (elem.getName().equals(svcTag)) { + Enumeration elems = elem.getChildren(); + String classID = null; + Element param = null; + + while (elems.hasMoreElements()) { + TextElement e = (TextElement) elems.nextElement(); + + if (e.getName().equals(mcidTag)) { + classID = e.getTextValue(); + continue; + } + if (e.getName().equals(paramTag)) { + param = e; + } + } + if (classID != null && param != null) { + // Add this param to the table. putServiceParam() + // clones param into a standalone document automatically. + // (classID gets cloned too). + try { + putServiceParam(IDFactory.fromURI(new URI(classID)), param); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad mcid in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a module class id: " + elem.getTextValue()); + } + } + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + if (null == getPeerGroupID()) { + throw new IllegalStateException("Peer Group Advertisement did not contain a peer group id."); + } + + if (null == getModuleSpecID()) { + throw new IllegalStateException("Peer Group Advertisement did not contain a module spec id."); + } + + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + Element e; + + e = adv.createElement(gidTag, getPeerGroupID().toString()); + adv.appendChild(e); + + e = adv.createElement(msidTag, getModuleSpecID().toString()); + adv.appendChild(e); + + // name is optional + if (null != getName()) { + e = adv.createElement(nameTag, getName()); + adv.appendChild(e); + } + + // desc is optional + StructuredDocument desc = getDesc(); + + if (desc != null) { + StructuredDocumentUtils.copyElements(adv, adv, desc); + } + + // FIXME: this is inefficient - we force our base class to make + // a deep clone of the table. + Hashtable serviceParams = getServiceParams(); + Enumeration classIds = serviceParams.keys(); + + while (classIds.hasMoreElements()) { + ModuleClassID classId = (ModuleClassID) classIds.nextElement(); + + Element s = adv.createElement(svcTag); + + adv.appendChild(s); + + e = adv.createElement(mcidTag, classId.toString()); + s.appendChild(e); + + e = (Element) serviceParams.get(classId); + StructuredDocumentUtils.copyElements(adv, s, e, paramTag); + + } + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return fields; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerGroupConfigAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerGroupConfigAdv.java new file mode 100644 index 000000000..c46845954 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerGroupConfigAdv.java @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Defines Peer Group Runtime Configuration parameters. + *

            + * This typically includes the peer group ID to use, the peer group name (if any) to use, and optional descriptive + * meta-data. + *

            + *

            
            + *   NetPeerGroupID=uuid-59313231343132314A484431544E504702
            + *   PeerGroupName=Network Infrastructure PeerGroup
            + *   PeerGroupDesc=Infrastructure Group Description
            + * 
            + */ +public final class PeerGroupConfigAdv extends ExtendableAdvertisement implements Cloneable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(PeerGroupConfigAdv.class.getName()); + + /** + * The advertisement index fields. (currently none). + */ + private final static String[] INDEX_FIELDS = {}; + + /** + * The DOCTYPE + */ + private final static String advType = "jxta:PeerGroupConfigAdv"; + + private final static String PEERGROUP_ID_TAG = "PeerGroupID"; + private final static String PEERGROUP_NAME_TAG = "PeerGroupName"; + private final static String PEERGROUP_DESC_TAG = "PeerGroupDesc"; + + /** + * Instantiator for PeerGroupConfigAdv + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new PeerGroupConfigAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new PeerGroupConfigAdv((XMLElement) root); + } + } + + /** + * ID for the peer group. + */ + private ID gid = null; + + /** + * Informal, non-canonical name of this peer group + */ + private String name = null; + + /** + * Descriptive meta-data about this peer group. + */ + private Element description = null; + + /** + * Returns the identifying type of this Advertisement. + *

            + * Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + *

            + * This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertisement.getAdvertisementType() no matter what the real type of the + * advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return advType; + } + + /** + * Use the Instantiator through the factory + */ + private PeerGroupConfigAdv() {} + + /** + * Use the Instantiator method to construct Peer Group Config Advs. + * + * @param doc the element + */ + private PeerGroupConfigAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Validate group id + if (null == getPeerGroupID()) { + throw new IllegalArgumentException("Peer Group Config Advertisement does not contain a peer group id."); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (PEERGROUP_ID_TAG.equals(elem.getName())) { + try { + URI grID = new URI(elem.getTextValue()); + + setPeerGroupID(IDFactory.fromURI(grID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Invalid peer group ID in advertisement: " + elem.getTextValue()); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Invalid group ID: " + elem.getTextValue()); + } + return true; + } + + if (PEERGROUP_NAME_TAG.equals(elem.getName())) { + setName(elem.getTextValue()); + return true; + } + + if (PEERGROUP_DESC_TAG.equals(elem.getName())) { + setDesc(elem); + return true; + } + + return false; + } + + /** + * Make a safe clone of this PeerGroupConfigAdv. + * + * @return Object A copy of this PeerGroupConfigAdv + */ + @Override + public PeerGroupConfigAdv clone() { + try { + PeerGroupConfigAdv clone = (PeerGroupConfigAdv) super.clone(); + + clone.setPeerGroupID(getPeerGroupID()); + clone.setName(getName()); + clone.setDesc(getDesc()); + + return clone; + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + return ID.nullID; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + if (null == getPeerGroupID()) { + throw new IllegalStateException("Peer Group Config Advertisement does not contain a peer group id."); + } + + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + Element e = adv.createElement(PEERGROUP_ID_TAG, getPeerGroupID().toString()); + + adv.appendChild(e); + + // name is optional + if (null != getName()) { + e = adv.createElement(PEERGROUP_NAME_TAG, getName()); + adv.appendChild(e); + } + + // desc is optional + StructuredDocument desc = getDesc(); + + if (desc != null) { + StructuredDocumentUtils.copyElements(adv, adv, desc); + } + + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEX_FIELDS; + } + + /** + * Returns the id of the peer group. + * + * @return ID the group id + */ + + public ID getPeerGroupID() { + return gid; + } + + /** + * Sets the id of the peer group. + * + * @param gid The id of this group. + */ + + public void setPeerGroupID(ID gid) { + this.gid = gid; + } + + /** + * Gets the name to use for the peer group. + * + * @return The name value + */ + public String getName() { + return name; + } + + /** + * Sets the name to use for the peer group. + * + * @param name The new name value + */ + public void setName(String name) { + this.name = name; + } + + /** + * returns the description + * + * @return String the description + */ + public String getDescription() { + if (description != null) { + return (String) description.getValue(); + } else { + return null; + } + } + + /** + * sets the description + * + * @param description the description + */ + public void setDescription(String description) { + + if (null != description) { + XMLDocument newdoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8 + , + PEERGROUP_DESC_TAG, description); + + setDesc(newdoc); + } else { + this.description = null; + } + } + + /** + * returns the description + * + * @return the description + */ + public XMLDocument getDesc() { + XMLDocument newDoc = null; + + if (description != null) { + newDoc = (XMLDocument) StructuredDocumentUtils.copyAsDocument(description); + } + return newDoc; + } + + /** + * Sets the description + * + * @param desc the description + */ + public void setDesc(XMLElement desc) { + + if (desc != null) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerInfoQueryMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerInfoQueryMsg.java new file mode 100644 index 000000000..1d2929177 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerInfoQueryMsg.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.protocol.PeerInfoQueryMessage; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + + +/** + * This class implements {@link net.jxta.protocol.PeerInfoQueryMessage}. + *

            + *

            This message is part of the Peer PeerInfoService protocol + *

            + *

            + * <xs:element name="PeerInfoQueryMessage" type="jxta:PeerInfoQueryMessage"/>
            + * 

            + * <xs:complexType name="PeerInfoQueryMessage"> + * <xs:element name="sourcePid" type="xs:anyURI"/> + * <xs:element name="targetPid" type="xs:anyURI"/> + * <!-- if no present then the response is the general peerinfo --> + * <xs:element name="request" type="xs:anyType" minOccurs="0"/> + * </xs:complexType> + *

            + * + * @since JXTA 1.0 + */ +public class PeerInfoQueryMsg extends PeerInfoQueryMessage { + + public PeerInfoQueryMsg() { + super(); + } + + public PeerInfoQueryMsg(Element root) { + initialize(root); + } + + public void initialize(Element root) { + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + setSourcePid(null); + setTargetPid(null); + + TextElement doc = (TextElement) root; + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement element = (TextElement) elements.nextElement(); + String elementName = element.getName(); + + if (elementName.equals("sourcePid")) { + try { + URI peerid = new URI(element.getTextValue()); + ID id = IDFactory.fromURI(peerid); + + setSourcePid((PeerID) id); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad peerid ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Unusable ID in advertisement"); + } + continue; + } + + if (elementName.equals("targetPid")) { + try { + URI peerid = new URI(element.getTextValue()); + ID id = IDFactory.fromURI(peerid); + + setTargetPid((PeerID) id); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad peerid ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Unusable ID in advertisement"); + } + } else if (elementName.equals("request")) { + Enumeration elems = element.getChildren(); + + if (elems.hasMoreElements()) { + setRequest(StructuredDocumentUtils.copyAsDocument((Element) elems.nextElement())); + } + } + } + } + + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredTextDocument doc = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(encodeAs, getMessageType()); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e = doc.createElement("sourcePid", getSourcePid().toString()); + + doc.appendChild(e); + + e = doc.createElement("targetPid", getTargetPid().toString()); + doc.appendChild(e); + + Element request = getRequest(); + + if (null != request) { + e = doc.createElement("request"); + doc.appendChild(e); + + StructuredDocumentUtils.copyElements(doc, e, request); + } + + return doc; + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerInfoResponseMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerInfoResponseMsg.java new file mode 100644 index 000000000..5a54cb380 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PeerInfoResponseMsg.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.protocol.PeerInfoResponseMessage; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + + +/** + * This class implements {@link net.jxta.protocol.PeerInfoResponseMessage}. + *

            + *

            This message is part of the Peer PeerInfoService protocol + *

            + *

            + * <xs:element name="PeerInfoResponse" type="jxta:PeerInfoResponse"/>
            + * 

            + * <xs:complexType name="PeerInfoResponse"> + * <xs:element name="sourcePid" type="xs:anyURI"/> + * <xs:element name="targetPid" type="xs:anyURI"/> + * <xs:element name="uptime" type="xs:unsignedLong" minOccurs="0"/> + * <xs:element name="timestamp" type="xs:unsignedLong" minOccurs="0"/> + * <xs:element name="response" type="xs:anyType" minOccurs="0"/> + * </xs:complexType> + *

            + * + * @since JXTA 1.0 + */ +public class PeerInfoResponseMsg extends PeerInfoResponseMessage { + + public PeerInfoResponseMsg() {} + + /** + * @param spid source PeerID + * @param tpid target PeerID + * @param uptime uotime in millis + * @param timestamp TimeStamp + * @deprecated Please use the individual setters + */ + @Deprecated + public PeerInfoResponseMsg(PeerID spid, PeerID tpid, long uptime, long timestamp) { + setSourcePid(spid); + setTargetPid(tpid); + setUptime(uptime); + setTimestamp(timestamp); + } + + public PeerInfoResponseMsg(Element root) { + initialize(root); + } + + private void initialize(Element root) { + + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + setSourcePid(null); + setTargetPid(null); + setUptime(0); + setTimestamp(0); + + TextElement doc = (TextElement) root; + + Enumeration elements; + + elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement element = (TextElement) elements.nextElement(); + String elementName = element.getName(); + + if (elementName.equals("sourcePid")) { + try { + URI peerid = new URI(element.getTextValue()); + ID id = IDFactory.fromURI(peerid); + + if (!(id instanceof PeerID)) { + throw new IllegalArgumentException("Bad ID in advertisement, not a PeerID"); + } + setSourcePid((PeerID) id); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad peerid ID in advertisement"); + } + continue; + } + + if (elementName.equals("targetPid")) { + try { + URI peerid = new URI(element.getTextValue()); + PeerID id = (PeerID) IDFactory.fromURI(peerid); + + setTargetPid(id); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad peerid ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Bad ID in advertisement, not a PeerID"); + } + } + + if (elementName.equals("uptime")) { + setUptime(Long.parseLong(element.getTextValue())); + continue; + } + + if (elementName.equals("timestamp")) { + setTimestamp(Long.parseLong(element.getTextValue())); + continue; + } + + if (elementName.equals("response")) { + Enumeration elems = element.getChildren(); + + if (elems.hasMoreElements()) { + setResponse(StructuredDocumentUtils.copyAsDocument((Element) elems.nextElement())); + } + } + + } + } + + @Override + public Document getDocument(MimeMediaType encodeAs) { + + StructuredTextDocument doc = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(encodeAs, getMessageType()); + TextElement e; + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + e = doc.createElement("sourcePid", getSourcePid().toString()); + doc.appendChild(e); + + e = doc.createElement("targetPid", getTargetPid().toString()); + doc.appendChild(e); + + Element response = getResponse(); + + if (null != response) { + e = doc.createElement("response"); + doc.appendChild(e); + + StructuredDocumentUtils.copyElements(doc, e, response); + } + + e = doc.createElement("uptime", String.valueOf(getUptime())); + doc.appendChild(e); + + e = doc.createElement("timestamp", String.valueOf(getTimestamp())); + doc.appendChild(e); + + return doc; + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PipeAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PipeAdv.java new file mode 100644 index 000000000..ca0916c9c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PipeAdv.java @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.net.URI; +import java.util.Enumeration; +import java.net.URISyntaxException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PipeAdvertisement; + + +/** + * This class implements the Pipe Advertisement according to the schema used by + * the standard Pipe Binding Protocol. (PBP) + * + *

            + * <xs:complexType name="PipeAdvertisement">
            + *   <xs:sequence>
            + *     <xs:element name="Id" type="jxta:JXTAID"/>
            + *     <xs:element name="Type" type="xs:string"/>
            + *     <xs:element name="Name" type="xs:string" minOccurs="0"/>
            + *     <xs:element name="Desc" type="xs:anyType" minOccurs="0"/>
            + *   </xs:sequence>
            + * </xs:complexType>
            + * 
            + * + * @see net.jxta.protocol.PipeAdvertisement + * @see net.jxta.pipe.PipeService + * @see JXTA Protocols Specification : Pipe Binding Protocol + */ +public class PipeAdv extends PipeAdvertisement { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(PipeAdv.class.getName()); + + /** + * Fields which will be returned by {@link #getIndexFields()} + **/ + private static final String[] INDEX_FIELDS = { PipeAdvertisement.NameTag, PipeAdvertisement.IdTag}; + + /** + * AvertisementFactory instantiator for our type. + */ + public final static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return PipeAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new PipeAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new PipeAdv((XMLElement) root); + } + } + + /** + * Private constructor for new instances. Use the instantiator. + */ + private PipeAdv() {} + + /** + * Private constructor for xml serialized instances. Use the instantiator. + * + * @param doc The XML serialization of the advertisement. + */ + private PipeAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem); + } + } + } + + // Sanity Check!!! + if ((null == getPipeID()) || getPipeID().equals(ID.nullID)) { + throw new IllegalArgumentException("Bad pipe ID in advertisement"); + } + + if ((null == getType()) || (0 == getType().length())) { + throw new IllegalArgumentException("Bad pipe type in advertisement"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (PipeAdvertisement.descTag.equals(elem.getName())) { + setDesc(elem); + return true; + } + + String value = elem.getTextValue(); + + if ((null == value) || (0 == value.trim().length())) { + return false; + } + + value = value.trim(); + + if (PipeAdvertisement.IdTag.equals(elem.getName())) { + try { + URI pipeID = new URI(value); + + setPipeID(IDFactory.fromURI(pipeID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad pipe ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("ID is not a pipe ID"); + } + return true; + } + + if (PipeAdvertisement.NameTag.equals(elem.getName())) { + setName(value); + return true; + } + + if (PipeAdvertisement.TypeTag.equals(elem.getName())) { + setType(value); + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + ID itsID = getPipeID(); + + if ((null == itsID) || itsID.equals(ID.nullID)) { + throw new IllegalStateException("Pipe has no assigned ID"); + } + + Element e = adv.createElement(PipeAdvertisement.IdTag, itsID.toString()); + + adv.appendChild(e); + + if ((null == getType()) || (0 == getType().length())) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Pipe type not set. Defaulting to " + PipeService.UnicastType + "." + + "\n This default is deprecated. Please set the pipe type in your code."); + } + + setType(PipeService.UnicastType); + // throw new IllegalArgumentException("Pipe type missing in advertisement"); + } + + e = adv.createElement(PipeAdvertisement.TypeTag, getType()); + adv.appendChild(e); + + // name is optional + if (getName() != null) { + e = adv.createElement(PipeAdvertisement.NameTag, getName()); + adv.appendChild(e); + } + + // desc is optional + StructuredDocument desc = getDesc(); + + if (desc != null) { + StructuredDocumentUtils.copyElements(adv, adv, desc); + } + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEX_FIELDS; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PipeResolverMsg.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PipeResolverMsg.java new file mode 100644 index 000000000..10e82bfc5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PipeResolverMsg.java @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.pipe.PipeID; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeResolverMessage; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Set; + + +/** + * This class implements {@link net.jxta.protocol.PipeResolverMessage} by + * providing {@link #initialize(Element)} and {@link #getDocument(MimeMediaType)} + * implementations. + *

            + *

            It implements the PipeResolver message for the standard Pipe + * Binding Protocol (PBP) with the following schema: + *

            + *

            
            + * <xs:element name="jxta:PipeResolver" type="jxta:PipeResolver"/>
            + * 

            + * <xs:simpleType name="PipeResolverMsgType"> + * <xs:restriction base="xs:string"> + * <!-- QUERY --> + * <xs:enumeration value="Query"/> + * <!-- ANSWER --> + * <xs:enumeration value="Answer"/> + * </xs:restriction> + * </xs:simpleType> + *

            + * <xs:complexType name="PipeResolver"> + * <xs:sequence> + * <xs:element name="MsgType" type="jxta:PipeResolverMsgType"/> + * <xs:element name="PipeId" type="jxta:JXTAID"/> + * <xs:element name="Type" type="xs:string"/> + *

            + * <!-- used in the query --> + * <xs:element name="Cached" type="xs:boolean" default="true" minOccurs="0"/> + * <xs:element name="Peer" type="jxta:JXTAID" minOccurs="0" maxOccurs="unbounded"/> + *

            + * <!-- used in the answer --> + * <xs:element name="Found" minOccurs="0" type="xs:boolean"/> + * <!-- This should refer to a peer adv, but is instead a whole doc --> + * <xs:element name="PeerAdv" minOccurs="0" type="xs:string" /> + * </xs:sequence> + * </xs:complexType> + *

            + * + * @see net.jxta.pipe.PipeService + * @see net.jxta.impl.pipe.PipeServiceImpl + * @see JXTA Protocols Specification : Pipe Binding Protocol + */ +public class PipeResolverMsg extends PipeResolverMessage { + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(PipeResolverMsg.class.getName()); + + private final static String MsgTypeTag = "MsgType"; + private final static String PipeIdTag = "PipeId"; + private final static String PipeTypeTag = "Type"; + private final static String PeerIdTag = "Peer"; + private final static String PeerAdvTag = "PeerAdv"; + private final static String FoundTag = "Found"; + + private final static String QueryMsgType = "Query"; + private final static String AnswerMsgType = "Answer"; + + public PipeResolverMsg() {} + + public PipeResolverMsg(Element root) { + initialize(root); + } + + private void initialize(Element root) { + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports TextElement"); + } + + TextElement doc = (TextElement) root; + + String docName = doc.getName(); + + if (!docName.equals(getMessageType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + docName); + } + + Enumeration each = doc.getChildren(); + + while (each.hasMoreElements()) { + TextElement elem = (TextElement) each.nextElement(); + + if (elem.getName().equals(MsgTypeTag)) { + String msgtype = elem.getTextValue(); + + if (msgtype.equals(QueryMsgType)) { + setMsgType(PipeResolverMessage.MessageType.QUERY); + } else if (msgtype.equals(AnswerMsgType)) { + setMsgType(PipeResolverMessage.MessageType.ANSWER); + } else { + throw new IllegalArgumentException("Unexpected Message Type in parsing."); + } + continue; + } + + if (elem.getName().equals(PipeIdTag)) { + try { + URI pipeID = new URI(elem.getTextValue()); + + setPipeID(IDFactory.fromURI(pipeID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad pipe ID in message"); + } + continue; + } + + if (elem.getName().equals(PipeTypeTag)) { + setPipeType(elem.getTextValue()); + continue; + } + + if (elem.getName().equals(PeerIdTag)) { + try { + URI peerID = new URI(elem.getTextValue()); + + addPeerID(IDFactory.fromURI(peerID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad peer ID in message"); + } + continue; + } + + if (elem.getName().equals(FoundTag)) { + setFound(Boolean.valueOf(elem.getTextValue())); + continue; + } + + // let's check whether the responder sent us a adv + if (elem.getName().equals(PeerAdvTag)) { + String peerAdv = elem.getTextValue(); + + try { + setInputPeerAdv( + (PeerAdvertisement) AdvertisementFactory.newAdvertisement(MimeMediaType.XMLUTF8 + , + new StringReader(peerAdv))); + } catch (IOException caught) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Malformed peer adv in message", caught); + } + throw new IllegalArgumentException("Malformed peer adv in message : " + caught.getMessage()); + } + } + + } + + // Begin validation + PipeResolverMessage.MessageType msgType = getMsgType(); + + if (null == msgType) { + throw new IllegalArgumentException("Message type was never set!"); + } + + ID pipeID = getPipeID(); + + if ((null == pipeID) || ID.nullID.equals(pipeID) || !(pipeID instanceof PipeID)) { + throw new IllegalArgumentException("Input Pipe ID not set or invalid"); + } + + if (null == getPipeType()) { + throw new IllegalArgumentException("Pipe type was never set!"); + } + + // Response extra checks + if (PipeResolverMessage.MessageType.ANSWER.equals(msgType)) { + if (getPeerIDs().isEmpty()) { + throw new IllegalArgumentException("An answer without responses is invalid"); + } + } + } + + /** + * Creates a document out of the message. + * + * @param encodeAs The document representation format requested. + * @return the message as a document. + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredTextDocument doc = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(encodeAs, getMessageType()); + + if (doc instanceof Attributable) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + PipeResolverMessage.MessageType msgType = getMsgType(); + + if (null == msgType) { + throw new IllegalStateException("Message type was never set!"); + } + + ID pipeID = getPipeID(); + + if ((null == pipeID) || ID.nullID.equals(pipeID) || !(pipeID instanceof PipeID)) { + throw new IllegalStateException("Pipe ID not set or invalid."); + } + + String pipeType = getPipeType(); + + if ((null == pipeType) || (0 == pipeType.trim().length())) { + throw new IllegalStateException("Pipe type was never set or is invalid."); + } + + Element element; + + if (PipeResolverMessage.MessageType.QUERY.equals(msgType)) { + element = doc.createElement(MsgTypeTag, QueryMsgType); + } else if (PipeResolverMessage.MessageType.ANSWER.equals(msgType)) { + element = doc.createElement(MsgTypeTag, AnswerMsgType); + } else { + throw new IllegalStateException("Unknown message type :" + msgType.toString()); + } + doc.appendChild(element); + + element = doc.createElement(PipeIdTag, pipeID.toString()); + doc.appendChild(element); + + if ((pipeType != null) && (0 != pipeType.length())) { + element = doc.createElement(PipeTypeTag, pipeType); + doc.appendChild(element); + } + + // Write the peer ids. + Set peers = getPeerIDs(); + + if (PipeResolverMessage.MessageType.ANSWER.equals(msgType) && peers.isEmpty()) { + throw new IllegalStateException("An ANSWER message must contain at least one peer as part of the response."); + } + + for (Object peer : peers) { + ID aPeer = (ID) peer; + + element = doc.createElement(PeerIdTag, aPeer.toString()); + doc.appendChild(element); + } + + if (PipeResolverMessage.MessageType.QUERY.equals(msgType)) {// nothing for now... + } else if (PipeResolverMessage.MessageType.ANSWER.equals(msgType)) { + element = doc.createElement(FoundTag, (isFound() ? Boolean.TRUE : Boolean.FALSE).toString()); + doc.appendChild(element); + + PeerAdvertisement peerAdv = getInputPeerAdv(); + + if (peerAdv != null) { + if (!peers.contains(peerAdv.getPeerID())) { + throw new IllegalStateException( + "Provided Peer Advertisement does not refer to one of the peers in the response list."); + } + + StructuredTextDocument asDoc = (StructuredTextDocument) peerAdv.getDocument(MimeMediaType.XMLUTF8); + + element = doc.createElement(PeerAdvTag, asDoc.toString()); + doc.appendChild(element); + } + } else { + throw new IllegalStateException("Unknown message type :" + msgType.toString()); + } + return doc; + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PlatformConfig.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PlatformConfig.java new file mode 100644 index 000000000..181d0fb64 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/PlatformConfig.java @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.protocol.ConfigParams; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Configuration container for the World Peer Group. For historical reasons the + * same configuration container and instance is also used for the Net Peer Group. + */ +public final class PlatformConfig extends GroupConfig implements Cloneable { + + private static final String advType = "jxta:PlatformConfig"; + + /** + * Instantiator for PlatformConfig + */ + public final static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new PlatformConfig(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(advType + " only supports XLMElement"); + } + + return new PlatformConfig((XMLElement) root); + } + } + + private static final Logger LOG = Logger.getLogger(PlatformConfig.class.getName()); + + private static final String PID_TAG = "PID"; + private static final String NAME_TAG = "Name"; + private static final String DESC_TAG = "Desc"; + + /** + * The id of this peer. + */ + private PeerID pid = null; + + /** + * The name of this peer. Not guaranteed to be unique in any way. May be + * empty or null. + */ + private String name = null; + + /** + * Descriptive meta-data about this peer. + */ + private Element description = null; + + /** + * Use the Instantiator through the factory + */ + PlatformConfig() {} + + /** + * Use the Instantiator through the factory + * + * @param doc the element + */ + PlatformConfig(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + } + + /** + * Make a safe clone of this PlatformConfig. + * + * @return Object an object of class PlatformConfig that is a deep-enough + * copy of this one. + */ + @Override + public PlatformConfig clone() { + PlatformConfig result = (PlatformConfig) super.clone(); + + result.setPeerID(getPeerID()); + result.setName(getName()); + result.setDesc(getDesc()); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + if(this == other) { + return true; + } + + if(other instanceof PlatformConfig) { + PlatformConfig likeMe = (PlatformConfig) other; + + boolean se = super.equals(likeMe); + + boolean ne = ((null == name) && (null == likeMe.name)) || ((null != name) && name.equals(likeMe.name)); + boolean ie = ((null == pid) && (null == likeMe.pid)) || ((null != pid) && pid.equals(likeMe.pid)); + boolean de = ((null == description) && (null == likeMe.description)) || ((null != description) && description.equals(likeMe.description)); + + return se && ne && ie && de; + } + + return false; + } + + /** + * returns the advertisement type + * + * @return string type + */ + public static String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * returns the name of the peer. + * + * @return String name of the peer. + */ + public String getName() { + return name; + } + + /** + * sets the name of the peer. + * + * @param name name of the peer. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the id of the peer. + * + * @return PeerID the peer id + */ + public PeerID getPeerID() { + return pid; + } + + /** + * Sets the peer ID to use for this peer. + * + * @param pid The peer ID to use for this peer. + */ + public void setPeerID(PeerID pid) { + this.pid = pid; + } + + /** + * Returns a unique ID for that peer X group intersection. This is for + * indexing purposes only. + */ + @Override + public ID getID() { + return pid; + } + + /** + * returns the description + * + * @return String the description + */ + public String getDescription() { + return (null == description) ? null : (String) description.getValue(); + } + + /** + * Sets the description + * + * @param description the description + */ + public void setDescription(String description) { + StructuredDocument newdoc = null; + + if (null != description) { + newdoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, DESC_TAG, description); + } + setDesc(newdoc); + } + + /** + * Returns the description + * + * @return the description + */ + public StructuredDocument getDesc() { + StructuredDocument newDoc = null; + + if (null != description) { + newDoc = StructuredDocumentUtils.copyAsDocument(description); + } + return newDoc; + } + + /** + * Sets the description + * + * @param desc the description + */ + public void setDesc(Element desc) { + if (null != desc) { + this.description = StructuredDocumentUtils.copyAsDocument(desc); + } else { + this.description = null; + } + } + + /** + * returns the debugLevel + * + * @deprecated The debug level is no longer set via this api. See + * {@link net.jxta.logging.Logging}. + * + * @return String the debugLevel + */ + @Deprecated + public String getDebugLevel() { + return "user default"; + } + + /** + * Sets the debugLevel + * + * @deprecated The debug level is no longer set via this api. See + * {@link net.jxta.logging.Logging}. + * + * @param debugLevel the debugLevel + */ + @Deprecated + public void setDebugLevel(String debugLevel) {} + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + String elName = elem.getName(); + + if (DESC_TAG.equals(elName)) { + setDesc(elem); + return true; + } + + String value = elem.getTextValue(); + + if (null == value) { + return false; + } + value = value.trim(); + + if (0 == value.length()) { + return false; + } + + if (PID_TAG.equals(elName)) { + try { + URI asURI = new URI(value); + PeerID pID = (PeerID) IDFactory.fromURI(asURI); + + setPeerID(pID); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Invalid PeerID in advertisement: " + value); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Invalid PeerID: " + value); + } + return true; + } + + if (NAME_TAG.equals(elName)) { + setName(value); + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean addDocumentElements(StructuredDocument adv) { + + Element e; + // peer ID is optional. (at least for the PlatformConfig it is) + PeerID peerID = getPeerID(); + + if ((null != peerID) && !ID.nullID.equals(peerID)) { + e = adv.createElement(PID_TAG, peerID.toString()); + adv.appendChild(e); + } + + // name is optional + if (getName() != null) { + e = adv.createElement(NAME_TAG, getName()); + adv.appendChild(e); + } + + // desc is optional + StructuredDocument desc = getDesc(); + + if (desc != null) { + StructuredDocumentUtils.copyElements(adv, adv, desc); + } + + super.addDocumentElements(adv); + + return true; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RdvAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RdvAdv.java new file mode 100644 index 000000000..05d12b56d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RdvAdv.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.net.URI; +import java.util.Enumeration; + +import java.net.URISyntaxException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + + +/** + * This class implements the RdvAdvertisement. + * + *

            + *   <xs:complexType name="RdvAdvertisement">
            + *     <xs:sequence>
            + *       <xs:element name="RdvGroupId" type="jxta:JXTAID"/>
            + *       <xs:element name="RdvPeerId" type="jxta:JXTAID"/>
            + *       <xs:element name="RdvServiceName" type="xs:string"/>
            + *       <xs:element name="Name" type="xs:string" minOccurs="0"/>
            + *       <!-- This should be a route -->
            + *       <xs:element name="RdvRoute" type="xs:anyType" minOccurs="0"/>
            + *     </xs:sequence>
            + *   </xs:complexType>
            + * 
            + **/ +public class RdvAdv extends RdvAdvertisement { + + /** + * Log4J Logger + **/ + private final static transient Logger LOG = Logger.getLogger(RdvAdv.class.getName()); + + private static final String[] INDEX_FIELDS = { PeerIDTag, ServiceNameTag, GroupIDTag }; + + /** + * Instantiator for our advertisement + **/ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + **/ + public String getAdvertisementType() { + return RdvAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + **/ + public Advertisement newInstance() { + return new RdvAdv(); + } + + /** + * {@inheritDoc} + **/ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new RdvAdv((XMLElement) root); + } + } + + /** + * Private constructor for new instances. Use the instantiator. + */ + private RdvAdv() { + } + + /** + * Private constructor for xml serialized instances. Use the instantiator. + * + * @param doc The XML serialization of the advertisement. + */ + private RdvAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + if (null == getGroupID()) { + throw new IllegalArgumentException("Missing peer group ID"); + } + + if (null == getPeerID()) { + throw new IllegalArgumentException("Missing peer ID"); + } + + if (null == getServiceName()) { + throw new IllegalArgumentException("Missing service name"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + **/ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (elem.getName().equals(RdvAdvertisement.GroupIDTag)) { + try { + URI groupID = new URI(elem.getTextValue().trim()); + + setGroupID((PeerGroupID) IDFactory.fromURI(groupID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad group ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("ID is not a group ID"); + } + return true; + } + + if (elem.getName().equals(RdvAdvertisement.PeerIDTag)) { + try { + URI peerID = new URI(elem.getTextValue().trim()); + + setPeerID((PeerID) IDFactory.fromURI(peerID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad group ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("ID is not a group ID"); + } + return true; + } + + if (elem.getName().equals(RdvAdvertisement.ServiceNameTag)) { + setServiceName(elem.getTextValue()); + return true; + } + + if (elem.getName().equals(RdvAdvertisement.RouteTag)) { + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + + XMLElement aXpt = (XMLElement) eachXpt.nextElement(); + + RouteAdvertisement xptAdv = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(aXpt); + + setRouteAdv(xptAdv); + } + return true; + } + + if (elem.getName().equals(RdvAdvertisement.NameTag)) { + setName(elem.getTextValue()); + return true; + } + + return false; + } + + /** + * {@inheritDoc} + **/ + @Override + public Document getDocument(MimeMediaType encodeAs) { + + // Sanity Check!!! + if (null == getGroupID()) { + throw new IllegalStateException("Missing peer group ID"); + } + + if (null == getPeerID()) { + throw new IllegalStateException("Missing peer ID"); + } + + if (null == getServiceName()) { + throw new IllegalStateException("Missing service name"); + } + + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + Element e = adv.createElement(RdvAdvertisement.GroupIDTag, getGroupID().toString()); + + adv.appendChild(e); + + e = adv.createElement(RdvAdvertisement.PeerIDTag, getPeerID().toString()); + adv.appendChild(e); + + e = adv.createElement(RdvAdvertisement.ServiceNameTag, getServiceName()); + adv.appendChild(e); + + String peerName = getName(); + + if (null != peerName) { + e = adv.createElement(RdvAdvertisement.NameTag, getName()); + adv.appendChild(e); + } + + if (getRouteAdv() != null) { + Element el = adv.createElement(RdvAdvertisement.RouteTag); + + adv.appendChild(el); + + StructuredTextDocument xptDoc = (StructuredTextDocument) + getRouteAdv().getDocument(encodeAs); + + StructuredDocumentUtils.copyElements(adv, el, xptDoc); + } + + return adv; + } + + /** + * {@inheritDoc} + **/ + @Override + public String[] getIndexFields() { + return INDEX_FIELDS; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RdvConfigAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RdvConfigAdv.java new file mode 100644 index 000000000..b743e16b3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RdvConfigAdv.java @@ -0,0 +1,948 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.ID; +import net.jxta.logging.Logging; + +import java.net.URI; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Contains parameters for configuration of the Reference Implementation + * Rendezvous Service. + *

            + *

            
            + * <xs:complexType name="RdvConfig">
            + *   <xs:sequence>
            + *     <xs:element name="seeds" minOccurs="0" maxOccurs="1">
            + *       <xs:complexType>
            + *         <xs:sequence>
            + *           <xs:element name="addr" minOccurs="1" maxOccurs="unbounded">
            + *             <xs:complexType>
            + *               <xs:simpleContent>
            + *                 <xs:extension base="jxta:JXTAID">
            + *                   <xs:attribute name="seeding" type="xs:boolean" default="false"/>
            + *                 </xs:extension>
            + *               </xs:simpleContent>
            + *             </xs:complexType>
            + *           </xs:element>
            + *         </xs:sequence>
            + *         <xs:attribute name="useOnlySeeds" type="xs:boolean" default="false"/>
            + *         <xs:attribute name="connectDelay" type="xs:unsignedLong"/>
            + *       </xs:complexType>
            + *     </xs:element>
            + *   </xs:sequence>
            + *   <xs:attribute name="config" type="jxta:RdvConfiguration"/>
            + *   <xs:attribute name="maxTTL" type="xs:unsignedInt"/>
            + *   <xs:attribute name="autoRendezvousInterval" type="xs:unsignedInt"/>
            + *   <xs:attribute name="probeRelays" type="xs:boolean" default="true"/>
            + *   <xs:attribute name="maxClients" type="xs:unsignedInt"/>
            + *   <xs:attribute name="leaseDuration" type="xs:unsignedLong"/>
            + *   <xs:attribute name="leaseMargin" type="xs:unsignedLong"/>
            + *   <xs:attribute name="minHappyPeerView" type="xs:unsignedInt"/>
            + * </xs:complexType>
            + * 
            + * + * @since JXTA 2.2 + */ +public final class RdvConfigAdv extends ExtendableAdvertisement implements Cloneable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(RdvConfigAdv.class.getName()); + + /** + * Instantiator for RdvConfigAdv + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new RdvConfigAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new RdvConfigAdv((XMLElement) root); + } + } + + /** + * Our DOCTYPE + */ + private static final String advType = "jxta:RdvConfig"; + + private static final String RDV_CONFIG_ATTR = "config"; + private static final String MAX_TTL_ATTR = "maxTTL"; + private static final String AUTO_RDV_INTERVAL_ATTR = "autoRendezvousInterval"; + private static final String PROBE_RELAYS_ATTR = "probeRelays"; + private static final String MAX_CLIENTS_ATTR = "maxClients"; + private static final String LEASE_DURATION_ATTR = "leaseDuration"; + private static final String LEASE_MARGIN_ATTR = "leaseMargin"; + private static final String MIN_HAPPY_PEERVIEW_ATTR = "minHappyPeerView"; + + private static final String SEEDS_RDV_ELEMENT = "seeds"; + private static final String USE_ONLY_SEEDS_ATTR = "useOnlySeeds"; + private static final String CONNECT_DELAY_ATTR = "connectDelay"; + + private static final String SEED_RDV_ADDR_ELEMENT = "addr"; + private static final String SEED_RDV_ADDR_SEEDING_ATTR = "seeding"; + private static final String ACL_URI = "acl"; + + // This one is deprecated. + private static final String PROPAGATE_RESPOND_ATTR = "propagateRespondProbability"; + + private static final String[] INDEXFIELDS = {}; + + /** + * Configuration for this peer. + */ + private RendezVousConfiguration configuration = RendezVousConfiguration.EDGE; + + /** + * The interval in relative milliseconds at which this peer will re-evaluate + * it's state as a rendezvous. If 0 (zero), the default, then + * the peer will remain in the state of isRendezvous. + */ + private long autoRendezvousCheckInterval = 0L; + + /** + * If true then rendezvous clients will probe relay servers for rendezvous. + */ + private boolean probeRelays = true; + + /** + * Max Clients + */ + private int maxClients = -1; + + /** + * Maximum TTL + */ + private int maximumTTL = -1; + + /** + * Lease Duration + */ + private long leaseDuration = 0L; + + /** + * Lease Margin + */ + private long leaseMargin = 0L; + + /** + * Minimum desirable peerview size. + */ + private int minHappyPeerView = -1; + + /** + * If true then this peer will use only seed rendezvous when configured as + * an edge peer. + */ + private boolean useOnlySeeds = false; + + /** + * The interval in relative milliseconds before which this peer will + * attempt to contact the the seed peers. + */ + private long seedRendezvousConnectDelay = 0L; + + /** + * The set of seed rendezvous. + */ + private final Set seedRendezvous = new HashSet(); + + /** + * The set of seeding resources. + */ + private final Set seedingURIs = new HashSet(); + + /** + * Access control URI + */ + private URI aclURI = null; + + /** + * Possible Rendezvous configurations. + */ + public enum RendezVousConfiguration { + + /** + * Connectionless + */ + AD_HOC, + + /** + * Edge peer + */ + EDGE, + + /** + * Rendezvous peer + */ + RENDEZVOUS + } + + /** + * Returns the identifying type of this Advertisement. + *

            + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + *

            + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertisement.getAdvertisementType() no matter what the real type of the + * advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return advType; + } + + /** + * Private constructor for new instances. Use the instantiator. + */ + private RdvConfigAdv() {} + + /** + * Private constructor for xml serialized instances. Use the instantiator. + * + * @param doc The XML serialization of the advertisement. + */ + private RdvConfigAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration eachAttr = doc.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aRdvAttr = (Attribute) eachAttr.nextElement(); + + if (super.handleAttribute(aRdvAttr)) {// nothing to do + } else if (RDV_CONFIG_ATTR.equals(aRdvAttr.getName())) { + String config = aRdvAttr.getValue().trim(); + + if ("adhoc".equals(config)) { + configuration = RendezVousConfiguration.AD_HOC; + } else if ("client".equals(config)) { + configuration = RendezVousConfiguration.EDGE; + } else if ("rendezvous".equals(config)) { + configuration = RendezVousConfiguration.RENDEZVOUS; + } else { + throw new IllegalArgumentException("Unrecognized Rendezvous configuration :" + config); + } + } else if (MAX_TTL_ATTR.equals(aRdvAttr.getName())) { + maximumTTL = Integer.parseInt(aRdvAttr.getValue().trim()); + } else if (AUTO_RDV_INTERVAL_ATTR.equals(aRdvAttr.getName())) { + autoRendezvousCheckInterval = Long.parseLong(aRdvAttr.getValue().trim()); + } else if (PROBE_RELAYS_ATTR.equals(aRdvAttr.getName())) { + probeRelays = Boolean.valueOf(aRdvAttr.getValue().trim()); + } else if (MAX_CLIENTS_ATTR.equals(aRdvAttr.getName())) { + maxClients = Integer.parseInt(aRdvAttr.getValue().trim()); + } else if (LEASE_DURATION_ATTR.equals(aRdvAttr.getName())) { + leaseDuration = Long.parseLong(aRdvAttr.getValue().trim()); + } else if (LEASE_MARGIN_ATTR.equals(aRdvAttr.getName())) { + leaseMargin = Long.parseLong(aRdvAttr.getValue().trim()); + } else if (MIN_HAPPY_PEERVIEW_ATTR.equals(aRdvAttr.getName())) { + minHappyPeerView = Integer.parseInt(aRdvAttr.getValue().trim()); + } else if (PROPAGATE_RESPOND_ATTR.equals(aRdvAttr.getName())) {// Ignored; deprecated. + } else if ("Flags".equals(aRdvAttr.getName())) { // deprecated + boolean onlySeeds = (aRdvAttr.getValue().indexOf("UseOnlySeeds") != -1); + + setUseOnlySeeds(onlySeeds); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aRdvAttr.getName()); + } + } + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + if ((maximumTTL != -1) && (maximumTTL < 0)) { + throw new IllegalArgumentException("Maximum TTL must be >= 0"); + } + + if (autoRendezvousCheckInterval < 0) { + throw new IllegalArgumentException("Auto Rendezvous Check Interval must be >= 0"); + } + + if (seedRendezvousConnectDelay < 0) { + throw new IllegalArgumentException("Seed Rendezvous Connect Delay must be >= 0"); + } + + if ((-1 != minHappyPeerView) && (minHappyPeerView <= 0)) { + throw new IllegalArgumentException("Min Happy Peer View must be > 0"); + } + + if ((seedingURIs.isEmpty() && seedRendezvous.isEmpty() && useOnlySeeds) && (configuration == RendezVousConfiguration.EDGE)) { + throw new IllegalArgumentException("Must specify rendezvous if 'useOnlySeeds' is enabled and configured as client"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + return ID.nullID; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (SEEDS_RDV_ELEMENT.equals(elem.getName())) { + + Enumeration eachSeedElem = elem.getChildren(); + + while (eachSeedElem.hasMoreElements()) { + XMLElement aSeedElem = (XMLElement) eachSeedElem.nextElement(); + + if (SEED_RDV_ADDR_ELEMENT.equals(aSeedElem.getName())) { + String endpAddrString = aSeedElem.getTextValue(); + + if (null != endpAddrString) { + URI endpAddr = URI.create(endpAddrString.trim()); + + Attribute seedingAttr = aSeedElem.getAttribute(SEED_RDV_ADDR_SEEDING_ATTR); + + if ((null != seedingAttr) && Boolean.valueOf(seedingAttr.getValue().trim())) { + seedingURIs.add(endpAddr); + } else { + seedRendezvous.add(endpAddr); + } + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + aSeedElem.getName()); + } + } + } + + Enumeration eachAttr = elem.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aSeedAttr = (Attribute) eachAttr.nextElement(); + + if (USE_ONLY_SEEDS_ATTR.equals(aSeedAttr.getName())) { + useOnlySeeds = Boolean.valueOf(aSeedAttr.getValue().trim()); + } else if (CONNECT_DELAY_ATTR.equals(aSeedAttr.getName())) { + seedRendezvousConnectDelay = Long.parseLong(aSeedAttr.getValue().trim()); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aSeedAttr.getName()); + } + } + } + + return true; + } else if (ACL_URI.equals(elem.getName())) { + String addrElement = elem.getTextValue(); + + if (null != addrElement) { + aclURI = URI.create(addrElement.trim()); + } + + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (!(adv instanceof Attributable)) { + throw new IllegalStateException("Only Attributable documents are supported."); + } + + Attributable attrDoc = (Attributable) adv; + + if (RendezVousConfiguration.AD_HOC == configuration) { + attrDoc.addAttribute(RDV_CONFIG_ATTR, "adhoc"); + } else if (RendezVousConfiguration.EDGE == configuration) { + attrDoc.addAttribute(RDV_CONFIG_ATTR, "client"); + } else if (RendezVousConfiguration.RENDEZVOUS == configuration) { + attrDoc.addAttribute(RDV_CONFIG_ATTR, "rendezvous"); + } + + if (maximumTTL != -1) { + if (maximumTTL < 0) { + throw new IllegalStateException("Maximum TTL must be >= 0"); + } + + attrDoc.addAttribute(MAX_TTL_ATTR, Integer.toString(maximumTTL)); + } + + if ((seedingURIs.isEmpty() && seedRendezvous.isEmpty() && useOnlySeeds) && (configuration == RendezVousConfiguration.EDGE)) { + throw new IllegalStateException("Must specify rendezvous if 'useOnlySeeds' is enabled and configured as client"); + } + + if (0 != autoRendezvousCheckInterval) { + if (autoRendezvousCheckInterval < 0) { + throw new IllegalStateException("Auto Rendezvous Check Interval must be >= 0"); + } + + attrDoc.addAttribute(AUTO_RDV_INTERVAL_ATTR, Long.toString(autoRendezvousCheckInterval)); + } + + if (!probeRelays) { + attrDoc.addAttribute(PROBE_RELAYS_ATTR, Boolean.toString(probeRelays)); + } + + if (-1 != maxClients) { + if (maxClients < 0) { + throw new IllegalStateException("Max Clients must be >= 0"); + } + + attrDoc.addAttribute(MAX_CLIENTS_ATTR, Integer.toString(maxClients)); + } + + if (0 != leaseDuration) { + if (leaseDuration < 0) { + throw new IllegalStateException("Lease Duration must be >= 0"); + } + + attrDoc.addAttribute(LEASE_DURATION_ATTR, Long.toString(leaseDuration)); + } + + if (0 != leaseMargin) { + if (leaseMargin < 0) { + throw new IllegalStateException("Lease Margin must be >= 0"); + } + + attrDoc.addAttribute(LEASE_MARGIN_ATTR, Long.toString(leaseMargin)); + } + + if (-1 != minHappyPeerView) { + if (minHappyPeerView < 0) { + throw new IllegalStateException("Min Happy Peer View must be > 0"); + } + + attrDoc.addAttribute(MIN_HAPPY_PEERVIEW_ATTR, Integer.toString(minHappyPeerView)); + } + + if (!seedRendezvous.isEmpty() || !seedingURIs.isEmpty()) { + Element seedsElem = adv.createElement(SEEDS_RDV_ELEMENT); + + adv.appendChild(seedsElem); + + Attributable attrSeeds = (Attributable) seedsElem; + + if (useOnlySeeds) { + attrSeeds.addAttribute(USE_ONLY_SEEDS_ATTR, Boolean.toString(useOnlySeeds)); + } + + if (0 != seedRendezvousConnectDelay) { + if (seedRendezvousConnectDelay < 0) { + throw new IllegalStateException("Seed Rendezvous Connect Delay must be >= 0"); + } + + attrSeeds.addAttribute(CONNECT_DELAY_ATTR, Long.toString(seedRendezvousConnectDelay)); + } + + for (URI seedRendezvou : seedRendezvous) { + Element aSeed = adv.createElement(SEED_RDV_ADDR_ELEMENT, seedRendezvou.toString()); + + seedsElem.appendChild(aSeed); + } + + for (URI seedingURI : seedingURIs) { + Element aSeed = adv.createElement(SEED_RDV_ADDR_ELEMENT, seedingURI.toString()); + + seedsElem.appendChild(aSeed); + + Attributable seedAttr = (Attributable) aSeed; + + seedAttr.addAttribute(SEED_RDV_ADDR_SEEDING_ATTR, Boolean.TRUE.toString()); + } + if (aclURI != null) { + Element acl = adv.createElement(ACL_URI, aclURI.toString()); + + adv.appendChild(acl); + } + } + + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEXFIELDS; + } + + /** + * True if this peer is to default to act as a rendezvous. + * + * @return True if this peer is to be a rendezvous + */ + public RendezVousConfiguration getConfiguration() { + return configuration; + } + + /** + * Set the default rendezvous state of this peer. + * + * @param newstate if true then this peer should default to acting as a + * rendezvous. + */ + public void setConfiguration(RendezVousConfiguration newstate) { + configuration = newstate; + } + + /** + * The interval in relative milliseconds at which this peer will re-evaluate + * it's state as a rendezvous. If 0 (zero), the default, then + * the peer will remain in the state of isRendezvous. + * + * @return The interval in relative milliseconds at which this peer will re-evaluate + * it's state as a rendezvous. If 0 (zero), the default, then + * the peer will remain in the state of isRendezvous. + */ + public long getAutoRendezvousCheckInterval() { + return autoRendezvousCheckInterval; + } + + /** + * Sets the interval in relative milliseconds at which this peer will re-evaluate + * it's state as a rendezvous. If 0 (zero), the default, then + * the peer will remain in the state of isRendezvous. + * + * @param newvalue The interval in relative milliseconds at which this peer + * will re-evaluate it's state as a rendezvous. If 0 (zero), + * the default, then the peer will remain in the state of + * isRendezvous. + */ + public void setAutoRendezvousCheckInterval(long newvalue) { + if (newvalue < 0) { + throw new IllegalArgumentException("Auto Rendezvous Check Interval must be >= 0"); + } + + autoRendezvousCheckInterval = newvalue; + } + + /** + * If true then rendezvous clients will probe relay servers for rendezvous. + * + * @return If true then rendezvous clients will probe relay servers for rendezvous. + */ + public boolean getProbeRelays() { + return probeRelays; + } + + /** + * Set whether rendezvous clients will probe relay servers for rendezvous. + * + * @param doProbe If true then rendezvous clients will probe relay servers for rendezvous. + */ + public void setProbeRelays(boolean doProbe) { + probeRelays = doProbe; + } + + public URI[] getSeedRendezvous() { + return seedRendezvous.toArray(new URI[seedRendezvous.size()]); + } + + public void addSeedRendezvous(URI addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedRendezvous.add(addr); + } + + public void addSeedRendezvous(String addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedRendezvous.add(URI.create(addr)); + } + + public boolean removeSeedRendezvous(URI addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + return seedRendezvous.remove(addr); + } + + public void clearSeedRendezvous() { + seedRendezvous.clear(); + } + + public URI[] getSeedingURIs() { + return seedingURIs.toArray(new URI[seedingURIs.size()]); + } + + public void addSeedingURI(URI addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedingURIs.add(addr); + } + + public void addSeedingURI(String addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedingURIs.add(URI.create(addr)); + } + + public boolean removeSeedingURI(URI addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + return seedingURIs.remove(addr); + } + + public void clearSeedingURIs() { + seedingURIs.clear(); + } + + /** + * If true then this peer will use only seed rendezvous when configured as + * an edge peer. + * + * @return If true then this peer will use only seed rendezvous when + * configured as an edge peer. + */ + public boolean getUseOnlySeeds() { + return useOnlySeeds; + } + + /** + * Set whether this peer will use only seed rendezvous when configured as + * an edge peer. + * + * @param onlySeeds If true then this peer will use only seed rendezvous + * when configured as an edge peer. + */ + public void setUseOnlySeeds(boolean onlySeeds) { + useOnlySeeds = onlySeeds; + } + + /** + * The interval in relative milliseconds before which this peer will + * attempt to contact the the seed peers. + * + * @return The interval in relative milliseconds before which this peer will + * attempt to contact the the seed peers. + */ + public long getSeedRendezvousConnectDelay() { + return seedRendezvousConnectDelay; + } + + /** + * Sets the interval in relative milliseconds before which this peer will + * attempt to contact the the seed peers. + * + * @param newvalue The interval in relative milliseconds before which this peer will + * attempt to contact the the seed peers or + * -1 for the default value. + */ + public void setSeedRendezvousConnectDelay(long newvalue) { + if ((-1 != newvalue) && (newvalue < 0)) { + throw new IllegalArgumentException("Seed Rendezvous Connect Delay must be >= 0"); + } + + seedRendezvousConnectDelay = newvalue; + } + + /** + * The interval in relative milliseconds of leases offered by rendezvous + * peers. + * + * @return The interval in relative milliseconds of leases offered by rendezvous + * peers. + */ + public long getLeaseDuration() { + return leaseDuration; + } + + /** + * Sets interval in relative milliseconds of leases to be offered by rendezvous + * peers. + * + * @param newvalue The interval in relative milliseconds of leases to be offered by rendezvous + * peers or -1 for the default value. + */ + public void setLeaseDuration(long newvalue) { + if ((-1 != newvalue) && (newvalue < 0)) { + throw new IllegalArgumentException("Lease Duration must be >= 0"); + } + + leaseDuration = newvalue; + } + + /** + * The interval in relative milliseconds of leases offered by rendezvous + * peers. + * + * @return The interval in relative milliseconds of leases offered by rendezvous + * peers. + */ + public long getLeaseMargin() { + return leaseMargin; + } + + /** + * Sets interval in relative milliseconds of leases to be offered by rendezvous + * peers. + * + * @param newvalue The interval in relative milliseconds of leases to be offered by rendezvous + * peers or + * -1 for the default value. + */ + public void setLeaseMargin(long newvalue) { + if ((-1 != newvalue) && (newvalue < 0)) { + throw new IllegalArgumentException("Lease Margin must be >= 0"); + } + + leaseMargin = newvalue; + } + + /** + * Return the maximum number of clients. + * + * @return The maximum number of clients. + */ + public int getMaxClients() { + return maxClients; + } + + /** + * Sets he maximum number of clients. + * + * @param newvalue The maximum number of clients or + * -1 for the default value. + */ + public void setMaxClients(int newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Max Clients must be > 0"); + } + + maxClients = newvalue; + } + + /** + * Returns the maximum TTL for messages propagated by this peer or + * -1 for the default value. + * + * @return the maximum TTL for messages propagated by this peer or + * -1 for the default value. + */ + public int getMaxTTL() { + return maximumTTL; + } + + /** + * Sets the maximum TTL for messages propagated by this peer. + * + * @param newvalue the maximum TTL for messages propagated by this peer or + * -1 for the default value. + */ + public void setMaxTTL(int newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Max TTL must be >= 0"); + } + + maximumTTL = newvalue; + } + + /** + * Returns the minimum peerview size which the rendezvous service will + * find sufficient. + * + * @return the minimum peerview size. + */ + public int getMinHappyPeerView() { + return minHappyPeerView; + } + + /** + * Sets the minimum peerview size which the rendezvous service will find + * sufficient. If the peerview size is below that threshold, the peerview + * will more aggressively try to discover additional members. If permitted, + * the local peer may eventually decide to become a rendezvous in order for + * the peerview to reach that size. + * + * @param newvalue the minimum peerview size, which must be > 0 or + * -1 for the default value. + */ + public void setMinHappyPeerView(int newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Min Happy Peer View size must be > 0"); + } + minHappyPeerView = newvalue; + } + + /** + * Return ACL URI if set + * + * @return ACL URI if set, null otherwise + */ + public URI getAclUri() { + return aclURI; + } + + /** + * Sets ACL URI + * + * @param uri URI if set, null otherwise + */ + public void setAclUri(URI uri) { + aclURI = uri; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RelayConfigAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RelayConfigAdv.java new file mode 100644 index 000000000..8707da7f7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RelayConfigAdv.java @@ -0,0 +1,997 @@ +/* + * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.net.URI; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + + +/** + * Contains parameters for configuration of the Reference Implemenation + * Relay Service. + *

            + *

            
            + * 

            + *

            + */ +public final class RelayConfigAdv extends ExtendableAdvertisement implements Cloneable { + + /** + * Log4J Logger + */ + private static final Logger LOG = Logger.getLogger(RelayConfigAdv.class.getName()); + + /** + * Our DOCTYPE + */ + private static final String advType = "jxta:RelayConfig"; + + private static final String RELAY_CLIENT_ATTR = "client"; + private static final String RELAY_SERVER_ATTR = "server"; + + private static final String RELAY_CLIENT_ELEMENT = "client"; + private static final String RELAY_CLIENT_SERVERS_ATTR = "maxRelays"; + private static final String RELAY_CLIENT_LEASE_ATTR = "maxLease"; + private static final String RELAY_CLIENT_POLL_ATTR = "messengerPollInterval"; + + private static final String RELAY_CLIENT_SEEDS_ELEMENT = "seeds"; + private static final String USE_ONLY_SEEDS_ATTR = "useOnlySeeds"; + + private static final String SEED_RELAY_ADDR_ELEMENT = "addr"; + private static final String SEED_RELAY_ADDR_SEEDING_ATTR = "seeding"; + + private static final String RELAY_SERVER_ELEMENT = "server"; + private static final String RELAY_SERVER_CLIENTS_ATTR = "maxClients"; + private static final String RELAY_SERVER_QUEUE_ATTR = "clientQueue"; + private static final String RELAY_SERVER_LEASE_ATTR = "leaseDuration"; + private static final String RELAY_SERVER_STALL_ATTR = "stallTimeout"; + private static final String RELAY_SERVER_ANNOUNCE_ATTR = "announceInterval"; + private static final String ACL_URI = "acl"; + + private static final String[] fields = {}; + + /** + * Are we configured as a relay client? + */ + private boolean clientEnabled = false; + + /** + * Max Relays + */ + private int maxRelays = -1; + + /** + * Max clients lease in relative milliseconds. + */ + private long maxClientLeaseDuration = -1; + + /** + * Messenger poll interval in relative milliseconds. + */ + private long messengerPollInterval = -1; + + /** + * Use only seeded relays. + */ + private boolean useOnlySeeds = false; + + /** + * Seed Relays + *

            + *

              + *
            • Elements are {@link net.jxta.endpoint.EndpointAddress}
            • + *
            + */ + private Set seedRelays = new HashSet(); + + /** + * The list of seeding resources. + *

            + *

              + *
            • The values are {@link java.net.URI}.
            • + *
            + */ + private Set seedingURIs = new HashSet(); + + /** + * Are we configured as a relay server? + */ + private boolean serverEnabled = false; + + /** + * Max Clients + */ + private int maxClients = -1; + + /** + */ + private int maxClientMessageQueue = -1; + + /** + * Max Lease offered by server in relative milliseconds. + */ + private long maxServerLeaseDuration = -1; + + /** + * Stall timeout in relative milliseconds. + */ + private long stallTimeout = -1; + + /** + * Announce interval in relative milliseconds. + */ + private long announceInterval = -1; + + /** + * Access control URI + */ + private URI aclURI = null; + + /** + * Instantiator for RelayConfigAdv + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return advType; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new RelayConfigAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + return new RelayConfigAdv(root); + } + } + + /** + * Returns the identifying type of this Advertisement. + *

            + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisment. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + *

            + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertiement.getAdvertisementType() no matter what the real type of the + * advertisment. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return advType; + } + + private RelayConfigAdv() {} + + private RelayConfigAdv(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration eachAttr = doc.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aRelayAttr = (Attribute) eachAttr.nextElement(); + + if (super.handleAttribute(aRelayAttr)) { + // nothing to do + ; + } else if (RELAY_CLIENT_ATTR.equals(aRelayAttr.getName())) { + clientEnabled = Boolean.valueOf(aRelayAttr.getValue().trim()); + } else if (RELAY_SERVER_ATTR.equals(aRelayAttr.getName())) { + serverEnabled = Boolean.valueOf(aRelayAttr.getValue().trim()); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aRelayAttr.getName()); + } + } + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + if ((-1 != maxRelays) && (maxRelays <= 0)) { + throw new IllegalArgumentException("Max relays must not be negative or zero."); + } + + if ((-1 != maxClientLeaseDuration) && (maxClientLeaseDuration <= 0)) { + throw new IllegalArgumentException("Max lease duration must not be negative or zero."); + } + + if ((-1 != messengerPollInterval) && (messengerPollInterval <= 0)) { + throw new IllegalArgumentException("Messenger poll interval must not be negative or zero."); + } + + if (useOnlySeeds && clientEnabled && seedRelays.isEmpty() && seedingURIs.isEmpty()) { + throw new IllegalArgumentException("Cannot specify 'useOnlySeeds' and no seed relays"); + } + + if ((-1 != maxClients) && (maxClients <= 0)) { + throw new IllegalArgumentException("Max clients must not be negative or zero."); + } + + if ((-1 != maxClientMessageQueue) && (maxClientMessageQueue <= 0)) { + throw new IllegalArgumentException("Max client queue must not be negative or zero."); + } + + if ((-1 != maxServerLeaseDuration) && (maxServerLeaseDuration <= 0)) { + throw new IllegalArgumentException("Max lease duration must not be negative or zero."); + } + + if ((-1 != stallTimeout) && (stallTimeout <= 0)) { + throw new IllegalArgumentException("Client stall timeout duration must not be negative or zero."); + } + + if ((-1 != announceInterval) && (announceInterval <= 0)) { + throw new IllegalArgumentException("Announce interval must not be negative or zero."); + } + } + + /** + * {@inheritDoc} + */ + @Override + public RelayConfigAdv clone() { + + RelayConfigAdv result; + + try { + result = (RelayConfigAdv) super.clone(); + } catch (CloneNotSupportedException impossible) { + throw new Error("Object.clone() threw CloneNotSupportedException", impossible); + } + + result.setAnnounceInterval(getAnnounceInterval()); + result.setClientEnabled(isClientEnabled()); + result.setClientLeaseDuration(getClientLeaseDuration()); + result.setClientMessageQueueSize(getClientMessageQueueSize()); + result.setMaxClients(getMaxClients()); + result.setMaxRelays(getMaxRelays()); + result.setMessengerPollInterval(getMessengerPollInterval()); + result.setServerEnabled(isServerEnabled()); + result.setServerLeaseDuration(getServerLeaseDuration()); + result.setStallTimeout(getStallTimeout()); + result.setUseOnlySeeds(getUseOnlySeeds()); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public final String getBaseAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public ID getID() { + return ID.nullID; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (RELAY_CLIENT_ELEMENT.equals(elem.getName())) { + Enumeration eachAttr = elem.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aRelayAttr = (Attribute) eachAttr.nextElement(); + + if (RELAY_CLIENT_SERVERS_ATTR.equals(aRelayAttr.getName())) { + maxRelays = Integer.parseInt(aRelayAttr.getValue().trim()); + } else if (RELAY_CLIENT_LEASE_ATTR.equals(aRelayAttr.getName())) { + maxClientLeaseDuration = Long.parseLong(aRelayAttr.getValue().trim()); + } else if (RELAY_CLIENT_POLL_ATTR.equals(aRelayAttr.getName())) { + messengerPollInterval = Long.parseLong(aRelayAttr.getValue().trim()); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aRelayAttr.getName()); + } + } + } + + Enumeration elements = elem.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement seedsElem = (XMLElement) elements.nextElement(); + + if (RELAY_CLIENT_SEEDS_ELEMENT.equals(seedsElem.getName())) { + Enumeration eachSeedsAttr = seedsElem.getAttributes(); + + while (eachSeedsAttr.hasMoreElements()) { + Attribute aRelayAttr = (Attribute) eachSeedsAttr.nextElement(); + + if (USE_ONLY_SEEDS_ATTR.equals(aRelayAttr.getName())) { + useOnlySeeds = Boolean.valueOf(aRelayAttr.getValue().trim()); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aRelayAttr.getName()); + } + } + } + + Enumeration addrElements = seedsElem.getChildren(); + + while (addrElements.hasMoreElements()) { + XMLElement addrElem = (XMLElement) addrElements.nextElement(); + + if (SEED_RELAY_ADDR_ELEMENT.equals(addrElem.getName())) { + String endpAddrString = addrElem.getTextValue(); + + if (null != endpAddrString) { + URI endpURI = URI.create(endpAddrString.trim()); + + Attribute seedingAttr = addrElem.getAttribute(SEED_RELAY_ADDR_SEEDING_ATTR); + + if ((null != seedingAttr) && Boolean.valueOf(seedingAttr.getValue().trim())) { + seedingURIs.add(endpURI); + } else { + seedRelays.add(new EndpointAddress(endpURI)); + } + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem.toString()); + } + } + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem.toString()); + } + } + } + + return true; + } else if (RELAY_SERVER_ELEMENT.equals(elem.getName())) { + Enumeration eachAttr = elem.getAttributes(); + + while (eachAttr.hasMoreElements()) { + Attribute aRelayAttr = (Attribute) eachAttr.nextElement(); + + if (RELAY_SERVER_CLIENTS_ATTR.equals(aRelayAttr.getName())) { + maxClients = Integer.parseInt(aRelayAttr.getValue().trim()); + } else if (RELAY_SERVER_QUEUE_ATTR.equals(aRelayAttr.getName())) { + maxClientMessageQueue = Integer.parseInt(aRelayAttr.getValue().trim()); + } else if (RELAY_SERVER_LEASE_ATTR.equals(aRelayAttr.getName())) { + maxServerLeaseDuration = Long.parseLong(aRelayAttr.getValue().trim()); + } else if (RELAY_SERVER_STALL_ATTR.equals(aRelayAttr.getName())) { + stallTimeout = Long.parseLong(aRelayAttr.getValue().trim()); + } else if (RELAY_SERVER_ANNOUNCE_ATTR.equals(aRelayAttr.getName())) { + announceInterval = Long.parseLong(aRelayAttr.getValue().trim()); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Attribute: " + aRelayAttr.getName()); + } + } + } + + return true; + } else if (ACL_URI.equals(elem.getName())) { + String addrElement = elem.getTextValue(); + + if (null != addrElement) { + aclURI = URI.create(addrElement.trim()); + } + + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (!(adv instanceof Attributable)) { + throw new IllegalStateException("Only Attributable documents are supported."); + } + + if ((-1 != maxRelays) && (maxRelays <= 0)) { + throw new IllegalStateException("Max relays must not be negative or zero."); + } + + if ((-1 != maxClientLeaseDuration) && (maxClientLeaseDuration <= 0)) { + throw new IllegalStateException("Max lease duration must not be negative or zero."); + } + + if ((-1 != messengerPollInterval) && (messengerPollInterval <= 0)) { + throw new IllegalStateException("Messenger poll interval must not be negative or zero."); + } + + if (useOnlySeeds && clientEnabled && seedRelays.isEmpty() && seedingURIs.isEmpty()) { + throw new IllegalStateException("Cannot specify 'useOnlySeeds' and no seed relays"); + } + + if ((-1 != maxClients) && (maxClients <= 0)) { + throw new IllegalStateException("Max clients must not be negative or zero."); + } + + if ((-1 != maxClientMessageQueue) && (maxClientMessageQueue <= 0)) { + throw new IllegalStateException("Max client queue must not be negative or zero."); + } + + if ((-1 != maxServerLeaseDuration) && (maxServerLeaseDuration <= 0)) { + throw new IllegalStateException("Max lease duration must not be negative or zero."); + } + + if ((-1 != stallTimeout) && (stallTimeout <= 0)) { + throw new IllegalStateException("Client stall timeout duration must not be negative or zero."); + } + + if ((-1 != announceInterval) && (announceInterval <= 0)) { + throw new IllegalStateException("Announce interval must not be negative or zero."); + } + + Attributable attrDoc = (Attributable) adv; + + if (clientEnabled) { + attrDoc.addAttribute(RELAY_CLIENT_ATTR, Boolean.TRUE.toString()); + } + + if (serverEnabled) { + attrDoc.addAttribute(RELAY_SERVER_ATTR, Boolean.TRUE.toString()); + } + + Element clientElem = adv.createElement(RELAY_CLIENT_ELEMENT); + + adv.appendChild(clientElem); + + Attributable attrElem = (Attributable) clientElem; + + if (-1 != maxRelays) { + attrElem.addAttribute(RELAY_CLIENT_SERVERS_ATTR, Integer.toString(maxRelays)); + } + + if (-1 != maxClientLeaseDuration) { + attrElem.addAttribute(RELAY_CLIENT_LEASE_ATTR, Long.toString(maxClientLeaseDuration)); + } + + if (-1 != messengerPollInterval) { + attrElem.addAttribute(RELAY_CLIENT_POLL_ATTR, Long.toString(messengerPollInterval)); + } + + if (!seedRelays.isEmpty() || !seedingURIs.isEmpty()) { + Element seedsElem = adv.createElement(RELAY_CLIENT_SEEDS_ELEMENT); + + clientElem.appendChild(seedsElem); + + attrElem = (Attributable) seedsElem; + + if (useOnlySeeds) { + attrElem.addAttribute(USE_ONLY_SEEDS_ATTR, Boolean.TRUE.toString()); + } + + for (EndpointAddress seedRelay : seedRelays) { + Element addrElement = adv.createElement(SEED_RELAY_ADDR_ELEMENT, seedRelay.toString()); + + seedsElem.appendChild(addrElement); + } + + for (URI seedingURI : seedingURIs) { + Element addrElement = adv.createElement(SEED_RELAY_ADDR_ELEMENT, seedingURI.toString()); + + seedsElem.appendChild(addrElement); + + ((Attributable) addrElement).addAttribute(SEED_RELAY_ADDR_SEEDING_ATTR, Boolean.TRUE.toString()); + } + } + + Element serverElem = adv.createElement(RELAY_SERVER_ELEMENT); + + adv.appendChild(serverElem); + + attrElem = (Attributable) serverElem; + + if (-1 != maxClients) { + attrElem.addAttribute(RELAY_SERVER_CLIENTS_ATTR, Integer.toString(maxClients)); + } + + if (-1 != maxClientMessageQueue) { + attrElem.addAttribute(RELAY_SERVER_QUEUE_ATTR, Integer.toString(maxClientMessageQueue)); + } + + if (-1 != maxServerLeaseDuration) { + attrElem.addAttribute(RELAY_SERVER_LEASE_ATTR, Long.toString(maxServerLeaseDuration)); + } + + if (-1 != stallTimeout) { + attrElem.addAttribute(RELAY_SERVER_STALL_ATTR, Long.toString(stallTimeout)); + } + + if (-1 != announceInterval) { + attrElem.addAttribute(RELAY_SERVER_ANNOUNCE_ATTR, Long.toString(announceInterval)); + } + if (aclURI != null) { + Element acl = adv.createElement(ACL_URI, aclURI.toString()); + + adv.appendChild(acl); + } + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return fields; + } + + /** + * If true then this peer will act as a relay client. + * + * @return If true then this peer will act as a relay client. + */ + public boolean isClientEnabled() { + return clientEnabled; + } + + /** + * If true then this peer will act as a relay client. + * + * @param enabled If true then this peer will act as a relay client. + */ + public void setClientEnabled(boolean enabled) { + clientEnabled = enabled; + } + + /** + * Return the maximum number of relay clients. + * + * @return The maximum number of relay clients or -1 for + * default value. + */ + public int getMaxRelays() { + return maxRelays; + } + + /** + * Sets the maximum number of relay clients. + * + * @param newvalue The maximum number of relay clients or -1 + * for default value or -1 for default value. + */ + public void setMaxRelays(int newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Max Relays must be > 0"); + } + + maxRelays = newvalue; + } + + /** + * The interval in relative milliseconds of leases accepted by clients. + * + * @return The interval in relative milliseconds of leases accepted by + * clients or -1 for default value. + */ + public long getClientLeaseDuration() { + return maxClientLeaseDuration; + } + + /** + * Sets interval in relative milliseconds of leases accepted by clients. + * + * @param newvalue The interval in relative milliseconds of leases accepted + * by clients or -1 for default value. + */ + public void setClientLeaseDuration(long newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Lease Duration must be > 0"); + } + + maxClientLeaseDuration = newvalue; + } + + /** + * The interval in relative milliseconds of at which clients will poll for + * messengers + * + * @return The interval in relative milliseconds of at which clients will + * poll for messengers or -1 for default value. + */ + public long getMessengerPollInterval() { + return messengerPollInterval; + } + + /** + * Sets interval in relative milliseconds of at which clients will poll for + * messengers. + * + * @param newvalue The interval in relative milliseconds of at which clients + * will poll for messengers or -1 for default value. + */ + public void setMessengerPollInterval(long newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Poll interval must be > 0"); + } + + messengerPollInterval = newvalue; + } + + /** + * If true then this peer will use only seed rendezvous when configured as + * an edge peer. + * + * @return If true then this peer will use only seed rendezvous when configured as + * an edge peer. + */ + public boolean getUseOnlySeeds() { + return useOnlySeeds; + } + + /** + * Set whether this peer will use only seed rendezvous when configured as + * an edge peer. + * + * @param onlySeeds If true then this peer will use only seed rendezvous when configured as + * an edge peer. + */ + public void setUseOnlySeeds(boolean onlySeeds) { + useOnlySeeds = onlySeeds; + } + + public EndpointAddress[] getSeedRelays() { + return seedRelays.toArray(new EndpointAddress[seedRelays.size()]); + } + + public void addSeedRelay(EndpointAddress addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedRelays.add(addr); + } + + public void addSeedRelay(String addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedRelays.add(new EndpointAddress(addr)); + } + + public boolean removeSeedRelay(EndpointAddress addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + return seedRelays.remove(addr); + } + + public void clearSeedRelays() { + seedRelays.clear(); + } + + public URI[] getSeedingURIs() { + return seedingURIs.toArray(new URI[seedingURIs.size()]); + } + + public void addSeedingURI(URI addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedingURIs.add(addr); + } + + public void addSeedingURI(String addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + seedingURIs.add(URI.create(addr)); + } + + public boolean removeSeedingURI(URI addr) { + if (null == addr) { + throw new IllegalArgumentException("addr may not be null"); + } + + return seedingURIs.remove(addr); + } + + public void clearSeedingURIs() { + seedingURIs.clear(); + } + + /** + * If true then this peer will act as a relay server. + * + * @return If true then this peer will act as a relay server. + */ + public boolean isServerEnabled() { + return serverEnabled; + } + + /** + * If true then this peer will act as a relay server. + * + * @param enabled If true then this peer will act as a relay server. + */ + public void setServerEnabled(boolean enabled) { + serverEnabled = enabled; + } + + /** + * Return the maximum number of relay clients. + * + * @return The maximum number of relay clients or -1 for + * default value. + */ + public int getMaxClients() { + return maxClients; + } + + /** + * Sets he maximum number of relay clients. + * + * @param newvalue The maximum number of relay clients or -1 + * for default value. + */ + public void setMaxClients(int newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Max Clients must be > 0"); + } + + maxClients = newvalue; + } + + /** + * Return the client message queue length size. + * + * @return The client message queue length size or -1 for default value. + */ + public int getClientMessageQueueSize() { + return maxClientMessageQueue; + } + + /** + * Sets the client message queue length size. + * + * @param newvalue The client message queue length size or -1 + * for default value. + */ + public void setClientMessageQueueSize(int newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Client Message Queue Size must be > 0"); + } + + maxClientMessageQueue = newvalue; + } + + /** + * The interval in relative milliseconds of leases offered by servers. + * + * @return The interval in relative milliseconds of leases offered by servers. + */ + public long getServerLeaseDuration() { + return maxServerLeaseDuration; + } + + /** + * Sets interval in relative milliseconds of leases offered by servers. + * + * @param newvalue The interval in relative milliseconds of leases offered + * by servers or -1 for default value. + */ + public void setServerLeaseDuration(long newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Lease Duration must be >= 0"); + } + + maxServerLeaseDuration = newvalue; + } + + /** + * The interval in relative milliseconds after which a client is assumed to + * no longer be connected if it fails to request messages. + * + * @return The interval in relative milliseconds after which a client is + * assumed to no longer be connected if it fails to request messages or + * -1 for default value. + */ + public long getStallTimeout() { + return stallTimeout; + } + + /** + * Sets interval in relative milliseconds after which a client is assumed to + * no longer be connected if it fails to request messages. + * + * @param newvalue The interval in relative milliseconds after which a + * client is assumed to no longer be connected if it fails to request + * messages or -1 for default value. + */ + public void setStallTimeout(long newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Stall timeout must be > 0"); + } + + stallTimeout = newvalue; + } + + /** + * The interval in relative milliseconds at which relay server will + * announce its presence. + * + * @return The interval in relative milliseconds at which relay server will + * broadcast its presence or -1 for default value. + */ + public long getAnnounceInterval() { + return announceInterval; + } + + /** + * Sets interval in relative milliseconds at which relay server will + * announce its presence or -1 for default value. + * + * @param newvalue The interval in relative milliseconds at which relay server will + * announce its presence. + */ + public void setAnnounceInterval(long newvalue) { + if ((-1 != newvalue) && (newvalue <= 0)) { + throw new IllegalArgumentException("Announce Interval must be > 0"); + } + + announceInterval = newvalue; + } + + /** + * Return ACL URI if set + * + * @return ACL URI if set, null otherwise + */ + public URI getAclUri() { + return aclURI; + } + + /** + * Sets ACL URI + * + * @param uri URI if set, null otherwise + */ + public void setAclUri(URI uri) { + aclURI = uri; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverQuery.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverQuery.java new file mode 100644 index 000000000..ac1ce0078 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverQuery.java @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.protocol; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.id.IDFactory; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.RouteAdvertisement; + +/** + * Implements the Resolver Query Message according to the + * schema defined by the core JXTA Peer Resolver Protocol (PRP). + *

            + *

            + * <xs:element name="ResolverQuery" type="jxta:ResolverQuery"/>
            + * 

            + * <xs:complexType name="ResolverQuery"> + * <xs:all> + * <xs:element ref="jxta:Cred" minOccurs="0"/> + * <xs:element name="SrcPeerID" type="jxta:JXTAID"/> + * <xs:element name="SrcPeerRoute" type="jxta:JXTA RouteAdv"/> + * <!-- This could be extended with a pattern restriction --> + * <xs:element name="HandlerName" type="xs:string"/> + * <xs:element name="QueryID" type="xs:string"/> + * <xs:element name="HC" type="xs:unsignedInt"/> + * <xs:element name="Query" type="xs:anyType"/> + * </xs:all> + * </xs:complexType> + *

            + *

            + *

            IMPORTANT: a ResolverQuery contains an internal + * state, the hopCount, which is incremented by various services that needs to. + * As a result, a ResolverQuery may have to be cloned when the hopCount state + * needs to be reset. + * + * @see net.jxta.resolver.ResolverService + * @see net.jxta.protocol.ResolverQueryMsg + * @see JXTA Protocols Specification : Peer Resolver Protocol + */ +public class ResolverQuery extends ResolverQueryMsg implements Cloneable { + + /** + * The logger + */ + private final static Logger LOG = Logger.getLogger(ResolverQuery.class.getName()); + + private static final String handlernameTag = "HandlerName"; + private static final String credentialTag = "jxta:Cred"; + private static final String queryIdTag = "QueryID"; + private static final String hopCountTag = "HC"; + private static final String srcPeerIdTag = "SrcPeerID"; + private static final String srcRouteTag = "SrcPeerRoute"; + private static final String queryTag = "Query"; + + /** + * Default constructor + */ + public ResolverQuery() { + super(); + } + + /** + * Construct a doc from strings + * + * @param HandlerName the handler name + * @param Credential credential document + * @param pId source PeerID + * @param Query opaque query string + * @param qid query ID + * @deprecated use the individual accessor methods instead. + */ + @Deprecated + public ResolverQuery(String HandlerName, StructuredDocument Credential, String pId, String Query, int qid) { + + this(); + setHandlerName(HandlerName); + setCredential(Credential); + setQueryId(qid); + setSrc(pId); + setQuery(Query); + } + + /** + * Construct from a StructuredDocument + * + * @param root the element + */ + public ResolverQuery(Element root) { + + this(); + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + String doctype = doc.getName(); + + if (!getAdvertisementType().equals(doctype)) { + throw new IllegalArgumentException("Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + readIt(doc); + + // sanity check! + if (null == getHandlerName()) { + throw new IllegalArgumentException("Query message does not contain a handler name."); + } + + if (null == getQuery()) { + throw new IllegalArgumentException("Query message does not contain a query."); + } + + if (null == getSrcPeer()) { + throw new IllegalArgumentException("Query message does not define a source."); + } + + RouteAdvertisement ra = getSrcPeerRoute(); + + if ((null != ra) && (null == ra.getDestPeerID())) { + throw new IllegalArgumentException("Route does not define a destination."); + } + } + + /** + * parses an XML document into this object + * + * @param doc the element + */ + public void readIt(XMLElement doc) { + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (elem.getName().equals(handlernameTag)) { + setHandlerName(elem.getTextValue()); + continue; + } + // Set credential + if (elem.getName().equals(credentialTag)) { + setCredential(StructuredDocumentUtils.copyAsDocument(elem)); + continue; + } + // Set queryid + if (elem.getName().equals(queryIdTag)) { + queryid = Integer.parseInt(elem.getTextValue()); + continue; + } + + // Set source route + if (elem.getName().equals(srcRouteTag)) { + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + XMLElement aXpt = (XMLElement) eachXpt.nextElement(); + RouteAdvertisement routeAdv = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(aXpt); + + if (null != routeAdv.getDestPeerID()) { + setSrcPeerRoute(routeAdv); + setSrcPeer(routeAdv.getDestPeerID()); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Incomplete Route Advertisement (missing peer id)."); + } + } + } + continue; + } + + // Set hopcount + if (elem.getName().equals(hopCountTag)) { + setHopCount(Integer.parseInt(elem.getTextValue())); + continue; + } + + // Set source peer + // FIXME tra 20031108 Since Peer Id is already part + // of the SrcRoute Tag. We should be able to remove + // processing this tag in the future. + if (elem.getName().equals(srcPeerIdTag)) { + try { + String value = elem.getTextValue(); + if (value != null && value.length() > 0) { + URI srcURI = new URI(elem.getTextValue()); + setSrcPeer(IDFactory.fromURI(srcURI)); + } + } catch (URISyntaxException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Bad ID in message", failed); + } + RuntimeException failure = new IllegalArgumentException("Bad ID in message"); + failure.initCause(failed); + throw failure; + } + continue; + } + // Set query + if (elem.getName().equals(queryTag)) { + setQuery(elem.getTextValue()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + // sanity check! + if (null == getHandlerName()) { + throw new IllegalStateException("Query message does not contain a handler name."); + } + + if (null == getQuery()) { + throw new IllegalStateException("Query message does not contain a query."); + } + + if (null == getSrcPeer()) { + throw new IllegalStateException("Query message does not define a source."); + } + + RouteAdvertisement ra = getSrcPeerRoute(); + + if ((null != ra) && (null == ra.getDestPeerID())) { + throw new IllegalStateException("Route does not define a destination."); + } + + StructuredTextDocument adv = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(encodeAs, getAdvertisementType()); + + if (adv instanceof XMLDocument) { + ((XMLDocument) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + Element e; + + e = adv.createElement(handlernameTag, getHandlerName()); + adv.appendChild(e); + if (getCredential() != null) { + StructuredDocumentUtils.copyElements(adv, adv, getCredential()); + } + e = adv.createElement(queryIdTag, Integer.toString(queryid)); + adv.appendChild(e); + e = adv.createElement(hopCountTag, Integer.toString(hopcount)); + adv.appendChild(e); + + // FIXME tra 20031108 Since Peer Id is already part of the SrcRoute Tag. + // We should stop emitting this tag in the future. + if (null != getSrcPeer()) { + e = adv.createElement(srcPeerIdTag, getSrcPeer().toString()); + adv.appendChild(e); + } + + RouteAdvertisement radv = this.getSrcPeerRoute(); + + if (radv != null) { + e = adv.createElement(srcRouteTag); + adv.appendChild(e); + StructuredTextDocument xptDoc = (StructuredTextDocument)radv.getDocument(encodeAs); + StructuredDocumentUtils.copyElements(adv, e, xptDoc); + } + + e = adv.createElement(queryTag, getQuery()); + adv.appendChild(e); + return adv; + } + + /** + * {@inheritDoc} + *

            Result is the query as an XML string. + */ + @Override + public String toString() { + return getDocument(MimeMediaType.XMLUTF8).toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public ResolverQuery clone() { + ResolverQuery tmp; + + try { + tmp = (ResolverQuery) super.clone(); + } catch (CloneNotSupportedException e) { + throw new Error("Object.clone() threw CloneNotSupportedException", e); + } + + tmp.setHandlerName(getHandlerName()); + tmp.setCredential(getCredential()); + tmp.setSrcPeer(getSrcPeer()); + tmp.setQuery(getQuery()); + tmp.setQueryId(getQueryId()); + tmp.setHopCount(getHopCount()); + tmp.setSrcPeerRoute(getSrcPeerRoute()); + + return tmp; + } + + /** + * {@inheritDoc} + * + * @return ResolverResponse Msg + */ + @Override + public ResolverResponseMsg makeResponse() { + // construct a new response + ResolverResponse res = new ResolverResponse(); + + // transfer the query information + res.setHandlerName(this.getHandlerName()); + res.setQueryId(this.getQueryId()); + + // transfer optional route information available in the query + // to the response. + // + // NOTE: The route field is just attached to the response and + // will not be sent as part of the response. We just use this to + // pass information to the resolver. The other alternative will + // be to add a resolver or peergroup arg to makeResponse() as + // we don't have access to any peergroup info here to process + // the route information we just received. We will process + // the information just before we send the response. This + // may be better anyway as the service may never really respond. + res.setSrcPeerRoute(this.getSrcPeerRoute()); + + return res; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverResponse.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverResponse.java new file mode 100644 index 000000000..211d772ed --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverResponse.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.util.Enumeration; + +import net.jxta.document.*; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.RouteAdvertisement; + + +/** + * ResolverResponse provides an implementation for + * {@link net.jxta.protocol.ResolverResponseMsg} using the standard JXTA + * Peer Resolver Protocol. + * + *

            The message is implemented with the following schema: + * + *

            
            + * <xs:complexType name="ResolverResponse">
            + *   <xs:all>
            + *     <xs:element ref="jxta:Cred" minOccurs="0"/>
            + *     <xs:element name="HandlerName" type="xs:string"/>
            + *     <xs:element name="QueryID" type="xs:string"/>
            + *     <xs:element name="Response" type="xs:anyType"/>
            + *   </xs:all>
            + * </xs:complexType>
            + *
            + * + * @see JXTA Protocols Specification : Peer Resolver Protocol + */ +public class ResolverResponse extends ResolverResponseMsg { + + private static final String handlernameTag = "HandlerName"; + private static final String credentialTag = "jxta:Cred"; + private static final String queryIdTag = "QueryID"; + private static final String responseTag = "Response"; + + /** + * optional route information to send the response + */ + private RouteAdvertisement srcRoute = null; + + /** + * + * Standard Constructor for new instances. + */ + public ResolverResponse() {} + + /** + * Construct a doc from strings + * + * @deprecated use the individual accessor methods instead. + * @param HandlerName the handler name + * @param Credential the credential doc + * @param QueryId query ID + * @param Response the response + * + */ + @Deprecated + public ResolverResponse(String HandlerName, StructuredDocument Credential, int QueryId, String Response) { + setHandlerName(HandlerName); + setCredential(Credential); + setQueryId(QueryId); + setResponse(Response); + } + + /** + * Construct from a StructuredDocument + * + * @param root the element + */ + public ResolverResponse(Element root) { + + this(); + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + String doctype = doc.getName(); + + if (!getAdvertisementType().equals(doctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + + readIt(doc); + + // sanity check + if (null == getHandlerName()) { + throw new IllegalArgumentException("Response message does not contain a handler name"); + } + + if (null == getResponse()) { + throw new IllegalArgumentException("Response message does not contain a response"); + } + } + + public void readIt(TextElement doc) { + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + + if (elem.getName().equals(handlernameTag)) { + setHandlerName(elem.getTextValue()); + continue; + } + // Set credential + if (elem.getName().equals(credentialTag)) { + setCredential(StructuredDocumentUtils.copyAsDocument(elem)); + continue; + } + // Set queryid + if (elem.getName().equals(queryIdTag)) { + queryid = Integer.parseInt(elem.getTextValue()); + continue; + } + // Set response + if (elem.getName().equals(responseTag)) { + setResponse(elem.getTextValue()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType asMimeType) { + + StructuredTextDocument adv = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); + + if (adv instanceof Attributable) { + ((Attributable) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e; + + e = adv.createElement(handlernameTag, getHandlerName()); + adv.appendChild(e); + if (getCredential() != null) { + StructuredDocumentUtils.copyElements(adv, adv, getCredential()); + } + e = adv.createElement(queryIdTag, Integer.toString(queryid)); + adv.appendChild(e); + e = adv.createElement(responseTag, getResponse()); + adv.appendChild(e); + return adv; + } + + /** + * {@inheritDoc} + * + *

            Result is the response as an XML string. + */ + @Override + public String toString() { + return getDocument(MimeMediaType.XMLUTF8).toString(); + } + + /** + * Set optional route information as part of the response. + * This information is just attached to the response and + * will not be sent as part of the response + * + * @param route RouteAdvertisement to send the response + */ + + @Override + public void setSrcPeerRoute(RouteAdvertisement route) { + srcRoute = route; + } + + /** + * Get optional route information that may be attached to the + * response. This information is just attached to the response and will + * not be sent as part of the response + * + * @return RouteAdvertisement to send the response + */ + + @Override + public RouteAdvertisement getSrcPeerRoute() { + if (srcRoute != null) { + return srcRoute.clone(); + } else { + return null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverSrdiMsgImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverSrdiMsgImpl.java new file mode 100644 index 000000000..e061b8f04 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/ResolverSrdiMsgImpl.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.protocol; + + +import java.util.Enumeration; + +import net.jxta.credential.Credential; +import net.jxta.document.*; +import net.jxta.membership.MembershipService; +import net.jxta.protocol.ResolverSrdiMsg; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * ResolverQuery provides the binding for the message to query other nodes + */ +public class ResolverSrdiMsgImpl extends ResolverSrdiMsg { + + private final static Logger LOG = Logger.getLogger(ResolverSrdiMsgImpl.class.getName()); + + /** + * Description of the Field + */ + public final static String handlernameTag = "HandlerName"; + + /** + * Description of the Field + */ + public final static String credentialTag = "jxta:Cred"; + + /** + * Description of the Field + */ + public final static String payloadTag = "Payload"; + + /** + * Constructor for the ResolverSrdiMsgImpl object + */ + public ResolverSrdiMsgImpl() {} + + /** + * Construct from a StructuredDocument + * + * @param root the underlying document + * @param membership membership service used to verify credentials + */ + public ResolverSrdiMsgImpl(Element root, MembershipService membership) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + String doctype = doc.getName(); + + if (!getMessageType().equals(doctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doctype); + } + readIt(doc, membership); + } + + /** + * Creates this object with a specific handler name, credential and payload + * + * @param handlerName the + * @param cred the credntial + * @param payload the payload + */ + public ResolverSrdiMsgImpl(String handlerName, Credential cred, String payload) { + + setHandlerName(handlerName); + setPayload(payload); + setCredential(cred); + } + + /** + * return the string representaion of this doc + * + * @return string representation of the message + */ + @Override + public String toString() { + + StructuredTextDocument doc = (StructuredTextDocument) getDocument(MimeMediaType.XMLUTF8); + + return doc.toString(); + } + + /** + * return a Document represetation of this object + * + * @param asMimeType type of message + * @return document + */ + @Override + public Document getDocument(MimeMediaType asMimeType) { + StructuredTextDocument adv = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(asMimeType + , + getMessageType()); + + if (adv instanceof XMLElement) { + ((XMLElement) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e; + + e = adv.createElement(handlernameTag, getHandlerName()); + adv.appendChild(e); + if (getCredential() != null) { + try { + StructuredDocumentUtils.copyElements(adv, adv, (getCredential()).getDocument(asMimeType)); + } catch (Exception ce) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Got an Exception during credential creation ", ce); + } + } + } + e = adv.createElement(payloadTag, getPayload()); + adv.appendChild(e); + return adv; + } + + /** + * Parses an XML document into this object + * + * @param doc the underlying document + * @param membership used to parse credentails if any + */ + private void readIt(XMLElement doc, MembershipService membership) { + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (elem.getName().equals(handlernameTag)) { + setHandlerName(elem.getTextValue()); + continue; + } + // Set credential + if (elem.getName().equals(credentialTag)) { + Credential credential; + + if (elem.getTextValue() != null) { + try { + credential = membership.makeCredential(elem); + setCredential(credential); + } catch (Exception ce) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Credential creation failed", ce); + } + } + } + continue; + } + + // Set payload + if (elem.getName().equals(payloadTag)) { + setPayload(elem.getTextValue()); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteAdv.java new file mode 100644 index 000000000..fd233626a --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteAdv.java @@ -0,0 +1,332 @@ +/* +Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLElement; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class implements the basic Route advertisement. + *

            + *

            + *    <xs:complexType name="RA">
            + *      <xs:sequence>
            + *          <xs:element name="DstPID" type="jxta:JXTAID" minOccurs="0"/>
            + *          <xs:element name="Dst">
            + *              <xs:complexType>
            + *            <xs:sequence>
            + *                      <xs:element ref="jxta:APA" />
            + *            </xs:sequence>
            + *              </xs:complexType>
            + *        </xs:element>
            + *        <xs:element name="Hops" minOccurs="0">
            + *              <xs:complexType>
            + *            <xs:sequence>
            + *                      <xs:element ref="jxta:APA" maxOccurs="unbounded" />
            + *            </xs:sequence>
            + *              </xs:complexType>
            + *        </xs:element>
            + *      </xs:sequence>
            + *    </xs:complexType>
            + * 
            + * + * @see net.jxta.protocol.RouteAdvertisement + */ +public class RouteAdv extends RouteAdvertisement implements Cloneable { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(RouteAdv.class.getName()); + + private static final String[] INDEX_FIELDS = {DEST_PID_TAG}; + + /** + * Instantiator for our advertisement + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return RouteAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new RouteAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getAdvertisementType() + " only supports XLMElement"); + } + + return new RouteAdv((XMLElement) root); + } + } + + /** + * Private constructor. Use instantiator + */ + private RouteAdv() {} + + /** + * Private constructor. Use instantiator + * + * @param doc the element + */ + private RouteAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException("Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Compatibility hack + setDestPeerID(getDestPeerID()); + + // Sanity Check!!! + if (hasALoop()) { + throw new IllegalArgumentException("Route contains a loop!"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public RouteAdv clone() { + return (RouteAdv) super.clone(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (DEST_PID_TAG.equals(elem.getName())) { + try { + URI pID = new URI(elem.getTextValue()); + + setDestPeerID((PeerID) IDFactory.fromURI(pID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("ID in advertisement is not a peer id"); + } + return true; + } + + if ("Dst".equals(elem.getName())) { + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + XMLElement aXpt = (XMLElement) eachXpt.nextElement(); + + AccessPointAdvertisement xptAdv = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(aXpt); + + setDest(xptAdv); + } + return true; + } + + if ("Hops".equals(elem.getName())) { + Vector hops = new Vector(); + + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + XMLElement aXpt = (XMLElement) eachXpt.nextElement(); + + AccessPointAdvertisement xptAdv = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(aXpt); + + hops.addElement(xptAdv); + } + setHops(hops); + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (hasALoop()) { + throw new IllegalStateException("I won't write a doc for a route with a loop"); + } + + PeerID pid = getDestPeerID(); + + if (null != pid) { + Element e0 = adv.createElement(DEST_PID_TAG, pid.toString()); + + adv.appendChild(e0); + } + + Element e1 = adv.createElement("Dst"); + + adv.appendChild(e1); + + AccessPointAdvertisement dest = getDest(); + + // create a copy without the PID if necessary (the pid is redundant) + AccessPointAdvertisement destAPA = dest; + if(null != dest.getPeerID()) { + destAPA = dest.clone(); + destAPA.setPeerID(null); + } + + StructuredDocument xptDoc = (StructuredDocument) destAPA.getDocument(encodeAs); + StructuredDocumentUtils.copyElements(adv, e1, xptDoc); + + Enumeration eachHop = getHops(); + + // only include hops if we have some + if (eachHop.hasMoreElements()) { + Element e2 = adv.createElement("Hops"); + + adv.appendChild(e2); + + while (eachHop.hasMoreElements()) { + AccessPointAdvertisement hop = eachHop.nextElement(); + + if (null == hop.getPeerID()) { + // Refuse to write illegal hops. + continue; + } + + xptDoc = (StructuredDocument) hop.getDocument(encodeAs); + + StructuredDocumentUtils.copyElements(adv, e2, xptDoc); + } + } + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEX_FIELDS; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteQuery.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteQuery.java new file mode 100644 index 000000000..9afedf377 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteQuery.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.XMLElement; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.protocol.RouteQueryMsg; + +import java.lang.reflect.UndeclaredThrowableException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.Enumeration; +import net.jxta.document.XMLDocument; + +/** + * RouteQuery message used by the Endpoint Routing protocol to + * query for route + */ +public class RouteQuery extends RouteQueryMsg { + + private static final String destPIDTag = "Dst"; + private static final String srcRouteTag = "Src"; + private static final String badHopTag = "Bad"; + + /** + * Default Constructor + */ + public RouteQuery() {} + + /** + * Constructs a RouteQuery + * + * @deprecated Use default constructor and accessors. + * + * @param dest dest PeerID + * @param srcRoute source source + * @param badhops lis of AccessPointAdvertisements + */ + @Deprecated + public RouteQuery(PeerID dest, RouteAdvertisement srcRoute, Collection badhops) { + setDestPeerID(dest); + setSrcRoute(srcRoute); + setBadHops(badhops); + } + + /** + * Construct from an XML document fragment. + * + * @param doc the element + */ + public RouteQuery(XMLElement doc) { + String doctype = doc.getName(); + + if (!doctype.equals(getAdvertisementType())) { + throw new IllegalArgumentException( + "Can not construct : " + getClass().getName() + " from doc containing a " + doctype); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = elements.nextElement(); + + if (elem.getName().equals(destPIDTag)) { + try { + URI pID = new URI(elem.getTextValue()); + PeerID pid = (PeerID) IDFactory.fromURI(pID); + + setDestPeerID(pid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Not a peer id"); + } + continue; + } + + if (elem.getName().equals(srcRouteTag)) { + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + XMLElement aXpt = eachXpt.nextElement(); + + RouteAdvertisement route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(aXpt); + + setSrcRoute(route); + } + continue; + } + + if (elem.getName().equals(badHopTag)) { + try { + URI pID = new URI(elem.getTextValue()); + PeerID pid = (PeerID) IDFactory.fromURI(pID); + + addBadHop(pid); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Bad PeerID ID in advertisement"); + } catch (ClassCastException badID) { + throw new IllegalArgumentException("Not a peer id"); + } + } + } + + if(null == getDestPeerID()) { + throw new IllegalArgumentException("Destination peer not initialized"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public StructuredDocument getDocument(MimeMediaType asMimeType) { + if(null == getDestPeerID()) { + throw new IllegalStateException("Destination peer not initialized"); + } + + StructuredDocument adv = StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); + + if (adv instanceof XMLElement) { + ((Attributable) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) adv).addAttribute("xml:space", "preserve"); + } + + Element e; + + PeerID dest = getDestPeerID(); + + e = adv.createElement(destPIDTag, dest.toString()); + adv.appendChild(e); + + RouteAdvertisement route = getSrcRoute(); + + if (route != null) { + e = adv.createElement(srcRouteTag); + adv.appendChild(e); + StructuredDocument xptDoc = (StructuredDocument) route.getDocument(asMimeType); + + StructuredDocumentUtils.copyElements(adv, e, xptDoc); + } + + for (PeerID eachPeer : getBadHops()) { + e = adv.createElement(badHopTag, eachPeer.toString()); + adv.appendChild(e); + } + + return adv; + } + + /** + * return a string representation of this RouteQuery doc + */ + @Override + public String toString() { + XMLDocument doc = (XMLDocument) getDocument(MimeMediaType.XMLUTF8); + + doc.addAttribute("xml:space", "default"); + + return doc.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteResponse.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteResponse.java new file mode 100644 index 000000000..22a60fe14 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/RouteResponse.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.protocol.RouteResponseMsg; + +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Enumeration; + + +/** + * Used by the Endpoint Routing protocol in response to Route Query Messages. + * The Route Response Message contains a route advertisement for the destination + * peer. + *

            + *

            + * <xs:complexType name="ERR">
            + *   <xs:sequence>
            + *     <xs:element name="Dst">
            + *       <xs:complexType>
            + *         <xs:sequence>
            + *           <xs:element ref="jxta:RA" />
            + *         </xs:sequence>
            + *       </xs:complexType>
            + *     </xs:element>
            + *     <xs:element name="Src">
            + *       <xs:complexType>
            + *         <xs:sequence>
            + *           <xs:element ref="jxta:RA" />
            + *         </xs:sequence>
            + *       </xs:complexType>
            + *     </xs:element>
            + *   </xs:sequence>
            + * </xs:complexType>
            + * 
            + * + * @see net.jxta.impl.endpoint.router.EndpointRouter + * @see JXTA Protocols Specification : Endpoint Routing Protocol + */ +public class RouteResponse extends RouteResponseMsg { + + private static final String destRouteTag = "Dst"; + private static final String srcRouteTag = "Src"; + + /** + * Construct a new Route Response Message + */ + public RouteResponse() {} + + /** + * Construct from an XML document fragment. + * + * @param doc the element + */ + public RouteResponse(XMLElement doc) { + + String doctype = doc.getName(); + + if (!doctype.equals(getAdvertisementType())) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + " from doc containing a " + doctype); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = elements.nextElement(); + + if (elem.getName().equals(destRouteTag)) { + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + XMLElement aXpt = eachXpt.nextElement(); + + RouteAdvertisement route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(aXpt); + + setDestRoute(route); + } + continue; + } + + if (elem.getName().equals(srcRouteTag)) { + for (Enumeration eachXpt = elem.getChildren(); eachXpt.hasMoreElements();) { + XMLElement aXpt = eachXpt.nextElement(); + + RouteAdvertisement route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(aXpt); + + setSrcRoute(route); + } + } + } + + // Validate. + + if (null == getSrcRoute()) { + throw new IllegalArgumentException("Missing source route."); + } + + if (null == getDestRoute()) { + throw new IllegalArgumentException("Missing destination route."); + } + + if (null == getSrcRoute().getDestPeerID()) { + throw new IllegalArgumentException("Bad source route."); + } + + if (null == getDestRoute().getDestPeerID()) { + throw new IllegalArgumentException("Bad destination route."); + } + } + + /** + * return a Document representation of this object + */ + @Override + public Document getDocument(MimeMediaType asMimeType) { + if (null == getSrcRoute()) { + throw new IllegalStateException("Missing source route."); + } + + if (null == getDestRoute()) { + throw new IllegalStateException("Missing destination route."); + } + + if (null == getSrcRoute().getDestPeerID()) { + throw new IllegalStateException("Bad source route."); + } + + if (null == getDestRoute().getDestPeerID()) { + throw new IllegalStateException("Bad destination route."); + } + + StructuredDocument adv = StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); + + if (adv instanceof XMLDocument) { + ((XMLDocument) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + ((XMLDocument) adv).addAttribute("xml:space", "preserve"); + } + + Element e; + + RouteAdvertisement route = getDestRoute(); + + if (route != null) { + e = adv.createElement(destRouteTag); + adv.appendChild(e); + StructuredTextDocument xptDoc = (StructuredTextDocument) + route.getDocument(asMimeType); + + StructuredDocumentUtils.copyElements(adv, e, xptDoc); + } + + route = getSrcRoute(); + if (route != null) { + e = adv.createElement(srcRouteTag); + adv.appendChild(e); + StructuredTextDocument xptDoc = (StructuredTextDocument) + route.getDocument(asMimeType); + + StructuredDocumentUtils.copyElements(adv, e, xptDoc); + } + return adv; + } + + /** + * {@inheritDoc} + * + *

            String representation of this RouteResponse doc. + */ + @Override + public String toString() { + XMLDocument doc = (XMLDocument) getDocument(MimeMediaType.XMLUTF8); + + doc.addAttribute("xml:space", "default"); + + return doc.toString(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/SignedAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/SignedAdv.java new file mode 100644 index 000000000..b37fc0fc9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/SignedAdv.java @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.ID; +import net.jxta.impl.membership.pse.PSECredential; +import net.jxta.impl.util.BASE64InputStream; +import net.jxta.impl.util.BASE64OutputStream; +import net.jxta.protocol.SignedAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.*; +import java.lang.reflect.UndeclaredThrowableException; +import java.security.Signature; +import java.util.Enumeration; + + +/** + * A container for signed Advertisements + */ +public class SignedAdv extends SignedAdvertisement { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(SignedAdv.class.getName()); + + private static final String ADV_TYPE = "jxta:SA"; + + private static final String[] INDEX_FIELDS = {}; + + /** + * Instantiator for SignedAdv + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return ADV_TYPE; + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new SignedAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + return new SignedAdv((XMLElement) root); + } + } + + private byte[] signature = null; + + /** + * Returns the identifying type of this Advertisement. + *

            + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + *

            + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertisement.getAdvertisementType() no matter what the real type of the + * advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return ADV_TYPE; + } + + /** + * Private constructor for new instances. Use the instantiator. + */ + private SignedAdv() { + } + + /** + * Private constructor for xml serialized instances. Use the instantiator. + * + * @param doc The XML serialization of the advertisement. + */ + private SignedAdv(XMLElement doc) { + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + Element elem = (Element) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEX_FIELDS; + } + + /** + * {@inheritDoc} + */ + @Override + public net.jxta.id.ID getID() { + // FIXME bondolo Needs real implementation. + return ID.nullID; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if ("Credential".equals(elem.getName())) { + signer = new PSECredential(elem); + + return true; + } else if ("Signature".equals(elem.getName())) { + try { + Reader signatureB64 = new StringReader(elem.getTextValue()); + InputStream bis = new BASE64InputStream(signatureB64); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + do { + int c = bis.read(); + + if (-1 == c) { + break; + } + bos.write(c); + } while (true); + + bis.close(); + bos.close(); + signature = bos.toByteArray(); + + return true; + } catch (IOException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Could not process Signature"); + + failure.initCause(failed); + + throw failure; + } + } else if ("Advertisement".equals(elem.getName())) { + try { + Reader advertisementB64 = new StringReader(elem.getTextValue()); + InputStream bis = new BASE64InputStream(advertisementB64); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + do { + int c = bis.read(); + + if (-1 == c) { + break; + } + bos.write(c); + } while (true); + + byte advbytes[] = bos.toByteArray(); + + Signature verifier = ((PSECredential) signer).getSignatureVerifier("SHA1WITHRSA"); + + verifier.update(advbytes); + + boolean matched = verifier.verify(signature); + + if (!matched) { + throw new IllegalArgumentException("Advertisement could not be verified"); + } + + advertisementB64 = new StringReader(elem.getTextValue()); + bis = new BASE64InputStream(advertisementB64); + + adv = AdvertisementFactory.newAdvertisement(elem.getRoot().getMimeType(), bis); + + return true; + } catch (IOException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Could not process Advertisement"); + + failure.initCause(failed); + + throw failure; + } catch (java.security.NoSuchAlgorithmException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Could not process Advertisement"); + + failure.initCause(failed); + + throw failure; + } catch (java.security.SignatureException failed) { + IllegalArgumentException failure = new IllegalArgumentException("Could not process Advertisement"); + + failure.initCause(failed); + + throw failure; + } + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + + if (null == adv) { + throw new IllegalStateException("Advertisement not initialized"); + } + + if (null == signer) { + throw new IllegalStateException("Signer Credential not initialized"); + } + + if (!(signer instanceof PSECredential)) { + throw new IllegalStateException("Signer Credential not initialized"); + } + + StructuredDocument doc = (StructuredDocument) super.getDocument(encodeAs); + + StructuredDocument advDoc = (StructuredDocument) adv.getDocument(encodeAs); + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + advDoc.sendToStream(bos); + bos.close(); + + byte advData[] = bos.toByteArray(); + + PSECredential psecred = (PSECredential) signer; + + Signature advSigner = psecred.getSigner("SHA1WITHRSA"); + + advSigner.update(advData); + + byte signature[] = advSigner.sign(); + + StringWriter signatureB64 = new StringWriter(); + StringWriter advertisementB64 = new StringWriter(); + + OutputStream signatureOut = new BASE64OutputStream(signatureB64); + + signatureOut.write(signature); + signatureOut.close(); + + OutputStream advertisementOut = new BASE64OutputStream(advertisementB64, 72); + + advertisementOut.write(advData); + advertisementOut.close(); + + StructuredDocument creddoc = signer.getDocument(encodeAs); + + StructuredDocumentUtils.copyElements(doc, doc, creddoc, "Credential"); + + Element elem = doc.createElement("Signature", signatureB64.toString()); + + doc.appendChild(elem); + + elem = doc.createElement("Advertisement", advertisementB64.toString()); + doc.appendChild(elem); + if (doc instanceof Attributable) { + ((Attributable) elem).addAttribute("type", adv.getAdvType()); + } + } catch (Exception failed) { + if (failed instanceof RuntimeException) { + throw (RuntimeException) failed; + } else { + throw new UndeclaredThrowableException(failed, "Failure building document"); + } + } + + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/SrdiMessageImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/SrdiMessageImpl.java new file mode 100644 index 000000000..7e890e7ae --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/SrdiMessageImpl.java @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import net.jxta.document.*; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.protocol.SrdiMessage; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + + +/** + * SrdiMessageImpl provides the SRDI message binding + */ +public class SrdiMessageImpl extends SrdiMessage { + + /** + * The Log4J debugging category. + */ + private final static Logger LOG = Logger.getLogger(SrdiMessageImpl.class.getName()); + + /** + * PeerID element name + */ + public final static String pidTag = "PID"; + + /** + * scope element name + */ + public final static String scopeTag = "ttl"; + + /** + * Entry element name + */ + public final static String entryTag = "Entry"; + + /** + * Primary Key element name + */ + public final static String pKeyTag = "PKey"; + + /** + * Secondary Key element name + */ + public final static String sKeyTag = "SKey"; + + /** + * Value element name + */ + public final static String valTag = "Value"; + + /** + * Expiration element name + */ + public final static String expirationTag = "Expiration"; + + /** + * Construct an empty doc + */ + public SrdiMessageImpl() { + setScope(PERSISTONLY); + } + + /** + * Construct a doc from InputStream + * + * @param stream the underlying input stream. + * @throws IOException if an I/O error occurs. + * @deprecated It's better to generate the document yourself. This method + * cannot deduce the mime type of the content. + */ + @Deprecated + public SrdiMessageImpl(InputStream stream) throws IOException { + + // We are asked to assume that the message from which this response + // is constructed is an XML document. + XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, stream); + + readIt(doc); + } + + /** + * Construct from a StructuredDocument + * + * @param root the underlying document + */ + public SrdiMessageImpl(Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getMessageType()) && !getMessageType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + readIt(doc); + } + + /** + * Construct a msg from entries + * + * @param peerid PeerID associated with this message + * @param scope scope @see #PERSISTONLY, #REPLICATE + * @param pKey primary key + * @param entries the entries for this message + */ + public SrdiMessageImpl(PeerID peerid, int scope, String pKey, List entries) { + + setPeerID(peerid); + setScope(scope); + setPrimaryKey(pKey); + setEntries(entries); + } + + /** + * Construct a msg consisting of a single entry + * + * @param peerid PeerID associated with this message + * @param scope scope @see #PERSISTONLY, #REPLICATE + * @param pKey primary key + * @param key the secondary key + * @param value value for the key + * @param expiration expirations for this entry + */ + public SrdiMessageImpl(PeerID peerid, int scope, String pKey, String key, String value, long expiration) { + + setPeerID(peerid); + setScope(scope); + setPrimaryKey(pKey); + addEntry(key, value, expiration); + } + + /** + * Construct a doc from vectors of strings + * + * @param peerid PeerID associated with this message + * @param scope scope @see #PERSISTONLY, #REPLICATE + * @param pKey primary key + * @param entries the entries for this message + */ + public SrdiMessageImpl(String peerid, int scope, String pKey, List entries) { + + PeerID pid; + + try { + pid = (PeerID) IDFactory.fromURI(new URI(peerid)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Invalid PeerID ID in message"); + } + + setPeerID(pid); + setScope(scope); + setPrimaryKey(pKey); + setEntries(entries); + } + + /** + * @param doc the element + */ + public void readIt(XMLElement doc) { + + String key; + String value; + long expiration; + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (elem.getName().equals(pidTag)) { + try { + URI pID = new URI(elem.getTextValue()); + + setPeerID((PeerID) IDFactory.fromURI(pID)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("Invalid PeerID ID in message"); + } + continue; + } + if (elem.getName().equals(pKeyTag)) { + setPrimaryKey(elem.getTextValue()); + } + if (elem.getName().equals(scopeTag)) { + setScope(Integer.parseInt(elem.getTextValue())); + } + + if (elem.getName().equals(entryTag)) { + Attribute keyEl = elem.getAttribute(sKeyTag); + + if (keyEl == null) { + key = "NA"; + } else { + key = keyEl.getValue(); + } + + value = elem.getTextValue(); + if (null != value) { + Attribute expAttr = elem.getAttribute(expirationTag); + + if (expAttr != null) { + String expstr = expAttr.getValue(); + + expiration = Long.parseLong(expstr); + } else { + expiration = -1; + } + SrdiMessage.Entry entry = new SrdiMessage.Entry(key, value, expiration); + + addEntry(entry); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SrdiMessage Entry with a Null value"); + } + } + } + } + } + + /** + * return a Document representation of this object + * + * @param encodeAs the mime type encoding + * @return document represtation of this object + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + + StructuredTextDocument adv = (StructuredTextDocument) + StructuredDocumentFactory.newStructuredDocument(encodeAs, getMessageType()); + + if (adv instanceof Attributable) { + ((Attributable) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + + Element e; + Iterator eachEntry = getEntries().iterator(); + PeerID peerid = getPeerID(); + + if (peerid != null) { + e = adv.createElement(pidTag, peerid.toString()); + adv.appendChild(e); + } + if (getPrimaryKey() != null) { + e = adv.createElement(pKeyTag, getPrimaryKey()); + adv.appendChild(e); + } + if (getScope() > 0) { + e = adv.createElement(scopeTag, Integer.toString(getScope())); + adv.appendChild(e); + } + + while (eachEntry.hasNext()) { + SrdiMessage.Entry entry = (SrdiMessage.Entry) eachEntry.next(); + + if (entry.key == null && entry.value == null) { + // skip bad entries + continue; + } + e = adv.createElement(entryTag, entry.value); + adv.appendChild(e); + ((Attributable) e).addAttribute(expirationTag, Long.toString(entry.expiration)); + ((Attributable) e).addAttribute(sKeyTag, entry.key); + } + return adv; + } + + /** + * returns the document string representation of this object + * + * @return String representation of the of this message type + */ + @Override + public String toString() { + StructuredTextDocument doc = (StructuredTextDocument) getDocument(MimeMediaType.XMLUTF8); + + return doc.toString(); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/TCPAdv.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/TCPAdv.java new file mode 100644 index 000000000..cd15ebad7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/TCPAdv.java @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.protocol; + + +import java.util.Arrays; +import java.util.Enumeration; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.XMLElement; +import net.jxta.protocol.TransportAdvertisement; + + +/** + * Provides configuration parameters for the JXTA TCP Message Transport. + */ +public class TCPAdv extends TransportAdvertisement { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(TCPAdv.class.getName()); + + private static final String CONFIGMODES[] = { "auto", "manual" }; + private static final String INDEXFIELDS[] = {/* none */}; + + private static final String PORT_ELEMENT = "Port"; + private static final String ClientOffTag = "ClientOff"; + private static final String ServerOffTag = "ServerOff"; + private static final String MULTICAST_OFF_TAG = "MulticastOff"; + private static final String FlagsTag = "Flags"; + private static final String PublicAddressOnlyAttr = "PublicAddressOnly"; + + private String configMode = CONFIGMODES[0]; + private String interfaceAddress = null; + private int startPort = -1; + private int listenPort = -1; + private int endPort = -1; + private String publicAddress = null; + private String multicastaddr = null; + private int multicastport = -1; + private int multicastsize = -1; + private boolean clientEnabled = true; + private boolean serverEnabled = true; + private boolean multicastEnabled = true; + private boolean publicAddressOnly = false; + + /** + * Our instantiator + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * {@inheritDoc} + */ + public String getAdvertisementType() { + return TCPAdv.getAdvertisementType(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance() { + return new TCPAdv(); + } + + /** + * {@inheritDoc} + */ + public Advertisement newInstance(net.jxta.document.Element root) { + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + return new TCPAdv((XMLElement) root); + } + } + + /** + * Returns the identifying type of this Advertisement. + * + *

            Note: This is a static method. It cannot be used to determine + * the runtime type of an advertisement. ie. + *

            +     *      Advertisement adv = module.getSomeAdv();
            +     *      String advType = adv.getAdvertisementType();
            +     *  
            + * + *

            This is wrong and does not work the way you might expect. + * This call is not polymorphic and calls + * Advertisement.getAdvertisementType() no matter what the real type of the + * advertisement. + * + * @return String the type of advertisement + */ + public static String getAdvertisementType() { + return "jxta:TCPTransportAdvertisement"; + } + + private TCPAdv() { + setProtocol("tcp"); + } + + private TCPAdv(XMLElement doc) { + this(); + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(getAdvertisementType()) && !getAdvertisementType().equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Attribute attr = doc.getAttribute(FlagsTag); + + if (attr != null) { + String options = attr.getValue(); + + publicAddressOnly = (options.indexOf(PublicAddressOnlyAttr) != -1); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unhandled Element: " + elem); + } + } + } + + // Sanity Check!!! + if (!Arrays.asList(CONFIGMODES).contains(configMode)) { + throw new IllegalArgumentException("Unsupported configuration mode."); + } + + if ((listenPort < -1) || (listenPort > 65535)) { + throw new IllegalArgumentException("Illegal Listen Port Value"); + } + + if ((startPort < -1) || (startPort > 65535)) { + throw new IllegalArgumentException("Illegal Start Port Value"); + } + + if ((endPort < -1) || (endPort > 65535)) { + throw new IllegalArgumentException("Illegal End Port Value"); + } + + if ((0 == startPort) && (endPort != 0) || (0 != startPort) && (endPort == 0)) { + throw new IllegalArgumentException("Port ranges must both be 0 or non-0"); + } + + if ((-1 == startPort) && (endPort != -1) || (-1 != startPort) && (endPort == -1)) { + throw new IllegalArgumentException("Port ranges must both be -1 or not -1"); + } + + if ((null != publicAddress) && ((-1 != startPort) || (listenPort <= 0))) { + throw new IllegalArgumentException("Dynamic ports not supported with public address port forwarding."); + } + + if (getMulticastState() && (null == getMulticastAddr())) { + throw new IllegalArgumentException("Multicast enabled and no address specified."); + } + + if (getMulticastState() && (-1 == getMulticastPort())) { + throw new IllegalArgumentException("Multicast enabled and no port specified."); + } + + if (getMulticastState() && ((getMulticastPort() <= 0) || (getMulticastPort() > 65536))) { + throw new IllegalArgumentException("Illegal Multicast Port Value"); + } + + if (getMulticastState() && (-1 == getMulticastSize())) { + throw new IllegalArgumentException("Multicast enabled and no size specified."); + } + + if (getMulticastState() && ((getMulticastSize() <= 0) || (getMulticastSize() > 1048575L))) { + throw new IllegalArgumentException("Illegal Multicast datagram size"); + } + + // XXX 20050118 bondolo Some versions apparently don't initialize this field. Eventually make it required. + if (null == getProtocol()) { + setProtocol("tcp"); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getAdvType() { + return getAdvertisementType(); + } + + /** + * Returns the interface which the TCP transport will use. + * + * @return The interface to use. May be a DNS name or an IP Address. + */ + public String getInterfaceAddress() { + return interfaceAddress; + } + + /** + * Sets the interface which the TCP transport will use. + * + * @param ia The interface to use. May be a DNS name or an IP Address. + */ + public void setInterfaceAddress(String ia) { + if (null != ia) { + ia = ia.trim(); + + if (0 == ia.length()) { + ia = null; + } + } + + this.interfaceAddress = ia; + } + + /** + * Returns the port on which the TCP Transport will listen if configured to + * do so. If a port range is specified then this the preference. Valid + * values are -1, 0 and 1-65535. + * The -1 value is used to signify that there is no port + * preference and any port in range will be used. The 0 + * specifies that the Socket API dynamic port allocation should be used. + * For values 1-65535 the value specifies the required port on + * which the TCP transport will listen. + * + * @return the port + */ + public int getPort() { + return listenPort; + } + + /** + * Sets the port on which the TCP Transport will listen if configured to + * do so. If a port range is specified then this the preference. Valid + * values are -1, 0 and 1-65535. + * The -1 value is used to signify that there is no port + * preference and any port in range will be used. The 0 + * specifies that the Socket API dynamic port allocation should be used. + * For values 1-65535 the value specifies the required port on + * which the TCP transport will listen. + * + * @param port the port on which to listen. + */ + public void setPort(int port) { + listenPort = port; + } + + /** + * Return the lowest port on which the TCP Transport will listen if + * configured to do so. Valid values are -1, 0 and + * 1-65535. The -1 value is used to signify that + * the port range feature should be disabled. The 0 specifies + * that the Socket API dynamic port allocation should be used. For values + * 1-65535 the value must be equal to or less than the value + * used for end port. + * + * @return the lowest port on which to listen. + */ + public int getStartPort() { + return startPort; + } + + /** + * Sets the lowest port on which the TCP Transport will listen if configured + * to do so. Valid values are -1, 0 and + * 1-65535. The -1 value is used to signify that + * the port range feature should be disabled. The 0 specifies + * that the Socket API dynamic port allocation should be used. For values + * 1-65535 the value must be equal to or less than the value + * used for end port. + * + * @param start the lowest port on which to listen. + */ + public void setStartPort(int start) { + startPort = start; + } + + /** + * Return the highest port on which the TCP Transport will listen if + * configured to do so. Valid values are -1, 0 and + * 1-65535. The -1 value is used to signify that + * the port range feature should be disabled. The 0 specifies + * that the Socket API dynamic port allocation should be used. For values + * 1-65535 the value must be equal to or greater than the value + * used for start port. + * + * @return the highest port on which to listen. + */ + public int getEndPort() { + return endPort; + } + + /** + * Sets the highest port on which the TCP Transport will listen if + * configured to do so. Valid values are -1, 0 and + * 1-65535. The -1 value is used to signify that + * the port range feature should be disabled. The 0 specifies + * that the Socket API dynamic port allocation should be used. For values + * 1-65535 the value must be equal to or greater than the value + * used for start port. + * + * @param end the highest port on which to listen. + */ + public void setEndPort(int end) { + endPort = end; + } + + /** + * Determine whether multicast if off or not + * + * @return boolean current multicast state + */ + public boolean getMulticastState() { + return multicastEnabled; + } + + /** + * Enable or disable multicast. + * + * @param newState the desired state. + */ + public void setMulticastState(boolean newState) { + multicastEnabled = newState; + } + + /** + * returns the multicastaddr + * + * @return string multicastaddr + */ + public String getMulticastAddr() { + return multicastaddr; + } + + /** + * set the multicastaddr + * + * @param multicastaddr set multicastaddr + */ + public void setMulticastAddr(String multicastaddr) { + if (null != multicastaddr) { + multicastaddr = multicastaddr.trim(); + + if (0 == multicastaddr.length()) { + multicastaddr = null; + } + } + + this.multicastaddr = multicastaddr; + } + + /** + * returns the multicastport + * + * @return string multicastport + */ + public int getMulticastPort() { + return multicastport; + } + + /** + * set the multicastport + * @param multicastport set multicastport + */ + public void setMulticastPort(int multicastport) { + this.multicastport = multicastport; + } + + /** + * returns the multicastsize + * + * @return integer containting the multicast size + */ + public int getMulticastSize() { + return multicastsize; + } + + /** + * set the multicastsize + * + * @param multicastsize set multicast size + */ + public void setMulticastSize(int multicastsize) { + this.multicastsize = multicastsize; + } + + /** + * Returns the public address + * + * @return string public address + */ + public String getServer() { + return publicAddress; + } + + /** + * Set the public address. That is, a the address of a server socket + * to connect to from the outside. Argument is in the form host:port + * + * @param address address + */ + public void setServer(String address) { + if (null != address) { + address = address.trim(); + + if (0 == address.length()) { + address = null; + } + } + + this.publicAddress = address; + } + + /** + * Returns the configuration for outbound connections. + * + * @return true if outbound connections are allowed otherwise + * false + */ + public boolean isClientEnabled() { + return clientEnabled; + } + + /** + * Sets the configuration for outbound connections. + * + * @param enabled true if outbound connections are allowed otherwise + * false + */ + public void setClientEnabled(boolean enabled) { + clientEnabled = enabled; + } + + /** + * Returns the configuration for inbound connections. + * + * @return true if inbound connections are allowed otherwise + * false + */ + public boolean isServerEnabled() { + return serverEnabled; + } + + /** + * Sets the configuration for inbound connections. + * + * @param enabled true if inbound connections are allowed otherwise + * false + */ + public void setServerEnabled(boolean enabled) { + serverEnabled = enabled; + } + + /** + * returns the config mode. That is, how the user prefers to configure + * the interface address: "auto", "manual" + * + * @return string config mode + */ + public String getConfigMode() { + return configMode; + } + + /** + * set the config mode. That is, how the user prefers to configure + * the interface address: "auto", "manual" + * + * This is just a pure config item. It is never in published advs. The TCP + * transport strips it when it initializes. + * + * @param mode Can be "auto", "manual" other settings will act as the default + * which is "auto". + */ + public void setConfigMode(String mode) { + if (!Arrays.asList(CONFIGMODES).contains(mode)) { + throw new IllegalArgumentException("Unsupported configuration mode."); + } + + configMode = mode; + } + + /** + * Returns the state of whether to only use public address + * @return boolean true if set to use "Public Address Only" + */ + public boolean getPublicAddressOnly() { + return publicAddressOnly; + } + + /** + * Sets the state of whether to only use public address + * @param only true to use "Public Address Only" + */ + public void setPublicAddressOnly(boolean only) { + publicAddressOnly = only; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean handleElement(Element raw) { + + if (super.handleElement(raw)) { + return true; + } + + XMLElement elem = (XMLElement) raw; + + if (elem.getName().equals(MULTICAST_OFF_TAG)) { + setMulticastState(false); + return true; + } + + if (elem.getName().equals(ClientOffTag)) { + setClientEnabled(false); + return true; + } + + if (elem.getName().equals(ServerOffTag)) { + setServerEnabled(false); + return true; + } + + String value = elem.getTextValue(); + + if ((null == value) || (0 == value.trim().length())) { + return false; + } + + value = value.trim(); + + if (elem.getName().equals("Protocol")) { + setProtocol(value); + return true; + } + + if (PORT_ELEMENT.equals(elem.getName())) { + try { + setPort(Integer.parseInt(value)); + Attribute startAttr = elem.getAttribute("start"); + Attribute endAttr = elem.getAttribute("end"); + + if ((null != startAttr) && (null != endAttr)) { + setStartPort(Integer.parseInt(startAttr.getValue().trim())); + setEndPort(Integer.parseInt(endAttr.getValue().trim())); + } + } catch (NumberFormatException badPort) { + throw new IllegalArgumentException("Illegal port value : " + value); + } + return true; + } + + if (elem.getName().equals("MulticastAddr")) { + setMulticastAddr(value); + return true; + } + + if (elem.getName().equals("MulticastPort")) { + try { + setMulticastPort(Integer.parseInt(value)); + } catch (NumberFormatException badPort) { + throw new IllegalArgumentException("Illegal multicast port value : " + value); + } + return true; + } + + if (elem.getName().equals("MulticastSize")) { + try { + int theMulticastSize = Integer.parseInt(value); + + setMulticastSize(theMulticastSize); + } catch (NumberFormatException badPort) { + throw new IllegalArgumentException("Illegal multicast datagram size : " + value); + } + return true; + } + + if (elem.getName().equals("Server")) { + setServer(value); + return true; + } + + if (elem.getName().equals("InterfaceAddress")) { + setInterfaceAddress(value); + return true; + } + + if (elem.getName().equals("ConfigMode")) { + setConfigMode(value); + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Document getDocument(MimeMediaType encodeAs) { + StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); + + if (!(adv instanceof Attributable)) { + throw new IllegalStateException("Only Attributable document types allowed."); + } + + // XXX 20050118 bondolo Some versions apparently don't initialize this field. Eventually make it required. + if (null == getProtocol()) { + setProtocol("tcp"); + } + + if ((listenPort < -1) || (listenPort > 65535)) { + throw new IllegalStateException("Illegal Listen Port Value"); + } + + if ((startPort < -1) || (startPort > 65535)) { + throw new IllegalStateException("Illegal Start Port Value"); + } + + if ((endPort < -1) || (endPort > 65535)) { + throw new IllegalStateException("Illegal End Port Value"); + } + + if ((0 == startPort) && (endPort != 0) || (0 != startPort) && (endPort == 0)) { + throw new IllegalStateException("Port ranges must both be 0 or non-0"); + } + + if ((-1 == startPort) && (endPort != -1) || (-1 != startPort) && (endPort == -1)) { + throw new IllegalStateException("Port ranges must both be -1 or not -1"); + } + + if ((null != publicAddress) && ((-1 != startPort) || (listenPort <= 0))) { + throw new IllegalStateException("Dynamic ports not supported with public address port forwarding."); + } + + if (getMulticastState() && (null == getMulticastAddr())) { + throw new IllegalStateException("Multicast enabled and no address specified."); + } + + if (getMulticastState() && (-1 == getMulticastPort())) { + throw new IllegalStateException("Multicast enabled and no port specified."); + } + + if (getMulticastState() && ((getMulticastPort() <= 0) || (getMulticastPort() > 65536))) { + throw new IllegalStateException("Illegal Multicast Port Value"); + } + + if (getMulticastState() && (-1 == getMulticastSize())) { + throw new IllegalStateException("Multicast enabled and no size specified."); + } + + if (getMulticastState() && ((getMulticastSize() <= 0) || (getMulticastSize() > 1048575L))) { + throw new IllegalStateException("Illegal Multicast datagram size"); + } + + if (adv instanceof Attributable) { + // Only one flag for now. Easy. + if (publicAddressOnly) { + ((Attributable) adv).addAttribute(FlagsTag, PublicAddressOnlyAttr); + } + } + + Element e11 = adv.createElement("Protocol", getProtocol()); + + adv.appendChild(e11); + + if (!isClientEnabled()) { + Element e19 = adv.createElement(ClientOffTag); + + adv.appendChild(e19); + } + + if (!isServerEnabled()) { + Element e20 = adv.createElement(ServerOffTag); + + adv.appendChild(e20); + } + + if (getConfigMode() != null) { + Element e18 = adv.createElement("ConfigMode", getConfigMode()); + + adv.appendChild(e18); + } + + String interfaceAddr = getInterfaceAddress(); + + if (null != interfaceAddr) { + Element e17 = adv.createElement("InterfaceAddress", interfaceAddr); + + adv.appendChild(e17); + } + + Element e12 = adv.createElement(PORT_ELEMENT, Integer.toString(listenPort)); + + adv.appendChild(e12); + if (adv instanceof Attributable) { + Attributable attrElem = (Attributable) e12; + + if ((-1 != startPort) && (-1 != endPort)) { + attrElem.addAttribute("start", Integer.toString(startPort)); + attrElem.addAttribute("end", Integer.toString(endPort)); + } + } + + String serverAddr = getServer(); + + if (null != serverAddr) { + Element e16 = adv.createElement("Server", serverAddr); + + adv.appendChild(e16); + } + + if (!getMulticastState()) { + Element e19 = adv.createElement(MULTICAST_OFF_TAG); + + adv.appendChild(e19); + } + + if (null != getMulticastAddr()) { + Element e13 = adv.createElement("MulticastAddr", getMulticastAddr()); + + adv.appendChild(e13); + } + + if (-1 != getMulticastPort()) { + Element e14 = adv.createElement("MulticastPort", Integer.toString(getMulticastPort())); + + adv.appendChild(e14); + } + + if (-1 != getMulticastSize()) { + Element e15 = adv.createElement("MulticastSize", Integer.toString(getMulticastSize())); + + adv.appendChild(e15); + } + + return adv; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getIndexFields() { + return INDEXFIELDS; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/package.html new file mode 100644 index 000000000..9574bd1c2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/protocol/package.html @@ -0,0 +1,19 @@ + + + + + + + Provides implementation objects for Advertisments and protocol messages for + the JXTA + Core + and + Standard + Protocols. These classes are responsible for serializing and deserializing + messages and advertisements. + + @see net.jxta.document.Advertisement + @see JXTA Protocols Specification - Overview : Advertisements + @see JXTA Protocols Specification - Advertisements + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/proxy/ProxyService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/proxy/ProxyService.java new file mode 100644 index 000000000..81e1cd9fe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/proxy/ProxyService.java @@ -0,0 +1,1191 @@ +/* + * Copyright (c) 2005-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.proxy; + +import net.jxta.discovery.DiscoveryEvent; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.exception.PeerGroupException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.util.Cache; +import net.jxta.impl.util.CacheEntry; +import net.jxta.impl.util.CacheEntryListener; +import net.jxta.impl.util.LRUCache; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.OutputPipeEvent; +import net.jxta.pipe.OutputPipeListener; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.DiscoveryResponseMsg; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.service.Service; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.TreeMap; + +import net.jxta.platform.Module; + + +// FIXME: jice@jxta.org - 20020515 +// All public methods are synchronized. +// None of them does anything blocking so that should be about OK, however +// first it is not 100% sure, second eventhough non-blocking, some of these +// operations could take a significant amount of time, which may be unfair +// to other threads that wish to enter for a quick operation. +// Making the locking finer-grain would require significant code rework, so +// it will have to do for now. + +public class ProxyService implements Service, EndpointListener, PipeMsgListener, OutputPipeListener, CacheEntryListener { + + private final static Logger LOG = Logger.getLogger(ProxyService.class.getName()); + + public final static int DEFAULT_THRESHOLD = 2; + public final static int DEFAULT_LIFETIME = 1000 * 60 * 30; // 30 minutes + + /** + * ********************************************************************* + * Define the proxy message tags + * ******************************************************************** + */ + public static final String REQUEST_TAG = "request"; + public static final String RESPONSE_TAG = "response"; + + static final String REQUESTID_TAG = "requestId"; + static final String TYPE_TAG = "type"; + static final String NAME_TAG = "name"; + static final String ID_TAG = "id"; + static final String ARG_TAG = "arg"; + static final String ATTRIBUTE_TAG = "attr"; + static final String VALUE_TAG = "value"; + static final String THRESHOLD_TAG = "threshold"; + static final String ERROR_MESSAGE_TAG = "error"; + static final String PROXYNS = "proxy"; + + /** + * ********************************************************************* + * Define the proxy request types + * ******************************************************************** + */ + public static final String REQUEST_JOIN = "join"; + public static final String REQUEST_CREATE = "create"; + public static final String REQUEST_SEARCH = "search"; + public static final String REQUEST_LISTEN = "listen"; + public static final String REQUEST_CLOSE = "close"; + public static final String REQUEST_SEND = "send"; + + /** + * ********************************************************************* + * Define the proxy response types + * ******************************************************************** + */ + public static final String RESPONSE_SUCCESS = "success"; + public static final String RESPONSE_ERROR = "error"; + public static final String RESPONSE_INFO = "info"; + public static final String RESPONSE_RESULT = "result"; + public static final String RESPONSE_MESSAGE = "data"; + + /** + * ********************************************************************* + * Define the proxy type tags + * ******************************************************************** + */ + public static final String TYPE_PEER = "PEER"; + public static final String TYPE_GROUP = "GROUP"; + public static final String TYPE_PIPE = "PIPE"; + + private PeerGroup group = null; + private ID assignedID = null; + private String serviceName = null; + private String serviceParameter = null; + private EndpointService endpoint = null; + private DiscoveryService discovery = null; + private PipeService pipe = null; + private ModuleImplAdvertisement implAdvertisement = null; + + private final LRUCache searchRequests = new LRUCache(25); // Currently unused + private final Map pipeListeners = new TreeMap(); + + /** + * Pending pipes cost only memory, so it is not a problrm to + * wait for the GC to cleanup things. No CacheEntryListener. + */ + private final Cache pendingPipes = new Cache(200, null); + private Cache resolvedPipes; + + private static Map proxiedGroups = new HashMap(16); + private static Map passwords = new HashMap(16); + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement implAdv) throws PeerGroupException { + this.group = group; + this.assignedID = assignedID; + this.serviceName = assignedID.toString(); + this.implAdvertisement = (ModuleImplAdvertisement) implAdv; + + serviceParameter = group.getPeerGroupID().toString(); + + // Resolved pipes cost non-memory resources, so we need to close + // them as early as we forget them. Need a CacheEntryListener (this). + resolvedPipes = new Cache(200, this); + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring JXME Proxy Service : " + assignedID); + + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group.getPeerGroupName()); + configInfo.append("\n\t\tGroup ID : ").append(group.getPeerGroupID()); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] args) { + + Service needed = group.getEndpointService(); + + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a endpoint service"); + } + + return START_AGAIN_STALLED; + } + + needed = group.getDiscoveryService(); + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a discovery service"); + } + + return START_AGAIN_STALLED; + } + + needed = group.getPipeService(); + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a pipe service"); + } + + return START_AGAIN_STALLED; + } + + endpoint = group.getEndpointService(); + discovery = group.getDiscoveryService(); + pipe = group.getPipeService(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("addListener " + serviceName + serviceParameter); + } + + endpoint.addIncomingMessageListener(this, serviceName, serviceParameter); + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("JXME Proxy Service started."); + } + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeListener " + serviceName + serviceParameter); + } + + endpoint.removeIncomingMessageListener(serviceName, serviceParameter); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("JXME Proxy Service stopped."); + } + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + */ + public ProxyService getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public synchronized void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + logMessage(message, LOG); + + Requestor requestor = null; + + try { + // requestor = Requestor.createRequestor(group, message, srcAddr); + // Commented out the above line and added the following three lines. + // The change allows to reduce the traffice going to a JXME peer + // by able to remove ERM completly. As a side effect (severe one) + // JXTA Proxy and JXTA relay need to be running on the same peer. + // This changes should be pulled out as soon as ERM is implemented + // in a more inteligent and effective way so that it doesn't + // have any impact on JXME peers. + EndpointAddress relayAddr = new EndpointAddress("relay", srcAddr.getProtocolAddress(), srcAddr.getServiceName(), + srcAddr.getServiceParameter()); + + requestor = Requestor.createRequestor(group, message, relayAddr, 0); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not create requestor", e); + } + } + + String request = popString(REQUEST_TAG, message); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("request = " + request + " requestor " + requestor); + } + + if (request != null && requestor != null) { + if (REQUEST_JOIN.equals(request)) { + handleJoinRequest(requestor, popString(ID_TAG, message), popString(ARG_TAG, message)); + } else if (REQUEST_CREATE.equals(request)) { + handleCreateRequest(requestor, popString(TYPE_TAG, message), popString(NAME_TAG, message), + popString(ID_TAG, message), popString(ARG_TAG, message)); + } else if (REQUEST_SEARCH.equals(request)) { + handleSearchRequest(requestor, popString(TYPE_TAG, message), popString(ATTRIBUTE_TAG, message), + popString(VALUE_TAG, message), popString(THRESHOLD_TAG, message)); + } else if ("listen".equals(request)) { + handleListenRequest(requestor, popString(ID_TAG, message)); + } else if ("close".equals(request)) { + handleCloseRequest(requestor, popString(ID_TAG, message)); + } else if ("send".equals(request)) { + handleSendRequest(requestor, popString(ID_TAG, message), message); + } + } + } + + // Right now there's a security hole: passwd come in clear. + // And not much is done for stopping clients to use the new group + // without being authenticated. We also never get rid of these + // additional groups. + private synchronized void handleJoinRequest(Requestor requestor, String grpId, String passwd) { + + PeerGroup g = proxiedGroups.get(grpId); + + if (g != null) { + if (g == this.group) { + requestor.notifyError("Same group"); + } else if (!passwords.get(grpId).equals(passwd)) { + requestor.notifyError("Incorrect password"); + } else { + requestor.notifySuccess(); + } + return; + } + + try { + g = group.newGroup((PeerGroupID) IDFactory.fromURI(new URI(grpId))); + g.getRendezVousService().startRendezVous(); + } catch (Exception ge) { + requestor.notifyError(ge.getMessage()); + return; + } + + // XXX check membership here. (would work only for single passwd grps) + // For now, assume join is always welcome. + + // So far so good. Try to start a proxy in that grp. + try { + // Fork this proxy into the new grp. + ProxyService proxyService = new ProxyService(); + proxyService.init(g, assignedID, implAdvertisement); + proxyService.startApp(null); + } catch (Exception e) { + requestor.notifyError(e.getMessage()); + return; + } + // set non-deft passwd + passwords.put(grpId, passwd); + proxiedGroups.put(grpId, g); + requestor.notifySuccess(); + } + + private void handleCreateRequest(Requestor requestor, String type, String name, String id, String arg) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleCreateRequest type=" + type + " name=" + name + " id=" + id + " arg=" + arg); + } + + if (name == null) { + name = ""; // default name + } + + if (TYPE_PEER.equals(type)) { + PeerAdvertisement adv = createPeerAdvertisement(name, id); + + if (adv != null) { + try { + discovery.publish(adv); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish peer advertisement", e); + } + } + requestor.send(adv, RESPONSE_SUCCESS); + } else { + requestor.notifyError("could not create advertisement"); + } + } else if (TYPE_GROUP.equals(type)) { + PeerGroupAdvertisement adv = createGroupAdvertisement(name, id); + + if (adv != null) { + requestor.send(adv, RESPONSE_SUCCESS); + } else { + requestor.notifyError("could not create advertisement"); + } + } else if (TYPE_PIPE.equals(type)) { + if (arg == null) { + arg = PipeService.UnicastType; // default pipe type + } + + PipeAdvertisement adv = createPipeAdvertisement(name, id, arg); + + if (adv != null) { + try { + discovery.publish(adv); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish pipe advertisement", e); + } + } + + requestor.send(adv, RESPONSE_SUCCESS); + } else { + requestor.notifyError("could not create advertisement"); + } + } else { + requestor.notifyError("unsupported type"); + } + } + + private void handleSearchRequest(Requestor requestor, String type, String attribute, String value, String threshold) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleSearchRequest type=" + type + " attribute=" + attribute + " value=" + value + " threshold=" + threshold); + } + + int discoveryType; + int thr = DEFAULT_THRESHOLD; + try { + thr = Integer.parseInt(threshold); + } catch (NumberFormatException nex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("handleSearchRequest failed to parse threshold " + threshold + ", using default " + DEFAULT_THRESHOLD); + } + } + requestor.setThreshold(thr); + + if (TYPE_PEER.equals(type)) { + discoveryType = DiscoveryService.PEER; + } else if (TYPE_GROUP.equals(type)) { + discoveryType = DiscoveryService.GROUP; + } else { + discoveryType = DiscoveryService.ADV; + } + + Enumeration each = null; + + try { + each = discovery.getLocalAdvertisements(discoveryType, attribute, value); + } catch (IOException e) { + requestor.notifyError("could not search locally"); + } + + int i = 0; + while (each.hasMoreElements() && i < thr) { + Advertisement adv = each.nextElement(); + + // notify the requestor of the result + // FIXME this can be optimized by sending all adv's in a + // single message + requestor.send(adv, RESPONSE_RESULT); + i++; + } + + // start the query + int queryId = discovery.getRemoteAdvertisements(null, discoveryType, attribute, value, thr); + + // register the query + searchRequests.put(queryId, requestor); + } + + /** + * Finds a JXTA Pipe and starts listening to it. + * + * @param requestor the peer sending listen request. + * @param id the id of the Pipe. + */ + private void handleListenRequest(Requestor requestor, String id) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleListenRequest id=" + id); + } + + if (id == null) { + requestor.notifyError("Pipe ID not specified"); + return; + } + + PipeAdvertisement pipeAdv = findPipeAdvertisement(null, id, null); + + if (pipeAdv == null) { + requestor.notifyError("Pipe Advertisement not found"); + return; + } + + String pipeId = pipeAdv.getPipeID().toString(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("listen to pipe name=" + pipeAdv.getName() + " id=" + pipeAdv.getPipeID() + " type=" + pipeAdv.getType()); + } + + // check to see if the input pipe already exist + PipeListenerList list = pipeListeners.get(pipeId); + + if (list == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("first listener, create input pipe"); + } + + // create an input pipe + try { + list = new PipeListenerList(pipe.createInputPipe(pipeAdv, this), pipeListeners, pipeId); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not listen to pipe", e); + } + requestor.notifyError("could not listen to pipe"); + return; + } + pipeListeners.put(pipeId, list); + } + + // add requestor to list + list.add(requestor); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("add requestor=" + requestor + " id=" + pipeId + " list=" + list); + LOG.fine("publish PipeAdvertisement"); + } + // advertise the pipe locally + try { + discovery.publish(pipeAdv); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not publish pipe advertisement", e); + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("done with listen request"); + } + + // notify requestor of success + requestor.notifySuccess(); + } + + private void handleCloseRequest(Requestor requestor, String id) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleCloseRequest id=" + id); + } + + PipeListenerList list = pipeListeners.get(id); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleCloseRequest list = " + list); + } + if (list != null) { + list.remove(requestor); + if (list.size() == 0) { + pipeListeners.remove(id); + } + } + + // notify requestor of success + requestor.notifySuccess(); + } + + // Send the given message to the given pipe. + private void sendToPipe(Requestor req, Message mess, OutputPipe out) { + try { + out.send(mess); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("output pipe send end"); + } + // notify requestor of success + req.notifySuccess(); + } catch (IOException e) { + req.notifyError("could not send to pipe"); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "could not send to pipe", e); + } + } + } + + class ClientMessage { + private Requestor requestor; + private Message message; + + public ClientMessage(Requestor req, Message mess) { + requestor = req; + message = mess; + } + + // Send this (pending) message + public void send(OutputPipe out) { + sendToPipe(requestor, message, out); + } + + } + + + class PendingPipe { + private ClientMessage pending; + + public PendingPipe() { + pending = null; + } + + // Just got resolved ! Will send the pending message(s). + public void sendPending(OutputPipe out) { + pending.send(out); + pending = null; + } + + // Enqueue a new pending message. + // (for now we only enqueue 1; others get trashed) + public void enqueue(Requestor req, Message mess) { + if (pending != null) { + return; + } + pending = new ClientMessage(req, mess); + } + } + + private void handleSendRequest(Requestor requestor, String id, Message message) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("handleSendRequest id=" + id); + } + + PipeAdvertisement pipeAdv = findPipeAdvertisement(null, id, null); + + if (pipeAdv == null) { + requestor.notifyError("Could not find pipe"); + return; + } + + String pipeId = pipeAdv.getPipeID().toString(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "send to pipe name=" + pipeAdv.getName() + " id=" + pipeAdv.getPipeID().toString() + " arg=" + + pipeAdv.getType()); + } + + // check if there are local listeners + + PipeListenerList list = pipeListeners.get(pipeId); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("local listener list " + list); + } + + if (list != null && PipeService.UnicastType.equals(pipeAdv.getType())) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("start sending to each requestor"); + } + + list.send(message, pipeId); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("end sending to each requestor"); + } + // notify requestor of success + requestor.notifySuccess(); + return; + } + + // NOTE: This part is NOT exercised by the load test because all + // clients are local. To exercise this part, comment out the + // optimization above. + + // This is not a unicast pipe with at least one local listener + // so we need to fingure out where the message should go. + // This may take a while and has to be done asynchronously... + // Carefull that the resolution can occur synchronously by this + // very thread, and java lock will not prevent re-entry. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("output pipe creation begin"); + } + + // Look for the pipe in the resolved list. If not found + // look in the pending list or add it there. + OutputPipe out = (OutputPipe) resolvedPipes.get(pipeId); + + if (out != null) { + sendToPipe(requestor, message, out); + return; + } + PendingPipe p = (PendingPipe) pendingPipes.get(pipeId); + + if (p != null) { + p.enqueue(requestor, message); + return; + } + + try { + p = new PendingPipe(); + p.enqueue(requestor, message); + pendingPipes.put(pipeId, p); + pipe.createOutputPipe(pipeAdv, this); + } catch (IOException e) { + pendingPipes.remove(pipeId); + requestor.notifyError("could not create output pipe"); + } + } + + // TBD: DO WE NEED THIS FUNCTIONALITY FOR JXME? + private PeerAdvertisement createPeerAdvertisement(String name, String id) { + PeerAdvertisement adv = null; + + PeerID pid = null; + + if (id != null) { + try { + ID tempId = IDFactory.fromURI(new URI(id)); + + pid = (PeerID) tempId; + } catch (URISyntaxException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not parse peerId from url", e); + } + } catch (ClassCastException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "id was not a peerid", e); + } + } + } + + if (pid == null) { + pid = IDFactory.newPeerID(group.getPeerGroupID()); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("newPeerAdvertisement name=" + name + " id=" + pid.toString()); + } + + try { + // Create a pipe advertisement for this pipe. + adv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(PeerAdvertisement.getAdvertisementType()); + + adv.setPeerID(pid); + adv.setPeerGroupID(group.getPeerGroupID()); + adv.setName(name); + adv.setDescription("Peer Advertisement created for a jxme device"); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "newPeerAdvertisement Exception", e); + } + } + + return adv; + } + + private PeerGroupAdvertisement createGroupAdvertisement(String name, String id) { + PeerGroupAdvertisement adv; + + PeerGroupID gid = null; + + if (id != null) { + try { + ID tempId = IDFactory.fromURI(new URI(id)); + + gid = (PeerGroupID) tempId; + } catch (URISyntaxException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Invalid peergroupId", e); + } + } catch (ClassCastException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "id was not a peergroup id", e); + } + } + } + + if (gid == null) { + gid = IDFactory.newPeerGroupID(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("newPeerGroupAdvertisement name=" + name + " id=" + gid.toString()); + } + + adv = group.getPeerGroupAdvertisement().clone(); + + try { + // Create a PeerGroup Advertisement for this pipe. + adv = (PeerGroupAdvertisement) AdvertisementFactory.newAdvertisement(PeerGroupAdvertisement.getAdvertisementType()); + adv.setName(name); + adv.setPeerGroupID(gid); + adv.setModuleSpecID(PeerGroup.allPurposePeerGroupSpecID); + adv.setDescription("PeerGroup Advertisement created for a jxme device"); + ModuleImplAdvertisement groupImplAdv = group.getAllPurposePeerGroupImplAdvertisement(); + + discovery.publish(groupImplAdv); + discovery.publish(adv); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "newPeerGroupAdvertisement Exception", e); + } + } + + return adv; + } + + private PipeAdvertisement createPipeAdvertisement(String pipeName, String pipeId, String pipeType) { + PipeAdvertisement adv = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("newPipeAdvertisement name=" + pipeName + " pipeId=" + pipeId + " pipeType=" + pipeType); + } + + if (pipeType == null || pipeType.length() == 0) { + pipeType = PipeService.UnicastType; + } + + if (pipeId == null) { + pipeId = IDFactory.newPipeID(group.getPeerGroupID()).toString(); + } + + try { + // Create a pipe advertisement for this pipe. + adv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + + adv.setName(pipeName); + adv.setPipeID(IDFactory.fromURI(new URI(pipeId))); + adv.setType(pipeType); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "newPipeAdvertisement Exception", e); + } + } + + return adv; + } + + private PipeAdvertisement findPipeAdvertisement(String name, String id, String arg) { + String attribute, value; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("findPipeAdvertisement name=" + name + " id=" + id + " arg=" + arg); + } + + if (id != null) { + attribute = PipeAdvertisement.IdTag; + value = id; + } else if (name != null) { + attribute = PipeAdvertisement.NameTag; + value = name; + } else { + // the id or the name must be specified + return null; + } + + Enumeration each; + + try { + each = discovery.getLocalAdvertisements(DiscoveryService.ADV, attribute, value); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "IOException in getLocalAdvertisements()", e); + } + return null; + } + + PipeAdvertisement pipeAdv = null; + + while (each.hasMoreElements()) { + Advertisement adv = each.nextElement(); + + // take the first match + if (adv instanceof PipeAdvertisement) { + pipeAdv = (PipeAdvertisement) adv; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("found PipeAdvertisement = " + pipeAdv); + } + break; + } + } + + return pipeAdv; + } + + public synchronized void discoveryEvent(DiscoveryEvent event) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("discoveryEvent " + event); + } + + Requestor requestor = searchRequests.get(event.getQueryID()); + if (requestor == null) { + return; + } + + DiscoveryResponseMsg response = event.getResponse(); + if (response == null) { + return; + } + + Enumeration each = response.getAdvertisements(); + if (each == null || !each.hasMoreElements()) { + return; + } + // we have a response remove it from the LRUCache + searchRequests.remove(event.getQueryID()); + int i = 0; + + while (each.hasMoreElements() && i < requestor.getThreshold()) { + try { + requestor.send(each.nextElement(), RESPONSE_RESULT); + } catch (Exception e) { + // this should not happen unless a bad result is returned + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Bad result returned by DiscoveryService", e); + } + } + } + } + + /** + * {@inheritDoc} + */ + public synchronized void pipeMsgEvent(PipeMsgEvent event) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("pipeMsgEvent " + event.getPipeID()); + } + + String id = event.getPipeID().toString(); + + PipeListenerList list = pipeListeners.get(id); + + if (list != null) { + Message message = event.getMessage(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("pipeMsgEvent: start sending to each requestor"); + } + list.send(message.clone(), id); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("pipeMsgEvent: end sending to each requestor"); + } + } else { + // there are no listeners, close the input pipe + ((InputPipe) event.getSource()).close(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("close pipe id=" + id); + } + } + } + + /** + * {@inheritDoc} + */ + public synchronized void outputPipeEvent(OutputPipeEvent event) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("outputPipeEvent " + event); + } + PendingPipe p = (PendingPipe) pendingPipes.remove(event.getPipeID()); + + // No one cares (anylonger). TBD should it be removed then?? + if (p == null) { + event.getOutputPipe().close(); + return; + } + + resolvedPipes.put(event.getPipeID(), event.getOutputPipe()); + p.sendPending(event.getOutputPipe()); + } + + private static String popString(String name, Message message) { + MessageElement el = message.getMessageElement(PROXYNS, name); + + if (el != null) { + message.removeMessageElement(el); + return el.toString(); + } + return null; + } + + static class PipeListenerList { + LinkedList list = new LinkedList(); + InputPipe inputPipe = null; + Map pipeListeners = null; + String id = null; + + PipeListenerList(InputPipe inputPipe, Map pipeListeners, String id) { + this.inputPipe = inputPipe; + this.pipeListeners = pipeListeners; + this.id = id; + + if (pipeListeners != null) { + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + LOG.config("number of pipeListeners = " + pipeListeners.size()); + } + } + } + + void add(Requestor requestor) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("add " + requestor + " from " + toString()); + } + + if (!list.contains(requestor)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("requestor add"); + } + list.add(requestor); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("requestor exits already"); + } + } + } + + void remove(Requestor requestor) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("remove " + requestor + " from " + toString()); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removed = " + list.remove(requestor)); + } + + if (list.size() == 0) { + // close the pipe and remove from the listenerList + if (inputPipe != null) { + inputPipe.close(); + } + + if (id != null && pipeListeners != null) { + pipeListeners.remove(id); + } + } + } + + int size() { + int size = list.size(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("size " + size); + } + return size; + } + + private static StringMessageElement sme = new StringMessageElement(RESPONSE_TAG, RESPONSE_MESSAGE, null); + + void send(Message message, String id) { + LOG.fine("send list.size = " + list.size()); + + message.addMessageElement(PROXYNS, sme); + message.addMessageElement(PROXYNS, new StringMessageElement(ID_TAG, id, null)); + + // removed all element that are known to be not needed + Iterator elements = message.getMessageElements(); + + while (elements.hasNext()) { + MessageElement el = elements.next(); + String name = el.getElementName(); + + if (name.startsWith("RendezVousPropagate")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeMessageElement " + name); + } + elements.remove(); + } else if (name.startsWith("JxtaWireHeader")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeMessageElement " + name); + } + elements.remove(); + } else if (name.startsWith("RdvIncarnjxta")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeMessageElement " + name); + } + elements.remove(); + } else if (name.startsWith("JxtaEndpointRouter")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeMessageElement " + name); + } + elements.remove(); + } else if (name.startsWith("EndpointRouterMsg")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeMessageElement " + name); + } + elements.remove(); + } else if (name.startsWith("EndpointHeaderSrcPeer")) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("removeMessageElement " + name); + } + elements.remove(); + } + } + + Iterator iterator = list.iterator(); + try { + while (iterator.hasNext()) { + Requestor requestor = iterator.next(); + + if (!requestor.send(message.clone())) { + // could not send to listener, remove them from the list + remove(requestor); + } + } + } catch (Exception ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Error sending" + ex); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "PipeListenerList size=" + list.size(); + } + } + + protected static void logMessage(Message message, Logger log) { + if (!Logging.SHOW_FINER || !log.isLoggable(Level.FINER)) { + return; + } + + StringBuilder out = new StringBuilder("\n**************** begin ****************\n"); + + Message.ElementIterator elements = message.getMessageElements(); + + while (elements.hasNext()) { + MessageElement element = elements.next(); + + out.append("[").append(elements.getNamespace()).append(",").append(element.getElementName()).append("]=").append(element.toString()).append( + "\n"); + } + + out.append("**************** end ****************\n"); + log.finer(out.toString()); + } + + /** + * {@inheritDoc} + */ + public void purged(CacheEntry ce) { + // A resolved pipe was purged from the cache because we have to + // many pre-resolved pipes hanging around. Close it, because + // it may be holding critical resources that the GC will not be + // sensitive to. + ((OutputPipe) (ce.getValue())).close(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/proxy/Requestor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/proxy/Requestor.java new file mode 100644 index 000000000..7d651b8c9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/proxy/Requestor.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.proxy; + + +import net.jxta.document.Advertisement; +import net.jxta.endpoint.*; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PeerGroupAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import java.io.IOException; + + +public class Requestor { + private final static Logger LOG = Logger.getLogger(Requestor.class.getName()); + + private PeerGroup group; + private EndpointAddress address; + private MessageElement requestId; + private Messenger messenger; + private int threshold = 1; + + public boolean send(Message message) { + int count; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("send to " + address.toString()); + } + + try { + synchronized (this) { + if ((null == messenger) || messenger.isClosed()) { + messenger = null; + count = 0; + // Add a retry in case we did not obtain a new messenger. + // Due to the heavy polling of the client, it seems that + // we can run in a race condition where we don't get + // a new messenger. + while (count < 2 && messenger == null) { + messenger = group.getEndpointService().getMessengerImmediate(address, null); + if (messenger != null) { + break; + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + Thread.interrupted(); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Retry getting a messenger" + e); + } + } + count++; + } + + if (null == messenger) { + LOG.warning("Could not get messenger for " + address); + return false; + } + } + } + messenger.sendMessage(message); + } catch (IOException e) { + LOG.log(Level.WARNING, "Could not send message to requestor for " + address, e); + return false; + } + + ProxyService.logMessage(message, LOG); + + return true; + } + + public boolean send(Advertisement adv, String resultType) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("send " + adv); + } + + Message message = new Message(); + + if (resultType == null) { + resultType = ""; + } + setString(message, ProxyService.RESPONSE_TAG, resultType); + + if (requestId != null) { + message.addMessageElement(ProxyService.PROXYNS, requestId); + } + + if (adv instanceof PeerAdvertisement) { + PeerAdvertisement peerAdv = (PeerAdvertisement) adv; + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.TYPE_TAG, ProxyService.TYPE_PEER, null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.NAME_TAG, peerAdv.getName(), null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.ID_TAG, peerAdv.getPeerID().toString(), null)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("send PeerAdvertisement name=" + peerAdv.getName() + " id=" + peerAdv.getPeerID().toString()); + } + + } else if (adv instanceof PeerGroupAdvertisement) { + PeerGroupAdvertisement groupAdv = (PeerGroupAdvertisement) adv; + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.TYPE_TAG, ProxyService.TYPE_GROUP, null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.NAME_TAG, groupAdv.getName(), null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.ID_TAG, groupAdv.getPeerGroupID().toString(), null)); + + LOG.fine("send GroupAdvertisement name=" + groupAdv.getName() + " id=" + groupAdv.getPeerGroupID().toString()); + + } else if (adv instanceof PipeAdvertisement) { + PipeAdvertisement pipeAdv = (PipeAdvertisement) adv; + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.TYPE_TAG, ProxyService.TYPE_PIPE, null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.NAME_TAG, pipeAdv.getName(), null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.ID_TAG, pipeAdv.getPipeID().toString(), null)); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.ARG_TAG, pipeAdv.getType(), null)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "send PipeAdvertisement name=" + pipeAdv.getName() + " id=" + pipeAdv.getPipeID().toString() + " arg=" + + pipeAdv.getType()); + } + + } else { + return false; + } + + return send(message); + } + + public boolean notifySuccess() { + LOG.fine("notifySuccess"); + + Message message = new Message(); + + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.RESPONSE_TAG, ProxyService.RESPONSE_SUCCESS, null)); + + if (requestId != null) { + message.addMessageElement(ProxyService.PROXYNS, requestId); + } + + return send(message); + } + + public boolean notifyError(String errorString) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("notifyError " + errorString); + } + + Message message = new Message(); + + if (requestId != null) { + message.addMessageElement(ProxyService.PROXYNS, requestId); + } + + if (errorString != null && errorString.length() > 0) { + message.addMessageElement(ProxyService.PROXYNS + , + new StringMessageElement(ProxyService.ERROR_MESSAGE_TAG, errorString, null)); + } + + return send(message); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(this + " equals " + obj); + } + + if (obj instanceof Requestor) { + Requestor dest = (Requestor) obj; + + if (address != null && dest.address != null) { + if (dest.address.toString().equals(address.toString())) { + return true; + } + } + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = 17; + + return 37 * result + requestId.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "Requestor " + address.toString(); + } + + private Requestor(PeerGroup group, EndpointAddress address, MessageElement requestId) throws IOException { + this.group = group; + this.address = address; + this.requestId = requestId; + } + + public static Requestor createRequestor(PeerGroup group, Message message, EndpointAddress address, int threshold) throws IOException { + Requestor requestor; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("create new Requestor - " + address.toString()); + } + + MessageElement elem = message.getMessageElement(ProxyService.REQUESTID_TAG); + + requestor = new Requestor(group, address, elem); + requestor.setThreshold(threshold); + message.removeMessageElement(elem); + return requestor; + } + + void setThreshold(int threshold) { + this.threshold = threshold; + } + + int getThreshold() { + return threshold; + } + + private void setString(Message message, String tag, String value) { + StringMessageElement sme = new StringMessageElement(tag, value, null); + + message.addMessageElement(ProxyService.PROXYNS, sme); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/PeerConnection.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/PeerConnection.java new file mode 100644 index 000000000..9d3ff3924 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/PeerConnection.java @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import java.util.Enumeration; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.endpoint.OutgoingMessageEventListener; +import net.jxta.id.ID; +import net.jxta.impl.util.TimeUtils; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.impl.endpoint.EndpointUtils; + +/** + * Manages a connection with a remote client or a rendezvous peer. + */ +public abstract class PeerConnection implements OutgoingMessageEventListener { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(PeerConnection.class.getName()); + + protected final PeerGroup group; + protected final EndpointService endpoint; + + /** + * ID of the remote peer. + */ + protected final ID peerid; + + /** + * Cached name of the peer for display purposes. + */ + protected String peerName = null; + + /** + * If true then we believe we are still connected to the remote peer. + */ + protected volatile boolean connected = true; + + /** + * The absolute time in milliseconds at which we expect this connection to + * expire unless renewed. + */ + protected long leasedTil = -1; + + /** + * A cached messenger to be used for sending messages to the remote peer. + */ + protected Messenger cachedMessenger = null; + + /** + * Constructor for the PeerConnection object + * + * @param group group context + * @param endpoint the endpoint service to use for sending messages. + * @param peerid destination peerid + */ + public PeerConnection(PeerGroup group, EndpointService endpoint, ID peerid) { + this.group = group; + this.endpoint = endpoint; + this.peerid = peerid; + + this.peerName = peerid.toString(); + } + + /** + * {@inheritDoc} + *

            + *

            performs PeerID comparison + */ + @Override + public boolean equals(Object obj) { + return obj instanceof PeerConnection && peerid.equals(((PeerConnection) obj).peerid); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return peerid.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return getPeerName() + (connected ? " C" : " c") + " : " + Long.toString(TimeUtils.toRelativeTimeMillis(leasedTil)); + } + + /** + * {@inheritDoc} + */ + public void messageSendFailed(OutgoingMessageEvent event) { + // If it's just a case of queue overflow, ignore it. + if (event.getFailure() == null) { + return; + } + setConnected(false); + } + + /** + * {@inheritDoc} + */ + public void messageSendSucceeded(OutgoingMessageEvent event) {// hurray! + } + + /** + * Get the peer id of the peer associated with this connection. + * + * @return The peer id of the connected peer. + */ + public ID getPeerID() { + return peerid; + } + + /** + * Get the peer name. If the symbolic name is available, use it, + * otherwise returns the peer id. + * + * @return The name of the connected peer. + */ + public String getPeerName() { + return peerName; + } + + /** + * set the peer name. + * + * @param name the peer name + */ + protected void setPeerName(String name) { + peerName = name; + } + + /** + * Set the lease duration in relative milliseconds. + * + * @param leaseDuration the lease duration in relative milliseconds. + */ + protected void setLease(long leaseDuration) { + leasedTil = TimeUtils.toAbsoluteTimeMillis(leaseDuration); + } + + /** + * Time at which the lease will expire in absolute milliseconds. + * + * @return The lease value + */ + public long getLeaseEnd() { + return leasedTil; + } + + /** + * Declare that we are connected for the specified amount of time. + * + * @param leaseDuration The duration of the lease in relative milliseconds. + */ + protected void connect(long leaseDuration) { + setLease(leaseDuration); + setConnected(true); + } + + /** + * Test if the connection is still active. + * + * @return The connected value + */ + public boolean isConnected() { + connected &= (TimeUtils.toRelativeTimeMillis(leasedTil) >= 0); + + return connected; + } + + /** + * Set the connection state. This operation must be idempotent. + * + * @param isConnected The new connected state. Be very careful when + * setting true state without setting a new lease. + */ + public void setConnected(boolean isConnected) { + connected = isConnected; + } + + /** + * Return a messenger suitable for communicating to this peer. + * + * @return a messenger for sending to this peer or null if + * none is available. + * @deprecated Preferred style is to pass the connection object around and + * use the sendMessage method rather than getting the messenger. + */ + @Deprecated + protected Messenger getCachedMessenger() { + + // We don't do the check on existing messenger under synchronization + // hence the temporary variable. + Messenger result = cachedMessenger; + + if ((null == result) || result.isClosed()) { + // We need a new messenger. + PeerAdvertisement padv = null; + + DiscoveryService discovery = group.getDiscoveryService(); + + // Try to see if we have a peer advertisement for this peer. + // This is very likely. + if (null != discovery) { + try { + Enumeration each = discovery.getLocalAdvertisements(DiscoveryService.PEER, "PID", peerid.toString()); + + if (each.hasMoreElements()) { + padv = (PeerAdvertisement) each.nextElement(); + } + } catch (Exception ignored) { + //ignored + } + } + result = getCachedMessenger(padv); + } + + return result; + } + + /** + * Return a messenger suitable for communicating to this peer. + * + * @param padv A peer advertisement which will be used for route hints if + * a new messenger is needed. + * @return a messenger for sending to this peer or null if + * none is available. + */ + protected synchronized Messenger getCachedMessenger(PeerAdvertisement padv) { + if ((null != padv) && !peerid.equals(padv.getPeerID())) { + throw new IllegalArgumentException("Peer Advertisement does not match connection"); + } + + if ((null != padv) && (null != padv.getName())) { + setPeerName(padv.getName()); + } + + // if we have a good messenger then re-use it. + if ((null != cachedMessenger) && !cachedMessenger.isClosed()) { + return cachedMessenger; + } + + cachedMessenger = null; + + if (isConnected()) { + // we only get new messengers while we are connected. It is not + // worth the effort for a disconnected peer. We WILL use an existing + // open messenger if we have one though. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting new cached Messenger for " + peerName); + } + + RouteAdvertisement hint = null; + + if (null != padv) { + hint = EndpointUtils.extractRouteAdv(padv); + } + + EndpointAddress destAddress = new EndpointAddress(peerid, null, null); + + cachedMessenger = endpoint.getMessenger(destAddress, hint); + + if (null == cachedMessenger) { + // no messenger? avoid doing more work. + setConnected(false); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("connection closed : NOT getting new cached Messenger for " + peerName); + } + } + + return cachedMessenger; + } + + /** + * Send a message to the remote peer. + * + * @param msg the message to send. + * @param service The destination service. + * @param param Parameters for the destination service. + * @return true if the message was queued to be sent, + * otherwise false. A true result does not mean + * that the destination peer will receive the message. + */ + public boolean sendMessage(Message msg, String service, String param) { + Messenger messenger = getCachedMessenger(); + + if (null != messenger) { + messenger.sendMessage(msg, service, param, this); + return true; + } else { + return false; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvGreeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvGreeter.java new file mode 100644 index 000000000..dab9789dd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvGreeter.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import java.io.IOException; + +import net.jxta.endpoint.Message; + +/** + * A Greeter is reponsible for receiving messages from walkers, and push them to + * the service that is listening to them. + * + * @see net.jxta.impl.rendezvous.RdvWalk + * @see net.jxta.impl.rendezvous.RdvWalker + */ +public interface RdvGreeter { + + /** + * Reply to a message received by the Greeter. + * + * @param msg The source message received previously by the Greeter + * @param reply The reply message to be sent to the source of the message. + * @throws IOException when the reply cannot be sent. + */ + public void replyMessage(Message msg, Message reply) throws IOException; + + /** + * Stop the greeter + */ + public void stop(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvWalk.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvWalk.java new file mode 100644 index 000000000..86508571f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvWalk.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import net.jxta.endpoint.EndpointListener; +import net.jxta.peergroup.PeerGroup; + +/** + * A Walk implements a particular protocol/behavior policy for sending messages + * through the Rendezvous Peers. A walk strategy is composed of a Walker and a + * Greeter. The Walker is used for sending messages according to the strategy. + * The Greeter receives messages and forwards them to a local listener and may + * provide the ability to continue a walk. + *

            + *

            Each walk is associated with a source service name and service param. + * These are the name and optional parameter of the service that uses the + * RdvWalk. + * + * @see net.jxta.impl.rendezvous.RdvWalker + * @see net.jxta.impl.rendezvous.RdvGreeter + */ +public abstract class RdvWalk { + + /** + * Peergroup in which this walk is running. + */ + protected final PeerGroup group; + + /** + * Intended recipient of messages received as part of this walk. + */ + protected final EndpointListener listener; + + /** + * Service name used by the (client) of this walk. + */ + protected final String srcServiceName; + + /** + * Optional service parameter used by the client of this walk. + */ + protected final String srcServiceParam; + + /** + * Standard constructor + * + * @param group Peergroup in which this walk is running. + * @param listener Intended recipient of messages received as part of this walk. + * @param srcServiceName Service name used by the client of this walk. + * @param srcServiceParam Optional service parameter used by the client of this walk. + */ + public RdvWalk(PeerGroup group, EndpointListener listener, String srcServiceName, String srcServiceParam) { + this.group = group; + this.listener = listener; + this.srcServiceName = srcServiceName; + this.srcServiceParam = srcServiceParam; + } + + /** + * Stop the walk. + */ + public abstract void stop(); + + /** + * Get/Create a walker to be used with this walk. + * + * @return A walker to be used with this walk. {@code null} is returned if + * no greeter is available or the walk has been stopped. + */ + public abstract RdvWalker getWalker(); + + /** + * Get/Create a greeter to be used with this walk. + * + * @return A greeter to be used with this walk. {@code null} is returned if + * no greeter is available or the walk has been stopped. + */ + public abstract RdvGreeter getGreeter(); + + /** + * Return the Peer Group in which this walk occurs. + * + * @return the Peer Group in which this walk occurs. + */ + public PeerGroup getPeerGroup() { + return group; + } + + /** + * Return the listener associated with this walk + * + * @return The listener associated with this walk. + */ + public EndpointListener getListener() { + return listener; + } + + /** + * Return the source Service Name for this walk. + * + * @return The source Service Name for this walk. + */ + public String getServiceName() { + return srcServiceName; + } + + /** + * Return the source Service Param for this walk. + * + * @return The source Service Param for this walk. + */ + public String getServiceParam() { + return srcServiceParam; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvWalker.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvWalker.java new file mode 100644 index 000000000..369cd9640 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RdvWalker.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import java.io.IOException; + +import net.jxta.endpoint.Message; +import net.jxta.peer.PeerID; + +/** + * A walker is responsible for implementing the strategy of sending messages for + * a walk. + * + * @see net.jxta.impl.rendezvous.RdvWalk + * @see net.jxta.impl.rendezvous.RdvGreeter + */ +public interface RdvWalker { + + /** + * Walk a message to other Rendezvous peers participating into the walk. An + * initial rendezvous peer can be optionally provided as a hint. + * + * @param destPeer An optional PeerID of the peer which will be the initial + * recipient of the walked message. + * @param msg The message to walk. The message will be modified. + * @param serviceName The name of the service. + * @param serviceParam The parameter of the service. + * @param ttl The maximum TTL of the message. This value may be decreased by + * the Walker implementation, but will never be increased. + * @throws IOException If the message was not sent to any other rendezvous + * peers. + */ + public void walkMessage(PeerID destPeer, Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Stop the walker. Some walkers may implement a strategy that has state and + * this method will stop any internal processing. + */ + public void stop(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousPropagateMessage.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousPropagateMessage.java new file mode 100644 index 000000000..ace7add16 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousPropagateMessage.java @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import net.jxta.document.Attributable; +import net.jxta.document.Attribute; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; +import net.jxta.logging.Logging; + +import java.net.URI; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class defines the wire format of the Propagation header for messages. + */ +public class RendezVousPropagateMessage { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RendezVousPropagateMessage.class.getName()); + + public final static String MSG_NAME = "jxta:RendezVousPropagateMessage"; + public static final String MsgIdTag = "MessageId"; + public final static String DestSNameTag = "DestSName"; + public final static String DestSParamTag = "DestSParam"; + public final static String TTLTag = "TTL"; + public final static String PathTag = "Path"; + + /** + * Description of the Field + */ + public final static String Name = "RendezVousPropagate"; + + private UUID msgId = null; + private String destSName = null; + private String destSParam = null; + private int TTL = Integer.MIN_VALUE; + private final Set visited = new LinkedHashSet(); + + /** + * Constructor for the RendezVousPropagateMessage object + */ + public RendezVousPropagateMessage() {} + + /** + * Constructor for the RendezVousPropagateMessage object + * + * @param root The root element of the message. + */ + public RendezVousPropagateMessage(Element root) { + this(); + + if (!XMLElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + " only supports XLMElement"); + } + + XMLElement doc = (XMLElement) root; + + String doctype = doc.getName(); + + String typedoctype = ""; + Attribute itsType = doc.getAttribute("type"); + + if (null != itsType) { + typedoctype = itsType.getValue(); + } + + if (!doctype.equals(MSG_NAME) && !MSG_NAME.equals(typedoctype)) { + throw new IllegalArgumentException( + "Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + + Enumeration elements = doc.getChildren(); + + while (elements.hasMoreElements()) { + XMLElement elem = (XMLElement) elements.nextElement(); + + if (!handleElement(elem)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Unhandled Element: " + elem.toString()); + } + } + } + + // Sanity Check!!! + + if (Integer.MIN_VALUE == getTTL()) { + throw new IllegalArgumentException("TTL value not specified"); + } + + if (null == destSName) { + throw new IllegalArgumentException("Destination service name uninitialized"); + } + + if (null == msgId) { + throw new IllegalArgumentException("Message id uninitialized"); + } + } + + /** + * Process the document + * + * @param raw the document + * @return true if successful + */ + protected boolean handleElement(Element raw) { + + XMLElement elem = (XMLElement) raw; + + if (elem.getName().equals(MsgIdTag)) { + try { + msgId = new UUID(elem.getTextValue().trim()); + } catch (IllegalArgumentException iae) { + // old message id format + try { + msgId = UUIDFactory.newHashUUID(Long.parseLong(elem.getTextValue().trim()), 0); + } catch (NumberFormatException notanumber) { + msgId = UUIDFactory.newHashUUID(elem.getTextValue().trim().hashCode(), 0); + } + } + return true; + } + + if (elem.getName().equals(DestSNameTag)) { + destSName = elem.getTextValue().trim(); + return true; + } + + if (elem.getName().equals(DestSParamTag)) { + destSParam = elem.getTextValue().trim(); + return true; + } + + if (elem.getName().equals(TTLTag)) { + TTL = Integer.parseInt(elem.getTextValue().trim()); + return true; + } + + if (elem.getName().equals(PathTag)) { + addVisited(URI.create(elem.getTextValue().trim())); + return true; + } + + return false; + } + + public UUID getMsgId() { + return msgId; + } + + public void setMsgId(UUID id) { + msgId = id; + } + + public String getDestSName() { + return destSName; + } + + public void setDestSName(String sName) { + this.destSName = sName; + } + + public String getDestSParam() { + return destSParam; + } + + public void setDestSParam(String sParam) { + this.destSParam = sParam; + } + + /** + * Gets the TTL attribute of the RendezVousPropagateMessage object + * + * @return The TTL value + */ + public int getTTL() { + return TTL; + } + + /** + * Sets the TTL attribute of the RendezVousPropagateMessage object + * + * @param ttl The new TTL value + */ + public void setTTL(int ttl) { + TTL = ttl; + } + + /** + * Adds a location to the Visited Set + * + * @param location which was visited. + */ + public void addVisited(URI location) { + visited.add(location); + } + + /** + * Returns true if the specified location is in the visited Set. + * + * @param location The location to check + * @return true if specified location has been visited. + */ + public boolean isVisited(URI location) { + return visited.contains(location); + } + + /** + * Returns the path which this message has travelled. + * + * @return the path this message travelled. + */ + public URI[] getPath() { + return visited.toArray(new URI[visited.size()]); + } + + public Document getDocument(MimeMediaType encodeAs) { + + // Sanity Check!!! + + if (getTTL() <= 0) { + throw new IllegalStateException("TTL value < 1"); + } + + if (null == destSName) { + throw new IllegalStateException("Destination service name uninitialized"); + } + + if (null == msgId) { + throw new IllegalStateException("Message id uninitialized"); + } + + if (visited.isEmpty()) { + throw new IllegalStateException("Message has not visited local peer."); + } + + StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(encodeAs, MSG_NAME); + + if (doc instanceof XMLDocument) { + ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); + ((Attributable) doc).addAttribute("xml:space", "preserve"); + } + + Element e = null; + + e = doc.createElement(MsgIdTag, msgId.toString()); + doc.appendChild(e); + + e = doc.createElement(DestSNameTag, destSName); + doc.appendChild(e); + + if (null != destSParam) { + e = doc.createElement(DestSParamTag, destSParam); + doc.appendChild(e); + } + + e = doc.createElement(TTLTag, Integer.toString(TTL)); + doc.appendChild(e); + + for (Object aVisited : visited) { + e = doc.createElement(PathTag, aVisited.toString()); + doc.appendChild(e); + } + return doc; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceImpl.java new file mode 100644 index 000000000..a1c2103c9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceImpl.java @@ -0,0 +1,945 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Random; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.NoSuchElementException; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.impl.endpoint.EndpointUtils; +import net.jxta.meter.MonitorResources; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.Module; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezVousStatus; +import net.jxta.rendezvous.RendezvousListener; +import net.jxta.service.Service; + +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.id.UUID.UUIDFactory; +import net.jxta.impl.meter.MonitorManager; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.rendezvous.adhoc.AdhocPeerRdvService; +import net.jxta.impl.rendezvous.edge.EdgePeerRdvService; +import net.jxta.impl.rendezvous.rdv.RdvPeerRdvService; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeterBuildSettings; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMonitor; +import net.jxta.impl.rendezvous.rpv.PeerView; +import net.jxta.impl.rendezvous.rpv.PeerViewElement; +import net.jxta.impl.util.TimeUtils; + +/** + * A JXTA {@link net.jxta.rendezvous.RendezVousService} implementation which + * implements the standard JXTA Rendezvous Protocol (RVP). + * + * @see net.jxta.rendezvous.RendezVousService + * @see JXTA Protocols Specification : Rendezvous Protocol + */ +public final class RendezVousServiceImpl implements RendezVousService { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RendezVousServiceImpl.class.getName()); + + private final static long rdv_watchdog_interval_default = 5 * TimeUtils.AMINUTE; // 5 Minutes + + private static final double DEMOTION_FACTOR = 0.05; + private static final long DEMOTION_MIN_PEERVIEW_COUNT = 5; + private static final long DEMOTION_MIN_CLIENT_COUNT = 3; + protected static final int MAX_MSGIDS = 1000; + + private final static Random random = new Random(); + + private PeerGroup group = null; + private ID assignedID = null; + private ModuleImplAdvertisement implAdvertisement = null; + + public EndpointService endpoint = null; + + private RendezvousServiceMonitor rendezvousServiceMonitor; + + private Timer timer; + private RdvWatchdogTask autoRdvTask = null; + + private long rdv_watchdog_interval = 5 * TimeUtils.AMINUTE; // 5 Minutes + + private final Set eventListeners = Collections.synchronizedSet(new HashSet()); + + /** + * The message IDs we have seen. Used for duplicate removal. + */ + private final List msgIds = new ArrayList(MAX_MSGIDS); + + /** + * Total number of messages which have been received. + */ + private int messagesReceived; + + private RdvConfigAdv.RendezVousConfiguration config = RdvConfigAdv.RendezVousConfiguration.EDGE; + private boolean autoRendezvous = false; + + private String[] savedArgs = null; + + /** + * If {@code true} then a rdv provider change is in progress. + */ + private AtomicBoolean rdvProviderSwitchStatus = new AtomicBoolean(false); + + /** + * The current provider + */ + private RendezVousServiceProvider provider = null; + + /** + * Our interface object. We currently always return the same object. + */ + private final RendezVousServiceInterface rendezvousInterface = new RendezVousServiceInterface(this); + + /** + * Constructor for the RendezVousServiceImpl object + */ + public RendezVousServiceImpl() { + } + + /** + * {@inheritDoc} + */ + public RendezVousService getInterface() { + return rendezvousInterface; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * Return the assigned ID for this service. + * + * @return The assigned ID for this service. + */ + public ID getAssignedID() { + return assignedID; + } + + /** + * {@inheritDoc} + *

            + *

            Note: it is permissible to pass null as the impl parameter + * when this instance is not being loaded via the module framework. + */ + public synchronized void init(PeerGroup g, ID assignedID, Advertisement impl) { + this.group = g; + this.assignedID = assignedID; + this.implAdvertisement = (ModuleImplAdvertisement) impl; + + RdvConfigAdv rdvConfigAdv = null; + ConfigParams confAdv = group.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + if (confAdv != null) { + Advertisement adv = null; + + try { + XMLDocument configDoc = (XMLDocument) confAdv.getServiceParam(getAssignedID()); + + if (null != configDoc) { + adv = AdvertisementFactory.newAdvertisement(configDoc); + } + } catch (NoSuchElementException failed) { + //ignored + } + + if (adv instanceof RdvConfigAdv) { + rdvConfigAdv = (RdvConfigAdv) adv; + } + } + + if (null == rdvConfigAdv) { + // Make a new advertisement for defaults. + rdvConfigAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + } + + config = rdvConfigAdv.getConfiguration(); + + autoRendezvous = rdvConfigAdv.getAutoRendezvousCheckInterval() > 0; + + rdv_watchdog_interval = rdvConfigAdv.getAutoRendezvousCheckInterval(); + + // force AD-HOC config for World Peer Group. + if (PeerGroupID.worldPeerGroupID.equals(group.getPeerGroupID())) { + config = RdvConfigAdv.RendezVousConfiguration.AD_HOC; + } + + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring RendezVous Service : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration :"); + configInfo.append("\n\t\tRendezVous : ").append(config); + configInfo.append("\n\t\tAuto RendezVous : ").append(autoRendezvous); + configInfo.append("\n\t\tAuto-RendezVous Reconfig Interval : ").append(rdv_watchdog_interval); + + LOG.config(configInfo.toString()); + } + + // "start" a rendezvous provider switch. We will finish in startApp() + rdvProviderSwitchStatus.set(true); + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + + return START_AGAIN_STALLED; + } + + Service needed = group.getMembershipService(); + + if (null == needed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + + return START_AGAIN_STALLED; + } + + // if( !PeerGroupID.worldPeerGroupID.equals(group.getPeerGroupID())) { + // MessageTransport router = endpoint.getMessageTransport( "jxta" ); + // + // if( null == router ) { + // if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + // LOG.warning("Stalled until there is a router "); + // } + // + // return START_AGAIN_STALLED; + // } + // } + // + + timer = new Timer("RendezVousServiceImpl Timer for " + group.getPeerGroupID(), true); + + if (!rdvProviderSwitchStatus.compareAndSet(true, true)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Unable to start rendezvous provider."); + } + + return -1; + } + + if (RdvConfigAdv.RendezVousConfiguration.AD_HOC == config) { + provider = new AdhocPeerRdvService(group, this); + } else if (RdvConfigAdv.RendezVousConfiguration.EDGE == config) { + provider = new EdgePeerRdvService(group, this); + } else if (RdvConfigAdv.RendezVousConfiguration.RENDEZVOUS == config) { + provider = new RdvPeerRdvService(group, this); + } else { + throw new IllegalStateException("Unrecognized rendezvous configuration"); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING) { + rendezvousServiceMonitor = (RendezvousServiceMonitor) MonitorManager.getServiceMonitor(group + , + MonitorResources.rendezvousServiceMonitorClassID); + provider.setRendezvousServiceMonitor(rendezvousServiceMonitor); + } + + provider.startApp(null); + + rdvProviderSwitchStatus.set(false); + + if (autoRendezvous && !PeerGroupID.worldPeerGroupID.equals(group.getPeerGroupID())) { + startWatchDogTimer(); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Rendezvous Serivce started"); + } + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public synchronized void stopApp() { + + // We won't ever release this lock. We are shutting down. There is + // no reason to switch after stopping is begun. + rdvProviderSwitchStatus.set(true); + + if (provider != null) { + provider.stopApp(); + provider = null; + } + + timer.cancel(); + timer = null; + + msgIds.clear(); + eventListeners.clear(); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Rendezvous Serivce stopped"); + } + } + + /** + * {@inheritDoc} + */ + public boolean isRendezVous() { + RendezVousStatus currentStatus = getRendezVousStatus(); + + return (RendezVousStatus.AUTO_RENDEZVOUS == currentStatus) || (RendezVousStatus.RENDEZVOUS == currentStatus); + } + + /** + * @inheritDoc + */ + public RendezVousStatus getRendezVousStatus() { + RendezVousServiceProvider currentProvider = provider; + + if (null == currentProvider) { + return RendezVousStatus.NONE; + } else if (currentProvider instanceof AdhocPeerRdvService) { + return RendezVousStatus.ADHOC; + } else if (currentProvider instanceof EdgePeerRdvService) { + return autoRendezvous ? RendezVousStatus.AUTO_EDGE : RendezVousStatus.EDGE; + } else if (currentProvider instanceof RdvPeerRdvService) { + return autoRendezvous ? RendezVousStatus.AUTO_RENDEZVOUS : RendezVousStatus.RENDEZVOUS; + } else { + return RendezVousStatus.UNKNOWN; + } + } + + /** + * {@inheritDoc} + */ + public boolean setAutoStart(boolean auto) { + return setAutoStart(auto, rdv_watchdog_interval_default); + } + + /** + * {@inheritDoc} + */ + public synchronized boolean setAutoStart(boolean auto, long period) { + rdv_watchdog_interval = period; + boolean old = autoRendezvous; + + autoRendezvous = auto; + + if (auto && !old) { + startWatchDogTimer(); + } else if (old && !auto) { + stopWatchDogTimer(); + } + return old; + } + + /** + * Attempt to connect to the specified rendezvous peer. + * + * @param addr The endpoint address of the rendezvous peer. + * @param hint An optional hint which may be {@code null}. + * @throws IOException If no connection could be made to the specified + * peer. + */ + private void connectToRendezVous(EndpointAddress addr, RouteAdvertisement hint) throws IOException { + RendezVousServiceProvider currentProvider = provider; + + if (currentProvider != null) { + currentProvider.connectToRendezVous(addr, hint); + } else { + throw new IOException("Currently switching rendezvous roles."); + } + } + + /** + * {@inheritDoc} + */ + public void connectToRendezVous(PeerAdvertisement adv) throws IOException { + EndpointAddress addr = new EndpointAddress("jxta", adv.getPeerID().getUniqueValue().toString(), null, null); + connectToRendezVous(addr, EndpointUtils.extractRouteAdv(adv)); + } + + /** + * {@inheritDoc} + */ + public void connectToRendezVous(EndpointAddress addr) throws IOException { + connectToRendezVous(addr, null); + } + + /** + * {@inheritDoc} + */ + public void challengeRendezVous(ID peer, long delay) { + RendezVousServiceProvider currentProvider = provider; + + if (currentProvider != null) { + currentProvider.challengeRendezVous(peer, delay); + } + } + + /** + * {@inheritDoc} + */ + public void disconnectFromRendezVous(ID peerId) { + + RendezVousServiceProvider currentProvider = provider; + + if (currentProvider != null) { + currentProvider.disconnectFromRendezVous(peerId); + } + } + + /** + * {@inheritDoc} + */ + public Enumeration getConnectedRendezVous() { + throw new UnsupportedOperationException("Deprecated opertaion. Use interface if you want to use this operation."); + } + + /** + * {@inheritDoc} + */ + public Enumeration getDisconnectedRendezVous() { + throw new UnsupportedOperationException("Deprecated opertaion. Use interface if you want to use this operation."); + } + + /** + * {@inheritDoc} + */ + public Enumeration getConnectedPeers() { + throw new UnsupportedOperationException("Deprecated opertaion. Use interface if you want to use this operation."); + } + + /** + * {@inheritDoc} + */ + public Vector getConnectedPeerIDs() { + RendezVousServiceProvider currentProvider = provider; + + if (currentProvider != null) { + return currentProvider.getConnectedPeerIDs(); + } + return new Vector(); + } + + /** + * Gets the rendezvousConnected attribute of the RendezVousServiceImpl object + * + * @return true if connected to a rendezvous, false otherwise + */ + public boolean isConnectedToRendezVous() { + RendezVousServiceProvider currentProvider = provider; + return currentProvider != null && currentProvider.isConnectedToRendezVous(); + } + + /** + * {@inheritDoc} + */ + public void startRendezVous() { + try { + if (isRendezVous() || PeerGroupID.worldPeerGroupID.equals(group.getPeerGroupID())) { + return; + } + + if (!rdvProviderSwitchStatus.compareAndSet(false, true)) { + IOException failed = new IOException("Currently switching rendezvous configuration. try again later."); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to start rendezvous", failed); + } + throw failed; + } + + // We are at this moment an Edge Peer. First, the current implementation + // must be stopped. + if (provider != null) { + provider.stopApp(); + provider = null; + } + + config = RdvConfigAdv.RendezVousConfiguration.RENDEZVOUS; + + // Now, a new instance of RdvPeerRdvService must be created and initialized. + provider = new RdvPeerRdvService(group, this); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING) { + provider.setRendezvousServiceMonitor(rendezvousServiceMonitor); + } + + provider.startApp(savedArgs); + + rdvProviderSwitchStatus.set(false); + } catch (IOException failure) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to start rendezvous", failure); + } + } + } + + /** + * {@inheritDoc} + */ + public void stopRendezVous() { + + if (!isRendezVous()) { + return; + } + + if (!rdvProviderSwitchStatus.compareAndSet(false, true)) { + IOException failed = new IOException("Currently switching rendezvous configuration. try again later."); + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed to stop rendezvous", failed); + } + } + + // If the service was already started, then it needs to be stopped, + // and a new instance of an EdgePeerRdvService must be created and initialized and + // started. + + if (provider != null) { + provider.stopApp(); + provider = null; + } + + config = RdvConfigAdv.RendezVousConfiguration.EDGE; + + provider = new EdgePeerRdvService(group, this); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING) { + provider.setRendezvousServiceMonitor(rendezvousServiceMonitor); + } + + provider.startApp(savedArgs); + + rdvProviderSwitchStatus.set(false); + } + + /** + * {@inheritDoc} + */ + public boolean addPropagateListener(String serviceName, String serviceParam, EndpointListener listener) { + if (null == endpoint) { + throw new IllegalStateException("Unable to register propagate listener. (not started)"); + } + + return endpoint.addIncomingMessageListener(listener, serviceName, serviceParam); + } + + /** + * {@inheritDoc} + */ + public EndpointListener removePropagateListener(String serviceName, String serviceParam, EndpointListener listener) { + + if (null == endpoint) { + throw new IllegalStateException("Unable to remove propagate listener. (not started)"); + } + + EndpointListener removed = endpoint.removeIncomingMessageListener(serviceName, serviceParam); + + if ((removed != listener) && (null != removed)) { + // Not the listener we expected. + // It's kind of bad that we removed it at all, but putting it back should fix things. + endpoint.addIncomingMessageListener(removed, serviceName, serviceParam); + return null; + } + return listener; + } + + /** + * {@inheritDoc} + */ + public void propagate(Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + RendezVousServiceProvider currentProvider = provider; + + if (null == currentProvider) { + throw new IOException("No RDV provider"); + } + currentProvider.propagate(msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void propagate(Enumeration destPeerIDs, Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + RendezVousServiceProvider currentProvider = provider; + + if (null == currentProvider) { + throw new IOException("No RDV provider"); + } + currentProvider.propagate(destPeerIDs, msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void walk(Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + RendezVousServiceProvider currentProvider = provider; + + if (null == currentProvider) { + throw new IOException("No RDV provider"); + } + currentProvider.walk(msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + RendezVousServiceProvider currentProvider = provider; + + if (null == currentProvider) { + throw new IOException("No RDV provider"); + } + currentProvider.walk(destPeerIDs, msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public Vector getLocalWalkView() { + + Vector result = new Vector(); + + PeerView currView = getPeerView(); + + if (null == currView) { + return result; + } + + Collection allPVE = new ArrayList(currView.getView()); + + for (PeerViewElement pve : allPVE) { + RdvAdvertisement adv = pve.getRdvAdvertisement(); + result.add(adv); + } + + return result; + } + + /** + * Returns the PeerView + * + * @return the PeerView + */ + public PeerView getPeerView() { + RendezVousServiceProvider currentProvider = provider; + + if (currentProvider instanceof RdvPeerRdvService) { + return ((RdvPeerRdvService) currentProvider).rpv; + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + public void propagateToNeighbors(Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + RendezVousServiceProvider currentProvider = provider; + + if (null == currentProvider) { + throw new IOException("No RDV provider"); + } + currentProvider.propagateToNeighbors(msg, serviceName, serviceParam, ttl); + } + + /** + * {@inheritDoc} + */ + public void propagateInGroup(Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + RendezVousServiceProvider currentProvider = provider; + if (null == currentProvider) { + throw new IOException("No RDV provider"); + } + currentProvider.propagateInGroup(msg, serviceName, serviceParam, ttl); + } + + /** + * {@inheritDoc} + */ + public final void addListener(RendezvousListener listener) { + eventListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + public final boolean removeListener(RendezvousListener listener) { + return eventListeners.remove(listener); + } + + /** + * Creates a rendezvous event and sends it to all registered listeners. + * + * @param type event type + * @param regarding event peer ID + */ + public final void generateEvent(int type, ID regarding) { + + Iterator eachListener = Arrays.asList(eventListeners.toArray()).iterator(); + RendezvousEvent event = new RendezvousEvent(getInterface(), type, regarding); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Calling listeners for " + event); + } + + while (eachListener.hasNext()) { + RendezvousListener aListener = (RendezvousListener) eachListener.next(); + + try { + aListener.rendezvousEvent(event); + } catch (Throwable ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable in listener (" + aListener + ")", ignored); + } + } + } + } + + private synchronized void startWatchDogTimer() { + stopWatchDogTimer(); + + autoRdvTask = new RdvWatchdogTask(); + + // Now that we have an Auto-switch flag we only use the higher timeout + // if auto-switch is off . + // Set a watchdog, so the peer will become rendezvous if, after rdv_watchdog_interval it + // still has not connected to any rendezvous peer. + timer.schedule(autoRdvTask, rdv_watchdog_interval, rdv_watchdog_interval); + } + + private synchronized void stopWatchDogTimer() { + RdvWatchdogTask tw = autoRdvTask; + + if (tw != null) { + autoRdvTask.cancel(); + autoRdvTask = null; + } + } + + /** + * Edge Peer mode connection watchdog. + */ + private class RdvWatchdogTask extends TimerTask { + + /** + * {@inheritDoc} + */ + @Override + public synchronized void run() { + try { + int connectedPeers = getConnectedPeerIDs().size(); + + if (!isRendezVous()) { + if (0 == connectedPeers) { + // This peer has not been able to connect to any rendezvous peer. + // become one. + + // become a rendezvous peer. + startRendezVous(); + } + } else { + // Perhaps we can demote ourselves back to an edge + + int peerViewSize = getLocalWalkView().size(); + + boolean isManyElementsInPeerView = (peerViewSize > DEMOTION_MIN_PEERVIEW_COUNT); + boolean isFewClients = (connectedPeers < DEMOTION_MIN_CLIENT_COUNT); + + if (isManyElementsInPeerView) { + if (connectedPeers == 0) { + // Demote ourselves if there are no clients and + // there are more than the minimum rendezvous around + stopRendezVous(); + } else if (isFewClients && (RendezVousServiceImpl.random.nextDouble() < DEMOTION_FACTOR)) { + // Randomly Demote ourselves if there are few clients and + // there are many rendezvous + stopRendezVous(); + } + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in Timer : " + Thread.currentThread().getName(), all); + } + } + } + } + + public boolean isMsgIdRecorded(UUID id) { + + boolean found; + + synchronized (msgIds) { + found = msgIds.contains(id); + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer(id + " = " + found); + } + + return found; + } + + /** + * Checks if a message id has been recorded. + * + * @param id message to record. + * @return {@code true} If message was added otherwise (duplicate) + * {@code false}. + */ + public boolean addMsgId(UUID id) { + + synchronized (msgIds) { + if (isMsgIdRecorded(id)) { + // Already there. Nothing to do + return false; + } + + if (msgIds.size() < MAX_MSGIDS) { + msgIds.add(id); + } else { + msgIds.set((messagesReceived % MAX_MSGIDS), id); + } + + messagesReceived++; + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Added Message ID : " + id); + } + + return true; + } + + public UUID createMsgId() { + return UUIDFactory.newSeqUUID(); + } + + /** + * Get the current provider. This is for debugging purposes only. + * + * @return the provider + * @deprecated This is private for debugging and diagnostics only. + */ + @Deprecated + net.jxta.impl.rendezvous.RendezVousServiceProvider getRendezvousProvider() { + return provider; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceInterface.java new file mode 100644 index 000000000..518a75e89 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceInterface.java @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.Vector; + +import java.io.IOException; +import java.util.Collection; + +import net.jxta.document.Advertisement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.id.ID; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezVousStatus; +import net.jxta.rendezvous.RendezvousListener; +import net.jxta.service.Service; + +import net.jxta.impl.rendezvous.rpv.PeerView; +import net.jxta.platform.Module; + +/** + * This class implements the RendezVousService interface. + */ +public class RendezVousServiceInterface implements RendezVousService { + + RendezVousServiceImpl impl = null; + + /** + * The only authorized constructor. + * + * @param theRealThing the wrapped service + */ + RendezVousServiceInterface(RendezVousServiceImpl theRealThing) { + impl = theRealThing; + } + + /** + * {@inheritDoc} + *

            + *

            Since THIS is already such an object, it returns itself. + * FIXME: it is kind of absurd to have this method part of the + * interface but we do not want to define two levels of Service interface + * just for that. + */ + public Service getInterface() { + return this; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return impl.getImplAdvertisement(); + } + + /** + * {@inheritDoc} + *

            + *

            FIXME: This is meaningless for the interface object; + * it is there only to satisfy the requirements of the + * interface that we implement. Ultimately, the API should define + * two levels of interfaces: one for the real service implementation + * and one for the interface object. Right now it feels a bit heavy + * to so that since the only different between the two would be + * init() and may-be getName(). + */ + + public void init(PeerGroup pg, ID assignedID, Advertisement impl) { + } + + /** + * {@inheritDoc} + *

            + *

            This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + */ + public int startApp(String[] arg) { + return Module.START_OK; + } + + /** + * {@inheritDoc} + *

            + *

            This is here for temporary class hierarchy reasons. + * it is ALWAYS ignored. By definition, the interface object + * protects the real object's start/stop methods from being called + *

            + *

            This request is currently ignored. + */ + public void stopApp() { + } + + /** + * {@inheritDoc} + */ + public void connectToRendezVous(PeerAdvertisement adv) throws IOException { + impl.connectToRendezVous(adv); + } + + /** + * {@inheritDoc} + */ + public void connectToRendezVous(EndpointAddress addr) throws IOException { + impl.connectToRendezVous(addr); + } + + /** + * {@inheritDoc} + */ + public void challengeRendezVous(ID peer, long delay) { + impl.challengeRendezVous(peer, delay); + } + + /** + * {@inheritDoc} + */ + public void disconnectFromRendezVous(ID rendezVous) { + impl.disconnectFromRendezVous(rendezVous); + } + + /** + * {@inheritDoc} + */ + public Enumeration getConnectedRendezVous() { + Collection connectedPeers = getConnectedPeerIDs(); + + return Collections.enumeration(connectedPeers); + } + + /** + * {@inheritDoc} + */ + public Enumeration getDisconnectedRendezVous() { + Collection empty = Collections.emptyList(); + + return Collections.enumeration(empty); + } + + /** + * This portion is for peers that are RendezVous + */ + + /** + * {@inheritDoc} + */ + public void startRendezVous() { + impl.startRendezVous(); + } + + /** + * {@inheritDoc} + */ + public void stopRendezVous() { + impl.stopRendezVous(); + } + + /** + * {@inheritDoc} + */ + public Enumeration getConnectedPeers() { + Collection connectedPeers = getConnectedPeerIDs(); + + return Collections.enumeration(connectedPeers); + } + + /** + * {@inheritDoc} + */ + public Vector getConnectedPeerIDs() { + return impl.getConnectedPeerIDs(); + } + + /** + * {@inheritDoc} + */ + public boolean addPropagateListener(String serviceName, String serviceParam, EndpointListener listener) { + + return impl.addPropagateListener(serviceName, serviceParam, listener); + } + + /** + * {@inheritDoc} + */ + public EndpointListener removePropagateListener(String serviceName, String serviceParam, EndpointListener listener) { + + return impl.removePropagateListener(serviceName, serviceParam, listener); + } + + /** + * {@inheritDoc} + */ + public void addListener(RendezvousListener listener) { + + impl.addListener(listener); + } + + /** + * {@inheritDoc} + */ + public boolean removeListener(RendezvousListener listener) { + + return impl.removeListener(listener); + } + + /** + * {@inheritDoc} + */ + public void propagate(Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + impl.propagate(msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void propagate(Enumeration destPeerIDs, Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + impl.propagate(destPeerIDs, msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void walk(Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + impl.walk(msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + + impl.walk(destPeerIDs, msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public Vector getLocalWalkView() { + + return impl.getLocalWalkView(); + } + + /** + * {@inheritDoc} + */ + public void propagateToNeighbors(Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + impl.propagateToNeighbors(msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public void propagateInGroup(Message msg, String serviceName, String serviceParam, int defaultTTL) throws IOException { + impl.propagateInGroup(msg, serviceName, serviceParam, defaultTTL); + } + + /** + * {@inheritDoc} + */ + public boolean isConnectedToRendezVous() { + return impl.isConnectedToRendezVous(); + } + + /** + * {@inheritDoc} + */ + public boolean isRendezVous() { + return impl.isRendezVous(); + } + + /** + * @inheritDoc + */ + public RendezVousStatus getRendezVousStatus() { + return impl.getRendezVousStatus(); + } + + /** + * {@inheritDoc} + */ + public boolean setAutoStart(boolean auto) { + return impl.setAutoStart(auto); + } + + /** + * {@inheritDoc} + */ + public boolean setAutoStart(boolean auto, long period) { + return impl.setAutoStart(auto, period); + } + + /** + * Get the current peerview. This is for debugging purposes only. + * + * @return the peer view + * @deprecated This is private for debugging and diagnostics only. + */ + @Deprecated + public PeerView getPeerView() { + return impl.getPeerView(); + } + + /** + * Get the current provider. This is for debugging purposes only. + * + * @return the provider + * @deprecated This is private for debugging and diagnostics only. + */ + @Deprecated + public net.jxta.impl.rendezvous.RendezVousServiceProvider getRendezvousProvider() { + return impl.getRendezvousProvider(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceProvider.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceProvider.java new file mode 100644 index 000000000..3696b13a2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/RendezVousServiceProvider.java @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.id.UUID.UUID; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeter; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeterBuildSettings; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousServiceMonitor; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.PeerAdvertisement; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This abstract class must be extended for all RendezVous Service providers + * that are managed by RendezVousServiceImpl. + *

            + * Implementors of providers are responsible for using appropriate + * synchronization. The RendezvousServiceImpl provides synchronization control + * only only those methods which involve changing the active provider. + */ +public abstract class RendezVousServiceProvider implements EndpointListener { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(RendezVousServiceProvider.class.getName()); + + protected static final String PropSName = "JxtaPropagate"; + + protected static final String RDV_MSG_NAMESPACE_NAME = "jxta"; + + protected final String PropPName; + protected final String PROP_HDR_ELEMENT_NAME; + + /** + * Maximum TTL we will allow for propagation and repropagation issued by + * this peer. + */ + protected int MAX_TTL; + + protected final PeerGroup group; + protected final RendezVousServiceImpl rdvService; + protected boolean closed = false; + + private PeerAdvertisement cachedPeerAdv = null; + private int cachedPeerAdvModCount = -1; + private XMLDocument cachedPeerAdvDoc = null; + + protected RendezvousServiceMonitor rendezvousServiceMonitor = null; + protected RendezvousMeter rendezvousMeter = null; + + /** + * + * @param group the peergroup + * @param rdvService the implementation + */ + protected RendezVousServiceProvider(PeerGroup group, RendezVousServiceImpl rdvService) { + + this.group = group; + this.rdvService = rdvService; + + PropPName = this.group.getPeerGroupID().getUniqueValue().toString(); + PROP_HDR_ELEMENT_NAME = RendezVousPropagateMessage.Name + PropPName; + } + + /** + * {@inheritDoc} + *

            + * EndpointListener for the JxtaPropagate/ + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + RendezVousPropagateMessage propHdr = checkPropHeader(msg); + + if (null != propHdr) { + // Get the destination real destination of the message + String sName = propHdr.getDestSName(); + String sParam = propHdr.getDestSParam(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Processing " + msg + "(" + propHdr.getMsgId() + ") for " + sName + "/" + sParam + " from " + srcAddr); + } + + // Check if we have a local listener for this message + processReceivedMessage(msg, propHdr, srcAddr, new EndpointAddress(dstAddr, sName, sParam)); + } + } + + protected XMLDocument getPeerAdvertisementDoc() { + PeerAdvertisement newPadv; + + synchronized (this) { + newPadv = group.getPeerAdvertisement(); + int newModCount = newPadv.getModCount(); + + if ((cachedPeerAdv != newPadv) || (cachedPeerAdvModCount != newModCount)) { + cachedPeerAdv = newPadv; + cachedPeerAdvModCount = newModCount; + } else { + newPadv = null; + } + + if (null != newPadv) { + cachedPeerAdvDoc = (XMLDocument) cachedPeerAdv.getDocument(MimeMediaType.XMLUTF8); + } + } + + return cachedPeerAdvDoc; + } + + /** + * Supply arguments and starts this service if it hadn't started by itself. + *

            + * Currently this service starts by itself and does not expect arguments. + * @return 0 if successful + * @param arg argument params + */ + protected int startApp(String[] arg) { + + // All propagated messages originated by RendezvousService.propagate are handled by the + // rendezvous service before being delivered to their local recipient. + // This includes: + // messages delivered here via netWorkPropagation. Therefore the rdv service has a special + // endpointService listener for that purpose. + // messages delivered here by rdv-to-rdv walk. + try { + if (!rdvService.endpoint.addIncomingMessageListener(this, PropSName, PropPName)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Cannot register the propagation listener (already registered)"); + } + + return -1; + } + } catch (Exception ez1) { + // Not much we can do here. + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Failed registering the endpoint listener", ez1); + } + + return -1; + } + + try { + // Update the peeradv with our status + if (rdvService.isRendezVous()) { + XMLDocument params = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + XMLElement e = params.createElement("Rdv", Boolean.TRUE.toString()); + + params.appendChild(e); + group.getPeerAdvertisement().putServiceParam(rdvService.getAssignedID(), params); + } else { + group.getPeerAdvertisement().removeServiceParam(rdvService.getAssignedID()); + } + } catch (Exception ignored) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not update Rdv Params in Peer Advertisement", ignored); + } + } + + return Module.START_OK; + } + + /** + * Ask this service to stop. + */ + protected void stopApp() { + EndpointListener shouldbeMe = rdvService.endpoint.removeIncomingMessageListener(PropSName, PropPName); + + if ((null != shouldbeMe) && (this != shouldbeMe)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unregistered listener was not as expected." + this + " != " + shouldbeMe); + } + } + + // Update the peeradv. We are not a rdv. + group.getPeerAdvertisement().removeServiceParam(rdvService.getAssignedID()); + } + + /** + * Set the RendezvousServiceMonitor. The RendezvousServiceMonitor is used to + * meter the activity of the RendezvousService. + * + * @param rendezvousServiceMonitor The monitor. + * @see net.jxta.impl.meter.MonitorManager + */ + public void setRendezvousServiceMonitor(RendezvousServiceMonitor rendezvousServiceMonitor) { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING) { + this.rendezvousServiceMonitor = rendezvousServiceMonitor; + + if (rendezvousServiceMonitor != null) { + this.rendezvousMeter = rendezvousServiceMonitor.getRendezvousMeter(); + } + } + } + + /** + * Resets the local idea of the lease to the specified value. + * As a result a lease response must be sought and obtained within the + * new specified delay or the rdv is considered disconnected. + * + * @param peer The peer to be challenged + * @param delay The delay + */ + public abstract void challengeRendezVous(ID peer, long delay); + + /** + * Attempt to connect to the specified rendezvous peer. + * + * @param addr The endpoint address of the rendezvous peer. + * @param hint An optional hint which may be {@code null}. + * @throws IOException If no connection could be made to the specified peer. + */ + public abstract void connectToRendezVous(EndpointAddress addr, Object hint) throws IOException; + + /** + * Remove a RendezVousService point. + * + * @param peerID the PeerId of the RendezVous to disconnect from. + */ + public abstract void disconnectFromRendezVous(ID peerID); + + /** + * Returns the peers that are currently connected to this peer. + * + * @return The peers that are currently connected to this peer. + */ + public abstract Vector getConnectedPeerIDs(); + + /** + * Propagates a message onto as many peers on the local network + * as possible. Typically the message will go to all the peers to + * which at least one endpoint transport can address without using + * the router. + *

            + * This method sends the message to all peers, rendezvous peers and + * edge peer. This method of propagation is very expensive and should + * not be frequently used. When rendezvous peers are used in order to + * cache index of data, it is more efficient to use the walk() method. + *

            + * Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + *

            + * Loop and TTL control are performed automatically. + *

            + * Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param msg is the message to propagate. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param initialTTL is the maximum TTL of the message (note that the Rendezvous + * Service implementation is free to decrease that value. + * @throws java.io.IOException if an io error occurs + */ + public abstract void propagate(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException; + + /** + * Propagates a message onto as many peers on the local network + * as possible. Typically the message will go to all the peers to + * which at least one endpoint transport can address without using + * the router. + *

            + * This method sends the message to all peers, rendezvous peers and + * edge peer. This method of propagation is very expensive and should + * not be frequently used. When rendezvous peers are used in order to + * cache index of data, it is more efficient to use the walk() method. + *

            + * Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + *

            + * Loop and TTL control are performed automatically. + *

            + * Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param destPeerIds An enumeration of the peers that are recipients of the + * propagated message. + * @param msg is the message to propagate. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param initialTTL is the maximum TTL of the message (note that the Rendezvous + * Service implementation is free to decrease that value. + * @throws java.io.IOException if an io error occurs + */ + public abstract void propagate(Enumeration destPeerIds, Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException; + + /** + * Propagates a message onto as many peers on the local network + * as possible. Typically the message will go to all the peers to + * which at least one endpoint transport can address without using + * the router. + *

            + * Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + *

            + * Loop and TTL control are performed automatically. + *

            + * Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param msg is the message to propagate. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param initialTTL is the maximum TTL of the message (note that the Rendezvous + * Service implementation is free to decrease that value. + * @throws java.io.IOException if an io error occurs + */ + public abstract void propagateToNeighbors(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException; + + /** + * Return true if connected to a rendezvous. + * + * @return true if connected to a rendezvous, false otherwise + */ + public abstract boolean isConnectedToRendezVous(); + + /** + ** The following API is related to the new Rendezvous Peer walk mechanism. + ** + **/ + + /** + * Walk a message through the rendezvous peers of the network: only + * rendezvous peers will receive the message. + *

            + * Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + *

            + * Loop and TTL control are performed automatically. + *

            + * Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param msg is the message to walk. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param initialTTL is the maximum TTL of the message (note that the Rendezvous + * Service implementation is free to decrease that value. + * @throws IOException when walking the message is impossible (network failure) + */ + public abstract void walk(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException; + + /** + * Walk a message through the rendezvous peers of the network: only + * rendezvous peers will receive the message. + *

            + * Only a single HOP at a time is performed. Messages are always + * delivered to the destination handler on arrival. This handler + * is responsible for repropagating further, if deemed appropriate. + *

            + * Loop and TTL control are performed automatically. + *

            + * Messages can be propagated via this method for the first time or + * can be re-propagated by re-using a message that came in via propagation. + * In the later case, the TTL and loop detection parameters CANNOT be + * re-initialized. If one wants to "re-propagate" a message with a new TTL + * and blank gateways list one must generate a completely new message. + * This limits the risk of accidental propagation storms, although they + * can always be engineered deliberately. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param destPeerIDs is a Vector of PeerID of the peers which are receiving + * first the walker. Note that each entry in the Vector will create its own + * walker. + * @param msg is the message to walk. + * @param serviceName is the name of the service + * @param serviceParam is the parameter of the service + * @param initialTTL is the maximum TTL of the message (note that the Rendezvous + * Service implementation is free to decrease that value. + * @throws IOException when walking the message is impossible (network failure) + */ + public abstract void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException; + + /** + * Process a propagated message. + * + * @param message the message received + * @param propHdr the message header + * @param srcAddr the source address + * @param dstAddr the message destination addreess + */ + protected void processReceivedMessage(Message message, RendezVousPropagateMessage propHdr, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + EndpointListener listener = rdvService.endpoint.getIncomingMessageListener(dstAddr.getServiceName(), + dstAddr.getServiceParameter()); + + if (listener != null) { + // We have a local listener for this message. Deliver it. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Calling local listener " + listener.getClass().getName() + " for [" + dstAddr.getServiceName() + "/" + + dstAddr.getServiceParameter() + "] with " + message + " (" + propHdr.getMsgId() + ")"); + } + + rdvService.endpoint.processIncomingMessage(message, srcAddr, dstAddr); + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedMessageProcessedLocally(); + } + + // NOTE: this this is only beneficial in ad-hoc mode with no rendezvous infrastructure + // with one node bridging two networks (2 interfaces). + // This should not be a base feature but rather an ad-hoc mode only feature, as + // it creates additional unnecessary traffic leading to message loss and latency. + // hamada disabling this feature as a general base functionality. + // This should addressed differently in Ad-hoc mode, where a multi-homed node would + // repropagate when more than one interface is enabled + + // Pass the message on. + // repropagate(message, propHdr, dstAddr.getServiceName(), dstAddr.getServiceParameter()); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No message listener found for ServiceName :" + dstAddr.getServiceName() + " ServiceParam :" + + dstAddr.getServiceParameter()); + } + } + } + + /** + * Responsible for forwarding received messages to the rest of the network + * as appropriate. This generally only makes sense for multicast or + * broadcast scenarios. + * + * @param msg the message to be repropagated. + * @param propHdr It's current propagation header. + * @param serviceName The destination service. + * @param serviceParam The destination service parameter. + */ + protected abstract void repropagate(Message msg, RendezVousPropagateMessage propHdr, String serviceName, String serviceParam); + + public abstract void propagateInGroup(Message msg, String serviceName, String serviceParam, int ttl) throws IOException; + + /** + * Propagates the message via endpoint propagation (multicast/broadcast) on + * all Message Transports. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param msg The message to be propagated. + * @param propHdr It's current propagation header. + * @throws java.io.IOException if an io error occurs + */ + protected void sendToNetwork(Message msg, RendezVousPropagateMessage propHdr) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Endpoint propagating " + msg + " (" + propHdr.getMsgId() + ")"); + } + + rdvService.endpoint.propagate(msg, PropSName, PropPName); + } + + /** + * Convenience method for constructing an endpoint address from an id + * + * @param destPeer peer id + * @param serv the service name (if any) + * @param parm the service param (if any) + * @return endpointAddress for this peer id. + */ + protected static EndpointAddress mkAddress(String destPeer, String serv, String parm) { + ID asID; + try { + asID = IDFactory.fromURI(new URI(destPeer)); + } catch (URISyntaxException caught) { + throw new IllegalArgumentException(caught.getMessage()); + } + + return mkAddress(asID, serv, parm); + } + + /** + * Convenience method for constructing an endpoint address from an id + * + * @param destPeer peer id + * @param serv the service name (if any) + * @param parm the service param (if any) + * @return endpointAddress for this peer id. + */ + protected static EndpointAddress mkAddress(ID destPeer, String serv, String parm) { + EndpointAddress addr = new EndpointAddress(RDV_MSG_NAMESPACE_NAME, destPeer.getUniqueValue().toString(), serv, parm); + return addr; + } + + /** + * Get propagate header from the message. + * + * @param msg The source message. + * @return The message's propagate header if any, otherwise null. + */ + protected RendezVousPropagateMessage getPropHeader(Message msg) { + + MessageElement elem = msg.getMessageElement(RDV_MSG_NAMESPACE_NAME, PROP_HDR_ELEMENT_NAME); + + if (elem == null) { + return null; + } + + try { + StructuredDocument asDoc = StructuredDocumentFactory.newStructuredDocument(elem); + return new RendezVousPropagateMessage(asDoc); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not get prop header of " + msg, failed); + } + IllegalArgumentException failure = new IllegalArgumentException("Could not get prop header of " + msg); + failure.initCause(failed); + throw failure; + } + } + + /** + * Check and updates the header message element + * + * @param msg the message to check + * @return an upadate message + */ + protected RendezVousPropagateMessage checkPropHeader(Message msg) { + RendezVousPropagateMessage propHdr; + + try { + propHdr = getPropHeader(msg); + if (null == propHdr) { + // No header. Discard the message + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Discarding " + msg + " -- missing propagate header."); + } + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.invalidMessageReceived(); + } + return null; + } + } catch (Exception failure) { + // Bad header. Discard the message + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Discarding " + msg + " -- bad propagate header.", failure); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.invalidMessageReceived(); + } + return null; + } + // Look at the Propagate header if any and check for loops. + // Do not remove it; we do not have to change it yet, and we have + // do look at it at different places and looking costs less on + // incoming elements than on outgoing. + + // TTL detection. A message arriving with TTL <= 0 should not even + // have been sent. Kill it. + + if (propHdr.getTTL() <= 0) { + // This message is dead on arrival. Drop it. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding " + msg + "(" + propHdr.getMsgId() + ") -- dead on arrival (TTl=" + propHdr.getTTL() + ")."); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedDeadMessage(); + } + return null; + } + + if (!rdvService.addMsgId(propHdr.getMsgId())) { + // We already received this message - discard + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding " + msg + "(" + propHdr.getMsgId() + ") -- feedback."); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedDuplicateMessage(); + } + return null; + } + + // Loop detection + if (propHdr.isVisited(group.getPeerID().toURI())) { + // Loop is detected - discard. + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding " + msg + "(" + propHdr.getMsgId() + ") -- loopback."); + } + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedLoopbackMessage(); + } + return null; + } + // Message is valid + return propHdr; + } + + protected RendezVousPropagateMessage updatePropHeader(Message msg, RendezVousPropagateMessage propHdr, String serviceName, String serviceParam, int initialTTL) { + + boolean newHeader = false; + + if (null == propHdr) { + propHdr = newPropHeader(serviceName, serviceParam, initialTTL); + newHeader = true; + } else { + if (null == updatePropHeader(propHdr, initialTTL)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("TTL expired for " + msg + " (" + propHdr.getMsgId() + ") TTL=" + propHdr.getTTL()); + } + return null; + } + } + + XMLDocument propHdrDoc = (XMLDocument) propHdr.getDocument(MimeMediaType.XMLUTF8); + MessageElement elem = new TextDocumentMessageElement(PROP_HDR_ELEMENT_NAME, propHdrDoc, null); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine((newHeader ? "Added" : "Updated") + " prop header for " + msg + " (" + propHdr.getMsgId() + ") TTL = " + + propHdr.getTTL()); + } + + msg.replaceMessageElement(RDV_MSG_NAMESPACE_NAME, elem); + return propHdr; + } + + /** + * Adds a propagation header to the given message with the given default + * TTL. Also adds this peer to the path recorded in the message. + * + * @param serviceName the service name + * @param serviceParam the parameter + * @param initialTTL initial TTL + * @return a updated message with the proper TTL and ID + */ + private RendezVousPropagateMessage newPropHeader(String serviceName, String serviceParam, int initialTTL) { + + RendezVousPropagateMessage propHdr = new RendezVousPropagateMessage(); + + propHdr.setTTL(initialTTL); + propHdr.setDestSName(serviceName); + propHdr.setDestSParam(serviceParam); + + UUID msgID = rdvService.createMsgId(); + + propHdr.setMsgId(msgID); + rdvService.addMsgId(msgID); + + // Add this peer to the path. + propHdr.addVisited(group.getPeerID().toURI()); + + return propHdr; + } + + /** + * Updates the propagation header of the message. Also adds this peer to the + * path recorded in the message. Returns true if the message should be + * repropagated, false otherwise. + * + * @param propHdr The propHdr for the message. + * @param maxTTL The maximum TTL which will be allowed. + * @return The updated propagate header if the message should be + * repropagated otherwise null. + */ + private RendezVousPropagateMessage updatePropHeader(RendezVousPropagateMessage propHdr, int maxTTL) { + + int msgTTL = propHdr.getTTL(); + URI me = group.getPeerID().toURI(); + + int useTTL = msgTTL; + + if (!propHdr.isVisited(me)) { + // only reduce TTL if message has not previously visited us. + useTTL--; + } + + // ensure TTL does not exceed maxTTL + useTTL = Math.min(useTTL, maxTTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Updating propagation header (" + propHdr.getMsgId() + ") TTL: " + msgTTL + "-->" + useTTL); + } + + propHdr.setTTL(useTTL); + + // Add this peer to the path. + propHdr.addVisited(me); + + // If message came in with TTL one or less, it was last trip. It can not go any further. + return (useTTL <= 0) ? null : propHdr; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/StdRendezVousService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/StdRendezVousService.java new file mode 100644 index 000000000..f0c1153f9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/StdRendezVousService.java @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.endpoint.EndpointUtils; +import net.jxta.impl.rendezvous.rdv.RdvPeerRdvService; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeterBuildSettings; +import net.jxta.impl.rendezvous.rpv.PeerViewElement; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.Timer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Base class for providers which implement the JXTA Standard Rendezvous + * Protocol. + * + * @see JXTA Protocols Specification : Rendezvous Protocol + */ +public abstract class StdRendezVousService extends RendezVousServiceProvider { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(StdRendezVousService.class.getName()); + + public final static String ConnectRequest = "Connect"; + public final static String DisconnectRequest = "Disconnect"; + public final static String ConnectedPeerReply = "ConnectedPeer"; + public final static String ConnectedLeaseReply = "ConnectedLease"; + public final static String ConnectedRdvAdvReply = "RdvAdvReply"; + + /** + * Default Maximum TTL. + */ + protected static final int DEFAULT_MAX_TTL = 200; + + protected final String pName; + protected final String pParam; + + /** + * The registered handler for messages using the Standard Rendezvous + * Protocol. + * + * @see JXTA Protocols Specification : Rendezvous Protocol + */ + private StdRdvProtocolListener handler; + + protected final Timer timer; + + /** + * Interface for listeners to : <assignedID>/ + */ + protected interface StdRdvProtocolListener extends EndpointListener {} + + /** + * Constructor + * + * @param group the PeerGroup + * @param rdvService the parent rendezvous service + */ + protected StdRendezVousService(PeerGroup group, RendezVousServiceImpl rdvService) { + + super(group, rdvService); + + MAX_TTL = DEFAULT_MAX_TTL; + + pName = rdvService.getAssignedID().toString(); + pParam = group.getPeerGroupID().getUniqueValue().toString(); + + timer = new Timer("StdRendezVousService Timer for " + group.getPeerGroupID(), true); + } + + /** + * {@inheritDoc} + */ + protected int startApp(String[] argv, StdRdvProtocolListener handler) { + + this.handler = handler; + + rdvService.endpoint.addIncomingMessageListener(handler, pName, null); + + return super.startApp(argv); + } + + /** + * {@inheritDoc} + */ + @Override + public void stopApp() { + EndpointListener shouldbehandler = rdvService.endpoint.removeIncomingMessageListener(pName, null); + + if (handler != shouldbehandler) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Unregistered listener was not as expected." + handler + " != " + shouldbehandler); + } + } + + timer.cancel(); + + super.stopApp(); + } + + /** + * {@inheritDoc} + */ + @Override + public void processReceivedMessage(Message message, RendezVousPropagateMessage propHdr, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (srcAddr.getProtocolName().equalsIgnoreCase("jxta")) { + String idstr = ID.URIEncodingName + ":" + ID.URNNamespace + ":" + srcAddr.getProtocolAddress(); + + ID peerid; + try { + peerid = IDFactory.fromURI(new URI(idstr)); + } catch (URISyntaxException badID) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Bad ID in message", badID); + } + return; + } + + if (!group.getPeerID().equals(peerid)) { + PeerConnection pConn = getPeerConnection(peerid); + + if (null == pConn) { + PeerViewElement pve; + + if (this instanceof RdvPeerRdvService) { + // cheap hack.... + pve = ((RdvPeerRdvService) this).rpv.getPeerViewElement(peerid); + } else { + pve = null; + } + + if (null == pve) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + message + " (" + propHdr.getMsgId() + ") from unrecognized peer : " + peerid); + } + + propHdr.setTTL(Math.min(propHdr.getTTL(), 3)); // will be reduced during repropagate stage. + + // FIXME 20040503 bondolo need to add tombstones so that we don't end up spamming disconnects. + if (rdvService.isRendezVous() || (getPeerConnections().length > 0)) { + // edge peers with no rdv should not send disconnect. + sendDisconnect(peerid, null); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + message + " (" + propHdr.getMsgId() + ") from " + pve); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + message + " (" + propHdr.getMsgId() + ") from " + pConn); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + message + " (" + propHdr.getMsgId() + ") from loopback."); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received " + message + " (" + propHdr.getMsgId() + ") from network -- repropagating with TTL 2"); + } + + propHdr.setTTL(Math.min(propHdr.getTTL(), 3)); // will be reduced during repropagate stage. + } + super.processReceivedMessage(message, propHdr, srcAddr, dstAddr); + } + + /** + * {@inheritDoc} + */ + @Override + public void propagate(Enumeration destPeerIDs, Message msg, String serviceName, String serviceParam, int initialTTL) { + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Propagating " + msg + "(TTL=" + useTTL + ") to :" + "\n\tsvc name:" + serviceName + "\tsvc params:" + + serviceParam); + } + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, useTTL); + + if (null != propHdr) { + int numPeers = 0; + + try { + while (destPeerIDs.hasMoreElements()) { + ID dest = destPeerIDs.nextElement(); + + try { + PeerConnection pConn = getPeerConnection(dest); + + // TODO: make use of PeerView connections as well + if (null == pConn) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " (" + propHdr.getMsgId() + ") to " + dest); + } + + EndpointAddress addr = mkAddress(dest, PropSName, PropPName); + + Messenger messenger = rdvService.endpoint.getMessengerImmediate(addr, null); + + if (null != messenger) { + try { + messenger.sendMessage(msg); + } catch (IOException ignored) { + continue; + } + } else { + continue; + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " (" + propHdr.getMsgId() + ") to " + pConn); + } + + if (pConn.isConnected()) { + pConn.sendMessage(msg.clone(), PropSName, PropPName); + } else { + continue; + } + } + numPeers++; + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to send " + msg + " (" + propHdr.getMsgId() + ") to " + dest); + } + } + } + } finally { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToPeers(numPeers); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagated " + msg + " (" + propHdr.getMsgId() + ") to " + numPeers + " peers."); + } + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Declined to send " + msg + " ( no propHdr )"); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void propagateToNeighbors(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + msg + "(TTL=" + useTTL + ") to neighbors to :" + "\n\tsvc name:" + serviceName+ "\tsvc params:" + serviceParam); + } + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, useTTL); + + if (null != propHdr) { + try { + sendToNetwork(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToNeighbors(); + } + } catch (IOException failed) { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToNeighborsFailed(); + } + + throw failed; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void repropagate(Message msg, RendezVousPropagateMessage propHdr, String serviceName, String serviceParam) { + msg = msg.clone(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Repropagating " + msg + " (" + propHdr.getMsgId() + ")"); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedMessageRepropagatedInGroup(); + } + + try { + propHdr = updatePropHeader(msg, propHdr, serviceName, serviceParam, MAX_TTL); + + if (null != propHdr) { + // Note (hamada): This is an unnecessary operation, and serves + // no purpose other than the additional loads it imposes on the + // rendezvous. Local subnet network operations should be (and are) + // sufficient to achieve the goal. + // sendToEachConnection(msg, propHdr); + sendToNetwork(msg, propHdr); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No propagate header, declining to repropagate " + msg + ")"); + } + } + } catch (Exception ez1) { + // Not much we can do + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + if (propHdr != null) { + LOG.log(Level.WARNING, "Failed to repropagate " + msg + " (" + propHdr.getMsgId() + ")", ez1); + } else { + LOG.log(Level.WARNING, "Could to repropagate " + msg, ez1); + } + } + } + } + + /** + * Returns the peer connection or null if not present. + * + * @param id the node ID + * @return PeerConnection the peer connection or null if not present. + */ + public abstract PeerConnection getPeerConnection(ID id); + + /** + * Returns an array of the current peer connections. + * + * @return An array of the current peer connections. + */ + protected abstract PeerConnection[] getPeerConnections(); + + /** + * Sends to all connected peers. + *

            + * Note: The original msg is not modified and may be reused upon return. + * + * @param msg The message to be sent. + * @param propHdr The propagation header associated with the message. + * @return the number of nodes the message was sent to + */ + protected int sendToEachConnection(Message msg, RendezVousPropagateMessage propHdr) { + List peers = Arrays.asList(getPeerConnections()); + int sentToPeers = 0; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + "(" + propHdr.getMsgId() + ") to " + peers.size() + " peers."); + } + + for (PeerConnection pConn : peers) { + // Check if this rendezvous has already processed this propagated message. + if (!pConn.isConnected()) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Skipping " + pConn + " for " + msg + "(" + propHdr.getMsgId() + ") -- disconnected."); + } + // next! + continue; + } + + if (propHdr.isVisited(pConn.getPeerID().toURI())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Skipping " + pConn + " for " + msg + "(" + propHdr.getMsgId() + ") -- already visited."); + } + // next! + continue; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + "(" + propHdr.getMsgId() + ") to " + pConn); + } + + if (pConn.sendMessage(msg.clone(), PropSName, PropPName)) { + sentToPeers++; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent " + msg + "(" + propHdr.getMsgId() + ") to " + sentToPeers + " of " + peers.size() + " peers."); + } + + return sentToPeers; + } + + /** + * Sends a disconnect message to the specified peer. + * + * @param peerid The peer to be disconnected. + * @param padv The peer to be disconnected. + */ + protected void sendDisconnect(ID peerid, PeerAdvertisement padv) { + + Message msg = new Message(); + + // The request simply includes the local peer advertisement. + try { + msg.replaceMessageElement("jxta", new TextDocumentMessageElement(DisconnectRequest, getPeerAdvertisementDoc(), null)); + + EndpointAddress addr = mkAddress(peerid, null, null); + + RouteAdvertisement hint = null; + + if (null != padv) { + hint = EndpointUtils.extractRouteAdv(padv); + } + + Messenger messenger = rdvService.endpoint.getMessengerImmediate(addr, hint); + + if (null == messenger) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not get messenger for " + peerid); + } + return; + } + + messenger.sendMessage(msg, pName, pParam); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "sendDisconnect failed", e); + } + } + } + + /** + * Sends a disconnect message to the specified peer. + * + * @param pConn The peer to be disconnected. + */ + protected void sendDisconnect(PeerConnection pConn) { + + Message msg = new Message(); + + // The request simply includes the local peer advertisement. + try { + msg.replaceMessageElement("jxta", new TextDocumentMessageElement(DisconnectRequest, getPeerAdvertisementDoc(), null)); + + pConn.sendMessage(msg, pName, pParam); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "sendDisconnect failed", e); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/adhoc/AdhocPeerRdvService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/adhoc/AdhocPeerRdvService.java new file mode 100644 index 000000000..8d7b0d376 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/adhoc/AdhocPeerRdvService.java @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.adhoc; + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.id.ID; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.rendezvous.RendezVousPropagateMessage; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; +import net.jxta.impl.rendezvous.RendezVousServiceProvider; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeterBuildSettings; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ConfigParams; +import net.jxta.rendezvous.RendezvousEvent; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A JXTA {@link net.jxta.rendezvous.RendezVousService} implementation which + * implements the ad hoc portion of the standard JXTA Rendezvous Protocol (RVP). + * + * @see net.jxta.rendezvous.RendezVousService + * @see JXTA Protocols Specification : Rendezvous Protocol + */ +public class AdhocPeerRdvService extends RendezVousServiceProvider { + + /** + * Log4J Logger + */ + private final static transient Logger LOG = Logger.getLogger(AdhocPeerRdvService.class.getName()); + + /** + * Default Maximum TTL. This is minimum needed to bridge networks. + */ + private static final int DEFAULT_MAX_TTL = 2; + + /** + * Constructor + * + * @param g the peergroup + * @param rdvService the rendezvous service + */ + public AdhocPeerRdvService(PeerGroup g, RendezVousServiceImpl rdvService) { + + super(g, rdvService); + + ConfigParams confAdv = g.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + if (confAdv != null) { + Advertisement adv = null; + + try { + XMLDocument configDoc = (XMLDocument) confAdv.getServiceParam(rdvService.getAssignedID()); + + if (null != configDoc) { + // XXX 20041027 backwards compatibility + configDoc.addAttribute("type", RdvConfigAdv.getAdvertisementType()); + + adv = AdvertisementFactory.newAdvertisement(configDoc); + } + } catch (java.util.NoSuchElementException ignored) {// ignored + } + + if (adv instanceof RdvConfigAdv) { + RdvConfigAdv rdvConfigAdv = (RdvConfigAdv) adv; + + MAX_TTL = (-1 != rdvConfigAdv.getMaxTTL()) ? rdvConfigAdv.getMaxTTL() : DEFAULT_MAX_TTL; + } else { + MAX_TTL = DEFAULT_MAX_TTL; + } + } else { + MAX_TTL = DEFAULT_MAX_TTL; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RendezVous Service is initialized for " + g.getPeerGroupID() + " as an ad hoc peer. "); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected int startApp(String[] arg) { + + super.startApp(arg); + + // The other services may not be fully functional but they're there + // so we can start our subsystems. + // As for us, it does not matter if our methods are called between init + // and startApp(). + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.startEdge(); + } + + // we are nominally an edge peer + rdvService.generateEvent(RendezvousEvent.BECAMEEDGE, group.getPeerID()); + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void stopApp() { + + if (closed) { + return; + } + + closed = true; + + super.stopApp(); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.stopEdge(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Vector getConnectedPeerIDs() { + + return new Vector(0); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isConnectedToRendezVous() { + // It's as connected as it's ever going to get.... + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void connectToRendezVous(EndpointAddress addr, Object hint) throws IOException { + + throw new UnsupportedOperationException("Not supported by ad hoc"); + } + + /** + * {@inheritDoc} + */ + @Override + public void challengeRendezVous(ID peer, long delay) { + + throw new UnsupportedOperationException("Not supported by ad hoc"); + } + + /** + * {@inheritDoc} + */ + @Override + public void disconnectFromRendezVous(ID peerId) { + + throw new UnsupportedOperationException("Not supported by ad hoc"); + } + + /** + * {@inheritDoc} + */ + @Override + public void propagate(Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + + ttl = Math.min(ttl, MAX_TTL); + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, ttl); + + if (null != propHdr) { + sendToNetwork(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToGroup(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void propagateInGroup(Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + + ttl = Math.min(ttl, MAX_TTL); + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, ttl); + + if (null != propHdr) { + sendToNetwork(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToGroup(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void propagate(Enumeration destPeerIDs, Message msg, String serviceName, String serviceParam, int ttl) { + + ttl = Math.min(ttl, MAX_TTL); + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, ttl); + + if (null != propHdr) { + int numPeers = 0; + + try { + while (destPeerIDs.hasMoreElements()) { + ID dest = destPeerIDs.nextElement(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " to client " + dest); + } + + EndpointAddress addr = mkAddress(dest, PropSName, PropPName); + + Messenger messenger = rdvService.endpoint.getMessenger(addr); + + if (null != messenger) { + try { + messenger.sendMessage(msg); + numPeers++; + } catch (IOException failed) {// ignored + } + } + } + } finally { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToPeers(numPeers); + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void propagateToNeighbors(Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + + ttl = Math.min(ttl, MAX_TTL); + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, ttl); + + if (null != propHdr) { + try { + sendToNetwork(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToNeighbors(); + } + } catch (IOException failed) { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToNeighborsFailed(); + } + + throw failed; + } + } + } + + /** + * {@inheritDoc} + *

            + * The definition of walk says that we should forward the message to the + * most appropriate peer. Since we don't make any effort keep track of other + * peers we don't have anywhere to send the message. + */ + @Override + public void walk(Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + // Do nothing. Really. + } + + /** + * {@inheritDoc} + *

            + * Unlike the undirected walk we are told where to send the message so we + * deliver it as requested. + */ + @Override + public void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int ttl) throws IOException { + + propagate(destPeerIDs.elements(), msg, serviceName, serviceParam, ttl); + } + + /** + * {@inheritDoc} + */ + @Override + protected void repropagate(Message msg, RendezVousPropagateMessage propHdr, String serviceName, String serviceParam) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Repropagating " + msg + " (" + propHdr.getMsgId() + ")"); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedMessageRepropagatedInGroup(); + } + + try { + propHdr = updatePropHeader(msg, propHdr, serviceName, serviceParam, MAX_TTL); + + if (null != propHdr) { + sendToNetwork(msg, propHdr); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No propagate header, declining to repropagate " + msg + ")"); + } + } + } catch (Exception ez1) { + // Not much we can do + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + if (propHdr != null) { + LOG.log(Level.WARNING, "Failed to repropagate " + msg + " (" + propHdr.getMsgId() + ")", ez1); + } else { + LOG.log(Level.WARNING, "Could to repropagate " + msg, ez1); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/edge/EdgePeerRdvService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/edge/EdgePeerRdvService.java new file mode 100644 index 000000000..74b9e05e7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/edge/EdgePeerRdvService.java @@ -0,0 +1,866 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.edge; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimerTask; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.IOException; +import java.net.URISyntaxException; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessageTransport; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.endpoint.relay.RelayReferralSeedingManager; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.Module; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.rendezvous.RendezvousEvent; + +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.rendezvous.PeerConnection; +import net.jxta.impl.rendezvous.RendezVousPropagateMessage; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; +import net.jxta.impl.rendezvous.RendezVousServiceProvider; +import net.jxta.impl.rendezvous.StdRendezVousService; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousConnectionMeter; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeterBuildSettings; +import net.jxta.impl.rendezvous.rpv.PeerviewSeedingManager; +import net.jxta.impl.util.SeedingManager; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.URISeedingManager; + +/** + * A JXTA {@link net.jxta.rendezvous.RendezVousService} implementation which + * implements the client portion of the standard JXTA Rendezvous Protocol (RVP). + * + * @see net.jxta.rendezvous.RendezVousService + * @see JXTA Protocols Specification : Rendezvous Protocol + */ +public class EdgePeerRdvService extends StdRendezVousService { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(EdgePeerRdvService.class.getName()); + + /** + * Interval in milliseconds at which we will check our rendezvous connection. + */ + private final static long MONITOR_INTERVAL = 15 * TimeUtils.ASECOND; + + /** + * Number of rendezvous we will try to connect to. + */ + private final int MAX_RDV_CONNECTIONS = 1; + + /** + * The default amount of time we will attempt to renew a lease before it + * expires. + */ + private long LEASE_MARGIN = 5 * TimeUtils.AMINUTE; + + /** + * Our source for rendezvous server seeds. + */ + private final SeedingManager seedingManager; + + /** + * Our current seeds. + */ + private final List seeds = new ArrayList(); + + /** + * Our current connections with RendezVous peers. + */ + private final Map rendezVous = Collections.synchronizedMap(new HashMap()); + + /** + * Standard Constructor + * + * @param group Description of Parameter + * @param rdvService Description of Parameter + */ + public EdgePeerRdvService(PeerGroup group, RendezVousServiceImpl rdvService) { + + super(group, rdvService); + + Advertisement adv = null; + ConfigParams confAdv = group.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + if (confAdv != null) { + adv = confAdv.getSvcConfigAdvertisement(rdvService.getAssignedID()); + } + + RdvConfigAdv rdvConfigAdv; + + if (!(adv instanceof RdvConfigAdv)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating new RdvConfigAdv for defaults."); + } + + rdvConfigAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + } else { + rdvConfigAdv = (RdvConfigAdv) adv; + } + + if (-1 != rdvConfigAdv.getMaxTTL()) { + MAX_TTL = rdvConfigAdv.getMaxTTL(); + } + + if (0 != rdvConfigAdv.getLeaseMargin()) { + LEASE_MARGIN = rdvConfigAdv.getLeaseMargin(); + } + + String serviceName = rdvService.getAssignedID().toString() + group.getPeerGroupID().getUniqueValue().toString(); + if (PeerGroupID.worldPeerGroupID.equals(group.getParentGroup().getPeerGroupID())) { + URISeedingManager uriSeedingManager; + + if (rdvConfigAdv.getProbeRelays()) { + uriSeedingManager = new RelayReferralSeedingManager(rdvConfigAdv.getAclUri(), rdvConfigAdv.getUseOnlySeeds(), group, serviceName); + } else { + uriSeedingManager = new URISeedingManager(rdvConfigAdv.getAclUri(), rdvConfigAdv.getUseOnlySeeds(), group, serviceName); + } + + for (URI aSeeder : Arrays.asList(rdvConfigAdv.getSeedingURIs())) { + uriSeedingManager.addSeedingURI(aSeeder); + } + + for (URI aSeed : Arrays.asList(rdvConfigAdv.getSeedRendezvous())) { + uriSeedingManager.addSeed(aSeed); + } + + this.seedingManager = uriSeedingManager; + } else { + this.seedingManager = new PeerviewSeedingManager(rdvConfigAdv.getAclUri(), group, group.getParentGroup(), serviceName); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RendezVous Service is initialized for " + group.getPeerGroupID() + " as an Edge peer."); + } + } + + /** + * Listener for + *

            + * <assignedID> + */ + private class StdRdvEdgeProtocolListener implements StdRendezVousService.StdRdvProtocolListener { + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupID() + "] processing " + msg); + } + + if ((msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, ConnectedPeerReply) != null) + || (msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, ConnectedRdvAdvReply) != null)) { + processConnectedReply(msg); + } + + if (msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, DisconnectRequest) != null) { + processDisconnectRequest(msg); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected int startApp(String[] arg) { + + super.startApp(arg, new StdRdvEdgeProtocolListener()); + + // The other services may not be fully functional but they're there + // so we can start our subsystems. + // As for us, it does not matter if our methods are called between init + // and startApp(). + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.startEdge(); + } + + rdvService.generateEvent(RendezvousEvent.BECAMEEDGE, group.getPeerID()); + + timer.schedule(new MonitorTask(), 0, MONITOR_INTERVAL); + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void stopApp() { + + if (closed) { + return; + } + + closed = true; + + seedingManager.stop(); + + disconnectFromAllRendezVous(); + + super.stopApp(); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.stopEdge(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Vector getConnectedPeerIDs() { + return new Vector(rendezVous.keySet()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isConnectedToRendezVous() { + return !rendezVous.isEmpty(); + } + + /** + * {@inheritDoc} + */ + @Override + public void connectToRendezVous(EndpointAddress addr, Object hint) { + if (seedingManager instanceof URISeedingManager) { + URISeedingManager uriseed = (URISeedingManager) seedingManager; + + if (hint instanceof RouteAdvertisement) { + uriseed.addSeed((RouteAdvertisement) hint); + } else { + uriseed.addSeed(addr.toURI()); + } + } else if (seedingManager instanceof PeerviewSeedingManager) { + PeerviewSeedingManager pvseed = (PeerviewSeedingManager) seedingManager; + + if (hint instanceof RouteAdvertisement) { + pvseed.addSeed((RouteAdvertisement) hint); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void challengeRendezVous(ID peerid, long delay) { + + // If immediate failure is requested, just do it. + // {@code disconnectFromRendezVous()} will at least get the peer + // removed from the peerView, even if it is not currently a rendezvous + // of ours. That permits to purge from the peerview rdvs that we try + // and fail to connect to, faster than the background keep alive done + // by PeerView itself. + if (delay <= 0) { + removeRdv(peerid, false); + return; + } + + RdvConnection pConn = rendezVous.get(peerid); + + if (null != pConn) { + long adjusted_delay = Math.max(0, Math.min(TimeUtils.toRelativeTimeMillis(pConn.getLeaseEnd()), delay)); + + pConn.setLease(adjusted_delay, adjusted_delay); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void disconnectFromRendezVous(ID peerId) { + removeRdv(peerId, false); + } + + /** + * {@inheritDoc} + */ + @Override + public void propagate(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + msg + "(TTL=" + useTTL + ") to :" + "\n\tsvc name:" + serviceName + "\tsvc params:"+ serviceParam); + } + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, useTTL); + + if (null != propHdr) { + sendToEachConnection(msg, propHdr); + sendToNetwork(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToGroup(); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Declining to propagate " + msg + " (No prop header)"); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void propagateInGroup(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + msg + "(TTL=" + useTTL + ") in group to :" + "\n\tsvc name:" + serviceName + "\tsvc params:" + + serviceParam); + } + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, useTTL); + + if (null != propHdr) { + sendToEachConnection(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToGroup(); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Declining to propagate " + msg + " (No prop header)"); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void walk(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + + propagateInGroup(msg, serviceName, serviceParam, initialTTL); + } + + /** + * {@inheritDoc} + */ + @Override + public void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + + propagate(destPeerIDs.elements(), msg, serviceName, serviceParam, initialTTL); + } + + /** + * @inheritDoc + */ + @Override + public PeerConnection getPeerConnection(ID peer) { + return rendezVous.get(peer); + } + + /** + * @inheritDoc + */ + @Override + protected PeerConnection[] getPeerConnections() { + return rendezVous.values().toArray(new PeerConnection[0]); + } + + private void disconnectFromAllRendezVous() { + + for (RdvConnection pConn : new ArrayList(rendezVous.values())) { + try { + disconnectFromRendezVous(pConn.getPeerID()); + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "disconnectFromRendezVous failed for " + pConn, failed); + } + } + } + } + + /** + * Handle a disconnection request from a remote peer. + * + * @param msg Description of Parameter + */ + private void processDisconnectRequest(Message msg) { + + try { + MessageElement elem = msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, DisconnectRequest); + + if (null != elem) { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(elem); + + PeerAdvertisement adv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + + RdvConnection rdvConnection = rendezVous.get(adv.getPeerID()); + + if (null != rdvConnection) { + rdvConnection.setConnected(false); + removeRdv(adv.getPeerID(), true); + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring disconnect request from " + adv.getPeerID()); + } + } + } + } catch (Exception failure) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure processing disconnect request", failure); + } + } + } + + /** + * Add a rendezvous to our collection of rendezvous peers. + * + * @param padv PeerAdvertisement for the rendezvous peer. + * @param lease The duration of the lease in relative milliseconds. + */ + private void addRdv(PeerAdvertisement padv, long lease) { + + int eventType; + + RdvConnection rdvConnection; + + synchronized (rendezVous) { + rdvConnection = rendezVous.get(padv.getPeerID()); + + if (null == rdvConnection) { + rdvConnection = new RdvConnection(group, rdvService, padv.getPeerID()); + rendezVous.put(padv.getPeerID(), rdvConnection); + eventType = RendezvousEvent.RDVCONNECT; + } else { + eventType = RendezvousEvent.RDVRECONNECT; + } + } + + // Check if the peer is already registered. + if (RendezvousEvent.RDVRECONNECT == eventType) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Renewed RDV lease from " + rdvConnection); + } + + // Already connected, just upgrade the lease + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousServiceMonitor != null)) { + RendezvousConnectionMeter rendezvousConnectionMeter = rendezvousServiceMonitor.getRendezvousConnectionMeter( + padv.getPeerID()); + + rendezvousConnectionMeter.leaseRenewed(lease); + } + } else { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("New RDV lease from " + rdvConnection); + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousServiceMonitor != null)) { + RendezvousConnectionMeter rendezvousConnectionMeter = rendezvousServiceMonitor.getRendezvousConnectionMeter( + padv.getPeerID()); + + rendezvousConnectionMeter.connectionEstablished(lease); + } + } + + rdvConnection.connect(padv, lease, Math.min(LEASE_MARGIN, (lease / 2))); + + rdvService.generateEvent(eventType, padv.getPeerID()); + } + + /** + * Remove the specified rendezvous from our collection of rendezvous. + * + * @param rdvid the id of the rendezvous to remove. + * @param requested if true, indicates a requested operation + */ + private void removeRdv(ID rdvid, boolean requested) { + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Disconnect from RDV " + rdvid); + } + + PeerConnection rdvConnection; + + synchronized (this) { + rdvConnection = rendezVous.remove(rdvid); + } + + if (null != rdvConnection) { + if (rdvConnection.isConnected()) { + rdvConnection.setConnected(false); + sendDisconnect(rdvConnection); + } + } + + rdvService.generateEvent(requested ? RendezvousEvent.RDVDISCONNECT : RendezvousEvent.RDVFAILED, rdvid); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousServiceMonitor != null)) { + RendezvousConnectionMeter rendezvousConnectionMeter = rendezvousServiceMonitor.getRendezvousConnectionMeter( + (PeerID) rdvid); + + rendezvousConnectionMeter.connectionDisconnected(); + } + } + + /** + * Send lease request to the specified peer. + * + * @param pConn The peer to which the message should be sent. + * @throws IOException Thrown for errors sending the lease request. + */ + private void sendLeaseRequest(RdvConnection pConn) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending Lease request to " + pConn); + } + + RendezvousConnectionMeter rendezvousConnectionMeter = null; + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousServiceMonitor != null)) { + rendezvousConnectionMeter = rendezvousServiceMonitor.getRendezvousConnectionMeter(pConn.getPeerID().toString()); + } + + Message msg = new Message(); + + // The request simply includes the local peer advertisement. + msg.replaceMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME + , + new TextDocumentMessageElement(ConnectRequest, getPeerAdvertisementDoc(), null)); + + pConn.sendMessage(msg, pName, pParam); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousConnectionMeter != null)) { + rendezvousConnectionMeter.beginConnection(); + } + } + + /** + * Description of the Method + * + * @param msg Description of Parameter + */ + private void processConnectedReply(Message msg) { + + // get the Peer Advertisement of the RDV. + MessageElement peerElem = msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, ConnectedRdvAdvReply); + + if (null == peerElem) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Missing rendezvous peer advertisement"); + } + + return; + } + + long lease; + + try { + MessageElement el = msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, ConnectedLeaseReply); + + if (el == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("missing lease"); + } + return; + } + lease = Long.parseLong(el.toString()); + } catch (Exception e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Parse lease failed with ", e); + } + return; + } + + ID pId; + MessageElement el = msg.getMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME, ConnectedPeerReply); + + if (el == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("missing rdv peer"); + } + return; + } + + try { + pId = IDFactory.fromURI(new URI(el.toString())); + } catch (URISyntaxException badID) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Bad RDV peer ID"); + } + return; + } + + if (lease <= 0) { + removeRdv(pId, false); + } else { + if (rendezVous.containsKey(pId) || (rendezVous.size() < MAX_RDV_CONNECTIONS)) { + PeerAdvertisement padv = null; + + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(peerElem); + + padv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + } catch (Exception failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed processing peer advertisement"); + } + } + + if (null == padv) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Missing rendezvous peer advertisement"); + } + return; + } + + if (!seedingManager.isAcceptablePeer(padv)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Rejecting lease offer from unacceptable peer : " + padv.getPeerID()); + } + + // XXX bondolo 20061123 perhaps we should send a disconnect here. + + return; + } + + addRdv(padv, lease); + + try { + DiscoveryService discovery = group.getDiscoveryService(); + + if (null != discovery) { + // This is not our own peer adv so we choose not to share it and keep it for only a short time. + discovery.publish(padv, lease * 2, 0); + } + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "failed to publish Rendezvous Advertisement", e); + } + } + + String rdvName = padv.getName(); + + if (null == padv.getName()) { + rdvName = pId.toString(); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RDV Connect Response : peer=" + rdvName + " lease=" + lease + "ms"); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring lease offer from " + pId); + } + // XXX bondolo 20040423 perhaps we should send a disconnect here. + } + } + } + + /** + * A timer task for monitoring our active rendezvous connections. + *

            + * Checks leases, initiates lease renewals, starts new lease requests. + */ + private class MonitorTask extends TimerTask { + + /** + * @inheritDoc + */ + @Override + public void run() { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group + "] Periodic rendezvous check"); + } + + if (closed) { + return; + } + + if (!PeerGroupID.worldPeerGroupID.equals(group.getPeerGroupID())) { + MessageTransport router = rdvService.endpoint.getMessageTransport("jxta"); + + if (null == router) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Rendezvous connection stalled until router is started!"); + } + + // Reschedule another run very soon. + timer.schedule(new MonitorTask(), 2 * TimeUtils.ASECOND); + return; + } + } + + List currentRdvs = new ArrayList(rendezVous.values()); + + for (RdvConnection pConn : currentRdvs) { + try { + if (!pConn.isConnected()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.fine("[" + group.getPeerGroupID() + "] Lease expired. Disconnected from " + pConn); + } + removeRdv(pConn.getPeerID(), false); + continue; + } + + if (TimeUtils.toRelativeTimeMillis(pConn.getRenewal()) <= 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupID() + "] Attempting lease renewal for " + pConn); + } + + sendLeaseRequest(pConn); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "[" + group.getPeerGroupID() + "] Failure while checking " + pConn, e); + } + } + } + + // Not enough Rdvs? Try finding more. + if (rendezVous.size() < MAX_RDV_CONNECTIONS) { + if (seeds.isEmpty()) { + seeds.addAll(Arrays.asList(EdgePeerRdvService.this.seedingManager.getActiveSeedRoutes())); + } + + int sentLeaseRequests = 0; + + while (!seeds.isEmpty() && (sentLeaseRequests < 3)) { + RouteAdvertisement aSeed = seeds.remove(0); + + Message msg = new Message(); + + // The lease request simply includes the local peer advertisement. + msg.addMessageElement(RendezVousServiceProvider.RDV_MSG_NAMESPACE_NAME + , + new TextDocumentMessageElement(ConnectRequest, getPeerAdvertisementDoc(), null)); + + Messenger msgr = null; + + if (null == aSeed.getDestPeerID()) { + // It is an incomplete route advertisement. We are going to assume that it is only a wrapper for a single ea. + List seed_eas = aSeed.getDest().getVectorEndpointAddresses(); + + if (!seed_eas.isEmpty()) { + EndpointAddress aSeedHost = new EndpointAddress(seed_eas.get(0)); + + msgr = rdvService.endpoint.getMessengerImmediate(aSeedHost, null); + } + } else { + // We have a full route, send it to the virtual address of the route! + EndpointAddress aSeedHost = new EndpointAddress(aSeed.getDestPeerID(), null, null); + + msgr = rdvService.endpoint.getMessengerImmediate(aSeedHost, aSeed); + } + + if (null != msgr) { + try { + msgr.sendMessageN(msg, pName, pParam); + sentLeaseRequests++; + } catch (Exception failed) { + // ignored + ; + } + } + } + } else { + // We don't need any of the current seeds. Get new ones when we need them. + seeds.clear(); + } + } catch (Throwable t) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught throwable in thread :" + Thread.currentThread().getName(), t); + } + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/edge/RdvConnection.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/edge/RdvConnection.java new file mode 100644 index 000000000..62b3cba44 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/edge/RdvConnection.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.edge; + +import net.jxta.id.ID; +import net.jxta.impl.rendezvous.PeerConnection; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; +import net.jxta.impl.util.TimeUtils; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PeerAdvertisement; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +/** + * Manages a connection with a client or a rendezvous peer. + */ +public class RdvConnection extends PeerConnection { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(RdvConnection.class.getName()); + + protected long leasedTil; + protected long beginRenewalAt; + + protected PeerAdvertisement cachedPeerAdvertisement = null; + protected int cachedModCount = -1; + + /** + * Constructor for the PeerConnection object + * + * @param group group context + * @param rdvService the rendezvous service to use for sending messages. + * @param peer destination peerid + */ + public RdvConnection(PeerGroup group, RendezVousServiceImpl rdvService, ID peer) { + super(group, rdvService.endpoint, peer); + + cachedPeerAdvertisement = group.getPeerAdvertisement(); + cachedModCount = cachedPeerAdvertisement.getModCount(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return super.toString() + " / " + Long.toString(TimeUtils.toRelativeTimeMillis(beginRenewalAt)); + } + + /** + * {@inheritDoc} + */ + @Override + protected void setLease(long leaseDuration) { + setLease(leaseDuration, 0); + } + + /** + * Set the lease duration in relative milliseconds. + * + * @param leaseDuration the lease duration in relative milliseconds. + * @param earlyRenewal amount of time in relative milliseconds before lease end to begin renewal + */ + public void setLease(long leaseDuration, long earlyRenewal) { + + if (leaseDuration < earlyRenewal) { + throw new IllegalArgumentException("Renewal scheduled before begining of lease"); + } + + super.setLease(leaseDuration); + beginRenewalAt = TimeUtils.toAbsoluteTimeMillis(leaseDuration - earlyRenewal); + } + + /** + * Declare that we are connected. + * + * @param padv the node advertisement + * @param leaseDuration lease duration in milliseconds + * @param earlyRenewal early renwal in milliseconds + */ + public void connect(PeerAdvertisement padv, long leaseDuration, long earlyRenewal) { + super.connect(leaseDuration); + + setLease(leaseDuration, earlyRenewal); + + // We will almost certainly need a messenger soon. Get it now. + getCachedMessenger(padv); + } + + /** + * Time at which the lease needs renewal in absolute milliseconds. + * + * @return The lease value + */ + public long getRenewal() { + return beginRenewalAt; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeGreeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeGreeter.java new file mode 100644 index 000000000..ebfc19e8f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeGreeter.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.limited; + +import java.io.IOException; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; + +import net.jxta.impl.protocol.LimitedRangeRdvMsg; +import net.jxta.impl.rendezvous.RdvGreeter; +import net.jxta.impl.rendezvous.rpv.PeerViewElement; + +/** + * The limited range rendezvous peer greeter. + * + * @see net.jxta.impl.rendezvous.RdvGreeter + * @see net.jxta.impl.rendezvous.RdvWalk + * @see net.jxta.impl.rendezvous.RdvWalker + * @see net.jxta.impl.protocol.LimitedRangeRdvMsg + */ +public class LimitedRangeGreeter implements EndpointListener, RdvGreeter { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(LimitedRangeGreeter.class.getName()); + + /** + * The walk we are associated with. + */ + private final LimitedRangeWalk walk; + + /** + * XXX It would be nice to avoid making another link to the endpoint. + */ + private final EndpointService endpoint; + + /** + * Constructor + * + * @param walk The walk we will be associated with. + */ + public LimitedRangeGreeter(LimitedRangeWalk walk) { + this.walk = walk; + + this.endpoint = walk.getPeerGroup().getEndpointService(); + + if (!endpoint.addIncomingMessageListener(this, walk.getWalkServiceName(), walk.getWalkServiceParam())) { + throw new IllegalStateException("Could not register endpoint listener for greeter."); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Listening on " + walk.getWalkServiceName() + "/" + walk.getWalkServiceParam()); + } + } + + /** + * {@inheritDoc} + */ + public synchronized void stop() { + endpoint.removeIncomingMessageListener(walk.getWalkServiceName(), walk.getWalkServiceParam()); + } + + /** + * {@inheritDoc} + *

            + * Listens on "LR-Greeter"<groupid>/<walkSvc><walkParam> + *

            + * Currently, all this method has to do, is to invoke the upper layer. + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Processing " + message + " from " + srcAddr); + } + + LimitedRangeRdvMsg rdvMsg = LimitedRangeWalk.getRdvMessage(message); + + // Check and update the Limited Range Rdv Message + if (null == rdvMsg) { + // Message is invalid, drop it + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Limited Range Greeter received invalid " + message + ". Dropping it."); + } + return; + } + + if (rdvMsg.getTTL() <= 0) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("No TTL remaining for " + message + ". Dropping it."); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Limited Range Greeter calling listener"); + } + + try { + walk.getListener().processIncomingMessage(message, srcAddr, dstAddr); + } catch (Throwable ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in listener (" + walk.getListener() + ")", ignored); + } + } + } + + /** + * {@inheritDoc} + */ + public void replyMessage(Message msg, Message reply) throws IOException { + LimitedRangeRdvMsg rdvMsg = LimitedRangeWalk.getRdvMessage(msg); + + if (rdvMsg == null) { + // No RdvMessage. This message was not received by this Greeter. + throw new IOException("LimitedRangeWalker was not able to send message" + ": not from this greeter"); + } + + PeerViewElement pve = walk.getPeerView().getPeerViewElement(rdvMsg.getSrcPeerID()); + + if (null == pve) { + throw new IOException("LimitedRangeWalker was not able to send message" + ": no pve"); + } + + if (!pve.sendMessage(msg, rdvMsg.getSrcSvcName(), rdvMsg.getSrcSvcParams())) { + throw new IOException("LimitedRangeWalker was not able to send message" + ": send failed"); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeWalk.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeWalk.java new file mode 100644 index 000000000..8404161b8 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeWalk.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.limited; + +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.peergroup.PeerGroup; + +import net.jxta.impl.protocol.LimitedRangeRdvMsg; +import net.jxta.impl.rendezvous.RdvWalk; +import net.jxta.impl.rendezvous.rpv.PeerView; + +/** + * This class is the Limited Walk Policy. + * + * @see net.jxta.impl.rendezvous.limited.LimitedRangeWalker + * @see net.jxta.impl.rendezvous.limited.LimitedRangeGreeter + */ +public class LimitedRangeWalk extends RdvWalk { + + /** + * The prefix we will use for service name we use for messaging. + */ + public static final String SERVICENAME = "LR-Greeter"; + + /** + * The name of the message element in which we will store our information. + */ + + public static final String ELEMENTNAME = "LimitedRangeRdvMessage"; + + /** + * The PeerView we walk. + */ + private final PeerView rpv; + + /** + * The service name for listener of this walk. All walkers in the same + * peer group have the same service name. + */ + private final String walkSvcName; + + /** + * The service param for listener of this walk. The walker param is + * composed of the walk service name concated with the walk service param. + */ + private final String walkSvcParam; + + /** + * Our walker (sender) + */ + private LimitedRangeWalker walker = null; + + /** + * Our greeter (listener) + */ + private LimitedRangeGreeter greeter = null; + + /** + * Returns the parsed LimitedRangeRdvMsg from the provided message or + * {@code null} if the message did not contain an appropriate element or + * the element couldn't be parsed. + * + * @param msg the Message which must contain the LimitedRangeRdvMsg. + * @return The LimitedRangeRdvMsg from the message or {@code null}. + */ + static LimitedRangeRdvMsg getRdvMessage(Message msg) { + MessageElement el = msg.getMessageElement("jxta", ELEMENTNAME); + + if (el == null) { + // The sender did not use this protocol + return null; + } + + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(el); + + return new LimitedRangeRdvMsg(asDoc); + } catch (Exception ez) { + return null; + } + } + + /** + * Standard constructor + * + * @param group Peergroup in which this walk is running. + * @param listener Intended recipient of messages received as part of this walk. + * @param srcServiceName Service name used by the client of this walk. + * @param srcServiceParam Optional service parameter used by the client of this walk. + * @param rpv the rendezvous peer PeerView to be used by this walk. + */ + public LimitedRangeWalk(PeerGroup group, EndpointListener listener, String srcServiceName, String srcServiceParam, PeerView rpv) { + super(group, listener, srcServiceName, srcServiceParam); + + this.rpv = rpv; + + this.walkSvcName = SERVICENAME + group.getPeerGroupID().toString(); + this.walkSvcParam = srcServiceName + srcServiceParam; + + this.walker = new LimitedRangeWalker(this); + this.greeter = new LimitedRangeGreeter(this); + } + + /** + * Return the Rendezvous peer PeerView used by this walk. + * + * @return The rendezvous peer PeerView used by this walk. + */ + PeerView getPeerView() { + return rpv; + } + + /** + * Return the Service Name used by listener of this walk. + * + * @return the Service Name used by listener of this walk. + */ + String getWalkServiceName() { + return walkSvcName; + } + + /** + * Return the Service Param used by listener of this walk. + * + * @return the Service Param used by listener of this walk. + */ + String getWalkServiceParam() { + return walkSvcParam; + } + + /** + * {@inheritDoc} + */ + @Override + public LimitedRangeWalker getWalker() { + return this.walker; + } + + /** + * {@inheritDoc} + */ + @Override + public LimitedRangeGreeter getGreeter() { + return this.greeter; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void stop() { + if (walker != null) { + walker.stop(); + walker = null; + } + + if (greeter != null) { + greeter.stop(); + greeter = null; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeWalker.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeWalker.java new file mode 100644 index 000000000..7a7abe75f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/limited/LimitedRangeWalker.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.limited; + +import java.io.IOException; + +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import java.util.logging.Logger; + +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.peer.PeerID; + +import net.jxta.impl.protocol.LimitedRangeRdvMsg; +import net.jxta.impl.rendezvous.RdvWalker; +import net.jxta.impl.rendezvous.rpv.PeerViewElement; + +/** + * The Limited Range Walker is designed to be used by Rendezvous Peer in + * order to propagate a message amongst them. A target destination peer + * is used in order to send the message to a primary peer. Then, depending + * on the TTL, the message is duplicated into two messages, each of them + * being sent in opposite "directions" of the RPV. + */ +public class LimitedRangeWalker implements RdvWalker { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(LimitedRangeWalker.class.getName()); + + /** + * The walk we are associated with. + */ + private final LimitedRangeWalk walk; + + /** + * Constructor + * + * @param walk The walk we will be associated with. + */ + public LimitedRangeWalker(LimitedRangeWalk walk) { + this.walk = walk; + } + + /** + * {@inheritDoc} + */ + public void stop() { + } + + /** + * {@inheritDoc} + *

            + * Sends message on : + *

            +     *  "LR-Greeter"<groupid>/<walkSvc><walkParam>
            +     *  
            + *

            + * XXX bondolo 20060720 This method will currently fail to walk the + * message to the DOWN peer if there is a failure sending the message to + * the UP peer. Perhaps it would be better to ignore any errors from + * sending to either peer? + */ + private void walkMessage(Message msg, LimitedRangeRdvMsg rdvMsg) throws IOException { + + LimitedRangeRdvMsg.WalkDirection dir = rdvMsg.getDirection(); + + if ((dir == LimitedRangeRdvMsg.WalkDirection.BOTH) || (dir == LimitedRangeRdvMsg.WalkDirection.UP)) { + PeerViewElement upPeer = walk.getPeerView().getUpPeer(); + + if ((upPeer != null) && upPeer.isAlive()) { + Message newMsg = msg.clone(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Walking " + newMsg + " [UP] to " + upPeer); + } + + rdvMsg.setDirection(LimitedRangeRdvMsg.WalkDirection.UP); + + updateRdvMessage(newMsg, rdvMsg); + upPeer.sendMessage(newMsg, walk.getWalkServiceName(), walk.getWalkServiceParam()); + } + } + + if ((dir == LimitedRangeRdvMsg.WalkDirection.BOTH) || (dir == LimitedRangeRdvMsg.WalkDirection.DOWN)) { + PeerViewElement downPeer = walk.getPeerView().getDownPeer(); + + if ((downPeer != null) && downPeer.isAlive()) { + Message newMsg = msg.clone(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Walking " + newMsg + " [DOWN] to " + downPeer); + } + + rdvMsg.setDirection(LimitedRangeRdvMsg.WalkDirection.DOWN); + + updateRdvMessage(newMsg, rdvMsg); + downPeer.sendMessage(newMsg, walk.getWalkServiceName(), walk.getWalkServiceParam()); + } + } + } + + /** + * {@inheritDoc} + */ + public void walkMessage(PeerID destination, Message msg, String srcSvcName, String srcSvcParam, int ttl) throws IOException { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Walking " + msg + " to " + srcSvcName + "/" + srcSvcParam); + } + + // Check if there is already a Rdv Message + LimitedRangeRdvMsg rdvMsg = LimitedRangeWalk.getRdvMessage(msg); + + if (rdvMsg == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating new Walk Header for " + msg + " with TTL=" + ttl); + } + + // Create a new one. + rdvMsg = new LimitedRangeRdvMsg(); + + rdvMsg.setTTL(Integer.MAX_VALUE); // will be reduced. + rdvMsg.setDirection(LimitedRangeRdvMsg.WalkDirection.BOTH); + rdvMsg.setSrcPeerID(walk.getPeerGroup().getPeerID()); + rdvMsg.setSrcSvcName(srcSvcName); + rdvMsg.setSrcSvcParams(srcSvcParam); + } else { + // decrement TTL before walk. + rdvMsg.setTTL(rdvMsg.getTTL() - 1); + } + + int useTTL = Math.min(ttl, rdvMsg.getTTL()); + + useTTL = Math.min(useTTL, walk.getPeerView().getView().size() + 1); + + rdvMsg.setTTL(useTTL); + + if (useTTL <= 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("LimitedRangeWalker was not able to send " + msg + " : No TTL remaining"); + } + + return; + } + + // Forward the message according to the direction set in the Rdv Message. + if (null != destination) { + Message tmp = msg.clone(); + + updateRdvMessage(tmp, rdvMsg); + sendToPeer(destination, walk.getWalkServiceName(), walk.getWalkServiceParam(), tmp); + } else { + walkMessage(msg, rdvMsg); + } + } + + /** + * Replace the old version of the rdvMsg + * + * @param msg The message to be updated. + * @param rdvMsg The LimitedRangeRdvMsg which will update the message. + * @return the updated message + */ + private Message updateRdvMessage(Message msg, LimitedRangeRdvMsg rdvMsg) { + XMLDocument asDoc = (XMLDocument) rdvMsg.getDocument(MimeMediaType.XMLUTF8); + MessageElement el = new TextDocumentMessageElement(LimitedRangeWalk.ELEMENTNAME, asDoc, null); + + msg.replaceMessageElement("jxta", el); + + return msg; + } + + /** + * Sends the provided message to the specified peer. The peer must be a + * current member of the PeerView. + * + * @param dest The destination peer. + * @param svcName The destinations service. + * @param svcParam The destination service params. + * @param msg The message to send. + * @throws IOException Thrown for problems sending the message. + */ + private void sendToPeer(PeerID dest, String svcName, String svcParam, Message msg) throws IOException { + PeerViewElement pve = walk.getPeerView().getPeerViewElement(dest); + + if (null == pve) { + throw new IOException("LimitedRangeWalker was not able to send " + msg + " : no pve"); + } + + if (!pve.sendMessage(msg, svcName, svcParam)) { + throw new IOException("LimitedRangeWalker was not able to send " + msg + " : send failed"); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/package.html new file mode 100644 index 000000000..554fba6d5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/package.html @@ -0,0 +1,14 @@ + + + + + + + A JXTA {@link net.jxta.rendezvous.RendezVousService} implementation which + implements the standard JXTA Rendezvous Protocol (RVP). + + @see net.jxta.rendezvous.RendezVousService + @see JXTA Protocols Specification : Rendezvous Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rdv/ClientConnection.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rdv/ClientConnection.java new file mode 100644 index 000000000..9893ec9b9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rdv/ClientConnection.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rdv; + +import java.util.logging.Logger; +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.PeerAdvertisement; + +import net.jxta.impl.rendezvous.PeerConnection; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; + +/** + * Manages a connection with a client peer. + */ +public class ClientConnection extends PeerConnection { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ClientConnection.class.getName()); + + /** + * Constructor for the PeerConnection object + * + * @param group The group context. + * @param rdvService The rendezvous service instance this connection is associated with. + * @param peer The peer id of the connection. + */ + public ClientConnection(PeerGroup group, RendezVousServiceImpl rdvService, ID peer) { + super(group, rdvService.endpoint, peer); + } + + /** + * Declare that we are connected. + * + * @param padv The peer advertisement of the peer. + * @param leaseDuration The duration of the lease which is offered to the client. + */ + public void connect(PeerAdvertisement padv, long leaseDuration) { + + super.connect(leaseDuration); + + // We will almost certainly need a messenger soon. Get it now. + getCachedMessenger(padv); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rdv/RdvPeerRdvService.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rdv/RdvPeerRdvService.java new file mode 100644 index 000000000..bebb827ee --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rdv/RdvPeerRdvService.java @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rdv; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.rendezvous.PeerConnection; +import net.jxta.impl.rendezvous.RdvWalk; +import net.jxta.impl.rendezvous.RdvWalker; +import net.jxta.impl.rendezvous.RendezVousPropagateMessage; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; +import net.jxta.impl.rendezvous.StdRendezVousService; +import net.jxta.impl.rendezvous.limited.LimitedRangeWalk; +import net.jxta.impl.rendezvous.rendezvousMeter.ClientConnectionMeter; +import net.jxta.impl.rendezvous.rendezvousMeter.RendezvousMeterBuildSettings; +import net.jxta.impl.rendezvous.rpv.PeerView; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.Module; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.rendezvous.RendezvousEvent; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimerTask; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A JXTA {@link net.jxta.rendezvous.RendezVousService} implementation which + * implements the rendezvous server portion of the standard JXTA Rendezvous + * Protocol (RVP). + * + * @see net.jxta.rendezvous.RendezVousService + * @see JXTA Protocols Specification : Rendezvous Protocol + */ +public class RdvPeerRdvService extends StdRendezVousService { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(RdvPeerRdvService.class.getName()); + + public static final String RDV_WALK_SVC_NAME = "RdvWalkSvcName"; + public static final String RDV_WALK_SVC_PARAM = "RdvWalkSvcParam"; + + public final static long GC_INTERVAL = 2 * TimeUtils.AMINUTE; + public final static long DEFAULT_LEASE_DURATION = 20L * TimeUtils.AMINUTE; + public final static int DEFAULT_MAX_CLIENTS = 200; + + /** + * Duration of leases we offer measured in relative milliseconds. + */ + private final long LEASE_DURATION; + + /** + * The maximum number of simultaneous clients we will allow. + */ + private final int MAX_CLIENTS; + + /** + * The clients which currently have a lease with us. + */ + private final Map clients = Collections.synchronizedMap(new HashMap()); + + private RdvWalk walk = null; + private RdvWalker walker = null; + + /** + * The peer view for this rendezvous server. + */ + public final PeerView rpv; + + /** + * Constructor for the RdvPeerRdvService object + * + * @param group the peer group + * @param rdvService the rendezvous service object + */ + public RdvPeerRdvService(PeerGroup group, RendezVousServiceImpl rdvService) { + + super(group, rdvService); + + Advertisement adv = null; + ConfigParams confAdv = group.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + if (confAdv != null) { + try { + XMLDocument configDoc = (XMLDocument) confAdv.getServiceParam(rdvService.getAssignedID()); + + if (null != configDoc) { + adv = AdvertisementFactory.newAdvertisement(configDoc); + } + } catch (java.util.NoSuchElementException failed) {// ignored + } + } + + RdvConfigAdv rdvConfigAdv; + + if (!(adv instanceof RdvConfigAdv)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating new RdvConfigAdv for defaults."); + } + + rdvConfigAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + } else { + rdvConfigAdv = (RdvConfigAdv) adv; + } + + if (rdvConfigAdv.getMaxTTL() > 0) { + MAX_TTL = rdvConfigAdv.getMaxTTL(); + } else { + MAX_TTL = StdRendezVousService.DEFAULT_MAX_TTL; + } + + if (rdvConfigAdv.getMaxClients() > 0) { + MAX_CLIENTS = rdvConfigAdv.getMaxClients(); + } else { + MAX_CLIENTS = DEFAULT_MAX_CLIENTS; + } + + if (rdvConfigAdv.getLeaseDuration() > 0) { + LEASE_DURATION = rdvConfigAdv.getLeaseDuration(); + } else { + LEASE_DURATION = DEFAULT_LEASE_DURATION; + } + + // Update the peeradv with that information: + // XXX 20050409 bondolo How does this interact with auto-rdv? + try { + XMLDocument params = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + Element e = params.createElement("Rdv", Boolean.TRUE.toString()); + + params.appendChild(e); + group.getPeerAdvertisement().putServiceParam(rdvService.getAssignedID(), params); + } catch (Exception ohwell) { + // don't worry about it for now. It'll still work. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed adding service params", ohwell); + } + } + + PeerGroup advGroup = group.getParentGroup(); + + if ((null == advGroup) || PeerGroupID.worldPeerGroupID.equals(advGroup.getPeerGroupID())) { + // For historical reasons, we publish in our own group rather than + // the parent if our parent is the world group. + advGroup = null; + } + + rpv = new PeerView(group, advGroup, rdvService, + rdvService.getAssignedID().toString() + group.getPeerGroupID().getUniqueValue().toString()); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RendezVous Service is initialized for " + group.getPeerGroupID() + " as a Rendezvous peer."); + } + } + + /** + * Listener for + *

            + * <assignedID>/<group-unique> + */ + private class StdRdvRdvProtocolListener implements StdRendezVousService.StdRdvProtocolListener { + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupID() + "] processing " + msg); + } + + if (msg.getMessageElement("jxta", ConnectRequest) != null) { + processLeaseRequest(msg); + } + + if (msg.getMessageElement("jxta", DisconnectRequest) != null) { + processDisconnectRequest(msg); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected int startApp(String[] argv) { + + super.startApp(argv, new StdRdvRdvProtocolListener()); + + rpv.start(); + + // The other services may not be fully functional but they're there + // so we can start our subsystems. + // As for us, it does not matter if our methods are called between init + // and startApp(). + + // Start the Walk protcol. Create a LimitedRange Walk + walk = new LimitedRangeWalk(group, new WalkListener(), pName, pParam, rpv); + + // We need to use a Walker in order to propagate the request + // when when have no answer. + walker = walk.getWalker(); + + timer.scheduleAtFixedRate(new GCTask(), GC_INTERVAL, GC_INTERVAL); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.startRendezvous(); + } + + rdvService.generateEvent(RendezvousEvent.BECAMERDV, group.getPeerID()); + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("RdvPeerRdvService is started"); + } + + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void stopApp() { + + if (closed) { + return; + } + + closed = true; + + walk.stop(); + walk = null; + + rpv.stop(); + + // Tell all our clientss that we are going down + disconnectAllClients(); + + clients.clear(); + + super.stopApp(); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.stopRendezvous(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void connectToRendezVous(EndpointAddress addr, Object hint) { + throw new UnsupportedOperationException("Not supported by rendezvous"); + } + + /** + * {@inheritDoc} + */ + @Override + public void challengeRendezVous(ID peer, long delay) { + throw new UnsupportedOperationException("Not supported by rendezvous"); + } + + /** + * {@inheritDoc} + */ + @Override + public void disconnectFromRendezVous(ID peerId) { + + throw new UnsupportedOperationException("Not supported by rendezvous"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isConnectedToRendezVous() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public Vector getConnectedPeerIDs() { + + Vector result = new Vector(); + List allClients = Arrays.asList(clients.values().toArray()); + + for (Object allClient : allClients) { + PeerConnection aConnection = (PeerConnection) allClient; + + if (aConnection.isConnected()) { + result.add(aConnection.getPeerID()); + } + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void propagate(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + if (closed) { + return; + } + + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + msg + "(TTL=" + useTTL + ") to :" + + "\n\tsvc name:" + serviceName + "\tsvc params:" + serviceParam); + } + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, useTTL); + + if (null != propHdr) { + walk(msg, PropSName, PropPName, useTTL); + // hamada: this is a very expensive operation and therefore not a supported operation + // sendToEachConnection(msg, propHdr); + sendToNetwork(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToGroup(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void propagateInGroup(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + if (closed) { + return; + } + + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating " + msg + "(TTL=" + useTTL + ") in group to :" + + "\n\tsvc name:" + serviceName + "\tsvc params:" + serviceParam); + } + + RendezVousPropagateMessage propHdr = updatePropHeader(msg, getPropHeader(msg), serviceName, serviceParam, useTTL); + + if (null != propHdr) { + walk(msg, PropSName, PropPName, useTTL); + sendToEachConnection(msg, propHdr); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.propagateToGroup(); + } + } + } + + /** + * @inheritDoc + */ + @Override + public PeerConnection getPeerConnection(ID peer) { + return clients.get(peer); + } + + /** + * @inheritDoc + */ + @Override + protected PeerConnection[] getPeerConnections() { + return clients.values().toArray(new PeerConnection[0]); + } + + /** + * Add a client to our collection of clients. + * + * @param padv The advertisement of the peer to be added. + * @param lease The lease duration in relative milliseconds. + * @return the ClientConnection + */ + private ClientConnection addClient(PeerAdvertisement padv, long lease) { + ClientConnectionMeter clientConnectionMeter = null; + + int eventType; + ClientConnection pConn; + + synchronized (clients) { + pConn = clients.get(padv.getPeerID()); + + // Check if the peer is already registered. + if (null != pConn) { + eventType = RendezvousEvent.CLIENTRECONNECT; + } else { + eventType = RendezvousEvent.CLIENTCONNECT; + pConn = new ClientConnection(group, rdvService, padv.getPeerID()); + clients.put(padv.getPeerID(), pConn); + } + } + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousServiceMonitor != null)) { + clientConnectionMeter = rendezvousServiceMonitor.getClientConnectionMeter(padv.getPeerID()); + } + + if (RendezvousEvent.CLIENTCONNECT == eventType) { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (clientConnectionMeter != null)) { + clientConnectionMeter.clientConnectionEstablished(lease); + } + } else { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (clientConnectionMeter != null)) { + clientConnectionMeter.clientLeaseRenewed(lease); + } + } + + rdvService.generateEvent(eventType, padv.getPeerID()); + + pConn.connect(padv, lease); + + return pConn; + } + + /** + * Removes the specified client from the clients collections. + * + * @param pConn The connection object to remove. + * @param requested If true then the disconnection was + * requested by the remote peer. + * @return the ClientConnection object of the client or null + * if the client was not known. + */ + private ClientConnection removeClient(PeerConnection pConn, boolean requested) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Disconnecting client " + pConn); + } + + if (pConn.isConnected()) { + pConn.setConnected(false); + sendDisconnect(pConn); + } + + rdvService.generateEvent(requested ? RendezvousEvent.CLIENTDISCONNECT : RendezvousEvent.CLIENTFAILED, pConn.getPeerID()); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousServiceMonitor != null)) { + ClientConnectionMeter clientConnectionMeter = rendezvousServiceMonitor.getClientConnectionMeter( + (PeerID) pConn.getPeerID()); + + clientConnectionMeter.clientConnectionDisconnected(requested); + } + + return clients.remove(pConn.getPeerID()); + } + + private void disconnectAllClients() { + for (Object o : Arrays.asList(clients.values().toArray())) { + ClientConnection pConn = (ClientConnection) o; + + try { + removeClient(pConn, false); + } catch (Exception ez1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "disconnectClient failed for" + pConn, ez1); + } + } + } + } + + /** + * Handle a disconnection request + * + * @param msg Message containing the disconnection request. + */ + private void processDisconnectRequest(Message msg) { + + PeerAdvertisement adv; + + try { + MessageElement elem = msg.getMessageElement("jxta", DisconnectRequest); + + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(elem); + + adv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not process disconnect request", e); + } + return; + } + + ClientConnection pConn = clients.get(adv.getPeerID()); + + if (null != pConn) { + pConn.setConnected(false); // Make sure we don't send a disconnect + removeClient(pConn, true); + } + } + + /** + * Handles a lease request message + * + * @param msg Message containing the lease request + */ + private void processLeaseRequest(Message msg) { + + PeerAdvertisement padv; + + try { + MessageElement elem = msg.getMessageElement("jxta", ConnectRequest); + + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(elem); + + padv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); + msg.removeMessageElement(elem); + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Cannot retrieve advertisment from lease request", e); + } + return; + } + + // Publish the client's peer advertisement + try { + // This is not our own peer adv so we must not keep it longer than + // its expiration time. + DiscoveryService discovery = group.getDiscoveryService(); + + if (null != discovery) { + discovery.publish(padv, LEASE_DURATION * 2, 0); + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Client peer advertisement publish failed", e); + } + } + + long lease; + + ClientConnection pConn = clients.get(padv.getPeerID()); + + if (null != pConn) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Renewing client lease to " + pConn); + } + + lease = LEASE_DURATION; + } else { + if (clients.size() < MAX_CLIENTS) { + lease = LEASE_DURATION; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Offering new client lease to " + padv.getName() + " [" + padv.getPeerID() + "]"); + } + } else { + lease = 0; + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning( + "Max clients exceeded, declining lease request from: " + padv.getName() + " [" + padv.getPeerID() + + "]"); + } + } + } + + if (lease > 0) { + pConn = addClient(padv, lease); + + // FIXME 20041015 bondolo We're supposed to send a lease 0 if we can't accept new clients. + sendLease(pConn, lease); + } + } + + /** + * Sends a Connected lease reply message to the specified peer + * + * @param pConn The client peer. + * @param lease lease duration. + * @return Description of the Returned Value + */ + private boolean sendLease(ClientConnection pConn, long lease) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending lease (" + lease + ") to " + pConn.getPeerName()); + } + + Message msg = new Message(); + + msg.addMessageElement("jxta", new TextDocumentMessageElement(ConnectedRdvAdvReply, getPeerAdvertisementDoc(), null)); + + msg.addMessageElement("jxta", new StringMessageElement(ConnectedPeerReply, group.getPeerID().toString(), null)); + + msg.addMessageElement("jxta", new StringMessageElement(ConnectedLeaseReply, Long.toString(lease), null)); + + return pConn.sendMessage(msg, pName, pParam); + } + + /** + * {@inheritDoc} + */ + @Override + public void walk(Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + if (closed) { + return; + } + + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Undirected walk of " + msg + "(TTL=" + useTTL + ") to :" + "\n\tsvc name:" + serviceName + "\tsvc params:" + + serviceParam); + } + + msg.replaceMessageElement("jxta", new StringMessageElement(RDV_WALK_SVC_NAME, serviceName, null)); + + msg.replaceMessageElement("jxta", new StringMessageElement(RDV_WALK_SVC_PARAM, serviceParam, null)); + + try { + walker.walkMessage(null, msg, pName, pParam, useTTL); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.walk(); + } + } catch (IOException failure) { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.walkFailed(); + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Cannot send message with Walker", failure); + } + + throw failure; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void walk(Vector destPeerIDs, Message msg, String serviceName, String serviceParam, int initialTTL) throws IOException { + if (closed) { + return; + } + + msg = msg.clone(); + int useTTL = Math.min(initialTTL, MAX_TTL); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Directed walk of " + msg + "(TTL=" + useTTL + ") to :" + "\n\tsvc name:" + serviceName + "\tsvc params:" + + serviceParam); + } + + msg.replaceMessageElement("jxta", new StringMessageElement(RDV_WALK_SVC_NAME, serviceName, null)); + + msg.replaceMessageElement("jxta", new StringMessageElement(RDV_WALK_SVC_PARAM, serviceParam, null)); + + for (ID destPeerID : destPeerIDs) { + try { + walker.walkMessage((PeerID) destPeerID, msg.clone(), pName, pParam, useTTL); + } catch (IOException failed) { + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.walkToPeersFailed(); + } + + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Cannot send message with Walker to: " + destPeerID, failed); + } + + IOException failure = new IOException("Cannot send message with Walker to: " + destPeerID); + + failure.initCause(failed); + + throw failure; + } + } + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.walkToPeers(destPeerIDs.size()); + } + } + + /** + * Periodic cleanup task + */ + private class GCTask extends TimerTask { + + /** + * {@inheritDoc + */ + @Override + public void run() { + + try { + long gcStart = TimeUtils.timeNow(); + int gcedClients = 0; + + List allClients = Arrays.asList(clients.values().toArray()); + + for (Object allClient : allClients) { + ClientConnection pConn = (ClientConnection) allClient; + + try { + long now = TimeUtils.timeNow(); + + if (!pConn.isConnected() || (pConn.getLeaseEnd() < now)) { + // This client has dropped out or the lease is over. + // remove it. + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("GC CLIENT: dropping " + pConn); + } + + pConn.setConnected(false); + removeClient(pConn, false); + gcedClients++; + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "GCTask failed for " + pConn, e); + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Client GC " + gcedClients + " of " + allClients.size() + " clients completed in " + + TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), gcStart) + "ms."); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } + } + } + + + /** + * @inheritDoc + */ + private class WalkListener implements EndpointListener { + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + MessageElement serviceME = msg.getMessageElement("jxta", RDV_WALK_SVC_NAME); + + if (null == serviceME) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding " + msg + " because its missing service name element"); + } + return; + } + + msg.removeMessageElement(serviceME); + String sName = serviceME.toString(); + + MessageElement paramME = msg.getMessageElement("jxta", RDV_WALK_SVC_PARAM); + + String sParam; + + if (null == paramME) { + sParam = null; + } else { + msg.removeMessageElement(paramME); + sParam = paramME.toString(); + } + + EndpointAddress realDest = new EndpointAddress(dstAddr, sName, sParam); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Calling local listener for [" + realDest.getServiceName() + " / " + realDest.getServiceParameter() + + "] with " + msg); + } + + rdvService.endpoint.processIncomingMessage(msg, srcAddr, realDest); + + if (RendezvousMeterBuildSettings.RENDEZVOUS_METERING && (rendezvousMeter != null)) { + rendezvousMeter.receivedMessageProcessedLocally(); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ClientConnectionMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ClientConnectionMeter.java new file mode 100644 index 000000000..bb7d7de3b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ClientConnectionMeter.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.peer.*; +import net.jxta.endpoint.*; + + +/** + * The rendezvous's meter for a client peer interacting with a it + **/ +public class ClientConnectionMeter { + private PeerID peerID; + + private ClientConnectionMetric cumulativeMetrics; + private ClientConnectionMetric deltaMetrics; + + private long transitionTime = 0; + private long lastLeaseRenewalTime = 0; + + public ClientConnectionMeter(PeerID peerID) { + this.peerID = peerID; + cumulativeMetrics = new ClientConnectionMetric(peerID); + } + + public ClientConnectionMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public synchronized ClientConnectionMetric collectMetrics() { + ClientConnectionMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + return prevDelta; + } + + private void createDeltaMetric() { + deltaMetrics = new ClientConnectionMetric(cumulativeMetrics); + } + + public void clientConnectionEstablished(long lease) { + transitionTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.clientConnectionEstablished(transitionTime, lease); + cumulativeMetrics.clientConnectionEstablished(transitionTime, lease); + } + + public void clientLeaseRenewed(long lease) { + lastLeaseRenewalTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.clientLeaseRenewed(lastLeaseRenewalTime, lease); + cumulativeMetrics.clientLeaseRenewed(lastLeaseRenewalTime, lease); + } + + public void errorAddingClient() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorAddingClient(); + cumulativeMetrics.errorAddingClient(); + } + + public void clientConnectionDisconnected(boolean normal) { + transitionTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.clientConnectionDisconnected(normal, transitionTime); + cumulativeMetrics.clientConnectionDisconnected(normal, transitionTime); + } + + public void unableToRespondToConnectRequest() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.unableToRespondToConnectRequest(); + cumulativeMetrics.unableToRespondToConnectRequest(); + } + + public void clientConnectionRefused() { + transitionTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.clientConnectionRefused(transitionTime); + cumulativeMetrics.clientConnectionRefused(transitionTime); + } + + @Override + public String toString() { + return "ClientConnectionMeter(" + peerID + ")"; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ClientConnectionMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ClientConnectionMetric.java new file mode 100644 index 000000000..ff9d91277 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ClientConnectionMetric.java @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.impl.meter.*; +import net.jxta.rendezvous.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.peer.*; +import net.jxta.endpoint.*; +import net.jxta.util.*; +import net.jxta.exception.*; + +import java.util.*; + + +/** + * The rendezvous's metric for a client peer interacting with a it + **/ +public class ClientConnectionMetric implements DocumentSerializable { + public static final String CONNECTED = "connected"; + public static final String DISCONNECTED = "disconnected"; + public static final String REFUSED = "refused"; + + private PeerID peerID; + + private String state = null; + private long transitionTime; + private long lastLeaseRenewalTime; + + private long lease; + private int numConnects; + private int numLeaseRenewals; + private int numDisconnects; + private int numConnectionsRefused; + private int numErrorsAddingClient; + private int numUnableToRespondToConnectRequest; + + private long totalTimeConnected; + + public ClientConnectionMetric() {} + + public ClientConnectionMetric(PeerID peerID) { + this.peerID = peerID; + this.state = DISCONNECTED; + } + + public ClientConnectionMetric(ClientConnectionMetric prototype) { + this.peerID = prototype.peerID; + this.state = prototype.state; + this.transitionTime = prototype.transitionTime; + this.lastLeaseRenewalTime = prototype.lastLeaseRenewalTime; + this.lease = prototype.lease; + } + + /** Peer ID of this Client Connection **/ + public PeerID getPeerID() { + return peerID; + } + + /** + * State of Client Connection + * @return ClientConnectionMetric.CONNECTED, ClientConnectionMetric.DISCONNECTED or ClientConnectionMetric.REFUSED + **/ + public String getState() { + return state; + } + + /** Get the time that it entered the current state + * @return transition time in ms since January 1, 1970, 00:00:00 GMT + **/ + public long getTransitionTime() { + return transitionTime; + } + + /** Is this client connected **/ + public boolean isConnected() { + return (state != null) && state.equals(CONNECTED); + } + + /** Get time Connected + * @return time or 0 if not connected + **/ + public long getTimeConnectionEstablished() { + return isConnected() ? transitionTime : 0; + } + + /** Get time Connected + * @return time or 0 if not disconnected + **/ + public long getDisconnectTime() { + return isDisconnected() ? transitionTime : 0; + } + + /** Is this client disconnected **/ + public boolean isDisconnected() { + return (state != null) && (state.equals(DISCONNECTED) || state.equals(REFUSED)); + } + + /** Get Lease time granted for last lease Renewal Request. + * @see #getLastLeaseRenewalTime() + **/ + public long getLease() { + return lease; + } + + /** Get Last Received Lease Renewal Time + * @see #getLease() + **/ + public long getLastLeaseRenewalTime() { + return lastLeaseRenewalTime; + } + + /** Get number of granted connect messages received from this peer **/ + public int getNumConnects() { + return numConnects; + } + + /** Get number of granted lease renewal messages received from this peer **/ + public int getNumLeaseRenewals() { + return numLeaseRenewals; + } + + /** Get number of disconnect messages received from this peer **/ + public int getNumDisconnects() { + return numDisconnects; + } + + /** Get number of refused connect/lease-renewal messages received from this peer **/ + public int getNumConnectionsRefused() { + return numConnectionsRefused; + } + + /** Get number of errors when attempting to add this peer as a client **/ + public int getNumErrorsAddingClient() { + return numErrorsAddingClient; + } + + /** Get number of errors when attempting to respond to this peer's request**/ + public int getNumUnableToRespondToConnectRequest() { + return numUnableToRespondToConnectRequest; + } + + /** Get the total time this peer has been connected. + *

            + * Note: This does not include the current time connected (if it is currently connected) + * @see #getTotalTimeConnected(long) + * @return time in ms (see note above) + **/ + public long getTotalTimeConnected() { + return totalTimeConnected; + } + + /** Get the total time this peer has been connected. If it is currently + * connected, then the total time is adjusted to include the time since the transition time + * to become connected until the provided time + * @param adjustmentTime The time of this metric will be adjusted to + * @see #getTotalTimeConnected() + * @return time in ms (see note above) + **/ + public long getTotalTimeConnected(long adjustmentTime) { + long result = totalTimeConnected; + + if (isConnected()) { + result += (adjustmentTime - this.transitionTime); + } + + return result; + } + + /** Get the duration of current connection relative to local clock (from transition time) + *

            + * Note: This assumes the clocks are in sync with the reporting peer + * @see #getTotalTimeConnected(long) + * @return time in ms (see note above) or 0 if not connected + **/ + public long getTimeConnected() { + return getTimeConnected(System.currentTimeMillis()); + } + + /** Get the duration of current connection until the specified time + * @param adjustmentTime The time of this metric will be computed until + * @see #getTimeConnected() + * @return time in ms (see note above) or 0 if not connected + **/ + public long getTimeConnected(long adjustmentTime) { + + if (isConnected()) { + return (adjustmentTime - this.transitionTime); + } else { + return 0; + } + } + + private void resetState(String state, long transitionTime) { + if (isConnected()) { + totalTimeConnected += (System.currentTimeMillis() - this.transitionTime); + } + + this.state = state; + this.transitionTime = transitionTime; + } + + void clientConnectionEstablished(long transitionTime, long lease) { + resetState(CONNECTED, transitionTime); + + this.numConnects++; + this.lease = lease; + } + + void clientLeaseRenewed(long lastLeaseRenewalTime, long lease) { + this.numLeaseRenewals++; + this.lease = lease; + this.lastLeaseRenewalTime = System.currentTimeMillis(); + + if (!isConnected()) { + resetState(CONNECTED, lastLeaseRenewalTime); + } + } + + void errorAddingClient() { + this.numErrorsAddingClient++; + ; + } + + void clientConnectionDisconnected(boolean normal, long transitionTime) { + resetState(DISCONNECTED, transitionTime); + this.numDisconnects++; + this.lease = 0; + } + + void unableToRespondToConnectRequest() { + this.numUnableToRespondToConnectRequest++; + } + + void clientConnectionRefused(long transitionTime) { + if (!isDisconnected()) { + clientConnectionDisconnected(false, transitionTime); + } + + this.transitionTime = transitionTime; + this.numConnectionsRefused++; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (peerID != null) { + DocumentSerializableUtilities.addString(element, "peerID", peerID.toString()); + } + if (state != null) { + DocumentSerializableUtilities.addString(element, "state", state); + } + if (transitionTime != 0) { + DocumentSerializableUtilities.addLong(element, "transitionTime", transitionTime); + } + if (lastLeaseRenewalTime != 0) { + DocumentSerializableUtilities.addLong(element, "lastLeaseRenewalTime", lastLeaseRenewalTime); + } + if (lease != 0) { + DocumentSerializableUtilities.addLong(element, "lease", lease); + } + if (numConnects != 0) { + DocumentSerializableUtilities.addInt(element, "numConnects", numConnects); + } + if (numLeaseRenewals != 0) { + DocumentSerializableUtilities.addInt(element, "numLeaseRenewals", numLeaseRenewals); + } + if (numDisconnects != 0) { + DocumentSerializableUtilities.addInt(element, "numDisconnects", numDisconnects); + } + if (numConnectionsRefused != 0) { + DocumentSerializableUtilities.addInt(element, "numConnectionsRefused", numConnectionsRefused); + } + if (numErrorsAddingClient != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsAddingClient", numErrorsAddingClient); + } + if (numUnableToRespondToConnectRequest != 0) { + DocumentSerializableUtilities.addInt(element, "numUnableToRespondToConnectRequest", numUnableToRespondToConnectRequest); + } + if (totalTimeConnected != 0) { + DocumentSerializableUtilities.addLong(element, "totalTimeConnected", totalTimeConnected); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + state = null; + + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("peerID")) { + String peerIDText = DocumentSerializableUtilities.getString(childElement); + + peerID = MetricUtilities.getPeerIdFromString(peerIDText); + } else if (tagName.equals("state")) { + state = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("transitionTime")) { + transitionTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("lastLeaseRenewalTime")) { + lastLeaseRenewalTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("lease")) { + lease = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numConnects")) { + numConnects = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numLeaseRenewals")) { + numLeaseRenewals = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numDisconnects")) { + numDisconnects = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numConnectionsRefused")) { + numConnectionsRefused = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsAddingClient")) { + numErrorsAddingClient = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numUnableToRespondToConnectRequest")) { + numUnableToRespondToConnectRequest = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("totalTimeConnected")) { + totalTimeConnected = DocumentSerializableUtilities.getLong(childElement); + } + } + } + + public void mergeMetrics(ClientConnectionMetric otherClientConnectionMetric) { + if (otherClientConnectionMetric == null) { + return; + } + + if (otherClientConnectionMetric.state != null) { + state = otherClientConnectionMetric.state; + } + + if (otherClientConnectionMetric.transitionTime != 0) { + transitionTime = otherClientConnectionMetric.transitionTime; + } + + lease = otherClientConnectionMetric.lease; + + numConnects += otherClientConnectionMetric.numConnects; + numLeaseRenewals += otherClientConnectionMetric.numLeaseRenewals; + numDisconnects += otherClientConnectionMetric.numDisconnects; + numConnectionsRefused += otherClientConnectionMetric.numConnectionsRefused; + numErrorsAddingClient += otherClientConnectionMetric.numErrorsAddingClient; + numUnableToRespondToConnectRequest += otherClientConnectionMetric.numUnableToRespondToConnectRequest; + totalTimeConnected += otherClientConnectionMetric.totalTimeConnected; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ConditionalRendezvousMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ConditionalRendezvousMeterBuildSettings.java new file mode 100644 index 000000000..921f0f03c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/ConditionalRendezvousMeterBuildSettings.java @@ -0,0 +1,80 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + +import java.util.ResourceBundle; +import net.jxta.impl.meter.*; + +public class ConditionalRendezvousMeterBuildSettings { + public static boolean isRuntimeMetering() { + boolean runtimeMetering = false; + + try { + ResourceBundle userResourceBundle = ResourceBundle.getBundle( "net.jxta.user" ); + String meteringProperty = "net.jxta.meter.conditionalRendezvousMetering"; + String meteringValue = userResourceBundle.getString( meteringProperty ); + runtimeMetering = "on".equalsIgnoreCase( meteringValue ); + } catch (Exception ignored) { + } + + return runtimeMetering; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousConnectionMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousConnectionMeter.java new file mode 100644 index 000000000..a0919e5cf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousConnectionMeter.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.peer.*; + + +/** + * The meter about a client peer's connection to a rendezvous + **/ +public class RendezvousConnectionMeter { + private PeerID peerID; + + private RendezvousConnectionMetric cumulativeMetrics; + private RendezvousConnectionMetric deltaMetrics; + + private long transitionTime = 0; + private long lastLeaseRenewalTime = 0; + + public RendezvousConnectionMeter(PeerID peerID) { + this.peerID = peerID; + cumulativeMetrics = new RendezvousConnectionMetric(peerID); + } + + public RendezvousConnectionMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public PeerID getPeerID() { + return peerID; + } + + public String getState() { + return cumulativeMetrics.getState(); + } + + public synchronized RendezvousConnectionMetric collectMetrics() { + RendezvousConnectionMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + return prevDelta; + } + + private void createDeltaMetric() { + deltaMetrics = new RendezvousConnectionMetric(cumulativeMetrics); + } + + @Override + public String toString() { + return "RendezvousConnectionMeter(" + peerID + ")"; + } + + public void beginConnection() { + transitionTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.beginConnection(transitionTime); + cumulativeMetrics.beginConnection(transitionTime); + } + + public void connectionEstablished(long lease) { + long now = System.currentTimeMillis(); + long timeToConnect = now - transitionTime; + + transitionTime = now; + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.connectionEstablished(transitionTime, timeToConnect, lease); + cumulativeMetrics.connectionEstablished(transitionTime, timeToConnect, lease); + } + + public void leaseRenewed(long lease) { + lastLeaseRenewalTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.leaseRenewed(lastLeaseRenewalTime, lease); + cumulativeMetrics.leaseRenewed(lastLeaseRenewalTime, lease); + } + + public void connectionRefused() { + transitionTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.connectionRefused(transitionTime); + cumulativeMetrics.connectionRefused(transitionTime); + } + + public void connectionDisconnected() { + transitionTime = System.currentTimeMillis(); + + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.connectionDisconnected(transitionTime); + cumulativeMetrics.connectionDisconnected(transitionTime); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousConnectionMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousConnectionMetric.java new file mode 100644 index 000000000..89421caf9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousConnectionMetric.java @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystem, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.rendezvous.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.peer.*; +import net.jxta.endpoint.*; +import net.jxta.util.*; +import net.jxta.exception.*; +import net.jxta.impl.meter.*; +import java.util.*; + + +/** + * The metrics about a client peer's connection to a rendezvous + **/ +public class RendezvousConnectionMetric implements DocumentSerializable { + public static final String CONNECTING = "connecting"; + public static final String CONNECTED = "connected"; + public static final String DISCONNECTED = "disconnected"; + public static final String REFUSED = "refused"; + + private PeerID peerID; + + private String state = null; + private long transitionTime; + + private long lease; + private int numConnectionsBegun = 0; + private int numConnectionsEstablished = 0; + private int numConnectionsRefused = 0; + private long totalTimesToConnect; + private long totalTimeConnected; + + private long lastLeaseRenewalTime; + private int numLeaseRenewals; + + private int numDisconnects; + + public RendezvousConnectionMetric() {} + + public RendezvousConnectionMetric(PeerID peerID) { + this.peerID = peerID; + this.state = DISCONNECTED; + } + + public RendezvousConnectionMetric(RendezvousConnectionMetric prototype) { + this.peerID = prototype.peerID; + this.state = prototype.state; + this.transitionTime = prototype.transitionTime; + this.lastLeaseRenewalTime = prototype.lastLeaseRenewalTime; + this.lease = prototype.lease; + } + + /** Peer ID of Rendezvous **/ + public PeerID getPeerID() { + return peerID; + } + + /** + * State of Client Rendezvous + * @return RendezvousConnectionMetric.CONNECTING, RendezvousConnectionMetric.CONNECTED, RendezvousConnectionMetric.DISCONNECTED or RendezvousConnectionMetric.REFUSED + **/ + public String getState() { + return state; + } + + /** Get the time that it entered the current state + * @return transition time in ms since January 1, 1970, 00:00:00 GMT + **/ + public long getTransitionTime() { + return transitionTime; + } + + /** Is connecting to Rendezvous **/ + public boolean isConnecting() { + return (state != null) && state.equals(CONNECTING); + } + + /** Get time began connecting to Rendezvous + * @return time began or 0 if not connecting + **/ + public long getBeginConnectionTime() { + return isConnecting() ? transitionTime : 0; + } + + /** Is connected to Rendezvous **/ + public boolean isConnected() { + return (state != null) && state.equals(CONNECTED); + } + + /** Get time connected to Rendezvous + * @return time began or 0 if not connected + **/ + public long getTimeConnectionEstablished() { + return isConnected() ? transitionTime : 0; + } + + /** Get lease establised with Rendezvous **/ + public long getLease() { + return lease; + } + + /** Get Number of Connections begun with Rendezvous **/ + public int getNumConnectionsBegun() { + return numConnectionsBegun; + } + + /** Get Number of Connections established with Rendezvous **/ + public int getNumConnectionsEstablished() { + return numConnectionsEstablished; + } + + /** Get Number of Connections refused by Rendezvous **/ + public int getNumConnectionsRefused() { + return numConnectionsRefused; + } + + /** Get Sum of times it took to connect **/ + public long getTotalTimesToConnect() { + return totalTimesToConnect; + } + + /** Get Last Lease Renewal Time **/ + public long getLastLeaseRenewalTime() { + return lastLeaseRenewalTime; + } + + /** Get Number of lease Renewals **/ + public int getNumLeaseRenewals() { + return numLeaseRenewals; + } + + /** Get Number of Disconnects **/ + public int getNumDisconnects() { + return numDisconnects; + } + + /** Get time disconnected to Rendezvous + * @return time began or 0 if not disconnected + **/ + public long getDisconnectTime() { + return isDisconnected() ? transitionTime : 0; + } + + /** Have we disconnected fromthis Rendezvous **/ + public boolean isDisconnected() { + return (state != null) && (state.equals(DISCONNECTED) || state.equals(REFUSED)); + } + + /** Get the total time this peer has been connected. + *

            + * Note: This does not include the current time connected (if it is currently connected) + * @see #getTotalTimeConnected(long) + * @return time in ms (see note above) + **/ + public long getTotalTimeConnected() { + return totalTimeConnected; + } + + /** Get the total time this peer has been connected. If it is currently + * connected, then the total time is adjusted to include the time since the transition time + * to become connected until the provided time + * @param adjustmentTime The time of this metric will be adjusted to + * @see #getTotalTimeConnected() + * @return time in ms (see note above) + **/ + public long getTotalTimeConnected(long adjustmentTime) { + long result = totalTimeConnected; + + if (isConnected()) { + result += (adjustmentTime - this.transitionTime); + } + + return result; + } + + /** Get the duration of current connection relative to local clock (from transition time) + *

            + * Note: This assumes the clocks are in sync with the reporting peer + * @see #getTotalTimeConnected(long) + * @return time in ms (see note above) or 0 if not connected + **/ + public long getTimeConnected() { + return getTimeConnected(System.currentTimeMillis()); + } + + /** Get the duration of current connection until the specified time + * @param adjustmentTime The time of this metric will be computed until + * @see #getTimeConnected() + * @return time in ms (see note above) or 0 if not connected + **/ + public long getTimeConnected(long adjustmentTime) { + + if (isConnected()) { + return (adjustmentTime - this.transitionTime); + } else { + return 0; + } + } + + private void resetState(String state, long transitionTime) { + if (isConnected()) { + totalTimeConnected += (System.currentTimeMillis() - this.transitionTime); + } + + this.state = state; + this.transitionTime = transitionTime; + } + + void beginConnection(long transitionTime) { + resetState(CONNECTING, transitionTime); + + this.numConnectionsBegun++; + } + + void connectionEstablished(long transitionTime, long timeToConnectTime, long lease) { + resetState(CONNECTED, transitionTime); + this.totalTimesToConnect += timeToConnectTime; + this.numConnectionsEstablished++; + + this.lease = lease; + } + + void leaseRenewed(long lastLeaseRenewalTime, long lease) { + this.numLeaseRenewals++; + + this.lastLeaseRenewalTime = lastLeaseRenewalTime; + this.lease = lease; + + if (!isConnected()) { + resetState(CONNECTED, lastLeaseRenewalTime); + } + } + + void connectionRefused(long transitionTime) { + resetState(REFUSED, lastLeaseRenewalTime); + numConnectionsRefused++; + } + + void connectionDisconnected(long transitionTime) { + resetState(DISCONNECTED, lastLeaseRenewalTime); + + numDisconnects++; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RendezvousConnectionMetric) { + RendezvousConnectionMetric other = (RendezvousConnectionMetric) obj; + + return (peerID.equals(other.peerID)); + } else { + return false; + } + } + + @Override + public int hashCode() { + return peerID.hashCode(); + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (peerID != null) { + DocumentSerializableUtilities.addString(element, "peerID", peerID.toString()); + } + if (state != null) { + DocumentSerializableUtilities.addString(element, "state", state); + } + if (transitionTime != 0) { + DocumentSerializableUtilities.addLong(element, "transitionTime", transitionTime); + } + if (lease != 0) { + DocumentSerializableUtilities.addLong(element, "lease", lease); + } + if (numConnectionsBegun != 0) { + DocumentSerializableUtilities.addInt(element, "numConnectionsBegun", numConnectionsBegun); + } + if (numConnectionsEstablished != 0) { + DocumentSerializableUtilities.addInt(element, "numConnectionsEstablished", numConnectionsEstablished); + } + if (numConnectionsRefused != 0) { + DocumentSerializableUtilities.addInt(element, "numConnectionsRefused", numConnectionsRefused); + } + if (totalTimesToConnect != 0) { + DocumentSerializableUtilities.addLong(element, "totalTimesToConnect", totalTimesToConnect); + } + if (totalTimeConnected != 0) { + DocumentSerializableUtilities.addLong(element, "totalTimeConnected", totalTimeConnected); + } + if (lastLeaseRenewalTime != 0) { + DocumentSerializableUtilities.addLong(element, "lastLeaseRenewalTime", lastLeaseRenewalTime); + } + if (numLeaseRenewals != 0) { + DocumentSerializableUtilities.addInt(element, "numLeaseRenewals", numLeaseRenewals); + } + if (numDisconnects != 0) { + DocumentSerializableUtilities.addInt(element, "numDisconnects", numDisconnects); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("peerID")) { + String peerIDText = DocumentSerializableUtilities.getString(childElement); + + peerID = MetricUtilities.getPeerIdFromString(peerIDText); + } else if (tagName.equals("state")) { + state = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("transitionTime")) { + transitionTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("lease")) { + lease = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numConnectionsBegun")) { + numConnectionsBegun = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numConnectionsEstablished")) { + numConnectionsEstablished = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numConnectionsRefused")) { + numConnectionsRefused = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("totalTimesToConnect")) { + totalTimesToConnect = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("totalTimeConnected")) { + totalTimeConnected = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("lastLeaseRenewalTime")) { + lastLeaseRenewalTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numLeaseRenewals")) { + numLeaseRenewals = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numDisconnects")) { + numDisconnects = DocumentSerializableUtilities.getInt(childElement); + } + } + } + + public void mergeMetrics(RendezvousConnectionMetric otherRendezvousConnectionMetric) { + if (otherRendezvousConnectionMetric == null) { + return; + } + + if (otherRendezvousConnectionMetric.state != null) { + state = otherRendezvousConnectionMetric.state; + } + + if (otherRendezvousConnectionMetric.transitionTime != 0) { + transitionTime = otherRendezvousConnectionMetric.transitionTime; + } + + if (otherRendezvousConnectionMetric.lastLeaseRenewalTime != 0) { + lastLeaseRenewalTime = otherRendezvousConnectionMetric.transitionTime; + } + + lease = otherRendezvousConnectionMetric.lease; + + numConnectionsBegun += otherRendezvousConnectionMetric.numConnectionsBegun; + numConnectionsEstablished += otherRendezvousConnectionMetric.numConnectionsEstablished; + numConnectionsRefused += otherRendezvousConnectionMetric.numConnectionsRefused; + totalTimeConnected += otherRendezvousConnectionMetric.totalTimeConnected; + + numLeaseRenewals += otherRendezvousConnectionMetric.numLeaseRenewals; + + numDisconnects += otherRendezvousConnectionMetric.numDisconnects; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMeter.java new file mode 100644 index 000000000..4059bba4e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMeter.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.peer.*; +import net.jxta.peergroup.*; +import net.jxta.rendezvous.*; +import net.jxta.impl.rendezvous.*; +import java.net.*; +import java.util.*; + + +/** + The Meter corresponding to the state and aggregate information of a Rendezvous Service + **/ +public class RendezvousMeter { + private RendezvousMetric cumulativeMetrics; + private RendezvousMetric deltaMetrics; + + private long transitionTime = System.currentTimeMillis(); + + public RendezvousMeter() { + cumulativeMetrics = new RendezvousMetric(null); + } + + public RendezvousMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public synchronized RendezvousMetric collectMetrics() { + RendezvousMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + + return prevDelta; + } + + private void createDeltaMetric() { + deltaMetrics = new RendezvousMetric(cumulativeMetrics); + } + + @Override + public String toString() { + return "RendezvousMeter"; + } + + public void startEdge() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + transitionTime = System.currentTimeMillis(); + deltaMetrics.startEdge(transitionTime); + cumulativeMetrics.startEdge(transitionTime); + } + + public void stopEdge() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + long now = System.currentTimeMillis(); + long timeAsEdge = now - transitionTime; + + transitionTime = now; + + if (!cumulativeMetrics.isEdge()) { + timeAsEdge = 0; + } + + deltaMetrics.stopEdge(now, timeAsEdge); + cumulativeMetrics.stopEdge(now, timeAsEdge); + } + + public void startRendezvous() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + transitionTime = System.currentTimeMillis(); + deltaMetrics.startRendezvous(transitionTime); + cumulativeMetrics.startRendezvous(transitionTime); + } + + public void stopRendezvous() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + long now = System.currentTimeMillis(); + long timeAsRendezvous = cumulativeMetrics.isRendezvous() ? (now - transitionTime) : 0; + + transitionTime = now; + + deltaMetrics.stopRendezvous(now, timeAsRendezvous); + cumulativeMetrics.stopRendezvous(now, timeAsRendezvous); + } + + public void invalidMessageReceived() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.invalidMessageReceived(); + cumulativeMetrics.invalidMessageReceived(); + } + + public void receivedMessageProcessedLocally() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.receivedMessageProcessedLocally(); + cumulativeMetrics.receivedMessageProcessedLocally(); + } + + public void receivedMessageRepropagatedInGroup() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.receivedMessageRepropagatedInGroup(); + cumulativeMetrics.receivedMessageRepropagatedInGroup(); + } + + public void receivedDeadMessage() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.receivedDeadMessage(); + cumulativeMetrics.receivedDeadMessage(); + } + + public void receivedLoopbackMessage() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.receivedLoopbackMessage(); + cumulativeMetrics.receivedLoopbackMessage(); + } + + public void receivedDuplicateMessage() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.receivedDuplicateMessage(); + cumulativeMetrics.receivedDuplicateMessage(); + } + + public void propagateToPeers(int numPeers) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.propagateToPeers(numPeers); + cumulativeMetrics.propagateToPeers(numPeers); + } + + public void propagateToNeighbors() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.propagateToNeighbors(); + cumulativeMetrics.propagateToNeighbors(); + } + + public void propagateToNeighborsFailed() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.propagateToNeighborsFailed(); + cumulativeMetrics.propagateToNeighborsFailed(); + } + + public void propagateToGroup() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.propagateToGroup(); + cumulativeMetrics.propagateToGroup(); + } + + public void walk() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.walk(); + cumulativeMetrics.walk(); + } + + public void walkFailed() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.walkFailed(); + cumulativeMetrics.walkFailed(); + } + + public void walkToPeers(int numPeers) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.walkToPeers(numPeers); + cumulativeMetrics.walkToPeers(numPeers); + } + + public void walkToPeersFailed() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.walkToPeersFailed(); + cumulativeMetrics.walkToPeersFailed(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMeterBuildSettings.java new file mode 100644 index 000000000..398985541 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMeterBuildSettings.java @@ -0,0 +1,67 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + +import net.jxta.impl.meter.*; + +public interface RendezvousMeterBuildSettings extends MeterBuildSettings { + public static final boolean RENDEZVOUS_METERING = ConditionalRendezvousMeterBuildSettings.isRuntimeMetering(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMetric.java new file mode 100644 index 000000000..719c0f0e4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousMetric.java @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.rendezvous.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; + +import java.util.*; + + +/** + The Metric corresponding to the state and aggregate information of a Rendezvous Service + **/ +public class RendezvousMetric implements DocumentSerializable { + + public static final String EDGE = "edge"; + public static final String RENDEZVOUS = "rendezvous"; + public static final String STOPPED = "stopped"; // but internally represent as null + + private String state = null; + private long transitionTime = 0; + + private long totalEdgeTime; + private int numEdgeTransitions; + + private long totalRendezvousTime; + private long numRendezvousTransitions; + + private int numReceivedProcessedLocally; + private int numReceivedRepropagatedInGroup; + private int numReceivedInvalid; + private int numReceivedDead; + private int numReceivedLoopback; + private int numReceivedDuplicate; + + private int numPropagated; + private int numFailedPropagating; + private int numRepropagated; + private int numFailedRepropagating; + + private int numPropagatedToPeers; + private int numFailedPropagatingToPeers; + private int numPeersPropagatedTo; + + private int numPropagatedInGroup; + + private int numPropagatedToNeighbors; + private int numFailedPropagatingToNeighbors; + + private int numWalks; + private int numFailedWalks; + + private int numWalkedToPeers; + private int numFailedWalkToPeers; + private int numPeersWalkedTo; + + public RendezvousMetric() {} + + public RendezvousMetric(RendezvousMetric prototype) { + if (prototype == null) { + this.state = STOPPED; + } else { + this.state = prototype.state; + this.transitionTime = prototype.transitionTime; + } + } + + /** Get the current state (edge, rendezvous or stopped) + * @return RendezvousMetric.EDGE, RendezvousMetric.RENDEZVOUS or RendezvousMetric.STOPPED + **/ + public String getState() { + return (state != null) ? state : STOPPED; + } + + /** Get the time that it entered the current state + * @return transition time in ms since January 1, 1970, 00:00:00 GMT + **/ + public long getTransitionTime() { + return transitionTime; + } + + /** Is this Rendezvous currently operating as an Edge **/ + public boolean isEdge() { + return (state != null) && state.equals(EDGE); + } + + /** Is this Rendezvous currently operating as an Rendezvous */ + public boolean isRendezvous() { + return (state != null) && state.equals(RENDEZVOUS); + } + + /** Get the time that it began operating as an Edge + * @return time or 0 if it is not currently an Edge + **/ + public long getEdgeStartTime() { + return isEdge() ? transitionTime : 0; + } + + /** Get the total time it began operating as an Edge. + *

            + * Note: This does not include the current time as edge (if it is currently an edge) + * @see #getTotalEdgeTime(long) + * @return time in ms (see note above) + **/ + public long getTotalEdgeTime() { + return totalEdgeTime; + } + + /** Get the total time it began operating as an Edge. If it is currently operating as + * an edge, then the total time is adjusted to include the time since the transition time + * to an edge until the provided time + * @param adjustmentTime The time of this metric will be adjusted to + * @see #getTotalEdgeTime() + * @return time in ms (see note above) + **/ + public long getTotalEdgeTime(long adjustmentTime) { + long result = totalEdgeTime; + + if (isEdge()) { + result += (adjustmentTime - this.transitionTime); + } + + return result; + } + + /** The number of times the peer has become an edge **/ + public int getNumEdgeTransitions() { + return numEdgeTransitions; + } + + /** Get the time that it began operating as an Rendezvous + * @return time or 0 if it is not currently an Rendezvous + **/ + public long getRendezvousStartTime() { + return isRendezvous() ? transitionTime : 0; + } + + /** Get the total time it began operating as an Rendezvous. + *

            + * Note: This does not include the current time as rendezvous (if it is currently an rendezvous) + * @see #getTotalRendezvousTime(long) + * @return time in ms (see note above) + **/ + public long getTotalRendezvousTime() { + return totalRendezvousTime; + } + + /** Get the total time it began operating as an Rendezvous. If it is currently operating as + * a rendezvous, then the total time is adjusted to include the time since the transition time + * to an rendezvous until the provided time + * @param adjustmentTime The time of this metric will be adjusted to + * @see #getTotalRendezvousTime() + * @return time in ms (see note above) + **/ + public long getTotalRendezvousTime(long adjustmentTime) { + long result = totalRendezvousTime; + + if (isRendezvous()) { + result += (adjustmentTime - this.transitionTime); + } + + return result; + } + + /** The number of times the peer has become an rendezvous **/ + public long getNumRendezvousTransitions() { + return numRendezvousTransitions; + } + + /** The number of messages received that were sent to local listeners **/ + public int getNumReceivedProcessedLocally() { + return numReceivedProcessedLocally; + } + + /** The number of messages received that were repropagated to the group **/ + public int getNumReceivedRepropagatedInGroup() { + return numReceivedRepropagatedInGroup; + } + + /** The number of invalid messages received **/ + public int getNumReceivedInvalid() { + return numReceivedInvalid; + } + + /** The number of TTL Dead messages received **/ + public int getNumReceivedDead() { + return numReceivedDead; + } + + /** The number of messages received that originated at peer **/ + public int getNumReceivedLoopback() { + return numReceivedLoopback; + } + + /** The number of duplicate messages received **/ + public int getNumReceivedDuplicate() { + return numReceivedDuplicate; + } + + /** The total number of inbound messages to the rendezvous service that could not be delivered**/ + public int getTotalReceivedUndelivered() { + return numReceivedInvalid + numReceivedDead + numReceivedLoopback + numReceivedDuplicate; + } + + /** The total number of inbound messages to the rendezvous service **/ + public int getTotalReceived() { + return getTotalReceivedUndelivered() + numReceivedProcessedLocally + numReceivedRepropagatedInGroup; + } + + /** The number of outbound messages propagated **/ + public int getNumPropagated() { + return numPropagated; + } + + /** The number of outbound messages failed during propagation **/ + public int getNumFailedPropagating() { + return numFailedPropagating; + } + + /** The number of outbound messages repropagated **/ + public int getNumRepropagated() { + return numRepropagated; + } + + /** The number of outbound messages failed during repropagation **/ + public int getNumFailedRepropagating() { + return numFailedRepropagating; + } + + /** The number of outbound messages propagated to peers **/ + public int getNumPropagatedToPeers() { + return numPropagatedToPeers; + } + + /** The number of outbound messages failed when propagated to peers **/ + public int getNumFailedPropagatingToPeers() { + return numFailedPropagatingToPeers; + } + + /** The number of peers that outbound messages were propagated to **/ + public int getNumPeersPropagatedTo() { + return numPeersPropagatedTo; + } + + /** The number of outbound messages propagated in group **/ + public int getNumPropagatedInGroup() { + return numPropagatedInGroup; + } + + /** The number of outbound messages propagated to neighbors **/ + public int getNumPropagatedToNeighbors() { + return numPropagatedToNeighbors; + } + + /** The number of outbound messages failed when propagated to neighbors **/ + public int getNumFailedPropagatingToNeighbors() { + return numFailedPropagatingToNeighbors; + } + + /** The number of outbound messages walked **/ + public int getNumWalks() { + return numWalks; + } + + /** The number of outbound messages failed attempting walk **/ + public int getNumFailedWalks() { + return numFailedWalks; + } + + /** The number of outbound messages walked to a set of peers **/ + public int getNumWalkedToPeers() { + return numWalkedToPeers; + } + + /** The number of outbound messages failed in an attempt to walk to a set of peers **/ + public int getNumFailedWalkToPeers() { + return numFailedWalkToPeers; + } + + /** The number of peers that outbound messages were walked to **/ + public int getNumPeersWalkedTo() { + return numPeersWalkedTo; + } + + /** Get the duration of current transition to an edge + *

            + * Note: This assumes the clocks are in sync with the reporting peer + * @see #getTimeAsEdge(long) + * @return time in ms (see note above) or 0 if not edge + **/ + public long getTimeAsEdge() { + return getTimeAsEdge(System.currentTimeMillis()); + } + + /** Get the duration of time became an edge until the specified time + * @param adjustmentTime The time of this metric will be computed until + * @see #getTimeAsEdge() + * @return time in ms (see note above) or 0 if not connected + **/ + public long getTimeAsEdge(long adjustmentTime) { + if (isEdge()) { + return (adjustmentTime - this.transitionTime); + } else { + return 0; + } + } + + /** Get the duration of current transition to a rendezvous + *

            + * Note: This assumes the clocks are in sync with the reporting peer + * @see #getTimeAsRendezvous(long) + * @return time in ms (see note above) or 0 if not edge + **/ + public long getTimeAsRendezvous() { + return getTimeAsRendezvous(System.currentTimeMillis()); + } + + /** Get the duration of time became an rendezvous until the specified time + * @param adjustmentTime The time of this metric will be computed until + * @see #getTimeAsRendezvous() + * @return time in ms (see note above) or 0 if not connected + **/ + public long getTimeAsRendezvous(long adjustmentTime) { + if (isRendezvous()) { + return (adjustmentTime - this.transitionTime); + } else { + return 0; + } + } + + void startEdge(long transitionTime) { + this.transitionTime = transitionTime; + this.state = EDGE; + this.numEdgeTransitions++; + } + + void stopEdge(long transitionTime, long timeAsEdge) { + this.state = STOPPED; + this.transitionTime = transitionTime; + this.totalEdgeTime += timeAsEdge; + } + + void startRendezvous(long transitionTime) { + this.state = RENDEZVOUS; + this.transitionTime = transitionTime; + this.numRendezvousTransitions++; + } + + void stopRendezvous(long transitionTime, long timeAsRendezvous) { + this.state = STOPPED; + this.transitionTime = transitionTime; + this.totalRendezvousTime += timeAsRendezvous; + } + + void invalidMessageReceived() { + numReceivedInvalid++; + } + + void receivedMessageProcessedLocally() { + numReceivedProcessedLocally++; + } + + void receivedMessageRepropagatedInGroup() { + numReceivedRepropagatedInGroup++; + } + + void receivedDeadMessage() { + numReceivedDead++; + } + + void receivedLoopbackMessage() { + numReceivedLoopback++; + } + + void receivedDuplicateMessage() { + numReceivedDuplicate++; + } + + void propagateToPeers(int numPeers) { + numPropagatedToPeers++; + numPeersPropagatedTo += numPeers; + } + + void propagateToNeighbors() { + numPropagatedToNeighbors++; + } + + void propagateToNeighborsFailed() { + numFailedPropagatingToNeighbors++; + } + + void propagateToGroup() { + numPropagatedInGroup++; + } + + void walk() { + numWalks++; + } + + void walkFailed() { + numFailedWalks++; + } + + void walkToPeers(int numPeers) { + numWalkedToPeers++; + numPeersWalkedTo += numPeers; + } + + void walkToPeersFailed() { + numFailedWalkToPeers++; + } + + public void mergeMetrics(RendezvousMetric otherRendezvousMetric) { + if (otherRendezvousMetric == null) { + return; + } + + if (otherRendezvousMetric.state != null) { + state = otherRendezvousMetric.state; + } + + if (otherRendezvousMetric.transitionTime != 0) { + transitionTime = otherRendezvousMetric.transitionTime; + } + + this.totalEdgeTime += otherRendezvousMetric.totalEdgeTime; + this.numEdgeTransitions += otherRendezvousMetric.numEdgeTransitions; + + this.totalRendezvousTime += otherRendezvousMetric.totalRendezvousTime; + this.numRendezvousTransitions += otherRendezvousMetric.numRendezvousTransitions; + + this.numReceivedProcessedLocally += otherRendezvousMetric.numReceivedProcessedLocally; + this.numReceivedRepropagatedInGroup += otherRendezvousMetric.numReceivedRepropagatedInGroup; + + this.numReceivedInvalid += otherRendezvousMetric.numReceivedInvalid; + + this.numReceivedDead += otherRendezvousMetric.numReceivedDead; + this.numReceivedLoopback += otherRendezvousMetric.numReceivedLoopback; + this.numReceivedDuplicate += otherRendezvousMetric.numReceivedDuplicate; + + this.numPropagated += otherRendezvousMetric.numPropagated; + this.numFailedPropagating += otherRendezvousMetric.numFailedPropagating; + this.numRepropagated += otherRendezvousMetric.numRepropagated; + this.numFailedRepropagating += otherRendezvousMetric.numFailedRepropagating; + + this.numPropagatedToPeers += otherRendezvousMetric.numPropagatedToPeers; + this.numFailedPropagatingToPeers += otherRendezvousMetric.numFailedPropagatingToPeers; + this.numPeersPropagatedTo += otherRendezvousMetric.numPeersPropagatedTo; + + this.numPropagatedInGroup += otherRendezvousMetric.numPropagatedInGroup; + + this.numPropagatedToNeighbors += otherRendezvousMetric.numPropagatedToNeighbors; + this.numFailedPropagatingToNeighbors += otherRendezvousMetric.numFailedPropagatingToNeighbors; + + this.numWalks += otherRendezvousMetric.numWalks; + this.numFailedWalks += otherRendezvousMetric.numFailedWalks; + + this.numWalkedToPeers += otherRendezvousMetric.numWalkedToPeers; + this.numFailedWalkToPeers += otherRendezvousMetric.numFailedWalkToPeers; + this.numPeersWalkedTo += otherRendezvousMetric.numPeersWalkedTo; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (state != null) { + DocumentSerializableUtilities.addString(element, "state", state); + } + if (transitionTime != 0) { + DocumentSerializableUtilities.addLong(element, "transitionTime", transitionTime); + } + if (totalEdgeTime != 0) { + DocumentSerializableUtilities.addLong(element, "totalEdgeTime", totalEdgeTime); + } + if (numEdgeTransitions != 0) { + DocumentSerializableUtilities.addInt(element, "numEdgeTransitions", numEdgeTransitions); + } + if (totalRendezvousTime != 0) { + DocumentSerializableUtilities.addLong(element, "totalRendezvousTime", totalRendezvousTime); + } + if (numRendezvousTransitions != 0) { + DocumentSerializableUtilities.addLong(element, "numRendezvousTransitions", numRendezvousTransitions); + } + if (numReceivedProcessedLocally != 0) { + DocumentSerializableUtilities.addInt(element, "numReceivedProcessedLocally", numReceivedProcessedLocally); + } + if (numReceivedRepropagatedInGroup != 0) { + DocumentSerializableUtilities.addInt(element, "numReceivedRepropagatedInGroup", numReceivedRepropagatedInGroup); + } + if (numReceivedInvalid != 0) { + DocumentSerializableUtilities.addInt(element, "numReceivedInvalid", numReceivedInvalid); + } + if (numReceivedDead != 0) { + DocumentSerializableUtilities.addInt(element, "numReceivedDead", numReceivedDead); + } + if (numReceivedLoopback != 0) { + DocumentSerializableUtilities.addInt(element, "numReceivedLoopback", numReceivedLoopback); + } + if (numReceivedDuplicate != 0) { + DocumentSerializableUtilities.addInt(element, "numReceivedDuplicate", numReceivedDuplicate); + } + if (numPropagated != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagated", numPropagated); + } + if (numFailedPropagating != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedPropagating", numFailedPropagating); + } + if (numRepropagated != 0) { + DocumentSerializableUtilities.addInt(element, "numRepropagated", numRepropagated); + } + if (numFailedRepropagating != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedRepropagating", numFailedRepropagating); + } + if (numPropagatedToPeers != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagatedToPeers", numPropagatedToPeers); + } + if (numFailedPropagatingToPeers != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedPropagatingToPeers", numFailedPropagatingToPeers); + } + if (numPeersPropagatedTo != 0) { + DocumentSerializableUtilities.addInt(element, "numPeersPropagatedTo", numPeersPropagatedTo); + } + if (numPropagatedInGroup != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagatedInGroup", numPropagatedInGroup); + } + if (numPropagatedToNeighbors != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagatedToNeighbors", numPropagatedToNeighbors); + } + if (numFailedPropagatingToNeighbors != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedPropagatingToNeighbors", numFailedPropagatingToNeighbors); + } + if (numWalks != 0) { + DocumentSerializableUtilities.addInt(element, "numWalks", numWalks); + } + if (numFailedWalks != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedWalks", numFailedWalks); + } + if (numWalkedToPeers != 0) { + DocumentSerializableUtilities.addInt(element, "numWalkedToPeers", numWalkedToPeers); + } + if (numFailedWalkToPeers != 0) { + DocumentSerializableUtilities.addInt(element, "numFailedWalkToPeers", numFailedWalkToPeers); + } + if (numPeersWalkedTo != 0) { + DocumentSerializableUtilities.addInt(element, "numPeersWalkedTo", numPeersWalkedTo); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("state")) { + state = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("transitionTime")) { + transitionTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("totalEdgeTime")) { + totalEdgeTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numEdgeTransitions")) { + numEdgeTransitions = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("totalRendezvousTime")) { + totalRendezvousTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numRendezvousTransitions")) { + numRendezvousTransitions = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numReceivedProcessedLocally")) { + numReceivedProcessedLocally = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numReceivedRepropagatedInGroup")) { + numReceivedRepropagatedInGroup = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numReceivedInvalid")) { + numReceivedInvalid = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numReceivedDead")) { + numReceivedDead = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numReceivedLoopback")) { + numReceivedLoopback = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numReceivedDuplicate")) { + numReceivedDuplicate = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagated")) { + numPropagated = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedPropagating")) { + numFailedPropagating = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numRepropagated")) { + numRepropagated = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedRepropagating")) { + numFailedRepropagating = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagatedToPeers")) { + numPropagatedToPeers = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedPropagatingToPeers")) { + numFailedPropagatingToPeers = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPeersPropagatedTo")) { + numPeersPropagatedTo = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagatedInGroup")) { + numPropagatedInGroup = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagatedToNeighbors")) { + numPropagatedToNeighbors = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedPropagatingToNeighbors")) { + numFailedPropagatingToNeighbors = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numWalks")) { + numWalks = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedWalks")) { + numFailedWalks = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numWalkedToPeers")) { + numWalkedToPeers = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numFailedWalkToPeers")) { + numFailedWalkToPeers = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPeersWalkedTo")) { + numPeersWalkedTo = DocumentSerializableUtilities.getInt(childElement); + } + } + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMetric.java new file mode 100644 index 000000000..d2e56f663 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMetric.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.meter.*; +import net.jxta.peer.*; + +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.platform.*; +import java.util.*; +import net.jxta.util.*; +import net.jxta.exception.*; +import net.jxta.id.*; +import java.net.*; + + +/** + * The Service Monitor Metric for the standard Rendezvous Service + **/ +public class RendezvousServiceMetric implements ServiceMetric { + private RendezvousMetric rendezvousMetric; + private LinkedList rendezvousConnectionMetrics = new LinkedList(); + private LinkedList clientConnectionMetrics = new LinkedList(); + private ModuleClassID moduleClassID = MonitorResources.rendezvousServiceMonitorClassID; + + /** + * Create a Service Metric: No-arg constructor is required + **/ + public RendezvousServiceMetric() {} + + private RendezvousServiceMetric(ModuleClassID moduleClassID) { + init(moduleClassID); + } + + /** + * Initialize the metric with the ModuleClassID of the Monitor + **/ + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + /** Get the ModuleClassID of the Monitor that generated this ServiceMetric **/ + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + /** + * Get the General Rendezvous Metric + **/ + public RendezvousMetric getRendezvousMetric() { + return rendezvousMetric; + } + + void setRendezvousMetric(RendezvousMetric rendezvousMetric) { + this.rendezvousMetric = rendezvousMetric; + } + + /** + * Append a Client Connection Metric + **/ + public void addClientConnectionMetric(ClientConnectionMetric clientConnectionMetric) { + synchronized (clientConnectionMetrics) { + clientConnectionMetrics.add(clientConnectionMetric); + } + } + + /** + * Get all the Client Connection Metrics + **/ + public Iterator getClientConnectionMetrics() { + return clientConnectionMetrics.iterator(); + } + + void clearClientConnectionMetrics() { + clientConnectionMetrics.clear(); + } + + /** + * Get the Client Connection Metrics for a single Peers ID + **/ + public ClientConnectionMetric getClientConnectionMetric(PeerID peerId) { + for (Iterator i = clientConnectionMetrics.iterator(); i.hasNext();) { + ClientConnectionMetric clientConnectionMetric = (ClientConnectionMetric) i.next(); + + if (peerId.equals(clientConnectionMetric.getPeerID())) { + return clientConnectionMetric; + } + } + + return null; + } + + /** + * Append a Rendezvous Connection Metric + **/ + public void addRendezvousConnectionMetric(RendezvousConnectionMetric rendezvousConnectionMetric) { + synchronized (rendezvousConnectionMetrics) { + rendezvousConnectionMetrics.add(rendezvousConnectionMetric); + } + } + + /** + * Get all the Rendezvous Connection Metrics + **/ + public Iterator getRendezvousConnectionMetrics() { + return rendezvousConnectionMetrics.iterator(); + } + + void clearRendezvousConnectionMetrics() { + rendezvousConnectionMetrics.clear(); + } + + /** + * Get the Rendezvous Connection Metrics for each Peers ID + **/ + public RendezvousConnectionMetric getRendezvousConnectionMetric(PeerID peerID) { + for (Iterator i = rendezvousConnectionMetrics.iterator(); i.hasNext();) { + RendezvousConnectionMetric rendezvousConnectionMetric = (RendezvousConnectionMetric) i.next(); + + if (peerID.equals(rendezvousConnectionMetric.getPeerID())) { + return rendezvousConnectionMetric; + } + } + + return null; + } + + /** + * {@inheritDoc} + **/ + public void serializeTo(Element element) throws DocumentSerializationException { + if (rendezvousMetric != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "rendezvousMetric", rendezvousMetric); + } + + for (Iterator i = clientConnectionMetrics.iterator(); i.hasNext();) { + ClientConnectionMetric clientConnectionMetric = (ClientConnectionMetric) i.next(); + + DocumentSerializableUtilities.addDocumentSerializable(element, "clientConnectionMetric", clientConnectionMetric); + } + + for (Iterator i = rendezvousConnectionMetrics.iterator(); i.hasNext();) { + RendezvousConnectionMetric rendezvousConnectionMetric = (RendezvousConnectionMetric) i.next(); + + DocumentSerializableUtilities.addDocumentSerializable(element, "rendezvousConnectionMetric" + , + rendezvousConnectionMetric); + } + + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + + } + + /** + * {@inheritDoc} + **/ + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("clientConnectionMetric")) { + ClientConnectionMetric clientConnectionMetric = (ClientConnectionMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, ClientConnectionMetric.class); + + clientConnectionMetrics.add(clientConnectionMetric); + } else if (tagName.equals("rendezvousConnectionMetric")) { + RendezvousConnectionMetric rendezvousConnectionMetric = (RendezvousConnectionMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, RendezvousConnectionMetric.class); + + rendezvousConnectionMetrics.add(rendezvousConnectionMetric); + } else if (tagName.equals("rendezvousMetric")) { + rendezvousMetric = (RendezvousMetric) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + RendezvousMetric.class); + } + if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't read moduleClassID", jex); + } + } + } + } + + /** + * {@inheritDoc} + **/ + public void mergeMetrics(ServiceMetric otherServiceMetric) { + mergeMetrics(otherServiceMetric, true, true, true); + } + + /** + * Make a deep copy of this metric only including the portions designated in the Filter + * The resulting metric is Safe to modify without danger to the underlying Monitor Metrics + * @param rendezvousServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + **/ + public RendezvousServiceMetric deepCopy(RendezvousServiceMonitorFilter rendezvousServiceMonitorFilter) { + RendezvousServiceMetric serviceMetric = new RendezvousServiceMetric(); + + serviceMetric.moduleClassID = moduleClassID; + + serviceMetric.mergeMetrics(this, true, rendezvousServiceMonitorFilter.isIncludeClientConnectionMetrics() + , + rendezvousServiceMonitorFilter.isIncludeRendezvousConnectionMetrics()); + return serviceMetric; + } + + /** + * {@inheritDoc} + *

            This will only merge the designated submetrics + * @param includeRendezvousMetric Include the basic Rendezvous Metric in the merge + * @param includeClientConnectionMetrics Include Client Connection Metrics in the merge + * @param includeRendezvousConnectionMetrics Include Rendezvous Connection Metrics in the merge + **/ + public void mergeMetrics(ServiceMetric otherServiceMetric, boolean includeRendezvousMetric, boolean includeClientConnectionMetrics, boolean includeRendezvousConnectionMetrics) { + RendezvousServiceMetric otherRendezvousServiceMetric = (RendezvousServiceMetric) otherServiceMetric; + + if (includeRendezvousMetric) { + RendezvousMetric otherRendezvousMetric = otherRendezvousServiceMetric.getRendezvousMetric(); + + if ((rendezvousMetric == null) && (otherRendezvousMetric != null)) { + rendezvousMetric = new RendezvousMetric(otherRendezvousMetric); + } + + if (otherRendezvousMetric != null) { + rendezvousMetric.mergeMetrics(otherRendezvousMetric); + } + } + + if (includeClientConnectionMetrics) { + for (Iterator i = otherRendezvousServiceMetric.getClientConnectionMetrics(); i.hasNext();) { + ClientConnectionMetric otherClientConnectionMetric = (ClientConnectionMetric) i.next(); + ClientConnectionMetric clientConnectionMetric = getClientConnectionMetric(otherClientConnectionMetric.getPeerID()); + + if (clientConnectionMetric == null) { + clientConnectionMetric = new ClientConnectionMetric(otherClientConnectionMetric); + addClientConnectionMetric(clientConnectionMetric); + } + + clientConnectionMetric.mergeMetrics(otherClientConnectionMetric); + } + } + + if (includeRendezvousConnectionMetrics) { + for (Iterator i = otherRendezvousServiceMetric.getRendezvousConnectionMetrics(); i.hasNext();) { + RendezvousConnectionMetric otherRendezvousConnectionMetric = (RendezvousConnectionMetric) i.next(); + RendezvousConnectionMetric rendezvousConnectionMetric = getRendezvousConnectionMetric( + otherRendezvousConnectionMetric.getPeerID()); + + if (rendezvousConnectionMetric == null) { + rendezvousConnectionMetric = new RendezvousConnectionMetric(otherRendezvousConnectionMetric); + addRendezvousConnectionMetric(rendezvousConnectionMetric); + } + + rendezvousConnectionMetric.mergeMetrics(otherRendezvousConnectionMetric); + } + } + } + + /** + * {@inheritDoc} + **/ + public void diffMetrics(ServiceMetric otherOne) { + throw new RuntimeException("Not Supported"); + } + + /** + * Make a shallow copy of this metric only including the portions designated in the Filter + *

            Note: since this is a shallow copy it is dangerous to modify the submetrics + * @param rendezvousServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + **/ + public RendezvousServiceMetric shallowCopy(RendezvousServiceMonitorFilter rendezvousServiceMonitorFilter) { + RendezvousServiceMetric rendezvousServiceMetric = new RendezvousServiceMetric(moduleClassID); + + rendezvousServiceMetric.rendezvousMetric = rendezvousMetric; + + if (rendezvousServiceMonitorFilter.isIncludeClientConnectionMetrics()) { + for (Iterator i = getClientConnectionMetrics(); i.hasNext();) { + ClientConnectionMetric clientConnectionMetric = (ClientConnectionMetric) i.next(); + + rendezvousServiceMetric.addClientConnectionMetric(clientConnectionMetric); + } + } + + if (rendezvousServiceMonitorFilter.isIncludeRendezvousConnectionMetrics()) { + for (Iterator i = getRendezvousConnectionMetrics(); i.hasNext();) { + RendezvousConnectionMetric rendezvousConnectionMetric = (RendezvousConnectionMetric) i.next(); + + rendezvousServiceMetric.addRendezvousConnectionMetric(rendezvousConnectionMetric); + } + } + + return rendezvousServiceMetric; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMonitor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMonitor.java new file mode 100644 index 000000000..07e2cc93f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMonitor.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.impl.meter.GenericServiceMonitor; +import net.jxta.impl.meter.MetricUtilities; +import net.jxta.meter.ServiceMetric; +import net.jxta.meter.ServiceMonitorFilter; +import net.jxta.peer.PeerID; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.LinkedList; + + +/** + * The Service Monitor for the standard Rendezvous Service + */ +public class RendezvousServiceMonitor extends GenericServiceMonitor { + private Hashtable clientConnectionMeters = new Hashtable(); + private LinkedList rendezvousConnectionMeters = new LinkedList(); + + private RendezvousMeter rendezvousMeter = new RendezvousMeter(); + + private RendezvousServiceMetric cumulativeRendezvousServiceMetric; + + /** + * {@inheritDoc} + */ + @Override + protected void init() { + cumulativeRendezvousServiceMetric = (RendezvousServiceMetric) getCumulativeServiceMetric(); + cumulativeRendezvousServiceMetric.setRendezvousMetric(rendezvousMeter.getCumulativeMetrics()); + } + + /** + * Get the General RendezvousMeter + * @return client RendezvousMeter + */ + public RendezvousMeter getRendezvousMeter() { + return rendezvousMeter; + } + + /** + * Get a Client Connection Meter + * + * @param endpointAddress containing Peer Id for the Meter + * @return client connection meter + */ + public synchronized ClientConnectionMeter getClientConnectionMeter(EndpointAddress endpointAddress) { + PeerID peerID = MetricUtilities.getPeerIdFromEndpointAddress(endpointAddress); + + return getClientConnectionMeter(peerID); + } + + /** + * Get a Client Connection Meter + * + * @param peerId Peer Id for the Meter + * @return client connection meter + */ + public synchronized ClientConnectionMeter getClientConnectionMeter(PeerID peerId) { + ClientConnectionMeter clientConnectionMeter = clientConnectionMeters.get(peerId); + + if (clientConnectionMeter == null) { + clientConnectionMeter = new ClientConnectionMeter(peerId); + clientConnectionMeters.put(peerId, clientConnectionMeter); + cumulativeRendezvousServiceMetric.addClientConnectionMetric(clientConnectionMeter.getCumulativeMetrics()); + } + + return clientConnectionMeter; + } + + /** + * Get a Client Connection Meter + * + * @param peerIdString Peer Id as a String + * @return client connection meter + */ + public synchronized ClientConnectionMeter getClientConnectionMeter(String peerIdString) { + PeerID peerID = MetricUtilities.getPeerIdFromString(peerIdString); + + return getClientConnectionMeter(peerID); + } + + /* + public synchronized void removeClientConnectionMeter(String peerId) { + clientConnectionMeters.remove(peerId); + } + */ + + /** + * Get a Rendezvous Connection Meter + * + * @param peerIdStr Peer Id for the Meter as a String + * @return the Rendezvous Connection Meter + */ + public synchronized RendezvousConnectionMeter getRendezvousConnectionMeter(String peerIdStr) { + PeerID peerID = MetricUtilities.getPeerIdFromString(peerIdStr); + + return getRendezvousConnectionMeter(peerID); + } + + /** + * Get a Rendezvous Connection Meter + * + * @param peerID Peer Id for the Meter + * @return the Rendezvous Connection Meter + */ + public synchronized RendezvousConnectionMeter getRendezvousConnectionMeter(PeerID peerID) { + if (peerID == null) { + peerID = MetricUtilities.BAD_PEERID; + } + + for (Object rendezvousConnectionMeter1 : rendezvousConnectionMeters) { + RendezvousConnectionMeter rendezvousConnectionMeter = (RendezvousConnectionMeter) rendezvousConnectionMeter1; + + if (peerID.equals(rendezvousConnectionMeter.getPeerID())) { + return rendezvousConnectionMeter; + } + } + + RendezvousConnectionMeter rendezvousConnectionMeter = new RendezvousConnectionMeter(peerID); + + rendezvousConnectionMeters.add(rendezvousConnectionMeter); + cumulativeRendezvousServiceMetric.addRendezvousConnectionMetric(rendezvousConnectionMeter.getCumulativeMetrics()); + + return rendezvousConnectionMeter; + } + + /* + public synchronized void removeRendezvousConnectionMeter(PeerID peerID) { + if (peerID == null) + return; + + for (Iterator i = rendezvousConnectionMeters.iterator(); i.hasNext(); ) { + RendezvousConnectionMeter rendezvousConnectionMeter = (RendezvousConnectionMeter)i.next(); + if (peerID.equals(rendezvousConnectionMeter.getPeerID())) { + i.remove(); + return; + } + } + } + */ + + /** + * {@inheritDoc} + */ + @Override + protected synchronized ServiceMetric collectServiceMetrics() { + RendezvousServiceMetric rendezvousServiceMetric = (RendezvousServiceMetric) createServiceMetric(); + + boolean anyData = false; + + for (Enumeration e = clientConnectionMeters.elements(); e.hasMoreElements();) { + ClientConnectionMeter clientConnectionMeter = e.nextElement(); + ClientConnectionMetric clientConnectionMetric = clientConnectionMeter.collectMetrics(); // clears delta from meter + + if (clientConnectionMetric != null) { + rendezvousServiceMetric.addClientConnectionMetric(clientConnectionMetric); + anyData = true; + } + } + + for (RendezvousConnectionMeter rendezvousConnectionMeter : rendezvousConnectionMeters) { + RendezvousConnectionMetric rendezvousConnectionMetric = rendezvousConnectionMeter.collectMetrics(); // clears delta from meter + + if (rendezvousConnectionMetric != null) { + rendezvousServiceMetric.addRendezvousConnectionMetric(rendezvousConnectionMetric); + anyData = true; + } + } + + RendezvousMetric rendezvousMetric = rendezvousMeter.collectMetrics(); + + if (rendezvousMetric != null) { + rendezvousServiceMetric.setRendezvousMetric(rendezvousMetric); + anyData = true; + } + + if (anyData) { + return rendezvousServiceMetric; + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public ServiceMetric getServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime, int pulseIndex, long reportRate) { + int deltaReportRateIndex = monitorManager.getReportRateIndex(reportRate); + RendezvousServiceMetric origMetric = (RendezvousServiceMetric) deltaServiceMetrics[deltaReportRateIndex]; + + if (origMetric == null) { + return null; + } + + RendezvousServiceMonitorFilter rendezvousServiceMonitorFilter = (RendezvousServiceMonitorFilter) serviceMonitorFilter; + + return origMetric.shallowCopy(rendezvousServiceMonitorFilter); + } + + /** + * {@inheritDoc} + */ + @Override + public ServiceMetric getCumulativeServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime) { + RendezvousServiceMonitorFilter rendezvousServiceMonitorFilter = (RendezvousServiceMonitorFilter) serviceMonitorFilter; + RendezvousServiceMetric origMetric = (RendezvousServiceMetric) getCumulativeServiceMetric(); + + return origMetric.deepCopy(rendezvousServiceMonitorFilter); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMonitorFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMonitorFilter.java new file mode 100644 index 000000000..25c82181f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rendezvousMeter/RendezvousServiceMonitorFilter.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.rendezvous.rendezvousMeter; + + +import net.jxta.meter.*; +import net.jxta.platform.*; +import net.jxta.document.*; +import net.jxta.util.documentSerializable.*; +import java.util.*; +import net.jxta.util.*; +import net.jxta.exception.*; +import java.net.*; +import net.jxta.id.IDFactory; + + +public class RendezvousServiceMonitorFilter implements ServiceMonitorFilter { + private boolean includeClientConnectionMetrics = true; + private boolean includeRendezvousConnectionMetrics = true; + private ModuleClassID moduleClassID = MonitorResources.rendezvousServiceMonitorClassID; + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + public RendezvousServiceMonitorFilter() {} + + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public boolean isIncludeClientConnectionMetrics() { + return includeClientConnectionMetrics; + } + + public boolean isIncludeRendezvousConnectionMetrics() { + return includeRendezvousConnectionMetrics; + } + + public void setIncludeClientConnectionMetrics(boolean includeClientConnectionMetrics) { + this.includeClientConnectionMetrics = includeClientConnectionMetrics; + } + + public void setIncludeRendezvousConnectionMetrics(boolean includeClientConnectionMetrics) { + this.includeRendezvousConnectionMetrics = includeClientConnectionMetrics; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addBoolean(element, "includeClientConnectionMetrics", includeClientConnectionMetrics); + DocumentSerializableUtilities.addBoolean(element, "includeRendezvousConnectionMetrics", includeRendezvousConnectionMetrics); + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("includeClientConnectionMetrics")) { + includeClientConnectionMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } else if (tagName.equals("includeRendezvousConnectionMetrics")) { + includeRendezvousConnectionMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } else if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI((DocumentSerializableUtilities.getString(childElement)))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't read moduleClassID", jex); + } + } + } + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerView.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerView.java new file mode 100644 index 000000000..44b006d83 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerView.java @@ -0,0 +1,2067 @@ +/* + * Copyright (c) 2002-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.Set; +import java.util.SortedSet; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeSet; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.logging.Logging; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezvousListener; + +import net.jxta.impl.endpoint.EndpointUtils; +import net.jxta.impl.endpoint.relay.RelayReferralSeedingManager; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; +import net.jxta.impl.util.SeedingManager; +import net.jxta.impl.util.TimeUtils; +import net.jxta.impl.util.URISeedingManager; + +/** + * This class models a Rendezvous Peer View (RPV): + * ordered collection of all other Rendezvous Peers visible to + * this peer. + *

            + * Presently this class implements a random "diffusion" algorithm + * where each Peer periodically selects a randomly selected peer advertisement + * from its view and sends it over to a randomly selected peer from its view. + * Over time, this causes every peer to learn about every other peer, resulting + * in a "converged" peer view. + *

            + * This diffusion process is bootstrapped by every peer sending their + * own peer advertisements to some well-known, stable, "seed" peers on + * startup. + */ +public final class PeerView implements EndpointListener, RendezvousListener { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(PeerView.class.getName()); + + /** + * Our service name + */ + static final String SERVICE_NAME = "PeerView"; + + /** + * Namespace used for rdv message elements. + */ + static final String MESSAGE_NAMESPACE = "jxta"; + + /** + * Element name of outgoing messages. Note that the element contains a + * RdvAvertisement and not a Peer Advertisement. + */ + static final String MESSAGE_ELEMENT_NAME = "PeerView.PeerAdv"; + + /** + * Element name of responses. Note that the element contains a + * RdvAvertisement and not a Peer Advertisement. + */ + static final String RESPONSE_ELEMENT_NAME = "PeerView.PeerAdv.Response"; + + /** + * Message element name for PeerView "Cached" Message Element + */ + static final String CACHED_RADV_ELEMENT_NAME = "PeerView.Cached"; + + /** + * Optional message element that specifies by its presence in a peerview + * message that the referenced peer is not the provider of the + * RdvAdvertisement and the advertisement is a "hint" or referral from the + * responding peer. + *

            + * In practice, when sending its own RdvAdvertisement, a peer does not + * include this element, but when sending another peer's RdvAdvertisement, + * this element is included. + */ + static final MessageElement CACHED_RADV_ELEMENT = new StringMessageElement(CACHED_RADV_ELEMENT_NAME, Boolean.TRUE.toString(), null); + + /** + * Message element name that specifies the route advertisement of the + * source of the message. + */ + static final String SRCROUTEADV_ELEMENT_NAME = "PeerView.SrcRouteAdv"; + + /** + * Message element name for PeerView "Edge" Message Element + */ + static final String EDGE_ELEMENT_NAME = "PeerView.EdgePeer"; + + /** + * Optional message element that specifies by its presence in a peerview + * message that the referenced peer is an edge peer and not a member of the + * peerview. + */ + static final MessageElement EDGE_ELEMENT = new StringMessageElement(EDGE_ELEMENT_NAME, Boolean.TRUE.toString(), null); + + /** + * Message element name for PeerView "Failure" Message Element + */ + static final String FAILURE_ELEMENT_NAME = "PeerView.Failure"; + + /** + * Optional message element that specifies by its presence in a peerview + * message that the referenced peer has either failed or is quitting. If the + * "cached" element is also set then the error is being reported by a third + * party. + */ + static final MessageElement FAILURE_ELEMENT = new StringMessageElement(FAILURE_ELEMENT_NAME, Boolean.TRUE.toString(), null); + + /** + * This is the interval between adv exchange in seconds. This is + * the main tunable runtime parameter for the diffusion + * process. An interval that is too low will improve view + * consistency at the expense of gratuitous network traffic. On + * the other hand, an interval that is too high will cause the + * view to become inconsistent. It is desirable to err on the side + * of extra traffic. + */ + private static final long DEFAULT_SEEDING_PERIOD = 5 * TimeUtils.ASECOND; + + private static final long WATCHDOG_PERIOD = 30 * TimeUtils.ASECOND; + private static final long WATCHDOG_GRACE_DELAY = 5 * TimeUtils.AMINUTE; + + private static final long DEFAULT_BOOTSTRAP_KICK_INTERVAL = 3 * TimeUtils.ASECOND; + + private static final int MIN_BOOTLEVEL = 0; + private static final int BOOTLEVEL_INCREMENT = 1; + private static final int MAX_BOOTLEVEL = 6; + + /** + * DEFAULT_SEEDING_RDVPEERS + *

            + * This value is the maximum number of rendezvous peers that will be + * send our own advertisement at boot time. + */ + //private static final int DEFAULT_SEEDING_RDVPEERS = 5; + + private final PeerGroup group; + + /** + * The group in which our propagate pipe will run. + */ + private final PeerGroup advertisingGroup; + private final RendezVousServiceImpl rdvService; + private final EndpointService endpoint; + + /** + * The name of this PeerView. + *

            + * FIXME 20040623 bondolo This should be a CodatID. + */ + private final String name; + + /** + * Delay in relative milliseconds to apply before contacting seeding rdvs. + * 0 is supposed to be reserved by RdvConfig to mean "use the default". + * However, it is in fact a valid value and also the one we want for the default. + * The only problem with that is that it is not possible to configure this value + * explicitly, should it one day not be the default. The issue is actually in RdvConfig. + */ + private long seedingRdvConnDelay = 0; + + private final boolean useOnlySeeds; + + private final SeedingManager seedingManager; + + /** + * If the peerview is smaller than this we will try harder to find + * additional peerview members. + */ + private int minHappyPeerView = 4; + + /** + * A single timer is used to periodically kick each PeerView + * into activity. For the Random PeerView, this activity consists + * of selecting a PeerViewElement at random from its view and + * sending it across to a randomly-selected peer from its view. + *

            + * FIXME 20021121 lomax + *

            + * The original idea of using a common timer in order to save threads IS a + * very good idea. However, limitations, and actually, bugs, in java.util.Timer + * creates the following problems when using a static Timer: + *

            + *

              + *
            • Memory Leak: Canceling a TimerTask does not remove it from the + * execution queue of the Timer until the Timer is canceled or the + * TimerTask is fired. Since most of the TimerTasks are inner classes + * this can mean that the PeerView is held around for a long time.
            • + *

              + *

            • java.util.Timer is not only not real-time (which is more or less fine + * for the PeerView, but it sequentially invokes tasks (only one Thread + * per Timer). As a result, tasks that takes a long time to run delays + * other tasks.
            • + *
            + *

            + * The PeerView would function better with a better Timer, but JDK does + * not provide a standard timer that would fulfill the needs of the + * PeerView. Maybe we should implement a JXTA Timer, since lots of the JXTA + * services, by being very asynchronous, rely on the same kind of timer + * semantics as the PeerView. Until then, creating a Timer per instance of + * the PeerView (i.e. per instance of joined PeerGroup) is the best + * workaround. + */ + private final Timer timer; + + /** + * A random number generator. + */ + private final static Random random = new Random(); + + /** + * List of scheduled tasks + */ + private final Set scheduledTasks = Collections.synchronizedSet(new HashSet()); + + /** + * Describes the frequency and amount of effort we will spend updating + * the peerview. + */ + private int bootLevel = MIN_BOOTLEVEL; + + /** + * Earliest absolute time in milliseconds at which we will allow a reseed + * to take place. + */ + private long earliestReseed = 0L; + + private final String uniqueGroupId; + + /** + * Listeners for PeerView Events. + */ + private final Set rpvListeners = Collections.synchronizedSet(new HashSet()); + + /** + * Used for querying for pves. + */ + private InputPipe wirePipeInputPipe = null; + + /** + * Used for querying for pves. + */ + private OutputPipe wirePipeOutputPipe = null; + + /** + * Used for notifications about pve failures. + */ + private InputPipe localGroupWirePipeInputPipe = null; + + /** + * Used for notifications about pve failures. + */ + private OutputPipe localGroupWirePipeOutputPipe = null; + + /** + * A task which monitors the up and down peers in the peerview. + */ + private WatchdogTask watchdogTask = null; + + /** + * This is the accumulated view by an instance of this class. + */ + private final SortedSet localView = Collections.synchronizedSortedSet(new TreeSet()); + + /** + * PVE for ourself. + *

            + * FIXME bondolo 20041015 This should be part of the local view. + */ + private final PeerViewElement self; + private PeerViewElement upPeer = null; + private PeerViewElement downPeer = null; + + private final PeerViewStrategy replyStrategy; + + private final PeerViewStrategy kickRecipientStrategy; + + private final PeerViewStrategy kickAdvertisementStrategy; + + private final PeerViewStrategy refreshRecipientStrategy; + + // PeerAdv tracking. + private PeerAdvertisement lastPeerAdv = null; + private int lastModCount = -1; + + private final PipeAdvertisement localGroupWirePipeAdv; + private final PipeAdvertisement advGroupPropPipeAdv; + + /** + * If true then this Peer View instance is closed and is + * shutting down. + */ + private volatile boolean closed = false; + + /** + * Get an instance of PeerView for the specified PeerGroup and Service. + * + * @param group Peer Group in which this Peer View instance operates. + * @param advertisingGroup Peer Group in which this Peer View instance will + * advertise and broadcast its existence. + * @param rdvService The rdvService we are to use. + * @param name The identifying name for this Peer View instance. + */ + public PeerView(PeerGroup group, PeerGroup advertisingGroup, RendezVousServiceImpl rdvService, String name) { + this.group = group; + this.advertisingGroup = advertisingGroup; + this.rdvService = rdvService; + this.name = name; + + this.endpoint = group.getEndpointService(); + + this.uniqueGroupId = group.getPeerGroupID().getUniqueValue().toString(); + + timer = new Timer("PeerView Timer for " + group.getPeerGroupID(), true); + + Advertisement adv = null; + ConfigParams confAdv = group.getConfigAdvertisement(); + + // Get the config. If we do not have a config, we're done; we just keep + // the defaults (edge peer/no auto-rdv) + if (confAdv != null) { + try { + XMLDocument configDoc = (XMLDocument) confAdv.getServiceParam(rdvService.getAssignedID()); + + if (null != configDoc) { + adv = AdvertisementFactory.newAdvertisement(configDoc); + } + } catch (java.util.NoSuchElementException failed) {// ignored + } + } + + RdvConfigAdv rdvConfigAdv; + + if (!(adv instanceof RdvConfigAdv)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Creating new RdvConfigAdv for defaults."); + } + + rdvConfigAdv = (RdvConfigAdv) AdvertisementFactory.newAdvertisement(RdvConfigAdv.getAdvertisementType()); + } else { + rdvConfigAdv = (RdvConfigAdv) adv; + } + + if (rdvConfigAdv.getSeedRendezvousConnectDelay() > 0) { + seedingRdvConnDelay = rdvConfigAdv.getSeedRendezvousConnectDelay(); + } + + useOnlySeeds = rdvConfigAdv.getUseOnlySeeds(); + + if (rdvConfigAdv.getMinHappyPeerView() > 0) { + minHappyPeerView = rdvConfigAdv.getMinHappyPeerView(); + } + + URISeedingManager seedingManager; + + if ((null == advertisingGroup) && rdvConfigAdv.getProbeRelays()) { + seedingManager = new RelayReferralSeedingManager(rdvConfigAdv.getAclUri(), useOnlySeeds, group, name); + } else { + seedingManager = new URISeedingManager(rdvConfigAdv.getAclUri(), useOnlySeeds, group, name); + } + + for (URI aSeeder : Arrays.asList(rdvConfigAdv.getSeedingURIs())) { + seedingManager.addSeedingURI(aSeeder); + } + + for (URI aSeed : Arrays.asList(rdvConfigAdv.getSeedRendezvous())) { + seedingManager.addSeed(aSeed); + } + + this.seedingManager = seedingManager; + + lastPeerAdv = group.getPeerAdvertisement(); + lastModCount = lastPeerAdv.getModCount(); + + // create a new local RdvAdvertisement and set it to self. + RdvAdvertisement radv = createRdvAdvertisement(lastPeerAdv, name); + + self = new PeerViewElement(endpoint, radv); + + // addPeerViewElement( self ); + + // setup endpoint listener + endpoint.addIncomingMessageListener(this, SERVICE_NAME, uniqueGroupId); + + // add rendezvous listener + rdvService.addListener(this); + + // initialize strategies + replyStrategy = new PeerViewRandomWithReplaceStrategy(localView); + + kickRecipientStrategy = new PeerViewRandomStrategy(localView); + + kickAdvertisementStrategy = new PeerViewRandomWithReplaceStrategy(localView); + + refreshRecipientStrategy = new PeerViewSequentialStrategy(localView); + + localGroupWirePipeAdv = makeWirePipeAdvertisement(group, group, name); + + if (null != advertisingGroup) { + advGroupPropPipeAdv = makeWirePipeAdvertisement(advertisingGroup, group, name); + } else { + advGroupPropPipeAdv = null; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info( "PeerView created for group \"" + group.getPeerGroupName() + + "\" [" + group.getPeerGroupID() + "] name \"" + name + "\""); + } + } + + /** + * {@inheritDoc} + *

            + * Listener for "PeerView"/<peergroup-unique-id> and propagate pipes. + */ + public void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + // check what kind of message this is (response or not). + boolean isResponse = false; + MessageElement me = msg.getMessageElement(MESSAGE_NAMESPACE, MESSAGE_ELEMENT_NAME); + + if (me == null) { + me = msg.getMessageElement(MESSAGE_NAMESPACE, RESPONSE_ELEMENT_NAME); + if (me == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Discarding damaged " + msg + "."); + } + return; + } else { + isResponse = true; + } + } + + Advertisement adv; + + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(me); + + adv = AdvertisementFactory.newAdvertisement(asDoc); + } catch (RuntimeException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building rdv advertisement from message element", failed); + } + return; + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building rdv advertisement from message element", failed); + } + return; + } + + if (!(adv instanceof RdvAdvertisement)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Response does not contain radv (" + adv.getAdvertisementType() + ")"); + } + return; + } + + RdvAdvertisement radv = (RdvAdvertisement) adv; + + if (null == radv.getRouteAdv()) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Rdv Advertisement does not contain route."); + } + return; + } + + // See if we can find a src route adv in the message. + me = msg.getMessageElement(MESSAGE_NAMESPACE, SRCROUTEADV_ELEMENT_NAME); + if (me != null) { + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(me); + Advertisement routeAdv = AdvertisementFactory.newAdvertisement(asDoc); + + if (!(routeAdv instanceof RouteAdvertisement)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Advertisement is not a RouteAdvertisement"); + } + } else { + RouteAdvertisement rdvRouteAdv = radv.getRouteAdv().clone(); + + // XXX we stich them together even if in the end it gets optimized away + RouteAdvertisement.stichRoute(rdvRouteAdv, (RouteAdvertisement) routeAdv); + radv.setRouteAdv(rdvRouteAdv); + } + } catch (RuntimeException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building route adv from message element", failed); + } + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building route adv from message element", failed); + } + } + } + me = null; + + // Is this a message about ourself? + if (group.getPeerID().equals(radv.getPeerID())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received a PeerView message about self. Discard."); + } + + return; + } + + // Collect the various flags. + + boolean isFailure = (msg.getMessageElement(MESSAGE_NAMESPACE, FAILURE_ELEMENT_NAME) != null); + boolean isCached = (msg.getMessageElement(MESSAGE_NAMESPACE, CACHED_RADV_ELEMENT_NAME) != null); + boolean isFromEdge = (msg.getMessageElement(MESSAGE_NAMESPACE, EDGE_ELEMENT_NAME) != null); + boolean isTrusted = isFromEdge || seedingManager.isAcceptablePeer(radv.getRouteAdv()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + String srcPeer = srcAddr.toString(); + + if ("jxta".equals(srcAddr.getProtocolName())) { + try { + String idstr = ID.URIEncodingName + ":" + ID.URNNamespace + ":" + srcAddr.getProtocolAddress(); + + ID asID = IDFactory.fromURI(new URI(idstr)); + + PeerViewElement pve = getPeerViewElement(asID); + + if (null != pve) { + srcPeer = "\"" + pve.getRdvAdvertisement().getName() + "\""; + } + } catch (URISyntaxException failed) {// ignored + } + } + + LOG.fine( + "[" + group.getPeerGroupID() + "] Received a" + (isCached ? " cached" : "") + (isResponse ? " response" : "") + + (isFailure ? " failure" : "") + " message (" + msg.toString() + ")" + (isFromEdge ? " from edge" : "") + + " regarding \"" + radv.getName() + "\" from " + srcPeer); + } + + if (!isTrusted) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Rejecting peerview message from " + radv.getPeerID()); + } + return; + } + + // if this is a notification failure. All we have to do is locally + // process the failure + if (isFailure) { + notifyFailure(radv.getPeerID(), false); + return; + } + + handlePeerViewMessage(isResponse, isCached, isFromEdge, isTrusted, radv); + } + + /** + * Following the extraction of a peerview message from a + */ + private void handlePeerViewMessage(boolean isResponse, boolean isCached, boolean isFromEdge, boolean isTrusted, RdvAdvertisement radv) { + + // Figure out if we know that peer already. If we do, reuse the pve + // that we have. + boolean isNewbie = false; + boolean added = false; + PeerViewElement pve; + + synchronized (localView) { + PeerViewElement newbie = new PeerViewElement(endpoint, radv); + + pve = getPeerViewElement(newbie); + + if (null == pve) { + pve = newbie; + isNewbie = true; + } + + if (!isFromEdge && !isCached && isTrusted) { + if (isNewbie) { + added = addPeerViewElement(pve); + } else { + pve.setRdvAdvertisement(radv); + } + } + } + + if (!isNewbie && isFromEdge && !isCached) { + // The message stated that it is from an edge we believed was a + // peerview member. Best thing to do is tell everyone that it's no + // longer in peerview. + notifyFailure(pve, true); + // we continue processing because it's not the other peer's fault we had the wrong idea. + } + + // Do the rest of the add related tasks out of synch. + // We must not nest any possibly synchronized ops in + // the LocalView lock; it's the lowest level. + + if (added) { + // Notify local listeners + generateEvent(PeerViewEvent.ADD, pve); + } + + /* + * Now, see what if any message we have to send as a result. + * There are three kinds of messages we can send: + * + * - A response with ourselves, if we're being probed and we're + * a rdv. + * + * - A probe to the peer whose adv we received, because we want + * confirmation that it's alive. + * + * - A response with a random adv from our cache if we're being probed + * + * We may send more than one message. + */ + + boolean status; + + if (!isCached) { + if (!isResponse) { + // Type 1: Respond to probe + // + // We are being probed by an edge peer or peerview member. We respond + // with our own advertisement. + status = send(pve, self, true, false); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Type 1 (Respond with self PVE) : Sent to " + pve + " result =" + status); + } + + // Type 3: Respond with random entry from our PV when we are probed. + // + // Respond with a strategized adv from our view. + PeerViewElement sendpve = replyStrategy.next(); + + if ((sendpve != null) && !pve.equals(sendpve) && !self.equals(sendpve)) { + status = send(pve, sendpve, true, false); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Type 3 (Respond with random PVE) : Sent " + sendpve + " to " + pve + " result=" + status); + } + } + } else { + // Heartbeat: do nothing. + } + } else if (isResponse) { + if (isNewbie && !useOnlySeeds && !isFromEdge) { + // Type 2: Probe a peer we have just learned about from a referral. + // + // If useOnlySeeds, we're not allowed to talk to peers other than our + // seeds, so do not probe anything we learn from 3rd party. (Probing of + // seeds happens as part of the "kick" strategy). + status = send(pve, self, false, false); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Type 2 (Probe PVE) : Probed " + pve + " result=" + status); + } + } else { + // Already known or ignoring: do nothing. + } + } else { + // Invalid : do nothing. + } + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("fallsthrough") + public void rendezvousEvent(RendezvousEvent event) { + + if (closed) { + return; + } + + boolean notifyFailure = false; + + synchronized (this) { + + int theEventType = event.getType(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("[" + group.getPeerGroupName() + "] Processing " + event); + } + + refreshSelf(); + + if ((RendezvousEvent.BECAMERDV == theEventType) || (RendezvousEvent.BECAMEEDGE == theEventType)) { + // kill any existing watchdog task + if (null != watchdogTask) { + removeTask(watchdogTask); + watchdogTask.cancel(); + watchdogTask = null; + } + } + + switch (theEventType) { + case RendezvousEvent.RDVCONNECT: + case RendezvousEvent.RDVRECONNECT: + case RendezvousEvent.CLIENTCONNECT: + case RendezvousEvent.CLIENTRECONNECT: + case RendezvousEvent.RDVFAILED: + case RendezvousEvent.RDVDISCONNECT: + case RendezvousEvent.CLIENTFAILED: + case RendezvousEvent.CLIENTDISCONNECT: + break; + + case RendezvousEvent.BECAMERDV: + openWirePipes(); + watchdogTask = new WatchdogTask(); + addTask(watchdogTask, WATCHDOG_PERIOD, WATCHDOG_PERIOD); + rescheduleKick(true); + break; + + case RendezvousEvent.BECAMEEDGE: + openWirePipes(); + if (!localView.isEmpty()) { + // FIXME bondolo 20040229 since we likely don't have a + // rendezvous connection, it is kind of silly to be sending + // this now. probably should wait until we get a rendezvous + // connection. + notifyFailure = true; + } + rescheduleKick(true); + break; + + default: + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("[" + group.getPeerGroupName() + "] Unexpected RDV event : " + event); + } + break; + } + } + + // we can't do the notification under synchronization. + if (notifyFailure) { + notifyFailure(self, true); + } + } + + public void start() {// do nothing for now... all the good stuff happens as a result of + // rendezvous events. + } + + public void stop() { + + synchronized (this) { + // Only one thread gets to perform the shutdown. + if (closed) { + return; + } + closed = true; + } + + // notify other rendezvous peers that we are going down + notifyFailure(self, true); + + // From now on we can nullify everything we want. Other threads check + // the closed flag where it matters. + synchronized (this) { + if (watchdogTask != null) { + removeTask(watchdogTask); + watchdogTask.cancel(); + watchdogTask = null; + } + + // Remove message listener. + endpoint.removeIncomingMessageListener(SERVICE_NAME, uniqueGroupId); + + // Remove rendezvous listener. + rdvService.removeListener(this); + + // Remove all our pending scheduled tasks + // Carefull with the indices while removing: do it backwards, it's + // cheaper and simpler. + + synchronized (scheduledTasks) { + Iterator eachTask = scheduledTasks.iterator(); + + while (eachTask.hasNext()) { + try { + TimerTask task = eachTask.next(); + + task.cancel(); + eachTask.remove(); + } catch (Exception ez1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Cannot cancel task: ", ez1); + } + } + } + } + + // Make sure that we close our WirePipes + closeWirePipes(); + + // Let go of the up and down peers. + downPeer = null; + upPeer = null; + localView.clear(); + + timer.cancel(); + + rpvListeners.clear(); + } + } + + protected void addTask(TimerTask task, long delay, long interval) { + + synchronized (scheduledTasks) { + if (scheduledTasks.contains(task)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Task list already contains specified task."); + } + } + scheduledTasks.add(task); + } + + if (interval >= 1) { + timer.schedule(task, delay, interval); + } else { + timer.schedule(task, delay); + } + } + + protected void removeTask(TimerTask task) { + scheduledTasks.remove(task); + } + + /** + * Adds the specified URI to the list of seeds. Even if useOnlySeeds is in + * effect, this seed may now be used, as if it was part of the initial + * configuration. + * + * @param seed the URI of the seed rendezvous. + */ + public void addSeed(URI seed) { + if (seedingManager instanceof URISeedingManager) { + ((URISeedingManager) seedingManager).addSeed(seed); + } + } + + /** + * Probe the specified peer immediately. + *

            + * Note: If "useOnlySeeds" is in effect and the peer is not a seed, any response to this probe will be ignored. + */ + public boolean probeAddress(EndpointAddress address, RouteAdvertisement hint) { + + PeerViewElement holdIt; + + synchronized (localView) { + holdIt = self; + } + + return send(address, hint, holdIt, false, false); + } + + /** + * Send our own advertisement to all of the seed rendezvous. + */ + public void seed() { + long reseedRemaining = earliestReseed - TimeUtils.timeNow(); + + if (reseedRemaining > 0) { + // Too early; the previous round is not even done. + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Still Seeding for " + reseedRemaining + "ms."); + } + return; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("New Seeding..."); + } + + // Schedule sending propagated query to our local network neighbors. + send(null, null, self, false, false); + + long iterations = 0; + + if (localView.size() < minHappyPeerView) { + // We only do these things if we don't have a "happy" Peer View. + // If the Peer View is already "happy" then we will use only + // Peer View referrals for learning of new entires. + + List seedRdvs = new ArrayList( + Arrays.asList(seedingManager.getActiveSeedRoutes())); + + while (!seedRdvs.isEmpty()) { + RouteAdvertisement aSeed = seedRdvs.remove(0); + + if (null == aSeed.getDestPeerID()) { + // It is an incomplete route advertisement. We are going to assume that it is only a wrapper for a single ea. + Vector seed_eas = aSeed.getDest().getVectorEndpointAddresses(); + + if (!seed_eas.isEmpty()) { + EndpointAddress aSeedHost = new EndpointAddress(seed_eas.get(0)); + + // XXX 20061220 bondolo We could check all of our current PVEs to make sure that this address is not already known. + + send(aSeedHost, null, self, false, false); + } + } else { + // We have a full route, send it to the virtual address of the route! + // FIXME malveaux 20070816 Second part of conjunct can be removed once 'self' is included in the peerview + if ((null == getPeerViewElement(aSeed.getDestPeerID())) && !group.getPeerID().equals(aSeed.getDestPeerID())) { + EndpointAddress aSeedHost = new EndpointAddress("jxta", aSeed.getDestPeerID().getUniqueValue().toString(), + null, null); + + send(aSeedHost, aSeed, self, false, false); + } + } + } + + if (!useOnlySeeds) { + // If use only seeds, we're not allowed to put in the peerview + // anything but our seed rdvs. So, we've done everything that + // was required. + + // Schedule sending propagated query to our advertising group + if (advertisingGroup != null) { + // send it, but not immediately. + scheduleAdvertisingGroupQuery(DEFAULT_SEEDING_PERIOD * 2); + } + } + } + + earliestReseed = TimeUtils.toAbsoluteTimeMillis(seedingRdvConnDelay + (DEFAULT_SEEDING_PERIOD * iterations)); + } + + /** + * Make sure that the PeerView properly changes behavior, when switching + * from edge mode to rdv mode, and vice-versa. + * Since openWirePipes() requires some other services such as the Pipe + * Service, and since updateStatus is invoked this work must happen in + * background, giving a chance to other services to be started. + */ + private class OpenPipesTask extends TimerTask { + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + if (closed) { + return; + } + + openWirePipes(); + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread: " + Thread.currentThread().getName(), all); + } + } finally { + removeTask(this); + } + } + } + + private void scheduleOpenPipes(long delay) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Scheduling open pipes attempt in " + delay + "ms."); + } + + addTask(new OpenPipesTask(), delay, -1); + } + + /** + * Send a PeerView Message to the specified peer. + * + * @param response indicates whether this is a response. Otherwise + * we may create a distributed loop where peers keep perpetually + * responding to each-other. + * @param failure Construct the message as a failure notification. + */ + private boolean send(PeerViewElement dest, PeerViewElement pve, boolean response, boolean failure) { + + Message msg = makeMessage(pve, response, failure); + + boolean result = dest.sendMessage(msg, SERVICE_NAME, uniqueGroupId); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " to " + dest + " success = " + result); + } + + return result; + } + + /** + * Send a PeerView Message to the specified peer. + * + * @param response indicates whether this is a response. Otherwise + * we may create a distributed loop where peers keep perpetually + * responding to each-other. + * @param failure Construct the message as a failure notification. + */ + private boolean send(EndpointAddress dest, RouteAdvertisement hint, PeerViewElement pve, boolean response, boolean failure) { + + Message msg = makeMessage(pve, response, failure); + + if (null != dest) { + EndpointAddress realAddr = new EndpointAddress(dest, SERVICE_NAME, uniqueGroupId); + + Messenger messenger = rdvService.endpoint.getMessengerImmediate(realAddr, hint); + + if (null != messenger) { + try { + boolean result = messenger.sendMessage(msg); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " to " + dest + " success = " + result); + } + + return result; + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not send " + msg + " to " + dest, failed); + } + return false; + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not get messenger for " + dest); + } + + return false; + } + } else { + // Else, propagate the message. + try { + endpoint.propagate(msg, SERVICE_NAME, uniqueGroupId); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sent " + msg + " via propagate"); + } + return true; + } catch (IOException ez) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + // Pretty strange. This has little basis for failure... + LOG.log(Level.WARNING, "Could not propagate " + msg, ez); + } + return false; + } + } + } + + /** + * Send a PeerView Message to the specified peer. + * + * @param response indicates whether this is a response. Otherwise + * we may create a distributed loop where peers keep perpetually + * responding to each-other. + * @param failure Construct the message as a failure notification. + * @param dest destination output pipe + * @param pve the peer view element + * @return true if successful + */ + private boolean send(OutputPipe dest, PeerViewElement pve, boolean response, boolean failure) { + + Message msg = makeMessage(pve, response, failure); + + try { + return dest.send(msg); + } catch (IOException ez) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not send " + msg, ez); + } + return false; + } + } + + /** + * Make a PeerView Message + * + * @param content the peer view element + * @param response the response + * @param failure whether to create a message based on a failure + * @return the message + */ + private Message makeMessage(PeerViewElement content, boolean response, boolean failure) { + + Message msg = new Message(); + + // // edge peers add an identifying element, RDV peers do not + // if (!rdvService.isRendezVous()) { + // msg.addMessageElement(MESSAGE_NAMESPACE, EDGE_ELEMENT); + // } + // + if (failure) { + // This is a failure notification. + msg.addMessageElement(MESSAGE_NAMESPACE, FAILURE_ELEMENT); + } + + refreshSelf(); + + RdvAdvertisement radv = content.getRdvAdvertisement(); + + XMLDocument doc = (XMLDocument) radv.getDocument(MimeMediaType.XMLUTF8); + String msgName = response ? RESPONSE_ELEMENT_NAME : MESSAGE_ELEMENT_NAME; + + MessageElement msge = new TextDocumentMessageElement(msgName, doc, null); + + msg.addMessageElement(MESSAGE_NAMESPACE, msge); + + if (!content.equals(self)) { + // This is a cached RdvAdvertisement + msg.addMessageElement(MESSAGE_NAMESPACE, CACHED_RADV_ELEMENT); + + // This message contains an RdvAdvertisement which is not ourself. In that + // case, it is wise to also send the local route advertisement (as the optional + // SrcRdvAdv) so the destination might have a better change to access the "content" + // RendezvousAdv (this peer will then act as a hop). + + RouteAdvertisement localra = EndpointUtils.extractRouteAdv(lastPeerAdv); + + if (localra != null) { + try { + XMLDocument radoc = (XMLDocument) localra.getDocument(MimeMediaType.XMLUTF8); + + msge = new TextDocumentMessageElement(SRCROUTEADV_ELEMENT_NAME, radoc, null); + msg.addMessageElement(MESSAGE_NAMESPACE, msge); + } catch (Exception ez1) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not create optional src route adv for " + content, ez1); + } + } + } + } + + return msg; + } + + /** + * Invoked by anyone in order to inform the PeerView of a failure + * of one of the member peers. + * + * @param pid ID of the peer which failed. + * @param propagateFailure If truethen broadcast the failure to + * other peers otherwise only update the local peerview. + */ + public void notifyFailure(PeerID pid, boolean propagateFailure) { + + PeerViewElement pve = getPeerViewElement(pid); + + if (null != pve) { + notifyFailure(pve, propagateFailure); + } + } + + /** + * Invoked when a peerview member peer becomes unreachable. + * + * @param pve The peer which failed. + * @param propagateFailure If {@code true} then broadcast the failure to + * other peers otherwise only update the local peerview. + */ + void notifyFailure(PeerViewElement pve, boolean propagateFailure) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Notifying failure of " + pve); + } + + try { + boolean removedFromPeerView = removePeerViewElement(pve); + + // only propagate if we actually knew of the peer + propagateFailure &= (removedFromPeerView || (self == pve)); + + // Notify local listeners + if (removedFromPeerView) { + generateEvent(PeerViewEvent.FAIL, pve); + } + + boolean emptyPeerView = localView.isEmpty(); + + // If the local view has become empty, reset the kicker into + // a seeding mode. + if (emptyPeerView && removedFromPeerView) { + rescheduleKick(true); + } + + if (propagateFailure) { + // Notify other rendezvous peers that there has been a failure. + OutputPipe op = localGroupWirePipeOutputPipe; + + if (null != op) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Propagating failure of " + pve); + } + + send(op, pve, true, true); + } + } + } catch (Exception ez) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure while generating noficiation of failure of PeerView : " + pve, ez); + } + } + } + + /** + * Invoked by the Timer thread to cause each PeerView to initiate + * a Peer Advertisement exchange. + */ + private void kick() { + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Begun kick() in " + group.getPeerGroupID()); + } + + // Use seed strategy. (it has its own throttling and resource limiting). + seed(); + + // refresh ourself to a peer in our view + PeerViewElement refreshee = refreshRecipientStrategy.next(); + + if ((refreshee != null) && (self != refreshee)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Refresh " + refreshee); + } + send(refreshee, self, false, false); + } + + // now share an adv from our local view to another peer from our + // local view. + + PeerViewElement recipient = kickRecipientStrategy.next(); + + if (recipient == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No recipient to send adv "); + } + return; + } + + PeerViewElement rpve = kickAdvertisementStrategy.next(); + + if (rpve == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No adv to send"); + } + return; + } + + if (rpve.equals(recipient) || self.equals(recipient)) { + // give up: no point in sending a peer its own adv + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("adv to send is same as recipient: Nothing to do."); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending adv " + rpve + " to " + recipient); + } + + send(recipient, rpve, true, false); + } finally { + rescheduleKick(false); + } + } + + /** + * Choose a boot level appropriate for the current configuration and state. + * + * @return the new boot level. + */ + private int adjustBootLevel() { + + boolean areWeHappy = localView.size() >= minHappyPeerView; + + // increment boot level faster if we have a reasonable peerview. + int increment = areWeHappy ? BOOTLEVEL_INCREMENT : BOOTLEVEL_INCREMENT * 2; + + // if we don't have a reasonable peerview, we continue to try harder. + int maxbootlevel = MAX_BOOTLEVEL - (areWeHappy ? 0 : BOOTLEVEL_INCREMENT); + + bootLevel = Math.min(maxbootlevel, bootLevel + increment); + + return bootLevel; + } + + private synchronized void rescheduleKick(boolean now) { + + if (closed) { + return; + } + + // Set the next iteration + try { + if (now) { + bootLevel = MIN_BOOTLEVEL; + } else { + adjustBootLevel(); + } + + long tilNextKick = DEFAULT_BOOTSTRAP_KICK_INTERVAL * ((1L << bootLevel) - 1); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Scheduling kick in " + (tilNextKick / TimeUtils.ASECOND) + " seconds at bootLevel " + bootLevel + + " in group " + group.getPeerGroupID()); + } + + KickerTask task = new KickerTask(); + + addTask(task, tilNextKick, -1); + } catch (Exception ez1) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Cannot set timer. RPV will not work.", ez1); + } + } + } + + /** + * Refresh the local copy of the peer advertisement and the rendezvous + * advertisement. + */ + private void refreshSelf() { + + RdvAdvertisement radv; + + synchronized (this) { + PeerAdvertisement newPadv = group.getPeerAdvertisement(); + int newModCount = newPadv.getModCount(); + + if ((lastPeerAdv != newPadv) || (lastModCount != newModCount)) { + lastPeerAdv = newPadv; + lastModCount = newModCount; + + // create a new local RdvAdvertisement and set it to self. + radv = createRdvAdvertisement(lastPeerAdv, name); + + if (radv != null) { + self.setRdvAdvertisement(radv); + } + } + } + } + + static RdvAdvertisement createRdvAdvertisement(PeerAdvertisement padv, String serviceName) { + + try { + // FIX ME: 10/19/2002 lomax@jxta.org. We need to properly set up the service ID. Unfortunately + // this current implementation of the PeerView takes a String as a service name and not its ID. + // Since currently, there is only PeerView per group (all peerviews share the same "service", this + // is not a problem, but that will have to be fixed eventually. + + // create a new RdvAdvertisement + RdvAdvertisement rdv = (RdvAdvertisement) AdvertisementFactory.newAdvertisement( + RdvAdvertisement.getAdvertisementType()); + + rdv.setPeerID(padv.getPeerID()); + rdv.setGroupID(padv.getPeerGroupID()); + rdv.setServiceName(serviceName); + rdv.setName(padv.getName()); + + RouteAdvertisement ra = EndpointUtils.extractRouteAdv(padv); + + // Insert it into the RdvAdvertisement. + rdv.setRouteAdv(ra); + + return rdv; + } catch (Exception ez) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Cannot create Local RdvAdvertisement: ", ez); + } + return null; + } + } + + /** + * Add a listener for PeerViewEvent + * + * @param listener An PeerViewListener to process the event. + * @return true if successful + */ + public boolean addListener(PeerViewListener listener) { + boolean added = rpvListeners.add(listener); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Registered PeerViewEvent Listener (" + listener.getClass().getName() + ")"); + } + + return added; + } + + /** + * Removes a PeerViewEvent Listener previously added with addListener. + * + * @param listener the PeerViewListener listener remove + * @return whether successful or not + */ + public boolean removeListener(PeerViewListener listener) { + boolean removed = rpvListeners.remove(listener); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Removed PeerViewEvent Listener (" + listener.getClass().getName() + ")"); + } + + return removed; + } + + /** + * Generate a PeerView Event and notify all listeners. + * + * @param type the Event Type. + * @param element The peer having the event. + */ + private void generateEvent(int type, PeerViewElement element) { + + PeerViewEvent newevent = new PeerViewEvent(this, type, element); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Calling listeners for " + newevent + " in group " + group.getPeerGroupID()); + } + + for (Object o : Arrays.asList(rpvListeners.toArray())) { + PeerViewListener pvl = (PeerViewListener) o; + + try { + pvl.peerViewEvent(newevent); + } catch (Throwable ignored) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in PeerViewEvent listener : (" + pvl.getClass().getName() + ")" + , + ignored); + } + } + } + } + + static PipeAdvertisement makeWirePipeAdvertisement(PeerGroup destGroup, PeerGroup group, String name) { + + PipeAdvertisement adv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + + // Create a pipe advertisement for this group. + // Generate a well known but unique ID. + // FIXME bondolo 20040507 The ID created is really poor, it has only + // 2 unique bytes on average. it would be much better to hash something + // also, since the the definition of how to use the seed bytes is not + // fixed, it's not reliable. + PipeID pipeId = IDFactory.newPipeID(destGroup.getPeerGroupID() + , + (SERVICE_NAME + group.getPeerGroupID().getUniqueValue().toString() + name).getBytes()); + + adv.setPipeID(pipeId); + adv.setType(PipeService.PropagateType); + adv.setName(SERVICE_NAME + " pipe for " + group.getPeerGroupID()); + + return adv; + } + + private synchronized void openWirePipes() { + + PipeService pipes = group.getPipeService(); + + if (null == pipes) { + scheduleOpenPipes(TimeUtils.ASECOND); // Try again in one second. + return; + } + + try { + // First, listen to in our own PeerGroup + if (null == localGroupWirePipeInputPipe) { + localGroupWirePipeInputPipe = pipes.createInputPipe(localGroupWirePipeAdv, new WirePipeListener()); + } + + if (null == localGroupWirePipeOutputPipe) { + // Creates the OutputPipe - note that timeout is irrelevant for + // propagated pipe. + + localGroupWirePipeOutputPipe = pipes.createOutputPipe(localGroupWirePipeAdv, 1 * TimeUtils.ASECOND); + } + + if (localGroupWirePipeOutputPipe == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Cannot get OutputPipe for current group"); + } + } + } catch (Exception failed) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("PipeService not ready yet. Trying again in 1 second."); + } + // Try again in one second. + scheduleOpenPipes(TimeUtils.ASECOND); + return; + } + + if (advertisingGroup != null) { + try { + pipes = advertisingGroup.getPipeService(); + + if (null == pipes) { + // Try again in one second. + scheduleOpenPipes(TimeUtils.ASECOND); + return; + } + + if (null == wirePipeInputPipe) { + wirePipeInputPipe = pipes.createInputPipe(advGroupPropPipeAdv, new WirePipeListener()); + } + + if (null == wirePipeOutputPipe) { + wirePipeOutputPipe = pipes.createOutputPipe(advGroupPropPipeAdv, 1 * TimeUtils.ASECOND); + } + + if (wirePipeOutputPipe == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Cannot get OutputPipe for current group"); + } + } + } catch (Exception failed) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Could not open pipes in local group. Trying again in 1 second."); + } + // Try again in one second. + scheduleOpenPipes(TimeUtils.ASECOND); + return; + } + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Propagate Pipes opened."); + } + } + + private synchronized void closeWirePipes() { + + if (localGroupWirePipeInputPipe != null) { + localGroupWirePipeInputPipe.close(); + localGroupWirePipeInputPipe = null; + } + + if (localGroupWirePipeOutputPipe != null) { + localGroupWirePipeOutputPipe.close(); + localGroupWirePipeOutputPipe = null; + } + + if (wirePipeInputPipe != null) { + wirePipeInputPipe.close(); + wirePipeInputPipe = null; + } + + if (wirePipeOutputPipe != null) { + wirePipeOutputPipe.close(); + wirePipeOutputPipe = null; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Propagate Pipes closed."); + } + } + + /** + * Adapter class for receiving wire pipe messages + */ + private class WirePipeListener implements PipeMsgListener { + + /** + * {@inheritDoc} + */ + public void pipeMsgEvent(PipeMsgEvent event) { + + Message msg = event.getMessage(); + + boolean failure = (null != msg.getMessageElement(MESSAGE_NAMESPACE, FAILURE_ELEMENT_NAME)); + boolean response = (null != msg.getMessageElement(MESSAGE_NAMESPACE, RESPONSE_ELEMENT_NAME)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "Received a PeerView " + (failure ? "failure " : "") + (response ? "response " : "") + "message [" + msg + + "] on propagated pipe " + event.getPipeID()); + } + + if (!failure && !response) { + + // If this is not a failure message then decide if we will respond. + // + // We play a game that is tuned by the view size so that the expectation of number of responses is equal to + // minHappyPeerView. The game is to draw a number between 0 and the pv size. If the result is < minHappyPeerView, + // then we win (respond) else we lose (stay silent). The probability of winning is HAPPY_SIZE/viewsize. If each of + // the viewsize peers plays the same game, on average HAPPY_SIZE of them win (with a significant variance, but + // that is good enough). If viewsize is <= HAPPY_SIZE, then all respond. This is approximate, of course, since + // the view size is not always consistent among peers. + + int viewsize = PeerView.this.localView.size(); + + if (viewsize > minHappyPeerView) { + int randinview = random.nextInt(viewsize); + + if (randinview >= minHappyPeerView) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Ignoring " + msg + " from pipe " + event.getPipeID()); + } + // We "lose". + return; + } + } // Else, we always win; don't bother playing. + } + + // Fabricate dummy src and dst addrs so that we can call processIncoming. These are + // only used for traces. The merit of using the pipeID is that it is recognizable + // in these traces. + EndpointAddress src = new EndpointAddress(event.getPipeID(), SERVICE_NAME, null); + EndpointAddress dest = new EndpointAddress(event.getPipeID(), SERVICE_NAME, null); + + try { + // call the peerview. + PeerView.this.processIncomingMessage(msg, src, dest); + } catch (Throwable ez) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed processing " + msg + " from pipe " + event.getPipeID(), ez); + } + } + } + } + + private synchronized void scheduleAdvertisingGroupQuery(long delay) { + + if (closed) { + return; + } + + TimerTask task = new AdvertisingGroupQueryTask(); + + addTask(task, delay, -1); + } + + /** + * Class implementing the query request on the AdvertisingGroup + */ + private final class AdvertisingGroupQueryTask extends TimerTask { + + /** + * {@inheritDoc} + */ + @Override + public boolean cancel() { + boolean res = super.cancel(); + return res; + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + if (closed) { + return; + } + + OutputPipe op = wirePipeOutputPipe; + + if (null != op) { + Message msg = makeMessage(self, false, false); + + op.send(msg); + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } finally { + removeTask(this); + } + } + } + + /** + * Get a copy of the PeerView for this group. + * + * @return A SortedSet which is the current local view of the peerview + */ + public SortedSet getView() { + synchronized (localView) { + return new TreeSet((SortedSet)localView); + } + } + + /** + * Add the provided element to the local peerview. + * + * @param pve the PeerViewElement to add. + * @return true if the element was not present and added + * otherwise false. + */ + private boolean addPeerViewElement(PeerViewElement pve) { + boolean added; + + if (null == pve.getRdvAdvertisement()) { + throw new IllegalStateException("Cannot add a seed pve to local view"); + } + + synchronized (localView) { + added = localView.add(pve); + + if (added) { + // Refresh, if necessary, our up and down peers. + updateUpAndDownPeers(); + } + } + + if (added) { + pve.setPeerView(this); + } + + return added; + } + + /** + * Remove the provided element from the local peerview. + * + * @param pve the PeerViewElement to remove. + * @return true if the element was present and removed + * otherwise false. + */ + private boolean removePeerViewElement(PeerViewElement pve) { + boolean removed; + + synchronized (localView) { + removed = localView.remove(pve); + + if (removed) { + // Refresh, if necessary, our up and down peers. + updateUpAndDownPeers(); + } + } + + if (removed) { + pve.setPeerView(null); + } + + return removed; + } + + /** + * Return from the local view, the PeerViewElement that is equal to the + * given PeerViewDestination, if one exists or null if it is + * not present. Identity is defined by {@link PeerViewDestination#equals} + * which only looks at the destination address. Thus a PeerViewDestination + * is enough. A full PeerViewElement may be passed as well. This method + * does not require external synchronization. + * + * @param wanted PeerViewDestination matching the desired one. + * @return the matching PeerViewElement or null if it could not + * be found. + */ + public PeerViewElement getPeerViewElement(PeerViewDestination wanted) { + + try { + PeerViewElement found = (PeerViewElement) localView.tailSet(wanted).first(); + + if (wanted.equals(found)) { + return found; + } + } catch (NoSuchElementException nse) {// This can happen if the tailset is empty. We could test for it, + // but it could still become empty after the test, since it reflects + // concurrent changes to localView. Not worth synchronizing for that + // rare occurence. The end-result is still correct. + } + + return null; + } + + /** + * Get from the local view, the PeerViewElement for the given PeerID, if one + * exists. Null otherwise. This method does not require external + * synchronization. + * + * @param pid the PeerID of the desired element. + * @return the matching PeerViewElement null if it could not be found. + */ + public PeerViewElement getPeerViewElement(ID pid) { + + return getPeerViewElement(new PeerViewDestination(pid)); + } + + /** + * Get the down peer from the local peer. + * + * @return the down PeerViewElement or null if there is no such peer. + */ + public PeerViewElement getDownPeer() { + return downPeer; + } + + /** + * Get the local peer. + * + * @return the local PeerViewElement + */ + public PeerViewElement getSelf() { + return self; + } + + /** + * Get the up peer from the local peer. + * + * @return the up PeerViewElement or null if there is no such peer. + */ + public PeerViewElement getUpPeer() { + return upPeer; + } + + /** + * update Up and Down Peers + */ + private void updateUpAndDownPeers() { + + synchronized (localView) { + final PeerViewElement oldDown = downPeer; + final PeerViewElement oldUp = upPeer; + + SortedSet headSet = localView.headSet(self); + + if (!headSet.isEmpty()) { + downPeer = (PeerViewElement) headSet.last(); + } else { + downPeer = null; + } + + SortedSet tailSet = localView.tailSet(self); + + if (!tailSet.isEmpty()) { + if (self.equals(tailSet.first())) { + Iterator eachTail = tailSet.iterator(); + + eachTail.next(); // self + + if (eachTail.hasNext()) { + upPeer = (PeerViewElement) eachTail.next(); + } else { + upPeer = null; + } + } else { + upPeer = (PeerViewElement) tailSet.first(); + } + } else { + upPeer = null; + } + + if ((oldDown != downPeer) && (downPeer != null)) { + downPeer.setLastUpdateTime(TimeUtils.timeNow()); + } + + if ((oldUp != upPeer) && (upPeer != null)) { + upPeer.setLastUpdateTime(TimeUtils.timeNow()); + } + } + } + + /** + * A task that checks on upPeer and downPeer. + */ + private final class WatchdogTask extends TimerTask { + + /** + * The number of iterations that the watchdog task has executed. + */ + int iterations = 0; + + WatchdogTask() {} + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + if (closed) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Watchdog task executing for group " + PeerView.this.group.getPeerGroupID()); + } + + refreshSelf(); + + if(0 == (iterations % 5)) { + DiscoveryService discovery = group.getDiscoveryService(); + if(null != discovery) { + discovery.publish(self.getRdvAdvertisement(), WATCHDOG_PERIOD * 10, WATCHDOG_PERIOD * 5); + } + } + + PeerViewElement up = PeerView.this.getUpPeer(); + + if (up != null) { + if (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), up.getLastUpdateTime()) > WATCHDOG_GRACE_DELAY) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("UP peer has gone MIA : " + up); + } + + notifyFailure(up, true); + + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Checking on UP peer : " + up); + } + + PeerView.this.send(up, PeerView.this.getSelf(), false, false); + } + } + + PeerViewElement down = PeerView.this.getDownPeer(); + + if (down != null) { + if (TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), down.getLastUpdateTime()) > WATCHDOG_GRACE_DELAY) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("DOWN peer has gone MIA : " + down); + } + + notifyFailure(down, true); + + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Checking on DOWN peer : " + down); + } + + PeerView.this.send(down, PeerView.this.getSelf(), false, false); + } + } + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } + + iterations++; + } + } + + + /** + * Class implementing the kicker + */ + private final class KickerTask extends TimerTask { + + /** + * {@inheritDoc} + */ + @Override + public void run() { + try { + if (closed) { + return; + } + + PeerView.this.kick(); + } catch (Throwable all) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread : " + Thread.currentThread().getName(), all); + } + } finally { + removeTask(this); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewDestination.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewDestination.java new file mode 100644 index 000000000..27a259462 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewDestination.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2002-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.id.ID; + +/** + * This class contains only the comparable portion of PeerViewElement, so that it is possible + * to search for elements in the sorted set that the local PeerView is, without having + * enough information to create a valid PeerViewElement. + */ +class PeerViewDestination implements Comparable { + + /** + * The peer which is associated with this element. + */ + private final ID peerid; + + /** + * Constructs a PeerViewDestination from a (peer)ID. + */ + PeerViewDestination(ID destination) { + peerid = destination; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + return this == other || other instanceof PeerViewDestination && 0 == compareTo((PeerViewDestination) other); + + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return peerid.hashCode(); + } + + /** + * {@inheritDoc} + *

            + * Note that this compares the unique value of the id. + */ + public int compareTo(PeerViewDestination pve) { + String myUniqueValue = peerid.getUniqueValue().toString(); + String itsUniqueValue = pve.peerid.getUniqueValue().toString(); + + return myUniqueValue.compareTo(itsUniqueValue); + } + + /** + * Get the peer id of the peer associated with this connection. + * + * @return The peer id of the connected peer. + */ + public ID getPeerID() { + return peerid; + } + + /** + * returns the destination address. + * + * @return The endpoint address of the connected peer. + */ + public EndpointAddress getDestAddress() { + return new EndpointAddress(peerid, null, null); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewElement.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewElement.java new file mode 100644 index 000000000..fab64a4db --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewElement.java @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2002-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.io.IOException; + +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.OutgoingMessageEvent; +import net.jxta.endpoint.OutgoingMessageEventListener; +import net.jxta.impl.util.TimeUtils; +import net.jxta.protocol.RdvAdvertisement; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +/** + * An element of the PeerView. + * + *

            The destination address (peerID) is part of PeerViewDestination, which implements the + * comparable interface. That makes it possible to sort and create ordered lists of + * PeerViewElements, and to search these lists while knowing only a destination address. + */ +public final class PeerViewElement extends PeerViewDestination implements OutgoingMessageEventListener { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(PeerViewElement.class.getName()); + + /** + * EndpointService that this PeerViewElement must use. + */ + private final EndpointService endpoint; + + /** + * Absolute time in milliseconds at which this element was created. + */ + private final long created; + + /** + * Absolute time in milliseconds at which this element was created. + */ + private long lastUpdate = 0; + + /** + * The encapsulated RdvAdvertisement for the Peer this instance + * represents. + */ + private RdvAdvertisement radv = null; + + /** + * True is the remote peer is known to be alive, false otherwise. + * It is always alive at birth. It may die soon after and we want to + * generate an event in that case. + */ + private boolean alive = true; + + /** + * If true then we are not accepting new messages until something unclogs. + */ + private volatile boolean throttling = false; + + /** + * PeerView that owns this PeerViewElement. + */ + private PeerView peerview = null; + + /** + * A cached Messenger for sending to the destination peer. + */ + private Messenger cachedMessenger = null; + + /** + * Initialize from a RdvAdvertisement. + * + * @param endpoint The endpoint service. + * @param radv the RdvAdvertisement from which to initialize + */ + PeerViewElement(EndpointService endpoint, RdvAdvertisement radv) { + + super(radv.getPeerID()); + + this.endpoint = endpoint; + this.radv = radv; + + created = TimeUtils.timeNow(); + lastUpdate = created; + } + + /** + * {@inheritDoc} + *

            + * A simple implementation for debugging. Do not attempt to parse this value! + */ + @Override + public String toString() { + StringBuilder asString = new StringBuilder(); + + asString.append('\"'); + asString.append(radv.getName()); + asString.append('\"'); + asString.append(alive ? " A " : " a "); + asString.append(isInPeerView() ? " P " : " p "); + asString.append(throttling ? " T " : " t "); + asString.append(" ["); + asString.append(TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), created) / TimeUtils.ASECOND); + asString.append("/"); + asString.append(TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), lastUpdate) / TimeUtils.ASECOND); + asString.append("]"); + return asString.toString(); + } + + /** + * {@inheritDoc} + */ + public void messageSendSucceeded(OutgoingMessageEvent e) { + + // As far as we know, connectivity is fine. + setAlive(true, true); + + throttling = false; + } + + /** + * {@inheritDoc} + */ + public void messageSendFailed(OutgoingMessageEvent e) { + + // As far as we know, connectivity is down. + // Except if failure is null; then it's just a queue overflow. + + if (null != e.getFailure()) { + setAlive(false, true); + } + + throttling = (e.getFailure() == null); + } + + /** + * Return true if the remote peer is known to be alive, + * false otherwise. + * + * @return Return true if the remote peer is known to be + * alive, false otherwise. + */ + public boolean isAlive() { + return alive; + } + + /** + * Update the connection status based upon the result of the last message + * send. + * + *

            We track the current dead-alive state and If we're in a peerview + * notify it of the transitions from alive to dead. + * + * @param live The known liveness of our connection to this peer. + * @param doNotify {@code true} will cause failure notifications to be sent. + * {@code false} makes notifications the caller's responsibility. + * @return {@code true} if a failure notification needs to be sent otherwise + * {@code false}. + */ + boolean setAlive(boolean live, boolean doNotify) { + boolean mustNotify; + + synchronized (this) { + mustNotify = alive && !live; + alive = live; + } + + // Since we do this out of sync, it is in theory possible that our alive + // status has already changed. It is rare but will only cause a little + // shake. So leave the sync behind, it causes a deadlock. + if (mustNotify && doNotify) { + PeerView temp = peerview; + + if (null != temp) { + temp.notifyFailure(this, true); + } + } + + return mustNotify; + } + + boolean isInPeerView() { + return (null != peerview); + } + + /** + * Sets the peerview + */ + synchronized void setPeerView(PeerView pv) { + if ((null != peerview) && (null != pv)) { + throw new IllegalStateException("Element already in " + peerview); + } + + peerview = pv; + } + + /** + * Return the time in absolute milliseconds at which we last updated this peer. + */ + long getLastUpdateTime() { + return lastUpdate; + } + + /** + * Sets the time in absolute milliseconds at which we last updated this peer. + */ + void setLastUpdateTime(long last) { + lastUpdate = last; + } + + /** + * Send a message to the peer which is represented by the current + * PeerViewElement. + * + * @param msg the message to send + * + * @param serviceName the service name on the destination peer to + * which the message will be demultiplexed + * + * @param serviceParam the service param on the destination peer + * to which the message will be demultiplexed + * + * @return true if the message was successfully handed off to the + * endpoint for delivery, false otherwise + */ + public boolean sendMessage(Message msg, String serviceName, String serviceParam) { + + if (throttling) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Declining to send -- throttling on " + this); + } + return false; + } + + Messenger sendVia = getCachedMessenger(); + + if (null == sendVia) { + // There is nothing really we can do. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Could not get messenger for " + getPeerID()); + } + + OutgoingMessageEvent event = new OutgoingMessageEvent(msg, + new IOException("Couldn't get messenger for " + getPeerID())); + + messageSendFailed(event); + return false; + } + + sendVia.sendMessage(msg, serviceName, serviceParam, this); + + return true; + } + + /** + * Get the encapsulated Peer Advertisement. + * + * @return the Advertisement of the Peer represented by this + * object + */ + public RdvAdvertisement getRdvAdvertisement() { + return radv; + } + + /** + * Set the encapsulated Peer Advertisement. + * + * @param adv is the RdvAdvertisement to be set. + * @return RdvAdvertisement the old Advertisement of the Peer represented by this + * object + */ + RdvAdvertisement setRdvAdvertisement(RdvAdvertisement adv) { + + if (!radv.getPeerID().equals(adv.getPeerID())) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("adv refers to a different peer"); + } + + throw new IllegalArgumentException("adv refers to a different peer"); + } + + RdvAdvertisement old = radv; + + this.radv = adv; + + setLastUpdateTime(TimeUtils.timeNow()); + + return old; + } + + /** + * Return a messenger suitable for sending to this peer. + * + * @return a messenger to this PVE peer or if {@code null} if peer is + * unreachable. + */ + private Messenger getCachedMessenger() { + + boolean mustNotify = false; + + synchronized (this) { + if ((null == cachedMessenger) || ((cachedMessenger.getState() & Messenger.USABLE) == 0)) { + cachedMessenger = null; + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting cached Messenger for " + radv.getName()); + } + + cachedMessenger = endpoint.getMessengerImmediate(getDestAddress(), radv.getRouteAdv()); + + if (null == cachedMessenger) { + mustNotify = setAlive(false, false); + } else if ((cachedMessenger.getState() & Messenger.RESOLVED) != 0) { + mustNotify = setAlive(true, false); + } + } + } + + // Since we do this out of sync, it is in theory possible that our alive + // status has already changed. It is rare but will only cause a little + // shake. So leave the sync behind, it causes a deadlock. + if (mustNotify) { + PeerView temp = peerview; + + if (null != temp) { + temp.notifyFailure(this, true); + } + } + + return cachedMessenger; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewEvent.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewEvent.java new file mode 100644 index 000000000..023bc5ea9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewEvent.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.util.EventObject; + +/** + * Container for PeerViewEvent events. + */ +public class PeerViewEvent extends EventObject { + + public static final int ADD = 10; + public static final int REMOVE = 11; + public static final int FAIL = 12; + + private static final String EVENTNAMES[] = { + "ADD", "REMOVE", "FAIL" + }; + + private int type; + private PeerViewElement element; + + /** + * Creates a new event + * + * @param source The peer view which is generating the event. + * @param type the event type + * @param element the peer associated with the event + */ + public PeerViewEvent(Object source, int type, PeerViewElement element) { + super(source); + this.type = type; + this.element = element; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + String eventType; + + if ((type >= ADD) && (type <= FAIL)) { + eventType = EVENTNAMES[type - ADD]; + } else { + eventType = "UNKNOWN (" + type + ")"; + } + + return super.toString() + " : " + eventType + " for " + element; + } + + /** + * Returns the event type + * + * @return int type + */ + public int getType() { + return type; + } + + /** + * Returns the PeerViewElement + * + * @return the peer view element associated with the event + */ + public PeerViewElement getPeerViewElement() { + + return element; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewListener.java new file mode 100644 index 000000000..cdad84e88 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewListener.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.util.EventListener; + +/** + * The listener interface for receiving PeerView events + */ +public interface PeerViewListener extends EventListener { + + /** + * Called when a peer view event occurs + * @param event the peerViewEvent event + */ + void peerViewEvent(PeerViewEvent event); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewRandomStrategy.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewRandomStrategy.java new file mode 100644 index 000000000..08a737114 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewRandomStrategy.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +/** + * Random without replacement + */ +final class PeerViewRandomStrategy implements PeerViewStrategy { + + private SortedSet set; + private List copy = new ArrayList(); + + PeerViewRandomStrategy(SortedSet set) { + this.set = set; + reset(); + } + + /** + * {@inheritDoc} + */ + public void reset() { + copy.clear(); + copy.addAll(set); + Collections.shuffle(copy); + } + + /** + * {@inheritDoc} + */ + public PeerViewElement next() { + synchronized (set) { + if (set.isEmpty()) { + copy.clear(); + return null; + } + + if (copy.isEmpty()) { + reset(); + } + + PeerViewElement pve = (PeerViewElement) copy.remove(0); + + if (set.contains(pve)) { + return pve; + } + } + return next(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewRandomWithReplaceStrategy.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewRandomWithReplaceStrategy.java new file mode 100644 index 000000000..99b089813 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewRandomWithReplaceStrategy.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2002 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.util.Random; +import java.util.SortedSet; +import java.util.Iterator; + +/** + * Random with replacement + */ +class PeerViewRandomWithReplaceStrategy implements PeerViewStrategy { + + private static Random random = new Random(); + private SortedSet set = null; + + PeerViewRandomWithReplaceStrategy(SortedSet set) { + this.set = set; + } + + /** + * {@inheritDoc} + */ + public void reset() { + } + + /** + * {@inheritDoc} + */ + public PeerViewElement next() { + synchronized (set) { + if (set.isEmpty()) { + return null; + } + + int i = random.nextInt(set.size()); + + // return the ith element + int n = 0; + Iterator si = set.iterator(); + + while (n < i) { + si.next(); + n++; + } + return (PeerViewElement) si.next(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewSequentialStrategy.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewSequentialStrategy.java new file mode 100644 index 000000000..59c707a59 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewSequentialStrategy.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.util.SortedSet; +import java.util.Iterator; + +/** + * Sequential + */ +class PeerViewSequentialStrategy implements PeerViewStrategy { + + private final SortedSet set; + private PeerViewElement current; + + PeerViewSequentialStrategy(SortedSet aset) { + set = aset; + reset(); + } + + /** + * {@inheritDoc} + */ + public void reset() { + current = null; + } + + /** + * {@inheritDoc} + */ + public PeerViewElement next() { + + synchronized (set) { + do { + if (null == current) { + if (!set.isEmpty()) { + // no current, take the first + current = (PeerViewElement) set.first(); + break; + } else { + // no first, return null + break; + } + } else { + SortedSet tail = set.tailSet(current); + + Iterator fromTail = tail.iterator(); + + if (fromTail.hasNext()) { + PeerViewDestination tailFirst = fromTail.next(); + + if (0 == current.compareTo(tailFirst)) { + if (fromTail.hasNext()) { + // first in tail is current so the new current + // is second in tail. + current = (PeerViewElement) fromTail.next(); + break; + } else { + // none left in tail after current, start over. + current = null; + } + } else { + // current is not in the tail set, so first in tail + // is new current + current = (PeerViewElement) tailFirst; + break; + } + } else { + // none in tail, start over. + current = null; + } + } + //FIXME by hamada this does not loop, current is always null, is the intended behavior? + } while (null == current); + } + + return current; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewStrategy.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewStrategy.java new file mode 100644 index 000000000..7ce022e3c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerViewStrategy.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +/** + * Describes a strategy for iterating over the values in a peerview. + */ +interface PeerViewStrategy { + + /** + * Reset the strategy. The meaning of reset depends entirely on the strategy + * which is used to return peer view elements. + */ + void reset(); + + /** + * Return the next PeerView Element using the strategy applied by this + * instance. + * + * @return the next peer view element in sequence or null if the peerview + * is empty. + */ + PeerViewElement next(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerviewSeedingManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerviewSeedingManager.java new file mode 100644 index 000000000..f456b30ec --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/rendezvous/rpv/PeerviewSeedingManager.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.rendezvous.rpv; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import java.util.logging.Logger; +import java.util.logging.Level; + +import net.jxta.logging.Logging; + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; + +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.RouteAdvertisement; + +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.impl.util.ACLSeedingManager; +import net.jxta.impl.util.TimeUtils; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.PipeAdvertisement; + +/** + * A Seeding Manager which uses the peerview advertisement pipes in order to + * locate seed peers for a given peer group. + */ +public class PeerviewSeedingManager extends ACLSeedingManager implements EndpointListener { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(PeerviewSeedingManager.class.getName()); + + /** + * This is the minimum interval at which we will refresh our "peerview" + */ + protected final static long MINIMUM_PEERVIEW_REFRESH_INTERVAL = 1 * TimeUtils.AMINUTE; + + /** + * The standard time interval after which we will refresh our "peerview" + */ + protected final static long STANDARD_PEERVIEW_REFRESH_INTERVAL = 20 * TimeUtils.AMINUTE; + + /** + * Our mock peerview we use to keep responses. + */ + protected Set peerview = new HashSet(); + + /** + * The absolute time at which we will refresh our "PeerView" + */ + protected long nextPeerViewRefresh = 0; + + /** + * The absolute time at which we will refresh our "PeerView" + */ + protected int unsuccessfulProbes = 0; + + protected final PeerGroup advGroup; + + protected final PeerGroup group; + + protected final String name; + + protected final PipeAdvertisement advPipeAdv; + + /** + * Creates a new instance of PeerviewSeedingManager + * + * @param aclLocation ACL uri + * @param group the group context + * @param advGroup the advertising group + * @param name service name + */ + public PeerviewSeedingManager(URI aclLocation, PeerGroup group, PeerGroup advGroup, String name) { + super(aclLocation); + + this.group = group; + this.advGroup = advGroup; + this.name = name; + + advPipeAdv = PeerView.makeWirePipeAdvertisement(advGroup, group, name); + + group.getEndpointService().addIncomingMessageListener(this, PeerView.SERVICE_NAME, group.getPeerGroupID().getUniqueValue().toString()); + } + + /** + * {@inheritDoc} + */ + public void stop() { + group.getEndpointService().removeIncomingMessageListener(PeerView.SERVICE_NAME, group.getPeerGroupID().getUniqueValue().toString()); + } + + /** + * Adds a rpv seed + * + * @param seed the seed + */ + public void addSeed(RouteAdvertisement seed) { + peerview.add(seed); + } + + /** + * {@inheritDoc} + */ + public URI[] getActiveSeedURIs() { + throw new UnsupportedOperationException("Not supported."); + } + + /** + * {@inheritDoc} + */ + public synchronized RouteAdvertisement[] getActiveSeedRoutes() { + refreshActiveSeeds(); + + List result = new ArrayList(); + + for (RouteAdvertisement anRA : peerview) { + result.add(anRA.clone()); + } + + return result.toArray(new RouteAdvertisement[result.size()]); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized boolean isAcceptablePeer(RouteAdvertisement radv) { + boolean acceptable = peerview.contains(radv); + + return acceptable && super.isAcceptablePeer(radv); + } + + protected void refreshActiveSeeds() { + if (TimeUtils.timeNow() < nextPeerViewRefresh) { + return; + } + + // remove the old stale entries. + peerview.clear(); + + Message message = makeMessage(); + + try { + PipeService pipes = advGroup.getPipeService(); + + OutputPipe output = pipes.createOutputPipe(advPipeAdv, 30 * TimeUtils.ASECOND); + + output.send(message); + + output.close(); + + // Only update the refresh if we we able to send. + + long untilNextRefresh; + + if (peerview.isEmpty()) { + unsuccessfulProbes++; + untilNextRefresh = Math.min(unsuccessfulProbes * MINIMUM_PEERVIEW_REFRESH_INTERVAL, + STANDARD_PEERVIEW_REFRESH_INTERVAL); + } else { + untilNextRefresh = STANDARD_PEERVIEW_REFRESH_INTERVAL; + } + + nextPeerViewRefresh = TimeUtils.toAbsoluteTimeMillis(untilNextRefresh); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed sending " + message + ".", failed); + } + } + } + + /** + * Make a PeerView Message. + * + * @return a peer view message + */ + private Message makeMessage() { + + Message msg = new Message(); + + msg.addMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.EDGE_ELEMENT); + + RdvAdvertisement radv = PeerView.createRdvAdvertisement(group.getPeerAdvertisement(), name); + + XMLDocument doc = (XMLDocument) radv.getDocument(MimeMediaType.XMLUTF8); + + MessageElement msge = new TextDocumentMessageElement(PeerView.MESSAGE_ELEMENT_NAME, doc, null); + + msg.addMessageElement(PeerView.MESSAGE_NAMESPACE, msge); + + return msg; + } + + /** + * {@inheritDoc} + *

            + *

            Listener for "PeerView"/<peergroup-unique-id> and propagate pipes. + */ + public synchronized void processIncomingMessage(Message msg, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + // check what kind of message this is (response or not). + boolean isResponse = false; + MessageElement me = msg.getMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.MESSAGE_ELEMENT_NAME); + + if (me == null) { + me = msg.getMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.RESPONSE_ELEMENT_NAME); + if (me == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Discarding damaged " + msg + "."); + } + return; + } else { + isResponse = true; + } + } + + Advertisement adv; + + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(me); + + adv = AdvertisementFactory.newAdvertisement(asDoc); + } catch (RuntimeException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building rdv advertisement from message element", failed); + } + return; + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building rdv advertisement from message element", failed); + } + return; + } + + if (!(adv instanceof RdvAdvertisement)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Response does not contain radv (" + adv.getAdvertisementType() + ")"); + } + return; + } + + RdvAdvertisement radv = (RdvAdvertisement) adv; + + if (null == radv.getRouteAdv()) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Radv does not contain route"); + } + return; + } + + // See if we can find a src route adv in the message.s + me = msg.getMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.SRCROUTEADV_ELEMENT_NAME); + if (me != null) { + try { + XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(me); + Advertisement routeAdv = AdvertisementFactory.newAdvertisement(asDoc); + + if (!(routeAdv instanceof RouteAdvertisement)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Advertisement is not a RouteAdvertisement"); + } + } else { + RouteAdvertisement rdvRouteAdv = radv.getRouteAdv().clone(); + + // XXX we stich them together even if in the end it gets optimized away + RouteAdvertisement.stichRoute(rdvRouteAdv, (RouteAdvertisement) routeAdv); + radv.setRouteAdv(rdvRouteAdv); + } + } catch (RuntimeException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building route adv from message element", failed); + } + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building route adv from message element", failed); + } + } + } + me = null; + + // Is this a message about ourself? + if (group.getPeerID().equals(radv.getPeerID())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Received a PeerView message about self. Discard."); + } + + return; + } + + // Collect the various flags. + + boolean isFailure = (msg.getMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.FAILURE_ELEMENT_NAME) != null); + boolean isCached = (msg.getMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.CACHED_RADV_ELEMENT_NAME) != null); + boolean isFromEdge = (msg.getMessageElement(PeerView.MESSAGE_NAMESPACE, PeerView.EDGE_ELEMENT_NAME) != null); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + String srcPeer = srcAddr.toString(); + LOG.fine("[" + group.getPeerGroupID() + "] Received a" + (isCached ? " cached" : "") + (isResponse ? " response" : "") + + (isFailure ? " failure" : "") + " message (" + msg.toString() + ")" + (isFromEdge ? " from edge" : "") + + " regarding \"" + radv.getName() + "\" from " + srcPeer); + } + + if (!isResponse || isFailure || isCached || isFromEdge) { + // We don't care about anything except responses from active rdvs. + return; + } + + peerview.add(radv.getRouteAdv()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/InternalQueryHandler.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/InternalQueryHandler.java new file mode 100644 index 000000000..03171ed60 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/InternalQueryHandler.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver; + + +import net.jxta.resolver.QueryHandler; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.endpoint.EndpointAddress; + + +/** + * Services that wish to act as a resolver handler must implement this interface. + *

            + * This interface extends the normal resolver query handler interface to add the + * source of the query. Typically this the query's last hop which may or may not + * be the same as the query's originator. Knowing the source of the query can be + * useful for sending NAK messages. + * + * @see net.jxta.resolver.ResolverService + * @see net.jxta.protocol.ResolverQueryMsg + */ +public interface InternalQueryHandler extends QueryHandler { + + /** + * Process the resolver query, and generate response + * it is the responsibility of the handler to send the response + * + *

            +     * result = processIncommingQuery(query);
            +     * if (result != null) {
            +     *   resolver.sendResponse(query.getSrc(), response);
            +     *   return resolver.OK;
            +     *  } else return resolver.Repropagate;
            +     * 
            + * + * @param srcAddr source address + * @param query ResolverQueryMsg query + * @return int status, {@link net.jxta.resolver.ResolverService#OK OK} success, + * {@link net.jxta.resolver.ResolverService#Repropagate Repropagate} to + * indicate a re-propagation is needed + */ + + public int processQuery(ResolverQueryMsg query, EndpointAddress srcAddr); + + /** + * Called when messages are received by the ResolverService + * it calls back this method to deal with received responses + * + * @param response ResolverQueryMsg response + * @param srcAddr source address + */ + public void processResponse(ResolverResponseMsg response, EndpointAddress srcAddr); + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/ResolverServiceImpl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/ResolverServiceImpl.java new file mode 100644 index 000000000..e505e26bc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/ResolverServiceImpl.java @@ -0,0 +1,1293 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver; + +import net.jxta.credential.Credential; +import net.jxta.document.Advertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.XMLDocument; +import net.jxta.endpoint.*; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.impl.endpoint.router.EndpointRouter; +import net.jxta.impl.endpoint.router.RouteControl; +import net.jxta.impl.meter.MonitorManager; +import net.jxta.impl.protocol.ResolverQuery; +import net.jxta.impl.protocol.ResolverResponse; +import net.jxta.impl.protocol.ResolverSrdiMsgImpl; +import net.jxta.impl.resolver.resolverMeter.QueryHandlerMeter; +import net.jxta.impl.resolver.resolverMeter.ResolverMeter; +import net.jxta.impl.resolver.resolverMeter.ResolverMeterBuildSettings; +import net.jxta.impl.resolver.resolverMeter.ResolverServiceMonitor; +import net.jxta.impl.resolver.resolverMeter.SrdiHandlerMeter; +import net.jxta.logging.Logging; +import net.jxta.membership.MembershipService; +import net.jxta.meter.MonitorResources; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.rendezvous.RendezVousStatus; +import net.jxta.resolver.QueryHandler; +import net.jxta.resolver.ResolverService; +import net.jxta.resolver.SrdiHandler; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * Implements the {@link net.jxta.resolver.ResolverService} using the standard + * JXTA Endpoint Resolver Protocol (ERP). + * + * @see net.jxta.resolver.ResolverService + * @see JXTA Protocols Specification : Endpoint Resolver Protocol + */ +public class ResolverServiceImpl implements ResolverService { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ResolverServiceImpl.class.getName()); + + /** + * Resolver query endpoint postfix + */ + public final static String outQueNameShort = "ORes"; + + /** + * Resolver response endpoint postfix + */ + public final static String inQueNameShort = "IRes"; + + /** + * Resolver srdi endpoint postfix + */ + public final static String srdiQueNameShort = "Srdi"; + + /** + * MIME Type for gzipped SRDI messages. + */ + private final static MimeMediaType GZIP_MEDIA_TYPE = new MimeMediaType("application/gzip").intern(); + + private String outQueName = outQueNameShort; + private String inQueName = inQueNameShort; + private String srdiQueName = srdiQueNameShort; + + private String handlerName = null; + private PeerGroup group = null; + private ModuleImplAdvertisement implAdvertisement = null; + private EndpointService endpoint = null; + private MembershipService membership = null; + + private RouteControl routeControl = null; + + private final Map handlers = Collections.synchronizedMap(new HashMap(5)); + private final Map srdiHandlers = Collections.synchronizedMap(new HashMap(5)); + + private EndpointListener queryListener = null; + private EndpointListener responseListener = null; + private EndpointListener srdiListener = null; + + private ResolverServiceMonitor resolverServiceMonitor; + private ResolverMeter resolverMeter; + + /** + * the resolver interface object + */ + private ResolverService resolverInterface = null; + + /** + * Encapsulates current Membership Service credential. + */ + final static class CurrentCredential { + + /** + * The current default credential + */ + final Credential credential; + + /** + * The current default credential in serialized XML form. + */ + final XMLDocument credentialDoc; + + CurrentCredential(Credential credential, XMLDocument credentialDoc) { + this.credential = credential; + this.credentialDoc = credentialDoc; + } + } + + /** + * The current Membership service default credential. + */ + CurrentCredential currentCredential; + + /** + * Listener we use for membership property events. + */ + private class CredentialListener implements PropertyChangeListener { + + /** + * Standard Constructor + */ + CredentialListener() { + } + + /** + * {@inheritDoc} + */ + public void propertyChange(PropertyChangeEvent evt) { + if (MembershipService.DEFAULT_CREDENTIAL_PROPERTY.equals(evt.getPropertyName())) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("New default credential event"); + } + + synchronized (ResolverServiceImpl.this) { + Credential cred = (Credential) evt.getNewValue(); + XMLDocument credentialDoc; + + if (null != cred) { + try { + credentialDoc = (XMLDocument) cred.getDocument(MimeMediaType.XMLUTF8); + currentCredential = new CurrentCredential(cred, credentialDoc); + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not generate credential document", all); + } + currentCredential = null; + } + } else { + currentCredential = null; + } + } + } + } + } + + final CredentialListener membershipCredListener = new CredentialListener(); + + /** + * Convenience method for constructing an endpoint address from an id + * + * @param destPeer peer id + * @param serv the service name (if any) + * @param parm the service param (if any) + * @return endpointAddress for this peer id. + */ + private static EndpointAddress mkAddress(ID destPeer, String serv, String parm) { + return new EndpointAddress("jxta", destPeer.getUniqueValue().toString(), serv, parm); + } + + /** + * {@inheritDoc} + */ + public void init(PeerGroup group, ID assignedID, Advertisement impl) { + implAdvertisement = (ModuleImplAdvertisement) impl; + + this.group = group; + handlerName = assignedID.toString(); + String uniqueStr = group.getPeerGroupID().getUniqueValue().toString(); + + outQueName = uniqueStr + outQueNameShort; + inQueName = uniqueStr + inQueNameShort; + srdiQueName = uniqueStr + srdiQueNameShort; + + if (ResolverMeterBuildSettings.RESOLVER_METERING) { // Fix-Me: This needs to be moved to startApp() when the load order issue is resolved + resolverServiceMonitor = (ResolverServiceMonitor) MonitorManager.getServiceMonitor(group, + MonitorResources.resolverServiceMonitorClassID); + if (resolverServiceMonitor != null) { + resolverMeter = resolverServiceMonitor.getResolverMeter(); + } + } + + // Tell tell the world about our configuration. + if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) { + StringBuilder configInfo = new StringBuilder("Configuring Resolver Service : " + assignedID); + + if (implAdvertisement != null) { + configInfo.append("\n\tImplementation :"); + configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID()); + configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription()); + configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri()); + configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode()); + } + + configInfo.append("\n\tGroup Params :"); + configInfo.append("\n\t\tGroup : ").append(group); + configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID()); + + configInfo.append("\n\tConfiguration:"); + configInfo.append("\n\t\tIn Queue name: ").append(outQueName); + configInfo.append("\n\t\tOut Queue name: ").append(inQueName); + configInfo.append("\n\t\tSRDI Queue name: ").append(srdiQueName); + + LOG.config(configInfo.toString()); + } + } + + /** + * {@inheritDoc} + */ + public int startApp(String[] arg) { + endpoint = group.getEndpointService(); + + if (null == endpoint) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is an endpoint service"); + } + return Module.START_AGAIN_STALLED; + } + + membership = group.getMembershipService(); + + if (null == membership) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Stalled until there is a membership service"); + } + return Module.START_AGAIN_STALLED; + } + + // Register Listeners + try { + // Register Query Listener + queryListener = new DemuxQuery(); + if (!endpoint.addIncomingMessageListener(queryListener, handlerName, outQueName)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Cannot register listener (already registered)"); + } + } + + // Register Response Listener + responseListener = new DemuxResponse(); + if (!endpoint.addIncomingMessageListener(responseListener, handlerName, inQueName)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Cannot register listener (already registered)"); + } + } + + // Register SRDI Listener + srdiListener = new DemuxSrdi(); + if (!endpoint.addIncomingMessageListener(srdiListener, handlerName, srdiQueName)) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.severe("Cannot register listener (already registered)"); + } + } + } catch (Exception e) { + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + LOG.log(Level.SEVERE, "failed to add listeners", e); + } + return -1; + } + + synchronized (this) { + // register our credential listener. + membership.addPropertyChangeListener(MembershipService.DEFAULT_CREDENTIAL_PROPERTY, membershipCredListener); + try { + // set the initial version of the default credential. + currentCredential = null; + Credential credential = membership.getDefaultCredential(); + XMLDocument credentialDoc; + if (null != credential) { + credentialDoc = (XMLDocument) credential.getDocument(MimeMediaType.XMLUTF8); + currentCredential = new CurrentCredential(credential, credentialDoc); + } + } catch (Exception all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "could not get default credential", all); + } + } + } + return Module.START_OK; + } + + /** + * {@inheritDoc} + */ + public void stopApp() { + endpoint.removeIncomingMessageListener(handlerName, outQueName); + endpoint.removeIncomingMessageListener(handlerName, inQueName); + + if (null != srdiListener) { + endpoint.removeIncomingMessageListener(handlerName, srdiQueName); + } + + queryListener = null; + responseListener = null; + srdiListener = null; + + membership.removePropertyChangeListener("defaultCredential", membershipCredListener); + currentCredential = null; + + routeControl = null; + membership = null; + group = null; + } + + /** + * {@inheritDoc} + */ + public synchronized ResolverService getInterface() { + if (resolverInterface == null) { + resolverInterface = new ResolverServiceInterface(this); + } + return resolverInterface; + } + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return implAdvertisement; + } + + /** + * {@inheritDoc} + */ + public QueryHandler registerHandler(String name, QueryHandler handler) { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + resolverServiceMonitor.registerQueryHandlerMeter(name); + } + return handlers.put(name, handler); + } + + /** + * {@inheritDoc} + */ + public QueryHandler unregisterHandler(String name) { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + resolverServiceMonitor.unregisterQueryHandlerMeter(name); + } + return handlers.remove(name); + } + + /** + * given a name returns the query handler associated with it + * + * @param name the handler to lookup + * @return returns the query handler + */ + public QueryHandler getHandler(String name) { + return handlers.get(name); + } + + /** + * {@inheritDoc} + */ + public SrdiHandler registerSrdiHandler(String name, SrdiHandler handler) { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + resolverServiceMonitor.registerSrdiHandlerMeter(name); + } + return srdiHandlers.put(name, handler); + } + + /** + * {@inheritDoc} + */ + public SrdiHandler unregisterSrdiHandler(String name) { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + resolverServiceMonitor.unregisterSrdiHandlerMeter(name); + } + return srdiHandlers.remove(name); + } + + /** + * given a name returns the srdi handler associated with it + * + * @param name the handler to lookup + * @return returns the SRDI handler + */ + public SrdiHandler getSrdiHandler(String name) { + return srdiHandlers.get(name); + } + + /** + * {@inheritDoc} + */ + public void sendQuery(String destPeer, ResolverQueryMsg query) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("sending query to resolver handler: " + query.getHandlerName()); + } + + // NOTE: Add route information about the issuing peer, so the + // resolver query responding peer can respond to the issuer without + // requiring any route discovery. In most case the responding peer + // is unlikely to know the route to the query issuer. This is a good + // optimization for edge peers. This optimzation is much less + // important for RDV peers as they are more likely to have a route + // to peers. Also, there is the concern that adding route info + // in resolver query exchanged between RDV will increase overhead due + // to the larger amount of information exchanged between RDV. + // Only update query if the query does not already contain any route + // information. We are mostly interested in the original src + // route information. + if (query.getSrcPeerRoute() == null) { + if (getRouteControl() != null) { + // FIXME tra 20031102 Until the new subscription service + // is implemented, we use the Router Control IOCTL + RouteAdvertisement route = routeControl.getMyLocalRoute(); + + if (route != null) { + query.setSrcPeerRoute(route.clone()); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending query with route info to " + destPeer); + } + } else { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No route control--could not set local route on query"); + } + } + } + + String queryHandlerName = query.getHandlerName(); + QueryHandlerMeter queryHandlerMeter = null; + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(queryHandlerName); + } + + if (destPeer == null) { + try { + Message queryMsg = new Message(); + XMLDocument asDoc = (XMLDocument) query.getDocument(MimeMediaType.XMLUTF8); + MessageElement docElem = new TextDocumentMessageElement(outQueName, asDoc, null); + queryMsg.addMessageElement("jxta", docElem); + RendezVousService rendezvous = group.getRendezVousService(); + + if (null != rendezvous) { + if (rendezvous.getRendezVousStatus() != RendezVousStatus.ADHOC) { + // Walk the message + rendezvous.walk(queryMsg.clone(), handlerName, outQueName, RendezVousService.DEFAULT_TTL); + } + // propagate to local net as well + rendezvous.propagateToNeighbors(queryMsg, handlerName, outQueName, 2); + } else { + endpoint.propagate(queryMsg, handlerName, outQueName); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.querySentInGroup(query); + } + } catch (IOException e) { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.queryPropagateError(); + } + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure during propagate", e); + } + } + } else { + // unicast instead + boolean success = sendMessage(destPeer, null, handlerName, outQueName, outQueName, + (XMLDocument) query.getDocument(MimeMediaType.XMLUTF8), false); + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + if (success) { + queryHandlerMeter.querySentViaUnicast(destPeer, query); + } else { + queryHandlerMeter.querySendError(); + } + } + } + } + + /** + * {@inheritDoc} + */ + public void sendResponse(String destPeer, ResolverResponseMsg response) { + + if (destPeer == null) { + propagateResponse(response); + } else { + QueryHandlerMeter queryHandlerMeter = null; + try { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(response.getHandlerName()); + } + + // Check if an optional route information is available to send the response + RouteAdvertisement route = response.getSrcPeerRoute(); + boolean success = sendMessage(destPeer, route, handlerName, inQueName, inQueName, + (XMLDocument) response.getDocument(MimeMediaType.XMLUTF8), false); + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + if (success) { + queryHandlerMeter.responseSentViaUnicast(destPeer, response); + } else { + queryHandlerMeter.responseSendError(); + } + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error in sending response", e); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.responseSendError(); + } + } + } + } + + /** + * {@inheritDoc} + */ + public void sendSrdi(String destPeer, ResolverSrdiMsg srdi) { + String srdiHandlerName = srdi.getHandlerName(); + SrdiHandlerMeter srdiHandlerMeter = null; + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + srdiHandlerMeter = resolverServiceMonitor.getSrdiHandlerMeter(srdiHandlerName); + } + + if (destPeer == null) { + RendezVousService rendezvous = group.getRendezVousService(); + + if (rendezvous == null) { + // no rendezvous service, dump it. + return; + } + Message propagateMsg = new Message(); + + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gos = new GZIPOutputStream(baos); + + srdi.getDocument(MimeMediaType.XMLUTF8).sendToStream(gos); + gos.finish(); + gos.close(); + byte gzipBytes[] = baos.toByteArray(); + + MessageElement zipElem = new ByteArrayMessageElement(srdiQueName, GZIP_MEDIA_TYPE, gzipBytes, null); + + propagateMsg.addMessageElement("jxta", zipElem); + + if (rendezvous.getRendezVousStatus() != RendezVousStatus.ADHOC) { + rendezvous.walk(propagateMsg, handlerName, srdiQueName, RendezVousService.DEFAULT_TTL); + } + + // propagate to local net as well + rendezvous.propagateToNeighbors(propagateMsg, handlerName, srdiQueName, 2); + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (srdiHandlerMeter != null)) { + srdiHandlerMeter.messageSentViaWalker(srdi); + } + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure sending srdi message", e); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (srdiHandlerMeter != null)) { + srdiHandlerMeter.errorPropagatingMessage(); + } + } + } else { + try { + boolean success = sendMessage(destPeer, null, handlerName, srdiQueName, srdiQueName, + (XMLDocument) srdi.getDocument(MimeMediaType.XMLUTF8), + // compression + true); + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (srdiHandlerMeter != null)) { + if (success) { + srdiHandlerMeter.messageSentViaUnicast(destPeer, srdi); + } else { + srdiHandlerMeter.errorSendingMessage(); + } + } + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Error in sending srdi message", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (srdiHandlerMeter != null)) { + srdiHandlerMeter.errorSendingMessage(); + } + } + } + } + + private void repropagateQuery(Message msg, ResolverQueryMsg query) { + RendezVousService rendezvous = group.getRendezVousService(); + + if ((null != rendezvous) && !group.isRendezvous()) { + // not a Rendezvous peer? Let someone else forward it. + return; + } + + // just in case an excessive of attempt to forward a query + // hopCount is used to determine forward counts independent of any other TTL + if (query.getHopCount() > 3) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("discarding ResolverQuery. HopCount exceeded : " + query.getHopCount()); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.propagationQueryDropped(query); + } + return; + } + + XMLDocument asDoc = (XMLDocument) query.getDocument(MimeMediaType.XMLUTF8); + MessageElement docElem = new TextDocumentMessageElement(outQueName, asDoc, null); + + msg.replaceMessageElement("jxta", docElem); + + // Re-propagate the message. + // Loop and TTL control is done in demux and propagate(). The TTL + // below is just a default it will be reduced appropriately. + + try { + if (null != rendezvous) { + if (rendezvous.getRendezVousStatus() != RendezVousStatus.ADHOC) { + rendezvous.walk(msg, handlerName, outQueName, RendezVousService.DEFAULT_TTL); + } + // propagate to local net as well + rendezvous.propagateToNeighbors(msg, handlerName, outQueName, 2); + } else { + endpoint.propagate(msg, handlerName, inQueName); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.queryPropagatedViaWalker(query); + } + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure propagating query", e); + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.queryPropagationError(query); + } + } + } + } + + /** + * Process a resolver query. + * + * @param query The query. + * @param srcAddr Who sent the query to us. May not be the same as the + * query originator. + * @return the query id assigned to the query + */ + private int processQuery(ResolverQueryMsg query, EndpointAddress srcAddr) { + String queryHandlerName = query.getHandlerName(); + QueryHandler theHandler = getHandler(queryHandlerName); + + if (query.getHopCount() > 2) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding query #" + query.getQueryId() + " hopCount > 2 : " + query.getHopCount()); + } + + // query has been forwarded too many times stop + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(queryHandlerName); + if (queryHandlerMeter != null) { + queryHandlerMeter.queryHopCountDropped(); + } else { + resolverMeter.invalidQueryDiscarded(srcAddr); + } + } + return ResolverService.OK; + } + + if (theHandler == null) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Discarding query #" + query.getQueryId() + ", no handler for :" + queryHandlerName); + } + // If this peer is a rendezvous peer, it needs to repropagate the query to other rendezvous peer that + // may have a handler. + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.unknownHandlerForQuery(query); + } + return ResolverService.Repropagate; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Handing query #" + query.getQueryId() + " to : " + queryHandlerName); + } + + QueryHandlerMeter queryHandlerMeter = null; + long startTime = 0; + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + startTime = System.currentTimeMillis(); + queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(queryHandlerName); + } + + try { + int result; + if (theHandler instanceof InternalQueryHandler) { + result = ((InternalQueryHandler) theHandler).processQuery(query, srcAddr); + } else { + result = theHandler.processQuery(query); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.queryProcessed(query, result, System.currentTimeMillis() - startTime); + } + return result; + } catch (Throwable any) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable from handler for : " + queryHandlerName, any); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.errorWhileProcessingQuery(query); + } + // stop repropagation + return ResolverService.OK; + } + } + + /** + * Process a resolver response. + * + * @param resp The response. + * @param srcAddr Who sent the response. May not be the same as the + * originator response. + */ + private void processResponse(ResolverResponseMsg resp, EndpointAddress srcAddr) { + String handlerName = resp.getHandlerName(); + + if (handlerName == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Missing handlername in response"); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidResponseDiscarded(srcAddr); + } + return; + } + + QueryHandler theHandler = getHandler(handlerName); + if (theHandler == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("No handler for :" + handlerName); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.unknownHandlerForResponse(srcAddr, resp); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Process response to query #" + resp.getQueryId() + " with " + handlerName); + } + + QueryHandlerMeter queryHandlerMeter = null; + long startTime = 0; + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + startTime = System.currentTimeMillis(); + queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + } + + try { + if (theHandler instanceof InternalQueryHandler) { + ((InternalQueryHandler) theHandler).processResponse(resp, srcAddr); + } else { + theHandler.processResponse(resp); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.responseProcessed(resp, System.currentTimeMillis() - startTime, srcAddr); + } + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable from handler for: " + handlerName, all); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.errorWhileProcessingResponse(srcAddr); + } + } + } + + /** + * propagate a response + * + * @param response response message to propagate + */ + private void propagateResponse(ResolverResponseMsg response) { + + Message propagateMsg = new Message(); + + String queryHandlerName = response.getHandlerName(); + QueryHandlerMeter queryHandlerMeter = null; + + try { + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(queryHandlerName); + } + + XMLDocument responseDoc = (XMLDocument) response.getDocument(MimeMediaType.XMLUTF8); + MessageElement elemDoc = new TextDocumentMessageElement(inQueName, responseDoc, null); + propagateMsg.addMessageElement("jxta", elemDoc); + RendezVousService rendezvous = group.getRendezVousService(); + + if (null != rendezvous) { + rendezvous.walk(propagateMsg, handlerName, inQueName, RendezVousService.DEFAULT_TTL); + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.responseSentViaWalker(response); + } + } else { + endpoint.propagate(propagateMsg, handlerName, inQueName); + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + // FIXME bondolo 20040909 not technically the correct metric + queryHandlerMeter.responseSentViaWalker(response); + } + } + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "failure during propagateResponse", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (queryHandlerMeter != null)) { + queryHandlerMeter.responsePropagateError(); + } + } + } + + /** + * Process an SRDI message. + * + * @param srdimsg The SRDI message. + * @param srcAddr Who sent the message. May not be the same as the + * originator of the message. + */ + private void processSrdi(ResolverSrdiMsgImpl srdimsg, EndpointAddress srcAddr) { + String handlerName = srdimsg.getHandlerName(); + + if (handlerName == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Missing handlername in response"); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidSrdiMessageDiscarded(srcAddr); + } + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Processing an SRDI msg for : " + handlerName + " in Group ID:" + group.getPeerGroupID()); + } + + SrdiHandler theHandler = getSrdiHandler(handlerName); + if (theHandler != null) { + SrdiHandlerMeter srdiHandlerMeter = null; + + try { + long startTime = 0; + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverServiceMonitor != null)) { + startTime = System.currentTimeMillis(); + srdiHandlerMeter = resolverServiceMonitor.getSrdiHandlerMeter(handlerName); + } + + theHandler.processSrdi(srdimsg); + if (ResolverMeterBuildSettings.RESOLVER_METERING && (srdiHandlerMeter != null)) { + srdiHandlerMeter.messageProcessed(srdimsg, System.currentTimeMillis() - startTime, srcAddr); + } + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable from handler for: " + handlerName, all); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (srdiHandlerMeter != null)) { + srdiHandlerMeter.errorWhileProcessing(srcAddr); + } + } + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING) && group.isRendezvous()) { + LOG.warning("No srdi handler registered :" + handlerName + " for Group ID:" + group.getPeerGroupID()); + } else if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("No srdi handler registered :" + handlerName + " for Group ID:" + group.getPeerGroupID()); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.unknownHandlerForSrdiMessage(srcAddr, handlerName); + } + } + } + + /** + * Send a resolver message to a peer + * + * @param destPeer destination peer + * @param route destination route advertisement + * @param pName service name on the destination + * @param pParam service param on the destination + * @param tagName tag name of the message element + * @param body the body of the message element + * @param gzip If true then encode the message body using gzip. + * @return {@code true} if successful + */ + private boolean sendMessage(String destPeer, RouteAdvertisement route, String pName, String pParam, String tagName, XMLDocument body, boolean gzip) { + // Get the messenger ready + ID dest; + try { + dest = IDFactory.fromURI(new URI(destPeer)); + } catch (URISyntaxException badpeer) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "bad destination peerid : " + destPeer, badpeer); + } + + return false; + } + + EndpointAddress destAddress = mkAddress(dest, pName, pParam); + + // FIXME add route to responses as well + Messenger messenger = null; + if (route == null) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("No route info available for " + destPeer); + } + } else { + // ok we have a route let's pass it to the router + if ((null == getRouteControl()) || (routeControl.addRoute(route) == RouteControl.FAILED)) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to add route for " + route.getDestPeerID()); + } + } else { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Added route for " + route.getDestPeerID()); + } + } + } + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Creating a messenger immediate for :" + destAddress); + } + + messenger = endpoint.getMessengerImmediate(destAddress, route); + if (null == messenger) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Failed creating messenger for " + destAddress); + } + return false; + } + + Message msg = new Message(); + try { + MessageElement msgEl; + if (gzip) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gos = new GZIPOutputStream(baos); + + body.sendToStream(gos); + gos.finish(); + gos.close(); + byte gzipBytes[] = baos.toByteArray(); + + msgEl = new ByteArrayMessageElement(tagName, GZIP_MEDIA_TYPE, gzipBytes, null); + } else { + msgEl = new TextDocumentMessageElement(tagName, body, null); + } + msg.addMessageElement("jxta", msgEl); + } catch (Exception ez1) { + // Not much we can do + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed building message", ez1); + } + return false; + } + + // Send the message + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending " + msg + " to " + destAddress + " " + tagName); + } + + // XXX 20040924 bondolo Convert this to ListenerAdaptor + messenger.sendMessage(msg, null, null, new FailureListener(dest)); + + return true; + } + + private RouteControl getRouteControl() { + // Obtain the route control object to manipulate route information when sending and receiving resolver queries. + if (routeControl == null) { + // insignificant race condition here + MessageTransport endpointRouter = endpoint.getMessageTransport("jxta"); + if (endpointRouter != null) { + routeControl = (RouteControl) endpointRouter.transportControl(EndpointRouter.GET_ROUTE_CONTROL, null); + } else { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed to get RouteControl object. Resolver will not set route hints."); + } + } + } + return routeControl; + } + + /** + * Inner class to handle incoming queries + */ + private class DemuxQuery implements EndpointListener { + + /** + * {@inheritDoc} + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Demuxing a query message from " + srcAddr); + } + + MessageElement element = message.getMessageElement("jxta", outQueName); + if (element == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Message does not contain a query. Discarding message"); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidQueryDiscarded(srcAddr); + } + return; + } + + ResolverQueryMsg query; + try { + StructuredDocument asDoc = StructuredDocumentFactory.newStructuredDocument(element); + query = new ResolverQuery(asDoc); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Ill formatted resolver query, ignoring.", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidQueryDiscarded(srcAddr); + } + return; + } catch (IllegalArgumentException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Ill formatted resolver query, ignoring.", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidQueryDiscarded(srcAddr); + } + return; + } + + int res = processQuery(query, srcAddr); + if (ResolverService.Repropagate == res) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Repropagating query " + message + " from " + srcAddr); + } + repropagateQuery(message, query); + } + } + } + + /** + * Inner class to handle incoming responses + */ + private class DemuxResponse implements EndpointListener { + + /** + * @inheritDoc + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Demuxing a response from " + srcAddr); + } + + MessageElement element = message.getMessageElement("jxta", inQueName); + if (null == element) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message does not contain a response. Discarding message"); + } + + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidResponseDiscarded(srcAddr); + } + return; + } + + ResolverResponse resolverResponse; + try { + StructuredDocument asDoc = StructuredDocumentFactory.newStructuredDocument(element); + resolverResponse = new ResolverResponse(asDoc); + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Ill formatted resolver response, ignoring.", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidResponseDiscarded(srcAddr); + } + return; + } catch (IllegalArgumentException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Ill formatted resolver response, ignoring.", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidResponseDiscarded(srcAddr); + } + return; + } + processResponse(resolverResponse, srcAddr); + } + } + + /** + * Inner class to handle SRDI messages + */ + private class DemuxSrdi implements EndpointListener { + + /** + * @inheritDoc + */ + public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Demuxing an SRDI message from : " + srcAddr); + } + + MessageElement element = message.getMessageElement("jxta", srdiQueName); + if (element == null) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Message does not contain a SRDI element. Discarding message"); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidSrdiMessageDiscarded(srcAddr); + } + return; + } + + ResolverSrdiMsgImpl srdimsg; + try { + if (element.getMimeType().getBaseMimeMediaType().equals(GZIP_MEDIA_TYPE)) { + InputStream gzipStream = new GZIPInputStream(element.getStream()); + StructuredDocument asDoc = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, gzipStream); + srdimsg = new ResolverSrdiMsgImpl(asDoc, membership); + } else { + StructuredDocument asDoc = StructuredDocumentFactory.newStructuredDocument(element); + srdimsg = new ResolverSrdiMsgImpl(asDoc, membership); + } + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Ill formatted SRDI message, ignoring.", e); + } + if (ResolverMeterBuildSettings.RESOLVER_METERING && (resolverMeter != null)) { + resolverMeter.invalidSrdiMessageDiscarded(srcAddr); + } + return; + } + processSrdi(srdimsg, srcAddr); + } + } + + /** + * Listener to find bad destinations and clean srdi tables for them. + */ + class FailureListener implements OutgoingMessageEventListener { + final ID dest; + + FailureListener(ID dest) { + this.dest = dest; + } + + /** + * {@inheritDoc} + */ + public void messageSendFailed(OutgoingMessageEvent event) { + // Ignore the failure if it's a case of queue overflow. + if (event.getFailure() == null) { + return; + } + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Clearing SRDI tables for failed peer : " + dest); + } + + for (Object o : Arrays.asList(srdiHandlers.values().toArray())) { + SrdiHandler theHandler = (SrdiHandler) o; + try { + theHandler.messageSendFailed((PeerID) dest, event); + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable from handler : " + theHandler, all); + } + } + } + } + + /** + * {@inheritDoc} + */ + public void messageSendSucceeded(OutgoingMessageEvent event) {// great! + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/ResolverServiceInterface.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/ResolverServiceInterface.java new file mode 100644 index 000000000..c3e9bcb02 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/ResolverServiceInterface.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver; + + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.platform.Module; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.ResolverQueryMsg; +import net.jxta.protocol.ResolverResponseMsg; +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.resolver.QueryHandler; +import net.jxta.resolver.ResolverService; +import net.jxta.resolver.SrdiHandler; +import net.jxta.service.Service; + + +/** + * Provides a controlled interface to the Resolver Service. + **/ +public class ResolverServiceInterface implements ResolverService { + + private final ResolverServiceImpl impl; + + /** + * Only authorized constructor + * @param theRealThing reference to the impl + */ + ResolverServiceInterface(ResolverServiceImpl theRealThing) { + impl = theRealThing; + } + + /** + * {@inheritDoc} + * + *

            Since THIS is already such an object, it returns itself. + * FIXME: it is kind of absurd to have this method part of the + * interface but we do not want to define two levels of Service interface + * just for that. + */ + public ResolverService getInterface() { + return this; + } + + /** + * {@inheritDoc} + * + *

            FIXME: This is meaningless for the interface object; + * it is there only to satisfy the requirements of the + * interface that we implement. Ultimately, the API should define + * two levels of interfaces: one for the real service implementation + * and one for the interface object. Right now it feels a bit heavy + * to so that since the only different between the two would be + * init() and may-be getName(). + */ + public void init(PeerGroup g, ID assignedID, Advertisement impl) {} + + /** + * {@inheritDoc} + * + *

            Does nothing in the interface object. + */ + public int startApp(String[] arg) { + return Module.START_OK; + } + + /** + * {@inheritDoc} + * + *

            Does nothing in the interface object. + */ + public void stopApp() {} + + /** + * {@inheritDoc} + */ + public ModuleImplAdvertisement getImplAdvertisement() { + return impl.getImplAdvertisement(); + } + + /** + * {@inheritDoc} + */ + public QueryHandler registerHandler(String name, QueryHandler handler) { + return impl.registerHandler(name, handler); + } + + /** + * {@inheritDoc} + */ + public QueryHandler unregisterHandler(String name) { + return impl.unregisterHandler(name); + } + + /** + * {@inheritDoc} + */ + public SrdiHandler registerSrdiHandler(String name, SrdiHandler handler) { + return impl.registerSrdiHandler(name, handler); + } + + /** + * {@inheritDoc} + */ + public SrdiHandler unregisterSrdiHandler(String name) { + return impl.unregisterSrdiHandler(name); + } + + /** + * {@inheritDoc} + */ + public void sendQuery(String rdvPeer, ResolverQueryMsg query) { + impl.sendQuery(rdvPeer, query); + } + + /** + * {@inheritDoc} + */ + public void sendResponse(String destPeer, ResolverResponseMsg response) { + impl.sendResponse(destPeer, response); + } + + /** + * {@inheritDoc} + */ + public void sendSrdi(String destPeer, ResolverSrdiMsg srdi) { + impl.sendSrdi(destPeer, srdi); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/package.html new file mode 100644 index 000000000..595f57130 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/package.html @@ -0,0 +1,13 @@ + + + + + + + A JXTA {@link net.jxta.resolver.ResolverService} implementation which + implements the standard JXTA Endpoint Resolver Protocol (ERP). + + @see net.jxta.resolver.ResolverService + @see JXTA Protocols Specification : Endpoint Resolver Protocol + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ConditionalResolverMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ConditionalResolverMeterBuildSettings.java new file mode 100644 index 000000000..c326f1965 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ConditionalResolverMeterBuildSettings.java @@ -0,0 +1,80 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.resolver.resolverMeter; + +import java.util.ResourceBundle; +import net.jxta.impl.meter.*; + +public class ConditionalResolverMeterBuildSettings { + public static boolean isRuntimeMetering() { + boolean runtimeMetering = false; + + try { + ResourceBundle userResourceBundle = ResourceBundle.getBundle( "net.jxta.user" ); + String meteringProperty = "net.jxta.meter.conditionalResolverMetering"; + String meteringValue = userResourceBundle.getString( meteringProperty ); + runtimeMetering = "on".equalsIgnoreCase( meteringValue ); + } catch (Exception ignored) { + } + + return runtimeMetering; + } +} \ No newline at end of file diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryDestinationMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryDestinationMeter.java new file mode 100644 index 000000000..5b6cd6ace --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryDestinationMeter.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.peer.*; +import net.jxta.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.util.*; +import java.util.*; + + +public class QueryDestinationMeter { + private PeerID peerID; + private QueryDestinationMetric cumulativeMetrics; + private QueryDestinationMetric deltaMetrics; + + public QueryDestinationMeter(PeerID peerID) { + cumulativeMetrics = new QueryDestinationMetric(peerID); + } + + public synchronized QueryDestinationMetric collectMetrics() { + QueryDestinationMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + return prevDelta; + } + + public QueryDestinationMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + private void createDeltaMetric() { + deltaMetrics = new QueryDestinationMetric(peerID); + } + + protected void querySentViaUnicast() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.querySentViaUnicast(); + cumulativeMetrics.querySentViaUnicast(); + } + + protected void responseSentViaUnicast() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseSentViaUnicast(); + cumulativeMetrics.responseSentViaUnicast(); + } + + protected void responseProcessed() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseProcessed(); + cumulativeMetrics.responseProcessed(); + } + + protected void responseToUnregisteredHandler() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseToUnregisteredHandler(); + cumulativeMetrics.responseToUnregisteredHandler(); + } + + protected void errorWhileProcessingResponse() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorWhileProcessingResponse(); + cumulativeMetrics.errorWhileProcessingResponse(); + } + + protected void queryProcessed() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryProcessed(); + cumulativeMetrics.queryProcessed(); + } + + protected void queryToUnregisteredHandler() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryToUnregisteredHandler(); + cumulativeMetrics.queryToUnregisteredHandler(); + } + + protected void errorWhileProcessingQuery() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorWhileProcessingQuery(); + cumulativeMetrics.errorWhileProcessingQuery(); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryDestinationMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryDestinationMetric.java new file mode 100644 index 000000000..e50e03aaf --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryDestinationMetric.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.peer.*; +import net.jxta.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.util.*; +import net.jxta.impl.meter.*; + +import java.util.*; + + +/** + * Metrics for a specific Query Destination for a specific handler + **/ +public class QueryDestinationMetric implements DocumentSerializable { + private PeerID peerID; + private int errorWhileProcessingQuery; + private int queryProcessed; + private int errorWhileProcessingResponse; + private int responseProcessed; + private int responseSentViaUnicast; + private int querySentViaUnicast; + + private int queryToUnregisteredHandler; + private int responseToUnregisteredHandler; + + public QueryDestinationMetric(PeerID pid) { + this.peerID = pid; + } + + public QueryDestinationMetric(QueryDestinationMetric prototype) { + this.peerID = prototype.peerID; + } + + public QueryDestinationMetric() {} + + public PeerID getPeerID() { + return peerID; + } + + void querySentViaUnicast() { + querySentViaUnicast++; + } + + /** Get Queries Sent via Unicast to this destinations **/ + public int getQueriesSentViaUnicast() { + return querySentViaUnicast; + } + + void responseSentViaUnicast() { + responseSentViaUnicast++; + } + + /** Get Responses Sent via Unicast to this destinations **/ + public int getResponsesSentViaUnicast() { + return responseSentViaUnicast; + } + + void responseToUnregisteredHandler() { + responseToUnregisteredHandler++; + } + + /** Get Responses Recieved to this handler when not registered **/ + public int getResponseToUnregisteredHandler() { + return responseToUnregisteredHandler; + } + + void responseProcessed() { + responseProcessed++; + } + + /** Get Responses received and processed locally **/ + public int getResponsesProcessed() { + return responseProcessed; + } + + void errorWhileProcessingResponse() { + errorWhileProcessingResponse++; + } + + /** Get Responses received but failing when processed locally **/ + public int getErrorsWhileProcessingResponse() { + return errorWhileProcessingResponse; + } + + void queryProcessed() { + queryProcessed++; + } + + /** Get Queries received and processed locally **/ + public int getQueriesProcessed() { + return queryProcessed; + } + + void queryToUnregisteredHandler() { + queryToUnregisteredHandler++; + } + + /** Get Queries Recieved to this handler when not registered **/ + public int getQueryToUnregisteredHandler() { + return queryToUnregisteredHandler; + } + + void errorWhileProcessingQuery() { + errorWhileProcessingQuery++; + } + + /** Get Queries received but failing when processed locally **/ + public int getErrorsWhileProcessingQuery() { + return errorWhileProcessingQuery; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (peerID != null) { + DocumentSerializableUtilities.addString(element, "peerID", peerID.toString()); + } + if (errorWhileProcessingQuery != 0) { + DocumentSerializableUtilities.addInt(element, "errorWhileProcessingQuery", errorWhileProcessingQuery); + } + if (queryProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "queryProcessed", queryProcessed); + } + if (errorWhileProcessingResponse != 0) { + DocumentSerializableUtilities.addInt(element, "errorWhileProcessingResponse", errorWhileProcessingResponse); + } + if (responseProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "responseProcessed", responseProcessed); + } + if (responseSentViaUnicast != 0) { + DocumentSerializableUtilities.addInt(element, "responseSentViaUnicast", responseSentViaUnicast); + } + if (querySentViaUnicast != 0) { + DocumentSerializableUtilities.addInt(element, "querySentViaUnicast", querySentViaUnicast); + } + if (queryToUnregisteredHandler != 0) { + DocumentSerializableUtilities.addInt(element, "queryToUnregisteredHandler", queryToUnregisteredHandler); + } + if (responseToUnregisteredHandler != 0) { + DocumentSerializableUtilities.addInt(element, "responseToUnregisteredHandler", responseToUnregisteredHandler); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("peerID")) { + String peerIDText = DocumentSerializableUtilities.getString(childElement); + + peerID = MetricUtilities.getPeerIdFromString(peerIDText); + } else if (tagName.equals("errorWhileProcessingQuery")) { + errorWhileProcessingQuery = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("queryProcessed")) { + queryProcessed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("errorWhileProcessingResponse")) { + errorWhileProcessingResponse = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("responseProcessed")) { + responseProcessed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("responseSentViaUnicast")) { + responseSentViaUnicast = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("querySentViaUnicast")) { + querySentViaUnicast = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("queryToUnregisteredHandler")) { + queryToUnregisteredHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("responseToUnregisteredHandler")) { + responseToUnregisteredHandler = DocumentSerializableUtilities.getInt(childElement); + } + } + } + + public void mergeMetrics(QueryDestinationMetric otherQueryDestinationMetric) { + this.errorWhileProcessingQuery += otherQueryDestinationMetric.errorWhileProcessingQuery; + this.queryProcessed += otherQueryDestinationMetric.queryProcessed; + this.errorWhileProcessingResponse += otherQueryDestinationMetric.errorWhileProcessingResponse; + this.responseProcessed += otherQueryDestinationMetric.responseProcessed; + this.responseSentViaUnicast += otherQueryDestinationMetric.responseSentViaUnicast; + this.querySentViaUnicast += otherQueryDestinationMetric.querySentViaUnicast; + this.queryToUnregisteredHandler += otherQueryDestinationMetric.queryToUnregisteredHandler; + this.responseToUnregisteredHandler += otherQueryDestinationMetric.responseToUnregisteredHandler; + } + + @Override + public int hashCode() { + return peerID.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof QueryDestinationMetric) { + QueryDestinationMetric otherQueryDestinationMetric = (QueryDestinationMetric) other; + + return peerID.equals(otherQueryDestinationMetric.peerID); + } else { + return false; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryHandlerMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryHandlerMeter.java new file mode 100644 index 000000000..f08337c7e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryHandlerMeter.java @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.peer.*; +import net.jxta.peergroup.*; +import net.jxta.resolver.*; +import net.jxta.impl.resolver.*; +import net.jxta.impl.meter.*; +import net.jxta.protocol.*; +import net.jxta.meter.*; +import net.jxta.util.*; + +import net.jxta.endpoint.*; +import net.jxta.exception.*; + +import java.net.*; +import java.util.*; + + +public class QueryHandlerMeter { + private static final int QUERY_CULLING_INTERVAL = 5 * 60 * 1000; // Fix-Me: Five minutes hardcoded for now... + + private ResolverServiceMonitor resolverServiceMonitor; + private String handlerName; + + private QueryHandlerMetric cumulativeMetrics; + private QueryHandlerMetric deltaMetrics; + + private Hashtable queryDestinationMeters = new Hashtable(); + + private Hashtable queryMetricsTable = null; + + private class QueryMetricsTable extends Hashtable { + + void deReference() { + queryMetricsTable = null; + } + + @Override + public String toString() { + return handlerName; + } + } + + + private class QueryMetric { + int queryId; + long querySentTime = System.currentTimeMillis(); + int numResponsesReceived = 0; + long lastResponseTime = 0; + + QueryMetric(int queryId) { + this.queryId = queryId; + } + } + + private static LinkedList queryMetricsTables = new LinkedList(); + + static { + Thread cullQueries = new Thread(new Runnable() { + public void run() { + for (;;) { + try { + Thread.sleep(QUERY_CULLING_INTERVAL); + } catch (Exception e) {} + + long dormantTime = System.currentTimeMillis() - QUERY_CULLING_INTERVAL; + + synchronized (queryMetricsTables) { + LinkedList keysToRemove = new LinkedList(); + + for (Iterator i = queryMetricsTables.iterator(); i.hasNext();) { + QueryMetricsTable queryMetricsTable = (QueryMetricsTable) i.next(); + + keysToRemove.clear(); + + synchronized (queryMetricsTable) { + for (Enumeration e = queryMetricsTable.keys(); e.hasMoreElements();) { + Integer key = (Integer) e.nextElement(); + QueryMetric queryMetric = (QueryMetric) queryMetricsTable.get(key); + + if (queryMetric.lastResponseTime < dormantTime) { + keysToRemove.add(key); + } + } + + for (Iterator k = keysToRemove.iterator(); k.hasNext();) { + Integer key = (Integer) k.next(); + + queryMetricsTable.deReference(); + queryMetricsTable.remove(key); + } + + if (queryMetricsTable.size() == 0) { + i.remove(); + } + } + } + } + } + } + }, "Resolver Query Metrics Culling Thread"); + + cullQueries.setDaemon(true); + cullQueries.start(); + } + + public QueryHandlerMeter(String handlerName, ResolverServiceMonitor resolverServiceMonitor) { + this.handlerName = handlerName; + cumulativeMetrics = new QueryHandlerMetric(handlerName); + this.resolverServiceMonitor = resolverServiceMonitor; + } + + public QueryHandlerMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public String getHandlerName() { + return handlerName; + } + + public synchronized QueryHandlerMetric collectMetrics() { + QueryHandlerMetric prevDelta = deltaMetrics; + + for (Enumeration e = queryDestinationMeters.elements(); e.hasMoreElements();) { + QueryDestinationMeter queryDestinationMeter = (QueryDestinationMeter) e.nextElement(); + + QueryDestinationMetric queryDestinationMetric = queryDestinationMeter.collectMetrics(); + + if (queryDestinationMetric != null) { + + /* Fix-me: while fixing an exception thrown by SrdiHandlerMeter, I noticed that + a similar problem might occur here if there can be a case where a destinationMtric + is available even though nothing has happened to create the delta. + If that is not possible (we need to do a code review!) remove the check for + a null delta here. + */ + if (prevDelta == null) { + createDeltaMetric(); + prevDelta = deltaMetrics; + } + prevDelta.addQueryDestinationMetric(queryDestinationMetric); + } + } + deltaMetrics = null; + return prevDelta; + } + + public synchronized QueryDestinationMeter getQueryDestinationMeter(EndpointAddress endpointAddress) { + PeerID peerID = MetricUtilities.getPeerIdFromEndpointAddress(endpointAddress); + + return getQueryDestinationMeter(peerID); + } + + public synchronized QueryDestinationMeter getQueryDestinationMeter(String peerIdString) { + PeerID peerID = MetricUtilities.getPeerIdFromString(peerIdString); + + return getQueryDestinationMeter(peerID); + } + + public synchronized QueryDestinationMeter getQueryDestinationMeter(PeerID peerID) { + QueryDestinationMeter queryDestinationMeter = (QueryDestinationMeter) queryDestinationMeters.get(peerID); + + if (queryDestinationMeter == null) { + queryDestinationMeter = new QueryDestinationMeter(peerID); + + queryDestinationMeters.put(peerID, queryDestinationMeter); + cumulativeMetrics.addQueryDestinationMetric(queryDestinationMeter.getCumulativeMetrics()); + } + + return queryDestinationMeter; + } + + private void createDeltaMetric() { + deltaMetrics = new QueryHandlerMetric(handlerName); + } + + @Override + public String toString() { + return "ResolverHandlerMeter(" + handlerName + ")"; + } + + public void setRegistered(boolean registered) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.setRegistered(registered); + cumulativeMetrics.setRegistered(registered); + } + + private QueryMetric getQueryMetric(int queryId) { + Integer key = new Integer(queryId); + + synchronized (queryMetricsTables) { + if (queryMetricsTable == null) { + queryMetricsTable = new QueryMetricsTable(); + + queryMetricsTables.add(queryMetricsTable); + } + + QueryMetric queryMetric = (QueryMetric) queryMetricsTable.get(key); + + if (queryMetric == null) { + queryMetric = new QueryMetric(queryId); + + queryMetricsTable.put(key, queryMetric); + } + + return queryMetric; + } + } + + // Sent Queries + + + public void querySentInGroup(ResolverQueryMsg query) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + getQueryMetric(query.getQueryId()); // register the query + + deltaMetrics.querySentInGroup(); + cumulativeMetrics.querySentInGroup(); + } + + public void querySentViaWalker(ResolverQueryMsg query) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + getQueryMetric(query.getQueryId()); // register the query + + deltaMetrics.querySentViaWalker(); + cumulativeMetrics.querySentViaWalker(); + } + + public void querySentViaUnicast(String peer, ResolverQueryMsg query) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + getQueryMetric(query.getQueryId()); // register the query + + deltaMetrics.querySentViaUnicast(peer); + cumulativeMetrics.querySentViaUnicast(peer); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(peer); + + destinationMeter.querySentViaUnicast(); + } + + public void querySendError() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.querySendError(); + cumulativeMetrics.querySendError(); + } + + public void queryPropagateError() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryPropagateError(); + cumulativeMetrics.queryPropagateError(); + } + + public void queryHopCountDropped() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryHopCountDropped(); + cumulativeMetrics.queryHopCountDropped(); + } + + public void unableToPropagate() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.unableToPropagate(); + cumulativeMetrics.unableToPropagate(); + } + + // Propagate Query + + public void queryPropagatedInGroup() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryPropagatedInGroup(); + cumulativeMetrics.queryPropagatedInGroup(); + } + + public void queryPropagatedViaWalker() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryPropagatedViaWalker(); + cumulativeMetrics.queryPropagatedViaWalker(); + } + + public void propagationQueryDropped() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.propagationQueryDropped(); + cumulativeMetrics.propagationQueryDropped(); + } + + // Sent Responses + + public void responseSentViaUnicast(String peer, ResolverResponseMsg response) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseSentViaUnicast(); + cumulativeMetrics.responseSentViaUnicast(); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(peer); + + destinationMeter.responseSentViaUnicast(); + } + + public void responseSentViaWalker(ResolverResponseMsg response) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseSentViaWalker(); + cumulativeMetrics.responseSentViaWalker(); + } + + public void responseSentInGroup(ResolverResponseMsg response) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseSentInGroup(); + cumulativeMetrics.responseSentInGroup(); + } + + public void responseSendError() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseSendError(); + cumulativeMetrics.responseSendError(); + } + + public void responsePropagateError() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responsePropagateError(); + cumulativeMetrics.responsePropagateError(); + } + + // Received Responses + + public void responseProcessed(ResolverResponseMsg response, long processTime, EndpointAddress srcAddr) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + QueryMetric queryMetric = getQueryMetric(response.getQueryId()); + long now = System.currentTimeMillis(); + long responseTime = now - queryMetric.querySentTime; + + queryMetric.lastResponseTime = now; + queryMetric.numResponsesReceived++; + + deltaMetrics.responseProcessed(responseTime, processTime); + cumulativeMetrics.responseProcessed(responseTime, processTime); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(srcAddr); + + destinationMeter.responseProcessed(); + } + + public void responseToUnregisteredHandler(EndpointAddress src) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.responseToUnregisteredHandler(); + cumulativeMetrics.responseToUnregisteredHandler(); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(src); + + destinationMeter.responseToUnregisteredHandler(); + } + + public void errorWhileProcessingResponse(EndpointAddress srcAddr) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorWhileProcessingResponse(); + cumulativeMetrics.errorWhileProcessingResponse(); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(srcAddr); + + destinationMeter.errorWhileProcessingResponse(); + } + + // Received Queries + + public void queryProcessed(ResolverQueryMsg query, int result, long processTime) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryProcessed(result, processTime); + cumulativeMetrics.queryProcessed(result, processTime); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(query.getSrc()); + + destinationMeter.queryProcessed(); + } + + public void queryToUnregisteredHandler(ResolverQueryMsg query) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.queryToUnregisteredHandler(); + cumulativeMetrics.queryToUnregisteredHandler(); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(query.getSrc()); + + destinationMeter.queryToUnregisteredHandler(); + } + + public void errorWhileProcessingQuery(ResolverQueryMsg query) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorWhileProcessingQuery(); + cumulativeMetrics.errorWhileProcessingQuery(); + + QueryDestinationMeter destinationMeter = getQueryDestinationMeter(query.getSrc()); + + destinationMeter.errorWhileProcessingQuery(); + } + + public Enumeration getQueryDestinationMeters() { + return queryDestinationMeters.elements(); + } + + public int getQueryDestinationCount() { + return queryDestinationMeters.size(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryHandlerMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryHandlerMetric.java new file mode 100644 index 000000000..e9eac4bf2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/QueryHandlerMetric.java @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.resolver.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.endpoint.*; +import net.jxta.exception.*; +import net.jxta.peer.*; +import net.jxta.util.*; +import java.util.*; + + +/** + * Metrics for a Registered handler Name + **/ +public class QueryHandlerMetric implements DocumentSerializable { + public static final String REGISTERED = "registered"; + public static final String UNREGISTERED = "unregistered"; + + private String handlerName; + private String registered; + + private int numResponses = 0; + private long responseProcessingTime = 0; + private long responseTime = 0; + private int numResponseErrors = 0; + + private int numQueries = 0; + private int numQueriesRepropagated = 0; + private long queryProcessingTime = 0; + private int numQueryErrors = 0; + + private int numQueriesSentInGroup = 0; + private int numQueriesSentViaWalker = 0; + private int numQueriesSentViaUnicast = 0; + private int numErrorsSendingQueries = 0; + private int numErrorsPropagatingQueries = 0; + private int numQueriesHopCountDropped = 0; + + private int numPropagationQueriesDropped = 0; + private int numPropagatedInGroup = 0; + private int numPropagatedViaWalker = 0; + private int numUnableToPropagate = 0; + + private int numResponsesToUnregisteredHandler = 0; + private int numQueriesToUnregisteredHandler = 0; + + private int numResponsesSentInGroup = 0; + private int numResponsesSentViaWalker = 0; + private int numResponsesSentViaUnicast = 0; + private int numErrorsSendingResponses = 0; + private int numErrorsPropagatingResponses = 0; + + private HashMap destinationMetrics = new HashMap(); + + public QueryHandlerMetric(String handlerName) { + this.handlerName = handlerName; + } + + public QueryHandlerMetric() {} + + public QueryHandlerMetric(QueryHandlerMetric prototype) { + this.handlerName = prototype.handlerName; + } + + void responseProcessed(long responseTime, long processingTime) { + numResponses++; + responseTime += responseTime; + responseProcessingTime += processingTime; + } + + void responseToUnregisteredHandler() { + numResponsesToUnregisteredHandler++; + } + + void errorWhileProcessingResponse() { + numResponseErrors++; + } + + void queryProcessed(int result, long processingTime) { + numQueries++; + + if (result == ResolverService.Repropagate) { + numQueriesRepropagated++; + } + + queryProcessingTime += processingTime; + } + + void queryToUnregisteredHandler() { + numQueriesToUnregisteredHandler++; + } + + void errorWhileProcessingQuery() { + numQueryErrors++; + } + + void querySentInGroup() { + numQueriesSentInGroup++; + } + + void querySentViaWalker() { + numQueriesSentViaWalker++; + } + + void querySentViaUnicast(String peer) { + numQueriesSentViaUnicast++; + } + + void querySendError() { + numErrorsSendingQueries++; + } + + void queryPropagateError() { + numErrorsPropagatingQueries++; + } + + void queryHopCountDropped() { + numQueriesHopCountDropped++; + } + + void responseSentInGroup() { + numResponsesSentInGroup++; + } + + void responseSentViaWalker() { + numResponsesSentViaWalker++; + } + + void responseSentViaUnicast() { + numResponsesSentViaUnicast++; + } + + void responseSendError() { + numErrorsSendingResponses++; + } + + void responsePropagateError() { + numErrorsPropagatingResponses++; + } + + void propagationQueryDropped() { + numPropagationQueriesDropped++; + } + + void queryPropagatedInGroup() { + numPropagatedInGroup++; + } + + void queryPropagatedViaWalker() { + numPropagatedViaWalker++; + } + + void unableToPropagate() { + numUnableToPropagate++; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof QueryHandlerMetric) { + QueryHandlerMetric otherQueryHandlerMetric = (QueryHandlerMetric) obj; + + return handlerName.equals((otherQueryHandlerMetric.handlerName)); + } else { + return false; + } + } + + @Override + public int hashCode() { + return handlerName.hashCode(); + } + + void setRegistered(boolean isRegistered) { + this.registered = isRegistered ? REGISTERED : UNREGISTERED; + } + + /** Get Handler Name for this Metric **/ + public String getHandlerName() { + return handlerName; + } + + /** Get State of Handler currently + * @return REGISTERED or UNREGISTERED + **/ + public String getRegistered() { + return (registered != null) ? registered : UNREGISTERED; + } + + /** The number of responses received by this Handler **/ + public int getNumResponses() { + return numResponses; + } + + /** The total clock time to process all responses received by this Handler **/ + public long getResponseProcessingTime() { + return responseProcessingTime; + } + + /** The average clock time to process responses received by this Handler **/ + public long getAverageResponseProcessingTime() { + return (numResponses == 0) ? 0 : (responseProcessingTime / numResponses); + } + + /** The total time to receive all responses to queries sent by this Handler **/ + public long getResponseTime() { + return responseTime; + } + + /** The average time to receive responses to queries sent by this Handler **/ + public long getAverageResponseTime() { + return (numResponses == 0) ? 0 : (responseTime / numResponses); + } + + /** Number of local errors while processing received responses **/ + public int getNumResponseErrors() { + return numResponseErrors; + } + + /** The number of queries received by this Handler **/ + public int getNumQueries() { + return numQueries; + } + + /** The number of queries received and repropagated by this Handler **/ + public int getNumQueriesRepropagated() { + return numQueriesRepropagated; + } + + /** The total clock time to process all Queries received by this Handler **/ + public long getQueryProcessingTime() { + return queryProcessingTime; + } + + /** The average clock time to process Queries received by this Handler **/ + public long getAverageQueryProcessingTime() { + return (numQueries == 0) ? 0 : (queryProcessingTime / numQueries); + } + + /** Number of local errors while processing received Queries **/ + public int getNumQueryErrors() { + return numQueryErrors; + } + + /** Number of Queries sent in Group ***/ + public int getNumQueriesSentInGroup() { + return numQueriesSentInGroup; + } + + /** Number of Queries sent via Walker ***/ + public int getNumQueriesSentViaWalker() { + return numQueriesSentViaWalker; + } + + /** Number of Queries sent via Unicast ***/ + public int getNumQueriesSentViaUnicast() { + return numQueriesSentViaUnicast; + } + + /** Number of Errors while sending Queries ***/ + public int getNumErrorsSendingQueries() { + return numErrorsSendingQueries; + } + + /** Number of Errors while propagating Queries ***/ + public int getNumErrorsPropagatingQueries() { + return numErrorsPropagatingQueries; + } + + /** Number of Responses sent in Group ***/ + public int getNumResponsesSentInGroup() { + return numResponsesSentInGroup; + } + + /** Number of Responses sent via Walker ***/ + public int getNumResponsesSentViaWalker() { + return numResponsesSentViaWalker; + } + + /** Number of Responses sent via Unicast ***/ + public int getNumResponsesSentViaUnicast() { + return numResponsesSentViaUnicast; + } + + /** Number of Errors while sending Responses ***/ + public int getNumErrorsSendingResponses() { + return numErrorsSendingResponses; + } + + /** Number of Errors while propagating Responses ***/ + public int getNumErrorsPropagatingResponses() { + return numErrorsPropagatingResponses; + } + + public int getNumQueriesSent() { + return (numQueriesSentInGroup + numQueriesSentViaWalker + numQueriesSentViaUnicast); + } + + public int getNumQuerySendErrors() { + return (numErrorsSendingQueries + numErrorsPropagatingQueries); + } + + public int getNumResponsesSent() { + return (numResponsesSentInGroup + numResponsesSentViaWalker + numResponsesSentViaUnicast); + } + + public int getNumResponseSendErrors() { + return (numErrorsSendingResponses + numErrorsPropagatingResponses); + } + + public void addQueryDestinationMetric(QueryDestinationMetric queryDestinationMetric) { + destinationMetrics.put(queryDestinationMetric.getPeerID(), queryDestinationMetric); + } + + public QueryDestinationMetric getQueryDestinationMetric(PeerID peerID) { + QueryDestinationMetric destinationMetric = (QueryDestinationMetric) destinationMetrics.get(peerID); + + if (destinationMetric == null) { + destinationMetric = new QueryDestinationMetric(peerID); + destinationMetrics.put(peerID, destinationMetric); + } + return destinationMetric; + } + + public Iterator getDestinationMetrics() { + + return destinationMetrics.values().iterator(); + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (handlerName != null) { + DocumentSerializableUtilities.addString(element, "handlerName", handlerName); + } + if (registered != null) { + DocumentSerializableUtilities.addString(element, "registered", registered); + } + if (numResponses != 0) { + DocumentSerializableUtilities.addInt(element, "numResponses", numResponses); + } + if (responseProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "responseProcessingTime", responseProcessingTime); + } + if (responseTime != 0) { + DocumentSerializableUtilities.addLong(element, "responseTime", responseTime); + } + if (numResponseErrors != 0) { + DocumentSerializableUtilities.addInt(element, "numResponseErrors", numResponseErrors); + } + if (numQueries != 0) { + DocumentSerializableUtilities.addInt(element, "numQueries", numQueries); + } + if (numQueriesRepropagated != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesRepropagated", numQueriesRepropagated); + } + if (queryProcessingTime != 0) { + DocumentSerializableUtilities.addLong(element, "queryProcessingTime", queryProcessingTime); + } + if (numQueryErrors != 0) { + DocumentSerializableUtilities.addInt(element, "numQueryErrors", numQueryErrors); + } + if (numQueriesSentInGroup != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesSentInGroup", numQueriesSentInGroup); + } + if (numQueriesSentViaWalker != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesSentViaWalker", numQueriesSentViaWalker); + } + if (numQueriesSentViaUnicast != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesSentViaUnicast", numQueriesSentViaUnicast); + } + if (numErrorsSendingQueries != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsSendingQueries", numErrorsSendingQueries); + } + if (numErrorsPropagatingQueries != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsPropagatingQueries", numErrorsPropagatingQueries); + } + if (numQueriesHopCountDropped != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesHopCountDropped", numQueriesHopCountDropped); + } + if (numPropagationQueriesDropped != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagationQueriesDropped", numPropagationQueriesDropped); + } + if (numPropagatedInGroup != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagatedInGroup", numPropagatedInGroup); + } + if (numPropagatedViaWalker != 0) { + DocumentSerializableUtilities.addInt(element, "numPropagatedViaWalker", numPropagatedViaWalker); + } + if (numUnableToPropagate != 0) { + DocumentSerializableUtilities.addInt(element, "numUnableToPropagate", numUnableToPropagate); + } + if (numResponsesToUnregisteredHandler != 0) { + DocumentSerializableUtilities.addInt(element, "numResponsesToUnregisteredHandler", numResponsesToUnregisteredHandler); + } + if (numQueriesToUnregisteredHandler != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesToUnregisteredHandler", numQueriesToUnregisteredHandler); + } + if (numResponsesSentInGroup != 0) { + DocumentSerializableUtilities.addInt(element, "numResponsesSentInGroup", numResponsesSentInGroup); + } + if (numResponsesSentViaWalker != 0) { + DocumentSerializableUtilities.addInt(element, "numResponsesSentViaWalker", numResponsesSentViaWalker); + } + if (numResponsesSentViaUnicast != 0) { + DocumentSerializableUtilities.addInt(element, "numResponsesSentViaUnicast", numResponsesSentViaUnicast); + } + if (numErrorsSendingResponses != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsSendingResponses", numErrorsSendingResponses); + } + if (numErrorsPropagatingResponses != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsPropagatingResponses", numErrorsPropagatingResponses); + } + + for (Iterator i = destinationMetrics.values().iterator(); i.hasNext();) { + Element queryDestinationElement = DocumentSerializableUtilities.createChildElement(element, "destination"); + QueryDestinationMetric queryDestinationMetric = (QueryDestinationMetric) i.next(); + + queryDestinationMetric.serializeTo(queryDestinationElement); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("handlerName")) { + handlerName = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("registered")) { + registered = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("numResponses")) { + numResponses = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("responseProcessingTime")) { + responseProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("responseTime")) { + responseTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numResponseErrors")) { + numResponseErrors = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueries")) { + numQueries = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesRepropagated")) { + numQueriesRepropagated = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("queryProcessingTime")) { + queryProcessingTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numQueryErrors")) { + numQueryErrors = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesSentInGroup")) { + numQueriesSentInGroup = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesSentViaWalker")) { + numQueriesSentViaWalker = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesSentViaUnicast")) { + numQueriesSentViaUnicast = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsSendingQueries")) { + numErrorsSendingQueries = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsPropagatingQueries")) { + numErrorsPropagatingQueries = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesHopCountDropped")) { + numQueriesHopCountDropped = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagationQueriesDropped")) { + numPropagationQueriesDropped = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagatedInGroup")) { + numPropagatedInGroup = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numPropagatedViaWalker")) { + numPropagatedViaWalker = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numUnableToPropagate")) { + numUnableToPropagate = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numResponsesToUnregisteredHandler")) { + numResponsesToUnregisteredHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesToUnregisteredHandler")) { + numQueriesToUnregisteredHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numResponsesSentInGroup")) { + numResponsesSentInGroup = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numResponsesSentViaWalker")) { + numResponsesSentViaWalker = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numResponsesSentViaUnicast")) { + numResponsesSentViaUnicast = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsSendingResponses")) { + numErrorsSendingResponses = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsPropagatingResponses")) { + numErrorsPropagatingResponses = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("destination")) { + QueryDestinationMetric queryDestinationMetric = new QueryDestinationMetric(); + + queryDestinationMetric.initializeFrom(childElement); + addQueryDestinationMetric(queryDestinationMetric); + } + } + } + + public void mergeMetrics(QueryHandlerMetric otherQueryHandlerMetric) { + this.numResponses += otherQueryHandlerMetric.numResponses; + this.responseProcessingTime += otherQueryHandlerMetric.responseProcessingTime; + this.responseTime += otherQueryHandlerMetric.responseTime; + this.numResponseErrors += otherQueryHandlerMetric.numResponseErrors; + + this.numQueries += otherQueryHandlerMetric.numQueries; + this.numQueriesRepropagated += otherQueryHandlerMetric.numQueriesRepropagated; + this.queryProcessingTime += otherQueryHandlerMetric.queryProcessingTime; + this.numQueryErrors += otherQueryHandlerMetric.numQueryErrors; + + this.numQueriesSentInGroup += otherQueryHandlerMetric.numQueriesSentInGroup; + this.numQueriesSentViaWalker += otherQueryHandlerMetric.numQueriesSentViaWalker; + this.numQueriesSentViaUnicast += otherQueryHandlerMetric.numQueriesSentViaUnicast; + this.numErrorsSendingQueries += otherQueryHandlerMetric.numErrorsSendingQueries; + this.numErrorsPropagatingQueries += otherQueryHandlerMetric.numErrorsPropagatingQueries; + this.numQueriesHopCountDropped += otherQueryHandlerMetric.numQueriesHopCountDropped; + + this.numResponsesSentInGroup += otherQueryHandlerMetric.numResponsesSentInGroup; + this.numResponsesSentViaWalker += otherQueryHandlerMetric.numResponsesSentViaWalker; + this.numResponsesSentViaUnicast += otherQueryHandlerMetric.numResponsesSentViaUnicast; + this.numErrorsSendingResponses += otherQueryHandlerMetric.numErrorsSendingResponses; + this.numErrorsPropagatingResponses += otherQueryHandlerMetric.numErrorsPropagatingResponses; + + for (Iterator i = otherQueryHandlerMetric.getDestinationMetrics(); i.hasNext();) { + QueryDestinationMetric otherQueryDestinationMetric = (QueryDestinationMetric) i.next(); + QueryDestinationMetric ourQueryDestinationMetric = getQueryDestinationMetric(otherQueryDestinationMetric.getPeerID()); + + if (ourQueryDestinationMetric == null) { + ourQueryDestinationMetric = new QueryDestinationMetric(otherQueryDestinationMetric); + addQueryDestinationMetric(ourQueryDestinationMetric); + } + + ourQueryDestinationMetric.mergeMetrics(otherQueryDestinationMetric); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMeter.java new file mode 100644 index 000000000..a52885521 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMeter.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.peer.*; +import net.jxta.peergroup.*; +import net.jxta.resolver.*; +import net.jxta.impl.resolver.*; +import net.jxta.protocol.*; +import net.jxta.endpoint.*; + +import java.net.*; +import java.util.*; + + +public class ResolverMeter { + private ResolverServiceMonitor resolverServiceMonitor; + private ResolverMetric cumulativeMetrics; + private ResolverMetric deltaMetrics; + + public ResolverMeter(ResolverServiceMonitor resolverServiceMonitor) { + this.resolverServiceMonitor = resolverServiceMonitor; + cumulativeMetrics = new ResolverMetric(); + } + + public ResolverMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public synchronized ResolverMetric collectMetrics() { + ResolverMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + return prevDelta; + } + + private void createDeltaMetric() { + deltaMetrics = new ResolverMetric(); + } + + @Override + public String toString() { + return "ResolverMeter"; + } + + public void invalidSrdiMessageDiscarded(EndpointAddress src) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.invalidSrdiMessageDiscarded(); + cumulativeMetrics.invalidSrdiMessageDiscarded(); + } + + public void unknownHandlerForSrdiMessage(EndpointAddress src, String handlerName) { + if (handlerName != null) { + SrdiHandlerMeter srdiHandlerMeter = resolverServiceMonitor.getSrdiHandlerMeter(handlerName); + + srdiHandlerMeter.srdiToUnregisteredHandler(src); + } else { + invalidSrdiDiscarded(); + } + } + + public void invalidSrdiDiscarded() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.invalidResponseDiscarded(); + cumulativeMetrics.invalidResponseDiscarded(); + } + + public void invalidResponseDiscarded(EndpointAddress src) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.invalidResponseDiscarded(); + cumulativeMetrics.invalidResponseDiscarded(); + } + + public void unknownHandlerForResponse(EndpointAddress src, ResolverResponseMsg resp) { + String handlerName = resp.getHandlerName(); + + if (handlerName != null) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + + queryHandlerMeter.responseToUnregisteredHandler(src); + } else { + invalidResponseDiscarded(src); + } + } + + public void invalidQueryDiscarded(EndpointAddress src) { + invalidQueryDiscarded(); // We aren't tracking on source at this point (or ever?) + } + + public void invalidQueryDiscarded() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.invalidQueryDiscarded(); + cumulativeMetrics.invalidQueryDiscarded(); + } + + public void unknownHandlerForQuery(ResolverQueryMsg query) { + String handlerName = query.getHandlerName(); + + if (handlerName != null) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + + queryHandlerMeter.queryToUnregisteredHandler(query); + } else { + invalidQueryDiscarded(); + } + } + + public void queryPropagatedInGroup(ResolverQueryMsg query) { + String handlerName = query.getHandlerName(); + + if (handlerName != null) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + + queryHandlerMeter.queryPropagatedInGroup(); + } else { + invalidQueryDiscarded(); + } + } + + public void queryPropagatedViaWalker(ResolverQueryMsg query) { + String handlerName = query.getHandlerName(); + + if (handlerName != null) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + + queryHandlerMeter.queryPropagatedViaWalker(); + } else { + invalidQueryDiscarded(); + } + } + + public void propagationQueryDropped(ResolverQueryMsg query) { + String handlerName = query.getHandlerName(); + + if (handlerName != null) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + + queryHandlerMeter.propagationQueryDropped(); + } else { + invalidQueryDiscarded(); + } + } + + public void queryPropagationError(ResolverQueryMsg query) { + String handlerName = query.getHandlerName(); + + if (handlerName != null) { + QueryHandlerMeter queryHandlerMeter = resolverServiceMonitor.getQueryHandlerMeter(handlerName); + + queryHandlerMeter.unableToPropagate(); + } else { + invalidQueryDiscarded(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMeterBuildSettings.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMeterBuildSettings.java new file mode 100644 index 000000000..a6d7b1250 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMeterBuildSettings.java @@ -0,0 +1,67 @@ +/* + * The Sun Project JXTA(TM) Software License + * + * Copyright (c) 2001-2006 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at https://jxta.dev.java.net. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * https://jxta.dev.java.net/ + * + * This license is based on the BSD license adopted by the Apache Foundation. + * + */ + + +/* **** THIS IS A GENERATED FILE. DO NOT EDIT. **** */ + +package net.jxta.impl.resolver.resolverMeter; + +import net.jxta.impl.meter.*; + +public interface ResolverMeterBuildSettings extends MeterBuildSettings { + public static final boolean RESOLVER_METERING = ConditionalResolverMeterBuildSettings.isRuntimeMetering(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMetric.java new file mode 100644 index 000000000..ae75b1de5 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverMetric.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.resolver.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; + +import java.util.*; + + +/** + * The general Metric for this resolver + **/ +public class ResolverMetric implements DocumentSerializable { + private int numInvalidSrdiMessages = 0; + private int numSrdiMessagesToUnknownHandler = 0; + + private int numInvalidResponses = 0; + private int numResponsesToUnknownHandler = 0; + + private int numInvalidQueries = 0; + private int numQueriesToUnknownHandler = 0; + + public ResolverMetric() {} + + public ResolverMetric(ResolverMetric prototype) {} + + /** Number of invalid Srdi Messages received */ + public int getNumInvalidSrdiMessages() { + return numInvalidSrdiMessages; + } + + /** Number of Srdi Messages received for unknown handlers */ + public int getNumSrdiMessagesToUnknownHandler() { + return numSrdiMessagesToUnknownHandler; + } + + /** Number of invalid Query Response Messages received */ + public int getNumInvalidResponses() { + return numInvalidResponses; + } + + /** Number of Response Messages to unknown handlers received */ + public int getNumResponsesToUnknownHandler() { + return numResponsesToUnknownHandler; + } + + /** Number of invalid Query Messages received */ + public int getNumInvalidQueries() { + return numInvalidQueries; + } + + /** Number of Query Messages to unknown handlers received */ + public int getNumQueriesToUnknownHandler() { + return numQueriesToUnknownHandler; + } + + void invalidSrdiMessageDiscarded() { + numInvalidSrdiMessages++; + } + + void unknownHandlerForSrdiMessage() { + numSrdiMessagesToUnknownHandler++; + } + + void invalidResponseDiscarded() { + numInvalidResponses++; + } + + void unknownHandlerForResponse() { + numResponsesToUnknownHandler++; + } + + void invalidQueryDiscarded() { + numInvalidQueries++; + } + + void unknownHandlerForQuery() { + numQueriesToUnknownHandler++; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (numInvalidSrdiMessages != 0) { + DocumentSerializableUtilities.addInt(element, "numInvalidSrdiMessages", numInvalidSrdiMessages); + } + if (numSrdiMessagesToUnknownHandler != 0) { + DocumentSerializableUtilities.addInt(element, "numSrdiMessagesToUnknownHandler", numSrdiMessagesToUnknownHandler); + } + if (numInvalidResponses != 0) { + DocumentSerializableUtilities.addInt(element, "numInvalidResponses", numInvalidResponses); + } + if (numResponsesToUnknownHandler != 0) { + DocumentSerializableUtilities.addInt(element, "numResponsesToUnknownHandler", numResponsesToUnknownHandler); + } + if (numInvalidQueries != 0) { + DocumentSerializableUtilities.addInt(element, "numInvalidQueries", numInvalidQueries); + } + if (numQueriesToUnknownHandler != 0) { + DocumentSerializableUtilities.addInt(element, "numQueriesToUnknownHandler", numQueriesToUnknownHandler); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("numInvalidSrdiMessages")) { + numInvalidSrdiMessages = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numSrdiMessagesToUnknownHandler")) { + numSrdiMessagesToUnknownHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numInvalidResponses")) { + numInvalidResponses = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numResponsesToUnknownHandler")) { + numResponsesToUnknownHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numInvalidQueries")) { + numInvalidQueries = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numQueriesToUnknownHandler")) { + numQueriesToUnknownHandler = DocumentSerializableUtilities.getInt(childElement); + } + } + } + + public void mergeMetrics(ResolverMetric otherResolverMetric) { + if (otherResolverMetric == null) { + return; + } + this.numInvalidSrdiMessages += otherResolverMetric.numInvalidSrdiMessages; + this.numSrdiMessagesToUnknownHandler += otherResolverMetric.numSrdiMessagesToUnknownHandler; + + this.numInvalidResponses += otherResolverMetric.numInvalidResponses; + this.numResponsesToUnknownHandler += otherResolverMetric.numResponsesToUnknownHandler; + + this.numInvalidQueries += otherResolverMetric.numInvalidQueries; + this.numQueriesToUnknownHandler += otherResolverMetric.numQueriesToUnknownHandler; + + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMetric.java new file mode 100644 index 000000000..f455fc8e3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMetric.java @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.meter.*; + +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.platform.*; +import net.jxta.id.*; +import java.util.*; +import net.jxta.util.*; +import net.jxta.exception.*; +import java.net.*; + + +/** + * The Service Monitor Metric for the standard Resolver Service + **/ +public class ResolverServiceMetric implements ServiceMetric { + private ResolverMetric resolverMetric; + private LinkedList queryHandlerMetrics = new LinkedList(); + private LinkedList srdiHandlerMetrics = new LinkedList(); + private ModuleClassID moduleClassID = MonitorResources.resolverServiceMonitorClassID; + + public ResolverServiceMetric() {} + + public ResolverServiceMetric(ModuleClassID moduleClassID) { + init(moduleClassID); + } + + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + /** + * Get the General Resolver Metric + **/ + public ResolverMetric getResolverMetric() { + return resolverMetric; + } + + void setResolverMetric(ResolverMetric resolverMetric) { + this.resolverMetric = resolverMetric; + } + + /** + * Add a Query Handler Metric + **/ + public void addQueryHandlerMetric(QueryHandlerMetric queryHandlerMetric) { + queryHandlerMetrics.add(queryHandlerMetric); + } + + /** + * Get All Query Handler Metrics as an iterator + **/ + public Iterator getQueryHandlerMetrics() { + return queryHandlerMetrics.iterator(); + } + + /** + * Get Query Handler Metrics for the corresponding handler + * @return Handler or null if not found + **/ + public QueryHandlerMetric getQueryHandlerMetric(String handlerName) { + for (Iterator i = queryHandlerMetrics.iterator(); i.hasNext();) { + QueryHandlerMetric queryHandlerMetric = (QueryHandlerMetric) i.next(); + + if (handlerName.equals(queryHandlerMetric.getHandlerName())) { + return queryHandlerMetric; + } + } + + return null; + } + + /** + * Add a Srdi Handler Metric + **/ + public void addSrdiHandlerMetric(SrdiHandlerMetric srdiHandlerMetric) { + srdiHandlerMetrics.add(srdiHandlerMetric); + } + + /** + * Get All Srdi Handler Metrics as an iterator + **/ + public Iterator getSrdiHandlerMetrics() { + return srdiHandlerMetrics.iterator(); + } + + /** + * Get Srdi Handler Metrics for the corresponding handler + * @return Handler or null if not found + **/ + public SrdiHandlerMetric getSrdiHandlerMetric(String handlerName) { + for (Iterator i = srdiHandlerMetrics.iterator(); i.hasNext();) { + SrdiHandlerMetric srdiHandlerMetric = (SrdiHandlerMetric) i.next(); + + if (handlerName.equals(srdiHandlerMetric.getHandlerName())) { + return srdiHandlerMetric; + } + } + + return null; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + + for (Iterator i = queryHandlerMetrics.iterator(); i.hasNext();) { + QueryHandlerMetric queryHandlerMetric = (QueryHandlerMetric) i.next(); + + DocumentSerializableUtilities.addDocumentSerializable(element, "queryHandlerMetric", queryHandlerMetric); + } + + for (Iterator i = srdiHandlerMetrics.iterator(); i.hasNext();) { + SrdiHandlerMetric srdiHandlerMetric = (SrdiHandlerMetric) i.next(); + + DocumentSerializableUtilities.addDocumentSerializable(element, "srdiHandlerMetric", srdiHandlerMetric); + } + + if (resolverMetric != null) { + DocumentSerializableUtilities.addDocumentSerializable(element, "resolverMetric", resolverMetric); + } + + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("queryHandlerMetric")) { + QueryHandlerMetric queryHandlerMetric = (QueryHandlerMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, QueryHandlerMetric.class); + + queryHandlerMetrics.add(queryHandlerMetric); + } + + if (tagName.equals("srdiHandlerMetric")) { + SrdiHandlerMetric srdiHandlerMetric = (SrdiHandlerMetric) DocumentSerializableUtilities.getDocumentSerializable( + childElement, SrdiHandlerMetric.class); + + srdiHandlerMetrics.add(srdiHandlerMetric); + } + + if (tagName.equals("resolverMetric")) { + resolverMetric = (ResolverMetric) DocumentSerializableUtilities.getDocumentSerializable(childElement + , + ResolverMetric.class); + } + if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't read moduleClassID", jex); + } + } + } + } + + public void mergeMetrics(ServiceMetric otherOne) { + mergeMetrics(otherOne, true, true, true); + } + + /** + * Make a deep copy of this metric only including the portions designated in the Filter + * The resulting metric is Safe to modify without danger to the underlying Monitor Metrics + * @param resolverServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + **/ + public ResolverServiceMetric deepCopy(ResolverServiceMonitorFilter resolverServiceMonitorFilter) { + ResolverServiceMetric serviceMetric = new ResolverServiceMetric(); + + serviceMetric.moduleClassID = moduleClassID; + + serviceMetric.mergeMetrics(this, true, resolverServiceMonitorFilter.isIncludeQueryHandlerMetrics() + , + resolverServiceMonitorFilter.isIncludeSrdiHandlerMetrics()); + return serviceMetric; + } + + public void mergeMetrics(ServiceMetric otherOne, boolean includeResolverMetric, boolean includeQueryHandlerMetrics, boolean includeSrdiHandlerMetrics) { + ResolverServiceMetric otherResolverServiceMetric = (ResolverServiceMetric) otherOne; + + if (includeResolverMetric) { + ResolverMetric otherResolverMetric = otherResolverServiceMetric.getResolverMetric(); + + if ((resolverMetric == null) && (otherResolverMetric != null)) { + resolverMetric = new ResolverMetric(otherResolverMetric); + } + + if (otherResolverMetric != null) { + resolverMetric.mergeMetrics(otherResolverMetric); + } + } + + if (includeQueryHandlerMetrics) { + for (Iterator i = otherResolverServiceMetric.getQueryHandlerMetrics(); i.hasNext();) { + QueryHandlerMetric otherQueryHandlerMetric = (QueryHandlerMetric) i.next(); + QueryHandlerMetric queryHandlerMetric = getQueryHandlerMetric(otherQueryHandlerMetric.getHandlerName()); + + if (queryHandlerMetric == null) { + queryHandlerMetric = new QueryHandlerMetric(otherQueryHandlerMetric); + addQueryHandlerMetric(queryHandlerMetric); + } + + queryHandlerMetric.mergeMetrics(otherQueryHandlerMetric); + } + } + + if (includeSrdiHandlerMetrics) { + for (Iterator i = otherResolverServiceMetric.getSrdiHandlerMetrics(); i.hasNext();) { + SrdiHandlerMetric otherSrdiHandlerMetric = (SrdiHandlerMetric) i.next(); + SrdiHandlerMetric srdiHandlerMetric = getSrdiHandlerMetric(otherSrdiHandlerMetric.getHandlerName()); + + if (srdiHandlerMetric == null) { + srdiHandlerMetric = new SrdiHandlerMetric(otherSrdiHandlerMetric); + addSrdiHandlerMetric(srdiHandlerMetric); + } + + srdiHandlerMetric.mergeMetrics(otherSrdiHandlerMetric); + } + } + } + + /** + * Make a shallow copy of this metric only including the portions designated in the Filter + *

            Note: since this is a shallow copy it is dangerous to modify the submetrics + * @param resolverServiceMonitorFilter Filter designates constituant parts to be included + * @return a copy of this metric with references to the designated parts + **/ + public ResolverServiceMetric shallowCopy(ResolverServiceMonitorFilter resolverServiceMonitorFilter) { + ResolverServiceMetric resolverServiceMetric = new ResolverServiceMetric(moduleClassID); + + resolverServiceMetric.resolverMetric = resolverMetric; + + if (resolverServiceMonitorFilter.isIncludeQueryHandlerMetrics()) { + for (Iterator i = getQueryHandlerMetrics(); i.hasNext();) { + QueryHandlerMetric queryHandlerMetric = (QueryHandlerMetric) i.next(); + + resolverServiceMetric.addQueryHandlerMetric(queryHandlerMetric); + } + } + + if (resolverServiceMonitorFilter.isIncludeSrdiHandlerMetrics()) { + for (Iterator i = getSrdiHandlerMetrics(); i.hasNext();) { + SrdiHandlerMetric srdiHandlerMetric = (SrdiHandlerMetric) i.next(); + + resolverServiceMetric.addSrdiHandlerMetric(srdiHandlerMetric); + } + } + + return resolverServiceMetric; + } + + public void diffMetrics(ServiceMetric otherOne) { + throw new RuntimeException("Not Supported"); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMonitor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMonitor.java new file mode 100644 index 000000000..19530b3b1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMonitor.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.meter.*; +import net.jxta.impl.meter.*; +import java.util.*; + + +/** + * The Service Monitor Metric for the standard Resolver Service + **/ +public class ResolverServiceMonitor extends GenericServiceMonitor { + public static final String UNKNOWN_HANDLER = "--UNKNOWN-HANDLER--"; + + private Hashtable queryHandlerMeters = new Hashtable(); + private Hashtable srdiHandlerMeters = new Hashtable(); + private Hashtable destinationMeters = new Hashtable(); + private Hashtable sourceMeters = new Hashtable(); + + private ResolverMeter resolverMeter = new ResolverMeter(this); + + private ResolverServiceMetric cumulativeResolverServiceMetric; + + @Override + protected void init() { + cumulativeResolverServiceMetric = (ResolverServiceMetric) getCumulativeServiceMetric(); + cumulativeResolverServiceMetric.setResolverMetric(resolverMeter.getCumulativeMetrics()); + } + + public ResolverMeter getResolverMeter() { + return resolverMeter; + } + + public synchronized QueryHandlerMeter registerQueryHandlerMeter(String handlerName) { + QueryHandlerMeter queryHandlerMeter = (QueryHandlerMeter) queryHandlerMeters.get(handlerName); + + if (queryHandlerMeter == null) { + queryHandlerMeter = addQueryHandlerMeter(handlerName, true); + } + + queryHandlerMeter.setRegistered(true); + + return queryHandlerMeter; + } + + public synchronized QueryHandlerMeter addQueryHandlerMeter(String handlerName, boolean registered) { + QueryHandlerMeter queryHandlerMeter = new QueryHandlerMeter(handlerName, this); + + queryHandlerMeters.put(handlerName, queryHandlerMeter); + cumulativeResolverServiceMetric.addQueryHandlerMetric(queryHandlerMeter.getCumulativeMetrics()); + queryHandlerMeter.setRegistered(registered); + + return queryHandlerMeter; + } + + public synchronized QueryHandlerMeter unregisterQueryHandlerMeter(String handlerName) { + QueryHandlerMeter queryHandlerMeter = getQueryHandlerMeter(handlerName); + + queryHandlerMeter.setRegistered(false); + + return queryHandlerMeter; + } + + public QueryHandlerMeter getQueryHandlerMeter(String handlerName) { + QueryHandlerMeter queryHandlerMeter = (QueryHandlerMeter) queryHandlerMeters.get(handlerName); + + if (queryHandlerMeter == null) { + queryHandlerMeter = addQueryHandlerMeter(handlerName, false); + } + + return queryHandlerMeter; + } + + public synchronized SrdiHandlerMeter registerSrdiHandlerMeter(String handlerName) { + SrdiHandlerMeter srdiHandlerMeter = (SrdiHandlerMeter) srdiHandlerMeters.get(handlerName); + + if (srdiHandlerMeter == null) { + srdiHandlerMeter = addSrdiHandlerMeter(handlerName, true); + } + + srdiHandlerMeter.setRegistered(true); + + return srdiHandlerMeter; + } + + public synchronized SrdiHandlerMeter addSrdiHandlerMeter(String handlerName, boolean registered) { + SrdiHandlerMeter srdiHandlerMeter = new SrdiHandlerMeter(handlerName); + + srdiHandlerMeters.put(handlerName, srdiHandlerMeter); + cumulativeResolverServiceMetric.addSrdiHandlerMetric(srdiHandlerMeter.getCumulativeMetrics()); + srdiHandlerMeter.setRegistered(registered); + + return srdiHandlerMeter; + } + + public synchronized SrdiHandlerMeter unregisterSrdiHandlerMeter(String handlerName) { + SrdiHandlerMeter srdiHandlerMeter = getSrdiHandlerMeter(handlerName); + + srdiHandlerMeter.setRegistered(false); + + return srdiHandlerMeter; + } + + public SrdiHandlerMeter getSrdiHandlerMeter(String handlerName) { + SrdiHandlerMeter srdiHandlerMeter = (SrdiHandlerMeter) srdiHandlerMeters.get(handlerName); + + if (srdiHandlerMeter == null) { + srdiHandlerMeter = addSrdiHandlerMeter(handlerName, false); + } + + return srdiHandlerMeter; + } + + @Override + protected ServiceMetric collectServiceMetrics() { + ResolverServiceMetric resolverServiceMetric = (ResolverServiceMetric) createServiceMetric(); + + boolean anyData = false; + + for (Enumeration e = queryHandlerMeters.elements(); e.hasMoreElements();) { + QueryHandlerMeter queryHandlerMeter = (QueryHandlerMeter) e.nextElement(); + QueryHandlerMetric queryHandlerMetric = queryHandlerMeter.collectMetrics(); // clears delta from meter + + if (queryHandlerMetric != null) { + resolverServiceMetric.addQueryHandlerMetric(queryHandlerMetric); + anyData = true; + } + } + + for (Enumeration e = srdiHandlerMeters.elements(); e.hasMoreElements();) { + SrdiHandlerMeter srdiHandlerMeter = (SrdiHandlerMeter) e.nextElement(); + SrdiHandlerMetric srdiHandlerMetric = srdiHandlerMeter.collectMetrics(); // clears delta from meter + + if (srdiHandlerMetric != null) { + resolverServiceMetric.addSrdiHandlerMetric(srdiHandlerMetric); + anyData = true; + } + } + + ResolverMetric resolverMetric = resolverMeter.collectMetrics(); + + if (resolverMetric != null) { + resolverServiceMetric.setResolverMetric(resolverMetric); + anyData = true; + } + + if (anyData) { + return resolverServiceMetric; + } else { + return null; + } + } + + @Override + public ServiceMetric getServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime, int pulseIndex, long reportRate) { + int deltaReportRateIndex = monitorManager.getReportRateIndex(reportRate); + ResolverServiceMetric origMetric = (ResolverServiceMetric) deltaServiceMetrics[deltaReportRateIndex]; + + if (origMetric == null) { + return null; + } + + ResolverServiceMonitorFilter resolverServiceMonitorFilter = (ResolverServiceMonitorFilter) serviceMonitorFilter; + + return origMetric.shallowCopy(resolverServiceMonitorFilter); + } + + @Override + public ServiceMetric getCumulativeServiceMetric(ServiceMonitorFilter serviceMonitorFilter, long fromTime, long toTime) { + ResolverServiceMonitorFilter resolverServiceMonitorFilter = (ResolverServiceMonitorFilter) serviceMonitorFilter; + ResolverServiceMetric origMetric = (ResolverServiceMetric) cumulativeServiceMetric; + + return origMetric.deepCopy(resolverServiceMonitorFilter); + } + + /* + private ResolverServiceMetric copy(ResolverServiceMetric origMetric) { + ResolverServiceMetric resolverServiceMetric = new ResolverServiceMetric(); + + for (Iterator i = origMetric.getQueryHandlerMetrics(); i.hasNext(); ) { + QueryHandlerMetric queryHandlerMetric = (QueryHandlerMetric)i.next(); + resolverServiceMetric.addQueryHandlerMetric(queryHandlerMetric); + } + + for (Iterator i = origMetric.getSrdiHandlerMetrics(); i.hasNext(); ) { + SrdiHandlerMetric srdiHandlerMetric = (SrdiHandlerMetric)i.next(); + resolverServiceMetric.addSrdiHandlerMetric(srdiHandlerMetric); + } + + return resolverServiceMetric; + } + */ +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMonitorFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMonitorFilter.java new file mode 100644 index 000000000..de4b98a16 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/ResolverServiceMonitorFilter.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.meter.*; +import net.jxta.platform.*; +import net.jxta.document.*; +import net.jxta.util.documentSerializable.*; +import java.util.*; +import net.jxta.util.*; +import net.jxta.exception.*; +import java.net.*; +import net.jxta.id.*; + + +public class ResolverServiceMonitorFilter implements ServiceMonitorFilter { + private boolean includeQueryHandlerMetrics = true; + private boolean includeSrdiHandlerMetrics = true; + private ModuleClassID moduleClassID = MonitorResources.resolverServiceMonitorClassID; + + public ModuleClassID getModuleClassID() { + return moduleClassID; + } + + public ResolverServiceMonitorFilter() {} + + public void init(ModuleClassID moduleClassID) { + this.moduleClassID = moduleClassID; + } + + public boolean isIncludeQueryHandlerMetrics() { + return includeQueryHandlerMetrics; + } + + public boolean isIncludeSrdiHandlerMetrics() { + return includeSrdiHandlerMetrics; + } + + public void setIncludeQueryHandlerMetrics(boolean includeQueryHandlerMetrics) { + this.includeQueryHandlerMetrics = includeQueryHandlerMetrics; + } + + public void setIncludeSrdiHandlerMetrics(boolean includeSrdiHandlerMetrics) { + this.includeSrdiHandlerMetrics = includeSrdiHandlerMetrics; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + DocumentSerializableUtilities.addBoolean(element, "includeQueryHandlerMetrics", includeQueryHandlerMetrics); + DocumentSerializableUtilities.addBoolean(element, "includeSrdiHandlerMetrics", includeSrdiHandlerMetrics); + if (moduleClassID != null) { + DocumentSerializableUtilities.addString(element, "moduleClassID", moduleClassID.toString()); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("includeQueryHandlerMetrics")) { + includeQueryHandlerMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } + if (tagName.equals("includeSrdiHandlerMetrics")) { + includeSrdiHandlerMetrics = DocumentSerializableUtilities.getBoolean(childElement); + } + if (tagName.equals("moduleClassID")) { + try { + moduleClassID = (ModuleClassID) IDFactory.fromURI( + new URI(DocumentSerializableUtilities.getString(childElement))); + } catch (URISyntaxException jex) { + throw new DocumentSerializationException("Can't read moduleClassID", jex); + } + } + } + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiDestinationMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiDestinationMeter.java new file mode 100644 index 000000000..fb705e57b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiDestinationMeter.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.peer.*; +import net.jxta.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.util.*; +import java.util.*; + + +public class SrdiDestinationMeter { + private PeerID peerID; + + private SrdiDestinationMetric cumulativeMetrics; + private SrdiDestinationMetric deltaMetrics; + + public SrdiDestinationMeter(PeerID peerID) { + this.peerID = peerID; + cumulativeMetrics = new SrdiDestinationMetric(peerID); + } + + /* + public SrdiDestinationMeter(EndpointAddress addr) { + super(addr); + cumulativeMetrics = new SrdiDestinationMetric(addr); + } + */ + public synchronized SrdiDestinationMetric collectMetrics() { + SrdiDestinationMetric prevDelta = deltaMetrics; + + deltaMetrics = null; + return prevDelta; + } + + public SrdiDestinationMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + private void createDeltaMetric() { + deltaMetrics = new SrdiDestinationMetric(peerID); + } + + public PeerID getPeerID() { + return peerID; + } + + protected void messageProcessed() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageProcessed(); + cumulativeMetrics.messageProcessed(); + } + + protected void srdiToUnregisteredHandler() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.srdiToUnregisteredHandler(); + cumulativeMetrics.srdiToUnregisteredHandler(); + } + + protected void errorWhileProcessing() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorWhileProcessing(); + cumulativeMetrics.errorWhileProcessing(); + } + + protected void messageSentViaUnicast() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageSentViaUnicast(); + cumulativeMetrics.messageSentViaUnicast(); + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiDestinationMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiDestinationMetric.java new file mode 100644 index 000000000..0bb9a5ddb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiDestinationMetric.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.peer.*; +import net.jxta.endpoint.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import java.util.*; +import net.jxta.impl.meter.*; + +import net.jxta.util.*; + + +/** + * Metrics for a specific Srdi Destination for a specific handler + **/ +public class SrdiDestinationMetric implements DocumentSerializable { + private PeerID peerID; + private int messageProcessed; + private int errorWhileProcessing; + private int srdiToUnregisteredHandler = 0; + + private int messageSentViaUnicast; + + public SrdiDestinationMetric(PeerID peerID) { + this.peerID = peerID; + } + + public SrdiDestinationMetric(SrdiDestinationMetric prototype) { + this.peerID = prototype.peerID; + } + + public SrdiDestinationMetric() {} + + public PeerID getPeerID() { + return peerID; + } + + void messageProcessed() { + messageProcessed++; + } + + /** Messages Received and Processed from this destinations **/ + public int getMessagesProcessed() { + return messageProcessed; + } + + void errorWhileProcessing() { + errorWhileProcessing++; + } + + /** Messages Received, but generating errors when processing **/ + public int getErrorsWhileProcessing() { + return errorWhileProcessing; + } + + void messageSentViaUnicast() { + messageSentViaUnicast++; + } + + /** Get Messages Sent via Unicast to this destinations **/ + public int getMessagesSentViaUnicast() { + return messageSentViaUnicast; + } + + public void srdiToUnregisteredHandler() { + srdiToUnregisteredHandler++; + } + + /** Messages Received, to this when it was not registered **/ + public int getSrdiToUnregisteredHandler() { + return srdiToUnregisteredHandler; + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (peerID != null) { + DocumentSerializableUtilities.addString(element, "peerID", peerID.toString()); + } + if (messageProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "messageProcessed", messageProcessed); + } + if (errorWhileProcessing != 0) { + DocumentSerializableUtilities.addInt(element, "errorWhileProcessing", errorWhileProcessing); + } + if (srdiToUnregisteredHandler != 0) { + DocumentSerializableUtilities.addInt(element, "srdiToUnregisteredHandler", srdiToUnregisteredHandler); + } + if (messageSentViaUnicast != 0) { + DocumentSerializableUtilities.addInt(element, "messageSentViaUnicast", messageSentViaUnicast); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("peerID")) { + String peerIDText = DocumentSerializableUtilities.getString(childElement); + + peerID = MetricUtilities.getPeerIdFromString(peerIDText); + } else if (tagName.equals("messageProcessed")) { + messageProcessed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("errorWhileProcessing")) { + errorWhileProcessing = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("srdiToUnregisteredHandler")) { + srdiToUnregisteredHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("messageSentViaUnicast")) { + messageSentViaUnicast = DocumentSerializableUtilities.getInt(childElement); + } + } + } + + public void mergeMetrics(SrdiDestinationMetric otherSrdiDestinationMetric) { + this.errorWhileProcessing += otherSrdiDestinationMetric.errorWhileProcessing; + this.messageProcessed += otherSrdiDestinationMetric.messageProcessed; + this.messageSentViaUnicast += otherSrdiDestinationMetric.messageSentViaUnicast; + } + + @Override + public int hashCode() { + return peerID.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof SrdiDestinationMetric) { + SrdiDestinationMetric otherSrdiDestinationMetric = (SrdiDestinationMetric) other; + + return peerID.equals(otherSrdiDestinationMetric.peerID); + } else { + return false; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiHandlerMeter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiHandlerMeter.java new file mode 100644 index 000000000..bdc6a90e1 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiHandlerMeter.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.protocol.ResolverSrdiMsg; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.peer.*; +import net.jxta.util.*; +import net.jxta.impl.meter.*; +import net.jxta.exception.*; +import java.util.*; + + +public class SrdiHandlerMeter { + private String handlerName; + + private SrdiHandlerMetric cumulativeMetrics; + private SrdiHandlerMetric deltaMetrics; + private Hashtable srdiDestinationMeters = new Hashtable(); + + public SrdiHandlerMeter(String handlerName) { + this.handlerName = handlerName; + cumulativeMetrics = new SrdiHandlerMetric(handlerName); + } + + public SrdiHandlerMetric getCumulativeMetrics() { + return cumulativeMetrics; + } + + public String getHandlerName() { + return handlerName; + } + + public synchronized SrdiHandlerMetric collectMetrics() { + SrdiHandlerMetric prevDelta = deltaMetrics; + + for (Enumeration e = srdiDestinationMeters.elements(); e.hasMoreElements();) { + SrdiDestinationMeter srdiDestinationMeter = (SrdiDestinationMeter) e.nextElement(); + + SrdiDestinationMetric srdiDestinationMetric = srdiDestinationMeter.collectMetrics(); + + if (srdiDestinationMetric != null) { + + /* Fix-me: Apparantly, we can have a case where NO Srdi mteric is tickled, but a + destination metric is available. This may be a bug. For now, we'll create the + delta in that case. + */ + if (prevDelta == null) { + createDeltaMetric(); + prevDelta = deltaMetrics; + } + prevDelta.addSrdiDestinationMetric(srdiDestinationMetric); + } + } + deltaMetrics = null; + return prevDelta; + } + + public synchronized SrdiDestinationMeter getSrdiDestinationMeter(EndpointAddress endpointAddress) { + PeerID peerID = MetricUtilities.getPeerIdFromEndpointAddress(endpointAddress); + + return getSrdiDestinationMeter(peerID); + } + + public synchronized SrdiDestinationMeter getSrdiDestinationMeter(String peer) { + PeerID peerID = MetricUtilities.getPeerIdFromString(peer); + + return getSrdiDestinationMeter(peerID); + } + + public synchronized SrdiDestinationMeter getSrdiDestinationMeter(PeerID peerID) { + + SrdiDestinationMeter srdiDestinationMeter = (SrdiDestinationMeter) srdiDestinationMeters.get(peerID); + + if (srdiDestinationMeter == null) { + srdiDestinationMeter = new SrdiDestinationMeter(peerID); + srdiDestinationMeters.put(peerID, srdiDestinationMeter); + cumulativeMetrics.addSrdiDestinationMetric(srdiDestinationMeter.getCumulativeMetrics()); + } + + return srdiDestinationMeter; + } + + private void createDeltaMetric() { + deltaMetrics = new SrdiHandlerMetric(handlerName); + } + + @Override + public String toString() { + return "SrdiHandlerMeter(" + handlerName + ")"; + } + + public void setRegistered(boolean registered) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.setRegistered(registered); + cumulativeMetrics.setRegistered(registered); + } + + // received + + public void messageProcessed(ResolverSrdiMsg srdi, long processTime, EndpointAddress srcAddr) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageProcessed(processTime); + cumulativeMetrics.messageProcessed(processTime); + + SrdiDestinationMeter destinationMeter = getSrdiDestinationMeter(srcAddr); + + destinationMeter.messageProcessed(); + } + + public void errorWhileProcessing(EndpointAddress srcAddr) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + deltaMetrics.errorWhileProcessing(); + cumulativeMetrics.errorWhileProcessing(); + + SrdiDestinationMeter destinationMeter = getSrdiDestinationMeter(srcAddr); + + destinationMeter.errorWhileProcessing(); + } + + public void srdiToUnregisteredHandler(EndpointAddress srcAddr) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.srdiToUnregisteredHandler(); + cumulativeMetrics.srdiToUnregisteredHandler(); + + SrdiDestinationMeter destinationMeter = getSrdiDestinationMeter(srcAddr); + + destinationMeter.srdiToUnregisteredHandler(); + } + + // send + + + public void messageSentViaUnicast(String peer, ResolverSrdiMsg srdi) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageSentViaUnicast(); + cumulativeMetrics.messageSentViaUnicast(); + + SrdiDestinationMeter destinationMeter = getSrdiDestinationMeter(peer); + + destinationMeter.messageSentViaUnicast(); + } + + public void messageSentViaWalker(ResolverSrdiMsg srdi) { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.messageSentViaWalker(); + cumulativeMetrics.messageSentViaWalker(); + } + + public void errorSendingMessage() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorSendingMessage(); + cumulativeMetrics.errorSendingMessage(); + } + + public void errorPropagatingMessage() { + if (deltaMetrics == null) { + createDeltaMetric(); + } + + deltaMetrics.errorPropagatingMessage(); + cumulativeMetrics.errorPropagatingMessage(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiHandlerMetric.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiHandlerMetric.java new file mode 100644 index 000000000..45815f43f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/resolver/resolverMeter/SrdiHandlerMetric.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.resolver.resolverMeter; + + +import net.jxta.resolver.*; +import net.jxta.util.documentSerializable.*; +import net.jxta.document.*; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.peer.*; +import net.jxta.impl.meter.*; + +import java.util.*; + + +public class SrdiHandlerMetric implements DocumentSerializable { + private String handlerName; + private boolean registered = true; + private int numProcessed = 0; + private int numErrorsWhileProcessing = 0; + private int numToUnregisteredHandler = 0; + + private long totalProcessTime = 0; + + private int numMessagesSentViaWalker = 0; + private int numMessagesSentViaUnicast = 0; + private int numErrorsSendingMessages = 0; + private int numErrorsPropagatingMessages = 0; + + private HashMap destinationMetrics = new HashMap(); + + public SrdiHandlerMetric(String handlerName) { + this.handlerName = handlerName; + } + + public SrdiHandlerMetric() {} + + public SrdiHandlerMetric(SrdiHandlerMetric prototype) { + this.handlerName = prototype.handlerName; + } + + public void setRegistered(boolean registered) { + this.registered = registered; + } + + public String getHandlerName() { + return handlerName; + } + + public boolean getRegistered() { + return registered; + } + + public int getNumProcessed() { + return numProcessed; + } + + public int getNumErrorsWhileProcessing() { + return numErrorsWhileProcessing; + } + + public long getTotalProcessTime() { + return totalProcessTime; + } + + public int getNumMessagesSentViaWalker() { + return numMessagesSentViaWalker; + } + + public int getNumMessagesSentViaUnicast() { + return numMessagesSentViaUnicast; + } + + public int getNumErrorsSendingMessages() { + return numErrorsSendingMessages; + } + + public int getNumErrorsPropagatingMessages() { + return numErrorsPropagatingMessages; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SrdiHandlerMetric) { + SrdiHandlerMetric otherSrdiHandlerMetric = (SrdiHandlerMetric) obj; + + return handlerName.equals((otherSrdiHandlerMetric.handlerName)); + } else { + return false; + } + } + + @Override + public int hashCode() { + return handlerName.hashCode(); + } + + public void messageProcessed(long processTime) { + numProcessed++; + totalProcessTime += processTime; + } + + public void errorWhileProcessing() { + numErrorsWhileProcessing++; + } + + public void srdiToUnregisteredHandler() { + numToUnregisteredHandler++; + } + + public void messageSentViaWalker() { + numMessagesSentViaWalker++; + } + + public void messageSentViaUnicast() { + numMessagesSentViaUnicast++; + } + + public void errorSendingMessage() { + numErrorsSendingMessages++; + } + + public void errorPropagatingMessage() { + numErrorsPropagatingMessages++; + } + + SrdiDestinationMetric getSrdiDestinationMetric(EndpointAddress endpointAddress) { + PeerID peerID = MetricUtilities.getPeerIdFromEndpointAddress(endpointAddress); + + return getSrdiDestinationMetric(peerID); + } + + SrdiDestinationMetric getSrdiDestinationMetric(PeerID peerID) { + + SrdiDestinationMetric destinationMetric = (SrdiDestinationMetric) destinationMetrics.get(peerID); + + if (destinationMetric == null) { + destinationMetric = new SrdiDestinationMetric(peerID); + destinationMetrics.put(peerID, destinationMetric); + } + return destinationMetric; + } + + public Iterator getDestinationMetrics() { + + return destinationMetrics.values().iterator(); + } + + public void addSrdiDestinationMetric(SrdiDestinationMetric srdiDestinationMetric) { + destinationMetrics.put(srdiDestinationMetric.getPeerID(), srdiDestinationMetric); + } + + public void serializeTo(Element element) throws DocumentSerializationException { + if (handlerName != null) { + DocumentSerializableUtilities.addString(element, "handlerName", handlerName); + } + DocumentSerializableUtilities.addBoolean(element, "registered", registered); + if (numProcessed != 0) { + DocumentSerializableUtilities.addInt(element, "numProcessed", numProcessed); + } + if (numErrorsWhileProcessing != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsWhileProcessing", numErrorsWhileProcessing); + } + if (numToUnregisteredHandler != 0) { + DocumentSerializableUtilities.addInt(element, "numToUnregisteredHandler", numToUnregisteredHandler); + } + if (totalProcessTime != 0) { + DocumentSerializableUtilities.addLong(element, "totalProcessTime", totalProcessTime); + } + if (numMessagesSentViaWalker != 0) { + DocumentSerializableUtilities.addInt(element, "numMessagesSentViaWalker", numMessagesSentViaWalker); + } + if (numMessagesSentViaUnicast != 0) { + DocumentSerializableUtilities.addInt(element, "numMessagesSentViaUnicast", numMessagesSentViaUnicast); + } + if (numErrorsSendingMessages != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsSendingMessages", numErrorsSendingMessages); + } + if (numErrorsPropagatingMessages != 0) { + DocumentSerializableUtilities.addInt(element, "numErrorsPropagatingMessages", numErrorsPropagatingMessages); + } + + for (Iterator i = destinationMetrics.values().iterator(); i.hasNext();) { + Element srdiDestinationElement = DocumentSerializableUtilities.createChildElement(element, "destination"); + SrdiDestinationMetric srdiDestinationMetric = (SrdiDestinationMetric) i.next(); + + srdiDestinationMetric.serializeTo(srdiDestinationElement); + } + } + + public void initializeFrom(Element element) throws DocumentSerializationException { + for (Enumeration e = element.getChildren(); e.hasMoreElements();) { + Element childElement = (TextElement) e.nextElement(); + String tagName = (String) childElement.getKey(); + + if (tagName.equals("handlerName")) { + handlerName = DocumentSerializableUtilities.getString(childElement); + } else if (tagName.equals("registered")) { + registered = DocumentSerializableUtilities.getBoolean(childElement); + } else if (tagName.equals("numProcessed")) { + numProcessed = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsWhileProcessing")) { + numErrorsWhileProcessing = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numToUnregisteredHandler")) { + numToUnregisteredHandler = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("totalProcessTime")) { + totalProcessTime = DocumentSerializableUtilities.getLong(childElement); + } else if (tagName.equals("numMessagesSentViaWalker")) { + numMessagesSentViaWalker = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numMessagesSentViaUnicast")) { + numMessagesSentViaUnicast = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsSendingMessages")) { + numErrorsSendingMessages = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("numErrorsPropagatingMessages")) { + numErrorsPropagatingMessages = DocumentSerializableUtilities.getInt(childElement); + } else if (tagName.equals("destination")) { + SrdiDestinationMetric srdiDestinationMetric = new SrdiDestinationMetric(); + + srdiDestinationMetric.initializeFrom(childElement); + addSrdiDestinationMetric(srdiDestinationMetric); + } + } + } + + public void mergeMetrics(SrdiHandlerMetric otherSrdiHandlerMetric) { + numProcessed += otherSrdiHandlerMetric.numProcessed; + numErrorsWhileProcessing += otherSrdiHandlerMetric.numErrorsWhileProcessing; + totalProcessTime += otherSrdiHandlerMetric.totalProcessTime; + numMessagesSentViaWalker += otherSrdiHandlerMetric.numMessagesSentViaWalker; + numMessagesSentViaUnicast += otherSrdiHandlerMetric.numMessagesSentViaUnicast; + numErrorsSendingMessages += otherSrdiHandlerMetric.numErrorsSendingMessages; + numErrorsPropagatingMessages += otherSrdiHandlerMetric.numErrorsPropagatingMessages; + for (Iterator i = otherSrdiHandlerMetric.getDestinationMetrics(); i.hasNext();) { + SrdiDestinationMetric otherSrdiDestinationMetric = (SrdiDestinationMetric) i.next(); + SrdiDestinationMetric ourSrdiDestinationMetric = getSrdiDestinationMetric(otherSrdiDestinationMetric.getPeerID()); + + if (ourSrdiDestinationMetric == null) { + ourSrdiDestinationMetric = new SrdiDestinationMetric(otherSrdiDestinationMetric); + addSrdiDestinationMetric(ourSrdiDestinationMetric); + } + + ourSrdiDestinationMetric.mergeMetrics(otherSrdiDestinationMetric); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ACLSeedingManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ACLSeedingManager.java new file mode 100644 index 000000000..97e93588c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ACLSeedingManager.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2002-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; + +import java.io.IOException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +import net.jxta.impl.access.AccessList; +import net.jxta.impl.endpoint.EndpointUtils; + + +/** + * Provides support for the optional access control list which determines which + * peers may be used. + */ +public abstract class ACLSeedingManager implements SeedingManager { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(ACLSeedingManager.class.getName()); + + /** + * The interval in milliseconds at which the ACL be refreshed from the + * source. + */ + private static final long ACL_REFRESH_INTERVAL = 30 * TimeUtils.AMINUTE; + + /** + * The access control list which controls which hosts are allowed. + */ + private final URI aclLocation; + + /** + * The last known modification time of the ACL. + */ + private long aclLastModified = 0; + + /** + * Manages access to the seeds. + */ + protected final AccessList acl = new AccessList(); + + /** + * The absolute time in milliseconds after which we will attempt to refresh + * the access control list from the acl URI. + */ + private long nextACLrefreshTime = 0; + + /** + * Constructs a new ACL seeding manager. + * + * @param aclLocation The location of the ACL file or {@code null} if no + * ACL file should be used. + */ + public ACLSeedingManager(URI aclLocation) { + this.aclLocation = aclLocation; + + // Default to allowing all peers. + acl.setGrantAll(true); + if (null == aclLocation) { + // forever. + nextACLrefreshTime = Long.MAX_VALUE; + } + } + + /** + * {@inheritDoc} + * + *

            Performs it's determination based solely on the list of peers in + * the access list. + */ + public boolean isAcceptablePeer(PeerAdvertisement peeradv) { + RouteAdvertisement route = EndpointUtils.extractRouteAdv(peeradv); + + if (null != route) { + return isAcceptablePeer(route); + } else { + // No route? It's only OK if we are approving everyone. + return acl.getGrantAll(); + } + } + + /** + * {@inheritDoc} + * + *

            Performs it's determination based solely on the list of peers in + * the access list. + */ + public synchronized boolean isAcceptablePeer(RouteAdvertisement radv) { + + // Refresh the ACL? + + if (TimeUtils.timeNow() > nextACLrefreshTime) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Updating ACL"); + } + + try { + URL asURL = aclLocation.toURL(); + URLConnection connection = asURL.openConnection(); + + connection.setDoInput(true); + InputStream is = connection.getInputStream(); + + long last_mod = connection.getLastModified(); + + if ((last_mod == 0) || (last_mod > aclLastModified)) { + acl.setGrantAll(false); + acl.refresh(is); + } + + nextACLrefreshTime = TimeUtils.toAbsoluteTimeMillis(ACL_REFRESH_INTERVAL); + } catch (IOException failed) { + // be lenient in response to failures. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "ACL update failed. GRANTING ALL PERMISSIONS.", failed); + } + + acl.setGrantAll(true); + + nextACLrefreshTime = TimeUtils.toAbsoluteTimeMillis(ACL_REFRESH_INTERVAL / 2); + } + } + + return acl.isAllowed(radv.getDestPeerID()); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/AdvCooker.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/AdvCooker.java new file mode 100644 index 000000000..b9bbe67bc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/AdvCooker.java @@ -0,0 +1,513 @@ + + +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredTextDocument; +import net.jxta.document.TextElement; +import net.jxta.document.XMLDocument; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleClassAdvertisement; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.PipeAdvertisement; + +import net.jxta.impl.peergroup.StdPeerGroup; +import net.jxta.impl.peergroup.StdPeerGroupParamAdv; + + +/** + * Advertisements and ID's "cooked" according to recipes lifted + * from J-C and Frog. Static methods meant for convenience in developing + * experimental propagation modules (pipe or rendezvous services, + * rendezvous managers) but maybe generally useful. + * + * @author vasha + */ +public class AdvCooker { + + /** + * Reconstructs a ModuleClassID from its String representation + * as printed by the foregoing recipes. + * + * @param url -- the module class id in String form, "urn:jxta:uuid-[the big hex string]" + * @throws URISyntaxException -- if url is messed up + * @return -- module class id reconstructed from String + */ + private static ModuleClassID buildModuleClassID(String uri) throws URISyntaxException { + return (ModuleClassID) IDFactory.fromURI(new URI(uri)); + } + + /** Reconstructs a ModuleSpecID from its String representation + * as printed by the foregoing recipes. + * + * @param url -- the module spec id in String form, "urn:jxta:uuid-[the big hex string]" + * @throws URISyntaxException -- if url is messed up + * @return -- module spec id reconstructed from String + */ + private static ModuleSpecID buildModuleSpecID(String uri) throws URISyntaxException { + return (ModuleSpecID) IDFactory.fromURI(new URI(uri)); + } + + /** + * The module class advertisement is to simply advertise the + * existence of a module. + * + * @param mcid -- the module class id + * @param serviceName -- something like "JXTAMOD:JXTA-WIRE-MyNewThing" + * @param serviceDescription -- something like "JXTA-WIRE MyNewThing Module" + * @return an appropriate ModuleClassAdvertisement + */ + public static ModuleClassAdvertisement buildModuleClassAdvertisement(ModuleClassID mcid, String serviceName, String serviceDescription) { + ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType()); + + mcadv.setName(serviceName); + mcadv.setDescription(serviceDescription); + mcadv.setModuleClassID(mcid); + return mcadv; + } + + /** + * The ModuleSpecAdvertisement has two purposes, to publish + * the uri of its formal specs for developers and to publish the + * means of remote access to the module's services if that + * is appropriate. (See {@link ModuleSpecAdvertisement} ) + * Use this form for a minimal advertisement, suitable + * for development. + * + * @param msid -- the module spec id, "urn:jxta:uuid-[the big hex string]" + * @param moduleSpecName -- something like "JXTASPEC:JXTA-WIRE-MyNewThing-SPEC" + * @param moduleSpecDescription -- something like "JXTA-WIRE MyNewThing Specification" + * @return -- a boilerplate suitable for development. + */ + public static ModuleSpecAdvertisement buildModuleSpecAdvertisement(ModuleSpecID msid, String moduleSpecName, String moduleSpecDescription) { + return buildModuleSpecAdvertisement(msid, moduleSpecName, moduleSpecDescription, null, null, null, null, null, null, null); + } + + /** + * Use this form for production provided remote access is not required. + * + * @param msid -- the module spec id, "urn:jxta:uuid-[the big hex string]" + * @param moduleSpecName -- something like "JXTASPEC:JXTA-WIRE-MyNewThing-SPEC" + * @param moduleSpecDescription -- something like "JXTA-WIRE MyNewThing Specification" + * @param creator -- something like "jxta.org" + * @param version -- something like "Version 1.0" + * @param specURI -- where to locate the formal specs, e.g. "http://www.jxta.org/MyNewThing" + * @return -- a fully populated advert suitable if remote access is not required. + */ + public static ModuleSpecAdvertisement buildModuleSpecAdvertisement(ModuleSpecID msid, String moduleSpecName, String moduleSpecDescription, String creator, String version, String specURI) { + return buildModuleSpecAdvertisement(msid, moduleSpecName, moduleSpecDescription, creator, version, specURI, null, null + , + null, null); + } + + /** + * Use this form for a fully populated advert. + * + * @param msid -- the module spec id, "urn:jxta:uuid-[the big hex string]" + * @param moduleSpecName -- something like "JXTASPEC:JXTA-WIRE-MyNewThing-SPEC" + * @param moduleSpecDescription -- something like "JXTA-WIRE MyNewThing Specification" + * @param creator -- something like "jxta.org" + * @param version -- something like "Version 2.0" + * @param specURI -- where to locate the formal specs, e.g. "http://www.jxta.org/MyNewThing" + * @param pipeAdv -- to make the module useable remotely (see {@link ModuleSpecAdvertisement}) + * @param proxySpecID -- sometimes required for remote use (see {@link ModuleSpecAdvertisement}) + * @param authorizationSpecID -- sometimes required for remote use (see {@link ModuleSpecAdvertisement}) + * @param param -- anything else + * @return -- a fully populated advert specifying remote access to module services. + */ + public static ModuleSpecAdvertisement buildModuleSpecAdvertisement(ModuleSpecID msid, String moduleSpecName, String moduleSpecDescription, String creator, String version, String specURI, PipeAdvertisement pipeAdv, ModuleSpecID proxySpecID, ModuleSpecID authorizationSpecID, StructuredDocument param) { + ModuleSpecAdvertisement msadv = (ModuleSpecAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType()); + + msadv.setModuleSpecID(msid); + msadv.setName(moduleSpecName); + msadv.setDescription(moduleSpecDescription); + msadv.setCreator(creator == null ? "jxta.org" : creator); + msadv.setVersion(version == null ? "Version 2.0" : version); + msadv.setSpecURI(specURI == null ? "http://www.jxta.org/" + moduleSpecName : specURI); + if (pipeAdv != null) { + msadv.setPipeAdvertisement(pipeAdv); + } + if (proxySpecID != null) { + msadv.setProxySpecID(proxySpecID); + } + if (authorizationSpecID != null) { + msadv.setAuthSpecID(authorizationSpecID); + } + if (param != null) { + msadv.setParam(param); + } + return msadv; + } + + /** + * Compat's (compatibility statements) serve to narrow the search + * for a ModuleImplAdvertisement. Basically you want something + * compatible with your group's implementation. Use this form for + * compatibilty with the current StdPeerGroup. + * + * @return -- boilerplate compat for StdPeerGroup + */ + public static XMLDocument buildCompat() { + + try { + PeerGroup wpg = PeerGroup.globalRegistry.lookupInstance(PeerGroupID.worldPeerGroupID); + + ModuleImplAdvertisement implAdv = wpg.getAllPurposePeerGroupImplAdvertisement(); + + wpg.unref(); + + XMLDocument compat = (XMLDocument) implAdv.getCompat(); + + return compat; + } catch (Exception e) { + // but if it doesn't work default to what was current on Feb 22 2006. + return buildCompat("JDK1.4.1", "V2.0 Ref Impl"); + } + } + + /** + * Use this form for customized compatibility statements. + * Alternatively a group's compat is accessible via + * group.getCompat() + * + * @param efmt -- something like "JDK1.4" + * @param bind -- something like "V1.0 Ref Impl" + * @return -- custom compatibility tag + */ + public static XMLDocument buildCompat(String efmt, String bind) { + XMLDocument doc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Comp"); + + Element e = doc.createElement("Efmt", efmt); + + doc.appendChild(e); + e = doc.createElement("Bind", bind); + doc.appendChild(e); + + return doc; + } + + /** + * A ModuleImplAdvertisement represents one of any number of + * published implementations of a given specification. Use this form + * with for a development boilerplate. Use buildCompat() for a compat + * boilerplate. + * (See {@link ModuleImplAdvertisement}.) + * + * @param msid -- the module spec id + * @param code -- the module's fully qualified classname, "net.jxta.impl.wire.MyNewThing" + * @param compat -- a compatibility statement. Use buildCompat() for a boilerplate. + * @return -- a development boilerplate with custom compatibility. + */ + public static ModuleImplAdvertisement buildModuleImplAdvertisement(ModuleSpecID msid, String code, Element compat) { + ModuleImplAdvertisement miadv = (ModuleImplAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType()); + + miadv.setCompat(compat); + miadv.setModuleSpecID(msid); + miadv.setCode(code); + miadv.setDescription(code + " Module, J2SE Implementation"); + miadv.setProvider("jxta.org"); + miadv.setUri("http://download.jxta.org"); + return miadv; + } + + /** Use this form to fully populate a ModuleImplAdvertisement. + * A ModuleImplAdvertisement has an optional field, "param" which is + * neglected here. If needed it should be set with advert's setParam method. + * (See {@link ModuleImplAdvertisement}.) + * + * @param msid -- the module spec id + * @param code -- the module's fully qualified classname, "net.jxta.impl.wire.MyNewThing" + * @param compat -- a compatibility statement + * @param description -- something like "MyNewThing Module, J2SE Implementation" + * @param provider -- something like "jxta.org" + * @param uri -- currently ornamental, eventually where to find binaries. + * @return -- a custom advert, fully populated except for "param" field. + */ + public static ModuleImplAdvertisement buildModuleImplAdvertisement(ModuleSpecID msid, String code, Element compat, String description, String provider, String uri) { + ModuleImplAdvertisement miadv = buildModuleImplAdvertisement(msid, code, compat); + + miadv.setDescription(description); + miadv.setProvider(provider); + miadv.setUri(uri); + return miadv; + } + + /** + * Modifies a copy of the parent's implementation + * advertisement to reflect the addition or replacement of + * services. The newServices Hashtable must have ModuleClassID + * keys and ModuleImplAdvertisement values. I've deferred adding + * applications or protocols for the moment --vasha@jxta.org Dec 3 2001. + * + * @return -- advert for the new peergroup which the StdPeerGroup module will implement. + * @param parent -- a running instance of the new group's parent + * @param newGroupModuleSpecID -- since new or replacement services are involved + * @param newDescription -- the new group's reason to be + * @param newServices -- advert's for the new services + * @throws IllegalArgumentException -- for a bad key or value type + * @throws Exception --- if the parent can't produce a copy of its own impl advert + */ + public static ModuleImplAdvertisement buildPeerGroupImplAdvertisement(StdPeerGroup parent, ModuleSpecID newGroupModuleSpecID, String newDescription, Map newServices) throws Exception { + Map newApps = null, newProtos = null; + + // illegal types will cause an IllegalArgumentException + typeCheckKeys(newServices); + typeCheckValues(newServices); + // get a copy of parent's general purpose advert as a template + ModuleImplAdvertisement implAdv = parent.getAllPurposePeerGroupImplAdvertisement(); + + implAdv.setDescription(newDescription); + implAdv.setModuleSpecID(newGroupModuleSpecID); + // extract embedded ad for standard modules + TextElement paramElement = (TextElement) implAdv.getParam(); + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(paramElement); + // alter services + Map services = paramAdv.getServices(); + + typeCheckKeys(services); + // mergeTables will override old services with new if base classes are the same + services = mergeTables(services, newServices); + paramAdv.setServices(services); + paramElement = (TextElement) paramAdv.getDocument(MimeMediaType.XMLUTF8); + implAdv.setParam(paramElement); + return implAdv; + } + + public static ModuleImplAdvertisement buildPeerGroupImplAdvertisement(PeerGroup parent, ModuleSpecID newGroupModuleSpecID, String newDescription, Map newServices, Map newApps) throws Exception { + Map newProtos = null; + + // illegal types will cause an IllegalArgumentException + typeCheckKeys(newServices); + typeCheckValues(newServices); + typeCheckKeys(newApps); + typeCheckValues(newApps); + + // get a copy of parent's general purpose advert as a template + ModuleImplAdvertisement implAdv = parent.getAllPurposePeerGroupImplAdvertisement(); + + implAdv.setDescription(newDescription); + implAdv.setModuleSpecID(newGroupModuleSpecID); + // extract embedded ad for standard modules + TextElement paramElement = (TextElement) implAdv.getParam(); + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(paramElement); + + // alter services + Map services = paramAdv.getServices(); + + typeCheckKeys(services); + // mergeTables will override old services with new if base classes are the same + services = mergeTables(services, newServices); + paramAdv.setServices(services); + + // alter apps + Map apps = paramAdv.getApps(); + + typeCheckKeys(apps); + apps = mergeTables(apps, newApps); + paramAdv.setApps(apps); + + paramElement = (TextElement) paramAdv.getDocument(MimeMediaType.XMLUTF8); + implAdv.setParam(paramElement); + + return implAdv; + } + + public static ModuleImplAdvertisement buildPeerGroupImplAdvertisement(PeerGroup parent, ModuleSpecID newGroupModuleSpecID, String newDescription, Map newServices, Map newApps, Map newProtos) throws Exception { + + // illegal types will cause an IllegalArgumentException + typeCheckKeys(newServices); + typeCheckValues(newServices); + typeCheckKeys(newApps); + typeCheckValues(newApps); + typeCheckKeys(newProtos); + typeCheckValues(newProtos); + + // get a copy of parent's general purpose advert as a template + ModuleImplAdvertisement implAdv = parent.getAllPurposePeerGroupImplAdvertisement(); + + implAdv.setDescription(newDescription); + implAdv.setModuleSpecID(newGroupModuleSpecID); + // extract embedded ad for standard modules + TextElement paramElement = (TextElement) implAdv.getParam(); + StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(paramElement); + + // alter services + Map services = paramAdv.getServices(); + + typeCheckKeys(services); + // mergeTables will override old services with new if base classes are the same + services = mergeTables(services, newServices); + paramAdv.setServices(services); + + // alter apps + Map apps = paramAdv.getApps(); + + typeCheckKeys(apps); + apps = mergeTables(apps, newApps); + paramAdv.setApps(newApps); + + // alter protos + Map protos = paramAdv.getProtos(); + + typeCheckKeys(protos); + apps = mergeTables(protos, newProtos); + paramAdv.setProtos(newProtos); + + paramElement = (TextElement) paramAdv.getDocument(MimeMediaType.XMLUTF8); + implAdv.setParam(paramElement); + + return implAdv; + } + + /** + * Module table vaules must be ModuleImplAdvertisements here. + * Though StdPeerGroup allows for values of type ModuleSpecID, + * the context in which they seem to apply is not our context of adding + * or replacing modules, so I've prohibited them. --vasha@jxta.org dec 3 2001. + * + * @param moduleTable -- a Hashtable of services, applications or protocols. + * @throws IllegalArgumentException -- for an invalid key or value type + */ + public static void typeCheckValues(Map moduleTable) { + String badVal = "Module table value not a ModuleImplAdvertisement "; + Iterator keys = moduleTable.keySet().iterator(); + + while (keys.hasNext()) { + // Tables allow for ModuleSpecID values when, as I understand it, + // they can load the module from the parent. I'm insisting that + // NEW or ALTERNATIVE modules supply a ModuleImplAdvertisement. + Object value = moduleTable.get(keys.next()); + boolean legalValue = value instanceof ModuleImplAdvertisement; + + if (!legalValue) { + throw(new IllegalArgumentException(badVal + value)); + } + } + } + + /** + * Module table keys must be ModuleClassID's. + * + * @param moduleTable -- a Hashtable of services, applications or protocols. + * @throws IllegalArgumentException -- for an invalid key or value type + */ + public static void typeCheckKeys(Map moduleTable) { + String badKey = "Module table key not a ModuleClassID "; + Iterator keys = moduleTable.keySet().iterator(); + + while (keys.hasNext()) { + Object key = keys.next(); + boolean legalKey = key instanceof ModuleClassID; + + if (!legalKey) { + throw(new IllegalArgumentException(badKey + key)); + } + } + } + + /** + * Merge two hashtables of servcices, overwriting old with new if + * they have the same base class id. + * + * @oldServices --service table of a parent group + * @newServices --services to be added or substituted + * @return --merged table + */ + private static Map mergeTables(Map oldServices, Map newServices) { + // just use brute force; we won't be doing it that often + Map mergedServices = new HashMap(oldServices); + Iterator newKeys = newServices.keySet().iterator(); + + while (newKeys.hasNext()) { + ModuleClassID key = (ModuleClassID) newKeys.next(); + Iterator oldKeys = oldServices.keySet().iterator(); + + while (oldKeys.hasNext()) { + ModuleClassID oldkey = (ModuleClassID) oldKeys.next(); + + if (oldkey.isOfSameBaseClass(key)) { + mergedServices.remove(oldkey); + } + } + mergedServices.put(key, newServices.get(key)); + } + return mergedServices; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/BASE64InputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/BASE64InputStream.java new file mode 100644 index 000000000..656a34645 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/BASE64InputStream.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.io.InputStream; +import java.io.Reader; + +import java.io.IOException; + +/** + * An InputStream implementation which decodes BASE64 encoded + * data from a text Reader. + * + *

            This implementation is not thread safe. + * + * @see net.jxta.impl.util.BASE64OutputStream + * @see IETF RFC 2045 MIME : Format of Internet Message Bodies + **/ +public class BASE64InputStream extends InputStream { + + /** + * The input source of BASE64 text data. + **/ + private Reader source; + + /** + * If true then the stream has been closed. + **/ + private boolean closed = false; + + /** + * If true then the source reader has reached EOF. + **/ + private boolean atEOF = false; + + /** + * Buffer for unread but decoded bytes. + **/ + private byte buffer[] = new byte[3]; + + /** + * Position of current available character in buffer. + **/ + private byte inBuffer = 3; + + /** + * Construct InputStream given a source of BASE64 encoded text. + **/ + public BASE64InputStream(Reader source) { + this.source = source; + } + + /** + * {@inheritDoc} + **/ + @Override + public int available() throws IOException { + if (closed) { + throw new IOException("InputStream closed."); + } + + int bufferAvail = buffer.length - inBuffer; + + return (bufferAvail > 0) ? bufferAvail : (source.ready() ? 1 : 0); + } + + /** + * {@inheritDoc} + **/ + @Override + public void close() throws IOException { + closed = true; + + source.close(); + source = null; + } + + /** + * {@inheritDoc} + **/ + @Override + public void mark(int readLimit) { + throw new IllegalStateException("Mark not supported."); + } + + /** + * {@inheritDoc} + **/ + @Override + public boolean markSupported() { + return false; + } + + /** + * {@inheritDoc} + **/ + @Override + public int read() throws IOException { + if (closed) { + throw new IOException("InputStream closed."); + } + + while (!atEOF) { + if (inBuffer < buffer.length) { + return buffer[inBuffer++] & 0x00FF; + } + + inBuffer = 0; + + int s0; + + do { + s0 = source.read(); + } while ((-1 != s0) && Character.isWhitespace((char) s0)); + + if (-1 == s0) { + atEOF = true; + break; + } + + int s1 = source.read(); + int s2 = source.read(); + int s3 = source.read(); + + if ((-1 == s1) || (-1 == s2) || (-1 == s3)) { + throw new IOException("Unexpected EOF"); + } + + int c0 = decodeSixBits((char) s0); + int c1 = decodeSixBits((char) s1); + int c2 = decodeSixBits((char) s2); + int c3 = decodeSixBits((char) s3); + + if ((-1 == c0) || (-1 == c1) || (-1 == c2) || (-1 == c3)) { + throw new IOException("Bad character in BASE64 data"); + } + + if (Integer.MAX_VALUE == c0) { + throw new IOException("'=' found in first position of BASE64 data"); + } + + if (Integer.MAX_VALUE == c1) { + throw new IOException("'=' found in second position of BASE64 data"); + } + + if (Integer.MAX_VALUE == c3) { + c3 = 0; + inBuffer++; + } + + if (Integer.MAX_VALUE == c2) { + c2 = 0; + inBuffer++; + } + + int val = (c0 << 18) + (c1 << 12) + (c2 << 6) + c3; + + buffer[ inBuffer ] = (byte) (val >> 16); + + if ((inBuffer + 1) < buffer.length) { + buffer[ inBuffer + 1 ] = (byte) (val >> 8); + } + + if ((inBuffer + 2) < buffer.length) { + buffer[ inBuffer + 2 ] = (byte) val; + } + } + + return -1; + } + + /** + * + * XXX bondolo this would be faster as a table. + **/ + private static int decodeSixBits(char c) { + int v; + + if ('A' <= c && c <= 'Z') { + v = (c - 'A'); + } else if ('a' <= c && c <= 'z') { + v = (c - 'a') + 26; + } else if ('0' <= c && c <= '9') { + v = (c - '0') + 52; + } else if (c == '+') { + v = 62; + } else if (c == '/') { + v = 63; + } else if (c == '=') { + v = Integer.MAX_VALUE; + } else { + v = -1; + } + + return v; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/BASE64OutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/BASE64OutputStream.java new file mode 100644 index 000000000..f2bf45f4f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/BASE64OutputStream.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.io.OutputStream; +import java.io.Writer; + +import java.io.IOException; +import java.io.StringReader; +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; + + +/** + * An OutputStream implementation which encodes the written bytes into BASE64 + * encoded character data and writes the output to an associated text Writer. + * + *

            This implementation is not thread safe. + * + * @see net.jxta.impl.util.BASE64InputStream + * @see IETF RFC 2045 MIME : Format of Internet Message Bodies + **/ +public class BASE64OutputStream extends OutputStream { + + /** + * If true then the output stream has been closed. + **/ + private boolean closed = false; + + /** + * The output writer. + **/ + private Writer sendTo = null; + + /** + * Column width to breakup out. + **/ + private final int columnWidth; + + /** + * Current output column. + **/ + private int column = 0; + + /** + * Buffer for incomplete characters. + **/ + private byte[] buffer = new byte[] { 0, 0, 0 }; + + /** + * The number of characters currently in the buffer. + **/ + private byte inBuffer = 0; + + /** + * Construct a BASE64 Output Stream. + * + * @param sendTo The text Writer to which the BASE64 output will be + * written. + **/ + public BASE64OutputStream(Writer sendTo) { + this(sendTo, -1); + } + + /** + * Construct a BASE64 Output Stream. The output will be broken into lines + * columnWidth long. + * + * @param sendTo The text Writer to which the BASE64 output will be + * written. + * @param columnWidth The width of lines to break output into. + **/ + public BASE64OutputStream(Writer sendTo, int columnWidth) { + this.sendTo = sendTo; + this.columnWidth = columnWidth; + } + + /** + * {@inheritDoc} + **/ + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("OutputStream closed."); + } + + buffer[ inBuffer++ ] = (byte) b; + + if (buffer.length == inBuffer) { + writeBuffer(); + } + } + + /** + * {@inheritDoc} + * + *

            The output writer is NOT closed. + **/ + @Override + public void close() throws IOException { + flush(); + + closed = true; + sendTo = null; + } + + /** + * {@inheritDoc} + **/ + @Override + public void flush() throws IOException { + writeBuffer(); + } + + /** + * Write a full or partial buffer to the output writer. + **/ + private void writeBuffer() throws IOException { + if (0 == inBuffer) { + return; + } + + int val = ((buffer[0] & 0x00FF) << 16) + ((buffer[1] & 0x00FF) << 8) + (buffer[2] & 0x00FF); + + int c0 = (val >> 18) & 0x003F; + int c1 = (val >> 12) & 0x003F; + int c2 = (val >> 6) & 0x003F; + int c3 = val & 0x003F; + + if ((columnWidth > 0) && (column > columnWidth)) { + sendTo.write('\n'); + column = 0; + } + + sendTo.write(encodeSixBits(c0)); + sendTo.write(encodeSixBits(c1)); + + if (inBuffer > 1) { + sendTo.write(encodeSixBits(c2)); + } else { + sendTo.write('='); + } + + if (inBuffer > 2) { + sendTo.write(encodeSixBits(c3)); + } else { + sendTo.write('='); + } + + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + + inBuffer = 0; + column += 4; + } + + /** + * BASE64 Encoding Table + **/ + static final char encode[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X' + , + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v' + , + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + /** + * Encode six bits into a character using the standard BASE64 table. + * + * @param b the bits to encode. b must be >=0 and <= 63 + * @return the appropriate character for the input value. + **/ + private static char encodeSixBits(int b) { + char c; + + if ((b < 0) || (b > 63)) { + throw new IllegalArgumentException("bad encode value"); + } else { + c = encode[b]; + } + + return c; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Base64.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Base64.java new file mode 100644 index 000000000..cea4bf09d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Base64.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.io.IOException; +import java.io.StringReader; +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; + + +/** + * @deprecated Planned for removal. This implementation has been replaced by + * {@link net.jxta.impl.util.BASE64InputStream} and + * {@link net.jxta.impl.util.BASE64OutputStream}. + * + **/ +@Deprecated +public final class Base64 { + + private Base64() {} + + // Base64 encoding. See Rfc1341 + + static public byte[] decodeBase64(String text) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + StringReader r = new StringReader(text); + + for (;;) { + char c0 = getBase64Char(r); + + if (c0 == '\0') { + break; + } + char c1 = getBase64Char(r); + + if (c1 == '\0') { + throw new IOException("binary data not a multiple of four bytes"); + } + char c2 = getBase64Char(r); + + if (c2 == '\0') { + throw new IOException("binary data not a multiple of four bytes"); + } + char c3 = getBase64Char(r); + + if (c3 == '\0') { + throw new IOException("binary data not a multiple of four bytes"); + } + + if (c0 == '=') { + throw new IOException("'=' found in first position of base64 data"); + } + if (c1 == '=') { + throw new IOException("'=' found in second position of base64 data"); + } + int n = 3; + + if (c2 == '=') { + n = 1; + c2 = c3 = 'A'; // So we get a value of 0. + } else if (c3 == '=') { + n = 2; + c3 = 'A'; // So we get a value of 0. + } + + int v = (decodeSixBits(c0) << 18) + (decodeSixBits(c1) << 12) + (decodeSixBits(c2) << 6) + decodeSixBits(c3); + + int b0 = (v >> 16) & 0xff; + int b1 = (v >> 8) & 0xff; + int b2 = (v) & 0xff; + + os.write(b0); + if (n >= 2) { + os.write(b1); + } + if (n == 3) { + os.write(b2); + } + } + + return os.toByteArray(); + } + + /** + * '\0' represents end of file. + */ + static private char getBase64Char(StringReader r) throws IOException { + for (;;) { + int i = r.read(); + + if (i == -1) { + return '\0'; + } + + char c = (char) i; + + if ('A' <= c && c <= 'Z') { + return c; + } else if ('a' <= c && c <= 'z') { + return c; + } else if ('0' <= c && c <= '9') { + return c; + } else if (c == '+') { + return c; + } else if (c == '/') { + return c; + } else if (c == '=') { + return c; + } + + // Not a base64 char, loop around and try again. + + } + } + + static public String encodeBase64(byte[] bytes) { + int n = 0; + StringWriter w = new StringWriter(); + int v; + int h; // Six bits. Six, thus h for hex. + + int len = bytes.length / 3 * 3; + + for (int i = 0; i < len; i += 3) { + v = (bytes[i] << 16) + ((bytes[i + 1] & 0xff) << 8) + (bytes[i + 2] & 0xff); + + h = (v >> 18) & 0x3f; + w.write(encodeSixBits(h)); + + h = ((v >> 12) & 0x3f); + w.write(encodeSixBits(h)); + + h = ((v >> 6) & 0x3f); + w.write(encodeSixBits(h)); + + h = ((v >> 0) & 0x3f); + w.write(encodeSixBits(h)); + + n += 4; + if (n >= 76) { + w.write("\r\n"); + n = 0; + } + + } + + switch (bytes.length - len) { + case 0: + break; + + case 1: + v = (bytes[len] << 16); + + h = (v >> 18) & 0x3f; + w.write(encodeSixBits(h)); + + h = (v >> 12) & 0x3f; + w.write(encodeSixBits(h)); + + w.write('='); + w.write('='); + break; + + case 2: + v = (bytes[len] << 16) + ((bytes[len + 1] & 0xff) << 8); + + h = (v >> 18) & 0x3f; + w.write(encodeSixBits(h)); + + h = ((v >> 12) & 0x3f); + w.write(encodeSixBits(h)); + + h = ((v >> 6) & 0x3f); + w.write(encodeSixBits(h)); + + w.write('='); + break; + } + w.write("\r\n"); + return w.toString(); + } + + static private char encodeSixBits(int b) { + char c; + + if (b <= 25) { + c = (char) ('A' + b); + } else if (b <= 51) { + c = (char) ('a' + b - 26); + } else if (b <= 61) { + c = (char) ('0' + b - 52); + } else if (b == 62) { + c = '+'; + } else { + // if (b == 63) + c = '/'; + } + return c; + } + + static private int decodeSixBits(char c) { + int v; + + if ('A' <= c && c <= 'Z') { + v = (c - 'A'); + } else if ('a' <= c && c <= 'z') { + v = (c - 'a') + 26; + } else if ('0' <= c && c <= '9') { + v = (c - '0') + 52; + } else if (c == '+') { + v = 62; + } else { + // if (c == '/') + v = 63; + } + + return v; + } + + public static void main(String args[]) { + byte bytes[] = new byte[200]; + + for (int i = 0; i < bytes.length; ++i) { + bytes[i] = (byte) i; + } + + System.out.println(encodeBase64(bytes)); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Cache.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Cache.java new file mode 100644 index 000000000..b7399deec --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Cache.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.HashMap; +import java.util.Map; + + +/** + * A Cache which is similar to {@link java.util.LinkedHashMap} + * + *

            LinkedList cannot be used efficiently because it + * cannot remove an element efficiently from the middle. For that, we need + * the externally referenced element (the thing to be removed) to + * be the list entry itself, rather than referenced by an invisible + * list entry. That is why we use the DLink/Dlist family. + */ +public class Cache { + + /** + * CacheEntryImpl objects are both part of a doubly linked list and + * inserted in a HashMap. They refer to the thing mapped which is what + * users of this class want to get, and to the key. The reason is + * that we need the key to remove from the map + * an entry that we found in list. The otherway around is made easy by + * the nature of the dlinked structure. + **/ + + class CacheEntryImpl extends Dlink implements CacheEntry { + + private final Object value; + private final Object key; + + // The application interface. + public CacheEntryImpl(Object k, Object v) { + key = k; + value = v; + } + + /** + * {@inheritDoc} + **/ + public Object getKey() { + return key; + } + + /** + * {@inheritDoc} + **/ + public Object getValue() { + return value; + } + } + + private final long maxSize; + private long size; + private final Map map = new HashMap(); + private final Dlist lru = new Dlist(); + + private final CacheEntryListener listener; + + /** + * Creates a cache whih will keep at most maxSize purgeable entries. + * Every new entry is purgeable by default. + * + *

            Entries that are not purgeable are not counted and are never removed + * unless clear() or remove() is called. Purgeable entries are removed + * silently as needed to make room for new entries so that the number + * of purgeable entries remains < maxSize. + * + *

            Entries prugeability is controlled by invoking the sticky() method + * or the stickyCacheEntry() method. + * + *

            For now, purged entries are abandonned to the GC which is probably not + * so bad. To permit acceleration of the collection of resources, a + * purge listener will be added soon. + */ + public Cache(long maxSize, CacheEntryListener listener) { + this.maxSize = maxSize; + this.size = 0; + this.listener = listener; + } + + /** + * Empties the cache completely. + * The entries are abandonned to the GC. + */ + public void clear() { + lru.clear(); + map.clear(); + } + + /** + * Purges some of the cache. + * The entries are cleaned-up properly. + */ + public void purge(int fraction) { + if (size == 0) { + return; + } + + if (fraction == 0) { + fraction = 1; + } + long nbToPurge = size / fraction; + + if (nbToPurge == 0) { + nbToPurge = 1; + } + + while (nbToPurge-- > 0) { + CacheEntryImpl toRm = (CacheEntryImpl) lru.next(); + + map.remove(toRm.getKey()); + toRm.unlink(); + --size; + if (listener != null) { + listener.purged(toRm); + } + } + } + + /** + * Inserts the given cache entry directly. + * Returns the previous cache entry associated with the given key, if any. + * Not exposed yet. Should not be a problem to expose it, but it is not + * needed yet. + */ + protected CacheEntry putCacheEntry(Object key, CacheEntry value) { + if (size == maxSize) { + CacheEntryImpl toRm = (CacheEntryImpl) lru.next(); + + map.remove(toRm.getKey()); + toRm.unlink(); + --size; + if (listener != null) { + listener.purged(toRm); + } + } + + lru.putLast((CacheEntryImpl) value); + ++size; + + CacheEntryImpl oldEntry = (CacheEntryImpl) map.put(key, value); + + if (oldEntry == null) { + return null; + } + + if (oldEntry.isLinked()) { + oldEntry.unlink(); + --size; + } + return oldEntry; + } + + /** + * Create a cache entry to hold the given value, and insert it. + * Returns the previous value associated with the given key, if any. + */ + public Object put(Object key, Object value) { + CacheEntry oldEntry = putCacheEntry(key, new CacheEntryImpl(key, value)); + + if (oldEntry == null) { + return null; + } + + return oldEntry.getValue(); + } + + /** + * Remove the value, if any, and cacheEntry associated with the given key. + * return the cacheEntry that has been removed. + * Not exposed yet. Should not be a problem to expose it, but it is not + * needed yet. + */ + protected CacheEntry removeCacheEntry(Object key) { + CacheEntryImpl oldEntry = (CacheEntryImpl) map.remove(key); + + if (oldEntry == null) { + return null; + } + if (oldEntry.isLinked()) { + oldEntry.unlink(); + --size; + } + return oldEntry; + } + + /** + * Remove the value, if any, and cacheEntry associated with the given key. + * returns the value that has been removed. + */ + public Object remove(Object key) { + CacheEntry oldEntry = removeCacheEntry(key); + + if (oldEntry == null) { + return null; + } + return oldEntry.getValue(); + } + + /** + * Return the cache entry, if any, associated with the given key. + * This is public; it improves performance by letting the application + * do a single lookup instead of two when it needs to find an object in + * the cache and then change its purgeability. + */ + public CacheEntry getCacheEntry(Object key) { + CacheEntryImpl foundEntry = (CacheEntryImpl) map.get(key); + + if (foundEntry == null) { + return null; + } + + // Leave the purgeability status alone but manage lru position if + // purgeable. + if (foundEntry.isLinked()) { + lru.putLast(foundEntry); + } + return foundEntry; + } + + /** + * Return the value, if any associated with the given key. + */ + public Object get(Object key) { + CacheEntry foundEntry = getCacheEntry(key); + + if (foundEntry == null) { + return null; + } + return foundEntry.getValue(); + } + + /** + * Change the purgeability of the given cacheEntry. + * If sticky is true, the entry cannot be purged. + * Note: if the CacheEntry is known, it is more efficient to use this + * method than sticky(), since sticky will preform a hashmap lookup + * to locate the cache entry. + */ + public void stickyCacheEntry(CacheEntry ce, boolean sticky) { + CacheEntryImpl target = (CacheEntryImpl) ce; + + if (sticky) { + + // Stiky => not purgeable. + + if (!target.isLinked()) { + return; + } + target.unlink(); + --size; + + } else { + + // ! Sticky => purgeable. + + if (target.isLinked()) { + return; + } + if (size == maxSize) { + CacheEntryImpl toRm = (CacheEntryImpl) lru.next(); + + map.remove(toRm.getKey()); + toRm.unlink(); + if (listener != null) { + listener.purged(toRm); + } + --size; + } + + lru.putLast(target); + ++size; + + } + } + + /** + * Force the value associated with the given key to be purgeable or + * non-purgeable from the cache (non-sticky vs. sticky). + * Note: Most often, a call to the get() method will be performed + * before it can be decided to invoke sticky(). Whenever this is the case + * it is better to invoke getCacheEntry() + getValue() and then + * stickyCacheEntry() since that eliminates one hashmap lookup. + */ + public void sticky(Object key, boolean sticky) { + CacheEntry foundEntry = (CacheEntry) map.get(key); + + if (foundEntry == null) { + return; + } + stickyCacheEntry(foundEntry, sticky); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/CacheEntry.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/CacheEntry.java new file mode 100644 index 000000000..ab25ff809 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/CacheEntry.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +/** + * Part of a pre jdk1.4 replacement for LinkedHashMap which is basically a + * cache. The following is the definition of an entry in the cache. + * The implementation is the business of the Cache class. As far as the + * application is concerned, it is a handle that can return a key and + * a value. It is constructed and managed by the Cache class. + */ + +public interface CacheEntry { + public Object getKey(); + public Object getValue(); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/CacheEntryListener.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/CacheEntryListener.java new file mode 100644 index 000000000..40fa9bbb6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/CacheEntryListener.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +/** + * Part of a pre jdk1.4 replacement for LinkedHashMap which is basically a + * cache. The following is the definition of an entry in the cache. + * The implementation is the business of the Cache user. + * This listener is used to alerts the cache owner of events that affect + * cache entries. Currently purge() is the only method. It is called when a + * cache entry is purged from the cache. + */ + +public interface CacheEntryListener { + public void purged(CacheEntry c); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ConsumerBiasedQueue.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ConsumerBiasedQueue.java new file mode 100644 index 000000000..e5b29e555 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ConsumerBiasedQueue.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import java.util.List; +import java.util.ArrayList; + +import net.jxta.impl.util.TimeUtils; + + +/** + * A queue who's implementation is biased towards effciency in removing + elements from the queue. + * + * FIXME 20020511 bondolo@jxta.org This could be more efficient with a + * circular queue implementation, but its a pain to write since we allow the + * queue to be resizable. + * + * FIXME 20020511 bondolo@jxta.org Exercise for the reader: Extend this + * class so that it does both LIFO and FIFO. + * + * @deprecated Please convert all code to use the java.util.concurrent BlockingQueue instead. + * + **/ +@Deprecated +public class ConsumerBiasedQueue extends UnbiasedQueue { + + /** + * Log4J + **/ + private static final Logger LOG = Logger.getLogger(ConsumerBiasedQueue.class.getName()); + + /** + * Default constructor. 100 element FIFO queue which drops oldest element + * when full. + */ + public ConsumerBiasedQueue() { + this(DEFAULT_MAX_OBJECTS, DROP_OLDEST_OBJECT); + } + + /** + * Full featured constructor for creating a new ConsumerBiasedQueue. + * + * @param size Queue will be not grow larger than this size. Use + * Integer.MAX_VALUE for "unbounded" queue size. + * @param dropOldest Controls behaviour of element insertion when the queue is + * full. If "true" and the queue is full upon a push operation then the + * oldest element will be dropped to be replaced with the element currently + * being pushed. If "false" then then newest item will be dropped. + */ + public ConsumerBiasedQueue(int size, boolean dropOldest) { + super(size, dropOldest, new ArrayList()); + } + + /** + * Flush the queue of all pending objects. + **/ + @Override + public void clear() { + synchronized (queue) { + super.clear(); + } + } + + @Override + public synchronized boolean push(Object obj) { + synchronized (queue) { + boolean pushed = super.push(obj); + + queue.notify(); // inform someone who is waiting. we dont have to tell everyone though + return pushed; + } + } + + /** + * Push an object onto the queue. If the queue is full then the push will + * wait for up to "timeout" milliseconds to push the object. At the end of + * "timeout" milliseconds, the push will either return false or remove the + * oldest item from the queue and insert "obj". This behaviour is contolled + * by the constructor parameter "dropOldest". + * + * This method, unlike all others is synchronized. This creates a + * bottleneck for producers seperate from the primary lock on the "queue" + * member. This reduces contention on the primary lock which benefits users + * who are popping items from the queue (Consumers). + * + * @param obj Object to be pushed onto the queue + * @param timeout Time in milliseconds to try to insert the item into a full + * queue. Per Java standards, a timeout of "0" (zero) will wait indefinitly. + * Negative values force no wait period at all. + * @return true if the object was intersted into the queue, otherwise false. + * @throws InterruptedException if the operation is interrupted before + * the timeout interval is completed. + **/ + @Override + public synchronized boolean push(Object obj, long timeout) throws InterruptedException { + return super.push(obj, timeout); + } + + /** + * Return next obj in the queue if there is one. + * + * @return Object, null if the queue is empty + **/ + @Override + public Object pop() { + synchronized (queue) { + return super.pop(); + } + } + + /** + * Returns an array of objects, possibly empty, from the queue. + * + * @param maxObjs the maximum number of items to return. + * @return an array of objects, possibly empty containing the returned + * queue elements. + **/ + @Override + public Object[] popMulti(int maxObjs) { + synchronized (queue) { + return super.popMulti(maxObjs); + } + } + + /** + * Set how many objects this queue may store. Note that if there are more + * objects already in the queue than the specified amount then the queue + * will retain its current capacity. + * + * @param maxObjs The number of objects which the queue must be able to + * store. + **/ + @Override + public void setMaxQueueSize(int maxObjs) { + synchronized (queue) { + super.setMaxQueueSize(maxObjs); + } + } + + /** + * Return the number of elements currently in the queue. This method is + * useful for statistical sampling, but should not be used to determine + * program logic due to the multi-threaded behaviour of these queues. You + * should use the return values and timeout behaviour of the push() and + * pop() methods to regulate how you use the queue. + * + * @return the number of elements currently in the queue. Be warned that + * even two sequential calls to this method may return different answers + * due to activity on other threads. + * + **/ + @Override + public int getCurrentInQueue() { + synchronized (queue) { + return super.getCurrentInQueue(); + } + } + + /** + * Return the average number of elements in the queue at Enqueue time. + * + * @return average number of elements which were in the queue at during all + * of the "push" operations which returned a "true" result. Does not + * include the item being pushed. If no elements have ever been enqueued + * then "NaN" will be returned. + **/ + @Override + public double getAvgInQueueAtEnqueue() { + synchronized (queue) { + return super.getAvgInQueueAtEnqueue(); + } + } + + /** + * Return the average number of elements in the queue at dequeue time. + * + * @return average number of elements which were in the queue at during all + * of the "pop" operations which returned a non-null result. Includes the + * item being "pop"ed in the average. If no elements have ever been dequeued + * then "NaN" will be returned. + **/ + @Override + public double getAvgInQueueAtDequeue() { + synchronized (queue) { + return super.getAvgInQueueAtDequeue(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Dlink.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Dlink.java new file mode 100644 index 000000000..ea9eaff40 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Dlink.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +/** + * A dlinkable base class. + * It is far less general than java's LinkedList but permits much better + * removal performance from the middle of the list because a contained + * element and the corresponding chaining object are one and the same. + * + * The major inconvenient of this class is that it is...a class, not an + * interface. Making it an interface does not make sense since one would have + * to re-implement it entirely. There is almost no value added in a List class + * in addition to a Link class. A list of these Dlink is just a stand-alone + * Dlink with just a couple of additional convenience methods. + */ + +public class Dlink { + + /** + * Previous element in list. + */ + private Dlink prev; + + /** + * Next element in list. + */ + private Dlink next; + + private void setNext(Dlink n) { + next = n; + } + + private void setPrev(Dlink p) { + prev = p; + } + + public Dlink next() { + return next; + } + + public Dlink prev() { + return prev; + } + + public void unlink() { + next.setPrev(prev); + prev.setNext(next); + next = prev = this; + } + + public boolean isLinked() { + return next != this; + } + + public void linkNewNext(Dlink ne) { + ne.unlink(); + ne.setPrev(this); + ne.setNext(next); + next.setPrev(ne); + next = ne; + } + + public void linkNewPrev(Dlink ne) { + ne.unlink(); + ne.setNext(this); + ne.setPrev(prev); + prev.setNext(ne); + prev = ne; + } + + public Dlink() { + next = prev = this; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Dlist.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Dlist.java new file mode 100644 index 000000000..f2f357a69 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/Dlist.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +/** + * A cheap doubly linked list. + * It is far less general than java's LinkedList but permits much better + * removal performance from the middle of the list because a contained + * element and the corresponding chaining object are one and the same. + * + * The major inconvenient of Dlink is that it is a class, not an + * interface. Making it an interface does not make sense since one would have + * to re-implement it entirely. A DList is just a stand-alone + * Dlink with just a couple of additional convenience methods. + * + * Note this class does not keep an element count. The way element removal + * works makes it impossible. Do it from the outside. + */ + +public class Dlist extends Dlink { + + public void putLast(Dlink ne) { + linkNewPrev(ne); + } + + public void putFirst(Dlink ne) { + linkNewNext(ne); + } + + public Dlink last() { + return prev(); + } + + public Dlink first() { + return next(); + } + + public void addLast(Dlink ne) { + linkNewPrev(ne); + } + + public void addFirst(Dlink ne) { + linkNewNext(ne); + } + + public Dlink getLast() { + return prev(); + } + + public Dlink getFirst() { + return next(); + } + + public Dlink removeLast() { + Dlink p = prev(); + + p.unlink(); + return p; + } + + public Dlink removeFirst() { + Dlink n = next(); + + n.unlink(); + return n; + } + + public void clear() { + unlink(); + } + + public boolean isEmpty() { + return !isLinked(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/DynamicEnumeration.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/DynamicEnumeration.java new file mode 100644 index 000000000..4df5507fe --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/DynamicEnumeration.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import java.util.NoSuchElementException; + + +/** + * A dynamic {@link java.util.Enumeration} which allows items to added to the + * enumeration while it is in use. This is mostly intended for use with + * {@link java.io.SequenceInputStream}. When used with {@code SequenceInputStream} + * it is important to call {@code close()} on the enumeration before calling + * {@code close()} on the stream. Failing to do so will cause the stream to + * block as it tries to "drain" the enumeration. + * + *

            This class is entirely thread safe. Attempting to use the enumeration + * and to add objects from a single thread is not recommended, as it may + * deadlock the thread. + * + **/ +public class DynamicEnumeration implements Enumeration { + private List sequence = new ArrayList(); + + private volatile boolean closed = false; + + /** + * Creates a new instance of DynamicEnumeration + **/ + public DynamicEnumeration() {} + + /** + * Creates a new instance of DynamicEnumeration + **/ + public DynamicEnumeration(List initial) { + sequence.addAll(initial); + } + + /** + * {@inheritDoc} + * + *

            If the Enumeration has not been closed we may have to block until we + * have a stream to return. + **/ + public boolean hasMoreElements() { + while (!closed) { + synchronized (sequence) { + if (!sequence.isEmpty()) { + return true; + } + + try { + sequence.wait(); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + } + } + + return false; + } + + /** + * {@inheritDoc} + * + *

            If the Enumeration has not been closed we may have to block until we + * have a stream to return. + **/ + public synchronized Object nextElement() { + while (!closed) { + synchronized (sequence) { + if (sequence.isEmpty()) { + try { + sequence.wait(); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + continue; + } + + Object result = sequence.remove(0); + + return result; + } + } + + throw new NoSuchElementException("No more elements"); + } + + /** + * Add another object to the enumeration. + **/ + public void add(Object add) { + if (closed) { + throw new IllegalStateException("Enumeration was closed"); + } + + synchronized (sequence) { + sequence.add(add); + sequence.notify(); + } + } + + /** + * There will be no more objects added. + **/ + public void close() { + closed = true; + synchronized (sequence) { + sequence.notify(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/EndpointServiceStatsFilter.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/EndpointServiceStatsFilter.java new file mode 100644 index 000000000..c58fdf185 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/EndpointServiceStatsFilter.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessageFilterListener; + +import java.util.Enumeration; +import java.util.Hashtable; + + +/** + * Instances of this clas can be registered with an EndpointService + * to gather statistics about what kind of messages pass through it. + *

            + * This class is not MT-safe, so make sure you plug it only + * into one endpoint service. + * + * @see net.jxta.endpoint.EndpointService#addIncomingMessageFilterListener + */ + +public class EndpointServiceStatsFilter implements MessageFilterListener { + + long lastMessageTime; + Hashtable channelTrafficTable; + Hashtable sourceCountTable; + Hashtable destCountTable; + + public EndpointServiceStatsFilter() { + + channelTrafficTable = new Hashtable(); + sourceCountTable = new Hashtable(); + destCountTable = new Hashtable(); + } + + /** + * This method is called by the EndpointService to give us a chance + * to look at the message before it is dispatched to any listeners. + */ + public Message filterMessage(Message msg, EndpointAddress source, EndpointAddress dest) { + Message.ElementIterator e = msg.getMessageElements(); + MessageElement el; + String namespace; + String name; + + while (e.hasNext()) { + el = e.next(); + + namespace = e.getNamespace(); + name = el.getElementName(); + + incrementCount(channelTrafficTable, source.getProtocolName() + "://" + source.getProtocolAddress() + "/" + namespace + , + (int) el.getByteLength()); + incrementCount(channelTrafficTable, source.getProtocolName() + "://" + source.getProtocolAddress() + "/" + name + , + (int) el.getByteLength()); + } + + if (source != null) { + incrementCount(sourceCountTable, source, 1); + } + + if (dest != null) { + incrementCount(destCountTable, dest, 1); + } + + lastMessageTime = System.currentTimeMillis(); + + return msg; + } + + /** + * Get the time we last saw a message. + * + * @return time last message was received, in milliseconds, + * since Jan. 1, 1970. + */ + + public long getLastMessageTime() { + return lastMessageTime; + } + + /** + * Get the number of messages seen with a given message element + * namespace or full message element name. (Both are referred + * to as "channel" here because filters and listeners are + * dispatched by the EndpointService based on message element + * namespaces or fully name.) + */ + public long getTrafficOnChannel(String channel) { + + return getCount(channelTrafficTable, channel); + } + + public Enumeration getChannelNames() { + return channelTrafficTable.keys(); + } + + /** + * Get the number of messages received from a given address. + */ + public long getMessageCountFrom(EndpointAddress addr) { + return getCount(sourceCountTable, addr); + } + + /** + * Get the number of messages we've seen that were adderssed + * to a given address. + */ + public long getMessageCountTo(EndpointAddress addr) { + return getCount(destCountTable, addr); + } + + private long getCount(Hashtable table, Object key) { + Counter counter = (Counter) table.get(key); + + return counter == null ? -1 : counter.value; + } + + private void incrementCount(Hashtable table, Object key, int incr) { + Counter counter = (Counter) table.get(key); + + if (counter == null) { + counter = new Counter(); + + table.put(key, counter); + } + + counter.value += incr; + } + + private static final class Counter { + long value; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/GenerateID.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/GenerateID.java new file mode 100644 index 000000000..10cf02c76 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/GenerateID.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.util; + + +import net.jxta.id.*; +import net.jxta.platform.*; +import net.jxta.peergroup.*; +import net.jxta.peer.*; +import net.jxta.pipe.*; +import net.jxta.codat.*; + + +/** + * @deprecated This would be much better as a JXTA shell command. Will be removed soon. + * + * Generate a new JXTA IDs from the command line. + * + * @author Kevin A. Burton + */ +@Deprecated +public class GenerateID { + + /** + * main() + * + */ + public static void main(String[] args) { + + try { + + ModuleClassID classID = IDFactory.newModuleClassID(); + + ModuleSpecID specID = IDFactory.newModuleSpecID(classID); + + PeerGroupID groupID = IDFactory.newPeerGroupID(); + + PeerID peerID = IDFactory.newPeerID(groupID); + + PipeID pipeID = IDFactory.newPipeID(groupID); + + CodatID codatID = IDFactory.newCodatID(groupID); + + ModuleSpecID groupSpecID = IDFactory.newModuleSpecID(PeerGroup.allPurposePeerGroupSpecID.getBaseClass()); + + System.out.println("Module Class ID - " + classID.toString()); + System.out.println("Module Spec ID - " + specID.toString()); + System.out.println("Peer Group ID - " + groupID.toString()); + System.out.println("Peer ID - " + peerID.toString()); + System.out.println("Pipe ID - " + pipeID.toString()); + System.out.println("Codat ID - " + codatID.toString()); + System.out.println("Peer Group Module Spec ID - " + groupSpecID.toString()); + + } catch (Throwable t) { + + t.printStackTrace(); + + } + + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/JxtaHash.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/JxtaHash.java new file mode 100644 index 000000000..1d10121b6 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/JxtaHash.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.util; + + +import java.util.*; +import java.io.File; +import java.math.BigInteger; +import java.io.InputStream; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * A message digest wrapper to provide hashing using java.security.MesssageDigest + */ +public class JxtaHash { + private final static Logger LOG = Logger.getLogger(JxtaHash.class.getName()); + public final static String SHA = "SHA"; + public final static String SHA1 = "SHA1"; + public final static String MD2 = "MD2"; + public final static String MD5 = "MD5"; + public final static String DSA = "DSA"; + public final static String RSA = "RSA"; + public final static String SHA1withDSA = "SHA1WITHDSA"; + private MessageDigest dig = null; + + /** + * Default JxtaHash constructor, with the default algorithm SHA1 + * + */ + public JxtaHash() { + try { + dig = MessageDigest.getInstance(SHA1); + } catch (NoSuchAlgorithmException ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(ex.toString()); + } + } + } + + /** + * Default JxtaHash constructor, with the default algorithm SHA1 + * + * @param expression message to hash + */ + public JxtaHash(String expression) { + this(SHA1, expression); + } + + /** + * Constructor for the JxtaHash object + * + * @deprecated This implementation may produce inconsistent results + * based upon varience of the locale. (The locale of getBytes() is + * not defined). + * + * @param algorithm algorithm - the name of the algorithm requested + * @param expression expression to digest + */ + @Deprecated + public JxtaHash(String algorithm, String expression) { + + this(algorithm, expression.getBytes()); + } + + /** + * Constructor for the JxtaHash object + * + * @param algorithm algorithm - the name of the algorithm requested + * @param expression expression to digest + */ + public JxtaHash(String algorithm, byte[] expression) { + try { + dig = MessageDigest.getInstance(algorithm); + if (expression != null) { + dig.update(expression); + } + } catch (NoSuchAlgorithmException ex) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(ex.toString()); + } + } + } + + /** + * Constructor for the JxtaHash object + * + * @param expression expression to digest + */ + public void update(String expression) { + if (expression != null) { + dig.update(expression.getBytes()); + } + } + + /** + * Gets the digest as digestInteger + * + * @return The digestInteger value + */ + public BigInteger getDigestInteger() { + + return new BigInteger(dig.digest()); + } + + /** + * Gets the digest as digestInteger + * + * @param expression expression to digest + * @return The digestInteger value + */ + public BigInteger getDigestInteger(byte[] expression) { + dig.reset(); + dig.update(expression); + return new BigInteger(dig.digest()); + } + + /** + * Gets the digest as digestInteger + * + * @param expression expression to digest + * @return The digestInteger value + */ + public BigInteger getDigestInteger(String expression) { + + return getDigestInteger(expression.getBytes()); + } + + /** + * Returns a int whose value is (getDigestInteger mod m). + * + * @param m the modulus. + * @return (getDigestInteger mod m). + */ + public int mod(long m) { + BigInteger bi = getDigestInteger(); + BigInteger mod = new BigInteger(longToBytes(m)); + BigInteger result = bi.mod(mod); + + return result.intValue(); + } + + /** + * convert a long into the byte array + * + * @param value long value to convert + * @return byte array + */ + private byte[] longToBytes(long value) { + byte[] bytes = new byte[8]; + + for (int eachByte = 0; eachByte < 8; eachByte++) { + bytes[eachByte] = (byte) (value >> ((7 - eachByte) * 8L)); + } + return bytes; + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/LRUCache.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/LRUCache.java new file mode 100644 index 000000000..e48ee64ed --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/LRUCache.java @@ -0,0 +1,216 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.jxta.impl.util; + +import java.util.Iterator; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class implements a Generic LRU Cache. The cache is not thread-safe. + * + * @author Ignacio J. Ortega + * @author Mohamed Abdelaziz + */ + +public class LRUCache { + + private final transient int cacheSize; + private transient int currentSize; + private transient CacheNode first; + private transient CacheNode last; + private final transient Map> nodes; + + /** + * Constructor for the LRUCache object + * + * @param size Description of the Parameter + */ + public LRUCache(int size) { + currentSize = 0; + cacheSize = size; + nodes = new HashMap>(size); + } + + /** + * clear the cache + */ + public void clear() { + first = null; + last = null; + nodes.clear(); + currentSize = 0; + } + + /** + * returns the number of elements currently in cache + * + * @return the number of elements in cache + */ + public int size() { + return currentSize; + } + + /** + * retrieve an object from cache + * + * @param key key + * @return object + */ + public V get(K key) { + CacheNode node = nodes.get(key); + + if (node != null) { + moveToHead(node); + return node.value; + } + return null; + } + + public boolean contains(K key) { + return nodes.keySet().contains(key); + } + + protected Iterator iterator(int size) { + List list = new ArrayList(); + + for (CacheNode node : nodes.values()) { + list.add(node.value); + if (list.size() >= size) { + break; + } + } + return list.iterator(); + } + + private void moveToHead(CacheNode node) { + if (node == first) { + return; + } + if (node.prev != null) { + node.prev.next = node.next; + } + if (node.next != null) { + node.next.prev = node.prev; + } + if (last == node) { + last = node.prev; + } + if (first != null) { + node.next = first; + first.prev = node; + } + first = node; + node.prev = null; + if (last == null) { + last = first; + } + } + + /** + * puts an object into cache + * + * @param key key to store value by + * @param value object to insert + */ + public void put(K key, V value) { + CacheNode node = nodes.get(key); + + if (node == null) { + if (currentSize >= cacheSize) { + if (last != null) { + nodes.remove(last.key); + } + removeLast(); + } else { + currentSize++; + } + node = new CacheNode(key, value); + } + node.value = value; + moveToHead(node); + nodes.put(key, node); + } + + /** + * remove an object from cache + * + * @param key key + * @return Object removed + */ + public V remove(K key) { + CacheNode node = nodes.get(key); + + if (node != null) { + if (node.prev != null) { + node.prev.next = node.next; + } + if (node.next != null) { + node.next.prev = node.prev; + } + if (last == node) { + last = node.prev; + } + if (first == node) { + first = node.next; + } + } + if (node != null) { + return node.value; + } else { + return null; + } + } + + /** + * removes the last entry from cache + */ + private void removeLast() { + if (last != null) { + if (last.prev != null) { + last.prev.next = null; + } else { + first = null; + } + last = last.prev; + } + } + + /** + * cache node object wrapper + */ + protected class CacheNode { + final K key; + CacheNode next; + + CacheNode prev; + V value; + + /** + * Constructor for the CacheNode object + * + * @param key key + * @param value value + */ + CacheNode(K key, V value) { + this.key = key; + this.value = value; + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ModuleManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ModuleManager.java new file mode 100644 index 000000000..81fb365ba --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ModuleManager.java @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.Enumeration; +import java.util.Hashtable; +import java.io.IOException; + +import net.jxta.platform.Module; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Element; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.StructuredDocumentUtils; +import net.jxta.document.TextElement; +import net.jxta.protocol.ModuleClassAdvertisement; +import net.jxta.protocol.ModuleImplAdvertisement; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.id.IDFactory; + + +/** + * Module Manager. + * + * This class allows to manage modules to be loaded, started and stopped + * within a PeerGroup. Modules that are loaded using the ModuleManager do not need + * to be listed within the PeerGroup advertisement, nor do they have to have + * published their ModuleSpec and ModuleImpl advertisements: the ModuleManager + * takes care of this task. However, other peers which may want to load the Module + * will also have to use its own loader (or the ModuleManager itself, of course): + * the ModuleManager only manages Modules on the local peer. + * + * The Module Manager allows, as an option, to use an application provided class loader. + * The default class loader is the PeerGroup class loader. + * + * The following example shows how to use the ModuleManager: + * + * + *

            + *      // Get the peergroup
            + *      PeerGroup group = getMyPeerGroup();
            + *      // Get the ModuleManager
            + *      ModuleManager moduleManager = ModuleManager.getModuleManager (group);
            + *
            + *      // Is the Module already loaded ?
            + *      Module module = moduleManager.lookupModule ("SampleModule");
            + *      if (module == null) {
            + *          // SampleModue is not loaded yet. Load it now.
            + *          module = moduleManager.loadModule ( "SampleModule", "net.jxta.app.SampleModule.SampleModule");
            + *      }
            + *
            + *      // Start SampleModule
            + *      moduleManager.startModule ("SampleModule", moduleArgs);
            + * 
            + */ + +public class ModuleManager { + + private static Hashtable managers = null; + private static long LOCAL_ADV_TTL = 5 * 60 * 1000; + // 5 minutes is more than sufficient + private static long REMOTE_ADV_TTL = 0; + // We do not allow remote access of the advertisements. + + private final Hashtable modules = new Hashtable(); + private final PeerGroup group; + + /** + * Private constructor that allows to create an instance of the Module Manager for each + * PeerGroup. + * + * @param group the PeerGroup for which the ModuleManager needs to allocated a new instance + * of itself. + */ + private ModuleManager(PeerGroup group) { + this.group = group; + } + + /** + * startModule + * + * This method is invoked by the application to start a previously loaded + * module. + * + * @param moduleName is the symbolic name of the module. + * @param args is an array of String containing optional arguments for the module. This + * array is passed directly to the startApp (String[] ) method of the Module. + */ + public void startModule(String moduleName, String[] args) { + + ModuleDesc moduleDesc = modules.get(moduleName); + + if (moduleDesc == null) { + // Cannot find such a module + return; + } + moduleDesc.startApp(args); + } + + /** + * stopModule + * + * This method is invoked by the application to stop a running module. + * + * @param moduleName is the symbolic name of the module. + */ + public void stopModule(String moduleName) { + + ModuleDesc moduleDesc = modules.get(moduleName); + + if (moduleDesc == null) { + // Cannot find such a module + return; + } + moduleDesc.stopApp(); + } + + /** + * getModuleManager + * + * This method is used in order to get the instance of the ModuleManager for a given + * PeerGroup. getModuleManager will create a new instance automatically if there is no + * instance for the given PeerGroup. + * + * @param group the PeerGroup for which the ModuleManager is asked. + * @return the ModuleManager instance for the given PeerGroup. + */ + public static ModuleManager getModuleManager(PeerGroup group) { + + if (managers == null) { + // This is the first time the ModuleManager is invoked. Create + // the Hashtable + managers = new Hashtable(); + } + ModuleManager manager; + + manager = managers.get(group.getPeerGroupID()); + + if (manager == null) { + manager = new ModuleManager(group); + managers.put(group.getPeerGroupID(), manager); + } + return manager; + } + + /** + * Description of the Method + * + * @param moduleName Description of the Parameter + * @param module Description of the Parameter + * @return Description of the Return Value + */ + private synchronized boolean registerModule(String moduleName, Module module) { + + ModuleDesc moduleDesc = modules.get(moduleName); + + if (moduleDesc != null) { + // There is already a module registered to that name. + return false; + } + moduleDesc = new ModuleDesc(module); + modules.put(moduleName, moduleDesc); + return true; + } + + /** + * lookupModule + * + * Get the Module from its symbolic name. + * + * @param moduleName symbolic name of the Module + * @return the Module for the given name. null is returned if there is no module + * of the given name. + */ + public synchronized Module lookupModule(String moduleName) { + + ModuleDesc moduleDesc = modules.get(moduleName); + + if (moduleDesc == null) { + // There is not any module registered to that name. + return null; + } + return moduleDesc.module; + } + + /** + * loadModule + * + * Loads a Module. A class loaded is provided by the application. + * If the module has already been loaded, the existing Module is returned. + * + * @param moduleName symbolic name of the Module + * @param loader application provided class loader + * @return the Module for the given name. null is returned if the module could not be + * loaded + */ + + public synchronized Module loadModule(String moduleName, ModuleManagerLoader loader) { + + // First check if the module is already loaded and registered + Module module = lookupModule(moduleName); + + if (module != null) { + return module; + } + module = loader.loadModule(moduleName); + if (module != null) { + // Since this module is not started by the standard + // JXTA PeerGroup, we need to initialize ourself. + // Note that the ID and the ModuleImplAdvertisement is + // then set to null, which is fine, since that has been + // the decision from the application to actually not use + // the standard PeerGroup Module loading scheme. + try { + module.init(group, null, null); + } catch (Exception e) { + // Init failed, the module cannot be initialized + return null; + } + registerModule(moduleName, module); + } + return module; + } + + /** + * loadModule + * + * Loads a Module. The default PeerGroup class loader will be used. The class + * must be within the CLASSPATH of the platform. + * If the module has already been loaded, the existing Module is returned. + * + * @param moduleName symbolic name of the Module + * @param moduleCode the name of the class to be loaded. + * @return the Module for the given name. null is returned if the module could not be + * loaded + */ + public synchronized Module loadModule(String moduleName, String moduleCode) { + + // First check if the module is already loaded and registered + Module module = lookupModule(moduleName); + + if (module != null) { + return module; + } + + if (!createModuleAdvs(moduleName, null, moduleCode, null, LOCAL_ADV_TTL, REMOTE_ADV_TTL)) { + + // Creation of the module advertisement has failed. + return null; + } + // Get the module. This should always work since the advertisements have + // just been created. + module = loadModule(moduleName); + if (module == null) { + // There is really nothing more we can do here. + return null; + } + return module; + } + + /** + * Description of the Method + * + * @param moduleName Description of the Parameter + * @return Description of the Return Value + */ + private synchronized Module loadModule(String moduleName) { + + // First check if the module is already loaded and registered + Module module = lookupModule(moduleName); + + if (module != null) { + return module; + } + + try { + // Recover the ModuleClassAdvertisement + Enumeration each = group.getDiscoveryService().getLocalAdvertisements(DiscoveryService.ADV, "Name", moduleName); + + if (!each.hasMoreElements()) { + // No advertisement. + return null; + } + + ModuleClassAdvertisement mcAdv = null; + + while (each.hasMoreElements()) { + try { + mcAdv = (ModuleClassAdvertisement) each.nextElement(); + break; + } catch (Exception ez1) {// ignored + } + } + + // Revover the Module Specification Advertisement + each = group.getDiscoveryService().getLocalAdvertisements(DiscoveryService.ADV, "Name", moduleName); + if (!each.hasMoreElements()) { + return null; + } + + ModuleSpecAdvertisement mSpecAdv = null; + + while (each.hasMoreElements()) { + try { + mSpecAdv = (ModuleSpecAdvertisement) each.nextElement(); + break; + } catch (Exception ez1) {// ignored + } + } + + module = group.loadModule(mcAdv.getModuleClassID(), mSpecAdv.getModuleSpecID(), PeerGroup.Here); + + if (module != null) { + registerModule(moduleName, module); + } + return module; + } catch (Exception ez2) { + return null; + } + } + + /** + * Description of the Method + * + * @param moduleName Description of the Parameter + * @param moduleSpecURI Description of the Parameter + * @param moduleCode Description of the Parameter + * @param moduleCodeURI Description of the Parameter + * @param localTTL Description of the Parameter + * @param remoteTTL Description of the Parameter + * @return Description of the Return Value + */ + private boolean createModuleAdvs(String moduleName, String moduleSpecURI, String moduleCode, String moduleCodeURI, long localTTL, long remoteTTL) { + + DiscoveryService disco = group.getDiscoveryService(); + + try { + // First create the Module class advertisement associated with the module + // We build the module class advertisement using the advertisement + // Factory class by passing it the type of the advertisement we + // want to construct. The Module class advertisement is to be used + // to simply advertise the existence of the module. This is a + // a very small advertisement that only advertise the existence + // of module. In order to access the module, a peer will + // have to discover the associated module spec advertisement. + + ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType()); + + mcadv.setName(moduleName); + mcadv.setDescription("Created by ModuleManager: " + moduleName); + + ModuleClassID mcID = IDFactory.newModuleClassID(); + + mcadv.setModuleClassID(mcID); + + // Ok the Module Class advertisement was created, just publish + // it in my local cache and to my peergroup. This + // is the NetPeerGroup + disco.publish(mcadv, localTTL, remoteTTL); + + // Create the Module Spec advertisement associated with the module + // We build the module Spec Advertisement using the advertisement + // Factory class by passing in the type of the advertisement we + // want to construct. The Module Spec advertisement will contain + // all the information necessary for a client to contact the module + // for instance it will contain a pipe advertisement to + // be used to contact the module + + ModuleSpecAdvertisement mdadv = (ModuleSpecAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType()); + + // ModuleManager does not allow to set up any customized + // information for the Module. + + mdadv.setName(moduleName); + mdadv.setCreator("jxta.org"); + mdadv.setModuleSpecID(IDFactory.newModuleSpecID(mcID)); + + if (moduleSpecURI != null) { + mdadv.setSpecURI(moduleSpecURI); + } + + // Ok the Module advertisement was created, just publish + // it in my local cache and into the NetPeerGroup. + disco.publish(mdadv, localTTL, remoteTTL); + + // Create the Module Implementation advertisement + ModuleImplAdvertisement miadv = (ModuleImplAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType()); + + miadv.setModuleSpecID(mdadv.getModuleSpecID()); + if (moduleCode != null) { + miadv.setCode(moduleCode); + } + + if (moduleCodeURI != null) { + miadv.setUri(moduleCodeURI); + } + miadv.setDescription("Created by ModuleManager: " + moduleName); + + // Steal the compat, provider, and uri from the + // group's own impl adv. We DO want them identical in + // this case. + ModuleImplAdvertisement pgImpl = (ModuleImplAdvertisement) group.getImplAdvertisement(); + + miadv.setCompat(pgImpl.getCompat()); + miadv.setUri(pgImpl.getUri()); + + // Ok the Module Class advertisement was created, just publish + // it in my local cache and to my peergroup. This + // is the NetPeerGroup + disco.publish(miadv, localTTL, remoteTTL); + } catch (Exception ex) { + return false; + } + return true; + } + + // FIXME this method should be refactored + /** + * Creates a Module Class, Spec, and Impl advertisements, and adds the service + * Advertisement as part of the Module Impl Advertisement, and publishes the advertisements + * in local cache + * + * @param group group + * @param moduleName module name + * @param description module description + * @param moduleSpecURI module spec uri + * @param moduleCode module code + * @param moduleCodeURI module code uri + * @param mcID module class id + * @param msID module spec id + * @param code module code + * @param serviceAdv service advertisement + * @param localTTL local cache lifetime in ms + * @param remoteTTL remote cache lifetime in ms + * @exception IOException if an io error occurs + */ + public void createServiceAdvertisement(PeerGroup group, String moduleName, String description, String moduleSpecURI, String moduleCode, String moduleCodeURI, ModuleClassID mcID, ModuleSpecID msID, String code, Advertisement serviceAdv, long localTTL, long remoteTTL) throws IOException { + + DiscoveryService discovery = group.getDiscoveryService(); + // Create module class advertisement + ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType()); + + mcadv.setModuleClassID(mcID); + mcadv.setName(moduleName); + mcadv.setDescription(description); + + // Module spec advertisement + ModuleSpecAdvertisement mdspec = (ModuleSpecAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType()); + + mdspec.setModuleSpecID(msID); + mdspec.setName(moduleName); + mdspec.setSpecURI(moduleSpecURI); + + // Module implementation advertisement + ModuleImplAdvertisement miadv = (ModuleImplAdvertisement) + AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType()); + + miadv.setModuleSpecID(mdspec.getModuleSpecID()); + miadv.setDescription(description); + if (moduleCodeURI != null) { + miadv.setUri(moduleCodeURI); + } + if (moduleCode != null) { + miadv.setCode(moduleCode); + } + // Steal the compat, provider, and uri from the + // group's own impl adv. We DO want them identical in + // this case. + ModuleImplAdvertisement pgImpl = (ModuleImplAdvertisement) group.getImplAdvertisement(); + + miadv.setCompat(pgImpl.getCompat()); + miadv.setCode(code); + Element pEl = (Element) serviceAdv.getDocument(MimeMediaType.XMLUTF8); + StructuredDocument svcParm = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm"); + + StructuredDocumentUtils.copyElements(svcParm, svcParm, pEl); + miadv.setParam(svcParm); + // publish the advertisements + discovery.publish(mcadv, localTTL, remoteTTL); + discovery.publish(mdspec, localTTL, remoteTTL); + discovery.publish(miadv, localTTL, remoteTTL); + } + + /** + * Retreives a Service Advertisement from a module impl advertisement + * @param group peer group + * @param mia ModuleImplAdvertisement + * @param advertismentType service advertisment string Type + * @return The service Advertisement + * @exception IOException if an io error occurs + */ + public Advertisement getServiceAdvertisement(PeerGroup group, ModuleImplAdvertisement mia, String advertismentType) throws IOException { + Element param = mia.getParam(); + Element pel = null; + + if (param != null) { + Enumeration list = param.getChildren(advertismentType); + + if (list.hasMoreElements()) { + pel = (Element) list.nextElement(); + } + } + Advertisement adv = AdvertisementFactory.newAdvertisement((TextElement) pel); + + return adv; + } + + /** + * Description of the Class + */ + private class ModuleDesc { + + /** + * Description of the Field + */ + protected Module module = null; + private boolean started = false; + private boolean stopped = true; + + /** + *Constructor for the ModuleDesc object + * + * @param module Description of the Parameter + */ + public ModuleDesc(Module module) { + this.module = module; + } + + /** + * Description of the Method + * + * @param args Description of the Parameter + */ + public void startApp(String[] args) { + if (module == null) { + return; + } + if (started) { + // Already started - nothing to do + return; + } + module.startApp(args); + started = true; + stopped = false; + } + + /** + * Description of the Method + */ + public void stopApp() { + if (module == null) { + return; + } + if (stopped) { + // Already stopped - nothing to do + return; + } + module.stopApp(); + stopped = true; + started = false; + } + } + + + /** + * ModuleManagerLoader interface. + * This interface is used by the application in order to provide its own + * class loader instead of using the standard PeerGroup loader. + */ + + public interface ModuleManagerLoader { + + /** + * This method is invoked by the ModuleManager when it is time to load + * the class associated to the module. The name of the module is provided, + * which allows the application provided loader to be able to load a variety + * of modules, if that is necessary for the application. Note that the ModuleManager + * assumes that the module which is loaded by the provided loader is not started: + * loading and starting a module are two different operations for the ModuleManager. + * + * @param moduleName is the symbolic name of the Module. + * @return Module the object that has been loaded. + */ + public Module loadModule(String moduleName); + } + +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ProducerBiasedQueue.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ProducerBiasedQueue.java new file mode 100644 index 000000000..084276d07 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ProducerBiasedQueue.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import java.util.List; +import java.util.ArrayList; + +import net.jxta.impl.util.TimeUtils; + + +/** + * A queue who's implementation is biased towards effciency in adding elements + * to the queue. + * + * @deprecated Please convert all code to use the java.util.concurrent BlockingQueue instead. + * + **/ +@Deprecated +public class ProducerBiasedQueue extends UnbiasedQueue { + + /** + * Log4J + **/ + private static final Logger LOG = Logger.getLogger(ProducerBiasedQueue.class.getName()); + + /** + * Default constructor. 100 element FIFO queue which drops oldest element + * when full. + */ + public ProducerBiasedQueue() { + this(DEFAULT_MAX_OBJECTS, DROP_OLDEST_OBJECT); + } + + /** + * Full featured constructor for creating a new ConsumerBiasedQueue. + * + * @param size Queue will be not grow larger than this size. Use + * Integer.MAX_VALUE for "unbounded" queue size. + * @param dropOldest Controls behaviour of element insertion when the queue is + * full. If "true" and the queue is full upon a push operation then the + * oldest element will be dropped to be replaced with the element currently + * being pushed. If "false" then then newest item will be dropped. + */ + public ProducerBiasedQueue(int size, boolean dropOldest) { + super(size, dropOldest, new ArrayList()); + } + + /** + * Flush the queue of all pending objects. + **/ + @Override + public void clear() { + synchronized (queue) { + super.clear(); + } + } + + @Override + public boolean push(Object obj) { + synchronized (queue) { + boolean pushed; + + pushed = super.push(obj); + queue.notify(); // inform someone who is waiting. we dont have to tell everyone though. + return pushed; + } + } + + /* The pop methods of this queue, unlike the "push" method. This creates a + * bottleneck for producers seperate from the primary lock on the "queue" + * member. This reduces contention on the primary lock which benefits users + * who are popping items from the queue (Consumers). + * + */ + + /** + * Return next obj in the queue if there is one. + * + * @return Object, null if the queue is empty + **/ + @Override + public synchronized Object pop() { + synchronized (queue) { + return super.pop(); + } + } + + /** + * Gets a Object from the queue. If no Object is immediately available, + * then wait the specified amount of time. Per Java convention, a timeout + * of zero (0) means wait an infinite amount of time. Negative values mean + * do not wait at all. + * + * @param timeout amount of time to wait in milliseconds for an object to + * be available. Per Java convention, a timeout of zero (0) means wait an + * infinite amount of time. Negative values mean do not wait at all. + * @return The next object in the queue. + * @throws InterruptedException if the operation is interrupted before + * the timeout interval is completed. + */ + @Override + public synchronized Object pop(long timeout) throws InterruptedException { + synchronized (queue) { + return super.pop(timeout); + } + } + + /** + * Returns an array of objects, possibly empty, from the queue. + * + * @param maxObjs the maximum number of items to return. + * @return an array of objects, possibly empty containing the returned + * queue elements. + **/ + @Override + public synchronized Object[] popMulti(int maxObjs) { + synchronized (queue) { + return super.popMulti(maxObjs); + } + } + + /** + * Set how many objects this queue may store. Note that if there are more + * objects already in the queue than the specified amount then the queue + * will retain its current capacity. + * + * @param maxObjs The number of objects which the queue must be able to + * store. + **/ + @Override + public void setMaxQueueSize(int maxObjs) { + synchronized (queue) { + super.setMaxQueueSize(maxObjs); + } + } + + /** + * Return the number of elements currently in the queue. This method is + * useful for statistical sampling, but should not be used to determine + * program logic due to the multi-threaded behaviour of these queues. You + * should use the return values and timeout behaviour of the push() and + * pop() methods to regulate how you use the queue. + * + * @return the number of elements currently in the queue. Be warned that + * even two sequential calls to this method may return different answers + * due to activity on other threads. + * + **/ + @Override + public int getCurrentInQueue() { + synchronized (queue) { + return super.getCurrentInQueue(); + } + } + + /** + * Return the average number of elements in the queue at Enqueue time. + * + * @return average number of elements which were in the queue at during all + * of the "push" operations which returned a "true" result. Does not + * include the item being pushed. If no elements have ever been enqueued + * then "NaN" will be returned. + **/ + @Override + public double getAvgInQueueAtEnqueue() { + synchronized (queue) { + return super.getAvgInQueueAtEnqueue(); + } + } + + /** + * Return the average number of elements in the queue at dequeue time. + * + * @return average number of elements which were in the queue at during all + * of the "pop" operations which returned a non-null result. Includes the + * item being "pop"ed in the average. If no elements have ever been dequeued + * then "NaN" will be returned. + **/ + @Override + public double getAvgInQueueAtDequeue() { + synchronized (queue) { + return super.getAvgInQueueAtDequeue(); + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/RdvAdvSeedingManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/RdvAdvSeedingManager.java new file mode 100644 index 000000000..7f0cdbddb --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/RdvAdvSeedingManager.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2002-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.logging.Logging; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + +/** + * Adds the ability to discover RdvAdvs via Discovery. + */ +public class RdvAdvSeedingManager extends ACLSeedingManager { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(URISeedingManager.class.getName()); + + /** + * The minimum frequence at which we will update our seed lists. + */ + final static long MIN_REFRESH_INTERVAL = 30 * TimeUtils.ASECOND; + + /** + * Group who's services we will utilize. + */ + final PeerGroup group; + + /** + * The identifier which we use to distinguish our RdvAdvertisements. + */ + final String serviceName; + + /** + * The absolute time in milliseconds at which we may sen our next remote + * discovery. + */ + long nextRemoteDiscovery = 0; + + /** + * The Route Advertisements we have discovered. + */ + final List discoveredRoutes = new ArrayList(); + + /** + * Creates a new instance of RdvAdvSeedingManager + * + * @param aclLocation The location of the ACL file or {@code null} if no + * ACL file should be used. + */ + public RdvAdvSeedingManager(URI aclLocation, PeerGroup group, String serviceName) { + super(aclLocation); + + this.group = group; + this.serviceName = serviceName; + } + + /** + * Update seeds + */ + private void refreshActiveSeeds() { + DiscoveryService discovery = group.getDiscoveryService(); + + if((null != discovery) && (TimeUtils.timeNow() > nextRemoteDiscovery)) { + // Send a remote search hoping for future responses. + discovery.getRemoteAdvertisements(null, DiscoveryService.ADV, RdvAdvertisement.ServiceNameTag, serviceName, 3); + + Enumeration advs; + try { + advs = discovery.getLocalAdvertisements(DiscoveryService.ADV, RdvAdvertisement.ServiceNameTag, serviceName); + } catch( IOException failed ) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure retrieving advertisements" , failed); + } + + return; + } + + synchronized(this) { + discoveredRoutes.clear(); + + while(advs.hasMoreElements()) { + Advertisement anAdv = advs.nextElement(); + if(!(anAdv instanceof RdvAdvertisement)) { + continue; + } + + RdvAdvertisement rdvAdv = (RdvAdvertisement) anAdv; + RouteAdvertisement routeAdv = rdvAdv.getRouteAdv(); + routeAdv.setDestPeerID(rdvAdv.getPeerID()); + + discoveredRoutes.add(routeAdv); + } + + Collections.shuffle(discoveredRoutes); + + if(discoveredRoutes.isEmpty()) { + // Be extra aggressive if we haven't found anything yet. + nextRemoteDiscovery = TimeUtils.toAbsoluteTimeMillis(MIN_REFRESH_INTERVAL / 2); + } else { + nextRemoteDiscovery = TimeUtils.toAbsoluteTimeMillis(MIN_REFRESH_INTERVAL); + } + } + } + } + + /** + * {@inheritDoc} + */ + public void stop() { + // do nothing. + } + + /** + * {@inheritDoc} + */ + public synchronized URI[] getActiveSeedURIs() { + refreshActiveSeeds(); + + List results = new ArrayList(); + + int eaIndex = 0; + boolean addedEA; + + do { + addedEA = false; + + for (RouteAdvertisement aRA : discoveredRoutes) { + List raEAs = aRA.getDestEndpointAddresses(); + if (eaIndex < raEAs.size()) { + URI seedURI = raEAs.get(eaIndex).toURI(); + if(!results.contains(seedURI)) { + results.add(seedURI); + } + addedEA = true; + } + } + + // Next loop we use the next most preferred address. + eaIndex++; + } while (addedEA); + + return results.toArray(new URI[results.size()]); + } + + /** + * {@inheritDoc} + */ + public synchronized RouteAdvertisement[] getActiveSeedRoutes() { + refreshActiveSeeds(); + + List results = new ArrayList(); + + for( RouteAdvertisement eachRoute : discoveredRoutes ) { + if(!results.contains(eachRoute)) { + results.add(eachRoute); + } + } + + return results.toArray(new RouteAdvertisement[results.size()]); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceAccount.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceAccount.java new file mode 100644 index 000000000..b505ebbe9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceAccount.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +/** + * A descriptor for a resource consumser. The resource consumer's resource + * allocation and dynamic usage is tracked. + */ +public interface ResourceAccount { + + /** + * Tear down this account. + * Releases all reserved resources. + */ + public void close(); + + /** + * Try and grant a new item to this account. If it cannot be done, + * the account may be eligible for the next available extra item. + * The account is automatically set to be in need, as if inNeed(true) + * has been invoked. + * + * @return boolean true if an item was granted, false otherwise. + */ + public boolean obtainItem(); + + /** + * Try and grant a certain quantity. + * + *

            It is useful to manage the allocation of variable sized aggregates + * when what matters is the cummulated quantity rather than an item + * count. Quantity could be a number of bytes needed to store + * something for example. The advantage of using this method rather + * than obtainItem repeatedly is that it is obvisouly faster if + * quantity is more than one or two, and also that it is atomic; + * the entire quantity is either granted or denied. + * Using this routine is by definition incompatible with the round-robin + * mode, which could only re-assign quantities of 1. + * + *

            It is legal to use this routine along with round-robin mode if the + * same dispatcher is used to manage quantities of 1 in this manner, + * but an account that has failed to obtain its desired quantity is + * not queued for later re-assignment. And items released with + * releaseQuantity() are not re-assigned, so overall it is + * probably best to not mix the two. + * + * @param quantity The number of units wanted. The unit is arbitrary + * It is only meaningfull to the code that uses this dispatcher. + * @return boolean whether the requested quantity is authorized. + */ + public boolean obtainQuantity(long quantity); + + /** + * This will release an item and return the most eligible account to + * re-use this item for. The account that is returned has been granted + * the item and thus the invoker is expected to do with this account + * whatever an invoker of obtainItem() would do in case of success. + * If the items that are managed are threads, the invoker is + * likely to be one these threads and it should therefore process + * the returned account as it did the one for which it was calling + * releaseItem, however be very carefull not to process the new account + * in the context of the old one; that would rapidly lead to stack + * overflow. In other words, be carefull of not making a construct + * equivalent to: + * + *

            +     * process() {
            +     *   doStuff();
            +     *   myAccount.releaseItem().getUserObject().process();
            +     * }
            +     * 
            + * + * That won't work. Instead do: + * + *

            +     * work() {
            +     *  while (myAccount != null) {
            +     *   myAccount.getUserObject().doStuff();
            +     *   myAccount = myAccount.releaseItem();
            +     *  }
            +     * }
            +     * 
            + * + *

            Or similar; always go back to base stack level. + * It is mandatory to handle accounts returned by {@code releaseItem()}. + * If handling leads to releaseItem, then it has to be done in a + * forever loop. That is typical if the items are threads. + * That is normally not happening if the items are only memory. + * + * @return ResourceAccount the account to which the released item + * has been re-assigned. null if the released item was not re-assigned. + */ + public ResourceAccount releaseItem(); + + /** + * This will release a number of items at once rather than + * once. To be used in conjunctino with obtainItems(). See that + * method. + * + * @param quantity the number of items to be released. + */ + public void releaseQuantity(long quantity); + + /** + * Call this with true as soon as this account needs a new item. + * Call this with false as soon as this account has all that it needs. + * For proper operation, this must be done. + * + * @param needs Whether the account needs a new item or not. + */ + public void inNeed(boolean needs); + + /** + * @return Object The userObject that was supplied when creating the + * account. + */ + public Object getUserObject(); + + /** + * Set the userObject associated with that account. + */ + public void setUserObject(Object obj); + + /** + * Returns the number of reserved items that can still be obtained by + * this account. + * + *

            If that number is negative or zero, it means that all reserved + * items are currently in use. Still more items might still be obtained + * from the extra items pool. + * + * @return long The number of reserved items. + */ + public long getNbReserved(); + + /** + * Tells if this account is idle (that is, none of the resources + * that it controls are currently in use). This means it can be closed + * safely. + */ + public boolean isIdle(); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceDispatcher.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceDispatcher.java new file mode 100644 index 000000000..019ce2d0c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceDispatcher.java @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.LinkedList; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.impl.util.ResourceAccount; + + +/** + * This class does not in itself allocate anything; it just does accounting. + * Its role is to make sure that resource consumers ("accounts") + * are guaranteed to be able to hold a pre-determined number of items, + * the extra being granted on a first-come-first-serve basis. + * It just replies yes/no to an account that wants to allocate an item. + * Synchronization is external. + * + *

            Note that this is all essentially a limiter device. It assumes + * that the resources that are dispatched in that way are not otherwise + * in short supply. + * + *

            The rules of the game are as follows: + *

            At initialization, an absolute maximum authorized number of items + * is computed. All item reservations and authorizations are done + * within this budget. + *

            At any given point in time, out of this maximum, a number of items are + * permanently reserved for the minimum guaranteed to each current account, + * a number of items are set aside for future accounts guarantee reservation, + * and the rest is open for dynamic attribution on a first come first serve + * basis. + * + *

            The current strategy is as follows: + * + * The initialization parameters are:

              + *
            • minimum number of guaranteed accounts: {@code minAccounts}
            • + *
            • minimum commitment to new accounts up to minAccounts: {@code minReserve}
            • + *
            • maximum commitment to new accounts: {@code maxReserve}
            • + *
            • extra number of dynamically allocatable items: {@code extraItems}
            • + *
            + * + *

            We infer the number of items dedicated to reservation: {@code reservedItems} + * That is {@code minReserve * minAccounts}. + * + *

            Accounts can ask for a commitment in excess of minReserve. Any reservation + * made by an account beyond the minimum is satisfied from extraItems + * limited by what's available and maxReserve. When minAccounts have + * registered, it is possible that reservedItems is exhausted. New accounts + * are then accepted on a best effort basis using extra items exclusively. This + * may cause such new accounts to be given a commitment inferior to minReserve, + * including zero. It is up to the account to reject the offer and give up + * by closing, or to go along with the offer. At this time, we do not try + * to raise the commitment made to an account while it is registered. + * + *

            During the life of the account, items are allocated first from the set + * reserved by this account. If the account is out of reserved items, an attempt + * is made at getting the item from extraItems. + * + *

            For each account we count the number of items reserved from reservedItems, + * reserved from extraItems, allocated from the local reserved items + * and allocated from extraItems separately. When an item is released, it is + * accounted to extraItems if the account had anything allocated from + * extra items, or to the local reserved items. + * When an account goes away, the number of items that were reserved from + * reserveItems go back to reserveItems and likewise for those coming + * from extraItems. This is done rather than giving priority to reserve + * items so that the system does not favor reservation beyond its initial + * parameters when an account goes away under load. + * + *

            When resources are scarce, two modes of operations are available. + *

            + *
            Unfair
            + *
            each account keeps its items as long it has a use for them. If + * the allocation of a new item is denied for an account, the account just has + * to live with it and try again the next time more items are desired. + *
            + *
            RoundRobin
            + *
            Each account releases each item after one use. When allocation + * of a new item is denied for an account by reason of item shortage, the + * account is placed on a list of eligible accounts. Every time an item is + * released, it is re-assigned to the oldest eligible account. + *
            + *
            + *

            From an API point of view the difference is not visible: account users + * are advised to release items after one use. Release returns the account to + * which the item has been re-assigned. If RoundRobin is not used, then + * the item is always re-assigned to the account that releases it unless it + * is not needed, in which case it returns to the available pool. + * So, with round-robin off the following is true: + *

            + * a.releaseItem() == (a.needs ? a : null);
            + * 
            + */ + +public class ResourceDispatcher { + + /** + * Logger + */ + private final static transient Logger LOG = Logger.getLogger(ResourceDispatcher.class.getName()); + + private long extraItems; + private long reservedItems; + private final long maxReservedPerAccount; + private final long minReservedPerAccount; + private final long maxExtraPerAccount; + private final long minExtraPoolSize; + private int nbEligibles; + + private final String myName; + + class ClientAccount extends Dlink implements ResourceAccount { + + /** + * Tells whether this account has any use for extra resources + * or not. This feature is required to support roundRobin mode + * properly when resources are scarce. + */ + private boolean needs; + + /** + * The number of items reserved for this account that may still be + * allocated. This decrements when we grant an item allocation. When + * it is <= 0, new items may be obtained from extraItems. If obtained + * we still decrement. When an item is released, if this counter is + * < 0 we return the item to extra items. This counter gets + * incremented either way. + */ + private long nbReserved; + + /** + * The number out of nbReserved that is due back in reservedItems + * when this account disappears. + * The rest goes back to extraItems. + * NOTE: If we go away with items unaccounted for, we take the option + * of accounting them as allocated. In other words, that amount is + * not returned to its right full item account. That's why we do not + * need to keep track of allocated items. The leak is felt + * by this allocator. Alternatively we could pretend that the + * leaked resources are not ours; but that might break the actual + * allocator of the resource if it relies on our accounting. + */ + private long fromReservedItems; + + /** + * Same idea but they have been reserved by reducing the number + * of extra items available. + */ + private final long fromExtraItems; + + /** + * The limit for extra items allocation. + * When nbReserved is at or below that, extra items cannot be + * granted. + */ + private final long extraLimit; + + /** + * The external object for which this account manages items. + * This is an opaque cookie to us. Whatever code invokes + * releaseItem knows what to do with it and the re-assigned item, but + * it needs to be told which of its own object got an item assigned. + */ + private Object userObject; + + /** + * Creates a client account with this resource manager. + * Not for external use. + * @param fromReservedItems + * @param fromExtraItems + * @param extraLimit + * @param userObject + */ + ClientAccount(long fromReservedItems, long fromExtraItems, long extraLimit, Object userObject) { + + this.nbReserved = fromReservedItems + fromExtraItems; + this.fromReservedItems = fromReservedItems; + this.fromExtraItems = fromExtraItems; + this.extraLimit = -extraLimit; + this.userObject = userObject; + this.needs = false; + } + + /** + * {@inheritDoc} + * + *

            To accelerate return of resources to the global pool, one + * may call close() explicitly. Otherwise it is called by + * {@code finalize}. + * + *

            Calling close() or letting the account be GC'ed while some of the + * resources have not been returned is an error, may create a leak and + * may display a warning message. + */ + public void close() { + notEligible(); + userObject = null; + + if ((nbReserved == 0) && (fromReservedItems == 0) && (fromExtraItems == 0)) { + return; + } + + if (nbReserved < (fromReservedItems + fromExtraItems)) { + // !!! someone just gave up on its resource controller + // without returning the resources ! + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("An account was abandoned with resources still allocated."); + } + + // Release whatever we can. + if (nbReserved >= fromReservedItems) { + releaseExtra(nbReserved - fromReservedItems); + releaseReserved(fromReservedItems); + } else if (nbReserved > 0) { + releaseReserved(nbReserved); + } + + } else { + releaseReserved(fromReservedItems); + releaseExtra(fromExtraItems); + } + + nbReserved = 0; + } + + /** + * {@inheritDoc} + * + *

            Will close the account. (close is idempotent). + */ + @Override + protected void finalize() throws Throwable { + close(); + + super.finalize(); + } + + /** + * {@inheritDoc} + */ + public boolean isIdle() { + return (nbReserved == fromExtraItems + fromReservedItems); + } + + public boolean isEligible() { + return isLinked(); + } + + /** + * Put that account in the queue of accounts eligible to + * receive a resource when one becomes available. + */ + public void beEligible() { + if ((eligibles != null) && !isEligible()) { + newEligible(this); + } + } + + /** + * Remove that account from the queue of accounts eligible to + * receive a resource when one becomes available. + */ + public void notEligible() { + if ((eligibles != null) && isEligible()) { + unEligible(this); + } + } + + // An extra item is being granted to this account (by being reassigned + // from another account upon release). + private void granted() { + + // In theory, there cannot be an account that should NOT be granted + // an item in the eligibles list. For now, check whether the theory + // survives observations. + // It could happen that the need flag was turned off while this + // account was in the eligible list. That's not realy a problem. + // Either it will be released immediately, or we could filter + // it in mostEligible(). + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + if (nbReserved <= extraLimit) { + LOG.warning("An account that should not get an item was found in the eligibles list"); + } + } + + --nbReserved; + + // We've been assigned an item. No-longer eligible. + notEligible(); + } + + /** + * {@inheritDoc} + */ + public boolean obtainQuantity(long quantity) { + + if ((nbReserved - quantity) < extraLimit) { + // That's asking too much. Denied. + return false; + } + + if (quantity > nbReserved) { + // We need to get some or all of it from the extra items. + long toAsk = nbReserved > 0 ? quantity - nbReserved : quantity; + long res = holdExtra(toAsk); + + if (res != toAsk) { + // Could not get enough. We got nothing. + releaseExtra(res); + return false; + } + } + + // Now record it. + nbReserved -= quantity; + + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + if (nbReserved > fromReservedItems + fromExtraItems) { + LOG.severe("Incorrect values after obtaining " + quantity + " : [" + this + "]"); + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + public boolean obtainItem() { + + // Set it for consistency. It will get cleared when + // the item is used to satisfy the need. + needs = true; + + if (nbReserved > 0) { + notEligible(); + --nbReserved; + return true; // Its pre-reserved. + } + + // This account may deliberately limit the number of extra + // items it uses. this translates into a lower limit for + // nbReserved when <= 0. + if (nbReserved <= extraLimit) { + notEligible(); + return false; + } + + if (holdExtra(1) == 1) { // Need authorization. + notEligible(); + --nbReserved; + return true; + } + + // We are out of luck but eligible. + beEligible(); + return false; + } + + /** + * {@inheritDoc} + */ + public void releaseQuantity(long quantity) { + if (nbReserved < 0) { + releaseExtra(quantity < -nbReserved ? quantity : -nbReserved); + } + nbReserved += quantity; + if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { + if (nbReserved > fromReservedItems + fromExtraItems) { + LOG.severe("Incorrect values after releasing " + quantity + " : [" + this + "]"); + } + } + } + + /** + * {@inheritDoc} + */ + public ResourceAccount releaseItem() { + if (nbReserved < 0) { + if (eligibles == null) { + // RoundRobin is OFF either we reuse it or we let + // it go. + if (needs) { + return this; + } + + ++nbReserved; + releaseExtra(1); + return null; + } + + // RoundRobin is ON, we compete with others for this item. + ++nbReserved; + + // Update our eligibility which depends on extraLimit and + // whether we have a use for the item or not. + if ((nbReserved > extraLimit) && needs) { + beEligible(); + } + + ClientAccount next = mostEligible(); + + if (next == null) { + releaseExtra(1); // noone wants it. return to main pool + } else { + next.granted(); + } + return next; + } + + // Since we are (back) in our reserved range, we can't be eligible + // for extra. + notEligible(); + + // In reserved range; we keep using the item if we need it. + if (needs) { + return this; + } + + ++nbReserved; + return null; + } + + /** + * {@inheritDoc} + */ + public void inNeed(boolean needs) { + this.needs = needs; + if ((nbReserved < 0) && (nbReserved > extraLimit) && needs) { + beEligible(); + } else { + notEligible(); + } + } + + /** + * {@inheritDoc} + */ + public Object getUserObject() { + return userObject; + } + + /** + * {@inheritDoc} + */ + public void setUserObject(Object object) { + userObject = object; + } + + /** + * {@inheritDoc} + */ + public long getNbReserved() { + return nbReserved; + } + + /** + * {@inheritDoc} + * + *

            Returns some human-readable status and identity information useful for debugging. + */ + @Override + public String toString() { + return super.toString() + " : needs=" + needs + " nbReserved=" + nbReserved + " fromReservedItems=" + + fromReservedItems + " fromExtraItems=" + fromExtraItems + " extraLimit=" + extraLimit; + } + + } + + /** + * The list of eligible accounts. + */ + private Dlist eligibles; + + /** + * Construct a Fair Resource Allocator with the given parameters: + * @param minAccounts The minimum number of client accounts that we want to + * guarantee we can handle. <0 means 0 + * + * @param minReservedPerAccount The minimum reservation request that we will + * always grant to accounts as long as we have less than minAccounts <0 means + * 0. + * @param maxReservedPerAccount The maximum reservation request that we ever + * will grant to any given account. extraItems means ==extraItems. + * @param minExtraPoolSize The number of extra items that can never be + * taken out of the extra pool to satisfy a reservation request. + * @param roundRobin If true, when there is no items available, all + * eligible accounts are put in a FIFO. Accounts release items often, and the + * oldest account in the FIFO will get it. If false, accounts always keep + * items for as long as they can use them, and there is no FIFO of eligible + * accounts. Accounts can obtain new resources only if available at the time + * they try to aquire it. RoundRobin is more fair but has more overhead. + * Neither mode will cause starvation as long as accounts reserve at least + * one item each. RoundRobin is most useful when allocating threads. + */ + public ResourceDispatcher(long minAccounts, long minReservedPerAccount, long maxReservedPerAccount, long extraItems, long maxExtraPerAccount, long minExtraPoolSize, boolean roundRobin, String dispatcherName) { + if (minAccounts < 0) { + minAccounts = 0; + } + if (minReservedPerAccount < 0) { + minReservedPerAccount = 0; + } + if (maxReservedPerAccount < minReservedPerAccount) { + maxReservedPerAccount = minReservedPerAccount; + } + if (extraItems < 0) { + extraItems = 0; + } + if (minExtraPoolSize < 0) { + minExtraPoolSize = 0; + } + + if ((maxExtraPerAccount < 0) || (maxExtraPerAccount > extraItems)) { + maxExtraPerAccount = extraItems; + } + + this.extraItems = extraItems; + this.minExtraPoolSize = minExtraPoolSize; + this.maxReservedPerAccount = maxReservedPerAccount; + this.minReservedPerAccount = minReservedPerAccount; + this.reservedItems = minAccounts * minReservedPerAccount; + this.maxExtraPerAccount = maxExtraPerAccount; + nbEligibles = 0; + if (roundRobin) { + eligibles = new Dlist(); + } + + this.myName = dispatcherName; + } + + private long holdReserved(long req) { + if (req > reservedItems) { + req = reservedItems; + } + reservedItems -= req; + return req; + } + + private void releaseReserved(long nb) { + reservedItems += nb; + } + + private long holdExtra(long req) { + if (req > extraItems) { + req = extraItems; + } + extraItems -= req; + return req; + } + + // Get items from the extra pool but only if there is at least + // minExtraPoolSize item + // left after that. The goal is to make sure we keep at least one + // un-reserved item when granting reserved items from the extra pool. + // Thanks to that, even accounts that could not get a single reserved + // item still stand a chance to make progress by taking turns using + // the one extra item left. + private long holdExtraKeepSome(long req) { + if (extraItems <= minExtraPoolSize) { + return 0; + } + long allowed = extraItems - minExtraPoolSize; + + if (req > allowed) { + req = allowed; + } + extraItems -= req; + return req; + } + + private void releaseExtra(long nb) { + extraItems += nb; + } + + private void newEligible(ClientAccount account) { + ++nbEligibles; + eligibles.putLast(account); + } + + private ClientAccount mostEligible() { + if (nbEligibles == 0) { + return null; + } + return (ClientAccount) eligibles.getFirst(); + } + + private void unEligible(ClientAccount account) { + --nbEligibles; + account.unlink(); + } + + // Not synch; it's just a snapshot for trace purposes. + public int getNbEligibles() { + return nbEligibles; + } + + /** + * Creates and returns a new client account. + * + * @param nbReq the number of reserved items requested (may not be + * always granted in full). A negative value is taken to mean 0. + * @param maxExtra the number of additional items that this account + * authorizes to be allocated in addition to the reserved ones. This + * is typically useful if the items are threads and if some accounts + * are not re-entrant. Then nbReq would be 1 and maxExtra would be 0. + * It is also permitted to have some accounts receive no items at all + * ever by setting nbReq and maxExtra both to zero. A negative maxExtra + * is taken as meaning no specified limit, in which case an actual limit + * may be set silently. + * @param userObject An opaque cookie that the account object will return + * when requested. This is useful to relate an account returned by + * ClientAccount.releaseItem() to an invoking code relevant object. + * @return ResourceAccount An account with this allocator. + */ + public ResourceAccount newAccount(long nbReq, long maxExtra, Object userObject) { + + long extra = 0; // reserved from extra pool + long reserved = 0; // reserved from reserved pool + + if (nbReq > maxReservedPerAccount) { + nbReq = maxReservedPerAccount; + } + + // Anything beyond the minimum comes from extra items if there's + // enough. + if (nbReq > minReservedPerAccount) { + extra = holdExtraKeepSome(nbReq - minReservedPerAccount); + nbReq = minReservedPerAccount; + } + + // Then the minimum comes from reserved items, if we can. + reserved = holdReserved(nbReq); + nbReq -= reserved; + + // If there's some letf to be had, it means that we're getting + // short on reserved items, we'll try to compensate by getting + // more items from extra, but the app should start getting rid + // of stale accounts if it can. + if (nbReq > 0) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Accepting extra account on a best effort basis."); + } + + extra += holdExtraKeepSome(nbReq); + if (extra + reserved < minReservedPerAccount) { + // Even that was not enough to reach our minimal commitment. + // The app should realy consider some cleanup. + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("[" + myName + "] Accepting extra account with below-minimal commitment:[" + userObject + "]"); + } + } + } + + if ((maxExtra > maxExtraPerAccount) || (maxExtra < 0)) { + maxExtra = maxExtraPerAccount; + } + + return new ClientAccount(reserved, extra, maxExtra, userObject); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/SeedingManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/SeedingManager.java new file mode 100644 index 000000000..e9b20319c --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/SeedingManager.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2002-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Random; +import java.util.Set; +import java.util.SortedSet; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeSet; + +import java.io.IOException; +import java.io.File; +import java.net.URISyntaxException; +import java.util.NoSuchElementException; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Attribute; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.endpoint.EndpointListener; +import net.jxta.endpoint.EndpointService; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.MessageTransport; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.TextDocumentMessageElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peer.PeerID; +import net.jxta.peergroup.PeerGroup; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.protocol.RdvAdvertisement; +import net.jxta.protocol.RouteAdvertisement; +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezvousListener; + +import net.jxta.impl.access.AccessList; +import net.jxta.impl.endpoint.relay.RelayClient; +import net.jxta.impl.protocol.RdvConfigAdv; +import net.jxta.impl.rendezvous.RendezVousServiceImpl; +import net.jxta.impl.util.TimeUtils; + + +/** + * Manages the location of seed peers. + */ +public interface SeedingManager { + + /** + * Stop this seeding manager. + */ + public void stop(); + + /** + * Returns the route advertisements of the active seed peers. The route + * advertisements are returned in the order which the consumer should + * attempt to contact the seed peers. In some cases the returned route + * advertisements may omit the destination {@code PeerID} if it is not + * known. + * + * @return The route advertisements of the active seed peers in the order + * in which the seed peers should be contacted. + */ + public RouteAdvertisement[] getActiveSeedRoutes(); + + /** + * Returns the {@code URI} of the endpoint addresses of the active seed + * peers. The {@code URI}s are returned in the order which the consumer + * should attempt to contact the seed peers. + * + *

            Using the endpoint address {@code URI}s is less optimal than using + * the route advertisements as there is no association between the + * potentially multiple message transport addresses referring to a single + * peer. + * + * @return The {@code URI}s of the active seed peers in the order + * in which the seed peers should be contacted. + */ + public URI[] getActiveSeedURIs(); + + /** + * Returns {@code true} if the provided peer advertisement is an acceptable + * peer as determined by the seeding manager. + * + * @param peeradv The {@code PeerAdvertisement} of the peer being tested. + */ + public boolean isAcceptablePeer(PeerAdvertisement peeradv); + + /** + * Returns {@code true} if the provided route advertisement is an acceptable + * peer as determined by the seeding manager. + * + * @param radv The {@code RouteAdvertisement} of the peer being tested. + */ + public boolean isAcceptablePeer(RouteAdvertisement radv); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/SequenceIterator.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/SequenceIterator.java new file mode 100644 index 000000000..eec3b0042 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/SequenceIterator.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import java.util.NoSuchElementException; + + +/** + * This class lets you combine a number of iterators. + */ +public class SequenceIterator implements Iterator { + + private Iterator iterators; + + private Iterator current = null; + + private Iterator previous = null; + + /** + * Creates a new instance of SequenceIterator + * + * @param iterators An iterator containing instances of Iterator. This + * iterator will iterate over all of the item in these iterators. + **/ + public SequenceIterator(Iterator iterators) { + this.iterators = iterators; + } + + /** + * Creates a new instance of SequenceIterator + **/ + public SequenceIterator(Iterator first, Iterator second) { + List iterators = new ArrayList(2); + + iterators.add(first); + iterators.add(second); + + this.iterators = iterators.iterator(); + } + + /** + * {@inheritDoc} + **/ + public boolean hasNext() { + + if ((null == current) || (!current.hasNext())) { + do { + if (!iterators.hasNext()) { + return false; + } + + current = (Iterator) iterators.next(); + } while (!current.hasNext()); + } + + return true; + } + + /** + * {@inheritDoc} + **/ + public Object next() { + if (!hasNext()) { + throw new NoSuchElementException("no next element"); + } + + previous = current; + return current.next(); + } + + /** + * {@inheritDoc} + **/ + public void remove() { + if (null == previous) { + throw new IllegalStateException("next() has not been called"); + } + + previous.remove(); + previous = null; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/TimeUtils.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/TimeUtils.java new file mode 100644 index 000000000..41c229213 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/TimeUtils.java @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.util; + +/** + * Utilities for manipulating absolute and relative times and for accelerating + * and decelerating time for testing purposes. + *

            + * The "time warp" functionality is useful for debugging and is scoped to + * the class loader in which the TimeUtils class is loaded. + */ +public final class TimeUtils { + + /** + * Zero milliseconds (yes its redundant). + */ + public static final long ZEROMILLISECONDS = 0L; + + /** + * The number of milliseconds in a millisecond. (yes its redundant). + */ + public static final long AMILLISECOND = 1L; + + /** + * The number of milliseconds in a hundredth of a second. + */ + public static final long AHUNDREDTHOFASECOND = 10 * AMILLISECOND; + + /** + * The number of milliseconds in a tenth of a second. + */ + public static final long ATENTHOFASECOND = 100 * AMILLISECOND; + + /** + * The number of milliseconds in a second. + */ + public static final long ASECOND = 1000 * AMILLISECOND; + + /** + * The number of milliseconds in a minute. + */ + public static final long AMINUTE = 60 * ASECOND; + + /** + * The number of milliseconds in an hour. + */ + public static final long ANHOUR = 60 * AMINUTE; + + /** + * The number of milliseconds in a day. + */ + public static final long ADAY = 24 * ANHOUR; + + /** + * The number of milliseconds in a week. + */ + public static final long AWEEK = 7 * ADAY; + + /** + * The number of milliseconds in a fortnight (two weeks). + */ + public static final long AFORTNIGHT = 14 * ADAY; + + /** + * The number of milliseconds in the month of January. + */ + public static final long AJANUARY = 31 * ADAY; + + /** + * The number of milliseconds in the month of February in a non-leap year. + */ + public static final long AFEBRUARY = 28 * ADAY; + + /** + * The number of milliseconds in the month of February in a leap year. + */ + public static final long ALEAPFEBRUARY = 29 * ADAY; + + /** + * The number of milliseconds in the month of March. + */ + public static final long AMARCH = 31 * ADAY; + + /** + * The number of milliseconds in the month of April. + */ + public static final long ANAPRIL = 30 * ADAY; + + /** + * The number of milliseconds in the month of May. + */ + public static final long AMAY = 31 * ADAY; + + /** + * The number of milliseconds in the month of June. + */ + public static final long AJUNE = 30 * ADAY; + + /** + * The number of milliseconds in the month of July. + */ + public static final long AJULY = 31 * ADAY; + + /** + * The number of milliseconds in the month of August. + */ + public static final long ANAUGUST = 31 * ADAY; + + /** + * The number of milliseconds in the month of September. + */ + public static final long ASEPTEMBER = 30 * ADAY; + + /** + * The number of milliseconds in the month of October. + */ + public static final long ANOCTOBER = 31 * ADAY; + + /** + * The number of milliseconds in the month of November. + */ + public static final long ANOVEMBER = 30 * ADAY; + + /** + * The number of milliseconds in the month of December. + */ + public static final long ADECEMBER = 31 * ADAY; + + /** + * The number of milliseconds in a non-leap year. + */ + public static final long AYEAR = AJANUARY + AFEBRUARY + AMARCH + ANAPRIL + AMAY + AJUNE + AJULY + ANAUGUST + ASEPTEMBER + + ANOCTOBER + ANOVEMBER + ADECEMBER; + + /** + * The number of milliseconds in a leap year. + */ + public static final long ALEAPYEAR = AJANUARY + ALEAPFEBRUARY + AMARCH + ANAPRIL + AMAY + AJUNE + AJULY + ANAUGUST + + ASEPTEMBER + ANOCTOBER + ANOVEMBER + ADECEMBER; + + /** + * This odd little guy is for use in testing. it is applied anywhere the + * current time is used and allows modules which use timeutils to be tested + * through long (simulated) periods of time passing. + */ + static volatile long TIMEWARP = 0; + + /** + * Absolute time in millis at which we began timewarping. + */ + static long WARPBEGAN = 0; + + /** + * The rate at which time is warped using the auto-warper. + */ + static double WARPFACTOR = 1.0; + + /** + * Don't let anyone instantiate this class. + */ + private TimeUtils() { + } + + /** + * Return the current time. This value may differ from the value returned + * by {@link System#currentTimeMillis()} if the {@link #timeWarp(long)} or + * {@link #autoWarp(double)} features are being used. Using + * {@link #timeNow()} allows test harnesses to simulate long periods of + * time passing. + * + * @return The current time which has been possibly adjusted by a "time warp" + * factor. + */ + public static long timeNow() { + long now = System.currentTimeMillis(); + + if (WARPFACTOR != 1.0) { + long elapsed = now - WARPBEGAN; + + long dialation = (long) (elapsed * WARPFACTOR); + + TIMEWARP += (dialation - elapsed); + } + + return now + TIMEWARP; + } + + /** + * Convert a duration into a duration expressed in milliseconds to absolute + * time realtive to the current real time. Special handling for the maximum + * and minimum durations converts them to the maximum and minimum absolute + * times. + * + * @param duration a time duration expressed in milliseconds. + * @return an absolute time in milliseconds based on the duration's + * relation to the current real time. + */ + public static long toAbsoluteTimeMillis(long duration) { + + return toAbsoluteTimeMillis(duration, timeNow()); + } + + /** + * Convert a duration into a duration expressed in milliseconds to absolute + * time realtive to the provided absolute time. Special handling for the + * maximum and minimum durations converts them to the maximum and minimum + * absolute times. + * + * @param duration a time duration expressed in milliseconds. + * @param fromWhen an absolute time expressed in milliseconds. + * @return an absolute time in milliseconds based on the duration's + * relation to the provided absolute time. + */ + public static long toAbsoluteTimeMillis(long duration, long fromWhen) { + + // Special cases for the boundaries. + + if (Long.MAX_VALUE == duration) { + return Long.MAX_VALUE; + } + + if (Long.MIN_VALUE == duration) { + return Long.MIN_VALUE; + } + + long whence = fromWhen + duration; + + if (duration > 0) { + // check for overflow + if (whence < fromWhen) { + whence = Long.MAX_VALUE; + } + + } else { + // check for underflow + if (whence > fromWhen) { + whence = Long.MIN_VALUE; + } + } + + return whence; + } + + /** + * Convert an absolute real time in milliseconds to a duration relative + * to the current real time. Special handling for the maximum and minimum + * absolute times converts them to the maximum and minimum durations. + * + * @param whence an absolute real time expressed in milliseconds. + * @return a duration expressed in milliseconds relative to the current + * real time. + */ + public static long toRelativeTimeMillis(long whence) { + return toRelativeTimeMillis(whence, timeNow()); + } + + /** + * Convert an absolute real time in milliseconds to a duration relative + * to the specified absolute real time. Special handling for the maximum + * and minimum absolute times converts them to the maximum and minimum + * durations. + * + * @param whence An absolute real time expressed in milliseconds. + * @param fromWhen The base time in absolute real time expressed in + * milliseconds from which the relative time will be calculated. + * @return a duration expressed in milliseconds relative to the provided + * absolute time. + */ + public static long toRelativeTimeMillis(long whence, long fromWhen) { + // Special cases for the boundaries. + + if (Long.MAX_VALUE == whence) { + return Long.MAX_VALUE; + } + + if (Long.MIN_VALUE == whence) { + return Long.MIN_VALUE; + } + + return whence - fromWhen; + } + + /** + * Multiplies a duration in relative milliseconds by a multiplier while + * accounting for overflow and underflow of the magnitude value. + * + * @param duration a time duration expressed in milliseconds. + * @param multiplier a non-negative value which will be multiplied against + * the duration. + * @return a time duration expressed in milliseconds. + */ + public static long multiplyRelativeTimeMillis(long duration, long multiplier) { + if (multiplier < 0) { + throw new IllegalArgumentException("Only non-negative multipliers are allowed."); + } + + long result_mag = (Long.MIN_VALUE != duration) + ? Long.highestOneBit(Math.abs(duration)) + Long.highestOneBit(multiplier) + : Long.SIZE + Long.highestOneBit(multiplier); + long result = duration * multiplier; + + if (result_mag > (Long.SIZE - 1)) { + // over or underflowed + result = (duration < 0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } + + return result; + } + + /** + * A utility for advancing the timewarp by the number of milliseconds + * specified. May not be used if you are also using {@link #autoWarp(double)}. + * + * @param advanceby Advance the timewarp by the number of milliseconds + * specified. + */ + public static void timeWarp(long advanceby) { + if (0 != WARPBEGAN) { + throw new IllegalStateException("auto time warping already initialized at warp factor " + WARPFACTOR); + } + + TIMEWARP += advanceby; + } + + /** + * A utility for automagically adjusting the time dialation of the + * time warp. + * + * @param warpfactor a decimal ratio at which artifical time will pass. + *

            + *

              + *
            • To have time pass at the rate of an hour every minute, initialize + * with: (double)(TimeUtils.ANHOUR / TimeUtils.AMINUTE).
            • + *
            • To have time pass at five times normal rate, initialize + * with: 5.0.
            • + *
            • etc.
            • + *
            + */ + public static void autoWarp(double warpfactor) { + if (0 != WARPBEGAN) { + throw new IllegalStateException("Auto time warping already initialized at warp factor " + WARPFACTOR); + } + + if (warpfactor <= 0.0) { + throw new IllegalArgumentException("Time should not stand still or run backwards. It's unnatural."); + } + + if (warpfactor != 1.0) { + WARPFACTOR = warpfactor; + WARPBEGAN = System.currentTimeMillis(); + } + } + + /** + * Return a relative time adjusted by the current warping factor. + * Needed for external methods which do not use {@link #timeNow()} such + * as {@link Object#wait(long)} and + * {@link java.net.Socket#setSoTimeout(int)}. + * + * @param initial The initial time value to "warp". + * @return The provided initial time adjusted by the current warping factor. + */ + public static long warpedRelativeTime(long initial) { + if (0 == initial) { + return 0; + } + + long adjusted = (long) (initial * WARPFACTOR); + + // Handle overflow and underflow + if (initial < 0) { + if (adjusted >= 0) { + adjusted = Long.MIN_VALUE; + } + } else { + if (adjusted < 0) { + adjusted = Long.MAX_VALUE; + } + } + + // since 0 is usually a special "wait forever" value we don't allow time + // to be reduced to zero because that would cause a change of behaviour + // in many cases. + return (0 != adjusted) ? adjusted : 1; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/TimerThreadNamer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/TimerThreadNamer.java new file mode 100644 index 000000000..d0f711af9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/TimerThreadNamer.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.TimerTask; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * A simple timer task who's sole purpose is to name the Thread on which timer + * tasks are running. You normally use it by : + * + *
            
            + *  Timer timer = new Timer();
            + *  timer.schedule( new TimerThreadNamer( "name for timer" ), 0 );
            + * 
            + * + * @deprecated Beginning with JSE 5.0 you may now name a Timer directly. + * + *

            Note that this implementation assumes the Timer implemntation found in + * Sun JDK 1.2-1.5 (and possibly later) in that there is a single thread + * attached to each Timer object. + **/ +@Deprecated +public class TimerThreadNamer extends TimerTask { + + private final static transient Logger LOG = Logger.getLogger(TimerThreadNamer.class.getName()); + + private boolean firstRun = true; + + private String nameToUse; + + /** + * Construct a Timer Thread Namer object + * + * @param useName The name which the timer thread will be given. + **/ + public TimerThreadNamer(String useName) { + nameToUse = useName; + + } + + /** + * {@inheritDoc} + **/ + @Override + public synchronized void run() { + + if (firstRun) { + Thread.currentThread().setName(nameToUse); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Naming TimerThread to : " + nameToUse); + } + nameToUse = null; + firstRun = false; + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/URISeedingManager.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/URISeedingManager.java new file mode 100644 index 000000000..835f95a81 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/URISeedingManager.java @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2002-2004 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.text.MessageFormat; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; +import net.jxta.document.Attribute; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.MimeMediaType; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.endpoint.EndpointAddress; +import net.jxta.impl.endpoint.EndpointUtils; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.AccessPointAdvertisement; +import net.jxta.protocol.PeerAdvertisement; +import net.jxta.protocol.RouteAdvertisement; + + +/** + * A seeding manager that supports both explicit seed peers and loading of + * seeds from seeding resources. + */ +public class URISeedingManager extends RdvAdvSeedingManager { + + /** + * Logger + */ + private static final transient Logger LOG = Logger.getLogger(URISeedingManager.class.getName()); + + /** + * The minimum amount of time we will wait between attempts to resolve the + * seeding URI sources. + */ + private static final long MINIMUM_SEEDING_REFRESH_INTERVAL = 5 * TimeUtils.AMINUTE; + + /** + * The standard interval at which we will attempt to refresh from the + * seeding URI sources. Also the maximum we will wait between failed + * attempts. + */ + private static final long STANDARD_SEEDING_REFRESH_INTERVAL = 30 * TimeUtils.AMINUTE; + + /** + * Whether we are restricted to using seed rdvs only. + */ + private boolean allowOnlySeeds = false; + + /** + * These URIs specify location of seed peer lists. The URIs will be resolved + * via URLConnection and are assumed to refer to plain text lists of + * absolute URIs or an XML document containing a list of Route Advertisements. + */ + private final Set seedingURIs = new HashSet(); + + /** + * The absolute time in milliseconds after which we will attempt to refresh + * the active seeds list using the seeding URIs. + */ + private long nextSeedingURIrefreshTime = 0; + + /** + * The number of sequential failures we have encountered while loading + */ + private int failedSeedingLoads = 0; + + /** + * These are seed peers which were specified as part of the configuration + * data or programmatically. These seeds are never deleted. + */ + private final Set permanentSeeds = new HashSet(); + + /** + * The ranked list of active seed peers. The seed addresses are ranked as + * follows : + * + *

              + *
            1. The lists of seed addresses returned by reading from the seeding + * addresses in the order they were returned. The seeding addresses are + * processed in random order.
            2. + *
            3. The list of permanent seed addresses in random order.
            4. + *
            + * + * Consumers of the seed list should process the list in the order returned + * and not request a new list until they have exhausted all entries from + * the each returned lists or found an active seed. + */ + private final List activeSeeds = new ArrayList(); + + + /** + * Get an instance of URISeedingManager. + * + * @param aclLocation The location of the ACL file or {@code null} if no + * ACL file should be used. + * @param allowOnlySeeds If {@code true} then the only peers which are part + * of the seed peer set will be + */ + public URISeedingManager(URI aclLocation, boolean allowOnlySeeds, PeerGroup group, String serviceName) { + super(aclLocation, group, serviceName); + + this.allowOnlySeeds = allowOnlySeeds; + } + + /** + * {@inheritDoc} + */ + public void stop() { + super.stop(); + } + + /** + * Adds the specified URI to the list of permanent seeds. Even if + * {@code allowOnlySeeds} is in effect, this seed may now be used, as if it + * was part of the initial configuration. + * + * @param seed The URI of the seed peer. + */ + public synchronized void addSeed(URI seed) { + RouteAdvertisement ra = (RouteAdvertisement) + AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); + AccessPointAdvertisement apa = (AccessPointAdvertisement) + AdvertisementFactory.newAdvertisement(AccessPointAdvertisement.getAdvertisementType()); + + ra.addDestEndpointAddress(new EndpointAddress(seed)); + + permanentSeeds.add(ra); + activeSeeds.add(ra); + } + + /** + * Adds the specified URI to the list of permanent seeds. Even if + * {@code allowOnlySeeds} is in effect, this seed may now be used, as if it + * was part of the initial configuration. + * + * @param seed The RouteAdvertisement of the seed peer. + */ + public synchronized void addSeed(RouteAdvertisement seed) { + permanentSeeds.add(seed.clone()); + activeSeeds.add(seed.clone()); + } + + /** + * Adds the specified URI to the list of seeding URIs. + * + * @param seeding The URI of the seeding list. + */ + public synchronized void addSeedingURI(URI seeding) { + seedingURIs.add(seeding); + + // Reset the refresh timer so that our new seeding URI will get used. + nextSeedingURIrefreshTime = TimeUtils.timeNow(); + } + + /** + * {@inheritDoc} + */ + public synchronized URI[] getActiveSeedURIs() { + List result = new ArrayList(); + + refreshActiveSeeds(); + + int eaIndex = 0; + boolean addedEA; + + do { + addedEA = false; + + for (RouteAdvertisement aRA : activeSeeds) { + List eas = aRA.getDest().getVectorEndpointAddresses(); + + if (eaIndex < eas.size()) { + String anEndpointAddress = eas.get(eaIndex); + + try { + result.add(new URI(anEndpointAddress)); + addedEA = true; + } catch (URISyntaxException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "bad address in route : " + anEndpointAddress, failed); + } + } + } + } + + // Next loop we use the next most preferred address. + eaIndex++; + } while (addedEA); + + // Add more primordial seeds. + if(!allowOnlySeeds) { + for(URI eachURI : Arrays.asList(super.getActiveSeedURIs())) { + if(!result.contains(eachURI)) { + result.add(eachURI); + } + } + } + + return result.toArray(new URI[result.size()]); + } + + /** + * {@inheritDoc} + */ + public synchronized RouteAdvertisement[] getActiveSeedRoutes() { + + refreshActiveSeeds(); + + List result = new ArrayList(activeSeeds); + + // Add more primordial seeds. + if(!allowOnlySeeds) { + for(RouteAdvertisement eachRoute : Arrays.asList(super.getActiveSeedRoutes())) { + if(!result.contains(eachRoute)) { + result.add(eachRoute); + } + } + } + + return result.toArray(new RouteAdvertisement[result.size()]); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized boolean isAcceptablePeer(PeerAdvertisement peeradv) { + RouteAdvertisement route = EndpointUtils.extractRouteAdv(peeradv); + + boolean acceptable = true; + + if (allowOnlySeeds) { + acceptable = isSeedPeer(route); + } + + if (!acceptable) { + return false; + } + + if (null != route) { + return isAcceptablePeer(route); + } else { + return acl.getGrantAll(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized boolean isAcceptablePeer(RouteAdvertisement radv) { + boolean acceptable = true; + + if (allowOnlySeeds) { + acceptable = isSeedPeer(radv); + } + + return acceptable && super.isAcceptablePeer(radv); + } + + private void refreshActiveSeeds() { + if (TimeUtils.timeNow() < nextSeedingURIrefreshTime) { + return; + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Regenerating active seeds list."); + } + + activeSeeds.clear(); + + if (!seedingURIs.isEmpty()) { + List allSeedingURIs = new ArrayList(seedingURIs); + boolean allLoadsFailed = true; + + Collections.shuffle(allSeedingURIs); + + for (URI aSeedingURI : allSeedingURIs) { + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Loading seeding list from : " + aSeedingURI); + } + + RouteAdvertisement ras[] = loadSeeds(aSeedingURI); + + for (RouteAdvertisement aRA : Arrays.asList(ras)) { + if (!activeSeeds.contains(aRA)) { + // Only add non-duplicates. + activeSeeds.add(aRA); + allLoadsFailed = false; + } + } + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Failed loading seeding list from : " + aSeedingURI); + } + } + } + + if (allLoadsFailed) { + // Allow for an early reload if we couldn't contact any of the + // seeding URIS. + failedSeedingLoads++; + long nextAttemptInterval = Math.min(MINIMUM_SEEDING_REFRESH_INTERVAL * failedSeedingLoads, + STANDARD_SEEDING_REFRESH_INTERVAL); + + nextSeedingURIrefreshTime = TimeUtils.toAbsoluteTimeMillis(nextAttemptInterval); + } else { + failedSeedingLoads = 0; + nextSeedingURIrefreshTime = TimeUtils.toAbsoluteTimeMillis(STANDARD_SEEDING_REFRESH_INTERVAL); + } + } + + // Add the (shuffled) permanent seeds at the last. + List asList = new ArrayList(permanentSeeds); + + Collections.shuffle(asList); + activeSeeds.addAll(asList); + } + + /** + * Evaluates if the given route corresponds to one of our seeds. This is + * to support the allowOnlySeeds flag. The test is not completely foolproof + * since our list of seeds is just transport addresses. We could be given a + * pve that exhibits an address that corresponds to one of our seeds but is + * fake. And we might later succeed in connecting to that peer via one + * the other, real addresses. As a result, allowOnlySeeds is *not* a + * security feature, just a convenience for certain kind of deployments. + * The remote peer's certificates should be examined in order to fully + * establish that it an appropriate peer. + */ + private boolean isSeedPeer(RouteAdvertisement route) { + List addrList = route.getDestEndpointAddresses(); + + ListIterator eachAddr = addrList.listIterator(); + + // convert each EndpointAddress to a URI to compare with seedHosts + while (eachAddr.hasNext()) { + EndpointAddress anAddr = (EndpointAddress) eachAddr.next(); + + eachAddr.set(anAddr.toURI()); + } + + addrList.retainAll(Arrays.asList(getActiveSeedURIs())); + + // What's left is the intersection of activeSeeds and the set of + // endpoint addresses in the given APA. If it is non-empty, then we + // accept the route as that of a seed host. + return (!addrList.isEmpty()); + } + + /** + * Load a list of seed peer RouteAdvertisements from the specified URI. + *

            + * Two formats are supported: + *

            + *
            TEXT
            + *
            A simple UTF-8 or US ASCII text file containing one seed + * endpoint address per line. These entries are converted into very + * simple {@code RouteAdvertisement}s.
            + *
            XML
            + *
            A simple XML file containing a sequence of seed + * {@code RouteAdvertisement}s. The seed advertisements may be ordered + * or unordered.
            + *
            + * + * @param seedingURI The intended source of the {@code RouteAdvertisement}s. + * @return The loaded {@code RouteAdvertisement}s. + * @throws IOException Thrown for errors encountered loading the seed + * RouteAdvertisements. + */ + static RouteAdvertisement[] loadSeeds(URI seedingURI) throws IOException { + boolean isXML; + URL seedingURL = seedingURI.toURL(); + URLConnection connection = seedingURL.openConnection(); + + connection.setDoInput(true); + InputStream is = connection.getInputStream(); + + // Determine if the input file is an XML document or a plain text list. + // If it is not XML then we assume it is text. + String content_type = connection.getContentType(); + MimeMediaType type; + + if (null == content_type) { + // If we couldn't get a content-type from the connection then let's + // try to get it from the URI path. + String name = seedingURI.getPath(); + int extIdx = name.lastIndexOf('.'); + int sepIdx = name.lastIndexOf('/'); + + if ((-1 != extIdx) && (extIdx > sepIdx)) { + String ext = name.substring(extIdx + 1); + + type = StructuredDocumentFactory.getMimeTypeForFileExtension(ext); + } else { + // Type is unknown. :-( + type = MimeMediaType.AOS; + } + } else { + type = new MimeMediaType(content_type); + } + + isXML = MimeMediaType.XML_DEFAULTENCODING.equalsIngoringParams(type) + || MimeMediaType.APPLICATION_XML_DEFAULTENCODING.equalsIngoringParams(type); + + BufferedReader seeds = new BufferedReader(new InputStreamReader(is)); + + List result = new ArrayList(); + + if (isXML) { + // Read in XML format seeds. (a list of Route Advertisements) + XMLDocument xmldoc = (XMLDocument) + StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XML_DEFAULTENCODING, seeds); + + Enumeration eachRA = xmldoc.getChildren(RouteAdvertisement.getAdvertisementType()); + + while (eachRA.hasMoreElements()) { + XMLElement anRAElement = eachRA.nextElement(); + RouteAdvertisement ra = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(anRAElement); + + result.add(ra); + } + + boolean randomize = true; + + Attribute ordered = xmldoc.getAttribute("ordered"); + + if (null != ordered) { + randomize = !Boolean.valueOf(ordered.getValue()); + } + + if (randomize) { + Collections.shuffle(result); + } + } else { + // Read in plain text format seeds. A list of Endpoint Addresses + while (true) { + String aSeed = seeds.readLine(); + + if (null == aSeed) { + break; + } + + aSeed = aSeed.trim(); + + if (0 == aSeed.length()) { + continue; + } + + try { + URI validation = URI.create(aSeed); + EndpointAddress ea = new EndpointAddress(validation.toString()); + + RouteAdvertisement ra = (RouteAdvertisement) AdvertisementFactory.newAdvertisement( + RouteAdvertisement.getAdvertisementType()); + + ra.addDestEndpointAddress(ea); + + // Add the world's most pathetic RouteAdvertisement to the result. + result.add(ra); + } catch (IllegalArgumentException badURI) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "bad URI in seeding list : " + aSeed, badURI); + } + } + } + } + + is.close(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(MessageFormat.format("Loaded #{0} seeds from : {1}", result.size(), seedingURI)); + } + + return result.toArray(new RouteAdvertisement[result.size()]); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/UnbiasedQueue.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/UnbiasedQueue.java new file mode 100644 index 000000000..25b8a576f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/UnbiasedQueue.java @@ -0,0 +1,875 @@ +/* + * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util; + + +import java.util.ArrayList; +import java.util.List; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + +import net.jxta.impl.util.TimeUtils; + + +/** + * A generic queue class. This queue is explicitly NOT a synchronized queue. + * + *

            FIXME 20020511 bondolo@jxta.org This could be more efficient with a + * circular queue implementation, but its a pain to write since we allow the + * queue to be resizable. + * + *

            FIXME 20020511 bondolo@jxta.org Exercise for the reader: Extend this + * class so that it does both LIFO and FIFO. + * + *

            FIXME 20020910 bondolo@jxta.org Needs an optional listener callback + * for droppped elments. + * + *

            FIXME 20020910 bondolo@jxta.org Needs an optional "strategy" for + * element insertion and removal. + * + * @deprecated Please convert all code to use the java.util.concurrent BlockingQueue instead. + * + */ +@Deprecated +public class UnbiasedQueue { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(UnbiasedQueue.class.getName()); + + /** + * Default number of queue elements. + */ + protected static final int DEFAULT_MAX_OBJECTS = 100; + + /** + * Default object dropping behaviour + */ + protected static final boolean DROP_OLDEST_OBJECT = true; + + /** + * Number of milliseconds between notifications that objects are being dropped. + */ + protected static final long DROPPED_OBJECT_WARNING_INTERVAL = 10 * TimeUtils.ASECOND; + + /** + * Contains the objects we currently have queued. + */ + protected List queue = null; + + /** + * The maximum number of objects we will hold in the queue at one time. + */ + protected int maxObjects; + + /** + * If true the queue is being closed and is currently in the process of + * being flushed. All new "push" requests will be refused. + */ + protected volatile boolean closeFlag = false; + + /** + * When we need to drop objects, drop the oldest obj. + */ + protected boolean dropOldestObject = true; + + /** + * total number of objects which have been enqueued into this queue + */ + protected long numEnqueued = 0; + + /** + * sum of queue sizes at enqueue time. + */ + protected long sumOfQueueSizesEnqueue = 0; + + /** + * total number of objects which have been dequeued from this queue + */ + protected long numDequeued = 0; + + /** + * sum of queue sizes at dequeue time. + */ + protected long sumOfQueueSizesDequeue = 0; + + /** + * the number of objects we have dropped since we began working. + */ + protected long numDropped = 0; + + /** + * absolute time in millis when it will be ok to display a obj about + * dropping objects. We throttle this so that there is a chance to do work + * rather than just always spewing warnings. + */ + protected long nextDroppedWarn = 0L; + + /** + * An inner class for wrapping arbitrary queues with synchronization. + */ + protected static class SynchronizedQueue extends UnbiasedQueue { + UnbiasedQueue innerqueue; + + /** + * Constructs a SynchronizedQueue from an UnbiasedQueue + * instance. + */ + public SynchronizedQueue(UnbiasedQueue queue) { + innerqueue = queue; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isClosed() { + synchronized (innerqueue.queue) { + return innerqueue.isClosed(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void close() { + synchronized (innerqueue.queue) { + innerqueue.close(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void clear() { + synchronized (innerqueue.queue) { + innerqueue.clear(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean push(Object obj) { + synchronized (innerqueue.queue) { + return innerqueue.push(obj); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean pushBack(Object obj) { + synchronized (innerqueue.queue) { + return innerqueue.pushBack(obj); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean push(Object obj, long timeout) throws InterruptedException { + synchronized (innerqueue.queue) { + return innerqueue.push(obj, timeout); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean pushBack(Object obj, long timeout) throws InterruptedException { + synchronized (innerqueue.queue) { + return innerqueue.pushBack(obj, timeout); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object peek() { + synchronized (innerqueue.queue) { + return innerqueue.peek(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object pop() { + synchronized (innerqueue.queue) { + return innerqueue.pop(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object pop(long timeout) throws InterruptedException { + synchronized (innerqueue.queue) { + return innerqueue.pop(timeout); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object[] popMulti(int maxObjs) { + synchronized (innerqueue.queue) { + return innerqueue.popMulti(maxObjs); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getMaxQueueSize() { + synchronized (innerqueue.queue) { + return innerqueue.getMaxQueueSize(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setMaxQueueSize(int maxObjs) { + synchronized (innerqueue.queue) { + innerqueue.setMaxQueueSize(maxObjs); + } + } + + @Override + public int getCurrentInQueue() { + synchronized (innerqueue.queue) { + return innerqueue.getCurrentInQueue(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public long getNumEnqueued() { + synchronized (innerqueue.queue) { + return innerqueue.getNumEnqueued(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public double getAvgInQueueAtEnqueue() { + synchronized (innerqueue.queue) { + return innerqueue.getAvgInQueueAtEnqueue(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public long getNumDequeued() { + synchronized (innerqueue.queue) { + return innerqueue.getNumDequeued(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public double getAvgInQueueAtDequeue() { + synchronized (innerqueue.queue) { + return innerqueue.getAvgInQueueAtDequeue(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public long getNumDropped() { + synchronized (innerqueue.queue) { + return innerqueue.getNumDropped(); + } + } + } + + /** + * Returns a synchronized (thread-safe) list backed by the specified queue. + * Most UnbiasedQueue subclasses are either unsynchronized or internally + * synchronized. If you need to do any atomic operations upon + * UnbiasedQueues (or subclasses) then this method should be used to + * "wrap" the queue with synchronization. + * + *

            In order to guarantee serial access, it is critical that all access + * to the backing queue is accomplished through the returned queue. + * + * @param queue the queue to be "wrapped" in a synchronized queue. + */ + public static UnbiasedQueue synchronizedQueue(UnbiasedQueue queue) { + return new SynchronizedQueue(queue); + } + + /** + * Default constructor. 100 element FIFO queue which drops oldest element + * when full. + */ + public UnbiasedQueue() { + this(DEFAULT_MAX_OBJECTS, DROP_OLDEST_OBJECT); + } + + /** + * Full featured constructor for creating a new UnBiasedQueue. + * + * @param maxsize Queue will not grow larger than this size. Use + * {@link java.lang.Integer#MAX_VALUE} for "unbounded" queue size. + * @param dropOldest Controls behaviour of element insertion when the + * queue is full. If true and the queue is full upon a + * {@link #push(Object) push} operation then the oldest element will be + * dropped to be replaced with the element currently being pushed. If + * false then the element will not be inserted if the queue is full. + */ + public UnbiasedQueue(int maxsize, boolean dropOldest) { + this(maxsize, dropOldest, new ArrayList()); + } + + /** + * Full featured constructor for creating a new UnBiasedQueue. + * + * @param maxsize Queue will not grow larger than this size. Use + * {@link java.lang.Integer#MAX_VALUE} for "unbounded" queue size. + * @param dropOldest Controls behaviour of element insertion when the + * queue is full. If true and the queue is full upon a + * {@link #push(Object) push} operation then the oldest element will be + * dropped to be replaced with the element currently being pushed. If + * false then the element will not be inserted if the queue is + * full. + * @param queue the List class instance to use. This does not need to be + * a synchronized list class. (and it works more effciently if it isn't). + */ + public UnbiasedQueue(int maxsize, boolean dropOldest, List queue) { + if (maxsize <= 0) { + throw new IllegalArgumentException("size must be > 0"); + } + + if (null == queue) { + throw new IllegalArgumentException("queue must be non-null"); + } + + maxObjects = maxsize; + this.queue = queue; + closeFlag = false; + + dropOldestObject = dropOldest; + } + + /** + * {@inheritDoc} + * + *

            A diagnostic toString implementation. + */ + @Override + public synchronized String toString() { + + return this.getClass().getName() + " :" + " size=" + getCurrentInQueue() + " capacity=" + getMaxQueueSize() + " enqueued=" + + getNumEnqueued() + " avgAtEnqueue=" + getAvgInQueueAtEnqueue() + " dequeued=" + getNumDequeued() + + " avgAtDequeue=" + getAvgInQueueAtDequeue(); + } + + /** + * Atomically return whether or not this queue has been closed. Closed + * queues will not accept "push" requests, but elements will still be + * returned with "pop". + * + * @return boolean indicating whether this queue has been closed. + */ + public boolean isClosed() { + return closeFlag; // closeFlag is volatile. + } + + /** + * Close the queue. This will prevent any further objects from being enqueued. + */ + public void close() { + closeFlag = true; + synchronized (queue) { + queue.notifyAll(); + } + } + + /** + * Flush the queue of all pending objects. + */ + public void clear() { + numDropped += queue.size(); + queue.clear(); + } + + /** + * Attempt to push an object onto the queue. If the queue is full then the + * object will not be pushed. This method does not use any synchronization + * and should not be used if other threads are using {@link #pop(long)} to + * retrieve elements. + * + * @param obj object to push + * @return true if the obj was pushed, otherwise false. + */ + public boolean push(Object obj) { + if (queue.size() >= maxObjects) { + return false; + } + + numEnqueued++; + sumOfQueueSizesEnqueue += queue.size(); + queue.add(obj); + + return true; + } + + /** + * Attempt to push an object back at the head the queue. If the queue is + * full then the object will not be pushed. This method does not use any + * synchronization and should not be used if other threads are using + * {@link #pop(long)} to retrieve elements. + * + * @param obj object to push + * @return true if the obj was pushed, otherwise false. + */ + public boolean pushBack(Object obj) { + if (queue.size() >= maxObjects) { + return false; + } + + numEnqueued++; + sumOfQueueSizesEnqueue += queue.size(); + queue.add(0, obj); + + return true; + } + + /** + * Push an object onto the queue. If the queue is full then the push will + * wait for up to "timeout" milliseconds to push the object. At the end of + * "timeout" milliseconds, the push will either return false or remove the + * oldest item from the queue and insert "obj". This behaviour is contolled + * by the constructor parameter "dropOldest". + * + * @param obj Object to be pushed onto the queue + * @param timeout Time in milliseconds to try to insert the item into a full + * queue. Per Java standards, a timeout of "0" (zero) will wait indefinitly. + * Negative values force no wait period at all. + * @return true if the object was intersted into the queue, otherwise false. + * @throws InterruptedException if the operation is interrupted before + * the timeout interval is completed. + */ + public boolean push(Object obj, long timeout) throws InterruptedException { + return push3(obj, timeout, false); + } + + /** + * Push an object back at the head of the queue. If the queue is full then + * the push will wait for up to "timeout" milliseconds to push the object. + * At the end of "timeout" milliseconds, the push will either return false + * or remove the oldest item from the queue and insert "obj". This behaviour + * is contolled by the constructor parameter "dropOldest". + * + *

            Timeout control is accomplished via synchronization and + * {@link Object#wait(long)}. {@link #pushBack(Object,long)} should only + * be used in conjunction with {@link #push(Object,long)} and + * {@link #pop(long)} + * + * @param obj Object to be pushed onto the queue + * @param timeout Time in milliseconds to try to insert the item into a full + * queue. Per Java standards, a timeout of "0" (zero) will wait indefinitly. + * Negative values force no wait period at all. + * @return true if the object was intersted into the queue, + * otherwise false. + * @throws InterruptedException if the operation is interrupted before + * the timeout interval is completed. + */ + public boolean pushBack(Object obj, long timeout) throws InterruptedException { + return push3(obj, timeout, true); + } + + private boolean push3(Object obj, long timeout, boolean atHead) throws InterruptedException { + if (null == obj) { + throw new AssertionError("obj is null"); + } + + if (null == queue) { + throw new AssertionError("queue is null"); + } + + if (0 == timeout) { + timeout = Long.MAX_VALUE; + } + + long absoluteTimeOut = TimeUtils.toAbsoluteTimeMillis(timeout); + + synchronized (queue) { + // this is the loop we stay in until there is space in the queue, + // the queue becomes closed or we get tired of waiting. + do { + // This queue is closed. No additional objects allowed. + if (isClosed()) { + queue.notify(); // inform someone who is waiting. we dont have to tell everyone though. + return false; + } + + if (queue.size() >= maxObjects) { + long waitfor = TimeUtils.toRelativeTimeMillis(absoluteTimeOut); + + if (waitfor > 0) { + queue.wait(waitfor); + + // something happened, we check again. + continue; + } + + // Queue is full but its time to do something. + // discard an element or simply return. + if (dropOldestObject) { + // Issue a warning if we have not done so recently. + long now = TimeUtils.timeNow(); + + if ((now > nextDroppedWarn) && Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Queue full, dropped one or more elements. Now dropped " + numDropped + " elements."); + nextDroppedWarn = now + DROPPED_OBJECT_WARNING_INTERVAL; + } + + if (atHead) { + // we have chosen to drop this element since it is + // the oldest. We can safely return true because we + // took the right action for this element. + + numEnqueued++; // one was queued. + numDropped++; // one was dropped. + // (happens they are the same) + + queue.notify(); // inform someone who is waiting. we dont have to tell everyone though. + return true; + } else { + // Due to queue resizing, we have have to drop more than + // one element + while (queue.size() >= maxObjects) { + numDropped++; + queue.remove(0); + } + } + } else { + queue.notify(); // inform someone who is waiting. we dont have to tell everyone though. + return false; + } + + } else { + break; + } + } while (!isClosed()); + + boolean pushed = (atHead ? pushBack(obj) : push(obj)); + + queue.notify(); // inform someone who is waiting. we dont have to tell everyone though. + return pushed; + } + } + + /** + * Return the next Object from the queue without removing it. + * + * @return Object, null if the queue is empty. + */ + public Object peek() { + Object result = null; + + if (queue.isEmpty()) { + return null; + } + + result = queue.get(0); + + return result; + } + + /** + * Remove and return the next Object from the queue. + * + * @return Object, null if the queue is empty. + */ + public Object pop() { + Object result = null; + + if (queue.isEmpty()) { + return null; + } + + sumOfQueueSizesDequeue += queue.size(); + numDequeued++; + + result = queue.remove(0); + + return result; + } + + /** + * Gets a Object from the queue. If no Object is immediately available, + * then wait the specified amount of time for an Object to be inserted. + * + * @param timeout Amount of time to wait in milliseconds for an object to + * be available. Per Java convention, a timeout of zero (0) means wait an + * infinite amount of time. Negative values mean do not wait at all. + * @return The next object in the queue. + * @throws InterruptedException if the operation is interrupted before + * the timeout interval is completed. + */ + public Object pop(long timeout) throws InterruptedException { + + if (0 == timeout) { + timeout = Long.MAX_VALUE; + } + + long absoluteTimeOut = TimeUtils.toAbsoluteTimeMillis(timeout); + + Object result = null; + + synchronized (queue) { + do { + + /* + * Because there may be more than one thread waiting on this + * queue, when we are woken up we do not necessarily get the + * next obj in the queue. In this case, rather than terminating + * because we didn't get the obj we resume waiting, but we + * ensure that we never wait longer than the amount of time + * which was originally requested. (if we fail to get the obj + * after being woken its actually a little less than the + * requested time) + */ + result = pop(); + + if (null != result) { + break; + } // we have an obj + + if (isClosed()) { // we didn't get one and its closed so there + break; + } // is no chance there will ever be one. + + long waitfor = TimeUtils.toRelativeTimeMillis(absoluteTimeOut); + + if (waitfor <= 0) { // there is no wait time left. + break; + } + + queue.wait(waitfor); + } while (!isClosed()); + + // wake someone else who might be waiting. This is apparently better + // than just letting the scheduler notice the synchro is no longer + // occupied. + queue.notify(); + } + + return result; + } + + /** + * Returns an array of objects, possibly empty, from the queue. + * + * @param maxObjs the maximum number of items to return. + * @return an array of objects, possibly empty containing the returned + * queue elements. + */ + public Object[] popMulti(int maxObjs) { + if (maxObjs <= 0) { + throw new IllegalArgumentException("maxObjs must be > 0"); + } + + maxObjs = Math.min(maxObjs, queue.size()); + Object[] result = new Object[maxObjs]; + + for (int eachElement = 0; eachElement < maxObjs; eachElement++) { + sumOfQueueSizesDequeue += queue.size(); + numDequeued++; + result[eachElement] = queue.remove(0); + } + + return result; + } + + /** + * How many objects will fit in this queue + * + * @return int indicating how many objects will fit in the queue. + */ + public int getMaxQueueSize() { + return maxObjects; + } + + /** + * Set how many objects this queue may store. Note that if there are more + * objects already in the queue than the specified amount then the queue + * will retain its current capacity. + * + * @param maxObjs The number of objects which the queue must be able to + * store. + */ + public void setMaxQueueSize(int maxObjs) { + maxObjects = maxObjs; + } + + /** + * Return the number of elements currently in the queue. This method is + * useful for statistical sampling, but should not be used to determine + * program logic due to the multi-threaded behaviour of these queues. + * + *

            You should use the return values and timeout behaviour of the + * {@link #push(Object)} and {@link #pop(long)} methods to regulate how you + * use the queue. + * + * @return the number of elements currently in the queue. Be warned that + * even two sequential calls to this method may return different answers + * due to activity on other threads. + */ + public int getCurrentInQueue() { + return queue.size(); + } + + /** + * Return the total number of objects which have been enqueued on to this + * queue during its existance. + * + * @return how many objects have been queued. + */ + public long getNumEnqueued() { + return numEnqueued; + } + + /** + * Return the average number of elements in the queue at Enqueue time. + * + * @return average number of elements which were in the queue at during all + * of the "push" operations which returned a "true" result. Does not + * include the item being pushed. If no elements have ever been enqueued + * then "NaN" will be returned. + */ + public double getAvgInQueueAtEnqueue() { + if (numEnqueued > 0) { + return (double) sumOfQueueSizesEnqueue / numEnqueued; + } else { + return Double.NaN; + } + } + + /** + * Return the total number of objects which have been dequeued from this + * queue during its existance. + * + * @return how many objects have been queued. + */ + public long getNumDequeued() { + return numDequeued; + } + + /** + * Return the average number of elements in the queue at dequeue time. + * + * @return average number of elements which were in the queue at during all + * of the "pop" operations which returned a non-null result. Includes the + * item being "pop"ed in the average. If no elements have ever been dequeued + * then "NaN" will be returned. + */ + public double getAvgInQueueAtDequeue() { + if (numDequeued > 0) { + return (double) sumOfQueueSizesDequeue / numDequeued; + } else { + return Double.NaN; + } + } + + /** + * Return the total number of objects which have been dropped by this queue + * during its existance. + * + * @return how many objects have been dropped. + */ + public long getNumDropped() { + return numDropped; + } + + public void interrupt() { + synchronized (queue) { + queue.notify(); + } + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/cm/DumpCm.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/cm/DumpCm.java new file mode 100644 index 000000000..ee6564ab7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/cm/DumpCm.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.cm; + + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.core.filer.BTreeCallback; +import net.jxta.impl.xindice.core.filer.BTreeFiler; +import net.jxta.impl.xindice.core.indexer.IndexQuery; +import net.jxta.impl.xindice.core.indexer.NameIndexer; + +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; + + +/** + * A utility to dump the CM databases. + */ + +public class DumpCm { + + private static final IndexQuery ANY = new IndexQuery(IndexQuery.ANY, "*"); + + public interface DumpCmCallback { + void println(String val); + } + + public static void dump(String args[], DumpCmCallback callback) throws IOException { + String type = null; + String dir = null; + String file = null; + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-type") && i + 1 < args.length) { + type = args[++i]; + } else if (args[i].equals("-dir") && i + 1 < args.length) { + dir = args[++i]; + } else if (args[i].equals("-file") && i + 1 < args.length) { + file = args[++i]; + } else { + throw new IllegalArgumentException("Incorrect option"); + } + } + + if (callback == null) { + throw new IllegalArgumentException("No callback was provided."); + } + + if (type == null || dir == null || file == null) { + throw new IllegalArgumentException("Missing mandatory option"); + } + + if (type.equals("index")) { + dumpIndex(dir, file, callback); + } else if (type.equals("offsets")) { + dumpOffsets(dir, file, callback); + } else if (type.equals("db")) { + dumpDatabase(dir, file, callback); + } else { + throw new IllegalArgumentException("Incorrect type"); + } + } + + public static void dumpIndex(String dir, String file, DumpCmCallback callback) throws IOException { + NameIndexer indexer = new NameIndexer(); + + // remove the suffix if present (setLocation automatically adds it back) + final String SUFFIX = ".idx"; + + if (file.endsWith(SUFFIX)) { + file = file.substring(0, file.length() - SUFFIX.length()); + } + + indexer.setLocation(dir, file); + try { + if (!indexer.open()) { + throw new IOException("Failed to open index file " + dir + File.separator + file + SUFFIX); + } + callback.println("Index " + dir + File.separator + file + SUFFIX); + indexer.query(ANY, new IndexCallback(callback)); + } catch (DBException dbe) { + throw new IOException(dbe.getMessage()); + } + } + + private static final class IndexCallback implements BTreeCallback { + + private DumpCmCallback callback = null; + + public IndexCallback(DumpCmCallback callback) { + this.callback = callback; + } + + public boolean indexInfo(Value val, long pos) { + callback.println(pos + " \t " + val.toString()); + return true; + } + } + + public static void dumpOffsets(String dir, String file, DumpCmCallback callback) throws IOException { + BTreeFiler filer = new BTreeFiler(); + + // remove the suffix if present (setLocation automatically adds it back) + final String SUFFIX = ".tbl"; + + if (file.endsWith(SUFFIX)) { + file = file.substring(0, file.length() - SUFFIX.length()); + } + + filer.setLocation(dir, file); + try { + if (!filer.open()) { + throw new IOException("Failed to open offsets file " + dir + File.separator + file + SUFFIX); + } + callback.println("Offsets " + dir + File.separator + file + SUFFIX); + filer.query(ANY, new OffsetsCallback(filer, callback)); + } catch (DBException dbe) { + throw new IOException(dbe.getMessage()); + } + } + + private static final class OffsetsCallback implements BTreeCallback { + + private BTreeFiler filer = null; + private DumpCmCallback callback = null; + + public OffsetsCallback(BTreeFiler filer, DumpCmCallback callback) { + this.filer = filer; + this.callback = callback; + } + + public boolean indexInfo(Value val, long pos) { + Record record = null; + + try { + record = filer.readRecord(pos); + } catch (DBException dbe) { + callback.println("Error reading record: " + dbe.getMessage()); + } + + StringBuilder offsets = new StringBuilder(); + DataInputStream dis = null; + + if (record != null) { + dis = new DataInputStream(record.getValue().getInputStream()); + } + try { + int size = 0; + + if (dis != null) { + size = dis.readInt(); + } + for (int i = 0; i < size; i++) { + if (dis != null) { + offsets.append(Long.toString(dis.readLong())); + } + offsets.append(" "); + } + } catch (IOException ie) { + callback.println("Error reading record: " + ie.getMessage()); + } + + callback.println(pos + " \t " + val.toString() + "\n\t " + offsets.toString()); + return true; + } + } + + public static void dumpDatabase(String dir, String file, DumpCmCallback callback) throws IOException { + BTreeFiler filer = new BTreeFiler(); + + // remove the suffix if present (setLocation automatically adds it back) + final String SUFFIX = ".tbl"; + + if (file.endsWith(SUFFIX)) { + file = file.substring(0, file.length() - SUFFIX.length()); + } + + filer.setLocation(dir, file); + try { + if (!filer.open()) { + throw new IOException("Failed to open database file " + dir + File.separator + file + SUFFIX); + } + callback.println("Database " + dir + File.separator + file + SUFFIX); + filer.query(ANY, new DatabaseCallback(filer, callback)); + } catch (DBException dbe) { + throw new IOException(dbe.getMessage()); + } + } + + private static final class DatabaseCallback implements BTreeCallback { + + private BTreeFiler filer = null; + private DumpCmCallback callback = null; + + public DatabaseCallback(BTreeFiler filer, DumpCmCallback callback) { + this.filer = filer; + this.callback = callback; + } + + public boolean indexInfo(Value val, long pos) { + Record record = null; + + try { + record = filer.readRecord(pos); + } catch (DBException dbe) { + callback.println("Error reading record: " + dbe.getMessage()); + } + + if (record != null) { + callback.println(pos + " \t " + val.toString() + "\n" + record.getValue().toString()); + } + return true; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/package.html b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/package.html new file mode 100644 index 000000000..006640af9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/package.html @@ -0,0 +1,11 @@ + + + + + + + A collection of utility classes used by the JXTA implementation. These + utilities are not exposed in the public JXTA API because they are either + specific to the implementation or not specifically related to JXTA. + + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/AdaptiveFlowControl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/AdaptiveFlowControl.java new file mode 100644 index 000000000..f460de78b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/AdaptiveFlowControl.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import net.jxta.impl.util.TimeUtils; + + +public class AdaptiveFlowControl extends FlowControl { + + static final int DEFAULT_RWINDOW = 2; + + /** + * global state. + */ + private int MAX_TENSION = 3; + private int tension = 0; + private long nextRwinChange = TimeUtils.timeNow(); + private long prevAveRTT = 10 * TimeUtils.ASECOND; + private int RINGSZ = 8; + private long[] ackTimeRing = new long[RINGSZ]; + private int currAckRingOff = 0; + private int nbSamples = 0; + private long currAvePeriod = 1; + private long prevAvePeriod = 1; // not in use yet. + private long periodRangeSlow = Long.MAX_VALUE; // not in use, yet. + private long periodRangeFast = (periodRangeSlow / 3) * 2; + + /** + * Current recommended rwindow. + */ + private volatile int rwindow = 0; + + /** + * state of the currentAck being processed + */ + + // Accum of acked packets + private int numberACKed = 0; + + // Accum of missing packets + private int numberMissing = 0; + + // Time this ACK arrived + private long currACKTime = 0; + + // These variables are used to evaluate the longest run + // of consecutive holes in the sack list. That is consecutive + // seqnums from the retrQ that are not being acknowleged, + // followed by an acknowleged one. + private int prevHole = -2; + private int btbHoles = 0; + private int maxHoleRun = 0; + + /** + * Constructs an adaptive flow control module with an initial rwindow of + * DEFAULT_RWINDOW. + */ + public AdaptiveFlowControl() { + this(DEFAULT_RWINDOW); + } + + /** + * @param rwindow Use this value as the initial value (not recommended + * except for experimental purposes. + */ + public AdaptiveFlowControl(int rwindow) { + this.currACKTime = TimeUtils.timeNow(); + this.rwindow = rwindow; + } + + /** + * {@inheritDoc} + */ + @Override + public int getRwindow() { + return rwindow; + } + + /** + * {@inheritDoc} + */ + @Override + public void ackEventBegin() { + currACKTime = TimeUtils.timeNow(); + numberACKed = 0; + numberMissing = 0; + maxHoleRun = 0; + + // Note the currently open holerun carries over from the prev ACK. + // So, we leave prevHole and btbHoles alone. + } + + /** + * {@inheritDoc} + */ + @Override + public void packetACKed(int seqnum) { + if (btbHoles > maxHoleRun) { + maxHoleRun = btbHoles; + } + btbHoles = 0; + prevHole = -2; + numberACKed++; + } + + /** + * {@inheritDoc} + */ + @Override + public void packetMissing(int seqnum) { + + if (seqnum != prevHole + 1) { + // End of run, begining of next + if (btbHoles > maxHoleRun) { + maxHoleRun = btbHoles; + } + btbHoles = 0; + } + btbHoles++; + prevHole = seqnum; + numberMissing++; + } + + boolean fastMode = true; + int takeAchance = 0; + + /** + * {@inheritDoc} + */ + @Override + public int ackEventEnd(int rQSize, long aveRTT, long lastRTT) { + + // Compute average ack rate. If nothing was acked by this + // ack msg, consider it a bad sign as far as ack rates go: as good + // as no ack at all. + + // Even if a few ack messages where lost, the current event + // encapsulate all the acks we missed. Count each of them + // as one individual ack for the purpose of rate computation: + // we want to count the messages the other side has received + // not the number of ack messages that found their way back. + + if (numberACKed > 0) { + for (int a = 0; a < numberACKed; ++a) { + + // Adds a new sample to the ring. Returns the new average + // sample period. Once the ring is filled, the average is + // computed by substracting the sample at the current + // offset (the oldest) from the new sample that replaces + // it, and dividing by the ring size (10). During the + // first round, we use the first sample, so precision is + // poorer. + + long oldest = ackTimeRing[currAckRingOff]; + + if (nbSamples < RINGSZ) { + // make a fake (very) oldest sample if there is nothing yet. + if (nbSamples == 0) { + ackTimeRing[0] = currACKTime / 2; + } + ++nbSamples; + oldest = ackTimeRing[0]; + } + ackTimeRing[currAckRingOff++] = currACKTime; + if (currAckRingOff == RINGSZ) { + currAckRingOff = 0; + } + prevAvePeriod = currAvePeriod; + currAvePeriod = (currACKTime - oldest) / nbSamples; + } + } + + // Compute rwindow. It should keep oscillating around + // the best value. + // Up to a certain point, the higher we keep rwindow the more + // we keep all the bandwidth utilized. Beyond that point we have + // it just serves to create congestion. + + int oldSize = rwindow; + + if (TimeUtils.toRelativeTimeMillis(nextRwinChange) < 0) { + if (maxHoleRun < 4) { + + if (numberACKed > 0) { + + if (currAvePeriod < periodRangeFast) { + + // All is well: new rate record. We can + // push some more. and adjust the + // expected rate range towards speed. + + periodRangeFast = currAvePeriod; + periodRangeSlow = (periodRangeFast * 3) / 2; + + prevAveRTT = aveRTT; + + tension = 0; + + } else { + + // If rate is not up and RTT has + // increased by one inter-ack period or more + // since the last time we took the mark, it + // looks like one or more packet just had to + // wait its turn. So packets are being + // buffered, which does not do any + // good. Refrain from pushing under these + // conditions. Wait for a more favorable time. + + // This compares the change in RTT with the period + // and gives us a badness index from 0 to 10 * n + // Beyond 20 or so, we start getting worried. + // The hairy formula below compensates for non + // linearity of the rtt_diff/period ratio with + // period. The formulat compresses the scale towards + // a period of 0. There is no compression at a period + // of around 100 and maximum compression at 0. + // To make the index less sensitive for low periods, + // increase the compression ratio. + + int compressionRatio100 = 90; + int pivot = 100; + long period = currAvePeriod <= 0 ? 1 : currAvePeriod; + long backupSign = (10 * pivot * (aveRTT - prevAveRTT)) + / (pivot * period + Math.max((compressionRatio100 * (pivot * period - period * period)) / 100, 0)); + + if (backupSign > 18) { + + // if detect a speed increase, we'll reset our + // idea of the normal RTT for next time. But we + // will drop rwindow tension for now. + + rwindow--; + tension = MAX_TENSION; + + // The first time this happens, it's the end of fast + // mode. + fastMode = false; + + } else if ((backupSign < 1) && (currAvePeriod >= periodRangeSlow)) { + + if (tension >= MAX_TENSION) { + // May be we should give it another chance + // and nudge it just a little. On very lossy + // links we may end-up with no congestion + // at all but stuck at low speed because + // we have stopped believing in speed increase. + if (takeAchance++ > 10) { + takeAchance = 0; + tension--; + } + } + } else { + takeAchance = 0; + } + } + + if (tension < MAX_TENSION) { + tension++; + rwindow++; + } + + } else { + // Carefull, the other side did not ack anything + // it is stuck on a missing packet...better slow down + tension = MAX_TENSION; + } + + } else { + + // We saturated the pipe. We need to slow down + // arbitrarily without changing our idea of speed, + // so that the correlation between speed and + // rwindow is shifted towards a smaller + // rwindow. + + rwindow -= (MAX_TENSION + 1); + prevAveRTT = aveRTT; + tension = MAX_TENSION; + + // The first time this happens, it's the end of fast + // mode. + fastMode = false; + } + + if (rwindow > rQSize) { + rwindow = rQSize; + } + + if (rwindow < 2) { + rwindow = 2; + } + + if (oldSize != rwindow) { + if (fastMode && (tension < MAX_TENSION)) { + nextRwinChange = TimeUtils.toAbsoluteTimeMillis(lastRTT / 10); + } else { + nextRwinChange = TimeUtils.toAbsoluteTimeMillis(aveRTT * 2); + } + } + } + + return rwindow; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Defs.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Defs.java new file mode 100644 index 000000000..34f12d491 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Defs.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import net.jxta.document.MimeMediaType; + + +public final class Defs { + + public static final int MAXQUEUESIZE = 100; + + public static final String NAMESPACE = "jxtarel"; + + public static final String RETRY_ELEMENT_NAME = "retry"; + public static final String RETRY_ELEMENT_VALUE = "RETRY"; + + public static final String ACK_ELEMENT_NAME = "ack"; + + public static final MimeMediaType MIME_TYPE_MSG = MimeMediaType.valueOf("application/x-jxta-msg"); + + public static final MimeMediaType MIME_TYPE_BLOCK = MimeMediaType.valueOf("application/x-jxta-reliable-block"); + + public static final MimeMediaType MIME_TYPE_ACK = MimeMediaType.valueOf("application/x-jxta-reliable-ack"); + + /** + * Static class + */ + private Defs() {} +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/FixedFlowControl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/FixedFlowControl.java new file mode 100644 index 000000000..ab92b1383 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/FixedFlowControl.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +public class FixedFlowControl extends FlowControl { + + static final int DEFAULT_RWINDOW = 5; + int maxRwindow = 0; + int rwindow = 2; + + /** + * Constructs a fixed flow control module with a fixed rwindow of + * DEFAULT_RWINDOW. It is not completely fixed. It grows by one + * at every ack message until it reaches the set RWINDOW. + */ + public FixedFlowControl() { + this(DEFAULT_RWINDOW); + } + + /** + * @param rwindow Use the specified value as the constant rwindow + */ + public FixedFlowControl(int rwindow) { + this.maxRwindow = rwindow; + } + + /** + * {@inheritDoc} + */ + @Override + public int getRwindow() { + return rwindow; + } + + /** + * {@inheritDoc} + */ + @Override + public int ackEventEnd(int rQSize, long aveRTT, long lastRTT) { + if (rwindow < maxRwindow) { + ++rwindow; + } + return rwindow; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/FlowControl.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/FlowControl.java new file mode 100644 index 000000000..b2562e1a2 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/FlowControl.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +/** + * A basis for any flow control module to be plugged into + * ReliableOutputStream. Synchronization can is assumed to be + * provided externaly. However all implementations are required to + * allow the getRwindow() method to be called at any time without + * synchronization. + */ + +public abstract class FlowControl { + + /** + * Returns the rwindow size that this flow control module suggests to use + * at this point in time. + * @return the remote window size + */ + public abstract int getRwindow(); + + /** + * Indicates that a new ack message is being processed. + */ + public void ackEventBegin() {} + + /** + * Invoked for each packet that is believed to have been received + * per the current ack message. + * + * @param seqnum The sequence number of the received packet. + */ + public void packetACKed(int seqnum) {} + + /** + * Invoked for each packet that is believed to have been lost + * per the current ack message. + * + * @param seqnum The sequence number of the missing packet. + */ + public void packetMissing(int seqnum) {} + + /** + * Concludes rwindow update for this ackEvent. That's where all the + * smarts are. A number of externally computed parameters must be + * passed. + * + * @param rQSize the last known value of the remote queue size. + * @param aveRTT the latest estimate of the average RTT. + * @param lastRTT the RTT inferred from the most recent ACK message. + * @return int the new recommended value for rwindow. + */ + + public abstract int ackEventEnd(int rQSize, long aveRTT, long lastRTT); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Incoming.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Incoming.java new file mode 100644 index 000000000..5c510cc46 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Incoming.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import net.jxta.endpoint.Message; + + +/** + * Incoming messages are delivered to a class implementing + * this interface. + */ +public interface Incoming { + + /** + * Receive this incoming message. This method should + * return quickly. If the receiving class needs to do + * substantial work with incoming messages, it should + * insert this message into a queue and then drain the + * queue processing the messages in its own thread. + * @param msg the message + */ + void recv(Message msg); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/IncomingPipeAdaptor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/IncomingPipeAdaptor.java new file mode 100644 index 000000000..b0462cfa9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/IncomingPipeAdaptor.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + +import net.jxta.pipe.InputPipe; +import net.jxta.endpoint.Message; + + +public class IncomingPipeAdaptor implements Runnable { + + private static final Logger LOG = Logger.getLogger(IncomingPipeAdaptor.class.getName()); + + private InputPipe pipe = null; + private Incoming incoming = null; + private Thread poller = null; + + public IncomingPipeAdaptor(InputPipe pipe, Incoming incoming) { + if (pipe == null) { + throw new IllegalArgumentException("pipe cannot be null"); + } + this.pipe = pipe; + + if (incoming == null) { + throw new IllegalArgumentException("incoming cannot be null"); + } + this.incoming = incoming; + + poller = new Thread(this, "Reliable IncomingPipe Message Poll Thread"); + poller.setDaemon(true); + poller.start(); + } + + public void run() { + try { + while (true) { + Message msg = null; + + try { + msg = pipe.waitForMessage(); + } catch (InterruptedException ignore) { + continue; + } + + if (msg != null) { + incoming.recv(msg); + } + } + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Outgoing.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Outgoing.java new file mode 100644 index 000000000..f61a1951f --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/Outgoing.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import java.io.IOException; +import net.jxta.endpoint.Message; + + +/** + * This interface specifies the methods that must be + * implemented by a connection in order to be able to + * reliably deliver messages over the connection. + */ +public interface Outgoing { + + /** + * Send a message to the remote peer. + * @param msg the message + * @return true is successful + * @throws java.io.IOException if io error occurs + */ + boolean send(Message msg) throws IOException; + + /** + * Close the connection. + */ + void close(); + + /** + * Amount of a connection must be idle before a + * reconnection attempt will be considered. + * @return min idle reconnect time in millis + */ + long getMinIdleReconnectTime(); + + /** + * Sets the Timeout attribute. A timeout of 0 blocks forever + * + * @param timeout The new soTimeout value + */ + void setTimeout(int timeout); + + /** + * Amount of time after which a connection is + * considered idle and may be scavenged. + * @return idle timeout in millis + */ + long getIdleTimeout(); + + /** + * Amount if time during which retries may remain + * queued for retransmission. If still unACKed after + * this amount of time then the connection is + * considered dead. + * @return max retry age in millis + */ + long getMaxRetryAge(); + + /** + * Get the time when this connection was last used. + * @return last accessed in millis + */ + long getLastAccessed(); + + /** + * Set the time when this connection was last used. + * @param time in millis + */ + void setLastAccessed(long time); +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingMsgrAdaptor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingMsgrAdaptor.java new file mode 100644 index 000000000..0ebf76460 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingMsgrAdaptor.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ +package net.jxta.impl.util.pipe.reliable; + + +import java.io.IOException; + +import net.jxta.endpoint.Message; +import net.jxta.endpoint.Messenger; +import net.jxta.impl.util.TimeUtils; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * OutgoingMessengerAdaptor + */ +public class OutgoingMsgrAdaptor implements Outgoing { + + private final static transient Logger LOG = Logger.getLogger(OutgoingMsgrAdaptor.class.getName()); + + private final Messenger msgr; + private int timeout; + private long lastAccessed = 0; + private boolean closed = false; + + /** + * Constructor for the OutgoingMsgrAdaptor object + * + *@param msgr the messenger used to send messages + *@param timeout timeout in milliseconds + */ + public OutgoingMsgrAdaptor(Messenger msgr, int timeout) { + if (msgr == null) { + throw new IllegalArgumentException("messenger cannot be null"); + } + this.msgr = msgr; + this.timeout = timeout; + + // initialize to some reasonable value + lastAccessed = TimeUtils.timeNow(); + } + + /** + * returns last accessed time as a string + * + *@return last accessed time as a string + */ + @Override + public String toString() { + return " lastAccessed=" + Long.toString(lastAccessed); + } + + /** + * Sets the Timeout attribute. A timeout of 0 blocks forever + * + * @param timeout The new soTimeout value + */ + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + /** + * close the messenger (does not close the messenger) + */ + public void close() { + closed = true; + } + + /** + * Gets the minIdleReconnectTime of the OutgoingMsgrAdaptor + * (obsolete). + *@return The minIdleReconnectTime value + */ + public long getMinIdleReconnectTime() { + return timeout; + } + + /** + * Gets the idleTimeout of the OutgoingMsgrAdaptor. The adaptor never times out. + *@return Long.MAX_VALUE + */ + public long getIdleTimeout() { + return Long.MAX_VALUE; + } + + /** + * Gets the maxRetryAge attribute of the OutgoingMsgrAdaptor + * + *@return The maxRetryAge value + */ + public long getMaxRetryAge() { + return timeout == 0 ? Long.MAX_VALUE : timeout; + } + + /** + * Gets the lastAccessed time of OutgoingMsgrAdaptor + * + *@return The lastAccessed in milliseconds + */ + public long getLastAccessed() { + return lastAccessed; + } + + /** + * Sets the lastAccessed of OutgoingMsgrAdaptor + * + *@param time The new lastAccessed in milliseconds + */ + public void setLastAccessed(long time) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Setting lastAccessed to :" + lastAccessed); + } + lastAccessed = time; + } + + /** + * Sends a message + * + *@param msg message to send + *@return true if message send is successful + *@exception IOException if an io error occurs + */ + public boolean send(Message msg) throws IOException { + if (closed) { + throw new IOException("broken connection"); + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Sending a Message"); + } + + msgr.sendMessageB(msg, null, null); + return true; + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingPipeAdaptor.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingPipeAdaptor.java new file mode 100644 index 000000000..34f0b4068 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingPipeAdaptor.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import java.io.IOException; + +import net.jxta.endpoint.Message; +import net.jxta.impl.util.TimeUtils; +import net.jxta.pipe.OutputPipe; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +public class OutgoingPipeAdaptor implements Outgoing { + + private static final Logger LOG = Logger.getLogger(OutgoingPipeAdaptor.class.getName()); + + private final OutputPipe pipe; + + private long lastAccessed = 0; + + public OutgoingPipeAdaptor(OutputPipe pipe, int wsize) { + if (pipe == null) { + throw new IllegalArgumentException("pipe cannot be null."); + } + + this.pipe = pipe; + + // initialize to some reasonable value + lastAccessed = TimeUtils.timeNow(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return pipe.toString() + " lastAccessed=" + Long.toString(lastAccessed); + } + + /** + * {@inheritDoc} + */ + public boolean send(Message msg) throws IOException { + try { + return pipe.send(msg); + } catch (IOException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to send message " + msg, ex); + } + + return false; + } + } + + /** + * {@inheritDoc} + */ + public void close() { + pipe.close(); + } + + /** + * {@inheritDoc} + */ + public long getMinIdleReconnectTime() { + return 10 * TimeUtils.AMINUTE; + } + + /** + * {@inheritDoc} + */ + public void setTimeout(int timeout) {} + + /** + * {@inheritDoc} + * + *

            Default should be "never", otherwise, connection closes while not + * in active use and ReliableOutputStream does NOT reconnect automatically. + */ + public long getIdleTimeout() { + return Long.MAX_VALUE; + } + + /** + * {@inheritDoc} + * + *

            This is the important tunable: how long to wait on a stale connection. + */ + public long getMaxRetryAge() { + return 2 * TimeUtils.AMINUTE; + } + + /** + * {@inheritDoc} + */ + public long getLastAccessed() { + return lastAccessed; + } + + /** + * {@inheritDoc} + */ + public void setLastAccessed(long time) { + lastAccessed = time; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingPipeAdaptorSync.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingPipeAdaptorSync.java new file mode 100644 index 000000000..80b5afd2b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/OutgoingPipeAdaptorSync.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import java.io.IOException; +import java.lang.IllegalStateException; + +import net.jxta.pipe.OutputPipe; +import net.jxta.endpoint.Message; +import net.jxta.impl.util.TimeUtils; + + +/** + * And ountgoing pipe adaptor which does not use a thread or queue. + * Additionally, the pipe does not need to be provided at construction time. + * The send() method blocks until the pipe is specified. + */ +public class OutgoingPipeAdaptorSync implements Outgoing { + + private OutputPipe pipe = null; + private long lastAccessed = 0; + private boolean closed = false; + + public OutgoingPipeAdaptorSync(OutputPipe pipe) { + + // Null permitted. Send will block until setPipe is called. + this.pipe = pipe; + + // initialize to some reasonable value + lastAccessed = TimeUtils.timeNow(); + } + + public boolean sendNb(Message msg) throws IOException { + OutputPipe locPipe; + + synchronized (this) { + locPipe = pipe; + } + + if (closed || locPipe == null) { + return false; + } + + locPipe.send(msg); + + return true; + } + + public boolean send(Message msg) throws IOException { + + OutputPipe locPipe; + + synchronized (this) { + while (pipe == null && !closed) { + try { + wait(); + } catch (InterruptedException ignore) {} + } + if (closed) { + return false; + } + locPipe = pipe; + } + + return locPipe.send(msg); + } + + public void setPipe(OutputPipe pipe) { + synchronized (this) { + if (closed || this.pipe != null) { + throw new IllegalStateException("Cannot change pipe nor re-open"); + } + this.pipe = pipe; + notifyAll(); + } + } + + /** + * {@inheritDoc} + */ + public void close() { + synchronized (this) { + if (closed) { + return; + } + + closed = true; + + if (pipe != null) { + pipe.close(); + pipe = null; + } + + notifyAll(); + } + } + + /** + * {@inheritDoc} + */ + public long getMinIdleReconnectTime() { + return 10 * TimeUtils.AMINUTE; + } + + /** + * {@inheritDoc} + * + *

            Default should be "never", otherwise, connection closes while not + * in active use and ReliableOutputStream does NOT reconnect automatically. + */ + public long getIdleTimeout() { + return Long.MAX_VALUE; + } + + /** + * {@inheritDoc} + */ + public void setTimeout(int timeout) {} + + /** + * {@inheritDoc} + * + *

            This is the important tunable: how long to wait on a stale connection. + */ + public long getMaxRetryAge() { + return 1 * TimeUtils.AMINUTE; + } + + /** + * {@inheritDoc} + */ + public long getLastAccessed() { + return lastAccessed; + } + + /** + * {@inheritDoc} + */ + public void setLastAccessed(long time) { + lastAccessed = time; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return ((pipe == null) ? "no pipe yet" : pipe.toString()) + " lastAccessed=" + Long.toString(lastAccessed); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/ReliableInputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/ReliableInputStream.java new file mode 100644 index 000000000..5233416bd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/ReliableInputStream.java @@ -0,0 +1,779 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.impl.util.TimeUtils; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * Acts as a reliable input stream. Accepts data which + * arrives in messages and orders it. + */ +public class ReliableInputStream extends InputStream implements Incoming { + + /** + * Logger + */ + private static final Logger LOG = Logger.getLogger(ReliableInputStream.class.getName()); + + /** + * Connection we are working for. + */ + private Outgoing outgoing; + + private volatile boolean closed = false; + private boolean closing = false; + + private MsgListener listener = null; + + /** + * The amount of time that read() operation will block. > 0 + */ + private long timeout; + + /** + * The current sequence number we are reading bytes from. + */ + private volatile int sequenceNumber = 0; + + /** + * Queue of incoming messages. + */ + private final List inputQueue = new ArrayList(); + + /** + * The I/O record for the message we are currently using for stream data. + */ + private final Record record; + + /** + * Input record Object + */ + private static class Record { + public InputStream inputStream; + // next inbuff byte + public long nextByte; + // size of Record + public long size; + + public Record() { + inputStream = null; // allocated by caller + nextByte = 0; // We read here (set by caller) + size = 0; // Record size(set by caller) + } + + /** reset the record element + * + */ + public void resetRecord() { + if (null != inputStream) { + try { + inputStream.close(); + } catch (IOException ignored) {} + } + inputStream = null; + size = nextByte = 0; + } + } + + + /** + * An input queue element which breaks out a received message in + * enqueueMessage(). + */ + private static class IQElt implements Comparable { + final int seqnum; + final MessageElement elt; + boolean ackd = false; + + IQElt(int sequence, MessageElement element) { + seqnum = sequence; + elt = element; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IQElt) { + IQElt targ = (IQElt) obj; + + return (this.seqnum == targ.seqnum); + } + return false; + } + + public int compareTo(IQElt el) { + return this.seqnum < el.seqnum ? -1 : this.seqnum == el.seqnum ? 0 : 1; + } + + /** + * {@inheritDoc} + */ + public int compareTo(Object o) { + return compareTo((IQElt) o); + } + } + + public ReliableInputStream(Outgoing outgoing, int timeout) { + this(outgoing, timeout, null); + } + + public ReliableInputStream(Outgoing outgoing, int timeout, MsgListener listener) { + this.outgoing = outgoing; + setTimeout(timeout); + + record = new Record(); + this.listener = listener; + // 1 <= seq# <= maxint, monotonically increasing + // Incremented before compare. + sequenceNumber = 0; + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + if (listener != null) { + LOG.info("Listener based ReliableInputStream created"); + } + } + } + + /** + * {@inheritDoc} + * + *

            This is an explicit close operation. All subsequent {@code read()} + * operations will fail. + */ + @Override + public void close() throws IOException { + super.close(); + synchronized (inputQueue) { + closed = true; + inputQueue.clear(); + inputQueue.notifyAll(); + } + } + + /** + * Returns true if closed + * + * @return true if closed + */ + public boolean isInputShutdown() { + return closed; + } + + /** + * Prepare this input stream to being closed. It will still deliver the + * packets that have been received, but nothing more. This is meant to be + * called in response to the other side having initiated closure. We assume + * that when the other side does it it means that it is satisfied with what + * we have acknowledged so far. + */ + public void softClose() { + synchronized (inputQueue) { + closing = true; + inputQueue.notifyAll(); + } + } + + /** + * Sets the Timeout attribute. A timeout of 0 blocks forever + * + * @param timeout The new soTimeout value + */ + public void setTimeout(int timeout) { + if (timeout < 0) { + throw new IllegalArgumentException("Timeout must be >=0"); + } + + this.timeout = (0 == timeout) ? Long.MAX_VALUE : timeout; + } + + /** + * {@inheritDoc} + */ + @Override + public int read() throws IOException { + if (closed) { + return -1; + } + + byte[] a = new byte[1]; + + while (true) { + int len = local_read(a, 0, 1); + + if (len < 0) { + break; + } + if (len > 0) { + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Read() : " + (a[0] & 255)); + } + + return a[0] & 0xFF; // The byte + } + } + + // If we've reached EOF, there's nothing to do but close(). + + close(); + return -1; + } + + /** + * {@inheritDoc} + */ + @Override + public int read(byte[] a, int offset, int length) throws IOException { + if (closed) { + return -1; + } + + if (0 == length) { + return 0; + } + + int i = local_read(a, offset, length); + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Read(byte[], int, " + length + "), bytes read = " + i); + } + + // If we've reached EOF; there's nothing to do but close(). + if (i == -1) { + close(); + } + return i; + } + + /** + * Send a sequential ACK and selective ACKs for all of + * the queued messages. + * + * @param seqnAck the sequence number being sequential ACKed + */ + private void sendACK(int seqnAck) { + // No need to sync on inputQueue, acking as many as we can is want we want + List selectedAckList = new ArrayList(); + List queue; + + synchronized (inputQueue) { + queue = new ArrayList(inputQueue); + } + + Iterator eachInQueue = queue.iterator(); + + while (eachInQueue.hasNext() && (selectedAckList.size() < Defs.MAXQUEUESIZE)) { + IQElt anIQElt = eachInQueue.next(); + + if (anIQElt.seqnum > seqnAck) { + if (!anIQElt.ackd) { + selectedAckList.add(anIQElt.seqnum); + anIQElt.ackd = true; + } + } + } + + // PERMIT DUPLICATE ACKS. Just a list and one small message. + sendACK(seqnAck, selectedAckList); + } + + /** + * Build an ACK message. The message provides a sequential ACK count and + * an optional list of selective ACKs. + * + * @param seqnAck the sequence number being sequential ACKed + * @param sackList a list of selective ACKs. Must be sorted in increasing + * order. + */ + private void sendACK(int seqnAck, List sackList) { + ByteArrayOutputStream bos = new ByteArrayOutputStream((1 + sackList.size()) * 4); + DataOutputStream dos = new DataOutputStream(bos); + + try { + dos.writeInt(seqnAck); + for (Integer aSackList : sackList) { + dos.writeInt(aSackList); + } + dos.close(); + bos.close(); + + Message ACKMsg = new Message(); + MessageElement elt = new ByteArrayMessageElement(Defs.ACK_ELEMENT_NAME, Defs.MIME_TYPE_ACK, bos.toByteArray(), null); + + ACKMsg.addMessageElement(Defs.NAMESPACE, elt); + + outgoing.send(ACKMsg); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SENT ACK, seqn#" + seqnAck + " and " + sackList.size() + " SACKs "); + } + } catch (IOException e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "sendACK caught IOException:", e); + } + } + } + + /** + * {@inheritDoc} + */ + public void recv(Message msg) { + queueIncomingMessage(msg); + } + + public boolean hasNextMessage() { + return !inputQueue.isEmpty(); + } + + Message nextMessage(boolean blocking) throws IOException { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("nextMessage blocking? [" + blocking + "]"); + } + MessageElement elt = dequeueMessage(sequenceNumber + 1, blocking); + + if (null == elt) { + return null; + } + sequenceNumber += 1; // next msg sequence number + + Message msg; + + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Converting message seqn :" + (sequenceNumber - 1) + "element to message"); + } + + msg = WireFormatMessageFactory.fromWire(elt.getStream(), Defs.MIME_TYPE_MSG, null); + } catch (IOException ex) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Could not deserialize message " + elt.getElementName(), ex); + } + return null; + } + return msg; + } + + /** + * queue messages by sequence number. + */ + private void queueIncomingMessage(Message msg) { + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Queue Incoming Message begins for " + msg); + } + + long startEnqueue = TimeUtils.timeNow(); + + Iterator eachElement = msg.getMessageElements(Defs.NAMESPACE, Defs.MIME_TYPE_BLOCK); + + // OK look for jxta message + while (!closed && !closing && eachElement.hasNext()) { + MessageElement elt = eachElement.next(); + + eachElement.remove(); + + int msgSeqn; + + try { + msgSeqn = Integer.parseInt(elt.getElementName()); + } catch (NumberFormatException n) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.warning("Discarding element (" + elt.getElementName() + ") Not one of ours."); + } + continue; + } + + IQElt newElt = new IQElt(msgSeqn, elt); + + // OK we must enqueue + + // We rely on the sender to not to send more than the window size + // because we do not limit the number of elements we allow to be + // enqueued. + + // see if this is a duplicate + if (newElt.seqnum <= sequenceNumber) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RCVD OLD MESSAGE : Discard seqn#" + newElt.seqnum + " now at seqn#" + sequenceNumber); + } + break; + } + + synchronized (inputQueue) { + + // dbl check with the lock held. + if (closing || closed) { + return; + } + + // Insert this message into the input queue. + // 1. Do not add duplicate messages + // 2. Store in increasing sequence nos. + int insertIndex = inputQueue.size(); + boolean duplicate = false; + + for (int j = 0; j < inputQueue.size(); j++) { + IQElt iq = inputQueue.get(j); + + if (newElt.seqnum < iq.seqnum) { + insertIndex = j; + break; + } else if (newElt.seqnum == iq.seqnum) { + duplicate = true; + break; + } + } + + if (duplicate) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RCVD OLD MESSAGE : Discard duplicate msg, seqn#" + newElt.seqnum); + } + break; + } + + inputQueue.add(insertIndex, newElt); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Enqueued msg with seqn#" + newElt.seqnum + " at index " + insertIndex); + } + + inputQueue.notifyAll(); + } + } + + if (listener != null) { + Message newmsg = null; + + while (true) { + try { + newmsg = nextMessage(false); + } catch (IOException io) {// do nothing as this exception will never occur + } + if (newmsg == null) { + break; + } + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("In listener mode, calling back listener"); + } + listener.processIncomingMessage(newmsg); + } catch (Throwable all) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Uncaught Throwable calling listener", all); + } + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + long waited = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), startEnqueue); + + LOG.fine("Queue Incoming Message for " + msg + " completed in " + waited + " msec."); + } + } + + long nextRetransRequest = TimeUtils.toAbsoluteTimeMillis(TimeUtils.ASECOND); + + /** + * Dequeue the message with the desired sequence number waiting as needed + * until the message is available. + * + * @param desiredSeqn the sequence number to be dequeued. + * @param blocking If {@code true} then this method should block while + * waiting for the specified message sequence number. + * @return the Message Element with the desired sequence number or null if + * the queue has been closed. + */ + private MessageElement dequeueMessage(int desiredSeqn, boolean blocking) throws IOException { + IQElt iQ = null; + + // Wait for incoming message here + long startDequeue = TimeUtils.timeNow(); + long timeoutAt = TimeUtils.toAbsoluteTimeMillis(timeout); + int wct = 0; + + synchronized (inputQueue) { + while (!closed) { + if (inputQueue.isEmpty()) { + if (!blocking) { + return null; + } + if (closing) { + return null; + } + try { + wct++; + inputQueue.wait(TimeUtils.ASECOND); + if (timeoutAt < TimeUtils.timeNow()) { + throw new SocketTimeoutException("Read timeout reached"); + } + } catch (InterruptedException e) { + Thread.interrupted(); + } + // reset retrans request timer since we don't want to immediately + // request retry after a long wait for out of order messages. + + nextRetransRequest = TimeUtils.toAbsoluteTimeMillis(TimeUtils.ASECOND); + continue; + } + + iQ = inputQueue.get(0); // FIFO + + if (iQ.seqnum < desiredSeqn) { + // Ooops a DUPE slipped in the head of the queue undetected + // (seqnum consistency issue). + // Just drop it. + inputQueue.remove(0); + // if such is the case then notify the other end so that + // the message does not remain in the retry queue eventually + // triggering a broken pipe exception + sendACK(iQ.seqnum); + continue; + } else if (iQ.seqnum != desiredSeqn) { + if (TimeUtils.toRelativeTimeMillis(nextRetransRequest) < 0) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Trigger retransmission. Wanted seqn#" + desiredSeqn + " found seqn#" + iQ.seqnum); + } + sendACK(desiredSeqn - 1); + nextRetransRequest = TimeUtils.toAbsoluteTimeMillis(TimeUtils.ASECOND); + } + if (!blocking) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Message out of sequece in Non-Blocking mode. returning"); + } + // not the element of interest return nothing + return null; + } + try { + wct++; + inputQueue.wait(TimeUtils.ASECOND); + if (timeoutAt < TimeUtils.timeNow()) { + throw new SocketTimeoutException("Read timeout reached"); + } + } catch (InterruptedException e) { + throw new InterruptedIOException("IO interrupted "); + } + continue; + } + inputQueue.remove(0); + break; + } + } + nextRetransRequest = 0; + // if we are closed then we return null + if (null == iQ) { + return null; + } + + sendACK(desiredSeqn); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + long waited = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), startDequeue); + + LOG.fine("DEQUEUED seqn#" + iQ.seqnum + " in " + waited + " msec on input queue"); + if (wct > 0) { + LOG.fine("DEQUEUE waited " + wct + " times on input queue"); + } + } + return iQ.elt; + } + + /** + * {@inheritDoc} + */ + @Override + public int available() throws IOException { + if (listener != null) { + throw new IOException("available() not supported in async mode"); + } + if (closed) { + throw new IOException("Stream closed"); + } + synchronized (record) { + if (record.inputStream != null) { + if ((record.size == 0) || (record.nextByte == record.size)) { + if (inputQueue.isEmpty()) { + return 0; + } + // reset the record + record.resetRecord(); // GC as necessary(inputStream byte[]) + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting next data block at seqn#" + (sequenceNumber + 1)); + } + MessageElement elt = dequeueMessage(sequenceNumber + 1, false); + + if (null == elt) { + return 0; + } + sequenceNumber += 1; // next msg sequence number + // Get the length of the Record + record.size = elt.getByteLength(); + record.inputStream = elt.getStream(); + } + return record.inputStream.available(); + } + } + return 0; + } + + private int local_read(byte[] buf, int offset, int length) throws IOException { + + if (listener != null) { + throw new IOException("read() not supported in async mode"); + } + + synchronized (record) { + if ((record.size == 0) || (record.nextByte == record.size)) { + + // reset the record + record.resetRecord(); // GC as necessary(inputStream byte[]) + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Getting next data block at seqn#" + (sequenceNumber + 1)); + } + + MessageElement elt = dequeueMessage(sequenceNumber + 1, true); + + if (null == elt) { + return -1; + } + + sequenceNumber += 1; // next msg sequence number + + // Get the length of the Record + record.size = elt.getByteLength(); + record.inputStream = elt.getStream(); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("new seqn#" + sequenceNumber + ", bytes = " + record.size); + } + } + + // return the requested Record data + // These calls should NEVER ask for more data than is in the + // received Record. + + long left = record.size - record.nextByte; + int copyLen = (int) Math.min(length, left); + int copied = 0; + + do { + int res = record.inputStream.read(buf, offset + copied, copyLen - copied); + + if (res < 0) { + break; + } + copied += res; + } while (copied < copyLen); + + record.nextByte += copied; + + if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { + LOG.finer("Requested " + length + ", Read " + copied + " bytes"); + } + + return copied; + } + } + + /** + * Returns the message listener for this pipe + * @return MsgListener + * + */ + public MsgListener getListener() { + return listener; + } + + /** + * The listener interface for receiving {@link net.jxta.endpoint.Message} + */ + public interface MsgListener { + + /** + * Called for each message received. + * + * @param message The message to be received. + */ + void processIncomingMessage(Message message); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/ReliableOutputStream.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/ReliableOutputStream.java new file mode 100644 index 000000000..f6129632e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/pipe/reliable/ReliableOutputStream.java @@ -0,0 +1,1277 @@ +/* + * Copyright (c) 2003-2007 Sun Microsystems, Inc. All rights reserved. + * + * The Sun Project JXTA(TM) Software License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by Sun Microsystems, Inc. for JXTA(TM) technology." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must + * not be used to endorse or promote products derived from this software + * without prior written permission. For written permission, please contact + * Project JXTA at http://www.jxta.org. + * + * 5. Products derived from this software may not be called "JXTA", nor may + * "JXTA" appear in their name, without prior written permission of Sun. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN + * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JXTA is a registered trademark of Sun Microsystems, Inc. in the United + * States and other countries. + * + * Please see the license information page at : + * for instructions on use of + * the license in source files. + * + * ==================================================================== + * + * This software consists of voluntary contributions made by many individuals + * on behalf of Project JXTA. For more information on Project JXTA, please see + * http://www.jxta.org. + * + * This license is based on the BSD license adopted by the Apache Foundation. + */ + +package net.jxta.impl.util.pipe.reliable; + + +import java.io.ByteArrayOutputStream; +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.Message; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.endpoint.WireFormatMessage; +import net.jxta.endpoint.WireFormatMessageFactory; +import net.jxta.impl.util.TimeUtils; +import net.jxta.logging.Logging; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Accepts data and packages it into messages for sending to the remote. The + * messages are kept in a retry queue until the remote peer acknowledges + * receipt of the message. + */ +public class ReliableOutputStream extends OutputStream implements Incoming { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(ReliableOutputStream.class.getName()); + + /** + * Initial estimated Round Trip Time + */ + private final static long initRTT = 10 * TimeUtils.ASECOND; + + /** + * The default size for the blocks we will chunk the stream into. + */ + private final static int DEFAULT_MESSAGE_CHUNK_SIZE = 63 * 1024; + + private final static MessageElement RETELT = new StringMessageElement(Defs.RETRY_ELEMENT_NAME, Defs.RETRY_ELEMENT_VALUE, null); + + /** + * A lock we use to ensure that write operations happen in order. + */ + private final Object writeLock = new String("writeLock"); + + /** + * The buffer we cache writes to. + */ + private byte[] writeBuffer = null; + + /** + * Number of bytes written to the write buffer. + */ + private int writeCount = 0; + + /** + * Set the default write buffer size. + */ + private int writeBufferSize = DEFAULT_MESSAGE_CHUNK_SIZE; + + /** + * Absolute time in milliseconds at which the write buffer began + * accumulating bytes to be written. + */ + private long writeBufferAge = Long.MAX_VALUE; + + /** + * If less than {@code TimeUtils.timenow()} then we are closed otherwise + * this is the absolute time at which we will become closed. We begin by + * setting this value as {@Long.MAX_VALUE} until we establish an earlier + * close deadline. + */ + private long closedAt = Long.MAX_VALUE; + + /** + * If {@code true} then we have received a close request from the remote + * side. They do not want to receive any more messages from us. + */ + private volatile boolean remoteClosed = false; + + /** + * If {@code true} then we have closed this stream locally and will not + * accept any further messages for sending. Unacknowledged messages will + * be retransmitted until the linger delay is passed. + */ + private volatile boolean localClosed = false; + + /** + * The relative time in milliseconds that we will allow our connection to + * linger. + */ + private long lingerDelay = 120 * TimeUtils.ASECOND; + + /** + * Sequence number of the message we most recently sent out. + */ + private AtomicInteger sequenceNumber = new AtomicInteger(0); + + /** + * Sequence number of highest sequential ACK. + */ + private volatile int maxACK = 0; + + /** + * connection we are working for + */ + private final Outgoing outgoing; + + /** + * The daemon thread that performs retransmissions. + */ + private Thread retrThread = null; + + // for retransmission + /** + * Average round trip time in milliseconds. + */ + private volatile long aveRTT = initRTT; + private volatile long remRTT = 0; + + /** + * Has aveRTT been set at least once over its initial guesstimate value. + */ + private boolean aveRTTreset = false; + + /** + * Number of ACK message received. + */ + private AtomicInteger numACKS = new AtomicInteger(0); + + /** + * When to start computing aveRTT + */ + private int rttThreshold = 0; + + /** + * Retry Time Out measured in milliseconds. + */ + private volatile long RTO = 0; + + /** + * Minimum Retry Timeout measured in milliseconds. + */ + private volatile long minRTO = initRTT * 5; + + /** + * Maximum Retry Timeout measured in milliseconds. + */ + private volatile long maxRTO = initRTT * 60; + + /** + * absolute time in milliseconds of last sequential ACK. + */ + private volatile long lastACKTime = 0; + + /** + * absolute time in milliseconds of last SACK based retransmit. + */ + private volatile long sackRetransTime = 0; + + // running average of receipients Input Queue + private int nIQTests = 0; + private int aveIQSize = 0; + + /** + * Our estimation of the current free space in the remote input queue. + */ + private volatile int mrrIQFreeSpace = 0; + + /** + * Our estimation of the maximum size of the remote input queue. + */ + private int rmaxQSize = Defs.MAXQUEUESIZE; + + /** + * The flow control module. + */ + private final FlowControl fc; + + /** + * Cache of the last rwindow recommendation by fc. + */ + private volatile int rwindow = 0; + + /** + * retrans queue element + */ + private static class RetrQElt { + + /** + * sequence number of this message. + */ + final int seqnum; + + /** + * the message + */ + final Message msg; + + /** + * absolute time of original enqueuing + */ + final long enqueuedAt; + + /** + * has been marked as retransmission + */ + int marked; + + /** + * absolute time when this msg was last transmitted + */ + long sentAt; + + /** + * Constructor for the RetrQElt object + * + * @param seqnum sequence number + * @param msg the message + */ + public RetrQElt(int seqnum, Message msg) { + this.seqnum = seqnum; + this.msg = msg; + this.enqueuedAt = TimeUtils.timeNow(); + this.sentAt = this.enqueuedAt; + this.marked = 0; + } + } + + /** + * The collection of messages available for re-transmission. + */ + protected final List retrQ = new ArrayList(); + + /** + * Constructor for the ReliableOutputStream object + * + * @param outgoing the outgoing object + */ + public ReliableOutputStream(Outgoing outgoing) { + // By default use the old behaviour: fixed fc with a rwin of 20 + this(outgoing, new FixedFlowControl(20)); + } + + /** + * Constructor for the ReliableOutputStream object + * + * @param outgoing the outgoing object + * @param fc flow-control + */ + public ReliableOutputStream(Outgoing outgoing, FlowControl fc) { + this.outgoing = outgoing; + + // initial RTO is set to maxRTO so as to give time + // to the receiver to catch-up + this.RTO = maxRTO; + + this.mrrIQFreeSpace = rmaxQSize; + this.rttThreshold = rmaxQSize; + + // Init last ACK Time to now + this.lastACKTime = TimeUtils.timeNow(); + this.sackRetransTime = TimeUtils.timeNow(); + + // Attach the flowControl module + this.fc = fc; + + // Update our initial rwindow to reflect fc's initial value + this.rwindow = fc.getRwindow(); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + flush(); + + super.close(); + localClosed = true; + closedAt = TimeUtils.toRelativeTimeMillis(lingerDelay); + + synchronized (retrQ) { + retrQ.notifyAll(); + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Closed."); + } + } + + public long getLingerDelay() { + return lingerDelay; + } + + public void setLingerDelay(long linger) { + if (linger < 0) { + throw new IllegalArgumentException("Linger delay may not be negative."); + } + + if (0 == linger) { + linger = Long.MAX_VALUE; + } + + lingerDelay = linger; + } + + /** + * Return the size of the buffers we are using for accumulating writes. + * + * @return size of our write buffers. + */ + public int setSendBufferSize() { + return writeBufferSize; + } + + /** + * Set the size of the buffers we will use for accumulating writes. + * + * @param size The desired size of write buffers. + * @throws IOException if an I/O error occurs. In particular, an IOException is thrown if the output stream is closed. + */ + public void setSendBufferSize(int size) throws IOException { + if (size <= 0) { + throw new IllegalArgumentException("Send buffer size may not be <= 0"); + } + + // Flush any existing buffered writes. Then next write will use the new buffer size. + synchronized (writeLock) { + flushBuffer(); + writeBufferSize = size; + } + } + + /** + * We have received a close request from the remote peer. We must stop + * retransmissions immediately. + */ + public void hardClose() { + remoteClosed = true; + closedAt = TimeUtils.timeNow(); + + // Clear the retry queue. Remote side doesn't care. + synchronized (retrQ) { + retrQ.clear(); + retrQ.notifyAll(); + } + + // Clear the write queue. Remote side doesn't care. + synchronized (writeLock) { + writeCount = 0; + writeBuffer = null; + writeBufferAge = Long.MAX_VALUE; + } + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Hard closed."); + } + } + + /** + * Returns the state of the stream + * + * @return true if closed + */ + public boolean isClosed() { + return localClosed || remoteClosed; + } + + /** + * {@inheritDoc} + */ + @Override + public void flush() throws IOException { + synchronized (writeLock) { + flushBuffer(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void write(int b) throws IOException { + write(new byte[] { (byte) b }, 0, 1); + } + + /** + * {@inheritDoc} + */ + @Override + public void write(byte b[], int off, int len) throws IOException { + synchronized (writeLock) { + if (isClosed()) { + throw new IOException("stream is closed"); + } + + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } + + if (len == 0) { + return; + } + + int current = off; + int end = current + len; + + while (current < end) { + if (0 == writeCount) { + // No bytes written? We need a new buffer. + writeBuffer = new byte[writeBufferSize]; + writeBufferAge = TimeUtils.timeNow(); + } + + int remain = end - current; + + int available = writeBuffer.length - writeCount; + int copy = Math.min(available, remain); + + System.arraycopy(b, current, writeBuffer, writeCount, copy); + writeCount += copy; + current += copy; + + if (writeBuffer.length == writeCount) { + flushBuffer(); + } + } + } + } + + /** + * Flush the internal buffer. {@code writeLock} must have been previously + * acquired. + * @throws IOException if an I/O error occurs. In particular, an IOException is thrown if the output stream is closed. + */ + private void flushBuffer() throws IOException { + if (writeCount > 0) { + // send the message + try { + writeBuffer(writeBuffer, 0, writeCount); + } finally { + writeCount = 0; + writeBuffer = null; + writeBufferAge = Long.MAX_VALUE; + } + } + } + + /** + * Write the internal buffer. {@code writeLock} must have been previously + * acquired. + * + * @param b data + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @throws IOException if an I/O error occurs. In particular, an IOException is thrown if the output stream is closed. + */ + private void writeBuffer(byte[] b, int off, int len) throws IOException { + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } + + if (len == 0) { + return; + } + + if (null == retrThread) { + retrThread = new Thread(new Retransmitter(), "JXTA Reliable Retransmiter for " + this); + retrThread.setDaemon(true); + retrThread.start(); + } + + // allocate new message + Message jmsg = new Message(); + + synchronized (retrQ) { + while (true) { + if (isClosed()) { + throw new IOException("Connection is " + (localClosed ? "closing" : "closed")); + } + if (retrQ.size() > Math.min(rwindow, mrrIQFreeSpace * 2)) { + try { + retrQ.wait(1000); + } catch (InterruptedException ignored) {// ignored + } + continue; + } + break; + } + + int sequenceToUse = sequenceNumber.incrementAndGet(); + MessageElement element = new ByteArrayMessageElement(Integer.toString(sequenceToUse), Defs.MIME_TYPE_BLOCK, b, off + , + len, null); + + jmsg.addMessageElement(Defs.NAMESPACE, element); + RetrQElt retrQel = new RetrQElt(sequenceToUse, jmsg.clone()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Reliable WRITE : seqn#" + sequenceNumber + " length=" + len); + } + + // place copy on retransmission queue + retrQ.add(retrQel); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Retrans Enqueue added seqn#" + sequenceNumber + " retrQ.size()=" + retrQ.size()); + } + } + + outgoing.send(jmsg); + mrrIQFreeSpace--; + // assume we have now taken a slot + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SENT : seqn#" + sequenceNumber + " length=" + len); + } + } + + /** + * Serialize a JXTA message as a reliable message. + * + *

            This method bypasses the built-in buffering and ignores the MTU size. + * + * @param msg message to send + * @return message sequence number + * @throws IOException if an I/O error occurs + */ + public int send(Message msg) throws IOException { + WireFormatMessage msgSerialized = WireFormatMessageFactory.toWire(msg, Defs.MIME_TYPE_MSG, null); + ByteArrayOutputStream baos = new ByteArrayOutputStream((int) msgSerialized.getByteLength()); + + msgSerialized.sendToStream(baos); + baos.close(); + byte[] bytes = baos.toByteArray(); + + synchronized (writeLock) { + flushBuffer(); + writeBuffer(bytes, 0, bytes.length); + return sequenceNumber.get(); + } + } + + /** + * Gets the maxAck attribute of the ReliableOutputStream object + * + * @return The maxAck value + */ + public int getMaxAck() { + return maxACK; + } + + /** + * Gets the seqNumber attribute of the ReliableOutputStream object + * + * @return The seqNumber value + */ + public int getSeqNumber() { + return sequenceNumber.get(); + } + + /** + * Gets the queueFull attribute of the ReliableOutputStream object + * + * @return The queueFull value + */ + protected boolean isQueueFull() { + return mrrIQFreeSpace < 1; + } + + /** + * Gets the queueEmpty attribute of the ReliableOutputStream object. + * + * @return {@code true} if the queue is empty otherwise {@code false}. + */ + public boolean isQueueEmpty() { + synchronized (retrQ) { + return retrQ.isEmpty(); + } + } + + /** + * Waits for the retransmit queue to become empty. + * + * @param timeout The relative time in milliseconds to wait for the queue to + * become empty. + * @return {@code true} if the queue is empty otherwise {@code false}. + * @throws InterruptedException if interrupted + */ + public boolean waitQueueEmpty(long timeout) throws InterruptedException { + long timeoutAt = TimeUtils.toAbsoluteTimeMillis(timeout); + + synchronized (retrQ) { + while (!retrQ.isEmpty() && (TimeUtils.timeNow() < timeoutAt)) { + long sleepTime = TimeUtils.toRelativeTimeMillis(timeoutAt); + + if (sleepTime > 0) { + retrQ.wait(sleepTime); + } + } + + return retrQ.isEmpty(); + } + } + + /** + * wait for activity on the retry queue + * + * @param timeout timeout in millis + * @throws InterruptedException when interrupted + */ + public void waitQueueEvent(long timeout) throws InterruptedException { + synchronized (retrQ) { + retrQ.wait(timeout); + } + } + + /** + * Calculates a message retransmission time-out + * + * @param dt base time + * @param msgSeqNum Message sequence number + */ + private void calcRTT(long dt, int msgSeqNum) { + + if (numACKS.incrementAndGet() == 1) { + // First ACK arrived. We can start computing aveRTT on the messages + // we send from now on. + rttThreshold = sequenceNumber.get() + 1; + } + + if (msgSeqNum > rttThreshold) { + // Compute only when it has stabilized a bit + // Since the initial mrrIQFreeSpace is small; the first few + // messages will be sent early on and may wait a long time + // for the return channel to initialize. After that things + // start flowing and RTT becomes relevant. + // Carefull with the computation: integer division with round-down + // causes cumulative damage: the ave never goes up if this is not + // taken care of. We keep the reminder from one round to the other. + + if (!aveRTTreset) { + aveRTT = dt; + aveRTTreset = true; + } else { + long tmp = (8 * aveRTT) + ((8 * remRTT) / 9) + dt; + + aveRTT = tmp / 9; + remRTT = tmp - aveRTT * 9; + } + } + + // Set retransmission time out: 2.5 x RTT + // RTO = (aveRTT << 1) + (aveRTT >> 1); + RTO = aveRTT * 2; + + // Enforce a min/max + RTO = Math.max(RTO, minRTO); + RTO = Math.min(RTO, maxRTO); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RTT = " + dt + "ms aveRTT = " + aveRTT + "ms" + " RTO = " + RTO + "ms"); + } + } + + /** + * @param iq Description of the Parameter + * @return Description of the Return Value + */ + private int calcAVEIQ(int iq) { + int n = nIQTests; + + nIQTests += 1; + aveIQSize = ((n * aveIQSize) + iq) / nIQTests; + return aveIQSize; + } + + /** + * process an incoming message + * + * @param msg message to process + */ + public void recv(Message msg) { + + Iterator eachACK = msg.getMessageElements(Defs.NAMESPACE, Defs.MIME_TYPE_ACK); + + while (eachACK.hasNext()) { + MessageElement elt = eachACK.next(); + + eachACK.remove(); + int sackCount = ((int) elt.getByteLength() / 4) - 1; + + try { + DataInputStream dis = new DataInputStream(elt.getStream()); + int seqack = dis.readInt(); + int[] sacs = new int[sackCount]; + + for (int eachSac = 0; eachSac < sackCount; eachSac++) { + sacs[eachSac] = dis.readInt(); + } + Arrays.sort(sacs); + // take care of the ACK here; + ackReceived(seqack, sacs); + } catch (IOException failed) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failure processing ACK", failed); + } + } + } + } + + /** + * Process an ACK Message. We remove ACKed + * messages from the retry queue. We only + * acknowledge messages received in sequence. + *

            + * The seqnum is for the largest unacknowledged seqnum + * the recipient has received. + *

            + * The sackList is a sequence of all of the + * received messages in the sender's input Q. All + * will be sequence numbers higher than the + * sequential ACK seqnum. + *

            + * Recipients are passive and only ack upon the + * receipt of an in sequence message. + *

            + * They depend on our RTO to fill holes in message + * sequences. + * + * @param seqnum message sequence number + * @param sackList array of message sequence numbers + */ + public void ackReceived(int seqnum, int[] sackList) { + + int numberACKed = 0; + long rttCalcDt = 0; + int rttCalcSeqnum = -1; + long fallBackDt = 0; + int fallBackSeqnum = -1; + + // remove acknowledged messages from retrans Q. + synchronized (retrQ) { + lastACKTime = TimeUtils.timeNow(); + fc.ackEventBegin(); + maxACK = Math.max(maxACK, seqnum); + + // dump the current Retry queue and the SACK list + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + StringBuilder dumpRETRQ = new StringBuilder("ACK RECEIVE : " + Integer.toString(seqnum)); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append('\n'); + } + dumpRETRQ.append("\tRETRQ (size=").append(retrQ.size()).append(")"); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append(" : "); + for (int y = 0; y < retrQ.size(); y++) { + if (0 != y) { + dumpRETRQ.append(", "); + } + RetrQElt r = retrQ.get(y); + + dumpRETRQ.append(r.seqnum); + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append('\n'); + } + dumpRETRQ.append("\tSACKLIST (size=").append(sackList.length).append(")"); + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + dumpRETRQ.append(" : "); + for (int y = 0; y < sackList.length; y++) { + if (0 != y) { + dumpRETRQ.append(", "); + } + dumpRETRQ.append(sackList[y]); + } + } + LOG.fine(dumpRETRQ.toString()); + } + + Iterator eachRetryQueueEntry = retrQ.iterator(); + + // First remove monotonically increasing seq#s in retrans vector + while (eachRetryQueueEntry.hasNext()) { + RetrQElt retrQElt = eachRetryQueueEntry.next(); + + if (retrQElt.seqnum > seqnum) { + break; + } + // Acknowledged + eachRetryQueueEntry.remove(); + + // Update RTT, RTO. Use only those that where acked + // w/o retrans otherwise the number may be phony (ack + // of first xmit received just after resending => RTT + // seems small). Also, we keep the worst of the bunch + // we encounter. If we really can't find a single + // non-resent message, we make do with a pessimistic + // approximation: we must not be left behind with an + // RTT that's too short, we'd keep resending like + // crazy. + long enqueuetime = retrQElt.enqueuedAt; + long dt = TimeUtils.toRelativeTimeMillis(lastACKTime, enqueuetime); + + // Update RTT, RTO + if (retrQElt.marked == 0) { + if (dt > rttCalcDt) { + rttCalcDt = dt; + rttCalcSeqnum = retrQElt.seqnum; + } + } else { + // In case we find no good candidate, make + // a guess by dividing by the number of attempts + // and keep the worst of them too. Since we + // know it may be too short, we will not use it + // if shortens rtt. + dt /= (retrQElt.marked + 1); + if (dt > fallBackDt) { + fallBackDt = dt; + fallBackSeqnum = retrQElt.seqnum; + } + } + fc.packetACKed(retrQElt.seqnum); + retrQElt = null; + numberACKed++; + } + // Update last accessed time in response to getting seq acks. + if (numberACKed > 0) { + outgoing.setLastAccessed(TimeUtils.timeNow()); + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SEQUENTIALLY ACKD SEQN = " + seqnum + ", (" + numberACKed + " acked)"); + } + // most recent remote IQ free space + mrrIQFreeSpace = rmaxQSize - sackList.length; + // let's look at average sacs.size(). If it is big, then this + // probably means we must back off because the system is slow. + // Our retrans Queue can be large and we can overwhelm the + // receiver with retransmissions. + // We will keep the rwin <= ave real input queue size. + int aveIQ = calcAVEIQ(sackList.length); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("remote IQ free space = " + mrrIQFreeSpace + " remote avg IQ occupancy = " + aveIQ); + } + + int retrans = 0; + + if (sackList.length > 0) { + Iterator eachRetrQElement = retrQ.iterator(); + int currentSACK = 0; + + while (eachRetrQElement.hasNext()) { + RetrQElt retrQElt = eachRetrQElement.next(); + + while (sackList[currentSACK] < retrQElt.seqnum) { + currentSACK++; + if (currentSACK == sackList.length) { + break; + } + } + if (currentSACK == sackList.length) { + break; + } + if (sackList[currentSACK] == retrQElt.seqnum) { + fc.packetACKed(retrQElt.seqnum); + numberACKed++; + eachRetrQElement.remove(); + + // Update RTT, RTO. Use only those that where acked w/o retrans + // otherwise the number is completely phony. + // Also, we keep the worst of the bunch we encounter. + long enqueuetime = retrQElt.enqueuedAt; + long dt = TimeUtils.toRelativeTimeMillis(lastACKTime, enqueuetime); + + // Update RTT, RTO + if (retrQElt.marked == 0) { + if (dt > rttCalcDt) { + rttCalcDt = dt; + rttCalcSeqnum = retrQElt.seqnum; + } + } else { + // In case we find no good candidate, make + // a guess by dividing by the number of attempts + // and keep the worst of them too. Since we + // know it may be too short, we will not use it + // if shortens rtt. + dt /= (retrQElt.marked + 1); + if (dt > fallBackDt) { + fallBackDt = dt; + fallBackSeqnum = retrQElt.seqnum; + } + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SACKD SEQN = " + retrQElt.seqnum); + } + + // GC this stuff + retrQElt = null; + + } else { + // Retransmit? Only if there is a hole in the selected + // acknowledgement list. Otherwise let RTO deal. + + // Given that this SACK acknowledged messages still + // in the retrQ: + // seqnum is the max consectively SACKD message. + // seqnum < retrQElt.seqnum means a message has not reached + // receiver. EG: sacklist == 10,11,13 seqnum == 11 + // We retransmit 12. + if (seqnum < retrQElt.seqnum) { + fc.packetMissing(retrQElt.seqnum); + retrans++; + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETR: Fill hole, SACK, seqn#" + retrQElt.seqnum + ", Window =" + retrans); + } + } + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SELECTIVE ACKD (" + numberACKed + ") " + retrans + " retrans wanted"); + } + } + + // Compute aveRTT on the most representative message, + // if any. That's the most accurate data. + // Failing that we use the fall back, provided that it not + // more recent than aveRTT ago - that would decrease aveRTT + // and in the absence of solid data, we do not want to take + // that risk. + if (rttCalcSeqnum != -1) { + calcRTT(rttCalcDt, rttCalcSeqnum); + // get fc to recompute rwindow + rwindow = fc.ackEventEnd(rmaxQSize, aveRTT, rttCalcDt); + } else if ((fallBackSeqnum != -1) && (fallBackDt > aveRTT)) { + calcRTT(fallBackDt, fallBackSeqnum); + // get fc to recompute rwindow + rwindow = fc.ackEventEnd(rmaxQSize, aveRTT, fallBackDt); + } + retrQ.notifyAll(); + } + } + + /** + * retransmit unacknowledged messages + * + * @param rwin max number of messages to retransmit + * @param triggerTime base time + * @return number of messages retransmitted. + */ + private int retransmit(int rwin, long triggerTime) { + + List retransMsgs = new ArrayList(); + + int numberToRetrans; + + // build a list of retries. + synchronized (retrQ) { + numberToRetrans = Math.min(retrQ.size(), rwin); + if (numberToRetrans > 0 && Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Number of messages pending retransmit =" + numberToRetrans); + } + for (int j = 0; j < numberToRetrans; j++) { + RetrQElt r = retrQ.get(j); + + // Mark message as retransmission + // need to know if a msg was retr or not for RTT eval + if (r.marked == 0) { + // First time: we're here because this message has not arrived, but + // the next one has. It may be an out of order message. + // Experience shows that such a message rarely arrives older than + // 1.2 * aveRTT. Beyond that, it's lost. It is also rare that we + // detect a hole within that delay. So, often enough, as soon as + // a hole is detected, it's time to resend...but not always. + if (TimeUtils.toRelativeTimeMillis(triggerTime, r.sentAt) < (6 * aveRTT) / 5) { + // Nothing to worry about, yet. + continue; + } + } else { + // That one has been retransmitted at least once already. + // So, we don't have much of a clue other than the age of the + // last transmission. It is unlikely that it arrives before aveRTT/2 + // but we have to anticipate its loss at the risk of making dupes. + // Otherwise the receiver will reach the hole, and that's really + // expensive. (Think that we've been trying for a while already.) + + if (TimeUtils.toRelativeTimeMillis(triggerTime, r.sentAt) < aveRTT) { + // Nothing to worry about, yet. + continue; + } + } + r.marked++; + // Make a copy to for sending + retransMsgs.add(r); + } + } + + // send the retries. + int retransmitted = 0; + Iterator eachRetrans = retransMsgs.iterator(); + + while (eachRetrans.hasNext()) { + RetrQElt r = eachRetrans.next(); + + eachRetrans.remove(); + try { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANSMIT seqn#" + r.seqnum); + } + Message sending = r.msg; + + // its possible that the message was + // acked while we were working in this + // case r.msg will have been nulled. + if (null != sending) { + sending = sending.clone(); + sending.replaceMessageElement(Defs.NAMESPACE, RETELT); + if (outgoing.send(sending)) { + r.sentAt = TimeUtils.timeNow(); + mrrIQFreeSpace--; + // assume we have now taken a slot + retransmitted++; + } else { + break; + // don't bother continuing sending now. + } + } + } catch (IOException e) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "FAILED RETRANS seqn#" + r.seqnum, e); + } + break; + // don't bother continuing. + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RETRANSMITED " + retransmitted + " of " + numberToRetrans); + } + + return retransmitted; + } + + /** + * Retransmission daemon thread + */ + private class Retransmitter implements Runnable { + + int nAtThisRTO = 0; + volatile int nretransmitted = 0; + + /** + * Constructor for the Retransmitter object + */ + public Retransmitter() { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("STARTED Reliable Retransmitter, RTO = " + RTO); + } + } + + /** + * Gets the retransCount attribute of the Retransmitter object + * + * @return The retransCount value + */ + public int getRetransCount() { + return nretransmitted; + } + + /** + * {@inheritDoc} + * + *

            Main processing method for the Retransmitter object + */ + public void run() { + try { + int idleCounter = 0; + + while (TimeUtils.toRelativeTimeMillis(closedAt) > 0) { + long conn_idle = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), outgoing.getLastAccessed()); + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine(outgoing + " idle for " + conn_idle); + } + + // check to see if we have not idled out. + if (outgoing.getIdleTimeout() < conn_idle) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Shutting down idle " + "connection " + outgoing); + } + + break; + } + + long sinceLastACK; + long oldestInQueueWait; + + synchronized (retrQ) { + try { + if (RTO > 0) { + retrQ.wait(RTO); + } + Thread.currentThread().setName( + "JXTA Reliable Retransmiter for " + this + " Queue size : " + retrQ.size()); + } catch (InterruptedException e) {// ignored + } + + if (TimeUtils.toRelativeTimeMillis(closedAt) <= 0) { + break; + } + + // see if we recently did a retransmit triggered by a SACK + long sinceLastSACKRetr = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), sackRetransTime); + + if (sinceLastSACKRetr < RTO) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("SACK retrans " + sinceLastSACKRetr + "ms ago"); + } + continue; + } + // See how long we've waited since RTO was set + sinceLastACK = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), lastACKTime); + + if (!retrQ.isEmpty()) { + RetrQElt elt = retrQ.get(0); + + oldestInQueueWait = TimeUtils.toRelativeTimeMillis(TimeUtils.timeNow(), elt.enqueuedAt); + } else { + oldestInQueueWait = 0; + } + } + + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("Last ACK " + sinceLastACK + "ms ago. Age of oldest in Queue " + oldestInQueueWait + "ms."); + } + + // see if the queue has gone dead + if (oldestInQueueWait > outgoing.getMaxRetryAge()) { + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("Shutting down stale connection " + outgoing); + } + + break; + } + + // get real wait as max of age of oldest in retrQ and + // lastAck time + long realWait = Math.max(oldestInQueueWait, sinceLastACK); + + // Retransmit only if RTO has expired. + // a. real wait time is longer than RTO + // b. oldest message on Q has been there longer + // than RTO. This is necessary because we may + // have just sent a message, and we do not + // want to overrun the receiver. Also, we + // do not want to restransmit a message that + // has not been idle for the RTO. + if ((realWait >= RTO) && (oldestInQueueWait >= RTO)) { + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("RTO RETRANSMISSION [" + rwindow + "]"); + } + // retransmit + int retransed = retransmit(rwindow, TimeUtils.timeNow()); + + // Total + nretransmitted += retransed; + // number at this RTO + nAtThisRTO += retransed; + // See if real wait is too long and queue is non-empty + // Remote may be dead - double until max. + // Double after window restransmitted msgs at this RTO + // exceeds the rwindow, and we've had no response for + // twice the current RTO. + if ((retransed > 0) && (realWait >= 2 * RTO) && (nAtThisRTO >= 2 * rwindow)) { + RTO = (realWait > maxRTO ? maxRTO : 2 * RTO); + nAtThisRTO = 0; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine( + "RETRANSMISSION " + retransed + " retrans " + nAtThisRTO + " at this RTO (" + RTO + ") " + + nretransmitted + " total retrans"); + } + } else { + idleCounter += 1; + // reset RTO to min if we are idle + if (idleCounter == 2) { + RTO = minRTO; + idleCounter = 0; + nAtThisRTO = 0; + } + if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) { + LOG.fine("IDLE : RTO=" + RTO + " WAIT=" + realWait); + } + } + } + } catch (Throwable all) { + LOG.log(Level.SEVERE, "Uncaught Throwable in thread :" + Thread.currentThread().getName(), all); + } finally { + hardClose(); + + retrThread = null; + + if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { + LOG.info("STOPPED Retransmit thread"); + } + } + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/Debug.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/Debug.java new file mode 100644 index 000000000..6ddf13f9b --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/Debug.java @@ -0,0 +1,125 @@ +package net.jxta.impl.xindice; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +import net.jxta.impl.xindice.util.*; +import java.io.*; + +import java.util.logging.Logger; +import java.util.logging.Level; +import net.jxta.logging.Logging; + + +/** + * Debug is a debugging class for the Xindice Server. Because the class + * and the Debugging field are final, the Java compiler should always + * inline the methods and optimize them away if Debugging is set to false. + */ + +public final class Debug { + + /** + * Log4J Logger. Since this is the logger for the whole of xindice, we + * compose the name a little differently than normal. + **/ + private final static Logger LOG = Logger.getLogger(Debug.class.getName()); + + public static final boolean Debugging = true; + + public static void SetPrintStream(PrintStream out) { + ; + } + + public static void println(Object obj, Object message) { + if (Debugging) { + if (obj instanceof Named) { + LOG.fine(((Named) obj).getName() + ": " + message); + } else { + LOG.fine(message + "\n\t@ " + obj); + } + } + } + + public static void println(Object message) { + if (Debugging) { + LOG.fine(message.toString()); + } + } + + public static void println() { + if (Debugging) { + LOG.fine(""); + } + } + + public static void printStackTrace(Throwable t) { + if (Debugging) { + LOG.log(Level.WARNING, t.getMessage(), t); + } + } + + public static void setPrintStream(PrintStream outStream) { + ; + } + + public static void setPrefix(String debugPrefix) { + ; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/DBException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/DBException.java new file mode 100644 index 000000000..9fdb2f628 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/DBException.java @@ -0,0 +1,86 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core; + +import net.jxta.impl.xindice.util.XindiceException; + +/** + * A DBException is thrown by the database if an exception occurs in the + * managing (creating, dropping) database objects such as Collections, + * Indexes, and XMLObjects. + */ +public class DBException extends XindiceException { + public int faultCode; + + public DBException() { + this(FaultCodes.GEN_UNKNOWN, "", null); + } + + public DBException(int faultCode) { + this(faultCode, "", null); + } + + public DBException(int faultCode, String message) { + this(faultCode, message, null); + } + + public DBException(int faultCode, String message, Throwable cause) { + super(message, cause); + this.faultCode = faultCode; + } + +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/DBObject.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/DBObject.java new file mode 100644 index 000000000..4b13995f3 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/DBObject.java @@ -0,0 +1,127 @@ +package net.jxta.impl.xindice.core; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + + +/** + * DBObject is the interface implemented by all Xindice database objects. + * DBObjects are typically objects that can be managed using XML + * configuration information, which is typically stored in the system + * database. XMLObjects are not considered DBObjects because of the + * steps involved in having to generate them, which is usually + * compilation of source code. + */ + +public interface DBObject { + + /** + * create creates a new DBObject and any associated resources for the new + * DBObject, such as disk files, etc. + * + * @return Whether or not the DBObject was created + * @throws DBException if a DB error occurs + */ + boolean create() throws DBException; + + /** + * open opens the DBObject + * + * @return Whether or not the DBObject was opened + * @throws DBException if a DB error occurs + */ + boolean open() throws DBException; + + /** + * isOpened returns whether or not the DBObject is opened for business. + * + * @return The open status of the DBObject + * @throws DBException if a DB error occurs + */ + boolean isOpened() throws DBException; + + /** + * exists returns whether or not a physical representation of this + * DBObject actually exists. In the case of a HashFiler, this would + * check for the file, and in the case of an FTPFiler, it might + * perform a connection check. + * + * @return Whether or not the physical resource exists + * @throws DBException if a DB error occurs + */ + boolean exists() throws DBException; + + /** + * drop instructs the DBObjectimplementation to remove itself from + * existence. The DBObject's parent is responsible for removing any + * references to the DBObject in its own context. + * + * @return Whether or not the DBObject was dropped + * @throws DBException if a DB error occurs + */ + boolean drop() throws DBException; + + /** + * close closes the DBObject + * + * @return Whether or not the DBObject was closed + * @throws DBException if a DB error occurs + */ + boolean close() throws DBException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/FaultCodes.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/FaultCodes.java new file mode 100644 index 000000000..b7f21a9c9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/FaultCodes.java @@ -0,0 +1,555 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core; + +import java.util.HashMap; +import java.util.Map; + +/** + * FaultCodes defines the Xindice specific fault codes and associated error + * messages. + */ +public abstract class FaultCodes { + + // the constants below have been pasted from + // org.apache.xindice.client.corba.db.FaultCodes + + // + // Constant value + // + public static final int GEN = (int) (0l); + + // + // Constant value + // + public static final int OBJ = (int) (100l); + + // + // Constant value + // + public static final int COL = (int) (200l); + + // + // Constant value + // + public static final int IDX = (int) (300l); + + // + // Constant value + // + public static final int TRX = (int) (400l); + + // + // Constant value + // + public static final int DBE = (int) (500l); + + // + // Constant value + // + public static final int QRY = (int) (600l); + + // + // Constant value + // + public static final int SEC = (int) (700l); + + // + // Constant value + // + public static final int URI = (int) (800l); + + // + // Constant value + // + public static final int JAVA = (int) (2000l); + + // + // Constant value + // + public static final int GEN_UNKNOWN = (int) (0l); + + // + // Constant value + // + public static final int GEN_GENERAL_ERROR = (int) (40l); + + // + // Constant value + // + public static final int GEN_CRITICAL_ERROR = (int) (70l); + + // + // Constant value + // + public static final int GEN_FATAL_ERROR = (int) (90l); + + // + // Constant value + // + public static final int OBJ_OBJECT_NOT_FOUND = (int) (100l); + + // + // Constant value + // + public static final int OBJ_METHOD_NOT_FOUND = (int) (101l); + + // + // Constant value + // + public static final int OBJ_NULL_RESULT = (int) (140l); + + // + // Constant value + // + public static final int OBJ_INVALID_RESULT = (int) (141l); + + // + // Constant value + // + public static final int OBJ_DUPLICATE_OBJECT = (int) (142l); + + // + // Constant value + // + public static final int OBJ_RUNTIME_EXCEPTION = (int) (170l); + + // + // Constant value + // + public static final int OBJ_CLASS_FORMAT_ERROR = (int) (171l); + + // + // Constant value + // + public static final int OBJ_INVALID_CONTEXT = (int) (172l); + + // + // Constant value + // + public static final int OBJ_CANNOT_CREATE = (int) (173l); + + // + // Constant value + // + public static final int COL_COLLECTION_NOT_FOUND = (int) (200l); + + // + // Constant value + // + public static final int COL_DOCUMENT_NOT_FOUND = (int) (201l); + + // + // Constant value + // + public static final int COL_DUPLICATE_COLLECTION = (int) (240l); + + // + // Constant value + // + public static final int COL_NULL_RESULT = (int) (241l); + + // + // Constant value + // + public static final int COL_NO_FILER = (int) (242l); + + // + // Constant value + // + public static final int COL_NO_INDEXMANAGER = (int) (242l); + + // + // Constant value + // + public static final int COL_DOCUMENT_MALFORMED = (int) (243l); + + // + // Constant value + // + public static final int COL_CANNOT_STORE = (int) (244l); + + // + // Constant value + // + public static final int COL_CANNOT_RETRIEVE = (int) (245l); + + // + // Constant value + // + public static final int COL_COLLECTION_READ_ONLY = (int) (246l); + + // + // Constant value + // + public static final int COL_COLLECTION_CLOSED = (int) (247l); + + // + // Constant value + // + public static final int COL_CANNOT_CREATE = (int) (270l); + + // + // Constant value + // + public static final int COL_CANNOT_DROP = (int) (271l); + + // + // Constant value + // + public static final int IDX_VALUE_NOT_FOUND = (int) (300l); + + // + // Constant value + // + public static final int IDX_INDEX_NOT_FOUND = (int) (301l); + + // + // Constant value + // + public static final int IDX_MATCHES_NOT_FOUND = (int) (340l); + + // + // Constant value + // + public static final int IDX_DUPLICATE_INDEX = (int) (341l); + + // + // Constant value + // + public static final int IDX_NOT_SUPPORTED = (int) (370l); + + // + // Constant value + // + public static final int IDX_STYLE_NOT_FOUND = (int) (371l); + + // + // Constant value + // + public static final int IDX_CORRUPTED = (int) (372l); + + // + // Constant value + // + public static final int IDX_CANNOT_CREATE = (int) (373l); + + // + // Constant value + // + public static final int TRX_DOC_LOCKED = (int) (400l); + + // + // Constant value + // + public static final int TRX_NO_CONTEXT = (int) (440l); + + // + // Constant value + // + public static final int TRX_NOT_ACTIVE = (int) (441l); + + // + // Constant value + // + public static final int TRX_NOT_SUPPORTED = (int) (470l); + + // + // Constant value + // + public static final int DBE_NO_PARENT = (int) (500l); + + // + // Constant value + // + public static final int DBE_CANNOT_DROP = (int) (570l); + + // + // Constant value + // + public static final int DBE_CANNOT_CREATE = (int) (571l); + + // + // Constant value + // + public static final int QRY_NULL_RESULT = (int) (600l); + + // + // Constant value + // + public static final int QRY_COMPILATION_ERROR = (int) (640l); + + // + // Constant value + // + public static final int QRY_PROCESSING_ERROR = (int) (641l); + + // + // Constant value + // + public static final int QRY_NOT_SUPPORTED = (int) (670l); + + // + // Constant value + // + public static final int QRY_STYLE_NOT_FOUND = (int) (671l); + + // + // Constant value + // + public static final int SEC_INVALID_USER = (int) (770l); + + // + // Constant value + // + public static final int SEC_INVALID_GROUP = (int) (771l); + + // + // Constant value + // + public static final int SEC_INVALID_ACCESS = (int) (772l); + + // + // Constant value + // + public static final int SEC_INVALID_CREDENTIALS = (int) (773l); + + // + // Constant value + // + public static final int URI_EMPTY = (int) (800l); + + // + // Constant value + // + public static final int URI_NULL = (int) (801l); + + // + // Constant value + // + public static final int URI_PARSE_ERROR = (int) (820l); + + // + // Constant value + // + public static final int JAVA_RUNTIME_ERROR = (int) (2070l); + + private static final Map FaultMsg = new HashMap(); + + private FaultCodes() {} + + static { + // General errors 0 series + putCodeMessage(GEN_UNKNOWN, "Unknown"); + putCodeMessage(GEN_GENERAL_ERROR, "General Error"); + putCodeMessage(GEN_CRITICAL_ERROR, "Critical Error"); + putCodeMessage(GEN_FATAL_ERROR, "Fatal Error"); + + // XMLObject invocation errors 100 series + putCodeMessage(OBJ_OBJECT_NOT_FOUND, "XMLObject Not Found"); + putCodeMessage(OBJ_METHOD_NOT_FOUND, "XMLObject Method Not Found"); + putCodeMessage(OBJ_NULL_RESULT, "XMLObject Null Result"); + putCodeMessage(OBJ_INVALID_RESULT, "XMLObject Invalid Result"); + putCodeMessage(OBJ_DUPLICATE_OBJECT, "XMLObject Duplicate Object"); + putCodeMessage(OBJ_RUNTIME_EXCEPTION, "XMLObject Runtime Exception"); + putCodeMessage(OBJ_CLASS_FORMAT_ERROR, "XMLObject Class Format Error"); + putCodeMessage(OBJ_INVALID_CONTEXT, "XMLObject Invalid Context"); + putCodeMessage(OBJ_CANNOT_CREATE, "XMLObject Cannot Create"); + + // Collection-related errors 200 series + putCodeMessage(COL_COLLECTION_NOT_FOUND, "Collection Not Found"); + putCodeMessage(COL_DOCUMENT_NOT_FOUND, "Collection Document Not Found"); + putCodeMessage(COL_DUPLICATE_COLLECTION, "Collection Duplicated"); + putCodeMessage(COL_NULL_RESULT, "Collection Null Result"); + putCodeMessage(COL_NO_FILER, "Collection No Filer"); + putCodeMessage(COL_NO_INDEXMANAGER, "Collection No IndexManager"); + putCodeMessage(COL_DOCUMENT_MALFORMED, "Collection Document Malformed"); + putCodeMessage(COL_CANNOT_STORE, "Collection Cannot Store"); + putCodeMessage(COL_CANNOT_RETRIEVE, "Collection Cannot Retrieve"); + putCodeMessage(COL_COLLECTION_READ_ONLY, "Collection Read-only"); + putCodeMessage(COL_COLLECTION_CLOSED, "Collection Closed"); + putCodeMessage(COL_CANNOT_CREATE, "Collection Cannot Create"); + putCodeMessage(COL_CANNOT_DROP, "Collection Cannot Drop"); + + // Index-related errors 300 series + putCodeMessage(IDX_VALUE_NOT_FOUND, "Index Value Not Found"); + putCodeMessage(IDX_INDEX_NOT_FOUND, "Index Not Found"); + putCodeMessage(IDX_MATCHES_NOT_FOUND, "Index Matches Not Found"); + putCodeMessage(IDX_DUPLICATE_INDEX, "Index Duplicate Index"); + putCodeMessage(IDX_NOT_SUPPORTED, "Index Not Supported"); + putCodeMessage(IDX_STYLE_NOT_FOUND, "Index Style Not Found"); + putCodeMessage(IDX_CORRUPTED, "Index Corrupted"); + putCodeMessage(IDX_CANNOT_CREATE, "Index Cannot Create"); + + // Transaction-related errors 400 series + putCodeMessage(TRX_DOC_LOCKED, "Transaction Document Locked"); + putCodeMessage(TRX_NO_CONTEXT, "Transaction No Context"); + putCodeMessage(TRX_NOT_ACTIVE, "Transaction Not Active"); + putCodeMessage(TRX_NOT_SUPPORTED, "Transaction Not Supported"); + + // Database-related errors 500 series + putCodeMessage(DBE_NO_PARENT, "Database No Parent"); + putCodeMessage(DBE_CANNOT_DROP, "Database Cannot Drop"); + putCodeMessage(DBE_CANNOT_CREATE, "Database Cannot Create"); + + // Query-related errors 600 series + putCodeMessage(QRY_NULL_RESULT, "Query Null Result"); + putCodeMessage(QRY_COMPILATION_ERROR, "Query Compilation Error"); + putCodeMessage(QRY_PROCESSING_ERROR, "Query Processing Error"); + putCodeMessage(QRY_NOT_SUPPORTED, "Query Not Supported"); + putCodeMessage(QRY_STYLE_NOT_FOUND, "Query Style Not Found"); + + // Security-related errors 700 series + putCodeMessage(SEC_INVALID_USER, "Security Invalid User"); + putCodeMessage(SEC_INVALID_GROUP, "Security Invalid Group"); + putCodeMessage(SEC_INVALID_ACCESS, "Security Invalid Access"); + putCodeMessage(SEC_INVALID_CREDENTIALS, "Security Invalid Credentials"); + + // URI-related errors 800 series + putCodeMessage(URI_EMPTY, "URI Empty"); + putCodeMessage(URI_NULL, "URI Null"); + putCodeMessage(URI_PARSE_ERROR, "URI Parse Error"); + + // Java-related errors 2000 series + putCodeMessage(JAVA_RUNTIME_ERROR, "Java Runtime Error"); + } + + private static void putCodeMessage(int code, String message) { + FaultMsg.put(code, message); + } + + /** + * getMessage returns a textual form for the specified fault code. + * + * @param code The Fault Code + * @return It's textual form + */ + public static String getMessage(int code) { + String msg = FaultMsg.get(code); + + return msg != null ? msg : ""; + } + + /** + * getFaultCodeType examines the provided exception to determine + * the general fault code that is associated with it. General + * fault codes are reduced from actual fault codes to be one of + * the GEN_ prefixed fault code values. + * + * @param e The Exception to examine + * @return The General Fault Code + */ + public static int getFaultCodeType(Exception e) { + int code = 0; + + if (e instanceof DBException) { + code = ((DBException) e).faultCode; + } + // Strip it to the General series + code = code % 100; + // Narrow to a General value + code = code - (code % 10); + return code; + } + + /** + * getFaultCodeSeries examines the provided exception to + * determine the fault code series that is associated with it. + * Series are reduced from actual fault codes to be one of + * the fault code prefixes (ex: COL, DB, SEC). + * + * @param e The Exception to examine + * @return The Fault Code Series + */ + public static int getFaultCodeSeries(Exception e) { + int code = 0; + + if (e instanceof DBException) { + code = ((DBException) e).faultCode; + } + // Strip it to the series + code = code - (code % 100); + return code; + } + + /** + * getFaultCode examines the provided exception to determine + * the fault code that is associated with it. + * + * @param e The Exception to examine + * @return The Fault Code + */ + public static int getFaultCode(Exception e) { + if (e instanceof DBException) { + return ((DBException) e).faultCode; + } else { + return 0; + } + } + + /** + * getFaultMessage examines the provided exception to determine + * the fault message that is associated with it. + * + * @param e The Exception to examine + * @return The Fault Message + */ + public static String getFaultMessage(Exception e) { + return getMessage(getFaultCode(e)); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Key.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Key.java new file mode 100644 index 000000000..8091cd09e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Key.java @@ -0,0 +1,125 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.data; + +/** + * Key extends Value by providing a hash value for the Key. + */ +public final class Key extends Value { + private int hash = 0; + + public Key(Value value) { + super(value); + } + + public Key(byte[] data) { + super(data); + } + + public Key(byte[] data, int pos, int len) { + super(data, pos, len); + } + + public Key(String data) { + super(data); + } + + // TODO: This has to be revisited + private void calculateHash() { + hash = 0; + int pl = pos + len; + + for (int i = pos; i < pl; i++) { + hash = (hash << 5) ^ data[i]; + hash = hash % 1234567891; + } + hash = Math.abs(hash); + } + + public int getHash() { + if (hash == 0) { + calculateHash(); + } + return hash; + } + + @Override + public boolean equals(Value value) { + if (value instanceof Key) { + Key key = (Key) value; + + return getHash() == key.getHash() && compareTo(key) == 0; + } else { + return super.equals(value); + } + } + + @Override + public int hashCode() { + return getHash(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Key) { + return equals((Key) obj); + } else { + return super.equals(obj); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Record.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Record.java new file mode 100644 index 000000000..5a7ff8e05 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Record.java @@ -0,0 +1,151 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.data; + +import java.util.Map; + +/** + * Record is a container for Key/Value pairs. Record also provides + * metadata for a Value stored in the database. + */ +public final class Record { + public static final String CREATED = "created"; + public static final String MODIFIED = "modified"; + public static final String LIFETIME = "lifetime"; + public static final String EXPIRATION = "expiration"; + public static final String OWNER = "owner"; + public static final String GROUP = "group"; + + private Key key = null; + private Value value = null; + private Map meta = null; + + public Record() {} + + public Record(Key key, Value value, Map meta) { + this.key = key; + this.value = value; + this.meta = meta; + } + + public Record(Key key, Value value) { + this.key = key; + this.value = value; + } + + /** + * setKey sets the Record's Key. + * + * @param key The new key + */ + public void setKey(Key key) { + this.key = key; + } + + /** + * getKey returns the Record's Key. + * + * @return The Record's Key + */ + public Key getKey() { + return key; + } + + /** + * setValue sets the Record's Value. + * + * @param value The new Value + */ + public void setValue(Value value) { + this.value = value; + } + + /** + * setValue sets the Record's Value. + * + * @param value The new Value + */ + public void setValue(String value) { + this.value = new Value(value); + } + + /** + * getValue returns the Record's Value. + * + * @return The Record's Value + */ + public Value getValue() { + return value; + } + + /** + * getMetaData returns metadata about the Value. + * + * @param name The property name + * @return The metadata value + */ + public Object getMetaData(Object name) { + return meta != null ? meta.get(name) : null; + } + + @Override + public String toString() { + return + (key != null ? key.toString() : "") + (value != null ? " = " + value.toString() : "") + + (meta != null ? " meta " + meta.toString() : ""); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/RecordSet.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/RecordSet.java new file mode 100644 index 000000000..b4b3074a4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/RecordSet.java @@ -0,0 +1,103 @@ +package net.jxta.impl.xindice.core.data; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +import net.jxta.impl.xindice.core.DBException; + +/** + * RecordSet is an interface for iterating over a set of Records. + * It is almost always returned by Filers. + */ +public interface RecordSet { + + /** + * hasMoreRecords returns whether or not there are any Records + * left in the set. + * + * @return Whether there are any more Records + * @throws net.jxta.impl.xindice.core.filer.BTreeException if a DB exception occurs + */ + boolean hasMoreRecords() throws DBException; + + /** + * getNextRecord returns the next Record in the set. + * + * @return The next Record + * @throws net.jxta.impl.xindice.core.filer.BTreeException if a DB exception occurs + */ + Record getNextRecord() throws DBException; + + /** + * getNextKey returns the next Record's Key, and skips the + * RecordSet ahead to the next Record. + * + * @return The next Key + * @throws net.jxta.impl.xindice.core.filer.BTreeException if a DB exception occurs + */ + Key getNextKey() throws DBException; + + /** + * getNextValue returns the next Record's Value, and skips the + * RecordSet ahead to the next Record. + * + * @return The next Value + * @throws net.jxta.impl.xindice.core.filer.BTreeException if a DB exception occurs + */ + Value getNextValue() throws DBException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Value.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Value.java new file mode 100644 index 000000000..3291128be --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/data/Value.java @@ -0,0 +1,278 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.data; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +/** + * Value is the primary base class for all data storing objects. + * The content window of Value objects are immutable, but the + * underlying byte array is not. + * + */ +public class Value implements Comparable { + + protected byte[] data = null; + protected int pos = 0; + protected int len = -1; + + public Value(Value value) { + this.data = value.data; + this.pos = value.pos; + this.len = value.len; + } + + public Value(byte[] data) { + this.data = data; + this.len = data.length; + } + + public Value(byte[] data, int pos, int len) { + this.data = data; + this.pos = pos; + this.len = len; + } + + public Value(String data) { + try { + this.data = data.getBytes("utf-8"); + this.len = this.data.length; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Java doesn't support UTF-8 encoding", e); + } + } + + /** + * getData retrieves the data being stored by the Value as a byte array. + * + * @return The Data + */ + public final byte[] getData() { + if (len != data.length) { + byte[] b = new byte[len]; + + System.arraycopy(data, pos, b, 0, len); + return b; + } else { + return data; + } + } + + /** + * getLength retrieves the length of the data being stored by the Value. + * + * @return The Value length + */ + public final int getLength() { + return len; + } + + /** + * getInputStream returns an InputStream for the Value. + * + * @return An InputStream + */ + public final InputStream getInputStream() { + return new ByteArrayInputStream(data, pos, len); + } + + /** + * streamTo streams the content of the Value to an OutputStream. + * + * @param out the OutputStream + * @throws java.io.IOException if an io error occurs + */ + public final void streamTo(OutputStream out) throws IOException { + out.write(data, pos, len); + } + + public final void copyTo(byte[] tdata, int tpos) { + System.arraycopy(data, pos, tdata, tpos, len); + } + + public final void copyTo(byte[] tdata, int tpos, int len) { + System.arraycopy(data, pos, tdata, tpos, len); + } + + @Override + public final String toString() { + try { + return new String(data, pos, len, "utf-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Java doesn't seem to support UTF-8!", e); + } + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + public boolean equals(Value value) { + return len == value.len && compareTo(value) == 0; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Value) { + return equals((Value) obj); + } else { + return equals(new Value(obj.toString())); + } + } + + public final int compareTo(Value value) { + byte[] ddata = value.data; + int dpos = value.pos; + int dlen = value.len; + + int stop = len > dlen ? dlen : len; + + for (int i = 0; i < stop; i++) { + byte b1 = data[pos + i]; + byte b2 = ddata[dpos + i]; + + if (b1 == b2) { + // do nothing + } else { + short s1 = (short) (b1 >>> 0); + short s2 = (short) (b2 >>> 0); + + return s1 > s2 ? (i + 1) : -(i + 1); + } + } + + if (len == dlen) { + return 0; + } else { + return len > dlen ? stop + 1 : -(stop + 1); + } + } + + public final int compareTo(Object obj) { + if (obj instanceof Value) { + return compareTo((Value) obj); + } else { + return compareTo(new Value(obj.toString())); + } + } + + public final boolean startsWith(Value value) { + if (len < value.len) { + return false; + } + + byte[] ddata = value.data; + int dpos = value.pos; + + for (int i = 0; i < value.len; i++) { + if (data[i + pos] != ddata[i + dpos]) { + return false; + } + } + + return true; + } + + public final boolean endsWith(Value value) { + if (len < value.len) { + return false; + } + + byte[] ddata = value.data; + int dpos = value.pos; + + int offset = len - value.len; + + for (int i = 0; i < value.len; i++) { + if (data[i + pos + offset] != ddata[i + dpos]) { + return false; + } + } + + return true; + } + + public final boolean contains(Value value) { + if (len < value.len) { + return false; + } + boolean match; + byte[] ddata = value.data; + int dpos = value.pos; + + for (int offset = 0; offset <= len - value.len; offset++) { + match = true; + for (int i = 0; i < value.len; i++) { + if (data[i + pos + offset] != ddata[i + dpos]) { + match = false; + } + } + if (match) { + return true; + } + } + return false; + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTree.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTree.java new file mode 100644 index 000000000..958e456f7 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTree.java @@ -0,0 +1,1194 @@ +package net.jxta.impl.xindice.core.filer; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.FaultCodes; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.core.indexer.IndexQuery; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Map; +import java.util.WeakHashMap; + +import java.util.logging.Level; +import net.jxta.logging.Logging; +import java.util.logging.Logger; + + +/** + * BTree represents a Variable Magnitude Simple-Prefix B+Tree File. + * A BTree is a bit flexible in that it can be used for set or + * map-based indexing. HashFiler uses the BTree as a set for + * producing RecordSet entries. The Indexers use BTree as a map for + * indexing entity and attribute values in Documents. + *

            + * For those who don't know how a Simple-Prefix B+Tree works, the primary + * distinction is that instead of promoting actual keys to branch pages, + * when leaves are split, a shortest-possible separator is generated at + * the pivot. That separator is what is promoted to the parent branch + * (and continuing up the list). As a result, actual keys and pointers + * can only be found at the leaf level. This also affords the index the + * ability to ignore costly merging and redistribution of pages when + * deletions occur. Deletions only affect leaf pages in this + * implementation, and so it is entirely possible for a leaf page to be + * completely empty after all of its keys have been removed. + *

            + * Also, the Variable Magnitude attribute means that the btree attempts + * to store as many values and pointers on one page as is possible. + *

            + * This implementation supports the notion of nested roots. This means + * that you can create a btree where the pointers actually point to the + * root of a separate btree being managed in the same file. + */ + +public class BTree extends Paged { + private final static Logger LOG = Logger.getLogger(BTree.class.getName()); + protected static final byte LEAF = 1; + protected static final byte BRANCH = 2; + protected static final byte STREAM = 3; + + /** + * Cache of the recently used tree nodes. + * + * Cache contains weak references to the BTreeNode objects, keys are page numbers (Long objects). + * Access synchronized by this map itself. + */ + private final Map> cache = new WeakHashMap>(); + + private BTreeFileHeader fileHeader; + private BTreeRootInfo rootInfo; + private BTreeNode rootNode; + + public BTree() { + super(); + fileHeader = (BTreeFileHeader) getFileHeader(); + } + + public BTree(File file) { + this(); + setFile(file); + } + + /** + * Setting this option forces all system buffers with the underlying device + * if sync is set writes return after all modified data and attributes of the DB + * have been written to the device. + * by default sync is true. + * {@link java.io.FileDescriptor} + * @param sync if true, invokes FD.sync(), an expensive operation, required to ensure high consistency, especially + * with system failures. + */ + public void setSync(boolean sync) { + this.sync = sync; + } + + @Override + public boolean open() throws DBException { + if (super.open()) { + long p = fileHeader.getRootPage(); + + rootInfo = new BTreeRootInfo(p); + rootNode = getBTreeNode(p, null); + return true; + } else { + return false; + } + } + + @Override + public boolean create() throws DBException { + if (super.create()) { + try { + // Don't call this.open() as it will try to read rootNode from the disk + super.open(); + + long p = fileHeader.getRootPage(); + + rootInfo = new BTreeRootInfo(p); + + // Initialize root node + rootNode = new BTreeNode(getPage(p), null, new Value[0], new long[0]); + rootNode.ph.setStatus(LEAF); + rootNode.write(); + synchronized (cache) { + cache.put(rootNode.page.getPageNum(), new WeakReference(rootNode)); + } + close(); + return true; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Failed to create BTree, return false", e); + } + } + } + return false; + } + + /** + * addValue adds a Value to the BTree and associates a pointer with + * it. The pointer can be used for referencing any type of data, it + * just so happens that Xindice uses it for referencing pages of + * associated data in the BTree file or other files. + * + * @param value The Value to add + * @param pointer The pointer to associate with it + * @return The previous value for the pointer (or -1) + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public long addValue(Value value, long pointer) throws IOException, BTreeException { + return getRootNode().addValue(value, pointer); + } + + /** + * addValue adds a Value to the BTree and associates a pointer with + * it. The pointer can be used for referencing any type of data, it + * just so happens that Xindice uses it for referencing pages of + * associated data in the BTree file or other files. + * + * @param root The BTree's root information (for nested trees) + * @param value The Value to add + * @param pointer The pointer to associate with it + * @return The previous value for the pointer (or -1) + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public long addValue(BTreeRootInfo root, Value value, long pointer) throws IOException, BTreeException { + return getRootNode(root).addValue(value, pointer); + } + + /** + * removeValue removes a Value from the BTree and returns the + * associated pointer for it. + * + * @param value The Value to remove + * @return The pointer that was associated with it + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public long removeValue(Value value) throws IOException, BTreeException { + return getRootNode().removeValue(value); + } + + /** + * removeValue removes a Value from the BTree and returns the + * associated pointer for it. + * + * @param root The BTree's root information (for nested trees) + * @param value The Value to remove + * @return The pointer that was associated with it + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public long removeValue(BTreeRootInfo root, Value value) throws IOException, BTreeException { + return getRootNode(root).removeValue(value); + } + + /** + * findValue finds a Value in the BTree and returns the associated + * pointer for it. + * + * @param value The Value to find + * @return The pointer that was associated with it + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public long findValue(Value value) throws IOException, BTreeException { + return getRootNode().findValue(value); + } + + /** + * findValue finds a Value in the BTree and returns the associated + * pointer for it. + * + * @param root The BTree's root information (for nested trees) + * @param value The Value to find + * @return The pointer that was associated with it + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public long findValue(BTreeRootInfo root, Value value) throws IOException, BTreeException { + return getRootNode(root).findValue(value); + } + + /** + * query performs a query against the BTree and performs callback + * operations to report the search results. + * + * @param query The IndexQuery to use (or null for everything) + * @param callback The callback instance + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public void query(IndexQuery query, BTreeCallback callback) throws IOException, BTreeException { + getRootNode().query(query, callback); + } + + /** + * query performs a query against the BTree and performs callback + * operations to report the search results. + * + * @param root The BTree's root information (for nested trees) + * @param query The IndexQuery to use (or null for everything) + * @param callback The callback instance + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + public void query(BTreeRootInfo root, IndexQuery query, BTreeCallback callback) throws IOException, BTreeException { + getRootNode(root).query(query, callback); + } + + /** + * createBTreeRoot creates a new BTree root node in the BTree file + * based on the provided value for the main tree. + * + * @param v The sub-tree Value to create + * @return The new BTreeRootInfo instance + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + protected final BTreeRootInfo createBTreeRoot(Value v) throws IOException, BTreeException { + BTreeNode n = createBTreeNode(BTree.LEAF, null); + n.write(); + long position = n.page.getPageNum(); + + addValue(v, position); + return new BTreeRootInfo(v, position); + } + + /** + * createBTreeRoot creates a new BTree root node in the BTree file + * based on the provided root information, and value for the tree. + * + * @param root The BTreeRootInfo to build off of + * @param v The sub-tree Value to create + * @return The new BTreeRootInfo instance + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + protected final BTreeRootInfo createBTreeRoot(BTreeRootInfo root, Value v) throws IOException, BTreeException { + BTreeNode n = createBTreeNode(BTree.LEAF, null); + + n.write(); + + long position = n.page.getPageNum(); + + addValue(v, position); + return new BTreeRootInfo(root, v, position); + } + + /** + * findBTreeRoot searches for a BTreeRoot in the file and returns + * the BTreeRootInfo for the specified value based on the main tree. + * + * @param v The sub-tree Value to search for + * @return The new BTreeRootInfo instance + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + protected final BTreeRootInfo findBTreeRoot(Value v) throws IOException, BTreeException { + long position = findValue(v); + + return new BTreeRootInfo(v, position); + } + + /** + * findBTreeRoot searches for a BTreeRoot in the file and returns + * the BTreeRootInfo for the specified value based on the provided + * BTreeRootInfo value. + * + * @param root The BTreeRootInfo to search from + * @param v The sub-tree Value to search for + * @return The new BTreeRootInfo instance + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + protected final BTreeRootInfo findBTreeRoot(BTreeRootInfo root, Value v) throws IOException, BTreeException { + long position = findValue(root, v); + + return new BTreeRootInfo(root, v, position); + } + + /** + * setRootNode resets the root for the specified root object to the + * provided BTreeNode's page number. + * + * This method is not thread safe. + * + * @param root The root to reset + * @param newRoot the new root node to use + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + protected final void setRootNode(BTreeRootInfo root, BTreeNode newRoot) throws IOException, BTreeException { + BTreeRootInfo parent = root.getParent(); + + if (parent == null) { + rootNode = newRoot; + long p = rootNode.page.getPageNum(); + + rootInfo.setPage(p); + fileHeader.setRootPage(p); + } else { + long p = newRoot.page.getPageNum(); + + root.setPage(p); + addValue(parent, root.name, p); + } + } + + /** + * setRootNode resets the file's root to the provided + * BTreeNode's page number. + * + * This method is not thread safe. + * + * @param rootNode the new root node to use + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + protected final void setRootNode(BTreeNode rootNode) throws IOException, BTreeException { + setRootNode(rootInfo, rootNode); + } + + /** + * getRootNode retreives the BTree node for the specified + * root object. + * + * @param root The root object to retrieve with + * @return The root node + */ + protected final BTreeNode getRootNode(BTreeRootInfo root) { + if (root.page == rootInfo.page) { + return rootNode; + } else { + return getBTreeNode(root.getPage(), null); + } + } + + /** + * getRootNode retreives the BTree node for the file's root. + * + * @return The root node + */ + protected final BTreeNode getRootNode() { + return rootNode; + } + + private BTreeNode getBTreeNode(long page, BTreeNode parent) { + try { + BTreeNode node = null; + + synchronized (cache) { + WeakReference ref = cache.get(page); + + if (ref != null) { + node = ref.get(); + } + + if (node == null) { + node = new BTreeNode(getPage(page), parent); + } else { + node.parent = parent; + } + + cache.put(node.page.getPageNum(), new WeakReference(node)); + } + + node.read(); + return node; + } catch (Exception e) { + if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, "Ignored exception", e); + } + return null; + } + } + + private BTreeNode createBTreeNode(byte status, BTreeNode parent) throws IOException { + Page p = getFreePage(); + BTreeNode node = new BTreeNode(p, parent, new Value[0], new long[0]); + + node.ph.setStatus(status); + synchronized (cache) { + cache.put(p.getPageNum(), new WeakReference(node)); + } + return node; + } + + /** + * BTreeRootInfo + */ + public final class BTreeRootInfo { + private final BTreeRootInfo parent; + private final Value name; + private long page; + + public BTreeRootInfo(BTreeRootInfo parent, String name, long page) { + this.parent = parent; + this.name = new Value(name); + this.page = page; + } + + public BTreeRootInfo(BTreeRootInfo parent, Value name, long page) { + this.parent = parent; + this.name = name; + this.page = page; + } + + public BTreeRootInfo(String name, long page) { + this.parent = rootInfo; + this.name = new Value(name); + this.page = page; + } + + public BTreeRootInfo(Value name, long page) { + this.parent = rootInfo; + this.name = name; + this.page = page; + } + + private BTreeRootInfo(long page) { + parent = null; + name = null; + this.page = page; + } + + public BTreeRootInfo getParent() { + return parent; + } + + public Value getName() { + return name; + } + + public synchronized long getPage() { + return page; + } + + public synchronized void setPage(long page) { + this.page = page; + } + } + + + /** + * BTreeNode + */ + private final class BTreeNode { + private final Page page; + private final BTreePageHeader ph; + private Value[] values; + private long[] ptrs; + private BTreeNode parent; + private boolean loaded; + + public BTreeNode(Page page) { + this(page, null); + } + + public BTreeNode(Page page, BTreeNode parent) { + this.page = page; + this.parent = parent; + this.ph = (BTreePageHeader) page.getPageHeader(); + } + + public BTreeNode(Page page, BTreeNode parent, Value[] values, long[] ptrs) { + this(page, parent); + set(values, ptrs); + this.loaded = true; + } + + /** + * Sets values and pointers. + * Internal (to the BTreeNode) method, not synchronized. + * @param ptrs pointers + * @param values their values + */ + private void set(Value[] values, long[] ptrs) { + this.values = values; + this.ph.setValueCount((short) values.length); + this.ptrs = ptrs; + } + + /** + * Reads node only if it is not loaded yet + * @throws java.io.IOException if an io error occurs + */ + public synchronized void read() throws IOException { + if (!this.loaded) { + Value v = readValue(page); + DataInputStream is = new DataInputStream(v.getInputStream()); + + // Read in the Values + values = new Value[ph.getValueCount()]; + for (int i = 0; i < values.length; i++) { + short valSize = is.readShort(); + byte[] b = new byte[valSize]; + + is.read(b); + values[i] = new Value(b); + } + + // Read in the pointers + ptrs = new long[ph.getPointerCount()]; + for (int i = 0; i < ptrs.length; i++) { + ptrs[i] = is.readLong(); + } + + this.loaded = true; + } + } + + public synchronized void write() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(fileHeader.getWorkSize()); + DataOutputStream os = new DataOutputStream(bos); + + // Write out the Values + for (Value value : values) { + os.writeShort(value.getLength()); + value.streamTo(os); + } + + // Write out the pointers + for (long ptr : ptrs) { + os.writeLong(ptr); + } + + writeValue(page, new Value(bos.toByteArray())); + } + + /** + * Internal (to the BTreeNode) method. + * Because this method is called only by BTreeNode itself, no synchronization done inside of this method. + * @param idx the index + * @return the BTree node + */ + private BTreeNode getChildNode(int idx) { + if (ph.getStatus() == BRANCH && idx >= 0 && idx < ptrs.length) { + return getBTreeNode(ptrs[idx], this); + } else { + return null; + } + } + + /* Not used + private synchronized void getChildStream(int idx, Streamable stream) throws IOException { + if (ph.getStatus() == LEAF && idx >= 0 && idx < ptrs.length) { + Value v = readValue(ptrs[idx]); + DataInputStream dis = new DataInputStream(v.getInputStream()); + stream.read(dis); + } + } + */ + + public synchronized long removeValue(Value value) throws IOException, BTreeException { + int idx = Arrays.binarySearch(values, value); + + switch (ph.getStatus()) { + case BRANCH: + idx = idx < 0 ? -(idx + 1) : idx + 1; + return getChildNode(idx).removeValue(value); + + case LEAF: + if (idx < 0) { + throw new BTreeNotFoundException("Value '" + value + "' doesn't exist"); + } else { + long oldPtr = ptrs[idx]; + + set(deleteArrayValue(values, idx), deleteArrayLong(ptrs, idx)); + + write(); + return oldPtr; + } + + default: + throw new BTreeCorruptException("Invalid page type '" + ph.getStatus() + "' in removeValue"); + } + } + + public synchronized long addValue(Value value, long pointer) throws IOException, BTreeException { + if (value == null) { + throw new BTreeException(FaultCodes.DBE_CANNOT_CREATE, "Can't add a null Value"); + } + + int idx = Arrays.binarySearch(values, value); + + switch (ph.getStatus()) { + case BRANCH: + idx = idx < 0 ? -(idx + 1) : idx + 1; + return getChildNode(idx).addValue(value, pointer); + + case LEAF: + if (idx >= 0) { + // Value was found... Overwrite + long oldPtr = ptrs[idx]; + + ptrs[idx] = pointer; + + set(values, ptrs); + + write(); + return oldPtr; + } else { + // Value was not found + idx = -(idx + 1); + + // Check to see if we've exhausted the block + boolean split = needSplit(value); + + set(insertArrayValue(values, value, idx), insertArrayLong(ptrs, pointer, idx)); + + if (split) { + split(); + } else { + write(); + } + } + return -1; + + default: + throw new BTreeCorruptException("Invalid Page Type In addValue"); + } + } + + private synchronized void promoteValue(Value value, long rightPointer) throws IOException, BTreeException { + // Check to see if we've exhausted the block + boolean split = needSplit(value); + + int idx = Arrays.binarySearch(values, value); + + idx = idx < 0 ? -(idx + 1) : idx + 1; + + set(insertArrayValue(values, value, idx), insertArrayLong(ptrs, rightPointer, idx + 1)); + + if (split) { + split(); + } else { + write(); + } + } + + private Value getSeparator(Value value1, Value value2) { + int idx = value1.compareTo(value2); + byte[] b = new byte[Math.abs(idx)]; + + value2.copyTo(b, 0, b.length); + return new Value(b); + } + + /** + * Do we need to split this node after adding one more value? + * @param value the value to split + * @return true if successful + */ + private boolean needSplit(Value value) { + // Do NOT split if just 4 key/values are in the node. + return this.values.length > 4 && // CurrLength + one Long pointer + value length + one short + this.ph.getDataLen() + 8 + value.getLength() + 2 > BTree.this.fileHeader.getWorkSize(); + } + + /** + * Internal to the BTreeNode method + * @throws java.io.IOException if an io error occurs + * @throws BTreeException if a DB exception occurs + */ + private void split() throws IOException, BTreeException { + Value[] leftVals; + Value[] rightVals; + long[] leftPtrs; + long[] rightPtrs; + Value separator; + + short vc = ph.getValueCount(); + int pivot = vc / 2; + + // Split the node into two nodes + switch (ph.getStatus()) { + case BRANCH: + leftVals = new Value[pivot]; + leftPtrs = new long[leftVals.length + 1]; + rightVals = new Value[vc - (pivot + 1)]; + rightPtrs = new long[rightVals.length + 1]; + + System.arraycopy(values, 0, leftVals, 0, leftVals.length); + System.arraycopy(ptrs, 0, leftPtrs, 0, leftPtrs.length); + System.arraycopy(values, leftVals.length + 1, rightVals, 0, rightVals.length); + System.arraycopy(ptrs, leftPtrs.length, rightPtrs, 0, rightPtrs.length); + + separator = values[leftVals.length]; + break; + + case LEAF: + leftVals = new Value[pivot]; + leftPtrs = new long[leftVals.length]; + rightVals = new Value[vc - pivot]; + rightPtrs = new long[rightVals.length]; + + System.arraycopy(values, 0, leftVals, 0, leftVals.length); + System.arraycopy(ptrs, 0, leftPtrs, 0, leftPtrs.length); + System.arraycopy(values, leftVals.length, rightVals, 0, rightVals.length); + System.arraycopy(ptrs, leftPtrs.length, rightPtrs, 0, rightPtrs.length); + + separator = getSeparator(leftVals[leftVals.length - 1], rightVals[0]); + break; + + default: + throw new BTreeCorruptException("Invalid Page Type In split"); + } + + // Promote the pivot to the parent branch + if (parent == null) { + // This can only happen if this is the root + BTreeNode rNode = createBTreeNode(ph.getStatus(), this); + + rNode.set(rightVals, rightPtrs); + + BTreeNode lNode = createBTreeNode(ph.getStatus(), this); + + lNode.set(leftVals, leftPtrs); + + ph.setStatus(BRANCH); + set(new Value[] { + separator + }, new long[] {lNode.page.getPageNum(), rNode.page.getPageNum()}); + + write(); + rNode.write(); + lNode.write(); + } else { + set(leftVals, leftPtrs); + + BTreeNode rNode = createBTreeNode(ph.getStatus(), parent); + + rNode.set(rightVals, rightPtrs); + + write(); + rNode.write(); + parent.promoteValue(separator, rNode.page.getPageNum()); + } + } + + // /////////////////////////////////////////////////////////////// + + public synchronized long findValue(Value value) throws IOException, BTreeException { + if (value == null) { + throw new BTreeNotFoundException("Can't search on null Value"); + } + + int idx = Arrays.binarySearch(values, value); + + switch (ph.getStatus()) { + case BRANCH: + idx = idx < 0 ? -(idx + 1) : idx + 1; + return getChildNode(idx).findValue(value); + + case LEAF: + if (idx < 0) { + throw new BTreeNotFoundException("Value '" + value + "' doesn't exist"); + } else { + return ptrs[idx]; + } + + default: + throw new BTreeCorruptException("Invalid page type '" + ph.getStatus() + "' in findValue"); + } + } + + // query is a BEAST of a method + public synchronized void query(IndexQuery query, BTreeCallback callback) throws IOException, BTreeException { + if (query != null && query.getOperator() != IndexQuery.ANY) { + Value[] qvals = query.getValues(); + int leftIdx = Arrays.binarySearch(values, qvals[0]); + int rightIdx = qvals.length > 1 ? Arrays.binarySearch(values, qvals[qvals.length - 1]) : leftIdx; + + switch (ph.getStatus()) { + case BRANCH: + leftIdx = leftIdx < 0 ? -(leftIdx + 1) : leftIdx + 1; + rightIdx = rightIdx < 0 ? -(rightIdx + 1) : rightIdx + 1; + + switch (query.getOperator()) { + case IndexQuery.BWX: + case IndexQuery.BW: + case IndexQuery.IN: + case IndexQuery.SW: + // TODO: Can leftIdx be less than 0 here? + if (leftIdx < 0) { + leftIdx = 0; + } + if (rightIdx > ptrs.length - 1) { + rightIdx = ptrs.length - 1; + } + for (int i = leftIdx; i <= rightIdx; i++) { + getChildNode(i).query(query, callback); + } + break; + + case IndexQuery.NBWX: + case IndexQuery.NBW: + case IndexQuery.NIN: + case IndexQuery.NSW: + if (leftIdx > ptrs.length - 1) { + leftIdx = ptrs.length - 1; + } + for (int i = 0; i <= leftIdx; i++) { + getChildNode(i).query(query, callback); + } + if (rightIdx < 0) { + rightIdx = 0; + } + for (int i = rightIdx; i < ptrs.length; i++) { + getChildNode(i).query(query, callback); + } + break; + + case IndexQuery.EQ: + getChildNode(leftIdx).query(query, callback); + break; + + case IndexQuery.LT: + case IndexQuery.LEQ: + if (leftIdx > ptrs.length - 1) { + leftIdx = ptrs.length - 1; + } + for (int i = 0; i <= leftIdx; i++) { + getChildNode(i).query(query, callback); + } + break; + + case IndexQuery.GT: + case IndexQuery.GEQ: + if (rightIdx < 0) { + rightIdx = 0; + } + for (int i = rightIdx; i < ptrs.length; i++) { + getChildNode(i).query(query, callback); + } + break; + + case IndexQuery.NEQ: + default: + for (int i = 0; i < ptrs.length; i++) { + getChildNode(i).query(query, callback); + } + break; + } + break; + + case LEAF: + switch (query.getOperator()) { + case IndexQuery.EQ: + if (leftIdx >= 0) { + callback.indexInfo(values[leftIdx], ptrs[leftIdx]); + } + break; + + case IndexQuery.NEQ: + for (int i = 0; i < ptrs.length; i++) { + if (i != leftIdx) { + callback.indexInfo(values[i], ptrs[i]); + } + } + break; + + case IndexQuery.BWX: + case IndexQuery.BW: + case IndexQuery.SW: + case IndexQuery.IN: + if (leftIdx < 0) { + leftIdx = -(leftIdx + 1); + } + if (rightIdx < 0) { + rightIdx = -(rightIdx + 1); + } + for (int i = 0; i < ptrs.length; i++) { // FIXME: VG: Optimize this loop + if (i >= leftIdx && i <= rightIdx && query.testValue(values[i])) { + callback.indexInfo(values[i], ptrs[i]); + } + } + break; + + case IndexQuery.NBWX: + case IndexQuery.NBW: + case IndexQuery.NSW: + if (leftIdx < 0) { + leftIdx = -(leftIdx + 1); + } + if (rightIdx < 0) { + rightIdx = -(rightIdx + 1); + } + for (int i = 0; i < ptrs.length; i++) { + if ((i <= leftIdx || i >= rightIdx) && query.testValue(values[i])) { + callback.indexInfo(values[i], ptrs[i]); + } + } + break; + + case IndexQuery.LT: + case IndexQuery.LEQ: + if (leftIdx < 0) { + leftIdx = -(leftIdx + 1); + } + for (int i = 0; i < ptrs.length; i++) { + if (i <= leftIdx && query.testValue(values[i])) { + callback.indexInfo(values[i], ptrs[i]); + } + } + break; + + case IndexQuery.GT: + case IndexQuery.GEQ: + if (rightIdx < 0) { + rightIdx = -(rightIdx + 1); + } + + for (int i = 0; i < ptrs.length; i++) { + if (i >= rightIdx && query.testValue(values[i])) { + callback.indexInfo(values[i], ptrs[i]); + } + } + break; + + case IndexQuery.NIN: + default: + for (int i = 0; i < ptrs.length; i++) { + if (query.testValue(values[i])) { + callback.indexInfo(values[i], ptrs[i]); + } + } + break; + } + break; + + default: + throw new BTreeCorruptException("Invalid Page Type In query"); + } + + } else { + // No Query - Just Walk The Tree + switch (ph.getStatus()) { + case BRANCH: + for (int i = 0; i < ptrs.length; i++) { + getChildNode(i).query(query, callback); + } + break; + + case LEAF: + for (int i = 0; i < values.length; i++) { + callback.indexInfo(values[i], ptrs[i]); + } + break; + + default: + throw new BTreeCorruptException("Invalid Page Type In query"); + } + } + } + } + + // ////////////////////////////////////////////////////////////////// + + @Override + public FileHeader createFileHeader() { + BTreeFileHeader header = new BTreeFileHeader(); + + header.setPageCount(1); + header.setTotalCount(1); + return header; + } + + @Override + public FileHeader createFileHeader(boolean read) throws IOException { + return new BTreeFileHeader(read); + } + + @Override + public FileHeader createFileHeader(long pageCount) { + return new BTreeFileHeader(pageCount); + } + + @Override + public FileHeader createFileHeader(long pageCount, int pageSize) { + return new BTreeFileHeader(pageCount, pageSize); + } + + @Override + public PageHeader createPageHeader() { + return new BTreePageHeader(); + } + + /** + * BTreeFileHeader + */ + + protected class BTreeFileHeader extends FileHeader { + private long rootPage = 0; + + public BTreeFileHeader() {} + + public BTreeFileHeader(long pageCount) { + super(pageCount); + } + + public BTreeFileHeader(long pageCount, int pageSize) { + super(pageCount, pageSize); + } + + public BTreeFileHeader(boolean read) throws IOException { + super(read); + } + + @Override + public synchronized void read(RandomAccessFile raf) throws IOException { + super.read(raf); + rootPage = raf.readLong(); + } + + @Override + public synchronized void write(RandomAccessFile raf) throws IOException { + super.write(raf); + raf.writeLong(rootPage); + } + + /** + * The root page of the storage tree + * @param rootPage the new root page + */ + public synchronized final void setRootPage(long rootPage) { + this.rootPage = rootPage; + setDirty(); + } + + /** + * The root page of the storage tree + * @return the root page + */ + public synchronized final long getRootPage() { + return rootPage; + } + } + + + /** + * BTreePageHeader + */ + + protected class BTreePageHeader extends PageHeader { + private short valueCount = 0; + + public BTreePageHeader() {} + + public BTreePageHeader(DataInputStream dis) throws IOException { + super(dis); + } + + @Override + public synchronized void read(DataInputStream dis) throws IOException { + super.read(dis); + if (getStatus() == UNUSED) { + return; + } + + valueCount = dis.readShort(); + } + + @Override + public synchronized void write(DataOutputStream dos) throws IOException { + super.write(dos); + dos.writeShort(valueCount); + } + + /** The number of values stored by this page + * @param valueCount the value count + */ + public synchronized final void setValueCount(short valueCount) { + this.valueCount = valueCount; + setDirty(); + } + + /** + * The number of values stored by this page + * @return the value count + */ + public synchronized final short getValueCount() { + return valueCount; + } + + /** + * The number of pointers stored by this page + * @return the pointer count + */ + public synchronized final short getPointerCount() { + if (getStatus() == BRANCH) { + return (short) (valueCount + 1); + } else { + return valueCount; + } + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeCallback.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeCallback.java new file mode 100644 index 000000000..fe04d57ca --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeCallback.java @@ -0,0 +1,76 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.data.Value; + +/** + * BTreeCallback is a callback interface for BTree queries. + */ + +public interface BTreeCallback { + + /** + * indexInfo is a callback method for index enumeration. + * + * @param value The Value being reported + * @param pointer The data pointer being reported + * @return false to cancel the enumeration + */ + boolean indexInfo(Value value, long pointer); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeCorruptException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeCorruptException.java new file mode 100644 index 000000000..5d4359744 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeCorruptException.java @@ -0,0 +1,74 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.FaultCodes; + +/** + * A BTreecorruptException is thrown by the BTree if the BTree + * appears to be corrupted in some way. + */ + +public final class BTreeCorruptException extends BTreeException { + public BTreeCorruptException() { + super(FaultCodes.IDX_CORRUPTED); + } + + public BTreeCorruptException(String message) { + super(FaultCodes.IDX_CORRUPTED, message); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeException.java new file mode 100644 index 000000000..d475410e4 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeException.java @@ -0,0 +1,75 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +/** + * A BTreeException is thrown by the BTree if an exception occurs + * in the managing of the BTree. + */ +public class BTreeException extends FilerException { + public BTreeException(int faultCode) { + super(faultCode); + } + + public BTreeException(int faultCode, String message) { + super(faultCode, message); + } + + public BTreeException(int faultCode, String message, Throwable cause) { + super(faultCode, message, cause); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeFiler.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeFiler.java new file mode 100644 index 000000000..4ad7990f9 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeFiler.java @@ -0,0 +1,491 @@ +package net.jxta.impl.xindice.core.filer; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.FaultCodes; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.RecordSet; +import net.jxta.impl.xindice.core.data.Value; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * BTreeFiler is a Filer implementation based on the BTree class. + */ +public final class BTreeFiler extends BTree implements Filer { + + protected static final byte RECORD = 20; + + private static final short PAGESIZE = 512; + // TODO: MAXKEYSIZE might need tuning + private static final short MAXKEYSIZE = 256; + + private BTreeFilerHeader fileHeader; + + private static final int DBE_CANNOT_READ = (int) (572l); + + public BTreeFiler() { + super(); + fileHeader = (BTreeFilerHeader) getFileHeader(); + } + + public void setLocation(String dir, String file) { + setFile(new File(dir, file + ".tbl")); + } + + public String getName() { + return getFile().getName(); + } + + @Override + public boolean open() throws DBException { + if (super.open()) { + // These are the only properties that can be changed after creation + fileHeader.setMaxKeySize(MAXKEYSIZE); + return true; + } else { + return false; + } + } + + @Override + public boolean create() throws DBException { + fileHeader.setPageSize(PAGESIZE); + fileHeader.setMaxKeySize(MAXKEYSIZE); + return super.create(); + } + + public Record readRecord(Key key) throws DBException { + if (key == null || key.getLength() == 0) { + return null; + } + + checkOpened(); + try { + long pos = findValue(key); + Record record = readRecord(pos); + + record.setKey(key); + return record; + } catch (BTreeNotFoundException b) {// do nothing + } catch (BTreeException b) { + throw b; + } catch (IOException e) { + throw new FilerException(DBE_CANNOT_READ, "Can't read record '" + key + "': " + e.getMessage(), e); + } + return null; + } + + public Record readRecord(long pos) throws DBException { + checkOpened(); + try { + Page startPage = getPage(pos); + Value v = readValue(startPage); + BTreeFilerPageHeader sph = (BTreeFilerPageHeader) startPage.getPageHeader(); + + HashMap meta = new HashMap(4); + + meta.put(Record.CREATED, sph.getCreated()); + meta.put(Record.MODIFIED, sph.getModified()); + meta.put(Record.LIFETIME, sph.getLifetime()); + meta.put(Record.EXPIRATION, sph.getExpiration()); + + return new Record(null, v, meta); + } catch (IOException e) { + throw new FilerException(DBE_CANNOT_READ, "Can't read record : " + e.getMessage(), e); + } + } + + public long writeRecord(Key key, Value value) throws DBException { + + return writeRecord(key, value, 0, 0); + } + + public long writeRecord(Key key, Value value, long lifetime, long expiration) throws DBException { + + if (key == null || key.getLength() == 0) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid key: '" + key + "'"); + } + if (value == null) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid null value"); + } + checkOpened(); + try { + Page p; + long pos; + try { + pos = findValue(key); + p = getPage(pos); + } catch (BTreeNotFoundException b) { + p = getFreePage(); + pos = p.getPageNum(); + addValue(key, p.getPageNum()); + fileHeader.incRecordCount(); + } + BTreeFilerPageHeader ph = (BTreeFilerPageHeader) p.getPageHeader(); + + long t = System.currentTimeMillis(); + + if (ph.getStatus() == UNUSED) { + ph.setCreated(t); + } + + ph.setModified(t); + ph.setLifetime(lifetime); + ph.setExpiration(expiration); + ph.setStatus(RECORD); + + writeValue(p, value); + flush(); + return pos; + } catch (IOException e) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Can't write record '" + key + "': " + e.getMessage(), e); + } + } + + public long writeRecord(long pos, Value value) throws DBException { + + if (value == null) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid null value"); + } + checkOpened(); + try { + writeValue(pos, value); + flush(); + return pos; + } catch (IOException e) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Can't write record '" + value + "': " + e.getMessage(), e); + } + } + + public boolean deleteRecord(Key key) throws DBException { + if (key == null || key.getLength() == 0) { + return false; + } + checkOpened(); + try { + long pos = findValue(key); + Page p = getPage(pos); + + removeValue(key); + unlinkPages(p.getPageNum()); + + fileHeader.decRecordCount(); + + flush(); + + return true; + } catch (BTreeNotFoundException b) {// not found move on + } catch (IOException e) { + throw new FilerException(FaultCodes.DBE_CANNOT_DROP, "Can't delete record '" + key + "': " + e.getMessage(), e); + } + return false; + } + + public long getRecordCount() throws DBException { + checkOpened(); + return fileHeader.getRecordCount(); + } + + public RecordSet getRecordSet() throws DBException { + checkOpened(); + return new BTreeFilerRecordSet(); + } + + /** + * BTreeFilerRecordSet + */ + + private class BTreeFilerRecordSet implements RecordSet, BTreeCallback { + private List keys = new ArrayList(); + private Iterator it; + + public BTreeFilerRecordSet() throws DBException { + try { + query(null, this); + it = keys.iterator(); + } catch (IOException e) { + throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error generating RecordSet", e); + } + } + + public synchronized boolean indexInfo(Value value, long pointer) { + keys.add(new Key(value)); + return true; + } + + public synchronized Key getNextKey() { + return it.next(); + } + + public synchronized Record getNextRecord() throws DBException { + return readRecord(it.next()); + } + + public synchronized Value getNextValue() throws DBException { + return getNextRecord().getValue(); + } + + public synchronized boolean hasMoreRecords() { + return it.hasNext(); + } + } + + // ////////////////////////////////////////////////////////////////// + + @Override + public FileHeader createFileHeader() { + return new BTreeFilerHeader(); + } + + @Override + public FileHeader createFileHeader(boolean read) throws IOException { + return new BTreeFilerHeader(read); + } + + @Override + public FileHeader createFileHeader(long pageCount) { + return new BTreeFilerHeader(pageCount); + } + + @Override + public FileHeader createFileHeader(long pageCount, int pageSize) { + return new BTreeFilerHeader(pageCount, pageSize); + } + + @Override + public PageHeader createPageHeader() { + return new BTreeFilerPageHeader(); + } + + /** + * BTreeFilerHeader + */ + + private final class BTreeFilerHeader extends BTreeFileHeader { + private long totalBytes = 0; + + public BTreeFilerHeader() {} + + public BTreeFilerHeader(long pageCount) { + super(pageCount); + } + + public BTreeFilerHeader(long pageCount, int pageSize) { + super(pageCount, pageSize); + } + + public BTreeFilerHeader(boolean read) throws IOException { + super(read); + } + + @Override + public synchronized void read(RandomAccessFile raf) throws IOException { + super.read(raf); + totalBytes = raf.readLong(); + } + + @Override + public synchronized void write(RandomAccessFile raf) throws IOException { + super.write(raf); + raf.writeLong(totalBytes); + } + + /** + * The total number of bytes in use by the file + * @param totalBytes the new total number of bytes + */ + public synchronized void setTotalBytes(long totalBytes) { + this.totalBytes = totalBytes; + setDirty(); + } + + /** + * The total number of bytes in use by the file + * @return the total number of bytes + */ + public synchronized long getTotalBytes() { + return totalBytes; + } + } + + + /** + * BTreeFilerPageHeader + */ + + private final class BTreeFilerPageHeader extends BTreePageHeader { + private long created = 0; + private long modified = 0; + private long lifetime = 0; + private long expiration = 0; + + public BTreeFilerPageHeader() {} + + public BTreeFilerPageHeader(DataInputStream dis) throws IOException { + super(dis); + } + + @Override + public synchronized void read(DataInputStream dis) throws IOException { + super.read(dis); + + if (getStatus() == UNUSED) { + return; + } + + created = dis.readLong(); + modified = dis.readLong(); + lifetime = dis.readLong(); + expiration = dis.readLong(); + } + + @Override + public synchronized void write(DataOutputStream dos) throws IOException { + super.write(dos); + dos.writeLong(created); + dos.writeLong(modified); + dos.writeLong(lifetime); + dos.writeLong(expiration); + } + + @Override + public synchronized void setRecordLen(int recordLen) { + fileHeader.setTotalBytes((fileHeader.totalBytes - getRecordLen()) + recordLen); + super.setRecordLen(recordLen); + } + + /** + * UNIX-time when this record was created + * @param created creation time + */ + public synchronized void setCreated(long created) { + this.created = created; + setDirty(); + } + + /** + * UNIX-time when this record was created + * @return creation time + */ + public synchronized long getCreated() { + return created; + } + + /** + * UNIX-time when this record was last modified + * @param modified modified time + */ + public synchronized void setModified(long modified) { + this.modified = modified; + setDirty(); + } + + /** + * UNIX-time when this record was last modified + * @return modified time + */ + public synchronized long getModified() { + return modified; + } + + /** + * JXTA-lifetime this record's lifetime + * @param lifetime the new record lifetime + */ + public synchronized void setLifetime(long lifetime) { + this.lifetime = lifetime; + setDirty(); + } + + /** + * JXTA-lifetime this record's lifetime + * @return the record lifetime + */ + public synchronized long getLifetime() { + return lifetime; + } + + /** + * JXTA-expiration this record's expiration + * @param expiration the record expiration time + */ + public synchronized void setExpiration(long expiration) { + this.expiration = expiration; + setDirty(); + } + + /** + * JXTA-expiration this record's expiration + * @return the record expiration time + */ + public synchronized long getExpiration() { + return expiration; + } + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeNotFoundException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeNotFoundException.java new file mode 100644 index 000000000..c4cb52003 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/BTreeNotFoundException.java @@ -0,0 +1,73 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.FaultCodes; + +/** + * A BTreeNotFoundException is thrown by the BTree if a Value + * can't be found in the BTree. + */ +public final class BTreeNotFoundException extends BTreeException { + public BTreeNotFoundException() { + super(FaultCodes.IDX_VALUE_NOT_FOUND); + } + + public BTreeNotFoundException(String message) { + super(FaultCodes.IDX_VALUE_NOT_FOUND, message); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Filer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Filer.java new file mode 100644 index 000000000..66c224081 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Filer.java @@ -0,0 +1,137 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.DBObject; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.RecordSet; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.util.Named; + +/** + * Filer is the low-level file management interface for Xindice. A Filer object + * is implemented in order to provide a data source to the Xindice Collection + * class. Filers are developed to perform transparent storage and retrieval to + * and from heterogenous data sources (such as FTP, HTTP, RDBMS, etc...) + */ +public interface Filer extends Named, DBObject { + + /** + * readRecord returns a Record from the Filer based on the specified + * Key. + * + * @param key The Record's Key + * @return The returned Record + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + Record readRecord(Key key) throws DBException; + + /** + * readRecord returns a Record from the Filer at the specified + * position. The Record's Key will be set to null. + * + * @param pos The Record's position + * @return The returned Record + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + Record readRecord(long pos) throws DBException; + + /** + * writeRecord writes a Value to the Filer based on the specified Key. + * + * @param key The Record's Key + * @param value The Record's Value + * @return 0 if the Record could not be written, the starting + * offset of the Record otherwise (used for indexing) + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + long writeRecord(Key key, Value value) throws DBException; + + /** + * deleteRecord removes a Record from the Filer based on the + * specified Key. + * + * @param key The Record's Key + * @return Whether or not the Record was deleted + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + boolean deleteRecord(Key key) throws DBException; + + /** + * getRecordCount returns the number of Records in the Filer. + * + * @return The Record count + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + long getRecordCount() throws DBException; + + /** + * getRecordSet returns a RecordSet object for the current Filer. + * + * @return The Filer Enumerator + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + RecordSet getRecordSet() throws DBException; + + /** + * flush forcefully flushes any unwritten buffers to disk. + * @throws net.jxta.impl.xindice.core.DBException if a db exception occurs + */ + void flush() throws DBException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/FilerException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/FilerException.java new file mode 100644 index 000000000..5b7b0e959 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/FilerException.java @@ -0,0 +1,77 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.DBException; + +/** + * A FilerException is thrown by a Filer if an exception occurs + * in the managing of the Filer. + */ +public class FilerException extends DBException { + public FilerException(int faultCode) { + super(faultCode); + } + + public FilerException(int faultCode, String message) { + super(faultCode, message); + } + + public FilerException(int faultCode, String message, Throwable cause) { + super(faultCode, message, cause); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/MemFiler.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/MemFiler.java new file mode 100644 index 000000000..0f4c887ec --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/MemFiler.java @@ -0,0 +1,226 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.FaultCodes; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Value; +import net.jxta.impl.xindice.core.data.Record; +import net.jxta.impl.xindice.core.data.RecordSet; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * MemFiler is an In-Memory Filer implementation for Xindice. MemFiler can be + * used for temporary collections and caching. It's basically a layering on + * top of HashMap. + */ +public final class MemFiler implements Filer { + private Map hashTable = null; + private Map posTable = null; + private boolean opened = false; + private boolean readOnly = false; + private long position = 0; + public MemFiler() { + hashTable = Collections.synchronizedMap(new HashMap()); + posTable = Collections.synchronizedMap(new HashMap()); + } + + public MemFiler(Map hashTable, boolean readOnly) { + this.hashTable = hashTable; + this.readOnly = readOnly; + } + + public MemFiler(Map hashTable) { + this(hashTable, false); + } + + public void setLocation(File root, String location) {} + + public String getName() { + return "MemFiler"; + } + + private void checkOpened() throws DBException { + if (!opened) { + throw new FilerException(FaultCodes.COL_COLLECTION_CLOSED, "Filer is closed"); + } + } + + private void checkReadOnly() throws DBException { + if (readOnly) { + throw new FilerException(FaultCodes.COL_COLLECTION_READ_ONLY, "Filer is read-only"); + } + } + + public boolean create() { + hashTable.clear(); + return true; + } + + public boolean open() { + opened = true; + return opened; + } + + public boolean isOpened() { + return opened; + } + + public boolean exists() { + return true; + } + + public boolean drop() { + hashTable.clear(); + opened = false; + return !opened; + } + + public boolean close() { + opened = false; + return !opened; + } + + public void flush() {} + + public Record readRecord(Key key) throws DBException { + if (key == null || key.getLength() == 0) { + return null; + } + checkOpened(); + return hashTable.get(key); + } + + public Record readRecord(long pos) throws DBException { + if (pos < 0) { + return null; + } + checkOpened(); + Key key = posTable.get(pos); + + return hashTable.get(key); + } + + public long writeRecord(Key key, Value value) throws DBException { + if (key == null || key.getLength() == 0) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid key: '" + key + "'"); + } + if (value == null) { + throw new FilerException(FaultCodes.DBE_CANNOT_CREATE, "Invalid null value"); + } + checkOpened(); + checkReadOnly(); + hashTable.put(key, new Record(key, value)); + posTable.put(position, key); + long result = position; + + position++; + return result; + } + + public boolean deleteRecord(Key key) throws DBException { + if (key == null || key.getLength() == 0) { + return false; + } + checkOpened(); + checkReadOnly(); + return hashTable.remove(key) != null; + } + + public long getRecordCount() throws DBException { + checkOpened(); + return hashTable.size(); + } + + public RecordSet getRecordSet() throws DBException { + checkOpened(); + return new MemRecordSet(); + } + + /** + * MemRecordSet + */ + + private class MemRecordSet implements RecordSet { + private Iterator it = hashTable.values().iterator(); + + public synchronized boolean hasMoreRecords() throws DBException { + return it.hasNext(); + } + + public synchronized Record getNextRecord() throws DBException { + checkOpened(); + return it.next(); + } + + public synchronized Value getNextValue() throws DBException { + checkOpened(); + return (it.next()).getValue(); + } + + public synchronized Key getNextKey() { + return (it.next()).getKey(); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Paged.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Paged.java new file mode 100644 index 000000000..bd3c4839e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Paged.java @@ -0,0 +1,1501 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.FaultCodes; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.data.Value; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.EmptyStackException; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Paged is a paged file implementation that is foundation for both the + * BTree class and the HashFiler. It provides flexible paged I/O and + * page caching functionality. + *

            + * Page has folowing configuration attributes: + *

              + *
            • pagesize: Size of the page used by the paged file. + * Default page size is 4096 bytes. This parameter can be set only + * before paged file is created. Once it is created, this parameter + * can not be changed.
            • + *
            • maxkeysize: Maximum allowed size of the key. + * Default maximum key size is 256 bytes.
            • + *
            • max-descriptors: Defines maximum amount of + * simultaneously opened file descriptors this paged file can have. + * Several descriptors are needed to provide multithreaded access + * to the underlying file. Too large number will limit amount of + * collections you can open. Default value is 16 + * (DEFAULT_DESCRIPTORS_MAX).
            • + *
            + *

            + *
            FIXME: Currently it seems that maxkeysize is not used anywhere. + *
            TODO: Introduce Paged interface, implementations. + */ +public abstract class Paged { + + /** + * Logger + */ + private final static Logger LOG = Logger.getLogger(Paged.class.getName()); + + /** + * The maximum number of pages that will be held in the dirty cache. + * Once number reaches the limit, pages are flushed to disk. + */ + private static final int MAX_DIRTY_SIZE = 128; + + // The maximum number of open random access files we can have + private static final int DEFAULT_DESCRIPTORS_MAX = 16; + + /** + * Unused page status + */ + protected static final byte UNUSED = 0; + + /** + * Overflow page status + */ + protected static final byte OVERFLOW = 126; + + /** + * Deleted page status + */ + protected static final byte DELETED = 127; + + /** + * Page ID of non-existent page + */ + protected static final int NO_PAGE = -1; + + /** + * flag whether to sync DB on every write or not. + */ + protected boolean sync = true; + + // TODO: This is not a cache right now, but a way to assure that only one page instance at most exists in memory at all times. + /** + * Cache of recently read pages. + *

            + * Cache contains weak references to the Page objects, keys are page numbers (Long objects). + * Access synchronized by this map itself. + */ + private final Map> pages = new WeakHashMap>(); + + /** + * Cache of modified pages waiting to be written out. + * Access is synchronized by the {@link #dirtyLock}. + */ + private Map dirty = new HashMap(); + + /** + * Lock for synchronizing access to the {@link #dirty} map. + */ + private final Object dirtyLock = new Object(); + + /** + * Random access file descriptors cache. + * Access to it and to {@link #descriptorsCount} is synchronized by itself. + */ + private final Stack descriptors = new Stack(); + + /** + * The number of random access file objects that exist, either in the + * cache {@link #descriptors}, or currently in use. + */ + private int descriptorsCount; + + /** + * The maximum number of random access file objects that can be opened + * by this paged instance. + */ + private int descriptorsMax; + + /** + * Whether the file is opened or not. + */ + private boolean opened; + + /** + * The underlying file where the Paged object stores its pages. + */ + private File file; + + /** + * Header of this Paged + */ + private final FileHeader fileHeader; + + public Paged() { + descriptorsMax = DEFAULT_DESCRIPTORS_MAX; + fileHeader = createFileHeader(); + } + + public Paged(File file) { + this(); + setFile(file); + } + + /** + * setFile sets the file object for this Paged. + * + * @param file The File + */ + protected final void setFile(final File file) { + this.file = file; + } + + /** + * getFile returns the file object for this Paged. + * + * @return The File + */ + protected final File getFile() { + return file; + } + + /** + * Obtain RandomAccessFile ('descriptor') object out of the pool. + * If no descriptors available, and maximum amount already allocated, + * the call will block. + * @return the file + * @throws java.io.IOException if an io error occurs + */ + protected final RandomAccessFile getDescriptor() throws IOException { + synchronized (descriptors) { + // If there are descriptors in the cache return one. + if (!descriptors.empty()) { + return descriptors.pop(); + } + // Otherwise we need to get one some other way. + + // First try to create a new one if there's room + if (descriptorsCount < descriptorsMax) { + descriptorsCount++; + return new RandomAccessFile(file, "rw"); + } + + // Otherwise we have to wait for one to be released by another thread. + while (true) { + try { + descriptors.wait(); + return descriptors.pop(); + } catch (InterruptedException e) {// Ignore, and continue to wait + } catch (EmptyStackException e) {// Ignore, and continue to wait + } + } + } + } + + /** + * Puts a RandomAccessFile ('descriptor') back into the descriptor pool. + * @param raf the file to add + */ + protected final void putDescriptor(RandomAccessFile raf) { + if (raf != null) { + synchronized (descriptors) { + descriptors.push(raf); + descriptors.notify(); + } + } + } + + /** + * Closes a RandomAccessFile ('descriptor') and removes it from the pool. + * @param raf the file to close + */ + protected final void closeDescriptor(RandomAccessFile raf) { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) {// Ignore close exception + } + + // Synchronization is necessary as decrement operation is not atomic + synchronized (descriptors) { + descriptorsCount--; + } + } + } + + /** + * getPage returns the page specified by pageNum. + * + * @param pageNum The Page number + * @return The requested Page + * @throws IOException if an Exception occurs + */ + protected final Page getPage(long pageNum) throws IOException { + final Long lp = pageNum; + Page page; + + synchronized (this) { + // Check if it's in the dirty cache + // No need to synchronize on dirtyLock thanks to atomic assignment + page = dirty.get(lp); + + // if not check if it's already loaded in the page cache + if (page == null) { + WeakReference ref = pages.get(lp); + + if (ref != null) { + page = ref.get(); + } + } + + // if still not found we need to create it and add it to the page cache. + if (page == null) { + page = new Page(lp); + pages.put(page.pageNum, new WeakReference(page)); + } + } + + // Load the page from disk if necessary + page.read(); + return page; + } + + /** + * readValue reads the multi-Paged Value starting at the specified + * Page. + * + * @param page The starting Page + * @return The Value + * @throws IOException if an Exception occurs + */ + protected final Value readValue(Page page) throws IOException { + final PageHeader sph = page.getPageHeader(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(sph.getRecordLen()); + + // Loop until we've read all the pages into memory. + Page p = page; + + while (true) { + PageHeader ph = p.getPageHeader(); + + // Add the contents of the page onto the stream + p.streamTo(bos); + + // Continue following the list of pages until we get to the end. + long nextPage = ph.getNextPage(); + + if (nextPage == NO_PAGE) { + break; + } + p = getPage(nextPage); + } + + // Return a Value with the collected contents of all pages. + return new Value(bos.toByteArray()); + } + + /** + * readValue reads the multi-Paged Value starting at the specified + * page number. + * + * @param page The starting page number + * @return The Value + * @throws IOException if an Exception occurs + */ + protected final Value readValue(long page) throws IOException { + return readValue(getPage(page)); + } + + /** + * writeValue writes the multi-Paged Value starting at the specified + * Page. + * + * @param page The starting Page + * @param value The Value to write + * @throws IOException if an Exception occurs + */ + protected final void writeValue(Page page, Value value) throws IOException { + if (value == null) { + throw new IOException("Can't write a null value"); + } + + InputStream is = value.getInputStream(); + + // Write as much as we can onto the primary page. + PageHeader hdr = page.getPageHeader(); + + hdr.setRecordLen(value.getLength()); + page.streamFrom(is); + + // Write out the rest of the value onto any needed overflow pages + while (is.available() > 0) { + Page lpage = page; + PageHeader lhdr = hdr; + + // Find an overflow page to use + long np = lhdr.getNextPage(); + + if (np != NO_PAGE) { + // Use an existing page. + page = getPage(np); + } else { + // Create a new overflow page + page = getFreePage(); + lhdr.setNextPage(page.getPageNum()); + } + + // Mark the page as an overflow page. + hdr = page.getPageHeader(); + hdr.setStatus(OVERFLOW); + + // Write some more of the value to the overflow page. + page.streamFrom(is); + lpage.write(); + } + + // Cleanup any unused overflow pages. i.e. the value is smaller then the + // last time it was written. + long np = hdr.getNextPage(); + + if (np != NO_PAGE) { + unlinkPages(np); + } + + hdr.setNextPage(NO_PAGE); + page.write(); + } + + /** + * writeValue writes the multi-Paged Value starting at the specified + * page number. + * + * @param page The starting page number + * @param value The Value to write + * @throws IOException if an Exception occurs + */ + protected final void writeValue(long page, Value value) throws IOException { + writeValue(getPage(page), value); + } + + /** + * unlinkPages unlinks a set of pages starting at the specified Page. + * + * @param page The starting Page to unlink + * @throws IOException if an Exception occurs + */ + protected final void unlinkPages(Page page) throws IOException { + // Handle the page if it's in primary space by setting its status to + // DELETED and freeing any overflow pages linked to it. + if (page.pageNum < fileHeader.pageCount) { + long nextPage = page.header.nextPage; + + page.header.setStatus(DELETED); + page.header.setNextPage(NO_PAGE); + page.write(); + + // See if there are any chained pages from the page that was just removed + if (nextPage == NO_PAGE) { + page = null; + } else { + page = getPage(nextPage); + } + } + + // Add any overflow pages to the list of free pages. + if (page != null) { + // Get the first and last page in the chain. + long firstPage = page.pageNum; + + while (page.header.nextPage != NO_PAGE) { + page = getPage(page.header.nextPage); + } + long lastPage = page.pageNum; + + // Free the chain + synchronized (fileHeader) { + // If there are already some free pages, add the start of the chain + // to the list of free pages. + if (fileHeader.lastFreePage != NO_PAGE) { + Page p = getPage(fileHeader.lastFreePage); + + p.header.setNextPage(firstPage); + p.write(); + } + + // Otherwise set the chain as the list of free pages. + if (fileHeader.firstFreePage == NO_PAGE) { + fileHeader.setFirstFreePage(firstPage); + } + + // Add a reference to the end of the chain. + fileHeader.setLastFreePage(lastPage); + } + } + } + + /** + * unlinkPages unlinks a set of pages starting at the specified + * page number. + * + * @param pageNum The starting page number to unlink + * @throws IOException if an Exception occurs + */ + protected final void unlinkPages(long pageNum) throws IOException { + unlinkPages(getPage(pageNum)); + } + + /** + * getFreePage returns the first free Page from secondary storage. + * If no Pages are available, the file is grown as appropriate. + * + * @return The next free Page + * @throws IOException if an Exception occurs + */ + protected final Page getFreePage() throws IOException { + Page p = null; + + // Synchronize read and write to the fileHeader.firstFreePage + synchronized (fileHeader) { + if (fileHeader.firstFreePage != NO_PAGE) { + // Steal a deleted page + p = getPage(fileHeader.firstFreePage); + fileHeader.setFirstFreePage(p.getPageHeader().nextPage); + if (fileHeader.firstFreePage == NO_PAGE) { + fileHeader.setLastFreePage(NO_PAGE); + } + } + } + + if (p == null) { + // No deleted pages, grow the file + p = getPage(fileHeader.incTotalCount()); + } + + // Initialize The Page Header (Cleanly) + p.header.setNextPage(NO_PAGE); + p.header.setStatus(UNUSED); + return p; + } + + /** + * @throws DBException COL_COLLECTION_CLOSED if paged file is closed + */ + protected final void checkOpened() throws DBException { + if (!opened) { + throw new FilerException(FaultCodes.COL_COLLECTION_CLOSED, "Filer is closed"); + } + } + + /** + * getFileHeader returns the FileHeader + * + * @return The FileHeader + */ + public FileHeader getFileHeader() { + return fileHeader; + } + + public boolean exists() { + return file.exists(); + } + + public boolean create() throws DBException { + try { + createFile(); + fileHeader.write(); + flush(); + return true; + } catch (Exception e) { + throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error creating " + file.getName(), e); + } + } + + private void createFile() throws IOException { + RandomAccessFile raf = null; + + try { + raf = getDescriptor(); + long o = fileHeader.headerSize + (fileHeader.pageCount + 1) * fileHeader.pageSize - 1; + + raf.seek(o); + raf.write(0); + } finally { + putDescriptor(raf); + } + } + + public boolean open() throws DBException { + RandomAccessFile raf = null; + + try { + if (exists()) { + raf = getDescriptor(); + fileHeader.read(); + opened = true; + } else { + opened = false; + } + return opened; + } catch (Exception e) { + throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error opening " + file.getName(), e); + } finally { + putDescriptor(raf); + } + } + + public synchronized boolean close() throws DBException { + if (isOpened()) { + try { + // First of all, mark as closed to prevent operations + opened = false; + flush(); + + synchronized (descriptors) { + final int total = descriptorsCount; + + // Close descriptors in cache + while (!descriptors.empty()) { + closeDescriptor(descriptors.pop()); + } + // Attempt to close descriptors in use. Max wait time = 0.5s * MAX_DESCRIPTORS + int n = descriptorsCount; + + while (descriptorsCount > 0 && n > 0) { + try { + descriptors.wait(500); + } catch (InterruptedException woken) { + Thread.interrupted(); + } + + if (descriptors.isEmpty()) { + n--; + } else { + closeDescriptor(descriptors.pop()); + } + } + if (descriptorsCount > 0) { + LOG.fine(descriptorsCount + " out of " + total + " files were not closed during close."); + } + } + } catch (Exception e) { + // Failed to close, leave open + opened = true; + throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error closing " + file.getName(), e); + } + } + return true; + } + + public boolean isOpened() { + return opened; + } + + public boolean drop() throws DBException { + try { + close(); + return !exists() || getFile().delete(); + } catch (Exception e) { + throw new FilerException(FaultCodes.COL_CANNOT_DROP, "Can't drop " + file.getName(), e); + } + } + + void addDirty(Page page) throws IOException { + synchronized (dirtyLock) { + dirty.put(page.pageNum, page); + if (dirty.size() > MAX_DIRTY_SIZE) { + try { + // Too many dirty pages... flush them + flush(); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + } + } + + public void flush() throws DBException { + // This method is not synchronized + + // Error flag/counter + int error = 0; + + // Obtain collection of dirty pages + Collection pages; + + synchronized (dirtyLock) { + pages = dirty.values(); + dirty = new HashMap(); + } + + // Flush dirty pages + for (Object page : pages) { + Page p = (Page) page; + + try { + p.flush(); + } catch (Exception e) { + LOG.log(Level.WARNING, "Exception while flushing page", e); + error++; + } + } + + // Flush header + if (fileHeader.dirty) { + try { + fileHeader.write(); + } catch (Exception e) { + LOG.log(Level.WARNING, "Exception while flushing file header", e); + error++; + } + } + + if (error != 0) { + throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error performing flush! Failed to flush " + error + " pages!"); + } + } + + /** + * createFileHeader must be implemented by a Paged implementation + * in order to create an appropriate subclass instance of a FileHeader. + * + * @return a new FileHeader + */ + public abstract FileHeader createFileHeader(); + + /** + * createFileHeader must be implemented by a Paged implementation + * in order to create an appropriate subclass instance of a FileHeader. + * + * @param read If true, reads the FileHeader from disk + * @return a new FileHeader + * @throws IOException if an exception occurs + */ + public abstract FileHeader createFileHeader(boolean read) throws IOException; + + /** + * createFileHeader must be implemented by a Paged implementation + * in order to create an appropriate subclass instance of a FileHeader. + * + * @param pageCount The number of pages to allocate for primary storage + * @return a new FileHeader + */ + public abstract FileHeader createFileHeader(long pageCount); + + /** + * createFileHeader must be implemented by a Paged implementation + * in order to create an appropriate subclass instance of a FileHeader. + * + * @param pageCount The number of pages to allocate for primary storage + * @param pageSize The size of a Page (should be a multiple of a FS block) + * @return a new FileHeader + */ + public abstract FileHeader createFileHeader(long pageCount, int pageSize); + + /** + * createPageHeader must be implemented by a Paged implementation + * in order to create an appropriate subclass instance of a PageHeader. + * + * @return a new PageHeader + */ + public abstract PageHeader createPageHeader(); + + // These are a bunch of utility methods for subclasses + + public static Value[] insertArrayValue(Value[] vals, Value val, int idx) { + Value[] newVals = new Value[vals.length + 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + newVals[idx] = val; + if (idx < vals.length) { + System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); + } + return newVals; + } + + public static Value[] deleteArrayValue(Value[] vals, int idx) { + Value[] newVals = new Value[vals.length - 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + if (idx < newVals.length) { + System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); + } + return newVals; + } + + public static long[] insertArrayLong(long[] vals, long val, int idx) { + long[] newVals = new long[vals.length + 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + newVals[idx] = val; + if (idx < vals.length) { + System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); + } + return newVals; + } + + public static long[] deleteArrayLong(long[] vals, int idx) { + long[] newVals = new long[vals.length - 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + if (idx < newVals.length) { + System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); + } + return newVals; + } + + public static int[] insertArrayInt(int[] vals, int val, int idx) { + int[] newVals = new int[vals.length + 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + newVals[idx] = val; + if (idx < vals.length) { + System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); + } + return newVals; + } + + public static int[] deleteArrayInt(int[] vals, int idx) { + int[] newVals = new int[vals.length - 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + if (idx < newVals.length) { + System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); + } + return newVals; + } + + public static short[] insertArrayShort(short[] vals, short val, int idx) { + short[] newVals = new short[vals.length + 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + newVals[idx] = val; + if (idx < vals.length) { + System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); + } + + return newVals; + } + + public static short[] deleteArrayShort(short[] vals, int idx) { + short[] newVals = new short[vals.length - 1]; + + if (idx > 0) { + System.arraycopy(vals, 0, newVals, 0, idx); + } + if (idx < newVals.length) { + System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); + } + + return newVals; + } + + /** + * Paged file's header + */ + public abstract class FileHeader { + private boolean dirty = false; + private int workSize; + + private short headerSize; + private int pageSize; + private long pageCount; + private long totalCount; + private long firstFreePage = -1; + private long lastFreePage = -1; + private byte pageHeaderSize = 64; + private short maxKeySize = 256; + private long recordCount; + + public FileHeader() { + this(1024); + } + + public FileHeader(long pageCount) { + this(pageCount, 4096); + } + + public FileHeader(long pageCount, int pageSize) { + this.pageSize = pageSize; + this.pageCount = pageCount; + totalCount = pageCount; + headerSize = (short) 4096; + calculateWorkSize(); + } + + public FileHeader(boolean read) throws IOException { + if (read) { + read(); + } + } + + public synchronized final void read() throws IOException { + RandomAccessFile raf = null; + + try { + raf = getDescriptor(); + raf.seek(0); + read(raf); + calculateWorkSize(); + } finally { + putDescriptor(raf); + } + } + + public synchronized void read(RandomAccessFile raf) throws IOException { + headerSize = raf.readShort(); + pageSize = raf.readInt(); + pageCount = raf.readLong(); + totalCount = raf.readLong(); + firstFreePage = raf.readLong(); + lastFreePage = raf.readLong(); + pageHeaderSize = raf.readByte(); + maxKeySize = raf.readShort(); + recordCount = raf.readLong(); + } + + public synchronized final void write() throws IOException { + if (!dirty) { + return; + } + + RandomAccessFile raf = null; + + try { + raf = getDescriptor(); + raf.seek(0); + write(raf); + dirty = false; + } finally { + putDescriptor(raf); + } + } + + public synchronized void write(RandomAccessFile raf) throws IOException { + raf.writeShort(headerSize); + raf.writeInt(pageSize); + raf.writeLong(pageCount); + raf.writeLong(totalCount); + raf.writeLong(firstFreePage); + raf.writeLong(lastFreePage); + raf.writeByte(pageHeaderSize); + raf.writeShort(maxKeySize); + raf.writeLong(recordCount); + } + + public synchronized final void setDirty() { + dirty = true; + } + + public synchronized final boolean isDirty() { + return dirty; + } + + /** + * The size of the FileHeader. Usually 1 OS Page. + * This method should be called only while initializing Paged, not during normal processing. + * @param headerSize the new header size + */ + public synchronized final void setHeaderSize(short headerSize) { + this.headerSize = headerSize; + dirty = true; + } + + /** + * The size of the FileHeader. Usually 1 OS Page + * @return the header size + */ + public synchronized final short getHeaderSize() { + return headerSize; + } + + /** + * The size of a page. Usually a multiple of a FS block. + * This method should be called only while initializing Paged, not during normal processing. + * @param pageSize the new page size + */ + public synchronized final void setPageSize(int pageSize) { + this.pageSize = pageSize; + calculateWorkSize(); + dirty = true; + } + + /** + * The size of a page. Usually a multiple of a FS block + * @return the page size + */ + public synchronized final int getPageSize() { + return pageSize; + } + + /** + * The number of pages in primary storage. + * This method should be called only while initializing Paged, not during normal processing. + * @param pageCount the new page count + */ + public synchronized final void setPageCount(long pageCount) { + this.pageCount = pageCount; + dirty = true; + } + + /** + * The number of pages in primary storage + * @return the page count + */ + public synchronized final long getPageCount() { + return pageCount; + } + + /** + * The number of total pages in the file. + * This method should be called only while initializing Paged, not during normal processing. + * @param totalCount the new total count + */ + public synchronized final void setTotalCount(long totalCount) { + this.totalCount = totalCount; + dirty = true; + } + + public synchronized final long incTotalCount() { + dirty = true; + return this.totalCount++; + } + + /** + * The number of total pages in the file + * @return the total count + */ + public synchronized final long getTotalCount() { + return totalCount; + } + + /** + * The first free page in unused secondary space + * @param firstFreePage the new first free page + */ + public synchronized final void setFirstFreePage(long firstFreePage) { + this.firstFreePage = firstFreePage; + dirty = true; + } + + /** + * The first free page in unused secondary space + * @return the first free page + */ + public synchronized final long getFirstFreePage() { + return firstFreePage; + } + + /** + * The last free page in unused secondary space + * @param lastFreePage sets the last free page + */ + public synchronized final void setLastFreePage(long lastFreePage) { + this.lastFreePage = lastFreePage; + dirty = true; + } + + /** + * The last free page in unused secondary space + * @return the last free page + */ + public synchronized final long getLastFreePage() { + return lastFreePage; + } + + /** + * Set the size of a page header. + *

            + * Normally, 64 is sufficient. + * @param pageHeaderSize the new page header size + */ + public synchronized final void setPageHeaderSize(byte pageHeaderSize) { + this.pageHeaderSize = pageHeaderSize; + calculateWorkSize(); + dirty = true; + } + + /** + * Get the size of a page header. + *

            + * Normally, 64 is sufficient + * @return the page header size + */ + public synchronized final byte getPageHeaderSize() { + return pageHeaderSize; + } + + /** + * Set the maximum number of bytes a key can be. + *

            + * Normally, 256 is good + * @param maxKeySize the new max key size + */ + public synchronized final void setMaxKeySize(short maxKeySize) { + this.maxKeySize = maxKeySize; + dirty = true; + } + + /** + * Get the maximum number of bytes. + *

            + * Normally, 256 is good. + * @return max key size + */ + public synchronized final short getMaxKeySize() { + return maxKeySize; + } + + /** + * Increment the number of records being managed by the file + */ + public synchronized final void incRecordCount() { + recordCount++; + dirty = true; + } + + /** + * Decrement the number of records being managed by the file + */ + public synchronized final void decRecordCount() { + recordCount--; + dirty = true; + } + + /** + * The number of records being managed by the file (not pages) + * @return the record count + */ + public synchronized final long getRecordCount() { + return recordCount; + } + + private synchronized void calculateWorkSize() { + workSize = pageSize - pageHeaderSize; + } + + public synchronized final int getWorkSize() { + return workSize; + } + } + + + /** + * PageHeader + */ + + public abstract class PageHeader implements Streamable { + private boolean dirty = false; + private byte status = UNUSED; + private int keyLen = 0; + private int keyHash = 0; + private int dataLen = 0; + private int recordLen = 0; + private long nextPage = -1; + + public PageHeader() {} + + public PageHeader(DataInputStream dis) throws IOException { + read(dis); + } + + public synchronized void read(DataInputStream dis) throws IOException { + status = dis.readByte(); + dirty = false; + if (status == UNUSED) { + return; + } + + keyLen = dis.readInt(); + if (keyLen < 0) { + // hack for win98/ME - see issue 564 + keyLen = 0; + } + keyHash = dis.readInt(); + dataLen = dis.readInt(); + recordLen = dis.readInt(); + nextPage = dis.readLong(); + } + + public synchronized void write(DataOutputStream dos) throws IOException { + dirty = false; + dos.writeByte(status); + dos.writeInt(keyLen); + dos.writeInt(keyHash); + dos.writeInt(dataLen); + dos.writeInt(recordLen); + dos.writeLong(nextPage); + } + + public synchronized final boolean isDirty() { + return dirty; + } + + public synchronized final void setDirty() { + dirty = true; + } + + /** + * The status of this page (UNUSED, RECORD, DELETED, etc...) + * @param status the new status + */ + public synchronized final void setStatus(byte status) { + this.status = status; + dirty = true; + } + + /** + * The status of this page (UNUSED, RECORD, DELETED, etc...) + * @return the status + */ + public synchronized final byte getStatus() { + return status; + } + + public synchronized final void setKey(Key key) { + // setKey WIPES OUT the Page data + setRecordLen(0); + dataLen = 0; + keyHash = key.getHash(); + keyLen = key.getLength(); + dirty = true; + } + + /** + * The length of the Key + * @param keyLen the new key length + */ + public synchronized final void setKeyLen(int keyLen) { + this.keyLen = keyLen; + dirty = true; + } + + /** + * The length of the Key + * @return the key length + */ + public synchronized final int getKeyLen() { + return keyLen; + } + + /** + * The hashed value of the Key for quick comparisons + * @param keyHash sets the key hash + */ + public synchronized final void setKeyHash(int keyHash) { + this.keyHash = keyHash; + dirty = true; + } + + /** + * The hashed value of the Key for quick comparisons + * @return the key hash + */ + public synchronized final int getKeyHash() { + return keyHash; + } + + /** + * The length of the Data + * @param dataLen sets the data length + */ + public synchronized final void setDataLen(int dataLen) { + this.dataLen = dataLen; + dirty = true; + } + + /** + * The length of the Data + * @return the data length + */ + public synchronized final int getDataLen() { + return dataLen; + } + + /** + * The length of the Record's value + * @param recordLen sets the record length + */ + public synchronized void setRecordLen(int recordLen) { + this.recordLen = recordLen; + dirty = true; + } + + /** + * The length of the Record's value + * @return record length + */ + public synchronized final int getRecordLen() { + return recordLen; + } + + /** + * The next page for this Record (if overflowed) + * @param nextPage next page + */ + public synchronized final void setNextPage(long nextPage) { + this.nextPage = nextPage; + dirty = true; + } + + /** + * The next page for this Record (if overflowed) + * @return next page + */ + public synchronized final long getNextPage() { + return nextPage; + } + } + + + /** + * Paged file's page + */ + public final class Page implements Comparable { + + /** + * This page number + */ + private final Long pageNum; + + /** + * The Header for this Page + */ + private final PageHeader header; + + /** + * The offset into the file that this page starts + */ + private final long offset; + + /** + * The data for this page. Null if page is not loaded. + */ + private byte[] data; + + /** + * The position (relative) of the Key in the data array + */ + private int keyPos; + + /** + * The position (relative) of the Data in the data array + */ + private int dataPos; + + public Page(Long pageNum) { + this.header = createPageHeader(); + this.pageNum = pageNum; + this.offset = fileHeader.headerSize + (pageNum * fileHeader.pageSize); + } + + /** + * Reads a page into the memory, once. Subsequent calls are ignored. + * @throws java.io.IOException if an io error occurs + */ + public synchronized void read() throws IOException { + if (data == null) { + RandomAccessFile raf = null; + + try { + byte[] data = new byte[fileHeader.pageSize]; + + raf = getDescriptor(); + raf.seek(this.offset); + raf.read(data); + + // Read in the header + ByteArrayInputStream bis = new ByteArrayInputStream(data); + + this.header.read(new DataInputStream(bis)); + + this.keyPos = fileHeader.pageHeaderSize; + this.dataPos = this.keyPos + this.header.keyLen; + + // Successfully read all the data + this.data = data; + } finally { + putDescriptor(raf); + } + } + } + + /** + * Writes out the header into the this.data, and adds a page to the set of + * dirty pages. + * @throws java.io.IOException if an io error occurs + */ + public void write() throws IOException { + // Write out the header into the this.data + synchronized (this) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(fileHeader.getPageHeaderSize()); + + header.write(new DataOutputStream(bos)); + byte[] b = bos.toByteArray(); + + System.arraycopy(b, 0, data, 0, b.length); + } + + // Add to the list of dirty pages + Paged.this.addDirty(this); + } + + /** + * Flushes content of the dirty page into the file + * @throws java.io.IOException if an io error occurs + */ + public synchronized void flush() throws IOException { + RandomAccessFile raf = null; + + try { + raf = getDescriptor(); + if (this.offset >= raf.length()) { + // Grow the file + long o = (fileHeader.headerSize + ((fileHeader.totalCount * 3) / 2) * fileHeader.pageSize) + + (fileHeader.pageSize - 1); + + raf.seek(o); + raf.writeByte(0); + } + raf.seek(this.offset); + raf.write(this.data); + if (sync) { + raf.getFD().sync(); + } + } finally { + putDescriptor(raf); + } + } + + // No synchronization - pageNum is final + public Long getPageNum() { + return this.pageNum; + } + + // No synchronization - header is final + public PageHeader getPageHeader() { + return this.header; + } + + public synchronized void setKey(Key key) { + header.setKey(key); + // Insert the key into the data array. + key.copyTo(this.data, this.keyPos); + + // Set the start of data to skip over the key. + this.dataPos = this.keyPos + header.keyLen; + } + + public synchronized Key getKey() { + if (header.keyLen > 0) { + return new Key(this.data, this.keyPos, header.keyLen); + } else { + return null; + } + } + + public synchronized void streamTo(OutputStream os) throws IOException { + if (header.dataLen > 0) { + os.write(this.data, this.dataPos, header.dataLen); + } + } + + public synchronized void streamFrom(InputStream is) throws IOException { + int avail = is.available(); + + header.dataLen = fileHeader.workSize - header.keyLen; + if (avail < header.dataLen) { + header.dataLen = avail; + } + if (header.dataLen > 0) { + is.read(this.data, this.keyPos + header.keyLen, header.dataLen); + } + } + + // No synchronization: pageNum is final. + public int compareTo(Page o) { + return (int) (this.pageNum - o.pageNum); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Streamable.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Streamable.java new file mode 100644 index 000000000..6541bb1f0 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/filer/Streamable.java @@ -0,0 +1,84 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package net.jxta.impl.xindice.core.filer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Streamable is an interface implemented by objects used by Filers and + * Indexers in order to serialize objects to and from IO streams. + */ +public interface Streamable { + + /** + * read reads the object state from the stream. + * + * @param is The DataInputStream + * @throws IOException if an IOException occurs + */ + public void read(DataInputStream is) throws IOException; + + /** + * write writes the object state to the stream. + * + * @param os The DataOutputStream + * @throws IOException if an IOException occurs + */ + public void write(DataOutputStream os) throws IOException; +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/IndexQuery.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/IndexQuery.java new file mode 100644 index 000000000..059a9456d --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/IndexQuery.java @@ -0,0 +1,275 @@ +package net.jxta.impl.xindice.core.indexer; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +import net.jxta.impl.xindice.core.data.*; +import java.util.*; + + +/** + * IndexQuery represents the most primitive form of index querying. + * Instances of this object should be created by QueryResolvers and + * cached in Query instances. + */ + +public class IndexQuery { + // No Operator + public static final int ANY = 0; // Any And All Matches + + // Singleton Operators + public static final int EQ = 1; // Equal To + public static final int NEQ = -1; // Not Equal To + public static final int GT = 2; // Greater Than + public static final int LEQ = -2; // Less Than Or Equal To + public static final int LT = 3; // Less Than + public static final int GEQ = -3; // Greater Than Or Equal To + + // Range Operators + public static final int BW = 4; // Between (Inclusive) + public static final int NBW = -4; // Not Between (Inclusive) + public static final int BWX = 5; // Between (Exclusive) + public static final int NBWX = -5; // Not Between (Exclusive) + + // Set Operators + public static final int IN = 6; // In The Set + public static final int NIN = -6; // Not In The Set + + // Other operators + public static final int SW = 7; // Starts-with + public static final int NSW = -7; // Not Starts-with + + public static final int EW = 8; // Ends-with + public static final int NEW = -8; // Not Ends-with + + protected int op; + protected Value[] vals; + + public IndexQuery() { + op = ANY; + } + + public IndexQuery(int op, Value[] vals) { + this.op = op; + this.vals = vals; + } + + public IndexQuery(Value[] vals) { + this(IN, vals); + } + + public IndexQuery(int op, Value val1) { + this.op = op; + if (op == SW || op == NSW) { + byte[] b = new byte[val1.getLength() + 1]; + + System.arraycopy(val1.getData(), 0, b, 0, b.length - 1); + b[b.length - 1] = 127; // TODO: Must fix this + Value val2 = new Value(b); + + vals = new Value[] { val1, val2 }; + } else { + vals = new Value[] { val1 }; + } + } + + public IndexQuery(Value val1) { + this(EQ, val1); + } + + public IndexQuery(int op, Value val1, Value val2) { + this.op = op; + vals = new Value[] { val1, val2 }; + } + + public IndexQuery(Value val1, Value val2) { + this(IN, val1, val2); + } + + public IndexQuery(int op, String val1) { + this(op, new Value(val1)); + } + + public IndexQuery(String val1) { + this(new Value(val1)); + } + + public IndexQuery(int op, String val1, String val2) { + this(op, new Value(val1), new Value(val2)); + } + + public IndexQuery(String val1, String val2) { + this(new Value(val1), new Value(val2)); + } + + /** + * getOperator returns the operator associated with this query. + * + * @return The operator + */ + public int getOperator() { + return op; + } + + /** + * getValue returns one of the Values associated with this query. + * + * @param index The Value index + * @return The request Value + */ + public final Value getValue(int index) { + return vals[index]; + } + + /** + * getValues returns the Values associated with this query. + * + * @return The Value set + */ + public Value[] getValues() { + return vals; + } + + /** + * getLength returns the length of the Value set associated with + * this query. + * + * @return The Value set length + */ + public final int getLength() { + return vals.length; + } + + /** + * testValue tests the specified value for validity against this + * IndexQuery. The helper classes in org.apache.xindice.core.indexer.helpers + * should be used for optimized performance. + * + * @param value The Value to compare + * @return Whether or not the value matches + */ + public boolean testValue(Value value) { + switch (op) { + // No Comparison (Any) + case ANY: + return true; + + // Singleton Comparisons + case EQ: + return value.equals(vals[0]); + + case NEQ: + return !value.equals(vals[0]); + + case GT: + return value.compareTo(vals[0]) > 0; + + case LEQ: + return value.compareTo(vals[0]) <= 0; + + case LT: + return value.compareTo(vals[0]) < 0; + + case GEQ: + return value.compareTo(vals[0]) >= 0; + + // Range Comparisons + case BW: + return value.compareTo(vals[0]) >= 0 && value.compareTo(vals[1]) <= 0; + + case NBW: + return value.compareTo(vals[0]) <= 0 || value.compareTo(vals[1]) >= 0; + + case BWX: + return value.compareTo(vals[0]) > 0 && value.compareTo(vals[1]) < 0; + + case NBWX: + return value.compareTo(vals[0]) < 0 || value.compareTo(vals[1]) > 0; + + // Set Comparisons + case IN: + case NIN: + return Arrays.binarySearch(vals, value) >= 0 ? op == IN : op == NIN; + + // Other comparisons + case SW: + case NSW: + return value.startsWith(vals[0]) ? op == SW : op == NSW; + + case EW: + case NEW: + return value.endsWith(vals[0]) ? op == EW : op == NEW; + + } + return false; + } + + /** + * testValue tests the specified value for validity against this + * IndexQuery. The helper classes in org.apache.xindice.core.indexer.helpers + * should be used for optimized performance. + * + * @param value The Value to compare + * @return Whether or not the value matches + */ + public final boolean testValue(String value) { + return testValue(new Value(value)); + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/Indexer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/Indexer.java new file mode 100644 index 000000000..d0f4d5d07 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/Indexer.java @@ -0,0 +1,99 @@ +package net.jxta.impl.xindice.core.indexer; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +import net.jxta.impl.xindice.core.*; +import net.jxta.impl.xindice.core.data.*; + + +/** + * Indexer is the abstract indexing interface for Xindice. An Indexer + * object is implemented in order to retrieve and manage indexes. + *

            + * Any number of Indexer instances may be associated with a single + * Collection. The type of Indexer utilized by a query depends on + * the 'Style' of Indexer and the type of QueryResolver that is being + * used to performt he query. Currently, Xindice only internally + * supports one kind of Indexer: 'XPath'. + */ + +public interface Indexer extends DBObject { + + /** + * remove removes all references to the specified Key from the Indexer. + * + * @param key The Object ID + */ + void remove(Key key) throws DBException; + + /** + * add adds a Document to the Indexer. + * + * @param key The Object ID + * @param pos record position + */ + void add(Key key, long pos) throws DBException; + + /** + * flush forcefully flushes any unwritten buffers to disk. + */ + void flush() throws DBException; +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/NameIndexer.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/NameIndexer.java new file mode 100644 index 000000000..6af7fe3fd --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/core/indexer/NameIndexer.java @@ -0,0 +1,113 @@ +package net.jxta.impl.xindice.core.indexer; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +import net.jxta.impl.xindice.core.DBException; +import net.jxta.impl.xindice.core.data.Key; +import net.jxta.impl.xindice.core.filer.BTree; +import net.jxta.impl.xindice.core.filer.BTreeCorruptException; + +import java.io.File; +import java.io.IOException; + + +/** + * NameIndexer is a basic implementation of the Indexer interface. + * It is used for maintaining element and element@attribute unique + * indexes. + */ + +public final class NameIndexer extends BTree implements Indexer { + + private static final short PAGESIZE = 4096; + // TODO: MAXKEYSIZE might need tuning + private static final short MAXKEYSIZE = 256; + + private FileHeader fileHeader; + + public NameIndexer() { + super(); + fileHeader = getFileHeader(); + fileHeader.setPageSize(PAGESIZE); + fileHeader.setMaxKeySize(MAXKEYSIZE); + } + + public void setLocation(String dir, String file) { + setFile(new File(dir, file + ".idx")); + } + + public synchronized void remove(Key key) throws DBException { + try { + removeValue(key); + } catch (IOException e) { + throw new BTreeCorruptException("Corruption detected on remove"); + } + } + + public synchronized void add(Key key, long pos) throws DBException { + try { + addValue(key, pos); + flush(); + } catch (IOException e) { + throw new BTreeCorruptException("Corruption detected on add"); + } + } +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/Named.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/Named.java new file mode 100644 index 000000000..17be80a6e --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/Named.java @@ -0,0 +1,75 @@ +package net.jxta.impl.xindice.util; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +/** + * Named identifies an object as having a contextually important Name. + */ + +public interface Named { + + /** + * getName retrieves the contextually important name of the object + * + * @return The object's name + */ + String getName(); +} + diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/XindiceException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/XindiceException.java new file mode 100644 index 000000000..8fe768228 --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/XindiceException.java @@ -0,0 +1,86 @@ +package net.jxta.impl.xindice.util; + + +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xindice" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999-2001, The dbXML + * Group, L.L.C., http://www.dbxmlgroup.com. For more + * information on the Apache Software Foundation, please see + * . + * + + */ + +import java.io.*; + + +/** + * A XindiceException is the base class for all Xindice related + * Exceptions. + */ + +public class XindiceException extends Exception { + + public XindiceException() {} + + public XindiceException(String message) { + super(message); + } + + public XindiceException(String message, Throwable wrapped) { + super(message); + initCause(wrapped); + } + + public Throwable getWrappedThrowable() { + return getCause(); + } +} diff --git a/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/XindiceRuntimeException.java b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/XindiceRuntimeException.java new file mode 100644 index 000000000..cdddff9cc --- /dev/null +++ b/p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/xindice/util/XindiceRuntimeException.java @@ -0,0 +1,78 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * CVS $Id$ + * CVS XindiceRuntimeException.java,v 1.5 2004/02/08 02:59:39 vgritsenko Exp $ + */ + +package net.jxta.impl.xindice.util; + + +import java.io.PrintStream; +import java.io.PrintWriter; + + +/** + * A XindiceRuntimeException is the base class for all Xindice related RuntimeExceptions. + * + * @version CVS $Revision$, $Date$ + */ +public class XindiceRuntimeException extends RuntimeException { + protected Throwable cause; + + public XindiceRuntimeException() {} + + public XindiceRuntimeException(String message) { + super(message); + } + + public XindiceRuntimeException(Throwable cause) { + super(); + this.cause = cause; + } + + public XindiceRuntimeException(String message, Throwable cause) { + super(message); + this.cause = cause; + } + + @Override + public void printStackTrace() { + printStackTrace(System.err); + } + + @Override + public void printStackTrace(PrintStream s) { + super.printStackTrace(s); + if (this.cause != null) { + s.print("Caused by: "); + this.cause.printStackTrace(s); + } + } + + @Override + public void printStackTrace(PrintWriter s) { + super.printStackTrace(s); + if (this.cause != null) { + s.print("Caused by: "); + this.cause.printStackTrace(s); + } + } + + @Override + public Throwable getCause() { + return cause; + } +} diff --git a/p2pproxy/dependencies/MJSIP.COPYRIGHT.txt b/p2pproxy/dependencies/MJSIP.COPYRIGHT.txt new file mode 100644 index 000000000..7dd44359e --- /dev/null +++ b/p2pproxy/dependencies/MJSIP.COPYRIGHT.txt @@ -0,0 +1,22 @@ +MjSip - http://www.mjsip.org + +Copyright (C) 2005 by Luca Veltri - University of Parma - Italy. +__________________________________________________ + + +MjSip is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MjSip is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MjSip; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +PLEASE READ CAREFULLY THE LICENSE DOCUMENT RECEIVED ALONG WITH THIS LIBRARY. \ No newline at end of file diff --git a/p2pproxy/dependencies/bcprov-jdk14.jar b/p2pproxy/dependencies/bcprov-jdk14.jar new file mode 100644 index 000000000..b27a81097 Binary files /dev/null and b/p2pproxy/dependencies/bcprov-jdk14.jar differ diff --git a/p2pproxy/dependencies/bouncycastle-LICENSE.txt b/p2pproxy/dependencies/bouncycastle-LICENSE.txt new file mode 100644 index 000000000..e8a967c32 --- /dev/null +++ b/p2pproxy/dependencies/bouncycastle-LICENSE.txt @@ -0,0 +1,22 @@ +License + +Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle +(http://www.bouncycastle.org) + +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, sublicense, 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 NONINFRINGEMENT. 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. diff --git a/p2pproxy/dependencies/javax.servlet.jar b/p2pproxy/dependencies/javax.servlet.jar new file mode 100644 index 000000000..d2dee6f9b Binary files /dev/null and b/p2pproxy/dependencies/javax.servlet.jar differ diff --git a/p2pproxy/dependencies/jstun-0.7.0.jar b/p2pproxy/dependencies/jstun-0.7.0.jar new file mode 100644 index 000000000..4d220efea Binary files /dev/null and b/p2pproxy/dependencies/jstun-0.7.0.jar differ diff --git a/p2pproxy/dependencies/junit-4.3.1.jar b/p2pproxy/dependencies/junit-4.3.1.jar new file mode 100644 index 000000000..ff5d1888f Binary files /dev/null and b/p2pproxy/dependencies/junit-4.3.1.jar differ diff --git a/p2pproxy/dependencies/jxta_license.html b/p2pproxy/dependencies/jxta_license.html new file mode 100644 index 000000000..ceb0e5ceb --- /dev/null +++ b/p2pproxy/dependencies/jxta_license.html @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + Content + + + + + + + + + + + + + + +

            + + + + + + + + + + + + + + + +
            + +
            + + + + + + + + + + + + + + + + + + + + + + +
            The Sun Project JXTA(TM) Software License (Based on the Apache Software License Version 1.1)
            + + + + + +


            +Copyright (c) 2001-2004 Sun Microsystems, Inc. All rights reserved.

            +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

            + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

            + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution.

            + +3. The end-user documentation included with the redistribution, if any, must +include the following acknowledgment: "This product includes software +developed by Sun Microsystems, Inc. for JXTA(TM) technology." Alternately, this +acknowledgment may appear in the software itself, if and wherever such +third-party acknowledgments normally appear.

            + +4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must +not be used to endorse or promote products derived from this software without +prior written permission. For written permission, please contact Project JXTA +at http://www.jxta.org.

            + +5. Products derived from this software may not be called "JXTA", nor may "JXTA" +appear in their name, without prior written permission of Sun.

            + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

            +JXTA is a registered trademark of Sun Microsystems, Inc. in the United States and other countries.

            +
            +

            Please see the license + information page for instructions on use of the license in source + files.

            +

            This software consists of voluntary contributions made by many individuals + on behalf of Project JXTA. For more information on Project JXTA, please + see http://www.jxta.org.
            +
            + This license is based on the BSD license adopted by the Apache Foundation. +

            +
            +
            +
            + + + + + + + diff --git a/p2pproxy/dependencies/log4j.LICENSE b/p2pproxy/dependencies/log4j.LICENSE new file mode 100644 index 000000000..6279e5206 --- /dev/null +++ b/p2pproxy/dependencies/log4j.LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 1999-2005 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/p2pproxy/dependencies/log4j.jar b/p2pproxy/dependencies/log4j.jar new file mode 100644 index 000000000..dde997210 Binary files /dev/null and b/p2pproxy/dependencies/log4j.jar differ diff --git a/p2pproxy/dependencies/org.mortbay.jetty.jar b/p2pproxy/dependencies/org.mortbay.jetty.jar new file mode 100644 index 000000000..db8d0811b Binary files /dev/null and b/p2pproxy/dependencies/org.mortbay.jetty.jar differ diff --git a/p2pproxy/dependencies/sip.jar b/p2pproxy/dependencies/sip.jar new file mode 100644 index 000000000..a8e988416 Binary files /dev/null and b/p2pproxy/dependencies/sip.jar differ diff --git a/p2pproxy/log4j.properties b/p2pproxy/log4j.properties new file mode 100644 index 000000000..215a77939 --- /dev/null +++ b/p2pproxy/log4j.properties @@ -0,0 +1,80 @@ +### Configuration file for log4j. For more details, see log4j's site: +### +### http://jakarta.apache.org/log4j/ + +### Set root loger level and its appender +log4j.rootLogger=ERROR, A1, R + +### Create an appender named A1 to log to console +log4j.appender.A1=org.apache.log4j.ConsoleAppender +log4j.appender.A1.Target=System.out +#log4j.appender.A1.Threshold=WARN +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +## the following conversion pattern produces: +## connectToRendezVous +log4j.appender.A1.layout.ConversionPattern=<%-5p %d{ISO8601} %c{1}::%M:%L> %x %m\n + +log4j.appender.R.Threshold=TRACE +log4j.appender.R=org.apache.log4j.RollingFileAppender +log4j.appender.R.File=${org.linphone.p2pproxy.home}/logs/p2pproxy.log +log4j.appender.R.MaxFileSize=1000KB +# Keep one backup file +log4j.appender.R.MaxBackupIndex=1 +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=<%-5p %d{ISO8601} %c{1}::%M:%L> %x %m\n + + +#java.util.logging +handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter + +# Limit the message that are printed on the console to INFO and above +java.util.logging.ConsoleHandler.level = FINEST +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter +# Facility specific properties. +# Provides extra control for each logger. +# +# For example, set the net.jxta.impi.pipe.PipeResolver logger to only log SEVERE +# messages: +#net.jxta.level = FINEST + + +#net.jxta.impl.peergroup.AutomaticConfigurator.level=INFO +#net.jxta.impl.peergroup.ConfigDialog.level=INFO +#net.jxta.impl.peergroup.DefaultConfigurator.level=INFO +#net.jxta.impl.peergroup.NullConfigurator.level=INFO + +### per-package filtering examples: + #net.jxta.level=WARN +# net.jxta.impl.peergroup.level=INFO +#net.jxta.impl.rendezvous.edge.level=FINEST +# net.jxta.impl.endpoint.relay.level=FINEST +#net.jxta.impl.endpoint.WireFormatMessageBinary.level=FINEST +#net.jxta.impl.discovery.level=FINEST +#net.jxta.impl.cm.level=FINEST +# net.jxta.impl.resolver.level=FINEST +# net.jxta.impl.endpoint.level=FINEST +# net.jxta.impl.endpoint.relay.level=FINEST +#net.jxta.impl.endpoint.relay.RelayClient.level=FINEST + #net.jxta.impl.endpoint.tcp.level=FINEST +#net.jxta.impl.endpoint.servlethttp.level=INFO +#net.jxta.impl.endpoint.servlethttp.HttpClientMessenger.level=FINEST +# net.jxta.impl.endpoint.router.EndpointRouter.level=WARNING +# net.jxta.impl.endpoint.EndpointServiceImpl.level=FINEST + #net.jxta.impl.pipe.level=FINEST +#net.jxta.socket.level=FINEST +#net.jxta.impl.util.pipe.reliable.level=FINEST +#net.jxta.impl.endpoint.router.level=INFO +#net.jxta.platform.level=FINEST + +log4j.logger.org.linphone.p2pproxy=INFO +#log4j.logger.net.jxta.impl.rendezvous.rpv=WARN +log4j.logger.org.linphone.p2pproxy.core.JxtaNetworkManager=DEBUG +log4j.logger.org.linphone.p2pproxy.core.P2pProxyAccountManagementImpl=DEBUG + +log4j.logger.org.linphone.p2pproxy.api.P2pProxyInstance=INFO +#log4j.logger.org.linphone.p2pproxy.test.utils=INFO +log4j.logger.org.linphone.p2pproxy.test=DEBUG +#log4j.logger.org.linphone.p2pproxy.core.rdvautoconfig=DEBUG diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyException.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyException.java new file mode 100644 index 000000000..15a023097 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyException.java @@ -0,0 +1,45 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pProxyException.java -Generic purpose Exception for P2pProxyMain. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.api; + +@SuppressWarnings("serial") +public class P2pProxyException extends Exception { + + public P2pProxyException() { + super(); + // TODO Auto-generated constructor stub + } + + public P2pProxyException(String arg0, Throwable arg1) { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public P2pProxyException(String arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + + public P2pProxyException(Throwable arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyInstance.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyInstance.java new file mode 100644 index 000000000..75629439b --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyInstance.java @@ -0,0 +1,76 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pProxyInstance.java -- + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.api; + +import org.zoolu.sip.provider.SipProvider; + +public interface P2pProxyInstance { + public static int BASE_HTTP = 9700; + public static int BASE_TCP = 30700; + + public enum Mode {relay, edge, auto,seeding_server}; + /** + * @return Returns the Mode. + */ + public abstract Mode getMode(); + + /** + * @param aModet. + */ + public abstract void setMode(Mode aMode); + + /** + * @return Returns the mIndex. + */ + public abstract int getIndex(); + + /** + * @param index The mIndex to set. + */ + public abstract void setIndex(int index); + + public abstract void start() throws Exception; + public abstract void stop() throws Exception; + + public abstract boolean isStarted() throws P2pProxyException; + + public abstract SipProvider getSipClientProvider(); + + public abstract String getSipClientName(); + + public int getNumberOfconnectedPeers(); + + public Object getOpaqueNetworkManager(); + + public void setPrivateHostAdress(String anAddress); + + public void setPublicHostAdress(String anAddress); + + public abstract P2pProxyNetworkProbe getManager(); + + public abstract P2pProxyRtpRelayManagement getRtpRelayManager(); + + public void setRelayCapacity(int aCapacity); + + public void setProperty(String key,String value) throws P2pProxyException; + + public int getAdvertisementDiscoveryTimeout(); + +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyManagement.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyManagement.java new file mode 100644 index 000000000..9ec9a62c6 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyManagement.java @@ -0,0 +1,33 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyManagement.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.api; + + +public interface P2pProxyManagement extends P2pProxyNetworkProbe,P2pProxyRtpRelayManagement { + + /** + * test if according both to local peer capabilities and supeer peer election polity this peer should become a super peer + * + * @return + */ + public boolean shouldIBehaveAsAnRdv() throws P2pProxyException; + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyNetworkProbe.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyNetworkProbe.java new file mode 100644 index 000000000..c2732430e --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyNetworkProbe.java @@ -0,0 +1,48 @@ +/* + p2pproxy + Copyright (C) 2007 Jehan Monnier () + + P2pProxyNetworkProbe.java - . + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.p2pproxy.api; + +import java.net.InetAddress; +import java.net.InetSocketAddress; + + + + +public interface P2pProxyNetworkProbe { + public enum Protocol {tcp,udp}; + /** + * request the rdv server for the edge IP address + * @return + * @throws P2pProxyException + */ + public abstract InetAddress getPublicIpAddress() throws P2pProxyException; + + /** + * Ask the network to test if the given ip,port, protocol is reachable from the network + * @param aSocketAddress + * @param aProtocol + * @return true if reachable + * @throws P2pProxyException + */ + public abstract boolean probeSocket(InetSocketAddress aSocketAddress, + Protocol aProtocol) throws P2pProxyException; + +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyRtpRelayManagement.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyRtpRelayManagement.java new file mode 100644 index 000000000..d2ee5b5a7 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyRtpRelayManagement.java @@ -0,0 +1,15 @@ +package org.linphone.p2pproxy.api; + +import java.net.InetSocketAddress; +import java.util.Map; + +import org.linphone.p2pproxy.core.media.rtprelay.MediaType; + +public interface P2pProxyRtpRelayManagement { + + /** + * + * @param aSource get list Socket address available for relay + */ + public Map getAddresses() throws P2pProxyException ; +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyUserAlreadyExistException.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyUserAlreadyExistException.java new file mode 100644 index 000000000..e3ba5ac6b --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyUserAlreadyExistException.java @@ -0,0 +1,58 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyUserAlreadyExistException.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.api; + +public class P2pProxyUserAlreadyExistException extends Exception { + + /** + * + */ + public P2pProxyUserAlreadyExistException() { + super(); + // TODO Auto-generated constructor stub + } + + /** + * @param arg0 + * @param arg1 + */ + public P2pProxyUserAlreadyExistException(String arg0, Throwable arg1) { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + /** + * @param arg0 + */ + public P2pProxyUserAlreadyExistException(String arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + + /** + * @param arg0 + */ + public P2pProxyUserAlreadyExistException(Throwable arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyUserNotFoundException.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyUserNotFoundException.java new file mode 100644 index 000000000..f628e00e8 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxyUserNotFoundException.java @@ -0,0 +1,55 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyUserNotFoundException.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.api; + + +@SuppressWarnings("serial") +public class P2pProxyUserNotFoundException extends P2pProxyException { + + /** + * + */ + public P2pProxyUserNotFoundException() { + super(); + } + + /** + * @param arg0 + * @param arg1 + */ + public P2pProxyUserNotFoundException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + /** + * @param arg0 + */ + public P2pProxyUserNotFoundException(String arg0) { + super(arg0); + } + + /** + * @param arg0 + */ + public P2pProxyUserNotFoundException(Throwable arg0) { + super(arg0); + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/Configurator.java b/p2pproxy/src/org/linphone/p2pproxy/core/Configurator.java new file mode 100644 index 000000000..56950b0e9 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/Configurator.java @@ -0,0 +1,68 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +Configurator.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.InvalidPropertiesFormatException; +import java.util.Properties; +import java.util.Set; + +import org.apache.log4j.Logger; + +@SuppressWarnings("serial") +public class Configurator extends Properties { + private final static Logger mLog = Logger.getLogger(Configurator.class); + private final File mFile; + public Configurator (File aFile) throws InvalidPropertiesFormatException, FileNotFoundException, IOException { + super(); + mFile = aFile; + if (mFile.exists()) { + loadFromXML(new FileInputStream(mFile)); + } + } + /** + * save to disk + * @throws IOException + * @throws FileNotFoundException + */ + public void save() throws FileNotFoundException, IOException { + storeToXML(new FileOutputStream(mFile),new Date().toString()); + } + public Object setProperty(String key,String value) { + Object lReturn = super.setProperty(key, value); + try { + save(); + } catch (Exception e) { + mLog.error("enable to save prop ["+key+"] value ["+value+"]", e); + } + return lReturn; + } + public void serProperties(Properties aProperties) { + for (Object key :aProperties.keySet()){ + setProperty((String)key,aProperties.getProperty((String)key)); + } + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/EdgePeerServiceManager.java b/p2pproxy/src/org/linphone/p2pproxy/core/EdgePeerServiceManager.java new file mode 100644 index 000000000..bc70b5ded --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/EdgePeerServiceManager.java @@ -0,0 +1,61 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +EdgePeerServiceManager.java - EdgePeer Service Manager. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.net.SocketException; +import java.net.UnknownHostException; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.rdvautoconfig.AutoConfigService; + +// Referenced classes of package org.linphone.p2pproxy.core: +// ServiceProvider, JxtaNetworkManager, Configurator + +public class EdgePeerServiceManager extends P2pProxyManagementImpl +{ + private final AutoConfigService mAutoConfigService; + private final static Logger mLog = Logger.getLogger(EdgePeerServiceManager.class); + EdgePeerServiceManager(Configurator aConfigurator, JxtaNetworkManager aJxtaNetworkManager)throws SocketException, UnknownHostException + { + super(aConfigurator,aJxtaNetworkManager); + mAutoConfigService = new AutoConfigService(mConfigurator,mJxtaNetworkManager,this); + } + + public void start(long aTimeout) throws P2pProxyException + { + super.start(aTimeout); + mAutoConfigService.start(aTimeout); + } + + public void stop() { + super.stop(); + mAutoConfigService.stop(); + mLog.info("EdgePeerServiceManager stopped"); + } + + + public boolean shouldIBehaveAsAnRdv() throws P2pProxyException{ + return mAutoConfigService.canIBehaveAsASuperPeer(); + } + + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/GenericService.java b/p2pproxy/src/org/linphone/p2pproxy/core/GenericService.java new file mode 100644 index 000000000..08455dd1a --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/GenericService.java @@ -0,0 +1,150 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RtpRelayService.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import java.net.Socket; +import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.id.IDFactory; + +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleClassAdvertisement; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.socket.JxtaServerSocket; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; + + +public class GenericService implements Runnable,ServiceProvider { + public interface ServiceSocketHandlerFactory { + + public Runnable create(Socket aSocket) ; + + } + private final JxtaNetworkManager mJxtaNetworkManager; + private final Configurator mProperties; + private final String SERVICE_PIPE_ID; + private final static Logger mLog = Logger.getLogger(GenericService.class); + private final String ADV_NAME ; + private final String MODULE_CLASS_ID; + private final String MODULE_SPEC_ID; + private JxtaServerSocket mJxtaServerSocket; + private final String mServiceName; + private Thread mSocketServerThread ; + private final ExecutorService mPool; + private final ServiceSocketHandlerFactory mServiceSocketHandlerFactory; + + public GenericService(Configurator lProperties,JxtaNetworkManager aJxtaNetworkManager,String aServiceName,ServiceSocketHandlerFactory aServiceSocketHandlerFactory) { + mJxtaNetworkManager = aJxtaNetworkManager; + mProperties = lProperties; + mServiceName = aServiceName.trim(); + SERVICE_PIPE_ID="org.linphone.p2pproxy."+mServiceName+".bidi-pipe.id"; + ADV_NAME = "JXTASPEC:LINPHONE-"+mServiceName; + MODULE_CLASS_ID="org.linphone.p2pproxy."+mServiceName+"Service.module-class.id"; + MODULE_SPEC_ID="org.linphone.p2pproxy."+mServiceName+"Service.module-spec.id"; + mSocketServerThread = new Thread(this,mServiceName+"Service server thread"); + mPool = Executors.newCachedThreadPool(); + mServiceSocketHandlerFactory = aServiceSocketHandlerFactory; + } + + public void start(long l) throws P2pProxyException { + try { + mLog.info("Start the RtpRelayService daemon"); + ModuleClassAdvertisement lModuleAdvertisement = (ModuleClassAdvertisement) AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType()); + + lModuleAdvertisement.setName("JXTAMOD:LINPHONE-"+mServiceName); + lModuleAdvertisement.setDescription("Service to provide " +mServiceName); + + ModuleClassID lModuleClassID; + // to avoid ID creation at each start + if (mProperties.getProperty(MODULE_CLASS_ID) == null) { + lModuleClassID = IDFactory.newModuleClassID(); + mProperties.setProperty(MODULE_CLASS_ID, lModuleClassID.toURI().toString()); + } else { + lModuleClassID = (ModuleClassID) IDFactory.fromURI(URI.create(mProperties.getProperty(MODULE_CLASS_ID))); + } + lModuleAdvertisement.setModuleClassID(lModuleClassID); + + // publish local only + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().publish(lModuleAdvertisement); + + ModuleSpecAdvertisement lModuleSpecAdvertisement = (ModuleSpecAdvertisement)AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType()); + lModuleSpecAdvertisement.setName(ADV_NAME); + lModuleSpecAdvertisement.setVersion("Version 1.0"); + lModuleSpecAdvertisement.setCreator("linphone.org"); + // to avoid ID creation at each start + ModuleSpecID lModuleSpecId; + if (mProperties.getProperty(MODULE_SPEC_ID) == null) { + lModuleSpecId = IDFactory.newModuleSpecID(lModuleClassID); + mProperties.setProperty(MODULE_SPEC_ID, lModuleSpecId.toURI().toString()); + } else { + lModuleSpecId = (ModuleSpecID) IDFactory.fromURI(URI.create(mProperties.getProperty(MODULE_SPEC_ID))); + } + lModuleSpecAdvertisement.setModuleSpecID(lModuleSpecId); + lModuleSpecAdvertisement.setSpecURI("http://www.linphone.org/"+mServiceName.toLowerCase()); + + PipeAdvertisement lSocketAdvertisement = mJxtaNetworkManager.createPipeAdvertisement(SERVICE_PIPE_ID, mServiceName.toLowerCase()); + + lModuleSpecAdvertisement.setPipeAdvertisement(lSocketAdvertisement); + mJxtaServerSocket = new JxtaServerSocket(mJxtaNetworkManager.getPeerGroup(), lSocketAdvertisement, 10); + mJxtaServerSocket.setSoTimeout(0); + mSocketServerThread.start(); + //publish local only + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().publish(lModuleSpecAdvertisement); + mLog.info("Adv ["+lModuleSpecAdvertisement+"] published"); + } + catch(Exception e) + { + mLog.error("socket instance error", e); + } + } + public void stop(){ + throw new RuntimeException("Not implemented"); + } + public void run() { + while (true) { + try { + mLog.info("Waiting for connection on service ["+ADV_NAME+"]"); + Socket lSocket = mJxtaServerSocket.accept(); + // set reliable + if (lSocket != null) { + mLog.info("socket created"); + mPool.execute(mServiceSocketHandlerFactory.create(lSocket)); + } + } catch (Exception e) { + mLog.error("Server socket error",e); + } + } + + } + + /** + * @return Returns the aDV_NAME. + */ + public String getAdvName() { + return ADV_NAME; + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/GenericServiceClient.java b/p2pproxy/src/org/linphone/p2pproxy/core/GenericServiceClient.java new file mode 100644 index 000000000..21b7698d8 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/GenericServiceClient.java @@ -0,0 +1,121 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +PeerInfoServiceClient.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.util.List; + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.socket.JxtaSocket; +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe; +import org.linphone.p2pproxy.core.Configurator; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.ServiceProvider; +import org.linphone.p2pproxy.core.JxtaNetworkManager.Mode; + + +public abstract class GenericServiceClient implements ServiceProvider{ + protected final JxtaNetworkManager mJxtaNetworkManager; + private final Configurator mProperties; + private final static Logger mLog = Logger.getLogger(GenericServiceClient.class); + protected JxtaSocket mJxtaSocket; + protected ObjectOutputStream mOut; + protected ObjectInputStream mIn; + boolean mStarted = false; + protected final int mSoTimout; + private final String mAdvertisementName; + + public GenericServiceClient(Configurator lProperties,JxtaNetworkManager aJxtaNetworkManager,String aAdvertisementName) { + mJxtaNetworkManager = aJxtaNetworkManager; + mProperties = lProperties; + mSoTimout = Integer.parseInt(lProperties.getProperty(JxtaNetworkManager.SO_TIMEOUT, "10000")); + mAdvertisementName = aAdvertisementName; + } + + public void start(long aTimeOut) throws P2pProxyException { + // 1 check if connected to a rdv + try { + + mStarted = true; + mLog.info(mAdvertisementName+" client started"); + } + catch(Exception e) { + throw new P2pProxyException(e); + } + + } + + + public void stop() { + try { + checkObject(); + mIn.close(); + mOut.close(); + mJxtaSocket.close(); + }catch (Exception e ) { + mLog.error("cannot "+mAdvertisementName+" client" , e); + } + mLog.info(mAdvertisementName+" client stopped"); + } + + protected void checkSocketConnection() throws IOException, P2pProxyException, InterruptedException { + //wo because close not sent + if (mJxtaSocket != null) mJxtaSocket.close(); + + if (mJxtaSocket == null ||mJxtaSocket.isClosed() || mJxtaSocket.isBound() == false) { + try { + mLog.info("Opening socket for ["+mAdvertisementName+"]"); + // try from local + mJxtaSocket = mJxtaNetworkManager.openSocket(null, mAdvertisementName, mSoTimout,true); + } catch (P2pProxyException e) { + //last chance + mLog.warn("cannot open socket ["+mAdvertisementName+"], trying from remote",e); + mJxtaSocket = mJxtaNetworkManager.openSocket(null, mAdvertisementName, mSoTimout,false); + } + if (mJxtaSocket == null) throw new P2pProxyException("Cannot start"+mAdvertisementName+" client because cannot bind jxta socket"); + mOut = new ObjectOutputStream(mJxtaSocket.getOutputStream()); + mIn = new ObjectInputStream(mJxtaSocket.getInputStream()); + //just to work-around socket establishment + mIn.readBoolean(); + } + + } + + protected void checkObject() throws P2pProxyException{ + if(!mStarted) throw new P2pProxyException(mAdvertisementName+" client not started"); + } + + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/GenericUdpSession.java b/p2pproxy/src/org/linphone/p2pproxy/core/GenericUdpSession.java new file mode 100644 index 000000000..e291cd110 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/GenericUdpSession.java @@ -0,0 +1,79 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +GenericUdpSession.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; + +import java.net.SocketException; +import java.net.UnknownHostException; + + + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.core.media.jxtaudpproxy.UdpSession; + +public class GenericUdpSession implements Runnable { + public interface MessageHandler { + public void onMessage(DatagramPacket lMessage); + } + private final static Logger mLog = Logger.getLogger(UdpSession.class); + private final DatagramSocket mLocalSocket; + private final Thread mLocalSocketThread; + + private final MessageHandler mMessageHandler; + private boolean mExit = false; + public GenericUdpSession(InetSocketAddress aSocketAddress,MessageHandler aMessageHandler) throws SocketException, UnknownHostException { + mMessageHandler = aMessageHandler; + mLocalSocket = new DatagramSocket(aSocketAddress); + mLocalSocketThread = new Thread(this,"udp session rtp ["+aSocketAddress+"]"); + mLocalSocketThread.start(); + } + public void run() { + + while (mExit != true) { + try { + byte[] lBuff = new byte[1500]; + DatagramPacket lDatagramPacket = new DatagramPacket(lBuff,lBuff.length); + mLocalSocket.receive(lDatagramPacket); + // if destination is known just send + mMessageHandler.onMessage(lDatagramPacket); + + }catch(Exception e) { + //nop + } + } + mLog.info("exit from thread ["+mLocalSocketThread+"]"); + + } + + public void close() { + mExit = true; + mLocalSocket.close(); + } + + public DatagramSocket getSocket() { + return mLocalSocket; + } + + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java b/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java new file mode 100644 index 000000000..0c3443b50 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java @@ -0,0 +1,362 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +JxtaNetworkManager.java -- connection to a jxta network. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; + +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.security.cert.CertificateException; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; + + + +import net.jxta.discovery.DiscoveryEvent; +import net.jxta.discovery.DiscoveryListener; +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.exception.JxtaException; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; +import net.jxta.peergroup.NetPeerGroupFactory; +import net.jxta.peergroup.PeerGroup; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.PipeID; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.pipe.PipeService; +import net.jxta.platform.NetworkConfigurator; +import net.jxta.protocol.ConfigParams; +import net.jxta.protocol.DiscoveryResponseMsg; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.rendezvous.RendezVousService; +import net.jxta.socket.JxtaSocket; + + +public class JxtaNetworkManager { + public enum Mode {relay, edge, auto,seeding_server}; + private PeerGroup mNetworkPeerGroup; + private RendezVousService mRendezVousService; + private final static Logger mLog = Logger.getLogger(JxtaNetworkManager.class); + public final static String RDV_CONNECT_TIMEOUT="org.linphone.p2pproxy.JxtaNetworkManager.rdv-connect.timout"; + public final static String ADV_DISCOVERY_TIMEOUT="org.linphone.p2pproxy.JxtaNetworkManager.adv-discovery.timout"; + public final static String MODE="org.linphone.p2pproxy.JxtaNetworkManager.mode"; + public final static String RELAY_CAPACITY="org.linphone.p2pproxy.JxtaNetworkManager.relay-capacity"; + public final static String SEEDING_RDV="org.linphone.p2pproxy.JxtaNetworkManager.seeding-rdv.url"; + public final static String SEEDING_RELAY="org.linphone.p2pproxy.JxtaNetworkManager.seeding-relay.url"; + public final static String TCP_LISTENING_PORT="org.linphone.p2pproxy.JxtaNetworkManager.tcp.port"; + public final static String HTTP_LISTENING_PORT="org.linphone.p2pproxy.JxtaNetworkManager.http.port"; + public final static String HTTP_LISTENING_PUBLIC_ADDRESS="org.linphone.p2pproxy.JxtaNetworkManager.http.listening.public.address"; + public final static String TCP_LISTENING_PUBLIC_ADDRESS="org.linphone.p2pproxy.JxtaNetworkManager.tcp.listening.public.address"; + public final static String SO_TIMEOUT="org.linphone.p2pproxy.so-timout"; + public final static String ENABLE_HTTP_CLIENT="org.linphone.p2pproxy.JxtaNetworkManager.http.client.enable"; + public static int EDGE_MODE = NetworkConfigurator.TCP_CLIENT| NetworkConfigurator.RDV_CLIENT | NetworkConfigurator.RELAY_CLIENT; + public static int SUPER_PEER_MODE = NetworkConfigurator.RDV_RELAY_PROXY_NODE; + final private Properties mProperties; + private Mode mMode; + public static int ADV_DISCOVERY_TIMEOUT_INT = 15000; + static { + System.setProperty("net.jxta.impl.cm.index.rebuild", "true"); + } + /** + * @return Returns the mMode. + */ + public Mode getMode() { + return mMode; + } + /** + * Create a jxta connection from a given config directory + * and connect to a rendez vous perr + * @param aConfigDir a jxta config dir + * @param aRdvConnectionTimout time in ms to wait until a succesfull connection to a rdv peer + * @throws JxtaException + * @throws InterruptedException + * @throws P2pProxyException + * @throws IOException + * @throws URISyntaxException + * @throws CertificateException + */ + public JxtaNetworkManager(Configurator aProperties,File aConfigDir) throws JxtaException, InterruptedException, P2pProxyException, IOException, URISyntaxException, CertificateException { + super(); + // get configuration + //System.setProperty("JXTA_HOME", aConfigDir.getAbsolutePath()); + + NetworkConfigurator lNetworkConfigurator; + mProperties = aProperties; + // set mode + mMode = Mode.valueOf(aProperties.getProperty(MODE, Mode.edge.name())); + int lMode; + if (mMode == Mode.relay || mMode == Mode.seeding_server) { + lMode = SUPER_PEER_MODE; + } else { + lMode = EDGE_MODE; + } + if (aProperties.getProperty(ENABLE_HTTP_CLIENT) != null && Boolean.parseBoolean(aProperties.getProperty(ENABLE_HTTP_CLIENT)) == true) { + lMode = lMode | NetworkConfigurator.HTTP_CLIENT; + } + + lNetworkConfigurator = new NetworkConfigurator(lMode,aConfigDir.toURI()); + + if (!lNetworkConfigurator.exists()) { + lNetworkConfigurator.setPeerID(IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID)); + lNetworkConfigurator.setDescription("p2p proxy instance"); + lNetworkConfigurator.save(); + } else { + lNetworkConfigurator.load(); + } + + // set sedding host + if (aProperties.getProperty(SEEDING_RDV) != null) { + StringTokenizer lSeedingRdvList = new StringTokenizer(aProperties.getProperty(SEEDING_RDV),"|" ); + while (lSeedingRdvList.hasMoreTokens()) { + lNetworkConfigurator.addSeedRendezvous(new URI(lSeedingRdvList.nextToken())); + } + } + if (aProperties.getProperty(SEEDING_RELAY) != null) { + StringTokenizer lSeedingRelayList = new StringTokenizer(aProperties.getProperty(SEEDING_RELAY),"|" ); + while (lSeedingRelayList.hasMoreTokens()) { + lNetworkConfigurator.addSeedRelay(new URI(lSeedingRelayList.nextToken())); + } + } + + if (aProperties.getProperty(HTTP_LISTENING_PUBLIC_ADDRESS) != null) { + lNetworkConfigurator.setHttpPublicAddress(aProperties.getProperty(HTTP_LISTENING_PUBLIC_ADDRESS), true); + } + + // set listening ports + if (aProperties.getProperty(HTTP_LISTENING_PORT) != null) { + lNetworkConfigurator.setHttpPort(Integer.parseInt(aProperties.getProperty(HTTP_LISTENING_PORT))); + } + + if (aProperties.getProperty(TCP_LISTENING_PUBLIC_ADDRESS) != null) { + lNetworkConfigurator.setTcpPublicAddress(aProperties.getProperty(TCP_LISTENING_PUBLIC_ADDRESS), true); + lNetworkConfigurator.setTcpStartPort(-1); + lNetworkConfigurator.setTcpEndPort(-1); + } + + if (aProperties.getProperty(TCP_LISTENING_PORT) != null) { + lNetworkConfigurator.setTcpPort(Integer.parseInt(aProperties.getProperty(TCP_LISTENING_PORT))); + } + + // connect to rdv + int lRdvConnectionTimout = Integer.parseInt(aProperties.getProperty(RDV_CONNECT_TIMEOUT,"60000")); + init(lNetworkConfigurator,lRdvConnectionTimout,mMode); + + + } + /** + * @param aProperties use to store pipe ID + * @param aNetworkConfigurator jxya native config + * @param aConnectTimout rdv connection timeout + * @throws JxtaException + * @throws InterruptedException + * @throws P2pProxyException + * @throws IOException + * @throws URISyntaxException + * @throws CertificateException + */ + public JxtaNetworkManager(Configurator aProperties, NetworkConfigurator aNetworkConfigurator,int aConnectTimout,Mode aMode) throws JxtaException, InterruptedException, P2pProxyException, IOException, URISyntaxException, CertificateException { + mProperties = aProperties; + mMode = aMode; + init(aNetworkConfigurator,aConnectTimout,aMode); + } + private void init(NetworkConfigurator aNetworkConfigurator,int aConnectTimout, Mode aMode) throws JxtaException, InterruptedException, P2pProxyException, IOException, URISyntaxException, CertificateException { + // connect to rdv + if (mProperties.getProperty(ADV_DISCOVERY_TIMEOUT) != null) { + ADV_DISCOVERY_TIMEOUT_INT = Integer.parseInt(mProperties.getProperty(ADV_DISCOVERY_TIMEOUT)); + } + NetPeerGroupFactory lFactory = new NetPeerGroupFactory((ConfigParams) aNetworkConfigurator.getPlatformConfig(),aNetworkConfigurator.getHome().toURI()); + mNetworkPeerGroup = lFactory.getInterface(); + + // The following step is required and only need to be done once, + // without this step the AdvertisementFactory has no means of + // associating an advertisement name space with the proper obect + // in this cast the AdvertisementTutorial + AdvertisementFactory.registerAdvertisementInstance(P2pUserProfileAdvertisement.getAdvertisementType(),new P2pUserProfileAdvertisement.Instantiator()); + + + mRendezVousService = mNetworkPeerGroup.getRendezVousService(); + mLog.info("Node PeerID ["+mNetworkPeerGroup.getPeerID()+"]"); + if ( aMode == Mode.edge && isConnectedToRendezVous(aConnectTimout) == false) { + throw new P2pProxyException("Cannot connect to rdv in the last "+aConnectTimout+" ms"); + } + mLog.info("jxta info name ["+mNetworkPeerGroup+"] mode ["+aMode+"] "); + + } + public PeerGroup getPeerGroup() { + return mNetworkPeerGroup; + } + + public PipeAdvertisement createPipeAdvertisement(String aPipePropertyName,String aPipeName) throws IOException { + PipeID lpipeID = null; + if (mProperties.getProperty(aPipePropertyName) == null) { + lpipeID = IDFactory.newPipeID(PeerGroupID.defaultNetPeerGroupID); + mProperties.setProperty(aPipePropertyName, lpipeID.toURI().toString()); + + } else { + lpipeID = (PipeID) ID.create(URI.create(mProperties.getProperty(aPipePropertyName))); + } + //create advertisement + PipeAdvertisement lAdvertisement = (PipeAdvertisement)AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType()); + lAdvertisement.setPipeID(lpipeID); + lAdvertisement.setType(PipeService.UnicastType); + lAdvertisement.setName(aPipeName); + mLog.debug("aPipePropertyName pipe:"+lAdvertisement); + return lAdvertisement; + } + + public InputPipe createPipe(PipeAdvertisement aPipeAdvertisement,PipeMsgListener aListener) throws IOException { + //create pipe + return mNetworkPeerGroup.getPipeService().createInputPipe(aPipeAdvertisement, aListener); + } + /** + * @param aPipePropertyName name use to save/load this pipe ID in the configuration file + * @param aPipeName pipe name + * @return + * @throws IOException + */ + public InputPipe createPipe(String aPipePropertyName,String aPipeName,PipeMsgListener aListener) throws IOException { + return createPipe(createPipeAdvertisement(aPipePropertyName,aPipeName),aListener); + } + public Advertisement getAdvertisement(String aPeerId, String anAdvertisementName,boolean isTryFromLocal) throws InterruptedException, IOException, P2pProxyAdvertisementNotFoundException { + return getAdvertisementList(aPeerId, anAdvertisementName,isTryFromLocal).get(0); + } + + /** + * seach advervitisement indexed by attribute "Name" + * @param aPeerId + * @param anAdvertisementName + * @param isTryFromLocal + * @return + * @throws InterruptedException + * @throws IOException + * @throws P2pProxyAdvertisementNotFoundException + */ + public List getAdvertisementList(String aPeerId, String anAdvertisementName,boolean isTryFromLocal) throws InterruptedException, IOException, P2pProxyAdvertisementNotFoundException { + return getAdvertisementList(aPeerId, "Name",anAdvertisementName, isTryFromLocal); + } + + public List getAdvertisementList(String aPeerId, String anAttributeName,String anAttributeValue, boolean isTryFromLocal) throws InterruptedException, IOException, P2pProxyAdvertisementNotFoundException { + DiscoveryService lDiscoveryService = getPeerGroup().getDiscoveryService(); + final Semaphore lSemaphore = new Semaphore(0); + final List lReturnList = new ArrayList(); + DiscoveryListener lDiscoveryListener = new DiscoveryListener() { + + public void discoveryEvent(DiscoveryEvent event) { + DiscoveryResponseMsg lRes = event.getResponse(); + enumeration2List(lRes.getAdvertisements(), lReturnList); + lSemaphore.release(); + } + + }; + if (isTryFromLocal == true) { + mLog.info("looking for advertisement indexing with ["+ anAttributeName+"="+anAttributeValue+"]"); + Enumeration lEnumeration = lDiscoveryService.getLocalAdvertisements(DiscoveryService.ADV, anAttributeName,anAttributeValue); + enumeration2List(lEnumeration, lReturnList); + } + if (lReturnList.isEmpty() == true) { + mLog.info("no advertisement found in local, trying remote..."); + lDiscoveryService.getRemoteAdvertisements(aPeerId, DiscoveryService.ADV, anAttributeName,anAttributeValue, 10,lDiscoveryListener); + if (lSemaphore.tryAcquire(ADV_DISCOVERY_TIMEOUT_INT,TimeUnit.MILLISECONDS) == false) { + throw new P2pProxyAdvertisementNotFoundException( anAttributeName+"="+anAttributeValue+ " not found"); + } + lSemaphore.release(); + } + if (mLog.isInfoEnabled() && mLog.isDebugEnabled() == false) mLog.info(lReturnList.get(0).toString()); + for (Advertisement lAdvertisement :lReturnList) { + mLog.debug(lAdvertisement.toString()); + } + return lReturnList; + } + public JxtaSocket openSocket(String aPeerId, String anAdvertisementName,int aSocketTimout,boolean isTryFromLocal) throws InterruptedException, P2pProxyException, IOException { + List lModuleSpecAdvertisementList; + lModuleSpecAdvertisementList = (List) getAdvertisementList(aPeerId, anAdvertisementName, isTryFromLocal); + // reset just in case + JxtaSocket lJxtaSocket = null; + for (int i=0; i < lModuleSpecAdvertisementList.size(); i++) { + try { + lJxtaSocket = new JxtaSocket(getPeerGroup(), null, lModuleSpecAdvertisementList.get(i).getPipeAdvertisement(), aSocketTimout, true); + // ok, socket connected :-) + mLog.info("socket ["+lJxtaSocket+"] connected"); + break; + }catch (IOException e) { + mLog.warn("cannot open socket, for index ["+i+"] try next from ["+lModuleSpecAdvertisementList.size()+"]", e); + mLog.debug("bad adv "+lModuleSpecAdvertisementList.get(i).getPipeAdvertisement().toString()); + } + } + if (lJxtaSocket == null) { + throw new P2pProxyException("Cannot start peer info service because cannot bind jxta socket"); + } else { + return lJxtaSocket; + } + +} + /** + * check if connected to an rdv for aTimeout + * @param aTimeout + * @return true if connected else false + * @throws InterruptedException + */ + public boolean isConnectedToRendezVous(long aTimeout) throws InterruptedException{ + long lStartTime = System.currentTimeMillis(); + boolean lExit = false; + while(lExit == false) { + if (mRendezVousService.isConnectedToRendezVous() ) { + ID lRdvPeerId = (ID)getPeerGroup().getRendezVousService().getConnectedRendezVous().nextElement(); + mLog.info("Connected to rdv ["+lRdvPeerId+"]"); + lExit=true; + } else { + mLog.info("waiting to rdv connection"); + Thread.sleep(500); + } + if (System.currentTimeMillis() - lStartTime > aTimeout) { + return false; + } + } + return true; + } + public void stop() { + mNetworkPeerGroup.stopApp(); + //mNetworkPeerGroup.unref(); + } + private List enumeration2List(Enumeration lEnumeration,List lList) { + if (lList == null) { + lList = new ArrayList(); + } + while (lEnumeration.hasMoreElements()) { + lList.add((Advertisement) lEnumeration.nextElement()) ; + } + return lList; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/MessageDispatcher.java b/p2pproxy/src/org/linphone/p2pproxy/core/MessageDispatcher.java new file mode 100644 index 000000000..da02655d7 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/MessageDispatcher.java @@ -0,0 +1,53 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +MessageDispatcher.java + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.log4j.Logger; + +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; + +/** + * + * @author jehan + * + */ +public class MessageDispatcher implements PipeMsgListener { + private final static Logger mLog = Logger.getLogger(MessageDispatcher.class); + + private List mPipeMsgListenerList = Collections.synchronizedList(new ArrayList()); + + public void pipeMsgEvent(PipeMsgEvent event) { + synchronized (this) { + mLog.debug("receiving event with message ["+event.getMessage()+"] propagating to ["+mPipeMsgListenerList.size()+"]"); + for (PipeMsgListener lPipeMsgListener:mPipeMsgListenerList) { + lPipeMsgListener.pipeMsgEvent(event); + } + } + } + synchronized void addPipeMsgListener(PipeMsgListener aPipeMsgListener) { + mPipeMsgListenerList.add(aPipeMsgListener); + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/NetworkResources.java b/p2pproxy/src/org/linphone/p2pproxy/core/NetworkResources.java new file mode 100644 index 000000000..b9588df86 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/NetworkResources.java @@ -0,0 +1,91 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +NetworkResources.java -- connection to a jxta network. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import java.io.IOException; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.core.media.jxtaudpproxy.RtpSession; +import org.linphone.p2pproxy.core.media.jxtaudpproxy.RtpSessionImpl; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.pipe.InputPipe; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeMsgListener; + +/** + * @author jehan + * + */ +public class NetworkResources { + public enum State {idle,offering,answering,ready} + private static String PIPE_ID="org.linphone.p2pproxy.bidi-pipe.id"; + private final InputPipe mInputPipe; + private MessageDispatcher mMessageDispatcher = new MessageDispatcher(); + private Map mRtpSessionTab = new HashMap(); + private final JxtaNetworkManager mJxtaNetworkManager; + private final static Logger mLog = Logger.getLogger(NetworkResources.class); + private State mState = State.idle; + NetworkResources(String aUserName, JxtaNetworkManager aJxtaNetworkManager) throws IOException { + mJxtaNetworkManager = aJxtaNetworkManager; + mInputPipe = mJxtaNetworkManager.createPipe(PIPE_ID+"-"+aUserName, aUserName, mMessageDispatcher); + } + public void release(){ + ; + } + public void putRtpSession(String key,RtpSessionImpl value) { + mRtpSessionTab.put(key, value); + addPipeMsgListener(value); + } + public RtpSessionImpl getRtpSession(String key) { + return mRtpSessionTab.get(key); + } + public boolean hasRtpSession(String key) { + return mRtpSessionTab.containsKey(key); + } + public void addPipeMsgListener(PipeMsgListener aPipeMsgListener) { + mMessageDispatcher.addPipeMsgListener( aPipeMsgListener); + } + public void publish(long anExpiration) throws IOException { + DiscoveryService lDiscoveryService = mJxtaNetworkManager.getPeerGroup().getDiscoveryService(); + + if (anExpiration > 0) { + //publish sip pipe + lDiscoveryService.publish(mInputPipe.getAdvertisement(), anExpiration, anExpiration); + } else { + //first flush in any cases + lDiscoveryService.flushAdvertisement(mInputPipe.getAdvertisement()); + mInputPipe.close(); + } + + mLog.info("adv ["+mInputPipe.getAdvertisement().getName()+"] published expire ["+anExpiration+"]"); + } + + public State getState() { + return mState; + } + public void setState(State state) { + mState = state; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAccountManagement.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAccountManagement.java new file mode 100644 index 000000000..117fac451 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAccountManagement.java @@ -0,0 +1,120 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyAccountManagement.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.io.IOException; +import java.util.List; + +import net.jxta.discovery.DiscoveryService; +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyUserNotFoundException; + +import org.linphone.p2pproxy.api.P2pProxyUserAlreadyExistException; + +public class P2pProxyAccountManagement implements ServiceProvider, P2pProxyAccountManagementMBean { + private final static Logger mLog = Logger.getLogger(P2pProxyAccountManagement.class); + protected final JxtaNetworkManager mJxtaNetworkManager; + + public P2pProxyAccountManagement() { + mJxtaNetworkManager = null; + } + /** + * @param jxtaNetworkManager + */ + public P2pProxyAccountManagement(final JxtaNetworkManager jxtaNetworkManager) { + super(); + mJxtaNetworkManager = jxtaNetworkManager; + } + + public void start(long aTimeOut) throws P2pProxyException { + mLog.info("P2pProxyAccountManagementMBean started"); + } + + public void stop() { + mLog.info("P2pProxyAccountManagementMBean stopped"); + } + + public void createAccount(String aUserName) throws P2pProxyException, P2pProxyUserAlreadyExistException { + // 1 check if already exist + if (isValidAccount(aUserName) == false) { + + // 2 creates and remote publish + P2pUserProfileAdvertisement lP2pUserProfileAdvertisement = (P2pUserProfileAdvertisement) AdvertisementFactory.newAdvertisement(P2pUserProfileAdvertisement.getAdvertisementType()); + + lP2pUserProfileAdvertisement.setID(IDFactory.newCodatID(mJxtaNetworkManager.getPeerGroup().getPeerGroupID())); + lP2pUserProfileAdvertisement.setUserName(aUserName); + try { + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().publish(lP2pUserProfileAdvertisement,DiscoveryService.INFINITE_LIFETIME,DiscoveryService.DEFAULT_EXPIRATION); + } catch (IOException e1) { + throw new P2pProxyException(e1); + } + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().remotePublish(lP2pUserProfileAdvertisement, DiscoveryService.NO_EXPIRATION); + mLog.debug("publishing P2pUserProfileAdvertisement :"+lP2pUserProfileAdvertisement); + } else { + throw new P2pProxyUserAlreadyExistException(aUserName); + } + + } + + public void deleteAccount(String aUserName) throws P2pProxyException, P2pProxyUserNotFoundException { + // 1 check if already exist + try { + List lAdvertisements = mJxtaNetworkManager.getAdvertisementList(null, P2pUserProfileAdvertisement.USER_NAME_TAG, aUserName, true); + if (lAdvertisements.isEmpty()) throw new P2pProxyUserNotFoundException (aUserName +" not found"); + + // 2 local and remote publish to 0 + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().flushAdvertisement(lAdvertisements.get(0)); + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().remotePublish(lAdvertisements.get(0), 0); + + } catch (P2pProxyAdvertisementNotFoundException e) { + throw e; + } catch (InterruptedException e) { + throw new P2pProxyException(e); + } catch (IOException e) { + throw new P2pProxyException(e); + } + + } + + public boolean isValidAccount(String aUserName) throws P2pProxyException { + boolean lStatus = false; + try { + if (mJxtaNetworkManager.getAdvertisementList(null, P2pUserProfileAdvertisement.USER_NAME_TAG, aUserName, true).size() >0 ) { + lStatus = true;; + } + } catch (P2pProxyAdvertisementNotFoundException e) { + lStatus = false; + }catch (Exception e) { + mLog.error("cannot check acount",e); + } + return lStatus; + } + + + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAccountManagementMBean.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAccountManagementMBean.java new file mode 100644 index 000000000..a36dc9847 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAccountManagementMBean.java @@ -0,0 +1,49 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyAccountManagementMBean.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyUserAlreadyExistException; + +public interface P2pProxyAccountManagementMBean { + /** + * a create an account with the given name (must be unique) + * @param aUserName + * @exception P2pProxyUserAlreadyExistException + * @throws P2pProxyException + */ + public void createAccount(String aUserName) throws P2pProxyUserAlreadyExistException, P2pProxyException; + /** + * check if a user name has been already created + * @param aUserName + * @return true if the account has been successfully created + * @exception P2pProxyUserAlreadyExistException + * @throws P2pProxyException + */ + public boolean isValidAccount(String aUserName) throws P2pProxyException; + + /** + * delete an account with the given name (must be unique) + * @param aUserName + * @exception P2pProxyUserAlreadyExistException + */ + public void deleteAccount(String aUserName) throws P2pProxyException; + } diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAdvertisementNotFoundException.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAdvertisementNotFoundException.java new file mode 100644 index 000000000..d35cf3ffb --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyAdvertisementNotFoundException.java @@ -0,0 +1,57 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyAdvertisementNotFoundException.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import org.linphone.p2pproxy.api.P2pProxyException; + +@SuppressWarnings("serial") +public class P2pProxyAdvertisementNotFoundException extends P2pProxyException { + + /** + * + */ + public P2pProxyAdvertisementNotFoundException() { + super(); + } + + /** + * @param arg0 + * @param arg1 + */ + public P2pProxyAdvertisementNotFoundException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + /** + * @param arg0 + */ + public P2pProxyAdvertisementNotFoundException(String arg0) { + super(arg0); + } + + /** + * @param arg0 + */ + public P2pProxyAdvertisementNotFoundException(Throwable arg0) { + super(arg0); + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyInstanceImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyInstanceImpl.java new file mode 100644 index 000000000..dc37431a3 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyInstanceImpl.java @@ -0,0 +1,273 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyInstanceImpl.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.io.File; +import java.net.InetAddress; +import java.net.URI; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.Properties; + +import net.jxta.id.IDFactory; +import net.jxta.peergroup.PeerGroupID; +import net.jxta.platform.NetworkConfigurator; +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.api.P2pProxyManagement; +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe; +import org.linphone.p2pproxy.api.P2pProxyRtpRelayManagement; +import org.zoolu.net.SocketAddress; +import org.zoolu.sip.provider.SipProvider; + + +public class P2pProxyInstanceImpl implements P2pProxyInstance { + private final static Logger mLog = Logger.getLogger(P2pProxyInstance.class); + private static int BASE_PROXY_SIP_PORT = 6000; + private static int BASE_CLIENT_SIP_PORT = 8000; + int mIndex=0; + private Mode mMode = Mode.edge ; + boolean isStarted = false; + boolean isRevoked = false; + JxtaNetworkManager mJxtaNetworkManager; + SipProxyRegistrar mSipProxy; + SipProvider mProviderForSipClient; + String mSipClientName; + String mPrivateHostAddress; + String mPublicHostAddress ; + private ServiceProvider mServiceProvider; + private P2pProxyManagement mP2pProxyManagement; + private P2pProxyAccountManagementMBean mP2pProxyAccountManagement; + private int mRelayCapacity=4; + private Configurator mConfigurator; + private Properties startupProperties = new Properties(); + public P2pProxyInstanceImpl () { + + } + /* (non-Javadoc) + * @see org.linphone.p2pproxy.P2pProxyInstance#getIndex() + */ + public int getIndex() { + return mIndex; + } + /* (non-Javadoc) + * @see org.linphone.p2pproxy.P2pProxyInstance#setIndex(int) + */ + public void setIndex(int index) { + mIndex = index; + } + /* (non-Javadoc) + * @see org.linphone.p2pproxy.P2pProxyInstance#start() + */ + public void start() throws Exception{ + Thread lThread = new Thread() { + public void run() { + try { + File lJxtaDirectory = new File ("P2pNetwork-"+getMode()+"-"+mIndex); + if (lJxtaDirectory.exists() == false) lJxtaDirectory.mkdir(); + mConfigurator = new Configurator(new File (lJxtaDirectory.getAbsolutePath()+"/prop.xml")); + mConfigurator.serProperties(P2pProxyInstanceImpl.this.startupProperties); + mConfigurator.setProperty(JxtaNetworkManager.RELAY_CAPACITY, String.valueOf(mRelayCapacity)); + // setup jxta network + NetworkConfigurator lNetworkConfigurator; + // set mode + lNetworkConfigurator = new NetworkConfigurator(JxtaNetworkManager.EDGE_MODE,lJxtaDirectory.toURI()); + lNetworkConfigurator.setHome(lJxtaDirectory); + if (!lNetworkConfigurator.exists()) { + lNetworkConfigurator.setPeerID(IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID)); + lNetworkConfigurator.setDescription("p2p proxy instance"); + lNetworkConfigurator.save(); + } else { + lNetworkConfigurator.load(); + } + // set sedding host + lNetworkConfigurator.addSeedRendezvous(new URI("http://"+getPublicHostAddress()+":"+BASE_HTTP)); + lNetworkConfigurator.addSeedRelay(new URI("http://"+getPublicHostAddress()+":"+BASE_HTTP)); + // set listening ports + lNetworkConfigurator.setHttpInterfaceAddress(getPrivateHostAddress()); + lNetworkConfigurator.setHttpPort(BASE_HTTP + mIndex); + lNetworkConfigurator.setTcpPort(BASE_TCP + mIndex); + + switch (mMode) { + case edge: + startEdge(mConfigurator,lNetworkConfigurator); + break; + case relay: + startRelay(mConfigurator,lNetworkConfigurator,false); + break; + case seeding_server: + startRelay(mConfigurator,lNetworkConfigurator,true); + break; + case auto: + //1 start edge + startEdge(mConfigurator,lNetworkConfigurator); + // check if peer mode required + if (mP2pProxyManagement.shouldIBehaveAsAnRdv() == true) { + String lPublicHttpAddress = mP2pProxyManagement.getPublicIpAddress().getHostAddress(); + + lNetworkConfigurator.setHttpPublicAddress(lPublicHttpAddress+":"+(BASE_HTTP + mIndex), true); + mServiceProvider.stop(); + mJxtaNetworkManager.stop(); + + startRelay(mConfigurator,lNetworkConfigurator,false); + // become relay + mMode = Mode.relay; + } else { + mMode = Mode.edge; + } + break; + default: + throw new Exception("unsupported mode ["+mMode+"]"); + } + mConfigurator.setProperty(SipProxyRegistrar.REGISTRAR_PORT,Integer.toString(BASE_PROXY_SIP_PORT+mIndex)); + // setup sip proxy + mP2pProxyAccountManagement = new P2pProxyAccountManagement(mJxtaNetworkManager); + mSipProxy = new SipProxyRegistrar(mConfigurator,mJxtaNetworkManager,mP2pProxyAccountManagement,mP2pProxyManagement); + // setup sip client + mProviderForSipClient = new SipProvider(getPrivateHostAddress(),BASE_CLIENT_SIP_PORT+mIndex); + mProviderForSipClient.setOutboundProxy(new SocketAddress(getPrivateHostAddress(),BASE_PROXY_SIP_PORT+mIndex)); + mSipClientName="sip:user-"+mIndex+"@p2pproxy.linphone.org"; + + + mLog.info(P2pProxyInstanceImpl.this+" started "); + isStarted = true; + } catch (Exception e) { + mLog.error(P2pProxyInstanceImpl.this+" cannot be started",e); + isRevoked = true; + } + } + }; + lThread.start(); + } + public boolean isStarted() throws P2pProxyException{ + if (isRevoked == true) { + throw new P2pProxyException("cannot start " + this.toString() ); + } else { + return isStarted; + } + } + public SipProvider getSipClientProvider() { + return mProviderForSipClient; + } + + public String toString() { + return "p2p instance ["+mIndex+"] mode ["+mMode+"] sip port ["+BASE_PROXY_SIP_PORT+mIndex+"]"; + } + public String getSipClientName() { + return mSipClientName; + } + public void stop() throws Exception { + mProviderForSipClient.halt(); + //mSipProxy.halt(); + mJxtaNetworkManager.stop(); + } + public int getNumberOfconnectedPeers() { + Enumeration lConnectedPeers = mJxtaNetworkManager.getPeerGroup().getRendezVousService().getConnectedPeers(); + int lResult = 0; + while (lConnectedPeers.hasMoreElements()) { + lResult++; + lConnectedPeers.nextElement(); + } + return lResult; + } + public Object getOpaqueNetworkManager() { + return mJxtaNetworkManager; + } + + /** + * @return Returns the mHostAddress. + * @throws UnknownHostException + */ + public String getPrivateHostAddress() throws UnknownHostException { + if (mPrivateHostAddress == null) { + mPrivateHostAddress = InetAddress.getLocalHost().getHostAddress(); + } + return mPrivateHostAddress; + } + public String getPublicHostAddress() throws UnknownHostException { + if (mPublicHostAddress == null) { + mPublicHostAddress = InetAddress.getLocalHost().getHostAddress(); + } + return mPublicHostAddress; + } + + public void setPrivateHostAdress(String anAddress) { + mPrivateHostAddress = anAddress; + } + public void setPublicHostAdress(String anAddress) { + mPublicHostAddress = anAddress; + } + public P2pProxyNetworkProbe getManager() { + return (P2pProxyNetworkProbe)mServiceProvider; + } + public Mode getMode() { + return mMode; + } + public void setMode(Mode aMode) { + mMode = aMode; + } + private void startEdge(Configurator aProperties,NetworkConfigurator aNetworkConfigurator) throws Exception{ + // setup jxta + aNetworkConfigurator.setMode(JxtaNetworkManager.EDGE_MODE); + aNetworkConfigurator.setHttpEnabled(true); + aNetworkConfigurator.setHttpOutgoing(true); + + mJxtaNetworkManager = new JxtaNetworkManager(aProperties,aNetworkConfigurator,60000,JxtaNetworkManager.Mode.edge); + mServiceProvider = new EdgePeerServiceManager(aProperties, mJxtaNetworkManager); + mP2pProxyManagement = (P2pProxyManagement) mServiceProvider; + mServiceProvider.start(3000L); + } + + private void startRelay(Configurator aProperties,NetworkConfigurator aNetworkConfigurator,boolean isSeeding) throws Exception{ + // setup jxta + aNetworkConfigurator.setMode(JxtaNetworkManager.SUPER_PEER_MODE); + if (isSeeding == true) { + mJxtaNetworkManager = new JxtaNetworkManager(aProperties,aNetworkConfigurator,60000,JxtaNetworkManager.Mode.seeding_server); + mServiceProvider = new SeedingPeerServiceManager(aProperties, mJxtaNetworkManager,false); + mP2pProxyManagement = null; + } else { + mJxtaNetworkManager = new JxtaNetworkManager(aProperties,aNetworkConfigurator,60000,JxtaNetworkManager.Mode.relay); + mServiceProvider = new SuperPeerServiceManager(aProperties, mJxtaNetworkManager); + mP2pProxyManagement = (P2pProxyManagement) mServiceProvider; + } + mServiceProvider.start(3000L); + } + public void setRelayCapacity(int aCapacity) { + mRelayCapacity = aCapacity; + + } + public void setProperty(String key, String value) throws P2pProxyException { + if (mConfigurator == null) { + startupProperties.setProperty(key, value); + } else { + throw new P2pProxyException(" started"); + } + } + public int getAdvertisementDiscoveryTimeout() { + return JxtaNetworkManager.ADV_DISCOVERY_TIMEOUT_INT; + } + public P2pProxyRtpRelayManagement getRtpRelayManager() { + return (P2pProxyRtpRelayManagement)mServiceProvider; + } +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java new file mode 100644 index 000000000..ba4c10965 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java @@ -0,0 +1,353 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pProxyMain.java - main class. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.net.URI; +import java.net.URL; +import java.util.InvalidPropertiesFormatException; +import java.util.Properties; + +import javax.management.ObjectName; + +import net.jxta.exception.JxtaException; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyManagement; +import org.linphone.p2pproxy.core.media.rtprelay.RtpRelayService; +import org.zoolu.sip.provider.SipStack; + +public class P2pProxyMain implements P2pProxyMainMBean { + private final static Logger mLog = Logger.getLogger(P2pProxyMain.class); + private static JxtaNetworkManager mJxtaNetworkManager; + private static ServiceProvider mServiceProvider; + private static P2pProxyManagement mP2pProxyManagement; + private static SipProxyRegistrar mSipAndPipeListener; + private static P2pProxyAccountManagementMBean mP2pProxyAccountManagement; + public final static String ACCOUNT_MGR_MBEAN_NAME="org.linphone.p2proxy:type=account-manager"; + public final static String PROXY_REG_MBEAN_NAME="org.linphone.p2proxy:type=proxy-registrar"; + public final static String MAIN_MBEAN_NAME="org.linphone.p2proxy:type=main"; + private static P2pProxyMain mP2pProxyMain = new P2pProxyMain(); + private static Configurator mConfigurator; + static { +// System.setProperty("com.sun.management.jmxremote", "true"); +// System.setProperty("com.sun.management.jmxremote.port", "6789"); +// System.setProperty("com.sun.management.jmxremote.authenticate", "false"); +// System.setProperty("com.sun.management.jmxremote.ssl", "false"); + } + + /** + * @param args + * @throws P2pProxyException + * @throws InterruptedException + * @throws JxtaException + * @throws IOException + * @throws FileNotFoundException + * @throws InvalidPropertiesFormatException + */ + public static void main(String[] args) { + try { + String lconfigHomeDir=System.getProperty("user.home")+"/.p2pproxy"; + int lsipPort=5040; + JxtaNetworkManager.Mode lMode = JxtaNetworkManager.Mode.auto; + boolean lEnableHttp = false; + // setup logging + + // get config dire first + for (int i=0; i < args.length; i=i+2) { + String argument = args[i]; + if (argument.equals("-jxta")) { + lconfigHomeDir = args[i + 1]; + File lFile = new File(lconfigHomeDir); + if (lFile.exists() == false) lFile.mkdir(); + + System.out.println("lconfigHomeDir detected[" + lconfigHomeDir + "]"); + } + } + System.setProperty("org.linphone.p2pproxy.home", lconfigHomeDir); + + + System.setProperty("net.jxta.logging.Logging", "FINEST"); + System.setProperty("net.jxta.level", "FINEST"); + + mP2pProxyMain.loadTraceConfigFile(); + + + + mLog.info("p2pproxy initilizing..."); + + File lPropertyFile = new File(lconfigHomeDir+"/p2pproxy.properties.xml"); + mConfigurator = new Configurator(lPropertyFile); + try { + ObjectName lObjectName = new ObjectName(MAIN_MBEAN_NAME); + ManagementFactory.getPlatformMBeanServer().registerMBean(mP2pProxyMain,lObjectName); + + + } catch (Exception e) { + mLog.warn("cannot register MBean",e); + } + String lSocksHost = null; + String lSocksPort = null; + // if (args.length <= 0) { +// usage(); +// System.exit(1); +// } + // get other params + for (int i=0; i < args.length; i=i+2) { + String argument = args[i]; + if (argument.equals("-jxta")) { + lconfigHomeDir = args[i + 1]; + //nop + } else if (argument.equals("-sip")) { + lsipPort = Integer.parseInt(args[i + 1]); + System.out.println("sipPort detected[" + lsipPort + "]"); + mConfigurator.setProperty(SipProxyRegistrar.REGISTRAR_PORT, Integer.toString(lsipPort)); + } else if (argument.equals("-relay")) { + lMode = JxtaNetworkManager.Mode.relay; + mConfigurator.setProperty(JxtaNetworkManager.MODE, lMode.name()); + System.out.println("relay mode detected"); + i--; + } else if (argument.equals("-edge-only")) { + lMode = JxtaNetworkManager.Mode.edge; + mConfigurator.setProperty(JxtaNetworkManager.MODE, lMode.name()); + System.out.println("edge only mode detected"); + i--; + }else if (argument.equals("-seeding-server")) { + lMode = JxtaNetworkManager.Mode.seeding_server; + mConfigurator.setProperty(JxtaNetworkManager.MODE, lMode.name()); + System.out.println("seeding-server detected"); + i--; + } else if (argument.equals("-auto-config")) { + lMode = JxtaNetworkManager.Mode.auto; + mConfigurator.setProperty(JxtaNetworkManager.MODE, lMode.name()); + System.out.println("auto-mode mode detected"); + i--; + } else if (argument.equals("-seeding-rdv")) { + mConfigurator.setProperty(JxtaNetworkManager.SEEDING_RDV, args[i + 1]); + System.out.println("seeding rdv detected[" + args[i + 1] + "]"); + } + else if (argument.equals("-seeding-relay")) { + mConfigurator.setProperty(JxtaNetworkManager.SEEDING_RELAY, args[i + 1]); + System.out.println("seeding relay detected[" + args[i + 1] + "]"); + } + else if (argument.equals("-public-address")) { + mConfigurator.setProperty(JxtaNetworkManager.HTTP_LISTENING_PUBLIC_ADDRESS,args[i + 1]+":9700"); + mConfigurator.setProperty(JxtaNetworkManager.TCP_LISTENING_PUBLIC_ADDRESS,args[i + 1]+":9701"); + mConfigurator.setProperty(RtpRelayService.AUDIO_VIDEO_PUBLIC_URI,"udp://"+args[i + 1]+":16000"); + System.out.println("public address detected[" + args[i + 1] + "]"); + } + else if (argument.equals("-socks-url")) { + try { + URI lSocksUrl = new URI(args[i + 1]); + lSocksHost = lSocksUrl.getHost(); + lSocksPort = Integer.toString(lSocksUrl.getPort()); + }catch (Exception e) { + mLog.warn("enable to get socks proxy from env",e); + } + System.out.println("socks serveur detected[" + args[i + 1] + "]"); + } else if (argument.equals("-enable-http-client")) { + lEnableHttp = true; + mConfigurator.setProperty(JxtaNetworkManager.ENABLE_HTTP_CLIENT, "true"); + System.out.println("enable-http mode detected"); + i--; + } + else + { + System.out.println("Invalid option: " + args[i]); + usage(); + System.exit(1); + } + } + String lProxyUrlString = null; + String lProxyHost = null; + String lProxyPort = null; + //configure http proxy + if ((lProxyUrlString = System.getenv("http_proxy")) != null) { + //get from env + try { + URL lProxyUrl = new URL(lProxyUrlString); + lProxyHost = lProxyUrl.getHost(); + lProxyPort = Integer.toString(lProxyUrl.getPort()); + }catch (Exception e) { + mLog.warn("enable do get http proxy from env",e); + } + } + //check from config + if (lProxyHost != null || (lProxyHost = mConfigurator.getProperty("http.proxyHost")) != null) { + System.setProperty("http.proxyHost", lProxyHost); + } + if (lProxyPort != null || (lProxyPort = mConfigurator.getProperty("http.proxyPort")) != null) { + System.setProperty("http.proxyPort", lProxyPort); + } + //configure socks proxy + if ((lProxyUrlString = System.getenv("socks_proxy")) != null) { + //get from env + + } + //check from config + if (lSocksHost != null || (lSocksHost = mConfigurator.getProperty("socksProxyHost")) != null) { + System.setProperty("socksProxyHost", lSocksHost); + } + if (lSocksPort != null || (lSocksPort = mConfigurator.getProperty("socksProxyPort")) != null) { + System.setProperty("socksProxyPort", lSocksPort); + } + + //check from env + + File lJxtaDirectory = new File (lconfigHomeDir); + if (lJxtaDirectory.exists() == false) lJxtaDirectory.mkdir(); + + + switch (lMode) { + case edge: + startEdge(mConfigurator,lJxtaDirectory); + break; + case relay: + startRelay(mConfigurator,lJxtaDirectory); + break; + case seeding_server: + startSeeding(mConfigurator,lJxtaDirectory); + break; + case auto: + //1 start edge + startEdge(mConfigurator,lJxtaDirectory); + // check if peer mode required + if (mP2pProxyManagement.shouldIBehaveAsAnRdv() == true) { + String lPublicAddress = mP2pProxyManagement.getPublicIpAddress().getHostAddress(); + mConfigurator.setProperty(JxtaNetworkManager.HTTP_LISTENING_PUBLIC_ADDRESS, lPublicAddress+":9700"); + mConfigurator.setProperty(JxtaNetworkManager.TCP_LISTENING_PUBLIC_ADDRESS, lPublicAddress+":9701"); + mServiceProvider.stop(); + mJxtaNetworkManager.stop(); + startRelay(mConfigurator,lJxtaDirectory); + mJxtaNetworkManager.getPeerGroup().getRendezVousService().setAutoStart(true); + } + break; + default: + mLog.fatal("unsupported mode ["+lMode+"]"); + System.exit(1); + + } + + //setup account manager + mP2pProxyAccountManagement = new P2pProxyAccountManagement(mJxtaNetworkManager); + // setup sip provider + SipStack.log_path = lconfigHomeDir+"/logs"; + mSipAndPipeListener = new SipProxyRegistrar(mConfigurator,mJxtaNetworkManager,mP2pProxyAccountManagement,mP2pProxyManagement); + //set management + try { + ObjectName lObjectName = new ObjectName(ACCOUNT_MGR_MBEAN_NAME); + ManagementFactory.getPlatformMBeanServer().registerMBean(mP2pProxyAccountManagement,lObjectName); + + lObjectName = new ObjectName(PROXY_REG_MBEAN_NAME); + ManagementFactory.getPlatformMBeanServer().registerMBean(mSipAndPipeListener,lObjectName); + + } catch (Exception e) { + mLog.warn("cannot register MBean",e); + } + + + mLog.warn("p2pproxy initilized"); + + while (true) { + Thread.sleep(1000); + } + } catch (Exception e) { + mLog.fatal("error",e); + System.exit(1); + } + } + private static void startEdge(Configurator aProperties,File aConfigDir) throws Exception{ + // setup jxta + mJxtaNetworkManager = new JxtaNetworkManager(aProperties,aConfigDir); + mServiceProvider = new EdgePeerServiceManager(aProperties, mJxtaNetworkManager); + mP2pProxyManagement = (P2pProxyManagement) mServiceProvider; + mServiceProvider.start(3000L); + } + + private static void startRelay(Configurator aProperties,File aConfigDir) throws Exception{ + // setup jxta + mJxtaNetworkManager = new JxtaNetworkManager(aProperties,aConfigDir); + mServiceProvider = new SuperPeerServiceManager(aProperties, mJxtaNetworkManager); + mP2pProxyManagement = (P2pProxyManagement) mServiceProvider; + mServiceProvider.start(3000L); + } + private static void startSeeding(Configurator aProperties,File aConfigDir) throws Exception{ + // setup jxta + mJxtaNetworkManager = new JxtaNetworkManager(aProperties,aConfigDir); + mServiceProvider = new SeedingPeerServiceManager(aProperties, mJxtaNetworkManager,true); + mP2pProxyManagement = null; + mServiceProvider.start(3000L); + } + private static void usage() { + System.out.println("p2pproxy"); + System.out.println("-jxta : directory where configuration/cache is located (including jxta cache.default is $HOME/.p2pproxy"); + System.out.println("-sip : udp proxy port, default 5060"); + System.out.println("-relay : super peer mode"); + System.out.println("-edge-only : edge mode"); + System.out.println("-seeding-server : seeding server mode"); + System.out.println("-auto-config : automatically choose edge or relay (default mode)"); + System.out.println("-seeding-rdv : list of boostrap rdv separated by | (ex tcp://127.0.0.1:9701|http://127.0.0.2:9700)"); + System.out.println("-seeding-relay : list of boostrap relay separated by |(ex tcp://127.0.0.1:9701|http://127.0.0.2:9700)"); + System.out.println("-public-address : ip as exported to peers (ex myPublicAddress.no-ip.org)"); + System.out.println("-socks-url : tcp://ip:port for socks server (ex tcp://socks.com:1080)"); + System.out.println("-enable-http-client : enable http transport for client (default = false)"); + } + public String getHttpProxy() { + return System.getProperty("http.proxyHost", "not-set")+":"+System.getProperty("http.proxyPort", "not-set"); + } + + public void setHttpProxy(String aProxyHost, String aProxyPort, String aUserName, String aPassword) { + System.setProperty("http.proxyHost",aProxyHost); + System.setProperty("http.proxyPort",aProxyPort); + + } +public String getSocksServer() { + return System.getProperty("socksProxyHost", "not-set")+":"+System.getProperty("socksProxyPort", "not-set"); +} +public void setSocksServer(String aSocksHost, String aSocksPort, String aUserName, String aPassword) { + System.setProperty("socksProxyHost",aSocksHost); + System.setProperty("socksProxyPort",aSocksPort); +} + +public void loadTraceConfigFile() throws P2pProxyException { + staticLoadTraceConfigFile(); + } +public static void staticLoadTraceConfigFile() throws P2pProxyException { + try { + PropertyConfigurator.configureAndWatch("log4j.properties"); + // read java.util.logging properties + Properties lLogginProperties = new Properties(); + lLogginProperties.load(new FileInputStream("log4j.properties")); + lLogginProperties.setProperty("java.util.logging.FileHandler.pattern",System.getProperty("org.linphone.p2pproxy.home")+"/logs/p2pproxy.log"); + lLogginProperties.store(new FileOutputStream("log4j.properties.tmp"), "tmp"); + System.setProperty("java.util.logging.config.file","log4j.properties.tmp"); + java.util.logging.LogManager.getLogManager().readConfiguration(); + } catch (Exception e) { + throw new P2pProxyException("enable to load traces",e); + } +} +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMainMBean.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMainMBean.java new file mode 100644 index 000000000..8f8d5c726 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMainMBean.java @@ -0,0 +1,35 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyMainMBean.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import org.linphone.p2pproxy.api.P2pProxyException; + +public interface P2pProxyMainMBean { + public void setHttpProxy(String aProxyHost,String aProxyPort,String aUserName,String aPassword); + public String getHttpProxy(); + public void setSocksServer(String aSocksHost,String aSocksPort,String aUserName,String aPassword); + public String getSocksServer(); + /** + * reload traces from file + * @throws P2pProxyException + */ + public void loadTraceConfigFile() throws P2pProxyException ; +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyManagementImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyManagementImpl.java new file mode 100644 index 000000000..a0ebedabb --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyManagementImpl.java @@ -0,0 +1,79 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pProxyManagementImpl.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyManagement; +import org.linphone.p2pproxy.core.media.rtprelay.MediaType; +import org.linphone.p2pproxy.core.media.rtprelay.RtpRelayServiceClient; +import org.linphone.p2pproxy.core.rdvautoconfig.PeerInfoServiceClient; + +public abstract class P2pProxyManagementImpl implements ServiceProvider,P2pProxyManagement { + protected final JxtaNetworkManager mJxtaNetworkManager; + protected final Configurator mConfigurator; + private final PeerInfoServiceClient mPeerInfoServiceClient; + private final RtpRelayServiceClient mRtpRelayServiceClient; + private final static Logger mLog = Logger.getLogger(P2pProxyManagementImpl.class); + + P2pProxyManagementImpl(Configurator aConfigurator, JxtaNetworkManager aJxtaNetworkManager) throws SocketException, UnknownHostException + { + mJxtaNetworkManager = aJxtaNetworkManager; + mConfigurator = aConfigurator; + mPeerInfoServiceClient = new PeerInfoServiceClient(aConfigurator, aJxtaNetworkManager); + mRtpRelayServiceClient = new RtpRelayServiceClient(aConfigurator, aJxtaNetworkManager); + } + + public void start(long aTimeout) throws P2pProxyException + { + mPeerInfoServiceClient.start(aTimeout); + mRtpRelayServiceClient.start(aTimeout); + + } + + public void stop() { + mPeerInfoServiceClient.stop(); + mRtpRelayServiceClient.stop(); + mLog.info("P2pProxyManagementImpl stopped"); + } + + public InetAddress getPublicIpAddress() + throws P2pProxyException + { + return mPeerInfoServiceClient.getPublicIpAddress(); + } + + public boolean probeSocket(InetSocketAddress aSocketAddress, Protocol aProtocol) throws P2pProxyException { + return mPeerInfoServiceClient.probeSocket(aSocketAddress, aProtocol); + } + + + public Map getAddresses() throws P2pProxyException { + return mRtpRelayServiceClient.getAddresses(); + } + + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pUserProfileAdvertisement.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pUserProfileAdvertisement.java new file mode 100644 index 000000000..beda4b18d --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pUserProfileAdvertisement.java @@ -0,0 +1,251 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pUserProfileAdvertisement.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + + +import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; + +import org.apache.log4j.Logger; + + + + +import net.jxta.document.Advertisement; +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.Attributable; +import net.jxta.document.Document; +import net.jxta.document.Element; +import net.jxta.document.ExtendableAdvertisement; +import net.jxta.document.MimeMediaType; +import net.jxta.document.StructuredDocument; +import net.jxta.document.StructuredDocumentFactory; +import net.jxta.document.TextElement; +import net.jxta.id.ID; +import net.jxta.id.IDFactory; + +/** + * derivated from jxta Advertisement tutorial + *
            + * <?xml version="1.0"?>
            + * <!DOCTYPE jxta:System>
            + * <jxta:System xmlns:jxta="http://jxta.org">
            + *   <id>id</id>
            + *   <user-name>endpoint user name</name>
            + * </jxta:System>
            + * 
            + */ +public class P2pUserProfileAdvertisement extends ExtendableAdvertisement implements Comparable, Cloneable, Serializable { + /** + * Instantiator + */ + public static class Instantiator implements AdvertisementFactory.Instantiator { + + /** + * Returns the identifying type of this Advertisement. + * + * @return String the type of advertisement + */ + public String getAdvertisementType() { + return P2pUserProfileAdvertisement.getAdvertisementType(); + } + + /** + * Constructs an instance of Advertisement matching the + * type specified by the advertisementType parameter. + * + * @return The instance of Advertisement or null if it + * could not be created. + */ + public Advertisement newInstance() { + return new P2pUserProfileAdvertisement(); + } + + /** + * Constructs an instance of Advertisement matching the + * type specified by the advertisementType parameter. + * + * @param root Specifies a portion of a StructuredDocument which will + * be converted into an Advertisement. + * @return The instance of Advertisement or null if it + * could not be created. + */ + public Advertisement newInstance(net.jxta.document.Element root) { + return new P2pUserProfileAdvertisement(root); + } + } + private ID mId ;; + private String mName; + public final static String USER_NAME_TAG = "user-name"; + private final static String mIdTag = "ID"; + private final static String[] mIndexs = {USER_NAME_TAG}; + private final static Logger mLog = Logger.getLogger(P2pUserProfileAdvertisement.class); + /** + * + */ + public P2pUserProfileAdvertisement(Element root) { + + TextElement doc = (TextElement) root; + + if (!getAdvertisementType().equals(doc.getName())) { + throw new IllegalArgumentException("Could not construct : " + getClass().getName() + "from doc containing a " + doc.getName()); + } + initialize(doc); + + } + public P2pUserProfileAdvertisement() { + + // TODO Auto-generated constructor stub + } + /* (non-Javadoc) + * @see net.jxta.document.ExtendableAdvertisement#getDocument(net.jxta.document.MimeMediaType) + */ + @Override + public Document getDocument(MimeMediaType asMimeType) { + + StructuredDocument adv = StructuredDocumentFactory.newStructuredDocument(asMimeType, + getAdvertisementType()); + if (adv instanceof Attributable) { + ((Attributable) adv).addAttribute("xmlns:jxta", "http://jxta.org"); + } + Element e; + e = adv.createElement(mIdTag, getID().toString()); + adv.appendChild(e); + e = adv.createElement(USER_NAME_TAG, getUserName().trim()); + adv.appendChild(e); + return adv; + } + + @Override + public ID getID() { + return mId; + } + + @Override + public String[] getIndexFields() { + return mIndexs; + } + public static String getAdvertisementType() { + return "jxta:p2p-proxy-user-profile"; + } + /* (non-Javadoc) + * @see net.jxta.document.Advertisement#toString() + */ + @Override + public String toString() { + // TODO Auto-generated method stub + return super.toString(); + } + public int compareTo(Object other) { + return getID().toString().compareTo(other.toString()); + } + /** + * Intialize a System advertisement from a portion of a structured document. + * + * @param root document root + */ + protected void initialize(Element root) { + if (!TextElement.class.isInstance(root)) { + throw new IllegalArgumentException(getClass().getName() + + " only supports TextElement"); + } + TextElement doc = (TextElement) root; + if (!doc.getName().equals(getAdvertisementType())) { + throw new IllegalArgumentException("Could not construct : " + + getClass().getName() + "from doc containing a " + + doc.getName()); + } + Enumeration elements = doc.getChildren(); + while (elements.hasMoreElements()) { + TextElement elem = (TextElement) elements.nextElement(); + if (!handleElement(elem)) { + mLog.warn("Unhandleded element \'" + elem.getName() + "\' in " + doc.getName()); + } + } + } + /** + * Process an individual element from the document. + * + * @param elem the element to be processed. + * @return true if the element was recognized, otherwise false. + */ + protected boolean handleElement(TextElement elem) { + if (elem.getName().equals(mIdTag)) { + try { + URI id = new URI(elem.getTextValue()); + setID(IDFactory.fromURI(id)); + } catch (URISyntaxException badID) { + throw new IllegalArgumentException("unknown ID format in advertisement: " + + elem.getTextValue()); + } + catch (ClassCastException badID) { + throw new IllegalArgumentException("Id is not a known id type: " + + elem.getTextValue()); + } + return true; + } + if (elem.getName().equals(USER_NAME_TAG)) { + setUserName(elem.getTextValue()); + return true; + } + return false; + } + public void setID(ID id) { + mId = id; + } + @Override + public String getBaseAdvType() { + // TODO Auto-generated method stub + return null; + } + /** + * @return Returns the mName. + */ + public String getUserName() { + return mName; + } + /** + * @param name The mName to set. + */ + public void setUserName(String name) { + mName = name; + } + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + if (obj instanceof P2pUserProfileAdvertisement) { + P2pUserProfileAdvertisement adv = (P2pUserProfileAdvertisement) obj; + return getID().equals(adv.getID()); + } + + return false; + + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/SdpProcessor.java b/p2pproxy/src/org/linphone/p2pproxy/core/SdpProcessor.java new file mode 100644 index 000000000..c23a74e74 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/SdpProcessor.java @@ -0,0 +1,39 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +SdpProcessor.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.p2pproxy.core; + + + +import net.jxta.pipe.OutputPipe; + +import org.linphone.p2pproxy.api.P2pProxyException; +import org.zoolu.sip.message.Message; + +public interface SdpProcessor { + /** + * process SDP in mode relay + * rewrite sdp. + */ + public void processSdpBeforeSendingToSipUA( Message aMessage) throws P2pProxyException; + + public void processSdpBeforeSendingToPipe( Message aMessage) throws P2pProxyException; + + public void processSdpAfterSentToPipe( Message aMessage,OutputPipe lOutputPipe) throws P2pProxyException; +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/SeedingPeerServiceManager.java b/p2pproxy/src/org/linphone/p2pproxy/core/SeedingPeerServiceManager.java new file mode 100644 index 000000000..56999094d --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/SeedingPeerServiceManager.java @@ -0,0 +1,59 @@ +// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) +// Source File Name: SuperPeerServiceManager.java + +package org.linphone.p2pproxy.core; + + +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.URI; +import java.net.UnknownHostException; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.media.rtprelay.RtpRelayService; +import org.linphone.p2pproxy.core.media.rtprelay.RtpRelayServerConfig; +import org.linphone.p2pproxy.core.rdvautoconfig.PeerInfoProviderService; + +public class SeedingPeerServiceManager implements ServiceProvider { + protected final JxtaNetworkManager mJxtaNetworkManager; + protected final Configurator mConfigurator; + private final PeerInfoProviderService mPeerInfoProviderService; + private RtpRelayService mUdpRelayService = null; + + private final static Logger mLog = Logger.getLogger(SeedingPeerServiceManager.class); + SeedingPeerServiceManager(Configurator aConfigurator, JxtaNetworkManager aJxtaNetworkManager,boolean enableUdpRelay) throws SocketException, UnknownHostException { + mJxtaNetworkManager = aJxtaNetworkManager; + mConfigurator = aConfigurator; + mPeerInfoProviderService = new PeerInfoProviderService(aConfigurator, aJxtaNetworkManager); + if (enableUdpRelay == true) { + URI lAudioVideoPublicUri = URI.create(aConfigurator.getProperty(RtpRelayService.AUDIO_VIDEO_PUBLIC_URI,RtpRelayService.getDefaultAudioVideoPublicUri())); + int lAudioVideoLocalPort = Integer.valueOf(aConfigurator.getProperty(RtpRelayService.AUDIO_VIDEO_LOCAL_PORT,String.valueOf(lAudioVideoPublicUri.getPort()))); + RtpRelayServerConfig lConfig = new RtpRelayServerConfig(new InetSocketAddress(lAudioVideoPublicUri.getHost(),lAudioVideoPublicUri.getPort()) + ,new InetSocketAddress(lAudioVideoLocalPort)); + mUdpRelayService = new RtpRelayService(lConfig,aConfigurator,aJxtaNetworkManager); + } + } + + public void start(long aTimeout) throws P2pProxyException { + mPeerInfoProviderService.start(aTimeout); + if (mUdpRelayService != null) { + mUdpRelayService.start(aTimeout); + } + mLog.info("SeedingPeerServiceManager started"); + } + + public void stop() { + mPeerInfoProviderService.stop(); + if (mUdpRelayService != null) { + mUdpRelayService.stop(); + } + mLog.info("SeedingPeerServiceManager stopped"); + } + + + + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/ServiceProvider.java b/p2pproxy/src/org/linphone/p2pproxy/core/ServiceProvider.java new file mode 100644 index 000000000..b5a982929 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/ServiceProvider.java @@ -0,0 +1,16 @@ +// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) +// Source File Name: ServiceProvider.java + +package org.linphone.p2pproxy.core; + +import org.linphone.p2pproxy.api.P2pProxyException; + +public interface ServiceProvider +{ + + public abstract void start(long aTimeOut) throws P2pProxyException; + + public abstract void stop(); +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/SipProxyRegistrar.java b/p2pproxy/src/org/linphone/p2pproxy/core/SipProxyRegistrar.java new file mode 100644 index 000000000..4abfa72e1 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/SipProxyRegistrar.java @@ -0,0 +1,478 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +SipListener.java - sip proxy. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.p2pproxy.core; + + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import net.jxta.document.Advertisement; +import net.jxta.endpoint.MessageElement; +import net.jxta.endpoint.StringMessageElement; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.protocol.PipeAdvertisement; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyRtpRelayManagement; +import org.linphone.p2pproxy.api.P2pProxyUserNotFoundException; + +import org.linphone.p2pproxy.core.media.rtprelay.MediaType; +import org.linphone.p2pproxy.core.media.rtprelay.SdpProcessorImpl; +import org.zoolu.sip.address.NameAddress; +import org.zoolu.sip.address.SipURL; +import org.zoolu.sip.header.ExpiresHeader; +import org.zoolu.sip.header.Header; +import org.zoolu.sip.header.MultipleHeader; +import org.zoolu.sip.header.RecordRouteHeader; +import org.zoolu.sip.header.RouteHeader; +import org.zoolu.sip.header.ViaHeader; +import org.zoolu.sip.message.Message; +import org.zoolu.sip.message.MessageFactory; +import org.zoolu.sip.provider.SipProvider; +import org.zoolu.sip.provider.SipProviderListener; +import org.zoolu.sip.provider.SipStack; +import org.zoolu.sip.transaction.TransactionServer; +public class SipProxyRegistrar implements SipProviderListener,PipeMsgListener,SipProxyRegistrarMBean { + private final static Logger mLog = Logger.getLogger(SipProxyRegistrar.class); + public final static String REGISTRAR_PORT="org.linphone.p2pproxy.SipListener.registrar.port"; + public final static String UDP_PORT_BEGING="org.linphone.p2pproxy.udp.port.begin"; + public final static String UDP_MEDIA_RELAY_PORT_START="org.linphone.p2pproxy.udp-media-relay.port.start"; + + // + private final SipProvider mProvider; + private final JxtaNetworkManager mJxtaNetworkManager; + private final ExecutorService mPool; + + private final Map mRegistrationTab = new HashMap(); + private final Map mCancalableTaskTab = new HashMap(); + + private final P2pProxyAccountManagementMBean mP2pProxyAccountManagement; + private final Configurator mProperties; + private final SdpProcessor mSdpProcessor; + //private long mNumberOfEstablishedCall; + private long mNumberOfRefusedRegistration; + private long mNumberOfSuccessfullRegistration; + private long mNumberOfUSerNotFound; + private long mNumberOfUnknownUSers; + private long mNumberOfUnknownUsersForRegistration; + private long mNumberOfUnRegistration; + + public static class Registration { + long RegistrationDate; + long Expiration; + public NetworkResources NetResources; + public Map RtpRelays = new HashMap() ; + String Contact; + final String From; + public Registration(String aFrom) {From = aFrom;} + } + + class SipMessageTask implements Callable { + private final SipProvider mProvider; + private final Message mMessage; + private Future mFuture; + + /** + * @return Returns the mMessage. + */ + public Message getMessage() { + return mMessage; + } + SipMessageTask(SipProvider aProvider, Message aMessage) { + mProvider = aProvider; + mMessage = aMessage; + } + public Boolean call() throws Exception { + NDC.push(mMessage.getFirstLine() + mMessage.getCallIdHeader().getCallId() +":"); + try { + if (mMessage.isRequest()) { + if (mMessage.isRegister()) { + processRegister(mProvider, mMessage); + } else { + proxyRequest(mProvider, mMessage); + } + } else { + proxyResponse(mProvider, mMessage); + } + synchronized (SipProxyRegistrar.this) { + if (mMessage.isInvite() && mCancalableTaskTab.containsKey(mMessage.getCallIdHeader().getCallId()) ) { + mCancalableTaskTab.remove(mMessage.getCallIdHeader().getCallId()); + } + } + } catch (InterruptedException eInter) { + mLog.info("request interrupted",eInter); + //nop + } + catch (Exception e) { + mLog.error("unexpected behavior",e); + if (mMessage.isRequest()) { + Message lResp= null; + lResp = MessageFactory.createResponse(mMessage,500,e.getMessage(),null); + TransactionServer lTransactionServer = new TransactionServer(mProvider,mMessage,null); + lTransactionServer.respondWith(lResp); + synchronized (SipProxyRegistrar.this) { + if (mMessage.isInvite() && mCancalableTaskTab.containsKey(mMessage.getCallIdHeader().getCallId()) ) { + mCancalableTaskTab.remove(mMessage.getCallIdHeader().getCallId()); + } + } + } + } finally { + NDC.pop(); + } + return true; + } + /** + * @return Returns the mFuture. + */ + public Future getFuture() { + return mFuture; + } + /** + * @param future The mFuture to set. + */ + public void setFuture(Future future) { + mFuture = future; + } + + } + + public SipProxyRegistrar(Configurator lProperties,JxtaNetworkManager aJxtaNetworkManager,P2pProxyAccountManagementMBean aP2pProxyAccountManagement,P2pProxyRtpRelayManagement aP2pProxyRtpRelayManagement) { + mJxtaNetworkManager = aJxtaNetworkManager; + mP2pProxyAccountManagement = aP2pProxyAccountManagement; + mProperties = lProperties; + File lFile = new File(SipStack.log_path); + if (lFile.exists() == false) lFile.mkdir(); + int lPort = Integer.parseInt(lProperties.getProperty(REGISTRAR_PORT, "5060")); + String[] lProto = {SipProvider.PROTO_UDP}; + mProvider=new SipProvider(null,lPort,lProto,SipProvider.ALL_INTERFACES); + mProvider.addSipProviderListener(SipProvider.PROMISQUE,this); + mPool = Executors.newCachedThreadPool(); + mSdpProcessor = new SdpProcessorImpl(mRegistrationTab,aP2pProxyRtpRelayManagement); + + } + public synchronized void onReceivedMessage(SipProvider aProvider, Message aMessage) { + String lCallId = aMessage.getCallIdHeader().getCallId(); + if (mLog.isInfoEnabled()) mLog.info("receiving message ["+aMessage+"]"); + if (aMessage.isCancel() && mCancalableTaskTab.containsKey(lCallId) ) { + // search for pending transaction + SipMessageTask lPendingSipMessageTask = mCancalableTaskTab.get(lCallId); + lPendingSipMessageTask.getFuture().cancel(true); + mCancalableTaskTab.remove(lCallId); + + removeVia(mProvider,lPendingSipMessageTask.getMessage()); + // accept cancel + Message lCancelResp = MessageFactory.createResponse(aMessage,200,"ok",null); + TransactionServer lCancelTransactionServer = new TransactionServer(mProvider,aMessage,null); + lCancelTransactionServer.respondWith(lCancelResp); + + // cancel invite + Message lInviteResp = MessageFactory.createResponse(lPendingSipMessageTask.getMessage(),487,"Request Terminated",null); + TransactionServer lInviteTransactionServer = new TransactionServer(mProvider,lPendingSipMessageTask.getMessage(),null); + lInviteTransactionServer.respondWith(lInviteResp); + + + + } else { + // normal behavior + SipMessageTask lSipMessageTask = new SipMessageTask(aProvider,aMessage); + lSipMessageTask.setFuture(mPool.submit(lSipMessageTask)); + if (aMessage.isInvite()) { + mCancalableTaskTab.put(aMessage.getCallIdHeader().getCallId(),lSipMessageTask); + } + + } + + } +////////////////////////////////////////////////////////////////////// +////Proxy methods +///////////////////////////////////////////////////////////////////// + private void proxyResponse(SipProvider aProvider, Message aMessage) throws NumberFormatException, InterruptedException, P2pProxyException, IOException { + //1 remove via header + removeVia(aProvider,aMessage); + String lFrom = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + mSdpProcessor.processSdpBeforeSendingToPipe(aMessage); + OutputPipe lOutputPipe = sendMessageToPipe(lFrom,aMessage.toString()); + mSdpProcessor.processSdpAfterSentToPipe( aMessage,lOutputPipe); + } + private void proxyRequest(SipProvider aProvider, Message aMessage) throws Exception { + + if (aMessage.isAck() && aMessage.getToHeader().getTag() == null) { + // just terminate the Invite transaction + return; + } + + if (aMessage.isInvite() == true) { + // 100 trying + TransactionServer lTransactionServer = new TransactionServer(aProvider,aMessage,null); + Message l100Trying = MessageFactory.createResponse(aMessage,100,"trying",null); + lTransactionServer.respondWith(l100Trying); + } + + String lTo = aMessage.getToHeader().getNameAddress().getAddress().toString(); + //remove route + MultipleHeader lMultipleRoute = aMessage.getRoutes(); + if (lMultipleRoute != null) { + lMultipleRoute.removeTop(); + aMessage.setRoutes(lMultipleRoute); + } + // add Via only udp + addVia(aProvider,aMessage); + // add recordRoute + addRecordRoute(aProvider,aMessage); + try { + mSdpProcessor.processSdpBeforeSendingToPipe(aMessage); + // proxy message to pipe + OutputPipe lOutputPipe = sendMessageToPipe(lTo,aMessage.toString()); + mSdpProcessor.processSdpAfterSentToPipe( aMessage,lOutputPipe); + } catch (P2pProxyUserNotFoundException e) { + //remove via + removeVia(aProvider, aMessage); + if (aMessage.isInvite()) { + Message lresp = MessageFactory.createResponse(aMessage,404,e.getMessage(),null); + TransactionServer lTransactionServer = new TransactionServer(aProvider,aMessage,null); + lTransactionServer.respondWith(lresp); + } else { + throw e; + } + } catch (Exception e2) { + //remove via + removeVia(aProvider, aMessage); + throw e2; + + } + } + + +////////////////////////////////////////////////////////////////////// +////Registrar methods +///////////////////////////////////////////////////////////////////// + + private synchronized void processRegister(SipProvider aProvider, Message aMessage) throws IOException, P2pProxyException { + + TransactionServer lTransactionServer = new TransactionServer(aProvider,aMessage,null); + Message l100Trying = MessageFactory.createResponse(aMessage,100,"trying",null); + lTransactionServer.respondWith(l100Trying); + Registration lRegistration=null; + + //check if already registered + + String lFromName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + if (mRegistrationTab.containsKey(lFromName)) { + + updateRegistration(lRegistration = mRegistrationTab.get(lFromName),aMessage); + + if (aMessage.getExpiresHeader().getDeltaSeconds() == 0) { + mRegistrationTab.remove(lFromName); + } + + } else { + // new registration + // test if account already created + + if (mP2pProxyAccountManagement.isValidAccount(lFromName)) { + lRegistration = new Registration(lFromName); + lRegistration.Contact = aMessage.getContactHeader().getNameAddress().getAddress().toString();; + updateRegistration(lRegistration,aMessage); + mRegistrationTab.put(lFromName, lRegistration); + } else { + // create negative answers + mLog.info("account for user ["+lFromName+"not crteated yet"); + Message lresp = MessageFactory.createResponse(aMessage,404,"Not found",null); + lTransactionServer.respondWith(lresp); + return; + } + } + // ok, create answers + Message lresp = MessageFactory.createResponse(aMessage,200,"Ok",null); + lresp.addContactHeader(aMessage.getContactHeader(), false); + ExpiresHeader lExpireHeader = new ExpiresHeader((int) (lRegistration.Expiration/1000)); + lresp.addHeader(lExpireHeader, false); + lTransactionServer.respondWith(lresp); + + } + private void updateRegistration(Registration aRegistration, Message aRegistrationMessage) throws IOException { + aRegistration.RegistrationDate = System.currentTimeMillis(); + // default registration periode + aRegistration.Expiration = 3600000; + if (aRegistrationMessage.getExpiresHeader() != null ) { + aRegistration.Expiration = aRegistrationMessage.getExpiresHeader().getDeltaSeconds()*1000; + } + + if (aRegistration.NetResources == null) { + // new registration, create pipe + aRegistration.NetResources = new NetworkResources(aRegistration.From,mJxtaNetworkManager); + aRegistration.NetResources.addPipeMsgListener(this); + } + + aRegistration.NetResources.publish(aRegistration.Expiration); + } + +////////////////////////////////////////////////////////////////////// +////jxta service methods +///////////////////////////////////////////////////////////////////// + + + public void pipeMsgEvent(PipeMsgEvent anEvent) { + MessageElement lMessageElement = anEvent.getMessage().getMessageElement("SIP"); + if (lMessageElement == null) { + //nop, this is not for me + return; + } + String lMesssage = lMessageElement.toString(); + mLog.info("pipe event sip message["+lMesssage+"]"); + Message lSipMessage = new Message(lMesssage); + // process request + if (lSipMessage.isRequest()) { + SipURL lNextHope ; + // get next hope from registrar + String lToName = lSipMessage.getToHeader().getNameAddress().getAddress().toString(); + if (mRegistrationTab.containsKey(lToName)) { + lNextHope = new SipURL(mRegistrationTab.get(lToName).Contact); + } else { + mLog.error("user ["+lToName+"] not found"); + return; + } + //RequestLine lRequestLine = new RequestLine(lSipMessage.getRequestLine().getMethod(),lNextHope); + //lSipMessage.setRequestLine(lRequestLine); + MultipleHeader lMultipleRoute = lSipMessage.getRoutes(); + RouteHeader lRouteHeader = new RouteHeader(new NameAddress(lNextHope+";lr")); + //lRouteHeader.setParameter("lr", null); + if (lMultipleRoute != null) { + lMultipleRoute.addTop(lRouteHeader); + lSipMessage.setRoutes(lMultipleRoute); + } else { + lSipMessage.addRouteHeader(lRouteHeader); + } + // add Via only udp + addVia(mProvider,lSipMessage); + // add recordRoute + addRecordRoute(mProvider,lSipMessage); + + } else { + //response + //1 remove via header + removeVia(mProvider,lSipMessage); + } + try { + mSdpProcessor.processSdpBeforeSendingToSipUA( lSipMessage); + } catch (P2pProxyException e) { + mLog.error("enable to re-write sdp",e); + } + + mProvider.sendMessage(lSipMessage); + // + } + + private Advertisement getPipeAdv(String aUser,long aDiscoveryTimout,boolean isTryFromLocal) throws InterruptedException, P2pProxyUserNotFoundException, IOException { + // search on all peers + try { + return mJxtaNetworkManager.getAdvertisement(null,aUser, isTryFromLocal); + } catch (P2pProxyAdvertisementNotFoundException e) { + throw new P2pProxyUserNotFoundException(e); + } + } + private OutputPipe sendMessageToPipe(String aDestination,String lContent) throws NumberFormatException, InterruptedException, P2pProxyException, IOException { + + //1 search for pipe + long lTimeout = JxtaNetworkManager.ADV_DISCOVERY_TIMEOUT_INT; + PipeAdvertisement lPipeAdvertisement = (PipeAdvertisement)getPipeAdv(aDestination,lTimeout,true); + OutputPipe lOutputPipe=null; + try { + // create output pipe + lOutputPipe = mJxtaNetworkManager.getPeerGroup().getPipeService().createOutputPipe(lPipeAdvertisement, lTimeout); + //create the message + } catch (IOException e) { + //second try from remote only to avoid wrong cached value + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().flushAdvertisement(lPipeAdvertisement); + mLog.warn("cannot create output pipe, trying to ask from rdv ",e); + lPipeAdvertisement = (PipeAdvertisement)getPipeAdv(aDestination,lTimeout,false); + lOutputPipe = mJxtaNetworkManager.getPeerGroup().getPipeService().createOutputPipe(lPipeAdvertisement, lTimeout); + } + net.jxta.endpoint.Message lMessage = new net.jxta.endpoint.Message(); + StringMessageElement lStringMessageElement = new StringMessageElement("SIP", lContent, null); + lMessage.addMessageElement("SIP", lStringMessageElement); + //send the message + lOutputPipe.send(lMessage); + mLog.debug("message sent to ["+aDestination+"]"); + return lOutputPipe; + + } + private void addVia(SipProvider aProvider, Message aMessage) { + ViaHeader via=new ViaHeader("udp",aProvider.getViaAddress(),aProvider.getPort()); + String branch=aProvider.pickBranch(aMessage); + via.setBranch(branch); + aMessage.addViaHeader(via); + } + private void addRecordRoute(SipProvider aProvider, Message aMessage) { + SipURL lRecordRoute; + lRecordRoute=new SipURL(aProvider.getViaAddress(),aProvider.getPort()); + lRecordRoute.addLr(); + RecordRouteHeader lRecordRouteHeader=new RecordRouteHeader(new NameAddress(lRecordRoute)); + aMessage.addRecordRouteHeader(lRecordRouteHeader); + } + private void removeVia(SipProvider aProvider, Message aMessage) { + synchronized (aMessage) { + ViaHeader lViaHeader =new ViaHeader((Header)aMessage.getVias().getHeaders().elementAt(0)); + if (lViaHeader.getHost().equals(aProvider.getViaAddress()) && lViaHeader.getPort() == aProvider.getPort() ) { + aMessage.removeViaHeader(); + } + } + } + // public long getNumberOfEstablishedCall() { +// return mNumberOfEstablishedCall; +// } + public long getNumberOfRefusedRegistration() { + return mNumberOfRefusedRegistration; + } + public long getNumberOfSuccessfullRegistration() { + return mNumberOfSuccessfullRegistration; + } + public long getNumberOfUSerNotFound() { + return mNumberOfUSerNotFound; + } + public long getNumberOfUnknownUSers() { + return mNumberOfUnknownUSers; + } + public long getNumberOfUnknownUsersForRegistration() { + return mNumberOfUnknownUsersForRegistration; + } + public String[] getRegisteredList() { + String[] lRegisteredList = new String[mRegistrationTab.size()] ; + int i=0; + for (String lRegistrationKey : mRegistrationTab.keySet()) { + lRegisteredList[i++] = lRegistrationKey; + } + return lRegisteredList; + } + public long getNumberOfUnRegistration() { + return mNumberOfUnRegistration; + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/SipProxyRegistrarMBean.java b/p2pproxy/src/org/linphone/p2pproxy/core/SipProxyRegistrarMBean.java new file mode 100644 index 000000000..42d25bf9e --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/SipProxyRegistrarMBean.java @@ -0,0 +1,34 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +SipProxyRegistrarMBean.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core; + +public interface SipProxyRegistrarMBean { + // registrar + public long getNumberOfSuccessfullRegistration(); + public long getNumberOfUnRegistration(); + public long getNumberOfRefusedRegistration(); + public long getNumberOfUnknownUsersForRegistration(); + public String[] getRegisteredList(); + //proxy + //public long getNumberOfEstablishedCall(); + public long getNumberOfUSerNotFound(); + public long getNumberOfUnknownUSers(); +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/SuperPeerServiceManager.java b/p2pproxy/src/org/linphone/p2pproxy/core/SuperPeerServiceManager.java new file mode 100644 index 000000000..8790aa152 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/SuperPeerServiceManager.java @@ -0,0 +1,47 @@ +// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) +// Source File Name: SuperPeerServiceManager.java + +package org.linphone.p2pproxy.core; + + + +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; + +import org.linphone.p2pproxy.core.rdvautoconfig.PeerInfoProviderService; + +// Referenced classes of package org.linphone.p2pproxy.core: +// EdgePeerServiceManager, Configurator, JxtaNetworkManager + +public class SuperPeerServiceManager extends P2pProxyManagementImpl { + private final static Logger mLog = Logger.getLogger(SuperPeerServiceManager.class); + private final PeerInfoProviderService mPeerInfoProviderService; + SuperPeerServiceManager(Configurator aConfigurator, JxtaNetworkManager aJxtaNetworkManager) throws P2pProxyException, SocketException, UnknownHostException + { + super(aConfigurator,aJxtaNetworkManager); + mPeerInfoProviderService = new PeerInfoProviderService(aConfigurator, aJxtaNetworkManager); + } + + public void start(long aTimeOut) throws P2pProxyException { + mPeerInfoProviderService.start(aTimeOut); + mLog.info("SuperPeerServiceManager started"); + } + + public void stop() { + super.stop(); + mPeerInfoProviderService.stop(); + mLog.info("SuperPeerServiceManager stopped"); + } + + + public boolean shouldIBehaveAsAnRdv() throws P2pProxyException{ + return false; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/jxtaext/EndpointRegistry.java b/p2pproxy/src/org/linphone/p2pproxy/core/jxtaext/EndpointRegistry.java new file mode 100644 index 000000000..7240a216f --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/jxtaext/EndpointRegistry.java @@ -0,0 +1,63 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +EndpointRegistry.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.jxtaext; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; + +public class EndpointRegistry { + final static private EndpointRegistry mInstance = new EndpointRegistry(); + final private Map mMap = new HashMap(); + private EndpointRegistry() { + } + + static public EndpointRegistry getInstance() { + return mInstance; + } + /** + * @param aKey peer Id as retyrned by EndpointAdress.getProtocolAddress() + * @return + */ + synchronized public boolean isPresent(String aKey) { + return mMap.containsKey(aKey); + } + /** + * @param aKey peer Id as retyrned by EndpointAdress.getProtocolAddress() + * @return IP address or null + */ + synchronized public InetAddress get(String aKey) { + return mMap.get(aKey); + } + /** + * @param a Key peer Id as retyrned by EndpointAdress.getProtocolAddress() + * @param aValue + */ + synchronized public void add(String aKey,InetAddress aValue) { + mMap.put(aKey, aValue) ; + } + /** + * @param aKey peer Id as retyrned by EndpointAdress.getProtocolAddress() + */ + synchronized public void remove(String aKey) { + mMap.remove(aKey) ; + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/jxtaext/NatedEndPointAddress.java b/p2pproxy/src/org/linphone/p2pproxy/core/jxtaext/NatedEndPointAddress.java new file mode 100644 index 000000000..626444223 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/jxtaext/NatedEndPointAddress.java @@ -0,0 +1,52 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +NatedEndPointAddress.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.jxtaext; + + +import net.jxta.endpoint.EndpointAddress; + +public class NatedEndPointAddress extends EndpointAddress { + + String mRemoteHost; + /** + * @return Returns the mRemoteHost. + */ + public String getRemoteHost() { + return mRemoteHost; + } + + + /** + * @param protocol + * @param address + * @param service + * @param serviceParam + */ + public NatedEndPointAddress(String protocol, String address, String service, String serviceParam,String remoteHost) { + super(protocol, address, service, serviceParam); + // TODO Auto-generated constructor stub + } + + public String toString() { + return super.toString() + "remote host address ["+mRemoteHost+"]"; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/RtpSession.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/RtpSession.java new file mode 100644 index 000000000..fa71f7385 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/RtpSession.java @@ -0,0 +1,9 @@ +package org.linphone.p2pproxy.core.media.jxtaudpproxy; + +import java.net.InetSocketAddress; + +public interface RtpSession { + + public abstract void setRemoteAddress(InetSocketAddress aRemoteAddress); + +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/RtpSessionImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/RtpSessionImpl.java new file mode 100644 index 000000000..6f0b5ae36 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/RtpSessionImpl.java @@ -0,0 +1,81 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +UdpSession.java + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.jxtaudpproxy; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; + +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; +import net.jxta.socket.JxtaSocket; + + +public class RtpSessionImpl implements PipeMsgListener, RtpSession{ + UdpSession mRtpChannel = null; + UdpSession mRtcpChannel = null; + int mLocalRtpPort; + + public RtpSessionImpl(int portStart, String aDomaineName) throws IOException { + mLocalRtpPort = portStart; + while (mRtpChannel == null) { + try { + mRtpChannel = new UdpSession(mLocalRtpPort ,aDomaineName+"-RTP"); + mRtcpChannel = new UdpSession(mLocalRtpPort +1 ,aDomaineName+"-RCTP"); + }catch (Exception e) { + //nop already used + mLocalRtpPort += 2; + } + + } + } + /* (non-Javadoc) + * @see org.linphone.p2pproxy.core.jxtaudpproxy.RtpSession#setRemoteAddress(java.net.InetSocketAddress) + */ + public void setRemoteAddress( InetSocketAddress aRemoteAddress) { + mRtpChannel.setRemoteAddress(aRemoteAddress); + InetSocketAddress lRtcpInetSocketAddress = new InetSocketAddress(aRemoteAddress.getAddress(),aRemoteAddress.getPort() + 1); + mRtcpChannel.setRemoteAddress(lRtcpInetSocketAddress); + } + public void setRemotePipe(OutputPipe aRemotePipe) { + mRtpChannel.setRemotePipe(aRemotePipe); + mRtcpChannel.setRemotePipe(aRemotePipe); + } + public void close() { + mRtpChannel.close(); + mRtcpChannel.close(); + } + public int getPort() { + return mRtpChannel.getPort(); + } + public String toString() { + return "rtp ["+mRtpChannel+"] rtcp "+mRtcpChannel+"]"; + } + public void pipeMsgEvent(PipeMsgEvent event) { + mRtpChannel.pipeMsgEvent(event); + mRtcpChannel.pipeMsgEvent(event); + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/SdpProcessorImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/SdpProcessorImpl.java new file mode 100644 index 000000000..0213a23a4 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/SdpProcessorImpl.java @@ -0,0 +1,190 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +SdpProcessorImpl.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.jxtaudpproxy; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Map; + +import net.jxta.pipe.OutputPipe; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.Configurator; + +import org.linphone.p2pproxy.core.NetworkResources; +import org.linphone.p2pproxy.core.SdpProcessor; +import org.linphone.p2pproxy.core.SipProxyRegistrar; +import org.linphone.p2pproxy.core.SipProxyRegistrar.Registration; +import org.zoolu.sdp.AttributeField; +import org.zoolu.sdp.ConnectionField; +import org.zoolu.sdp.MediaDescriptor; +import org.zoolu.sdp.MediaField; +import org.zoolu.sdp.SessionDescriptor; +import org.zoolu.sip.message.Message; + +public class SdpProcessorImpl implements SdpProcessor { + private final static Logger mLog = Logger.getLogger(SdpProcessorImpl.class); + private final Map mRegistrationTab; + private final Configurator mProperties; + public SdpProcessorImpl(Map aRegistrationTab,Configurator aProperties) { + mRegistrationTab = aRegistrationTab; + mProperties = aProperties;; + } + /* + * process SDP in mode relay + * rewrite sdp. + */ + public void processSdpBeforeSendingToSipUA( Message aMessage) throws P2pProxyException { + try { + //check if sdp present + if (aMessage.hasBody() && "application/sdp".equals(aMessage.getBodyType())) { + SessionDescriptor lOrigSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + SessionDescriptor lNewSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + lNewSessionDescriptor.removeMediaDescriptors(); + lNewSessionDescriptor.setConnection(null); + + String lUserName=""; + if (aMessage.isInvite()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isResponse()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isAck()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else { + mLog.warn("strange, sdp in message ["+aMessage+"]"); + } + // build rtp session if required + NetworkResources lNetworkResources = buildRtpSessions(lOrigSessionDescriptor, lUserName); + + for (Object lMediaDescriptorObject :lOrigSessionDescriptor.getMediaDescriptors()) { + MediaDescriptor lMediaDescriptor = (MediaDescriptor)lMediaDescriptorObject; + RtpSessionImpl lRtpSession = lNetworkResources.getRtpSession(lMediaDescriptor.getMedia().getMedia()); + // create new media desc + ConnectionField lConnectionField = new ConnectionField("IP4",InetAddress.getLocalHost().getHostAddress()); + MediaField lOrigMediaField = lMediaDescriptor.getMedia(); + MediaField lNewMediaField = new MediaField(lOrigMediaField.getMedia() + , lRtpSession.getPort() //new port + , 0 + , lOrigMediaField.getTransport() + , lOrigMediaField.getFormatList()); + MediaDescriptor lNewMediaDescriptor = new MediaDescriptor(lNewMediaField,lConnectionField); + for (Object lAttributeField:lMediaDescriptor.getAttributes()) { + lNewMediaDescriptor.addAttribute((AttributeField) lAttributeField); + } + lNewSessionDescriptor.addMediaDescriptor(lNewMediaDescriptor); + + } + aMessage.setBody(lNewSessionDescriptor.toString()); + mLog.debug("new sdp:" +aMessage.getBody()); + + } + }catch (Exception e) { + throw new P2pProxyException(e); + } + + } + public void processSdpAfterSentToPipe( Message aMessage,OutputPipe lOutputPipe) throws P2pProxyException { + try { + if (aMessage.hasBody() && "application/sdp".equals(aMessage.getBodyType())) { + SessionDescriptor lOrigSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + String lUserName=""; + if (aMessage.isInvite()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isResponse()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isAck()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else { + mLog.warn("strange, sdp in message ["+aMessage+"]"); + } + // build rtp session if required + NetworkResources lNetworkResources = buildRtpSessions(lOrigSessionDescriptor, lUserName,lOutputPipe); + + // check remote address + ConnectionField lConnectionField = lOrigSessionDescriptor.getConnection(); + //search from m blocs + for (Object lMediaDescriptorObject :lOrigSessionDescriptor.getMediaDescriptors()) { + MediaDescriptor lMediaDescriptor = (MediaDescriptor)lMediaDescriptorObject; + if (lConnectionField == null ) { + lConnectionField = lMediaDescriptor.getConnection(); + } + RtpSession lRtpSession = lNetworkResources.getRtpSession(lMediaDescriptor.getMedia().getMedia()); + InetAddress lInetAddress = InetAddress.getByName(lConnectionField.getAddress()); + InetSocketAddress lInetSocketAddress = new InetSocketAddress(lInetAddress,lMediaDescriptor.getMedia().getPort()); + lRtpSession.setRemoteAddress(lInetSocketAddress); + mLog.info("rtp session updated ["+lRtpSession+"]"); + } + // + + } + }catch (Exception e) { + throw new P2pProxyException(e); + } + + } + private NetworkResources buildRtpSessions(SessionDescriptor lSessionDescriptor , String aFrom) throws P2pProxyException { + return buildRtpSessions(lSessionDescriptor , aFrom,null); + } + private NetworkResources buildRtpSessions(SessionDescriptor lSessionDescriptor , String aFrom,OutputPipe aRemotePipe) throws P2pProxyException { + try { + // get Registration + Registration lRegistration = mRegistrationTab.get(aFrom); + + for (Object lMediaDescriptorObject :lSessionDescriptor.getMediaDescriptors()) { + MediaDescriptor lMediaDescriptor = (MediaDescriptor)lMediaDescriptorObject; + //1 check if port != 0 + if (lMediaDescriptor.getMedia().getPort() == 0) { + // nothing to change, offers rejected + break; + } + //3 open datagram socket + if (lMediaDescriptor.getMedia().getTransport().equalsIgnoreCase("RTP/AVP") == false) { + mLog.warn("enable to process non udp mlines ["+lMediaDescriptor.getMedia().getTransport()+"]"); + break; + } + + String lMLineName = lMediaDescriptor.getMedia().getMedia(); + RtpSessionImpl lRtpSession = null; + if (lRegistration.NetResources.hasRtpSession(lMLineName) == false) { + // first time, just create + int lPortStart = Integer.parseInt(mProperties.getProperty(SipProxyRegistrar.UDP_MEDIA_RELAY_PORT_START, "15000")); + lRtpSession = new RtpSessionImpl (lPortStart,lMLineName); + lRegistration.NetResources.putRtpSession(lMLineName, lRtpSession); + } else { + lRtpSession = lRegistration.NetResources.getRtpSession(lMLineName); + } + if (aRemotePipe != null) { + lRtpSession.setRemotePipe(aRemotePipe); + } + + } + return lRegistration.NetResources; + }catch (Exception e) { + throw new P2pProxyException(e); + } + + } + public void processSdpBeforeSendingToPipe(Message message) throws P2pProxyException { + // TODO Auto-generated method stub + + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/UdpSession.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/UdpSession.java new file mode 100644 index 000000000..312b89961 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/jxtaudpproxy/UdpSession.java @@ -0,0 +1,90 @@ +package org.linphone.p2pproxy.core.media.jxtaudpproxy; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.core.GenericUdpSession; + +import net.jxta.endpoint.ByteArrayMessageElement; +import net.jxta.endpoint.MessageElement; +import net.jxta.pipe.OutputPipe; +import net.jxta.pipe.PipeMsgEvent; +import net.jxta.pipe.PipeMsgListener; + +public class UdpSession implements GenericUdpSession.MessageHandler ,PipeMsgListener{ + private final static Logger mLog = Logger.getLogger(UdpSession.class); + private InetSocketAddress mRemoteAddress; + private OutputPipe mRemotePipe; + private boolean mExit = false; + private final String mMessageName; + private final GenericUdpSession mGenericUdpSession; + UdpSession(int aPort,String aMessageName) throws SocketException, UnknownHostException { + mMessageName = aMessageName; + mGenericUdpSession = new GenericUdpSession(new InetSocketAddress(aPort),this); + } + + + + public void pipeMsgEvent(PipeMsgEvent event) { + MessageElement lMessageElement = event.getMessage().getMessageElement(mMessageName); + if (lMessageElement == null) { + //nop, this is not for me + return; + } + //test if we have an address to forward to + if (mRemoteAddress == null) { + mLog.warn("no remote adress, message discarded"); + return; + } + byte[] lBuff = lMessageElement.getBytes(false); + DatagramPacket lDatagramPacket = new DatagramPacket(lBuff,(int) lMessageElement.getByteLength()); + lDatagramPacket.setSocketAddress(mRemoteAddress); + try { + mGenericUdpSession.getSocket().send(lDatagramPacket); + mLog.debug("message from ["+mMessageName+"] sent to ["+mRemoteAddress+"]"); + } catch (IOException e) { + mLog.error("cannot send message for session ["+this+"]" , e); + } + // + } + public void setRemoteAddress( InetSocketAddress aRemoteAddress) { + mRemoteAddress = aRemoteAddress; + } + public void setRemotePipe(OutputPipe aRemotePipe) { + mRemotePipe = aRemotePipe; + } + public void close() { + mExit = true; + mGenericUdpSession.close(); + } + + public String toString() { + return "name ["+mMessageName +"] udp dest ["+mRemoteAddress+"]"; + } + public int getPort() { + return mGenericUdpSession.getSocket().getPort(); + } + public void onMessage(DatagramPacket message) { + try { + // if destination is known just send + if (mRemotePipe != null) { + net.jxta.endpoint.Message lMessage = new net.jxta.endpoint.Message(); + ByteArrayMessageElement lByteArrayMessageElement = new ByteArrayMessageElement(mMessageName, null,message.getData(),0,message.getLength(), null); + lMessage.addMessageElement(mMessageName, lByteArrayMessageElement); + //send the message + mRemotePipe.send(lMessage); + mLog.debug("message from ["+message.getAddress()+":"+message.getPort()+"]sent to ["+mRemotePipe.getPipeID()+"]"); + } else { + mLog.warn("output pipe not set for ["+this+"], discarding message"); + } + }catch(Exception e) { + //nop + } + + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/AddressRequest.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/AddressRequest.java new file mode 100644 index 000000000..4bc2f3eb5 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/AddressRequest.java @@ -0,0 +1,32 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RouteAddRequest.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.Serializable; +import java.net.SocketAddress; + +public class AddressRequest implements Serializable { + private static final long serialVersionUID = 1L; + + public AddressRequest() { + + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/AddressResponse.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/AddressResponse.java new file mode 100644 index 000000000..c40069791 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/AddressResponse.java @@ -0,0 +1,47 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RouteAddResponse.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.Map; + +public class AddressResponse implements Serializable { + private static final long serialVersionUID = 1L; + private final Map mAddressTable; + public AddressResponse(Map anAddressTable) { + mAddressTable = anAddressTable; + } + /** + * @return Returns the mMediaType. + */ + public Map getAddressTable() { + return mAddressTable; + } + + public String toString() { + StringBuffer lReturnString = new StringBuffer(); + for (MediaType lMediaType:mAddressTable.keySet()) { + lReturnString.append(mAddressTable.get(lMediaType)+" for type "+lMediaType+" :"); + } + return lReturnString.toString(); + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/IceSdpProcessorImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/IceSdpProcessorImpl.java new file mode 100644 index 000000000..98337c27b --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/IceSdpProcessorImpl.java @@ -0,0 +1,222 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +SdpProcessorImpl.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.StringTokenizer; + +import net.jxta.pipe.OutputPipe; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyRtpRelayManagement; +import org.linphone.p2pproxy.core.SdpProcessor; +import org.linphone.p2pproxy.core.SipProxyRegistrar.Registration; +import org.zoolu.sdp.AttributeField; +import org.zoolu.sdp.ConnectionField; +import org.zoolu.sdp.MediaDescriptor; +import org.zoolu.sdp.MediaField; +import org.zoolu.sdp.SessionDescriptor; +import org.zoolu.sip.message.Message; + +/** + * rewrite SDP to insert an ICE aware rtp relay + * + * + */ +public class IceSdpProcessorImpl implements SdpProcessor { + private final String CANDIDATE_RELAY_NAME="relay"; + + class CandidateAttributeParser { + final private String mCandidateAttribute; + + final private String mfoundation; + final private String mComponentId; + final private String mTransport; + final private String mPriority; + final private String mConnectionAddress; + final private String mPort; + final private String mType; + + public CandidateAttributeParser(String aCandidateAttribute){ + mCandidateAttribute = aCandidateAttribute; + StringTokenizer st = new StringTokenizer(mCandidateAttribute); + mfoundation = st.nextToken(); + mComponentId = st.nextToken(); + mTransport = st.nextToken(); + mPriority = st.nextToken(); + mConnectionAddress = st.nextToken(); + mPort = st.nextToken(); + st.nextToken(); //skip typ + mType = st.nextToken();; + } + public CandidateAttributeParser(InetSocketAddress aRelayAddress){ + mfoundation = "3"; + mComponentId = "1"; + mTransport = "UDP"; + mPriority = "0"; + mConnectionAddress = aRelayAddress.getAddress().getHostAddress(); + mPort = String.valueOf(aRelayAddress.getPort()); + mType = CANDIDATE_RELAY_NAME; + mCandidateAttribute = toString(); + } + + InetSocketAddress getAddress() { + return new InetSocketAddress(mConnectionAddress,Integer.parseInt(mPort)); + } + public String toString() { + return mfoundation +" "+ mComponentId +" "+ mTransport +" "+ mPriority +" "+ mConnectionAddress +" "+ mPort +" typ " +mType; + } + } + + private final static Logger mLog = Logger.getLogger(IceSdpProcessorImpl.class); + private final Map mRegistrationTab; + private final P2pProxyRtpRelayManagement mP2pProxyRtpRelayManagement; + public IceSdpProcessorImpl(Map aRegistrationTab,P2pProxyRtpRelayManagement aP2pProxyRtpRelayManagement) { + mRegistrationTab = aRegistrationTab; + mP2pProxyRtpRelayManagement = aP2pProxyRtpRelayManagement; + + } + public void processSdpAfterSentToPipe(Message message, OutputPipe outputPipe) + throws P2pProxyException { + //nop + + } + + public void processSdpBeforeSendingToSipUA(Message aMessage) throws P2pProxyException { + String lUserName=""; + if (aMessage.isInvite()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isResponse()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isAck()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else { + mLog.warn("strange, sdp in message ["+aMessage+"]"); + } + processSdp(aMessage,lUserName); + } + + public void processSdpBeforeSendingToPipe(Message aMessage) throws P2pProxyException { + String lUserName=""; + if (aMessage.isInvite()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isResponse()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isAck()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else { + mLog.warn("strange, sdp in message ["+aMessage+"]"); + } + processSdp(aMessage,lUserName); + } + + //check if already have relay candidate + //1 search for relay if not available + //2 rewrite c line /port + //3 add candidate + //4 if relay was available, clean relay + private void processSdp(Message aMessage, String aUserName) throws P2pProxyException { + //check if sdp present + if (aMessage.hasBody() && "application/sdp".equals(aMessage.getBodyType())) { + SessionDescriptor lOrigSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + + SessionDescriptor lNewSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + lNewSessionDescriptor.removeMediaDescriptors(); + lNewSessionDescriptor.setConnection(null); + + // get Registration + Registration lRegistration = mRegistrationTab.get(aUserName); + if (lRegistration == null) { + throw new P2pProxyException("unknown user ["+aUserName+"]"); + } + boolean lrelayCandidateDetected = false; + //check if already have relay candidate + for (Object lMediaDescriptorObject :lOrigSessionDescriptor.getMediaDescriptors()) { + MediaDescriptor lMediaDescriptor = (MediaDescriptor)lMediaDescriptorObject; + MediaType lMediaType = MediaType.parseString(lMediaDescriptor.getMedia().getMedia()); + String lRelayCandidateValue = getRelayCandidate(lMediaDescriptor); + + if (lRelayCandidateValue != null) { + if (lRegistration.RtpRelays.containsKey(lMediaType) == false) {// get relay address from from candidate + CandidateAttributeParser lCandidateAttributeParser = new CandidateAttributeParser(lRelayCandidateValue); + lRegistration.RtpRelays.put(lMediaType, lCandidateAttributeParser.getAddress()); + mLog.info("relay candidate detected, adding relay ["+lCandidateAttributeParser.getAddress()+" for ["+lMediaDescriptor.getMedia().getMedia()+"]"); + } else { + lRegistration.RtpRelays.remove(lMediaType); + mLog.info("relay candidate removing address "); + } + lrelayCandidateDetected = true; + } else { + InetSocketAddress lInetSocketAddress=null; + if (lRegistration.RtpRelays.containsKey(lMediaType) == false) { + //put relay candidate from network + lRegistration.RtpRelays = mP2pProxyRtpRelayManagement.getAddresses(); + lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType); + } else { + lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType); + lRegistration.RtpRelays.remove(lMediaType); + mLog.info("no relay candidate relay removing address "); + } + + // build candidate attribute + CandidateAttributeParser lCandidateAttributeParser = new CandidateAttributeParser(lInetSocketAddress ); + // create new media desc + ConnectionField lConnectionField = new ConnectionField("IP4",lInetSocketAddress.getAddress().getHostAddress()); + MediaField lOrigMediaField = lMediaDescriptor.getMedia(); + MediaField lNewMediaField = new MediaField(lOrigMediaField.getMedia() + , lInetSocketAddress.getPort() //new port + , 0 + , lOrigMediaField.getTransport() + , lOrigMediaField.getFormatList()); + MediaDescriptor lNewMediaDescriptor = new MediaDescriptor(lNewMediaField,lConnectionField); + for (Object lAttributeField:lMediaDescriptor.getAttributes()) { + lNewMediaDescriptor.addAttribute((AttributeField) lAttributeField); + } + // add relay candidate + AttributeField lAttributeField = new AttributeField("candidate", lCandidateAttributeParser.toString()); + lNewMediaDescriptor.addAttribute(lAttributeField); + lNewSessionDescriptor.addMediaDescriptor(lNewMediaDescriptor); + } + + } + if (lrelayCandidateDetected == false) { + //to work-around mjsip bug + lNewSessionDescriptor.setConnection(((MediaDescriptor)lNewSessionDescriptor.getMediaDescriptors().elementAt(0)).getConnection()); + aMessage.setBody(lNewSessionDescriptor.toString()); + mLog.debug("new sdp:" +aMessage.getBody()); + } + + } + } + + private String getRelayCandidate(MediaDescriptor aMediaDescriptor) { + //1 get candidate + for (Object lField:aMediaDescriptor.getAttributes()) { + AttributeField lAttributeField = (AttributeField)lField; + if (lAttributeField.getAttributeName().equalsIgnoreCase("candidate") && lAttributeField.getAttributeValue().contains(CANDIDATE_RELAY_NAME)) { + return lAttributeField.getAttributeValue(); + } + } + return null; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/MediaType.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/MediaType.java new file mode 100644 index 000000000..3761b885f --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/MediaType.java @@ -0,0 +1,38 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +MediaType.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import org.linphone.p2pproxy.api.P2pProxyException; + +public enum MediaType { + audio,video,any; + static MediaType parseString (String value) throws P2pProxyException{ + if ("audio".equals(value)) { + return audio; + } else if("video".equals(value)) { + return video; + } else if("any".equals(value)) { + return any; + } else { + throw new P2pProxyException("unknown media type ["+value+"]"); + } + } +} + diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RouteAddRequest.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RouteAddRequest.java new file mode 100644 index 000000000..7bf52c510 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RouteAddRequest.java @@ -0,0 +1,57 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RouteAddRequest.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.Serializable; +import java.net.SocketAddress; + +public class RouteAddRequest implements Serializable { + private final SocketAddress mSource; + private final SocketAddress mDest; + private final MediaType mMediaType; + private static final long serialVersionUID = 1L; + public RouteAddRequest(SocketAddress aSource, SocketAddress aDest,MediaType aMediaType) { + mSource = aSource; + mDest = aDest; + mMediaType = aMediaType; + } + /** + * @return Returns the mSource. + */ + public SocketAddress getSource() { + return mSource; + } + /** + * @return Returns the mDest. + */ + public SocketAddress getDest() { + return mDest; + } + /** + * @return Returns the mMediaType. + */ + public MediaType getMediaType() { + return mMediaType; + } + public String toString() { + return "source ["+mSource+"] dest ["+mDest+"] type ["+mMediaType+"]"; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RouteAddResponse.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RouteAddResponse.java new file mode 100644 index 000000000..106cf1b16 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RouteAddResponse.java @@ -0,0 +1,50 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RouteAddResponse.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.Serializable; +import java.net.SocketAddress; + +public class RouteAddResponse implements Serializable { + private static final long serialVersionUID = 1L; + private final SocketAddress mSocketAddress; + private final MediaType mMediaType; + + public RouteAddResponse(SocketAddress aSocketAddress,MediaType aMediaType) { + mSocketAddress = aSocketAddress; + mMediaType =aMediaType; + } + public String toString() { + return "sdp adress ["+mSocketAddress+"] type ["+mMediaType+"]"; + } + /** + * @return Returns the mMediaType. + */ + public MediaType getMediaType() { + return mMediaType; + } + /** + * @return Returns the mSocketAddress. + */ + public SocketAddress getSocketAddress() { + return mSocketAddress; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RoutingTable.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RoutingTable.java new file mode 100644 index 000000000..c1afd50ce --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RoutingTable.java @@ -0,0 +1,60 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RoutingTable.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; + +public class RoutingTable implements RtpRoutingRules { + private final static Logger mLog = Logger.getLogger(RoutingTable.class); + static private RoutingTable mInstance = new RoutingTable(); + private final Map mTable = new HashMap(); + + private RoutingTable() { + + } + static public RoutingTable getInstance() { + return mInstance; + } + /** + * @param aSource + * @return null if not found + */ + public SocketAddress getRoute(SocketAddress aSource) { + return mTable.get(aSource); + } + public void addRoute(int anSsrc, InetSocketAddress source) { + mLog.info("route for ["+anSsrc+"] dest ["+source+"] added"); + + } + public SocketAddress getRoute(int anSsrc) throws P2pProxyException { + // TODO Auto-generated method stub + return null; + } + public void removeRoute(int anSsrc) { + mLog.info("route for ["+anSsrc+"] removed"); + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServer.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServer.java new file mode 100644 index 000000000..b57b7df9f --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServer.java @@ -0,0 +1,326 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +UdpSession.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.GenericUdpSession; + + + +public class RtpRelayServer implements GenericUdpSession.MessageHandler { + private final static Logger mLog = Logger.getLogger(RtpRelayServer.class); + private final GenericUdpSession mGenericUdpSession; + + class RoutingTable { + class GarbageCollectorTask extends TimerTask { + + public void run() { + synchronized (RtpRelayServer.RoutingTable.this) { + for (RoutingElement lElement :new HashMap (mSessionIdTable).values()) { + if (System.currentTimeMillis() - lElement.getLastAccess() > mMaxSilenceDuration) { + mLog.info("removing element ["+lElement+"]"); + mSessionIdTable.remove(lElement.mSessionId); + mSsrcElementTable.remove(lElement.mSsrcA); + mSsrcElementTable.remove(lElement.mSsrcB); + } + } + } + } + } + class RoutingElement { + //private final String mSessionId; + private SocketAddress mPeerARtp; + private SocketAddress mPeerARtcp; + private long mSsrcA; + private SocketAddress mPeerBRtp; + private SocketAddress mPeerBRtcp; + private long mSsrcB; + private long mLastDestAddressAccess = System.currentTimeMillis(); + private final String mSessionId; + RoutingElement(long aSsrc, String aSessionId) { + mSsrcA = aSsrc; + mSessionId = aSessionId; + } + void setPeerAddress(SocketAddress aReceivedAddress,long aSsrc,boolean isRtcp) { + if (aSsrc == mSsrcA ) { + if (isRtcp) { + mPeerARtcp = aReceivedAddress; + } else { + mPeerARtp = aReceivedAddress; + } + } else if (aSsrc == mSsrcB) { + if (isRtcp) { + mPeerBRtcp = aReceivedAddress; + } else { + mPeerBRtp = aReceivedAddress; + } + } else { + mLog.warn("ssrc ["+aSsrc+" not found for ["+aReceivedAddress+"]"); + } + } + void setPeerBSsrc(long aSsrc) { + mSsrcB = aSsrc; + } + public SocketAddress getDestAddr(long aSourceSsrc,boolean isRtcp) throws P2pProxyException{ + mLastDestAddressAccess = System.currentTimeMillis(); + if (aSourceSsrc == mSsrcA && isRtcp) { + if ( mPeerBRtcp != null) { + return mPeerBRtcp ; + } else { + throw new P2pProxyException("PeerBRtcp not found for ssrc ["+aSourceSsrc+"]"); + } + } else if (aSourceSsrc == mSsrcA && !isRtcp) { + + if ( mPeerBRtp != null) { + return mPeerBRtp ; + } else { + throw new P2pProxyException("PeerBRtp not found for ssrc ["+aSourceSsrc+" "); + } + } else if (aSourceSsrc == mSsrcB && isRtcp) { + + if ( mPeerARtcp != null) { + return mPeerARtcp ; + } else { + throw new P2pProxyException("PeerARtcp not found for ssrc ["+aSourceSsrc+" "); + } + } else if (aSourceSsrc == mSsrcB && !isRtcp) { + + if ( mPeerARtp != null) { + return mPeerARtp ; + } else { + throw new P2pProxyException("PeerARtp not found for ssrc ["+aSourceSsrc+" "); + } + }else { + throw new P2pProxyException("ssrc ["+aSourceSsrc+" not found"); + } + + } + public long getLastAccess() { + return mLastDestAddressAccess; + } + public String toString() { + return "Session id ["+mSessionId+"] ssrc a ["+mSsrcA+"] rtp source ["+mPeerARtp+"] rtcp source ["+mPeerARtcp+"]" + +"ssrc b ["+mSsrcB+"] rtp source ["+mPeerBRtp+"] rtcp source ["+mPeerBRtcp+"]"; + } + } + private final Map mSessionIdTable = new HashMap (); + private final Map mSsrcElementTable = new HashMap (); + private final long mMaxSilenceDuration ; + private final long mGCPeriod; + Timer mTimer = new Timer("Routing Elements GC"); + + public RoutingTable (long aMaxSilenceDuration, long aGCPeriod) { + mMaxSilenceDuration = aMaxSilenceDuration; + mGCPeriod = aGCPeriod; + mTimer.scheduleAtFixedRate(new GarbageCollectorTask(), 0, mGCPeriod); + } + public synchronized boolean containsSessionId(String aSessionId) { + return mSessionIdTable.containsKey(aSessionId); + } + + public synchronized void addRoutingElement(String aSessionId, long aSsrc) { + if (mLog.isInfoEnabled()) mLog.info("add routing element for session id ["+aSessionId+"] with ssrc ["+aSsrc+"]"); + RoutingElement lRoutingElement = new RoutingElement(aSsrc,aSessionId); + mSessionIdTable.put(aSessionId, lRoutingElement); + mSsrcElementTable.put(aSsrc, lRoutingElement); + } + + public synchronized void UpdateRoutingElement(String aSessionId, long aSsrc) { + if (mLog.isInfoEnabled()) mLog.info("update routing element session id ["+aSessionId+"] with ssrc ["+aSsrc+"]"); + RoutingElement lRoutingElement = mSessionIdTable.get(aSessionId); + lRoutingElement.setPeerBSsrc(aSsrc); + mSsrcElementTable.put(aSsrc, lRoutingElement); + + } + + public synchronized void updateSourceAddress(long aSsrc, SocketAddress aSocketAddress,boolean isRtcp) throws P2pProxyException{ + if (mSsrcElementTable.containsKey(aSsrc) == false) { + throw new P2pProxyException("No routing element present for ssrc["+aSsrc+"]"); + } + if (mLog.isInfoEnabled()) mLog.info("update routing element for ssrc ["+aSsrc+"] with address ["+aSocketAddress+"]" ); + RoutingElement lRoutineElement = mSsrcElementTable.get(aSsrc); + lRoutineElement.setPeerAddress(aSocketAddress, aSsrc, isRtcp); + } + public synchronized SocketAddress getDestAddress(long aSsrc,boolean isRtcp) throws P2pProxyException{ + //1 check if element exist for this ssrc + if (mSsrcElementTable.containsKey(aSsrc) == false) { + throw new P2pProxyException("No routing element present for ssrc["+aSsrc+"]"); + } + RoutingElement lRoutingElement = mSsrcElementTable.get(aSsrc); + return lRoutingElement.getDestAddr(aSsrc, isRtcp); + } + public synchronized int getSize() { + return mSessionIdTable.size(); + } + } + + + + private static final String SESSIONID_NAME="RSID"; //Relay session Id + private final RoutingTable mRoutingTable; + public RtpRelayServer(InetSocketAddress aSocketAddress) throws SocketException, UnknownHostException { + this(aSocketAddress,3600000,60000); + } + public RtpRelayServer(InetSocketAddress aSocketAddress,long aMaxSilenceDuration, long aGCPeriod) throws SocketException, UnknownHostException { + mRoutingTable = new RoutingTable(aMaxSilenceDuration,aGCPeriod); + mGenericUdpSession = new GenericUdpSession(aSocketAddress,this); + } + public void onMessage(DatagramPacket aMessage) { + try { + if (mLog.isInfoEnabled()) mLog.info("new incoming message from ["+aMessage.getSocketAddress()+"]"); + long lSsrc = getSsrc(aMessage); + if (isSessionIdPresent(aMessage)) { + String lSessionId = getSessionId(aMessage); + //1 check if already exist + if (mRoutingTable.containsSessionId(lSessionId)) { + //second call, update ssrc + mRoutingTable.UpdateRoutingElement(lSessionId,lSsrc); + + } else { + //first call + mRoutingTable.addRoutingElement(lSessionId,lSsrc); + } + } + mRoutingTable.updateSourceAddress(lSsrc, aMessage.getSocketAddress(),isRtcp(aMessage)); + + SocketAddress lDestAddress = mRoutingTable.getDestAddress(lSsrc,isRtcp(aMessage)); + //does not forward session id msg + if (!isSessionIdPresent(aMessage)) { + // ok forwarding + if (mLog.isInfoEnabled()) mLog.info("forwarding ["+aMessage.getLength()+"] bytes from ["+aMessage.getSocketAddress()+"] to ["+lDestAddress+"]"); + aMessage.setSocketAddress(lDestAddress); + mGenericUdpSession.getSocket().send(aMessage); + } + } catch (IOException e) { + mLog.error("cannot forward ["+aMessage+"]", e); + } catch (Exception e) { + mLog.warn("unknown destination for message from ["+aMessage.getSocketAddress()+"] discarding",e); + + } + } + public InetSocketAddress getInetSocketAddress() { + return (InetSocketAddress) mGenericUdpSession.getSocket().getLocalSocketAddress(); + } + public void close() { + mGenericUdpSession.close(); + } + private long getSsrc(DatagramPacket aMessage) { +// The RTP header has the following format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P|X| CC |M| PT | sequence number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | synchronization source (SSRC) identifier | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | contributing source (CSRC) identifiers | +// | .... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (isRtcp(aMessage)) { + //rtcp packet + return b2UB(aMessage.getData()[7]) + + (b2UB(aMessage.getData()[6]) << 8) + + (b2UB(aMessage.getData()[5]) << 16) + + (b2UB(aMessage.getData()[4]) << 24); + } else { + //rtp packet + return b2UB(aMessage.getData()[11]) + + (b2UB(aMessage.getData()[10]) << 8) + + (b2UB(aMessage.getData()[9]) << 16) + + (b2UB(aMessage.getData()[8]) << 24); + } + + } + private boolean isSessionIdPresent(DatagramPacket aMessage) { +// APP: Application-Defined RTCP Packet +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| subtype | PT=APP=204 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC/CSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | name (ASCII) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | application-dependent data ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (b2UB(aMessage.getData()[1]) != 204) return false; + String aName = String.valueOf((char)b2UB(aMessage.getData()[8])) + + String.valueOf((char)b2UB(aMessage.getData()[9])) + + String.valueOf((char)b2UB(aMessage.getData()[10])) + + String.valueOf((char)b2UB(aMessage.getData()[11])); + return SESSIONID_NAME.equalsIgnoreCase(aName); + } + + private String getSessionId(DatagramPacket aMessage) throws P2pProxyException{ +// APP: Application-Defined RTCP Packet +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| subtype | PT=APP=204 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC/CSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | name (ASCII) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | application-dependent data ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (isSessionIdPresent(aMessage) == false) { + throw new P2pProxyException("Cannot find SessionId"); + } + long lPacketLenght = 1 + b2UB(aMessage.getData()[3]) + (b2UB(aMessage.getData()[2]) << 8) ; + StringBuffer lSessionId = new StringBuffer(); + for (int i = 12 ; i< lPacketLenght; i++) { + lSessionId.append(b2UB(aMessage.getData()[i])); + } + return lSessionId.toString(); + + } + private boolean isRtcp(DatagramPacket aMessage) { + return b2UB(aMessage.getData()[1]) >= 200 ; + } + public static int b2UB(byte b) { + return b >= 0 ? b : 256 + b; + } + + //stats + public int getRoutingtableSize() { + return mRoutingTable.getSize(); + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServerConfig.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServerConfig.java new file mode 100644 index 000000000..9f49887af --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServerConfig.java @@ -0,0 +1,28 @@ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.net.InetSocketAddress; + +/** + */ +public class RtpRelayServerConfig { + private final InetSocketAddress mAudioVideoPublicSocketAddress; + private final InetSocketAddress mVideovideoPrivateSocketAddress; + + public RtpRelayServerConfig(InetSocketAddress anAudioVideoPublicSocketAddress,InetSocketAddress anAudioVideoPrivateSocketAddress) { + mAudioVideoPublicSocketAddress = anAudioVideoPublicSocketAddress; + mVideovideoPrivateSocketAddress = anAudioVideoPrivateSocketAddress; + } + + /** + * @return Returns the mAudioPublicSocketAddress. + */ + public InetSocketAddress getAudioVideoPublicSocketAddress() { + return mAudioVideoPublicSocketAddress; + } + /** + * @return Returns the mVideoPublicSocketAddress. + */ + public InetSocketAddress getAudioVideoPrivateSocketAddress() { + return mVideovideoPrivateSocketAddress; + } +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayService.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayService.java new file mode 100644 index 000000000..9929ad496 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayService.java @@ -0,0 +1,134 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +UdpRelayService.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.Configurator; +import org.linphone.p2pproxy.core.GenericService; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.ServiceProvider; + + +public class RtpRelayService implements ServiceProvider{ + private final static Logger mLog = Logger.getLogger(RtpRelayService.class); + private final RtpRelayServer mRtpRelayServer; + public final static String AUDIO_VIDEO_LOCAL_PORT="org.linphone.p2pproxy.udp-media-relay.audio-video.port"; + public final static String AUDIO_VIDEO_PUBLIC_URI="org.linphone.p2pproxy.udp-media-relay.audio-video.public-uri"; + private final static String SRV_NAME = "RTPRELAY"; + public final static String ADV_NAME = "JXTASPEC:LINPHONE-"+SRV_NAME; + // + private final RtpRelayServerConfig mConfig; + private final GenericService mGenericService; + private class SocketHandlerFactory implements GenericService.ServiceSocketHandlerFactory { + + public Runnable create(final Socket socket) { + return new Runnable() { + public void run() { + try { + ObjectOutputStream lOut = new ObjectOutputStream(socket.getOutputStream()); + //work around to unlock the socket + lOut.writeBoolean(true); + lOut.flush(); + ObjectInputStream lIn = new ObjectInputStream(socket.getInputStream()); + Object lInputObj; + boolean lStop = false; + while (lStop == false) { + lInputObj = lIn.readObject(); + mLog.info("request message ["+lInputObj+"] received"); + if (lInputObj instanceof AddressRequest) { + SingleAddressResponse lAddressResponse = new SingleAddressResponse(mConfig.getAudioVideoPublicSocketAddress()); + lOut.writeObject(lAddressResponse); + lOut.flush(); + } else { + mLog.error("unknown request ["+lInputObj+"]"); + + } + + lStop = true; + } + } catch (Exception e) { + mLog.error("socket instance error",e); + } + finally { + try { + socket.close(); + } catch (IOException e) { + mLog.error("cannot close socket ",e); + } + } + } + }; + } + } + + + + /** + * @param properties mandatory parameter are: + * {@link AUDIO_LOCAL_PORT} ,{@link AUDIO_PUBLIC_URI} , {@link VIDEO_LOCAL_PORT}, {@link VIDEO_PUBLIC_URI} + * @param jxtaNetworkManager + * @param serviceName + * @param serviceSocketHandlerFactory + * @throws SocketException + * @throws UnknownHostException + */ + public RtpRelayService(RtpRelayServerConfig aConfig,Configurator properties, JxtaNetworkManager jxtaNetworkManager) throws SocketException, UnknownHostException { + + mGenericService = new GenericService(properties, jxtaNetworkManager,SRV_NAME ,new SocketHandlerFactory()); + mConfig = aConfig; + mRtpRelayServer = new RtpRelayServer(mConfig.getAudioVideoPrivateSocketAddress()); + mLog.info("UdpRelayService created "+this); + } + + + public String toString() { + return mRtpRelayServer +" public address ["+mConfig.getAudioVideoPublicSocketAddress()+"] private address address ["+mConfig.getAudioVideoPrivateSocketAddress()+"]"; + } + + public void start(long timeOut) throws P2pProxyException { + mGenericService.start(timeOut); + + } + + public void stop() { + mRtpRelayServer.close(); + mGenericService.stop(); + + } + public static String getDefaultAudioVideoPublicUri() throws UnknownHostException { + return "udp://"+InetAddress.getLocalHost().getHostAddress()+":16000"; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServiceClient.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServiceClient.java new file mode 100644 index 000000000..0f764e4b1 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRelayServiceClient.java @@ -0,0 +1,53 @@ +package org.linphone.p2pproxy.core.media.rtprelay; + + +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Map; + + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.Configurator; +import org.linphone.p2pproxy.core.GenericServiceClient; +import org.linphone.p2pproxy.core.JxtaNetworkManager; + +public class RtpRelayServiceClient extends GenericServiceClient { + private final static Logger mLog = Logger.getLogger(RtpRelayServiceClient.class); + + + public RtpRelayServiceClient(Configurator aProperties,JxtaNetworkManager aJxtaNetworkManager) throws SocketException, UnknownHostException { + super (aProperties,aJxtaNetworkManager,RtpRelayService.ADV_NAME); + } + + public void stop() { + super.stop(); + } + + + + public Map getAddresses() throws P2pProxyException { + try { + checkObject(); + checkSocketConnection(); + AddressRequest lAddressRequest = new AddressRequest(); + mOut.writeObject(lAddressRequest); + mOut.flush(); + mLog.info("request message ["+lAddressRequest+"] sent"); + Object lInputObj = mIn.readObject(); + mLog.info("response message ["+lInputObj+"] received"); + if(lInputObj instanceof AddressResponse) { + AddressResponse lAddressResponse = (AddressResponse)lInputObj; + if (mLog.isDebugEnabled()) mLog.debug("receiving relay address ["+lAddressResponse.toString()+"]"); + return lAddressResponse.getAddressTable(); + } else { + throw new P2pProxyException("unknown response ["+lInputObj+"]"); + } + } catch(Exception e) { + throw new P2pProxyException(e); + } + + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRoutingRules.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRoutingRules.java new file mode 100644 index 000000000..0660a7789 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/RtpRoutingRules.java @@ -0,0 +1,48 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +RtpRoutingRules.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import org.linphone.p2pproxy.api.P2pProxyException; + +public interface RtpRoutingRules { + + /** + * add route for a given ssrc + * @param aSource + */ + public void addRoute(int anSsrc, InetSocketAddress aSource); + + /** + * remove route + * @param aSource + */ + public void removeRoute(int anSsrc); + + /** + * return dest address + * @param aSource + * @return the destination address + * @throws P2pProxyException + */ + public SocketAddress getRoute(int anSsrc) throws P2pProxyException; +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/SdpProcessorImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/SdpProcessorImpl.java new file mode 100644 index 000000000..fac12b043 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/SdpProcessorImpl.java @@ -0,0 +1,222 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +SdpProcessorImpl.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.StringTokenizer; + +import net.jxta.pipe.OutputPipe; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyRtpRelayManagement; +import org.linphone.p2pproxy.core.SdpProcessor; +import org.linphone.p2pproxy.core.SipProxyRegistrar.Registration; +import org.zoolu.sdp.AttributeField; +import org.zoolu.sdp.ConnectionField; +import org.zoolu.sdp.MediaDescriptor; +import org.zoolu.sdp.MediaField; +import org.zoolu.sdp.SessionDescriptor; +import org.zoolu.sip.message.Message; + +/** + * rewrite SDP to insert an ICE aware rtp relay + * + * + */ +public class SdpProcessorImpl implements SdpProcessor { + private final String CANDIDATE_RELAY_NAME="relay"; + + class CandidateAttributeParser { + final private String mCandidateAttribute; + + final private String mfoundation; + final private String mComponentId; + final private String mTransport; + final private String mPriority; + final private String mConnectionAddress; + final private String mPort; + final private String mType; + + public CandidateAttributeParser(String aCandidateAttribute){ + mCandidateAttribute = aCandidateAttribute; + StringTokenizer st = new StringTokenizer(mCandidateAttribute); + mfoundation = st.nextToken(); + mComponentId = st.nextToken(); + mTransport = st.nextToken(); + mPriority = st.nextToken(); + mConnectionAddress = st.nextToken(); + mPort = st.nextToken(); + st.nextToken(); //skip typ + mType = st.nextToken();; + } + public CandidateAttributeParser(InetSocketAddress aRelayAddress){ + mfoundation = "3"; + mComponentId = "1"; + mTransport = "UDP"; + mPriority = "0"; + mConnectionAddress = aRelayAddress.getAddress().getHostAddress(); + mPort = String.valueOf(aRelayAddress.getPort()); + mType = CANDIDATE_RELAY_NAME; + mCandidateAttribute = toString(); + } + + InetSocketAddress getAddress() { + return new InetSocketAddress(mConnectionAddress,Integer.parseInt(mPort)); + } + public String toString() { + return mfoundation +" "+ mComponentId +" "+ mTransport +" "+ mPriority +" "+ mConnectionAddress +" "+ mPort +" typ " +mType; + } + } + + private final static Logger mLog = Logger.getLogger(SdpProcessorImpl.class); + private final Map mRegistrationTab; + private final P2pProxyRtpRelayManagement mP2pProxyRtpRelayManagement; + public SdpProcessorImpl(Map aRegistrationTab,P2pProxyRtpRelayManagement aP2pProxyRtpRelayManagement) { + mRegistrationTab = aRegistrationTab; + mP2pProxyRtpRelayManagement = aP2pProxyRtpRelayManagement; + + } + public void processSdpAfterSentToPipe(Message message, OutputPipe outputPipe) + throws P2pProxyException { + //nop + + } + + public void processSdpBeforeSendingToSipUA(Message aMessage) throws P2pProxyException { + String lUserName=""; + if (aMessage.isInvite()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isResponse()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isAck()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else { + mLog.warn("strange, sdp in message ["+aMessage+"]"); + } + processSdp(aMessage,lUserName); + } + + public void processSdpBeforeSendingToPipe(Message aMessage) throws P2pProxyException { + String lUserName=""; + if (aMessage.isInvite()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isResponse()) { + lUserName = aMessage.getToHeader().getNameAddress().getAddress().toString(); + } else if (aMessage.isAck()) { + lUserName = aMessage.getFromHeader().getNameAddress().getAddress().toString(); + } else { + mLog.warn("strange, sdp in message ["+aMessage+"]"); + } + processSdp(aMessage,lUserName); + } + + //check if already have relay candidate + //1 search for relay if not available + //2 rewrite c line /port + //3 add candidate + //4 if relay was available, clean relay + private void processSdp(Message aMessage, String aUserName) throws P2pProxyException { + //check if sdp present + if (aMessage.hasBody() && "application/sdp".equals(aMessage.getBodyType())) { + SessionDescriptor lOrigSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + + SessionDescriptor lNewSessionDescriptor = new SessionDescriptor(aMessage.getBody()); + lNewSessionDescriptor.removeMediaDescriptors(); + lNewSessionDescriptor.setConnection(null); + + // get Registration + Registration lRegistration = mRegistrationTab.get(aUserName); + if (lRegistration == null) { + throw new P2pProxyException("unknown user ["+aUserName+"]"); + } + boolean lrelayCandidateDetected = false; + //check if already have relay candidate + for (Object lMediaDescriptorObject :lOrigSessionDescriptor.getMediaDescriptors()) { + MediaDescriptor lMediaDescriptor = (MediaDescriptor)lMediaDescriptorObject; + MediaType lMediaType = MediaType.parseString(lMediaDescriptor.getMedia().getMedia()); + String lRelayCandidateValue = getRelayCandidate(lMediaDescriptor); + + if (lRelayCandidateValue != null) { + if (lRegistration.RtpRelays.containsKey(lMediaType) == false) {// get relay address from from candidate + CandidateAttributeParser lCandidateAttributeParser = new CandidateAttributeParser(lRelayCandidateValue); + lRegistration.RtpRelays.put(lMediaType, lCandidateAttributeParser.getAddress()); + mLog.info("relay candidate detected, adding relay ["+lCandidateAttributeParser.getAddress()+" for ["+lMediaDescriptor.getMedia().getMedia()+"]"); + } else { + lRegistration.RtpRelays.remove(lMediaType); + mLog.info("relay candidate removing address "); + } + lrelayCandidateDetected = true; + } else { + InetSocketAddress lInetSocketAddress=null; + if (lRegistration.RtpRelays.containsKey(lMediaType) == false) { + //put relay candidate from network + lRegistration.RtpRelays = mP2pProxyRtpRelayManagement.getAddresses(); + lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType); + } else { + lInetSocketAddress = lRegistration.RtpRelays.get(lMediaType); + lRegistration.RtpRelays.remove(lMediaType); + mLog.info("no relay candidate relay removing address "); + } + + // build candidate attribute + CandidateAttributeParser lCandidateAttributeParser = new CandidateAttributeParser(lInetSocketAddress ); + // create new media desc + ConnectionField lConnectionField = new ConnectionField("IP4",lInetSocketAddress.getAddress().getHostAddress()); + MediaField lOrigMediaField = lMediaDescriptor.getMedia(); + MediaField lNewMediaField = new MediaField(lOrigMediaField.getMedia() + , lInetSocketAddress.getPort() //new port + , 0 + , lOrigMediaField.getTransport() + , lOrigMediaField.getFormatList()); + MediaDescriptor lNewMediaDescriptor = new MediaDescriptor(lNewMediaField,lConnectionField); + for (Object lAttributeField:lMediaDescriptor.getAttributes()) { + lNewMediaDescriptor.addAttribute((AttributeField) lAttributeField); + } + // add relay candidate + AttributeField lAttributeField = new AttributeField("candidate", lCandidateAttributeParser.toString()); + lNewMediaDescriptor.addAttribute(lAttributeField); + lNewSessionDescriptor.addMediaDescriptor(lNewMediaDescriptor); + } + + } + if (lrelayCandidateDetected == false) { + //to work-around mjsip bug + lNewSessionDescriptor.setConnection(((MediaDescriptor)lNewSessionDescriptor.getMediaDescriptors().elementAt(0)).getConnection()); + aMessage.setBody(lNewSessionDescriptor.toString()); + mLog.debug("new sdp:" +aMessage.getBody()); + } + + } + } + + private String getRelayCandidate(MediaDescriptor aMediaDescriptor) { + //1 get candidate + for (Object lField:aMediaDescriptor.getAttributes()) { + AttributeField lAttributeField = (AttributeField)lField; + if (lAttributeField.getAttributeName().equalsIgnoreCase("candidate") && lAttributeField.getAttributeValue().contains(CANDIDATE_RELAY_NAME)) { + return lAttributeField.getAttributeValue(); + } + } + return null; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/SingleAddressResponse.java b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/SingleAddressResponse.java new file mode 100644 index 000000000..5907c1ea0 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/media/rtprelay/SingleAddressResponse.java @@ -0,0 +1,43 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +SingleAddressResponse.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.media.rtprelay; + +import java.io.Serializable; +import java.net.InetSocketAddress; + + +public class SingleAddressResponse implements Serializable { + private static final long serialVersionUID = 1L; + private final InetSocketAddress mAddress; + public SingleAddressResponse(InetSocketAddress anAddress) { + mAddress = anAddress; + } + /** + * @return Returns the relay adress. + */ + public InetSocketAddress getAddress() { + return mAddress; + } + + public String toString() { + + return mAddress.toString(); + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/AutoConfigService.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/AutoConfigService.java new file mode 100644 index 000000000..702201562 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/AutoConfigService.java @@ -0,0 +1,146 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +AutoConfigService.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Enumeration; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.document.XMLDocument; +import net.jxta.document.XMLElement; +import net.jxta.impl.protocol.HTTPAdv; +import net.jxta.impl.protocol.TCPAdv; +import net.jxta.peergroup.PeerGroup; +import net.jxta.protocol.TransportAdvertisement; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe; +import org.linphone.p2pproxy.core.Configurator; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.ServiceProvider; +import org.linphone.p2pproxy.core.media.rtprelay.RtpRelayService; + +public class AutoConfigService implements ServiceProvider { + private final static Logger mLog = Logger.getLogger(AutoConfigService.class); + private final JxtaNetworkManager mJxtaNetworkManager; + private final Configurator mProperties; + private final int mRelayCapacity; + private final P2pProxyNetworkProbe mP2pProxyManagement; + private InetAddress mPubliAddress; + public AutoConfigService(Configurator lProperties,JxtaNetworkManager aJxtaNetworkManager,P2pProxyNetworkProbe aServiceProvider) { + mJxtaNetworkManager = aJxtaNetworkManager; + mProperties = lProperties; + mP2pProxyManagement = aServiceProvider; + mRelayCapacity = Integer.parseInt(lProperties.getProperty(JxtaNetworkManager.RELAY_CAPACITY, "100")); + } + public void start(long aTimeOut) throws P2pProxyException { + try { + if(!mJxtaNetworkManager.isConnectedToRendezVous(aTimeOut)) + throw new P2pProxyException("Cannot start peer info service because not connected to any rdv"); + //check if capable + + mLog.info("AutoConfigService started"); + } + catch(Exception e) { + throw new P2pProxyException(e); + } + + } + + public void stop() { + mLog.info("AutoConfigService stopped"); + } + private HTTPAdv getHttpAdv() throws P2pProxyException { + + XMLDocument lHttpDoc = (XMLDocument) mJxtaNetworkManager.getPeerGroup().getConfigAdvertisement().getServiceParam(PeerGroup.httpProtoClassID); + if (lHttpDoc == null) { + throw new P2pProxyException("cannot find HTTPAdv"); + } + Enumeration lHttpChilds = lHttpDoc.getChildren( TransportAdvertisement.getAdvertisementType()); + // get the HTTPAdv from TransportAdv + if( lHttpChilds.hasMoreElements() ) { + return (HTTPAdv) AdvertisementFactory.newAdvertisement( (XMLElement) lHttpChilds.nextElement() ); + } else { + throw new P2pProxyException("cannot find HTTPAdv from transport"); + } + } + private TCPAdv getTcpAdv() throws P2pProxyException { + XMLDocument lTcpDoc = (XMLDocument) mJxtaNetworkManager.getPeerGroup().getConfigAdvertisement().getServiceParam(PeerGroup.tcpProtoClassID); + if (lTcpDoc == null) { + throw new P2pProxyException("cannot find TCPAdv"); + } + Enumeration lHttpChilds = lTcpDoc.getChildren( TransportAdvertisement.getAdvertisementType()); + // get the HTTPAdv from TransportAdv + if( lHttpChilds.hasMoreElements() ) { + return (TCPAdv) AdvertisementFactory.newAdvertisement( (XMLElement) lHttpChilds.nextElement() ); + } else { + throw new P2pProxyException("cannot find TCPAdv from transport"); + } + } + + /** + * test if the peer is capable to behave as a superpeer + * @return + */ + public boolean canIBehaveAsASuperPeer() { + boolean lHttpServerOk=false; + boolean lTcpServerOk=false; + + try { +// 1 check local ip + mPubliAddress = mP2pProxyManagement.getPublicIpAddress(); + //2 probe the http socket + InetSocketAddress lSocketAddress = new InetSocketAddress(mPubliAddress,getHttpAdv().getPort()); + lHttpServerOk = mP2pProxyManagement.probeSocket(lSocketAddress, P2pProxyNetworkProbe.Protocol.tcp); + + // 3 probe tcp socket + lSocketAddress = new InetSocketAddress(mPubliAddress,getTcpAdv().getPort()); + lTcpServerOk = mP2pProxyManagement.probeSocket(lSocketAddress, P2pProxyNetworkProbe.Protocol.tcp); + + if (lTcpServerOk || lHttpServerOk) { + mLog.info("can behave as a super peer :-)"); + return true; + } else { + mLog.info("cannot behave as a super peer :-("); + return false; + } + } catch (P2pProxyException e) { + mLog.info("cannot behave as a super peer", e); + return false; + } + } + public boolean startUdpProxyIfPossible() { + int lAudioVideoPort = Integer.parseInt(mProperties.getProperty(RtpRelayService.AUDIO_VIDEO_LOCAL_PORT,"16000")); + InetSocketAddress lSocketAddress=null; + try { + lSocketAddress = new InetSocketAddress(mPubliAddress,lAudioVideoPort); + mP2pProxyManagement.probeSocket(lSocketAddress, P2pProxyNetworkProbe.Protocol.udp); + return true; + }catch (P2pProxyException e) { + mLog.info("cannot open audio server on ["+lSocketAddress+"]", e); + } + return false; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/P2pproxyRdvListener.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/P2pproxyRdvListener.java new file mode 100644 index 000000000..444c265f3 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/P2pproxyRdvListener.java @@ -0,0 +1,33 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pproxyRdvListener.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + +import net.jxta.rendezvous.RendezvousEvent; +import net.jxta.rendezvous.RendezvousListener; + +public class P2pproxyRdvListener implements RendezvousListener { + + public void rendezvousEvent(RendezvousEvent event) { + // TODO Auto-generated method stub + + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoProvider.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoProvider.java new file mode 100644 index 000000000..93c55ebd2 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoProvider.java @@ -0,0 +1,33 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +PeerInfoProvider.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + +import java.net.InetAddress; + +public interface PeerInfoProvider { + /** + * get the public address as found in the http header during the ping procedure. + * @param aPeerAddress jxta address + * @return an IP address or null + */ + public InetAddress getPublicAddress(String aPeerAddress); + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoProviderService.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoProviderService.java new file mode 100644 index 000000000..aa11a8688 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoProviderService.java @@ -0,0 +1,233 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +PeerInfoProviderService.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + + + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URI; + +import net.jxta.document.AdvertisementFactory; +import net.jxta.id.IDFactory; +import net.jxta.platform.ModuleClassID; +import net.jxta.platform.ModuleSpecID; +import net.jxta.protocol.ModuleClassAdvertisement; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.protocol.PipeAdvertisement; +import net.jxta.socket.JxtaServerSocket; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.core.Configurator; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.ServiceProvider; +import org.linphone.p2pproxy.core.jxtaext.EndpointRegistry; + + + +public class PeerInfoProviderService implements Runnable,PeerInfoProvider,ServiceProvider{ + private final JxtaNetworkManager mJxtaNetworkManager; + private final Configurator mProperties; + public final static String PEER_INFO_SERVICE_PIPE_ID="org.linphone.p2pproxy.PeerInfoProviderService.bidi-pipe.id"; + private final static Logger mLog = Logger.getLogger(PeerInfoProviderService.class); + private JxtaServerSocket mJxtaServerSocket; + private Thread mSocketServerThread = new Thread(this,"PeerInfoProviderService server thread"); + public final static String ADV_NAME = "JXTASPEC:LINPHONE-PEERINFO"; + private final static int SO_TIMOUT=3000; + public final static String PEERINFO_MODULE_CLASS_ID="org.linphone.p2pproxy.PeerInfoProviderService.module-class.id"; + public final static String PEERINFO_MODULE_SPEC_ID="org.linphone.p2pproxy.PeerInfoProviderService.module-spec.id"; + + public PeerInfoProviderService(Configurator lProperties,JxtaNetworkManager aJxtaNetworkManager) { + mJxtaNetworkManager = aJxtaNetworkManager; + mProperties = lProperties; + } + + public void start(long l) throws P2pProxyException { + try { + mLog.info("Start the PeerInfoProviderService daemon"); + ModuleClassAdvertisement lModuleAdvertisement = (ModuleClassAdvertisement) AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType()); + + lModuleAdvertisement.setName("JXTAMOD:LINPHONE-PEERINFO"); + lModuleAdvertisement.setDescription("Service to provide peer with data like its public ip,etc"); + + ModuleClassID lModuleClassID; + // to avoid ID creation at each start + if (mProperties.getProperty(PEERINFO_MODULE_CLASS_ID) == null) { + lModuleClassID = IDFactory.newModuleClassID(); + mProperties.setProperty(PEERINFO_MODULE_CLASS_ID, lModuleClassID.toURI().toString()); + } else { + lModuleClassID = (ModuleClassID) IDFactory.fromURI(URI.create(mProperties.getProperty(PEERINFO_MODULE_CLASS_ID))); + } + lModuleAdvertisement.setModuleClassID(lModuleClassID); + + // publish local only + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().publish(lModuleAdvertisement); + + ModuleSpecAdvertisement lModuleSpecAdvertisement = (ModuleSpecAdvertisement)AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType()); + lModuleSpecAdvertisement.setName(ADV_NAME); + lModuleSpecAdvertisement.setVersion("Version 1.0"); + lModuleSpecAdvertisement.setCreator("linphone.org"); + // to avoid ID creation at each start + ModuleSpecID lModuleSpecId; + if (mProperties.getProperty(PEERINFO_MODULE_SPEC_ID) == null) { + lModuleSpecId = IDFactory.newModuleSpecID(lModuleClassID); + mProperties.setProperty(PEERINFO_MODULE_SPEC_ID, lModuleSpecId.toURI().toString()); + } else { + lModuleSpecId = (ModuleSpecID) IDFactory.fromURI(URI.create(mProperties.getProperty(PEERINFO_MODULE_SPEC_ID))); + } + lModuleSpecAdvertisement.setModuleSpecID(lModuleSpecId); + lModuleSpecAdvertisement.setSpecURI("http://www.linphone.org/peerinfo"); + + PipeAdvertisement lSocketAdvertisement = mJxtaNetworkManager.createPipeAdvertisement(PEER_INFO_SERVICE_PIPE_ID, "peer-info-service"); + + lModuleSpecAdvertisement.setPipeAdvertisement(lSocketAdvertisement); + mJxtaServerSocket = new JxtaServerSocket(mJxtaNetworkManager.getPeerGroup(), lSocketAdvertisement, 10); + mJxtaServerSocket.setSoTimeout(0); + mSocketServerThread.start(); + //publish local only + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().publish(lModuleSpecAdvertisement); + mLog.info("Adv ["+lModuleSpecAdvertisement+"] published"); + } + catch(Exception e) + { + PeerInfoProviderService.mLog.error("socket instance error", e); + } + } + public void stop(){ + throw new RuntimeException("Not implemented"); + } + + public void run() { + while (true) { + try { + mLog.info("Waiting for connection on ["+ADV_NAME+"]"); + Socket lSocket = mJxtaServerSocket.accept(); + // set reliable + if (lSocket != null) { + mLog.info("socket created"); + Thread thread = new Thread(new PeerInfoProviderServiceHandler(lSocket), "Connection Handler Thread"); + thread.start(); + } + } catch (Exception e) { + mLog.error("Server socket error",e); + } + } + + } + class PeerInfoProviderServiceHandler implements Runnable { + Socket mSocket = null; + + PeerInfoProviderServiceHandler(Socket aSocket) { + mSocket = aSocket; + } + + public void run() { + try { + ObjectOutputStream lOut = new ObjectOutputStream(mSocket.getOutputStream()); + //work around to unlock the socket + lOut.writeBoolean(true); + lOut.flush(); + ObjectInputStream lIn = new ObjectInputStream(mSocket.getInputStream()); + Object lInputObj; + Object lOutputObj; + boolean lStop = false; + while (lStop == false) { + lInputObj = lIn.readObject(); + mLog.info("request message ["+lInputObj+"] received"); + + if (lInputObj instanceof PublicIpAddressRequest) { +// PublicIpAddressRequest + PublicIpAddressRequest lPublicIpAddressRequest = (PublicIpAddressRequest) lInputObj; + InetAddress lInetAddress = getPeerInfoProvider().getPublicAddress(lPublicIpAddressRequest.getPeerId()); + PublicIpAddressResponse lPublicIpAddressResponse; + if (lInetAddress == null) { + lPublicIpAddressResponse = new PublicIpAddressResponse("address not found for["+lPublicIpAddressRequest.getPeerId()+"]"); + } else { + lPublicIpAddressResponse = new PublicIpAddressResponse(lInetAddress); + } + lOutputObj = lPublicIpAddressResponse; + lOut.writeObject(lOutputObj); + lOut.flush(); + mLog.info("request reponse ["+lOutputObj+"] sent"); + } else if (lInputObj instanceof SocketProbeRequest) { +// SocketProbeRequest + SocketProbeRequest lSocketProbeRequest = (SocketProbeRequest)lInputObj; + switch (lSocketProbeRequest.getProtocol()) { + case tcp: { + Socket lSocket = new Socket(); + lSocket.setSoTimeout(SO_TIMOUT); + + try { + lSocket.connect(lSocketProbeRequest.getSocketAddress()); + mLog.info("socket ["+lSocketProbeRequest+"] is reachable"); + }catch (Exception e) { + mLog.info("cannot reach ["+lSocketProbeRequest+"] in mode ["+lSocketProbeRequest.getProtocol()+"] for"+SO_TIMOUT+""); + } + lSocket.close(); + break; + } + case udp: { + DatagramSocket lSocket = new DatagramSocket(); + String lPing = "ping"; + DatagramPacket lDatagramPacket = new DatagramPacket(lPing.getBytes(),lPing.getBytes().length); + lDatagramPacket.setSocketAddress(lSocketProbeRequest.getSocketAddress()); + lSocket.send(lDatagramPacket); + mLog.info("ping sent to socket ["+lSocketProbeRequest+"] in mode ["+lSocketProbeRequest.getProtocol()+"]"); + lSocket.close(); + break; + } + default: throw new P2pProxyException("unsupported protocol ["+lSocketProbeRequest.getProtocol()+"]"); + } + + }else { + mLog.error("unknown request ["+lInputObj+"]"); + lOutputObj = null; + } + + + } + } catch (Exception e) { + mLog.error("socket instance error",e); + } + finally { + try { + mSocket.close(); + } catch (IOException e) { + mLog.error("cannot close socket ",e); + } + } + } + } + public PeerInfoProvider getPeerInfoProvider() { + return this; + } + public InetAddress getPublicAddress(String aPeerAddress) { + return EndpointRegistry.getInstance().get(aPeerAddress); + } + +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoServiceClient.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoServiceClient.java new file mode 100644 index 000000000..d83526fb1 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PeerInfoServiceClient.java @@ -0,0 +1,150 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +PeerInfoServiceClient.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.util.List; + +import net.jxta.document.Advertisement; +import net.jxta.id.ID; +import net.jxta.protocol.ModuleSpecAdvertisement; +import net.jxta.socket.JxtaSocket; +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe; +import org.linphone.p2pproxy.core.Configurator; +import org.linphone.p2pproxy.core.GenericServiceClient; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.ServiceProvider; +import org.linphone.p2pproxy.core.JxtaNetworkManager.Mode; + + +public class PeerInfoServiceClient extends GenericServiceClient implements P2pProxyNetworkProbe, ServiceProvider{ + private final static Logger mLog = Logger.getLogger(PeerInfoServiceClient.class); + + public PeerInfoServiceClient(Configurator lProperties,JxtaNetworkManager aJxtaNetworkManager) { + super(lProperties,aJxtaNetworkManager,PeerInfoProviderService.ADV_NAME); + } + + + public InetAddress getPublicIpAddress() throws P2pProxyException { + checkObject(); + try { + checkSocketConnection(); + PublicIpAddressRequest lPublicIpAddressRequest = new PublicIpAddressRequest(mJxtaNetworkManager.getPeerGroup().getPeerID().toString()); + mOut.writeObject(lPublicIpAddressRequest); + mOut.flush(); + mLog.info("request message ["+lPublicIpAddressRequest+"] sent"); + Object lInputObj = mIn.readObject(); + mLog.info("response message ["+lInputObj+"] received"); + if(lInputObj instanceof PublicIpAddressResponse) { + PublicIpAddressResponse lPublicIpAddressResponse = (PublicIpAddressResponse)lInputObj; + InetAddress lInetAddress = lPublicIpAddressResponse.getPublicAddress(); + mLog.info("public IP ["+lInetAddress+"] received"); + return lInetAddress; + } else { + throw new P2pProxyException("unknown response ["+lInputObj+"]"); + } + } + catch(Exception e) { + throw new P2pProxyException(e); + } + + } + + + + + public boolean probeSocket(InetSocketAddress aSocketAddress, Protocol aProtocol) throws P2pProxyException { + checkObject(); + boolean lResult = false; + try { + checkSocketConnection(); + switch(aProtocol) { + case tcp: { + // open the socket on 0.0.0.0:port for NAT + + ServerSocket lSocketServer = new ServerSocket(aSocketAddress.getPort()); + lSocketServer.setSoTimeout(mSoTimout); + + // send request to server + sendRequest(aSocketAddress,aProtocol); + try { + lSocketServer.accept(); + + lResult = true; + }catch (SocketTimeoutException e) { + // + } + lSocketServer.close(); + break; + } + case udp: { + // open the socket on 0.0.0.0:port for NAT + DatagramSocket lLocalSocket = new DatagramSocket(aSocketAddress.getPort()); + byte[] lBuff = new byte[1500]; + DatagramPacket lDatagramPacket = new DatagramPacket(lBuff,lBuff.length); + lLocalSocket.setSoTimeout(mSoTimout); + + // send request to server + SocketProbeRequest lSocketProbeRequest = new SocketProbeRequest(aSocketAddress,aProtocol); + mOut.writeObject(lSocketProbeRequest); + mOut.flush(); + mLog.info("request message ["+lSocketProbeRequest+"] sent"); + try { + lLocalSocket.receive(lDatagramPacket); + lResult = true; + }catch (SocketTimeoutException e) { + // nop + } + lLocalSocket.close(); + break; + } + default: throw new P2pProxyException("unsupported protocol ["+aProtocol+"]"); + } + if (lResult) { + mLog.info("socket ["+aSocketAddress+"] is reachable with protocol ["+aProtocol+"]"); + } else { + mLog.info("cannot reach ["+aSocketAddress+"] with protocol ["+aProtocol+"] for ["+mSoTimout+"] ms"); + } + return lResult; + } + catch(Exception e) { + throw new P2pProxyException(e); + } + } + private void sendRequest(SocketAddress aSocketAddress, Protocol aProtocol) throws IOException { + SocketProbeRequest lSocketProbeRequest = new SocketProbeRequest(aSocketAddress,aProtocol); + mOut.writeObject(lSocketProbeRequest); + mOut.flush(); + mLog.info("request message ["+lSocketProbeRequest+"] sent"); + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PublicIpAddressRequest.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PublicIpAddressRequest.java new file mode 100644 index 000000000..86904dd87 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PublicIpAddressRequest.java @@ -0,0 +1,41 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +PublicIpAddressRequest.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + +import java.io.Serializable; + +public class PublicIpAddressRequest implements Serializable{ + /** + * + */ + private static final long serialVersionUID = 1L; + final private String mPeerId; + PublicIpAddressRequest(String aPeerId) { + mPeerId = aPeerId; + } + public String getPeerId() { + return mPeerId; + } + public String toString() { + return "PublicIpAddressRequest for ["+mPeerId+"]"; + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PublicIpAddressResponse.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PublicIpAddressResponse.java new file mode 100644 index 000000000..7d246d0a3 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/PublicIpAddressResponse.java @@ -0,0 +1,58 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +PublicIpAddressResponse.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + +import java.io.Serializable; +import java.net.InetAddress; + +public class PublicIpAddressResponse implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + final private InetAddress mPublicAddress; + final private boolean mIsError; + final private String mErrorText; + public PublicIpAddressResponse(InetAddress aPublicAdress) { + mPublicAddress = aPublicAdress; + mIsError = false; + mErrorText =""; + } + public PublicIpAddressResponse(String anErroText) { + mPublicAddress = null; + mIsError = true; + mErrorText =anErroText; + + } + public InetAddress getPublicAddress() { + return mPublicAddress; + } + public boolean isError() { + return mIsError; + } + public String getErrorText() { + return mErrorText; + } + public String toString() { + return "PublicIpAddressResponse ip ["+mPublicAddress+"] error ["+mErrorText+"]"; + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/SocketProbeRequest.java b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/SocketProbeRequest.java new file mode 100644 index 000000000..adcfc0e88 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/rdvautoconfig/SocketProbeRequest.java @@ -0,0 +1,55 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +SocketProbeRequest.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.rdvautoconfig; + +import java.io.Serializable; +import java.net.SocketAddress; + +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe.Protocol; + +public class SocketProbeRequest implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + final private SocketAddress mSocketAddress; + final private Protocol mProtocol; + public SocketProbeRequest(SocketAddress aSocketAddress, Protocol aProtocol) { + mSocketAddress = aSocketAddress; + mProtocol = aProtocol; + } + /** + * @return Returns the mProtocol. + */ + public Protocol getProtocol() { + return mProtocol; + } + /** + * @return Returns the mSocketAddress. + */ + public SocketAddress getSocketAddress() { + return mSocketAddress; + } + + public String toString() { + return "SocketProbeRequest for ["+mSocketAddress+"] protocol ["+mProtocol+"]"; + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/turnserver/TurnServer.java b/p2pproxy/src/org/linphone/p2pproxy/core/turnserver/TurnServer.java new file mode 100644 index 000000000..1931afec9 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/turnserver/TurnServer.java @@ -0,0 +1,279 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package org.linphone.p2pproxy.core.turnserver; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Vector; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; + + +import de.javawi.jstun.attribute.ChangeRequest; +import de.javawi.jstun.attribute.ChangedAddress; +import de.javawi.jstun.attribute.MappedAddress; +import de.javawi.jstun.attribute.MessageAttributeException; +import de.javawi.jstun.attribute.MessageAttributeParsingException; +import de.javawi.jstun.attribute.ResponseAddress; +import de.javawi.jstun.attribute.SourceAddress; +import de.javawi.jstun.attribute.UnknownAttribute; +import de.javawi.jstun.attribute.UnknownMessageAttributeException; +import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType; +import de.javawi.jstun.header.MessageHeader; +import de.javawi.jstun.header.MessageHeaderParsingException; +import de.javawi.jstun.header.MessageHeaderInterface.MessageHeaderType; +import de.javawi.jstun.util.Address; +import de.javawi.jstun.util.UtilityException; + +/* + * This class implements a STUN server as described in RFC 3489. + * The server requires a machine that is dual-homed to be functional. + * This implementation uses a single ip/port. This lead to limited functionnality. + */ +public class TurnServer { + private static Logger logger = Logger.getLogger(TurnServer.class); + Vector sockets; + + public TurnServer(int primaryPort, InetAddress primary) throws SocketException { + sockets = new Vector(); + sockets.add(new DatagramSocket(primaryPort, primary)); + } + + public TurnServer(int primaryPort, InetAddress primary, int secondaryPort, InetAddress secondary) throws SocketException { + sockets = new Vector(); + sockets.add(new DatagramSocket(primaryPort, primary)); + //sockets.add(new DatagramSocket(secondaryPort, primary)); + //sockets.add(new DatagramSocket(primaryPort, secondary)); + //sockets.add(new DatagramSocket(secondaryPort, secondary)); + } + + public void start() throws SocketException { + for (DatagramSocket socket : sockets) { + socket.setReceiveBufferSize(2000); + StunServerReceiverThread ssrt = new StunServerReceiverThread(socket); + ssrt.start(); + } + } + + /* + * Inner class to handle incoming packets and react accordingly. + * I decided not to start a thread for every received Binding Request, because the time + * required to receive a Binding Request, parse it, generate a Binding Response and send + * it varies only between 2 and 4 milliseconds. This amount of time is small enough so + * that no extra thread is needed for incoming Binding Request. + */ + class StunServerReceiverThread extends Thread { + private DatagramSocket receiverSocket; + private DatagramSocket changedPort; + private DatagramSocket changedIP; + private DatagramSocket changedPortIP; + + StunServerReceiverThread(DatagramSocket datagramSocket) { + this.receiverSocket = datagramSocket; + for (DatagramSocket socket : sockets) { + if ((socket.getLocalPort() != receiverSocket.getLocalPort()) && + (socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedPort = socket; + if ((socket.getLocalPort() == receiverSocket.getLocalPort()) && + (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedIP = socket; + if ((socket.getLocalPort() != receiverSocket.getLocalPort()) && + (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedPortIP = socket; + } + } + + public void run() { + while (true) { + try { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + receiverSocket.receive(receive); + logger.debug(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " datagram received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort()); + MessageHeader receiveMH = MessageHeader.parseHeader(receive.getData()); + try { + receiveMH.parseAttributes(receive.getData()); + logger.info(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " Request received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort()); + + if (receiveMH.getType() == MessageHeaderType.BindingRequest) { + logger.info("Binding Request received "); + ChangeRequest cr = (ChangeRequest) receiveMH.getMessageAttribute(MessageAttributeType.ChangeRequest); + if (cr == null) throw new MessageAttributeException("Message attribute change request is not set."); + ResponseAddress ra = (ResponseAddress) receiveMH.getMessageAttribute(MessageAttributeType.ResponseAddress); + + MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingResponse); + sendMH.setTransactionID(receiveMH.getTransactionID()); + + // Mapped address attribute + MappedAddress ma = new MappedAddress(); + ma.setAddress(new Address(receive.getAddress().getAddress())); + ma.setPort(receive.getPort()); + sendMH.addMessageAttribute(ma); + // Changed address attribute + //ChangedAddress ca = new ChangedAddress(); + //ca.setAddress(new Address(changedPortIP.getLocalAddress().getAddress())); + //ca.setPort(changedPortIP.getLocalPort()); + //sendMH.addMessageAttribute(ca); + if (cr.isChangePort() && (!cr.isChangeIP())) { + logger.info("Change port received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(changedPort.getLocalAddress().getAddress())); + sa.setPort(changedPort.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + changedPort.send(send); + logger.info(changedPort.getLocalAddress().getHostAddress() + ":" + changedPort.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } else if ((!cr.isChangePort()) && cr.isChangeIP()) { + logger.info("Change ip received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(changedIP.getLocalAddress().getAddress())); + sa.setPort(changedIP.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + changedIP.send(send); + logger.info(changedIP.getLocalAddress().getHostAddress() + ":" + changedIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } else if ((!cr.isChangePort()) && (!cr.isChangeIP())) { + logger.info("Nothing received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(receiverSocket.getLocalAddress().getAddress())); + sa.setPort(receiverSocket.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + receiverSocket.send(send); + logger.info(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } else if (cr.isChangePort() && cr.isChangeIP()) { + logger.info("Change port and ip received in Change Request attribute"); + // Source address attribute + SourceAddress sa = new SourceAddress(); + sa.setAddress(new Address(changedPortIP.getLocalAddress().getAddress())); + sa.setPort(changedPortIP.getLocalPort()); + sendMH.addMessageAttribute(sa); + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + if (ra != null) { + send.setPort(ra.getPort()); + send.setAddress(ra.getAddress().getInetAddress()); + } else { + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + } + changedPortIP.send(send); + logger.info(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } + } else if (receiveMH.getType() == MessageHeaderType.AllocateRequest) { + logger.info("Allocate Request received "); + MessageHeader sendMH = new MessageHeader(MessageHeaderType.AllocateResponse); + sendMH.setTransactionID(receiveMH.getTransactionID()); + + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + receiverSocket.send(send); + logger.info( "Send Allocate Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } + } catch (UnknownMessageAttributeException umae) { + umae.printStackTrace(); + // Generate Binding error response + MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingErrorResponse); + sendMH.setTransactionID(receiveMH.getTransactionID()); + + // Unknown attributes + UnknownAttribute ua = new UnknownAttribute(); + ua.addAttribute(umae.getType()); + sendMH.addMessageAttribute(ua); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + send.setPort(receive.getPort()); + send.setAddress(receive.getAddress()); + receiverSocket.send(send); + logger.info(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Error Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); + } + } catch (IOException ioe) { + ioe.printStackTrace(); + } catch (MessageAttributeParsingException mape) { + mape.printStackTrace(); + } catch (MessageAttributeException mae) { + mae.printStackTrace(); + } catch (MessageHeaderParsingException mhpe) { + mhpe.printStackTrace(); + } catch (UtilityException ue) { + ue.printStackTrace(); + } catch (ArrayIndexOutOfBoundsException aioobe) { + aioobe.printStackTrace(); + } + } + } + } + + /* + * To invoke the STUN server two IP addresses and two ports are required. + */ + public static void main(String args[]) { + try { + if (args.length != 4) { + System.out.println("usage: java de.javawi.jstun.test.demo.StunServer PORT1 IP1 PORT2 IP2"); + System.out.println(); + System.out.println(" PORT1 - the first port that should be used by the server"); + System.out.println(" IP1 - the first ip address that should be used by the server"); + System.out.println(" PORT2 - the second port that should be used by the server"); + System.out.println(" IP2 - the second ip address that should be used by the server"); + System.exit(0); + } + BasicConfigurator.configure(); + TurnServer ss = new TurnServer(Integer.parseInt(args[0]), + InetAddress.getByName(args[1]), + Integer.parseInt(args[2]), + InetAddress.getByName(args[3])); + ss.start(); + } catch (SocketException se) { + se.printStackTrace(); + } catch (UnknownHostException uhe) { + uhe.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/utils/AccountManagerCli.java b/p2pproxy/src/org/linphone/p2pproxy/core/utils/AccountManagerCli.java new file mode 100644 index 000000000..95cf84948 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/utils/AccountManagerCli.java @@ -0,0 +1,129 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +AccountManagerCli.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.utils; + + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyUserAlreadyExistException; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.P2pProxyAccountManagementMBean; +import org.linphone.p2pproxy.core.P2pProxyMain; +import org.linphone.p2pproxy.core.P2pProxyMainMBean; +import org.linphone.p2pproxy.core.SipProxyRegistrar; + +public class AccountManagerCli { + public final static String USER_ADD = "user-add"; + public final static String RELOAD_TRACE = "reload-trace"; + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) { + try { + // get other params + String lCommand = "null"; + int lCommandArgsIndex=0; + for (int i=0; i < args.length; i=i+2) { + String argument = args[i]; + if (argument.equals("-c")) { + lCommand = args[i + 1]; + //nop + } else { + // no more option, takes args + lCommandArgsIndex = i; + + } + } + // Create an RMI connector client and + // connect it to the RMI connector server + // + JMXServiceURL lJMXServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:6789/jmxrmi"); + JMXConnector lJMXConnector = JMXConnectorFactory.connect(lJMXServiceURL, null); + + // Get an MBeanServerConnection + // + MBeanServerConnection lMBeanServerConnection = lJMXConnector.getMBeanServerConnection(); + + + ObjectName lP2pProxyAccountManagementMBeanName = new ObjectName(P2pProxyMain.ACCOUNT_MGR_MBEAN_NAME); + ObjectName lP2pProxyMainMBeanName = new ObjectName(P2pProxyMain.MAIN_MBEAN_NAME); + + if (USER_ADD.equals(lCommand)) { + P2pProxyAccountManagementMBean lP2pProxyAccountManagementMBean = (P2pProxyAccountManagementMBean) + MBeanServerInvocationHandler.newProxyInstance( lMBeanServerConnection + ,lP2pProxyAccountManagementMBeanName + ,P2pProxyAccountManagementMBean.class + ,true); + + System.out.println("creating user account for "+args[lCommandArgsIndex]); + System.out.println("please wait"); + try { + lP2pProxyAccountManagementMBean.createAccount(args[lCommandArgsIndex]); + } catch (P2pProxyUserAlreadyExistException e) { + System.out.println("cannot create user account for "+args[lCommandArgsIndex]); + System.out.println("already exist"); + + } + System.out.println("done"); + } else if (RELOAD_TRACE.equals(lCommand)) { + P2pProxyMainMBean lP2pProxyMainMBean = (P2pProxyMainMBean) + MBeanServerInvocationHandler.newProxyInstance( lMBeanServerConnection + ,lP2pProxyMainMBeanName + ,P2pProxyMainMBean.class + ,true); + + System.out.println("loading trace config file..."); + try { + lP2pProxyMainMBean.loadTraceConfigFile(); + } catch (P2pProxyException e) { + System.out.println("cannot load trace config file"); + } + System.out.println("done"); + } + else { + + System.out.println("unkwon command ["+lCommand+"]"); + usage(); + System.exit(1); + } + lJMXConnector.close(); + }catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + + + + } + + private static void usage() { + System.out.println("p2pproxy-cli"); + System.out.println("-c : command to execute {"+USER_ADD+" | "+RELOAD_TRACE+"}"); + System.out.println("-p : client port"); + } +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/utils/DumpLocalCache.java b/p2pproxy/src/org/linphone/p2pproxy/core/utils/DumpLocalCache.java new file mode 100644 index 000000000..9f6f2d797 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/utils/DumpLocalCache.java @@ -0,0 +1,45 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +DumpLocalCache.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.core.utils; + + + +import net.jxta.impl.util.cm.DumpCm; +import net.jxta.impl.util.cm.DumpCm.DumpCmCallback; + +public class DumpLocalCache { + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + DumpCm.dump(args, new DumpCmCallback() { + + public void println(String val) { + System.out.println(val); + } + + }); + + } + +} diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/utils/PeerGroupIdGenerator.java b/p2pproxy/src/org/linphone/p2pproxy/core/utils/PeerGroupIdGenerator.java new file mode 100644 index 000000000..e78dbc0cc --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/utils/PeerGroupIdGenerator.java @@ -0,0 +1,74 @@ +package org.linphone.p2pproxy.core.utils; +import java.security.MessageDigest; + +import net.jxta.id.IDFactory; + +/* + * Created on Sep 14, 2007 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ + +public class PeerGroupIdGenerator { + + /** + * @param args + */ + public static void main(String[] args) { + + System.out.print(createInfrastructurePeerGroupID("p2p.linphone.org","p2pproxy")); + + } + public static final net.jxta.peergroup.PeerGroupID createInfrastructurePeerGroupID(String clearTextID, String function){ + System.out.println("Creating peer group ID = clearText:'"+clearTextID+"' , function:'"+function+"'"); + byte[] digest = generateHash(clearTextID, function); + net.jxta.peergroup.PeerGroupID peerGroupID = IDFactory.newPeerGroupID( digest ); + return peerGroupID; + } + /** + * Generates an SHA-1 digest hash of the string: clearTextID+"-"+function or: clearTextID if function was blank.

            + * + * Note that the SHA-1 used only creates a 20 byte hash.

            + * + * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data. + * @param function A function related to the clearTextID string. This is used to create a hash associated with clearTextID so that it is a uique code. + * + * @return array of bytes containing the hash of the string: clearTextID+"-"+function or clearTextID if function was blank. Can return null if SHA-1 does not exist on platform. + */ + public static final byte[] generateHash(String clearTextID, String function) { + String id; + String functionSeperator = "-"; + if (function == null) { + id = clearTextID; + } else { + ; + id = clearTextID + functionSeperator + function; + } + byte[] buffer = id.getBytes(); + + MessageDigest algorithm = null; + + try { + algorithm = MessageDigest.getInstance("MD5"); + } catch (Exception e) { + System.out.println("Cannot load selected Digest Hash implementation"); + e.printStackTrace(); + return null; + } + + + // Generate the digest. + algorithm.reset(); + algorithm.update(buffer); + + try{ + byte[] digest1 = algorithm.digest(); + return digest1; + }catch(Exception de){ + System.out.println("Failed to creat a digest."); + de.printStackTrace(); + return null; + } + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pAutoConfigTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pAutoConfigTester.java new file mode 100644 index 000000000..3ef51d0b7 --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pAutoConfigTester.java @@ -0,0 +1,110 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pAutoConfigTester.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test; + + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe; +import org.linphone.p2pproxy.api.P2pProxyInstance.Mode; +import org.linphone.p2pproxy.core.P2pProxyInstanceImpl; + +public class P2pAutoConfigTester extends TestCase { + static private P2pProxyInstance mP2pProxyInstance; + private final static Logger mLog = Logger.getLogger(P2pAutoConfigTester.class); + //@BeforeClass + public static void setUpBeforeClass() throws Exception { + // setup logging + PropertyConfigurator.configure("log4j.properties"); + +// // 1 setup relays +// String lRunString = "java -cp eclipsebuild:dependencies/*.jar "; +// //lRunString +=" -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"; +// lRunString +=" org.linphone.p2pproxy.core.P2pProxyMain"; +// lRunString +=" -jxta " +System.getProperty("user.home")+"/P2pAutoConfigTester-seeding"; +// lRunString +=" -sip 5040 -seeding-server "; +// lRunString +=" -seeding-relay http://"+InetAddress.getLocalHost().getHostAddress()+":"+P2pProxyInstance.BASE_HTTP; +// lRunString +=" -seeding-rdv http://"+InetAddress.getLocalHost().getHostAddress()+":"+P2pProxyInstance.BASE_HTTP; +// mLog.info("starting ["+lRunString+"]"); +// Process lProcess = Runtime.getRuntime().exec(lRunString); + + + // setup edge + mP2pProxyInstance = new P2pProxyInstanceImpl(); + mP2pProxyInstance.setMode(Mode.edge); + mP2pProxyInstance.setIndex(1); + mP2pProxyInstance.start(); + while (mP2pProxyInstance.isStarted() == false) Thread.sleep(500); + + } + + //@Before + public void setUp() throws Exception { + if (mP2pProxyInstance == null) { + setUpBeforeClass(); + } + } + /** + * + */ + public void testGetPublicAddress() { + try { + Assert.assertEquals("wrong public ip" ,mP2pProxyInstance.getManager().getPublicIpAddress().getHostAddress(), InetAddress.getLocalHost().getHostAddress()); + mLog.info("testGetPublicAddress ok"); + } catch (Exception e) { + mLog.error("testGetPublicAddress ko",e); + Assert.fail(e.getMessage()); + } + } + /** + * + */ + public void testProbeTcpSocket() { + try { + InetSocketAddress lSocketAddress = new InetSocketAddress(InetAddress.getLocalHost(),9500); + Assert.assertTrue("cannot prob" ,mP2pProxyInstance.getManager().probeSocket(lSocketAddress, P2pProxyNetworkProbe.Protocol.tcp)); + mLog.info("testProbeSocket ok"); + } catch (Exception e) { + mLog.error("testProbeSocket ko",e); + Assert.fail(e.getMessage()); + } + } + /** + * + */ + public void testProbeUdpSocket() { + try { + InetSocketAddress lSocketAddress = new InetSocketAddress(InetAddress.getLocalHost(),9500); + Assert.assertTrue("cannot prob" ,mP2pProxyInstance.getManager().probeSocket(lSocketAddress, P2pProxyNetworkProbe.Protocol.udp)); + mLog.info("testProbeSocket ok"); + } catch (Exception e) { + mLog.error("testProbeSocket ko",e); + Assert.fail(e.getMessage()); + } + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyAccountManagementTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyAccountManagementTester.java new file mode 100644 index 000000000..837845b48 --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyAccountManagementTester.java @@ -0,0 +1,86 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyAccountManagementTester.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.linphone.p2pproxy.api.P2pProxyException; +import org.linphone.p2pproxy.api.P2pProxyUserAlreadyExistException; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.P2pProxyAccountManagement; +import org.linphone.p2pproxy.core.P2pProxyAccountManagementMBean; +import org.linphone.p2pproxy.test.utils.P2pNetwork; + +import junit.framework.Assert; +import junit.framework.TestCase; + + +public class P2pProxyAccountManagementTester extends TestCase { + private final static Logger mLog = Logger.getLogger(P2pProxyAccountManagementTester.class); + static private P2pNetwork mP2pNetwork=null; + static private P2pProxyAccountManagementMBean mP2pProxyAccountManagementA; + static private final String USER_A = "sip:usera@p2pproxytester.org"; + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + if (mP2pNetwork == null) { + // setup logging + PropertyConfigurator.configure("log4j.properties"); + + mP2pNetwork = new P2pNetwork(0,1); + mP2pProxyAccountManagementA = new P2pProxyAccountManagement((JxtaNetworkManager) mP2pNetwork.getSuperPeers().get(0).getOpaqueNetworkManager()); + } + } + + /* (non-Javadoc) + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); + } + public void testCreateAccount() { + try { + //1 create + mP2pProxyAccountManagementA.createAccount(USER_A); + //2 delete + mP2pProxyAccountManagementA.deleteAccount(USER_A); + } catch (Exception e) { + mLog.error("testCreateAccount ko",e); + Assert.fail(e.getMessage()); + } + } + + public void testDeleteAccount() { + + } + + public void testCreateAlreadyExistingAccount() { + + } + public void testDeleteNotExistingAccount() { + + } + +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyNatedNetworkTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyNatedNetworkTester.java new file mode 100644 index 000000000..075af0cdb --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyNatedNetworkTester.java @@ -0,0 +1,48 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pProxyNatedNetworkTester.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test; + +import java.net.InetAddress; +import java.util.ArrayList; + +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.test.utils.P2pNetwork; +import org.linphone.p2pproxy.test.utils.SipClient; + + +public class P2pProxyNatedNetworkTester extends P2pProxyNetworkingTester { + + /* (non-Javadoc) + * @see org.linphone.p2pproxy.test.P2pProxyNetworkingTester#setUp() + */ + @Override + protected void setUp() throws Exception { + if (mP2pNetwork == null) { + mP2pNetwork = new P2pNetwork(1,1,0,0,10,true,System.getProperty("p2pproxy.publicAddressUser",System.getProperty("user.name")),System.getProperty("p2pproxy.publicAddress",InetAddress.getLocalHost().getHostName())); + mProxyInstanceList = new ArrayList(mP2pNetwork.getAllPeers()); + for (P2pProxyInstance lP2pProxyInstance:mProxyInstanceList) { + SipClient lSipClient = new SipClient(lP2pProxyInstance.getSipClientProvider(),lP2pProxyInstance.getSipClientName(),lP2pProxyInstance.getAdvertisementDiscoveryTimeout()); + lSipClient.register(); + mClientList.add(lSipClient); + } + } + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyNetworkingTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyNetworkingTester.java new file mode 100644 index 000000000..e354b7379 --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyNetworkingTester.java @@ -0,0 +1,148 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pProxyNetworkTester.java - junit test for a whole p2pproxy network + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.test.utils.P2pNetwork; +import org.linphone.p2pproxy.test.utils.SipClient; + +import junit.framework.Assert; +import junit.framework.TestCase; + +public class P2pProxyNetworkingTester extends TestCase { + static { + PropertyConfigurator.configure("log4j.properties"); + } + static P2pNetwork mP2pNetwork =null; + static List mClientList = new ArrayList(); + static List mProxyInstanceList; + private final static Logger mLog = Logger.getLogger(P2pProxyNetworkingTester.class); + public P2pProxyNetworkingTester() { + // TODO Auto-generated constructor stub + } + + public P2pProxyNetworkingTester(String arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + public void testConnectedRdv() { + int lConnectedPeers=0; + for (P2pProxyInstance lSuperPeer:mP2pNetwork.getSuperPeers()) { + lConnectedPeers += lSuperPeer.getNumberOfconnectedPeers(); + } + Assert.assertEquals("all peer are not connected",mP2pNetwork.getEdgesPeers().size(),lConnectedPeers) ; + mLog.info("testConnectedPeers ok"); + } + /** + * test call from all peers + * + */ + public void testBasicCallFromAllPeers() { + try { + + for (int i=0;i(mP2pNetwork.getAllPeers()); + for (P2pProxyInstance lP2pProxyInstance:mProxyInstanceList) { + SipClient lSipClient = new SipClient(lP2pProxyInstance.getSipClientProvider(),lP2pProxyInstance.getSipClientName(),lP2pProxyInstance.getAdvertisementDiscoveryTimeout()); + lSipClient.register(); + mClientList.add(lSipClient); + } + Thread.sleep(10000); + } + } + + /* (non-Javadoc) + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); +// for (P2pProxyInstance lP2pProxyInstance:mProxyInstanceList) { +// SipClient lSipClient = new SipClient(lP2pProxyInstance.getSipClientProvider(),lP2pProxyInstance.getSipClientName()); +// lSipClient.unRegister(); +// } + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyTester.java new file mode 100644 index 000000000..de7502f20 --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/P2pProxyTester.java @@ -0,0 +1,441 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pProxyTester.java - junit test for p2pproxy + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + + + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.api.P2pProxyInstance.Mode; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.P2pProxyAccountManagement; +import org.linphone.p2pproxy.core.P2pProxyAccountManagementMBean; +import org.linphone.p2pproxy.core.P2pProxyInstanceImpl; +import org.linphone.p2pproxy.test.utils.DefaultCallListener; +import org.linphone.p2pproxy.test.utils.SipClient; +import org.zoolu.sip.address.NameAddress; +import org.zoolu.sip.call.Call; +import org.zoolu.sip.call.CallListener; +import org.zoolu.sip.message.Message; +import org.zoolu.sip.provider.SipProvider; + +import junit.framework.Assert; +import junit.framework.TestCase; + +public class P2pProxyTester extends TestCase { + + + private final static Logger mLog = Logger.getLogger(P2pProxyTester.class); + + static private SipProvider mProvider; + static final String mDefaultSipIdentity = "sip:p2pTester@linphone.org"; + static private SipClient mSipClient; + static private P2pProxyInstance mP2pProxyInstance; + final private String mCallerUri = "sip:caller@linphone.org"; + final private String mCalleeUri = "sip:callee@linphone.org"; + final private int RDV_DISCOVERY_TIMEOUT = 5000; + static private P2pProxyAccountManagementMBean mP2pProxyAccountManagement; + + public P2pProxyTester() { + + } + protected void setUp() throws Exception { + // setup logging + PropertyConfigurator.configure("log4j.properties"); + + if (mP2pProxyInstance == null) { + setupJxta(); + mProvider = mP2pProxyInstance.getSipClientProvider() ; + mSipClient = new SipClient(mProvider, mDefaultSipIdentity,RDV_DISCOVERY_TIMEOUT*2); + // create account for user mDefaultSipIdentity, mCallerUri, mCalleeUri if not exist + mP2pProxyAccountManagement = new P2pProxyAccountManagement((JxtaNetworkManager)mP2pProxyInstance.getOpaqueNetworkManager()); + + try { + mP2pProxyAccountManagement.createAccount(mDefaultSipIdentity); + } catch (Exception e) { + mLog.warn(e); + } + try { + mP2pProxyAccountManagement.createAccount(mCallerUri); + } catch (Exception e) { + mLog.warn(e); + } + + try { + mP2pProxyAccountManagement.createAccount(mCalleeUri); + } catch (Exception e) { + mLog.warn(e); + } + } + + } + + protected void tearDown() throws Exception { + } + + public void testSipRegisterUnregister() { + try { + //register + mSipClient.register(); + //unregister + mSipClient.unRegister(); + mLog.info("testSipRegisterUnregister ok"); + } catch (Exception e) { + mLog.error("testSipRegisterUnregister ko",e); + Assert.fail(e.getMessage()); + } + + } + public void testRegisterUnknownUser() { + try { + //register + Assert.assertFalse(mSipClient.register(900,"sip:toto@linphone.org",404)); + mLog.info("testRegisterUnknownUser ok"); + } catch (Exception e) { + mLog.error("testRegisterUnknownUser ko",e); + Assert.fail(e.getMessage()); + } + + } +// public void testPipeDiscovery() { +// try { +// long lDiscoveryTimout = 10000; +// //register +// mSipClient.register(900,mDefaultSipIdentity); +// DiscoveryService lDiscoveryService = ((JxtaNetworkManager)mP2pProxyInstance.getOpaqueNetworkManager()).getPeerGroup().getDiscoveryService(); +// final Semaphore lSemaphore = new Semaphore(0); +// DiscoveryListener lDiscoveryListener = new DiscoveryListener() { +// +// public void discoveryEvent(DiscoveryEvent event) { +// DiscoveryResponseMsg LRes = event.getResponse(); +// Enumeration lAdvertisementLists = LRes.getAdvertisements(); +// Advertisement lAdvertisement = (Advertisement) lAdvertisementLists.nextElement(); +// //Assert.assertEquals("not the good adv name", lContact, lAdvertisement.) +// mLog.info(lAdvertisement.toString()); +// lSemaphore.release(); +// } +// +// }; +// lDiscoveryService.getRemoteAdvertisements(null, DiscoveryService.ADV, "Name",mDefaultSipIdentity, 1,lDiscoveryListener); +// Assert.assertTrue("pipe not found until ["+lDiscoveryTimout+"]", lSemaphore.tryAcquire(lDiscoveryTimout,TimeUnit.MILLISECONDS)); +// lSemaphore.release(); +// +// //unregister +// mSipClient.register(0,mDefaultSipIdentity); +// mLog.info("testPipeDiscovery ok"); +// } catch (Exception e) { +// mLog.error("testPipeDiscovery ko",e); +// Assert.fail(e.getMessage()); +// } +// +// } + public void testCall() { + try { + Call(false); + } catch (Exception e) { + mLog.error("testCall ko",e); + Assert.fail(e.getMessage()); + } + + } + public void testCallWithSdp() { + try { + Call(true); + } catch (Exception e) { + mLog.error("testCallWithSdp ko",e); + Assert.fail(e.getMessage()); + } + + } + + private void Call(boolean useSdp) throws Exception { + //register + mSipClient.register(900,mCallerUri); + mSipClient.register(900,mCalleeUri); + call(mCallerUri,mCalleeUri,useSdp); + // unregister + mSipClient.register(0,mCallerUri); + mSipClient.register(0,mCalleeUri); + + mLog.info("testCall ok"); + + } + public void testUserNotFound() { + try { + long lTimout = (long) (RDV_DISCOVERY_TIMEOUT * 2); + //register + mSipClient.register(900,mCallerUri); + final Semaphore lCallerSemaphoreRefused = new Semaphore(0); + CallListener lCallerListener = new DefaultCallListener() { + public void onCallRefused(Call call, String reason, Message resp) { + lCallerSemaphoreRefused.release(); + Assert.assertEquals("bad reason, must be user not found", 404, resp.getStatusLine().getCode()); + } + }; + Call lCaller = new Call(mProvider, mCallerUri, mSipClient.getContact(mProvider), lCallerListener); + lCaller.call(mCalleeUri); + Assert.assertTrue("caller call not refused until ["+lTimout+"]", lCallerSemaphoreRefused.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + // unregister + mSipClient.register(0,mCallerUri); + + mLog.info("testUserNotFound ok"); + } catch (Exception e) { + mLog.error("testUserNotFound ko",e); + Assert.fail(e.getMessage()); + } + } + public void testUserUnregisterred() { + try { + long lTimout = RDV_DISCOVERY_TIMEOUT * 2; + //register + mSipClient.register(900,mCallerUri); + mSipClient.register(900,mCalleeUri); + //unregister callee + mSipClient.register(0,mCalleeUri); + final Semaphore lCallerSemaphoreRefused = new Semaphore(0); + CallListener lCallerListener = new DefaultCallListener() { + public void onCallRefused(Call call, String reason, Message resp) { + lCallerSemaphoreRefused.release(); + Assert.assertEquals("bad reason, must be user not found", 404, resp.getStatusLine().getCode()); + } + }; + Call lCaller = new Call(mProvider, mCallerUri, mSipClient.getContact(mProvider), lCallerListener); + lCaller.call(mCalleeUri); + Assert.assertTrue("caller call not refused until ["+lTimout+"]", lCallerSemaphoreRefused.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + // unregister caller + mSipClient.register(0,mCallerUri); + + mLog.info("testUserNotFound ok"); + } catch (Exception e) { + mLog.error("testUserNotFound ko",e); + Assert.fail(e.getMessage()); + } + } + public void testCallCancelledBeforeDialogEstablishement() { + try { + //Assert.fail("not debugged yet"); + long lTimout = RDV_DISCOVERY_TIMEOUT * 2; + //register + mSipClient.register(900,mCallerUri); + //mSipClient.register(0,mCalleeUri); + final Semaphore lCallerSemaphoreCancel = new Semaphore(0); + CallListener lCallerListener = new DefaultCallListener() { + public void onCallRefused(Call call, String reason, Message resp) { + Assert.assertEquals("bad reason, must be Request Terminated", 487, resp.getStatusLine().getCode()); + lCallerSemaphoreCancel.release(); + } + + }; + Call lCaller = new Call(mProvider, mCallerUri, mSipClient.getContact(mProvider), lCallerListener); + lCaller.call(mCalleeUri); + Thread.sleep(1000); + lCaller.cancel(); + Assert.assertTrue("caller call not canceled until ["+lTimout+"]", lCallerSemaphoreCancel.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + // unregister + mSipClient.register(0,mCallerUri); + + mLog.info("testCallCancelledBeforeDialogEstablishement ok"); + } catch (Exception e) { + mLog.error("testCallCancelledBeforeDialogEstablishement ko",e); + Assert.fail(e.getMessage()); + } + } + + public void testCallCancelledAfterRinging() { + try { + long lTimout = RDV_DISCOVERY_TIMEOUT * 2; + //register + mSipClient.register(900,mCallerUri); + mSipClient.register(900,mCalleeUri); + final Semaphore lCalleeSemaphoreCanceling = new Semaphore(0); + final Semaphore lCallerSemaphoreRinging = new Semaphore(0); + final Semaphore lCallerSemaphoreCanceled = new Semaphore(0); + CallListener lCallerListener = new DefaultCallListener() { + + public void onCallRinging(Call call, Message resp) { + lCallerSemaphoreRinging.release(); + } + public void onCallRefused(Call call, String reason, Message resp) { + Assert.assertEquals("bad reason, must be Request Terminated", 487, resp.getStatusLine().getCode()); + lCallerSemaphoreCanceled.release(); + } + + }; + Call lCaller = new Call(mProvider, mCallerUri, mSipClient.getContact(mProvider), lCallerListener); + final Semaphore lCalleeSemaphoreIncoming = new Semaphore(0); + CallListener lCalleeListener = new DefaultCallListener() { + public void onCallIncoming(Call call, NameAddress callee, NameAddress caller, String sdp, Message invite) { + lCalleeSemaphoreIncoming.release(); + call.ring(); + } + public void onCallCanceling(Call call, Message cancel) { + lCalleeSemaphoreCanceling.release(); + } + + }; + Call lCallee = new Call(mProvider, mCalleeUri, mSipClient.getContact(mProvider), lCalleeListener); + lCallee.listen(); + lCaller.call(mCalleeUri); + + Assert.assertTrue("callee not alerted until ["+lTimout+"]", lCalleeSemaphoreIncoming.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + Assert.assertTrue("callee call not ringing until ["+lTimout+"]", lCallerSemaphoreRinging.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + lCaller.cancel(); + Assert.assertTrue("caller call not canceling until ["+lTimout+"]", lCalleeSemaphoreCanceling.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + Assert.assertTrue("caller call not refused until ["+lTimout+"]", lCallerSemaphoreCanceled.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + + // unregister + mSipClient.register(0,mCallerUri); + mSipClient.register(0,mCalleeUri); + + mLog.info("testCallCancelledAfterRinging ok"); + } catch (Exception e) { + mLog.error("testCallCancelledAfterRinging ko",e); + Assert.fail(e.getMessage()); + } + + } + public void testAlreadyRegister() { + Assert.fail("not implemented yet"); + } + public void testReRegisterAfterExpired() { + try { + //register + mSipClient.register(10,mCallerUri); + mSipClient.register(10,mCalleeUri); + call(mCallerUri,mCalleeUri); + // wait + Thread.sleep(10000); + mSipClient.register(20,mCallerUri); + mSipClient.register(20,mCalleeUri); + + call(mCallerUri,mCalleeUri); + + // unregister + mSipClient.register(0,mCallerUri); + mSipClient.register(0,mCalleeUri); + + mLog.info("testReRegisterAfterExpired ok"); + } catch (Exception e) { + mLog.error("testtestReRegisterAfterExpired ko",e); + Assert.fail(e.getMessage()); + } + + + } + public void testReRegisterBeforeExpired() { + try { + //register + mSipClient.register(900,mCallerUri); + mSipClient.register(900,mCalleeUri); + + call(mCallerUri,mCalleeUri); + //re-register + mSipClient.register(900,mCallerUri); + mSipClient.register(900,mCalleeUri); + + call(mCallerUri,mCalleeUri); + + // unregister + mSipClient.register(0,mCallerUri); + mSipClient.register(0,mCalleeUri); + + mLog.info("testReRegisterBeforeExpired ok"); + } catch (Exception e) { + mLog.error("testReRegisterBeforeExpired ko",e); + Assert.fail(e.getMessage()); + } + + + } + + private void setupJxta() throws Exception { + mP2pProxyInstance = new P2pProxyInstanceImpl(); + mP2pProxyInstance.setMode(Mode.relay); + mP2pProxyInstance.setIndex(0); + mP2pProxyInstance.setProperty(JxtaNetworkManager.ADV_DISCOVERY_TIMEOUT, String.valueOf(RDV_DISCOVERY_TIMEOUT)); + mP2pProxyInstance.start(); + while (mP2pProxyInstance.isStarted() == false) Thread.sleep(500); + } + private void call(String aCaller,String aCallee) throws Exception { + call(aCaller,aCallee,false); + } + + private void call(String aCaller,String aCallee,boolean useSdp) throws Exception { + long lTimout = 1000; + final Semaphore lCallerSemaphoreAccepted = new Semaphore(0); + final Semaphore lCalleeSemaphoreClosed = new Semaphore(0); + final Semaphore lCallerSemaphoreRinging = new Semaphore(0); + CallListener lCallerListener = new DefaultCallListener() { + public void onCallAccepted(Call call, String sdp, Message resp) { + lCallerSemaphoreAccepted.release(); + call.ackWithAnswer(sdp); + } + public void onCallClosing(Call call, Message bye) { + //nop + } + public void onCallRinging(Call call, Message resp) { + lCallerSemaphoreRinging.release(); + } + }; + Call lCaller = new Call(mProvider, aCaller, mSipClient.getContact(mProvider), lCallerListener); + if (useSdp) { + lCaller.setLocalSessionDescriptor(SipClient.sdp_offer); + } + final Semaphore lCalleeSemaphoreConfirmed = new Semaphore(0); + final Semaphore lCalleeSemaphoreIncoming = new Semaphore(0); + CallListener lCalleeListener = new DefaultCallListener() { + public void onCallConfirmed(Call call, String sdp, Message ack) { + lCalleeSemaphoreConfirmed.release(); + call.bye(); + } + public void onCallIncoming(Call call, NameAddress callee, NameAddress caller, String sdp, Message invite) { + lCalleeSemaphoreIncoming.release(); + call.accept(sdp); + } + public void onCallClosed(Call call, Message resp) { + lCalleeSemaphoreClosed.release(); + } + }; + Call lCallee = new Call(mProvider, aCallee, mSipClient.getContact(mProvider), lCalleeListener); + if (useSdp) { + lCallee.setLocalSessionDescriptor(SipClient.sdp_offer); + } + lCallee.listen(); + lCaller.call(aCallee); + + Assert.assertTrue("callee not alerted until ["+lTimout+"]", lCalleeSemaphoreIncoming.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + Assert.assertTrue("caller call not accepted until ["+lTimout+"]", lCallerSemaphoreAccepted.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + Assert.assertTrue("callee call not confirmed until ["+lTimout+"]", lCalleeSemaphoreConfirmed.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + Assert.assertTrue("caller call not closed until ["+lTimout+"]", lCalleeSemaphoreClosed.tryAcquire(lTimout,TimeUnit.MILLISECONDS)); + + } + public void testBunchOfCall() { + for (int i=0;i<20;i++) { + testCallCancelledBeforeDialogEstablishement(); + testCall(); + testCallCancelledAfterRinging(); + } + } + +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/RtpRelayServerTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/RtpRelayServerTester.java new file mode 100644 index 000000000..082791e37 --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/RtpRelayServerTester.java @@ -0,0 +1,182 @@ +package org.linphone.p2pproxy.test; + + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.log4j.BasicConfigurator; +import org.junit.After; +import org.junit.Before; +import org.linphone.p2pproxy.core.media.rtprelay.RtpRelayServer; + +public class RtpRelayServerTester extends TestCase{ + + static private RtpRelayServer mRtpRelayServer; + static private int RTP_SERVER_PORT = 16000; + @Before + public void setUp() throws Exception { + if (mRtpRelayServer == null) { + BasicConfigurator.configure(); + mRtpRelayServer = new RtpRelayServer(new InetSocketAddress(RTP_SERVER_PORT),1000,1000); + } + } + + @After + public void tearDown() throws Exception { + //mRtpRelayServer.close(); + } + public void testRouting() { + _testRouting(1); + } + private void _testRouting(int aSessionId) { + byte lSsrcA = (byte) aSessionId; + byte lSsrcB = (byte) ~aSessionId; + byte[] lRtcpA = {0x55,(byte) 204,0x0,16 + ,0x0,0x01,0x02,lSsrcA //ssrc + ,'R','S','I','D' + ,'S','E','S','S',(byte) aSessionId}; + + byte[] lRtpA = {0x55,(byte) 34,0x0,16 + ,0x55,0x55,0x55,0x55 + ,0x0,0x01,0x02,lSsrcA //ssrc + ,0x55,0x55,0x55,0x55 + ,0x55,0x55,0x55,0x55}; + + + byte[] lRtcpB = {0x55,(byte) 204,0x0,16 + ,0x04,0x05,0x06,lSsrcB + ,'R','S','I','D' + ,'S','E','S','S',(byte) aSessionId}; + + byte[] lRtpB = {0x55,(byte) 34,0x0,16 + ,0x55,0x55,0x55,0x55 + ,0x04,0x05,0x06,lSsrcB //ssrc + ,0x55,0x55,0x55,0x55 + ,0x55,0x55,0x55,0x55}; + + + try { + //1 send rtcp app A + DatagramSocket lRtcpSocketA = new DatagramSocket(new InetSocketAddress("localhost", 0)); + DatagramPacket lRtcpaPacket = new DatagramPacket(lRtcpA,lRtcpA.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtcpSocketA.setSoTimeout(100); + lRtcpSocketA.send(lRtcpaPacket); + + //2 send rtcp app B + DatagramSocket lRtcpSocketB = new DatagramSocket(new InetSocketAddress("localhost", 0)); + DatagramPacket lRtcpbPacket = new DatagramPacket(lRtcpB,lRtcpB.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtcpSocketB.setSoTimeout(100); + lRtcpSocketB.send(lRtcpbPacket); + + + //3 send rtp A + DatagramSocket lRtpSocketA = new DatagramSocket(new InetSocketAddress("localhost", 0)); + DatagramPacket lRtpaPacket = new DatagramPacket(lRtpA,lRtpA.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtpSocketA.setSoTimeout(100); + lRtpSocketA.send(lRtpaPacket); + + //4 send rtp B + DatagramSocket lRtpSocketB = new DatagramSocket(new InetSocketAddress("localhost", 0)); + DatagramPacket lRtpblPacket = new DatagramPacket(lRtpB,lRtpB.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtpSocketB.send(lRtpblPacket); + lRtpSocketB.setSoTimeout(100); + + + + // check RTP B -> A + DatagramPacket lReceivedRtpaPacket = new DatagramPacket(new byte[1500],1500); + + + try { + lRtpSocketA.receive(lReceivedRtpaPacket); + // check ssrc + Assert.assertEquals("Unexpected packet received ",lSsrcB,(byte)RtpRelayServer.b2UB(lReceivedRtpaPacket.getData()[11])); + } catch (SocketTimeoutException e) { + Assert.fail("packet not relayed cause [" + e.getMessage()+"]"); + } + + //check RTP A->B + DatagramPacket lReceivedRtpbPacket = new DatagramPacket(new byte[1500],1500); + lRtpSocketA.setSoTimeout(100); + lRtpSocketA.send(lRtpaPacket); + try { + lRtpSocketB.receive(lReceivedRtpbPacket); + // check ssrc + Assert.assertEquals("Unexpected packet received ",lSsrcA,(byte)RtpRelayServer.b2UB(lReceivedRtpbPacket.getData()[11])); + } catch (SocketTimeoutException e) { + Assert.fail("packet not relayed cause [" + e.getMessage()+"]"); + } + + // check RTCP A->B + byte[] lRtcpASR = {0x55,(byte) 200,0x0,16 + ,0x0,0x01,0x02,lSsrcA //ssrc + ,'B','L','A','B','L','A'}; + + DatagramPacket lRtcpASRPacket = new DatagramPacket(lRtcpASR,lRtcpASR.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtcpSocketA.send(lRtcpASRPacket); + try { + lRtcpSocketB.receive(lReceivedRtpbPacket); + // check ssrc + Assert.assertEquals("Unexpected packet received ",lSsrcA,(byte)RtpRelayServer.b2UB(lReceivedRtpbPacket.getData()[7])); + } catch (SocketTimeoutException e) { + Assert.fail("packet not relayed cause [" + e.getMessage()+"]"); + } + + // check RTCP B->A + byte[] lRtcpBSR = {0x55,(byte) 200,0x0,16 + ,0x04,0x05,0x06,lSsrcB //ssrc + ,'B','L','A','B','L','A'}; + + DatagramPacket lRtcpBSRPacket = new DatagramPacket(lRtcpBSR,lRtcpBSR.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtcpSocketB.send(lRtcpBSRPacket); + try { + lRtcpSocketA.receive(lReceivedRtpbPacket); + // check ssrc + Assert.assertEquals("Unexpected packet received ",lSsrcB,(byte)RtpRelayServer.b2UB(lReceivedRtpbPacket.getData()[7])); + } catch (SocketTimeoutException e) { + Assert.fail("packet not relayed cause [" + e.getMessage()+"]"); + } + + // check unknown RTCP B->A + byte[] lRtcpSR = {0x55,(byte) 200,0x0,16 + ,0x55,0x55,0x56,0x55 //ssrc + ,'B','L','A','B','L','A'}; + + DatagramPacket lRtcpSRPacket = new DatagramPacket(lRtcpSR,lRtcpSR.length,InetAddress.getByName("localhost"), RTP_SERVER_PORT); + lRtcpSocketB.send(lRtcpSRPacket); + try { + lRtcpSocketA.receive(lReceivedRtpbPacket); + // check ssrc + Assert.fail("Unexpected packet received "); + } catch (SocketTimeoutException e) { + //ok + } + + + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + + } + public void testGC() { + try { + //1 launch traffic + int lOldValue = mRtpRelayServer.getRoutingtableSize(); + _testRouting(2); + Assert.assertEquals("unexpected routing table size", lOldValue+1,mRtpRelayServer.getRoutingtableSize()); + //2 wait 1,5s + Thread.sleep(1500); + Assert.assertTrue("unexpected routing table size ["+mRtpRelayServer.getRoutingtableSize()+"] should be less than or equal to ["+lOldValue+"]", mRtpRelayServer.getRoutingtableSize()<=lOldValue); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + + } + +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/TurnServerTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/TurnServerTester.java new file mode 100644 index 000000000..d69bc7ae0 --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/TurnServerTester.java @@ -0,0 +1,421 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - All rights + * reserved. + * + * This software is licensed under either the GNU Public License (GPL), + * or the Apache 2.0 license. Copies of both license agreements are + * included in this distribution. + */ + +package org.linphone.p2pproxy.test; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.core.turnserver.TurnServer; + + +import de.javawi.jstun.attribute.ChangeRequest; +import de.javawi.jstun.attribute.ChangedAddress; +import de.javawi.jstun.attribute.ErrorCode; +import de.javawi.jstun.attribute.MappedAddress; +import de.javawi.jstun.attribute.MessageAttribute; +import de.javawi.jstun.attribute.MessageAttributeException; +import de.javawi.jstun.attribute.MessageAttributeParsingException; +import de.javawi.jstun.header.MessageHeader; +import de.javawi.jstun.header.MessageHeaderParsingException; +import de.javawi.jstun.test.DiscoveryInfo; +import de.javawi.jstun.util.UtilityException; + +public class TurnServerTester extends TestCase { + private static Logger logger = Logger.getLogger(TurnServerTester.class); + InetAddress iaddress ; + String stunServer = "localhost"; + int port = 16000; + int timeoutInitValue = 300; //ms + MappedAddress ma = null; + ChangedAddress ca = null; + boolean nodeNatted = true; + DatagramSocket socketTest1 = null; + DiscoveryInfo di = null; + static TurnServer mSturServer = null; + + + public void setUp() throws Exception { + + if (mSturServer == null) { + BasicConfigurator.configure(); + if (mSturServer == null) mSturServer = new TurnServer(port,InetAddress.getByName("localhost")); + mSturServer.start(); + iaddress = InetAddress.getLocalHost(); + } + di = new DiscoveryInfo(iaddress); + } + + public DiscoveryInfo xxxtest() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException{ + ma = null; + ca = null; + nodeNatted = true; + socketTest1 = null; + di = new DiscoveryInfo(iaddress); + +// if (test1()) { +// if (test2()) { +// if (test1Redo()) { +// test3(); +// } +// } +// } + + socketTest1.close(); + + return di; + } + + public void testBindRequest() { + try { + bindRequest(); + } catch (Exception e) { + logger.error("testBindRequest ko",e); + Assert.fail(e.getMessage()); + } + + } + private boolean bindRequest() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageHeaderParsingException { + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + try { + // Test 1 including response + socketTest1 = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + socketTest1.setReuseAddress(true); + socketTest1.connect(InetAddress.getByName(stunServer), port); + socketTest1.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + socketTest1.send(send); + logger.info("Test 1: Binding Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + socketTest1.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + + ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress); + ca = (ChangedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ChangedAddress); + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.info("Message header contains an Errorcode message attribute."); + return false; + } + if ((ma == null) || (ca == null)) { + di.setError(700, "The server is sending an incomplete response (Mapped Address and Changed Address message attributes are missing). The client should not retry."); + logger.info("Response does not contain a Mapped Address or Changed Address message attribute."); + return false; + } else { + di.setPublicIP(ma.getAddress().getInetAddress()); + if ((ma.getPort() == socketTest1.getLocalPort()) && (ma.getAddress().getInetAddress().equals(socketTest1.getLocalAddress()))) { + logger.info("Node is not natted."); + nodeNatted = false; + } else { + logger.info("Node is natted."); + } + return true; + } + } catch (SocketTimeoutException ste) { + if (timeSinceFirstTransmission < 7900) { + logger.info("Test 1: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + // node is not capable of udp communication + logger.info("Test 1: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + di.setBlockedUDP(); + logger.info("Node is not capable of UDP communication."); + return false; + } + } + } + } + /** + * Test allocate request + * ALLOCATEREQUEST + * + */ + public void testAllocateRequest() { + + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + try { + // Test 1 including response + socketTest1 = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + socketTest1.setReuseAddress(true); + socketTest1.connect(InetAddress.getByName(stunServer), port); + socketTest1.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.AllocateRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + socketTest1.send(send); + logger.info("Allocate Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + socketTest1.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + + } catch (Exception ste) { + if (timeSinceFirstTransmission < 7900) { + logger.info("Allocate Rquest: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + // node is not capable of udp communication + logger.info("Allocate Rquest: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + di.setBlockedUDP(); + logger.info("Node is not capable of UDP communication."); + } + } + } + + + private boolean xxxtest2() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException { + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + try { + // Test 2 including response + DatagramSocket sendSocket = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + sendSocket.connect(InetAddress.getByName(stunServer), port); + sendSocket.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + changeRequest.setChangeIP(); + changeRequest.setChangePort(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + sendSocket.send(send); + logger.info("Test 2: Binding Request sent."); + + int localPort = sendSocket.getLocalPort(); + InetAddress localAddress = sendSocket.getLocalAddress(); + + sendSocket.close(); + + DatagramSocket receiveSocket = new DatagramSocket(localPort, localAddress); + receiveSocket.connect(ca.getAddress().getInetAddress(), ca.getPort()); + receiveSocket.setSoTimeout(timeout); + + MessageHeader receiveMH = new MessageHeader(); + while(!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + receiveSocket.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.info("Message header contains an Errorcode message attribute."); + return false; + } + if (!nodeNatted) { + di.setOpenAccess(); + logger.info("Node has open access to the Internet (or, at least the node is behind a full-cone NAT without translation)."); + } else { + di.setFullCone(); + logger.info("Node is behind a full-cone NAT."); + } + return false; + } catch (SocketTimeoutException ste) { + if (timeSinceFirstTransmission < 7900) { + logger.info("Test 2: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + logger.info("Test 2: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + if (!nodeNatted) { + di.setSymmetricUDPFirewall(); + logger.info("Node is behind a symmetric UDP firewall."); + return false; + } else { + // not is natted + // redo test 1 with address and port as offered in the changed-address message attribute + return true; + } + } + } + } + } + + private boolean xxxtest1Redo() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageHeaderParsingException{ + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + // redo test 1 with address and port as offered in the changed-address message attribute + try { + // Test 1 with changed port and address values + socketTest1.connect(ca.getAddress().getInetAddress(), ca.getPort()); + socketTest1.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + socketTest1.send(send); + logger.info("Test 1 redo with changed address: Binding Request sent."); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + socketTest1.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + MappedAddress ma2 = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress); + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.info("Message header contains an Errorcode message attribute."); + return false; + } + if (ma2 == null) { + di.setError(700, "The server is sending an incomplete response (Mapped Address message attribute is missing). The client should not retry."); + logger.info("Response does not contain a Mapped Address message attribute."); + return false; + } else { + if ((ma.getPort() != ma2.getPort()) || (!(ma.getAddress().getInetAddress().equals(ma2.getAddress().getInetAddress())))) { + di.setSymmetric(); + logger.info("Node is behind a symmetric NAT."); + return false; + } + } + return true; + } catch (SocketTimeoutException ste2) { + if (timeSinceFirstTransmission < 7900) { + logger.info("Test 1 redo with changed address: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + logger.info("Test 1 redo with changed address: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + return false; + } + } + } + } + + private void xxxtest3() throws UtilityException, SocketException, UnknownHostException, IOException, MessageAttributeParsingException, MessageAttributeException, MessageHeaderParsingException { + int timeSinceFirstTransmission = 0; + int timeout = timeoutInitValue; + while (true) { + try { + // Test 3 including response + DatagramSocket sendSocket = new DatagramSocket(new InetSocketAddress(iaddress, 0)); + sendSocket.connect(InetAddress.getByName(stunServer), port); + sendSocket.setSoTimeout(timeout); + + MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest); + sendMH.generateTransactionID(); + + ChangeRequest changeRequest = new ChangeRequest(); + changeRequest.setChangePort(); + sendMH.addMessageAttribute(changeRequest); + + byte[] data = sendMH.getBytes(); + DatagramPacket send = new DatagramPacket(data, data.length); + sendSocket.send(send); + logger.info("Test 3: Binding Request sent."); + + int localPort = sendSocket.getLocalPort(); + InetAddress localAddress = sendSocket.getLocalAddress(); + + sendSocket.close(); + + DatagramSocket receiveSocket = new DatagramSocket(localPort, localAddress); + receiveSocket.connect(InetAddress.getByName(stunServer), ca.getPort()); + receiveSocket.setSoTimeout(timeout); + + MessageHeader receiveMH = new MessageHeader(); + while (!(receiveMH.equalTransactionID(sendMH))) { + DatagramPacket receive = new DatagramPacket(new byte[200], 200); + receiveSocket.receive(receive); + receiveMH = MessageHeader.parseHeader(receive.getData()); + receiveMH.parseAttributes(receive.getData()); + } + ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.ErrorCode); + if (ec != null) { + di.setError(ec.getResponseCode(), ec.getReason()); + logger.info("Message header contains an Errorcode message attribute."); + return; + } + if (nodeNatted) { + di.setRestrictedCone(); + logger.info("Node is behind a restricted NAT."); + return; + } + } catch (SocketTimeoutException ste) { + if (timeSinceFirstTransmission < 7900) { + logger.info("Test 3: Socket timeout while receiving the response."); + timeSinceFirstTransmission += timeout; + int timeoutAddValue = (timeSinceFirstTransmission * 2); + if (timeoutAddValue > 1600) timeoutAddValue = 1600; + timeout = timeoutAddValue; + } else { + logger.info("Test 3: Socket timeout while receiving the response. Maximum retry limit exceed. Give up."); + di.setPortRestrictedCone(); + logger.info("Node is behind a port restricted NAT."); + return; + } + } + } + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/UdpRelayTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/UdpRelayTester.java new file mode 100644 index 000000000..add0cde6e --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/UdpRelayTester.java @@ -0,0 +1,125 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +P2pAutoConfigTester.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test; + + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.api.P2pProxyNetworkProbe; +import org.linphone.p2pproxy.api.P2pProxyInstance.Mode; +import org.linphone.p2pproxy.core.JxtaNetworkManager; +import org.linphone.p2pproxy.core.P2pProxyAccountManagement; +import org.linphone.p2pproxy.core.P2pProxyInstanceImpl; +import org.linphone.p2pproxy.core.P2pProxyMain; +import org.linphone.p2pproxy.test.utils.SipClient; + +public class UdpRelayTester extends TestCase { + static private P2pProxyInstance mP2pProxyInstance; + private static P2pProxyAccountManagement mP2pProxyAccountManagement; + static final String mDefaultSipIdentity = "sip:p2pTester@p2p.linphone.org"; + static final private String mCallerUri = "sip:caller@p2p.linphone.org"; + static final private String mCalleeUri = "sip:callee@p2p.linphone.org"; + + private final static Logger mLog = Logger.getLogger(UdpRelayTester.class); + + //@BeforeClass + public static void setUpBeforeClass() throws Exception { + // setup logging + //PropertyConfigurator.configure("log4j.properties"); + +// // 1 setup relays +// String lRunString = "java -cp eclipsebuild:dependencies/*.jar "; +// //lRunString +=" -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"; +// lRunString +=" org.linphone.p2pproxy.core.P2pProxyMain"; +// lRunString +=" -jxta " +System.getProperty("user.home")+"/P2pAutoConfigTester-seeding"; +// lRunString +=" -sip 5040 -seeding-server "; +// lRunString +=" -seeding-relay http://"+InetAddress.getLocalHost().getHostAddress()+":"+P2pProxyInstance.BASE_HTTP; +// lRunString +=" -seeding-rdv http://"+InetAddress.getLocalHost().getHostAddress()+":"+P2pProxyInstance.BASE_HTTP; +// mLog.info("starting ["+lRunString+"]"); +// Process lProcess = Runtime.getRuntime().exec(lRunString); + + System.setProperty("org.linphone.p2pproxy.home", "."); + P2pProxyMain.staticLoadTraceConfigFile(); + // setup edge + mP2pProxyInstance = new P2pProxyInstanceImpl(); + mP2pProxyInstance.setMode(Mode.edge); + mP2pProxyInstance.setIndex(1); + mP2pProxyInstance.start(); + while (mP2pProxyInstance.isStarted() == false) Thread.sleep(500); + + mP2pProxyAccountManagement = new P2pProxyAccountManagement((JxtaNetworkManager)mP2pProxyInstance.getOpaqueNetworkManager()); + + try { + mP2pProxyAccountManagement.createAccount(mDefaultSipIdentity); + } catch (Exception e) { + mLog.warn(e); + } + try { + mP2pProxyAccountManagement.createAccount(mCallerUri); + } catch (Exception e) { + mLog.warn(e); + } + + try { + mP2pProxyAccountManagement.createAccount(mCalleeUri); + } catch (Exception e) { + mLog.warn(e); + } + } + + //@Before + public void setUp() throws Exception { + if (mP2pProxyInstance == null) { + setUpBeforeClass(); + } + } + public void testAddressRequest() throws Exception { + try { + + Assert.assertTrue("cannot get relay addresses" ,mP2pProxyInstance.getRtpRelayManager().getAddresses().size()!=0); + mLog.info("testAddressRequest ok"); + } catch (Exception e) { + mLog.error("testAddressRequest ko",e); + Assert.fail(e.getMessage()); + } + } + public void testCallWithRelay() throws Exception { + try { + SipClient lCaller = new SipClient(mP2pProxyInstance.getSipClientProvider(),mCallerUri,mP2pProxyInstance.getAdvertisementDiscoveryTimeout()); + lCaller.register(); + SipClient lCallee = new SipClient(mP2pProxyInstance.getSipClientProvider(),mCalleeUri,mP2pProxyInstance.getAdvertisementDiscoveryTimeout()); + lCallee.register(); + + mLog.info("testCallWithRelay ok"); + } catch (Exception e) { + mLog.error("testCallWithRelay ko",e); + Assert.fail(e.getMessage()); + } + + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/utils/DefaultCallListener.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/utils/DefaultCallListener.java new file mode 100644 index 000000000..fddfbb17c --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/utils/DefaultCallListener.java @@ -0,0 +1,75 @@ +/* +p2pproxy +Copyright (C) 2007 Jehan Monnier () + +DefaultCallListener.java - . + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test.utils; + +import java.util.Vector; + +import junit.framework.Assert; + +import org.zoolu.sip.address.NameAddress; +import org.zoolu.sip.call.Call; +import org.zoolu.sip.call.CallListener; +import org.zoolu.sip.message.Message; + +public class DefaultCallListener implements CallListener { + public void onCallAccepted(Call call, String sdp, Message resp) { + Assert.fail("call accepted"); + } + public void onCallCanceling(Call call, Message cancel) { + Assert.fail("call canceled"); + } + public void onCallClosed(Call call, Message resp) { + Assert.fail("call closed"); } + + public void onCallClosing(Call call, Message bye) { + Assert.fail("call closing"); + } + public void onCallConfirmed(Call call, String sdp, Message ack) { + Assert.fail("call Confirmed"); + } + public void onCallIncoming(Call call, NameAddress callee, NameAddress caller, String sdp, Message invite) { + Assert.fail("call Incoming"); + } + public void onCallModifying(Call call, String sdp, Message invite) { + Assert.fail("call Modifying"); + } + public void onCallReInviteAccepted(Call call, String sdp, Message resp) { + Assert.fail("call ReInviteAccepted"); + } + public void onCallReInviteRefused(Call call, String reason, Message resp) { + Assert.fail("call ReInviteRefused"); + } + public void onCallReInviteTimeout(Call call) { + Assert.fail("call ReInviteTimeout"); + } + public void onCallRedirection(Call call, String reason, Vector contact_list, Message resp) { + Assert.fail("call Redirection"); + } + public void onCallRefused(Call call, String reason, Message resp) { + Assert.fail("call Refused reason ["+resp.getStatusLine()+"]"); + } + public void onCallRinging(Call call, Message resp) { + Assert.fail("call Ringing"); + } + public void onCallTimeout(Call call) { + Assert.fail("call Timeout"); + } +} diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/utils/P2pNetwork.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/utils/P2pNetwork.java new file mode 100644 index 000000000..eefbe34ad --- /dev/null +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/utils/P2pNetwork.java @@ -0,0 +1,224 @@ +/* +p2pproxy Copyright (C) 2007 Jehan Monnier () + +P2pNetwork.java -- create a jxta network. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.p2pproxy.test.utils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.InvalidPropertiesFormatException; +import java.util.List; + +import javax.security.cert.CertificateException; + +import org.apache.log4j.Logger; +import org.linphone.p2pproxy.api.P2pProxyInstance; +import org.linphone.p2pproxy.api.P2pProxyInstance.Mode; + +import net.jxta.exception.JxtaException; + +//import org.linphone.p2pproxy.Configurator; +//import org.linphone.p2pproxy.JxtaNetworkManager; +//import org.linphone.p2pproxy.P2pProxyException; + + +public class P2pNetwork { + private List mEdges = new ArrayList(); + private List mSuperPeers = new ArrayList(); + private final static Logger mLog = Logger.getLogger(P2pNetwork.class); + Process mSshProcess; + //String mPrivateAdress = "192.168.145.1"; + String mPrivateAdress = "127.0.0.1"; + + String mPublicAdress ; + String mPublicAdressUser ; + /** + * create a p2p network with super peers and edges + * @param nEdgees number of edge peer + * @param mRdv number of super peer + * @throws IOException + * @throws FileNotFoundException + * @throws InvalidPropertiesFormatException + * @throws CertificateException + * @throws URISyntaxException + * @throws P2pProxyException + * @throws InterruptedException + * @throws JxtaException + */ + public P2pNetwork(int nEdge,int mRdv) throws Exception { + this(nEdge,mRdv,0,0,100,false,System.getProperty("user.name"),"127.0.0.1"); + } + public P2pNetwork(int nEdge,int mRdv,int pAuto,int aBaseIndex,int aRelayCapacity, boolean isNated, String aUser,String aRemoteHost) throws Exception { + mPublicAdress = aRemoteHost; + mPublicAdressUser=aUser; + try { + + if (isNated == true) { + + //1 + setupDummySocks(aBaseIndex,nEdge+mRdv+pAuto); + //2 + + System.setProperty("socksProxyHost", mPrivateAdress); + System.setProperty("socksProxyPort", "1080"); + } + String [] lClassPath = { + "./antbuild/p2pproxy" + ,"./dependencies/bcprov-jdk14.jar" + ,"./dependencies/javax.servlet.jar" + ,"./dependencies/org.mortbay.jetty.jar" + }; + URL[] lUrlTab = new URL[lClassPath.length]; + for (int i=0;i(mEdges)) { + if (lP2pProxyInstance.isStarted() == false) { + lstarted = false; + } else { + if (lP2pProxyInstance.getMode() == Mode.relay) { + // move from edge list to relay + mEdges.remove(lP2pProxyInstance); + mSuperPeers.add(lP2pProxyInstance); + mLog.info("peer [ "+lP2pProxyInstance+"] moved from edge to relay" ); + } + } + } + Thread.sleep(1000); + }while (lstarted == false); + mLog.info("P2pNetwork started with ["+getEdgesPeers().size()+"] egdges and ["+getSuperPeers().size()+"]super peers"); + + } catch (Exception e) { + mLog.fatal("cannot create network",e); + } + + } + /** + * @return Returns the mEdges. + */ + public List getEdgesPeers() { + return mEdges; + } + /** + * @return Returns the mSuperPeers. + */ + public List getSuperPeers() { + return mSuperPeers; + } + public List getAllPeers() { + List lP2pProxyInstanceList = new ArrayList (); + lP2pProxyInstanceList.addAll(mSuperPeers); + lP2pProxyInstanceList.addAll(mEdges); + return lP2pProxyInstanceList; + } + public void stop() { + for (P2pProxyInstance lP2pProxyInstance:getAllPeers()) { + try { + lP2pProxyInstance.stop(); + } catch (Exception e) { + mLog.error("stop error", e); + //nop + } + } + mSshProcess.destroy(); + + } + private void setupDummySocks(int aBaseIndex, int numberOfPeers) throws InterruptedException, IOException { + StringBuffer lCommand =new StringBuffer("ssh -D "+mPrivateAdress+":1080 "); + for (int i=aBaseIndex; i